~audio-recorder/audio-recorder/trunk

« back to all changes in this revision

Viewing changes to src/timer.c

  • Committer: Osmo Antero
  • Date: 2012-09-29 18:12:44 UTC
  • Revision ID: osmoma@gmail.com-20120929181244-gmrxd5xww9pua60a
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include "support.h"
26
26
#include "dconf.h"
27
27
#include "log.h"
28
 
#include "gst-listener.h"
 
28
#include "gst-vad.h"
29
29
#include "audio-sources.h"
30
30
#include "rec-manager.h"
31
31
 
 
32
/*
 
33
  Sample commands:
 
34
 
 
35
  Clock time:
 
36
 
 
37
  start at 09:30 pm
 
38
  start at 21:30
 
39
  start at 21:30:00
 
40
 
 
41
  -- During runtime:
 
42
       * Compare clock time to given timer value (clock time hh:mm:ss).
 
43
       * Start recorder (pipeline) if condition is TRUE.
 
44
       * User must stop recording manually (or by other command).
 
45
  -----------------------------------------------------
 
46
 
 
47
  Clock time or duration of recording:
 
48
 
 
49
  stop at 11:30 am
 
50
  stop after 1h 20m
 
51
  stop after 1 hour 20 min
 
52
  pause after 20 min
 
53
 
 
54
  -- During runtime:
 
55
       * Compare clock time to the given timer value.
 
56
       * Compare duration to the given timer limit.
 
57
       * Stop or pause recorder (pipeline) if condition is TRUE.
 
58
  -----------------------------------------------------
 
59
 
 
60
  Managing "silence".
 
61
 
 
62
  stop if silence
 
63
  stop if silence 5s
 
64
  stop if silence 5s 0.4
 
65
  stop if silence 5s 40%
 
66
 
 
67
  -- During runtime:
 
68
       * Make sure VAD is running.
 
69
       * Send threshold signals to this module (timer.c)
 
70
       * Recorder will stop if threshold < limit.
 
71
  ------------------------------------------------------
 
72
 
 
73
  pause if silence 5s 0.3
 
74
  pause if silence 5s 30%
 
75
  pause if silence 5s -24dB
 
76
  pause if silence
 
77
 
 
78
  -- During runtime:
 
79
       * Make sure VAD is running.
 
80
       * Send threshold signals to this module (timer.c)
 
81
       * Recorder will PAUSE if threshold < limit, and PLAY if threshold >= limit.
 
82
  ---------------------------------------------------------
 
83
 
 
84
  Using "sound", "voice" and "audio" commands.
 
85
 
 
86
  start if sound
 
87
  start if sound 0.3
 
88
  start if voice 30%
 
89
  start if voice 0.3
 
90
  start if audio -20dB
 
91
 
 
92
  NOTICE: Unfortunately these commands cannot handle time delay very well!
 
93
 
 
94
  These commands fire immediately after the volume exceeds/or is beneath the given limit (default limit is 0.3, or 30%).
 
95
 
 
96
  -- During runtime:
 
97
       * Make sure VAD is running.
 
98
       * Send threshold signals to gst-recorder.c.
 
99
       * Recorder will START if threshold >= limit, and PAUSE if threshold < limit.
 
100
  ---------------------------------------------------------    
 
101
 
 
102
  File size:
 
103
 
 
104
  stop after 10MB
 
105
  pause if 2MB
 
106
 
 
107
  -- During runtime:
 
108
       * Take recorded file size and compare it to value in the timer command (in timer.c).
 
109
       * Start recorder (pipeline) if condition is TRUE.
 
110
  ---------------------------------------------------------    
 
111
 
 
112
  stop after 2 GB | 12 pm | silence 4s
 
113
  start at 10:20 pm | voice 
 
114
 
 
115
  Multiple conditions on one line, separated by "|" or "or".
 
116
  ---------------------------------------------------------    
 
117
 
 
118
  Notice: The words "voice", "audio" and "sound" have all *same meaning*. Ok!
 
119
 
 
120
  The word "silence" is relative to the given volume level/threshold. 
 
121
  Silence has both duration (in seconds) and volume limit.
 
122
 
 
123
  Volume limit can be given as:
 
124
  -Decimal value between [0, 1.0].
 
125
  -% value between [0%, 100%]. So 1.0 = 100%.
 
126
  -Or decibel value.
 
127
  
 
128
*/
 
129
 
32
130
// Timer function call frequency in seconds
33
131
#define TIMER_CALL_FREQ 1
34
132
 
35
 
// Default silence period (in seconds)
36
 
#define DEF_SILENCE_DURATION 7
37
 
 
38
 
// Default sound/audio/voice period (in seconds)
39
 
#define DEF_SOUND_DURATION 3
40
 
 
41
 
// Default RMS level for "silence" and "sound", "voice", "audio".
42
 
#define DEF_RMS_LEVEL 7 // 7% (ca. -24dB)
 
133
// Default silence duration (in seconds)
 
134
#define DEF_SILENCE_DURATION 3
43
135
 
44
136
// Timer function id
45
137
static guint g_timer_func_id = 0;
60
152
static void timer_set_start_time();
61
153
static struct tm timer_get_start_time();
62
154
static void timer_update_records_1();
63
 
static void timer_update_records_2();
64
155
 
65
156
static gchar timer_test_filesize(TimerRec *tr);
66
 
static gchar timer_test_silence(TimerRec *tr);
67
 
static gchar timer_test_sound(TimerRec *tr);
68
157
static gchar timer_test_clock_time(TimerRec *tr);
69
158
static gchar timer_test_time_duration(TimerRec *tr);
70
159
 
 
160
static void test_silence(TimerRec *tr, GstClockTimeDiff time_diff, gdouble rms);
 
161
static void test_sound(TimerRec *tr, GstClockTimeDiff time_diff, gdouble rms);
 
162
static void execute_action(TimerRec *tr, gchar action);
 
