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/stringfields.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/callerid.h"
#include "asterisk/mod_format.h"
#include "asterisk/linkedlists.h"
#include "asterisk/test.h"
#include "asterisk/mixmonitor.h"
#include "asterisk/format_cache.h"
#include "asterisk/beep.h"

Include dependency graph for app_mixmonitor.c:

Go to the source code of this file.

Data Structures

struct  mixmonitor
struct  mixmonitor_ds
struct  vm_recipient

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_VMRECIPIENTS, OPT_ARG_BEEP_INTERVAL,
  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), MUXFLAG_VMRECIPIENTS = (1 << 10), MUXFLAG_BEEP = (1 << 11), MUXFLAG_BEEP_START = (1 << 12),
  MUXFLAG_BEEP_STOP = (1 << 13)
}

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void add_vm_recipients_from_string (struct mixmonitor *mixmonitor, const char *vm_recipients)
static int clear_mixmonitor_methods (void)
static void clear_mixmonitor_recipient_list (struct mixmonitor *mixmonitor)
static void copy_to_voicemail (struct mixmonitor *mixmonitor, const char *ext, const char *filename)
static void destroy_monitor_audiohook (struct mixmonitor *mixmonitor)
static char * filename_parse (char *filename, char *buffer, size_t len)
static int func_mixmonitor_read (struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static char * handle_cli_mixmonitor (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int 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, const char *recipients, const char *beep_id)
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, char **ext)
static void * mixmonitor_thread (void *obj)
static int set_mixmonitor_methods (void)
static int setup_mixmonitor_ds (struct mixmonitor *mixmonitor, struct ast_channel *chan, char **datastore_id, const char *beep_id)
static int start_mixmonitor_callback (struct ast_channel *chan, const char *filename, const char *options)
static int startmon (struct ast_channel *chan, struct ast_audiohook *audiohook)
static int stop_mixmonitor_callback (struct ast_channel *chan, const char *mixmonitor_id)
static int stop_mixmonitor_exec (struct ast_channel *chan, const char *data)
static int stop_mixmonitor_full (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, .support_level = AST_MODULE_SUPPORT_CORE, }
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_custom_function mixmonitor_function
static struct ast_app_option mixmonitor_opts [128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'B' ] = { .flag = MUXFLAG_BEEP , .arg_index = OPT_ARG_BEEP_INTERVAL + 1 }, [ 'p' ] = { .flag = MUXFLAG_BEEP_START }, [ 'P' ] = { .flag = MUXFLAG_BEEP_STOP }, [ '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 }, [ 'm' ] = { .flag = MUXFLAG_VMRECIPIENTS , .arg_index = OPT_ARG_VMRECIPIENTS + 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 277 of file app_mixmonitor.c.

Referenced by mixmonitor_exec().

#define SAMPLES_PER_FRAME   160

Definition at line 525 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_VMRECIPIENTS 
OPT_ARG_BEEP_INTERVAL 
OPT_ARG_ARRAY_SIZE 

Definition at line 339 of file app_mixmonitor.c.

00339                      {
00340    OPT_ARG_READVOLUME = 0,
00341    OPT_ARG_WRITEVOLUME,
00342    OPT_ARG_VOLUME,
00343    OPT_ARG_WRITENAME,
00344    OPT_ARG_READNAME,
00345    OPT_ARG_UID,
00346    OPT_ARG_VMRECIPIENTS,
00347    OPT_ARG_BEEP_INTERVAL,
00348    OPT_ARG_ARRAY_SIZE,  /* Always last element of the enum */
00349 };

Enumerator:
MUXFLAG_APPEND 
MUXFLAG_BRIDGED 
MUXFLAG_VOLUME 
MUXFLAG_READVOLUME 
MUXFLAG_WRITEVOLUME 
MUXFLAG_READ 
MUXFLAG_WRITE 
MUXFLAG_COMBINED 
MUXFLAG_UID 
MUXFLAG_VMRECIPIENTS 
MUXFLAG_BEEP 
MUXFLAG_BEEP_START 
MUXFLAG_BEEP_STOP 

Definition at line 323 of file app_mixmonitor.c.

00323                       {
00324    MUXFLAG_APPEND = (1 << 1),
00325    MUXFLAG_BRIDGED = (1 << 2),
00326    MUXFLAG_VOLUME = (1 << 3),
00327    MUXFLAG_READVOLUME = (1 << 4),
00328    MUXFLAG_WRITEVOLUME = (1 << 5),
00329    MUXFLAG_READ = (1 << 6),
00330    MUXFLAG_WRITE = (1 << 7),
00331    MUXFLAG_COMBINED = (1 << 8),
00332    MUXFLAG_UID = (1 << 9),
00333    MUXFLAG_VMRECIPIENTS = (1 << 10),
00334    MUXFLAG_BEEP = (1 << 11),
00335    MUXFLAG_BEEP_START = (1 << 12),
00336    MUXFLAG_BEEP_STOP = (1 << 13)
00337 };


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1534 of file app_mixmonitor.c.

static void __unreg_module ( void   )  [static]

Definition at line 1534 of file app_mixmonitor.c.

static void add_vm_recipients_from_string ( struct mixmonitor mixmonitor,
const char *  vm_recipients 
) [static]

Definition at line 467 of file app_mixmonitor.c.

References ast_copy_string(), ast_debug, AST_LIST_INSERT_HEAD, ast_log, ast_malloc, ast_strdupa, ast_strlen_zero, ast_verb, vm_recipient::context, vm_recipient::folder, LOG_ERROR, vm_recipient::mailbox, vm_recipient::next, and mixmonitor::recipient_list.

Referenced by launch_monitor_thread().

00468 {
00469    /* recipients are in a single string with a format format resembling "mailbox@context/INBOX,mailbox2@context2,mailbox3@context3/Work" */
00470    char *cur_mailbox = ast_strdupa(vm_recipients);
00471    char *cur_context;
00472    char *cur_folder;
00473    char *next;
00474    int elements_processed = 0;
00475 
00476    while (!ast_strlen_zero(cur_mailbox)) {
00477       ast_debug(3, "attempting to add next element %d from %s\n", elements_processed, cur_mailbox);
00478       if ((next = strchr(cur_mailbox, ',')) || (next = strchr(cur_mailbox, '&'))) {
00479          *(next++) = '\0';
00480       }
00481 
00482       if ((cur_folder = strchr(cur_mailbox, '/'))) {
00483          *(cur_folder++) = '\0';
00484       } else {
00485          cur_folder = "INBOX";
00486       }
00487 
00488       if ((cur_context = strchr(cur_mailbox, '@'))) {
00489          *(cur_context++) = '\0';
00490       } else {
00491          cur_context = "default";
00492       }
00493 
00494       if (!ast_strlen_zero(cur_mailbox) && !ast_strlen_zero(cur_context)) {
00495          struct vm_recipient *recipient;
00496          if (!(recipient = ast_malloc(sizeof(*recipient)))) {
00497             ast_log(LOG_ERROR, "Failed to allocate recipient. Aborting function.\n");
00498             return;
00499          }
00500          ast_copy_string(recipient->context, cur_context, sizeof(recipient->context));
00501          ast_copy_string(recipient->mailbox, cur_mailbox, sizeof(recipient->mailbox));
00502          ast_copy_string(recipient->folder, cur_folder, sizeof(recipient->folder));
00503 
00504          /* Add to list */
00505          ast_verb(4, "Adding %s@%s to recipient list\n", recipient->mailbox, recipient->context);
00506          AST_LIST_INSERT_HEAD(&mixmonitor->recipient_list, recipient, list);
00507       } else {
00508          ast_log(LOG_ERROR, "Failed to properly parse extension and/or context from element %d of recipient string: %s\n", elements_processed, vm_recipients);
00509       }
00510 
00511       cur_mailbox = next;
00512       elements_processed++;
00513    }
00514 }

static int clear_mixmonitor_methods ( void   )  [static]

Definition at line 1497 of file app_mixmonitor.c.

References ast_clear_mixmonitor_methods().

Referenced by unload_module().

01498 {
01499    return ast_clear_mixmonitor_methods();
01500 }

static void clear_mixmonitor_recipient_list ( struct mixmonitor mixmonitor  )  [static]

Definition at line 516 of file app_mixmonitor.c.

References ast_free, AST_LIST_REMOVE_HEAD, and mixmonitor::recipient_list.

Referenced by mixmonitor_free().

00517 {
00518    struct vm_recipient *current;
00519    while ((current = AST_LIST_REMOVE_HEAD(&mixmonitor->recipient_list, list))) {
00520       /* Clear list element data */
00521       ast_free(current);
00522    }
00523 }

static void copy_to_voicemail ( struct mixmonitor mixmonitor,
const char *  ext,
const char *  filename 
) [static]

Definition at line 558 of file app_mixmonitor.c.

References ast_app_copy_recording_to_vm(), AST_LIST_TRAVERSE, ast_log, ast_string_field_free_memory, ast_string_field_init, ast_string_field_set, ast_verb, mixmonitor::call_callerchan, ast_vm_recording_data::call_callerchan, mixmonitor::call_callerid, ast_vm_recording_data::call_callerid, mixmonitor::call_context, ast_vm_recording_data::call_context, mixmonitor::call_extension, ast_vm_recording_data::call_extension, mixmonitor::call_macrocontext, ast_vm_recording_data::call_macrocontext, mixmonitor::call_priority, ast_vm_recording_data::call_priority, ast_vm_recording_data::context, vm_recipient::context, vm_recipient::folder, LOG_ERROR, ast_vm_recording_data::mailbox, vm_recipient::mailbox, NULL, mixmonitor::recipient_list, ast_vm_recording_data::recording_ext, and ast_vm_recording_data::recording_file.

Referenced by mixmonitor_thread().

00559 {
00560    struct vm_recipient *recipient = NULL;
00561    struct ast_vm_recording_data recording_data;
00562    if (ast_string_field_init(&recording_data, 512)) {
00563       ast_log(LOG_ERROR, "Failed to string_field_init, skipping copy_to_voicemail\n");
00564       return;
00565    }
00566 
00567    /* Copy strings to stringfields that will be used for all recipients */
00568    ast_string_field_set(&recording_data, recording_file, filename);
00569    ast_string_field_set(&recording_data, recording_ext, ext);
00570    ast_string_field_set(&recording_data, call_context, mixmonitor->call_context);
00571    ast_string_field_set(&recording_data, call_macrocontext, mixmonitor->call_macrocontext);
00572    ast_string_field_set(&recording_data, call_extension, mixmonitor->call_extension);
00573    ast_string_field_set(&recording_data, call_callerchan, mixmonitor->call_callerchan);
00574    ast_string_field_set(&recording_data, call_callerid, mixmonitor->call_callerid);
00575    /* and call_priority gets copied too */
00576    recording_data.call_priority = mixmonitor->call_priority;
00577 
00578    AST_LIST_TRAVERSE(&mixmonitor->recipient_list, recipient, list) {
00579       /* context, mailbox, and folder need to be set per recipient */
00580       ast_string_field_set(&recording_data, context, recipient->context);
00581       ast_string_field_set(&recording_data, mailbox, recipient->mailbox);
00582       ast_string_field_set(&recording_data, folder, recipient->folder);
00583 
00584       ast_verb(4, "MixMonitor attempting to send voicemail copy to %s@%s\n", recording_data.mailbox,
00585          recording_data.context);
00586       ast_app_copy_recording_to_vm(&recording_data);
00587    }
00588 
00589    /* Free the string fields for recording_data before exiting the function. */
00590    ast_string_field_free_memory(&recording_data);
00591 }

static void destroy_monitor_audiohook ( struct mixmonitor mixmonitor  )  [static]

Definition at line 438 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, mixmonitor::mixmonitor_ds, and NULL.

Referenced by mixmonitor_thread().

00439 {
00440    if (mixmonitor->mixmonitor_ds) {
00441       ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00442       mixmonitor->mixmonitor_ds->audiohook = NULL;
00443       ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00444    }
00445    /* kill the audiohook.*/
00446    ast_audiohook_lock(&mixmonitor->audiohook);
00447    ast_audiohook_detach(&mixmonitor->audiohook);
00448    ast_audiohook_unlock(&mixmonitor->audiohook);
00449    ast_audiohook_destroy(&mixmonitor->audiohook);
00450 }

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

Definition at line 962 of file app_mixmonitor.c.

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

00963 {
00964    char *slash;
00965    if (ast_strlen_zero(filename)) {
00966       ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
00967    } else if (filename[0] != '/') {
00968       char *build;
00969       build = ast_alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
00970       sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
00971       filename = build;
00972    }
00973 
00974    ast_copy_string(buffer, filename, len);
00975 
00976    if ((slash = strrchr(filename, '/'))) {
00977       *slash = '\0';
00978    }
00979    ast_mkdir(filename, 0777);
00980 
00981    return buffer;
00982 }

static int func_mixmonitor_read ( struct ast_channel chan,
const char *  cmd,
char *  data,
char *  buf,
size_t  len 
) [static]

Definition at line 1440 of file app_mixmonitor.c.

References args, AST_APP_ARG, ast_channel_datastore_find(), ast_channel_lock, ast_channel_unlock, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log, AST_STANDARD_APP_ARGS, ast_strlen_zero, ast_datastore::data, mixmonitor_ds::filename, and LOG_WARNING.

01442 {
01443    struct ast_datastore *datastore;
01444    struct mixmonitor_ds *ds_data;
01445    AST_DECLARE_APP_ARGS(args,
01446       AST_APP_ARG(id);
01447       AST_APP_ARG(key);
01448    );
01449 
01450    AST_STANDARD_APP_ARGS(args, data);
01451 
01452    if (ast_strlen_zero(args.id) || ast_strlen_zero(args.key)) {
01453       ast_log(LOG_WARNING, "Not enough arguments provided to %s. "
01454             "An ID and key must be provided\n", cmd);
01455       return -1;
01456    }
01457 
01458    ast_channel_lock(chan);
01459    datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info, args.id);
01460    ast_channel_unlock(chan);
01461 
01462    if (!datastore) {
01463       ast_log(LOG_WARNING, "Could not find MixMonitor with ID %s\n", args.id);
01464       return -1;
01465    }
01466 
01467    ds_data = datastore->data;
01468 
01469    if (!strcasecmp(args.key, "filename")) {
01470       ast_copy_string(buf, ds_data->filename, len);
01471    } else {
01472       ast_log(LOG_WARNING, "Unrecognized %s option %s\n", cmd, args.key);
01473       return -1;
01474    }
01475    return 0;
01476 }

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

