Wed Aug 18 22:33:59 2010

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 "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/channel.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 void destroy_monitor_audiohook (struct mixmonitor *mixmonitor)
static char * handle_cli_mixmonitor (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
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 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 , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, }
static const char * app = "MixMonitor"
static 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 49 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

Definition at line 217 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 99 of file app_mixmonitor.c.

00099      {
00100    MUXFLAG_APPEND = (1 << 1),
00101    MUXFLAG_BRIDGED = (1 << 2),
00102    MUXFLAG_VOLUME = (1 << 3),
00103    MUXFLAG_READVOLUME = (1 << 4),
00104    MUXFLAG_WRITEVOLUME = (1 << 5),
00105 } mixmonitor_flags;

anonymous enum

Enumerator:
OPT_ARG_READVOLUME 
OPT_ARG_WRITEVOLUME 
OPT_ARG_VOLUME 
OPT_ARG_ARRAY_SIZE 

Definition at line 107 of file app_mixmonitor.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 601 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 601 of file app_mixmonitor.c.

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

Definition at line 187 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().

00188 {
00189    if (mixmonitor->mixmonitor_ds) {
00190       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00191       mixmonitor->mixmonitor_ds->audiohook = NULL;
00192       ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00193    }
00194    /* kill the audiohook.*/
00195    ast_audiohook_lock(&mixmonitor->audiohook);
00196    ast_audiohook_detach(&mixmonitor->audiohook);
00197    ast_audiohook_unlock(&mixmonitor->audiohook);
00198    ast_audiohook_destroy(&mixmonitor->audiohook);
00199 }

static char* handle_cli_mixmonitor ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 539 of file app_mixmonitor.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_audiohook_detach_source(), ast_channel_unlock, ast_cli(), ast_complete_channels(), ast_get_channel_by_name_prefix_locked(), chan, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, ast_cli_args::line, mixmonitor_exec(), ast_cli_args::n, ast_cli_args::pos, ast_cli_entry::usage, and ast_cli_args::word.

00540 {
00541    struct ast_channel *chan;
00542 
00543    switch (cmd) {
00544    case CLI_INIT:
00545       e->command = "mixmonitor [start|stop]";
00546       e->usage =
00547          "Usage: mixmonitor <start|stop> <chan_name> [args]\n"
00548          "       The optional arguments are passed to the MixMonitor\n"
00549          "       application when the 'start' command is used.\n";
00550       return NULL;
00551    case CLI_GENERATE:
00552       return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
00553    }
00554 
00555    if (a->argc < 3)
00556       return CLI_SHOWUSAGE;
00557 
00558    if (!(chan = ast_get_channel_by_name_prefix_locked(a->argv[2], strlen(a->argv[2])))) {
00559       ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
00560       /* Technically this is a failure, but we don't want 2 errors printing out */
00561       return CLI_SUCCESS;
00562    }
00563 
00564    if (!strcasecmp(a->argv[1], "start")) {
00565       mixmonitor_exec(chan, a->argv[3]);
00566       ast_channel_unlock(chan);
00567    } else {
00568       ast_channel_unlock(chan);
00569       ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00570    }
00571 
00572    return CLI_SUCCESS;
00573 }

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 350 of file app_mixmonitor.c.

References ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_calloc, ast_log(), ast_pthread_create_detached_background, ast_set_flag, ast_strdupa, ast_strlen_zero(), mixmonitor::audiohook, chan, 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().

00352 {
00353    pthread_t thread;
00354    struct mixmonitor *mixmonitor;
00355    char postprocess2[1024] = "";
00356    size_t len;
00357 
00358    len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
00359 
00360    postprocess2[0] = 0;
00361    /* If a post process system command is given attach it to the structure */
00362    if (!ast_strlen_zero(post_process)) {
00363       char *p1, *p2;
00364 
00365       p1 = ast_strdupa(post_process);
00366       for (p2 = p1; *p2 ; p2++) {
00367          if (*p2 == '^' && *(p2+1) == '{') {
00368             *p2 = '$';
00369          }
00370       }
00371       pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
00372       if (!ast_strlen_zero(postprocess2))
00373          len += strlen(postprocess2) + 1;
00374    }
00375 
00376    /* Pre-allocate mixmonitor structure and spy */
00377    if (!(mixmonitor = ast_calloc(1, len))) {
00378       return;
00379    }
00380 
00381    /* Setup the actual spy before creating our thread */
00382    if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
00383       mixmonitor_free(mixmonitor);
00384       return;
00385    }
00386 
00387    /* Copy over flags and channel name */
00388    mixmonitor->flags = flags;
00389    if (setup_mixmonitor_ds(mixmonitor, chan)) {
00390       mixmonitor_free(mixmonitor);
00391       return;
00392    }
00393    mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
00394    strcpy(mixmonitor->name, chan->name);
00395    if (!ast_strlen_zero(postprocess2)) {
00396       mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
00397       strcpy(mixmonitor->post_process, postprocess2);
00398    }
00399 
00400    mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
00401    strcpy(mixmonitor->filename, filename);
00402 
00403    ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
00404 
00405    if (readvol)
00406       mixmonitor->audiohook.options.read_volume = readvol;
00407    if (writevol)
00408       mixmonitor->audiohook.options.write_volume = writevol;
00409 
00410    if (startmon(chan, &mixmonitor->audiohook)) {
00411       ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
00412          mixmonitor_spy_type, chan->name);
00413       ast_audiohook_destroy(&mixmonitor->audiohook);
00414       mixmonitor_free(mixmonitor);
00415       return;
00416    }
00417 
00418    ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
00419 }

