Sat Aug 6 00:39:35 2011

Asterisk developer's documentation


app_mixmonitor.c File Reference

MixMonitor() - Record a call and mix the audio during the recording. More...

#include "asterisk.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
#include "asterisk/utils.h"

Go to the source code of this file.

Data Structures

struct  mixmonitor
struct  mixmonitor_ds

Defines

#define get_volfactor(x)   x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
#define SAMPLES_PER_FRAME   160

Enumerations

enum  {
  MUXFLAG_APPEND = (1 << 1), MUXFLAG_BRIDGED = (1 << 2), MUXFLAG_VOLUME = (1 << 3), MUXFLAG_READVOLUME = (1 << 4),
  MUXFLAG_WRITEVOLUME = (1 << 5)
}
enum  { OPT_ARG_READVOLUME = 0, OPT_ARG_WRITEVOLUME, OPT_ARG_VOLUME, OPT_ARG_ARRAY_SIZE }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static char * complete_mixmonitor_cli (const char *line, const char *word, int pos, int state)
static void destroy_monitor_audiohook (struct mixmonitor *mixmonitor)
static void launch_monitor_thread (struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process)
static int load_module (void)
static int mixmonitor_cli (int fd, int argc, char **argv)
static void mixmonitor_ds_chan_fixup (void *data, struct ast_channel *old_chan, struct ast_channel *new_chan)
static void mixmonitor_ds_close_fs (struct mixmonitor_ds *mixmonitor_ds)
static void mixmonitor_ds_destroy (void *data)
static int mixmonitor_exec (struct ast_channel *chan, void *data)
static void mixmonitor_free (struct mixmonitor *mixmonitor)
static void * mixmonitor_thread (void *obj)
static int setup_mixmonitor_ds (struct mixmonitor *mixmonitor, struct ast_channel *chan)
static int startmon (struct ast_channel *chan, struct ast_audiohook *audiohook)
static int stop_mixmonitor_exec (struct ast_channel *chan, void *data)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Mixed Audio Monitoring Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, }
static const char * app = "MixMonitor"
static const struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_mixmonitor []
static const char * desc
module_symbols * me
enum { ... }  mixmonitor_args
static struct ast_datastore_info mixmonitor_ds_info
enum { ... }  mixmonitor_flags
static struct ast_app_option mixmonitor_opts [128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 },}
static const char * mixmonitor_spy_type = "MixMonitor"
static const char * stop_app = "StopMixMonitor"
static const char * stop_desc
static const char * stop_synopsis = "Stop recording a call through MixMonitor"
static const char * synopsis = "Record a call and mix the audio during the recording"


Detailed Description

MixMonitor() - Record a call and mix the audio during the recording.

Author:
Mark Spencer <markster@digium.com>

Kevin P. Fleming <kpfleming@digium.com>

Note:
Based on app_muxmon.c provided by Anthony Minessale II <anthmct@yahoo.com>

Definition in file app_mixmonitor.c.


Define Documentation

#define get_volfactor (  )     x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0

Definition at line 58 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

Definition at line 227 of file app_mixmonitor.c.

Referenced by mixmonitor_thread().


Enumeration Type Documentation

anonymous enum

Enumerator:
MUXFLAG_APPEND 
MUXFLAG_BRIDGED 
MUXFLAG_VOLUME 
MUXFLAG_READVOLUME 
MUXFLAG_WRITEVOLUME 

Definition at line 108 of file app_mixmonitor.c.

00108      {
00109    MUXFLAG_APPEND = (1 << 1),
00110    MUXFLAG_BRIDGED = (1 << 2),
00111    MUXFLAG_VOLUME = (1 << 3),
00112    MUXFLAG_READVOLUME = (1 << 4),
00113    MUXFLAG_WRITEVOLUME = (1 << 5),
00114 } mixmonitor_flags;

anonymous enum

Enumerator:
OPT_ARG_READVOLUME 
OPT_ARG_WRITEVOLUME 
OPT_ARG_VOLUME 
OPT_ARG_ARRAY_SIZE 

Definition at line 116 of file app_mixmonitor.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 624 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 624 of file app_mixmonitor.c.

static char* complete_mixmonitor_cli ( const char *  line,
const char *  word,
int  pos,
int  state 
) [static]