Definition at line 1186 of file app_mixmonitor.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_channel_datastores(), ast_channel_get_by_name_prefix(), ast_channel_lock, ast_channel_unlock, ast_channel_unref, ast_cli(), ast_complete_channels(), AST_LIST_TRAVERSE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_datastore::data, 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, NULL, ast_cli_args::pos, stop_mixmonitor_exec(), ast_cli_entry::usage, and ast_cli_args::word.

01187 {
01188    struct ast_channel *chan;
01189    struct ast_datastore *datastore = NULL;
01190    struct mixmonitor_ds *mixmonitor_ds = NULL;
01191 
01192    switch (cmd) {
01193    case CLI_INIT:
01194       e->command = "mixmonitor {start|stop|list}";
01195       e->usage =
01196          "Usage: mixmonitor start <chan_name> [args]\n"
01197          "         The optional arguments are passed to the MixMonitor application.\n"
01198          "       mixmonitor stop <chan_name> [args]\n"
01199          "         The optional arguments are passed to the StopMixMonitor application.\n"
01200          "       mixmonitor list <chan_name>\n";
01201       return NULL;
01202    case CLI_GENERATE:
01203       return ast_complete_channels(a->line, a->word, a->pos, a->n, 2);
01204    }
01205 
01206    if (a->argc < 3) {
01207       return CLI_SHOWUSAGE;
01208    }
01209 
01210    if (!(chan = ast_channel_get_by_name_prefix(a->argv[2], strlen(a->argv[2])))) {
01211       ast_cli(a->fd, "No channel matching '%s' found.\n", a->argv[2]);
01212       /* Technically this is a failure, but we don't want 2 errors printing out */
01213       return CLI_SUCCESS;
01214    }
01215 
01216    if (!strcasecmp(a->argv[1], "start")) {
01217       mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
01218    } else if (!strcasecmp(a->argv[1], "stop")){
01219       stop_mixmonitor_exec(chan, (a->argc >= 4) ? a->argv[3] : "");
01220    } else if (!strcasecmp(a->argv[1], "list")) {
01221       ast_cli(a->fd, "MixMonitor ID\tFile\tReceive File\tTransmit File\n");
01222       ast_cli(a->fd, "=========================================================================\n");
01223       ast_channel_lock(chan);
01224       AST_LIST_TRAVERSE(ast_channel_datastores(chan), datastore, entry) {
01225          if (datastore->info == &mixmonitor_ds_info) {
01226             char *filename = "";
01227             char *filename_read = "";
01228             char *filename_write = "";
01229 
01230             mixmonitor_ds = datastore->data;
01231             if (mixmonitor_ds->fs) {
01232                filename = mixmonitor_ds->fs->filename;
01233             }
01234             if (mixmonitor_ds->fs_read) {
01235                filename_read = mixmonitor_ds->fs_read->filename;
01236             }
01237             if (mixmonitor_ds->fs_write) {
01238                filename_write = mixmonitor_ds->fs_write->filename;
01239             }
01240             ast_cli(a->fd, "%p\t%s\t%s\t%s\n", mixmonitor_ds, filename, filename_read, filename_write);
01241          }
01242       }
01243       ast_channel_unlock(chan);
01244    } else {
01245       chan = ast_channel_unref(chan);
01246       return CLI_SHOWUSAGE;
01247    }
01248 
01249    chan = ast_channel_unref(chan);
01250 
01251    return CLI_SUCCESS;
01252 }

