mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-19 19:52:48 +00:00
OneTouchRecord: Make so Monitor/MixMonitor can be toggled/started/stopped.
The OneTouchRecord feature has historically been a toggle. This patch adds the ability to make the OneTouchRecord hook optionally start/stop recording only. If OneTouchRecord is already doing what is requested then only the invoker hears the courtesy tone and/or start/stop recording message. The new feature is written so we could easily add explicit start/stop recording DTMF hooks for Monitor and MixMonitor. The majority of the changes in bridge_builtin_features.c is a refactoring of the OneTouchRecord code (Monitor and MixMonitor versions) so it is easy to direct the toggle/start/stop functionality. Review: https://reviewboard.asterisk.org/r/2655/ git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@393612 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -466,15 +466,57 @@ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridg
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg)
|
enum set_touch_variables_res {
|
||||||
|
SET_TOUCH_SUCCESS,
|
||||||
|
SET_TOUCH_UNSET,
|
||||||
|
SET_TOUCH_ALLOC_FAILURE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void set_touch_variable(enum set_touch_variables_res *res, struct ast_channel *chan, const char *var_name, char **touch)
|
||||||
{
|
{
|
||||||
const char *stop_message;
|
const char *c_touch;
|
||||||
|
|
||||||
ast_channel_lock(bridge_channel->chan);
|
if (*res == SET_TOUCH_ALLOC_FAILURE) {
|
||||||
stop_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MONITOR_MESSAGE_STOP");
|
return;
|
||||||
stop_message = ast_strdupa(S_OR(stop_message, ""));
|
}
|
||||||
ast_channel_unlock(bridge_channel->chan);
|
c_touch = pbx_builtin_getvar_helper(chan, var_name);
|
||||||
|
if (!ast_strlen_zero(c_touch)) {
|
||||||
|
*touch = ast_strdup(c_touch);
|
||||||
|
if (!*touch) {
|
||||||
|
*res = SET_TOUCH_ALLOC_FAILURE;
|
||||||
|
} else {
|
||||||
|
*res = SET_TOUCH_SUCCESS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum set_touch_variables_res 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 *var_format;
|
||||||
|
const char *var_monitor;
|
||||||
|
const char *var_prefix;
|
||||||
|
|
||||||
|
SCOPED_CHANNELLOCK(lock, chan);
|
||||||
|
|
||||||
|
if (is_mixmonitor) {
|
||||||
|
var_format = "TOUCH_MIXMONITOR_FORMAT";
|
||||||
|
var_monitor = "TOUCH_MIXMONITOR";
|
||||||
|
var_prefix = "TOUCH_MIXMONITOR_PREFIX";
|
||||||
|
} else {
|
||||||
|
var_format = "TOUCH_MONITOR_FORMAT";
|
||||||
|
var_monitor = "TOUCH_MONITOR";
|
||||||
|
var_prefix = "TOUCH_MONITOR_PREFIX";
|
||||||
|
}
|
||||||
|
set_touch_variable(&res, chan, var_format, touch_format);
|
||||||
|
set_touch_variable(&res, chan, var_monitor, touch_monitor);
|
||||||
|
set_touch_variable(&res, chan, var_prefix, touch_monitor_prefix);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
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_verb(3, "AutoMonitor used to stop recording call.\n");
|
ast_verb(3, "AutoMonitor used to stop recording call.\n");
|
||||||
|
|
||||||
ast_channel_lock(peer_chan);
|
ast_channel_lock(peer_chan);
|
||||||
@@ -506,54 +548,10 @@ static void stop_automonitor(struct ast_bridge_channel *bridge_channel, struct a
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum set_touch_variables_res {
|
static void start_automonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
|
||||||
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;
|
char *touch_filename;
|
||||||
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;
|
size_t len;
|
||||||
const char *automon_message;
|
|
||||||
int x;
|
int x;
|
||||||
enum set_touch_variables_res set_touch_res;
|
enum set_touch_variables_res set_touch_res;
|
||||||
|
|
||||||
@@ -561,49 +559,47 @@ static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_chan
|
|||||||
RAII_VAR(char *, touch_monitor, NULL, ast_free);
|
RAII_VAR(char *, touch_monitor, NULL, ast_free);
|
||||||
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
||||||
|
|
||||||
RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
|
set_touch_res = set_touch_variables(bridge_channel->chan, 0, &touch_format,
|
||||||
RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
|
&touch_monitor, &touch_monitor_prefix);
|
||||||
|
switch (set_touch_res) {
|
||||||
features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
|
case SET_TOUCH_SUCCESS:
|
||||||
peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
|
break;
|
||||||
|
case SET_TOUCH_UNSET:
|
||||||
if (!peer_chan) {
|
set_touch_res = set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor,
|
||||||
ast_verb(3, "Cannot start AutoMonitor for %s - can not determine peer in bridge.\n", ast_channel_name(bridge_channel->chan));
|
&touch_monitor_prefix);
|
||||||
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) {
|
if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
|
||||||
return 0;
|
return;
|
||||||
}
|
|
||||||
if (set_touch_variables(peer_chan, 0, &touch_format, &touch_monitor, &touch_monitor_prefix) == SET_TOUCH_ALLOC_FAILURE) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case SET_TOUCH_ALLOC_FAILURE:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ast_strlen_zero(touch_monitor)) {
|
if (!ast_strlen_zero(touch_monitor)) {
|
||||||
len = strlen(touch_monitor) + 50;
|
len = strlen(touch_monitor) + 50;
|
||||||
touch_filename = ast_alloca(len);
|
touch_filename = ast_alloca(len);
|
||||||
snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
|
snprintf(touch_filename, len, "%s-%ld-%s",
|
||||||
|
S_OR(touch_monitor_prefix, "auto"),
|
||||||
|
(long) time(NULL),
|
||||||
|
touch_monitor);
|
||||||
} else {
|
} else {
|
||||||
|
char *caller_chan_id;
|
||||||
|
char *peer_chan_id;
|
||||||
|
|
||||||
caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
|
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)));
|
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,
|
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)));
|
ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
|
||||||
len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
|
len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
|
||||||
touch_filename = ast_alloca(len);
|
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);
|
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++) {
|
for (x = 0; x < strlen(touch_filename); x++) {
|
||||||
if (touch_filename[x] == '/') {
|
if (touch_filename[x] == '/') {
|
||||||
touch_filename[x] = '-';
|
touch_filename[x] = '-';
|
||||||
}
|
}
|
||||||
@@ -612,40 +608,102 @@ static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_chan
|
|||||||
ast_verb(3, "AutoMonitor used to record call. Filename: %s\n", touch_filename);
|
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)) {
|
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));
|
ast_verb(3, "automon feature was tried by '%s' but monitor failed to start.\n",
|
||||||
return 0;
|
ast_channel_name(bridge_channel->chan));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_channel_lock(bridge_channel->chan);
|
if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
|
||||||
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_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||||
ast_bridge_channel_write_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)) {
|
if (!ast_strlen_zero(start_message)) {
|
||||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, automon_message, NULL);
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
|
||||||
ast_bridge_channel_write_playfile(bridge_channel, NULL, automon_message, NULL);
|
ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pbx_builtin_setvar_helper(peer_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
|
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)
|
static int feature_automonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
|
||||||
{
|
{
|
||||||
|
const char *start_message;
|
||||||
const char *stop_message;
|
const char *stop_message;
|
||||||
|
struct ast_bridge_features_automonitor *options = hook_pvt;
|
||||||
|
enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
|
||||||
|
int is_monitoring;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
ast_channel_lock(bridge_channel->chan);
|
ast_channel_lock(bridge_channel->chan);
|
||||||
stop_message = pbx_builtin_getvar_helper(bridge_channel->chan, "TOUCH_MIXMONITOR_MESSAGE_STOP");
|
start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
|
||||||
|
"TOUCH_MONITOR_MESSAGE_START");
|
||||||
|
start_message = ast_strdupa(S_OR(start_message, ""));
|
||||||
|
stop_message = pbx_builtin_getvar_helper(bridge_channel->chan,
|
||||||
|
"TOUCH_MONITOR_MESSAGE_STOP");
|
||||||
stop_message = ast_strdupa(S_OR(stop_message, ""));
|
stop_message = ast_strdupa(S_OR(stop_message, ""));
|
||||||
ast_channel_unlock(bridge_channel->chan);
|
ast_channel_unlock(bridge_channel->chan);
|
||||||
|
|
||||||
|
is_monitoring = ast_channel_monitor(peer_chan) != NULL;
|
||||||
|
switch (start_stop) {
|
||||||
|
case AUTO_MONITOR_TOGGLE:
|
||||||
|
if (is_monitoring) {
|
||||||
|
stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
|
||||||
|
} else {
|
||||||
|
start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case AUTO_MONITOR_START:
|
||||||
|
if (!is_monitoring) {
|
||||||
|
start_automonitor(bridge_channel, peer_chan, features_cfg, start_message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ast_verb(3, "AutoMonitor already recording call.\n");
|
||||||
|
break;
|
||||||
|
case AUTO_MONITOR_STOP:
|
||||||
|
if (is_monitoring) {
|
||||||
|
stop_automonitor(bridge_channel, peer_chan, features_cfg, stop_message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ast_verb(3, "AutoMonitor already not recording call.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fake start/stop to invoker so will think it did something but
|
||||||
|
* was already in that mode.
|
||||||
|
*/
|
||||||
|
if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
|
||||||
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||||
|
}
|
||||||
|
if (is_monitoring) {
|
||||||
|
if (!ast_strlen_zero(start_message)) {
|
||||||
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!ast_strlen_zero(stop_message)) {
|
||||||
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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_verb(3, "AutoMixMonitor used to stop recording call.\n");
|
ast_verb(3, "AutoMixMonitor used to stop recording call.\n");
|
||||||
|
|
||||||
if (ast_stop_mixmonitor(peer_chan, NULL)) {
|
if (ast_stop_mixmonitor(peer_chan, NULL)) {
|
||||||
@@ -656,7 +714,7 @@ static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struc
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (features_cfg && !(ast_strlen_zero(features_cfg->courtesytone))) {
|
if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
|
||||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||||
ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
ast_bridge_channel_write_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||||
}
|
}
|
||||||
@@ -665,67 +723,62 @@ static void stop_automixmonitor(struct ast_bridge_channel *bridge_channel, struc
|
|||||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
|
||||||
ast_bridge_channel_write_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)
|
static void start_automixmonitor(struct ast_bridge_channel *bridge_channel, struct ast_channel *peer_chan, struct ast_features_general_config *features_cfg, const char *start_message)
|
||||||
{
|
{
|
||||||
char *caller_chan_id = NULL, *peer_chan_id = NULL, *touch_filename = NULL;
|
char *touch_filename;
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *automon_message;
|
int x;
|
||||||
static char *mixmonitor_spy_type = "MixMonitor";
|
|
||||||
int count, x;
|
|
||||||
enum set_touch_variables_res set_touch_res;
|
enum set_touch_variables_res set_touch_res;
|
||||||
|
|
||||||
RAII_VAR(char *, touch_format, NULL, ast_free);
|
RAII_VAR(char *, touch_format, NULL, ast_free);
|
||||||
RAII_VAR(char *, touch_monitor, NULL, ast_free);
|
RAII_VAR(char *, touch_monitor, NULL, ast_free);
|
||||||
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
RAII_VAR(char *, touch_monitor_prefix, NULL, ast_free);
|
||||||
|
|
||||||
RAII_VAR(struct ast_channel *, peer_chan, NULL, ast_channel_cleanup);
|
set_touch_res = set_touch_variables(bridge_channel->chan, 1, &touch_format,
|
||||||
RAII_VAR(struct ast_features_general_config *, features_cfg, NULL, ao2_cleanup);
|
&touch_monitor, &touch_monitor_prefix);
|
||||||
|
switch (set_touch_res) {
|
||||||
features_cfg = ast_get_chan_features_general_config(bridge_channel->chan);
|
case SET_TOUCH_SUCCESS:
|
||||||
|
break;
|
||||||
peer_chan = ast_bridge_peer(bridge, bridge_channel->chan);
|
case SET_TOUCH_UNSET:
|
||||||
|
set_touch_res = set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor,
|
||||||
if (!peer_chan) {
|
&touch_monitor_prefix);
|
||||||
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) {
|
if (set_touch_res == SET_TOUCH_ALLOC_FAILURE) {
|
||||||
return 0;
|
return;
|
||||||
}
|
|
||||||
if (set_touch_variables(peer_chan, 1, &touch_format, &touch_monitor, &touch_monitor_prefix) == SET_TOUCH_ALLOC_FAILURE) {
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case SET_TOUCH_ALLOC_FAILURE:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ast_strlen_zero(touch_monitor)) {
|
if (!ast_strlen_zero(touch_monitor)) {
|
||||||
len = strlen(touch_monitor) + 50;
|
len = strlen(touch_monitor) + 50;
|
||||||
touch_filename = ast_alloca(len);
|
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"));
|
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 {
|
} else {
|
||||||
|
char *caller_chan_id;
|
||||||
|
char *peer_chan_id;
|
||||||
|
|
||||||
caller_chan_id = ast_strdupa(S_COR(ast_channel_caller(bridge_channel->chan)->id.number.valid,
|
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)));
|
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,
|
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)));
|
ast_channel_caller(peer_chan)->id.number.str, ast_channel_name(peer_chan)));
|
||||||
len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
|
len = strlen(caller_chan_id) + strlen(peer_chan_id) + 50;
|
||||||
touch_filename = ast_alloca(len);
|
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"));
|
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++) {
|
for (x = 0; x < strlen(touch_filename); x++) {
|
||||||
if (touch_filename[x] == '/') {
|
if (touch_filename[x] == '/') {
|
||||||
touch_filename[x] = '-';
|
touch_filename[x] = '-';
|
||||||
}
|
}
|
||||||
@@ -734,33 +787,103 @@ static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_c
|
|||||||
ast_verb(3, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
|
ast_verb(3, "AutoMixMonitor used to record call. Filename: %s\n", touch_filename);
|
||||||
|
|
||||||
if (ast_start_mixmonitor(peer_chan, touch_filename, "b")) {
|
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));
|
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)) {
|
if (features_cfg && !ast_strlen_zero(features_cfg->recordingfailsound)) {
|
||||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->recordingfailsound, NULL);
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ast_channel_lock(bridge_channel->chan);
|
if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
|
||||||
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_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||||
ast_bridge_channel_write_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)) {
|
if (!ast_strlen_zero(start_message)) {
|
||||||
ast_bridge_channel_queue_playfile(bridge_channel, NULL, automon_message, NULL);
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
|
||||||
ast_bridge_channel_write_playfile(bridge_channel, NULL, automon_message, NULL);
|
ast_bridge_channel_write_playfile(bridge_channel, NULL, start_message, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
|
pbx_builtin_setvar_helper(peer_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int feature_automixmonitor(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt)
|
||||||
|
{
|
||||||
|
static const char *mixmonitor_spy_type = "MixMonitor";
|
||||||
|
const char *stop_message;
|
||||||
|
const char *start_message;
|
||||||
|
struct ast_bridge_features_automixmonitor *options = hook_pvt;
|
||||||
|
enum ast_bridge_features_monitor start_stop = options ? options->start_stop : AUTO_MONITOR_TOGGLE;
|
||||||
|
int is_monitoring;
|
||||||
|
|
||||||
|
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 do AutoMixMonitor for %s - cannot 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
ast_channel_lock(bridge_channel->chan);
|
||||||
|
start_message = pbx_builtin_getvar_helper(bridge_channel->chan,
|
||||||
|
"TOUCH_MIXMONITOR_MESSAGE_START");
|
||||||
|
start_message = ast_strdupa(S_OR(start_message, ""));
|
||||||
|
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);
|
||||||
|
|
||||||
|
is_monitoring =
|
||||||
|
0 < ast_channel_audiohook_count_by_source(peer_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
|
||||||
|
switch (start_stop) {
|
||||||
|
case AUTO_MONITOR_TOGGLE:
|
||||||
|
if (is_monitoring) {
|
||||||
|
stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
|
||||||
|
} else {
|
||||||
|
start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case AUTO_MONITOR_START:
|
||||||
|
if (!is_monitoring) {
|
||||||
|
start_automixmonitor(bridge_channel, peer_chan, features_cfg, start_message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ast_verb(3, "AutoMixMonitor already recording call.\n");
|
||||||
|
break;
|
||||||
|
case AUTO_MONITOR_STOP:
|
||||||
|
if (is_monitoring) {
|
||||||
|
stop_automixmonitor(bridge_channel, peer_chan, features_cfg, stop_message);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ast_verb(3, "AutoMixMonitor already not recording call.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fake start/stop to invoker so will think it did something but
|
||||||
|
* was already in that mode.
|
||||||
|
*/
|
||||||
|
if (features_cfg && !ast_strlen_zero(features_cfg->courtesytone)) {
|
||||||
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, features_cfg->courtesytone, NULL);
|
||||||
|
}
|
||||||
|
if (is_monitoring) {
|
||||||
|
if (!ast_strlen_zero(start_message)) {
|
||||||
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, start_message, NULL);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!ast_strlen_zero(stop_message)) {
|
||||||
|
ast_bridge_channel_queue_playfile(bridge_channel, NULL, stop_message, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -267,6 +267,25 @@ struct ast_bridge_features_attended_transfer {
|
|||||||
char complete[MAXIMUM_DTMF_FEATURE_STRING];
|
char complete[MAXIMUM_DTMF_FEATURE_STRING];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ast_bridge_features_monitor {
|
||||||
|
/*! Toggle start/stop of Monitor/MixMonitor. */
|
||||||
|
AUTO_MONITOR_TOGGLE,
|
||||||
|
/*! Start Monitor/MixMonitor if not already started. */
|
||||||
|
AUTO_MONITOR_START,
|
||||||
|
/*! Stop Monitor/MixMonitor if not already stopped. */
|
||||||
|
AUTO_MONITOR_STOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ast_bridge_features_automonitor {
|
||||||
|
/*! Start/Stop behavior. */
|
||||||
|
enum ast_bridge_features_monitor start_stop;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ast_bridge_features_automixmonitor {
|
||||||
|
/*! Start/Stop behavior. */
|
||||||
|
enum ast_bridge_features_monitor start_stop;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Structure that contains configuration information for the limits feature
|
* \brief Structure that contains configuration information for the limits feature
|
||||||
*/
|
*/
|
||||||
@@ -329,6 +348,26 @@ int ast_bridge_features_register(enum ast_bridge_builtin_feature feature, ast_br
|
|||||||
*/
|
*/
|
||||||
int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature);
|
int ast_bridge_features_unregister(enum ast_bridge_builtin_feature feature);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Invoke a built in feature hook now.
|
||||||
|
*
|
||||||
|
* \param feature The feature to invoke
|
||||||
|
*
|
||||||
|
* \note This API call is only meant to be used by bridge
|
||||||
|
* subclasses and hook callbacks to request a builtin feature
|
||||||
|
* hook to be executed.
|
||||||
|
*
|
||||||
|
* \retval 0 on success
|
||||||
|
* \retval -1 on failure
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
*
|
||||||
|
* \code
|
||||||
|
* ast_bridge_features_do(AST_BRIDGE_BUILTIN_ATTENDED_TRANSFER, bridge, bridge_channel, hook_pvt);
|
||||||
|
* \endcode
|
||||||
|
*/
|
||||||
|
int ast_bridge_features_do(enum ast_bridge_builtin_feature feature, struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Attach interval hooks to a bridge features structure
|
* \brief Attach interval hooks to a bridge features structure
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user