Replace direct access to channel name with accessor functions
[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/file.h"
46 #include "asterisk/audiohook.h"
47 #include "asterisk/pbx.h"
48 #include "asterisk/module.h"
49 #include "asterisk/cli.h"
50 #include "asterisk/app.h"
51 #include "asterisk/channel.h"
52 #include "asterisk/autochan.h"
53 #include "asterisk/manager.h"
54 #include "asterisk/mod_format.h"
55
56 /*** DOCUMENTATION
57         <application name="MixMonitor" language="en_US">
58                 <synopsis>
59                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
60                         to guarantee the audio file is available for processing during dialplan execution.
61                 </synopsis>
62                 <syntax>
63                         <parameter name="file" required="true" argsep=".">
64                                 <argument name="filename" required="true">
65                                         <para>If <replaceable>filename</replaceable> is an absolute path, uses that path, otherwise
66                                         creates the file in the configured monitoring directory from <filename>asterisk.conf.</filename></para>
67                                 </argument>
68                                 <argument name="extension" required="true" />
69                         </parameter>
70                         <parameter name="options">
71                                 <optionlist>
72                                         <option name="a">
73                                                 <para>Append to the file instead of overwriting it.</para>
74                                         </option>
75                                         <option name="b">
76                                                 <para>Only save audio to the file while the channel is bridged.</para>
77                                                 <note><para>Does not include conferences or sounds played to each bridged party</para></note>
78                                                 <note><para>If you utilize this option inside a Local channel, you must make sure the Local
79                                                 channel is not optimized away. To do this, be sure to call your Local channel with the
80                                                 <literal>/n</literal> option. For example: Dial(Local/start@mycontext/n)</para></note>
81                                         </option>
82                                         <option name="v">
83                                                 <para>Adjust the <emphasis>heard</emphasis> volume by a factor of <replaceable>x</replaceable>
84                                                 (range <literal>-4</literal> to <literal>4</literal>)</para>
85                                                 <argument name="x" required="true" />
86                                         </option>
87                                         <option name="V">
88                                                 <para>Adjust the <emphasis>spoken</emphasis> volume by a factor
89                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
90                                                 <argument name="x" required="true" />
91                                         </option>
92                                         <option name="W">
93                                                 <para>Adjust both, <emphasis>heard and spoken</emphasis> volumes by a factor
94                                                 of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
95                                                 <argument name="x" required="true" />
96                                         </option>
97                                         <option name="r">
98                                                 <argument name="file" required="true" />
99                                                 <para>Use the specified file to record the <emphasis>receive</emphasis> audio feed.
100                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
101                                                 the file in the configured monitoring directory.</para>
102
103                                         </option>
104                                         <option name="t">
105                                                 <argument name="file" required="true" />
106                                                 <para>Use the specified file to record the <emphasis>transmit</emphasis> audio feed.
107                                                 Like with the basic filename argument, if an absolute path isn't given, it will create
108                                                 the file in the configured monitoring directory.</para>
109                                         </option>
110                                 </optionlist>
111                         </parameter>
112                         <parameter name="command">
113                                 <para>Will be executed when the recording is over.</para>
114                                 <para>Any strings matching <literal>^{X}</literal> will be unescaped to <variable>X</variable>.</para>
115                                 <para>All variables will be evaluated at the time MixMonitor is called.</para>
116                         </parameter>
117                 </syntax>
118                 <description>
119                         <para>Records the audio on the current channel to the specified file.</para>
120                         <para>This application does not automatically answer and should be preceeded by
121                         an application such as Answer or Progress().</para>
122                         <variablelist>
123                                 <variable name="MIXMONITOR_FILENAME">
124                                         <para>Will contain the filename used to record.</para>
125                                 </variable>
126                         </variablelist> 
127                 </description>
128                 <see-also>
129                         <ref type="application">Monitor</ref>
130                         <ref type="application">StopMixMonitor</ref>
131                         <ref type="application">PauseMonitor</ref>
132                         <ref type="application">UnpauseMonitor</ref>
133                 </see-also>
134         </application>
135         <application name="StopMixMonitor" language="en_US">
136                 <synopsis>
137                         Stop recording a call through MixMonitor, and free the recording's file handle.
138                 </synopsis>
139                 <syntax />
140                 <description>
141                         <para>Stops the audio recording that was started with a call to <literal>MixMonitor()</literal>
142                         on the current channel.</para>
143                 </description>
144                 <see-also>
145                         <ref type="application">MixMonitor</ref>
146                 </see-also>
147         </application>
148         <manager name="MixMonitorMute" language="en_US">
149                 <synopsis>
150                         Mute / unMute a Mixmonitor recording.
151                 </synopsis>
152                 <syntax>
153                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
154                         <parameter name="Channel" required="true">
155                                 <para>Used to specify the channel to mute.</para>
156                         </parameter>
157                         <parameter name="Direction">
158                                 <para>Which part of the recording to mute:  read, write or both (from channel, to channel or both channels).</para>
159                         </parameter>
160                         <parameter name="State">
161                                 <para>Turn mute on or off : 1 to turn on, 0 to turn off.</para>
162                         </parameter>
163                 </syntax>
164                 <description>
165                         <para>This action may be used to mute a MixMonitor recording.</para>
166                 </description>
167         </manager>
168         <manager name="MixMonitor" language="en_US">
169                 <synopsis>
170                         Record a call and mix the audio during the recording.  Use of StopMixMonitor is required
171                         to guarantee the audio file is available for processing during dialplan execution.
172                 </synopsis>
173                 <syntax>
174                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
175                         <parameter name="Channel" required="true">
176                                 <para>Used to specify the channel to record.</para>
177                         </parameter>
178                         <parameter name="File">
179                                 <para>Is the name of the file created in the monitor spool directory.
180                                 Defaults to the same name as the channel (with slashes replaced with dashes).
181                                 This argument is optional if you specify to record unidirectional audio with
182                                 either the r(filename) or t(filename) options in the options field. If
183                                 neither MIXMONITOR_FILENAME or this parameter is set, the mixed stream won't
184                                 be recorded.</para>
185                         </parameter>
186                         <parameter name="options">
187                                 <para>Options that apply to the MixMonitor in the same way as they
188                                 would apply if invoked from the MixMonitor application. For a list of
189                                 available options, see the documentation for the mixmonitor application. </para>
190                         </parameter>
191                 </syntax>
192                 <description>
193                         <para>This action records the audio on the current channel to the specified file.</para>
194                         <variablelist>
195                                 <variable name="MIXMONITOR_FILENAME">
196                                         <para>Will contain the filename used to record the mixed stream.</para>
197                                 </variable>
198                         </variablelist>
199                 </description>
200         </manager>
201         <manager name="StopMixMonitor" language="en_US">
202                 <synopsis>
203                         Stop recording a call through MixMonitor, and free the recording's file handle.
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>The name of the channel monitored.</para>
209                         </parameter>
210                 </syntax>
211                 <description>
212                         <para>This action stops the audio recording that was started with the <literal>MixMonitor</literal>
213                         action on the current channel.</para>
214                 </description>
215         </manager>
216
217  ***/
218
219 #define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
220
221 static const char * const app = "MixMonitor";
222
223 static const char * const stop_app = "StopMixMonitor";
224
225 static const char * const mixmonitor_spy_type = "MixMonitor";
226
227 struct mixmonitor {
228         struct ast_audiohook audiohook;
229         char *filename;
230         char *filename_read;
231         char *filename_write;
232         char *post_process;
233         char *name;
234         unsigned int flags;
235         struct ast_autochan *autochan;
236         struct mixmonitor_ds *mixmonitor_ds;
237 };
238
239 enum mixmonitor_flags {
240         MUXFLAG_APPEND = (1 << 1),
241         MUXFLAG_BRIDGED = (1 << 2),
242         MUXFLAG_VOLUME = (1 << 3),
243         MUXFLAG_READVOLUME = (1 << 4),
244         MUXFLAG_WRITEVOLUME = (1 << 5),
245         MUXFLAG_READ = (1 << 6),
246         MUXFLAG_WRITE = (1 << 7),
247         MUXFLAG_COMBINED = (1 << 8),
248 };
249
250 enum mixmonitor_args {
251         OPT_ARG_READVOLUME = 0,
252         OPT_ARG_WRITEVOLUME,
253         OPT_ARG_VOLUME,
254         OPT_ARG_WRITENAME,
255         OPT_ARG_READNAME,
256         OPT_ARG_ARRAY_SIZE,     /* Always last element of the enum */
257 };
258
259 AST_APP_OPTIONS(mixmonitor_opts, {
260         AST_APP_OPTION('a', MUXFLAG_APPEND),
261         AST_APP_OPTION('b', MUXFLAG_BRIDGED),
262         AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME),
263         AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME),
264         AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),
265         AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
266         AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
267 });
268
269 struct mixmonitor_ds {
270         unsigned int destruction_ok;
271         ast_cond_t destruction_condition;
272         ast_mutex_t lock;
273
274         /* The filestream is held in the datastore so it can be stopped
275          * immediately during stop_mixmonitor or channel destruction. */
276         int fs_quit;
277
278         struct ast_filestream *fs;
279         struct ast_filestream *fs_read;
280         struct ast_filestream *fs_write;
281
282         struct ast_audiohook *audiohook;
283
284         unsigned int samp_rate;
285 };
286
287 /*!
288  * \internal
289  * \pre mixmonitor_ds must be locked before calling this function
290  */
291 static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
292 {
293         unsigned char quitting = 0;
294
295         if (mixmonitor_ds->fs) {
296                 quitting = 1;
297                 ast_closestream(mixmonitor_ds->fs);
298                 mixmonitor_ds->fs = NULL;
299                 ast_verb(2, "MixMonitor close filestream (mixed)\n");
300         }
301
302         if (mixmonitor_ds->fs_read) {
303                 quitting = 1;
304                 ast_closestream(mixmonitor_ds->fs_read);
305                 mixmonitor_ds->fs_read = NULL;
306                 ast_verb(2, "MixMonitor close filestream (read)\n");
307         }
308
309         if (mixmonitor_ds->fs_write) {
310                 quitting = 1;
311                 ast_closestream(mixmonitor_ds->fs_write);
312                 mixmonitor_ds->fs_write = NULL;
313                 ast_verb(2, "MixMonitor close filestream (write)\n");
314         }
315
316         if (quitting) {
317                 mixmonitor_ds->fs_quit = 1;
318         }
319 }
320
321 static void mixmonitor_ds_destroy(void *data)
322 {
323         struct mixmonitor_ds *mixmonitor_ds = data;
324
325         ast_mutex_lock(&mixmonitor_ds->lock);
326         mixmonitor_ds->audiohook = NULL;
327         mixmonitor_ds->destruction_ok = 1;
328         ast_cond_signal(&mixmonitor_ds->destruction_condition);
329         ast_mutex_unlock(&mixmonitor_ds->lock);
330 }
331
332 static struct ast_datastore_info mixmonitor_ds_info = {
333         .type = "mixmonitor",
334         .destroy = mixmonitor_ds_destroy,
335 };
336
337 static void destroy_monitor_audiohook(struct mixmonitor *mixmonitor)
338 {
339         if (mixmonitor->mixmonitor_ds) {
340                 ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
341                 mixmonitor->mixmonitor_ds->audiohook = NULL;
342                 ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
343         }
344         /* kill the audiohook.*/
345         ast_audiohook_lock(&mixmonitor->audiohook);
346         ast_audiohook_detach(&mixmonitor->audiohook);
347         ast_audiohook_unlock(&mixmonitor->audiohook);
348         ast_audiohook_destroy(&mixmonitor->audiohook);
349 }
350
351 static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook) 
352 {
353         struct ast_channel *peer = NULL;
354         int res = 0;
355
356         if (!chan)
357                 return -1;
358
359         ast_audiohook_attach(chan, audiohook);
360
361         if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
362                 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
363
364         return res;
365 }
366
367 #define SAMPLES_PER_FRAME 160
368
369 static void mixmonitor_free(struct mixmonitor *mixmonitor)
370 {
371         if (mixmonitor) {
372                 if (mixmonitor->mixmonitor_ds) {
373                         ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
374                         ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
375                         ast_free(mixmonitor->filename_write);
376                         ast_free(mixmonitor->filename_read);
377                         ast_free(mixmonitor->mixmonitor_ds);
378                         ast_free(mixmonitor->name);
379                         ast_free(mixmonitor->post_process);
380                 }
381                 ast_free(mixmonitor);
382         }
383 }
384
385 static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag)
386 {
387         /* Initialize the file if not already done so */
388         char *ext = NULL;
389         char *last_slash = NULL;
390         if (!ast_strlen_zero(filename)) {
391                 if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
392                         *oflags = O_CREAT | O_WRONLY;
393                         *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
394
395                         last_slash = strrchr(filename, '/');
396
397                         if ((ext = strrchr(filename, '.')) && (ext > last_slash)) {
398                                 *(ext++) = '\0';
399                         } else {
400                                 ext = "raw";
401                         }
402
403                         if (!(*fs = ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) {
404                                 ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext);
405                                 *errflag = 1;
406                         } else {
407                                 struct ast_filestream *tmp = *fs;
408                                 mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
409                         }
410                 }
411         }
412 }
413
414 static void *mixmonitor_thread(void *obj) 
415 {
416         struct mixmonitor *mixmonitor = obj;
417
418         struct ast_filestream **fs = NULL;
419         struct ast_filestream **fs_read = NULL;
420         struct ast_filestream **fs_write = NULL;
421
422         unsigned int oflags;
423         int errflag = 0;
424         struct ast_format format_slin;
425
426         ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
427
428         fs = &mixmonitor->mixmonitor_ds->fs;
429         fs_read = &mixmonitor->mixmonitor_ds->fs_read;
430         fs_write = &mixmonitor->mixmonitor_ds->fs_write;
431
432         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
433         mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
434         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
435         mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);
436
437         ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);
438
439         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
440
441
442         /* The audiohook must enter and exit the loop locked */
443         ast_audiohook_lock(&mixmonitor->audiohook);
444         while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
445                 struct ast_frame *fr = NULL;
446                 struct ast_frame *fr_read = NULL;
447                 struct ast_frame *fr_write = NULL;
448
449                 if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
450                                                 &fr_read, &fr_write))) {
451                         ast_audiohook_trigger_wait(&mixmonitor->audiohook);
452
453                         if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
454                                 break;
455                         }
456                         continue;
457                 }
458
459                 /* audiohook lock is not required for the next block.
460                  * Unlock it, but remember to lock it before looping or exiting */
461                 ast_audiohook_unlock(&mixmonitor->audiohook);
462
463                 if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
464                         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
465
466                         /* Write out the frame(s) */
467                         if ((*fs_read) && (fr_read)) {
468                                 struct ast_frame *cur;
469
470                                 for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
471                                         ast_writestream(*fs_read, cur);
472                                 }
473                         }
474
475                         if ((*fs_write) && (fr_write)) {
476                                 struct ast_frame *cur;
477
478                                 for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
479                                         ast_writestream(*fs_write, cur);
480                                 }
481                         }
482
483                         if ((*fs) && (fr)) {
484                                 struct ast_frame *cur;
485
486                                 for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
487                                         ast_writestream(*fs, cur);
488                                 }
489                         }
490                         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
491                 }
492                 /* All done! free it. */
493                 if (fr) {
494                         ast_frame_free(fr, 0);
495                 }
496                 if (fr_read) {
497                         ast_frame_free(fr_read, 0);
498                 }
499                 if (fr_write) {
500                         ast_frame_free(fr_write, 0);
501                 }
502
503                 fr = NULL;
504                 fr_write = NULL;
505                 fr_read = NULL;
506
507                 ast_audiohook_lock(&mixmonitor->audiohook);
508         }
509         ast_audiohook_unlock(&mixmonitor->audiohook);
510
511         ast_autochan_destroy(mixmonitor->autochan);
512
513         /* Datastore cleanup.  close the filestream and wait for ds destruction */
514         ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
515         mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
516         if (!mixmonitor->mixmonitor_ds->destruction_ok) {
517                 ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
518         }
519         ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
520
521         /* kill the audiohook */
522         destroy_monitor_audiohook(mixmonitor);
523
524         if (mixmonitor->post_process) {
525                 ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
526                 ast_safe_system(mixmonitor->post_process);
527         }
528
529         ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
530         mixmonitor_free(mixmonitor);
531         return NULL;
532 }
533
534 static int setup_mixmonitor_ds(struct mixmonitor *mixmonitor, struct ast_channel *chan)
535 {
536         struct ast_datastore *datastore = NULL;
537         struct mixmonitor_ds *mixmonitor_ds;
538
539         if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
540                 return -1;
541         }
542
543         ast_mutex_init(&mixmonitor_ds->lock);
544         ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
545
546         if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
547                 ast_mutex_destroy(&mixmonitor_ds->lock);
548                 ast_cond_destroy(&mixmonitor_ds->destruction_condition);
549                 ast_free(mixmonitor_ds);
550                 return -1;
551         }
552
553
554         mixmonitor_ds->samp_rate = 8000;
555         mixmonitor_ds->audiohook = &mixmonitor->audiohook;
556         datastore->data = mixmonitor_ds;
557
558         ast_channel_lock(chan);
559         ast_channel_datastore_add(chan, datastore);
560         ast_channel_unlock(chan);
561
562         mixmonitor->mixmonitor_ds = mixmonitor_ds;
563         return 0;
564 }
565
566 static void launch_monitor_thread(struct ast_channel *chan, const char *filename,
567                                   unsigned int flags, int readvol, int writevol,
568                                   const char *post_process, const char *filename_write,
569                                   const char *filename_read) 
570 {
571         pthread_t thread;
572         struct mixmonitor *mixmonitor;
573         char postprocess2[1024] = "";
574
575         postprocess2[0] = 0;
576         /* If a post process system command is given attach it to the structure */
577         if (!ast_strlen_zero(post_process)) {
578                 char *p1, *p2;
579
580                 p1 = ast_strdupa(post_process);
581                 for (p2 = p1; *p2; p2++) {
582                         if (*p2 == '^' && *(p2+1) == '{') {
583                                 *p2 = '$';
584                         }
585                 }
586                 pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
587         }
588
589         /* Pre-allocate mixmonitor structure and spy */
590         if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
591                 return;
592         }
593
594         /* Setup the actual spy before creating our thread */
595         if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
596                 mixmonitor_free(mixmonitor);
597                 return;
598         }
599
600         /* Copy over flags and channel name */
601         mixmonitor->flags = flags;
602         if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
603                 mixmonitor_free(mixmonitor);
604                 return;
605         }
606
607         if (setup_mixmonitor_ds(mixmonitor, chan)) {
608                 ast_autochan_destroy(mixmonitor->autochan);
609                 mixmonitor_free(mixmonitor);
610                 return;
611         }
612
613         mixmonitor->name = ast_strdup(ast_channel_name(chan));
614
615         if (!ast_strlen_zero(postprocess2)) {
616                 mixmonitor->post_process = ast_strdup(postprocess2);
617         }
618
619         if (!ast_strlen_zero(filename)) {
620                 mixmonitor->filename = ast_strdup(filename);
621         }
622
623         if (!ast_strlen_zero(filename_write)) {
624                 mixmonitor->filename_write = ast_strdup(filename_write);
625         }
626
627         if (!ast_strlen_zero(filename_read)) {
628                 mixmonitor->filename_read = ast_strdup(filename_read);
629         }
630
631         ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
632
633         if (readvol)
634                 mixmonitor->audiohook.options.read_volume = readvol;
635         if (writevol)
636                 mixmonitor->audiohook.options.write_volume = writevol;
637
638         if (startmon(chan, &mixmonitor->audiohook)) {
639                 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
640                         mixmonitor_spy_type, ast_channel_name(chan));
641                 ast_audiohook_destroy(&mixmonitor->audiohook);
642                 mixmonitor_free(mixmonitor);
643                 return;
644         }
645
646         ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
647 }
648
649 /* a note on filename_parse: creates directory structure and assigns absolute path from relative paths for filenames */
650 /* requires immediate copying of string from return to retain data since otherwise it will immediately lose scope */
651 static char *filename_parse(char *filename, char *buffer, size_t len)
652 {
653         char *slash;
654         if (ast_strlen_zero(filename)) {
655                 ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
656         } else if (filename[0] != '/') {
657                 char *build;
658                 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
659                 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
660                 filename = build;
661         }
662
663         ast_copy_string(buffer, filename, len);
664
665         if ((slash = strrchr(filename, '/'))) {
666                 *slash = '\0';
667         }
668         ast_mkdir(filename, 0777);
669
670         return buffer;
671 }
672
673 static int mixmonitor_exec(struct ast_channel *chan, const char *data)
674 {
675         int x, readvol = 0, writevol = 0;
676         char *filename_read = NULL;
677         char *filename_write = NULL;
678         char filename_buffer[1024] = "";
679
680         struct ast_flags flags = { 0 };
681         char *parse;
682         AST_DECLARE_APP_ARGS(args,
683                 AST_APP_ARG(filename);
684                 AST_APP_ARG(options);
685                 AST_APP_ARG(post_process);
686         );
687         
688         if (ast_strlen_zero(data)) {
689                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
690                 return -1;
691         }
692
693         parse = ast_strdupa(data);
694
695         AST_STANDARD_APP_ARGS(args, parse);
696
697         if (args.options) {
698                 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
699
700                 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
701
702                 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
703                         if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
704                                 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
705                         } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
706                                 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
707                         } else {
708                                 readvol = get_volfactor(x);
709                         }
710                 }
711                 
712                 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
713                         if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
714                                 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
715                         } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
716                                 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
717                         } else {
718                                 writevol = get_volfactor(x);
719                         }
720                 }
721                 
722                 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
723                         if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
724                                 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
725                         } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
726                                 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
727                         } else {
728                                 readvol = writevol = get_volfactor(x);
729                         }
730                 }
731
732                 if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
733                         filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
734                 }
735
736                 if (ast_test_flag(&flags, MUXFLAG_READ)) {
737                         filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
738                 }
739         }
740
741         /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
742
743         if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
744                 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
745                 return -1;
746         }
747
748         /* If filename exists, try to create directories for it */
749         if (!(ast_strlen_zero(args.filename))) {
750                 args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
751         }
752
753         pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
754         launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, filename_write, filename_read);
755
756         return 0;
757 }
758
759 static int stop_mixmonitor_exec(struct ast_channel *chan, const char *data)
760 {
761         struct ast_datastore *datastore = NULL;
762
763         ast_channel_lock(chan);
764         ast_audiohook_detach_source(chan, mixmonitor_spy_type);
765         if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
766                 struct mixmonitor_ds *mixmonitor_ds = datastore->data;
767
768                 ast_mutex_lock(&mixmonitor_ds->lock);
769
770                 /* closing the filestream here guarantees the file is avaliable to the dialplan
771                  * after calling StopMixMonitor */
772                 mixmonitor_ds_close_fs(mixmonitor_ds);
773
774                 /* The mixmonitor thread may be waiting on the audiohook trigger.
775                  * In order to exit from the mixmonitor loop before waiting on channel
776                  * destruction, poke the audiohook trigger. */
777                 if (mixmonitor_ds->audiohook) {
778                         ast_audiohook_lock(mixmonitor_ds->audiohook);
779                         ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
780                         ast_audiohook_unlock(mixmonitor_ds->audiohook);
781                         mixmonitor_ds->audiohook = NULL;
782                 }
783
784                 ast_mutex_unlock(&mixmonitor_ds->lock);
785
786                 /* Remove the datastore so the monitor thread can exit */
787                 if (!ast_channel_datastore_remove(chan, datastore)) {
788                         ast_datastore_free(datastore);
789                 }
790         }
791         ast_channel_unlock(chan);
792
793         return 0;
794 }
795
796 static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
797 {
798         struct ast_channel *chan;
799
800         switch (cmd) {
801         case CLI_INIT:
802                 e->command = "mixmonitor {start|stop}";
803                 e->usage =
804                         "Usage: mixmonitor <start|stop> <chan_name> [args]\n"
805                         "       The optional arguments are passed to the MixMonitor\n"
806                         "       application when the 'start' command is used.\n";
807                 return NULL;
808         case CLI_GENERATE:
809                 return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
810         }
811
812         if (a->argc < 3)
813                 return CLI_SHOWUSAGE;
814
815         if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
816                 ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
817                 /* Technically this is a failure, but we don't want 2 errors printing out */
818                 return CLI_SUCCESS;
819         }
820
821         ast_channel_lock(chan);
822
823         if (!strcasecmp(a->argv[1], "start")) {
824                 mixmonitor_exec(chan, a->argv[3]);
825                 ast_channel_unlock(chan);
826         } else {
827                 ast_channel_unlock(chan);
828                 ast_audiohook_detach_source(chan, mixmonitor_spy_type);
829         }
830
831         chan = ast_channel_unref(chan);
832
833         return CLI_SUCCESS;
834 }
835
836 /*! \brief  Mute / unmute  a MixMonitor channel */
837 static int manager_mute_mixmonitor(struct mansession *s, const struct message *m)
838 {
839         struct ast_channel *c = NULL;
840
841         const char *name = astman_get_header(m, "Channel");
842         const char *id = astman_get_header(m, "ActionID");
843         const char *state = astman_get_header(m, "State");
844         const char *direction = astman_get_header(m,"Direction");
845
846         int clearmute = 1;
847
848         enum ast_audiohook_flags flag;
849
850         if (ast_strlen_zero(direction)) {
851                 astman_send_error(s, m, "No direction specified. Must be read, write or both");
852                 return AMI_SUCCESS;
853         }
854
855         if (!strcasecmp(direction, "read")) {
856                 flag = AST_AUDIOHOOK_MUTE_READ;
857         } else  if (!strcasecmp(direction, "write")) {
858                 flag = AST_AUDIOHOOK_MUTE_WRITE;
859         } else  if (!strcasecmp(direction, "both")) {
860                 flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
861         } else {
862                 astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
863                 return AMI_SUCCESS;
864         }
865
866         if (ast_strlen_zero(name)) {
867                 astman_send_error(s, m, "No channel specified");
868                 return AMI_SUCCESS;
869         }
870
871         if (ast_strlen_zero(state)) {
872                 astman_send_error(s, m, "No state specified");
873                 return AMI_SUCCESS;
874         }
875
876         clearmute = ast_false(state);
877         c = ast_channel_get_by_name(name);
878
879         if (!c) {
880                 astman_send_error(s, m, "No such channel");
881                 return AMI_SUCCESS;
882         }
883
884         if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
885                 c = ast_channel_unref(c);
886                 astman_send_error(s, m, "Cannot set mute flag");
887                 return AMI_SUCCESS;
888         }
889
890         astman_append(s, "Response: Success\r\n");
891
892         if (!ast_strlen_zero(id)) {
893                 astman_append(s, "ActionID: %s\r\n", id);
894         }
895
896         astman_append(s, "\r\n");
897
898         c = ast_channel_unref(c);
899
900         return AMI_SUCCESS;
901 }
902
903 static int manager_mixmonitor(struct mansession *s, const struct message *m)
904 {
905         struct ast_channel *c = NULL;
906
907         const char *name = astman_get_header(m, "Channel");
908         const char *id = astman_get_header(m, "ActionID");
909         const char *file = astman_get_header(m, "File");
910         const char *options = astman_get_header(m, "Options");
911
912         int res;
913         char args[PATH_MAX] = "";
914         if (ast_strlen_zero(name)) {
915                 astman_send_error(s, m, "No channel specified");
916                 return AMI_SUCCESS;
917         }
918
919         c = ast_channel_get_by_name(name);
920
921         if (!c) {
922                 astman_send_error(s, m, "No such channel");
923                 return AMI_SUCCESS;
924         }
925
926         strcpy(args, file);
927         strcat(args, ",");
928         strcat(args, options);
929
930         ast_channel_lock(c);
931         res = mixmonitor_exec(c, args);
932         ast_channel_unlock(c);
933
934         if (res) {
935                 astman_send_error(s, m, "Could not start monitoring channel");
936                 return AMI_SUCCESS;
937         }
938
939         astman_append(s, "Response: Success\r\n");
940
941         if (!ast_strlen_zero(id)) {
942                 astman_append(s, "ActionID: %s\r\n", id);
943         }
944
945         astman_append(s, "\r\n");
946
947         c = ast_channel_unref(c);
948
949         return AMI_SUCCESS;
950 }
951
952 static int manager_stop_mixmonitor(struct mansession *s, const struct message *m)
953 {
954         struct ast_channel *c = NULL;
955
956         const char *name = astman_get_header(m, "Channel");
957         const char *id = astman_get_header(m, "ActionID");
958
959         int res;
960         if (ast_strlen_zero(name)) {
961                 astman_send_error(s, m, "No channel specified");
962                 return AMI_SUCCESS;
963         }
964
965         c = ast_channel_get_by_name(name);
966
967         if (!c) {
968                 astman_send_error(s, m, "No such channel");
969                 return AMI_SUCCESS;
970         }
971
972         res = stop_mixmonitor_exec(c, NULL);
973
974         if (res) {
975                 astman_send_error(s, m, "Could not stop monitoring channel");
976                 return AMI_SUCCESS;
977         }
978
979         astman_append(s, "Response: Success\r\n");
980
981         if (!ast_strlen_zero(id)) {
982                 astman_append(s, "ActionID: %s\r\n", id);
983         }
984
985         astman_append(s, "\r\n");
986
987         c = ast_channel_unref(c);
988
989         return AMI_SUCCESS;
990 }
991
992 static struct ast_cli_entry cli_mixmonitor[] = {
993         AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
994 };
995
996 static int unload_module(void)
997 {
998         int res;
999
1000         ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1001         res = ast_unregister_application(stop_app);
1002         res |= ast_unregister_application(app);
1003         res |= ast_manager_unregister("MixMonitorMute");
1004         res |= ast_manager_unregister("MixMonitor");
1005         res |= ast_manager_unregister("StopMixMonitor");
1006
1007         return res;
1008 }
1009
1010 static int load_module(void)
1011 {
1012         int res;
1013
1014         ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
1015         res = ast_register_application_xml(app, mixmonitor_exec);
1016         res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
1017         res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
1018         res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor);
1019         res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor);
1020
1021         return res;
1022 }
1023
1024 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");