~audio-recorder/audio-recorder/trunk

22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
1
/*
1 by Osmo Antero Maatta
Initial import 17.jan.2011
2
 * Copyright (c) Linux community.
3
 *
4
 * This library is free software; you can redistribute it and/or
5
 * modify it under the terms of the GNU Library General Public
6
 * License as published by the Free Software Foundation; either
7
 * version 2 of the License, or (at your option) any later version.
8
 *
9
 * This library is distributed in the hope that it will be useful,
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU
12
 * Library General Public License for more details.
13
 *
14
 * You should have received a copy of the GNU Library General Public
15
 * License along with this library; if not, write to the
16
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17
 * Boston, MA 02111-1307, USA.
18
*/
19
#include <string.h>
20
#include <glib.h>
21
#include <math.h>
22
#include "timer.h"
23
24
#include "utility.h"
25
#include "support.h"
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
26
#include "dconf.h"
1 by Osmo Antero Maatta
Initial import 17.jan.2011
27
#include "log.h"
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
28
#include "gst-vad.h"
1 by Osmo Antero Maatta
Initial import 17.jan.2011
29
#include "audio-sources.h"
30
#include "rec-manager.h"
31
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
130
// Timer function call frequency in seconds
131
#define TIMER_CALL_FREQ 1
1 by Osmo Antero Maatta
Initial import 17.jan.2011
132
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
133
// Default silence duration (in seconds)
134
#define DEF_SILENCE_DURATION 3
1 by Osmo Antero Maatta
Initial import 17.jan.2011
135
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
136
// Timer function id
1 by Osmo Antero Maatta
Initial import 17.jan.2011
137
static guint g_timer_func_id = 0;
138
139
// A GList of TimerRec nodes from the timer-parser.c
140
G_LOCK_DEFINE_STATIC(g_t_list);
141
static GList *g_t_list = NULL;
142
143
// Timer's start time
144
static struct tm g_timer_start_time;
145
146
void timer_func_stop();
147
gboolean timer_func_cb(gpointer user_data);
148
void timer_func_exit_cb(gpointer user_data);
149
150
void timer_func_exec_command(TimerRec *tr);
151
152
static void timer_set_start_time();
153
static struct tm timer_get_start_time();
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
154
static void timer_update_records_1();
1 by Osmo Antero Maatta
Initial import 17.jan.2011
155
156
static gchar timer_test_filesize(TimerRec *tr);
157
static gchar timer_test_clock_time(TimerRec *tr);
158
static gchar timer_test_time_duration(TimerRec *tr);
159
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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
1 by Osmo Antero Maatta
Initial import 17.jan.2011
164
void timer_module_init() {
165
    LOG_DEBUG("Init timer.c.\n");
166
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
167
    // Init gst-vad.c
168
    vad_module_init();
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
169
1 by Osmo Antero Maatta
Initial import 17.jan.2011
170
    g_timer_func_id = 0;
171
172
    // Init parser module
173
    parser_module_init();
174
175
    // Start the timer function
176
    timer_func_start();
177
}
178
179
void timer_module_exit() {
180
    LOG_DEBUG("Clean up timer.c.\n");
181
182
    // Stop timer function
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
183
    timer_func_stop();
1 by Osmo Antero Maatta
Initial import 17.jan.2011
184
185
    // Clean up parser module
186
    parser_module_exit();
187
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
188
    // Clean up gst-vad.c
189
    vad_module_exit();
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
190
1 by Osmo Antero Maatta
Initial import 17.jan.2011
191
    g_t_list = NULL;
192
}
193
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
194
void timer_set_debug_flag(gboolean on_off) {
51 by Osmo Antero Maatta
Formatted code with astyle (instructions about astyle in README)
195
    // Set debug flag. Please see application options:
196
    // $ audio-recorder --help
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
197
    vad_set_debug_flag(on_off);
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
198
}
199
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
200
void timer_module_reset(gint for_state) {
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
201
    // Reset timer before we move to the given state
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
202
203
    switch (for_state) {
204
    case GST_STATE_PLAYING:
205
        timer_update_records_1();
206
        break;
207
208
    case GST_STATE_PAUSED:
209
    case GST_STATE_NULL:
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
210
        //timer_update_records_2();
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
211
        break;
212
213
    default:
214
        ;
215
    }
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
216
}
217
218
void timer_module_rec_start() {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
219
    // Called when recording stops.
220
221
    // Reset timer
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
222
    timer_update_records_1();
1 by Osmo Antero Maatta
Initial import 17.jan.2011
223
}
224
225
// --------------------------------------------------
226
// The actual timer function
227
// --------------------------------------------------
228
229
void timer_func_start() {
230
    // Already running?
231
    if (g_timer_func_id > 0) {
232
        return;
233
    }
234
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
235
    // Start the timer function
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
238
}
239
240
void timer_func_stop() {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
241
    // Stop the timer funcion
242
    if (g_timer_func_id > 0) {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
243
        g_source_remove(g_timer_func_id);
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
244
    }
1 by Osmo Antero Maatta
Initial import 17.jan.2011
245
    g_timer_func_id = 0;
246
}
247
248
void timer_func_exit_cb(gpointer user_data) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
249
    // Nothing to cleanup
