Introducing the log message unique call identifiers feature
[asterisk/asterisk.git] / apps / app_mixmonitor.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005, Anthony Minessale II
5  * Copyright (C) 2005 - 2006, Digium, Inc.
6  *
7  * Mark Spencer <markster@digium.com>
8  * Kevin P. Fleming <kpfleming@digium.com>
9  *
10  * Based on app_muxmon.c provided by
11  * Anthony Minessale II <anthmct@yahoo.com>
12  *
13  * See http://www.asterisk.org for more information about
14  * the Asterisk project. Please do not directly contact
15  * any of the maintainers of this project for assistance;
16  * the project provides a web site, mailing lists and IRC
17  * channels for your use.
18  *
19  * This program is free software, distributed under the terms of
20  * the GNU General Public License Version 2. See the LICENSE file
21  * at the top of the source tree.
22  */
23
24 /*! \file
25  *
26  * \brief MixMonitor() - Record a call and mix the audio during the recording
27  * \ingroup applications
28  *
29  * \author Mark Spencer <markster@digium.com>
30  * \author Kevin P. Fleming <kpfleming@digium.com>
31  *
32  * \note Based on app_muxmon.c provided by
33  * Anthony Minessale II <anthmct@yahoo.com>
34  */
35
36 /*** MODULEINFO
37         <support_level>core</support_level>
38  ***/
39
40 #include "asterisk.h"
41
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
43
44 #include "asterisk/paths.h"     /* use ast_config_AST_MONITOR_DIR */
45 #include "asterisk/file.h"
46 #include "asterisk/audiohook.h"
47 #include "asterisk/pbx.h"
48 #include "asterisk/module.h"
49 #include "asterisk/cli.h"
50 #include "asterisk/app.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/autochan.h"
53 #include "asterisk/manager.h"
54 #include "asterisk/mod_format.h"
55 #include "asterisk/linkedlists.h"
56
57 /*** DOCUMENTATION
58         <application name="MixMonitor" language="en_US">
59                 <synopsis>
60                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
61                         to guarantee the audio file is available for processing during dialplan execution.
62                 </synopsis>
63                 <syntax>
64                         <parameter name="file" required="true" argsep=".">
65                                 <argument name="filename" required="true">
66                                         <para>If <replaceable>filename</replaceable> is an absolute path, uses that path, otherwise
67                                         creates the file in the configured monitoring directory from <filename>asterisk.conf.</filename></para>
68                                 </argument>
69                                 <argument name="extension" required="true" />
70                         </parameter>
71                         <parameter name="options">
72                                 <optionlist>
73                                         <option name="a">
74                                                 <para>Append to the file instead of overwriting it.</para>
75                                         </option>
76                                         <option name="b">
77                                                 <para>Only save audio to the file while the channel is bridged.</para>
78                                                 <note><para>Does not include conferences or sounds played to each bridged party</para></note>
79                                                 <note><para>If you utilize this option inside a Local channel, you must make sure the Local
80                                                 channel is not optimized away. To do this, be sure to call your Local channel with the
81                                                 <literal>/n</literal> option. For example: Dial(Local/start@mycontext/n)</para></note>
82                                         </option>
83                                         <option name="v">
84                                                 <para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
85                                                 (range <literal>-4</literal> to <literal>4</literal>)</para>
86                                                 <argument name="x" required="true" />
87                                         </option>
88                                         <option name="V">
89                                                 <para>Adjust the <emphasis>spoken</emphasis> volume by a factor
90                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
91                                                 <argument name="x" required="true" />
92                                         </option>
93                                         <option name="W">
94                                                 <para>Adjust both, <emphasis>heard and spoken</emphasis> volumes by a factor
95                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
96                                                 <argument name="x" required="true" />
97                                         </option>
98                                         <option name="r">
99                                                 <argument name="file" required="true" />
100                                                 <para>Use the specified file to record the <emphasis>receive</emphasis> audio feed.
101                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
102                                                 the file in the configured monitoring directory.</para>
103
104                                         </option>
105                                         <option name="t">
106                                                 <argument name="file" required="true" />
107                                                 <para>Use the specified file to record the <emphasis>transmit</emphasis> audio feed.
108                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
109                                                 the file in the configured monitoring directory.</para>
110                                         </option>
111                                         <option name="i">
112                                                 <argument name="chanvar" required="true" />
113                                                 <para>Stores the MixMonitor's ID on this channel variable.</para>
114                                         </option>
115                                 </optionlist>
116                         </parameter>
117                         <parameter name="command">
118                                 <para>Will be executed when the recording is over.</para>
119                                 <para>Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.</para>
120                                 <para>All variables will be evaluated at the time MixMonitor is called.</para>
121                         </parameter>
122                 </syntax>
123                 <description>
124                         <para>Records the audio on the current channel to the specified file.</para>
125                         <para>This application does not automatically answer and should be preceeded by
126                         an application such as Answer or Progress().</para>
127                         <variablelist>
128                                 <variable name="MIXMONITOR_FILENAME">
129                                         <para>Will contain the filename used to record.</para>
130                                 </variable>
131                         </variablelist> 
132                 </description>
133                 <see-also>
134                         <ref type="application">Monitor</ref>
135                         <ref type="application">StopMixMonitor</ref>
136                         <ref type="application">PauseMonitor</ref>
137                         <ref type="application">UnpauseMonitor</ref>
138                 </see-also>
139         </application>
140         <application name="StopMixMonitor" language="en_US">
141                 <synopsis>
142                         Stop recording a call through MixMonitor, and free the recording's file handle.
143                 </synopsis>
144                 <syntax>
145                         <parameter name="MixMonitorID" required="false">
146                                 <para>If a valid ID is provided, then this command will stop only that specific
147                                 MixMonitor.</para>
148                         </parameter>
149                 </syntax>
150                 <description>
151                         <para>Stops the audio recording that was started with a call to <literal>MixMonitor()</literal>
152                         on the current channel.</para>
153                 </description>
154                 <see-also>
155                         <ref type="application">MixMonitor</ref>
156                 </see-also>
157         </application>
158         <manager name="MixMonitorMute" language="en_US">
159                 <synopsis>
160                         Mute / unMute a Mixmonitor recording.
161                 </synopsis>
162                 <syntax>
163                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
164                         <parameter name="Channel" required="true">
165                                 <para>Used to specify the channel to mute.</para>
166                         </parameter>
167                         <parameter name="Direction">
168                                 <para>Which part of the recording to mute:  read, write or both (from channel, to channel or both channels).</para>
169                         </parameter>
170                         <parameter name="State">
171                                 <para>Turn mute on or off : 1 to turn on, 0 to turn off.</para>
172                         </parameter>
173                 </syntax>
174                 <description>
175                         <para>This action may be used to mute a MixMonitor recording.</para>
176                 </description>
177         </manager>
178         <manager name="MixMonitor" language="en_US">
179                 <synopsis>
180                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
181                         to guarantee the audio file is available for processing during dialplan execution.
182                 </synopsis>
183                 <syntax>
184                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
185                         <parameter name="Channel" required="true">
186                                 <para>Used to specify the channel to record.</para>
187                         </parameter>
188                         <parameter name="File">
189                                 <para>Is the name of the file created in the monitor spool directory.
190                                 Defaults to the same name as the channel (with slashes replaced with dashes).
191                                 This argument is optional if you specify to record unidirectional audio with
192                                 either the r(filename) or t(filename) options in the options field. If
193                                 neither MIXMONITOR_FILENAME or this parameter is set, the mixed stream won't
194                                 be recorded.</para>
195                         </parameter>
196                         <parameter name="options">
197                                 <para>Options that apply to the MixMonitor in the same way as they
198                                 would apply if invoked from the MixMonitor application. For a list of
199                                 available options, see the documentation for the mixmonitor application. </para>
200                         </parameter>
201                 </syntax>
202                 <description>
203                         <para>This action records the audio on the current channel to the specified file.</para>
204                         <variablelist>
205                                 <variable name="MIXMONITOR_FILENAME">
206                                         <para>Will contain the filename used to record the mixed stream.</para>
207                                 </variable>
208                         </variablelist>
209                 </description>
210         </manager>
211         <manager name="StopMixMonitor" language="en_US">
212                 <synopsis>
213                         Stop recording a call through MixMonitor, and free the recording's file handle.
214                 </synopsis>
215                 <syntax>
216                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
217                         <parameter name="Channel" required="true">
218                                 <para>The name of the channel monitored.</para>
219                         </parameter>
220                         <parameter name="MixMonitorID" required="false">
221                                 <para>If a valid ID is provided, then this command will stop only that specific
222                                 MixMonitor.</para>
223                         </parameter>
224                 </syntax>
225                 <description>
226                         <para>This action stops the audio recording that was started with the <literal>MixMonitor</literal>
227                         action on the current channel.</para>
228                 </description>
229         </manager>
230
231  ***/
232
233 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
234
235 static const char * const app = "MixMonitor";
236
237 static const char * const stop_app = "StopMixMonitor";
238
239 static const char * const mixmonitor_spy_type = "MixMonitor";
240
241 struct mixmonitor {
242         struct ast_audiohook audiohook;
243         struct ast_callid *callid;
244         char *filename;
245         char *filename_read;
246         char *filename_write;
247         char *post_process;
248         char *name;
249         unsigned int flags;
250         struct ast_autochan *autochan;
251         struct mixmonitor_ds *mixmonitor_ds;
252 };
253
254 enum mixmonitor_flags {
255         MUXFLAG_APPEND = (1 << 1),
256         MUXFLAG_BRIDGED = (1 << 2),
257         MUXFLAG_VOLUME = (1 << 3),
258         MUXFLAG_READVOLUME = (1 << 4),
259         MUXFLAG_WRITEVOLUME = (1 << 5),
260         MUXFLAG_READ = (1 << 6),
261         MUXFLAG_WRITE = (1 << 7),
262         MUXFLAG_COMBINED = (1 << 8),
263         MUXFLAG_UID = (1 << 9),
264 };
265
266 enum mixmonitor_args {
267         OPT_ARG_READVOLUME = 0,
268         OPT_ARG_WRITEVOLUME,
269         OPT_ARG_VOLUME,
270         OPT_ARG_WRITENAME,
271         OPT_ARG_READNAME,
272         OPT_ARG_UID,
273         OPT_ARG_ARRAY_SIZE,     /* Always last element of the enum */
274 };
275
276 AST_APP_OPTIONS(mixmonitor_opts, {
277         AST_APP_OPTION('a', MUXFLAG_APPEND),
278         AST_APP_OPTION('b', MUXFLAG_BRIDGED),
279         AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
280         AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
281         AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
282         AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
283         AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
284         AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
285 });
286
287 struct mixmonitor_ds {
288         unsigned int destruction_ok;
289         ast_cond_t destruction_condition;
290         ast_mutex_t lock;
291
292         /* The filestream is held in the datastore so it can be stopped
293          * immediately during stop_mixmonitor or channel destruction. */
294         int fs_quit;
295
296         struct ast_filestream *fs;
297         struct ast_filestream *fs_read;
298         struct ast_filestream *fs_write;
299
300         struct ast_audiohook *audiohook;
301
302         unsigned int samp_rate;
303 };
304
305 /*!
306  * \internal
307  * \pre mixmonitor_ds must be locked before calling this function
308  */
309 static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
310 {
311         unsigned char quitting = 0;
312
313         if (mixmonitor_ds->fs) {
314                 quitting = 1;
315                 ast_closestream(mixmonitor_ds->fs);
316                 mixmonitor_ds->fs = NULL;
317                 ast_verb(2, "MixMonitor close filestream (mixed)\n");
318         }
319
320         if (mixmonitor_ds->fs_read) {
321                 quitting = 1;
322                 ast_closestream(mixmonitor_ds->fs_read);
323                 mixmonitor_ds->fs_read = NULL;
324                 ast_verb(2, "MixMonitor close filestream (read)\n");
325         }
326
327         if (mixmonitor_ds->fs_write) {
328                 quitting = 1;
329                 ast_closestream(mixmonitor_ds->fs_write);
330                 mixmonitor_ds->fs_write = NULL;
331                 ast_verb(2, "MixMonitor close filestream (write)\n");
332         }
333
334         if (quitting) {
335                 mixmonitor_ds->fs_quit = 1;
336         }
337 }
338
339 static void mixmonitor_ds_destroy(void *data)
340 {
341         struct mixmonitor_ds *mixmonitor_ds = data;
342
343         ast_mutex_lock(&mixmonitor_ds->lock);
344         mixmonitor_ds->audiohook = NULL;
345         mixmonitor_ds->destruction_ok = 1;
346         ast_cond_signal(&mixmonitor_ds->destruction_condition);
347         ast_mutex_unlock(&mixmonitor_ds->lock);
348 }
349
350 static struct ast_datastore_info mixmonitor_ds_info = {
351         .type = "mixmonitor",
352         .destroy = mixmonitor_ds_destroy,
353 };
354
355 static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
356 {
357         if (mixmonitor->mixmonitor_ds) {
358                 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
359                 mixmonitor->mixmonitor_ds->audiohook = NULL;
360                 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
361         }
362         /* kill the audiohook.*/
363         ast_audiohook_lock(&mixmonitor->audiohook);
364         ast_audiohook_detach(&mixmonitor->audiohook);
365         ast_audiohook_unlock(&mixmonitor->audiohook);
366         ast_audiohook_destroy(&mixmonitor->audiohook);
367 }
368
369 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) 
370 {
371         struct ast_channel *peer = NULL;
372         int res = 0;
373
374         if (!chan)
375                 return -1;
376
377         ast_audiohook_attach(chan, audiohook);
378
379         if (!res && ast_test_flag(ast_channel_flags(chan), AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
380                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
381
382         return res;
383 }
384
385 #define SAMPLES_PER_FRAME 160
386
387 static void mixmonitor_free(struct mixmonitor *mixmonitor)
388 {
389         if (mixmonitor) {
390                 if (mixmonitor->mixmonitor_ds) {
391                         ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
392                         ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
393                         ast_free(mixmonitor->filename_write);
394                         ast_free(mixmonitor->filename_read);
395                         ast_free(mixmonitor->mixmonitor_ds);
396                         ast_free(mixmonitor->name);
397                         ast_free(mixmonitor->post_process);
398                 }
399
400                 if (mixmonitor->callid) {
401                         ast_callid_unref(mixmonitor->callid);
402                 }
403                 ast_free(mixmonitor);
404         }
405 }
406
407 static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag)
408 {
409         /* Initialize the file if not already done so */
410         char *ext = NULL;
411         char *last_slash = NULL;
412         if (!ast_strlen_zero(filename)) {
413                 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
414                         *oflags = O_CREAT | O_WRONLY;
415                         *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
416
417                         last_slash = strrchr(filename, '/');
418
419                         if ((ext = strrchr(filename, '.')) && (ext > last_slash)) {
420                                 *(ext++) = '\0';
421                         } else {
422                                 ext = "raw";
423                         }
424
425                         if (!(*fs = ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) {
426                                 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext);
427                                 *errflag = 1;
428                         } else {
429                                 struct ast_filestream *tmp = *fs;
430                                 mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
431                         }
432                 }
433         }
434 }
435
436 static void *mixmonitor_thread(void *obj) 
437 {
438         struct mixmonitor *mixmonitor = obj;
439
440         struct ast_filestream **fs = NULL;
441         struct ast_filestream **fs_read = NULL;
442         struct ast_filestream **fs_write = NULL;
443
444         unsigned int oflags;
445         int errflag = 0;
446         struct ast_format format_slin;
447
448         /* Keep callid association before any log messages */
449         if (mixmonitor->callid) {
450                 ast_callid_threadassoc_add(mixmonitor->callid);
451         }
452
453         ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
454
455         fs = &mixmonitor->mixmonitor_ds->fs;
456         fs_read = &mixmonitor->mixmonitor_ds->fs_read;
457         fs_write = &mixmonitor->mixmonitor_ds->fs_write;
458
459         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
460         mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
461         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
462         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);
463
464         ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);
465
466         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
467
468
469         /* The audiohook must enter and exit the loop locked */
470         ast_audiohook_lock(&mixmonitor->audiohook);
471         while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
472                 struct ast_frame *fr = NULL;
473                 struct ast_frame *fr_read = NULL;
474                 struct ast_frame *fr_write = NULL;
475
476                 if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
477                                                 &fr_read, &fr_write))) {
478                         ast_audiohook_trigger_wait(&mixmonitor->audiohook);
479
480                         if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
481                                 break;
482                         }
483                         continue;
484                 }
485
486                 /* audiohook lock is not required for the next block.
487                  * Unlock it, but remember to lock it before looping or exiting */
488                 ast_audiohook_unlock(&mixmonitor->audiohook);
489
490                 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
491                         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
492
493                         /* Write out the frame(s) */
494                         if ((*fs_read) && (fr_read)) {
495                                 struct ast_frame *cur;
496
497                                 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
498                                         ast_writestream(*fs_read, cur);
499                                 }
500                         }
501
502                         if ((*fs_write) && (fr_write)) {
503                                 struct ast_frame *cur;
504
505                                 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
506                                         ast_writestream(*fs_write, cur);
507                                 }
508                         }
509
510                         if ((*fs) && (fr)) {
511                                 struct ast_frame *cur;
512
513                                 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
514                                         ast_writestream(*fs, cur);
515                                 }
516                         }
517                         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
518                 }
519                 /* All done! free it. */
520                 if (fr) {
521                         ast_frame_free(fr, 0);
522                 }
523                 if (fr_read) {
524                         ast_frame_free(fr_read, 0);
525                 }
526                 if (fr_write) {
527                         ast_frame_free(fr_write, 0);
528                 }
529
530                 fr = NULL;
531                 fr_write = NULL;
532                 fr_read = NULL;
533
534                 ast_audiohook_lock(&mixmonitor->audiohook);
535         }
536         ast_audiohook_unlock(&mixmonitor->audiohook);
537
538         ast_autochan_destroy(mixmonitor->autochan);
539
540         /* Datastore cleanup.  close the filestream and wait for ds destruction */
541         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
542         mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
543         if (!mixmonitor->mixmonitor_ds->destruction_ok) {
544                 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
545         }
546         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
547
548         /* kill the audiohook */
549         destroy_monitor_audiohook(mixmonitor);
550
551         if (mixmonitor->post_process) {
552                 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
553                 ast_safe_system(mixmonitor->post_process);
554         }
555
556         ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
557         mixmonitor_free(mixmonitor);
558         return NULL;
559 }
560
561 static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id)
562 {
563         struct ast_datastore *datastore = NULL;
564         struct mixmonitor_ds *mixmonitor_ds;
565
566         if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
567                 return -1;
568         }
569
570         if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
571                 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
572         }
573
574         ast_mutex_init(&mixmonitor_ds->lock);
575         ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
576
577         if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
578                 ast_mutex_destroy(&mixmonitor_ds->lock);
579                 ast_cond_destroy(&mixmonitor_ds->destruction_condition);
580                 ast_free(mixmonitor_ds);
581                 return -1;
582         }
583
584
585         mixmonitor_ds->samp_rate = 8000;
586         mixmonitor_ds->audiohook = &mixmonitor->audiohook;
587         datastore->data = mixmonitor_ds;
588
589         ast_channel_lock(chan);
590         ast_channel_datastore_add(chan, datastore);
591         ast_channel_unlock(chan);
592
593         mixmonitor->mixmonitor_ds = mixmonitor_ds;
594         return 0;
595 }
596
597 static void launch_monitor_thread(struct ast_channel *chan, const char *filename,
598                                   unsigned int flags, int readvol, int writevol,
599                                   const char *post_process, const char *filename_write,
600                                   char *filename_read, const char *uid_channel_var)
601 {
602         pthread_t thread;
603         struct mixmonitor *mixmonitor;
604         char postprocess2[1024] = "";
605         char *datastore_id = NULL;
606
607         postprocess2[0] = 0;
608         /* If a post process system command is given attach it to the structure */
609         if (!ast_strlen_zero(post_process)) {
610                 char *p1, *p2;
611
612                 p1 = ast_strdupa(post_process);
613                 for (p2 = p1; *p2; p2++) {
614                         if (*p2 == '^' && *(p2+1) == '{') {
615                                 *p2 = '$';
616                         }
617                 }
618                 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
619         }
620
621         /* Pre-allocate mixmonitor structure and spy */
622         if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
623                 return;
624         }
625
626         /* Setup the actual spy before creating our thread */
627         if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
628                 mixmonitor_free(mixmonitor);
629                 return;
630         }
631
632         /* Copy over flags and channel name */
633         mixmonitor->flags = flags;
634         if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
635                 mixmonitor_free(mixmonitor);
636                 return;
637         }
638
639         if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
640                 ast_autochan_destroy(mixmonitor->autochan);
641                 mixmonitor_free(mixmonitor);
642                 ast_free(datastore_id);
643                 return;
644         }
645
646         if (!ast_strlen_zero(uid_channel_var)) {
647                 if (datastore_id) {
648                         pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
649                 }
650         }
651         ast_free(datastore_id);
652
653
654         mixmonitor->name = ast_strdup(ast_channel_name(chan));
655
656         if (!ast_strlen_zero(postprocess2)) {
657                 mixmonitor->post_process = ast_strdup(postprocess2);
658         }
659
660         if (!ast_strlen_zero(filename)) {
661                 mixmonitor->filename = ast_strdup(filename);
662         }
663
664         if (!ast_strlen_zero(filename_write)) {
665                 mixmonitor->filename_write = ast_strdup(filename_write);
666         }
667
668         if (!ast_strlen_zero(filename_read)) {
669                 mixmonitor->filename_read = ast_strdup(filename_read);
670         }
671
672         ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
673
674         if (readvol)
675                 mixmonitor->audiohook.options.read_volume = readvol;
676         if (writevol)
677                 mixmonitor->audiohook.options.write_volume = writevol;
678
679         if (startmon(chan, &mixmonitor->audiohook)) {
680                 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
681                         mixmonitor_spy_type, ast_channel_name(chan));
682                 ast_audiohook_destroy(&mixmonitor->audiohook);
683                 mixmonitor_free(mixmonitor);
684                 return;
685         }
686
687         /* reference be released at mixmonitor destruction */
688         mixmonitor->callid = ast_read_threadstorage_callid();
689
690         ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
691 }
692
693 /* a note on filename_parse: creates directory structure and assigns absolute path from relative paths for filenames */
694 /* requires immediate copying of string from return to retain data since otherwise it will immediately lose scope */
695 static char *filename_parse(char *filename, char *buffer, size_t len)
696 {
697         char *slash;
698         if (ast_strlen_zero(filename)) {
699                 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
700         } else if (filename[0] != '/') {
701                 char *build;
702                 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
703                 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
704                 filename = build;
705         }
706
707         ast_copy_string(buffer, filename, len);
708
709         if ((slash = strrchr(filename, '/'))) {
710                 *slash = '\0';
711         }
712         ast_mkdir(filename, 0777);
713
714         return buffer;
715 }
716
717 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
718 {
719         int x, readvol = 0, writevol = 0;
720         char *filename_read = NULL;
721         char *filename_write = NULL;
722         char filename_buffer[1024] = "";
723         char *uid_channel_var = NULL;
724
725         struct ast_flags flags = { 0 };
726         char *parse;
727         AST_DECLARE_APP_ARGS(args,
728                 AST_APP_ARG(filename);
729                 AST_APP_ARG(options);
730                 AST_APP_ARG(post_process);
731         );
732
733         if (ast_strlen_zero(data)) {
734                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
735                 return -1;
736         }
737
738         parse = ast_strdupa(data);
739
740         AST_STANDARD_APP_ARGS(args, parse);
741
742         if (args.options) {
743                 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
744
745                 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
746
747                 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
748                         if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
749                                 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
750                         } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
751                                 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
752                         } else {
753                                 readvol = get_volfactor(x);
754                         }
755                 }
756
757                 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
758                         if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
759                                 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
760                         } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
761                                 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
762                         } else {
763                                 writevol = get_volfactor(x);
764                         }
765                 }
766
767                 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
768                         if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
769                                 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
770                         } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
771                                 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
772                         } else {
773                                 readvol = writevol = get_volfactor(x);
774                         }
775                 }
776
777                 if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
778                         filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
779                 }
780
781                 if (ast_test_flag(&flags, MUXFLAG_READ)) {
782                         filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
783                 }
784
785                 if (ast_test_flag(&flags, MUXFLAG_UID)) {
786                         uid_channel_var = opts[OPT_ARG_UID];
787                 }
788         }
789         /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
790
791         if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
792                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
793                 return -1;
794         }
795
796         /* If filename exists, try to create directories for it */
797         if (!(ast_strlen_zero(args.filename))) {
798                 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
799         }
800
801         pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
802         launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, filename_write, filename_read, uid_channel_var);
803
804         return 0;
805 }
806
807 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
808 {
809         struct ast_datastore *datastore = NULL;
810         char *parse = "";
811         struct mixmonitor_ds *mixmonitor_ds;
812
813         AST_DECLARE_APP_ARGS(args,
814                 AST_APP_ARG(mixmonid);
815         );
816
817         if (!ast_strlen_zero(data)) {
818                 parse = ast_strdupa(data);
819         }
820
821         AST_STANDARD_APP_ARGS(args, parse);
822
823         ast_channel_lock(chan);
824
825         if (!(datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid))) {
826                 ast_channel_unlock(chan);
827                 return -1;
828         }
829         mixmonitor_ds = datastore->data;
830
831         ast_mutex_lock(&mixmonitor_ds->lock);
832
833         /* closing the filestream here guarantees the file is avaliable to the dialplan
834          * after calling StopMixMonitor */
835         mixmonitor_ds_close_fs(mixmonitor_ds);
836
837         /* The mixmonitor thread may be waiting on the audiohook trigger.
838          * In order to exit from the mixmonitor loop before waiting on channel
839          * destruction, poke the audiohook trigger. */
840         if (mixmonitor_ds->audiohook) {
841                 if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
842                         ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
843                 }
844                 ast_audiohook_lock(mixmonitor_ds->audiohook);
845                 ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
846                 ast_audiohook_unlock(mixmonitor_ds->audiohook);
847                 mixmonitor_ds->audiohook = NULL;
848         }
849
850         ast_mutex_unlock(&mixmonitor_ds->lock);
851
852         /* Remove the datastore so the monitor thread can exit */
853         if (!ast_channel_datastore_remove(chan, datastore)) {
854                 ast_datastore_free(datastore);
855         }
856         ast_channel_unlock(chan);
857
858         return 0;
859 }
860
861 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
862 {
863         struct ast_channel *chan;
864         struct ast_datastore *datastore = NULL;
865         struct mixmonitor_ds *mixmonitor_ds = NULL;
866
867         switch (cmd) {
868         case CLI_INIT:
869                 e->command = "mixmonitor {start|stop|list}";
870                 e->usage =
871                         "Usage: mixmonitor <start|stop|list> <chan_name> [args]\n"
872                         "       The optional arguments are passed to the MixMonitor\n"
873                         "       application when the 'start' command is used.\n";
874                 return NULL;
875         case CLI_GENERATE:
876                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
877         }
878
879         if (a->argc < 3) {
880                 return CLI_SHOWUSAGE;
881         }
882
883         if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
884                 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
885                 /* Technically this is a failure, but we don't want 2 errors printing out */
886                 return CLI_SUCCESS;
887         }
888
889         ast_channel_lock(chan);
890
891         if (!strcasecmp(a->argv[1], "start")) {
892                 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
893                 ast_channel_unlock(chan);
894         } else if (!strcasecmp(a->argv[1], "stop")){
895                 ast_channel_unlock(chan);
896                 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
897         } else if (!strcasecmp(a->argv[1], "list")) {
898                 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
899                 ast_cli(a->fd, "=========================================================================\n");
900                 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
901                         if (datastore->info == &mixmonitor_ds_info) {
902                                 char *filename = "";
903                                 char *filename_read = "";
904                                 char *filename_write = "";
905                                 mixmonitor_ds = datastore->data;
906                                 if (mixmonitor_ds->fs)
907                                         filename = ast_strdupa(mixmonitor_ds->fs->filename);
908                                 if (mixmonitor_ds->fs_read)
909                                         filename_read = ast_strdupa(mixmonitor_ds->fs_read->filename);
910                                 if (mixmonitor_ds->fs_write)
911                                         filename_write = ast_strdupa(mixmonitor_ds->fs_write->filename);
912                                 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
913                         }
914                 }
915                 ast_channel_unlock(chan);
916         } else {
917                 ast_channel_unlock(chan);
918                 chan = ast_channel_unref(chan);
919                 return CLI_SHOWUSAGE;
920         }
921
922         chan = ast_channel_unref(chan);
923
924         return CLI_SUCCESS;
925 }
926
927 /*! \brief  Mute / unmute  a MixMonitor channel */
928 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
929 {
930         struct ast_channel *c = NULL;
931
932         const char *name = astman_get_header(m, "Channel");
933         const char *id = astman_get_header(m, "ActionID");
934         const char *state = astman_get_header(m, "State");
935         const char *direction = astman_get_header(m,"Direction");
936
937         int clearmute = 1;
938
939         enum ast_audiohook_flags flag;
940
941         if (ast_strlen_zero(direction)) {
942                 astman_send_error(s, m, "No direction specified. Must be read, write or both");
943                 return AMI_SUCCESS;
944         }
945
946         if (!strcasecmp(direction, "read")) {
947                 flag = AST_AUDIOHOOK_MUTE_READ;
948         } else  if (!strcasecmp(direction, "write")) {
949                 flag = AST_AUDIOHOOK_MUTE_WRITE;
950         } else  if (!strcasecmp(direction, "both")) {
951                 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
952         } else {
953                 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
954                 return AMI_SUCCESS;
955         }
956
957         if (ast_strlen_zero(name)) {
958                 astman_send_error(s, m, "No channel specified");
959                 return AMI_SUCCESS;
960         }
961
962         if (ast_strlen_zero(state)) {
963                 astman_send_error(s, m, "No state specified");
964                 return AMI_SUCCESS;
965         }
966
967         clearmute = ast_false(state);
968         c = ast_channel_get_by_name(name);
969
970         if (!c) {
971                 astman_send_error(s, m, "No such channel");
972                 return AMI_SUCCESS;
973         }
974
975         if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
976                 c = ast_channel_unref(c);
977                 astman_send_error(s, m, "Cannot set mute flag");
978                 return AMI_SUCCESS;
979         }
980
981         astman_append(s, "Response: Success\r\n");
982
983         if (!ast_strlen_zero(id)) {
984                 astman_append(s, "ActionID: %s\r\n", id);
985         }
986
987         astman_append(s, "\r\n");
988
989         c = ast_channel_unref(c);
990
991         return AMI_SUCCESS;
992 }
993
994 static int manager_mixmonitor(struct mansession *s, const struct message *m)
995 {
996         struct ast_channel *c = NULL;
997
998         const char *name = astman_get_header(m, "Channel");
999         const char *id = astman_get_header(m, "ActionID");
1000         const char *file = astman_get_header(m, "File");
1001         const char *options = astman_get_header(m, "Options");
1002         char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1003         struct ast_flags flags = { 0 };
1004         char *uid_channel_var = NULL;
1005         const char *mixmonitor_id = NULL;
1006
1007         int res;
1008         char args[PATH_MAX] = "";
1009         if (ast_strlen_zero(name)) {
1010                 astman_send_error(s, m, "No channel specified");
1011                 return AMI_SUCCESS;
1012         }
1013
1014         c = ast_channel_get_by_name(name);
1015
1016         if (!c) {
1017                 astman_send_error(s, m, "No such channel");
1018                 return AMI_SUCCESS;
1019         }
1020
1021         if (!ast_strlen_zero(options)) {
1022                 ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
1023         }
1024
1025         snprintf(args, sizeof(args), "%s,%s", file, options);
1026
1027         ast_channel_lock(c);
1028         res = mixmonitor_exec(c, args);
1029
1030         if (ast_test_flag(&flags, MUXFLAG_UID)) {
1031                 uid_channel_var = opts[OPT_ARG_UID];
1032                 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1033         }
1034         ast_channel_unlock(c);
1035
1036         if (res) {
1037                 astman_send_error(s, m, "Could not start monitoring channel");
1038                 return AMI_SUCCESS;
1039         }
1040
1041         astman_append(s, "Response: Success\r\n");
1042
1043         if (!ast_strlen_zero(id)) {
1044                 astman_append(s, "ActionID: %s\r\n", id);
1045         }
1046
1047         if (!ast_strlen_zero(mixmonitor_id)) {
1048                 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1049         }
1050
1051         astman_append(s, "\r\n");
1052
1053         c = ast_channel_unref(c);
1054
1055         return AMI_SUCCESS;
1056 }
1057
1058 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
1059 {
1060         struct ast_channel *c = NULL;
1061
1062         const char *name = astman_get_header(m, "Channel");
1063         const char *id = astman_get_header(m, "ActionID");
1064         const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1065
1066         int res;
1067         if (ast_strlen_zero(name)) {
1068                 astman_send_error(s, m, "No channel specified");
1069                 return AMI_SUCCESS;
1070         }
1071
1072         c = ast_channel_get_by_name(name);
1073
1074         if (!c) {
1075                 astman_send_error(s, m, "No such channel");
1076                 return AMI_SUCCESS;
1077         }
1078
1079         res = stop_mixmonitor_exec(c, mixmonitor_id);
1080
1081         if (res) {
1082                 astman_send_error(s, m, "Could not stop monitoring channel");
1083                 return AMI_SUCCESS;
1084         }
1085
1086         astman_append(s, "Response: Success\r\n");
1087
1088         if (!ast_strlen_zero(id)) {
1089                 astman_append(s, "ActionID: %s\r\n", id);
1090         }
1091
1092         astman_append(s, "\r\n");
1093
1094         c = ast_channel_unref(c);
1095
1096         return AMI_SUCCESS;
1097 }
1098
1099 static struct ast_cli_entry cli_mixmonitor[] = {
1100         AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1101 };
1102
1103 static int unload_module(void)
1104 {
1105         int res;
1106
1107         ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1108         res = ast_unregister_application(stop_app);
1109         res |= ast_unregister_application(app);
1110         res |= ast_manager_unregister("MixMonitorMute");
1111         res |= ast_manager_unregister("MixMonitor");
1112         res |= ast_manager_unregister("StopMixMonitor");
1113
1114         return res;
1115 }
1116
1117 static int load_module(void)
1118 {
1119         int res;
1120
1121         ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1122         res = ast_register_application_xml(app, mixmonitor_exec);
1123         res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
1124         res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
1125         res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor);
1126         res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor);
1127
1128         return res;
1129 }
1130
1131 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");