#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"

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_info * | ast_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" |
Definition in file app_mixmonitor.c.
| #define get_volfactor | ( | x | ) | x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 |
| #define SAMPLES_PER_FRAME 160 |
| enum mixmonitor_args |
| 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 };
| enum mixmonitor_flags |
| 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 };
| 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] |
Definition at line 1104 of file app_mixmonitor.c.
References ARRAY_LEN, ast_cli_register_multiple(), ast_manager_register_xml, ast_register_application_xml, manager_mixmonitor(), manager_mute_mixmonitor(), manager_stop_mixmonitor(), mixmonitor_exec(), and stop_mixmonitor_exec().
01105 { 01106 int res; 01107 01108 ast_cli_register_multiple(cli_mixmonitor, ARRAY_LEN(cli_mixmonitor)); 01109 res = ast_register_application_xml(app, mixmonitor_exec); 01110 res |= ast_register_application_xml(stop_app, stop_mixmonitor_exec); 01111 res |= ast_manager_register_xml("MixMonitorMute", 0, manager_mute_mixmonitor); 01112 res |= ast_manager_register_xml("MixMonitor", 0, manager_mixmonitor); 01113 res |= ast_manager_register_xml("StopMixMonitor", 0, manager_stop_mixmonitor); 01114 01115 return res; 01116 }
| 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 }
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.
struct ast_module_info* ast_module_info = &__mod_info [static] |
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.
struct ast_datastore_info mixmonitor_ds_info [static] |
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] |
const char* const stop_app = "StopMixMonitor" [static] |
Definition at line 237 of file app_mixmonitor.c.
1.5.6