250
    ;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
251
}
252
253
void timer_settings_changed() {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
254
    // Increment the counter so various modules know that the timer-settings have been altered
255
    gint count = 0;
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
256
    conf_get_int_value("timer-setting-counter", &count);
257
    conf_save_int_value("timer-setting-counter", count+1);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
258
}
259
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
260
static void timer_update_records_1() {
51 by Osmo Antero Maatta
Formatted code with astyle (instructions about astyle in README)
261
    // Reset timer nodes
1 by Osmo Antero Maatta
Initial import 17.jan.2011
262
    G_LOCK(g_t_list);
263
264
    GList *item = g_list_first(g_t_list);
265
    while (item) {
266
        TimerRec *tr = (TimerRec*)item->data;
267
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
268
        // Start to count from 0
269
        tr->time_below = 0.0;
270
        tr->time_above = 0.0;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
271
272
        // Next item
273
        item = g_list_next(item);
274
    }
275
276
    G_UNLOCK(g_t_list);
277
}
278
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
279
#if 0 
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
280
static void timer_update_records_2() {
51 by Osmo Antero Maatta
Formatted code with astyle (instructions about astyle in README)
281
    // Reset timer nodes
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
282
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
283
    G_LOCK(g_t_list);
284
285
    GList *item = g_list_first(g_t_list);
286
    while (item) {
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
287
        //TimerRec *tr = (TimerRec*)item->data;
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
288
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
289
        // Start to count from 0
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
290
        //tr->seconds = 0;
291
        //tr->seconds_x = 0;
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
292
293
        // Next item
294
        item = g_list_next(item);
295
    }
296
    G_UNLOCK(g_t_list);
297
}
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
298
#endif
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
299
1 by Osmo Antero Maatta
Initial import 17.jan.2011
300
static void timer_clear_list() {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
301
    // Reset the timer list
1 by Osmo Antero Maatta
Initial import 17.jan.2011
302
303
    // Lock g_timer_list
304
    G_LOCK(g_t_list);
305
306
    parser_free_list();
307
    g_t_list = NULL;
308
309
    // Unlock
310
    G_UNLOCK(g_t_list);
311
}
312
313
static void timer_set_start_time() {
314
    // Set timer's start time
315
    time_t t = time(NULL);
316
    localtime_r(&t, &g_timer_start_time);
317
}
318
319
static struct tm timer_get_start_time() {
320
    return g_timer_start_time;
321
}
322
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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
1 by Osmo Antero Maatta
Initial import 17.jan.2011
381
gboolean timer_func_cb(gpointer user_data) {
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
382
    // The actual timer function
1 by Osmo Antero Maatta
Initial import 17.jan.2011
383
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
384
    // Timer is ON/OFF?
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
385
    static gboolean timer_active = FALSE;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
386
387
    // Counter to detect if GConf settings have been altered
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
388
    static gint setting_counter = -1;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
389
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
390
    // Do we need VAD-pipeline?
391
    static gboolean need_VAD = FALSE;
392
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
393
    // Timer (GConf) settings changed?
1 by Osmo Antero Maatta
Initial import 17.jan.2011
394
    gint val = 0;
69 by Osmo Antero
Ported this application to GTK/GDK 3. Using now GSettings (and dconf) instead of GConf2
395
    conf_get_int_value("timer-setting-counter", &val);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
396
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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");
1 by Osmo Antero Maatta
Initial import 17.jan.2011
449
51 by Osmo Antero Maatta
Formatted code with astyle (instructions about astyle in README)
450
#if defined(DEBUG_TIMER)
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
451
        // Debug print the command list
452
        parser_print_list(g_t_list);
51 by Osmo Antero Maatta
Formatted code with astyle (instructions about astyle in README)
453
#endif
454
    }
