2922e0cd37cb65362f2efb851598883a105e9ca1
[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         <use type="module">func_periodic_hook</use>
38         <support_level>core</support_level>
39  ***/
40
41 #include "asterisk.h"
42
43 #include "asterisk/paths.h"     /* use ast_config_AST_MONITOR_DIR */
44 #include "asterisk/stringfields.h"
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/callerid.h"
55 #include "asterisk/mod_format.h"
56 #include "asterisk/linkedlists.h"
57 #include "asterisk/test.h"
58 #include "asterisk/mixmonitor.h"
59 #include "asterisk/format_cache.h"
60 #include "asterisk/beep.h"
61
62 /*** DOCUMENTATION
63         <application name="MixMonitor" language="en_US">
64                 <synopsis>
65                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
66                         to guarantee the audio file is available for processing during dialplan execution.
67                 </synopsis>
68                 <syntax>
69                         <parameter name="file" required="true" argsep=".">
70                                 <argument name="filename" required="true">
71                                         <para>If <replaceable>filename</replaceable> is an absolute path, uses that path, otherwise
72                                         creates the file in the configured monitoring directory from <filename>asterisk.conf.</filename></para>
73                                 </argument>
74                                 <argument name="extension" required="true" />
75                         </parameter>
76                         <parameter name="options">
77                                 <optionlist>
78                                         <option name="a">
79                                                 <para>Append to the file instead of overwriting it.</para>
80                                         </option>
81                                         <option name="b">
82                                                 <para>Only save audio to the file while the channel is bridged.</para>
83                                                 <note><para>If you utilize this option inside a Local channel, you must make sure the Local
84                                                 channel is not optimized away. To do this, be sure to call your Local channel with the
85                                                 <literal>/n</literal> option. For example: Dial(Local/start@mycontext/n)</para></note>
86                                         </option>
87                                         <option name="B">
88                                                 <para>Play a periodic beep while this call is being recorded.</para>
89                                                 <argument name="interval"><para>Interval, in seconds. Default is 15.</para></argument>
90                                         </option>
91                                         <option name="v">
92                                                 <para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
93                                                 (range <literal>-4</literal> to <literal>4</literal>)</para>
94                                                 <argument name="x" required="true" />
95                                         </option>
96                                         <option name="V">
97                                                 <para>Adjust the <emphasis>spoken</emphasis> volume by a factor
98                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
99                                                 <argument name="x" required="true" />
100                                         </option>
101                                         <option name="W">
102                                                 <para>Adjust both, <emphasis>heard and spoken</emphasis> volumes by a factor
103                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
104                                                 <argument name="x" required="true" />
105                                         </option>
106                                         <option name="r">
107                                                 <argument name="file" required="true" />
108                                                 <para>Use the specified file to record the <emphasis>receive</emphasis> audio feed.
109                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
110                                                 the file in the configured monitoring directory.</para>
111                                         </option>
112                                         <option name="t">
113                                                 <argument name="file" required="true" />
114                                                 <para>Use the specified file to record the <emphasis>transmit</emphasis> audio feed.
115                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
116                                                 the file in the configured monitoring directory.</para>
117                                         </option>
118                                         <option name="i">
119                                                 <argument name="chanvar" required="true" />
120                                                 <para>Stores the MixMonitor's ID on this channel variable.</para>
121                                         </option>
122                                         <option name="p">
123                                                 <para>Play a beep on the channel that starts the recording.</para>
124                                         </option>
125                                         <option name="P">
126                                                 <para>Play a beep on the channel that stops the recording.</para>
127                                         </option>
128                                         <option name="m">
129                                                 <argument name="mailbox" required="true" />
130                                                 <para>Create a copy of the recording as a voicemail in the indicated <emphasis>mailbox</emphasis>(es)
131                                                 separated by commas eg. m(1111@default,2222@default,...).  Folders can be optionally specified using
132                                                 the syntax: mailbox@context/folder</para>
133                                         </option>
134                                 </optionlist>
135                         </parameter>
136                         <parameter name="command">
137                                 <para>Will be executed when the recording is over.</para>
138                                 <para>Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.</para>
139                                 <para>All variables will be evaluated at the time MixMonitor is called.</para>
140                                 <warning><para>Do not use untrusted strings such as <variable>CALLERID(num)</variable>
141                                 or <variable>CALLERID(name)</variable> as part of the command parameters.  You
142                                 risk a command injection attack executing arbitrary commands if the untrusted
143                                 strings aren't filtered to remove dangerous characters.  See function
144                                 <variable>FILTER()</variable>.</para></warning>
145                         </parameter>
146                 </syntax>
147                 <description>
148                         <para>Records the audio on the current channel to the specified file.</para>
149                         <para>This application does not automatically answer and should be preceeded by
150                         an application such as Answer or Progress().</para>
151                         <note><para>MixMonitor runs as an audiohook.</para></note>
152                         <variablelist>
153                                 <variable name="MIXMONITOR_FILENAME">
154                                         <para>Will contain the filename used to record.</para>
155                                 </variable>
156                         </variablelist>
157                         <warning><para>Do not use untrusted strings such as <variable>CALLERID(num)</variable>
158                         or <variable>CALLERID(name)</variable> as part of ANY of the application's
159                         parameters.  You risk a command injection attack executing arbitrary commands
160                         if the untrusted strings aren't filtered to remove dangerous characters.  See
161                         function <variable>FILTER()</variable>.</para></warning>
162                 </description>
163                 <see-also>
164                         <ref type="application">Monitor</ref>
165                         <ref type="application">StopMixMonitor</ref>
166                         <ref type="application">PauseMonitor</ref>
167                         <ref type="application">UnpauseMonitor</ref>
168                         <ref type="function">AUDIOHOOK_INHERIT</ref>
169                 </see-also>
170         </application>
171         <application name="StopMixMonitor" language="en_US">
172                 <synopsis>
173                         Stop recording a call through MixMonitor, and free the recording's file handle.
174                 </synopsis>
175                 <syntax>
176                         <parameter name="MixMonitorID" required="false">
177                                 <para>If a valid ID is provided, then this command will stop only that specific
178                                 MixMonitor.</para>
179                         </parameter>
180                 </syntax>
181                 <description>
182                         <para>Stops the audio recording that was started with a call to <literal>MixMonitor()</literal>
183                         on the current channel.</para>
184                 </description>
185                 <see-also>
186                         <ref type="application">MixMonitor</ref>
187                 </see-also>
188         </application>
189         <manager name="MixMonitorMute" language="en_US">
190                 <synopsis>
191                         Mute / unMute a Mixmonitor recording.
192                 </synopsis>
193                 <syntax>
194                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
195                         <parameter name="Channel" required="true">
196                                 <para>Used to specify the channel to mute.</para>
197                         </parameter>
198                         <parameter name="Direction">
199                                 <para>Which part of the recording to mute:  read, write or both (from channel, to channel or both channels).</para>
200                         </parameter>
201                         <parameter name="State">
202                                 <para>Turn mute on or off : 1 to turn on, 0 to turn off.</para>
203                         </parameter>
204                 </syntax>
205                 <description>
206                         <para>This action may be used to mute a MixMonitor recording.</para>
207                 </description>
208         </manager>
209         <manager name="MixMonitor" language="en_US">
210                 <synopsis>
211                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
212                         to guarantee the audio file is available for processing during dialplan execution.
213                 </synopsis>
214                 <syntax>
215                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
216                         <parameter name="Channel" required="true">
217                                 <para>Used to specify the channel to record.</para>
218                         </parameter>
219                         <parameter name="File">
220                                 <para>Is the name of the file created in the monitor spool directory.
221                                 Defaults to the same name as the channel (with slashes replaced with dashes).
222                                 This argument is optional if you specify to record unidirectional audio with
223                                 either the r(filename) or t(filename) options in the options field. If
224                                 neither MIXMONITOR_FILENAME or this parameter is set, the mixed stream won't
225                                 be recorded.</para>
226                         </parameter>
227                         <parameter name="options">
228                                 <para>Options that apply to the MixMonitor in the same way as they
229                                 would apply if invoked from the MixMonitor application. For a list of
230                                 available options, see the documentation for the mixmonitor application. </para>
231                         </parameter>
232                         <parameter name="Command">
233                                 <para>Will be executed when the recording is over.
234                                 Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.
235                                 All variables will be evaluated at the time MixMonitor is called.</para>
236                                 <warning><para>Do not use untrusted strings such as <variable>CALLERID(num)</variable>
237                                 or <variable>CALLERID(name)</variable> as part of the command parameters.  You
238                                 risk a command injection attack executing arbitrary commands if the untrusted
239                                 strings aren't filtered to remove dangerous characters.  See function
240                                 <variable>FILTER()</variable>.</para></warning>
241                         </parameter>
242                 </syntax>
243                 <description>
244                         <para>This action records the audio on the current channel to the specified file.</para>
245                         <variablelist>
246                                 <variable name="MIXMONITOR_FILENAME">
247                                         <para>Will contain the filename used to record the mixed stream.</para>
248                                 </variable>
249                         </variablelist>
250                 </description>
251         </manager>
252         <manager name="StopMixMonitor" language="en_US">
253                 <synopsis>
254                         Stop recording a call through MixMonitor, and free the recording's file handle.
255                 </synopsis>
256                 <syntax>
257                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
258                         <parameter name="Channel" required="true">
259                                 <para>The name of the channel monitored.</para>
260                         </parameter>
261                         <parameter name="MixMonitorID" required="false">
262                                 <para>If a valid ID is provided, then this command will stop only that specific
263                                 MixMonitor.</para>
264                         </parameter>
265                 </syntax>
266                 <description>
267                         <para>This action stops the audio recording that was started with the <literal>MixMonitor</literal>
268                         action on the current channel.</para>
269                 </description>
270         </manager>
271         <function name="MIXMONITOR" language="en_US">
272                 <synopsis>
273                         Retrieve data pertaining to specific instances of MixMonitor on a channel.
274                 </synopsis>
275                 <syntax>
276                         <parameter name="id" required="true">
277                                 <para>The unique ID of the MixMonitor instance. The unique ID can be retrieved through the channel
278                                 variable used as an argument to the <replaceable>i</replaceable> option to MixMonitor.</para>
279                         </parameter>
280                         <parameter name="key" required="true">
281                                 <para>The piece of data to retrieve from the MixMonitor.</para>
282                                 <enumlist>
283                                         <enum name="filename" />
284                                 </enumlist>
285                         </parameter>
286                 </syntax>
287         </function>
288
289  ***/
290
291 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
292
293 static const char * const app = "MixMonitor";
294
295 static const char * const stop_app = "StopMixMonitor";
296
297 static const char * const mixmonitor_spy_type = "MixMonitor";
298
299 /*!
300  * \internal
301  * \brief This struct is a list item holds data needed to find a vm_recipient within voicemail
302  */
303 struct vm_recipient {
304         char mailbox[AST_MAX_CONTEXT];
305         char context[AST_MAX_EXTENSION];
306         char folder[80];
307         AST_LIST_ENTRY(vm_recipient) list;
308 };
309
310 struct mixmonitor {
311         struct ast_audiohook audiohook;
312         char *filename;
313         char *filename_read;
314         char *filename_write;
315         char *post_process;
316         char *name;
317         ast_callid callid;
318         unsigned int flags;
319         struct ast_autochan *autochan;
320         struct mixmonitor_ds *mixmonitor_ds;
321
322         /* the below string fields describe data used for creating voicemails from the recording */
323         AST_DECLARE_STRING_FIELDS(
324                 AST_STRING_FIELD(call_context);
325                 AST_STRING_FIELD(call_macrocontext);
326                 AST_STRING_FIELD(call_extension);
327                 AST_STRING_FIELD(call_callerchan);
328                 AST_STRING_FIELD(call_callerid);
329         );
330         int call_priority;
331
332         /* FUTURE DEVELOPMENT NOTICE
333          * recipient_list will need locks if we make it editable after the monitor is started */
334         AST_LIST_HEAD_NOLOCK(, vm_recipient) recipient_list;
335 };
336
337 enum mixmonitor_flags {
338         MUXFLAG_APPEND = (1 << 1),
339         MUXFLAG_BRIDGED = (1 << 2),
340         MUXFLAG_VOLUME = (1 << 3),
341         MUXFLAG_READVOLUME = (1 << 4),
342         MUXFLAG_WRITEVOLUME = (1 << 5),
343         MUXFLAG_READ = (1 << 6),
344         MUXFLAG_WRITE = (1 << 7),
345         MUXFLAG_COMBINED = (1 << 8),
346         MUXFLAG_UID = (1 << 9),
347         MUXFLAG_VMRECIPIENTS = (1 << 10),
348         MUXFLAG_BEEP = (1 << 11),
349         MUXFLAG_BEEP_START = (1 << 12),
350         MUXFLAG_BEEP_STOP = (1 << 13)
351 };
352
353 enum mixmonitor_args {
354         OPT_ARG_READVOLUME = 0,
355         OPT_ARG_WRITEVOLUME,
356         OPT_ARG_VOLUME,
357         OPT_ARG_WRITENAME,
358         OPT_ARG_READNAME,
359         OPT_ARG_UID,
360         OPT_ARG_VMRECIPIENTS,
361         OPT_ARG_BEEP_INTERVAL,
362         OPT_ARG_ARRAY_SIZE,     /* Always last element of the enum */
363 };
364
365 AST_APP_OPTIONS(mixmonitor_opts, {
366         AST_APP_OPTION('a', MUXFLAG_APPEND),
367         AST_APP_OPTION('b', MUXFLAG_BRIDGED),
368         AST_APP_OPTION_ARG('B', MUXFLAG_BEEP, OPT_ARG_BEEP_INTERVAL),
369         AST_APP_OPTION('p', MUXFLAG_BEEP_START),
370         AST_APP_OPTION('P', MUXFLAG_BEEP_STOP),
371         AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
372         AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
373         AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
374         AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
375         AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
376         AST_APP_OPTION_ARG('i', MUXFLAG_UID, OPT_ARG_UID),
377         AST_APP_OPTION_ARG('m', MUXFLAG_VMRECIPIENTS, OPT_ARG_VMRECIPIENTS),
378 });
379
380 struct mixmonitor_ds {
381         unsigned int destruction_ok;
382         ast_cond_t destruction_condition;
383         ast_mutex_t lock;
384
385         /* The filestream is held in the datastore so it can be stopped
386          * immediately during stop_mixmonitor or channel destruction. */
387         int fs_quit;
388
389         struct ast_filestream *fs;
390         struct ast_filestream *fs_read;
391         struct ast_filestream *fs_write;
392
393         struct ast_audiohook *audiohook;
394
395         unsigned int samp_rate;
396         char *filename;
397         char *beep_id;
398 };
399
400 /*!
401  * \internal
402  * \pre mixmonitor_ds must be locked before calling this function
403  */
404 static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
405 {
406         unsigned char quitting = 0;
407
408         if (mixmonitor_ds->fs) {
409                 quitting = 1;
410                 ast_closestream(mixmonitor_ds->fs);
411                 mixmonitor_ds->fs = NULL;
412                 ast_verb(2, "MixMonitor close filestream (mixed)\n");
413         }
414
415         if (mixmonitor_ds->fs_read) {
416                 quitting = 1;
417                 ast_closestream(mixmonitor_ds->fs_read);
418                 mixmonitor_ds->fs_read = NULL;
419                 ast_verb(2, "MixMonitor close filestream (read)\n");
420         }
421
422         if (mixmonitor_ds->fs_write) {
423                 quitting = 1;
424                 ast_closestream(mixmonitor_ds->fs_write);
425                 mixmonitor_ds->fs_write = NULL;
426                 ast_verb(2, "MixMonitor close filestream (write)\n");
427         }
428
429         if (quitting) {
430                 mixmonitor_ds->fs_quit = 1;
431         }
432 }
433
434 static void mixmonitor_ds_destroy(void *data)
435 {
436         struct mixmonitor_ds *mixmonitor_ds = data;
437
438         ast_mutex_lock(&mixmonitor_ds->lock);
439         mixmonitor_ds->audiohook = NULL;
440         mixmonitor_ds->destruction_ok = 1;
441         ast_free(mixmonitor_ds->filename);
442         ast_free(mixmonitor_ds->beep_id);
443         ast_cond_signal(&mixmonitor_ds->destruction_condition);
444         ast_mutex_unlock(&mixmonitor_ds->lock);
445 }
446
447 static const struct ast_datastore_info mixmonitor_ds_info = {
448         .type = "mixmonitor",
449         .destroy = mixmonitor_ds_destroy,
450 };
451
452 static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
453 {
454         if (mixmonitor->mixmonitor_ds) {
455                 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
456                 mixmonitor->mixmonitor_ds->audiohook = NULL;
457                 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
458         }
459         /* kill the audiohook.*/
460         ast_audiohook_lock(&mixmonitor->audiohook);
461         ast_audiohook_detach(&mixmonitor->audiohook);
462         ast_audiohook_unlock(&mixmonitor->audiohook);
463         ast_audiohook_destroy(&mixmonitor->audiohook);
464 }
465
466 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
467 {
468         if (!chan) {
469                 return -1;
470         }
471
472         return ast_audiohook_attach(chan, audiohook);
473 }
474
475 /*!
476  * \internal
477  * \brief adds recipients to a mixmonitor's recipient list
478  * \param mixmonitor mixmonitor being affected
479  * \param vm_recipients string containing the desired recipients to add
480  */
481 static void add_vm_recipients_from_string(struct mixmonitor *mixmonitor, const char *vm_recipients)
482 {
483         /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
484         char *cur_mailbox = ast_strdupa(vm_recipients);
485         char *cur_context;
486         char *cur_folder;
487         char *next;
488         int elements_processed = 0;
489
490         while (!ast_strlen_zero(cur_mailbox)) {
491                 ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
492                 if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
493                         *(next++) = '\0';
494                 }
495
496                 if ((cur_folder = strchr(cur_mailbox, '/'))) {
497                         *(cur_folder++) = '\0';
498                 } else {
499                         cur_folder = "INBOX";
500                 }
501
502                 if ((cur_context = strchr(cur_mailbox, '@'))) {
503                         *(cur_context++) = '\0';
504                 } else {
505                         cur_context = "default";
506                 }
507
508                 if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
509                         struct vm_recipient *recipient;
510                         if (!(recipient = ast_malloc(sizeof(*recipient)))) {
511                                 ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
512                                 return;
513                         }
514                         ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
515                         ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
516                         ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
517
518                         /* Add to list */
519                         ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
520                         AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list);
521                 } else {
522                         ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
523                 }
524
525                 cur_mailbox = next;
526                 elements_processed++;
527         }
528 }
529
530 static void clear_mixmonitor_recipient_list(struct mixmonitor *mixmonitor)
531 {
532         struct vm_recipient *current;
533         while ((current = AST_LIST_REMOVE_HEAD(&mixmonitor->recipient_list, list))) {
534                 /* Clear list element data */
535                 ast_free(current);
536         }
537 }
538
539 #define SAMPLES_PER_FRAME 160
540
541 static void mixmonitor_free(struct mixmonitor *mixmonitor)
542 {
543         if (mixmonitor) {
544                 if (mixmonitor->mixmonitor_ds) {
545                         ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
546                         ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
547                         ast_free(mixmonitor->mixmonitor_ds);
548                 }
549
550                 ast_free(mixmonitor->name);
551                 ast_free(mixmonitor->post_process);
552                 ast_free(mixmonitor->filename);
553                 ast_free(mixmonitor->filename_write);
554                 ast_free(mixmonitor->filename_read);
555
556                 /* Free everything in the recipient list */
557                 clear_mixmonitor_recipient_list(mixmonitor);
558
559                 /* clean stringfields */
560                 ast_string_field_free_memory(mixmonitor);
561
562                 ast_free(mixmonitor);
563         }
564 }
565
566 /*!
567  * \internal
568  * \brief Copies the mixmonitor to all voicemail recipients
569  * \param mixmonitor The mixmonitor that needs to forward its file to recipients
570  * \param ext Format of the file that was saved
571  */
572 static void copy_to_voicemail(struct mixmonitor *mixmonitor, const char *ext, const char *filename)
573 {
574         struct vm_recipient *recipient = NULL;
575         struct ast_vm_recording_data recording_data;
576         if (ast_string_field_init(&recording_data, 512)) {
577                 ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
578                 return;
579         }
580
581         /* Copy strings to stringfields that will be used for all recipients */
582         ast_string_field_set(&recording_data, recording_file, filename);
583         ast_string_field_set(&recording_data, recording_ext, ext);
584         ast_string_field_set(&recording_data, call_context, mixmonitor->call_context);
585         ast_string_field_set(&recording_data, call_macrocontext, mixmonitor->call_macrocontext);
586         ast_string_field_set(&recording_data, call_extension, mixmonitor->call_extension);
587         ast_string_field_set(&recording_data, call_callerchan, mixmonitor->call_callerchan);
588         ast_string_field_set(&recording_data, call_callerid, mixmonitor->call_callerid);
589         /* and call_priority gets copied too */
590         recording_data.call_priority = mixmonitor->call_priority;
591
592         AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
593                 /* context, mailbox, and folder need to be set per recipient */
594                 ast_string_field_set(&recording_data, context, recipient->context);
595                 ast_string_field_set(&recording_data, mailbox, recipient->mailbox);
596                 ast_string_field_set(&recording_data, folder, recipient->folder);
597
598                 ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
599                         recording_data.context);
600                 ast_app_copy_recording_to_vm(&recording_data);
601         }
602
603         /* Free the string fields for recording_data before exiting the function. */
604         ast_string_field_free_memory(&recording_data);
605 }
606
607 static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag, char **ext)
608 {
609         /* Initialize the file if not already done so */
610         char *last_slash = NULL;
611         if (!ast_strlen_zero(filename)) {
612                 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
613                         *oflags = O_CREAT | O_WRONLY;
614                         *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
615
616                         last_slash = strrchr(filename, '/');
617
618                         if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
619                                 **ext = '\0';
620                                 *ext = *ext + 1;
621                         } else {
622                                 *ext = "raw";
623                         }
624
625                         if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
626                                 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
627                                 *errflag = 1;
628                         } else {
629                                 struct ast_filestream *tmp = *fs;
630                                 mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_get_sample_rate(tmp->fmt->format));
631                         }
632                 }
633         }
634 }
635
636 static int mixmonitor_autochan_is_bridged(struct ast_autochan *autochan)
637 {
638         int is_bridged;
639
640         ast_autochan_channel_lock(autochan);
641         is_bridged = ast_channel_is_bridged(autochan->chan);
642         ast_autochan_channel_unlock(autochan);
643         return is_bridged;
644 }
645
646 static void *mixmonitor_thread(void *obj)
647 {
648         struct mixmonitor *mixmonitor = obj;
649         char *fs_ext = "";
650         char *fs_read_ext = "";
651         char *fs_write_ext = "";
652
653         struct ast_filestream **fs = NULL;
654         struct ast_filestream **fs_read = NULL;
655         struct ast_filestream **fs_write = NULL;
656
657         unsigned int oflags;
658         int errflag = 0;
659         struct ast_format *format_slin;
660
661         /* Keep callid association before any log messages */
662         if (mixmonitor->callid) {
663                 ast_callid_threadassoc_add(mixmonitor->callid);
664         }
665
666         ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
667
668         fs = &mixmonitor->mixmonitor_ds->fs;
669         fs_read = &mixmonitor->mixmonitor_ds->fs_read;
670         fs_write = &mixmonitor->mixmonitor_ds->fs_write;
671
672         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
673         mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
674         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
675         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
676
677         format_slin = ast_format_cache_get_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate);
678
679         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
680
681         /* The audiohook must enter and exit the loop locked */
682         ast_audiohook_lock(&mixmonitor->audiohook);
683         while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
684                 struct ast_frame *fr = NULL;
685                 struct ast_frame *fr_read = NULL;
686                 struct ast_frame *fr_write = NULL;
687
688                 if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, format_slin,
689                                                 &fr_read, &fr_write))) {
690                         ast_audiohook_trigger_wait(&mixmonitor->audiohook);
691
692                         if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
693                                 break;
694                         }
695                         continue;
696                 }
697
698                 /* audiohook lock is not required for the next block.
699                  * Unlock it, but remember to lock it before looping or exiting */
700                 ast_audiohook_unlock(&mixmonitor->audiohook);
701
702                 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED)
703                         || mixmonitor_autochan_is_bridged(mixmonitor->autochan)) {
704                         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
705
706                         /* Write out the frame(s) */
707                         if ((*fs_read) && (fr_read)) {
708                                 struct ast_frame *cur;
709
710                                 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
711                                         ast_writestream(*fs_read, cur);
712                                 }
713                         }
714
715                         if ((*fs_write) && (fr_write)) {
716                                 struct ast_frame *cur;
717
718                                 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
719                                         ast_writestream(*fs_write, cur);
720                                 }
721                         }
722
723                         if ((*fs) && (fr)) {
724                                 struct ast_frame *cur;
725
726                                 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
727                                         ast_writestream(*fs, cur);
728                                 }
729                         }
730                         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
731                 }
732                 /* All done! free it. */
733                 if (fr) {
734                         ast_frame_free(fr, 0);
735                 }
736                 if (fr_read) {
737                         ast_frame_free(fr_read, 0);
738                 }
739                 if (fr_write) {
740                         ast_frame_free(fr_write, 0);
741                 }
742
743                 fr = NULL;
744                 fr_write = NULL;
745                 fr_read = NULL;
746
747                 ast_audiohook_lock(&mixmonitor->audiohook);
748         }
749
750         ast_audiohook_unlock(&mixmonitor->audiohook);
751
752         if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) {
753                 ast_autochan_channel_lock(mixmonitor->autochan);
754                 ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
755                 ast_autochan_channel_unlock(mixmonitor->autochan);
756         }
757
758         ast_autochan_destroy(mixmonitor->autochan);
759
760         /* Datastore cleanup.  close the filestream and wait for ds destruction */
761         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
762         mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
763         if (!mixmonitor->mixmonitor_ds->destruction_ok) {
764                 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
765         }
766         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
767
768         /* kill the audiohook */
769         destroy_monitor_audiohook(mixmonitor);
770
771         if (mixmonitor->post_process) {
772                 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
773                 ast_safe_system(mixmonitor->post_process);
774         }
775
776         ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
777         ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
778
779         if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
780                 if (ast_strlen_zero(fs_ext)) {
781                         ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
782                                 mixmonitor -> name);
783                 } else {
784                         ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
785                         copy_to_voicemail(mixmonitor, fs_ext, mixmonitor->filename);
786                 }
787                 if (!ast_strlen_zero(fs_read_ext)) {
788                         ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
789                         copy_to_voicemail(mixmonitor, fs_read_ext, mixmonitor->filename_read);
790                 }
791                 if (!ast_strlen_zero(fs_write_ext)) {
792                         ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
793                         copy_to_voicemail(mixmonitor, fs_write_ext, mixmonitor->filename_write);
794                 }
795         } else {
796                 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
797         }
798
799         mixmonitor_free(mixmonitor);
800
801         ast_module_unref(ast_module_info->self);
802         return NULL;
803 }
804
805 static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
806 {
807         struct ast_datastore *datastore = NULL;
808         struct mixmonitor_ds *mixmonitor_ds;
809
810         if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
811                 return -1;
812         }
813
814         if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
815                 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
816         }
817
818         ast_mutex_init(&mixmonitor_ds->lock);
819         ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
820
821         if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
822                 ast_mutex_destroy(&mixmonitor_ds->lock);
823                 ast_cond_destroy(&mixmonitor_ds->destruction_condition);
824                 ast_free(mixmonitor_ds);
825                 return -1;
826         }
827
828         if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) {
829                 ast_autochan_channel_lock(mixmonitor->autochan);
830                 ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
831                 ast_autochan_channel_unlock(mixmonitor->autochan);
832         }
833
834         mixmonitor_ds->samp_rate = 8000;
835         mixmonitor_ds->audiohook = &mixmonitor->audiohook;
836         mixmonitor_ds->filename = ast_strdup(mixmonitor->filename);
837         if (!ast_strlen_zero(beep_id)) {
838                 mixmonitor_ds->beep_id = ast_strdup(beep_id);
839         }
840         datastore->data = mixmonitor_ds;
841
842         ast_channel_lock(chan);
843         ast_channel_datastore_add(chan, datastore);
844         ast_channel_unlock(chan);
845
846         mixmonitor->mixmonitor_ds = mixmonitor_ds;
847         return 0;
848 }
849
850 static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
851                                   unsigned int flags, int readvol, int writevol,
852                                   const char *post_process, const char *filename_write,
853                                   char *filename_read, const char *uid_channel_var,
854                                   const char *recipients, const char *beep_id)
855 {
856         pthread_t thread;
857         struct mixmonitor *mixmonitor;
858         char postprocess2[1024] = "";
859         char *datastore_id = NULL;
860
861         postprocess2[0] = 0;
862         /* If a post process system command is given attach it to the structure */
863         if (!ast_strlen_zero(post_process)) {
864                 char *p1, *p2;
865
866                 p1 = ast_strdupa(post_process);
867                 for (p2 = p1; *p2; p2++) {
868                         if (*p2 == '^' && *(p2+1) == '{') {
869                                 *p2 = '$';
870                         }
871                 }
872                 ast_channel_lock(chan);
873                 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
874                 ast_channel_unlock(chan);
875         }
876
877         /* Pre-allocate mixmonitor structure and spy */
878         if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
879                 return -1;
880         }
881
882         /* Now that the struct has been calloced, go ahead and initialize the string fields. */
883         if (ast_string_field_init(mixmonitor, 512)) {
884                 mixmonitor_free(mixmonitor);
885                 return -1;
886         }
887
888         /* Setup the actual spy before creating our thread */
889         if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
890                 mixmonitor_free(mixmonitor);
891                 return -1;
892         }
893
894         /* Copy over flags and channel name */
895         mixmonitor->flags = flags;
896         if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
897                 mixmonitor_free(mixmonitor);
898                 return -1;
899         }
900
901         if (!ast_strlen_zero(filename)) {
902                 mixmonitor->filename = ast_strdup(filename);
903         }
904
905         if (!ast_strlen_zero(filename_write)) {
906                 mixmonitor->filename_write = ast_strdup(filename_write);
907         }
908
909         if (!ast_strlen_zero(filename_read)) {
910                 mixmonitor->filename_read = ast_strdup(filename_read);
911         }
912
913         if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
914                 ast_autochan_destroy(mixmonitor->autochan);
915                 mixmonitor_free(mixmonitor);
916                 ast_free(datastore_id);
917                 return -1;
918         }
919
920         if (!ast_strlen_zero(uid_channel_var)) {
921                 if (datastore_id) {
922                         pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
923                 }
924         }
925         ast_free(datastore_id);
926
927         mixmonitor->name = ast_strdup(ast_channel_name(chan));
928
929         if (!ast_strlen_zero(postprocess2)) {
930                 mixmonitor->post_process = ast_strdup(postprocess2);
931         }
932
933         if (!ast_strlen_zero(recipients)) {
934                 char callerid[256];
935                 struct ast_party_connected_line *connected;
936
937                 ast_channel_lock(chan);
938
939                 /* We use the connected line of the invoking channel for caller ID. */
940
941                 connected = ast_channel_connected(chan);
942                 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
943                         connected->id.name.str, connected->id.number.valid,
944                         connected->id.number.str);
945                 ast_callerid_merge(callerid, sizeof(callerid),
946                         S_COR(connected->id.name.valid, connected->id.name.str, NULL),
947                         S_COR(connected->id.number.valid, connected->id.number.str, NULL),
948                         "Unknown");
949
950                 ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
951                 ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
952                 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
953                 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
954                 ast_string_field_set(mixmonitor, call_callerid, callerid);
955                 mixmonitor->call_priority = ast_channel_priority(chan);
956
957                 ast_channel_unlock(chan);
958
959                 add_vm_recipients_from_string(mixmonitor, recipients);
960         }
961
962         ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
963
964         if (readvol)
965                 mixmonitor->audiohook.options.read_volume = readvol;
966         if (writevol)
967                 mixmonitor->audiohook.options.write_volume = writevol;
968
969         if (startmon(chan, &mixmonitor->audiohook)) {
970                 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
971                         mixmonitor_spy_type, ast_channel_name(chan));
972                 ast_audiohook_destroy(&mixmonitor->audiohook);
973                 mixmonitor_free(mixmonitor);
974                 return -1;
975         }
976
977         /* reference be released at mixmonitor destruction */
978         mixmonitor->callid = ast_read_threadstorage_callid();
979
980         return ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
981 }
982
983 /* a note on filename_parse: creates directory structure and assigns absolute path from relative paths for filenames */
984 /* requires immediate copying of string from return to retain data since otherwise it will immediately lose scope */
985 static char *filename_parse(char *filename, char *buffer, size_t len)
986 {
987         char *slash;
988         if (ast_strlen_zero(filename)) {
989                 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
990         } else if (filename[0] != '/') {
991                 char *build;
992                 build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
993                 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
994                 filename = build;
995         }
996
997         ast_copy_string(buffer, filename, len);
998
999         if ((slash = strrchr(filename, '/'))) {
1000                 *slash = '\0';
1001         }
1002         ast_mkdir(filename, 0777);
1003
1004         return buffer;
1005 }
1006
1007 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
1008 {
1009         int x, readvol = 0, writevol = 0;
1010         char *filename_read = NULL;
1011         char *filename_write = NULL;
1012         char filename_buffer[1024] = "";
1013         char *uid_channel_var = NULL;
1014         char beep_id[64] = "";
1015
1016         struct ast_flags flags = { 0 };
1017         char *recipients = NULL;
1018         char *parse;
1019         AST_DECLARE_APP_ARGS(args,
1020                 AST_APP_ARG(filename);
1021                 AST_APP_ARG(options);
1022                 AST_APP_ARG(post_process);
1023         );
1024
1025         if (ast_strlen_zero(data)) {
1026                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1027                 return -1;
1028         }
1029
1030         parse = ast_strdupa(data);
1031
1032         AST_STANDARD_APP_ARGS(args, parse);
1033
1034         if (args.options) {
1035                 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1036
1037                 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
1038
1039                 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
1040                         if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
1041                                 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1042                         } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1043                                 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1044                         } else {
1045                                 readvol = get_volfactor(x);
1046                         }
1047                 }
1048
1049                 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
1050                         if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
1051                                 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1052                         } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1053                                 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1054                         } else {
1055                                 writevol = get_volfactor(x);
1056                         }
1057                 }
1058
1059                 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
1060                         if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1061                                 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1062                         } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1063                                 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1064                         } else {
1065                                 readvol = writevol = get_volfactor(x);
1066                         }
1067                 }
1068
1069                 if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) {
1070                         if (ast_strlen_zero(opts[OPT_ARG_VMRECIPIENTS])) {
1071                                 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1072                         } else {
1073                                 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1074                         }
1075                 }
1076
1077                 if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
1078                         filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1079                 }
1080
1081                 if (ast_test_flag(&flags, MUXFLAG_READ)) {
1082                         filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1083                 }
1084
1085                 if (ast_test_flag(&flags, MUXFLAG_UID)) {
1086                         uid_channel_var = opts[OPT_ARG_UID];
1087                 }
1088
1089                 if (ast_test_flag(&flags, MUXFLAG_BEEP)) {
1090                         const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1091                         unsigned int interval = 15;
1092
1093                         if (sscanf(interval_str, "%30u", &interval) != 1) {
1094                                 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1095                                                 interval_str, interval);
1096                         }
1097
1098                         if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1099                                 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1100                                 return -1;
1101                         }
1102                 }
1103         }
1104         /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1105
1106         if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
1107                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1108                 return -1;
1109         }
1110
1111         /* If filename exists, try to create directories for it */
1112         if (!(ast_strlen_zero(args.filename))) {
1113                 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1114         }
1115
1116         pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1117
1118         /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1119         ast_module_ref(ast_module_info->self);
1120         if (launch_monitor_thread(chan,
1121                         args.filename,
1122                         flags.flags,
1123                         readvol,
1124                         writevol,
1125                         args.post_process,
1126                         filename_write,
1127                         filename_read,
1128                         uid_channel_var,
1129                         recipients,
1130                         beep_id)) {
1131                 ast_module_unref(ast_module_info->self);
1132         }
1133
1134         return 0;
1135 }
1136
1137 static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
1138 {
1139         struct ast_datastore *datastore = NULL;
1140         char *parse = "";
1141         struct mixmonitor_ds *mixmonitor_ds;
1142         const char *beep_id = NULL;
1143
1144         AST_DECLARE_APP_ARGS(args,
1145                 AST_APP_ARG(mixmonid);
1146         );
1147
1148         if (!ast_strlen_zero(data)) {
1149                 parse = ast_strdupa(data);
1150         }
1151
1152         AST_STANDARD_APP_ARGS(args, parse);
1153
1154         ast_channel_lock(chan);
1155
1156         datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info,
1157                 S_OR(args.mixmonid, NULL));
1158         if (!datastore) {
1159                 ast_channel_unlock(chan);
1160                 return -1;
1161         }
1162         mixmonitor_ds = datastore->data;
1163
1164         ast_mutex_lock(&mixmonitor_ds->lock);
1165
1166         /* closing the filestream here guarantees the file is available to the dialplan
1167          * after calling StopMixMonitor */
1168         mixmonitor_ds_close_fs(mixmonitor_ds);
1169
1170         /* The mixmonitor thread may be waiting on the audiohook trigger.
1171          * In order to exit from the mixmonitor loop before waiting on channel
1172          * destruction, poke the audiohook trigger. */
1173         if (mixmonitor_ds->audiohook) {
1174                 if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
1175                         ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
1176                 }
1177                 ast_audiohook_lock(mixmonitor_ds->audiohook);
1178                 ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
1179                 ast_audiohook_unlock(mixmonitor_ds->audiohook);
1180                 mixmonitor_ds->audiohook = NULL;
1181         }
1182
1183         if (!ast_strlen_zero(mixmonitor_ds->beep_id)) {
1184                 beep_id = ast_strdupa(mixmonitor_ds->beep_id);
1185         }
1186
1187         ast_mutex_unlock(&mixmonitor_ds->lock);
1188
1189         /* Remove the datastore so the monitor thread can exit */
1190         if (!ast_channel_datastore_remove(chan, datastore)) {
1191                 ast_datastore_free(datastore);
1192         }
1193
1194         ast_channel_unlock(chan);
1195
1196         if (!ast_strlen_zero(beep_id)) {
1197                 ast_beep_stop(chan, beep_id);
1198         }
1199
1200         return 0;
1201 }
1202
1203 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
1204 {
1205         stop_mixmonitor_full(chan, data);
1206         return 0;
1207 }
1208
1209 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1210 {
1211         struct ast_channel *chan;
1212         struct ast_datastore *datastore = NULL;
1213         struct mixmonitor_ds *mixmonitor_ds = NULL;
1214
1215         switch (cmd) {
1216         case CLI_INIT:
1217                 e->command = "mixmonitor {start|stop|list}";
1218                 e->usage =
1219                         "Usage: mixmonitor start <chan_name> [args]\n"
1220                         "         The optional arguments are passed to the MixMonitor application.\n"
1221                         "       mixmonitor stop <chan_name> [args]\n"
1222                         "         The optional arguments are passed to the StopMixMonitor application.\n"
1223                         "       mixmonitor list <chan_name>\n";
1224                 return NULL;
1225         case CLI_GENERATE:
1226                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1227         }
1228
1229         if (a->argc < 3) {
1230                 return CLI_SHOWUSAGE;
1231         }
1232
1233         if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1234                 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1235                 /* Technically this is a failure, but we don't want 2 errors printing out */
1236                 return CLI_SUCCESS;
1237         }
1238
1239         if (!strcasecmp(a->argv[1], "start")) {
1240                 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1241         } else if (!strcasecmp(a->argv[1], "stop")){
1242                 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1243         } else if (!strcasecmp(a->argv[1], "list")) {
1244                 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1245                 ast_cli(a->fd, "=========================================================================\n");
1246                 ast_channel_lock(chan);
1247                 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1248                         if (datastore->info == &mixmonitor_ds_info) {
1249                                 char *filename = "";
1250                                 char *filename_read = "";
1251                                 char *filename_write = "";
1252
1253                                 mixmonitor_ds = datastore->data;
1254                                 if (mixmonitor_ds->fs) {
1255                                         filename = mixmonitor_ds->fs->filename;
1256                                 }
1257                                 if (mixmonitor_ds->fs_read) {
1258                                         filename_read = mixmonitor_ds->fs_read->filename;
1259                                 }
1260                                 if (mixmonitor_ds->fs_write) {
1261                                         filename_write = mixmonitor_ds->fs_write->filename;
1262                                 }
1263                                 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1264                         }
1265                 }
1266                 ast_channel_unlock(chan);
1267         } else {
1268                 chan = ast_channel_unref(chan);
1269                 return CLI_SHOWUSAGE;
1270         }
1271
1272         chan = ast_channel_unref(chan);
1273
1274         return CLI_SUCCESS;
1275 }
1276
1277 /*! \brief  Mute / unmute  a MixMonitor channel */
1278 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
1279 {
1280         struct ast_channel *c;
1281         const char *name = astman_get_header(m, "Channel");
1282         const char *id = astman_get_header(m, "ActionID");
1283         const char *state = astman_get_header(m, "State");
1284         const char *direction = astman_get_header(m,"Direction");
1285         int clearmute = 1;
1286         enum ast_audiohook_flags flag;
1287
1288         if (ast_strlen_zero(direction)) {
1289                 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1290                 return AMI_SUCCESS;
1291         }
1292
1293         if (!strcasecmp(direction, "read")) {
1294                 flag = AST_AUDIOHOOK_MUTE_READ;
1295         } else  if (!strcasecmp(direction, "write")) {
1296                 flag = AST_AUDIOHOOK_MUTE_WRITE;
1297         } else  if (!strcasecmp(direction, "both")) {
1298                 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
1299         } else {
1300                 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1301                 return AMI_SUCCESS;
1302         }
1303
1304         if (ast_strlen_zero(name)) {
1305                 astman_send_error(s, m, "No channel specified");
1306                 return AMI_SUCCESS;
1307         }
1308
1309         if (ast_strlen_zero(state)) {
1310                 astman_send_error(s, m, "No state specified");
1311                 return AMI_SUCCESS;
1312         }
1313
1314         clearmute = ast_false(state);
1315
1316         c = ast_channel_get_by_name(name);
1317         if (!c) {
1318                 astman_send_error(s, m, "No such channel");
1319                 return AMI_SUCCESS;
1320         }
1321
1322         if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
1323                 ast_channel_unref(c);
1324                 astman_send_error(s, m, "Cannot set mute flag");
1325                 return AMI_SUCCESS;
1326         }
1327
1328         astman_append(s, "Response: Success\r\n");
1329
1330         if (!ast_strlen_zero(id)) {
1331                 astman_append(s, "ActionID: %s\r\n", id);
1332         }
1333
1334         astman_append(s, "\r\n");
1335
1336         ast_channel_unref(c);
1337
1338         return AMI_SUCCESS;
1339 }
1340
1341 static int start_mixmonitor_callback(struct ast_channel *chan, const char *filename, const char *options)
1342 {
1343         char args[PATH_MAX];
1344
1345         if (ast_strlen_zero(options)) {
1346                 snprintf(args, sizeof(args), "%s", filename);
1347         } else {
1348                 snprintf(args, sizeof(args), "%s,%s", filename, options);
1349         }
1350
1351         return mixmonitor_exec(chan, args);
1352 }
1353
1354 static int stop_mixmonitor_callback(struct ast_channel *chan, const char *mixmonitor_id)
1355 {
1356         return stop_mixmonitor_full(chan, mixmonitor_id);
1357 }
1358
1359 static int manager_mixmonitor(struct mansession *s, const struct message *m)
1360 {
1361         struct ast_channel *c;
1362         const char *name = astman_get_header(m, "Channel");
1363         const char *id = astman_get_header(m, "ActionID");
1364         const char *file = astman_get_header(m, "File");
1365         const char *options = astman_get_header(m, "Options");
1366         const char *command = astman_get_header(m, "Command");
1367         char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1368         struct ast_flags flags = { 0 };
1369         char *uid_channel_var = NULL;
1370         const char *mixmonitor_id = NULL;
1371         int res;
1372         char args[PATH_MAX];
1373
1374         if (ast_strlen_zero(name)) {
1375                 astman_send_error(s, m, "No channel specified");
1376                 return AMI_SUCCESS;
1377         }
1378
1379         c = ast_channel_get_by_name(name);
1380         if (!c) {
1381                 astman_send_error(s, m, "No such channel");
1382                 return AMI_SUCCESS;
1383         }
1384
1385         if (!ast_strlen_zero(options)) {
1386                 ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
1387         }
1388
1389         snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1390
1391         res = mixmonitor_exec(c, args);
1392
1393         if (ast_test_flag(&flags, MUXFLAG_UID)) {
1394                 uid_channel_var = opts[OPT_ARG_UID];
1395                 ast_channel_lock(c);
1396                 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1397                 mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1398                 ast_channel_unlock(c);
1399         }
1400
1401         if (res) {
1402                 ast_channel_unref(c);
1403                 astman_send_error(s, m, "Could not start monitoring channel");
1404                 return AMI_SUCCESS;
1405         }
1406
1407         astman_append(s, "Response: Success\r\n");
1408
1409         if (!ast_strlen_zero(id)) {
1410                 astman_append(s, "ActionID: %s\r\n", id);
1411         }
1412
1413         if (!ast_strlen_zero(mixmonitor_id)) {
1414                 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1415         }
1416
1417         astman_append(s, "\r\n");
1418
1419         ast_channel_unref(c);
1420
1421         return AMI_SUCCESS;
1422 }
1423
1424 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
1425 {
1426         struct ast_channel *c;
1427         const char *name = astman_get_header(m, "Channel");
1428         const char *id = astman_get_header(m, "ActionID");
1429         const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1430         int res;
1431
1432         if (ast_strlen_zero(name)) {
1433                 astman_send_error(s, m, "No channel specified");
1434                 return AMI_SUCCESS;
1435         }
1436
1437         c = ast_channel_get_by_name(name);
1438         if (!c) {
1439                 astman_send_error(s, m, "No such channel");
1440                 return AMI_SUCCESS;
1441         }
1442
1443         res = stop_mixmonitor_full(c, mixmonitor_id);
1444         if (res) {
1445                 ast_channel_unref(c);
1446                 astman_send_error(s, m, "Could not stop monitoring channel");
1447                 return AMI_SUCCESS;
1448         }
1449
1450         astman_append(s, "Response: Success\r\n");
1451
1452         if (!ast_strlen_zero(id)) {
1453                 astman_append(s, "ActionID: %s\r\n", id);
1454         }
1455
1456         astman_append(s, "\r\n");
1457
1458         ast_channel_unref(c);
1459
1460         return AMI_SUCCESS;
1461 }
1462
1463 static int func_mixmonitor_read(struct ast_channel *chan, const char *cmd, char *data,
1464                 char *buf, size_t len)
1465 {
1466         struct ast_datastore *datastore;
1467         struct mixmonitor_ds *ds_data;
1468         AST_DECLARE_APP_ARGS(args,
1469                 AST_APP_ARG(id);
1470                 AST_APP_ARG(key);
1471         );
1472
1473         AST_STANDARD_APP_ARGS(args, data);
1474
1475         if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1476                 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1477                                 "An ID and key must be provided\n", cmd);
1478                 return -1;
1479         }
1480
1481         ast_channel_lock(chan);
1482         datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1483         ast_channel_unlock(chan);
1484
1485         if (!datastore) {
1486                 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1487                 return -1;
1488         }
1489
1490         ds_data = datastore->data;
1491
1492         if (!strcasecmp(args.key, "filename")) {
1493                 ast_copy_string(buf, ds_data->filename, len);
1494         } else {
1495                 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1496                 return -1;
1497         }
1498         return 0;
1499 }
1500
1501 static struct ast_custom_function mixmonitor_function = {
1502         .name = "MIXMONITOR",
1503         .read = func_mixmonitor_read,
1504 };
1505
1506 static struct ast_cli_entry cli_mixmonitor[] = {
1507         AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1508 };
1509
1510 static int set_mixmonitor_methods(void)
1511 {
1512         struct ast_mixmonitor_methods mixmonitor_methods = {
1513                 .start = start_mixmonitor_callback,
1514                 .stop = stop_mixmonitor_callback,
1515         };
1516
1517         return ast_set_mixmonitor_methods(&mixmonitor_methods);
1518 }
1519
1520 static int clear_mixmonitor_methods(void)
1521 {
1522         return ast_clear_mixmonitor_methods();
1523 }
1524
1525 static int unload_module(void)
1526 {
1527         int res;
1528
1529         ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1530         res = ast_unregister_application(stop_app);
1531         res |= ast_unregister_application(app);
1532         res |= ast_manager_unregister("MixMonitorMute");
1533         res |= ast_manager_unregister("MixMonitor");
1534         res |= ast_manager_unregister("StopMixMonitor");
1535         res |= ast_custom_function_unregister(&mixmonitor_function);
1536         res |= clear_mixmonitor_methods();
1537
1538         return res;
1539 }
1540
1541 static int load_module(void)
1542 {
1543         int res;
1544
1545         ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1546         res = ast_register_application_xml(app, mixmonitor_exec);
1547         res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
1548         res |= ast_manager_register_xml("MixMonitorMute", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, manager_mute_mixmonitor);
1549         res |= ast_manager_register_xml("MixMonitor", EVENT_FLAG_SYSTEM, manager_mixmonitor);
1550         res |= ast_manager_register_xml("StopMixMonitor", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, manager_stop_mixmonitor);
1551         res |= ast_custom_function_register(&mixmonitor_function);
1552         res |= set_mixmonitor_methods();
1553
1554         return res;
1555 }
1556
1557 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");