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