static int load_module ( void   )  [static]

Definition at line 590 of file app_mixmonitor.c.

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

00591 {
00592    int res;
00593 
00594    ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00595    res = ast_register_application(app, mixmonitor_exec, synopsis, desc);
00596    res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc);
00597 
00598    return res;
00599 }

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

Definition at line 172 of file app_mixmonitor.c.

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

00173 {
00174    struct mixmonitor_ds *mixmonitor_ds = data;
00175 
00176    ast_mutex_lock(&mixmonitor_ds->lock);
00177    mixmonitor_ds->chan = new_chan;
00178    ast_mutex_unlock(&mixmonitor_ds->lock);
00179 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

Definition at line 150 of file app_mixmonitor.c.

References ast_closestream(), ast_verb, mixmonitor_ds::fs, and mixmonitor_ds::fs_quit.

Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().

00151 {
00152    if (mixmonitor_ds->fs) {
00153       ast_closestream(mixmonitor_ds->fs);
00154       mixmonitor_ds->fs = NULL;
00155       mixmonitor_ds->fs_quit = 1;
00156       ast_verb(2, "MixMonitor close filestream\n");
00157    }
00158 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

Definition at line 160 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.

00161 {
00162    struct mixmonitor_ds *mixmonitor_ds = data;
00163 
00164    ast_mutex_lock(&mixmonitor_ds->lock);
00165    mixmonitor_ds->chan = NULL;
00166    mixmonitor_ds->audiohook = NULL;
00167    mixmonitor_ds->destruction_ok = 1;
00168    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00169    ast_mutex_unlock(&mixmonitor_ds->lock);
00170 }

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

Definition at line 421 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_mkdir(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, chan, 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 handle_cli_mixmonitor(), and load_module().

00422 {
00423    int x, readvol = 0, writevol = 0;
00424    struct ast_flags flags = {0};
00425    char *parse, *tmp, *slash;
00426    AST_DECLARE_APP_ARGS(args,
00427       AST_APP_ARG(filename);
00428       AST_APP_ARG(options);
00429       AST_APP_ARG(post_process);
00430    );
00431    
00432    if (ast_strlen_zero(data)) {
00433       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00434       return -1;
00435    }
00436 
00437    parse = ast_strdupa(data);
00438 
00439    AST_STANDARD_APP_ARGS(args, parse);
00440    
00441    if (ast_strlen_zero(args.filename)) {
00442       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00443       return -1;
00444    }
00445 
00446    if (args.options) {
00447       char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00448 
00449       ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
00450 
00451       if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
00452          if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
00453             ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
00454          } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00455             ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
00456          } else {
00457             readvol = get_volfactor(x);
00458          }
00459       }
00460       
00461       if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
00462          if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
00463             ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
00464          } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00465             ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
00466          } else {
00467             writevol = get_volfactor(x);
00468          }
00469       }
00470       
00471       if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
00472          if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
00473             ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
00474          } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00475             ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
00476          } else {
00477             readvol = writevol = get_volfactor(x);
00478          }
00479       }
00480    }
00481 
00482    /* if not provided an absolute path, use the system-configured monitoring directory */
00483    if (args.filename[0] != '/') {
00484       char *build;
00485 
00486       build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
00487       sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
00488       args.filename = build;
00489    }
00490 
00491    tmp = ast_strdupa(args.filename);
00492    if ((slash = strrchr(tmp, '/')))
00493       *slash = '\0';
00494    ast_mkdir(tmp, 0777);
00495 
00496    pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
00497    launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
00498 
00499    return 0;
00500 }

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

Definition at line 219 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().

00220 {
00221    if (mixmonitor) {
00222       if (mixmonitor->mixmonitor_ds) {
00223          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00224          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00225          ast_free(mixmonitor->mixmonitor_ds);
00226       }
00227       ast_free(mixmonitor);
00228    }
00229 }

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