static int 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,
const char *  recipients,
const char *  beep_id 
) [static]

Definition at line 827 of file app_mixmonitor.c.

References add_vm_recipients_from_string(), ast_audiohook_destroy(), ast_audiohook_init(), AST_AUDIOHOOK_TRIGGER_SYNC, AST_AUDIOHOOK_TYPE_SPY, ast_autochan_destroy(), ast_autochan_setup(), ast_callerid_merge(), ast_calloc, ast_channel_connected(), ast_channel_context(), ast_channel_exten(), ast_channel_lock, ast_channel_macrocontext(), ast_channel_name(), ast_channel_priority(), ast_channel_unlock, ast_debug, ast_free, ast_log, ast_pthread_create_detached_background, ast_read_threadstorage_callid(), ast_set_flag, ast_strdup, ast_strdupa, ast_string_field_init, ast_string_field_set, ast_strlen_zero, mixmonitor::audiohook, mixmonitor::autochan, mixmonitor::call_priority, mixmonitor::callid, connected, mixmonitor::filename, mixmonitor::filename_read, mixmonitor::filename_write, mixmonitor::flags, ast_party_connected_line::id, LOG_WARNING, mixmonitor_free(), mixmonitor_thread(), ast_party_id::name, mixmonitor::name, NULL, ast_party_id::number, ast_audiohook::options, pbx_builtin_setvar_helper(), pbx_substitute_variables_helper(), mixmonitor::post_process, ast_audiohook_options::read_volume, S_COR, setup_mixmonitor_ds(), startmon(), ast_party_number::str, ast_party_name::str, thread, ast_party_number::valid, ast_party_name::valid, and ast_audiohook_options::write_volume.

Referenced by mixmonitor_exec().