455
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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:
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
469
470
    // Timer is ON?
471
    if (!timer_active) {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
472
        // No.
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
473
        // Make sure the VAD has stopped (do not waste CPU cycles)
474
        vad_stop_VAD();
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
475
        goto LBL_1;
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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();
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
485
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
486
    } else {
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
487
        // Yes.
488
        // Start VAD.
489
        vad_start_VAD();
1 by Osmo Antero Maatta
Initial import 17.jan.2011
490
    }
491
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
492
    // ------------------------
493
    // Evaluate timer commands
494
    // ------------------------
49 by Osmo Antero Maatta
Employ listener (in gst-listener.c) ONLY when needed. Also listener process was created 2 times (was unstoppable)
495
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
496
    // For all TimerRec structures in GList...
1 by Osmo Antero Maatta
Initial import 17.jan.2011
497
    GList *item = g_list_first(g_t_list);
498
    while (item) {
499
        TimerRec *tr = (TimerRec*)item->data;
500
51 by Osmo Antero Maatta
Formatted code with astyle (instructions about astyle in README)
501
        // Set lock
1 by Osmo Antero Maatta
Initial import 17.jan.2011
502
        G_LOCK(g_t_list);
503
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
504
        // Check the timer condition
1 by Osmo Antero Maatta
Initial import 17.jan.2011
505
        timer_func_exec_command(tr);
506
507
        // Unlock
508
        G_UNLOCK(g_t_list);
509
510
        // Next item
511
        item = g_list_next(item);
512
    }
513
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
514
LBL_1:
515
    // Continue calling this function
516
    return TRUE;