Definition at line 586 of file app_mixmonitor.c.

References ast_complete_channels().

00587 {
00588    return ast_complete_channels(line, word, pos, state, 2);
00589 }

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

Definition at line 197 of file app_mixmonitor.c.

References ast_audiohook_destroy(), ast_audiohook_detach(), ast_audiohook_lock, ast_audiohook_unlock, ast_mutex_lock(), ast_mutex_unlock(), mixmonitor::audiohook, mixmonitor_ds::audiohook, mixmonitor_ds::lock, and mixmonitor::mixmonitor_ds.

Referenced by mixmonitor_thread().

00198 {
00199    if (mixmonitor->mixmonitor_ds) {
00200       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00201       mixmonitor->mixmonitor_ds->audiohook = NULL;
00202       ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00203    }
00204    /* kill the audiohook.*/
00205    ast_audiohook_lock(&mixmonitor->audiohook);
00206    ast_audiohook_detach(&mixmonitor->audiohook);
00207    ast_audiohook_unlock(&mixmonitor->audiohook);
00208    ast_audiohook_destroy(&mixmonitor->audiohook);
00209 }

static void launch_monitor_thread ( struct ast_channel chan,
const char *  filename,
unsigned int  flags,
int  readvol,
int  writevol,
const char *  post_process 
) [static]

Definition at line 369 of file app_mixmonitor.c.

References ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_log(), ast_pthread_create_background, ast_set_flag, ast_strdupa, ast_strlen_zero(), mixmonitor::audiohook, calloc, mixmonitor::flags, len(), LOG_WARNING, mixmonitor_free(), mixmonitor_thread(), mixmonitor::name, ast_channel::name, pbx_substitute_variables_helper(), setup_mixmonitor_ds(), startmon(), and thread.

Referenced by mixmonitor_exec().

00371 {
00372    pthread_attr_t attr;
00373    pthread_t thread;
00374    struct mixmonitor *mixmonitor;
00375    char postprocess2[1024] = "";
00376    size_t len;
00377 
00378    len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
00379 
00380    /* If a post process system command is given attach it to the structure */
00381    if (!ast_strlen_zero(post_process)) {
00382       char *p1, *p2;
00383 
00384       p1 = ast_strdupa(post_process);
00385       for (p2 = p1; *p2 ; p2++) {
00386          if (*p2 == '^' && *(p2+1) == '{') {
00387             *p2 = '$';
00388          }
00389       }
00390 
00391       pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
00392       if (!ast_strlen_zero(postprocess2))
00393          len += strlen(postprocess2) + 1;
00394    }
00395 
00396    /* Pre-allocate mixmonitor structure and spy */
00397    if (!(mixmonitor = calloc(1, len))) {
00398       return;
00399    }
00400 
00401    /* Setup the actual spy before creating our thread */
00402    if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
00403       mixmonitor_free(mixmonitor);
00404       return;
00405    }
00406 
00407    /* Copy over flags and channel name */
00408    mixmonitor->flags = flags;
00409    if (setup_mixmonitor_ds(mixmonitor, chan)) {
00410       mixmonitor_free(mixmonitor);
00411       return;
00412    }
00413    mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
00414    strcpy(mixmonitor->name, chan->name);
00415    if (!ast_strlen_zero(postprocess2)) {
00416       mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
00417       strcpy(mixmonitor->post_process, postprocess2);
00418    }
00419 
00420    mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
00421    strcpy(mixmonitor->filename, filename);
00422 
00423    ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
00424    
00425    if (readvol)
00426       mixmonitor->audiohook.options.read_volume = readvol;
00427    if (writevol)
00428       mixmonitor->audiohook.options.write_volume = writevol;
00429 
00430    if (startmon(chan, &mixmonitor->audiohook)) {
00431       ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
00432          mixmonitor_spy_type, chan->name);
00433       /* Since we couldn't add ourselves - bail out! */
00434       ast_audiohook_destroy(&mixmonitor->audiohook);
00435       mixmonitor_free(mixmonitor);
00436       return;
00437    }
00438 
00439    pthread_attr_init(&attr);
00440    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00441    ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor);
00442    pthread_attr_destroy(&attr);
00443 }

