Sat Feb 11 06:33:49 2012

Asterisk developer's documentation


app_mixmonitor.c File Reference

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

#include "asterisk.h"
#include "asterisk/paths.h"
#include "asterisk/file.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/channel.h"
#include "asterisk/autochan.h"
#include "asterisk/manager.h"
#include "asterisk/mod_format.h"
#include "asterisk/linkedlists.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  mixmonitor_args {
  OPT_ARG_READVOLUME = 0, OPT_ARG_WRITEVOLUME, OPT_ARG_VOLUME, OPT_ARG_WRITENAME,
  OPT_ARG_READNAME, OPT_ARG_UID, 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), MUXFLAG_READ = (1 << 6), MUXFLAG_WRITE = (1 << 7), MUXFLAG_COMBINED = (1 << 8),
  MUXFLAG_UID = (1 << 9)
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void destroy_monitor_audiohook (struct mixmonitor *mixmonitor)
static char * filename_parse (char *filename, char *buffer, size_t len)
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, const char *filename_write, char *filename_read, const char *uid_channel_var)
static int load_module (void)
static int manager_mixmonitor (struct mansession *s, const struct message *m)
static int manager_mute_mixmonitor (struct mansession *s, const struct message *m)
 Mute / unmute a MixMonitor channel.
static int manager_stop_mixmonitor (struct mansession *s, const struct message *m)
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_save_prep (struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag)
static void * mixmonitor_thread (void *obj)
static int setup_mixmonitor_ds (struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id)
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 = AST_BUILDOPT_SUM, .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 }, [ 'r' ] = { .flag = MUXFLAG_READ , .arg_index = OPT_ARG_READNAME + 1 }, [ 't' ] = { .flag = MUXFLAG_WRITE , .arg_index = OPT_ARG_WRITENAME + 1 }, [ 'i' ] = { .flag = MUXFLAG_UID , .arg_index = OPT_ARG_UID + 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 233 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

Definition at line 384 of file app_mixmonitor.c.

Referenced by mixmonitor_thread().


Enumeration Type Documentation

Enumerator:
OPT_ARG_READVOLUME 
OPT_ARG_WRITEVOLUME 
OPT_ARG_VOLUME 
OPT_ARG_WRITENAME 
OPT_ARG_READNAME 
OPT_ARG_UID 
OPT_ARG_ARRAY_SIZE 

Definition at line 265 of file app_mixmonitor.c.

00265                      {
00266    OPT_ARG_READVOLUME = 0,
00267    OPT_ARG_WRITEVOLUME,
00268    OPT_ARG_VOLUME,
00269    OPT_ARG_WRITENAME,
00270    OPT_ARG_READNAME,
00271         OPT_ARG_UID,
00272    OPT_ARG_ARRAY_SIZE,  /* Always last element of the enum */
00273 };

Enumerator:
MUXFLAG_APPEND 
MUXFLAG_BRIDGED 
MUXFLAG_VOLUME 
MUXFLAG_READVOLUME 
MUXFLAG_WRITEVOLUME 
MUXFLAG_READ 
MUXFLAG_WRITE 
MUXFLAG_COMBINED 
MUXFLAG_UID 

Definition at line 253 of file app_mixmonitor.c.

00253                       {
00254    MUXFLAG_APPEND = (1 << 1),
00255    MUXFLAG_BRIDGED = (1 << 2),
00256    MUXFLAG_VOLUME = (1 << 3),
00257    MUXFLAG_READVOLUME = (1 << 4),
00258    MUXFLAG_WRITEVOLUME = (1 << 5),
00259    MUXFLAG_READ = (1 << 6),
00260    MUXFLAG_WRITE = (1 << 7),
00261    MUXFLAG_COMBINED = (1 << 8),
00262         MUXFLAG_UID = (1 << 9),
00263 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1118 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 1118 of file app_mixmonitor.c.

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

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

00355 {
00356    if (mixmonitor->mixmonitor_ds) {
00357       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00358       mixmonitor->mixmonitor_ds->audiohook = NULL;
00359       ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00360    }
00361    /* kill the audiohook.*/
00362    ast_audiohook_lock(&mixmonitor->audiohook);
00363    ast_audiohook_detach(&mixmonitor->audiohook);
00364    ast_audiohook_unlock(&mixmonitor->audiohook);
00365    ast_audiohook_destroy(&mixmonitor->audiohook);
00366 }

static char* filename_parse ( char *  filename,
char *  buffer,
size_t  len 
) [static]

Definition at line 682 of file app_mixmonitor.c.

References ast_config_AST_MONITOR_DIR, ast_copy_string(), ast_log(), ast_mkdir(), ast_strlen_zero(), and LOG_WARNING.

Referenced by mixmonitor_exec().

00683 {
00684    char *slash;
00685    if (ast_strlen_zero(filename)) {
00686       ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
00687    } else if (filename[0] != '/') {
00688       char *build;
00689       build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
00690       sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
00691       filename = build;
00692    }
00693 
00694    ast_copy_string(buffer, filename, len);
00695 
00696    if ((slash = strrchr(filename, '/'))) {
00697       *slash = '\0';
00698    }
00699    ast_mkdir(filename, 0777);
00700 
00701    return buffer;
00702 }

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

Definition at line 848 of file app_mixmonitor.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_channel_get_by_name_prefix(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), AST_LIST_TRAVERSE, ast_strdupa, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_datastore::data, ast_channel::datastores, ast_cli_args::fd, ast_filestream::filename, mixmonitor_ds::fs, mixmonitor_ds::fs_read, mixmonitor_ds::fs_write, ast_datastore::info, ast_cli_args::line, mixmonitor_exec(), ast_cli_args::n, ast_cli_args::pos, stop_mixmonitor_exec(), ast_cli_entry::usage, and ast_cli_args::word.

00849 {
00850    struct ast_channel *chan;
00851    struct ast_datastore *datastore = NULL;
00852    struct mixmonitor_ds *mixmonitor_ds = NULL;
00853 
00854    switch (cmd) {
00855    case CLI_INIT:
00856       e->command = "mixmonitor {start|stop|list}";
00857       e->usage =
00858          "Usage: mixmonitor <start|stop|list> <chan_name> [args]\n"
00859          "       The optional arguments are passed to the MixMonitor\n"
00860          "       application when the 'start' command is used.\n";
00861       return NULL;
00862    case CLI_GENERATE:
00863       return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
00864    }
00865 
00866    if (a->argc < 3) {
00867       return CLI_SHOWUSAGE;
00868    }
00869 
00870    if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
00871       ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
00872       /* Technically this is a failure, but we don't want 2 errors printing out */
00873       return CLI_SUCCESS;
00874    }
00875 
00876    ast_channel_lock(chan);
00877 
00878    if (!strcasecmp(a->argv[1], "start")) {
00879       mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
00880       ast_channel_unlock(chan);
00881    } else if (!strcasecmp(a->argv[1], "stop")){
00882       ast_channel_unlock(chan);
00883       stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
00884    } else if (!strcasecmp(a->argv[1], "list")) {
00885       ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
00886       ast_cli(a->fd, "=========================================================================\n");
00887       AST_LIST_TRAVERSE(&chan->datastores, datastore, entry) {
00888          if (datastore->info == &mixmonitor_ds_info) {
00889             char *filename = "";
00890             char *filename_read = "";
00891             char *filename_write = "";
00892             mixmonitor_ds = datastore->data;
00893             if (mixmonitor_ds->fs)
00894                filename = ast_strdupa(mixmonitor_ds->fs->filename);
00895             if (mixmonitor_ds->fs_read)
00896                filename_read = ast_strdupa(mixmonitor_ds->fs_read->filename);
00897             if (mixmonitor_ds->fs_write)
00898                filename_write = ast_strdupa(mixmonitor_ds->fs_write->filename);
00899             ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
00900          }
00901       }
00902       ast_channel_unlock(chan);
00903    } else {
00904       ast_channel_unlock(chan);
00905       chan = ast_channel_unref(chan);
00906       return CLI_SHOWUSAGE;
00907    }
00908 
00909    chan = ast_channel_unref(chan);
00910 
00911    return CLI_SUCCESS;
00912 }

static void launch_monitor_thread ( struct ast_channel chan,
const char *  filename,
unsigned int  flags,
int  readvol,
int  writevol,
const char *  post_process,
const char *  filename_write,
char *  filename_read,
const char *  uid_channel_var 
) [static]

Definition at line 587 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_channel_name(), ast_free, ast_log(), ast_pthread_create_detached_background, ast_set_flag, ast_strdup, ast_strdupa, ast_strlen_zero(), mixmonitor::audiohook, mixmonitor::autochan, mixmonitor::filename, mixmonitor::filename_read, mixmonitor::filename_write, mixmonitor::flags, LOG_WARNING, mixmonitor_free(), mixmonitor_thread(), mixmonitor::name, ast_audiohook::options, pbx_builtin_setvar_helper(), 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().

00591 {
00592    pthread_t thread;
00593    struct mixmonitor *mixmonitor;
00594    char postprocess2[1024] = "";
00595    char *datastore_id = NULL;
00596 
00597    postprocess2[0] = 0;
00598    /* If a post process system command is given attach it to the structure */
00599    if (!ast_strlen_zero(post_process)) {
00600       char *p1, *p2;
00601 
00602       p1 = ast_strdupa(post_process);
00603       for (p2 = p1; *p2; p2++) {
00604          if (*p2 == '^' && *(p2+1) == '{') {
00605             *p2 = '$';
00606          }
00607       }
00608       pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
00609    }
00610 
00611    /* Pre-allocate mixmonitor structure and spy */
00612    if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
00613       return;
00614    }
00615 
00616    /* Setup the actual spy before creating our thread */
00617    if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
00618       mixmonitor_free(mixmonitor);
00619       return;
00620    }
00621 
00622    /* Copy over flags and channel name */
00623    mixmonitor->flags = flags;
00624    if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
00625       mixmonitor_free(mixmonitor);
00626       return;
00627    }
00628 
00629    if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id)) {
00630       ast_autochan_destroy(mixmonitor->autochan);
00631       mixmonitor_free(mixmonitor);
00632       ast_free(datastore_id);
00633       return;
00634    }
00635 
00636    if (!ast_strlen_zero(uid_channel_var)) {
00637       if (datastore_id) {
00638          pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
00639       }
00640    }
00641    ast_free(datastore_id);
00642 
00643 
00644    mixmonitor->name = ast_strdup(ast_channel_name(chan));
00645 
00646    if (!ast_strlen_zero(postprocess2)) {
00647       mixmonitor->post_process = ast_strdup(postprocess2);
00648    }
00649 
00650    if (!ast_strlen_zero(filename)) {
00651       mixmonitor->filename = ast_strdup(filename);
00652    }
00653 
00654    if (!ast_strlen_zero(filename_write)) {
00655       mixmonitor->filename_write = ast_strdup(filename_write);
00656    }
00657 
00658    if (!ast_strlen_zero(filename_read)) {
00659       mixmonitor->filename_read = ast_strdup(filename_read);
00660    }
00661 
00662    ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
00663 
00664    if (readvol)
00665       mixmonitor->audiohook.options.read_volume = readvol;
00666    if (writevol)
00667       mixmonitor->audiohook.options.write_volume = writevol;
00668 
00669    if (startmon(chan, &mixmonitor->audiohook)) {
00670       ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
00671          mixmonitor_spy_type, ast_channel_name(chan));
00672       ast_audiohook_destroy(&mixmonitor->audiohook);
00673       mixmonitor_free(mixmonitor);
00674       return;
00675    }
00676 
00677    ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
00678 }

