Fri Feb 19 17:12:50 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 <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 destroy_monitor_audiohook (struct mixmonitor *mixmonitor)
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 = "361d7bb937402d51e4658efb5b4d76e4" , .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 227 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 621 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 621 of file app_mixmonitor.c.

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

Definition at line 583 of file app_mixmonitor.c.

References ast_complete_channels().

00584 {
00585    return ast_complete_channels(line, word, pos, state, 2);
00586 }

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

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

00198 {
00199    if (mixmonitor->mixmonitor_ds) {
00200       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00201       mixmonitor->mixmonitor_ds->audiohook = NULL;
00202       ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00203    }
00204    /* kill the audiohook.*/
00205    ast_audiohook_lock(&mixmonitor->audiohook);
00206    ast_audiohook_detach(&mixmonitor->audiohook);
00207    ast_audiohook_unlock(&mixmonitor->audiohook);
00208    ast_audiohook_destroy(&mixmonitor->audiohook);
00209 }

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 366 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(), mixmonitor::audiohook, calloc, 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().

00368 {
00369    pthread_attr_t attr;
00370    pthread_t thread;
00371    struct mixmonitor *mixmonitor;
00372    char postprocess2[1024] = "";
00373    size_t len;
00374 
00375    len = sizeof(*mixmonitor) + strlen(chan->name) + strlen(filename) + 2;
00376 
00377    /* If a post process system command is given attach it to the structure */
00378    if (!ast_strlen_zero(post_process)) {
00379       char *p1, *p2;
00380 
00381       p1 = ast_strdupa(post_process);
00382       for (p2 = p1; *p2 ; p2++) {
00383          if (*p2 == '^' && *(p2+1) == '{') {
00384             *p2 = '$';
00385          }
00386       }
00387 
00388       pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
00389       if (!ast_strlen_zero(postprocess2))
00390          len += strlen(postprocess2) + 1;
00391    }
00392 
00393    /* Pre-allocate mixmonitor structure and spy */
00394    if (!(mixmonitor = calloc(1, len))) {
00395       return;
00396    }
00397 
00398    /* Setup the actual spy before creating our thread */
00399    if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type)) {
00400       mixmonitor_free(mixmonitor);
00401       return;
00402    }
00403 
00404    /* Copy over flags and channel name */
00405    mixmonitor->flags = flags;
00406    if (setup_mixmonitor_ds(mixmonitor, chan)) {
00407       mixmonitor_free(mixmonitor);
00408       return;
00409    }
00410    mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
00411    strcpy(mixmonitor->name, chan->name);
00412    if (!ast_strlen_zero(postprocess2)) {
00413       mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
00414       strcpy(mixmonitor->post_process, postprocess2);
00415    }
00416 
00417    mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
00418    strcpy(mixmonitor->filename, filename);
00419 
00420    ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
00421    
00422    if (readvol)
00423       mixmonitor->audiohook.options.read_volume = readvol;
00424    if (writevol)
00425       mixmonitor->audiohook.options.write_volume = writevol;
00426 
00427    if (startmon(chan, &mixmonitor->audiohook)) {
00428       ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
00429          mixmonitor_spy_type, chan->name);
00430       /* Since we couldn't add ourselves - bail out! */
00431       ast_audiohook_destroy(&mixmonitor->audiohook);
00432       mixmonitor_free(mixmonitor);
00433       return;
00434    }
00435 
00436    pthread_attr_init(&attr);
00437    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00438    ast_pthread_create_background(&thread, &attr, mixmonitor_thread, mixmonitor);
00439    pthread_attr_destroy(&attr);
00440 }

static int load_module ( void   )  [static]

Definition at line 610 of file app_mixmonitor.c.

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

00611 {
00612    int res;
00613 
00614    ast_cli_register_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00615    res = ast_register_application(app, mixmonitor_exec, synopsis, desc);
00616    res |= ast_register_application(stop_app, stop_mixmonitor_exec, stop_synopsis, stop_desc);
00617 
00618    return res;
00619 }

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

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