static int load_module ( void   )  [static]

Definition at line 613 of file app_mixmonitor.c.

References ast_cli_register_multiple(), ast_register_application(), cli_mixmonitor, mixmonitor_exec(), and stop_mixmonitor_exec().

00614 {
00615    int res;
00616 
00617    ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00618    res = ast_register_application(app, mixmonitor_exec, synopsis, desc);
00619    res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc);
00620 
00621    return res;
00622 }

static int mixmonitor_cli ( int  fd,
int  argc,
char **  argv 
) [static]

Definition at line 564 of file app_mixmonitor.c.

References ast_audiohook_detach_source(), ast_channel_unlock, ast_cli(), ast_get_channel_by_name_prefix_locked(), mixmonitor_exec(), RESULT_SHOWUSAGE, and RESULT_SUCCESS.

00565 {
00566    struct ast_channel *chan;
00567 
00568    if (argc < 3)
00569       return RESULT_SHOWUSAGE;
00570 
00571    if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) {
00572       ast_cli(fd, "No channel matching '%s' found.\n", argv[2]);
00573       return RESULT_SUCCESS;
00574    }
00575 
00576    if (!strcasecmp(argv[1], "start"))
00577       mixmonitor_exec(chan, argv[3]);
00578    else if (!strcasecmp(argv[1], "stop"))
00579       ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00580 
00581    ast_channel_unlock(chan);
00582 
00583    return RESULT_SUCCESS;
00584 }

static void mixmonitor_ds_chan_fixup ( void *  data,
struct ast_channel old_chan,
struct ast_channel new_chan 
) [static]

Definition at line 182 of file app_mixmonitor.c.

References ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::chan, and mixmonitor_ds::lock.

00183 {
00184    struct mixmonitor_ds *mixmonitor_ds = data;
00185 
00186    ast_mutex_lock(&mixmonitor_ds->lock);
00187    mixmonitor_ds->chan = new_chan;
00188    ast_mutex_unlock(&mixmonitor_ds->lock);
00189 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

Definition at line 159 of file app_mixmonitor.c.

References ast_closestream(), ast_verbose(), mixmonitor_ds::fs, mixmonitor_ds::fs_quit, option_verbose, and VERBOSE_PREFIX_2.

Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().

00160 {
00161    if (mixmonitor_ds->fs) {
00162       ast_closestream(mixmonitor_ds->fs);
00163       mixmonitor_ds->fs = NULL;
00164       mixmonitor_ds->fs_quit = 1;
00165       if (option_verbose > 1)
00166          ast_verbose(VERBOSE_PREFIX_2 "MixMonitor close filestream\n");
00167    }
00168 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

Definition at line 170 of file app_mixmonitor.c.

References ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::audiohook, mixmonitor_ds::chan, mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, and mixmonitor_ds::lock.

00171 {
00172    struct mixmonitor_ds *mixmonitor_ds = data;
00173 
00174    ast_mutex_lock(&mixmonitor_ds->lock);
00175    mixmonitor_ds->audiohook = NULL;
00176    mixmonitor_ds->chan = NULL;
00177    mixmonitor_ds->destruction_ok = 1;
00178    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00179    ast_mutex_unlock(&mixmonitor_ds->lock);
00180 }

static int mixmonitor_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 445 of file app_mixmonitor.c.

References AST_APP_ARG, ast_app_parse_options(), ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, ast_log(), ast_module_user_add, ast_module_user_remove, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_flags::flags, get_volfactor, launch_monitor_thread(), LOG_NOTICE, LOG_WARNING, mixmonitor_opts, MUXFLAG_READVOLUME, MUXFLAG_VOLUME, MUXFLAG_WRITEVOLUME, OPT_ARG_ARRAY_SIZE, OPT_ARG_READVOLUME, OPT_ARG_VOLUME, OPT_ARG_WRITEVOLUME, parse(), and pbx_builtin_setvar_helper().

Referenced by load_module(), and mixmonitor_cli().

00446 {
00447    int x, readvol = 0, writevol = 0;
00448    struct ast_module_user *u;
00449    struct ast_flags flags = {0};
00450    char *parse;
00451    AST_DECLARE_APP_ARGS(args,
00452       AST_APP_ARG(filename);
00453       AST_APP_ARG(options);
00454       AST_APP_ARG(post_process);
00455    );
00456    
00457    if (ast_strlen_zero(data)) {
00458       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00459       return -1;
00460    }
00461 
00462    u = ast_module_user_add(chan);
00463 
00464    parse = ast_strdupa(data);
00465 
00466    AST_STANDARD_APP_ARGS(args, parse);
00467    
00468    if (ast_strlen_zero(args.filename)) {
00469       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00470       ast_module_user_remove(u);
00471       return -1;
00472    }
00473 
00474    if (args.options) {
00475       char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00476 
00477       ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
00478 
00479       if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
00480          if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
00481             ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
00482          } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00483             ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
00484          } else {
00485             readvol = get_volfactor(x);
00486          }
00487       }
00488       
00489       if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
00490          if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
00491             ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
00492          } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00493             ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
00494          } else {
00495             writevol = get_volfactor(x);
00496          }
00497       }
00498       
00499       if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
00500          if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
00501             ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
00502          } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00503             ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
00504          } else {
00505             readvol = writevol = get_volfactor(x);
00506          }
00507       }
00508    }
00509 
00510    /* if not provided an absolute path, use the system-configured monitoring directory */
00511    if (args.filename[0] != '/') {
00512       char *build;
00513 
00514       build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
00515       sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
00516       args.filename = build;
00517    }
00518 
00519    pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
00520    launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
00521 
00522    ast_module_user_remove(u);
00523 
00524    return 0;
00525 }

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

