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