00832 {
00833    pthread_t thread;
00834    struct mixmonitor *mixmonitor;
00835    char postprocess2[1024] = "";
00836    char *datastore_id = NULL;
00837 
00838    postprocess2[0] = 0;
00839    /* If a post process system command is given attach it to the structure */
00840    if (!ast_strlen_zero(post_process)) {
00841       char *p1, *p2;
00842 
00843       p1 = ast_strdupa(post_process);
00844       for (p2 = p1; *p2; p2++) {
00845          if (*p2 == '^' && *(p2+1) == '{') {
00846             *p2 = '$';
00847          }
00848       }
00849       ast_channel_lock(chan);
00850       pbx_substitute_variables_helper(chan, p1, postprocess2, sizeof(postprocess2) - 1);
00851       ast_channel_unlock(chan);
00852    }
00853 
00854    /* Pre-allocate mixmonitor structure and spy */
00855    if (!(mixmonitor = ast_calloc(1, sizeof(*mixmonitor)))) {
00856       return -1;
00857    }
00858 
00859    /* Now that the struct has been calloced, go ahead and initialize the string fields. */
00860    if (ast_string_field_init(mixmonitor, 512)) {
00861       mixmonitor_free(mixmonitor);
00862       return -1;
00863    }
00864 
00865    /* Setup the actual spy before creating our thread */
00866    if (ast_audiohook_init(&mixmonitor->audiohook, AST_AUDIOHOOK_TYPE_SPY, mixmonitor_spy_type, 0)) {
00867       mixmonitor_free(mixmonitor);
00868       return -1;
00869    }
00870 
00871    /* Copy over flags and channel name */
00872    mixmonitor->flags = flags;
00873    if (!(mixmonitor->autochan = ast_autochan_setup(chan))) {
00874       mixmonitor_free(mixmonitor);
00875       return -1;
00876    }
00877 
00878    if (!ast_strlen_zero(filename)) {
00879       mixmonitor->filename = ast_strdup(filename);
00880    }
00881 
00882    if (!ast_strlen_zero(filename_write)) {
00883       mixmonitor->filename_write = ast_strdup(filename_write);
00884    }
00885 
00886    if (!ast_strlen_zero(filename_read)) {
00887       mixmonitor->filename_read = ast_strdup(filename_read);
00888    }
00889 
00890    if (setup_mixmonitor_ds(mixmonitor, chan, &datastore_id, beep_id)) {
00891       ast_autochan_destroy(mixmonitor->autochan);
00892       mixmonitor_free(mixmonitor);
00893       ast_free(datastore_id);
00894       return -1;
00895    }
00896 
00897    if (!ast_strlen_zero(uid_channel_var)) {
00898       if (datastore_id) {
00899          pbx_builtin_setvar_helper(chan, uid_channel_var, datastore_id);
00900       }
00901    }
00902    ast_free(datastore_id);
00903 
00904    mixmonitor->name = ast_strdup(ast_channel_name(chan));
00905 
00906    if (!ast_strlen_zero(postprocess2)) {
00907       mixmonitor->post_process = ast_strdup(postprocess2);
00908    }
00909 
00910    if (!ast_strlen_zero(recipients)) {
00911       char callerid[256];
00912       struct ast_party_connected_line *connected;
00913 
00914       ast_channel_lock(chan);
00915 
00916       /* We use the connected line of the invoking channel for caller ID. */
00917 
00918       connected = ast_channel_connected(chan);
00919       ast_debug(3, "Connected Line CID = %d - %s : %d - %s\n", connected->id.name.valid,
00920          connected->id.name.str, connected->id.number.valid,
00921          connected->id.number.str);
00922       ast_callerid_merge(callerid, sizeof(callerid),
00923          S_COR(connected->id.name.valid, connected->id.name.str, NULL),
00924          S_COR(connected->id.number.valid, connected->id.number.str, NULL),
00925          "Unknown");
00926 
00927       ast_string_field_set(mixmonitor, call_context, ast_channel_context(chan));
00928       ast_string_field_set(mixmonitor, call_macrocontext, ast_channel_macrocontext(chan));
00929       ast_string_field_set(mixmonitor, call_extension, ast_channel_exten(chan));
00930       ast_string_field_set(mixmonitor, call_callerchan, ast_channel_name(chan));
00931       ast_string_field_set(mixmonitor, call_callerid, callerid);
00932       mixmonitor->call_priority = ast_channel_priority(chan);
00933 
00934       ast_channel_unlock(chan);
00935 
00936       add_vm_recipients_from_string(mixmonitor, recipients);
00937    }
00938 
00939    ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
00940 
00941    if (readvol)
00942       mixmonitor->audiohook.options.read_volume = readvol;
00943    if (writevol)
00944       mixmonitor->audiohook.options.write_volume = writevol;
00945 
00946    if (startmon(chan, &mixmonitor->audiohook)) {
00947       ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n",
00948          mixmonitor_spy_type, ast_channel_name(chan));
00949       ast_audiohook_destroy(&mixmonitor->audiohook);
00950       mixmonitor_free(mixmonitor);
00951       return -1;
00952    }
00953 
00954    /* reference be released at mixmonitor destruction */
00955    mixmonitor->callid = ast_read_threadstorage_callid();
00956 
00957    return ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
00958 }

static int load_module ( void   )  [static]

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

Definition at line 1336 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(), c, mixmonitor_exec(), mixmonitor_opts, MUXFLAG_UID, NULL, OPT_ARG_ARRAY_SIZE, OPT_ARG_UID, pbx_builtin_getvar_helper(), and S_OR.

Referenced by load_module().

01337 {
01338    struct ast_channel *c;
01339    const char *name = astman_get_header(m, "Channel");
01340    const char *id = astman_get_header(m, "ActionID");
01341    const char *file = astman_get_header(m, "File");
01342    const char *options = astman_get_header(m, "Options");
01343    const char *command = astman_get_header(m, "Command");
01344    char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
01345    struct ast_flags flags = { 0 };
01346    char *uid_channel_var = NULL;
01347    const char *mixmonitor_id = NULL;
01348    int res;
01349    char args[PATH_MAX];
01350 
01351    if (ast_strlen_zero(name)) {
01352       astman_send_error(s, m, "No channel specified");
01353       return AMI_SUCCESS;
01354    }
01355 
01356    c = ast_channel_get_by_name(name);
01357    if (!c) {
01358       astman_send_error(s, m, "No such channel");
01359       return AMI_SUCCESS;
01360    }
01361 
01362    if (!ast_strlen_zero(options)) {
01363       ast_app_parse_options(mixmonitor_opts, &flags, opts, ast_strdupa(options));
01364    }
01365 
01366    snprintf(args, sizeof(args), "%s,%s,%s", file, options, command);
01367 
01368    res = mixmonitor_exec(c, args);
01369 
01370    if (ast_test_flag(&flags, MUXFLAG_UID)) {
01371       uid_channel_var = opts[OPT_ARG_UID];
01372       ast_channel_lock(c);
01373       mixmonitor_id = pbx_builtin_getvar_helper(c, uid_channel_var);
01374       mixmonitor_id = ast_strdupa(S_OR(mixmonitor_id, ""));
01375       ast_channel_unlock(c);
01376    }
01377 
01378    if (res) {
01379       ast_channel_unref(c);
01380       astman_send_error(s, m, "Could not start monitoring channel");
01381       return AMI_SUCCESS;
01382    }
01383 
01384    astman_append(s, "Response: Success\r\n");
01385 
01386    if (!ast_strlen_zero(id)) {
01387       astman_append(s, "ActionID: %s\r\n", id);
01388    }
01389 
01390    if (!ast_strlen_zero(mixmonitor_id)) {
01391       astman_append(s, "MixMonitorID: %s\r\n", mixmonitor_id);
01392    }
01393 
01394    astman_append(s, "\r\n");
01395 
01396    ast_channel_unref(c);
01397 
01398    return AMI_SUCCESS;
01399 }

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

Mute / unmute a MixMonitor channel.

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

Referenced by load_module().

01256 {
01257    struct ast_channel *c;
01258    const char *name = astman_get_header(m, "Channel");
01259    const char *id = astman_get_header(m, "ActionID");
01260    const char *state = astman_get_header(m, "State");
01261    const char *direction = astman_get_header(m,"Direction");
01262    int clearmute = 1;
01263    enum ast_audiohook_flags flag;
01264 
01265    if (ast_strlen_zero(direction)) {
01266       astman_send_error(s, m, "No direction specified. Must be read, write or both");
01267       return AMI_SUCCESS;
01268    }
01269 
01270    if (!strcasecmp(direction, "read")) {
01271       flag = AST_AUDIOHOOK_MUTE_READ;
01272    } else  if (!strcasecmp(direction, "write")) {
01273       flag = AST_AUDIOHOOK_MUTE_WRITE;
01274    } else  if (!strcasecmp(direction, "both")) {
01275       flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
01276    } else {
01277       astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
01278       return AMI_SUCCESS;
01279    }
01280 
01281    if (ast_strlen_zero(name)) {
01282       astman_send_error(s, m, "No channel specified");
01283       return AMI_SUCCESS;
01284    }
01285 
01286    if (ast_strlen_zero(state)) {
01287       astman_send_error(s, m, "No state specified");
01288       return AMI_SUCCESS;
01289    }
01290 
01291    clearmute = ast_false(state);
01292 
01293    c = ast_channel_get_by_name(name);
01294    if (!c) {
01295       astman_send_error(s, m, "No such channel");
01296       return AMI_SUCCESS;
01297    }
01298 
01299    if (ast_audiohook_set_mute(c, mixmonitor_spy_type, flag, clearmute)) {
01300       ast_channel_unref(c);
01301       astman_send_error(s, m, "Cannot set mute flag");
01302       return AMI_SUCCESS;
01303    }
01304 
01305    astman_append(s, "Response: Success\r\n");
01306 
01307    if (!ast_strlen_zero(id)) {
01308       astman_append(s, "ActionID: %s\r\n", id);
01309    }
01310 
01311    astman_append(s, "\r\n");
01312 
01313    ast_channel_unref(c);
01314 
01315    return AMI_SUCCESS;
01316 }

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

