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