Fri Sep 11 13:45:07 2009

Asterisk developer's documentation


app_mixmonitor.c File Reference

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

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

Go to the source code of this file.

Data Structures

struct  mixmonitor
struct  mixmonitor_ds

Defines

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

Enumerations

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

Functions

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

Variables

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


Detailed Description

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

Author:
Mark Spencer <markster@digium.com>

Kevin P. Fleming <kpfleming@digium.com>

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

Definition in file app_mixmonitor.c.


Define Documentation

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

Definition at line 58 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

Definition at line 209 of file app_mixmonitor.c.

Referenced by mixmonitor_thread().


Enumeration Type Documentation

anonymous enum

Enumerator:
MUXFLAG_APPEND 
MUXFLAG_BRIDGED 
MUXFLAG_VOLUME 
MUXFLAG_READVOLUME 
MUXFLAG_WRITEVOLUME 

Definition at line 108 of file app_mixmonitor.c.

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

anonymous enum

Enumerator:
OPT_ARG_READVOLUME 
OPT_ARG_WRITEVOLUME 
OPT_ARG_VOLUME 
OPT_ARG_ARRAY_SIZE 

Definition at line 116 of file app_mixmonitor.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 579 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 579 of file app_mixmonitor.c.

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

Definition at line 541 of file app_mixmonitor.c.

References ast_complete_channels().

00542 {
00543    return ast_complete_channels(line, word, pos, state, 2);
00544 }

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

References ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_log(), ast_pthread_create_background, ast_set_flag, ast_strdupa, ast_strlen_zero(), calloc, mixmonitor::flags, free, 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().

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

static int load_module ( void   )  [static]

Definition at line 568 of file app_mixmonitor.c.

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

00569 {
00570    int res;
00571 
00572    ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00573    res = ast_register_application(app, mixmonitor_exec, synopsis, desc);
00574    res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc);
00575 
00576    return res;
00577 }

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

Definition at line 519 of file app_mixmonitor.c.

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

00520 {
00521    struct ast_channel *chan;
00522 
00523    if (argc < 3)
00524       return RESULT_SHOWUSAGE;
00525 
00526    if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) {
00527       ast_cli(fd, "No channel matching '%s' found.\n", argv[2]);
00528       return RESULT_SUCCESS;
00529    }
00530 
00531    if (!strcasecmp(argv[1], "start"))
00532       mixmonitor_exec(chan, argv[3]);
00533    else if (!strcasecmp(argv[1], "stop"))
00534       ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00535 
00536    ast_channel_unlock(chan);
00537 
00538    return RESULT_SUCCESS;
00539 }

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

Definition at line 178 of file app_mixmonitor.c.

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

