Sat Mar 10 01:54:34 2012

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"
#include "asterisk/autochan.h"
#include "asterisk/manager.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  mixmonitor_args { OPT_ARG_READVOLUME = 0, OPT_ARG_WRITEVOLUME, OPT_ARG_VOLUME, OPT_ARG_ARRAY_SIZE }
enum  mixmonitor_flags {
  MUXFLAG_APPEND = (1 << 1), MUXFLAG_BRIDGED = (1 << 2), MUXFLAG_VOLUME = (1 << 3), MUXFLAG_READVOLUME = (1 << 4),
  MUXFLAG_WRITEVOLUME = (1 << 5)
}

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 int manager_mute_mixmonitor (struct mansession *s, const struct message *m)
 Mute / unmute a MixMonitor channel.
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, const char *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, const char *data)
static int unload_module (void)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static const char *const app = "MixMonitor"
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry cli_mixmonitor []
static struct ast_datastore_info mixmonitor_ds_info
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 *const mixmonitor_spy_type = "MixMonitor"
static const char *const stop_app = "StopMixMonitor"


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

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

Definition at line 270 of file app_mixmonitor.c.

Referenced by mixmonitor_thread().


Enumeration Type Documentation

enum mixmonitor_args

Enumerator:
OPT_ARG_READVOLUME 
OPT_ARG_WRITEVOLUME 
OPT_ARG_VOLUME 
OPT_ARG_ARRAY_SIZE 

Definition at line 183 of file app_mixmonitor.c.

00183                      {
00184    OPT_ARG_READVOLUME = 0,
00185    OPT_ARG_WRITEVOLUME,
00186    OPT_ARG_VOLUME,
00187    OPT_ARG_ARRAY_SIZE,
00188 };

enum mixmonitor_flags

Enumerator:
MUXFLAG_APPEND 
MUXFLAG_BRIDGED 
MUXFLAG_VOLUME 
MUXFLAG_READVOLUME 
MUXFLAG_WRITEVOLUME 

Definition at line 175 of file app_mixmonitor.c.

00175                       {
00176    MUXFLAG_APPEND = (1 << 1),
00177    MUXFLAG_BRIDGED = (1 << 2),
00178    MUXFLAG_VOLUME = (1 << 3),
00179    MUXFLAG_READVOLUME = (1 << 4),
00180    MUXFLAG_WRITEVOLUME = (1 << 5),
00181 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 733 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 733 of file app_mixmonitor.c.

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

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

00241 {
00242    if (mixmonitor->mixmonitor_ds) {
00243       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00244       mixmonitor->mixmonitor_ds->audiohook = NULL;
00245       ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00246    }
00247    /* kill the audiohook.*/
00248    ast_audiohook_lock(&mixmonitor->audiohook);
00249    ast_audiohook_detach(&mixmonitor->audiohook);
00250    ast_audiohook_unlock(&mixmonitor->audiohook);
00251    ast_audiohook_destroy(&mixmonitor->audiohook);
00252 }

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

Definition at line 598 of file app_mixmonitor.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_audiohook_detach_source(), ast_channel_get_by_name_prefix(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), 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.

00599 {
00600    struct ast_channel *chan;
00601 
00602    switch (cmd) {
00603    case CLI_INIT:
00604       e->command = "mixmonitor {start|stop}";
00605       e->usage =
00606          "Usage: mixmonitor <start|stop> <chan_name> [args]\n"
00607          "       The optional arguments are passed to the MixMonitor\n"
00608          "       application when the 'start' command is used.\n";
00609       return NULL;
00610    case CLI_GENERATE:
00611       return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
00612    }
00613 
00614    if (a->argc < 3)
00615       return CLI_SHOWUSAGE;
00616 
00617    if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
00618       ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
00619       /* Technically this is a failure, but we don't want 2 errors printing out */
00620       return CLI_SUCCESS;
00621    }
00622 
00623    ast_channel_lock(chan);
00624 
00625    if (!strcasecmp(a->argv[1], "start")) {
00626       mixmonitor_exec(chan, a->argv[3]);
00627       ast_channel_unlock(chan);
00628    } else {
00629       ast_channel_unlock(chan);
00630       ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00631    }
00632 
00633    chan = ast_channel_unref(chan);
00634 
00635    return CLI_SUCCESS;
00636 }

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

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