static int load_module ( void   )  [static]

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

Definition at line 981 of file app_mixmonitor.c.

References AMI_SUCCESS, args, ast_app_parse_options(), ast_channel_get_by_name(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_strdupa, ast_strlen_zero(), ast_test_flag, astman_append(), astman_get_header(), astman_send_error(), mixmonitor_exec(), mixmonitor_opts, MUXFLAG_UID, name, OPT_ARG_ARRAY_SIZE, OPT_ARG_UID, and pbx_builtin_getvar_helper().

Referenced by load_module().

00982 {
00983    struct ast_channel *c = NULL;
00984 
00985    const char *name = astman_get_header(m, "Channel");
00986    const char *id = astman_get_header(m, "ActionID");
00987    const char *file = astman_get_header(m, "File");
00988    const char *options = astman_get_header(m, "Options");
00989    char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00990    struct ast_flags flags = { 0 };
00991    char *uid_channel_var = NULL;
00992    const char *mixmonitor_id = NULL;
00993 
00994    int res;
00995    char args[PATH_MAX] = "";
00996    if (ast_strlen_zero(name)) {
00997       astman_send_error(s, m, "No channel specified");
00998       return AMI_SUCCESS;
00999    }
01000 
01001    c = ast_channel_get_by_name(name);
01002 
01003    if (!c) {
01004       astman_send_error(s, m, "No such channel");
01005       return AMI_SUCCESS;
01006    }
01007 
01008    if (!ast_strlen_zero(options)) {
01009       ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
01010    }
01011 
01012    snprintf(args, sizeof(args), "%s,%s", file, options);
01013 
01014    ast_channel_lock(c);
01015    res = mixmonitor_exec(c, args);
01016 
01017    if (ast_test_flag(&flags, MUXFLAG_UID)) {
01018       uid_channel_var = opts[OPT_ARG_UID];
01019       mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
01020    }
01021    ast_channel_unlock(c);
01022 
01023    if (res) {
01024       astman_send_error(s, m, "Could not start monitoring channel");
01025       return AMI_SUCCESS;
01026    }
01027 
01028    astman_append(s, "Response: Success\r\n");
01029 
01030    if (!ast_strlen_zero(id)) {
01031       astman_append(s, "ActionID: %s\r\n", id);
01032    }
01033 
01034    if (!ast_strlen_zero(mixmonitor_id)) {
01035       astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
01036    }
01037 
01038    astman_append(s, "\r\n");
01039 
01040    c = ast_channel_unref(c);
01041 
01042    return AMI_SUCCESS;
01043 }

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

Mute / unmute a MixMonitor channel.

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

00916 {
00917    struct ast_channel *c = NULL;
00918 
00919    const char *name = astman_get_header(m, "Channel");
00920    const char *id = astman_get_header(m, "ActionID");
00921    const char *state = astman_get_header(m, "State");
00922    const char *direction = astman_get_header(m,"Direction");
00923 
00924    int clearmute = 1;
00925 
00926    enum ast_audiohook_flags flag;
00927 
00928    if (ast_strlen_zero(direction)) {
00929       astman_send_error(s, m, "No direction specified. Must be read, write or both");
00930       return AMI_SUCCESS;
00931    }
00932 
00933    if (!strcasecmp(direction, "read")) {
00934       flag = AST_AUDIOHOOK_MUTE_READ;
00935    } else  if (!strcasecmp(direction, "write")) {
00936       flag = AST_AUDIOHOOK_MUTE_WRITE;
00937    } else  if (!strcasecmp(direction, "both")) {
00938       flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
00939    } else {
00940       astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
00941       return AMI_SUCCESS;
00942    }
00943 
00944    if (ast_strlen_zero(name)) {
00945       astman_send_error(s, m, "No channel specified");
00946       return AMI_SUCCESS;
00947    }
00948 
00949    if (ast_strlen_zero(state)) {
00950       astman_send_error(s, m, "No state specified");
00951       return AMI_SUCCESS;
00952    }
00953 
00954    clearmute = ast_false(state);
00955    c = ast_channel_get_by_name(name);
00956 
00957    if (!c) {
00958       astman_send_error(s, m, "No such channel");
00959       return AMI_SUCCESS;
00960    }
00961 
00962    if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
00963       c = ast_channel_unref(c);
00964       astman_send_error(s, m, "Cannot set mute flag");
00965       return AMI_SUCCESS;
00966    }
00967 
00968    astman_append(s, "Response: Success\r\n");
00969 
00970    if (!ast_strlen_zero(id)) {
00971       astman_append(s, "ActionID: %s\r\n", id);
00972    }
00973 
00974    astman_append(s, "\r\n");
00975 
00976    c = ast_channel_unref(c);
00977 
00978    return AMI_SUCCESS;
00979 }

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

