#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "asterisk.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/chanspy.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/lock.h"
#include "asterisk/cli.h"
#include "asterisk/options.h"
#include "asterisk/app.h"
#include "asterisk/linkedlists.h"
Include dependency graph for app_mixmonitor.c:
Go to the source code of this file.
Data Structures | |
struct | mixmonitor |
Defines | |
#define | get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0 |
#define | SAMPLES_PER_FRAME 160 |
Enumerations | |
enum | { MUXFLAG_APPEND = (1 << 1), MUXFLAG_BRIDGED = (1 << 2), MUXFLAG_VOLUME = (1 << 3), MUXFLAG_READVOLUME = (1 << 4), MUXFLAG_WRITEVOLUME = (1 << 5) } |
enum | { OPT_ARG_READVOLUME = 0, OPT_ARG_WRITEVOLUME, OPT_ARG_VOLUME, OPT_ARG_ARRAY_SIZE } |
Functions | |
AST_APP_OPTIONS (mixmonitor_opts,{AST_APP_OPTION('a', MUXFLAG_APPEND), AST_APP_OPTION('b', MUXFLAG_BRIDGED), AST_APP_OPTION_ARG('v', MUXFLAG_READVOLUME, OPT_ARG_READVOLUME), AST_APP_OPTION_ARG('V', MUXFLAG_WRITEVOLUME, OPT_ARG_WRITEVOLUME), AST_APP_OPTION_ARG('W', MUXFLAG_VOLUME, OPT_ARG_VOLUME),}) | |
char * | description (void) |
Provides a description of the module. | |
char * | key () |
Returns the ASTERISK_GPL_KEY. | |
static void | launch_monitor_thread (struct ast_channel *chan, const char *filename, unsigned int flags, int readvol, int writevol, const char *post_process) |
int | load_module (void) |
Initialize the module. | |
static int | mixmonitor_cli (int fd, int argc, char **argv) |
static int | mixmonitor_exec (struct ast_channel *chan, void *data) |
static void * | mixmonitor_thread (void *obj) |
static int | startmon (struct ast_channel *chan, struct ast_channel_spy *spy) |
static void | stopmon (struct ast_channel *chan, struct ast_channel_spy *spy) |
int | unload_module (void) |
Cleanup all module structures, sockets, etc. | |
int | usecount (void) |
Provides a usecount. | |
Variables | |
static const char * | app = "MixMonitor" |
static struct ast_cli_entry | cli_mixmonitor |
static const char * | desc |
LOCAL_USER_DECL | |
enum { ... } | mixmonitor_args |
struct { | |
int alarm | |
char * description | |
unsigned int event_log:1 | |
enum queue_result id | |
char * name | |
char * name | |
char * name | |
rtpPayloadType payloadType | |
unsigned int queue_log:1 | |
char * subtype | |
char * text | |
char * type | |
int val | |
} | mixmonitor_flags |
static const char * | mixmonitor_spy_type = "MixMonitor" |
STANDARD_LOCAL_USER | |
static const char * | synopsis = "Record a call and mix the audio during the recording" |
static const char * | tdesc = "Mixed Audio Monitoring Application" |
Definition in file app_mixmonitor.c.
|
Definition at line 50 of file app_mixmonitor.c. |
|
Definition at line 146 of file app_mixmonitor.c. Referenced by mixmonitor_thread(). |
|
Definition at line 90 of file app_mixmonitor.c. 00090 { 00091 MUXFLAG_APPEND = (1 << 1), 00092 MUXFLAG_BRIDGED = (1 << 2), 00093 MUXFLAG_VOLUME = (1 << 3), 00094 MUXFLAG_READVOLUME = (1 << 4), 00095 MUXFLAG_WRITEVOLUME = (1 << 5), 00096 } mixmonitor_flags;
|
|
Definition at line 98 of file app_mixmonitor.c. 00098 { 00099 OPT_ARG_READVOLUME = 0, 00100 OPT_ARG_WRITEVOLUME, 00101 OPT_ARG_VOLUME, 00102 OPT_ARG_ARRAY_SIZE, 00103 } mixmonitor_args;
|
|
|
|
Provides a description of the module.
Definition at line 449 of file app_mixmonitor.c. 00450 { 00451 return (char *) tdesc; 00452 }
|
|
Returns the ASTERISK_GPL_KEY. This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:
char *key(void) { return ASTERISK_GPL_KEY; }
Definition at line 463 of file app_mixmonitor.c. References ASTERISK_GPL_KEY. 00464 { 00465 return ASTERISK_GPL_KEY; 00466 }
|
|
Definition at line 276 of file app_mixmonitor.c. References ast_log(), ast_pthread_create, ast_strlen_zero(), calloc, mixmonitor::chan, mixmonitor::filename, LOG_ERROR, and mixmonitor_thread(). Referenced by mixmonitor_exec(). 00278 { 00279 pthread_attr_t attr; 00280 pthread_t thread; 00281 struct mixmonitor *mixmonitor; 00282 int len; 00283 00284 len = sizeof(*mixmonitor) + strlen(filename) + 1; 00285 if (!ast_strlen_zero(post_process)) 00286 len += strlen(post_process) + 1; 00287 00288 if (!(mixmonitor = calloc(1, len))) { 00289 ast_log(LOG_ERROR, "Memory Error!\n"); 00290 return; 00291 } 00292 00293 mixmonitor->chan = chan; 00294 mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor); 00295 strcpy(mixmonitor->filename, filename); 00296 if (!ast_strlen_zero(post_process)) { 00297 mixmonitor->post_process = mixmonitor->filename + strlen(filename) + 1; 00298 strcpy(mixmonitor->post_process, post_process); 00299 } 00300 mixmonitor->readvol = readvol; 00301 mixmonitor->writevol = writevol; 00302 mixmonitor->flags = flags; 00303 00304 pthread_attr_init(&attr); 00305 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00306 ast_pthread_create(&thread, &attr, mixmonitor_thread, mixmonitor); 00307 pthread_attr_destroy(&attr); 00308 }
|
|
Initialize the module. Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.
Definition at line 439 of file app_mixmonitor.c. References ast_cli_register(), ast_register_application(), cli_mixmonitor, and mixmonitor_exec(). 00440 { 00441 int res; 00442 00443 res = ast_cli_register(&cli_mixmonitor); 00444 res |= ast_register_application(app, mixmonitor_exec, synopsis, desc); 00445 00446 return res; 00447 }
|
|
Definition at line 396 of file app_mixmonitor.c. References ast_channel_spy_stop_by_type(), ast_cli(), ast_get_channel_by_name_prefix_locked(), ast_mutex_unlock(), ast_channel::lock, mixmonitor_exec(), RESULT_SHOWUSAGE, and RESULT_SUCCESS. 00397 { 00398 struct ast_channel *chan; 00399 00400 if (argc < 3) 00401 return RESULT_SHOWUSAGE; 00402 00403 if (!(chan = ast_get_channel_by_name_prefix_locked(argv[2], strlen(argv[2])))) { 00404 ast_cli(fd, "No channel matching '%s' found.\n", argv[2]); 00405 return RESULT_SUCCESS; 00406 } 00407 00408 if (!strcasecmp(argv[1], "start")) 00409 mixmonitor_exec(chan, argv[3]); 00410 else if (!strcasecmp(argv[1], "stop")) 00411 ast_channel_spy_stop_by_type(chan, mixmonitor_spy_type); 00412 00413 ast_mutex_unlock(&chan->lock); 00414 00415 return RESULT_SUCCESS; 00416 }
|
|
Definition at line 310 of file app_mixmonitor.c. References AST_APP_ARG, ast_app_parse_options(), ast_config_AST_MONITOR_DIR, AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_flags::flags, get_volfactor, launch_monitor_thread(), LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_NOTICE, LOG_WARNING, MUXFLAG_READVOLUME, MUXFLAG_VOLUME, MUXFLAG_WRITEVOLUME, OPT_ARG_ARRAY_SIZE, OPT_ARG_READVOLUME, OPT_ARG_VOLUME, OPT_ARG_WRITEVOLUME, parse(), pbx_builtin_setvar_helper(), mixmonitor::readvol, and mixmonitor::writevol. Referenced by load_module(), and mixmonitor_cli(). 00311 { 00312 int x, readvol = 0, writevol = 0; 00313 struct localuser *u; 00314 struct ast_flags flags = {0}; 00315 char *parse; 00316 AST_DECLARE_APP_ARGS(args, 00317 AST_APP_ARG(filename); 00318 AST_APP_ARG(options); 00319 AST_APP_ARG(post_process); 00320 ); 00321 00322 if (ast_strlen_zero(data)) { 00323 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00324 return -1; 00325 } 00326 00327 LOCAL_USER_ADD(u); 00328 00329 if (!(parse = ast_strdupa(data))) { 00330 ast_log(LOG_WARNING, "Memory Error!\n"); 00331 LOCAL_USER_REMOVE(u); 00332 return -1; 00333 } 00334 00335 AST_STANDARD_APP_ARGS(args, parse); 00336 00337 if (ast_strlen_zero(args.filename)) { 00338 ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n"); 00339 LOCAL_USER_REMOVE(u); 00340 return -1; 00341 } 00342 00343 if (args.options) { 00344 char *opts[OPT_ARG_ARRAY_SIZE] = { NULL, }; 00345 00346 ast_app_parse_options(mixmonitor_opts, &flags, opts, args.options); 00347 00348 if (ast_test_flag(&flags, MUXFLAG_READVOLUME)) { 00349 if (ast_strlen_zero(opts[OPT_ARG_READVOLUME])) { 00350 ast_log(LOG_WARNING, "No volume level was provided for the heard volume ('v') option.\n"); 00351 } else if ((sscanf(opts[OPT_ARG_READVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { 00352 ast_log(LOG_NOTICE, "Heard volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_READVOLUME]); 00353 } else { 00354 readvol = get_volfactor(x); 00355 } 00356 } 00357 00358 if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) { 00359 if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) { 00360 ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n"); 00361 } else if ((sscanf(opts[OPT_ARG_WRITEVOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { 00362 ast_log(LOG_NOTICE, "Spoken volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_WRITEVOLUME]); 00363 } else { 00364 writevol = get_volfactor(x); 00365 } 00366 } 00367 00368 if (ast_test_flag(&flags, MUXFLAG_VOLUME)) { 00369 if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) { 00370 ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n"); 00371 } else if ((sscanf(opts[OPT_ARG_VOLUME], "%d", &x) != 1) || (x < -4) || (x > 4)) { 00372 ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]); 00373 } else { 00374 readvol = writevol = get_volfactor(x); 00375 } 00376 } 00377 } 00378 00379 /* if not provided an absolute path, use the system-configured monitoring directory */ 00380 if (args.filename[0] != '/') { 00381 char *build; 00382 00383 build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3); 00384 sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename); 00385 args.filename = build; 00386 } 00387 00388 pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename); 00389 launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process); 00390 00391 LOCAL_USER_REMOVE(u); 00392 00393 return 0; 00394 }
|
|
Definition at line 148 of file app_mixmonitor.c. References ast_bridged_channel(), ast_channel_spy_read_frame(), ast_channel_spy_trigger_wait(), ast_check_hangup(), AST_FORMAT_SLINEAR, ast_frfree(), ast_log(), ast_mutex_init(), ast_mutex_lock(), ast_mutex_unlock(), ast_seekstream(), ast_set_flag, ast_strdupa, ast_test_flag, ast_verbose(), ast_writefile(), ast_writestream(), mixmonitor::chan, CHANSPY_FORMAT_AUDIO, CHANSPY_MIXAUDIO, CHANSPY_READ_VOLADJUST, CHANSPY_RUNNING, CHANSPY_WRITE_VOLADJUST, mixmonitor::filename, LOG_ERROR, LOG_WARNING, MUXFLAG_APPEND, MUXFLAG_BRIDGED, ast_channel::name, name, ast_frame::next, option_verbose, pbx_substitute_variables_helper(), mixmonitor::post_process, mixmonitor::readvol, SAMPLES_PER_FRAME, STANDARD_INCREMENT_USECOUNT, startmon(), VERBOSE_PREFIX_2, and mixmonitor::writevol. Referenced by launch_monitor_thread(). 00149 { 00150 struct mixmonitor *mixmonitor = obj; 00151 struct ast_channel_spy spy; 00152 struct ast_filestream *fs = NULL; 00153 char *ext, *name; 00154 unsigned int oflags; 00155 struct ast_frame *f; 00156 char post_process[1024] = ""; 00157 00158 STANDARD_INCREMENT_USECOUNT; 00159 00160 name = ast_strdupa(mixmonitor->chan->name); 00161 00162 oflags = O_CREAT|O_WRONLY; 00163 oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC; 00164 00165 if ((ext = strrchr(mixmonitor->filename, '.'))) { 00166 *(ext++) = '\0'; 00167 } else { 00168 ext = "raw"; 00169 } 00170 00171 fs = ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0644); 00172 if (!fs) { 00173 ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext); 00174 goto out; 00175 } 00176 00177 if (ast_test_flag(mixmonitor, MUXFLAG_APPEND)) 00178 ast_seekstream(fs, 0, SEEK_END); 00179 00180 memset(&spy, 0, sizeof(spy)); 00181 ast_set_flag(&spy, CHANSPY_FORMAT_AUDIO); 00182 ast_set_flag(&spy, CHANSPY_MIXAUDIO); 00183 spy.type = mixmonitor_spy_type; 00184 spy.status = CHANSPY_RUNNING; 00185 spy.read_queue.format = AST_FORMAT_SLINEAR; 00186 spy.write_queue.format = AST_FORMAT_SLINEAR; 00187 if (mixmonitor->readvol) { 00188 ast_set_flag(&spy, CHANSPY_READ_VOLADJUST); 00189 spy.read_vol_adjustment = mixmonitor->readvol; 00190 } 00191 if (mixmonitor->writevol) { 00192 ast_set_flag(&spy, CHANSPY_WRITE_VOLADJUST); 00193 spy.write_vol_adjustment = mixmonitor->writevol; 00194 } 00195 ast_mutex_init(&spy.lock); 00196 00197 if (startmon(mixmonitor->chan, &spy)) { 00198 ast_log(LOG_WARNING, "Unable to add '%s' spy to channel '%s'\n", 00199 spy.type, mixmonitor->chan->name); 00200 goto out2; 00201 } 00202 00203 if (option_verbose > 1) 00204 ast_verbose(VERBOSE_PREFIX_2 "Begin MixMonitor Recording %s\n", name); 00205 00206 if (mixmonitor->post_process) { 00207 char *p; 00208 00209 for (p = mixmonitor->post_process; *p ; p++) { 00210 if (*p == '^' && *(p+1) == '{') { 00211 *p = '$'; 00212 } 00213 } 00214 pbx_substitute_variables_helper(mixmonitor->chan, mixmonitor->post_process, post_process, sizeof(post_process) - 1); 00215 } 00216 00217 while (1) { 00218 struct ast_frame *next; 00219 int write; 00220 00221 ast_mutex_lock(&spy.lock); 00222 00223 ast_channel_spy_trigger_wait(&spy); 00224 00225 if (ast_check_hangup(mixmonitor->chan) || spy.status != CHANSPY_RUNNING) { 00226 ast_mutex_unlock(&spy.lock); 00227 break; 00228 } 00229 00230 while (1) { 00231 if (!(f = ast_channel_spy_read_frame(&spy, SAMPLES_PER_FRAME))) 00232 break; 00233 00234 write = (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || 00235 ast_bridged_channel(mixmonitor->chan)); 00236 00237 /* it is possible for ast_channel_spy_read_frame() to return a chain 00238 of frames if a queue flush was necessary, so process them 00239 */ 00240 for (; f; f = next) { 00241 next = f->next; 00242 if (write) 00243 ast_writestream(fs, f); 00244 ast_frfree(f); 00245 } 00246 } 00247 00248 ast_mutex_unlock(&spy.lock); 00249 } 00250 00251 stopmon(mixmonitor->chan, &spy); 00252 00253 if (option_verbose > 1) 00254 ast_verbose(VERBOSE_PREFIX_2 "End MixMonitor Recording %s\n", name); 00255 00256 if (!ast_strlen_zero(post_process)) { 00257 if (option_verbose > 2) 00258 ast_verbose(VERBOSE_PREFIX_2 "Executing [%s]\n", post_process); 00259 ast_safe_system(post_process); 00260 } 00261 00262 out2: 00263 ast_mutex_destroy(&spy.lock); 00264 00265 if (fs) 00266 ast_closestream(fs); 00267 00268 out: 00269 free(mixmonitor); 00270 00271 STANDARD_DECREMENT_USECOUNT; 00272 00273 return NULL; 00274 }
|
|
Definition at line 128 of file app_mixmonitor.c. References ast_bridged_channel(), ast_channel_spy_add(), AST_FLAG_NBRIDGE, ast_mutex_lock(), ast_mutex_unlock(), ast_softhangup(), AST_SOFTHANGUP_UNBRIDGE, ast_test_flag, and ast_channel::lock. Referenced by mixmonitor_thread(). 00129 { 00130 struct ast_channel *peer; 00131 int res; 00132 00133 if (!chan) 00134 return -1; 00135 00136 ast_mutex_lock(&chan->lock); 00137 res = ast_channel_spy_add(chan, spy); 00138 ast_mutex_unlock(&chan->lock); 00139 00140 if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan))) 00141 ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE); 00142 00143 return res; 00144 }
|
|
Definition at line 113 of file app_mixmonitor.c. References ast_channel_spy_remove(), ast_mutex_lock(), ast_mutex_unlock(), CHANSPY_DONE, ast_channel::lock, and ast_channel_spy::status. 00114 { 00115 /* If our status has changed to DONE, then the channel we're spying on is gone.... 00116 DON'T TOUCH IT!!! RUN AWAY!!! */ 00117 if (spy->status == CHANSPY_DONE) 00118 return; 00119 00120 if (!chan) 00121 return; 00122 00123 ast_mutex_lock(&chan->lock); 00124 ast_channel_spy_remove(chan, spy); 00125 ast_mutex_unlock(&chan->lock); 00126 }
|
|
Cleanup all module structures, sockets, etc. This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).
Definition at line 427 of file app_mixmonitor.c. References ast_cli_unregister(), ast_unregister_application(), cli_mixmonitor, and STANDARD_HANGUP_LOCALUSERS. 00428 { 00429 int res; 00430 00431 res = ast_cli_unregister(&cli_mixmonitor); 00432 res |= ast_unregister_application(app); 00433 00434 STANDARD_HANGUP_LOCALUSERS; 00435 00436 return res; 00437 }
|
|
Provides a usecount. This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.
Definition at line 454 of file app_mixmonitor.c. References STANDARD_USECOUNT. 00455 { 00456 int res; 00457 00458 STANDARD_USECOUNT(res); 00459 00460 return res; 00461 }
|
|
Definition at line 53 of file app_mixmonitor.c. |
|
Definition at line 419 of file app_mixmonitor.c. Referenced by load_module(), and unload_module(). |
|
Definition at line 55 of file app_mixmonitor.c. |
|
Definition at line 77 of file app_mixmonitor.c. |
|
|
|
|
|
Definition at line 79 of file app_mixmonitor.c. |
|
Definition at line 75 of file app_mixmonitor.c. |
|
Definition at line 54 of file app_mixmonitor.c. |
|
Definition at line 52 of file app_mixmonitor.c. |