diff options
author | Richard Mudgett <rmudgett@digium.com> | 2013-05-21 18:00:22 +0000 |
---|---|---|
committer | Richard Mudgett <rmudgett@digium.com> | 2013-05-21 18:00:22 +0000 |
commit | 3d63833bd6c869b7efa383e8dea14be1a6eff998 (patch) | |
tree | 34957dd051b8f67c7cc58a510e24ee3873a61ad4 /main/rtp_engine.c | |
parent | e1e1cc2deefb92f8b43825f1f34e619354737842 (diff) |
Merge in the bridge_construction branch to make the system use the Bridging API.
Breaks many things until they can be reworked. A partial list:
chan_agent
chan_dahdi, chan_misdn, chan_iax2 native bridging
app_queue
COLP updates
DTMF attended transfers
Protocol attended transfers
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@389378 65c4cc65-6c06-0410-ace0-fbb531ad65f3
Diffstat (limited to 'main/rtp_engine.c')
-rw-r--r-- | main/rtp_engine.c | 669 |
1 files changed, 4 insertions, 665 deletions
diff --git a/main/rtp_engine.c b/main/rtp_engine.c index b25cb95b3..8e58f658d 100644 --- a/main/rtp_engine.c +++ b/main/rtp_engine.c @@ -928,497 +928,6 @@ struct ast_rtp_glue *ast_rtp_instance_get_glue(const char *type) return glue; } -static enum ast_bridge_result local_bridge_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp_instance *instance0, struct ast_rtp_instance *instance1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1) -{ - enum ast_bridge_result res = AST_BRIDGE_FAILED; - struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, }; - struct ast_frame *fr = NULL; - struct timeval start; - - /* Start locally bridging both instances */ - if (instance0->engine->local_bridge && instance0->engine->local_bridge(instance0, instance1)) { - ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", ast_channel_name(c0), ast_channel_name(c1)); - ast_channel_unlock(c0); - ast_channel_unlock(c1); - return AST_BRIDGE_FAILED_NOWARN; - } - if (instance1->engine->local_bridge && instance1->engine->local_bridge(instance1, instance0)) { - ast_debug(1, "Failed to locally bridge %s to %s, backing out.\n", ast_channel_name(c1), ast_channel_name(c0)); - if (instance0->engine->local_bridge) { - instance0->engine->local_bridge(instance0, NULL); - } - ast_channel_unlock(c0); - ast_channel_unlock(c1); - return AST_BRIDGE_FAILED_NOWARN; - } - - ast_channel_unlock(c0); - ast_channel_unlock(c1); - - instance0->bridged = instance1; - instance1->bridged = instance0; - - ast_poll_channel_add(c0, c1); - - /* Hop into a loop waiting for a frame from either channel */ - cs[0] = c0; - cs[1] = c1; - cs[2] = NULL; - start = ast_tvnow(); - for (;;) { - int ms; - /* If the underlying formats have changed force this bridge to break */ - if ((ast_format_cmp(ast_channel_rawreadformat(c0), ast_channel_rawwriteformat(c1)) == AST_FORMAT_CMP_NOT_EQUAL) || - (ast_format_cmp(ast_channel_rawreadformat(c1), ast_channel_rawwriteformat(c0)) == AST_FORMAT_CMP_NOT_EQUAL)) { - ast_debug(1, "rtp-engine-local-bridge: Oooh, formats changed, backing out\n"); - res = AST_BRIDGE_FAILED_NOWARN; - break; - } - /* Check if anything changed */ - if ((ast_channel_tech_pvt(c0) != pvt0) || - (ast_channel_tech_pvt(c1) != pvt1) || - (ast_channel_masq(c0) || ast_channel_masqr(c0) || ast_channel_masq(c1) || ast_channel_masqr(c1)) || - (ast_channel_monitor(c0) || ast_channel_audiohooks(c0) || ast_channel_monitor(c1) || ast_channel_audiohooks(c1)) || - (!ast_framehook_list_is_empty(ast_channel_framehooks(c0)) || !ast_framehook_list_is_empty(ast_channel_framehooks(c1)))) { - ast_debug(1, "rtp-engine-local-bridge: Oooh, something is weird, backing out\n"); - /* If a masquerade needs to happen we have to try to read in a frame so that it actually happens. Without this we risk being called again and going into a loop */ - if ((ast_channel_masq(c0) || ast_channel_masqr(c0)) && (fr = ast_read(c0))) { - ast_frfree(fr); - } - if ((ast_channel_masq(c1) || ast_channel_masqr(c1)) && (fr = ast_read(c1))) { - ast_frfree(fr); - } - res = AST_BRIDGE_RETRY; - break; - } - /* Wait on a channel to feed us a frame */ - ms = ast_remaining_ms(start, timeoutms); - if (!(who = ast_waitfor_n(cs, 2, &ms))) { - if (!ms) { - res = AST_BRIDGE_RETRY; - break; - } - ast_debug(2, "rtp-engine-local-bridge: Ooh, empty read...\n"); - if (ast_check_hangup(c0) || ast_check_hangup(c1)) { - break; - } - continue; - } - /* Read in frame from channel */ - fr = ast_read(who); - other = (who == c0) ? c1 : c0; - /* Depending on the frame we may need to break out of our bridge */ - if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) && - ((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) | - ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1)))) { - /* Record received frame and who */ - *fo = fr; - *rc = who; - ast_debug(1, "rtp-engine-local-bridge: Ooh, got a %s\n", fr ? "digit" : "hangup"); - res = AST_BRIDGE_COMPLETE; - break; - } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) { - if ((fr->subclass.integer == AST_CONTROL_HOLD) || - (fr->subclass.integer == AST_CONTROL_UNHOLD) || - (fr->subclass.integer == AST_CONTROL_VIDUPDATE) || - (fr->subclass.integer == AST_CONTROL_SRCUPDATE) || - (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) || - (fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) { - /* If we are going on hold, then break callback mode and P2P bridging */ - if (fr->subclass.integer == AST_CONTROL_HOLD) { - if (instance0->engine->local_bridge) { - instance0->engine->local_bridge(instance0, NULL); - } - if (instance1->engine->local_bridge) { - instance1->engine->local_bridge(instance1, NULL); - } - instance0->bridged = NULL; - instance1->bridged = NULL; - } else if (fr->subclass.integer == AST_CONTROL_UNHOLD) { - if (instance0->engine->local_bridge) { - instance0->engine->local_bridge(instance0, instance1); - } - if (instance1->engine->local_bridge) { - instance1->engine->local_bridge(instance1, instance0); - } - instance0->bridged = instance1; - instance1->bridged = instance0; - } - /* Since UPDATE_BRIDGE_PEER is only used by the bridging code, don't forward it */ - if (fr->subclass.integer != AST_CONTROL_UPDATE_RTP_PEER) { - ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); - } - ast_frfree(fr); - } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) { - if (ast_channel_connected_line_sub(who, other, fr, 1) && - ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) { - ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); - } - ast_frfree(fr); - } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) { - if (ast_channel_redirecting_sub(who, other, fr, 1) && - ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) { - ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); - } - ast_frfree(fr); - } else if (fr->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) { - ast_channel_hangupcause_hash_set(other, fr->data.ptr, fr->datalen); - ast_frfree(fr); - } else { - *fo = fr; - *rc = who; - ast_debug(1, "rtp-engine-local-bridge: Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass.integer, ast_channel_name(who)); - res = AST_BRIDGE_COMPLETE; - break; - } - } else { - if ((fr->frametype == AST_FRAME_DTMF_BEGIN) || - (fr->frametype == AST_FRAME_DTMF_END) || - (fr->frametype == AST_FRAME_VOICE) || - (fr->frametype == AST_FRAME_VIDEO) || - (fr->frametype == AST_FRAME_IMAGE) || - (fr->frametype == AST_FRAME_HTML) || - (fr->frametype == AST_FRAME_MODEM) || - (fr->frametype == AST_FRAME_TEXT)) { - ast_write(other, fr); - } - - ast_frfree(fr); - } - /* Swap priority */ - cs[2] = cs[0]; - cs[0] = cs[1]; - cs[1] = cs[2]; - } - - /* Stop locally bridging both instances */ - if (instance0->engine->local_bridge) { - instance0->engine->local_bridge(instance0, NULL); - } - if (instance1->engine->local_bridge) { - instance1->engine->local_bridge(instance1, NULL); - } - - instance0->bridged = NULL; - instance1->bridged = NULL; - - ast_poll_channel_del(c0, c1); - - return res; -} - -static enum ast_bridge_result remote_bridge_loop(struct ast_channel *c0, - struct ast_channel *c1, - struct ast_rtp_instance *instance0, - struct ast_rtp_instance *instance1, - struct ast_rtp_instance *vinstance0, - struct ast_rtp_instance *vinstance1, - struct ast_rtp_instance *tinstance0, - struct ast_rtp_instance *tinstance1, - struct ast_rtp_glue *glue0, - struct ast_rtp_glue *glue1, - struct ast_format_cap *cap0, - struct ast_format_cap *cap1, - int timeoutms, - int flags, - struct ast_frame **fo, - struct ast_channel **rc, - void *pvt0, - void *pvt1) -{ - enum ast_bridge_result res = AST_BRIDGE_FAILED; - struct ast_channel *who = NULL, *other = NULL, *cs[3] = { NULL, }; - struct ast_format_cap *oldcap0 = ast_format_cap_dup(cap0); - struct ast_format_cap *oldcap1 = ast_format_cap_dup(cap1); - struct ast_sockaddr ac1 = {{0,}}, vac1 = {{0,}}, tac1 = {{0,}}, ac0 = {{0,}}, vac0 = {{0,}}, tac0 = {{0,}}; - struct ast_sockaddr t1 = {{0,}}, vt1 = {{0,}}, tt1 = {{0,}}, t0 = {{0,}}, vt0 = {{0,}}, tt0 = {{0,}}; - struct ast_frame *fr = NULL; - struct timeval start; - - if (!oldcap0 || !oldcap1) { - ast_channel_unlock(c0); - ast_channel_unlock(c1); - goto remote_bridge_cleanup; - } - /* Test the first channel */ - if (!(glue0->update_peer(c0, instance1, vinstance1, tinstance1, cap1, 0))) { - ast_rtp_instance_get_remote_address(instance1, &ac1); - if (vinstance1) { - ast_rtp_instance_get_remote_address(vinstance1, &vac1); - } - if (tinstance1) { - ast_rtp_instance_get_remote_address(tinstance1, &tac1); - } - } else { - ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", ast_channel_name(c0), ast_channel_name(c1)); - } - - /* Test the second channel */ - if (!(glue1->update_peer(c1, instance0, vinstance0, tinstance0, cap0, 0))) { - ast_rtp_instance_get_remote_address(instance0, &ac0); - if (vinstance0) { - ast_rtp_instance_get_remote_address(instance0, &vac0); - } - if (tinstance0) { - ast_rtp_instance_get_remote_address(instance0, &tac0); - } - } else { - ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", ast_channel_name(c1), ast_channel_name(c0)); - } - - ast_channel_unlock(c0); - ast_channel_unlock(c1); - - instance0->bridged = instance1; - instance1->bridged = instance0; - - ast_poll_channel_add(c0, c1); - - /* Go into a loop handling any stray frames that may come in */ - cs[0] = c0; - cs[1] = c1; - cs[2] = NULL; - start = ast_tvnow(); - for (;;) { - int ms; - /* Check if anything changed */ - if ((ast_channel_tech_pvt(c0) != pvt0) || - (ast_channel_tech_pvt(c1) != pvt1) || - (ast_channel_masq(c0) || ast_channel_masqr(c0) || ast_channel_masq(c1) || ast_channel_masqr(c1)) || - (ast_channel_monitor(c0) || ast_channel_audiohooks(c0) || ast_channel_monitor(c1) || ast_channel_audiohooks(c1)) || - (!ast_framehook_list_is_empty(ast_channel_framehooks(c0)) || !ast_framehook_list_is_empty(ast_channel_framehooks(c1)))) { - ast_debug(1, "Oooh, something is weird, backing out\n"); - res = AST_BRIDGE_RETRY; - break; - } - - /* Check if they have changed their address */ - ast_rtp_instance_get_remote_address(instance1, &t1); - if (vinstance1) { - ast_rtp_instance_get_remote_address(vinstance1, &vt1); - } - if (tinstance1) { - ast_rtp_instance_get_remote_address(tinstance1, &tt1); - } - if (glue1->get_codec) { - ast_format_cap_remove_all(cap1); - glue1->get_codec(c1, cap1); - } - - ast_rtp_instance_get_remote_address(instance0, &t0); - if (vinstance0) { - ast_rtp_instance_get_remote_address(vinstance0, &vt0); - } - if (tinstance0) { - ast_rtp_instance_get_remote_address(tinstance0, &tt0); - } - if (glue0->get_codec) { - ast_format_cap_remove_all(cap0); - glue0->get_codec(c0, cap0); - } - - if ((ast_sockaddr_cmp(&t1, &ac1)) || - (vinstance1 && ast_sockaddr_cmp(&vt1, &vac1)) || - (tinstance1 && ast_sockaddr_cmp(&tt1, &tac1)) || - (!ast_format_cap_identical(cap1, oldcap1))) { - char tmp_buf[512] = { 0, }; - ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n", - ast_channel_name(c1), ast_sockaddr_stringify(&t1), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1)); - ast_debug(1, "Oooh, '%s' changed end vaddress to %s (format %s)\n", - ast_channel_name(c1), ast_sockaddr_stringify(&vt1), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1)); - ast_debug(1, "Oooh, '%s' changed end taddress to %s (format %s)\n", - ast_channel_name(c1), ast_sockaddr_stringify(&tt1), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap1)); - ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", - ast_channel_name(c1), ast_sockaddr_stringify(&ac1), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1)); - ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", - ast_channel_name(c1), ast_sockaddr_stringify(&vac1), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1)); - ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", - ast_channel_name(c1), ast_sockaddr_stringify(&tac1), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap1)); - if (glue0->update_peer(c0, - ast_sockaddr_isnull(&t1) ? NULL : instance1, - ast_sockaddr_isnull(&vt1) ? NULL : vinstance1, - ast_sockaddr_isnull(&tt1) ? NULL : tinstance1, - cap1, 0)) { - ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", ast_channel_name(c0), ast_channel_name(c1)); - } - ast_sockaddr_copy(&ac1, &t1); - ast_sockaddr_copy(&vac1, &vt1); - ast_sockaddr_copy(&tac1, &tt1); - ast_format_cap_copy(oldcap1, cap1); - } - if ((ast_sockaddr_cmp(&t0, &ac0)) || - (vinstance0 && ast_sockaddr_cmp(&vt0, &vac0)) || - (tinstance0 && ast_sockaddr_cmp(&tt0, &tac0)) || - (!ast_format_cap_identical(cap0, oldcap0))) { - char tmp_buf[512] = { 0, }; - ast_debug(1, "Oooh, '%s' changed end address to %s (format %s)\n", - ast_channel_name(c0), ast_sockaddr_stringify(&t0), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), cap0)); - ast_debug(1, "Oooh, '%s' was %s/(format %s)\n", - ast_channel_name(c0), ast_sockaddr_stringify(&ac0), - ast_getformatname_multiple(tmp_buf, sizeof(tmp_buf), oldcap0)); - if (glue1->update_peer(c1, t0.len ? instance0 : NULL, - vt0.len ? vinstance0 : NULL, - tt0.len ? tinstance0 : NULL, - cap0, 0)) { - ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", ast_channel_name(c1), ast_channel_name(c0)); - } - ast_sockaddr_copy(&ac0, &t0); - ast_sockaddr_copy(&vac0, &vt0); - ast_sockaddr_copy(&tac0, &tt0); - ast_format_cap_copy(oldcap0, cap0); - } - - ms = ast_remaining_ms(start, timeoutms); - /* Wait for frame to come in on the channels */ - if (!(who = ast_waitfor_n(cs, 2, &ms))) { - if (!ms) { - res = AST_BRIDGE_RETRY; - break; - } - ast_debug(1, "Ooh, empty read...\n"); - if (ast_check_hangup(c0) || ast_check_hangup(c1)) { - break; - } - continue; - } - fr = ast_read(who); - other = (who == c0) ? c1 : c0; - if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) && - (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) || - ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) { - /* Break out of bridge */ - *fo = fr; - *rc = who; - ast_debug(1, "Oooh, got a %s\n", fr ? "digit" : "hangup"); - res = AST_BRIDGE_COMPLETE; - break; - } else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) { - if ((fr->subclass.integer == AST_CONTROL_HOLD) || - (fr->subclass.integer == AST_CONTROL_UNHOLD) || - (fr->subclass.integer == AST_CONTROL_VIDUPDATE) || - (fr->subclass.integer == AST_CONTROL_SRCUPDATE) || - (fr->subclass.integer == AST_CONTROL_T38_PARAMETERS) || - (fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER)) { - if (fr->subclass.integer == AST_CONTROL_HOLD) { - /* If we someone went on hold we want the other side to reinvite back to us */ - if (who == c0) { - glue1->update_peer(c1, NULL, NULL, NULL, 0, 0); - } else { - glue0->update_peer(c0, NULL, NULL, NULL, 0, 0); - } - } else if (fr->subclass.integer == AST_CONTROL_UNHOLD || - fr->subclass.integer == AST_CONTROL_UPDATE_RTP_PEER) { - /* If they went off hold they should go back to being direct, or if we have - * been told to force a peer update, go ahead and do it. */ - if (who == c0) { - glue1->update_peer(c1, instance0, vinstance0, tinstance0, cap0, 0); - } else { - glue0->update_peer(c0, instance1, vinstance1, tinstance1, cap1, 0); - } - } - /* Update local address information */ - ast_rtp_instance_get_remote_address(instance0, &t0); - ast_sockaddr_copy(&ac0, &t0); - ast_rtp_instance_get_remote_address(instance1, &t1); - ast_sockaddr_copy(&ac1, &t1); - /* Update codec information */ - if (glue0->get_codec && ast_channel_tech_pvt(c0)) { - ast_format_cap_remove_all(cap0); - ast_format_cap_remove_all(oldcap0); - glue0->get_codec(c0, cap0); - ast_format_cap_append(oldcap0, cap0); - - } - if (glue1->get_codec && ast_channel_tech_pvt(c1)) { - ast_format_cap_remove_all(cap1); - ast_format_cap_remove_all(oldcap1); - glue1->get_codec(c1, cap1); - ast_format_cap_append(oldcap1, cap1); - } - /* Since UPDATE_BRIDGE_PEER is only used by the bridging code, don't forward it */ - if (fr->subclass.integer != AST_CONTROL_UPDATE_RTP_PEER) { - ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); - } - ast_frfree(fr); - } else if (fr->subclass.integer == AST_CONTROL_CONNECTED_LINE) { - if (ast_channel_connected_line_sub(who, other, fr, 1) && - ast_channel_connected_line_macro(who, other, fr, other == c0, 1)) { - ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); - } - ast_frfree(fr); - } else if (fr->subclass.integer == AST_CONTROL_REDIRECTING) { - if (ast_channel_redirecting_sub(who, other, fr, 1) && - ast_channel_redirecting_macro(who, other, fr, other == c0, 1)) { - ast_indicate_data(other, fr->subclass.integer, fr->data.ptr, fr->datalen); - } - ast_frfree(fr); - } else if (fr->subclass.integer == AST_CONTROL_PVT_CAUSE_CODE) { - ast_channel_hangupcause_hash_set(other, fr->data.ptr, fr->datalen); - ast_frfree(fr); - } else { - *fo = fr; - *rc = who; - ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass.integer, ast_channel_name(who)); - res = AST_BRIDGE_COMPLETE; - goto remote_bridge_cleanup; - } - } else { - if ((fr->frametype == AST_FRAME_DTMF_BEGIN) || - (fr->frametype == AST_FRAME_DTMF_END) || - (fr->frametype == AST_FRAME_VOICE) || - (fr->frametype == AST_FRAME_VIDEO) || - (fr->frametype == AST_FRAME_IMAGE) || - (fr->frametype == AST_FRAME_HTML) || - (fr->frametype == AST_FRAME_MODEM) || - (fr->frametype == AST_FRAME_TEXT)) { - ast_write(other, fr); - } - ast_frfree(fr); - } - /* Swap priority */ - cs[2] = cs[0]; - cs[0] = cs[1]; - cs[1] = cs[2]; - } - - if (ast_test_flag(ast_channel_flags(c0), AST_FLAG_ZOMBIE)) { - ast_debug(1, "Channel '%s' Zombie cleardown from bridge\n", ast_channel_name(c0)); - } else if (ast_channel_tech_pvt(c0) != pvt0) { - ast_debug(1, "Channel c0->'%s' pvt changed, in bridge with c1->'%s'\n", ast_channel_name(c0), ast_channel_name(c1)); - } else if (glue0 != ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) { - ast_debug(1, "Channel c0->'%s' technology changed, in bridge with c1->'%s'\n", ast_channel_name(c0), ast_channel_name(c1)); - } else if (glue0->update_peer(c0, NULL, NULL, NULL, 0, 0)) { - ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", ast_channel_name(c0)); - } - if (ast_test_flag(ast_channel_flags(c1), AST_FLAG_ZOMBIE)) { - ast_debug(1, "Channel '%s' Zombie cleardown from bridge\n", ast_channel_name(c1)); - } else if (ast_channel_tech_pvt(c1) != pvt1) { - ast_debug(1, "Channel c1->'%s' pvt changed, in bridge with c0->'%s'\n", ast_channel_name(c1), ast_channel_name(c0)); - } else if (glue1 != ast_rtp_instance_get_glue(ast_channel_tech(c1)->type)) { - ast_debug(1, "Channel c1->'%s' technology changed, in bridge with c0->'%s'\n", ast_channel_name(c1), ast_channel_name(c0)); - } else if (glue1->update_peer(c1, NULL, NULL, NULL, 0, 0)) { - ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", ast_channel_name(c1)); - } - - instance0->bridged = NULL; - instance1->bridged = NULL; - - ast_poll_channel_del(c0, c1); - -remote_bridge_cleanup: - ast_format_cap_destroy(oldcap0); - ast_format_cap_destroy(oldcap1); - - return res; -} - /*! * \brief Conditionally unref an rtp instance */ @@ -1430,184 +939,14 @@ static void unref_instance_cond(struct ast_rtp_instance **instance) } } -enum ast_bridge_result ast_rtp_instance_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms) +struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance) { - struct ast_rtp_instance *instance0 = NULL, *instance1 = NULL, - *vinstance0 = NULL, *vinstance1 = NULL, - *tinstance0 = NULL, *tinstance1 = NULL; - struct ast_rtp_glue *glue0, *glue1; - struct ast_sockaddr addr1 = { {0, }, }, addr2 = { {0, }, }; - enum ast_rtp_glue_result audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID, video_glue0_res = AST_RTP_GLUE_RESULT_FORBID; - enum ast_rtp_glue_result audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID, video_glue1_res = AST_RTP_GLUE_RESULT_FORBID; - enum ast_bridge_result res = AST_BRIDGE_FAILED; - enum ast_rtp_dtmf_mode dmode; - struct ast_format_cap *cap0 = ast_format_cap_alloc_nolock(); - struct ast_format_cap *cap1 = ast_format_cap_alloc_nolock(); - int unlock_chans = 1; - int read_ptime0, read_ptime1, write_ptime0, write_ptime1; - - if (!cap0 || !cap1) { - unlock_chans = 0; - goto done; - } - - /* Lock both channels so we can look for the glue that binds them together */ - ast_channel_lock_both(c0, c1); - - /* Ensure neither channel got hungup during lock avoidance */ - if (ast_check_hangup(c0) || ast_check_hangup(c1)) { - ast_log(LOG_WARNING, "Got hangup while attempting to bridge '%s' and '%s'\n", ast_channel_name(c0), ast_channel_name(c1)); - goto done; - } - - /* Grab glue that binds each channel to something using the RTP engine */ - if (!(glue0 = ast_rtp_instance_get_glue(ast_channel_tech(c0)->type)) || !(glue1 = ast_rtp_instance_get_glue(ast_channel_tech(c1)->type))) { - ast_debug(1, "Can't find native functions for channel '%s'\n", glue0 ? ast_channel_name(c1) : ast_channel_name(c0)); - goto done; - } - - audio_glue0_res = glue0->get_rtp_info(c0, &instance0); - video_glue0_res = glue0->get_vrtp_info ? glue0->get_vrtp_info(c0, &vinstance0) : AST_RTP_GLUE_RESULT_FORBID; - - audio_glue1_res = glue1->get_rtp_info(c1, &instance1); - video_glue1_res = glue1->get_vrtp_info ? glue1->get_vrtp_info(c1, &vinstance1) : AST_RTP_GLUE_RESULT_FORBID; - - /* Apply any limitations on direct media bridging that may be present */ - if (audio_glue0_res == audio_glue1_res && audio_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) { - if (glue0->allow_rtp_remote && !(glue0->allow_rtp_remote(c0, instance1))) { - /* If the allow_rtp_remote indicates that remote isn't allowed, revert to local bridge */ - audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; - } else if (glue1->allow_rtp_remote && !(glue1->allow_rtp_remote(c1, instance0))) { - audio_glue0_res = audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; - } - } - if (video_glue0_res == video_glue1_res && video_glue1_res == AST_RTP_GLUE_RESULT_REMOTE) { - if (glue0->allow_vrtp_remote && !(glue0->allow_vrtp_remote(c0, instance1))) { - /* if the allow_vrtp_remote indicates that remote isn't allowed, revert to local bridge */ - video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; - } else if (glue1->allow_vrtp_remote && !(glue1->allow_vrtp_remote(c1, instance0))) { - video_glue0_res = video_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; - } - } - - /* If we are carrying video, and both sides are not going to remotely bridge... fail the native bridge */ - if (video_glue0_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue0_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue0_res != AST_RTP_GLUE_RESULT_REMOTE)) { - audio_glue0_res = AST_RTP_GLUE_RESULT_FORBID; - } - if (video_glue1_res != AST_RTP_GLUE_RESULT_FORBID && (audio_glue1_res != AST_RTP_GLUE_RESULT_REMOTE || video_glue1_res != AST_RTP_GLUE_RESULT_REMOTE)) { - audio_glue1_res = AST_RTP_GLUE_RESULT_FORBID; - } - - /* If any sort of bridge is forbidden just completely bail out and go back to generic bridging */ - if (audio_glue0_res == AST_RTP_GLUE_RESULT_FORBID || audio_glue1_res == AST_RTP_GLUE_RESULT_FORBID) { - res = AST_BRIDGE_FAILED_NOWARN; - goto done; - } - - - /* If address families differ, force a local bridge */ - ast_rtp_instance_get_remote_address(instance0, &addr1); - ast_rtp_instance_get_remote_address(instance1, &addr2); - - if (addr1.ss.ss_family != addr2.ss.ss_family || - (ast_sockaddr_is_ipv4_mapped(&addr1) != ast_sockaddr_is_ipv4_mapped(&addr2))) { - audio_glue0_res = AST_RTP_GLUE_RESULT_LOCAL; - audio_glue1_res = AST_RTP_GLUE_RESULT_LOCAL; - } - - /* If we need to get DTMF see if we can do it outside of the RTP stream itself */ - dmode = ast_rtp_instance_dtmf_mode_get(instance0); - if ((flags & AST_BRIDGE_DTMF_CHANNEL_0) && dmode) { - res = AST_BRIDGE_FAILED_NOWARN; - goto done; - } - dmode = ast_rtp_instance_dtmf_mode_get(instance1); - if ((flags & AST_BRIDGE_DTMF_CHANNEL_1) && dmode) { - res = AST_BRIDGE_FAILED_NOWARN; - goto done; - } - - /* If we have gotten to a local bridge make sure that both sides have the same local bridge callback and that they are DTMF compatible */ - if ((audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) - && (instance0->engine->local_bridge != instance1->engine->local_bridge - || (instance0->engine->dtmf_compatible && !instance0->engine->dtmf_compatible(c0, instance0, c1, instance1)))) { - res = AST_BRIDGE_FAILED_NOWARN; - goto done; - } - - /* Make sure that codecs match */ - if (glue0->get_codec){ - glue0->get_codec(c0, cap0); - } - if (glue1->get_codec) { - glue1->get_codec(c1, cap1); - } - if (!ast_format_cap_is_empty(cap0) && !ast_format_cap_is_empty(cap1) && !ast_format_cap_has_joint(cap0, cap1)) { - char tmp0[256] = { 0, }; - char tmp1[256] = { 0, }; - ast_debug(1, "Channel codec0 = %s is not codec1 = %s, cannot native bridge in RTP.\n", - ast_getformatname_multiple(tmp0, sizeof(tmp0), cap0), - ast_getformatname_multiple(tmp1, sizeof(tmp1), cap1)); - res = AST_BRIDGE_FAILED_NOWARN; - goto done; - } - - read_ptime0 = (ast_codec_pref_getsize(&instance0->codecs.pref, ast_channel_rawreadformat(c0))).cur_ms; - read_ptime1 = (ast_codec_pref_getsize(&instance1->codecs.pref, ast_channel_rawreadformat(c1))).cur_ms; - write_ptime0 = (ast_codec_pref_getsize(&instance0->codecs.pref, ast_channel_rawwriteformat(c0))).cur_ms; - write_ptime1 = (ast_codec_pref_getsize(&instance1->codecs.pref, ast_channel_rawwriteformat(c1))).cur_ms; - - if (read_ptime0 != write_ptime1 || read_ptime1 != write_ptime0) { - ast_debug(1, "Packetization differs between RTP streams (%d != %d or %d != %d). Cannot native bridge in RTP\n", - read_ptime0, write_ptime1, read_ptime1, write_ptime0); - res = AST_BRIDGE_FAILED_NOWARN; - goto done; - } - - instance0->glue = glue0; - instance1->glue = glue1; - instance0->chan = c0; - instance1->chan = c1; - - /* Depending on the end result for bridging either do a local bridge or remote bridge */ - if (audio_glue0_res == AST_RTP_GLUE_RESULT_LOCAL || audio_glue1_res == AST_RTP_GLUE_RESULT_LOCAL) { - ast_verb(3, "Locally bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1)); - res = local_bridge_loop(c0, c1, instance0, instance1, timeoutms, flags, fo, rc, ast_channel_tech_pvt(c0), ast_channel_tech_pvt(c1)); - } else { - ast_verb(3, "Remotely bridging %s and %s\n", ast_channel_name(c0), ast_channel_name(c1)); - res = remote_bridge_loop(c0, c1, instance0, instance1, vinstance0, vinstance1, - tinstance0, tinstance1, glue0, glue1, cap0, cap1, timeoutms, flags, - fo, rc, ast_channel_tech_pvt(c0), ast_channel_tech_pvt(c1)); - } - - instance0->glue = NULL; - instance1->glue = NULL; - instance0->chan = NULL; - instance1->chan = NULL; - - unlock_chans = 0; - -done: - if (unlock_chans) { - ast_channel_unlock(c0); - ast_channel_unlock(c1); - } - ast_format_cap_destroy(cap1); - ast_format_cap_destroy(cap0); - - unref_instance_cond(&instance0); - unref_instance_cond(&instance1); - unref_instance_cond(&vinstance0); - unref_instance_cond(&vinstance1); - unref_instance_cond(&tinstance0); - unref_instance_cond(&tinstance1); - - return res; + return instance->bridged; } -struct ast_rtp_instance *ast_rtp_instance_get_bridged(struct ast_rtp_instance *instance) +void ast_rtp_instance_set_bridged(struct ast_rtp_instance *instance, struct ast_rtp_instance *bridged) { - return instance->bridged; + instance->bridged = bridged; } void ast_rtp_instance_early_bridge_make_compatible(struct ast_channel *c0, struct ast_channel *c1) |