1 by Osmo Antero Maatta
Initial import 17.jan.2011
517
}
518
519
void timer_func_exec_command(TimerRec *tr) {
520
521
    // Actions: 'S'=start, 'T'=stop, 'P'=pause, 'p'=pause, 'c'=continue, 0=No action.
522
    gchar action = 0;
523
524
    // Test filesize?
525
    if (tr->data_type == 'f') {
526
        // stop/pause if ### bytes/KB/MB/GB/TB
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
527
        // Example:
528
        // stop/pause if 250 MB
1 by Osmo Antero Maatta
Initial import 17.jan.2011
529
530
        action = timer_test_filesize(tr);
531
532
        if (action) {
533
            LOG_TIMER("Filesize test = TRUE.\n");
534
        }
535
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
536
        // Test clock time ##:##:##?
1 by Osmo Antero Maatta
Initial import 17.jan.2011
537
    } else if (tr->data_type == 't') {
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
538
        // start/stop/pause at ##:##:## am/pm (where ##:##:## is a clock time in hh:mm:ss format)
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
539
        // Example:
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
540
        // start/stop/pause at 10:15:00 pm
1 by Osmo Antero Maatta
Initial import 17.jan.2011
541
542
        action = timer_test_clock_time(tr);
543
544
        if (action) {
545
            LOG_TIMER("Clock time test = TRUE.\n");
546
        }
547
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
548
        // Test time duration?
1 by Osmo Antero Maatta
Initial import 17.jan.2011
549
    } else if (tr->data_type == 'd') {
550
        // start/stop/pause after # hour # min # seconds
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
551
        // Example:
552
        // start/stop/pause after 1 h 25 min
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
553
1 by Osmo Antero Maatta
Initial import 17.jan.2011
554
        action = timer_test_time_duration(tr);
555
556
        if (action) {
557
            LOG_TIMER("Test for time period/duration = TRUE.\n");
558
        }
559
    }
560
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
561
    execute_action(tr, action);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
562
}
563
564
static gchar timer_test_filesize(TimerRec *tr) {
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
565
    // Test filesize.
566
    // stop/pause if/after/on ### bytes/KB/MB/GB/TB
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
567
    // Examples:
568
    //  stop after 250 MB
569
    //  pause if 1.2 GB
1 by Osmo Antero Maatta
Initial import 17.jan.2011
570
571
    gchar action = 0;
572
573
    // Get output filename
574
    gchar *filename = rec_manager_get_output_filename();
575
576
    if (!filename) {
577
        return action;
578
    }
579
580
    // Get file size
581
    gdouble filesize = 1.0 * get_file_size(filename);
582
25 by Osmo Antero Maatta
Fixed crash on Fedora 14. LOG_TIMER(...) in timer.c caused crash when gint64 was formatted with %ld. Now I cast everything to long.
583
    LOG_TIMER("Testing filesize: filesize=%3.1f bytes, unit=%s, current filesize=%3.1f bytes, filename=<%s>\n",
584
              tr->val[0], tr->label, filesize, filename);
1 by Osmo Antero Maatta
Initial import 17.jan.2011
585
586
    g_free(filename);
587
588
    // Filesize limit exceeded?
589
    if (filesize >= tr->val[0]) {
590
        // Execute
591
        action = tr->action;
592
    }
593
594
    return action;
595
}
596
597
static gchar timer_test_clock_time(TimerRec *tr) {
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
598
    // Test clock time.
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
599
    // start/stop/pause at ##:##:## am/pm (where ##:##:## is a clock time in hh:mm:ss format)
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
600
    // Examples:
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
601
    //  start at 10:15:00 pm
602
    //  pause at 9:30 am
603
    //  stop at 23:00
1 by Osmo Antero Maatta
Initial import 17.jan.2011
604
605
    gchar action = 0;
606
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
607
    // Get current, local date & time
1 by Osmo Antero Maatta
Initial import 17.jan.2011
608
    time_t t = time(NULL);
609
    struct tm *tmp;
610
    tmp = localtime(&t);
611
612
    gint64 clock_secs = tmp->tm_hour*3600 + tmp->tm_min*60 + tmp->tm_sec;
613
614
    gint64 timer_secs = tr->val[0]*3600 +  tr->val[1]*60 +  tr->val[2];
615
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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));
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
619
12 by Osmo Antero Maatta
Better test for clock-time in timer.c
620
    // Note:
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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.
12 by Osmo Antero Maatta
Better test for clock-time in timer.c
624
625
    gint64 diff_secs = (clock_secs - timer_secs);
626
627
    gboolean do_action = (diff_secs > 0 && diff_secs < (60 * 60)/*1 HOUR HARD-CODED*/);
628
629
    if (do_action && tr->day_of_year != tmp->tm_yday) {
1 by Osmo Antero Maatta
Initial import 17.jan.2011
630
631
        action = tr->action;
632
633
        // Save day_of_year so we know when the clock turns around (to the next day).
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
634
        // This timer command will become valid and fire again.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
635
        tr->day_of_year = tmp->tm_yday;
636
    }
637
638
    return action;