Definition at line 1401 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(), c, and stop_mixmonitor_full().

Referenced by load_module().

01402 {
01403    struct ast_channel *c;
01404    const char *name = astman_get_header(m, "Channel");
01405    const char *id = astman_get_header(m, "ActionID");
01406    const char *mixmonitor_id = astman_get_header(m, "MixMonitorID");
01407    int res;
01408 
01409    if (ast_strlen_zero(name)) {
01410       astman_send_error(s, m, "No channel specified");
01411       return AMI_SUCCESS;
01412    }
01413 
01414    c = ast_channel_get_by_name(name);
01415    if (!c) {
01416       astman_send_error(s, m, "No such channel");
01417       return AMI_SUCCESS;
01418    }
01419 
01420    res = stop_mixmonitor_full(c, mixmonitor_id);
01421    if (res) {
01422       ast_channel_unref(c);
01423       astman_send_error(s, m, "Could not stop monitoring channel");
01424       return AMI_SUCCESS;
01425    }
01426 
01427    astman_append(s, "Response: Success\r\n");
01428 
01429    if (!ast_strlen_zero(id)) {
01430       astman_append(s, "ActionID: %s\r\n", id);
01431    }
01432 
01433    astman_append(s, "\r\n");
01434 
01435    ast_channel_unref(c);
01436 
01437    return AMI_SUCCESS;
01438 }

static void mixmonitor_ds_close_fs ( struct mixmonitor_ds mixmonitor_ds  )  [static]

Definition at line 390 of file app_mixmonitor.c.

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

Referenced by mixmonitor_thread(), and stop_mixmonitor_full().

00391 {
00392    unsigned char quitting = 0;
00393 
00394    if (mixmonitor_ds->fs) {
00395       quitting = 1;
00396       ast_closestream(mixmonitor_ds->fs);
00397       mixmonitor_ds->fs = NULL;
00398       ast_verb(2, "MixMonitor close filestream (mixed)\n");
00399    }
00400 
00401    if (mixmonitor_ds->fs_read) {
00402       quitting = 1;
00403       ast_closestream(mixmonitor_ds->fs_read);
00404       mixmonitor_ds->fs_read = NULL;
00405       ast_verb(2, "MixMonitor close filestream (read)\n");
00406    }
00407 
00408    if (mixmonitor_ds->fs_write) {
00409       quitting = 1;
00410       ast_closestream(mixmonitor_ds->fs_write);
00411       mixmonitor_ds->fs_write = NULL;
00412       ast_verb(2, "MixMonitor close filestream (write)\n");
00413    }
00414 
00415    if (quitting) {
00416       mixmonitor_ds->fs_quit = 1;
00417    }
00418 }

static void mixmonitor_ds_destroy ( void *  data  )  [static]

Definition at line 420 of file app_mixmonitor.c.

References ast_cond_signal, ast_free, ast_mutex_lock, ast_mutex_unlock, mixmonitor_ds::audiohook, mixmonitor_ds::beep_id, mixmonitor_ds::destruction_condition, mixmonitor_ds::destruction_ok, mixmonitor_ds::filename, mixmonitor_ds::lock, and NULL.

00421 {
00422    struct mixmonitor_ds *mixmonitor_ds = data;
00423 
00424    ast_mutex_lock(&mixmonitor_ds->lock);
00425    mixmonitor_ds->audiohook = NULL;
00426    mixmonitor_ds->destruction_ok = 1;
00427    ast_free(mixmonitor_ds->filename);
00428    ast_free(mixmonitor_ds->beep_id);
00429    ast_cond_signal(&mixmonitor_ds->destruction_condition);
00430    ast_mutex_unlock(&mixmonitor_ds->lock);
00431 }

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

Definition at line 984 of file app_mixmonitor.c.

References args, AST_APP_ARG, ast_app_parse_options(), ast_beep_start(), AST_DECLARE_APP_ARGS, ast_log, ast_module_ref, ast_module_unref, AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero, ast_test_flag, filename_parse(), ast_flags::flags, get_volfactor, launch_monitor_thread(), LOG_NOTICE, LOG_WARNING, mixmonitor_opts, MUXFLAG_BEEP, MUXFLAG_READ, MUXFLAG_READVOLUME, MUXFLAG_UID, MUXFLAG_VMRECIPIENTS, MUXFLAG_VOLUME, MUXFLAG_WRITE, MUXFLAG_WRITEVOLUME, NULL, OPT_ARG_ARRAY_SIZE, OPT_ARG_BEEP_INTERVAL, OPT_ARG_READNAME, OPT_ARG_READVOLUME, OPT_ARG_UID, OPT_ARG_VMRECIPIENTS, OPT_ARG_VOLUME, OPT_ARG_WRITENAME, OPT_ARG_WRITEVOLUME, parse(), pbx_builtin_setvar_helper(), and S_OR.

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