Definition at line 1045 of file app_mixmonitor.c.

References AMI_SUCCESS, ast_channel_get_by_name(), ast_channel_unref, ast_strlen_zero(), astman_append(), astman_get_header(), astman_send_error(), name, and stop_mixmonitor_exec().

Referenced by load_module().

01046 {
01047    struct ast_channel *c = NULL;
01048 
01049    const char *name = astman_get_header(m, "Channel");
01050    const char *id = astman_get_header(m, "ActionID");
01051    const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
01052 
01053    int res;
01054    if (ast_strlen_zero(name)) {
01055       astman_send_error(s, m, "No channel specified");
01056       return AMI_SUCCESS;
01057    }
01058 
01059    c = ast_channel_get_by_name(name);
01060 
01061    if (!c) {
01062       astman_send_error(s, m, "No such channel");
01063       return AMI_SUCCESS;
01064    }
01065 
01066    res = stop_mixmonitor_exec(c, mixmonitor_id);
01067 
01068    if (res) {
01069       astman_send_error(s, m, "Could not stop monitoring channel");
01070       return AMI_SUCCESS;
01071    }
01072 
01073    astman_append(s, "Response: Success\r\n");
01074 
01075    if (!ast_strlen_zero(id)) {
01076       astman_append(s, "ActionID: %s\r\n", id);
01077    }
01078 
01079    astman_append(s, "\r\n");
01080 
01081    c = ast_channel_unref(c);
01082 
01083    return AMI_SUCCESS;
01084 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

Definition at line 308 of file app_mixmonitor.c.

References ast_closestream(), ast_verb, mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::fs_read, and mixmonitor_ds::fs_write.

Referenced by mixmonitor_thread(), and stop_mixmonitor_exec().

00309 {
00310    unsigned char quitting = 0;
00311 
00312    if (mixmonitor_ds->fs) {
00313       quitting = 1;
00314       ast_closestream(mixmonitor_ds->fs);
00315       mixmonitor_ds->fs = NULL;
00316       ast_verb(2, "MixMonitor close filestream (mixed)\n");
00317    }
00318 
00319    if (mixmonitor_ds->fs_read) {
00320       quitting = 1;
00321       ast_closestream(mixmonitor_ds->fs_read);
00322       mixmonitor_ds->fs_read = NULL;
00323       ast_verb(2, "MixMonitor close filestream (read)\n");
00324    }
00325 
00326    if (mixmonitor_ds->fs_write) {
00327       quitting = 1;
00328       ast_closestream(mixmonitor_ds->fs_write);
00329       mixmonitor_ds->fs_write = NULL;
00330       ast_verb(2, "MixMonitor close filestream (write)\n");
00331    }
00332 
00333    if (quitting) {
00334       mixmonitor_ds->fs_quit = 1;
00335    }
00336 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

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

00339 {
00340    struct mixmonitor_ds *mixmonitor_ds = data;
00341 
00342    ast_mutex_lock(&mixmonitor_ds->lock);
00343    mixmonitor_ds->audiohook = NULL;
00344    mixmonitor_ds->destruction_ok = 1;
00345    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00346    ast_mutex_unlock(&mixmonitor_ds->lock);
00347 }

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

Definition at line 704 of file app_mixmonitor.c.

References args, AST_APP_ARG, ast_app_parse_options(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, filename_parse(), mixmonitor::filename_read, mixmonitor::filename_write, ast_flags::flags, get_volfactor, launch_monitor_thread(), LOG_NOTICE, LOG_WARNING, mixmonitor_opts, MUXFLAG_READ, MUXFLAG_READVOLUME, MUXFLAG_UID, MUXFLAG_VOLUME, MUXFLAG_WRITE, MUXFLAG_WRITEVOLUME, OPT_ARG_ARRAY_SIZE, OPT_ARG_READNAME, OPT_ARG_READVOLUME, OPT_ARG_UID, OPT_ARG_VOLUME, OPT_ARG_WRITENAME, OPT_ARG_WRITEVOLUME, parse(), and pbx_builtin_setvar_helper().

Referenced by handle_cli_mixmonitor(), load_module(), and manager_mixmonitor().

00705 {
00706    int x, readvol = 0, writevol = 0;
00707    char *filename_read = NULL;
00708    char *filename_write = NULL;
00709    char filename_buffer[1024] = "";
00710         char *uid_channel_var = NULL;
00711 
00712    struct ast_flags flags = { 0 };
00713    char *parse;
00714    AST_DECLARE_APP_ARGS(args,
00715       AST_APP_ARG(filename);
00716       AST_APP_ARG(options);
00717       AST_APP_ARG(post_process);
00718    );
00719 
00720    if (ast_strlen_zero(data)) {
00721       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
00722       return -1;
00723    }
00724 
00725    parse = ast_strdupa(data);
00726 
00727    AST_STANDARD_APP_ARGS(args, parse);
00728 
00729    if (args.options) {
00730       char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
00731 
00732       ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
00733 
00734       if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
00735          if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
00736             ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
00737          } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00738             ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
00739          } else {
00740             readvol = get_volfactor(x);
00741          }
00742       }
00743 
00744       if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
00745          if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
00746             ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
00747          } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00748             ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
00749          } else {
00750             writevol = get_volfactor(x);
00751          }
00752       }
00753 
00754       if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
00755          if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
00756             ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
00757          } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
00758             ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
00759          } else {
00760             readvol = writevol = get_volfactor(x);
00761          }
00762       }
00763 
00764       if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
00765          filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
00766       }
00767 
00768       if (ast_test_flag(&flags, MUXFLAG_READ)) {
00769          filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
00770       }
00771 
00772       if (ast_test_flag(&flags, MUXFLAG_UID)) {
00773          uid_channel_var = opts[OPT_ARG_UID];
00774       }
00775    }
00776    /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
00777 
00778    if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
00779       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
00780       return -1;
00781    }
00782 
00783    /* If filename exists, try to create directories for it */
00784    if (!(ast_strlen_zero(args.filename))) {
00785       args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
00786    }
00787 
00788    pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
00789    launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, filename_write, filename_read, uid_channel_var);
00790 
00791    return 0;
00792 }

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