00405 {
00406    pthread_t thread;
00407    struct mixmonitor *mixmonitor;
00408    char postprocess2[1024] = "";
00409    size_t len;
00410 
00411    len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
00412 
00413    postprocess2[0] = 0;
00414    /* If a post process system command is given attach it to the structure */
00415    if (!ast_strlen_zero(post_process)) {
00416       char *p1, *p2;
00417 
00418       p1 = ast_strdupa(post_process);
00419       for (p2 = p1; *p2 ; p2++) {
00420          if (*p2 == '^' && *(p2+1) == '{') {
00421             *p2 = '$';
00422          }
00423       }
00424       pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
00425       if (!ast_strlen_zero(postprocess2))
00426          len += strlen(postprocess2) + 1;
00427    }
00428 
00429    /* Pre-allocate mixmonitor structure and spy */
00430    if (!(mixmonitor = ast_calloc(1, len))) {
00431       return;
00432    }
00433 
00434    /* Setup the actual spy before creating our thread */
00435    if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
00436       mixmonitor_free(mixmonitor);
00437       return;
00438    }
00439 
00440    /* Copy over flags and channel name */
00441    mixmonitor->flags = flags;
00442    if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
00443       mixmonitor_free(mixmonitor);
00444       return;
00445    }
00446 
00447    if (setup_mixmonitor_ds(mixmonitor, chan)) {
00448       ast_autochan_destroy(mixmonitor->autochan);
00449       mixmonitor_free(mixmonitor);
00450       return;
00451    }
00452    mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
00453    strcpy(mixmonitor->name, chan->name);
00454    if (!ast_strlen_zero(postprocess2)) {
00455       mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
00456       strcpy(mixmonitor->post_process, postprocess2);
00457    }
00458 
00459    mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
00460    strcpy(mixmonitor->filename, filename);
00461 
00462    ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
00463 
00464    if (readvol)
00465       mixmonitor->audiohook.options.read_volume = readvol;
00466    if (writevol)
00467       mixmonitor->audiohook.options.write_volume = writevol;
00468 
00469    if (startmon(chan, &mixmonitor->audiohook)) {
00470       ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
00471          mixmonitor_spy_type, chan->name);
00472       ast_audiohook_destroy(&mixmonitor->audiohook);
00473       mixmonitor_free(mixmonitor);
00474       return;
00475    }
00476 
00477    ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
00478 }

static int load_module ( void   )  [static]

Definition at line 721 of file app_mixmonitor.c.

References ARRAY_LEN, ast_cli_register_multiple(), ast_manager_register_xml, ast_register_application_xml, cli_mixmonitor, manager_mute_mixmonitor(), mixmonitor_exec(), and stop_mixmonitor_exec().

00722 {
00723    int res;
00724 
00725    ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
00726    res = ast_register_application_xml(app, mixmonitor_exec);
00727    res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
00728    res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
00729 
00730    return res;
00731 }

static int manager_mute_mixmonitor ( struct mansession s,
const struct message m 
) [static]

Mute / unmute a MixMonitor channel.

Definition at line 639 of file app_mixmonitor.c.

References AMI_SUCCESS, AST_AUDIOHOOK_MUTE_READ, AST_AUDIOHOOK_MUTE_WRITE, ast_audiohook_set_mute(), ast_channel_get_by_name(), ast_channel_unref, ast_false(), ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), and name.

Referenced by load_module().