Definition at line 229 of file app_mixmonitor.c.

References ast_cond_destroy(), ast_free, ast_mutex_destroy(), mixmonitor_ds::destruction_condition, mixmonitor_ds::lock, and mixmonitor::mixmonitor_ds.

Referenced by launch_monitor_thread(), and mixmonitor_thread().

00230 {
00231    if (mixmonitor) {
00232       if (mixmonitor->mixmonitor_ds) {
00233          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00234          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00235          ast_free(mixmonitor->mixmonitor_ds);
00236       }
00237       ast_free(mixmonitor);
00238    }
00239 }

static void* mixmonitor_thread ( void *  obj  )  [static]

Definition at line 241 of file app_mixmonitor.c.

References AST_AUDIOHOOK_DIRECTION_BOTH, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_trigger_wait(), ast_audiohook_unlock, ast_bridged_channel(), ast_cond_wait(), AST_FORMAT_SLINEAR, ast_frame_free(), AST_LIST_NEXT, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_safe_system(), ast_test_flag, ast_verbose(), ast_writefile(), ast_writestream(), mixmonitor::audiohook, mixmonitor_ds::chan, destroy_monitor_audiohook(), mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, ext, mixmonitor::filename, mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::lock, LOG_ERROR, mixmonitor::mixmonitor_ds, mixmonitor_ds_close_fs(), mixmonitor_free(), MUXFLAG_APPEND, MUXFLAG_BRIDGED, mixmonitor::name, option_verbose, mixmonitor::post_process, SAMPLES_PER_FRAME, ast_audiohook::status, and VERBOSE_PREFIX_2.

Referenced by launch_monitor_thread().