Definition at line 386 of file app_mixmonitor.c.

References ast_cond_destroy, ast_free, ast_mutex_destroy, mixmonitor_ds::destruction_condition, mixmonitor::filename_read, mixmonitor::filename_write, mixmonitor_ds::lock, mixmonitor::mixmonitor_ds, mixmonitor::name, and mixmonitor::post_process.

Referenced by launch_monitor_thread(), and mixmonitor_thread().

00387 {
00388    if (mixmonitor) {
00389       if (mixmonitor->mixmonitor_ds) {
00390          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00391          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00392          ast_free(mixmonitor->filename_write);
00393          ast_free(mixmonitor->filename_read);
00394          ast_free(mixmonitor->mixmonitor_ds);
00395          ast_free(mixmonitor->name);
00396          ast_free(mixmonitor->post_process);
00397       }
00398       ast_free(mixmonitor);
00399    }
00400 }

static void mixmonitor_save_prep ( struct mixmonitor mixmonitor,
char *  filename,
struct ast_filestream **  fs,
unsigned int *  oflags,
int *  errflag 
) [static]

Definition at line 402 of file app_mixmonitor.c.

References ast_format_rate(), ast_log(), ast_strlen_zero(), ast_test_flag, ast_writefile(), ext, ast_filestream::fmt, ast_format_def::format, mixmonitor_ds::fs_quit, LOG_ERROR, MAX, mixmonitor::mixmonitor_ds, MUXFLAG_APPEND, and mixmonitor_ds::samp_rate.