Definition at line 231 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_verb, 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, mixmonitor::post_process, SAMPLES_PER_FRAME, and ast_audiohook::status.

Referenced by launch_monitor_thread().

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

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

Definition at line 318 of file app_mixmonitor.c.

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

Referenced by launch_monitor_thread().

00319 {
00320    struct ast_datastore *datastore = NULL;
00321    struct mixmonitor_ds *mixmonitor_ds;
00322 
00323    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00324       return -1;
00325    }
00326 
00327    ast_mutex_init(&mixmonitor_ds->lock);
00328    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00329 
00330    if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
00331       ast_mutex_destroy(&mixmonitor_ds->lock);
00332       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00333       ast_free(mixmonitor_ds);
00334       return -1;
00335    }
00336 
00337    /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
00338    mixmonitor_ds->chan = chan;
00339    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00340    datastore->data = mixmonitor_ds;
00341 
00342    ast_channel_lock(chan);
00343    ast_channel_datastore_add(chan, datastore);
00344    ast_channel_unlock(chan);
00345 
00346    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00347    return 0;
00348 }

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

Definition at line 201 of file app_mixmonitor.c.

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

Referenced by launch_monitor_thread().

00202 {
00203    struct ast_channel *peer = NULL;
00204    int res = 0;
00205 
00206    if (!chan)
00207       return -1;
00208 
00209    ast_audiohook_attach(chan, audiohook);
00210 
00211    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00212       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00213 
00214    return res;
00215 }

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

Definition at line 502 of file app_mixmonitor.c.

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

Referenced by load_module().

00503 {
00504    struct ast_datastore *datastore = NULL;
00505 
00506    ast_channel_lock(chan);
00507    ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00508    if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
00509       struct mixmonitor_ds *mixmonitor_ds = datastore->data;
00510 
00511       ast_mutex_lock(&mixmonitor_ds->lock);
00512 
00513       /* closing the filestream here guarantees the file is avaliable to the dialplan
00514        * after calling StopMixMonitor */
00515       mixmonitor_ds_close_fs(mixmonitor_ds);
00516 
00517       /* The mixmonitor thread may be waiting on the audiohook trigger.
00518        * In order to exit from the mixmonitor loop before waiting on channel
00519        * destruction, poke the audiohook trigger. */
00520       if (mixmonitor_ds->audiohook) {
00521          ast_audiohook_lock(mixmonitor_ds->audiohook);
00522          ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
00523          ast_audiohook_unlock(mixmonitor_ds->audiohook);
00524          mixmonitor_ds->audiohook = NULL;
00525       }
00526 
00527       ast_mutex_unlock(&mixmonitor_ds->lock);
00528 
00529       /* Remove the datastore so the monitor thread can exit */
00530       if (!ast_channel_datastore_remove(chan, datastore)) {
00531          ast_datastore_free(datastore);
00532       }
00533    }
00534    ast_channel_unlock(chan);
00535 
00536    return 0;
00537 }

static int unload_module ( void   )  [static]

Definition at line 579 of file app_mixmonitor.c.

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

00580 {
00581    int res;
00582 
00583    ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00584    res = ast_unregister_application(stop_app);
00585    res |= ast_unregister_application(app);
00586    
00587    return res;
00588 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .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 = "a9c98e5d177805051735cb5b0b16b0a0" , .load = load_module, .unload = unload_module, } [static]

Definition at line 601 of file app_mixmonitor.c.

const char* app = "MixMonitor" [static]

Definition at line 51 of file app_mixmonitor.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 601 of file app_mixmonitor.c.

struct ast_cli_entry cli_mixmonitor[] [static]

Initial value:

 {
   { .handler =  handle_cli_mixmonitor , .summary =  "Execute a MixMonitor command" ,__VA_ARGS__ }
}

Definition at line 575 of file app_mixmonitor.c.

Referenced by load_module(), and unload_module().

const char* desc [static]

Definition at line 53 of file app_mixmonitor.c.

struct module_symbols* me

Definition at line 86 of file app_mixmonitor.c.

Referenced by _sip_tcp_helper_thread(), handle_mgcp_audit_endpoint(), and handle_mgcp_show_endpoints().

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 181 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 120 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

const char* mixmonitor_spy_type = "MixMonitor" [static]

Definition at line 88 of file app_mixmonitor.c.

Referenced by builtin_automixmonitor().

const char* stop_app = "StopMixMonitor" [static]

Definition at line 79 of file app_mixmonitor.c.

const char* stop_desc [static]

Initial value:

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

Definition at line 81 of file app_mixmonitor.c.

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

Definition at line 80 of file app_mixmonitor.c.

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

Definition at line 52 of file app_mixmonitor.c.


Generated on Wed Aug 18 22:33:59 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7