cf7b935185320bef8fff7e50ae01a6eaf72bf47f
[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         ast_channel_lock(mixmonitor->autochan->chan);
747         if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) {
748                 ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
749         }
750         ast_channel_unlock(mixmonitor->autochan->chan);
751
752         ast_audiohook_unlock(&mixmonitor->audiohook);
753
754         ast_autochan_destroy(mixmonitor->autochan);
755
756         /* Datastore cleanup.  close the filestream and wait for ds destruction */
757         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
758         mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
759         if (!mixmonitor->mixmonitor_ds->destruction_ok) {
760                 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
761         }
762         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
763
764         /* kill the audiohook */
765         destroy_monitor_audiohook(mixmonitor);
766
767         if (mixmonitor->post_process) {
768                 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
769                 ast_safe_system(mixmonitor->post_process);
770         }
771
772         ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
773
774         if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
775                 if (ast_strlen_zero(fs_ext)) {
776                         ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
777                                 mixmonitor -> name);
778                 } else {
779                         ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
780                         copy_to_voicemail(mixmonitor, fs_ext, mixmonitor->filename);
781                 }
782                 if (!ast_strlen_zero(fs_read_ext)) {
783                         ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
784                         copy_to_voicemail(mixmonitor, fs_read_ext, mixmonitor->filename_read);
785                 }
786                 if (!ast_strlen_zero(fs_write_ext)) {
787                         ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
788                         copy_to_voicemail(mixmonitor, fs_write_ext, mixmonitor->filename_write);
789                 }
790         } else {
791                 ast_debug(3, "No recipients to forward monitor to, moving on.\n");
792         }
793
794         mixmonitor_free(mixmonitor);
795
796         ast_module_unref(ast_module_info->self);
797         return NULL;
798 }
799
800 static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
801 {
802         struct ast_datastore *datastore = NULL;
803         struct mixmonitor_ds *mixmonitor_ds;
804
805         if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
806                 return -1;
807         }
808
809         if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
810                 ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
811         }
812
813         ast_mutex_init(&mixmonitor_ds->lock);
814         ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
815
816         if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
817                 ast_mutex_destroy(&mixmonitor_ds->lock);
818                 ast_cond_destroy(&mixmonitor_ds->destruction_condition);
819                 ast_free(mixmonitor_ds);
820                 return -1;
821         }
822
823         ast_channel_lock(mixmonitor->autochan->chan);
824         if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) {
825                 ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
826         }
827         ast_channel_unlock(mixmonitor->autochan->chan);
828
829         mixmonitor_ds->samp_rate = 8000;
830         mixmonitor_ds->audiohook = &mixmonitor->audiohook;
831         mixmonitor_ds->filename = ast_strdup(mixmonitor->filename);
832         if (!ast_strlen_zero(beep_id)) {
833                 mixmonitor_ds->beep_id = ast_strdup(beep_id);
834         }
835         datastore->data = mixmonitor_ds;
836
837         ast_channel_lock(chan);
838         ast_channel_datastore_add(chan, datastore);
839         ast_channel_unlock(chan);
840
841         mixmonitor->mixmonitor_ds = mixmonitor_ds;
842         return 0;
843 }
844
845 static int launch_monitor_thread(struct ast_channel *chan, const char *filename,
846                                   unsigned int flags, int readvol, int writevol,
847                                   const char *post_process, const char *filename_write,
848                                   char *filename_read, const char *uid_channel_var,
849                                   const char *recipients, const char *beep_id)
850 {
851         pthread_t thread;
852         struct mixmonitor *mixmonitor;
853         char postprocess2[1024] = "";
854         char *datastore_id = NULL;
855
856         postprocess2[0] = 0;
857         /* If a post process system command is given attach it to the structure */
858         if (!ast_strlen_zero(post_process)) {
859                 char *p1, *p2;
860
861                 p1 = ast_strdupa(post_process);
862                 for (p2 = p1; *p2; p2++) {
863                         if (*p2 == '^' && *(p2+1) == '{') {
864                                 *p2 = '$';
865                         }
866                 }
867                 ast_channel_lock(chan);
868                 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
869                 ast_channel_unlock(chan);
870         }
871
872         /* Pre-allocate mixmonitor structure and spy */
873         if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
874                 return -1;
875         }
876
877         /* Now that the struct has been calloced, go ahead and initialize the string fields. */
878         if (ast_string_field_init(mixmonitor, 512)) {
879                 mixmonitor_free(mixmonitor);
880                 return -1;
881         }
882
883         /* Setup the actual spy before creating our thread */
884         if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
885                 mixmonitor_free(mixmonitor);
886                 return -1;
887         }
888
889         /* Copy over flags and channel name */
890         mixmonitor->flags = flags;
891         if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
892                 mixmonitor_free(mixmonitor);
893                 return -1;
894         }
895
896         if (!ast_strlen_zero(filename)) {
897                 mixmonitor->filename = ast_strdup(filename);
898         }
899
900         if (!ast_strlen_zero(filename_write)) {
901                 mixmonitor->filename_write = ast_strdup(filename_write);
902         }
903
904         if (!ast_strlen_zero(filename_read)) {
905                 mixmonitor->filename_read = ast_strdup(filename_read);
906         }
907
908         if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
909                 ast_autochan_destroy(mixmonitor->autochan);
910                 mixmonitor_free(mixmonitor);
911                 ast_free(datastore_id);
912                 return -1;
913         }
914
915         if (!ast_strlen_zero(uid_channel_var)) {
916                 if (datastore_id) {
917                         pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
918                 }
919         }
920         ast_free(datastore_id);
921
922         mixmonitor->name = ast_strdup(ast_channel_name(chan));
923
924         if (!ast_strlen_zero(postprocess2)) {
925                 mixmonitor->post_process = ast_strdup(postprocess2);
926         }
927
928         if (!ast_strlen_zero(recipients)) {
929                 char callerid[256];
930                 struct ast_party_connected_line *connected;
931
932                 ast_channel_lock(chan);
933
934                 /* We use the connected line of the invoking channel for caller ID. */
935
936                 connected = ast_channel_connected(chan);
937                 ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
938                         connected->id.name.str, connected->id.number.valid,
939                         connected->id.number.str);
940                 ast_callerid_merge(callerid, sizeof(callerid),
941                         S_COR(connected->id.name.valid, connected->id.name.str, NULL),
942                         S_COR(connected->id.number.valid, connected->id.number.str, NULL),
943                         "Unknown");
944
945                 ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
946                 ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
947                 ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
948                 ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
949                 ast_string_field_set(mixmonitor, call_callerid, callerid);
950                 mixmonitor->call_priority = ast_channel_priority(chan);
951
952                 ast_channel_unlock(chan);
953
954                 add_vm_recipients_from_string(mixmonitor, recipients);
955         }
956
957         ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
958
959         if (readvol)
960                 mixmonitor->audiohook.options.read_volume = readvol;
961         if (writevol)
962                 mixmonitor->audiohook.options.write_volume = writevol;
963
964         if (startmon(chan, &mixmonitor->audiohook)) {
965                 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
966                         mixmonitor_spy_type, ast_channel_name(chan));
967                 ast_audiohook_destroy(&mixmonitor->audiohook);
968                 mixmonitor_free(mixmonitor);
969                 return -1;
970         }
971
972         /* reference be released at mixmonitor destruction */
973         mixmonitor->callid = ast_read_threadstorage_callid();
974
975         return ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
976 }
977
978 /* a note on filename_parse: creates directory structure and assigns absolute path from relative paths for filenames */
979 /* requires immediate copying of string from return to retain data since otherwise it will immediately lose scope */
980 static char *filename_parse(char *filename, char *buffer, size_t len)
981 {
982         char *slash;
983         if (ast_strlen_zero(filename)) {
984                 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
985         } else if (filename[0] != '/') {
986                 char *build;
987                 build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
988                 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
989                 filename = build;
990         }
991
992         ast_copy_string(buffer, filename, len);
993
994         if ((slash = strrchr(filename, '/'))) {
995                 *slash = '\0';
996         }
997         ast_mkdir(filename, 0777);
998
999         return buffer;
1000 }
1001
1002 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
1003 {
1004         int x, readvol = 0, writevol = 0;
1005         char *filename_read = NULL;
1006         char *filename_write = NULL;
1007         char filename_buffer[1024] = "";
1008         char *uid_channel_var = NULL;
1009         char beep_id[64] = "";
1010
1011         struct ast_flags flags = { 0 };
1012         char *recipients = NULL;
1013         char *parse;
1014         AST_DECLARE_APP_ARGS(args,
1015                 AST_APP_ARG(filename);
1016                 AST_APP_ARG(options);
1017                 AST_APP_ARG(post_process);
1018         );
1019
1020         if (ast_strlen_zero(data)) {
1021                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
1022                 return -1;
1023         }
1024
1025         parse = ast_strdupa(data);
1026
1027         AST_STANDARD_APP_ARGS(args, parse);
1028
1029         if (args.options) {
1030                 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1031
1032                 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
1033
1034                 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
1035                         if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
1036                                 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
1037                         } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1038                                 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
1039                         } else {
1040                                 readvol = get_volfactor(x);
1041                         }
1042                 }
1043
1044                 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
1045                         if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
1046                                 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
1047                         } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1048                                 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
1049                         } else {
1050                                 writevol = get_volfactor(x);
1051                         }
1052                 }
1053
1054                 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
1055                         if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
1056                                 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
1057                         } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
1058                                 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
1059                         } else {
1060                                 readvol = writevol = get_volfactor(x);
1061                         }
1062                 }
1063
1064                 if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) {
1065                         if (ast_strlen_zero(opts[OPT_ARG_VMRECIPIENTS])) {
1066                                 ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
1067                         } else {
1068                                 recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
1069                         }
1070                 }
1071
1072                 if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
1073                         filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
1074                 }
1075
1076                 if (ast_test_flag(&flags, MUXFLAG_READ)) {
1077                         filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
1078                 }
1079
1080                 if (ast_test_flag(&flags, MUXFLAG_UID)) {
1081                         uid_channel_var = opts[OPT_ARG_UID];
1082                 }
1083
1084                 if (ast_test_flag(&flags, MUXFLAG_BEEP)) {
1085                         const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
1086                         unsigned int interval = 15;
1087
1088                         if (sscanf(interval_str, "%30u", &interval) != 1) {
1089                                 ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
1090                                                 interval_str, interval);
1091                         }
1092
1093                         if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
1094                                 ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
1095                                 return -1;
1096                         }
1097                 }
1098         }
1099         /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
1100
1101         if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
1102                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
1103                 return -1;
1104         }
1105
1106         /* If filename exists, try to create directories for it */
1107         if (!(ast_strlen_zero(args.filename))) {
1108                 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
1109         }
1110
1111         pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
1112
1113         /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
1114         ast_module_ref(ast_module_info->self);
1115         if (launch_monitor_thread(chan,
1116                         args.filename,
1117                         flags.flags,
1118                         readvol,
1119                         writevol,
1120                         args.post_process,
1121                         filename_write,
1122                         filename_read,
1123                         uid_channel_var,
1124                         recipients,
1125                         beep_id)) {
1126                 ast_module_unref(ast_module_info->self);
1127         }
1128
1129         return 0;
1130 }
1131
1132 static int stop_mixmonitor_full(struct ast_channel *chan, const char *data)
1133 {
1134         struct ast_datastore *datastore = NULL;
1135         char *parse = "";
1136         struct mixmonitor_ds *mixmonitor_ds;
1137         const char *beep_id = NULL;
1138
1139         AST_DECLARE_APP_ARGS(args,
1140                 AST_APP_ARG(mixmonid);
1141         );
1142
1143         if (!ast_strlen_zero(data)) {
1144                 parse = ast_strdupa(data);
1145         }
1146
1147         AST_STANDARD_APP_ARGS(args, parse);
1148
1149         ast_channel_lock(chan);
1150
1151         datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid);
1152         if (!datastore) {
1153                 ast_channel_unlock(chan);
1154                 return -1;
1155         }
1156         mixmonitor_ds = datastore->data;
1157
1158         ast_mutex_lock(&mixmonitor_ds->lock);
1159
1160         /* closing the filestream here guarantees the file is available to the dialplan
1161          * after calling StopMixMonitor */
1162         mixmonitor_ds_close_fs(mixmonitor_ds);
1163
1164         /* The mixmonitor thread may be waiting on the audiohook trigger.
1165          * In order to exit from the mixmonitor loop before waiting on channel
1166          * destruction, poke the audiohook trigger. */
1167         if (mixmonitor_ds->audiohook) {
1168                 if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
1169                         ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
1170                 }
1171                 ast_audiohook_lock(mixmonitor_ds->audiohook);
1172                 ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
1173                 ast_audiohook_unlock(mixmonitor_ds->audiohook);
1174                 mixmonitor_ds->audiohook = NULL;
1175         }
1176
1177         if (!ast_strlen_zero(mixmonitor_ds->beep_id)) {
1178                 beep_id = ast_strdupa(mixmonitor_ds->beep_id);
1179         }
1180
1181         ast_mutex_unlock(&mixmonitor_ds->lock);
1182
1183         /* Remove the datastore so the monitor thread can exit */
1184         if (!ast_channel_datastore_remove(chan, datastore)) {
1185                 ast_datastore_free(datastore);
1186         }
1187
1188         ast_channel_unlock(chan);
1189
1190         if (!ast_strlen_zero(beep_id)) {
1191                 ast_beep_stop(chan, beep_id);
1192         }
1193
1194         return 0;
1195 }
1196
1197 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
1198 {
1199         stop_mixmonitor_full(chan, data);
1200         return 0;
1201 }
1202
1203 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1204 {
1205         struct ast_channel *chan;
1206         struct ast_datastore *datastore = NULL;
1207         struct mixmonitor_ds *mixmonitor_ds = NULL;
1208
1209         switch (cmd) {
1210         case CLI_INIT:
1211                 e->command = "mixmonitor {start|stop|list}";
1212                 e->usage =
1213                         "Usage: mixmonitor start <chan_name> [args]\n"
1214                         "         The optional arguments are passed to the MixMonitor application.\n"
1215                         "       mixmonitor stop <chan_name> [args]\n"
1216                         "         The optional arguments are passed to the StopMixMonitor application.\n"
1217                         "       mixmonitor list <chan_name>\n";
1218                 return NULL;
1219         case CLI_GENERATE:
1220                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
1221         }
1222
1223         if (a->argc < 3) {
1224                 return CLI_SHOWUSAGE;
1225         }
1226
1227         if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
1228                 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
1229                 /* Technically this is a failure, but we don't want 2 errors printing out */
1230                 return CLI_SUCCESS;
1231         }
1232
1233         if (!strcasecmp(a->argv[1], "start")) {
1234                 mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1235         } else if (!strcasecmp(a->argv[1], "stop")){
1236                 stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
1237         } else if (!strcasecmp(a->argv[1], "list")) {
1238                 ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
1239                 ast_cli(a->fd, "=========================================================================\n");
1240                 ast_channel_lock(chan);
1241                 AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
1242                         if (datastore->info == &mixmonitor_ds_info) {
1243                                 char *filename = "";
1244                                 char *filename_read = "";
1245                                 char *filename_write = "";
1246
1247                                 mixmonitor_ds = datastore->data;
1248                                 if (mixmonitor_ds->fs) {
1249                                         filename = mixmonitor_ds->fs->filename;
1250                                 }
1251                                 if (mixmonitor_ds->fs_read) {
1252                                         filename_read = mixmonitor_ds->fs_read->filename;
1253                                 }
1254                                 if (mixmonitor_ds->fs_write) {
1255                                         filename_write = mixmonitor_ds->fs_write->filename;
1256                                 }
1257                                 ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
1258                         }
1259                 }
1260                 ast_channel_unlock(chan);
1261         } else {
1262                 chan = ast_channel_unref(chan);
1263                 return CLI_SHOWUSAGE;
1264         }
1265
1266         chan = ast_channel_unref(chan);
1267
1268         return CLI_SUCCESS;
1269 }
1270
1271 /*! \brief  Mute / unmute  a MixMonitor channel */
1272 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
1273 {
1274         struct ast_channel *c;
1275         const char *name = astman_get_header(m, "Channel");
1276         const char *id = astman_get_header(m, "ActionID");
1277         const char *state = astman_get_header(m, "State");
1278         const char *direction = astman_get_header(m,"Direction");
1279         int clearmute = 1;
1280         enum ast_audiohook_flags flag;
1281
1282         if (ast_strlen_zero(direction)) {
1283                 astman_send_error(s, m, "No direction specified. Must be read, write or both");
1284                 return AMI_SUCCESS;
1285         }
1286
1287         if (!strcasecmp(direction, "read")) {
1288                 flag = AST_AUDIOHOOK_MUTE_READ;
1289         } else  if (!strcasecmp(direction, "write")) {
1290                 flag = AST_AUDIOHOOK_MUTE_WRITE;
1291         } else  if (!strcasecmp(direction, "both")) {
1292                 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
1293         } else {
1294                 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
1295                 return AMI_SUCCESS;
1296         }
1297
1298         if (ast_strlen_zero(name)) {
1299                 astman_send_error(s, m, "No channel specified");
1300                 return AMI_SUCCESS;
1301         }
1302
1303         if (ast_strlen_zero(state)) {
1304                 astman_send_error(s, m, "No state specified");
1305                 return AMI_SUCCESS;
1306         }
1307
1308         clearmute = ast_false(state);
1309
1310         c = ast_channel_get_by_name(name);
1311         if (!c) {
1312                 astman_send_error(s, m, "No such channel");
1313                 return AMI_SUCCESS;
1314         }
1315
1316         if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
1317                 ast_channel_unref(c);
1318                 astman_send_error(s, m, "Cannot set mute flag");
1319                 return AMI_SUCCESS;
1320         }
1321
1322         astman_append(s, "Response: Success\r\n");
1323
1324         if (!ast_strlen_zero(id)) {
1325                 astman_append(s, "ActionID: %s\r\n", id);
1326         }
1327
1328         astman_append(s, "\r\n");
1329
1330         ast_channel_unref(c);
1331
1332         return AMI_SUCCESS;
1333 }
1334
1335 static int start_mixmonitor_callback(struct ast_channel *chan, const char *filename, const char *options)
1336 {
1337         char args[PATH_MAX];
1338
1339         if (ast_strlen_zero(options)) {
1340                 snprintf(args, sizeof(args), "%s", filename);
1341         } else {
1342                 snprintf(args, sizeof(args), "%s,%s", filename, options);
1343         }
1344
1345         return mixmonitor_exec(chan, args);
1346 }
1347
1348 static int stop_mixmonitor_callback(struct ast_channel *chan, const char *mixmonitor_id)
1349 {
1350         return stop_mixmonitor_full(chan, mixmonitor_id);
1351 }
1352
1353 static int manager_mixmonitor(struct mansession *s, const struct message *m)
1354 {
1355         struct ast_channel *c;
1356         const char *name = astman_get_header(m, "Channel");
1357         const char *id = astman_get_header(m, "ActionID");
1358         const char *file = astman_get_header(m, "File");
1359         const char *options = astman_get_header(m, "Options");
1360         const char *command = astman_get_header(m, "Command");
1361         char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
1362         struct ast_flags flags = { 0 };
1363         char *uid_channel_var = NULL;
1364         const char *mixmonitor_id = NULL;
1365         int res;
1366         char args[PATH_MAX];
1367
1368         if (ast_strlen_zero(name)) {
1369                 astman_send_error(s, m, "No channel specified");
1370                 return AMI_SUCCESS;
1371         }
1372
1373         c = ast_channel_get_by_name(name);
1374         if (!c) {
1375                 astman_send_error(s, m, "No such channel");
1376                 return AMI_SUCCESS;
1377         }
1378
1379         if (!ast_strlen_zero(options)) {
1380                 ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
1381         }
1382
1383         snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
1384
1385         res = mixmonitor_exec(c, args);
1386
1387         if (ast_test_flag(&flags, MUXFLAG_UID)) {
1388                 uid_channel_var = opts[OPT_ARG_UID];
1389                 ast_channel_lock(c);
1390                 mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
1391                 mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
1392                 ast_channel_unlock(c);
1393         }
1394
1395         if (res) {
1396                 ast_channel_unref(c);
1397                 astman_send_error(s, m, "Could not start monitoring channel");
1398                 return AMI_SUCCESS;
1399         }
1400
1401         astman_append(s, "Response: Success\r\n");
1402
1403         if (!ast_strlen_zero(id)) {
1404                 astman_append(s, "ActionID: %s\r\n", id);
1405         }
1406
1407         if (!ast_strlen_zero(mixmonitor_id)) {
1408                 astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
1409         }
1410
1411         astman_append(s, "\r\n");
1412
1413         ast_channel_unref(c);
1414
1415         return AMI_SUCCESS;
1416 }
1417
1418 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
1419 {
1420         struct ast_channel *c;
1421         const char *name = astman_get_header(m, "Channel");
1422         const char *id = astman_get_header(m, "ActionID");
1423         const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
1424         int res;
1425
1426         if (ast_strlen_zero(name)) {
1427                 astman_send_error(s, m, "No channel specified");
1428                 return AMI_SUCCESS;
1429         }
1430
1431         c = ast_channel_get_by_name(name);
1432         if (!c) {
1433                 astman_send_error(s, m, "No such channel");
1434                 return AMI_SUCCESS;
1435         }
1436
1437         res = stop_mixmonitor_full(c, mixmonitor_id);
1438         if (res) {
1439                 ast_channel_unref(c);
1440                 astman_send_error(s, m, "Could not stop monitoring channel");
1441                 return AMI_SUCCESS;
1442         }
1443
1444         astman_append(s, "Response: Success\r\n");
1445
1446         if (!ast_strlen_zero(id)) {
1447                 astman_append(s, "ActionID: %s\r\n", id);
1448         }
1449
1450         astman_append(s, "\r\n");
1451
1452         ast_channel_unref(c);
1453
1454         return AMI_SUCCESS;
1455 }
1456
1457 static int func_mixmonitor_read(struct ast_channel *chan, const char *cmd, char *data,
1458                 char *buf, size_t len)
1459 {
1460         struct ast_datastore *datastore;
1461         struct mixmonitor_ds *ds_data;
1462         AST_DECLARE_APP_ARGS(args,
1463                 AST_APP_ARG(id);
1464                 AST_APP_ARG(key);
1465         );
1466
1467         AST_STANDARD_APP_ARGS(args, data);
1468
1469         if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
1470                 ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
1471                                 "An ID and key must be provided\n", cmd);
1472                 return -1;
1473         }
1474
1475         ast_channel_lock(chan);
1476         datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
1477         ast_channel_unlock(chan);
1478
1479         if (!datastore) {
1480                 ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
1481                 return -1;
1482         }
1483
1484         ds_data = datastore->data;
1485
1486         if (!strcasecmp(args.key, "filename")) {
1487                 ast_copy_string(buf, ds_data->filename, len);
1488         } else {
1489                 ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
1490                 return -1;
1491         }
1492         return 0;
1493 }
1494
1495 static struct ast_custom_function mixmonitor_function = {
1496         .name = "MIXMONITOR",
1497         .read = func_mixmonitor_read,
1498 };
1499
1500 static struct ast_cli_entry cli_mixmonitor[] = {
1501         AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
1502 };
1503
1504 static int set_mixmonitor_methods(void)
1505 {
1506         struct ast_mixmonitor_methods mixmonitor_methods = {
1507                 .start = start_mixmonitor_callback,
1508                 .stop = stop_mixmonitor_callback,
1509         };
1510
1511         return ast_set_mixmonitor_methods(&mixmonitor_methods);
1512 }
1513
1514 static int clear_mixmonitor_methods(void)
1515 {
1516         return ast_clear_mixmonitor_methods();
1517 }
1518
1519 static int unload_module(void)
1520 {
1521         int res;
1522
1523         ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1524         res = ast_unregister_application(stop_app);
1525         res |= ast_unregister_application(app);
1526         res |= ast_manager_unregister("MixMonitorMute");
1527         res |= ast_manager_unregister("MixMonitor");
1528         res |= ast_manager_unregister("StopMixMonitor");
1529         res |= ast_custom_function_unregister(&mixmonitor_function);
1530         res |= clear_mixmonitor_methods();
1531
1532         return res;
1533 }
1534
1535 static int load_module(void)
1536 {
1537         int res;
1538
1539         ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1540         res = ast_register_application_xml(app, mixmonitor_exec);
1541         res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
1542         res |= ast_manager_register_xml("MixMonitorMute", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, manager_mute_mixmonitor);
1543         res |= ast_manager_register_xml("MixMonitor", EVENT_FLAG_SYSTEM, manager_mixmonitor);
1544         res |= ast_manager_register_xml("StopMixMonitor", EVENT_FLAG_SYSTEM | EVENT_FLAG_CALL, manager_stop_mixmonitor);
1545         res |= ast_custom_function_register(&mixmonitor_function);
1546         res |= set_mixmonitor_methods();
1547
1548         return res;
1549 }
1550
1551 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");