static void *app_control_dial(struct stasis_app_control *control, struct ast_channel *chan, void *data) { RAII_VAR(struct ast_dial *, dial, ast_dial_create(), ast_dial_destroy); RAII_VAR(struct stasis_app_control_dial_data *, dial_data, data, ast_free); enum ast_dial_result res; char *tech, *resource; struct ast_channel *new_chan; struct ast_bridge *bridge; tech = dial_data->endpoint; if (!(resource = strchr(tech, '/'))) { return NULL; } *resource++ = '\0'; if (!dial) { ast_log(LOG_ERROR, "Failed to create dialing structure.\n"); return NULL; } if (ast_dial_append(dial, tech, resource) < 0) { ast_log(LOG_ERROR, "Failed to add %s/%s to dialing structure.\n", tech, resource); return NULL; } ast_dial_set_global_timeout(dial, dial_data->timeout); res = ast_dial_run(dial, NULL, 0); if (res != AST_DIAL_RESULT_ANSWERED || !(new_chan = ast_dial_answered_steal(dial))) { return NULL; } if (!(bridge = ast_bridge_basic_new())) { ast_log(LOG_ERROR, "Failed to create basic bridge.\n"); return NULL; } if (ast_bridge_impart(bridge, new_chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { ast_hangup(new_chan); } else { stasis_app_control_add_channel_to_bridge(control, bridge); } return NULL; }
/*! * \brief Bridge channels together * \param s * \param m * * Make sure valid channels were specified, * send errors if any of the channels could not be found/locked, answer channels if needed, * create the placeholder channels and grab the other channels * make the channels compatible, send error if we fail doing so * setup the bridge thread object and start the bridge. * * \retval 0 */ static int action_bridge(struct mansession *s, const struct message *m) { const char *channela = astman_get_header(m, "Channel1"); const char *channelb = astman_get_header(m, "Channel2"); enum play_tone_action playtone = parse_playtone(astman_get_header(m, "Tone")); RAII_VAR(struct ast_channel *, chana, NULL, ao2_cleanup); RAII_VAR(struct ast_channel *, chanb, NULL, ao2_cleanup); const char *chana_exten; const char *chana_context; int chana_priority; const char *chanb_exten; const char *chanb_context; int chanb_priority; struct ast_bridge *bridge; char buf[256]; RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_a, NULL, ao2_cleanup); RAII_VAR(struct ast_features_xfer_config *, xfer_cfg_b, NULL, ao2_cleanup); /* make sure valid channels were specified */ if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) { astman_send_error(s, m, "Missing channel parameter in request"); return 0; } ast_debug(1, "Performing Bridge action on %s and %s\n", channela, channelb); /* Start with chana */ chana = ast_channel_get_by_name_prefix(channela, strlen(channela)); if (!chana) { snprintf(buf, sizeof(buf), "Channel1 does not exist: %s", channela); astman_send_error(s, m, buf); return 0; } ast_channel_lock(chana); xfer_cfg_a = ast_get_chan_features_xfer_config(chana); chana_exten = ast_strdupa(ast_channel_exten(chana)); chana_context = ast_strdupa(ast_channel_context(chana)); chana_priority = ast_channel_priority(chana); if (!ast_test_flag(ast_channel_flags(chana), AST_FLAG_IN_AUTOLOOP)) { chana_priority++; } ast_channel_unlock(chana); chanb = ast_channel_get_by_name_prefix(channelb, strlen(channelb)); if (!chanb) { snprintf(buf, sizeof(buf), "Channel2 does not exist: %s", channelb); astman_send_error(s, m, buf); return 0; } ast_channel_lock(chanb); xfer_cfg_b = ast_get_chan_features_xfer_config(chanb); chanb_exten = ast_strdupa(ast_channel_exten(chanb)); chanb_context = ast_strdupa(ast_channel_context(chanb)); chanb_priority = ast_channel_priority(chanb); if (!ast_test_flag(ast_channel_flags(chanb), AST_FLAG_IN_AUTOLOOP)) { chanb_priority++; } ast_channel_unlock(chanb); bridge = ast_bridge_basic_new(); if (!bridge) { astman_send_error(s, m, "Unable to create bridge\n"); return 0; } ast_bridge_set_after_go_on(chana, chana_context, chana_exten, chana_priority, NULL); if (ast_bridge_add_channel(bridge, chana, NULL, playtone & PLAYTONE_CHANNEL1, xfer_cfg_a ? xfer_cfg_a->xfersound : NULL)) { snprintf(buf, sizeof(buf), "Unable to add Channel1 to bridge: %s", ast_channel_name(chana)); astman_send_error(s, m, buf); ast_bridge_destroy(bridge, 0); return 0; } ast_bridge_set_after_go_on(chanb, chanb_context, chanb_exten, chanb_priority, NULL); if (ast_bridge_add_channel(bridge, chanb, NULL, playtone & PLAYTONE_CHANNEL2, xfer_cfg_b ? xfer_cfg_b->xfersound : NULL)) { snprintf(buf, sizeof(buf), "Unable to add Channel2 to bridge: %s", ast_channel_name(chanb)); astman_send_error(s, m, buf); ast_bridge_destroy(bridge, 0); return 0; } astman_send_ack(s, m, "Channels have been bridged"); ao2_cleanup(bridge); return 0; }
int ast_bridge_call_with_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, unsigned int flags) { int res; struct ast_bridge *bridge; struct ast_bridge_features chan_features; struct ast_bridge_features *peer_features; /* Setup features. */ res = ast_bridge_features_init(&chan_features); peer_features = ast_bridge_features_new(); if (res || !peer_features) { ast_bridge_features_destroy(peer_features); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } if (pre_bridge_setup(chan, peer, config, &chan_features, peer_features)) { ast_bridge_features_destroy(peer_features); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } /* Create bridge */ bridge = ast_bridge_basic_new(); if (!bridge) { ast_bridge_features_destroy(peer_features); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } ast_bridge_basic_set_flags(bridge, flags); /* Put peer into the bridge */ if (ast_bridge_impart(bridge, peer, NULL, peer_features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT | AST_BRIDGE_IMPART_INHIBIT_JOIN_COLP)) { ast_bridge_destroy(bridge, 0); ast_bridge_features_cleanup(&chan_features); bridge_failed_peer_goto(chan, peer); return -1; } /* Join bridge */ ast_bridge_join(bridge, chan, NULL, &chan_features, NULL, AST_BRIDGE_JOIN_PASS_REFERENCE | AST_BRIDGE_JOIN_INHIBIT_JOIN_COLP); /* * If the bridge was broken for a hangup that isn't real, then * don't run the h extension, because the channel isn't really * hung up. This should really only happen with * AST_SOFTHANGUP_ASYNCGOTO. */ res = -1; ast_channel_lock(chan); if (ast_channel_softhangup_internal_flag(chan) & AST_SOFTHANGUP_ASYNCGOTO) { res = 0; } ast_channel_unlock(chan); ast_bridge_features_cleanup(&chan_features); if (res && config->end_bridge_callback) { config->end_bridge_callback(config->end_bridge_callback_data); } return res; }