Fri Nov 12 11:50:22 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"
Include dependency graph for app_mixmonitor.c:

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 = "0901e4e500243c855563a2d78b0c03e4" , .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 []
struct 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"

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

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

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

00148      {
00149    MUXFLAG_APPEND = (1 << 1),
00150    MUXFLAG_BRIDGED = (1 << 2),
00151    MUXFLAG_VOLUME = (1 << 3),
00152    MUXFLAG_READVOLUME = (1 << 4),
00153    MUXFLAG_WRITEVOLUME = (1 << 5),
00154 } mixmonitor_flags;

anonymous enum
Enumerator:
OPT_ARG_READVOLUME 
OPT_ARG_WRITEVOLUME 
OPT_ARG_VOLUME 
OPT_ARG_ARRAY_SIZE 

Definition at line 156 of file app_mixmonitor.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 649 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 649 of file app_mixmonitor.c.

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

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

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

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

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

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

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 398 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_strlen_zero(), mixmonitor::audiohook, mixmonitor::filename, mixmonitor::flags, len(), LOG_WARNING, mixmonitor_free(), mixmonitor_thread(), mixmonitor::name, ast_channel::name, ast_audiohook::options, pbx_substitute_variables_helper(), mixmonitor::post_process, ast_audiohook_options::read_volume, setup_mixmonitor_ds(), startmon(), thread, and ast_audiohook_options::write_volume.

Referenced by mixmonitor_exec().

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

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

Definition at line 221 of file app_mixmonitor.c.

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

00222 {
00223    struct mixmonitor_ds *mixmonitor_ds = data;
00224 
00225    ast_mutex_lock(&mixmonitor_ds->lock);
00226    mixmonitor_ds->chan = new_chan;
00227    ast_mutex_unlock(&mixmonitor_ds->lock);
00228 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

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

00200 {
00201    if (mixmonitor_ds->fs) {
00202       ast_closestream(mixmonitor_ds->fs);
00203       mixmonitor_ds->fs = NULL;
00204       mixmonitor_ds->fs_quit = 1;
00205       ast_verb(2, "MixMonitor close filestream\n");
00206    }
00207 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

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

00210 {
00211    struct mixmonitor_ds *mixmonitor_ds = data;
00212 
00213    ast_mutex_lock(&mixmonitor_ds->lock);
00214    mixmonitor_ds->chan = NULL;
00215    mixmonitor_ds->audiohook = NULL;
00216    mixmonitor_ds->destruction_ok = 1;
00217    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00218    ast_mutex_unlock(&mixmonitor_ds->lock);
00219 }

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

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

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

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

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

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

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

Definition at line 280 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, ast_frame::frame_list, 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().

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

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

Definition at line 366 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, mixmonitor_ds::audiohook, mixmonitor_ds::chan, ast_datastore::data, mixmonitor_ds::destruction_condition, mixmonitor_ds::lock, and mixmonitor::mixmonitor_ds.

Referenced by launch_monitor_thread().

00367 {
00368    struct ast_datastore *datastore = NULL;
00369    struct mixmonitor_ds *mixmonitor_ds;
00370 
00371    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00372       return -1;
00373    }
00374 
00375    ast_mutex_init(&mixmonitor_ds->lock);
00376    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00377 
00378    if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, NULL))) {
00379       ast_mutex_destroy(&mixmonitor_ds->lock);
00380       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00381       ast_free(mixmonitor_ds);
00382       return -1;
00383    }
00384 
00385    /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
00386    mixmonitor_ds->chan = chan;
00387    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00388    datastore->data = mixmonitor_ds;
00389 
00390    ast_channel_lock(chan);
00391    ast_channel_datastore_add(chan, datastore);
00392    ast_channel_unlock(chan);
00393 
00394    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00395    return 0;
00396 }

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

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

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

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

Definition at line 550 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(), and ast_audiohook::trigger.

Referenced by load_module().

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

static int unload_module ( void   )  [static]

Definition at line 627 of file app_mixmonitor.c.

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

00628 {
00629    int res;
00630 
00631    ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
00632    res = ast_unregister_application(stop_app);
00633    res |= ast_unregister_application(app);
00634    
00635    return res;
00636 }


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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, } [static]

Definition at line 649 of file app_mixmonitor.c.

const char* app = "MixMonitor" [static]

Definition at line 131 of file app_mixmonitor.c.

Definition at line 649 of file app_mixmonitor.c.

struct ast_cli_entry cli_mixmonitor[] [static]
Initial value:
 {
   AST_CLI_DEFINE(handle_cli_mixmonitor, "Execute a MixMonitor command")
}

Definition at line 623 of file app_mixmonitor.c.

struct module_symbols* me
enum { ... } mixmonitor_args
Initial value:
 {
   .type = "mixmonitor",
   .destroy = mixmonitor_ds_destroy,
   .chan_fixup = mixmonitor_ds_chan_fixup,
}

Definition at line 230 of file app_mixmonitor.c.

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

Referenced by mixmonitor_exec().

const char* mixmonitor_spy_type = "MixMonitor" [static]

Definition at line 137 of file app_mixmonitor.c.

Referenced by builtin_automixmonitor().

const char* stop_app = "StopMixMonitor" [static]

Definition at line 133 of file app_mixmonitor.c.


Generated by  doxygen 1.6.2