163
 
71
164
void timer_module_init() {
72
165
    LOG_DEBUG("Init timer.c.\n");
73
166
 
74
 
    // Init gst-listener.c
75
 
    listener_module_init();
 
167
    // Init gst-vad.c
 
168
    vad_module_init();
76
169
 
77
170
    g_timer_func_id = 0;
78
171
 
92
185
    // Clean up parser module
93
186
    parser_module_exit();
94
187
 
95
 
    // Clean up gst-listener.c
96
 
    listener_module_exit();
 
188
    // Clean up gst-vad.c
 
189
    vad_module_exit();
97
190
 
98
191
    g_t_list = NULL;
99
192
}
101
194
void timer_set_debug_flag(gboolean on_off) {
102
195
    // Set debug flag. Please see application options:
103
196
    // $ audio-recorder --help
104
 
    listener_set_debug_flag(on_off);
 
197
    vad_set_debug_flag(on_off);
105
198
}
106
199
 
107
200
void timer_module_reset(gint for_state) {
114
207
 
115
208
    case GST_STATE_PAUSED:
116
209
    case GST_STATE_NULL:
117
 
        timer_update_records_2();
 
210
        //timer_update_records_2();
118
211
        break;
119
212
 
120
213
    default:
125
218
void timer_module_rec_start() {
126
219
    // Called when recording stops.
127
220
 
128
 
    // Reset listener's signal/level statistics
129
 
    listener_clear_data();
130
 
 
131
221
    // Reset timer
132
 
    timer_update_records_2();
 
222
    timer_update_records_1();
133
223
}
134
224
 
135
225
// --------------------------------------------------
143
233
    }
144
234
 
145
235
    // Start the timer function
146
 
    g_timer_func_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, TIMER_CALL_FREQ, (GSourceFunc)timer_func_cb, (gpointer)1/*!= 0*/, (GDestroyNotify)timer_func_exit_cb);
 
236
    g_timer_func_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, TIMER_CALL_FREQ, (GSourceFunc)timer_func_cb, 
 
237
                                                 (gpointer)1/*!= 0*/, (GDestroyNotify)timer_func_exit_cb);
147
238
}
148
239
 
