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