Mon Jun 27 16:50:59 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 "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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .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 151 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

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

00177                      {
00178    OPT_ARG_READVOLUME = 0,
00179    OPT_ARG_WRITEVOLUME,
00180    OPT_ARG_VOLUME,
00181    OPT_ARG_ARRAY_SIZE,
00182 };

enum mixmonitor_flags

Enumerator:
MUXFLAG_APPEND 
MUXFLAG_BRIDGED 
MUXFLAG_VOLUME 
MUXFLAG_READVOLUME 
MUXFLAG_WRITEVOLUME 

Definition at line 169 of file app_mixmonitor.c.

00169                       {
00170    MUXFLAG_APPEND = (1 << 1),
00171    MUXFLAG_BRIDGED = (1 << 2),
00172    MUXFLAG_VOLUME = (1 << 3),
00173    MUXFLAG_READVOLUME = (1 << 4),
00174    MUXFLAG_WRITEVOLUME = (1 << 5),
00175 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 725 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 725 of file app_mixmonitor.c.

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

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

00235 {
00236    if (mixmonitor->mixmonitor_ds) {
00237       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00238       mixmonitor->mixmonitor_ds->audiohook = NULL;
00239       ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00240    }
00241    /* kill the audiohook.*/
00242    ast_audiohook_lock(&mixmonitor->audiohook);
00243    ast_audiohook_detach(&mixmonitor->audiohook);
00244    ast_audiohook_unlock(&mixmonitor->audiohook);
00245    ast_audiohook_destroy(&mixmonitor->audiohook);
00246 }

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

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

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

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 395 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().

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

static int load_module ( void   )  [static]

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

00714 {
00715    int res;
00716 
00717    ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
00718    res = ast_register_application_xml(app, mixmonitor_exec);
00719    res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec);
00720    res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor);
00721 
00722    return res;
00723 }

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

Mute / unmute a MixMonitor channel.

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

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

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

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

00209 {
00210    if (mixmonitor_ds->fs) {
00211       ast_closestream(mixmonitor_ds->fs);
00212       mixmonitor_ds->fs = NULL;
00213       mixmonitor_ds->fs_quit = 1;
00214       ast_verb(2, "MixMonitor close filestream\n");
00215    }
00216 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

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

00219 {
00220    struct mixmonitor_ds *mixmonitor_ds = data;
00221 
00222    ast_mutex_lock(&mixmonitor_ds->lock);
00223    mixmonitor_ds->audiohook = NULL;
00224    mixmonitor_ds->destruction_ok = 1;
00225    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00226    ast_mutex_unlock(&mixmonitor_ds->lock);
00227 }

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

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

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

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

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

00267 {
00268    if (mixmonitor) {
00269       if (mixmonitor->mixmonitor_ds) {
00270          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00271          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00272          ast_free(mixmonitor->mixmonitor_ds);
00273       }
00274       ast_free(mixmonitor);
00275    }
00276 }

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

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

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

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

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

00366 {
00367    struct ast_datastore *datastore = NULL;
00368    struct mixmonitor_ds *mixmonitor_ds;
00369 
00370    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00371       return -1;
00372    }
00373 
00374    ast_mutex_init(&mixmonitor_ds->lock);
00375    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00376 
00377    if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
00378       ast_mutex_destroy(&mixmonitor_ds->lock);
00379       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00380       ast_free(mixmonitor_ds);
00381       return -1;
00382    }
00383 
00384    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00385    datastore->data = mixmonitor_ds;
00386 
00387    ast_channel_lock(chan);
00388    ast_channel_datastore_add(chan, datastore);
00389    ast_channel_unlock(chan);
00390 
00391    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00392    return 0;
00393 }

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

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

00249 {
00250    struct ast_channel *peer = NULL;
00251    int res = 0;
00252 
00253    if (!chan)
00254       return -1;
00255 
00256    ast_audiohook_attach(chan, audiohook);
00257 
00258    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00259       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00260 
00261    return res;
00262 }

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

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

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

static int unload_module ( void   )  [static]

Definition at line 701 of file app_mixmonitor.c.

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

00702 {
00703    int res;
00704 
00705    ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
00706    res = ast_unregister_application(stop_app);
00707    res |= ast_unregister_application(app);
00708    res |= ast_manager_unregister("MixMonitorMute");
00709    
00710    return res;
00711 }


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 = "8586c2a7d357cb591cc3a6607a8f62d1" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, } [static]

Definition at line 725 of file app_mixmonitor.c.

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

Definition at line 153 of file app_mixmonitor.c.

struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 725 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 697 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 229 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 190 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

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

Definition at line 157 of file app_mixmonitor.c.

Referenced by builtin_automixmonitor().

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

Definition at line 155 of file app_mixmonitor.c.


Generated on Mon Jun 27 16:50:59 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7