00985 {
00986    int x, readvol = 0, writevol = 0;
00987    char *filename_read = NULL;
00988    char *filename_write = NULL;
00989    char filename_buffer[1024] = "";
00990    char *uid_channel_var = NULL;
00991    char beep_id[64] = "";
00992 
00993    struct ast_flags flags = { 0 };
00994    char *recipients = NULL;
00995    char *parse;
00996    AST_DECLARE_APP_ARGS(args,
00997       AST_APP_ARG(filename);
00998       AST_APP_ARG(options);
00999       AST_APP_ARG(post_process);
01000    );
01001 
01002    if (ast_strlen_zero(data)) {
01003       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
01004       return -1;
01005    }
01006 
01007    parse = ast_strdupa(data);
01008 
01009    AST_STANDARD_APP_ARGS(args, parse);
01010 
01011    if (args.options) {
01012       char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, };
01013 
01014       ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options);
01015 
01016       if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) {
01017          if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) {
01018             ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n");
01019          } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
01020             ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]);
01021          } else {
01022             readvol = get_volfactor(x);
01023          }
01024       }
01025 
01026       if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
01027          if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
01028             ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
01029          } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
01030             ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]);
01031          } else {
01032             writevol = get_volfactor(x);
01033          }
01034       }
01035 
01036       if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
01037          if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
01038             ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
01039          } else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
01040             ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
01041          } else {
01042             readvol = writevol = get_volfactor(x);
01043          }
01044       }
01045 
01046       if (ast_test_flag(&flags, MUXFLAG_VMRECIPIENTS)) {
01047          if (ast_strlen_zero(opts[OPT_ARG_VMRECIPIENTS])) {
01048             ast_log(LOG_WARNING, "No voicemail recipients were specified for the vm copy ('m') option.\n");
01049          } else {
01050             recipients = ast_strdupa(opts[OPT_ARG_VMRECIPIENTS]);
01051          }
01052       }
01053 
01054       if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
01055          filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME], filename_buffer, sizeof(filename_buffer)));
01056       }
01057 
01058       if (ast_test_flag(&flags, MUXFLAG_READ)) {
01059          filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME], filename_buffer, sizeof(filename_buffer)));
01060       }
01061 
01062       if (ast_test_flag(&flags, MUXFLAG_UID)) {
01063          uid_channel_var = opts[OPT_ARG_UID];
01064       }
01065 
01066       if (ast_test_flag(&flags, MUXFLAG_BEEP)) {
01067          const char *interval_str = S_OR(opts[OPT_ARG_BEEP_INTERVAL], "15");
01068          unsigned int interval = 15;
01069 
01070          if (sscanf(interval_str, "%30u", &interval) != 1) {
01071             ast_log(LOG_WARNING, "Invalid interval '%s' for periodic beep. Using default of %u\n",
01072                   interval_str, interval);
01073          }
01074 
01075          if (ast_beep_start(chan, interval, beep_id, sizeof(beep_id))) {
01076             ast_log(LOG_WARNING, "Unable to enable periodic beep, please ensure func_periodic_hook is loaded.\n");
01077             return -1;
01078          }
01079       }
01080    }
01081    /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
01082 
01083    if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
01084       ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
01085       return -1;
01086    }
01087 
01088    /* If filename exists, try to create directories for it */
01089    if (!(ast_strlen_zero(args.filename))) {
01090       args.filename = ast_strdupa(filename_parse(args.filename, filename_buffer, sizeof(filename_buffer)));
01091    }
01092 
01093    pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
01094 
01095    /* If launch_monitor_thread works, the module reference must not be released until it is finished. */
01096    ast_module_ref(ast_module_info->self);
01097    if (launch_monitor_thread(chan,
01098          args.filename,
01099          flags.flags,
01100          readvol,
01101          writevol,
01102          args.post_process,
01103          filename_write,
01104          filename_read,
01105          uid_channel_var,
01106          recipients,
01107          beep_id)) {
01108       ast_module_unref(ast_module_info->self);
01109    }
01110 
01111    return 0;
01112 }

static void mixmonitor_free ( struct mixmonitor mixmonitor  )  [static]

Definition at line 527 of file app_mixmonitor.c.

References ast_cond_destroy, ast_free, ast_mutex_destroy, ast_string_field_free_memory, clear_mixmonitor_recipient_list(), mixmonitor_ds::destruction_condition, mixmonitor::filename, 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().

00528 {
00529    if (mixmonitor) {
00530       if (mixmonitor->mixmonitor_ds) {
00531          ast_mutex_destroy(&mixmonitor->mixmonitor_ds->lock);
00532          ast_cond_destroy(&mixmonitor->mixmonitor_ds->destruction_condition);
00533          ast_free(mixmonitor->mixmonitor_ds);
00534       }
00535 
00536       ast_free(mixmonitor->name);
00537       ast_free(mixmonitor->post_process);
00538       ast_free(mixmonitor->filename);
00539       ast_free(mixmonitor->filename_write);
00540       ast_free(mixmonitor->filename_read);
00541 
00542       /* Free everything in the recipient list */
00543       clear_mixmonitor_recipient_list(mixmonitor);
00544 
00545       /* clean stringfields */
00546       ast_string_field_free_memory(mixmonitor);
00547 
00548       ast_free(mixmonitor);
00549    }
00550 }

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

Definition at line 593 of file app_mixmonitor.c.

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

Referenced by mixmonitor_thread().

00594 {
00595    /* Initialize the file if not already done so */
00596    char *last_slash = NULL;
00597    if (!ast_strlen_zero(filename)) {
00598       if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
00599          *oflags = O_CREAT | O_WRONLY;
00600          *oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
00601 
00602          last_slash = strrchr(filename, '/');
00603 
00604          if ((*ext = strrchr(filename, '.')) && (*ext > last_slash)) {
00605             **ext = '\0';
00606             *ext = *ext + 1;
00607          } else {
00608             *ext = "raw";
00609          }
00610 
00611          if (!(*fs = ast_writefile(filename, *ext, NULL, *oflags, 0, 0666))) {
00612             ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, *ext);
00613             *errflag = 1;
00614          } else {
00615             struct ast_filestream *tmp = *fs;
00616             mixmonitor->mixmonitor_ds->samp_rate = MAX(mixmonitor->mixmonitor_ds->samp_rate, ast_format_get_sample_rate(tmp->fmt->format));
00617          }
00618       }
00619    }
00620 }

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

Definition at line 622 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_callid_threadassoc_add(), ast_channel_is_bridged(), ast_channel_lock, ast_channel_unlock, ast_cond_wait, ast_debug, ast_format_cache_get_slin_by_rate(), ast_frame_free(), AST_LIST_EMPTY, AST_LIST_NEXT, ast_log, ast_module_unref, ast_mutex_lock, ast_mutex_unlock, ast_safe_system(), ast_stream_and_wait(), ast_strlen_zero, ast_test_flag, ast_test_suite_event_notify, ast_verb, ast_writestream(), mixmonitor::audiohook, mixmonitor::autochan, mixmonitor::callid, ast_autochan::chan, copy_to_voicemail(), 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, LOG_ERROR, mixmonitor::mixmonitor_ds, mixmonitor_ds_close_fs(), mixmonitor_free(), mixmonitor_save_prep(), MUXFLAG_BEEP_STOP, MUXFLAG_BRIDGED, mixmonitor::name, NULL, mixmonitor::post_process, mixmonitor::recipient_list, mixmonitor_ds::samp_rate, SAMPLES_PER_FRAME, and ast_audiohook::status.

Referenced by launch_monitor_thread().

