[asterisk-commits] jrose: branch jrose/mix-monitor-branch r309258 - in /team/jrose/mix-monitor-b...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Wed Mar 2 13:59:53 CST 2011
Author: jrose
Date: Wed Mar 2 13:59:49 2011
New Revision: 309258
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=309258
Log:
Significant changes to improve code reuse and better conform to the written standards for development in Asterisk.
Modified:
team/jrose/mix-monitor-branch/apps/app_mixmonitor.c
team/jrose/mix-monitor-branch/include/asterisk/audiohook.h
team/jrose/mix-monitor-branch/main/audiohook.c
Modified: team/jrose/mix-monitor-branch/apps/app_mixmonitor.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/mix-monitor-branch/apps/app_mixmonitor.c?view=diff&rev=309258&r1=309257&r2=309258
==============================================================================
--- team/jrose/mix-monitor-branch/apps/app_mixmonitor.c (original)
+++ team/jrose/mix-monitor-branch/apps/app_mixmonitor.c Wed Mar 2 13:59:49 2011
@@ -37,7 +37,7 @@
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
-#include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
+#include "asterisk/paths.h" /* use ast_config_AST_MONITOR_DIR */
#include "asterisk/file.h"
#include "asterisk/audiohook.h"
#include "asterisk/pbx.h"
@@ -89,6 +89,19 @@
of <replaceable>x</replaceable> (range <literal>-4</literal> to <literal>4</literal>)</para>
<argument name="x" required="true" />
</option>
+ <option name="r">
+ <argument name="file" required="true" />
+ <para>Use the specified file to record the <emphasis>receive</emphasis> audio feed.
+ Like with the basic filename argument, if an absolute path isn't given, it will create
+ the file in the configured monitoring directory.</para>
+
+ </option>
+ <option name="t">
+ <argument name="file" required="true" />
+ <para>Use the specified file to record the <emphasis>transmit</emphasis> audio feed.
+ Like with the basic filename argument, if an absolute path isn't given, it will create
+ the file in the configured monitoring directory.</para>
+ </option>
</optionlist>
</parameter>
<parameter name="command">
@@ -103,7 +116,7 @@
<variable name="MIXMONITOR_FILENAME">
<para>Will contain the filename used to record.</para>
</variable>
- </variablelist>
+ </variablelist>
</description>
<see-also>
<ref type="application">Monitor</ref>
@@ -150,59 +163,59 @@
#define get_volfactor(x) x ? ((x > 0) ? (1 << x) : ((1 << abs(x)) * -1)) : 0
- static const char *const app = "MixMonitor";
-
- static const char *const stop_app = "StopMixMonitor";
-
- static const char *const mixmonitor_spy_type = "MixMonitor";
-
- struct mixmonitor {
- struct ast_audiohook audiohook;
- char *filename;
- char *filename_read;
- char *filename_write;
- char *post_process;
- char *name;
- unsigned int flags;
- struct ast_autochan *autochan;
- struct mixmonitor_ds *mixmonitor_ds;
- };
-
- 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),
-
- };
-
- enum mixmonitor_args {
- OPT_ARG_READVOLUME = 0,
- OPT_ARG_WRITEVOLUME,
- OPT_ARG_VOLUME,
- OPT_ARG_WRITENAME,
- OPT_ARG_READNAME,
- OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
- };
+static const char *const app = "MixMonitor";
+
+static const char *const stop_app = "StopMixMonitor";
+
+static const char *const mixmonitor_spy_type = "MixMonitor";
+
+struct mixmonitor {
+ struct ast_audiohook audiohook;
+ char *filename;
+ char *filename_read;
+ char *filename_write;
+ char *post_process;
+ char *name;
+ unsigned int flags;
+ struct ast_autochan *autochan;
+ struct mixmonitor_ds *mixmonitor_ds;
+ };
+
+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),
+ };
+
+enum mixmonitor_args {
+ OPT_ARG_READVOLUME = 0,
+ OPT_ARG_WRITEVOLUME,
+ OPT_ARG_VOLUME,
+ OPT_ARG_WRITENAME,
+ OPT_ARG_READNAME,
+ OPT_ARG_ARRAY_SIZE, /* Always last element of the enum */
+ };
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),
- AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
- AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
+ 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),
+ AST_APP_OPTION_ARG('r', MUXFLAG_READ, OPT_ARG_READNAME),
+ AST_APP_OPTION_ARG('t', MUXFLAG_WRITE, OPT_ARG_WRITENAME),
});
struct mixmonitor_ds {
unsigned int destruction_ok;
ast_cond_t destruction_condition;
ast_mutex_t lock;
+
/* The filestream is held in the datastore so it can be stopped
* immediately during stop_mixmonitor or channel destruction. */
int fs_quit;
@@ -220,22 +233,30 @@
*/
static void mixmonitor_ds_close_fs(struct mixmonitor_ds *mixmonitor_ds)
{
+ unsigned char quitting = 0;
+
if (mixmonitor_ds->fs) {
- if (mixmonitor_ds->fs_read)
- ast_closestream(mixmonitor_ds->fs_read);
- if (mixmonitor_ds->fs_write)
- ast_closestream(mixmonitor_ds->fs_write);
- if (mixmonitor_ds->fs)
- ast_closestream(mixmonitor_ds->fs);
-
+ quitting = 1;
+ ast_closestream(mixmonitor_ds->fs);
mixmonitor_ds->fs = NULL;
+ ast_verb(2, "MixMonitor close filestream (mixed)\n");
+ }
+
+ if (mixmonitor_ds->fs_read) {
+ quitting = 1;
+ ast_closestream(mixmonitor_ds->fs_read);
mixmonitor_ds->fs_read = NULL;
+ ast_verb(2, "MixMonitor close filestream (read)\n");
+ }
+
+ if (mixmonitor_ds->fs_write) {
+ quitting = 1;
+ ast_closestream(mixmonitor_ds->fs_write);
mixmonitor_ds->fs_write = NULL;
-
- mixmonitor_ds->fs_quit = 1;
-
- ast_verb(2, "MixMonitor close filestream(s)\n");
- }
+ ast_verb(2, "MixMonitor close filestream (write)\n");
+ }
+
+ if (quitting) { mixmonitor_ds->fs_quit = 1; }
}
static void mixmonitor_ds_destroy(void *data)
@@ -261,14 +282,14 @@
mixmonitor->mixmonitor_ds->audiohook = NULL;
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
- /* kill the audiohook. */
+ /* kill the audiohook.*/
ast_audiohook_lock(&mixmonitor->audiohook);
ast_audiohook_detach(&mixmonitor->audiohook);
ast_audiohook_unlock(&mixmonitor->audiohook);
ast_audiohook_destroy(&mixmonitor->audiohook);
}
-static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
+static int startmon(struct ast_channel *chan, struct ast_audiohook *audiohook)
{
struct ast_channel *peer = NULL;
int res = 0;
@@ -279,7 +300,7 @@
ast_audiohook_attach(chan, audiohook);
if (!res && ast_test_flag(chan, AST_FLAG_NBRIDGE) && (peer = ast_bridged_channel(chan)))
- ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
+ ast_softhangup(peer, AST_SOFTHANGUP_UNBRIDGE);
return res;
}
@@ -300,6 +321,33 @@
}
}
+static void mixmonitor_save_prep(struct mixmonitor *mixmonitor, char *filename, struct ast_filestream **fs, unsigned int *oflags, int *errflag)
+{
+ /* Initialize the file if not already done so */
+ char *ext = NULL;
+ if (!ast_strlen_zero(filename)) {
+
+
+ if (!*fs && !*errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
+ *oflags = O_CREAT | O_WRONLY;
+ *oflags |=
+ ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
+
+ if ((ext = strrchr(filename, '.')))
+ *(ext++) = '\0';
+ else
+ ext = "raw";
+
+ if (!
+ (*fs =
+ ast_writefile(filename, ext, NULL, *oflags, 0, 0666))) {
+ ast_log(LOG_ERROR, "Cannot open %s.%s\n", filename, ext);
+ *errflag = 1;
+ }
+ }
+ }
+}
+
static void *mixmonitor_thread(void *obj)
{
struct mixmonitor *mixmonitor = obj;
@@ -309,8 +357,6 @@
struct ast_filestream **fs_write = NULL;
unsigned int oflags;
- char *ext = NULL;
-
int errflag = 0;
struct ast_format format_slin;
@@ -324,17 +370,14 @@
/* The audiohook must enter and exit the loop locked */
ast_audiohook_lock(&mixmonitor->audiohook);
- while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING &&
-!mixmonitor->mixmonitor_ds->fs_quit) {
+ while (mixmonitor->audiohook.status == AST_AUDIOHOOK_STATUS_RUNNING && !mixmonitor->mixmonitor_ds->fs_quit) {
struct ast_frame *fr = NULL;
struct ast_frame *fr_read = NULL;
struct ast_frame *fr_write = NULL;
-
/* here we need to use a modified version of the ast_audiohook_read_frame function
* designed to take our read and write frames as arguments. */
- if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME,
- AST_AUDIOHOOK_DIRECTION_BOTH, &format_slin,
+ if (!(fr = ast_audiohook_read_frame_all(&mixmonitor->audiohook, SAMPLES_PER_FRAME, &format_slin,
&fr_read, &fr_write))) {
ast_audiohook_trigger_wait(&mixmonitor->audiohook);
@@ -348,78 +391,12 @@
* Unlock it, but remember to lock it before looping or exiting */
ast_audiohook_unlock(&mixmonitor->audiohook);
- if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) ||
- (mixmonitor->autochan->chan &&
- ast_bridged_channel(mixmonitor->autochan->chan))) {
+ if (!ast_test_flag(mixmonitor, MUXFLAG_BRIDGED) || (mixmonitor->autochan->chan && ast_bridged_channel(mixmonitor->autochan->chan))) {
ast_mutex_lock(&mixmonitor->mixmonitor_ds->lock);
- /* Initialize the file if not already done so */
- if (mixmonitor->filename[0] != '\0') {
-
- if (!*fs && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
- oflags = O_CREAT | O_WRONLY;
- oflags |=
- ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
-
- if ((ext = strrchr(mixmonitor->filename, '.')))
- *(ext++) = '\0';
- else
- ext = "raw";
-
- if (!
- (*fs =
- ast_writefile(mixmonitor->filename, ext, NULL, oflags, 0, 0666))) {
- ast_log(LOG_ERROR, "Cannot open %s.%s\n", mixmonitor->filename, ext);
- errflag = 1;
- }
- }
- }
-
- /* repeat for the reading file if necessary */
-
- if (ast_test_flag(mixmonitor, MUXFLAG_READ)) {
- if (!*fs_read && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
- oflags = O_CREAT | O_WRONLY;
- oflags |= ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
-
- if ((ext = strrchr(mixmonitor->filename_read, '.')))
- *(ext++) = '\0';
- else
- ext = "raw";
-
- if (!
- (*fs_read =
- ast_writefile(mixmonitor->filename_read, ext, NULL, oflags, 0, 0666))) {
- ast_log(LOG_ERROR, "Cannot open %s.%s\n",
- mixmonitor->filename_read, ext);
- errflag = 1;
- }
- }
- }
-
- /* repeat for write */
-
- if (ast_test_flag(mixmonitor, MUXFLAG_WRITE)) {
- if (!*fs_write && !errflag && !mixmonitor->mixmonitor_ds->fs_quit) {
- oflags = O_CREAT | O_WRONLY;
- oflags |=
- ast_test_flag(mixmonitor, MUXFLAG_APPEND) ? O_APPEND : O_TRUNC;
-
- if ((ext = strrchr(mixmonitor->filename_write, '.')))
- *(ext++) = '\0';
- else
- ext = "raw";
-
- if (!
- (*fs_write =
- ast_writefile(mixmonitor->filename_write, ext, NULL, oflags, 0,
- 0666))) {
- ast_log(LOG_ERROR, "Cannot open %s.%s\n",
- mixmonitor->filename_write, ext);
- errflag = 1;
- }
- }
- }
+ mixmonitor_save_prep(mixmonitor, mixmonitor->filename, fs, &oflags, &errflag);
+ mixmonitor_save_prep(mixmonitor, mixmonitor->filename_read, fs_read, &oflags, &errflag);
+ mixmonitor_save_prep(mixmonitor, mixmonitor->filename_write, fs_write, &oflags, &errflag);
/* Write out the frame(s) */
if ((*fs_read) && (fr_read)) {
@@ -438,17 +415,17 @@
}
}
- if ((fs) && (fr)) {
- struct ast_frame *cur;
+ if ((*fs) && (fr)) {
+ struct ast_frame *cur;
for (cur = fr; cur; cur = AST_LIST_NEXT(cur, frame_list)) {
ast_writestream(*fs, cur);
}
-
}
ast_mutex_unlock(&mixmonitor->mixmonitor_ds->lock);
}
+
/* All done! free it. */
if (fr) {
ast_frame_free(fr, 0);
@@ -523,9 +500,9 @@
}
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,
- const char *filename_read)
+ unsigned int flags, int readvol, int writevol,
+ const char *post_process, const char *filename_write,
+ const char *filename_read)
{
pthread_t thread;
struct mixmonitor *mixmonitor;
@@ -541,7 +518,7 @@
p1 = ast_strdupa(post_process);
for (p2 = p1; *p2; p2++) {
- if (*p2 == '^' && *(p2 + 1) == '{') {
+ if (*p2 == '^' && *(p2+1) == '{') {
*p2 = '$';
}
}
@@ -576,17 +553,15 @@
mixmonitor->name = (char *) mixmonitor + sizeof(*mixmonitor);
strcpy(mixmonitor->name, chan->name);
if (!ast_strlen_zero(postprocess2)) {
- mixmonitor->post_process =
- mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
+ mixmonitor->post_process = mixmonitor->name + strlen(mixmonitor->name) + strlen(filename) + 2;
strcpy(mixmonitor->post_process, postprocess2);
}
mixmonitor->filename = (char *) mixmonitor + sizeof(*mixmonitor) + strlen(chan->name) + 1;
- strcpy(mixmonitor->filename, filename);
-
+
+ mixmonitor->filename = ast_strdup(filename);
mixmonitor->filename_write = ast_strdup(filename_write);
mixmonitor->filename_read = ast_strdup(filename_read);
-
ast_set_flag(&mixmonitor->audiohook, AST_AUDIOHOOK_TRIGGER_SYNC);
@@ -606,21 +581,40 @@
ast_pthread_create_detached_background(&thread, NULL, mixmonitor_thread, mixmonitor);
}
+static char *filename_parse(char *filename)
+{
+ char *tmp, *slash;
+ if (ast_strlen_zero(filename)) {
+ ast_log(LOG_WARNING, "No file name was provided for a file save option.\n");
+ } else if (filename[0] != '/') {
+ char *build;
+ build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(filename) + 3);
+ sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, filename);
+ filename = build;
+ }
+
+ tmp = ast_strdupa(filename);
+ if ((slash = strrchr(tmp, '/')))
+ *slash = '\0';
+ ast_mkdir(tmp, 0777);
+
+ return filename;
+}
+
static int mixmonitor_exec(struct ast_channel *chan, const char *data)
{
int x, readvol = 0, writevol = 0;
char *filename_read = NULL;
char *filename_write = NULL;
-
struct ast_flags flags = { 0 };
- char *parse, *tmp, *slash;
+ char *parse;
AST_DECLARE_APP_ARGS(args,
- AST_APP_ARG(filename);
- AST_APP_ARG(options);
- AST_APP_ARG(post_process);
- );
-
+ AST_APP_ARG(filename);
+ AST_APP_ARG(options);
+ AST_APP_ARG(post_process);
+ );
+
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "MixMonitor requires an argument (filename or ,t(filename) and/or r(filename)\n");
return -1;
@@ -644,7 +638,7 @@
readvol = get_volfactor(x);
}
}
-
+
if (ast_test_flag(&flags, MUXFLAG_WRITEVOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_WRITEVOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the spoken volume ('V') option.\n");
@@ -654,81 +648,41 @@
writevol = get_volfactor(x);
}
}
-
+
if (ast_test_flag(&flags, MUXFLAG_VOLUME)) {
if (ast_strlen_zero(opts[OPT_ARG_VOLUME])) {
ast_log(LOG_WARNING, "No volume level was provided for the combined volume ('W') option.\n");
} else if ((sscanf(opts[OPT_ARG_VOLUME], "%2d", &x) != 1) || (x < -4) || (x > 4)) {
- ast_log(LOG_NOTICE,
- "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
+ ast_log(LOG_NOTICE, "Combined volume must be a number between -4 and 4, not '%s'\n", opts[OPT_ARG_VOLUME]);
} else {
readvol = writevol = get_volfactor(x);
}
}
-
-
if (ast_test_flag(&flags, MUXFLAG_WRITE)) {
- if (ast_strlen_zero(opts[OPT_ARG_WRITENAME])) {
- ast_log(LOG_WARNING,
- "No file name was provided for the transmission ('t') option.\n");
- }
- /* if not provided an absolute path, use the system-configured monitoring directory for the write file */
- else if (opts[OPT_ARG_WRITENAME][0] != '/') {
- char *build;
- build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(opts[OPT_ARG_WRITENAME]) + 3);
- sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, opts[OPT_ARG_WRITENAME]);
- opts[OPT_ARG_WRITENAME] = build;
- }
-
- filename_write = opts[OPT_ARG_WRITENAME];
- tmp = ast_strdupa(opts[OPT_ARG_WRITENAME]);
- if ((slash = strrchr(tmp, '/')))
- *slash = '\0';
- ast_mkdir(tmp, 0777);
- }
-
-
+ filename_write = ast_strdupa(filename_parse(opts[OPT_ARG_WRITENAME]));
+ }
if (ast_test_flag(&flags, MUXFLAG_READ)) {
- if (ast_strlen_zero(opts[OPT_ARG_READNAME])) {
- ast_log(LOG_WARNING, "No file name was provided for the receiving ('r') option.\n");
- }
- /* if not provided an absolute path, use the system-configured monitoring directory for the read file */
- else if (opts[OPT_ARG_READNAME][0] != '/') {
-
- char *build;
- build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(opts[OPT_ARG_READNAME]) + 3);
- sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, opts[OPT_ARG_READNAME]);
- opts[OPT_ARG_READNAME] = build;
- }
-
- filename_read = opts[OPT_ARG_READNAME];
- tmp = ast_strdupa(opts[OPT_ARG_READNAME]);
- if ((slash = strrchr(tmp, '/')))
- *slash = '\0';
- ast_mkdir(tmp, 0777);
- }
- }
-
- /* if not provided an absolute path, use the system-configured monitoring directory */
- if (args.filename[0] != '/') {
- char *build;
-
- build = alloca(strlen(ast_config_AST_MONITOR_DIR) + strlen(args.filename) + 3);
- sprintf(build, "%s/%s", ast_config_AST_MONITOR_DIR, args.filename);
- args.filename = build;
- }
-
- tmp = ast_strdupa(args.filename);
- if ((slash = strrchr(tmp, '/')))
- *slash = '\0';
- ast_mkdir(tmp, 0777);
-
+ filename_read = ast_strdupa(filename_parse(opts[OPT_ARG_READNAME]));
+ }
+ }
+
+ /* If there are no file writing arguments/options for the mix monitor, send a warning message and return -1 */
+
+ if (!ast_test_flag(&flags, MUXFLAG_WRITE) && !ast_test_flag(&flags, MUXFLAG_READ) && ast_strlen_zero(args.filename)) {
+ ast_log(LOG_WARNING, "MixMonitor requires an argument (filename)\n");
+ return -1;
+ }
+
+ /* If filename exists, try to create directories for it */
+ if (!(ast_strlen_zero(args.filename))) {
+ args.filename = ast_strdupa(filename_parse(args.filename));
+ }
+
pbx_builtin_setvar_helper(chan, "MIXMONITOR_FILENAME", args.filename);
- launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol,
- args.post_process, filename_write, filename_read);
-
+ launch_monitor_thread(chan, args.filename, flags.flags, readvol, writevol, args.post_process, filename_write, filename_read);
+
return 0;
}
@@ -769,8 +723,7 @@
return 0;
}
-static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd,
- struct ast_cli_args *a)
+static char *handle_cli_mixmonitor(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
{
struct ast_channel *chan;
@@ -836,8 +789,7 @@
} else if (!strcasecmp(direction, "both")) {
flag = AST_AUDIOHOOK_MUTE_READ | AST_AUDIOHOOK_MUTE_WRITE;
} else {
- astman_send_error(s, m,
- "Invalid direction specified. Must be read, write or both");
+ astman_send_error(s, m, "Invalid direction specified. Must be read, write or both");
return AMI_SUCCESS;
}
@@ -890,7 +842,7 @@
res = ast_unregister_application(stop_app);
res |= ast_unregister_application(app);
res |= ast_manager_unregister("MixMonitorMute");
-
+
return res;
}
@@ -906,4 +858,4 @@
return res;
}
-AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");
+AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Mixed Audio Monitoring Application");
Modified: team/jrose/mix-monitor-branch/include/asterisk/audiohook.h
URL: http://svnview.digium.com/svn/asterisk/team/jrose/mix-monitor-branch/include/asterisk/audiohook.h?view=diff&rev=309258&r1=309257&r2=309258
==============================================================================
--- team/jrose/mix-monitor-branch/include/asterisk/audiohook.h (original)
+++ team/jrose/mix-monitor-branch/include/asterisk/audiohook.h Wed Mar 2 13:59:49 2011
@@ -28,7 +28,6 @@
#endif
/* these two are used in struct ast_audiohook */
-
#include "asterisk/lock.h"
#include "asterisk/linkedlists.h"
#include "asterisk/slinfactory.h"
@@ -152,16 +151,16 @@
*/
struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format);
-/*! \brief Reads a frame in from the audiohook structure, automatically tweaks provided frames
+/*! \brief Reads a frame in from the audiohook structure in mixed audio mode and copies read and write frame data to provided arguments.
* \param audiohook Audiohook structure
* \param samples Number of samples wanted
* \param direction Direction the audio frame came from
* \param format Format of frame remote side wants back
- * \param ast_frame readFrame - if available, we'll copy the read buffer to this.
- * \param ast_frame writeFrame - if available, we'll copy the write buffer to this.
+ * \param ast_frame read_frame - if available, we'll copy the read buffer to this.
+ * \param ast_frame write_frame - if available, we'll copy the write buffer to this.
* \return Returns frame on success, NULL on failure
*/
-struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **readFrame, struct ast_frame **writeFrame);
+struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame);
/*! \brief Attach audiohook to channel
* \param chan Channel
Modified: team/jrose/mix-monitor-branch/main/audiohook.c
URL: http://svnview.digium.com/svn/asterisk/team/jrose/mix-monitor-branch/main/audiohook.c?view=diff&rev=309258&r1=309257&r2=309258
==============================================================================
--- team/jrose/mix-monitor-branch/main/audiohook.c (original)
+++ team/jrose/mix-monitor-branch/main/audiohook.c Wed Mar 2 13:59:49 2011
@@ -238,7 +238,7 @@
return ast_frdup(&frame);
}
-static struct ast_frame *audiohook_read_frame_both_all(struct ast_audiohook *audiohook, size_t samples, struct ast_frame **readFrame, struct ast_frame **writeFrame)
+static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples, struct ast_frame **read_reference, struct ast_frame **write_reference)
{
int i = 0, usable_read, usable_write;
short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
@@ -248,7 +248,6 @@
.datalen = sizeof(buf1),
.samples = samples,
};
-
ast_format_set(&frame.subclass.format, AST_FORMAT_SLINEAR, 0);
/* Make sure both factories have the required samples */
@@ -311,27 +310,22 @@
}
ast_debug(1, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
-
-
/* Basically we figure out which buffer to use... and if mixing can be done here */
-
if (!read_buf && !write_buf)
return NULL;
- if (read_buf) {
- final_buf = buf1;
- frame.data.ptr = final_buf;
- *readFrame = ast_frdup(&frame);
- }
-
-
- if (write_buf) {
- final_buf = buf2;
- frame.data.ptr = final_buf;
- *writeFrame = ast_frdup(&frame);
- }
-
+ if (read_buf) {
+ final_buf = buf1;
+ frame.data.ptr = final_buf;
+ *read_reference = ast_frdup(&frame);
+ }
+
+ if (write_buf) {
+ final_buf = buf2;
+ frame.data.ptr = final_buf;
+ *write_reference = ast_frdup(&frame);
+ }
if (read_buf && write_buf) {
for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
@@ -339,176 +333,20 @@
final_buf = buf1;
}
-
/* Make the final buffer part of the frame, so it gets duplicated fine */
frame.data.ptr = final_buf;
/* Yahoo, a combined copy of the audio! */
return ast_frdup(&frame);
-
-}
-
-static struct ast_frame *audiohook_read_frame_both(struct ast_audiohook *audiohook, size_t samples)
-{
- int i = 0, usable_read, usable_write;
- short buf1[samples], buf2[samples], *read_buf = NULL, *write_buf = NULL, *final_buf = NULL, *data1 = NULL, *data2 = NULL;
- struct ast_frame frame = {
- .frametype = AST_FRAME_VOICE,
- .data.ptr = NULL,
- .datalen = sizeof(buf1),
- .samples = samples,
- };
- ast_format_set(&frame.subclass.format, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0);
-
- /* Make sure both factories have the required samples */
- usable_read = (ast_slinfactory_available(&audiohook->read_factory) >= samples ? 1 : 0);
- usable_write = (ast_slinfactory_available(&audiohook->write_factory) >= samples ? 1 : 0);
-
- if (!usable_read && !usable_write) {
- /* If both factories are unusable bail out */
- ast_debug(1, "Read factory %p and write factory %p both fail to provide %zd samples\n", &audiohook->read_factory, &audiohook->write_factory, samples);
- return NULL;
- }
-
- /* If we want to provide only a read factory make sure we aren't waiting for other audio */
- if (usable_read && !usable_write && (ast_tvdiff_ms(ast_tvnow(), audiohook->write_time) < (samples/8)*2)) {
- ast_debug(3, "Write factory %p was pretty quick last time, waiting for them.\n", &audiohook->write_factory);
- return NULL;
- }
-
- /* If we want to provide only a write factory make sure we aren't waiting for other audio */
- if (usable_write && !usable_read && (ast_tvdiff_ms(ast_tvnow(), audiohook->read_time) < (samples/8)*2)) {
- ast_debug(3, "Read factory %p was pretty quick last time, waiting for them.\n", &audiohook->read_factory);
- return NULL;
- }
-
- /* Start with the read factory... if there are enough samples, read them in */
- if (usable_read) {
- if (ast_slinfactory_read(&audiohook->read_factory, buf1, samples)) {
- read_buf = buf1;
- /* Adjust read volume if need be */
- if (audiohook->options.read_volume) {
- int count = 0;
- short adjust_value = abs(audiohook->options.read_volume);
- for (count = 0; count < samples; count++) {
- if (audiohook->options.read_volume > 0)
- ast_slinear_saturated_multiply(&buf1[count], &adjust_value);
- else if (audiohook->options.read_volume < 0)
- ast_slinear_saturated_divide(&buf1[count], &adjust_value);
- }
- }
- }
- }
- ast_debug(1, "Failed to get %d samples from read factory %p\n", (int)samples, &audiohook->read_factory);
-
- /* Move on to the write factory... if there are enough samples, read them in */
- if (usable_write) {
- if (ast_slinfactory_read(&audiohook->write_factory, buf2, samples)) {
- write_buf = buf2;
- /* Adjust write volume if need be */
- if (audiohook->options.write_volume) {
- int count = 0;
- short adjust_value = abs(audiohook->options.write_volume);
- for (count = 0; count < samples; count++) {
- if (audiohook->options.write_volume > 0)
- ast_slinear_saturated_multiply(&buf2[count], &adjust_value);
- else if (audiohook->options.write_volume < 0)
- ast_slinear_saturated_divide(&buf2[count], &adjust_value);
- }
- }
- }
- }
- ast_debug(1, "Failed to get %d samples from write factory %p\n", (int)samples, &audiohook->write_factory);
-
- /* Basically we figure out which buffer to use... and if mixing can be done here */
- if (!read_buf && !write_buf)
- return NULL;
- else if (read_buf && write_buf) {
- for (i = 0, data1 = read_buf, data2 = write_buf; i < samples; i++, data1++, data2++)
- ast_slinear_saturated_add(data1, data2);
- final_buf = buf1;
- } else if (read_buf)
- final_buf = buf1;
- else if (write_buf)
- final_buf = buf2;
-
- /* Make the final buffer part of the frame, so it gets duplicated fine */
- frame.data.ptr = final_buf;
-
- /* Yahoo, a combined copy of the audio! */
- return ast_frdup(&frame);
-}
-
-/*! \brief Reads a frame in from the audiohook structure
- * \param audiohook Audiohook structure
- * \param samples Number of samples wanted in requested output format
- * \param direction Direction the audio frame came from
- * \param format Format of frame remote side wants back
- * \return Returns frame on success, NULL on failure
- */
-struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
+}
+
+static struct ast_frame *ast_audiohook_read_frame_helper(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **read_reference, struct ast_frame **write_reference)
{
struct ast_frame *read_frame = NULL, *final_frame = NULL;
struct ast_format tmp_fmt;
- int samples_converted;
-
- /* the number of samples requested is based on the format they are requesting. Inorder
- * to process this correctly samples must be converted to our internal sample rate */
- if (audiohook->hook_internal_samp_rate == ast_format_rate(format)) {
- samples_converted = samples;
- } else if (audiohook->hook_internal_samp_rate > ast_format_rate(format)) {
- samples_converted = samples * (audiohook->hook_internal_samp_rate / (float) ast_format_rate(format));
- } else {
- samples_converted = samples * (ast_format_rate(format) / (float) audiohook->hook_internal_samp_rate);
- }
-
- if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ?
- audiohook_read_frame_both(audiohook, samples_converted) :
- audiohook_read_frame_single(audiohook, samples_converted, direction)))) {
- return NULL;
- }
-
- /* If they don't want signed linear back out, we'll have to send it through the translation path */
- if (format->id != ast_format_slin_by_rate(audiohook->hook_internal_samp_rate)) {
- /* Rebuild translation path if different format then previously */
- if (ast_format_cmp(format, &audiohook->format) == AST_FORMAT_CMP_NOT_EQUAL) {
- if (audiohook->trans_pvt) {
- ast_translator_free_path(audiohook->trans_pvt);
- audiohook->trans_pvt = NULL;
- }
-
- /* Setup new translation path for this format... if we fail we can't very well return signed linear so free the frame and return nothing */
- if (!(audiohook->trans_pvt = ast_translator_build_path(format, ast_format_set(&tmp_fmt, ast_format_slin_by_rate(audiohook->hook_internal_samp_rate), 0)))) {
- ast_frfree(read_frame);
- return NULL;
- }
- ast_format_copy(&audiohook->format, format);
- }
- /* Convert to requested format, and allow the read in frame to be freed */
- final_frame = ast_translate(audiohook->trans_pvt, read_frame, 1);
- } else {
- final_frame = read_frame;
- }
-
- return final_frame;
-}
-
-
-/*! \brief Reads a frame in from the audiohook structure
- * \param audiohook Audiohook structure
- * \param samples Number of samples wanted
- * \param direction Direction the audio frame came from
- * \param format Format of frame remote side wants back
- * \return Returns frame on success, NULL on failure
- */
-struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format, struct ast_frame **readFrame, struct ast_frame **writeFrame)
-{
- struct ast_frame *read_frame = NULL, *final_frame = NULL;
- struct ast_format tmp_fmt;
-
- if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both_all(audiohook, samples, readFrame, writeFrame) : audiohook_read_frame_single(audiohook, samples, direction))))
- return NULL;
-
+
+ if (!(read_frame = (direction == AST_AUDIOHOOK_DIRECTION_BOTH ? audiohook_read_frame_both(audiohook, samples, read_reference, write_reference) : audiohook_read_frame_single(audiohook, samples, direction)))) { return NULL; }
+
/* If they don't want signed linear back out, we'll have to send it through the translation path */
if (format->id != AST_FORMAT_SLINEAR) {
/* Rebuild translation path if different format then previously */
@@ -532,9 +370,30 @@
return final_frame;
}
-
-
-
+/*! \brief Reads a frame in from the audiohook structure
+ * \param audiohook Audiohook structure
+ * \param samples Number of samples wanted in requested output format
+ * \param direction Direction the audio frame came from
+ * \param format Format of frame remote side wants back
+ * \return Returns frame on success, NULL on failure
+ */
+struct ast_frame *ast_audiohook_read_frame(struct ast_audiohook *audiohook, size_t samples, enum ast_audiohook_direction direction, struct ast_format *format)
+{
+ return ast_audiohook_read_frame_helper(audiohook, samples, direction, format, NULL, NULL);
+}
+
+/*! \brief Reads a frame in from the audiohook structure
+ * \param audiohook Audiohook structure
+ * \param samples Number of samples wanted
+ * \param direction Direction the audio frame came from
+ * \param format Format of frame remote side wants back
+ * \param read_frame
+ * \return Returns frame on success, NULL on failure
+ */
+struct ast_frame *ast_audiohook_read_frame_all(struct ast_audiohook *audiohook, size_t samples, struct ast_format *format, struct ast_frame **read_frame, struct ast_frame **write_frame)
+{
+ return ast_audiohook_read_frame_helper(audiohook, samples, AST_AUDIOHOOK_DIRECTION_BOTH, format, read_frame, write_frame);
+}
static void audiohook_list_set_samplerate_compatibility(struct ast_audiohook_list *audiohook_list)
{
@@ -547,7 +406,6 @@
}
}
}
-
/*! \brief Attach audiohook to channel
* \param chan Channel
@@ -1051,9 +909,9 @@
wait = ast_tvadd(ast_tvnow(), ast_samp2tv(50000, 1000));
ts.tv_sec = wait.tv_sec;
ts.tv_nsec = wait.tv_usec * 1000;
-
+
ast_cond_timedwait(&audiohook->trigger, &audiohook->lock, &ts);
-
+
return;
}
More information about the asterisk-commits
mailing list