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:
parent
53fb7866ab
commit
e915d19e2f
295
channel.c
295
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
20
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[])
|
||||
|
|
Reference in New Issue