Newer
Older
Richard Mudgett
committed
struct ast_channel *current_dest_chan;
char *tmp_data = NULL;
struct ast_flags opts = { 0, };
struct ast_bridge_config bconfig = { { 0, }, };
char *opt_args[OPT_ARG_ARRAY_SIZE];
struct timeval calldurationlimit = { 0, };
Richard Mudgett
committed
const char *context;
const char *extension;
int priority;
Richard Mudgett
committed
int bridge_add_failed;
int res = -1;
Mark Michelson
committed
struct ast_bridge_features chan_features;
struct ast_bridge_features *peer_features;
struct ast_bridge *bridge;
Richard Mudgett
committed
struct ast_features_xfer_config *xfer_cfg;
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(dest_chan);
AST_APP_ARG(options);
);
if (ast_strlen_zero(data)) {
ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
return -1;
}
tmp_data = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, tmp_data);
if (!ast_strlen_zero(args.options))
ast_app_parse_options(bridge_exec_options, &opts, opt_args, args.options);
/* make sure we have a valid end point */
Richard Mudgett
committed
current_dest_chan = ast_channel_get_by_name_prefix(args.dest_chan,
strlen(args.dest_chan));
if (!current_dest_chan) {
ast_log(LOG_WARNING, "Bridge failed because channel %s does not exist\n",
args.dest_chan);
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
Mark Michelson
committed
/* avoid bridge with ourselves */
if (chan == current_dest_chan) {
Richard Mudgett
committed
ast_channel_unref(current_dest_chan);
Mark Michelson
committed
ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", ast_channel_name(chan));
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
return 0;
if (ast_test_flag(&opts, OPT_DURATION_LIMIT)
&& !ast_strlen_zero(opt_args[OPT_ARG_DURATION_LIMIT])
&& ast_bridge_timelimit(chan, &bconfig, opt_args[OPT_ARG_DURATION_LIMIT], &calldurationlimit)) {
goto done;
}
if (ast_test_flag(&opts, OPT_CALLEE_TRANSFER))
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_REDIRECT);
if (ast_test_flag(&opts, OPT_CALLER_TRANSFER))
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_REDIRECT);
if (ast_test_flag(&opts, OPT_CALLEE_HANGUP))
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
if (ast_test_flag(&opts, OPT_CALLER_HANGUP))
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
if (ast_test_flag(&opts, OPT_CALLEE_MONITOR))
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_AUTOMON);
if (ast_test_flag(&opts, OPT_CALLER_MONITOR))
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_AUTOMON);
if (ast_test_flag(&opts, OPT_CALLEE_PARK))
ast_set_flag(&(bconfig.features_callee), AST_FEATURE_PARKCALL);
if (ast_test_flag(&opts, OPT_CALLER_PARK))
ast_set_flag(&(bconfig.features_caller), AST_FEATURE_PARKCALL);
Richard Mudgett
committed
/* Setup after bridge goto location. */
if (ast_test_flag(&opts, OPT_CALLEE_GO_ON)) {
ast_channel_lock(chan);
context = ast_strdupa(ast_channel_context(chan));
extension = ast_strdupa(ast_channel_exten(chan));
priority = ast_channel_priority(chan);
ast_channel_unlock(chan);
ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority,
Richard Mudgett
committed
opt_args[OPT_ARG_CALLEE_GO_ON]);
} else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
Mark Michelson
committed
ast_channel_lock(current_dest_chan);
context = ast_strdupa(ast_channel_context(current_dest_chan));
extension = ast_strdupa(ast_channel_exten(current_dest_chan));
priority = ast_channel_priority(current_dest_chan);
ast_channel_unlock(current_dest_chan);
ast_bridge_set_after_go_on(current_dest_chan, context, extension, priority, NULL);
Mark Michelson
committed
}
if (ast_bridge_features_init(&chan_features)) {
ast_bridge_features_cleanup(&chan_features);
goto done;
Richard Mudgett
committed
}
Mark Michelson
committed
peer_features = ast_bridge_features_new();
if (!peer_features) {
ast_bridge_features_cleanup(&chan_features);
goto done;
}
if (pre_bridge_setup(chan, current_dest_chan, &bconfig, &chan_features, peer_features)) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
goto done;
}
bridge = ast_bridge_basic_new();
if (!bridge) {
ast_bridge_features_destroy(peer_features);
ast_bridge_features_cleanup(&chan_features);
goto done;
}
ast_channel_lock(current_dest_chan);
xfer_cfg = ast_get_chan_features_xfer_config(current_dest_chan);
ast_channel_unlock(current_dest_chan);
Richard Mudgett
committed
bridge_add_failed = ast_bridge_add_channel(bridge, current_dest_chan, peer_features,
ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE),
xfer_cfg ? xfer_cfg->xfersound : NULL);
ao2_cleanup(xfer_cfg);
if (bridge_add_failed) {
Mark Michelson
committed
ast_bridge_features_cleanup(&chan_features);
Richard Mudgett
committed
ast_bridge_destroy(bridge, 0);
Mark Michelson
committed
goto done;
}
Richard Mudgett
committed
/* Don't keep the channel ref in case it was not already in a bridge. */
current_dest_chan = ast_channel_unref(current_dest_chan);
res = ast_bridge_join(bridge, chan, NULL, &chan_features, NULL,
AST_BRIDGE_JOIN_PASS_REFERENCE);
Mark Michelson
committed
ast_bridge_features_cleanup(&chan_features);
if (res == -1) {
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "FAILURE");
} else {
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
}
ast_free((char *) bconfig.warning_sound);
ast_free((char *) bconfig.end_sound);
ast_free((char *) bconfig.start_sound);
Richard Mudgett
committed
ast_channel_cleanup(current_dest_chan);
/*!
* \internal
* \brief Clean up resources on Asterisk shutdown
*/
static void features_shutdown(void)
{
ast_features_config_shutdown();
ast_manager_unregister("Bridge");
Richard Mudgett
committed
ast_unregister_application(app_bridge);
}
int ast_features_init(void)
{
int res;
res = ast_features_config_init();
res |= ast_register_application2(app_bridge, bridge_exec, NULL, NULL, NULL);
res |= ast_manager_register_xml_core("Bridge", EVENT_FLAG_CALL, action_bridge);
if (res) {
features_shutdown();
} else {
ast_register_cleanup(features_shutdown);