dect
/
asterisk
Archived
13
0
Fork 0

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: http://svn.digium.com/svn/asterisk/trunk@6312 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
kpfleming 2005-08-09 01:59:59 +00:00
parent 53fb7866ab
commit e915d19e2f
6 changed files with 355 additions and 322 deletions

295
channel.c
View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;
}
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 AST_BRIDGE_FAILED;
}
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)) {
ast_mutex_unlock(&c0->lock);
ast_mutex_unlock(&c1->lock);
return -1;
}
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, "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", p0->channel, oi0, p1->channel, oi1);
tone_zone_play_tone(p0->subs[oi0].zfd, -1);
}
if ((oi1 == SUB_REAL) && (oi2 == SUB_REAL)) {
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, "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 ((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))) {
if ((who == c0) && p0->pulsedial) {
ast_write(c1, f);
} else if (p1->pulsedial) {
ast_write(c0, f);
} else {
*fo = f;
*rc = who;
if (slave && master)
zt_unlink(slave, master, 1);
return 0;
} else if ((who == c0) && p0->pulsedial) {
ast_write(c1, f);
} else if ((who == c1) && p1->pulsedial) {
ast_write(c0, f);
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)

View File

@ -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);

20
rtp.c
View File

@ -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[])