00640 {
00641    struct ast_channel *c = NULL;
00642 
00643    const char *name = astman_get_header(m, "Channel");
00644    const char *id = astman_get_header(m, "ActionID");
00645    const char *state = astman_get_header(m, "State");
00646    const char *direction = astman_get_header(m,"Direction");
00647 
00648    int clearmute = 1;
00649 
00650    enum ast_audiohook_flags flag;
00651 
00652    if (ast_strlen_zero(direction)) {
00653       astman_send_error(s, m, "No direction specified. Must be read, write or both");
00654       return AMI_SUCCESS;
00655    }
00656 
00657    if (!strcasecmp(direction, "read")) {
00658       flag = AST_AUDIOHOOK_MUTE_READ;
00659    } else  if (!strcasecmp(direction, "write")) {
00660       flag = AST_AUDIOHOOK_MUTE_WRITE;
00661    } else  if (!strcasecmp(direction, "both")) {
00662       flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
00663    } else {
00664       astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
00665       return AMI_SUCCESS;
00666    }
00667 
00668    if (ast_strlen_zero(name)) {
00669       astman_send_error(s, m, "No channel specified");
00670       return AMI_SUCCESS;
00671    }
00672 
00673    if (ast_strlen_zero(state)) {
00674       astman_send_error(s, m, "No state specified");
00675       return AMI_SUCCESS;
00676    }
00677 
00678    clearmute = ast_false(state);
00679    c = ast_channel_get_by_name(name);
00680 
00681    if (!c) {
00682       astman_send_error(s, m, "No such channel");
00683       return AMI_SUCCESS;
00684    }
00685 
00686    if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
00687       c = ast_channel_unref(c);
00688       astman_send_error(s, m, "Cannot set mute flag");
00689       return AMI_SUCCESS;
00690    }
00691 
00692    astman_append(s, "Response: Success\r\n");
00693 
00694    if (!ast_strlen_zero(id)) {
00695       astman_append(s, "ActionID: %s\r\n", id);
00696    }
00697 
00698    astman_append(s, "\r\n");
00699 
00700    c = ast_channel_unref(c);
00701 
00702    return AMI_SUCCESS;
00703 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

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

00215 {
00216    if (mixmonitor_ds->fs) {
00217       ast_closestream(mixmonitor_ds->fs);
00218       mixmonitor_ds->fs = NULL;
00219       mixmonitor_ds->fs_quit = 1;
00220       ast_verb(2, "MixMonitor close filestream\n");
00221    }
00222 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

Definition at line 224 of file app_mixmonitor.c.

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

00225 {
00226    struct mixmonitor_ds *mixmonitor_ds = data;
00227 
00228    ast_mutex_lock(&mixmonitor_ds->lock);
00229    mixmonitor_ds->audiohook = NULL;
00230    mixmonitor_ds->destruction_ok = 1;
00231    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00232    ast_mutex_unlock(&mixmonitor_ds->lock);
00233 }

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

Definition at line 480 of file app_mixmonitor.c.

References args, 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, 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().

00481 {
00482    int x, readvol = 0, writevol = 0;
00483    struct ast_flags flags = {0};
00484    char *parse, *tmp, *slash;
00485    AST_DECLARE_APP_ARGS(args,
00486       AST_APP_ARG(filename);
00487       AST_APP_ARG(options);
00488       AST_APP_ARG(post_process);
00489    );
00490    
00491    if (ast_strlen_zero(data)) {
00492       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00493       return -1;
00494    }
00495 
00496    parse = ast_strdupa(data);
00497 
00498    AST_STANDARD_APP_ARGS(args, parse);
00499    
00500    if (ast_strlen_zero(args.filename)) {
00501       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00502       return -1;
00503    }
00504 
00505    if (args.options) {
00506       char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00507 
00508       ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
00509 
00510       if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
00511          if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
00512             ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
00513          } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00514             ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
00515          } else {
00516             readvol = get_volfactor(x);
00517          }
00518       }
00519       
00520       if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
00521          if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
00522             ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
00523          } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00524             ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
00525          } else {
00526             writevol = get_volfactor(x);
00527          }
00528       }
00529       
00530       if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
00531          if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
00532             ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
00533          } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00534             ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
00535          } else {
00536             readvol = writevol = get_volfactor(x);
00537          }
00538       }
00539    }
00540 
00541    /* if not provided an absolute path, use the system-configured monitoring directory */
00542    if (args.filename[0] != '/') {
00543       char *build;
00544 
00545       build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
00546       sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
00547       args.filename = build;
00548    }
00549 
00550    tmp = ast_strdupa(args.filename);
00551    if ((slash = strrchr(tmp, '/')))
00552       *slash = '\0';
00553    ast_mkdir(tmp, 0777);
00554 
00555    pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
00556    launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
00557 
00558    return 0;
00559 }

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

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

