From ce7a1e4768c73b8a81805bbc10f7627b3412bd12 Mon Sep 17 00:00:00 2001 From: "Kevin P. Fleming" <kpfleming@digium.com> Date: Tue, 9 Aug 2005 01:59:59 +0000 Subject: [PATCH] bridging code cleanups: code style, formatting use enum/symbolic constants for return codes efficiency improvements (zaptel) only disable DTMF detection once per bridge, not every frame (zaptel) ensure VPM DTMF detector is turned off during native bridge git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6312 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- channel.c | 295 ++++++++++++++++++------------------ channels/chan_iax2.c | 32 ++-- channels/chan_vpb.c | 15 +- channels/chan_zap.c | 300 ++++++++++++++++++++----------------- include/asterisk/channel.h | 11 +- rtp.c | 20 ++- 6 files changed, 353 insertions(+), 320 deletions(-) diff --git a/channel.c b/channel.c index ee076ee3b1..e8b72b3a67 100755 --- a/channel.c +++ b/channel.c @@ -2874,19 +2874,21 @@ static void bridge_playfile(struct ast_channel *chan, struct ast_channel *peer, check = ast_autoservice_stop(peer); } -static int ast_generic_bridge(int *playitagain, int *playit, struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) +static enum ast_bridge_result ast_generic_bridge(int *playitagain, int *playit, struct ast_channel *c0, struct ast_channel *c1, + struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) { - /* Copy voice back and forth between the two channels. Give the peer - the ability to transfer calls with '#<extension' syntax. */ + /* Copy voice back and forth between the two channels. */ struct ast_channel *cs[3]; int to; struct ast_frame *f; struct ast_channel *who = NULL; void *pvt0, *pvt1; - int res=0; + enum ast_bridge_result res = AST_BRIDGE_COMPLETE; int o0nativeformats; int o1nativeformats; long elapsed_ms=0, time_left_ms=0; + int watch_c0_dtmf; + int watch_c1_dtmf; cs[0] = c0; cs[1] = c1; @@ -2894,12 +2896,15 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct ast_channel pvt1 = c1->pvt; o0nativeformats = c0->nativeformats; o1nativeformats = c1->nativeformats; + watch_c0_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_0; + watch_c1_dtmf = config->flags & AST_BRIDGE_DTMF_CHANNEL_1; for (;;) { - if ((c0->pvt != pvt0) || (c1->pvt != pvt1) || (o0nativeformats != c0->nativeformats) || - (o1nativeformats != c1->nativeformats)) { + if ((c0->pvt != pvt0) || (c1->pvt != pvt1) || + (o0nativeformats != c0->nativeformats) || + (o1nativeformats != c1->nativeformats)) { /* Check for Masquerade, codec changes, etc */ - res = -3; + res = AST_BRIDGE_RETRY; break; } /* timestamp */ @@ -2908,25 +2913,27 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct ast_channel elapsed_ms = ast_tvdiff_ms(ast_tvnow(), config->start_time); time_left_ms = config->timelimit - elapsed_ms; - if (*playitagain && ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) || (ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING))) && (config->play_warning && time_left_ms <= config->play_warning)) { + if (*playitagain && + ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) || + (ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING))) && + (config->play_warning && time_left_ms <= config->play_warning)) { if (config->warning_freq == 0 || time_left_ms == config->play_warning || (time_left_ms % config->warning_freq) <= 50) { - res = -3; + res = AST_BRIDGE_RETRY; break; } } if (time_left_ms <= 0) { - res = -3; + res = AST_BRIDGE_RETRY; break; } if (time_left_ms >= 5000 && *playit) { - res = -3; + res = AST_BRIDGE_RETRY; break; } to = time_left_ms; } else to = -1; - who = ast_waitfor_n(cs, 2, &to); if (!who) { ast_log(LOG_DEBUG, "Nobody there, continuing...\n"); @@ -2937,7 +2944,6 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct ast_channel c1->_softhangup = 0; c0->_bridge = c1; c1->_bridge = c0; - continue; } continue; } @@ -2945,7 +2951,7 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct ast_channel if (!f) { *fo = NULL; *rc = who; - res = 0; + res = AST_BRIDGE_COMPLETE; ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name); break; } @@ -2956,40 +2962,27 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct ast_channel } else { *fo = f; *rc = who; - res = 0; + res = AST_BRIDGE_COMPLETE; ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name); break; } } if ((f->frametype == AST_FRAME_VOICE) || - (f->frametype == AST_FRAME_TEXT) || - (f->frametype == AST_FRAME_VIDEO) || - (f->frametype == AST_FRAME_IMAGE) || - (f->frametype == AST_FRAME_HTML) || - (f->frametype == AST_FRAME_DTMF)) { - - if ((f->frametype == AST_FRAME_DTMF) && - (config->flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) { - if ((who == c0)) { - if ((config->flags & AST_BRIDGE_DTMF_CHANNEL_0)) { - *rc = c0; - *fo = f; - /* Take out of conference mode */ - res = 0; - ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_0 on c0 (%s)\n",c0->name); - break; - } else - goto tackygoto; - } else - if ((who == c1)) { - if (config->flags & AST_BRIDGE_DTMF_CHANNEL_1) { - *rc = c1; - *fo = f; - res = 0; - ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_1 on c1 (%s)\n",c1->name); - break; - } else - goto tackygoto; + (f->frametype == AST_FRAME_DTMF) || + (f->frametype == AST_FRAME_VIDEO) || + (f->frametype == AST_FRAME_IMAGE) || + (f->frametype == AST_FRAME_HTML) || + (f->frametype == AST_FRAME_TEXT)) { + if (f->frametype == AST_FRAME_DTMF) { + if (((who == c0) && watch_c0_dtmf) || + ((who == c1) && watch_c1_dtmf)) { + *rc = who; + *fo = f; + res = AST_BRIDGE_COMPLETE; + ast_log(LOG_DEBUG, "Got DTMF on channel (%s)\n", who->name); + break; + } else { + goto tackygoto; } } else { #if 0 @@ -2999,12 +2992,7 @@ static int ast_generic_bridge(int *playitagain, int *playit, struct ast_channel last = who; #endif tackygoto: - /* Don't copy packets if there is a generator on either one, since they're - not supposed to be listening anyway */ - if (who == c0) - ast_write(c1, f); - else - ast_write(c0, f); + ast_write((who == c0) ? c1 : c0, f); } } ast_frfree(f); @@ -3018,37 +3006,20 @@ tackygoto: } /*--- ast_channel_bridge: Bridge two channels together */ -int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) +enum ast_bridge_result ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, + struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc) { - /* Copy voice back and forth between the two channels. Give the peer - the ability to transfer calls with '#<extension' syntax. */ - struct ast_channel *cs[3]; struct ast_channel *who = NULL; - int res=0; + enum ast_bridge_result res = AST_BRIDGE_COMPLETE; int nativefailed=0; int firstpass; int o0nativeformats; int o1nativeformats; long elapsed_ms=0, time_left_ms=0; int playit=0, playitagain=1, first_time=1; + char caller_warning = 0; + char callee_warning = 0; - *fo = NULL; - firstpass = config->firstpass; - config->firstpass = 0; - - /* timestamp */ - if (! (config->start_time.tv_sec && config->start_time.tv_usec)) - config->start_time = ast_tvnow(); - time_left_ms = config->timelimit; - - if ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) && config->start_sound && firstpass) - bridge_playfile(c0,c1,config->start_sound,time_left_ms / 1000); - if ((ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING)) && config->start_sound && firstpass) - bridge_playfile(c1,c0,config->start_sound,time_left_ms / 1000); - - /* Stop if we're a zombie or need a soft hangup */ - if (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) || ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1)) - return -1; if (c0->_bridge) { ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", c0->name, c0->_bridge->name); @@ -3060,49 +3031,68 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct as return -1; } + /* Stop if we're a zombie or need a soft hangup */ + if (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) || + ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1)) + return -1; + + *fo = NULL; + firstpass = config->firstpass; + config->firstpass = 0; + + if (ast_tvzero(config->start_time)) + config->start_time = ast_tvnow(); + time_left_ms = config->timelimit; + + caller_warning = ast_test_flag(&config->features_caller, AST_FEATURE_PLAY_WARNING); + callee_warning = ast_test_flag(&config->features_callee, AST_FEATURE_PLAY_WARNING); + + if (config->start_sound && firstpass) { + if (caller_warning) + bridge_playfile(c0, c1, config->start_sound, time_left_ms / 1000); + if (callee_warning) + bridge_playfile(c1, c0, config->start_sound, time_left_ms / 1000); + } + /* Keep track of bridge */ c0->_bridge = c1; c1->_bridge = c0; - cs[0] = c0; - cs[1] = c1; manager_event(EVENT_FLAG_CALL, "Link", - "Channel1: %s\r\n" - "Channel2: %s\r\n" - "Uniqueid1: %s\r\n" - "Uniqueid2: %s\r\n" - "CallerID1: %s\r\n" - "CallerID2: %s\r\n", - c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); + "Channel1: %s\r\n" + "Channel2: %s\r\n" + "Uniqueid1: %s\r\n" + "Uniqueid2: %s\r\n" + "CallerID1: %s\r\n" + "CallerID2: %s\r\n", + c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); - o1nativeformats = c1->nativeformats; o0nativeformats = c0->nativeformats; + o1nativeformats = c1->nativeformats; + for (/* ever */;;) { - /* timestamp */ if (config->timelimit) { elapsed_ms = ast_tvdiff_ms(ast_tvnow(), config->start_time); time_left_ms = config->timelimit - elapsed_ms; - if (playitagain && ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) || (ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING))) && (config->play_warning && time_left_ms <= config->play_warning)) { + if (playitagain && (caller_warning || callee_warning) && (config->play_warning && time_left_ms <= config->play_warning)) { /* narrowing down to the end */ if (config->warning_freq == 0) { playit = 1; - first_time=0; - playitagain=0; + first_time = 0; + playitagain = 0; } else if (first_time) { playit = 1; - first_time=0; - } else { - if ((time_left_ms % config->warning_freq) <= 50) { - playit = 1; - } + first_time = 0; + } else if ((time_left_ms % config->warning_freq) <= 50) { + playit = 1; } } if (time_left_ms <= 0) { - if ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) && config->end_sound) - bridge_playfile(c0,c1,config->end_sound,0); - if ((ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING)) && config->end_sound) - bridge_playfile(c1,c0,config->end_sound,0); + if (caller_warning && config->end_sound) + bridge_playfile(c0, c1, config->end_sound, 0); + if (callee_warning && config->end_sound) + bridge_playfile(c1, c0, config->end_sound, 0); *fo = NULL; if (who) *rc = who; @@ -3110,13 +3100,12 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct as break; } if (time_left_ms >= 5000 && playit) { - if ((ast_test_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING)) && config->warning_sound && config->play_warning) - bridge_playfile(c0,c1,config->warning_sound,time_left_ms / 1000); - if ((ast_test_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING)) && config->warning_sound && config->play_warning) - bridge_playfile(c1,c0,config->warning_sound,time_left_ms / 1000); + if (caller_warning && config->warning_sound && config->play_warning) + bridge_playfile(c0, c1, config->warning_sound, time_left_ms / 1000); + if (callee_warning && config->warning_sound && config->play_warning) + bridge_playfile(c1, c0, config->warning_sound, time_left_ms / 1000); playit = 0; } - } if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) { @@ -3131,87 +3120,105 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct as } /* Stop if we're a zombie or need a soft hangup */ - if (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) || ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1)) { + if (ast_test_flag(c0, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c0) || + ast_test_flag(c1, AST_FLAG_ZOMBIE) || ast_check_hangup_locked(c1)) { *fo = NULL; if (who) *rc = who; res = 0; - ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",c0->name,c1->name,ast_test_flag(c0, AST_FLAG_ZOMBIE)?"Yes":"No",ast_check_hangup(c0)?"Yes":"No",ast_test_flag(c1, AST_FLAG_ZOMBIE)?"Yes":"No",ast_check_hangup(c1)?"Yes":"No"); + ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n", + c0->name, c1->name, + ast_test_flag(c0, AST_FLAG_ZOMBIE) ? "Yes" : "No", + ast_check_hangup(c0) ? "Yes" : "No", + ast_test_flag(c1, AST_FLAG_ZOMBIE) ? "Yes" : "No", + ast_check_hangup(c1) ? "Yes" : "No"); break; } - if (c0->tech->bridge && config->timelimit==0 && - (c0->tech->bridge == c1->tech->bridge) && !nativefailed && !c0->monitor && !c1->monitor && !c0->spiers && !c1->spiers) { - /* Looks like they share a bridge code */ + + if (c0->tech->bridge && + (config->timelimit == 0) && + (c0->tech->bridge == c1->tech->bridge) && + !nativefailed && !c0->monitor && !c1->monitor && !c0->spiers && !c1->spiers) { + /* Looks like they share a bridge method */ if (option_verbose > 2) ast_verbose(VERBOSE_PREFIX_3 "Attempting native bridge of %s and %s\n", c0->name, c1->name); ast_set_flag(c0, AST_FLAG_NBRIDGE); ast_set_flag(c1, AST_FLAG_NBRIDGE); - if (!(res = c0->tech->bridge(c0, c1, config->flags, fo, rc))) { - c0->_bridge = NULL; - c1->_bridge = NULL; + if ((res = c0->tech->bridge(c0, c1, config->flags, fo, rc)) == AST_BRIDGE_COMPLETE) { manager_event(EVENT_FLAG_CALL, "Unlink", - "Channel1: %s\r\n" - "Channel2: %s\r\n" - "Uniqueid1: %s\r\n" - "Uniqueid2: %s\r\n" - "CallerID1: %s\r\n" - "CallerID2: %s\r\n", - c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); - ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n",c0->name ,c1->name); + "Channel1: %s\r\n" + "Channel2: %s\r\n" + "Uniqueid1: %s\r\n" + "Uniqueid2: %s\r\n" + "CallerID1: %s\r\n" + "CallerID2: %s\r\n", + c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); + ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n", c0->name, c1->name); + ast_clear_flag(c0, AST_FLAG_NBRIDGE); ast_clear_flag(c1, AST_FLAG_NBRIDGE); - if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) { - c0->_bridge = c1; - c1->_bridge = c0; + + if (c0->_softhangup == AST_SOFTHANGUP_UNBRIDGE || c1->_softhangup == AST_SOFTHANGUP_UNBRIDGE) continue; - } - else - return 0; + + c0->_bridge = NULL; + c1->_bridge = NULL; + + return res; } else { ast_clear_flag(c0, AST_FLAG_NBRIDGE); ast_clear_flag(c1, AST_FLAG_NBRIDGE); } - /* If they return non-zero then continue on normally. Let "-2" mean don't worry about - my not wanting to bridge */ - if ((res != -2) && (res != -3)) + switch (res) { + case AST_BRIDGE_RETRY: + continue; + default: ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name); - if (res != -3) + /* fallthrough */ + case AST_BRIDGE_FAILED_NOWARN: nativefailed++; + break; + } } - if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) || (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) && - !(c0->generator || c1->generator)) { + if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) || + (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) && + !(c0->generator || c1->generator)) { if (ast_channel_make_compatible(c0, c1)) { ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name); manager_event(EVENT_FLAG_CALL, "Unlink", - "Channel1: %s\r\n" - "Channel2: %s\r\n" - "Uniqueid1: %s\r\n" - "Uniqueid2: %s\r\n" - "CallerID1: %s\r\n" - "CallerID2: %s\r\n", - c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); - return -1; + "Channel1: %s\r\n" + "Channel2: %s\r\n" + "Uniqueid1: %s\r\n" + "Uniqueid2: %s\r\n" + "CallerID1: %s\r\n" + "CallerID2: %s\r\n", + c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); + return AST_BRIDGE_FAILED; } o0nativeformats = c0->nativeformats; o1nativeformats = c1->nativeformats; } + res = ast_generic_bridge(&playitagain, &playit, c0, c1, config, fo, rc); - if (res != -3) + if (res != AST_BRIDGE_RETRY) break; } + c0->_bridge = NULL; c1->_bridge = NULL; + manager_event(EVENT_FLAG_CALL, "Unlink", - "Channel1: %s\r\n" - "Channel2: %s\r\n" - "Uniqueid1: %s\r\n" - "Uniqueid2: %s\r\n" - "CallerID1: %s\r\n" - "CallerID2: %s\r\n", - c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); - ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n",c0->name,c1->name); + "Channel1: %s\r\n" + "Channel2: %s\r\n" + "Uniqueid1: %s\r\n" + "Uniqueid2: %s\r\n" + "CallerID1: %s\r\n" + "CallerID2: %s\r\n", + c0->name, c1->name, c0->uniqueid, c1->uniqueid, c0->cid.cid_num, c1->cid.cid_num); + ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n", c0->name, c1->name); + return res; } diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index cfa62bb549..9c12b29f58 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -708,7 +708,7 @@ static struct ast_frame *iax2_read(struct ast_channel *c); static int iax2_write(struct ast_channel *c, struct ast_frame *f); static int iax2_indicate(struct ast_channel *c, int condition); static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen); -static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); +static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); static int iax2_transfer(struct ast_channel *c, const char *dest); static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan); @@ -3050,7 +3050,7 @@ static void unlock_both(unsigned short callno0, unsigned short callno1) ast_mutex_unlock(&iaxsl[callno0]); } -static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) +static enum ast_bridge_result iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) { struct ast_channel *cs[3]; struct ast_channel *who; @@ -3089,7 +3089,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags iaxs[callno1]->bridgecallno = 0; ast_mutex_unlock(&iaxsl[callno1]); } - return -2; + return AST_BRIDGE_FAILED_NOWARN; } if (c0->nativeformats != c1->nativeformats) { if (option_verbose > 2) { @@ -3104,7 +3104,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags iaxs[callno0]->bridgecallno = 0; iaxs[callno1]->bridgecallno = 0; unlock_both(callno0, callno1); - return -2; + return AST_BRIDGE_FAILED_NOWARN; } /* check if transfered and if we really want native bridging */ if (!transferstarted && !ast_test_flag(iaxs[callno0], IAX_NOTRANSFER) && !ast_test_flag(iaxs[callno1], IAX_NOTRANSFER) && @@ -3124,7 +3124,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags c1->_softhangup |= AST_SOFTHANGUP_DEV; *fo = NULL; *rc = c0; - res = 0; + res = AST_BRIDGE_COMPLETE; break; } } @@ -3132,7 +3132,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags who = ast_waitfor_n(cs, 2, &to); if (!who) { if (ast_check_hangup(c0) || ast_check_hangup(c1)) { - res = -1; + res = AST_BRIDGE_FAILED; break; } continue; @@ -3141,28 +3141,27 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags if (!f) { *fo = NULL; *rc = who; - res = 0; + res = AST_BRIDGE_COMPLETE; break; } if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) { *fo = f; *rc = who; - res = 0; + res = AST_BRIDGE_COMPLETE; break; } if ((f->frametype == AST_FRAME_VOICE) || - (f->frametype == AST_FRAME_TEXT) || - (f->frametype == AST_FRAME_VIDEO) || - (f->frametype == AST_FRAME_IMAGE) || - (f->frametype == AST_FRAME_DTMF)) { + (f->frametype == AST_FRAME_TEXT) || + (f->frametype == AST_FRAME_VIDEO) || + (f->frametype == AST_FRAME_IMAGE) || + (f->frametype == AST_FRAME_DTMF)) { if ((f->frametype == AST_FRAME_DTMF) && - (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) { + (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) { if ((who == c0)) { if ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) { *rc = c0; *fo = f; - /* Take out of conference mode */ - res = 0; + res = AST_BRIDGE_COMPLETE; /* Remove from native mode */ break; } else @@ -3172,8 +3171,7 @@ static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags if (flags & AST_BRIDGE_DTMF_CHANNEL_1) { *rc = c1; *fo = f; - res = 0; - /* Remove from native mode */ + res = AST_BRIDGE_COMPLETE; break; } else goto tackygoto; diff --git a/channels/chan_vpb.c b/channels/chan_vpb.c index 6289629ebd..be60049924 100755 --- a/channels/chan_vpb.c +++ b/channels/chan_vpb.c @@ -326,7 +326,7 @@ static int vpb_hangup(struct ast_channel *ast); static int vpb_answer(struct ast_channel *ast); static struct ast_frame *vpb_read(struct ast_channel *ast); static int vpb_write(struct ast_channel *ast, struct ast_frame *frame); -static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); +static enum ast_bridge_result vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); static int vpb_indicate(struct ast_channel *ast, int condition); static int vpb_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); @@ -396,11 +396,12 @@ static struct ast_channel_tech vpb_tech_indicate = { /* #define HALF_DUPLEX_BRIDGE */ /* This is the Native bridge code, which Asterisk will try before using its own bridging code */ -static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) +static enum ast_bridge_result vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) { struct vpb_pvt *p0 = (struct vpb_pvt *)c0->tech_pvt; struct vpb_pvt *p1 = (struct vpb_pvt *)c1->tech_pvt; - int i, res; + int i; + enum ast_bridge_result res; struct ast_channel *cs[3]; struct ast_channel *who; @@ -412,10 +413,10 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, #ifdef BAD_V4PCI_BRIDGE if(p0->vpb_model==vpb_model_v4pci) - return -2; + return AST_BRIDGE_FAILED_NOWARN; #endif if ( UseNativeBridge != 1){ - return -2; + return AST_BRIDGE_FAILED_NOWARN; } /* @@ -444,7 +445,7 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, ast_log(LOG_WARNING, "%s: vpb_bridge: Failed to bridge %s and %s!\n", p0->dev, c0->name, c1->name); ast_mutex_unlock(&p0->lock); ast_mutex_unlock(&p1->lock); - return -2; + return AST_BRIDGE_FAILED_NOWARN; } else { /* Set bridge pointers. You don't want to take these locks while holding bridge lock.*/ ast_mutex_lock(&p0->lock); { @@ -581,7 +582,7 @@ static int vpb_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, ast_mutex_unlock(&p0->lock); ast_mutex_unlock(&p1->lock); */ - return (res==VPB_OK)?0:-1; + return (res==VPB_OK) ? AST_BRIDGE_COMPLETE : AST_BRIDGE_FAILED; } /* Caller ID can be located in different positions between the rings depending on your Telco diff --git a/channels/chan_zap.c b/channels/chan_zap.c index 0874a31181..b352a1fa64 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -323,7 +323,7 @@ static pthread_t monitor_thread = AST_PTHREADT_NULL; static int restart_monitor(void); -static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); +static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); static int zt_sendtext(struct ast_channel *c, const char *text); @@ -664,7 +664,6 @@ static int zt_hangup(struct ast_channel *ast); static int zt_answer(struct ast_channel *ast); struct ast_frame *zt_read(struct ast_channel *ast); static int zt_write(struct ast_channel *ast, struct ast_frame *frame); -static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); struct ast_frame *zt_exception(struct ast_channel *ast); static int zt_indicate(struct ast_channel *chan, int condition); static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); @@ -2775,29 +2774,59 @@ static void zt_link(struct zt_pvt *slave, struct zt_pvt *master) { ast_log(LOG_DEBUG, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x); } -static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) +static void disable_dtmf_detect(struct zt_pvt *p) { - struct ast_channel *who = NULL, *cs[3]; + int val; + + p->ignoredtmf = 1; + +#ifdef ZT_TONEDETECT + val = 0; + ioctl(p->subs[SUB_REAL].zfd, ZT_TONEDETECT, &val); +#endif + +} + +static void enable_dtmf_detect(struct zt_pvt *p) +{ + int val; + + p->ignoredtmf = 0; + +#ifdef ZT_TONEDETECT + val = ZT_TONEDETECT_ON | ZT_TONEDETECT_MUTE; + ioctl(p->subs[SUB_REAL].zfd, ZT_TONEDETECT, &val); +#endif +} + +static enum ast_bridge_result zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) +{ + struct ast_channel *who; struct zt_pvt *p0, *p1, *op0, *op1; - struct zt_pvt *master=NULL, *slave=NULL; + struct zt_pvt *master = NULL, *slave = NULL; struct ast_frame *f; int to; int inconf = 0; - int nothingok = 0; - int ofd1, ofd2; - int oi1, oi2, i1 = -1, i2 = -1, t1, t2; - int os1 = -1, os2 = -1; - struct ast_channel *oc1, *oc2; + int nothingok = 1; + int ofd0, ofd1; + int oi0, oi1, i0 = -1, i1 = -1, t0, t1; + int os0 = -1, os1 = -1; + struct ast_channel *oc0, *oc1; + enum ast_bridge_result res; + #ifdef PRI_2BCT int triedtopribridge = 0; q931_call *q931c0 = NULL, *q931c1 = NULL; #endif + /* For now, don't attempt to native bridge if either channel needs DTMF detection. + There is code below to handle it properly until DTMF is actually seen, + but due to currently unresolved issues it's ignored... + */ - /* if need DTMF, cant native bridge */ if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) - return -2; - + return AST_BRIDGE_FAILED_NOWARN; + ast_mutex_lock(&c0->lock); ast_mutex_lock(&c1->lock); @@ -2807,24 +2836,23 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) { ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); - return -2; + return AST_BRIDGE_FAILED_NOWARN; } - op0 = p0 = c0->tech_pvt; - op1 = p1 = c1->tech_pvt; - ofd1 = c0->fds[0]; - ofd2 = c1->fds[0]; - oi1 = zt_get_index(c0, p0, 0); - oi2 = zt_get_index(c1, p1, 0); - oc1 = p0->owner; - oc2 = p1->owner; - if ((oi1 < 0) || (oi2 < 0)) { + oi0 = zt_get_index(c0, p0, 0); + oi1 = zt_get_index(c1, p1, 0); + if ((oi0 < 0) || (oi1 < 0)) { ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); - return -1; + return AST_BRIDGE_FAILED; } - + op0 = p0 = c0->tech_pvt; + op1 = p1 = c1->tech_pvt; + ofd0 = c0->fds[0]; + ofd1 = c1->fds[0]; + oc0 = p0->owner; + oc1 = p1->owner; ast_mutex_lock(&p0->lock); if (ast_mutex_trylock(&p1->lock)) { @@ -2833,13 +2861,11 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); ast_log(LOG_NOTICE, "Avoiding deadlock...\n"); - return -3; + return AST_BRIDGE_RETRY; } - if ((oi1 == SUB_REAL) && (oi2 == SUB_REAL)) { - if (!p0->owner || !p1->owner) { - /* Currently unowned -- Do nothing. */ - nothingok = 1; - } else { + + if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) { + if (p0->owner && p1->owner) { /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */ if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) { master = p0; @@ -2851,40 +2877,41 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, inconf = 1; } else { ast_log(LOG_WARNING, "Huh? Both calls are callwaits or 3-ways? That's clever...?\n"); - ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n", p0->channel, oi1, (p0->subs[SUB_CALLWAIT].zfd > -1) ? 1 : 0, p0->subs[SUB_REAL].inthreeway, - p0->channel, oi1, (p1->subs[SUB_CALLWAIT].zfd > -1) ? 1 : 0, p1->subs[SUB_REAL].inthreeway); + ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n", + p0->channel, + oi0, (p0->subs[SUB_CALLWAIT].zfd > -1) ? 1 : 0, + p0->subs[SUB_REAL].inthreeway, p0->channel, + oi0, (p1->subs[SUB_CALLWAIT].zfd > -1) ? 1 : 0, + p1->subs[SUB_REAL].inthreeway); } + nothingok = 0; } - } else if ((oi1 == SUB_REAL) && (oi2 == SUB_THREEWAY)) { + } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) { if (p1->subs[SUB_THREEWAY].inthreeway) { master = p1; slave = p0; - } else { - nothingok = 1; + nothingok = 0; } - } else if ((oi1 == SUB_THREEWAY) && (oi2 == SUB_REAL)) { + } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) { if (p0->subs[SUB_THREEWAY].inthreeway) { master = p0; slave = p1; - } else { - nothingok = 1; + nothingok = 0; } - } else if ((oi1 == SUB_REAL) && (oi2 == SUB_CALLWAIT)) { + } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) { /* We have a real and a call wait. If we're in a three way call, put us in it, otherwise, don't put us in anything */ if (p1->subs[SUB_CALLWAIT].inthreeway) { master = p1; slave = p0; - } else { - nothingok = 1; + nothingok = 0; } - } else if ((oi1 == SUB_CALLWAIT) && (oi2 == SUB_REAL)) { + } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) { /* Same as previous */ if (p0->subs[SUB_CALLWAIT].inthreeway) { master = p0; slave = p1; - } else { - nothingok = 1; + nothingok = 0; } } ast_log(LOG_DEBUG, "master: %d, slave: %d, nothingok: %d\n", @@ -2893,31 +2920,31 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, /* Stop any tones, or play ringtone as appropriate. If they're bridged in an active threeway call with a channel that is ringing, we should indicate ringing. */ - if ((oi2 == SUB_THREEWAY) && - p1->subs[SUB_THREEWAY].inthreeway && - p1->subs[SUB_REAL].owner && - p1->subs[SUB_REAL].inthreeway && - (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { - ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name); - tone_zone_play_tone(p0->subs[oi1].zfd, ZT_TONE_RINGTONE); - os2 = p1->subs[SUB_REAL].owner->_state; - } else { - ast_log(LOG_DEBUG, "Stoping tones on %d/%d talking to %d/%d\n", p0->channel, oi1, p1->channel, oi2); - tone_zone_play_tone(p0->subs[oi1].zfd, -1); - } if ((oi1 == SUB_THREEWAY) && - p0->subs[SUB_THREEWAY].inthreeway && - p0->subs[SUB_REAL].owner && - p0->subs[SUB_REAL].inthreeway && - (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { - ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name); - tone_zone_play_tone(p1->subs[oi2].zfd, ZT_TONE_RINGTONE); - os1 = p0->subs[SUB_REAL].owner->_state; + p1->subs[SUB_THREEWAY].inthreeway && + p1->subs[SUB_REAL].owner && + p1->subs[SUB_REAL].inthreeway && + (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { + ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name); + tone_zone_play_tone(p0->subs[oi0].zfd, ZT_TONE_RINGTONE); + os1 = p1->subs[SUB_REAL].owner->_state; + } else { + ast_log(LOG_DEBUG, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1); + tone_zone_play_tone(p0->subs[oi0].zfd, -1); + } + if ((oi0 == SUB_THREEWAY) && + p0->subs[SUB_THREEWAY].inthreeway && + p0->subs[SUB_REAL].owner && + p0->subs[SUB_REAL].inthreeway && + (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) { + ast_log(LOG_DEBUG, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name); + tone_zone_play_tone(p1->subs[oi1].zfd, ZT_TONE_RINGTONE); + os0 = p0->subs[SUB_REAL].owner->_state; } else { - ast_log(LOG_DEBUG, "Stoping tones on %d/%d talking to %d/%d\n", p1->channel, oi2, p0->channel, oi1); - tone_zone_play_tone(p1->subs[oi1].zfd, -1); + ast_log(LOG_DEBUG, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0); + tone_zone_play_tone(p1->subs[oi0].zfd, -1); } - if ((oi1 == SUB_REAL) && (oi2 == SUB_REAL)) { + if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) { if (!p0->echocanbridged || !p1->echocanbridged) { /* Disable echo cancellation if appropriate */ zt_disable_ec(p0); @@ -2927,12 +2954,12 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, zt_link(slave, master); master->inconference = inconf; } else if (!nothingok) - ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi1], p1->channel, subnames[oi2]); + ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]); update_conf(p0); update_conf(p1); - t1 = p0->subs[SUB_REAL].inthreeway; - t2 = p1->subs[SUB_REAL].inthreeway; + t0 = p0->subs[SUB_REAL].inthreeway; + t1 = p1->subs[SUB_REAL].inthreeway; ast_mutex_unlock(&p0->lock); ast_mutex_unlock(&p1->lock); @@ -2942,17 +2969,22 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, /* Native bridge failed */ if ((!master || !slave) && !nothingok) { - if (op0 == p0) - zt_enable_ec(p0); - if (op1 == p1) - zt_enable_ec(p1); - return -1; + zt_enable_ec(p0); + zt_enable_ec(p1); + return AST_BRIDGE_FAILED; } - cs[0] = c0; - cs[1] = c1; - cs[2] = NULL; + if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) + disable_dtmf_detect(op0); + + if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) + disable_dtmf_detect(op1); + for (;;) { + struct ast_channel *c0_priority[2] = {c0, c1}; + struct ast_channel *c1_priority[2] = {c1, c0}; + int priority = 0; + /* Here's our main loop... Start by locking things, looking for private parts, and then balking if anything is wrong */ ast_mutex_lock(&c0->lock); @@ -2964,94 +2996,84 @@ static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, q931c0 = p0->call; q931c1 = p1->call; if (p0->transfer && p1->transfer - && q931c0 && q931c1 - && !triedtopribridge) { - + && q931c0 && q931c1 + && !triedtopribridge) { pri_channel_bridge(q931c0, q931c1); triedtopribridge = 1; } #endif + if (op0 == p0) - i1 = zt_get_index(c0, p0, 1); + i0 = zt_get_index(c0, p0, 1); if (op1 == p1) - i2 = zt_get_index(c1, p1, 1); + i1 = zt_get_index(c1, p1, 1); ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); - if ((op0 != p0) || (op1 != p1) || - (ofd1 != c0->fds[0]) || - (ofd2 != c1->fds[0]) || - (p0->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p0->subs[SUB_REAL].owner->_state)) || - (p1->subs[SUB_REAL].owner && (os2 > -1) && (os2 != p1->subs[SUB_REAL].owner->_state)) || - (oc1 != p0->owner) || - (oc2 != p1->owner) || - (t1 != p0->subs[SUB_REAL].inthreeway) || - (t2 != p1->subs[SUB_REAL].inthreeway) || - (oi1 != i1) || - (oi2 != i2)) { - if (slave && master) - zt_unlink(slave, master, 1); + + if ((op0 != p0) || + (op1 != p1) || + (ofd0 != c0->fds[0]) || + (ofd1 != c1->fds[0]) || + (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) || + (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) || + (oc0 != p0->owner) || + (oc1 != p1->owner) || + (t0 != p0->subs[SUB_REAL].inthreeway) || + (t1 != p1->subs[SUB_REAL].inthreeway) || + (oi0 != i0) || + (oi1 != i0)) { ast_log(LOG_DEBUG, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n", - op0->channel, oi1, op1->channel, oi2); - if (op0 == p0) - zt_enable_ec(p0); - if (op1 == p1) - zt_enable_ec(p1); - return -3; + op0->channel, oi0, op1->channel, oi1); + res = AST_BRIDGE_RETRY; + goto return_from_bridge; } to = -1; - who = ast_waitfor_n(cs, 2, &to); + who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &to); if (!who) { ast_log(LOG_DEBUG, "Ooh, empty read...\n"); continue; } - if (who->tech_pvt == op0) - op0->ignoredtmf = 1; - else if (who->tech_pvt == op1) - op1->ignoredtmf = 1; f = ast_read(who); - if (who->tech_pvt == op0) - op0->ignoredtmf = 0; - else if (who->tech_pvt == op1) - op1->ignoredtmf = 0; - if (!f) { - *fo = NULL; - *rc = who; - if (slave && master) - zt_unlink(slave, master, 1); - if (op0 == p0) - zt_enable_ec(p0); - if (op1 == p1) - zt_enable_ec(p1); - return 0; - } - if (f->frametype == AST_FRAME_CONTROL) { + if (!f || (f->frametype == AST_FRAME_CONTROL)) { *fo = f; *rc = who; - if (slave && master) - zt_unlink(slave, master, 1); - return 0; + res = AST_BRIDGE_COMPLETE; + goto return_from_bridge; } if (f->frametype == AST_FRAME_DTMF) { - if (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) || - ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))) { - *fo = f; - *rc = who; - if (slave && master) - zt_unlink(slave, master, 1); - return 0; - } else if ((who == c0) && p0->pulsedial) { + if ((who == c0) && p0->pulsedial) { ast_write(c1, f); - } else if ((who == c1) && p1->pulsedial) { + } else if (p1->pulsedial) { ast_write(c0, f); + } else { + *fo = f; + *rc = who; + res = AST_BRIDGE_COMPLETE; + goto return_from_bridge; } } ast_frfree(f); - + /* Swap who gets priority */ - cs[2] = cs[0]; - cs[0] = cs[1]; - cs[1] = cs[2]; + priority = !priority; } + +return_from_bridge: + if (op0 == p0) + zt_enable_ec(p0); + + if (op1 == p1) + zt_enable_ec(p1); + + if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0)) + enable_dtmf_detect(op0); + + if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1)) + enable_dtmf_detect(op1); + + zt_unlink(slave, master, 1); + + return res; } static int zt_fixup(struct ast_channel *oldchan, struct ast_channel *newchan) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index de2099288b..cd45cb1a3e 100755 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -53,6 +53,13 @@ extern "C" { #define AST_MAX_FDS 8 +enum ast_bridge_result { + AST_BRIDGE_COMPLETE = 0, + AST_BRIDGE_FAILED = -1, + AST_BRIDGE_FAILED_NOWARN = -2, + AST_BRIDGE_RETRY = -3, +}; + typedef unsigned long long ast_group_t; struct ast_generator { @@ -130,8 +137,8 @@ struct ast_channel_tech { struct ast_frame * (* const exception)(struct ast_channel *chan); /*! Bridge two channels of the same type together */ - int (* const bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags, - struct ast_frame **fo, struct ast_channel **rc); + enum ast_bridge_result (* const bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags, + struct ast_frame **fo, struct ast_channel **rc); /*! Indicate a particular condition (e.g. AST_CONTROL_BUSY or AST_CONTROL_RINGING or AST_CONTROL_CONGESTION */ int (* const indicate)(struct ast_channel *c, int condition); diff --git a/rtp.c b/rtp.c index 31f98a5cde..642a821ad3 100755 --- a/rtp.c +++ b/rtp.c @@ -1425,7 +1425,7 @@ static struct ast_rtp_protocol *get_proto(struct ast_channel *chan) /* ast_rtp_bridge: Bridge calls. If possible and allowed, initiate re-invite so the peers exchange media directly outside of Asterisk. */ -int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) +enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) { struct ast_frame *f; struct ast_channel *who, *cs[3]; @@ -1449,7 +1449,7 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st /* if need DTMF, cant native bridge */ if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) - return -2; + return AST_BRIDGE_FAILED_NOWARN; /* Lock channels */ ast_mutex_lock(&c0->lock); @@ -1466,13 +1466,13 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name); ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); - return -1; + return AST_BRIDGE_FAILED; } if (!pr1) { ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name); ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); - return -1; + return AST_BRIDGE_FAILED; } /* Get channel specific interface structures */ @@ -1496,7 +1496,7 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st /* Somebody doesn't want to play... */ ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); - return -2; + return AST_BRIDGE_FAILED_NOWARN; } /* Get codecs from both sides */ if (pr0->get_codec) @@ -1514,7 +1514,7 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st ast_log(LOG_DEBUG, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1); ast_mutex_unlock(&c0->lock); ast_mutex_unlock(&c1->lock); - return -2; + return AST_BRIDGE_FAILED_NOWARN; } } @@ -1559,8 +1559,7 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st if (pr1->set_rtp_peer(c1, NULL, NULL, 0)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); } - /* Tell it to try again later */ - return -3; + return AST_BRIDGE_RETRY; } to = -1; /* Now check if they have changed address */ @@ -1629,8 +1628,7 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st if (pr1->set_rtp_peer(c1, NULL, NULL, 0)) ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name); } - /* That's all we needed */ - return 0; + return AST_BRIDGE_COMPLETE; } else { if ((f->frametype == AST_FRAME_DTMF) || (f->frametype == AST_FRAME_VOICE) || @@ -1650,7 +1648,7 @@ int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, st cs[1] = cs[2]; } - return -1; + return AST_BRIDGE_FAILED; } static int rtp_do_debug_ip(int fd, int argc, char *argv[]) -- GitLab