25
25
#include "support.h"
28
#include "gst-listener.h"
29
29
#include "audio-sources.h"
30
30
#include "rec-manager.h"
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
-----------------------------------------------------
47
Clock time or duration of recording:
51
stop after 1 hour 20 min
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
-----------------------------------------------------
64
stop if silence 5s 0.4
65
stop if silence 5s 40%
68
* Make sure VAD is running.
69
* Send threshold signals to this module (timer.c)
70
* Recorder will stop if threshold < limit.
71
------------------------------------------------------
73
pause if silence 5s 0.3
74
pause if silence 5s 30%
75
pause if silence 5s -24dB
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
---------------------------------------------------------
84
Using "sound", "voice" and "audio" commands.
92
NOTICE: Unfortunately these commands cannot handle time delay very well!
94
These commands fire immediately after the volume exceeds/or is beneath the given limit (default limit is 0.3, or 30%).
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
---------------------------------------------------------
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
---------------------------------------------------------
112
stop after 2 GB | 12 pm | silence 4s
113
start at 10:20 pm | voice
115
Multiple conditions on one line, separated by "|" or "or".
116
---------------------------------------------------------
118
Notice: The words "voice", "audio" and "sound" have all *same meaning*. Ok!
120
The word "silence" is relative to the given volume level/threshold.
121
Silence has both duration (in seconds) and volume limit.
123
Volume limit can be given as:
124
-Decimal value between [0, 1.0].
125
-% value between [0%, 100%]. So 1.0 = 100%.
32
130
// Timer function call frequency in seconds
33
131
#define TIMER_CALL_FREQ 1
35
// Default silence period (in seconds)
36
#define DEF_SILENCE_DURATION 7
38
// Default sound/audio/voice period (in seconds)
39
#define DEF_SOUND_DURATION 3
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
44
136
// Timer function id
45
137
static guint g_timer_func_id = 0;
231
320
return g_timer_start_time;
323
gdouble normalize_threshold(gdouble threshold, gchar *threshold_unit) {
324
gdouble val = threshold;
325
if (!threshold_unit) return val;
328
if (threshold_unit[0] == 'd') {
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);
335
else if (threshold_unit[0] == '%') {
338
// Already in [0 - 1.0]
346
gboolean check_need_VAD() {
347
GList *item = g_list_first(g_t_list);
349
TimerRec *tr = (TimerRec*)item->data;
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")) {
360
item = g_list_next(item);
365
void normalize_values() {
366
GList *item = g_list_first(g_t_list);
368
TimerRec *tr = (TimerRec*)item->data;
370
// Convert hh:mm:ss to seconds
371
tr->norm_secs = (gdouble)(tr->val[0]*3600 + tr->val[1]*60 + tr->val[2]);
373
// Convert tr->threshold to [0 - 1.0] from tr->threshold_unit
374
tr->norm_threshold = normalize_threshold(tr->threshold, tr->threshold_unit);
377
item = g_list_next(item);
234
381
gboolean timer_func_cb(gpointer user_data) {
235
382
// The actual timer function
237
384
// Timer is ON/OFF?
238
385
static gboolean timer_active = FALSE;
240
// Do we need data from the gst-listener.c?
241
static gboolean need_listener = FALSE;
243
387
// Counter to detect if GConf settings have been altered
244
388
static gint setting_counter = -1;
390
// Do we need VAD-pipeline?
391
static gboolean need_VAD = FALSE;
246
393
// Timer (GConf) settings changed?
248
395
conf_get_int_value("timer-setting-counter", &val);
250
if (val != setting_counter) {
251
// Save settings counter
252
setting_counter = val;
254
// Get new values from GConf
255
conf_get_boolean_value("timer-active", &timer_active);
257
LOG_TIMER("Timer settings changed:<%s>\n", (timer_active ? "timer ON" : "timer OFF"));
266
listener_stop_listening();
272
// Set timer's start time
273
timer_set_start_time();
275
// Free the old g_t_list
282
gchar *timer_text = NULL;
283
conf_get_string_value("timer-text", &timer_text);
285
LOG_TIMER("----------------\nTimer text is:\n<%s>\n--------------\n", timer_text);
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);
293
if (g_list_length(g_t_list) < 1) {
294
LOG_TIMER("The timer has no conditions.\n");
297
LOG_TIMER("The timer conditions are:\n");
397
if (val == setting_counter) {
398
// No changes in parameters.
399
// Evaluate timer values.
403
// Save settings counter
404
setting_counter = val;
406
// Get new values from GConf and parse values
407
conf_get_boolean_value("timer-active", &timer_active);
409
LOG_TIMER("Timer settings changed:<%s>\n", (timer_active ? "timer ON" : "timer OFF"));
423
// Set timer's start time
424
timer_set_start_time();
426
// Free the old g_t_list
433
gchar *timer_text = NULL;
434
conf_get_string_value("timer-text", &timer_text);
436
LOG_TIMER("----------------\nTimer text is:\n<%s>\n--------------\n", timer_text);
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);
444
if (g_list_length(g_t_list) < 1) {
445
LOG_TIMER("The timer has no conditions.\n");
448
LOG_TIMER("The timer conditions are:\n");
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);
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.
308
need_listener = FALSE;
310
GList *item = g_list_first(g_t_list);
312
TimerRec *tr = (TimerRec*)item->data;
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")) {
319
need_listener = TRUE;
324
item = g_list_next(item);
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();
460
// Check if recorder was started with --debug-signal (or -d) argument
461
need_VAD = need_VAD || vad_get_debug_flag();
334
471
if (!timer_active) {
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)
480
// Do we need data from gst-vad.c?
483
// Make sure the VAD has stopped (do not waste CPU cycles)
343
// Do we need data from gst-listener.c?
344
if (!need_listener) {
346
// Make sure the listener has stopped (do not waste CPU cycles)
347
listener_stop_listening();
351
// Start the listener and collect signal/level statistics
352
listener_start_listening();
492
// ------------------------
493
// Evaluate timer commands
494
// ------------------------
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);
360
499
TimerRec *tr = (TimerRec*)item->data;
394
533
LOG_TIMER("Filesize test = TRUE.\n");
397
// Test for silence (if average audio signal is under givel level)?
398
} else if (!g_strcmp0(tr->label, "silence")) {
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.
404
action = timer_test_silence(tr);
407
LOG_TIMER("Silence test. Continue after pause = TRUE.\n");
409
LOG_TIMER("Silence test = TRUE.\n");
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")) {
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.
421
action = timer_test_sound(tr);
424
LOG_TIMER("Sound/Audio/Voice test. Recording paused.\n");
426
LOG_TIMER("Sound/Audio/Voice test = TRUE.\n");
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)
433
540
// start/stop/pause at 10:15:00 pm
520
static gchar timer_test_silence(TimerRec *tr) {
521
// Test for silence (test if average audio signal is under givel level).
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.
529
// stop/pause if silence 8s -20 dB
530
// stop/pause if silence 8 sec 10 %
535
gdouble seconds = tr->val[0]*3600.0 + tr->val[1]*60.0 + tr->val[2];
537
seconds = DEF_SILENCE_DURATION;
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);
544
double rms_level = 0;
546
// The tr->level is given as % (0 - 100)?
547
if (!g_strcmp0(tr->level_unit, "%")) {
548
rms_level = tr->level; // %
550
} else if (!g_strcmp0(tr->level_unit, "db")) {
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%
558
rms_level = DEF_RMS_LEVEL;
561
// Get current recording state
564
rec_manager_get_state(&state, &pending);
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);
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);
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).
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;
585
if (tr->seconds_x >= 1 /*1 SECONDS HARD-CODED*/) {
586
// Continue recording (small 'c')
601
// Audio level is below rms_level?
602
if (avg_rms < rms_level) {
604
tr->seconds += TIMER_CALL_FREQ;
606
if (tr->seconds >= seconds) {
609
// Execute this command
612
// Reset silence counter
618
// Reset silence counter
626
static gchar timer_test_sound(TimerRec *tr) {
627
// Test for voice/audio/sound.
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.
635
// start/stop/pause if voice/audio/sound 8s 10%
636
// start/stop/pause if voice/audio/sound 8s -20dB
640
// Length of audio/voice/sound
641
gint64 seconds = (gint64)(tr->val[0]*3600 + tr->val[1]*60 + tr->val[2]);
643
seconds = DEF_SOUND_DURATION;
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);
650
double rms_level = 0;
652
// The tr->level is given as % (0 - 100)?
653
if (!g_strcmp0(tr->level_unit, "%")) {
654
rms_level = tr->level; // %
656
} else if (!g_strcmp0(tr->level_unit, "db")) {
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%
664
rms_level = DEF_RMS_LEVEL;
667
// Get current recording state
670
rec_manager_get_state(&state, &pending);
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);
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);
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.
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;
691
if (tr->seconds_x >= 4 /* 4 SECONDS HARD-CODED */) {
692
// Pause recording (small 'p')
699
// Reset seconds_x (seconds before we pause)
703
gint64 test_seconds = 0;
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 */;
711
// Seconds defined in the timer.
712
// start if sound 5s <---
713
test_seconds = seconds;
718
// Audio level is above rms_level (and state != GST_STATE_PLAYING)?
719
if (avg_rms >= rms_level && state != GST_STATE_PLAYING) {
721
tr->seconds += TIMER_CALL_FREQ;
723
if (tr->seconds >= test_seconds) {
726
// Execute command (normally 'S' for start)
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)
746
601
// start at 10:15:00 pm
747
602
// pause at 9:30 am
759
614
gint64 timer_secs = tr->val[0]*3600 + tr->val[1]*60 + tr->val[2];
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));
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.
768
625
gint64 diff_secs = (clock_secs - timer_secs);
722
void timer_evaluate_triggers(GstClockTimeDiff time_diff, gdouble rms) {
723
// This is called from gst-vad.c.
724
// Evaluate VAD related timer commands.
727
GList *item = g_list_first(g_t_list);
729
TimerRec *tr = (TimerRec*)item->data;
731
if (!g_strcmp0(tr->label, "silence")) {
733
test_silence(tr, time_diff, rms);
735
} else if (!g_strcmp0(tr->label, "voice") ||
736
!g_strcmp0(tr->label, "sound") ||
737
!g_strcmp0(tr->label, "audio")) {
739
test_sound(tr, time_diff, rms);
743
item = g_list_next(item);
749
static void test_silence(TimerRec *tr, GstClockTimeDiff time_diff, gdouble rms) {
751
// stop if silence 5s
752
// stop if silence 5s 0.4
753
// stop if silence 5s 40%
756
// pause if silence 5s 0.3
757
// pause if silence 5s 30%
758
// pause if silence 5s -24dB
761
gdouble seconds = tr->norm_secs;
763
#if defined(DEBUG_TIMER) || defined(DEBUG_ALL)
764
// Get recording state (for debugging)
767
rec_manager_get_state(&state, &pending);
770
const gchar *state_name = rec_manager_get_state_name(state);
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);
776
// RMS > tr->threshold?
777
if (rms > tr->norm_threshold + 0.001) { // 0.001=noise
779
tr->time_below = 0.0;
781
if (tr->action == 'P') { // Pause
782
// Resume (continue) recording after pause
789
// Add time_diff to tr->time_below, convert to seconds
790
tr->time_below += ((gdouble)time_diff / GST_SECOND);
792
// tr->time_below < seconds?
793
if (tr->time_below < seconds) {
798
// Avoid overflow (no reason to keep this growing)
799
if (tr->time_below > seconds + 140000) {
800
tr->time_below = seconds + 140000;
803
// If here: RMS has been <= tr->threshold in seconds time.
804
// Execute timer command.
806
if (tr->action == 'T') { // sTop
808
// stop if silence 0.3 4s
811
} else if (tr->action == 'P') { // Pause
812
// pause if silence 3s 0.2
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));
822
execute_action(tr, action);
825
static void test_sound(TimerRec *tr, GstClockTimeDiff time_diff, gdouble rms) {
827
// start if sound 0.3
828
// start if voice 30%
829
// start if voice 0.3
830
// start if audio -20dB
833
gdouble seconds = tr->norm_secs;
837
rec_manager_get_state(&state, &pending);
839
#if defined(DEBUG_TIMER) || defined(DEBUG_ALL)
841
const gchar *state_name = rec_manager_get_state_name(state);
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);
847
// rms over threshold?
848
if (rms > tr->norm_threshold + 0.001) { // 0.001=noise
850
// Paused temporarily?
851
if (state == GST_STATE_PAUSED) {
852
// Resume/continue recording immediately
854
tr->time_above = 0.0;
855
tr->time_below = 0.0;
859
// Add time_diff to tr->time_above, convert to seconds
860
tr->time_above += ((gdouble)time_diff / GST_SECOND);
862
// tr->time_above < seconds?
863
if (tr->time_above < seconds) {
868
// Avoid overflow (no reason to keep this growing)
869
if (tr->time_above > seconds + 140000) {
870
tr->time_above = seconds + 140000;
873
tr->time_below = 0.0;
875
// If here: RMS has been > tr->threshold in seconds time.
876
// Execute timer command.
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));
886
// Here: rms < tr->norm_threshold.
888
// Count seconds to pause
889
tr->time_below += ((gdouble)time_diff / GST_SECOND);
891
if (tr->time_below < 4.0) {
896
// Pause recording temporarily
898
tr->time_above = 0.0;
899
tr->time_below = 0.0;
903
execute_action(tr, action);
907
void execute_action(TimerRec *tr, gchar action) {
908
// Execute timer command
910
// Get recording state (do not stress the command queue unnecessarily)
913
rec_manager_get_state(&state, &pending);
916
case 'S': // Start recording
918
if (state != GST_STATE_PLAYING)
919
rec_manager_start_recording();
922
case 'T': // Stop recording
924
if (state != GST_STATE_NULL)
925
rec_manager_stop_recording();
928
case 'P': // Pause recording
930
if (state == GST_STATE_PLAYING)
931
rec_manager_pause_recording();
934
case 'p': // Pause recording
936
if (state == GST_STATE_PLAYING)
937
rec_manager_pause_recording();
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();
945
case 0: // Do nothing
949
LOG_ERROR("Unknown timer action <%c>.\n", action);