00242 {
00243    struct mixmonitor *mixmonitor = obj;
00244    struct ast_filestream **fs = NULL;
00245    unsigned int oflags;
00246    char *ext;
00247    char *last_slash;
00248    int errflag = 0;
00249 
00250    if (option_verbose > 1)
00251       ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name);
00252 
00253    fs = &mixmonitor->mixmonitor_ds->fs;
00254 
00255    /* The audiohook must enter and exit the loop locked */
00256    ast_audiohook_lock(&mixmonitor->audiohook);
00257    while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
00258       struct ast_frame *fr = NULL;
00259 
00260       if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) {
00261          ast_audiohook_trigger_wait(&mixmonitor->audiohook);
00262 
00263          if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00264             break;
00265          }
00266          continue;
00267       }
00268 
00269       /* audiohook lock is not required for the next block.
00270        * Unlock it, but remember to lock it before looping or exiting */
00271       ast_audiohook_unlock(&mixmonitor->audiohook);
00272 
00273       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00274       if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
00275          ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00276          /* Initialize the file if not already done so */
00277          if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
00278             oflags = O_CREAT | O_WRONLY;
00279             oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
00280 
00281             last_slash = strrchr(mixmonitor->filename, '/');
00282             if ((ext = strrchr(mixmonitor->filename, '.')) && (ext > last_slash))
00283                *(ext++) = '\0';
00284             else
00285                ext = "raw";
00286 
00287             if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) {
00288                ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
00289                errflag = 1;
00290             }
00291          }
00292 
00293          /* Write out the frame(s) */
00294          if (*fs) {
00295             struct ast_frame *cur;
00296 
00297             for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00298                ast_writestream(*fs, cur);
00299             }
00300          }
00301       } else {
00302          ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00303       }
00304 
00305       /* All done! free it. */
00306       ast_frame_free(fr, 0);
00307 
00308       ast_audiohook_lock(&mixmonitor->audiohook);
00309    }
00310    ast_audiohook_unlock(&mixmonitor->audiohook);
00311 
00312    /* Datastore cleanup.  close the filestream and wait for ds destruction */
00313    ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00314    mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
00315    if (!mixmonitor->mixmonitor_ds->destruction_ok) {
00316       ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
00317    }
00318    ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00319 
00320    /* kill the audiohook */
00321    destroy_monitor_audiohook(mixmonitor);
00322 
00323    if (mixmonitor->post_process) {
00324       if (option_verbose > 2)
00325          ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
00326       ast_safe_system(mixmonitor->post_process);
00327    }
00328 
00329    if (option_verbose > 1)
00330       ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
00331 
00332    mixmonitor_free(mixmonitor);
00333 
00334    return NULL;
00335 }

static int setup_mixmonitor_ds ( struct mixmonitor mixmonitor,
struct ast_channel chan 
) [static]

Definition at line 337 of file app_mixmonitor.c.

References ast_calloc, ast_channel_datastore_add(), ast_channel_datastore_alloc(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy(), ast_cond_init(), ast_free, ast_mutex_destroy(), ast_mutex_init(), mixmonitor::audiohook, mixmonitor_ds::chan, ast_datastore::data, mixmonitor::mixmonitor_ds, and mixmonitor_ds_info.

Referenced by launch_monitor_thread().

00338 {
00339    struct ast_datastore *datastore = NULL;
00340    struct mixmonitor_ds *mixmonitor_ds;
00341 
00342    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00343       return -1;
00344    }
00345    
00346    ast_mutex_init(&mixmonitor_ds->lock);
00347    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00348 
00349    if (!(datastore = ast_channel_datastore_alloc(&mixmonitor_ds_info, NULL))) {
00350       ast_mutex_destroy(&mixmonitor_ds->lock);
00351       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00352       ast_free(mixmonitor_ds);
00353       return -1;
00354    }
00355 
00356    /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
00357    mixmonitor_ds->chan = chan;
00358    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00359    datastore->data = mixmonitor_ds;
00360 
00361    ast_channel_lock(chan);
00362    ast_channel_datastore_add(chan, datastore);
00363    ast_channel_unlock(chan);
00364 
00365    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00366    return 0;
00367 }

static int startmon ( struct ast_channel chan,
struct ast_audiohook audiohook 
) [static]

Definition at line 211 of file app_mixmonitor.c.

References ast_audiohook_attach(), ast_bridged_channel(), AST_FLAG_NBRIDGE, ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, and ast_test_flag.

Referenced by launch_monitor_thread().

00212 {
00213    struct ast_channel *peer;
00214    int res;
00215 
00216    if (!chan)
00217       return -1;
00218 
00219    res = ast_audiohook_attach(chan, audiohook);
00220 
00221    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00222       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00223 
00224    return res;
00225 }

static int stop_mixmonitor_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 527 of file app_mixmonitor.c.

References ast_audiohook_detach_source(), ast_audiohook_lock, ast_audiohook_unlock, ast_channel_datastore_find(), ast_channel_datastore_free(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_cond_signal(), ast_mutex_lock(), ast_mutex_unlock(), mixmonitor_ds::audiohook, mixmonitor_ds::chan, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), mixmonitor_ds_info, and ast_audiohook::trigger.

Referenced by load_module().

