diff --git a/bridges/bridge_native_rtp.c b/bridges/bridge_native_rtp.c index 639b8946c69692f64e7c376e76c7e6fb6ba04320..27d8d77cac869ff8af1f1054b24cb28107ccd781 100644 --- a/bridges/bridge_native_rtp.c +++ b/bridges/bridge_native_rtp.c @@ -183,89 +183,10 @@ static int native_rtp_bridge_start(struct ast_bridge *bridge, struct ast_channel return 0; } -/*! - * \internal - * \brief Given a bridge channel, get its RTP instance - * - * The returned ast_rtp_instance has its refcount bumped. - * - * \param bridge_channel Take a guess - * \retval NULL No RTP instance on this bridge channel - * \retval non-NULL The RTP instance on this bridge channel - */ -static struct ast_rtp_instance *bridge_channel_get_rtp_instance(struct ast_bridge_channel *bridge_channel) -{ - struct ast_rtp_glue *glue; - struct ast_rtp_instance *instance; - - glue = ast_rtp_instance_get_glue(ast_channel_tech(bridge_channel->chan)->type); - if (!glue) { - return NULL; - } - - glue->get_rtp_info(bridge_channel->chan, &instance); - return instance; -} - -/*! - * \internal - * \brief Determine which two channels are bridged together - * - * Because of the nature of swapping, when the time comes for a channel to - * leave a native RTP bridge, it may be that there are more than two channels - * in the list of bridge channels. Therefore, it is important to correctly - * determine which two channels were bridged together. - * - * \param bridge The involved bridge - * \param leaving The bridge channel that is leaving the native RTP bridge - * \param[out] c0 The first bridged channel - * \param[out] c1 The second bridged channel - */ -static void find_bridged_channels(struct ast_bridge *bridge, struct ast_bridge_channel *leaving, - struct ast_bridge_channel **c0, struct ast_bridge_channel **c1) -{ - RAII_VAR(struct ast_rtp_instance *, leaving_instance, bridge_channel_get_rtp_instance(leaving), ao2_cleanup); - struct ast_bridge_channel *iter; - - if (!leaving_instance) { - return; - } - - AST_LIST_TRAVERSE(&bridge->channels, iter, entry) { - RAII_VAR(struct ast_rtp_instance *, instance, NULL, ao2_cleanup); - - if (iter == leaving) { - continue; - } - - instance = bridge_channel_get_rtp_instance(iter); - if (!instance) { - continue; - } - - if (instance == ast_rtp_instance_get_bridged(leaving_instance)) { - break; - } - } - *c0 = leaving; - *c1 = iter; - return; -} - -/*! - * \internal - * \brief Stop native RTP bridging of two channels - * - * \param bridge The bridge that had native RTP bridging happening on it - * \param target If remote RTP bridging, the channel that is placed on hold. - * \param leaving If this is called because a channel is leaving, this is the - * bridge channel that is leaving the bridge - */ -static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel *target, - struct ast_bridge_channel *leaving) +static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel *target) { - struct ast_bridge_channel *c0 = NULL; - struct ast_bridge_channel *c1 = NULL; + struct ast_bridge_channel *c0 = AST_LIST_FIRST(&bridge->channels); + struct ast_bridge_channel *c1 = AST_LIST_LAST(&bridge->channels); enum ast_rtp_glue_result native_type; struct ast_rtp_glue *glue0, *glue1 = NULL; RAII_VAR(struct ast_rtp_instance *, instance0, NULL, ao2_cleanup); @@ -273,17 +194,7 @@ static void native_rtp_bridge_stop(struct ast_bridge *bridge, struct ast_channel RAII_VAR(struct ast_rtp_instance *, vinstance0, NULL, ao2_cleanup); RAII_VAR(struct ast_rtp_instance *, vinstance1, NULL, ao2_cleanup); - if (bridge->num_channels == 2) { - c0 = AST_LIST_FIRST(&bridge->channels); - c1 = AST_LIST_LAST(&bridge->channels); - } else if (bridge->num_channels > 2) { - /* When a channel leaves a native RTP bridge, it is possible for - * more channels to exist in the bridge than when the RTP bridge - * was started. Thus we need to determine which two channels were - * bridged based on the leaving channel - */ - find_bridged_channels(bridge, leaving, &c0, &c1); - } else { + if (c0 == c1) { return; } @@ -347,7 +258,7 @@ static struct ast_frame *native_rtp_framehook(struct ast_channel *chan, struct a if (bridge) { if (f->subclass.integer == AST_CONTROL_HOLD) { - native_rtp_bridge_stop(bridge, chan, NULL); + native_rtp_bridge_stop(bridge, chan); } else if ((f->subclass.integer == AST_CONTROL_UNHOLD) || (f->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) { native_rtp_bridge_start(bridge, chan); } @@ -511,9 +422,33 @@ static void native_rtp_bridge_unsuspend(struct ast_bridge *bridge, struct ast_br static void native_rtp_bridge_leave(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel) { + struct ast_rtp_glue *glue; + RAII_VAR(struct ast_rtp_instance *, instance, NULL, ao2_cleanup); + RAII_VAR(struct ast_rtp_instance *, vinstance, NULL, ao2_cleanup); + RAII_VAR(struct ast_rtp_instance *, tinstance, NULL, ao2_cleanup); + native_rtp_bridge_framehook_detach(bridge_channel); - native_rtp_bridge_stop(bridge, NULL, bridge_channel); + glue = ast_rtp_instance_get_glue(ast_channel_tech(bridge_channel->chan)->type); + glue->get_rtp_info(bridge_channel->chan, &instance); + glue->get_vrtp_info ? glue->get_vrtp_info(bridge_channel->chan, &vinstance) : AST_RTP_GLUE_RESULT_FORBID; + glue->get_trtp_info ? glue->get_trtp_info(bridge_channel->chan, &tinstance) : AST_RTP_GLUE_RESULT_FORBID; + + /* Tear down P2P bridges */ + if (instance) { + ast_rtp_instance_set_bridged(instance, NULL); + } + if (vinstance) { + ast_rtp_instance_set_bridged(vinstance, NULL); + } + if (tinstance) { + ast_rtp_instance_set_bridged(tinstance, NULL); + } + + /* Direct RTP may have occurred, tear it down */ + glue->update_peer(bridge_channel->chan, NULL, NULL, NULL, NULL, 0); + + native_rtp_bridge_stop(bridge, NULL); } static int native_rtp_bridge_write(struct ast_bridge *bridge, struct ast_bridge_channel *bridge_channel, struct ast_frame *frame)