149
240
void timer_func_stop() {
168
259
 
169
260
static void timer_update_records_1() {
170
261
    // Reset timer nodes
171
 
 
172
262
    G_LOCK(g_t_list);
173
263
 
174
264
    GList *item = g_list_first(g_t_list);
175
265
    while (item) {
176
266
        TimerRec *tr = (TimerRec*)item->data;
177
267
 
178
 
        if (tr->done) {
179
 
            // Start to count from 0
180
 
            tr->seconds = 0;
181
 
            tr->seconds_x = 0;
182
 
        }
 
268
        // Start to count from 0
 
269
        tr->time_below = 0.0;
 
270
        tr->time_above = 0.0;
183
271
 
184
272
        // Next item
185
273
        item = g_list_next(item);
188
276
    G_UNLOCK(g_t_list);
189
277
}
190
278
 
 
279
#if 0 
191
280
static void timer_update_records_2() {
192
281
    // Reset timer nodes
193
282
 
195
284
 
196
285
    GList *item = g_list_first(g_t_list);
197
286
    while (item) {
198
 
        TimerRec *tr = (TimerRec*)item->data;
 
287
        //TimerRec *tr = (TimerRec*)item->data;
199
288
 
200
289
        // Start to count from 0
201
 
        tr->seconds = 0;
202
 
        tr->seconds_x = 0;
 
290
        //tr->seconds = 0;
 
291
        //tr->seconds_x = 0;
203
292
 
204
293
        // Next item
205
294
        item = g_list_next(item);
206
295
    }
207
 
 
208
296
    G_UNLOCK(g_t_list);
209
297
}
 
298
#endif
210
299
 
211
300
static void timer_clear_list() {
212
301
    // Reset the timer list
231
320
    return g_timer_start_time;
232
321
}
233
322
 
 
323
gdouble normalize_threshold(gdouble threshold, gchar *threshold_unit) {
 
324
    gdouble val = threshold;
 
325
    if (!threshold_unit) return val;
 
326
 
 
327
    // dB?
 
328
    if (threshold_unit[0] == 'd')  {
 
329
        // rms_dB:
 
330
        // RMS, http://en.wikipedia.org/wiki/Root_mean_square
 
331
        // From dB to a normalized 0 - 1.0 value.
 
332
        val = pow(10, threshold / 20);
 
333
    }
 
334
    // [0 - 100]% ?
 
335
    else if (threshold_unit[0] == '%')  {
 
336
        val = val / 100.0;
 
337
 
 
338
    // Already in [0 - 1.0]
 
339
    } else {
 
340
        // val = threshold;
 
341
    }
 
342
 
 
343
    return val;
 
344
}
 
345
 
 
346
gboolean check_need_VAD() {
 
347
    GList *item = g_list_first(g_t_list);
 
348
    while (item) {
 
349
        TimerRec *tr = (TimerRec*)item->data;
 
350
 
 
351
        if (!g_strcmp0(tr->label, "silence") ||
 
352
            !g_strcmp0(tr->label, "voice") ||
 
353
            !g_strcmp0(tr->label, "sound") ||
 
354
            !g_strcmp0(tr->label, "audio")) {
 
355
 
 
356
            return TRUE;
 
357
        }
 
358
 
 
359
        // Next item
 
360
        item = g_list_next(item);
 
361
    }
 
362
    return FALSE;
 
363
}
 
364
 
 
365
void normalize_values() {
 
366
    GList *item = g_list_first(g_t_list);
 
367
    while (item) {
 
368
        TimerRec *tr = (TimerRec*)item->data;
 
369
 
 
370
        // Convert hh:mm:ss to seconds
 
371
        tr->norm_secs = (gdouble)(tr->val[0]*3600 + tr->val[1]*60 + tr->val[2]);
 
372
 
 
373
        // Convert tr->threshold to [0 - 1.0] from tr->threshold_unit
 
374
        tr->norm_threshold = normalize_threshold(tr->threshold, tr->threshold_unit);
 
375
 
 
376
        // Next item
 
377
        item = g_list_next(item);
 
378
    }
 
379
}
 
380
 
234
381
gboolean timer_func_cb(gpointer user_data) {
235
382
    // The actual timer function
236
383
 
237
384
    // Timer is ON/OFF?
238
385
    static gboolean timer_active = FALSE;
239
386
 
240
 
    // Do we need data from the gst-listener.c?
241
 
    static gboolean need_listener = FALSE;
242
 
 
243
387
    // Counter to detect if GConf settings have been altered
244
388
    static gint setting_counter = -1;
245
389
 
 
390
    // Do we need VAD-pipeline?
 
391
    static gboolean need_VAD = FALSE;
 
392
 
246
393
    // Timer (GConf) settings changed?
247
394
    gint val = 0;
248
395
    conf_get_int_value("timer-setting-counter", &val);
249
396
 
250
 
    if (val != setting_counter) {
251
 
        // Save settings counter
252
 
        setting_counter = val;
253
 
 
254
 
        // Get new values from GConf
255
 
        conf_get_boolean_value("timer-active", &timer_active);
256
 
 
257
 
        LOG_TIMER("Timer settings changed:<%s>\n", (timer_active ? "timer ON" : "timer OFF"));
258
 
 
259
 
        // Timer is ON/OFF?
260
 
        if (!timer_active) {
261
 
            // It's OFF
262
 
 
263
 
            timer_clear_list();
264
 
 
265
 
            // Stop the listener
266
 
            listener_stop_listening();
267
 
 
268
 
            goto LBL_1;
269
 
 
270
 
        } else {
271
 
 
272
 
            // Set timer's start time
273
 
            timer_set_start_time();
274
 
 
275
 
            // Free the old g_t_list
276
 
            timer_clear_list();
277
 
 
278
 
            // Set lock
279
 
            G_LOCK(g_t_list);
280
 
 
281
 
            // Get timer text
282
 
            gchar *timer_text = NULL;
283
 
            conf_get_string_value("timer-text", &timer_text);
284
 
 
285
 
            LOG_TIMER("----------------\nTimer text is:\n<%s>\n--------------\n", timer_text);
286
 
 
287
 
            // Parse timer conditions.
288
 
            // This will return pointer to the g_timer_list (GList) in timer-parser.c.
289
 
            g_t_list = parser_parse_actions(timer_text);
290
 
 
291
 
            g_free(timer_text);
292
 
 
293
 
            if (g_list_length(g_t_list) < 1) {
294
 
                LOG_TIMER("The timer has no conditions.\n");
295
 
 
296
 
            } else {
297
 
                LOG_TIMER("The timer conditions are:\n");
 
397
    if (val == setting_counter) {
 
398
        // No changes in parameters.
 
399
        // Evaluate timer values.
 
400
        goto EVAL_0;
 
401
    }
 
402
 
 
403
    // Save settings counter
 
404
    setting_counter = val;
 
405
 
 
406
    // Get new values from GConf and parse values
 
407
    conf_get_boolean_value("timer-active", &timer_active);
 
408
 
 
409
    LOG_TIMER("Timer settings changed:<%s>\n", (timer_active ? "timer ON" : "timer OFF"));
 
410
 
 
411
    // Timer is ON/OFF?
 
412
    if (!timer_active) {
 
413
        // It's OFF
 
414
 
 
415
        timer_clear_list();
 
416
 
 
417
        // Stop the listener
 
418
        vad_stop_VAD();
 
419
 
 
420
        goto LBL_1;
 
421
    }
 
422
    
 
423
    // Set timer's start time
 
424
    timer_set_start_time();
 
425
 
 
426
    // Free the old g_t_list
 
427
    timer_clear_list();
 
428
 
 
429
    // Set lock
 
430
    G_LOCK(g_t_list);
 
431
 
 
432
    // Get timer text
 
433
    gchar *timer_text = NULL;
 
434
    conf_get_string_value("timer-text", &timer_text);
 
435
 
 
436
    LOG_TIMER("----------------\nTimer text is:\n<%s>\n--------------\n", timer_text);
 
437
 
 
438
    // Parse timer conditions.
 
439
    // This will return pointer to the g_timer_list (GList) in timer-parser.c.
 
440
    g_t_list = parser_parse_actions(timer_text);
 
441
 
 
442
    g_free(timer_text);
 
443
 
 
444
    if (g_list_length(g_t_list) < 1) {
 
445
        LOG_TIMER("The timer has no conditions.\n");
 
446
 
 
447
    } else {
 
448
        LOG_TIMER("The timer conditions are:\n");
298
449
 
299
450
#if defined(DEBUG_TIMER)
300
 
                // Debug print the command list
301
 
                parser_print_list(g_t_list);
 
451
        // Debug print the command list
 
452
        parser_print_list(g_t_list);
302
453
#endif
303
 
            }
304
 
 
305
 
            // Important: Start the listener only when we need it. It's CPU intensive.
306
 
            // Only "silence", "voice", "audio" and "sound" commands/conditions need data from the listener.
307
 
 
308
 
            need_listener = FALSE;
309
 
 
310
 
            GList *item = g_list_first(g_t_list);
311
 
            while (item) {
312
 
                TimerRec *tr = (TimerRec*)item->data;
313
 
 
314
 
                if (!g_strcmp0(tr->label, "silence") ||
315
 
                        !g_strcmp0(tr->label, "voice") ||
316
 
                        !g_strcmp0(tr->label, "sound") ||
317
 
                        !g_strcmp0(tr->label, "audio")) {
318
 
 
319
 
                    need_listener = TRUE;
320
 
                    break;
321
 
                }
322
 
 
323
 
                // Next item
324
 
                item = g_list_next(item);
325
 
            }
326
 
 
327
 
            // Unlock
328
 
            G_UNLOCK(g_t_list);
329
 
        }
330
454
    }
331
455
 
 
456
    // Important: Start VAD-pipeline only when we needed.
 
457
    // Only "silence", "voice", "audio" and "sound" commands/conditions need VAD (Voice Activity Detection).
 
458
    need_VAD = check_need_VAD();
 
459
    
 
460
    // Check if recorder was started with --debug-signal (or -d) argument
 
461
    need_VAD = need_VAD || vad_get_debug_flag();
 
462
 
 
463
    // Normalize values
 
464
    normalize_values();
 
465
 
 
466
    G_UNLOCK(g_t_list);
 
467
 
 
468
  EVAL_0:
332
469
 
333
470
    // Timer is ON?
334
471
    if (!timer_active) {
335
472
        // No.
336
 
        // Make sure the listener has stopped (do not waste CPU cycles)
337
 
        listener_stop_listening();
 
473
        // Make sure the VAD has stopped (do not waste CPU cycles)
 
474
        vad_stop_VAD();
338
475
        goto LBL_1;
 
476
    }
 
477
 
 
478
    // Yes. Timer is ON.
 
479
 
 
480
    // Do we need data from gst-vad.c?
 
481
    if (!need_VAD) {
 
482
        // No.
 
483
        // Make sure the VAD has stopped (do not waste CPU cycles)
 
484
        vad_stop_VAD();
339
485
 
340
486
    } else {
341
 
        // Yes. Timer is ON.
342
 
 
343
 
        // Do we need data from gst-listener.c?
344
 
        if (!need_listener) {
345
 
            // No.
346
 
            // Make sure the listener has stopped (do not waste CPU cycles)
347
 
            listener_stop_listening();
348
 
 
349
 
        } else {
350
 
            // Yes.
351
 
            // Start the listener and collect signal/level statistics
352
 
            listener_start_listening();
353
 
        }
 
487
        // Yes.
 
488
        // Start VAD.
 
489
        vad_start_VAD();
354
490
    }
355
491
 
 
492
    // ------------------------
 
493
    // Evaluate timer commands
 
494
    // ------------------------
356
495
 
357
 
    // Execute the TimerRec commands. For all TimerRec structures in GList...
 
496
    // For all TimerRec structures in GList...
358
497
    GList *item = g_list_first(g_t_list);
359
498
    while (item) {
360
499
        TimerRec *tr = (TimerRec*)item->data;
394
533
            LOG_TIMER("Filesize test = TRUE.\n");
395
534
        }
396
535
 
397
 
        // Test for silence (if average audio signal is under givel level)?
398
 
    } else if (!g_strcmp0(tr->label, "silence")) {
399
 
        // Examples:
400
 
        // stop/pause if silence 8s -26 dB
401
 
        // stop/pause if silence 8 sec 7 %
402
 
        // = start/stop/pause recording if sound level is under x dB in n seconds time.
403
 
 
404
 
        action = timer_test_silence(tr);
405
 
 
406
 
        if (action == 'c') {
407
 
            LOG_TIMER("Silence test. Continue after pause = TRUE.\n");
408
 
        } else if (action) {
409
 
            LOG_TIMER("Silence test = TRUE.\n");
410
 
        }
411
 
 
412
 
        // Test for voice/audio/sound?
413
 
    } else if (!g_strcmp0(tr->label, "voice") ||
414
 
               !g_strcmp0(tr->label, "sound") ||
415
 
               !g_strcmp0(tr->label, "audio")) {
416
 
 
417
 
        // start/stop/pause if voice/audio/sound 8s 7%
418
 
        // start/stop/pause if voice/audio/sound 8s -26dB
419
 
        // = start/stop/pause recording if voice/audio/sound is above x dB in n seconds period.
420
 
 
421
 
        action = timer_test_sound(tr);
422
 
 
423
 
        if (action == 'p') {
424
 
            LOG_TIMER("Sound/Audio/Voice test. Recording paused.\n");
425
 
        } else if (action) {
426
 
            LOG_TIMER("Sound/Audio/Voice test = TRUE.\n");
427
 
        }
428
 
 
429
536
        // Test clock time ##:##:##?
430
537
    } else if (tr->data_type == 't') {
431
 
        // start/stop/pause at ##:##:## am/pm (where ##:##:## is clock time in hh:mm:ss format)
 
538
        // start/stop/pause at ##:##:## am/pm (where ##:##:## is a clock time in hh:mm:ss format)
432
539
        // Example:
433
540
        // start/stop/pause at 10:15:00 pm
434
541
 
451
558
        }
452
559
    }
453
560
 
454
 
    switch (action) {
455
 
    case 'S': // Start recording
456
 
        tr->done = TRUE;
457
 
        rec_manager_start_recording();
458
 
        break;
459
 
 
460
 
    case 'T': // Stop recording
461
 
        tr->done = TRUE;
462
 
        rec_manager_stop_recording();
463
 
        break;
464
 
 
465
 
    case 'P': // Pause recording
466
 
        tr->done = TRUE;
467
 
        rec_manager_pause_recording();
468
 
        break;
469
 
 
470
 
    case 'p': // Pause (if recording was on).
471
 
        tr->done = TRUE;
472
 
        rec_manager_pause_recording();
473
 
        break;
474
 
 
475
 
    case 'c': // Continue (if was paused). Does not restart if recording is off.
476
 
        rec_manager_continue_recording();
477
 
        break;
478
 
 
479
 
    case 0: // Do nothing
480
 
        break;
481
 
 
482
 
    default:
483
 
        LOG_ERROR("Unknown timer action <%c>.\n", action);
484
 
    }
 
561
    execute_action(tr, action);
485
562
}
486
563
 
487
564
static gchar timer_test_filesize(TimerRec *tr) {
517
594
    return action;
518
595
}
519
596
 
520
 
static gchar timer_test_silence(TimerRec *tr) {
521
 
    // Test for silence (test if average audio signal is under givel level).
522
 
    //
523
 
    // 1. Test if audio level drops below x dB treshold (in n seconds time)
524
 
    // 2. Stop or pause recording if the condition is true.
525
 
    // 3. When audio level rises over x dB (in 1 seconds time), resume recording.
526
 
    // 4. Goto step 1.
527
 
    //
528
 
    // Examples:
529
 
    //  stop/pause if silence 8s -20 dB
530
 
    //  stop/pause if silence 8 sec 10 %
531
 
 
532
 
    gchar action = 0;
533
 
 
534
 
    // Length of silence
535
 
    gdouble seconds = tr->val[0]*3600.0 + tr->val[1]*60.0 + tr->val[2];
536
 
    if (seconds < 1)
537
 
        seconds = DEF_SILENCE_DURATION;
538
 
 
539
 
    // Get average RMS signal value from the listener process
540
 
    gdouble avg_rms_dB = 0; // In decibel (dB), -41dB to 0dB.
541
 
    gdouble avg_rms = 0; // In %, 0 - 100%. 0dB=100%, -41dB=0%.
542
 
    listener_get_average_rms(&avg_rms_dB, &avg_rms);
543
 
 
544
 
    double rms_level = 0;
545
 
 
546
 
    // The tr->level is given as % (0 - 100)?
547
 
    if (!g_strcmp0(tr->level_unit, "%")) {
548
 
        rms_level = tr->level; // %
549
 
 
550
 
    } else if (!g_strcmp0(tr->level_unit, "db")) {
551
 
 
552
 
        // Convert dB to % value
553
 
        rms_level = pow(10, tr->level / 20); // 0 - 1.0
554
 
        rms_level = rms_level * 100.0; // 0 - 100%
555
 
 
556
 
    } else {
557
 
        // Set default value
558
 
        rms_level = DEF_RMS_LEVEL;
559
 
    }
560
 
 
561
 
    // Get current recording state
562
 
    gint state = -1;
563
 
    gint pending = -1;
564
 
    rec_manager_get_state(&state, &pending);
565
 
 
566
 
#if defined(DEBUG_TIMER) || defined(DEBUG_ALL)
567
 
    // Name of state (for debugging)
568
 
    const gchar *state_name = rec_manager_get_state_name(state);
569
 
 
570
 
    LOG_TIMER("Silence test, seconds:%ld  curr seconds:%ld level:%3.1f%s (%3.1f%%), avg.rms:%3.1fdB (%3.1f%%) rec.state=%s\n", (long)seconds,
571
 
              (long)tr->seconds, tr->level, (tr->level_unit ? tr->level_unit : "dB"), rms_level, avg_rms_dB, avg_rms, state_name);
572
 
#endif
573
 
 
574
 
    // Step 3:
575
 
    // Test if we have paused the recording.
576
 
    // Eg. "pause if silence 5s 6%" has triggered a pause.
577
 
    // Now we have to continue/resume recording if the signal rises over rms_level (there is sound on the line).
578
 
 
579
 
    // Audio level is over or equal to rms_level?
580
 
    if (avg_rms >= rms_level && state == GST_STATE_PAUSED) {
581
 
        // Count seconds to continue
582
 
        tr->seconds_x += TIMER_CALL_FREQ;
583
 
 
584
 
        // Step 3:
585
 
        if (tr->seconds_x >= 1 /*1 SECONDS HARD-CODED*/) {
586
 
            // Continue recording (small 'c')
587
 
            action = 'c';
588
 
            tr->seconds = 0;
589
 
            tr->seconds_x = 0;
590
 
 
591
 
            // Reset done flag
592
 
            tr->done = FALSE;
593
 
        }
594
 
 
595
 
    } else {
596
 
        // Reset seconds_x
597
 
        tr->seconds_x = 0;
598
 
    }
599
 
 
600
 
    // Step 1:
601
 
    // Audio level is below rms_level?
602
 
    if (avg_rms < rms_level) {
603
 
        // Count seconds
604
 
        tr->seconds += TIMER_CALL_FREQ;
605
 
 
606
 
        if (tr->seconds >= seconds) {
607
 
 
608
 
            // Step 2:
609
 
            // Execute this command
610
 
            action = tr->action;
611
 
 
612
 
            // Reset silence counter
613
 
            tr->seconds = 0;
614
 
            tr->seconds_x = 0;
615
 
        }
616
 
 
617
 
    } else {
618
 
        // Reset silence counter
619
 
        tr->seconds = 0;
620
 
        tr->seconds_x = 0;
621
 
    }
622
 
 
623
 
    return action;
624
 
}
625
 
 
626
 
static gchar timer_test_sound(TimerRec *tr) {
627
 
    // Test for voice/audio/sound.
628
 
    //
629
 
    // 1. Test if audio level rises over x dB treshold (in n seconds time)
630
 
    // 2. Start/stop/pause recording if the condition is true.
631
 
    // 3. When audio level drops under x dB (in 4 seconds time), pause recording.
632
 
    // 4. Goto step 1.
633
 
    //
634
 
    // Examples:
635
 
    //  start/stop/pause if voice/audio/sound 8s 10%
636
 
    //  start/stop/pause if voice/audio/sound 8s -20dB
637
 
 
638
 
    gchar action = 0;
639
 
 
640
 
    // Length of audio/voice/sound
641
 
    gint64 seconds = (gint64)(tr->val[0]*3600 + tr->val[1]*60 + tr->val[2]);
642
 
    if (seconds < 1)
643
 
        seconds = DEF_SOUND_DURATION;
644
 
 
645
 
    // Get average RMS signal values from the listener process
646
 
    gdouble avg_rms_dB = 0; // In decibel (dB), -50dB to 0dB.
647
 
    gdouble avg_rms = 0; // In %, 0 - 100%. 0dB=100%, -41dB=0%.
648
 
    listener_get_average_rms(&avg_rms_dB, &avg_rms);
649
 
 
650
 
    double rms_level = 0;
651
 
 
652
 
    // The tr->level is given as % (0 - 100)?
653
 
    if (!g_strcmp0(tr->level_unit, "%")) {
654
 
        rms_level = tr->level; // %
655
 
 
656
 
    } else if (!g_strcmp0(tr->level_unit, "db")) {
657
 
 
658
 
        // Convert from dB to % value
659
 
        rms_level = pow(10, tr->level / 20); // 0 - 1.0
660
 
        rms_level = rms_level * 100.0; // 0 - 100%
661
 
 
662
 
    } else {
663
 
        // Set default value
664
 
        rms_level = DEF_RMS_LEVEL;
665
 
    }
666
 
 
667
 
    // Get current recording state
668
 
    gint state = -1;
669
 
    gint pending = -1;
670
 
    rec_manager_get_state(&state, &pending);
671
 
 
672
 
#if defined(DEBUG_TIMER) || defined(DEBUG_ALL)
673
 
    // Name of state (for debugging)
674
 
    const gchar *state_name = rec_manager_get_state_name(state);
675
 
 
676
 
    LOG_TIMER("Sound/Audio/Voice test: seconds:%ld  curr seconds:%ld(%ld) level:%3.1f%s (%3.1f%%), avg.rms:%3.1fdB (%3.1f%%), rec.state:%s\n",
677
 
              (long)seconds, (long)tr->seconds, (long)tr->seconds_x, tr->level, (tr->level_unit ? tr->level_unit : "dB"),
678
 
              rms_level, avg_rms_dB, avg_rms, state_name);
679
 
#endif
680
 
 
681
 
    // Step 3:
682
 
    // Test if we have already started recording.
683
 
    // Eg. "start if audio 4%" command has started recording.
684
 
    // Now we have to _pause_ if the signal drops under rms_level value for 5 seconds time.
685
 
 
686
 
    // Audio level is under rms_level?
687
 
    if (avg_rms < rms_level && state == GST_STATE_PLAYING) {
688
 
        // Count seconds to pause
689
 
        tr->seconds_x += TIMER_CALL_FREQ;
690
 
 
691
 
        if (tr->seconds_x >= 4 /* 4 SECONDS HARD-CODED */) {
692
 
            // Pause recording (small 'p')
693
 
            action = 'p';
694
 
            tr->seconds = 0;
695
 
            tr->seconds_x = 0;
696
 
        }
697
 
 
698
 
    } else {
699
 
        // Reset seconds_x (seconds before we pause)
700
 
        tr->seconds_x = 0;
701
 
    }
702
 
 
703
 
    gint64 test_seconds = 0;
704
 
 
705
 
    if (state == GST_STATE_PAUSED) {
706
 
        // Resume recording after 2 seconds if in paused state (see above).
707
 
        test_seconds = 2/* 2 SECONDS HARD-CODED */;
708
 
 
709
 
    } else {
710
 
 
711
 
        // Seconds defined in the timer.
712
 
        // start if sound 5s <---
713
 
        test_seconds = seconds;
714
 
    }
715
 
 
716
 
 
717
 
    // Step 1:
718
 
    // Audio level is above rms_level (and state != GST_STATE_PLAYING)?
719
 
    if (avg_rms >= rms_level && state != GST_STATE_PLAYING) {
720
 
        // Count seconds
721
 
        tr->seconds += TIMER_CALL_FREQ;
722
 
 
723
 
        if (tr->seconds >= test_seconds) {
724
 
 
725
 
            // Step 2:
726
 
            // Execute command (normally 'S' for start)
727
 
            action = tr->action;
728
 
 
729
 
            // Reset seconds
730
 
            tr->seconds = 0;
731
 
            tr->seconds_x = 0;
732
 
        }
733
 
 
734
 
    } else {
735
 
        // Reset seconds
736
 
        tr->seconds = 0;
737
 
    }
738
 
 
739
 
    return action;
740
 
}
741
 
 
742
597
static gchar timer_test_clock_time(TimerRec *tr) {
743
598
    // Test clock time.
744
 
    // start/stop/pause at ##:##:## am/pm (where ##:##:## is clock time in hh:mm:ss format)
 
599
    // start/stop/pause at ##:##:## am/pm (where ##:##:## is a clock time in hh:mm:ss format)
745
600
    // Examples:
746
601
    //  start at 10:15:00 pm
747
602
    //  pause at 9:30 am
758
613
 
759
614
    gint64 timer_secs = tr->val[0]*3600 +  tr->val[1]*60 +  tr->val[2];
760
615
 
761
 
    LOG_TIMER("Test clock time: current time is %02d:%02d:%02d  timer setting is %02.0f:%02.0f:%02.0f (day_of_year:%d/%d) diff in seconds:%ld\n",
762
 
              tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tr->val[0], tr->val[1], tr->val[2], tmp->tm_yday, tr->day_of_year, (long)(timer_secs - clock_secs));
 
616
    LOG_TIMER("Test clock time: current time is %02d:%02d:%02d  timer setting is %02.0f:%02.0f:%02.0f (day_of_year:%d/%d) diff in seconds:%ld\n", 
 
617
     tmp->tm_hour, tmp->tm_min, tmp->tm_sec, tr->val[0], tr->val[1], tr->val[2], tmp->tm_yday, 
 
618
     tr->day_of_year, (long)(timer_secs - clock_secs));
763
619
 
764
620
    // Note:
765
 
    // Do NOT fire if current clock time is 60 minutes or more over the timer value.
766
 
    // Eg. Do not fire if clock time is 14:00:00, and timer setting is:12:10:00 pm. We will assume here that the user means 12:10pm tomorrow, not today.
 
621
    // Do NOT fire if current clock time is 60 minutes or more over the trigger value.
 
622
    // Eg. Do not fire if clock time is 14:00:00, and timer setting is 12:10:00 pm. 
 
623
    // We will assume here that the user means 12:10pm tomorrow, not today.
767
624
 
768
625
    gint64 diff_secs = (clock_secs - timer_secs);
769
626
 
812
669
 
813
670
        gint64 diff = timer_secs - recording_time_secs;
814
671
 
815
 
        LOG_TIMER("Test time period (for sTop and Pause): current rec.time:%02d:%02d:%02d  timer setting is:%02.0f:%02.0f:%02.0f  diff in seconds:%ld\n",
 
672
        LOG_TIMER("Test time period (for sTop and Pause): current rec.time:%02d:%02d:%02d  timer setting:%02.0f:%02.0f:%02.0f  diff:%ld secs.\n", 
816
673
                  hh, mm, ss, tr->val[0], tr->val[1], tr->val[2], (long)diff);
 
674
 
817
675
#endif
818
676
 
819
677
        if (recording_time_secs >= timer_secs) {
845
703
        (void) diff; // Avoid unused var message
846
704
 
847
705
 
848
 
        LOG_TIMER("Test time period (for Start): clock time:%02d:%02d:%02d timer thread started:%02d:%02d:%02d setting:%02.0f:%02.0f:%02.0f  diff in secs:%ld\n",
849
 
                  tmp->tm_hour, tmp->tm_min, tmp->tm_sec, start_time.tm_hour, start_time.tm_min, start_time.tm_sec,
850
 
                  tr->val[0], tr->val[1], tr->val[2], (long)diff);
 
706
        LOG_TIMER("Test time period (for Start): clock time:%02d:%02d:%02d timer thread started:%02d:%02d:%02d setting:%02.0f:%02.0f:%02.0f  diff:%ld secs.\n",
 
707
          tmp->tm_hour, tmp->tm_min, tmp->tm_sec, start_time.tm_hour, start_time.tm_min, start_time.tm_sec,
 
708
          tr->val[0], tr->val[1], tr->val[2], (long)diff);
851
709
 
852
710
        if ((curr_time_secs - start_time_secs) >= timer_secs ) {
853
711
            // Execute command
861
719
    return action;
862
720
}
863
721
 
 
722
void timer_evaluate_triggers(GstClockTimeDiff time_diff, gdouble rms) {
 
723
    // This is called from gst-vad.c.
 
724
    // Evaluate VAD related timer commands.
 
725
    G_LOCK(g_t_list);
 
726
 
 
727
    GList *item = g_list_first(g_t_list);
 
728
    while (item) {
 
729
        TimerRec *tr = (TimerRec*)item->data;
 
730
 
 
731
        if (!g_strcmp0(tr->label, "silence")) {
 
732
 
 
733
            test_silence(tr, time_diff, rms);
 
734
 
 
735
        } else if (!g_strcmp0(tr->label, "voice") ||
 
736
                   !g_strcmp0(tr->label, "sound") ||
 
737
                   !g_strcmp0(tr->label, "audio")) {
 
738
 
 
739
            test_sound(tr, time_diff, rms);
 
740
        }
 
741
 
 
742
        // Next item
 
743
        item = g_list_next(item);
 
744
    }
 
745
 
 
746
    G_UNLOCK(g_t_list);
 
747
}
 
748
 
 
749
static void test_silence(TimerRec *tr, GstClockTimeDiff time_diff, gdouble rms) {
 
750
    // stop if silence
 
751
    // stop if silence 5s
 
752
    // stop if silence 5s 0.4
 
753
    // stop if silence 5s 40%
 
754
 
 
755
    // pause if silence
 
756
    // pause if silence 5s 0.3
 
757
    // pause if silence 5s 30%
 
758
    // pause if silence 5s -24dB
 
759
    gchar action = '\0';
 
760
 
 
761
    gdouble seconds = tr->norm_secs;
 
762
 
 
763
#if defined(DEBUG_TIMER) || defined(DEBUG_ALL)
 
764
    // Get recording state (for debugging)
 
765
    gint state = -1;
 
766
    gint pending = -1;
 
767
    rec_manager_get_state(&state, &pending);
 
768
 
 
769
    // Name of state
 
770
    const gchar *state_name = rec_manager_get_state_name(state);
 
771
 
 
772
    LOG_TIMER("Silence test. timer value:%3.1f sec, count seconds:%3.1f sec, *RMS:%3.2f, threshold:%3.1f%s (%3.2f), state:%s\n",
 
773
        seconds, tr->time_below, rms, tr->threshold, (tr->threshold_unit ? tr->threshold_unit : ""), tr->norm_threshold, state_name);
 
774
#endif
 
775
 
 
776
    // RMS > tr->threshold?
 
777
    if (rms > tr->norm_threshold + 0.001) { // 0.001=noise
 
778
        // Reset time teller
 
779
        tr->time_below = 0.0;
 
780
 
 
781
        if (tr->action == 'P') { // Pause
 
782
            // Resume (continue) recording after pause
 
783
            action = 'c'; 
 
784
            goto LBL_1;
 
785
        }
 
786
        return;
 
787
    }
 
788
 
 
789
    // Add time_diff to tr->time_below, convert to seconds
 
790
    tr->time_below += ((gdouble)time_diff / GST_SECOND);
 
791
 
 
792
    // tr->time_below < seconds?
 
793
    if (tr->time_below < seconds) {
 
794
        // Wait more
 
795
        return;
 
796
    }
 
797
 
 
798
    // Avoid overflow (no reason to keep this growing)
 
799
    if (tr->time_below > seconds + 140000) {
 
800
        tr->time_below = seconds + 140000;
 
801
    }
 
802
 
 
803
    // If here: RMS has been <= tr->threshold in seconds time.
 
804
    // Execute timer command.
 
805
 
 
806
    if (tr->action == 'T') { // sTop
 
807
        // stop if silence
 
808
        // stop if silence 0.3 4s
 
809
        action = 'T';
 
810
 
 
811
    } else if (tr->action == 'P') { // Pause
 
812
        // pause if silence 3s 0.2
 
813
        action = 'P';
 
814
    }
 
815
 
 
816
    LOG_TIMER("Condition %3.2f <= %3.2f (%3.2f%s) is TRUE in %3.1f seconds time. Execute command:%s.\n",
 
817
              rms, tr->norm_threshold, tr->threshold, (tr->threshold_unit ? tr->threshold_unit : ""),
 
818
              seconds, parser_get_action_name(action));
 
819
 
 
820
  LBL_1:
 
821
    // Exceute action 
 
822
    execute_action(tr, action);
 
823
}
 
824
 
 
825
static void test_sound(TimerRec *tr, GstClockTimeDiff time_diff, gdouble rms) {
 
826
    // start if sound
 
827
    // start if sound 0.3
 
828
    // start if voice 30%
 
829
    // start if voice 0.3
 
830
    // start if audio -20dB
 
831
    gchar action = '\0';
 
832
 
 
833
    gdouble seconds = tr->norm_secs;
 
834
 
 
835
    gint state = -1;
 
836
    gint pending = -1;
 
837
    rec_manager_get_state(&state, &pending);
 
838
 
 
839
#if defined(DEBUG_TIMER) || defined(DEBUG_ALL)
 
840
    // Name of state
 
841
    const gchar *state_name = rec_manager_get_state_name(state);
 
842
 
 
843
    LOG_TIMER("Sound/Voice/Audio test. timer value:%3.1f sec, count seconds:%3.1f sec, *RMS:%3.2f, threshold:%3.1f%s (%3.2f), state:%s\n",
 
844
        seconds, tr->time_above, rms, tr->threshold, (tr->threshold_unit ? tr->threshold_unit : ""), tr->norm_threshold, state_name);
 
845
#endif
 
846
 
 
847
    // rms over threshold?
 
848
    if (rms > tr->norm_threshold + 0.001) { // 0.001=noise
 
849
 
 
850
        // Paused temporarily?
 
851
        if (state == GST_STATE_PAUSED) {
 
852
            // Resume/continue recording immediately
 
853
            action = 'c';
 
854
            tr->time_above = 0.0;
 
855
            tr->time_below = 0.0;
 
856
            goto LBL_1;
 
857
        }
 
858
        
 
859
        // Add time_diff to tr->time_above, convert to seconds
 
860
        tr->time_above += ((gdouble)time_diff / GST_SECOND);
 
861
 
 
862
        // tr->time_above < seconds?
 
863
        if (tr->time_above < seconds) {
 
864
            // Wait more
 
865
            return;
 
866
        }
 
867
 
 
868
        // Avoid overflow (no reason to keep this growing)
 
869
        if (tr->time_above > seconds + 140000) {
 
870
            tr->time_above = seconds + 140000;
 
871
        }
 
872
 
 
873
        tr->time_below = 0.0;
 
874
 
 
875
        // If here: RMS has been > tr->threshold in seconds time.
 
876
        // Execute timer command.
 
877
        action = tr->action;
 
878
 
 
879
        LOG_TIMER("Condition %3.2f > %3.2f (%3.2f%s) is TRUE in %3.1f seconds time. Execute command:%s.\n",
 
880
                  rms, tr->norm_threshold, tr->threshold, (tr->threshold_unit ? tr->threshold_unit : ""),
 
881
                  seconds, parser_get_action_name(action));
 
882
 
 
883
        goto LBL_1;
 
884
    }
 
885
 
 
886
    // Here: rms < tr->norm_threshold.
 
887
 
 
888
    // Count seconds to pause
 
889
    tr->time_below += ((gdouble)time_diff / GST_SECOND);
 
890
 
 
891
    if (tr->time_below < 4.0) {
 
892
        // Wait more
 
893
        return;
 
894
    }
 
895
 
 
896
    // Pause recording temporarily
 
897
    action = 'p';
 
898
    tr->time_above = 0.0;
 
899
    tr->time_below = 0.0;
 
900
 
 
901
  LBL_1:
 
902
    // Excecute action 
 
903
    execute_action(tr, action);
 
904
 
 
905
}
 
906
 
 
907
void execute_action(TimerRec *tr, gchar action) {
 
908
    // Execute timer command
 
909
 
 
910
    // Get recording state (do not stress the command queue unnecessarily)
 
911
    gint state = -1;
 
912
    gint pending = -1;
 
913
    rec_manager_get_state(&state, &pending);
 
914
 
 
915
    switch (action) {
 
916
    case 'S': // Start recording
 
917
        tr->done = TRUE;
 
918
        if (state != GST_STATE_PLAYING)
 
919
            rec_manager_start_recording();
 
920
        break;
 
921
 
 
922
    case 'T': // Stop recording
 
923
        tr->done = TRUE;
 
924
        if (state != GST_STATE_NULL)
 
925
            rec_manager_stop_recording();
 
926
        break;
 
927
 
 
928
    case 'P': // Pause recording
 
929
        tr->done = TRUE;
 
930
        if (state == GST_STATE_PLAYING)
 
931
            rec_manager_pause_recording();
 
932
        break;
 
933
 
 
934
    case 'p': // Pause recording
 
935
        tr->done = TRUE;
 
936
        if (state == GST_STATE_PLAYING)
 
937
            rec_manager_pause_recording();
 
938
        break;
 
939
 
 
940
    case 'c': // Continue/resume (if was paused). Does not restart if recording is off.
 
941
        if (state != GST_STATE_PLAYING)
 
942
            rec_manager_continue_recording();
 
943
        break;
 
944
 
 
945
    case 0: // Do nothing
 
946
        break;
 
947
 
 
948
    default:
 
949
        LOG_ERROR("Unknown timer action <%c>.\n", action);
 
950
    }
 
951
}
 
952