00179 {
00180    struct mixmonitor_ds *mixmonitor_ds = data;
00181 
00182    ast_mutex_lock(&mixmonitor_ds->lock);
00183    mixmonitor_ds->chan = new_chan;
00184    ast_mutex_unlock(&mixmonitor_ds->lock);
00185 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

Definition at line 154 of file app_mixmonitor.c.

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

Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().

00155 {
00156    ast_mutex_lock(&mixmonitor_ds->lock);
00157    if (mixmonitor_ds->fs) {
00158       ast_closestream(mixmonitor_ds->fs);
00159       mixmonitor_ds->fs = NULL;
00160       mixmonitor_ds->fs_quit = 1;
00161       if (option_verbose > 1)
00162          ast_verbose(VERBOSE_PREFIX_2 "MixMonitor close filestream\n");
00163    }
00164    ast_mutex_unlock(&mixmonitor_ds->lock);
00165 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

Definition at line 167 of file app_mixmonitor.c.

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

00168 {
00169    struct mixmonitor_ds *mixmonitor_ds = data;
00170 
00171    ast_mutex_lock(&mixmonitor_ds->lock);
00172    mixmonitor_ds->chan = NULL;
00173    mixmonitor_ds->destruction_ok = 1;
00174    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00175    ast_mutex_unlock(&mixmonitor_ds->lock);
00176 }

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

Definition at line 417 of file app_mixmonitor.c.

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

Referenced by load_module(), and mixmonitor_cli().

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

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

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

00212 {
00213    if (mixmonitor) {
00214       if (mixmonitor->mixmonitor_ds) {
00215          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00216          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00217          ast_free(mixmonitor->mixmonitor_ds);
00218       }
00219       ast_free(mixmonitor);
00220    }
00221 }

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

Definition at line 223 of file app_mixmonitor.c.

References ast_audiohook_destroy(), ast_audiohook_detach(), AST_AUDIOHOOK_DIRECTION_BOTH, ast_audiohook_lock, ast_audiohook_read_frame(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_trigger_wait(), ast_audiohook_unlock, ast_bridged_channel(), ast_cond_wait(), AST_FORMAT_SLINEAR, ast_frame_free(), AST_LIST_NEXT, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_safe_system(), ast_test_flag, ast_verbose(), ast_writefile(), ast_writestream(), mixmonitor::audiohook, mixmonitor_ds::chan, 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, option_verbose, mixmonitor::post_process, SAMPLES_PER_FRAME, ast_audiohook::status, and VERBOSE_PREFIX_2.

Referenced by launch_monitor_thread().

00224 {
00225    struct mixmonitor *mixmonitor = obj;
00226    struct ast_filestream **fs = NULL;
00227    unsigned int oflags;
00228    char *ext;
00229    int errflag = 0;
00230 
00231    if (option_verbose > 1)
00232       ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", mixmonitor->name);
00233 
00234    ast_audiohook_lock(&mixmonitor->audiohook);
00235 
00236    fs = &mixmonitor->mixmonitor_ds->fs;
00237 
00238    while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
00239       struct ast_frame *fr = NULL;
00240 
00241       ast_audiohook_trigger_wait(&mixmonitor->audiohook);
00242 
00243       if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING)
00244          break;
00245 
00246       if (!(fr = ast_audiohook_read_frame(&mixmonitor->audiohook, SAMPLES_PER_FRAME, AST_AUDIOHOOK_DIRECTION_BOTH, AST_FORMAT_SLINEAR)))
00247          continue;
00248 
00249       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00250       if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->mixmonitor_ds->chan && ast_bridged_channel(mixmonitor->mixmonitor_ds->chan))) {
00251          ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00252          /* Initialize the file if not already done so */
00253          if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
00254             oflags = O_CREAT | O_WRONLY;
00255             oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
00256 
00257             if ((ext = strrchr(mixmonitor->filename, '.')))
00258                *(ext++) = '\0';
00259             else
00260                ext = "raw";
00261 
00262             if (!(*fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644))) {
00263                ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
00264                errflag = 1;
00265             }
00266          }
00267 
00268          /* Write out the frame(s) */
00269          if (*fs) {
00270             struct ast_frame *cur;
00271 
00272             for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00273                ast_writestream(*fs, cur);
00274             }
00275          }
00276       } else {
00277          ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00278       }
00279 
00280       /* All done! free it. */
00281       ast_frame_free(fr, 0);
00282    }
00283 
00284    ast_audiohook_detach(&mixmonitor->audiohook);
00285    ast_audiohook_unlock(&mixmonitor->audiohook);
00286    ast_audiohook_destroy(&mixmonitor->audiohook);
00287 
00288    mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
00289 
00290    if (mixmonitor->post_process) {
00291       if (option_verbose > 2)
00292          ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", mixmonitor->post_process);
00293       ast_safe_system(mixmonitor->post_process);
00294    }
00295 
00296    ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00297    if (!mixmonitor->mixmonitor_ds->destruction_ok) {
00298       ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
00299    }
00300    ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00301 
00302    if (option_verbose > 1)
00303       ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", mixmonitor->name);
00304 
00305    mixmonitor_free(mixmonitor);
00306 
00307    return NULL;
00308 }

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

