a89b6cc5dd4121c169b915e3c4f8730325caeb8b
[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         char *filename;
244         char *filename_read;
245         char *filename_write;
246         char *post_process;
247         char *name;
248         unsigned int flags;
249         struct ast_autochan *autochan;
250         struct mixmonitor_ds *mixmonitor_ds;
251 };
252
253 enum mixmonitor_flags {
254         MUXFLAG_APPEND = (1 << 1),
255         MUXFLAG_BRIDGED = (1 << 2),
256         MUXFLAG_VOLUME = (1 << 3),
257         MUXFLAG_READVOLUME = (1 << 4),
258         MUXFLAG_WRITEVOLUME = (1 << 5),
259         MUXFLAG_READ = (1 << 6),
260         MUXFLAG_WRITE = (1 << 7),
261         MUXFLAG_COMBINED = (1 << 8),
262         MUXFLAG_UID = (1 << 9),
263 };
264
265 enum mixmonitor_args {
266         OPT_ARG_READVOLUME = 0,
267         OPT_ARG_WRITEVOLUME,
268         OPT_ARG_VOLUME,
269         OPT_ARG_WRITENAME,
270         OPT_ARG_READNAME,
271         OPT_ARG_UID,
272         OPT_ARG_ARRAY_SIZE,     /* Always last element of the enum */
273 };
274
275 AST_APP_OPTIONS(mixmonitor_opts, {
276         AST_APP_OPTION('a', MUXFLAG_APPEND),
277         AST_APP_OPTION('b', MUXFLAG_BRIDGED),
278         AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
279         AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
280         AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
281         AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
282         AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
283         AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
284 });
285
286 struct mixmonitor_ds {
287         unsigned int destruction_ok;
288         ast_cond_t destruction_condition;
289         ast_mutex_t lock;
290
291         /* The filestream is held in the datastore so it can be stopped
292          * immediately during stop_mixmonitor or channel destruction. */
293         int fs_quit;
294
295         struct ast_filestream *fs;
296         struct ast_filestream *fs_read;
297         struct ast_filestream *fs_write;
298
299         struct ast_audiohook *audiohook;
300
301         unsigned int samp_rate;
302 };
303
304 /*!
305  * \internal
306  * \pre mixmonitor_ds must be locked before calling this function
307  */
308 static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
309 {
310         unsigned char quitting = 0;
311
312         if (mixmonitor_ds->fs) {
313                 quitting = 1;
314                 ast_closestream(mixmonitor_ds->fs);
315                 mixmonitor_ds->fs = NULL;
316                 ast_verb(2, "MixMonitor close filestream (mixed)\n");
317         }
318
319         if (mixmonitor_ds->fs_read) {
320                 quitting = 1;
321                 ast_closestream(mixmonitor_ds->fs_read);
322                 mixmonitor_ds->fs_read = NULL;
323                 ast_verb(2, "MixMonitor close filestream (read)\n");
324         }
325
326         if (mixmonitor_ds->fs_write) {
327                 quitting = 1;
328                 ast_closestream(mixmonitor_ds->fs_write);
329                 mixmonitor_ds->fs_write = NULL;
330                 ast_verb(2, "MixMonitor close filestream (write)\n");
331         }
332
333         if (quitting) {
334                 mixmonitor_ds->fs_quit = 1;
335         }
336 }
337
338 static void mixmonitor_ds_destroy(void *data)
339 {
340         struct mixmonitor_ds *mixmonitor_ds = data;
341
342         ast_mutex_lock(&mixmonitor_ds->lock);
343         mixmonitor_ds->audiohook = NULL;
344         mixmonitor_ds->destruction_ok = 1;
345         ast_cond_signal(&mixmonitor_ds->destruction_condition);
346         ast_mutex_unlock(&mixmonitor_ds->lock);
347 }
348
349 static struct ast_datastore_info mixmonitor_ds_info = {
350         .type = "mixmonitor",
351         .destroy = mixmonitor_ds_destroy,
352 };
353
354 static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
355 {
356         if (mixmonitor->mixmonitor_ds) {
357                 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
358                 mixmonitor->mixmonitor_ds->audiohook = NULL;
359                 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
360         }
361         /* kill the audiohook.*/
362         ast_audiohook_lock(&mixmonitor->audiohook);
363         ast_audiohook_detach(&mixmonitor->audiohook);
364         ast_audiohook_unlock(&mixmonitor->audiohook);
365         ast_audiohook_destroy(&mixmonitor->audiohook);
366 }
367
368 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) 
369 {
370         struct ast_channel *peer = NULL;
371         int res = 0;
372
373         if (!chan)
374                 return -1;
375
376         ast_audiohook_attach(chan, audiohook);
377
378         if (!res && ast_test_flag(ast_channel_flags(chan), AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
379                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
380
381         return res;
382 }
383
384 #define SAMPLES_PER_FRAME 160
385
386 static void mixmonitor_free(struct mixmonitor *mixmonitor)
387 {
388         if (mixmonitor) {
389                 if (mixmonitor->mixmonitor_ds) {
390                         ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
391                         ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
392                         ast_free(mixmonitor->filename_write);
393                         ast_free(mixmonitor->filename_read);
394                         ast_free(mixmonitor->mixmonitor_ds);
395                         ast_free(mixmonitor->name);
396                         ast_free(mixmonitor->post_process);
397                 }
398                 ast_free(mixmonitor);
399         }
400 }
401
402 static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag)
403 {
404         /* Initialize the file if not already done so */
405         char *ext = NULL;
406         char *last_slash = NULL;
407         if (!ast_strlen_zero(filename)) {
408                 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
409                         *oflags = O_CREAT | O_WRONLY;
410                         *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
411
412                         last_slash = strrchr(filename, '/');
413
414                         if ((ext = strrchr(filename, '.')) && (ext > last_slash)) {
415                                 *(ext++) = '\0';
416                         } else {
417                                 ext = "raw";
418                         }
419
420                         if (!(*fs = ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) {
421                                 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext);
422                                 *errflag = 1;
423                         } else {
424                                 struct ast_filestream *tmp = *fs;
425                                 mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
426                         }
427                 }
428         }
429 }
430
431 static void *mixmonitor_thread(void *obj) 
432 {
433         struct mixmonitor *mixmonitor = obj;
434
435         struct ast_filestream **fs = NULL;
436         struct ast_filestream **fs_read = NULL;
437         struct ast_filestream **fs_write = NULL;
438
439         unsigned int oflags;
440         int errflag = 0;
441         struct ast_format format_slin;
442
443         ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
444
445         fs = &mixmonitor->mixmonitor_ds->fs;
446         fs_read = &mixmonitor->mixmonitor_ds->fs_read;
447         fs_write = &mixmonitor->mixmonitor_ds->fs_write;
448
449         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
450         mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
451         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
452         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);
453
454         ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);
455
456         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
457
458
459         /* The audiohook must enter and exit the loop locked */
460         ast_audiohook_lock(&mixmonitor->audiohook);
461         while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
462                 struct ast_frame *fr = NULL;
463                 struct ast_frame *fr_read = NULL;
464                 struct ast_frame *fr_write = NULL;
465
466                 if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
467                                                 &fr_read, &fr_write))) {
468                         ast_audiohook_trigger_wait(&mixmonitor->audiohook);
469
470                         if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
471                                 break;
472                         }
473                         continue;
474                 }
475
476                 /* audiohook lock is not required for the next block.
477                  * Unlock it, but remember to lock it before looping or exiting */
478                 ast_audiohook_unlock(&mixmonitor->audiohook);
479
480                 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
481                         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
482
483                         /* Write out the frame(s) */
484                         if ((*fs_read) && (fr_read)) {
485                                 struct ast_frame *cur;
486
487                                 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
488                                         ast_writestream(*fs_read, cur);
489                                 }
490                         }
491
492                         if ((*fs_write) && (fr_write)) {
493                                 struct ast_frame *cur;
494
495                                 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
496                                         ast_writestream(*fs_write, cur);
497                                 }
498                         }
499
500                         if ((*fs) && (fr)) {
501                                 struct ast_frame *cur;
502
503                                 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
504                                         ast_writestream(*fs, cur);
505                                 }
506                         }
507                         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
508                 }
509                 /* All done! free it. */
510                 if (fr) {
511                         ast_frame_free(fr, 0);
512                 }
513                 if (fr_read) {
514                         ast_frame_free(fr_read, 0);
515                 }
516                 if (fr_write) {
517                         ast_frame_free(fr_write, 0);
518                 }
519
520                 fr = NULL;
521                 fr_write = NULL;
522                 fr_read = NULL;
523
524                 ast_audiohook_lock(&mixmonitor->audiohook);
525         }
526         ast_audiohook_unlock(&mixmonitor->audiohook);
527
528         ast_autochan_destroy(mixmonitor->autochan);
529
530         /* Datastore cleanup.  close the filestream and wait for ds destruction */
531         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
532         mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
533         if (!mixmonitor->mixmonitor_ds->destruction_ok) {
534                 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
535         }
536         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
537
538         /* kill the audiohook */
539         destroy_monitor_audiohook(mixmonitor);
540
541         if (mixmonitor->post_process) {
542                 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
543                 ast_safe_system(mixmonitor->post_process);
544         }
545
546         ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
547         mixmonitor_free(mixmonitor);
548         return NULL;
549 }
550
551 static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id)
552 {
553         struct ast_datastore *datastore = NULL;
554         struct mixmonitor_ds *mixmonitor_ds;
555
556         if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
557                 return -1;
558         }
559
560         if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
561                 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
562         }
563
564         ast_mutex_init(&mixmonitor_ds->lock);
565         ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
566
567         if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
568                 ast_mutex_destroy(&mixmonitor_ds->lock);
569                 ast_cond_destroy(&mixmonitor_ds->destruction_condition);
570                 ast_free(mixmonitor_ds);
571                 return -1;
572         }
573
574
575         mixmonitor_ds->samp_rate = 8000;
576         mixmonitor_ds->audiohook = &mixmonitor->audiohook;
577         datastore->data = mixmonitor_ds;
578
579         ast_channel_lock(chan);
580         ast_channel_datastore_add(chan, datastore);
581         ast_channel_unlock(chan);
582
583         mixmonitor->mixmonitor_ds = mixmonitor_ds;
584         return 0;
585 }
586
587 static void launch_monitor_thread(struct ast_channel *chan, const char *filename,
588                                   unsigned int flags, int readvol, int writevol,
589                                   const char *post_process, const char *filename_write,
590                                   char *filename_read, const char *uid_channel_var)
591 {
592         pthread_t thread;
593         struct mixmonitor *mixmonitor;
594         char postprocess2[1024] = "";
595         char *datastore_id = NULL;
596
597         postprocess2[0] = 0;
598         /* If a post process system command is given attach it to the structure */
599         if (!ast_strlen_zero(post_process)) {
600                 char *p1, *p2;
601
602                 p1 = ast_strdupa(post_process);
603                 for (p2 = p1; *p2; p2++) {
604                         if (*p2 == '^' && *(p2+1) == '{') {
605                                 *p2 = '$';
606                         }
607                 }
608                 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
609         }
610
611         /* Pre-allocate mixmonitor structure and spy */
612         if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
613                 return;
614         }
615
616         /* Setup the actual spy before creating our thread */
617         if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
618                 mixmonitor_free(mixmonitor);
619                 return;
620         }
621
622         /* Copy over flags and channel name */
623         mixmonitor->flags = flags;
624         if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
625                 mixmonitor_free(mixmonitor);
626                 return;
627         }
628
629         if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
630                 ast_autochan_destroy(mixmonitor->autochan);
631                 mixmonitor_free(mixmonitor);
632                 ast_free(datastore_id);
633                 return;
634         }
635
636         if (!ast_strlen_zero(uid_channel_var)) {
637                 if (datastore_id) {
638                         pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
639                 }
640         }
641         ast_free(datastore_id);
642
643
644         mixmonitor->name = ast_strdup(ast_channel_name(chan));
645
646         if (!ast_strlen_zero(postprocess2)) {
647                 mixmonitor->post_process = ast_strdup(postprocess2);
648         }
649
650         if (!ast_strlen_zero(filename)) {
651                 mixmonitor->filename = ast_strdup(filename);
652         }
653
654         if (!ast_strlen_zero(filename_write)) {
655                 mixmonitor->filename_write = ast_strdup(filename_write);
656         }
657
658         if (!ast_strlen_zero(filename_read)) {
659                 mixmonitor->filename_read = ast_strdup(filename_read);
660         }
661
662         ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
663
664         if (readvol)
665                 mixmonitor->audiohook.options.read_volume = readvol;
666         if (writevol)
667                 mixmonitor->audiohook.options.write_volume = writevol;
668
669         if (startmon(chan, &mixmonitor->audiohook)) {
670                 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
671                         mixmonitor_spy_type, ast_channel_name(chan));
672                 ast_audiohook_destroy(&mixmonitor->audiohook);
673                 mixmonitor_free(mixmonitor);
674                 return;
675         }
676
677         ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
678 }
679
680 /* a note on filename_parse: creates directory structure and assigns absolute path from relative paths for filenames */
681 /* requires immediate copying of string from return to retain data since otherwise it will immediately lose scope */
682 static char *filename_parse(char *filename, char *buffer, size_t len)
683 {
684         char *slash;
685         if (ast_strlen_zero(filename)) {
686                 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
687         } else if (filename[0] != '/') {
688                 char *build;
689                 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
690                 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
691                 filename = build;
692         }
693
694         ast_copy_string(buffer, filename, len);
695
696         if ((slash = strrchr(filename, '/'))) {
697                 *slash = '\0';
698         }
699         ast_mkdir(filename, 0777);
700
701         return buffer;
702 }
703
704 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
705 {
706         int x, readvol = 0, writevol = 0;
707         char *filename_read = NULL;
708         char *filename_write = NULL;
709         char filename_buffer[1024] = "";
710         char *uid_channel_var = NULL;
711
712         struct ast_flags flags = { 0 };
713         char *parse;
714         AST_DECLARE_APP_ARGS(args,
715                 AST_APP_ARG(filename);
716                 AST_APP_ARG(options);
717                 AST_APP_ARG(post_process);
718         );
719
720         if (ast_strlen_zero(data)) {
721                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
722                 return -1;
723         }
724
725         parse = ast_strdupa(data);
726
727         AST_STANDARD_APP_ARGS(args, parse);
728
729         if (args.options) {
730                 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
731
732                 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
733
734                 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
735                         if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
736                                 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
737                         } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
738                                 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
739                         } else {
740                                 readvol = get_volfactor(x);
741                         }
742                 }
743
744                 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
745                         if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
746                                 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
747                         } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
748                                 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
749                         } else {
750                                 writevol = get_volfactor(x);
751                         }
752                 }
753
754                 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
755                         if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
756                                 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
757                         } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
758                                 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
759                         } else {
760                                 readvol = writevol = get_volfactor(x);
761                         }
762                 }
763
764                 if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
765                         filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
766                 }
767
768                 if (ast_test_flag(&flags, MUXFLAG_READ)) {
769                         filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
770                 }
771
772                 if (ast_test_flag(&flags, MUXFLAG_UID)) {
773                         uid_channel_var = opts[OPT_ARG_UID];
774                 }
775         }
776         /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
777
778         if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
779                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
780                 return -1;
781         }
782
783         /* If filename exists, try to create directories for it */
784         if (!(ast_strlen_zero(args.filename))) {
785                 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
786         }
787
788         pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
789         launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, filename_write, filename_read, uid_channel_var);
790
791         return 0;
792 }
793
794 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
795 {
796         struct ast_datastore *datastore = NULL;
797         char *parse = "";
798         struct mixmonitor_ds *mixmonitor_ds;
799
800         AST_DECLARE_APP_ARGS(args,
801                 AST_APP_ARG(mixmonid);
802         );
803
804         if (!ast_strlen_zero(data)) {
805                 parse = ast_strdupa(data);
806         }
807
808         AST_STANDARD_APP_ARGS(args, parse);
809
810         ast_channel_lock(chan);
811
812         if (!(datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid))) {
813                 ast_channel_unlock(chan);
814                 return -1;
815         }
816         mixmonitor_ds = datastore->data;
817
818         ast_mutex_lock(&mixmonitor_ds->lock);
819
820         /* closing the filestream here guarantees the file is avaliable to the dialplan
821          * after calling StopMixMonitor */
822         mixmonitor_ds_close_fs(mixmonitor_ds);
823
824         /* The mixmonitor thread may be waiting on the audiohook trigger.
825          * In order to exit from the mixmonitor loop before waiting on channel
826          * destruction, poke the audiohook trigger. */
827         if (mixmonitor_ds->audiohook) {
828                 if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
829                         ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
830                 }
831                 ast_audiohook_lock(mixmonitor_ds->audiohook);
832                 ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
833                 ast_audiohook_unlock(mixmonitor_ds->audiohook);
834                 mixmonitor_ds->audiohook = NULL;
835         }
836
837         ast_mutex_unlock(&mixmonitor_ds->lock);
838
839         /* Remove the datastore so the monitor thread can exit */
840         if (!ast_channel_datastore_remove(chan, datastore)) {
841                 ast_datastore_free(datastore);
842         }
843         ast_channel_unlock(chan);
844
845         return 0;
846 }
847
848 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
849 {
850         struct ast_channel *chan;
851         struct ast_datastore *datastore = NULL;
852         struct mixmonitor_ds *mixmonitor_ds = NULL;
853
854         switch (cmd) {
855         case CLI_INIT:
856                 e->command = "mixmonitor {start|stop|list}";
857                 e->usage =
858                         "Usage: mixmonitor <start|stop|list> <chan_name> [args]\n"
859                         "       The optional arguments are passed to the MixMonitor\n"
860                         "       application when the 'start' command is used.\n";
861                 return NULL;
862         case CLI_GENERATE:
863                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
864         }
865
866         if (a->argc < 3) {
867                 return CLI_SHOWUSAGE;
868         }
869
870         if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
871                 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
872                 /* Technically this is a failure, but we don't want 2 errors printing out */
873                 return CLI_SUCCESS;
874         }
875
876         ast_channel_lock(chan);
877
878         if (!strcasecmp(a->argv[1], "start")) {
879                 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
880                 ast_channel_unlock(chan);
881         } else if (!strcasecmp(a->argv[1], "stop")){
882                 ast_channel_unlock(chan);
883                 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
884         } else if (!strcasecmp(a->argv[1], "list")) {
885                 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
886                 ast_cli(a->fd, "=========================================================================\n");
887                 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
888                         if (datastore->info == &mixmonitor_ds_info) {
889                                 char *filename = "";
890                                 char *filename_read = "";
891                                 char *filename_write = "";
892                                 mixmonitor_ds = datastore->data;
893                                 if (mixmonitor_ds->fs)
894                                         filename = ast_strdupa(mixmonitor_ds->fs->filename);
895                                 if (mixmonitor_ds->fs_read)
896                                         filename_read = ast_strdupa(mixmonitor_ds->fs_read->filename);
897                                 if (mixmonitor_ds->fs_write)
898                                         filename_write = ast_strdupa(mixmonitor_ds->fs_write->filename);
899                                 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
900                         }
901                 }
902                 ast_channel_unlock(chan);
903         } else {
904                 ast_channel_unlock(chan);
905                 chan = ast_channel_unref(chan);
906                 return CLI_SHOWUSAGE;
907         }
908
909         chan = ast_channel_unref(chan);
910
911         return CLI_SUCCESS;
912 }
913
914 /*! \brief  Mute / unmute  a MixMonitor channel */
915 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
916 {
917         struct ast_channel *c = NULL;
918
919         const char *name = astman_get_header(m, "Channel");
920         const char *id = astman_get_header(m, "ActionID");
921         const char *state = astman_get_header(m, "State");
922         const char *direction = astman_get_header(m,"Direction");
923
924         int clearmute = 1;
925
926         enum ast_audiohook_flags flag;
927
928         if (ast_strlen_zero(direction)) {
929                 astman_send_error(s, m, "No direction specified. Must be read, write or both");
930                 return AMI_SUCCESS;
931         }
932
933         if (!strcasecmp(direction, "read")) {
934                 flag = AST_AUDIOHOOK_MUTE_READ;
935         } else  if (!strcasecmp(direction, "write")) {
936                 flag = AST_AUDIOHOOK_MUTE_WRITE;
937         } else  if (!strcasecmp(direction, "both")) {
938                 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
939         } else {
940                 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
941                 return AMI_SUCCESS;
942         }
943
944         if (ast_strlen_zero(name)) {
945                 astman_send_error(s, m, "No channel specified");
946                 return AMI_SUCCESS;
947         }
948
949         if (ast_strlen_zero(state)) {
950                 astman_send_error(s, m, "No state specified");
951                 return AMI_SUCCESS;
952         }
953
954         clearmute = ast_false(state);
955         c = ast_channel_get_by_name(name);
956
957         if (!c) {
958                 astman_send_error(s, m, "No such channel");
959                 return AMI_SUCCESS;
960         }
961
962         if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
963                 c = ast_channel_unref(c);
964                 astman_send_error(s, m, "Cannot set mute flag");
965                 return AMI_SUCCESS;
966         }
967
968         astman_append(s, "Response: Success\r\n");
969
970         if (!ast_strlen_zero(id)) {
971                 astman_append(s, "ActionID: %s\r\n", id);
972         }
973
974         astman_append(s, "\r\n");
975
976         c = ast_channel_unref(c);
977
978         return AMI_SUCCESS;
979 }
980
981 static int manager_mixmonitor(struct mansession *s, const struct message *m)
982 {
983         struct ast_channel *c = NULL;
984
985         const char *name = astman_get_header(m, "Channel");
986         const char *id = astman_get_header(m, "ActionID");
987         const char *file = astman_get_header(m, "File");
988         const char *options = astman_get_header(m, "Options");
989         char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
990         struct ast_flags flags = { 0 };
991         char *uid_channel_var = NULL;
992         const char *mixmonitor_id = NULL;
993
994         int res;
995         char args[PATH_MAX] = "";
996         if (ast_strlen_zero(name)) {
997                 astman_send_error(s, m, "No channel specified");
998                 return AMI_SUCCESS;
999         }
1000
1001         c = ast_channel_get_by_name(name);
1002
1003         if (!c) {
1004                 astman_send_error(s, m, "No such channel");
1005                 return AMI_SUCCESS;
1006         }
1007
1008         if (!ast_strlen_zero(options)) {
1009                 ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
1010         }
1011
1012         snprintf(args, sizeof(args), "%s,%s", file, options);
1013
1014         ast_channel_lock(c);
1015         res = mixmonitor_exec(c, args);
1016
1017         if (ast_test_flag(&flags, MUXFLAG_UID)) {
1018                 uid_channel_var = opts[OPT_ARG_UID];
1019                 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1020         }
1021         ast_channel_unlock(c);
1022
1023         if (res) {
1024                 astman_send_error(s, m, "Could not start monitoring channel");
1025                 return AMI_SUCCESS;
1026         }
1027
1028         astman_append(s, "Response: Success\r\n");
1029
1030         if (!ast_strlen_zero(id)) {
1031                 astman_append(s, "ActionID: %s\r\n", id);
1032         }
1033
1034         if (!ast_strlen_zero(mixmonitor_id)) {
1035                 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1036         }
1037
1038         astman_append(s, "\r\n");
1039
1040         c = ast_channel_unref(c);
1041
1042         return AMI_SUCCESS;
1043 }
1044
1045 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
1046 {
1047         struct ast_channel *c = NULL;
1048
1049         const char *name = astman_get_header(m, "Channel");
1050         const char *id = astman_get_header(m, "ActionID");
1051         const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1052
1053         int res;
1054         if (ast_strlen_zero(name)) {
1055                 astman_send_error(s, m, "No channel specified");
1056                 return AMI_SUCCESS;
1057         }
1058
1059         c = ast_channel_get_by_name(name);
1060
1061         if (!c) {
1062                 astman_send_error(s, m, "No such channel");
1063                 return AMI_SUCCESS;
1064         }
1065
1066         res = stop_mixmonitor_exec(c, mixmonitor_id);
1067
1068         if (res) {
1069                 astman_send_error(s, m, "Could not stop monitoring channel");
1070                 return AMI_SUCCESS;
1071         }
1072
1073         astman_append(s, "Response: Success\r\n");
1074
1075         if (!ast_strlen_zero(id)) {
1076                 astman_append(s, "ActionID: %s\r\n", id);
1077         }
1078
1079         astman_append(s, "\r\n");
1080
1081         c = ast_channel_unref(c);
1082
1083         return AMI_SUCCESS;
1084 }
1085
1086 static struct ast_cli_entry cli_mixmonitor[] = {
1087         AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1088 };
1089
1090 static int unload_module(void)
1091 {
1092         int res;
1093
1094         ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1095         res = ast_unregister_application(stop_app);
1096         res |= ast_unregister_application(app);
1097         res |= ast_manager_unregister("MixMonitorMute");
1098         res |= ast_manager_unregister("MixMonitor");
1099         res |= ast_manager_unregister("StopMixMonitor");
1100
1101         return res;
1102 }
1103
1104 static int load_module(void)
1105 {
1106         int res;
1107
1108         ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1109         res = ast_register_application_xml(app, mixmonitor_exec);
1110         res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
1111         res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
1112         res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor);
1113         res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor);
1114
1115         return res;
1116 }
1117
1118 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");