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