Definition at line 310 of file app_mixmonitor.c.

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

Referenced by launch_monitor_thread().

00311 {
00312    struct ast_datastore *datastore = NULL;
00313    struct mixmonitor_ds *mixmonitor_ds;
00314 
00315    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00316       return -1;
00317    }
00318    
00319    ast_mutex_init(&mixmonitor_ds->lock);
00320    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00321 
00322    if (!(datastore = ast_channel_datastore_alloc(&mixmonitor_ds_info, NULL))) {
00323       ast_mutex_destroy(&mixmonitor_ds->lock);
00324       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00325       ast_free(mixmonitor_ds);
00326       return -1;
00327    }
00328 
00329    /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
00330    mixmonitor_ds->chan = chan;
00331    datastore->data = mixmonitor_ds;
00332 
00333    ast_channel_lock(chan);
00334    ast_channel_datastore_add(chan, datastore);
00335    ast_channel_unlock(chan);
00336 
00337    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00338    return 0;
00339 }

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

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

00194 {
00195    struct ast_channel *peer;
00196    int res;
00197 
00198    if (!chan)
00199       return -1;
00200 
00201    res = ast_audiohook_attach(chan, audiohook);
00202 
00203    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00204       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00205 
00206    return res;
00207 }

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

Definition at line 499 of file app_mixmonitor.c.

References ast_audiohook_detach_source(), ast_channel_datastore_find(), ast_module_user_add, ast_module_user_remove, ast_datastore::data, mixmonitor_ds_close_fs(), and mixmonitor_ds_info.

Referenced by load_module().

00500 {
00501    struct ast_module_user *u;
00502    struct ast_datastore *datastore = NULL;
00503 
00504    /* closing the filestream here guarantees the file is avaliable to the dialplan
00505     * after calling StopMixMonitor */
00506    if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
00507       mixmonitor_ds_close_fs(datastore->data);
00508    }
00509 
00510    u = ast_module_user_add(chan);
00511 
00512    ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00513 
00514    ast_module_user_remove(u);
00515 
00516    return 0;
00517 }

static int unload_module ( void   )  [static]

Definition at line 555 of file app_mixmonitor.c.

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

00556 {
00557    int res;
00558 
00559    ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00560    res = ast_unregister_application(stop_app);
00561    res |= ast_unregister_application(app);
00562    
00563    ast_module_user_hangup_all();
00564 
00565    return res;
00566 }


Variable Documentation

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

Definition at line 579 of file app_mixmonitor.c.

const char* app = "MixMonitor" [static]

Definition at line 60 of file app_mixmonitor.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 579 of file app_mixmonitor.c.

struct ast_cli_entry cli_mixmonitor[] [static]

Definition at line 546 of file app_mixmonitor.c.

Referenced by load_module(), and unload_module().

const char* desc [static]

Definition at line 62 of file app_mixmonitor.c.

struct module_symbols* me

Definition at line 95 of file app_mixmonitor.c.

enum { ... } mixmonitor_args

struct ast_datastore_info mixmonitor_ds_info [static]

Initial value:

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

Definition at line 187 of file app_mixmonitor.c.

Referenced by setup_mixmonitor_ds(), and stop_mixmonitor_exec().

enum { ... } mixmonitor_flags

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

Definition at line 129 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

const char* mixmonitor_spy_type = "MixMonitor" [static]

Definition at line 97 of file app_mixmonitor.c.

const char* stop_app = "StopMixMonitor" [static]

Definition at line 88 of file app_mixmonitor.c.

const char* stop_desc [static]

Initial value:

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

Definition at line 90 of file app_mixmonitor.c.

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

Definition at line 89 of file app_mixmonitor.c.

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

Definition at line 61 of file app_mixmonitor.c.


Generated on Fri Sep 11 13:45:07 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7