/*! \brief Internal built in feature for blind transfers */ static int feature_blind_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) { char exten[AST_MAX_EXTENSION] = ""; struct ast_channel *chan = NULL; struct ast_bridge_features_blind_transfer *blind_transfer = hook_pvt; const char *context = (blind_transfer && !ast_strlen_zero(blind_transfer->context) ? blind_transfer->context : bridge_channel->chan->context); /* Grab the extension to transfer to */ if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) { ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* Get a channel that is the destination we wish to call */ if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) { ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* This is sort of the fun part. We impart the above channel onto the bridge, and have it take our place. */ ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL); return 0; }
/*! \brief Called when the channel should actually be dialed */ static int bridge_call(struct ast_channel *ast, char *dest, int timeout) { struct bridge_pvt *p = ast->tech_pvt; /* If no bridge has been provided on the input channel, bail out */ if (!ast->bridge) { return -1; } /* Impart the output channel upon the given bridge of the input channel */ ast_bridge_impart(p->input->bridge, p->output, NULL, NULL, 0); return 0; }
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; }
int sccpconf_announce_channel_push(struct ast_channel *ast, struct ast_bridge *bridge) { struct ast_bridge_features *features; struct ast_channel *chan; struct announce_pvt *p = NULL; { ast_channel_lock(ast); p = ast_channel_tech_pvt(ast); if (!p) { ast_channel_unlock(ast); return -1; } ao2_ref(p, +1); chan = p->base.chan; if (!chan) { ast_channel_unlock(ast); ao2_cleanup(p); return -1; } ast_channel_ref(chan); ast_channel_unlock(ast); } features = ast_bridge_features_new(); if (!features) { ast_channel_unref(chan); ao2_cleanup(p); return -1; } ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE); // Impart the output channel into the bridge if (ast_bridge_impart(bridge, chan, NULL, features, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { ast_bridge_features_destroy(features); ast_channel_unref(chan); ao2_cleanup(p); return -1; } ao2_lock(p); ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); ao2_cleanup(p); return 0; }
/*! * \brief Add a channel to the singleton dial bridge. * * \param control The Stasis control structure * \param chan The channel to add to the bridge * \retval -1 Failed * \retval 0 Success */ static int add_to_dial_bridge(struct stasis_app_control *control, struct ast_channel *chan) { struct ast_bridge *bridge; bridge = get_dial_bridge(); if (!bridge) { return -1; } control->bridge = bridge; ast_bridge_set_after_callback(chan, dial_bridge_after_cb, dial_bridge_after_cb_failed, control); if (ast_bridge_impart(bridge, chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_DEPARTABLE)) { control->bridge = NULL; ao2_ref(bridge, -1); return -1; } ao2_ref(bridge, -1); return 0; }
int conf_announce_channel_push(struct ast_channel *ast) { struct ast_bridge_features *features; struct ast_channel *chan; RAII_VAR(struct announce_pvt *, p, NULL, ao2_cleanup); { SCOPED_CHANNELLOCK(lock, ast); p = ast_channel_tech_pvt(ast); if (!p) { return -1; } ao2_ref(p, +1); chan = p->base.chan; if (!chan) { return -1; } } features = ast_bridge_features_new(); if (!features) { return -1; } ast_set_flag(&features->feature_flags, AST_BRIDGE_CHANNEL_FLAG_IMMOVABLE); /* Impart the output channel into the bridge */ if (ast_bridge_impart(p->bridge, chan, NULL, features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { return -1; } ao2_lock(p); ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); return 0; }
/*! \brief Initiate new call, part of PBX interface * dest is the dial string */ static int local_call(struct ast_channel *ast, const char *dest, int timeout) { struct local_pvt *p = ast_channel_tech_pvt(ast); int pvt_locked = 0; struct ast_channel *owner = NULL; struct ast_channel *chan = NULL; int res; char *reduced_dest = ast_strdupa(dest); char *slash; const char *chan_cid; if (!p) { return -1; } /* since we are letting go of channel locks that were locked coming into * this function, then we need to give the tech pvt a ref */ ao2_ref(p, 1); ast_channel_unlock(ast); ast_unreal_lock_all(&p->base, &chan, &owner); pvt_locked = 1; if (owner != ast) { res = -1; goto return_cleanup; } if (!owner || !chan) { res = -1; goto return_cleanup; } ast_unreal_call_setup(owner, chan); /* * If the local channel has /n on the end of it, we need to lop * that off for our argument to setting up the CC_INTERFACES * variable. */ if ((slash = strrchr(reduced_dest, '/'))) { *slash = '\0'; } ast_set_cc_interfaces_chanvar(chan, reduced_dest); ao2_unlock(p); pvt_locked = 0; ast_channel_unlock(owner); chan_cid = S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL); if (chan_cid) { chan_cid = ast_strdupa(chan_cid); } ast_channel_unlock(chan); res = -1; switch (p->type) { case LOCAL_CALL_ACTION_DIALPLAN: if (!ast_exists_extension(NULL, p->context, p->exten, 1, chan_cid)) { ast_log(LOG_NOTICE, "No such extension/context %s@%s while calling Local channel\n", p->exten, p->context); } else { publish_local_bridge_message(p); /* Start switch on sub channel */ res = ast_pbx_start(chan); } break; case LOCAL_CALL_ACTION_BRIDGE: publish_local_bridge_message(p); ast_answer(chan); res = ast_bridge_impart(p->action.bridge.join, chan, p->action.bridge.swap, p->action.bridge.features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT); ao2_ref(p->action.bridge.join, -1); p->action.bridge.join = NULL; ao2_cleanup(p->action.bridge.swap); p->action.bridge.swap = NULL; p->action.bridge.features = NULL; break; case LOCAL_CALL_ACTION_MASQUERADE: publish_local_bridge_message(p); ast_answer(chan); res = ast_channel_move(p->action.masq, chan); if (!res) { /* Chan is now an orphaned zombie. Destroy it. */ ast_hangup(chan); } p->action.masq = ast_channel_unref(p->action.masq); break; } if (!res) { ao2_lock(p); ast_set_flag(&p->base, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); } /* we already unlocked them, clear them here so the cleanup label won't touch them. */ owner = ast_channel_unref(owner); chan = ast_channel_unref(chan); return_cleanup: if (p) { if (pvt_locked) { ao2_unlock(p); } ao2_ref(p, -1); } if (chan) { ast_channel_unlock(chan); ast_channel_unref(chan); } /* * owner is supposed to be == to ast, if it is, don't unlock it * because ast must exit locked */ if (owner) { if (owner != ast) { ast_channel_unlock(owner); ast_channel_lock(ast); } ast_channel_unref(owner); } else { /* we have to exit with ast locked */ ast_channel_lock(ast); } return res; }
/*! \brief Internal built in feature for attended transfers */ static int feature_attended_transfer(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, void *hook_pvt) { char exten[AST_MAX_EXTENSION] = ""; struct ast_channel *chan = NULL; struct ast_bridge *attended_bridge = NULL; struct ast_bridge_features caller_features, called_features; enum ast_bridge_channel_state attended_bridge_result; struct ast_bridge_features_attended_transfer *attended_transfer = hook_pvt; const char *context = (attended_transfer && !ast_strlen_zero(attended_transfer->context) ? attended_transfer->context : bridge_channel->chan->context); /* Grab the extension to transfer to */ if (!grab_transfer(bridge_channel->chan, exten, sizeof(exten), context)) { ast_stream_and_wait(bridge_channel->chan, "pbx-invalid", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* Get a channel that is the destination we wish to call */ if (!(chan = dial_transfer(bridge_channel->chan, exten, context))) { ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* Create a bridge to use to talk to the person we are calling */ if (!(attended_bridge = ast_bridge_new(AST_BRIDGE_CAPABILITY_1TO1MIX, 0))) { ast_hangup(chan); ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); return 0; } /* Setup our called features structure so that if they hang up we immediately get thrown out of the bridge */ ast_bridge_features_init(&called_features); ast_bridge_features_set_flag(&called_features, AST_BRIDGE_FLAG_DISSOLVE); /* This is how this is going down, we are imparting the channel we called above into this bridge first */ ast_bridge_impart(attended_bridge, chan, NULL, &called_features); /* Before we join setup a features structure with the hangup option, just in case they want to use DTMF */ ast_bridge_features_init(&caller_features); ast_bridge_features_enable(&caller_features, AST_BRIDGE_BUILTIN_HANGUP, (attended_transfer && !ast_strlen_zero(attended_transfer->complete) ? attended_transfer->complete : "*1"), NULL); ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->threeway) ? attended_transfer->threeway : "*2"), attended_threeway_transfer, NULL); ast_bridge_features_hook(&caller_features, (attended_transfer && !ast_strlen_zero(attended_transfer->abort) ? attended_transfer->abort : "*3"), attended_abort_transfer, NULL); /* But for the caller we want to join the bridge in a blocking fashion so we don't spin around in this function doing nothing while waiting */ attended_bridge_result = ast_bridge_join(attended_bridge, bridge_channel->chan, NULL, &caller_features); /* Since the above returned the caller features structure is of no more use */ ast_bridge_features_cleanup(&caller_features); /* Drop the channel we are transferring to out of the above bridge since it has ended */ if ((attended_bridge_result != AST_BRIDGE_CHANNEL_STATE_HANGUP) && !ast_bridge_depart(attended_bridge, chan)) { /* If the user wants to turn this into a threeway transfer then do so, otherwise they take our place */ if (attended_bridge_result == AST_BRIDGE_CHANNEL_STATE_DEPART) { /* We want to impart them upon the bridge and just have us return to it as normal */ ast_bridge_impart(bridge, chan, NULL, NULL); } else { ast_bridge_impart(bridge, chan, bridge_channel->chan, NULL); } } else { ast_stream_and_wait(bridge_channel->chan, "beeperr", AST_DIGIT_ANY); ast_bridge_change_state(bridge_channel, AST_BRIDGE_CHANNEL_STATE_WAIT); } /* Now that all channels are out of it we can destroy the bridge and the called features structure */ ast_bridge_features_cleanup(&called_features); ast_bridge_destroy(attended_bridge); return 0; }
/*! * \internal * \brief Determine if an extension is a parking extension */ static int parking_is_exten_park(const char *context, const char *exten) { struct ast_exten *exten_obj; struct pbx_find_info info = { .stacklen = 0 }; /* the rest is reset in pbx_find_extension */ const char *app_at_exten; ast_debug(4, "Checking if %s@%s is a parking exten\n", exten, context); exten_obj = pbx_find_extension(NULL, NULL, &info, context, exten, 1, NULL, NULL, E_MATCH); if (!exten_obj) { return 0; } app_at_exten = ast_get_extension_app(exten_obj); if (!app_at_exten || strcasecmp(PARK_APPLICATION, app_at_exten)) { return 0; } return 1; } /*! * \internal * \since 12.0.0 * \brief Perform a blind transfer to a parking lot * * In general, most parking features should work to call this function. This will safely * park either a channel in the bridge with \ref bridge_channel or will park the entire * bridge if more than one channel is in the bridge. It will create the correct data to * pass to the \ref AstBridging Bridging API to safely park the channel. * * \param bridge_channel The bridge_channel representing the channel performing the park * \param context The context to blind transfer to * \param exten The extension to blind transfer to * \param parked_channel_cb Optional callback executed prior to sending the parked channel into the bridge * \param parked_channel_data Data for the parked_channel_cb * * \retval 0 on success * \retval non-zero on error */ static int parking_blind_transfer_park(struct ast_bridge_channel *bridge_channel, const char *context, const char *exten, transfer_channel_cb parked_channel_cb, struct transfer_channel_data *parked_channel_data) { RAII_VAR(struct ast_bridge_channel *, other, NULL, ao2_cleanup); RAII_VAR(struct ast_channel *, other_chan, NULL, ast_channel_cleanup); struct ast_exten *e; struct pbx_find_info find_info = { .stacklen = 0 }; int peer_count; if (ast_strlen_zero(context) || ast_strlen_zero(exten)) { return -1; } if (!bridge_channel->in_bridge) { return -1; } if (!parking_is_exten_park(context, exten)) { return -1; } ast_bridge_channel_lock_bridge(bridge_channel); peer_count = bridge_channel->bridge->num_channels; if (peer_count == 2) { other = ast_bridge_channel_peer(bridge_channel); ao2_ref(other, +1); other_chan = other->chan; ast_channel_ref(other_chan); } ast_bridge_unlock(bridge_channel->bridge); if (peer_count < 2) { /* There is nothing to do if there is no one to park. */ return -1; } /* With a multiparty bridge, we need to do a regular blind transfer. We link the * existing bridge to the parking lot with a Local channel rather than * transferring others. */ if (peer_count > 2) { struct ast_channel *transfer_chan = NULL; transfer_chan = park_local_transfer(bridge_channel->chan, context, exten, parked_channel_data); if (!transfer_chan) { return -1; } ast_channel_ref(transfer_chan); if (parked_channel_cb) { parked_channel_cb(transfer_chan, parked_channel_data, AST_BRIDGE_TRANSFER_MULTI_PARTY); } if (ast_bridge_impart(bridge_channel->bridge, transfer_chan, NULL, NULL, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { ast_hangup(transfer_chan); ast_channel_unref(transfer_chan); return -1; } ast_channel_unref(transfer_chan); return 0; } /* Subscribe to park messages with the other channel entering */ if (create_parked_subscription_full(bridge_channel->chan, ast_channel_uniqueid(other->chan), 1, parked_channel_data)) { return -1; } if (parked_channel_cb) { parked_channel_cb(other_chan, parked_channel_data, AST_BRIDGE_TRANSFER_SINGLE_PARTY); } e = pbx_find_extension(NULL, NULL, &find_info, context, exten, 1, NULL, NULL, E_MATCH); /* Write the park frame with the intended recipient and other data out to the bridge. */ ast_bridge_channel_write_park(bridge_channel, ast_channel_uniqueid(other_chan), ast_channel_uniqueid(bridge_channel->chan), e ? ast_get_extension_app_data(e) : NULL); return 0; } /*! * \internal * \since 12.0.0 * \brief Perform a direct park on a channel in a bridge * * \note This will be called from within the \ref AstBridging Bridging API * * \param bridge_channel The bridge_channel representing the channel to be parked * \param uuid_parkee The UUID of the channel being parked * \param uuid_parker The UUID of the channel performing the park * \param app_data Application parseable data to pass to the parking application */ static int parking_park_bridge_channel(struct ast_bridge_channel *bridge_channel, const char *uuid_parkee, const char *uuid_parker, const char *app_data) { RAII_VAR(struct ast_bridge *, parking_bridge, NULL, ao2_cleanup); RAII_VAR(struct ast_bridge *, original_bridge, NULL, ao2_cleanup); RAII_VAR(struct ast_channel *, parker, NULL, ao2_cleanup); if (strcmp(ast_channel_uniqueid(bridge_channel->chan), uuid_parkee)) { /* We aren't the parkee, so ignore this action. */ return -1; } parker = ast_channel_get_by_name(uuid_parker); if (!parker) { ast_log(LOG_NOTICE, "Channel with uuid %s left before we could start parking the call. Parking canceled.\n", uuid_parker); publish_parked_call_failure(bridge_channel->chan); return -1; } if (!(parking_bridge = park_application_setup(bridge_channel->chan, parker, app_data, NULL))) { publish_parked_call_failure(bridge_channel->chan); return -1; } ast_bridge_set_transfer_variables(bridge_channel->chan, ast_channel_name(parker), 0); /* bridge_channel must be locked so we can get a reference to the bridge it is currently on */ ao2_lock(bridge_channel); original_bridge = bridge_channel->bridge; if (!original_bridge) { ao2_unlock(bridge_channel); publish_parked_call_failure(bridge_channel->chan); return -1; } ao2_ref(original_bridge, +1); /* Cleaned by RAII_VAR */ ao2_unlock(bridge_channel); if (ast_bridge_move(parking_bridge, original_bridge, bridge_channel->chan, NULL, 1)) { ast_log(LOG_ERROR, "Failed to move %s into the parking bridge.\n", ast_channel_name(bridge_channel->chan)); return -1; } 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; }
static int app_control_add_channel_to_bridge( struct stasis_app_control *control, struct ast_channel *chan, void *data) { struct ast_bridge *bridge = data; int res; if (!control || !bridge) { return -1; } ast_debug(3, "%s: Adding to bridge %s\n", stasis_app_control_get_channel_id(control), bridge->uniqueid); ast_assert(chan != NULL); /* Depart whatever Stasis bridge we're currently in. */ if (stasis_app_get_bridge(control)) { /* Note that it looks like there's a race condition here, since * we don't have control locked. But this happens from the * control callback thread, so there won't be any other * concurrent attempts to bridge. */ ast_bridge_depart(chan); } res = ast_bridge_set_after_callback(chan, bridge_after_cb, bridge_after_cb_failed, control); if (res != 0) { ast_log(LOG_ERROR, "Error setting after-bridge callback\n"); return -1; } { /* pbx and bridge are modified by the bridging impart thread. * It shouldn't happen concurrently, but we still need to lock * for the memory fence. */ SCOPED_AO2LOCK(lock, control); /* Save off the channel's PBX */ ast_assert(control->pbx == NULL); if (!control->pbx) { control->pbx = ast_channel_pbx(chan); ast_channel_pbx_set(chan, NULL); } res = ast_bridge_impart(bridge, chan, NULL, /* swap channel */ NULL, /* features */ AST_BRIDGE_IMPART_CHAN_DEPARTABLE); if (res != 0) { ast_log(LOG_ERROR, "Error adding channel to bridge\n"); ast_channel_pbx_set(chan, control->pbx); control->pbx = NULL; return -1; } ast_assert(stasis_app_get_bridge(control) == NULL); control->bridge = bridge; } return 0; }
int ast_unreal_channel_push_to_bridge(struct ast_channel *ast, struct ast_bridge *bridge, unsigned int flags) { struct ast_bridge_features *features; struct ast_channel *chan; struct ast_channel *owner; RAII_VAR(struct ast_unreal_pvt *, p, NULL, ao2_cleanup); RAII_VAR(struct ast_callid *, bridge_callid, NULL, ast_callid_cleanup); ast_bridge_lock(bridge); bridge_callid = bridge->callid ? ast_callid_ref(bridge->callid) : NULL; ast_bridge_unlock(bridge); { SCOPED_CHANNELLOCK(lock, ast); p = ast_channel_tech_pvt(ast); if (!p) { return -1; } ao2_ref(p, +1); } { SCOPED_AO2LOCK(lock, p); chan = p->chan; if (!chan) { return -1; } owner = p->owner; if (!owner) { return -1; } ast_channel_ref(chan); ast_channel_ref(owner); } if (bridge_callid) { struct ast_callid *chan_callid; struct ast_callid *owner_callid; /* chan side call ID setting */ ast_channel_lock(chan); chan_callid = ast_channel_callid(chan); if (!chan_callid) { ast_channel_callid_set(chan, bridge_callid); } ast_channel_unlock(chan); ast_callid_cleanup(chan_callid); /* owner side call ID setting */ ast_channel_lock(owner); owner_callid = ast_channel_callid(owner); if (!owner_callid) { ast_channel_callid_set(owner, bridge_callid); } ast_channel_unlock(owner); ast_callid_cleanup(owner_callid); } /* We are done with the owner now that its call ID matches the bridge */ ast_channel_unref(owner); owner = NULL; features = ast_bridge_features_new(); if (!features) { ast_channel_unref(chan); return -1; } ast_set_flag(&features->feature_flags, flags); /* Impart the semi2 channel into the bridge */ if (ast_bridge_impart(bridge, chan, NULL, features, AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) { ast_bridge_features_destroy(features); ast_channel_unref(chan); return -1; } ao2_lock(p); ast_set_flag(p, AST_UNREAL_CARETAKER_THREAD); ao2_unlock(p); ast_channel_unref(chan); return 0; }
int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap) { int res; if (!control || !bridge) { return -1; } ast_debug(3, "%s: Adding to bridge %s\n", stasis_app_control_get_channel_id(control), bridge->uniqueid); ast_assert(chan != NULL); /* Depart whatever Stasis bridge we're currently in. */ if (stasis_app_get_bridge(control)) { /* Note that it looks like there's a race condition here, since * we don't have control locked. But this happens from the * control callback thread, so there won't be any other * concurrent attempts to bridge. */ ast_bridge_depart(chan); } res = ast_bridge_set_after_callback(chan, bridge_after_cb, bridge_after_cb_failed, control); if (res != 0) { ast_log(LOG_ERROR, "Error setting after-bridge callback\n"); return -1; } { /* pbx and bridge are modified by the bridging impart thread. * It shouldn't happen concurrently, but we still need to lock * for the memory fence. */ SCOPED_AO2LOCK(lock, control); /* Ensure the controlling application is subscribed early enough * to receive the ChannelEnteredBridge message. This works in concert * with the subscription handled in the Stasis application execution * loop */ app_subscribe_bridge(control->app, bridge); /* Save off the channel's PBX */ ast_assert(control->pbx == NULL); if (!control->pbx) { control->pbx = ast_channel_pbx(chan); ast_channel_pbx_set(chan, NULL); } res = ast_bridge_impart(bridge, chan, swap, NULL, /* features */ AST_BRIDGE_IMPART_CHAN_DEPARTABLE); if (res != 0) { ast_log(LOG_ERROR, "Error adding channel to bridge\n"); ast_channel_pbx_set(chan, control->pbx); control->pbx = NULL; return -1; } ast_assert(stasis_app_get_bridge(control) == NULL); control->bridge = bridge; ast_channel_lock(chan); set_interval_hook(chan); ast_channel_unlock(chan); } return 0; }
int control_swap_channel_in_bridge(struct stasis_app_control *control, struct ast_bridge *bridge, struct ast_channel *chan, struct ast_channel *swap) { int res; struct ast_bridge_features *features; if (!control || !bridge) { return -1; } ast_debug(3, "%s: Adding to bridge %s\n", stasis_app_control_get_channel_id(control), bridge->uniqueid); ast_assert(chan != NULL); /* Depart whatever Stasis bridge we're currently in. */ if (stasis_app_get_bridge(control)) { /* Note that it looks like there's a race condition here, since * we don't have control locked. But this happens from the * control callback thread, so there won't be any other * concurrent attempts to bridge. */ ast_bridge_depart(chan); } res = ast_bridge_set_after_callback(chan, bridge_after_cb, bridge_after_cb_failed, control); if (res != 0) { ast_log(LOG_ERROR, "Error setting after-bridge callback\n"); return -1; } ao2_lock(control); /* Ensure the controlling application is subscribed early enough * to receive the ChannelEnteredBridge message. This works in concert * with the subscription handled in the Stasis application execution * loop */ app_subscribe_bridge(control->app, bridge); /* Save off the channel's PBX */ ast_assert(control->pbx == NULL); if (!control->pbx) { control->pbx = ast_channel_pbx(chan); ast_channel_pbx_set(chan, NULL); } /* Pull bridge features from the control */ features = control->bridge_features; control->bridge_features = NULL; ast_assert(stasis_app_get_bridge(control) == NULL); /* We need to set control->bridge here since bridge_after_cb may be run * before ast_bridge_impart returns. bridge_after_cb gets a reason * code so it can tell if the bridge is actually valid or not. */ control->bridge = bridge; /* We can't be holding the control lock while impart is running * or we could create a deadlock with bridge_after_cb which also * tries to lock control. */ ao2_unlock(control); res = ast_bridge_impart(bridge, chan, swap, features, /* features */ AST_BRIDGE_IMPART_CHAN_DEPARTABLE); if (res != 0) { /* ast_bridge_impart failed before it could spawn the depart * thread. The callbacks aren't called in this case. * The impart could still fail even if ast_bridge_impart returned * ok but that's handled by bridge_after_cb. */ ast_log(LOG_ERROR, "Error adding channel to bridge\n"); ao2_lock(control); ast_channel_pbx_set(chan, control->pbx); control->pbx = NULL; control->bridge = NULL; ao2_unlock(control); } else { ast_channel_lock(chan); set_interval_hook(chan); ast_channel_unlock(chan); } return res; }