summaryrefslogtreecommitdiff
path: root/bridges
diff options
context:
space:
mode:
authorJonathan Rose <jrose@digium.com>2013-07-01 16:01:24 +0000
committerJonathan Rose <jrose@digium.com>2013-07-01 16:01:24 +0000
commitf306dbd8412778ef31df791b658dc38e15629ae3 (patch)
treef8203232ba890acc8cfdd5bd0ce8004c9801433b /bridges
parent909ee4bfb9180a87e02504acb47f27b47cb5adea (diff)
bridge_features: Support One touch Monitor/MixMonitor
In addition to porting those features, they now enjoy greater feature parity with one another. Specifically, AutoMixMon now has a start and stop message that can be specified with TOUCH_MIXMONITOR_MESSAGE_START and TOUCH_MIXMONITOR_MESSAGE_STOP. (closes issue ASTERISK-21553) Reported by: Matt Jordan Review: https://reviewboard.asterisk.org/r/2620/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393309 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'bridges')
-rw-r--r--bridges/bridge_builtin_features.c303
1 files changed, 303 insertions, 0 deletions
diff --git a/bridges/bridge_builtin_features.c b/bridges/bridge_builtin_features.c
index 2d8a68a1a..91f709bc4 100644
--- a/bridges/bridge_builtin_features.c
+++ b/bridges/bridge_builtin_features.c
@@ -50,6 +50,9 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/pbx.h"
#include "asterisk/parking.h"
#include "asterisk/features_config.h"
+#include "asterisk/monitor.h"
+#include "asterisk/mixmonitor.h"
+#include "asterisk/audiohook.h"
/*!
* \brief Helper function that presents dialtone and grabs extension
@@ -463,6 +466,304 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg
return 0;
}
+static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg)
+{
+ const char *stop_message;
+
+ ast_channel_lock(bridge_channel->chan);
+ stop_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MONITOR_MESSAGE_STOP");
+ stop_message = ast_strdupa(S_OR(stop_message, ""));
+ ast_channel_unlock(bridge_channel->chan);
+
+ ast_verb(3, "AutoMonitor used to stop recording call.\n");
+
+ ast_channel_lock(peer_chan);
+ if (ast_channel_monitor(peer_chan)) {
+ if (ast_channel_monitor(peer_chan)->stop(peer_chan, 1)) {
+ ast_verb(3, "Cannot stop AutoMonitor for %s\n", ast_channel_name(bridge_channel->chan));
+ if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
+ }
+ ast_channel_unlock(peer_chan);
+ return;
+ }
+ } else {
+ /* Something else removed the Monitor before we got to it. */
+ ast_channel_unlock(peer_chan);
+ return;
+ }
+
+ ast_channel_unlock(peer_chan);
+
+ if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ }
+
+ if (!ast_strlen_zero(stop_message)) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
+ }
+}
+
+enum set_touch_variables_res {
+ SET_TOUCH_SUCCESS = 0,
+ SET_TOUCH_UNSET,
+ SET_TOUCH_ALLOC_FAILURE,
+};
+
+static int set_touch_variables(struct ast_channel *chan, int is_mixmonitor, char **touch_format, char **touch_monitor, char **touch_monitor_prefix)
+{
+ enum set_touch_variables_res res = SET_TOUCH_UNSET;
+ const char *c_touch_format, *c_touch_monitor, *c_touch_monitor_prefix;
+
+ SCOPED_CHANNELLOCK(lock, chan);
+
+ c_touch_format = pbx_builtin_getvar_helper(chan, is_mixmonitor ? "TOUCH_MIXMONITOR_FORMAT" : "TOUCH_MONITOR_FORMAT");
+
+ if (!ast_strlen_zero(c_touch_format)) {
+ if (!(*touch_format = ast_strdup(c_touch_format))) {
+ return SET_TOUCH_ALLOC_FAILURE;
+ }
+ res = SET_TOUCH_SUCCESS;
+ }
+
+ c_touch_monitor = pbx_builtin_getvar_helper(chan, is_mixmonitor ? "TOUCH_MIXMONITOR" : "TOUCH_MONITOR");
+
+ if (!ast_strlen_zero(c_touch_monitor)) {
+ if (!(*touch_monitor = ast_strdup(c_touch_monitor))) {
+ return SET_TOUCH_ALLOC_FAILURE;
+ }
+ res = SET_TOUCH_SUCCESS;
+ }
+
+ c_touch_monitor_prefix = pbx_builtin_getvar_helper(chan, is_mixmonitor ? "TOUCH_MIXMONITOR_PREFIX" : "TOUCH_MONITOR_PREFIX");
+
+ if (!ast_strlen_zero(c_touch_monitor_prefix)) {
+ if (!(*touch_monitor_prefix = ast_strdup(c_touch_monitor_prefix))) {
+ return SET_TOUCH_ALLOC_FAILURE;
+ }
+ res = SET_TOUCH_SUCCESS;
+ }
+
+ return res;
+}
+
+static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ char *caller_chan_id = NULL, *peer_chan_id = NULL, *touch_filename = NULL;
+ size_t len;
+ const char *automon_message;
+ int x;
+ enum set_touch_variables_res set_touch_res;
+
+ RAII_VAR(char *, touch_format, NULL, ast_free);
+ RAII_VAR(char *, touch_monitor, NULL, ast_free);
+ RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
+
+ RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
+ RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
+
+ features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
+ peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
+
+ if (!peer_chan) {
+ ast_verb(3, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n", ast_channel_name(bridge_channel->chan));
+ if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
+ }
+ return 0;
+ }
+
+ if (ast_channel_monitor(peer_chan)) {
+ stop_automonitor(bridge_channel, peer_chan, features_cfg);
+ return 0;
+ }
+
+ if ((set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format, &touch_monitor, &touch_monitor_prefix))) {
+ if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
+ return 0;
+ }
+ if (set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor, &touch_monitor_prefix) == SET_TOUCH_ALLOC_FAILURE) {
+ return 0;
+ }
+ }
+
+ if (!ast_strlen_zero(touch_monitor)) {
+ len = strlen(touch_monitor) + 50;
+ touch_filename = ast_alloca(len);
+ snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
+ } else {
+ caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
+ ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
+ peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
+ ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
+ len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
+ touch_filename = ast_alloca(len);
+ snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, peer_chan_id);
+ }
+
+ for ( x = 0; x < strlen(touch_filename); x++) {
+ if (touch_filename[x] == '/') {
+ touch_filename[x] = '-';
+ }
+ }
+
+ ast_verb(3, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
+
+ if (ast_monitor_start(peer_chan, touch_format, touch_filename, 1, X_REC_IN | X_REC_OUT)) {
+ ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n", ast_channel_name(bridge_channel->chan));
+ return 0;
+ }
+
+ ast_channel_lock(bridge_channel->chan);
+ if ((automon_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MONITOR_MESSAGE_START"))) {
+ automon_message = ast_strdupa(automon_message);
+ }
+ ast_channel_unlock(bridge_channel->chan);
+
+ if ((features_cfg = ast_get_chan_features_general_config(bridge_channel->chan)) && !(ast_strlen_zero(features_cfg->courtesytone))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ }
+
+ if (!ast_strlen_zero(automon_message)) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, automon_message, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, automon_message, NULL);
+ }
+
+ pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
+
+ return 0;
+}
+
+static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg)
+{
+ const char *stop_message;
+
+ ast_channel_lock(bridge_channel->chan);
+ stop_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MIXMONITOR_MESSAGE_STOP");
+ stop_message = ast_strdupa(S_OR(stop_message, ""));
+ ast_channel_unlock(bridge_channel->chan);
+
+ ast_verb(3, "AutoMixMonitor used to stop recording call.\n");
+
+ if (ast_stop_mixmonitor(peer_chan, NULL)) {
+ ast_verb(3, "Failed to stop Mixmonitor for %s.\n", ast_channel_name(bridge_channel->chan));
+ if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
+ }
+ return;
+ }
+
+ if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ }
+
+ if (!ast_strlen_zero(stop_message)) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, stop_message, NULL);
+ }
+
+}
+
+static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
+{
+ char *caller_chan_id = NULL, *peer_chan_id = NULL, *touch_filename = NULL;
+ size_t len;
+ const char *automon_message;
+ static char *mixmonitor_spy_type = "MixMonitor";
+ int count, x;
+ enum set_touch_variables_res set_touch_res;
+
+ RAII_VAR(char *, touch_format, NULL, ast_free);
+ RAII_VAR(char *, touch_monitor, NULL, ast_free);
+ RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
+
+ RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
+ RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
+
+ features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
+
+ peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
+
+ if (!peer_chan) {
+ ast_verb(3, "Cannot start AutoMixMonitor for %s - can not determine peer in bridge.\n", ast_channel_name(bridge_channel->chan));
+ if (features_cfg && !(ast_strlen_zero(features_cfg->recordingfailsound))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
+ }
+ return 0;
+ }
+
+ count = ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
+ if (count > 0) {
+ stop_automixmonitor(bridge_channel, peer_chan, features_cfg);
+ return 0;
+ }
+
+ if ((set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format, &touch_monitor, &touch_monitor_prefix))) {
+ if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
+ return 0;
+ }
+ if (set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor, &touch_monitor_prefix) == SET_TOUCH_ALLOC_FAILURE) {
+ return 0;
+ }
+ }
+
+ if (!ast_strlen_zero(touch_monitor)) {
+ len = strlen(touch_monitor) + 50;
+ touch_filename = ast_alloca(len);
+ snprintf(touch_filename, len, "%s-%ld-%s.%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor, S_OR(touch_format, "wav"));
+ } else {
+ caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
+ ast_channel_caller(bridge_channel->chan)->id.number.str, ast_channel_name(bridge_channel->chan)));
+ peer_chan_id = ast_strdupa(S_COR(ast_channel_caller(peer_chan)->id.number.valid,
+ ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
+ len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
+ touch_filename = ast_alloca(len);
+ snprintf(touch_filename, len, "%s-%ld-%s-%s.%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, peer_chan_id, S_OR(touch_format, "wav"));
+ }
+
+ for ( x = 0; x < strlen(touch_filename); x++) {
+ if (touch_filename[x] == '/') {
+ touch_filename[x] = '-';
+ }
+ }
+
+ ast_verb(3, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
+
+ if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
+ ast_verb(3, "automixmon feature was tried by '%s' but mixmonitor failed to start.\n", ast_channel_name(bridge_channel->chan));
+
+ if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
+ }
+
+ return 0;
+ }
+
+ ast_channel_lock(bridge_channel->chan);
+ if ((automon_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MIXMONITOR_MESSAGE_START"))) {
+ automon_message = ast_strdupa(automon_message);
+ }
+ ast_channel_unlock(bridge_channel->chan);
+
+ if ((features_cfg = ast_get_chan_features_general_config(bridge_channel->chan)) && !(ast_strlen_zero(features_cfg->courtesytone))) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
+ }
+
+ if (!ast_strlen_zero(automon_message)) {
+ ast_bridge_channel_queue_playfile(bridge_channel, NULL, automon_message, NULL);
+ ast_bridge_channel_write_playfile(bridge_channel, NULL, automon_message, NULL);
+ }
+
+ pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
+
+ return 0;
+}
+
/*! \brief Internal built in feature for hangup */
static int feature_hangup(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
{
@@ -485,6 +786,8 @@ static int load_module(void)
ast_bridge_features_register(AST_BRIDGE_BUILTIN_BLINDTRANSFER, feature_blind_transfer, NULL);
ast_bridge_features_register(AST_BRIDGE_BUILTIN_ATTENDEDTRANSFER, feature_attended_transfer, NULL);
ast_bridge_features_register(AST_BRIDGE_BUILTIN_HANGUP, feature_hangup, NULL);
+ ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMON, feature_automonitor, NULL);
+ ast_bridge_features_register(AST_BRIDGE_BUILTIN_AUTOMIXMON, feature_automixmonitor, NULL);
/* Bump up our reference count so we can't be unloaded */
ast_module_ref(ast_module_info->self);