00623 {
00624    struct mixmonitor *mixmonitor = obj;
00625    char *fs_ext = "";
00626    char *fs_read_ext = "";
00627    char *fs_write_ext = "";
00628 
00629    struct ast_filestream **fs = NULL;
00630    struct ast_filestream **fs_read = NULL;
00631    struct ast_filestream **fs_write = NULL;
00632 
00633    unsigned int oflags;
00634    int errflag = 0;
00635    struct ast_format *format_slin;
00636 
00637    /* Keep callid association before any log messages */
00638    if (mixmonitor->callid) {
00639       ast_callid_threadassoc_add(mixmonitor->callid);
00640    }
00641 
00642    ast_verb(2, "Begin MixMonitor Recording %s\n", mixmonitor->name);
00643 
00644    fs = &mixmonitor->mixmonitor_ds->fs;
00645    fs_read = &mixmonitor->mixmonitor_ds->fs_read;
00646    fs_write = &mixmonitor->mixmonitor_ds->fs_write;
00647 
00648    ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00649    mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag, &fs_ext);
00650    mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag, &fs_read_ext);
00651    mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag, &fs_write_ext);
00652 
00653    format_slin = ast_format_cache_get_slin_by_rate(mixmonitor->mixmonitor_ds->samp_rate);
00654 
00655    ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00656 
00657    /* The audiohook must enter and exit the loop locked */
00658    ast_audiohook_lock(&mixmonitor->audiohook);
00659    while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
00660       struct ast_frame *fr = NULL;
00661       struct ast_frame *fr_read = NULL;
00662       struct ast_frame *fr_write = NULL;
00663 
00664       if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, format_slin,
00665                   &fr_read, &fr_write))) {
00666          ast_audiohook_trigger_wait(&mixmonitor->audiohook);
00667 
00668          if (mixmonitor->audiohook.status != AST_AUDIOHOOK_STATUS_RUNNING) {
00669             break;
00670          }
00671          continue;
00672       }
00673 
00674       /* audiohook lock is not required for the next block.
00675        * Unlock it, but remember to lock it before looping or exiting */
00676       ast_audiohook_unlock(&mixmonitor->audiohook);
00677 
00678       if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED)
00679          || (mixmonitor->autochan->chan
00680             && ast_channel_is_bridged(mixmonitor->autochan->chan))) {
00681          ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00682 
00683          /* Write out the frame(s) */
00684          if ((*fs_read) && (fr_read)) {
00685             struct ast_frame *cur;
00686 
00687             for (cur = fr_read; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00688                ast_writestream(*fs_read, cur);
00689             }
00690          }
00691 
00692          if ((*fs_write) && (fr_write)) {
00693             struct ast_frame *cur;
00694 
00695             for (cur = fr_write; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00696                ast_writestream(*fs_write, cur);
00697             }
00698          }
00699 
00700          if ((*fs) && (fr)) {
00701             struct ast_frame *cur;
00702 
00703             for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
00704                ast_writestream(*fs, cur);
00705             }
00706          }
00707          ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00708       }
00709       /* All done! free it. */
00710       if (fr) {
00711          ast_frame_free(fr, 0);
00712       }
00713       if (fr_read) {
00714          ast_frame_free(fr_read, 0);
00715       }
00716       if (fr_write) {
00717          ast_frame_free(fr_write, 0);
00718       }
00719 
00720       fr = NULL;
00721       fr_write = NULL;
00722       fr_read = NULL;
00723 
00724       ast_audiohook_lock(&mixmonitor->audiohook);
00725    }
00726 
00727    ast_audiohook_unlock(&mixmonitor->audiohook);
00728 
00729    ast_channel_lock(mixmonitor->autochan->chan);
00730    if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_STOP)) {
00731       ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
00732    }
00733    ast_channel_unlock(mixmonitor->autochan->chan);
00734 
00735    ast_autochan_destroy(mixmonitor->autochan);
00736 
00737    /* Datastore cleanup.  close the filestream and wait for ds destruction */
00738    ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
00739    mixmonitor_ds_close_fs(mixmonitor->mixmonitor_ds);
00740    if (!mixmonitor->mixmonitor_ds->destruction_ok) {
00741       ast_cond_wait(&mixmonitor->mixmonitor_ds->destruction_condition, &mixmonitor->mixmonitor_ds->lock);
00742    }
00743    ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
00744 
00745    /* kill the audiohook */
00746    destroy_monitor_audiohook(mixmonitor);
00747 
00748    if (mixmonitor->post_process) {
00749       ast_verb(2, "Executing [%s]\n", mixmonitor->post_process);
00750       ast_safe_system(mixmonitor->post_process);
00751    }
00752 
00753    ast_verb(2, "End MixMonitor Recording %s\n", mixmonitor->name);
00754    ast_test_suite_event_notify("MIXMONITOR_END", "File: %s\r\n", mixmonitor->filename);
00755 
00756    if (!AST_LIST_EMPTY(&mixmonitor->recipient_list)) {
00757       if (ast_strlen_zero(fs_ext)) {
00758          ast_log(LOG_ERROR, "No file extension set for Mixmonitor %s. Skipping copy to voicemail.\n",
00759             mixmonitor -> name);
00760       } else {
00761          ast_verb(3, "Copying recordings for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
00762          copy_to_voicemail(mixmonitor, fs_ext, mixmonitor->filename);
00763       }
00764       if (!ast_strlen_zero(fs_read_ext)) {
00765          ast_verb(3, "Copying read recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
00766          copy_to_voicemail(mixmonitor, fs_read_ext, mixmonitor->filename_read);
00767       }
00768       if (!ast_strlen_zero(fs_write_ext)) {
00769          ast_verb(3, "Copying write recording for Mixmonitor %s to voicemail recipients\n", mixmonitor->name);
00770          copy_to_voicemail(mixmonitor, fs_write_ext, mixmonitor->filename_write);
00771       }
00772    } else {
00773       ast_debug(3, "No recipients to forward monitor to, moving on.\n");
00774    }
00775 
00776    mixmonitor_free(mixmonitor);
00777 
00778    ast_module_unref(ast_module_info->self);
00779    return NULL;
00780 }

static int set_mixmonitor_methods ( void   )  [static]

Definition at line 1487 of file app_mixmonitor.c.

References ast_set_mixmonitor_methods(), ast_mixmonitor_methods::start, start_mixmonitor_callback(), and stop_mixmonitor_callback().

Referenced by load_module().

01488 {
01489    struct ast_mixmonitor_methods mixmonitor_methods = {
01490       .start = start_mixmonitor_callback,
01491       .stop = stop_mixmonitor_callback,
01492    };
01493 
01494    return ast_set_mixmonitor_methods(&mixmonitor_methods);
01495 }

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

Definition at line 782 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, ast_strdup, ast_stream_and_wait(), ast_strlen_zero, ast_test_flag, mixmonitor::audiohook, mixmonitor_ds::audiohook, mixmonitor::autochan, mixmonitor_ds::beep_id, ast_autochan::chan, ast_datastore::data, mixmonitor_ds::destruction_condition, mixmonitor::filename, mixmonitor_ds::filename, mixmonitor_ds::lock, LOG_ERROR, mixmonitor::mixmonitor_ds, MUXFLAG_BEEP_START, NULL, and mixmonitor_ds::samp_rate.

Referenced by launch_monitor_thread().

00783 {
00784    struct ast_datastore *datastore = NULL;
00785    struct mixmonitor_ds *mixmonitor_ds;
00786 
00787    if (!(mixmonitor_ds = ast_calloc(1, sizeof(*mixmonitor_ds)))) {
00788       return -1;
00789    }
00790 
00791    if (ast_asprintf(datastore_id, "%p", mixmonitor_ds) == -1) {
00792       ast_log(LOG_ERROR, "Failed to allocate memory for MixMonitor ID.\n");
00793    }
00794 
00795    ast_mutex_init(&mixmonitor_ds->lock);
00796    ast_cond_init(&mixmonitor_ds->destruction_condition, NULL);
00797 
00798    if (!(datastore = ast_datastore_alloc(&mixmonitor_ds_info, *datastore_id))) {
00799       ast_mutex_destroy(&mixmonitor_ds->lock);
00800       ast_cond_destroy(&mixmonitor_ds->destruction_condition);
00801       ast_free(mixmonitor_ds);
00802       return -1;
00803    }
00804 
00805    ast_channel_lock(mixmonitor->autochan->chan);
00806    if (ast_test_flag(mixmonitor, MUXFLAG_BEEP_START)) {
00807       ast_stream_and_wait(mixmonitor->autochan->chan, "beep", "");
00808    }
00809    ast_channel_unlock(mixmonitor->autochan->chan);
00810 
00811    mixmonitor_ds->samp_rate = 8000;
00812    mixmonitor_ds->audiohook = &mixmonitor->audiohook;
00813    mixmonitor_ds->filename = ast_strdup(mixmonitor->filename);
00814    if (!ast_strlen_zero(beep_id)) {
00815       mixmonitor_ds->beep_id = ast_strdup(beep_id);
00816    }
00817    datastore->data = mixmonitor_ds;
00818 
00819    ast_channel_lock(chan);
00820    ast_channel_datastore_add(chan, datastore);
00821    ast_channel_unlock(chan);
00822 
00823    mixmonitor->mixmonitor_ds = mixmonitor_ds;
00824    return 0;
00825 }

static int start_mixmonitor_callback ( struct ast_channel chan,
const char *  filename,
const char *  options 
) [static]

Definition at line 1318 of file app_mixmonitor.c.

References args, ast_strlen_zero, and mixmonitor_exec().

Referenced by set_mixmonitor_methods().

01319 {
01320    char args[PATH_MAX];
01321 
01322    if (ast_strlen_zero(options)) {
01323       snprintf(args, sizeof(args), "%s", filename);
01324    } else {
01325       snprintf(args, sizeof(args), "%s,%s", filename, options);
01326    }
01327 
01328    return mixmonitor_exec(chan, args);
01329 }

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

Definition at line 452 of file app_mixmonitor.c.

References ast_audiohook_attach().

Referenced by launch_monitor_thread().

00453 {
00454    if (!chan) {
00455       return -1;
00456    }
00457 
00458    return ast_audiohook_attach(chan, audiohook);
00459 }

static int stop_mixmonitor_callback ( struct ast_channel chan,
const char *  mixmonitor_id 
) [static]

Definition at line 1331 of file app_mixmonitor.c.

References stop_mixmonitor_full().

Referenced by set_mixmonitor_methods().

01332 {
01333    return stop_mixmonitor_full(chan, mixmonitor_id);
01334 }

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

Definition at line 1180 of file app_mixmonitor.c.

References stop_mixmonitor_full().

Referenced by handle_cli_mixmonitor(), and load_module().

01181 {
01182    stop_mixmonitor_full(chan, data);
01183    return 0;
01184 }

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

Definition at line 1114 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_beep_stop(), 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, mixmonitor_ds::beep_id, ast_datastore::data, mixmonitor_ds::lock, mixmonitor_ds_close_fs(), NULL, parse(), S_OR, ast_audiohook::status, and ast_audiohook::trigger.

Referenced by manager_stop_mixmonitor(), stop_mixmonitor_callback(), and stop_mixmonitor_exec().

01115 {
01116    struct ast_datastore *datastore = NULL;
01117    char *parse = "";
01118    struct mixmonitor_ds *mixmonitor_ds;
01119    const char *beep_id = NULL;
01120 
01121    AST_DECLARE_APP_ARGS(args,
01122       AST_APP_ARG(mixmonid);
01123    );
01124 
01125    if (!ast_strlen_zero(data)) {
01126       parse = ast_strdupa(data);
01127    }
01128 
01129    AST_STANDARD_APP_ARGS(args, parse);
01130 
01131    ast_channel_lock(chan);
01132 
01133    datastore = ast_channel_datastore_find(chan, &mixmonitor_ds_info,
01134       S_OR(args.mixmonid, NULL));
01135    if (!datastore) {
01136       ast_channel_unlock(chan);
01137       return -1;
01138    }
01139    mixmonitor_ds = datastore->data;
01140 
01141    ast_mutex_lock(&mixmonitor_ds->lock);
01142 
01143    /* closing the filestream here guarantees the file is available to the dialplan
01144     * after calling StopMixMonitor */
01145    mixmonitor_ds_close_fs(mixmonitor_ds);
01146 
01147    /* The mixmonitor thread may be waiting on the audiohook trigger.
01148     * In order to exit from the mixmonitor loop before waiting on channel
01149     * destruction, poke the audiohook trigger. */
01150    if (mixmonitor_ds->audiohook) {
01151       if (mixmonitor_ds->audiohook->status != AST_AUDIOHOOK_STATUS_DONE) {
01152          ast_audiohook_update_status(mixmonitor_ds->audiohook, AST_AUDIOHOOK_STATUS_SHUTDOWN);
01153       }
01154       ast_audiohook_lock(mixmonitor_ds->audiohook);
01155       ast_cond_signal(&mixmonitor_ds->audiohook->trigger);
01156       ast_audiohook_unlock(mixmonitor_ds->audiohook);
01157       mixmonitor_ds->audiohook = NULL;
01158    }
01159 
01160    if (!ast_strlen_zero(mixmonitor_ds->beep_id)) {
01161       beep_id = ast_strdupa(mixmonitor_ds->beep_id);
01162    }
01163 
01164    ast_mutex_unlock(&mixmonitor_ds->lock);
01165 
01166    /* Remove the datastore so the monitor thread can exit */
01167    if (!ast_channel_datastore_remove(chan, datastore)) {
01168       ast_datastore_free(datastore);
01169    }
01170 
01171    ast_channel_unlock(chan);
01172 
01173    if (!ast_strlen_zero(beep_id)) {
01174       ast_beep_stop(chan, beep_id);
01175    }
01176 
01177    return 0;
01178 }

static int unload_module ( void   )  [static]

Definition at line 1502 of file app_mixmonitor.c.

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

01503 {
01504    int res;
01505 
01506    ast_cli_unregister_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor));
01507    res = ast_unregister_application(stop_app);
01508    res |= ast_unregister_application(app);
01509    res |= ast_manager_unregister("MixMonitorMute");
01510    res |= ast_manager_unregister("MixMonitor");
01511    res |= ast_manager_unregister("StopMixMonitor");
01512    res |= ast_custom_function_unregister(&mixmonitor_function);
01513    res |= clear_mixmonitor_methods();
01514 
01515    return res;
01516 }


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, .support_level = AST_MODULE_SUPPORT_CORE, } [static]