Referenced by mixmonitor_thread().

00403 {
00404    /* Initialize the file if not already done so */
00405    char *ext = NULL;
00406    char *last_slash = NULL;
00407    if (!ast_strlen_zero(filename)) {
00408       if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
00409          *oflags = O_CREAT | O_WRONLY;
00410          *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
00411 
00412          last_slash = strrchr(filename, '/');
00413 
00414          if ((ext = strrchr(filename, '.')) && (ext > last_slash)) {
00415             *(ext++) = '\0';
00416          } else {
00417             ext = "raw";
00418          }
00419 
00420          if (!(*fs = ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) {
00421             ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext);
00422             *errflag = 1;
00423          } else {
00424             struct ast_filestream *tmp = *fs;
00425             mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_rate(&tmp->fmt->format));
00426          }
00427       }
00428    }
00429 }

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

Definition at line 431 of file app_mixmonitor.c.

References ast_audiohook_lock, ast_audiohook_read_frame_all(), AST_AUDIOHOOK_STATUS_RUNNING, ast_audiohook_trigger_wait(), ast_audiohook_unlock, ast_autochan_destroy(), ast_bridged_channel(), ast_cond_wait, ast_format_set(), ast_format_slin_by_rate(), ast_frame_free(), AST_LIST_NEXT, ast_mutex_lock, ast_mutex_unlock, ast_safe_system(), ast_test_flag, ast_verb, ast_writestream(), mixmonitor::audiohook, mixmonitor::autochan, ast_autochan::chan, destroy_monitor_audiohook(), mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, mixmonitor::filename, mixmonitor::filename_read, mixmonitor::filename_write, mixmonitor_ds::fs, mixmonitor_ds::fs_quit, mixmonitor_ds::fs_read, mixmonitor_ds::fs_write, mixmonitor_ds::lock, mixmonitor::mixmonitor_ds, mixmonitor_ds_close_fs(), mixmonitor_free(), mixmonitor_save_prep(), MUXFLAG_BRIDGED, mixmonitor::name, mixmonitor::post_process, mixmonitor_ds::samp_rate, SAMPLES_PER_FRAME, and ast_audiohook::status.