00562 {
00563    struct ast_channel *chan;
00564 
00565    if (argc < 3)
00566       return RESULT_SHOWUSAGE;
00567 
00568    if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) {
00569       ast_cli(fd, "No channel matching '%s' found.\n", argv[2]);
00570       return RESULT_SUCCESS;
00571    }
00572 
00573    if (!strcasecmp(argv[1], "start"))
00574       mixmonitor_exec(chan, argv[3]);
00575    else if (!strcasecmp(argv[1], "stop"))
00576       ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00577 
00578    ast_channel_unlock(chan);
00579 
00580    return RESULT_SUCCESS;
00581 }

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

Definition at line 182 of file app_mixmonitor.c.

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

00183 {
00184    struct mixmonitor_ds *mixmonitor_ds = data;
00185 
00186    ast_mutex_lock(&mixmonitor_ds->lock);
00187    mixmonitor_ds->chan = new_chan;
00188    ast_mutex_unlock(&mixmonitor_ds->lock);
00189 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

Definition at line 159 of file app_mixmonitor.c.

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

Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().

00160 {
00161    if (mixmonitor_ds->fs) {
00162       ast_closestream(mixmonitor_ds->fs);
00163       mixmonitor_ds->fs = NULL;
00164       mixmonitor_ds->fs_quit = 1;
00165       if (option_verbose > 1)
00166          ast_verbose(VERBOSE_PREFIX_2 "MixMonitor close filestream\n");
00167    }
00168 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

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

00171 {
00172    struct mixmonitor_ds *mixmonitor_ds = data;
00173 
00174    ast_mutex_lock(&mixmonitor_ds->lock);
00175    mixmonitor_ds->audiohook = NULL;
00176    mixmonitor_ds->chan = NULL;
00177    mixmonitor_ds->destruction_ok = 1;
00178    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00179    ast_mutex_unlock(&mixmonitor_ds->lock);
00180 }

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

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

00443 {
00444    int x, readvol = 0, writevol = 0;
00445    struct ast_module_user *u;
00446    struct ast_flags flags = {0};
00447    char *parse;
00448    AST_DECLARE_APP_ARGS(args,
00449       AST_APP_ARG(filename);
00450       AST_APP_ARG(options);
00451       AST_APP_ARG(post_process);
00452    );
00453    
00454    if (ast_strlen_zero(data)) {
00455       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00456       return -1;
00457    }
00458 
00459    u = ast_module_user_add(chan);
00460 
00461    parse = ast_strdupa(data);
00462 
00463    AST_STANDARD_APP_ARGS(args, parse);
00464    
00465    if (ast_strlen_zero(args.filename)) {
00466       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00467       ast_module_user_remove(u);
00468       return -1;
00469    }
00470 
00471    if (args.options) {
00472       char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00473 
00474       ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
00475 
00476       if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
00477          if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
00478             ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
00479          } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00480             ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
00481          } else {
00482             readvol = get_volfactor(x);
00483          }
00484       }
00485       
00486       if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
00487          if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
00488             ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
00489          } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00490             ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
00491          } else {
00492             writevol = get_volfactor(x);
00493          }
00494       }
00495       
00496       if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
00497          if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
00498             ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
00499          } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00500             ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
00501          } else {
00502             readvol = writevol = get_volfactor(x);
00503          }
00504       }
00505    }
00506 
00507    /* if not provided an absolute path, use the system-configured monitoring directory */
00508    if (args.filename[0] != '/') {
00509       char *build;
00510 
00511       build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
00512       sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
00513       args.filename = build;
00514    }
00515 
00516    pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
00517    launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process);
00518 
00519    ast_module_user_remove(u);
00520 
00521    return 0;
00522 }

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

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