Definition at line 1534 of file app_mixmonitor.c.

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

Definition at line 279 of file app_mixmonitor.c.

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

Initial value:

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

Definition at line 433 of file app_mixmonitor.c.

Initial value:

 {
   .name = "MIXMONITOR",
   .read = func_mixmonitor_read,
}

Definition at line 1478 of file app_mixmonitor.c.

struct ast_app_option mixmonitor_opts[128] = { [ 'a' ] = { .flag = MUXFLAG_APPEND }, [ 'b' ] = { .flag = MUXFLAG_BRIDGED }, [ 'B' ] = { .flag = MUXFLAG_BEEP , .arg_index = OPT_ARG_BEEP_INTERVAL + 1 }, [ 'p' ] = { .flag = MUXFLAG_BEEP_START }, [ 'P' ] = { .flag = MUXFLAG_BEEP_STOP }, [ '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 }, [ 'm' ] = { .flag = MUXFLAG_VMRECIPIENTS , .arg_index = OPT_ARG_VMRECIPIENTS + 1 },} [static]

Definition at line 364 of file app_mixmonitor.c.

Referenced by manager_mixmonitor(), and mixmonitor_exec().

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

Definition at line 283 of file app_mixmonitor.c.

Referenced by feature_automixmonitor().

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

Definition at line 281 of file app_mixmonitor.c.


Generated on Thu Apr 16 06:28:34 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6