Referenced by launch_monitor_thread().

00432 {
00433    struct mixmonitor *mixmonitor = obj;
00434 
00435    struct ast_filestream **fs = NULL;
00436    struct ast_filestream **fs_read = NULL;
00437    struct ast_filestream **fs_write = NULL;
00438 
00439    unsigned int oflags;
00440    int errflag = 0;
00441    struct ast_format format_slin;
00442 
00443    ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
00444 
00445    fs = &mixmonitor->mixmonitor_ds->fs;
00446    fs_read = &mixmonitor->mixmonitor_ds->fs_read;
00447    fs_write = &mixmonitor->mixmonitor_ds->fs_write;
00448 
00449    ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00450    mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
00451    mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
00452    mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);
00453 
00454    ast_format_set(&format_slin, ast_format_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate), 0);
00455 
00456    ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00457 
00458 
00459    /* The audiohook must enter and exit the loop locked */
00460    ast_audiohook_lock(&mixmonitor->audiohook);
00461    while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
00462       struct ast_frame *fr = NULL;
00463       struct ast_frame *fr_read = NULL;
00464       struct ast_frame *fr_write = NULL;
00465 
00466       if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
00467                   &fr_read, &fr_write))) {
00468          ast_audiohook_trigger_wait(&mixmonitor->audiohook);
00469 
00470          if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00471             break;
00472          }
00473          continue;
00474       }
00475 
00476       /* audiohook lock is not required for the next block.
00477        * Unlock it, but remember to lock it before looping or exiting */
00478       ast_audiohook_unlock(&mixmonitor->audiohook);
00479 
00480       if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
00481          ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00482 
00483          /* Write out the frame(s) */
00484          if ((*fs_read) && (fr_read)) {
00485             struct ast_frame *cur;
00486 
00487             for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00488                ast_writestream(*fs_read, cur);
00489             }
00490          }
00491 
00492          if ((*fs_write) && (fr_write)) {
00493             struct ast_frame *cur;
00494 
00495             for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00496                ast_writestream(*fs_write, cur);
00497             }
00498          }
00499 
00500          if ((*fs) && (fr)) {
00501             struct ast_frame *cur;
00502 
00503             for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00504                ast_writestream(*fs, cur);
00505             }
00506          }
00507          ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00508       }
00509       /* All done! free it. */
00510       if (fr) {
00511          ast_frame_free(fr, 0);
00512       }
00513       if (fr_read) {
00514          ast_frame_free(fr_read, 0);
00515       }
00516       if (fr_write) {
00517          ast_frame_free(fr_write, 0);
00518       }
00519 
00520       fr = NULL;
00521       fr_write = NULL;
00522       fr_read = NULL;
00523 
00524       ast_audiohook_lock(&mixmonitor->audiohook);
00525    }
00526    ast_audiohook_unlock(&mixmonitor->audiohook);
00527 
00528    ast_autochan_destroy(mixmonitor->autochan);
00529 
00530    /* Datastore cleanup.  close the filestream and wait for ds destruction */
00531    ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00532    mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
00533    if (!mixmonitor->mixmonitor_ds->destruction_ok) {
00534       ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
00535    }
00536    ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00537 
00538    /* kill the audiohook */
00539    destroy_monitor_audiohook(mixmonitor);
00540 
00541    if (mixmonitor->post_process) {
00542       ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
00543       ast_safe_system(mixmonitor->post_process);
00544    }
00545 
00546    ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
00547    mixmonitor_free(mixmonitor);
00548    return NULL;
00549 }

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