639
}
640
641
static gchar timer_test_time_duration(TimerRec *tr) {
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
642
    // Test time duration/time period.
643
    // start/stop/pause after # hour/h # minuntes/m/min # seconds/s/sec
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
644
    // Examples:
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
645
    //  start after 1 h 25 min
646
    //  stop after 30 minutes
647
    //  pause after 1 h 15 m 20 s
1 by Osmo Antero Maatta
Initial import 17.jan.2011
648
649
    gchar action = 0;
650
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
651
    // Action is 'T' (sTop) or 'P' (Pause) recording?
1 by Osmo Antero Maatta
Initial import 17.jan.2011
652
    if (tr->action == 'T'  || tr->action == 'P') {
653
        // Eg. stop/pause after 8 min 20 sec
654
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
655
        // Compare recording's stream time to the given timer value.
1 by Osmo Antero Maatta
Initial import 17.jan.2011
656
657
        // Get actual recording time in seconds
658
        gint64 recording_time_secs = rec_manager_get_stream_time();
659
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
660
        // This TimeRec's value in seconds
1 by Osmo Antero Maatta
Initial import 17.jan.2011
661
        gint64 timer_secs = tr->val[0]*3600.0 + tr->val[1]*60.0 +  tr->val[2];
662
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
663
#if defined(DEBUG_TIMER) || defined(DEBUG_ALL)
664
        guint hh = -1;
665
        guint mm = -1;
666
        guint ss = -1;
667
        // Split value to hours, minutes and seconds
668
        seconds_to_h_m_s(recording_time_secs, &hh, &mm, &ss);
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
669
25 by Osmo Antero Maatta
Fixed crash on Fedora 14. LOG_TIMER(...) in timer.c caused crash when gint64 was formatted with %ld. Now I cast everything to long.
670
        gint64 diff = timer_secs - recording_time_secs;
671
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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", 
25 by Osmo Antero Maatta
Fixed crash on Fedora 14. LOG_TIMER(...) in timer.c caused crash when gint64 was formatted with %ld. Now I cast everything to long.
673
                  hh, mm, ss, tr->val[0], tr->val[1], tr->val[2], (long)diff);
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
674
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
675
#endif
1 by Osmo Antero Maatta
Initial import 17.jan.2011
676
677
        if (recording_time_secs >= timer_secs) {
678
            // Execute
679
            action = tr->action;
680
        }
681
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
682
        // Action is 'S' (Start) recording?
683
        // Eg. start after 1 min 20 sec (execute "start after..." command only once during timer's life time)
1 by Osmo Antero Maatta
Initial import 17.jan.2011
684
    } else {
685
686
        // Execute only once pr. timer's life time!
687
        if (tr->done) goto LBL_1;
688
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
689
        // Get start time for this timer (when lines were parsed)
1 by Osmo Antero Maatta
Initial import 17.jan.2011
690
        struct tm start_time = timer_get_start_time();
691
        gint64 start_time_secs = start_time.tm_hour*3600.0 + start_time.tm_min*60.0 + start_time.tm_sec;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
692
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
693
        // Get current, local date & time
1 by Osmo Antero Maatta
Initial import 17.jan.2011
694
        time_t t = time(NULL);
695
        struct tm *tmp;
696
        tmp = localtime(&t);
697
        gint64 curr_time_secs = tmp->tm_hour*3600.0 + tmp->tm_min*60.0 + tmp->tm_sec;
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
698
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
699
        // This TimerRec's value in seconds
1 by Osmo Antero Maatta
Initial import 17.jan.2011
700
        gint64 timer_secs = tr->val[0]*3600.0 + tr->val[1]*60.0 +  tr->val[2];
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
701
25 by Osmo Antero Maatta
Fixed crash on Fedora 14. LOG_TIMER(...) in timer.c caused crash when gint64 was formatted with %ld. Now I cast everything to long.
702
        gint64 diff = timer_secs - (curr_time_secs - start_time_secs);
47 by Osmo Antero Maatta
Formatted code (in src/*.[ch]) with astyle. Ref. README file.
703
        (void) diff; // Avoid unused var message
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
704
25 by Osmo Antero Maatta
Fixed crash on Fedora 14. LOG_TIMER(...) in timer.c caused crash when gint64 was formatted with %ld. Now I cast everything to long.
705
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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);
9 by Osmo Antero Maatta
Cleaning up the rec_stop_recording() code + other improvements
709
1 by Osmo Antero Maatta
Initial import 17.jan.2011
710
        if ((curr_time_secs - start_time_secs) >= timer_secs ) {
40 by Osmo Antero Maatta
Added ability to record from multiple devices. Major changes in all modules.
711
            // Execute command
1 by Osmo Antero Maatta
Initial import 17.jan.2011
712
            action = tr->action;
713
        }
714
22 by Osmo Antero Maatta
Formatted the code using astyle. See README for instructions.
715
LBL_1:
1 by Osmo Antero Maatta
Initial import 17.jan.2011
716
        ;
717
    }
718
719
    return action;
720
}
721
173 by Osmo Antero
Support new systems; Ubuntu 12.10, Fedora 18. Improved timer and VAD-modules. Better gst-pipeline.
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