00230 {
00231    if (mixmonitor) {
00232       if (mixmonitor->mixmonitor_ds) {
00233          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00234          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00235          ast_free(mixmonitor->mixmonitor_ds);
00236       }
00237       ast_free(mixmonitor);
00238    }
00239 }

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

Definition at line 241 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_verbose(), 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, option_verbose, mixmonitor::post_process, SAMPLES_PER_FRAME, ast_audiohook::status, and VERBOSE_PREFIX_2.

Referenced by launch_monitor_thread().

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

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

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

Referenced by launch_monitor_thread().

00335 {
00336    struct ast_datastore *datastore = NULL;
00337    struct mixmonitor_ds *mixmonitor_ds;
00338 
00339    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00340       return -1;
00341    }
00342    
00343    ast_mutex_init(&mixmonitor_ds->lock);
00344    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00345 
00346    if (!(datastore = ast_channel_datastore_alloc(&mixmonitor_ds_info, NULL))) {
00347       ast_mutex_destroy(&mixmonitor_ds->lock);
00348       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00349       ast_free(mixmonitor_ds);
00350       return -1;
00351    }
00352 
00353    /* No need to lock mixmonitor_ds since this is still operating in the channel's thread */
00354    mixmonitor_ds->chan = chan;
00355    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00356    datastore->data = mixmonitor_ds;
00357 
00358    ast_channel_lock(chan);
00359    ast_channel_datastore_add(chan, datastore);
00360    ast_channel_unlock(chan);
00361 
00362    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00363    return 0;
00364 }

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

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

00212 {
00213    struct ast_channel *peer;
00214    int res;
00215 
00216    if (!chan)
00217       return -1;
00218 
00219    res = ast_audiohook_attach(chan, audiohook);
00220 
00221    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00222       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00223 
00224    return res;
00225 }

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

Definition at line 524 of file app_mixmonitor.c.

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

Referenced by load_module().

00525 {
00526    struct ast_datastore *datastore = NULL;
00527 
00528    ast_channel_lock(chan);
00529    ast_audiohook_detach_source(chan, mixmonitor_spy_type);
00530    if ((datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, NULL))) {
00531       struct mixmonitor_ds *mixmonitor_ds = datastore->data;
00532 
00533       ast_mutex_lock(&mixmonitor_ds->lock);
00534 
00535       /* closing the filestream here guarantees the file is avaliable to the dialplan
00536        * after calling StopMixMonitor */
00537       mixmonitor_ds_close_fs(mixmonitor_ds);
00538 
00539       /* The mixmonitor thread may be waiting on the audiohook trigger.
00540        * In order to exit from the mixmonitor loop before waiting on channel
00541        * destruction, poke the audiohook trigger. */
00542       if (mixmonitor_ds->audiohook) {
00543          ast_audiohook_lock(mixmonitor_ds->audiohook);
00544          ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
00545          ast_audiohook_unlock(mixmonitor_ds->audiohook);
00546          mixmonitor_ds->audiohook = NULL;
00547       }
00548 
00549       ast_mutex_unlock(&mixmonitor_ds->lock);
00550 
00551       /* Remove the datastore so the monitor thread can exit */
00552       if (!ast_channel_datastore_remove(chan, datastore)) {
00553          ast_channel_datastore_free(datastore);
00554       }
00555    }
00556    ast_channel_unlock(chan);
00557 
00558    return 0;
00559 }

static int unload_module ( void   )  [static]

Definition at line 597 of file app_mixmonitor.c.

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

00598 {
00599    int res;
00600 
00601    ast_cli_unregister_multiple(cli_mixmonitor, sizeof(cli_mixmonitor) / sizeof(struct ast_cli_entry));
00602    res = ast_unregister_application(stop_app);
00603    res |= ast_unregister_application(app);
00604    
00605    ast_module_user_hangup_all();
00606 
00607    return res;
00608 }


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

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

struct ast_cli_entry cli_mixmonitor[] [static]

Definition at line 588 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 191 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 Feb 19 17:12:50 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7