Definition at line 551 of file app_mixmonitor.c.

References ast_asprintf, ast_calloc, ast_channel_datastore_add(), ast_channel_lock, ast_channel_unlock, ast_cond_destroy, ast_cond_init, ast_datastore_alloc, ast_free, ast_log(), ast_mutex_destroy, ast_mutex_init, mixmonitor::audiohook, mixmonitor_ds::audiohook, ast_datastore::data, mixmonitor_ds::destruction_condition, mixmonitor_ds::lock, LOG_ERROR, mixmonitor::mixmonitor_ds, and mixmonitor_ds::samp_rate.

Referenced by launch_monitor_thread().

00552 {
00553    struct ast_datastore *datastore = NULL;
00554    struct mixmonitor_ds *mixmonitor_ds;
00555 
00556    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00557       return -1;
00558    }
00559 
00560    if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
00561       ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
00562    }
00563 
00564    ast_mutex_init(&mixmonitor_ds->lock);
00565    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00566 
00567    if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
00568       ast_mutex_destroy(&mixmonitor_ds->lock);
00569       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00570       ast_free(mixmonitor_ds);
00571       return -1;
00572    }
00573 
00574 
00575    mixmonitor_ds->samp_rate = 8000;
00576    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00577    datastore->data = mixmonitor_ds;
00578 
00579    ast_channel_lock(chan);
00580    ast_channel_datastore_add(chan, datastore);
00581    ast_channel_unlock(chan);
00582 
00583    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00584    return 0;
00585 }

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

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

