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