00273 {
00274    if (mixmonitor) {
00275       if (mixmonitor->mixmonitor_ds) {
00276          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00277          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00278          ast_free(mixmonitor->mixmonitor_ds);
00279       }
00280       ast_free(mixmonitor);
00281    }
00282 }

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

Definition at line 283 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_autochan_destroy(), 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::autochan, ast_autochan::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().

00284 {
00285    struct mixmonitor *mixmonitor = obj;
00286    struct ast_filestream **fs = NULL;
00287    unsigned int oflags;
00288    char *ext;
00289    char *last_slash;
00290    int errflag = 0;
00291 
00292    ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
00293 
00294    fs = &mixmonitor->mixmonitor_ds->fs;
00295 
00296    /* The audiohook must enter and exit the loop locked */
00297    ast_audiohook_lock(&mixmonitor->audiohook);
00298    while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
00299       struct ast_frame *fr = NULL;
00300 
00301       if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR))) {
00302          ast_audiohook_trigger_wait(&mixmonitor->audiohook);
00303 
00304          if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00305             break;
00306          }
00307          continue;
00308       }
00309 
00310       /* audiohook lock is not required for the next block.
00311        * Unlock it, but remember to lock it before looping or exiting */
00312       ast_audiohook_unlock(&mixmonitor->audiohook);
00313 
00314       if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
00315          ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00316          /* Initialize the file if not already done so */
00317          if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
00318             oflags = O_CREAT | O_WRONLY;
00319             oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
00320 
00321             last_slash = strrchr(mixmonitor->filename, '/');
00322             if ((ext = strrchr(mixmonitor->filename, '.')) && (ext > last_slash))
00323                *(ext++) = '\0';
00324             else
00325                ext = "raw";
00326 
00327             if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) {
00328                ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
00329                errflag = 1;
00330             }
00331          }
00332 
00333          /* Write out the frame(s) */
00334          if (*fs) {
00335             struct ast_frame *cur;
00336 
00337             for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00338                ast_writestream(*fs, cur);
00339             }
00340          }
00341          ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00342       }
00343       /* All done! free it. */
00344       ast_frame_free(fr, 0);
00345 
00346       ast_audiohook_lock(&mixmonitor->audiohook);
00347    }
00348    ast_audiohook_unlock(&mixmonitor->audiohook);
00349 
00350    ast_autochan_destroy(mixmonitor->autochan);
00351 
00352    /* Datastore cleanup.  close the filestream and wait for ds destruction */
00353    ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00354    mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
00355    if (!mixmonitor->mixmonitor_ds->destruction_ok) {
00356       ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
00357    }
00358    ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00359 
00360    /* kill the audiohook */
00361    destroy_monitor_audiohook(mixmonitor);
00362 
00363    if (mixmonitor->post_process) {
00364       ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
00365       ast_safe_system(mixmonitor->post_process);
00366    }
00367 
00368    ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
00369    mixmonitor_free(mixmonitor);
00370    return NULL;
00371 }

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

