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