00369 {
00370    struct ast_channel *peer = NULL;
00371    int res = 0;
00372 
00373    if (!chan)
00374       return -1;
00375 
00376    ast_audiohook_attach(chan, audiohook);
00377 
00378    if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
00379       ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);  
00380 
00381    return res;
00382 }

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

Definition at line 794 of file app_mixmonitor.c.

References args, AST_APP_ARG, ast_audiohook_lock, AST_AUDIOHOOK_STATUS_DONE, AST_AUDIOHOOK_STATUS_SHUTDOWN, ast_audiohook_unlock, ast_audiohook_update_status(), ast_channel_datastore_find(), ast_channel_datastore_remove(), ast_channel_lock, ast_channel_unlock, ast_cond_signal, ast_datastore_free(), AST_DECLARE_APP_ARGS, ast_mutex_lock, ast_mutex_unlock, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), mixmonitor_ds::audiohook, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), parse(), ast_audiohook::status, and ast_audiohook::trigger.

Referenced by handle_cli_mixmonitor(), load_module(), and manager_stop_mixmonitor().

00795 {
00796    struct ast_datastore *datastore = NULL;
00797    char *parse = "";
00798    struct mixmonitor_ds *mixmonitor_ds;
00799 
00800    AST_DECLARE_APP_ARGS(args,
00801       AST_APP_ARG(mixmonid);
00802    );
00803 
00804    if (!ast_strlen_zero(data)) {
00805       parse = ast_strdupa(data);
00806    }
00807 
00808    AST_STANDARD_APP_ARGS(args, parse);
00809 
00810    ast_channel_lock(chan);
00811 
00812    if (!(datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.mixmonid))) {
00813       ast_channel_unlock(chan);
00814                 return -1;
00815    }
00816    mixmonitor_ds = datastore->data;
00817 
00818    ast_mutex_lock(&mixmonitor_ds->lock);
00819 
00820    /* closing the filestream here guarantees the file is avaliable to the dialplan
00821     * after calling StopMixMonitor */
00822    mixmonitor_ds_close_fs(mixmonitor_ds);
00823 
00824    /* The mixmonitor thread may be waiting on the audiohook trigger.
00825     * In order to exit from the mixmonitor loop before waiting on channel
00826     * destruction, poke the audiohook trigger. */
00827    if (mixmonitor_ds->audiohook) {
00828       if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
00829          ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
00830       }
00831       ast_audiohook_lock(mixmonitor_ds->audiohook);
00832       ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
00833       ast_audiohook_unlock(mixmonitor_ds->audiohook);
00834       mixmonitor_ds->audiohook = NULL;
00835    }
00836 
00837    ast_mutex_unlock(&mixmonitor_ds->lock);
00838 
00839    /* Remove the datastore so the monitor thread can exit */
00840    if (!ast_channel_datastore_remove(chan, datastore)) {
00841       ast_datastore_free(datastore);
00842    }
00843    ast_channel_unlock(chan);
00844 
00845    return 0;
00846 }

static int unload_module ( void   )  [static]

Definition at line 1090 of file app_mixmonitor.c.

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

01091 {
01092    int res;
01093 
01094    ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
01095    res = ast_unregister_application(stop_app);
01096    res |= ast_unregister_application(app);
01097    res |= ast_manager_unregister("MixMonitorMute");
01098    res |= ast_manager_unregister("MixMonitor");
01099    res |= ast_manager_unregister("StopMixMonitor");
01100 
01101    return res;
01102 }


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

Definition at line 1118 of file app_mixmonitor.c.

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

Definition at line 235 of file app_mixmonitor.c.

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

Initial value:

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

Definition at line 349 of file app_mixmonitor.c.

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 }, [ 'r' ] = { .flag = MUXFLAG_READ , .arg_index = OPT_ARG_READNAME + 1 }, [ 't' ] = { .flag = MUXFLAG_WRITE , .arg_index = OPT_ARG_WRITENAME + 1 }, [ 'i' ] = { .flag = MUXFLAG_UID , .arg_index = OPT_ARG_UID + 1 },} [static]

Definition at line 284 of file app_mixmonitor.c.

Referenced by manager_mixmonitor(), and mixmonitor_exec().

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

Definition at line 239 of file app_mixmonitor.c.

Referenced by builtin_automixmonitor().

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

Definition at line 237 of file app_mixmonitor.c.


Generated on Sat Feb 11 06:33:49 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6