Definition at line 373 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, ast_datastore::data, mixmonitor::mixmonitor_ds, and mixmonitor_ds_info.

Referenced by launch_monitor_thread().

00374 {
00375    struct ast_datastore *datastore = NULL;
00376    struct mixmonitor_ds *mixmonitor_ds;
00377 
00378    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00379       return -1;
00380    }
00381 
00382    ast_mutex_init(&mixmonitor_ds->lock);
00383    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00384 
00385    if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
00386       ast_mutex_destroy(&mixmonitor_ds->lock);
00387       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00388       ast_free(mixmonitor_ds);
00389       return -1;
00390    }
00391 
00392    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00393    datastore->data = mixmonitor_ds;
00394 
00395    ast_channel_lock(chan);
00396    ast_channel_datastore_add(chan, datastore);
00397    ast_channel_unlock(chan);
00398 
00399    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00400    return 0;
00401 }

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

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

00255 {
00256    struct ast_channel *peer = NULL;
00257    int res = 0;
00258 
00259    if (!chan)
00260       return -1;
00261 
00262    ast_audiohook_attach(chan, audiohook);
00263 
00264    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00265       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00266 
00267    return res;
00268 }

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

Definition at line 561 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, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), mixmonitor_ds_info, and ast_audiohook::trigger.

Referenced by load_module().

00562 {
00563    struct ast_datastore *datastore = NULL;
00564 
00565    ast_channel_lock(chan);
00566    ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00567    if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
00568       struct mixmonitor_ds *mixmonitor_ds = datastore->data;
00569 
00570       ast_mutex_lock(&mixmonitor_ds->lock);
00571 
00572       /* closing the filestream here guarantees the file is avaliable to the dialplan
00573        * after calling StopMixMonitor */
00574       mixmonitor_ds_close_fs(mixmonitor_ds);
00575 
00576       /* The mixmonitor thread may be waiting on the audiohook trigger.
00577        * In order to exit from the mixmonitor loop before waiting on channel
00578        * destruction, poke the audiohook trigger. */
00579       if (mixmonitor_ds->audiohook) {
00580          ast_audiohook_lock(mixmonitor_ds->audiohook);
00581          ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
00582          ast_audiohook_unlock(mixmonitor_ds->audiohook);
00583          mixmonitor_ds->audiohook = NULL;
00584       }
00585 
00586       ast_mutex_unlock(&mixmonitor_ds->lock);
00587 
00588       /* Remove the datastore so the monitor thread can exit */
00589       if (!ast_channel_datastore_remove(chan, datastore)) {
00590          ast_datastore_free(datastore);
00591       }
00592    }
00593    ast_channel_unlock(chan);
00594 
00595    return 0;
00596 }

static int unload_module ( void   )  [static]

Definition at line 709 of file app_mixmonitor.c.

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

00710 {
00711    int res;
00712 
00713    ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
00714    res = ast_unregister_application(stop_app);
00715    res |= ast_unregister_application(app);
00716    res |= ast_manager_unregister("MixMonitorMute");
00717    
00718    return res;
00719 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "88eaa8f5c1bd988bedd71113385e0886" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 733 of file app_mixmonitor.c.

const char* const app = "MixMonitor" [static]

Definition at line 159 of file app_mixmonitor.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

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

Referenced by load_module(), and unload_module().

struct ast_datastore_info mixmonitor_ds_info [static]

Initial value:

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

Definition at line 235 of file app_mixmonitor.c.

Referenced by setup_mixmonitor_ds(), and stop_mixmonitor_exec().

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

Referenced by mixmonitor_exec().

const char* const mixmonitor_spy_type = "MixMonitor" [static]

Definition at line 163 of file app_mixmonitor.c.

Referenced by builtin_automixmonitor().

const char* const stop_app = "StopMixMonitor" [static]

Definition at line 161 of file app_mixmonitor.c.


Generated on Sat Mar 10 01:54:34 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7