00528 {
00529    struct ast_datastore *datastore = NULL;
00530 
00531    ast_channel_lock(chan);
00532    ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00533    if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
00534       struct mixmonitor_ds *mixmonitor_ds = datastore->data;
00535 
00536       ast_mutex_lock(&mixmonitor_ds->lock);
00537 
00538       /* closing the filestream here guarantees the file is avaliable to the dialplan
00539        * after calling StopMixMonitor */
00540       mixmonitor_ds_close_fs(mixmonitor_ds);
00541 
00542       /* The mixmonitor thread may be waiting on the audiohook trigger.
00543        * In order to exit from the mixmonitor loop before waiting on channel
00544        * destruction, poke the audiohook trigger. */
00545       if (mixmonitor_ds->audiohook) {
00546          ast_audiohook_lock(mixmonitor_ds->audiohook);
00547          ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
00548          ast_audiohook_unlock(mixmonitor_ds->audiohook);
00549          mixmonitor_ds->audiohook = NULL;
00550       }
00551 
00552       ast_mutex_unlock(&mixmonitor_ds->lock);
00553 
00554       /* Remove the datastore so the monitor thread can exit */
00555       if (!ast_channel_datastore_remove(chan, datastore)) {
00556          ast_channel_datastore_free(datastore);
00557       }
00558    }
00559    ast_channel_unlock(chan);
00560 
00561    return 0;
00562 }

static int unload_module ( void   )  [static]

Definition at line 600 of file app_mixmonitor.c.

References ast_cli_unregister_multiple(), ast_module_user_hangup_all, ast_unregister_application(), and cli_mixmonitor.

00601 {
00602    int res;
00603 
00604    ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00605    res = ast_unregister_application(stop_app);
00606    res |= ast_unregister_application(app);
00607    
00608    ast_module_user_hangup_all();
00609 
00610    return res;
00611 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | AST_MODFLAG_BUILDSUM, .description = "Mixed Audio Monitoring Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, } [static]

Definition at line 624 of file app_mixmonitor.c.

const char* app = "MixMonitor" [static]

Definition at line 60 of file app_mixmonitor.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 624 of file app_mixmonitor.c.

struct ast_cli_entry cli_mixmonitor[] [static]

Definition at line 591 of file app_mixmonitor.c.

Referenced by load_module(), and unload_module().

const char* desc [static]

Definition at line 62 of file app_mixmonitor.c.

struct module_symbols* me

Definition at line 95 of file app_mixmonitor.c.

enum { ... } mixmonitor_args

struct ast_datastore_info mixmonitor_ds_info [static]

Initial value:

 {
   .type = "mixmonitor",
   .destroy = mixmonitor_ds_destroy,
   .chan_fixup = mixmonitor_ds_chan_fixup,
}

Definition at line 191 of file app_mixmonitor.c.

Referenced by setup_mixmonitor_ds(), and stop_mixmonitor_exec().

enum { ... } mixmonitor_flags

struct ast_app_option mixmonitor_opts[128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'v' ] = { .flag = MUXFLAG_READVOLUME , .arg_index = OPT_ARG_READVOLUME + 1 }, [ 'V' ] = { .flag = MUXFLAG_WRITEVOLUME , .arg_index = OPT_ARG_WRITEVOLUME + 1 }, [ 'W' ] = { .flag = MUXFLAG_VOLUME , .arg_index = OPT_ARG_VOLUME + 1 },} [static]

Definition at line 129 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

const char* mixmonitor_spy_type = "MixMonitor" [static]

Definition at line 97 of file app_mixmonitor.c.

const char* stop_app = "StopMixMonitor" [static]

Definition at line 88 of file app_mixmonitor.c.

const char* stop_desc [static]

Initial value:

 ""
"  StopMixMonitor()\n\n"
"Stop recording a call through MixMonitor, and free the recording's file handle.\n"
""

Definition at line 90 of file app_mixmonitor.c.

const char* stop_synopsis = "Stop recording a call through MixMonitor" [static]

Definition at line 89 of file app_mixmonitor.c.

const char* synopsis = "Record a call and mix the audio during the recording" [static]

Definition at line 61 of file app_mixmonitor.c.


Generated on Sat Aug 6 00:39:35 2011 for Asterisk - the Open Source PBX by  doxygen 1.4.7