mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-26 14:27:14 +00:00
Adding Realtime Text support (T.140) to Asterisk
T.140/RFC 2793 is a live communication channel, originally created for IP based text phones for hearing impaired. Feels very much like the old Unix talk application. This code is developed and disclaimed by John Martin of Aupix, UK. Tested for interoperability by myself and Omnitor in Sweden, the company that wrote most of the specifications. A big thank you to everyone involved in this. git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@54838 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
118
main/rtp.c
118
main/rtp.c
@@ -118,6 +118,8 @@ struct ast_rtp {
|
||||
unsigned int lastrxts;
|
||||
unsigned int lastividtimestamp;
|
||||
unsigned int lastovidtimestamp;
|
||||
unsigned int lastitexttimestamp;
|
||||
unsigned int lastotexttimestamp;
|
||||
unsigned int lasteventseqn;
|
||||
int lastrxseqno; /*!< Last received sequence number */
|
||||
unsigned short seedrxseqno; /*!< What sequence number did they start with?*/
|
||||
@@ -1333,7 +1335,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
return f ? f : &ast_null_frame;
|
||||
}
|
||||
rtp->lastrxformat = rtp->f.subclass = rtpPT.code;
|
||||
rtp->f.frametype = (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) ? AST_FRAME_VOICE : AST_FRAME_VIDEO;
|
||||
rtp->f.frametype = (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) ? AST_FRAME_VOICE : (rtp->f.subclass < AST_FORMAT_MAX_VIDEO) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;
|
||||
|
||||
if (!rtp->lastrxts)
|
||||
rtp->lastrxts = timestamp;
|
||||
@@ -1357,7 +1359,7 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
rtp->f.ts = timestamp / 8;
|
||||
rtp->f.len = rtp->f.samples / 8;
|
||||
rtp->f.seqno = seqno;
|
||||
} else {
|
||||
} else if(rtp->f.subclass < AST_FORMAT_MAX_VIDEO) {
|
||||
/* Video -- samples is # of samples vs. 90000 */
|
||||
if (!rtp->lastividtimestamp)
|
||||
rtp->lastividtimestamp = timestamp;
|
||||
@@ -1367,7 +1369,14 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp)
|
||||
rtp->f.delivery.tv_usec = 0;
|
||||
if (mark)
|
||||
rtp->f.subclass |= 0x1;
|
||||
|
||||
} else {
|
||||
/* TEXT -- samples is # of samples vs. 1000 */
|
||||
if (!rtp->lastitexttimestamp)
|
||||
rtp->lastitexttimestamp = timestamp;
|
||||
rtp->f.samples = timestamp - rtp->lastitexttimestamp;
|
||||
rtp->lastitexttimestamp = timestamp;
|
||||
rtp->f.delivery.tv_sec = 0;
|
||||
rtp->f.delivery.tv_usec = 0;
|
||||
}
|
||||
rtp->f.src = "RTP";
|
||||
return &rtp->f;
|
||||
@@ -1524,9 +1533,10 @@ int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
|
||||
// dest = c0, src = c1
|
||||
struct ast_rtp *destp = NULL, *srcp = NULL; /* Audio RTP Channels */
|
||||
struct ast_rtp *vdestp = NULL, *vsrcp = NULL; /* Video RTP channels */
|
||||
struct ast_rtp *tdestp = NULL, *tsrcp = NULL; /* Text RTP channels */
|
||||
struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
|
||||
enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED, text_dest_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED, text_src_res = AST_RTP_GET_FAILED;
|
||||
int srccodec, nat_active = 0;
|
||||
|
||||
/* Lock channels */
|
||||
@@ -1560,12 +1570,14 @@ int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get audio and video interface (if native bridge is possible) */
|
||||
/* Get audio, video and text interface (if native bridge is possible) */
|
||||
audio_dest_res = destpr->get_rtp_info(c0, &destp);
|
||||
video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(c0, &vdestp) : AST_RTP_GET_FAILED;
|
||||
text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(c0, &tdestp) : AST_RTP_GET_FAILED;
|
||||
if (srcpr) {
|
||||
audio_src_res = srcpr->get_rtp_info(c1, &srcp);
|
||||
video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(c1, &vsrcp) : AST_RTP_GET_FAILED;
|
||||
text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(c1, &tsrcp) : AST_RTP_GET_FAILED;
|
||||
}
|
||||
|
||||
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
|
||||
@@ -1586,7 +1598,7 @@ int ast_rtp_early_bridge(struct ast_channel *c0, struct ast_channel *c1)
|
||||
if (srcp && (srcp->nat || ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
|
||||
nat_active = 1;
|
||||
/* Bridge media early */
|
||||
if (destpr->set_rtp_peer(c0, srcp, vsrcp, srccodec, nat_active))
|
||||
if (destpr->set_rtp_peer(c0, srcp, vsrcp, tsrcp, srccodec, nat_active))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
|
||||
ast_channel_unlock(c0);
|
||||
if (c1)
|
||||
@@ -1600,9 +1612,10 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i
|
||||
{
|
||||
struct ast_rtp *destp = NULL, *srcp = NULL; /* Audio RTP Channels */
|
||||
struct ast_rtp *vdestp = NULL, *vsrcp = NULL; /* Video RTP channels */
|
||||
struct ast_rtp *tdestp = NULL, *tsrcp = NULL; /* Text RTP channels */
|
||||
struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
|
||||
enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED, video_dest_res = AST_RTP_GET_FAILED, text_dest_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED, video_src_res = AST_RTP_GET_FAILED, text_src_res = AST_RTP_GET_FAILED;
|
||||
int srccodec;
|
||||
|
||||
/* Lock channels */
|
||||
@@ -1632,8 +1645,10 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i
|
||||
/* Get audio and video interface (if native bridge is possible) */
|
||||
audio_dest_res = destpr->get_rtp_info(dest, &destp);
|
||||
video_dest_res = destpr->get_vrtp_info ? destpr->get_vrtp_info(dest, &vdestp) : AST_RTP_GET_FAILED;
|
||||
text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(dest, &tdestp) : AST_RTP_GET_FAILED;
|
||||
audio_src_res = srcpr->get_rtp_info(src, &srcp);
|
||||
video_src_res = srcpr->get_vrtp_info ? srcpr->get_vrtp_info(src, &vsrcp) : AST_RTP_GET_FAILED;
|
||||
text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(src, &tsrcp) : AST_RTP_GET_FAILED;
|
||||
|
||||
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
|
||||
if (audio_dest_res != AST_RTP_TRY_NATIVE || audio_src_res != AST_RTP_TRY_NATIVE) {
|
||||
@@ -1645,13 +1660,15 @@ int ast_rtp_make_compatible(struct ast_channel *dest, struct ast_channel *src, i
|
||||
ast_rtp_pt_copy(destp, srcp);
|
||||
if (vdestp && vsrcp)
|
||||
ast_rtp_pt_copy(vdestp, vsrcp);
|
||||
if (tdestp && tsrcp)
|
||||
ast_rtp_pt_copy(tdestp, tsrcp);
|
||||
if (srcpr->get_codec)
|
||||
srccodec = srcpr->get_codec(src);
|
||||
else
|
||||
srccodec = 0;
|
||||
if (media) {
|
||||
/* Bridge early */
|
||||
if (destpr->set_rtp_peer(dest, srcp, vsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
|
||||
if (destpr->set_rtp_peer(dest, srcp, vsrcp, tsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src->name);
|
||||
}
|
||||
ast_channel_unlock(dest);
|
||||
@@ -2080,6 +2097,8 @@ void ast_rtp_reset(struct ast_rtp *rtp)
|
||||
rtp->lastrxts = 0;
|
||||
rtp->lastividtimestamp = 0;
|
||||
rtp->lastovidtimestamp = 0;
|
||||
rtp->lastitexttimestamp = 0;
|
||||
rtp->lastotexttimestamp = 0;
|
||||
rtp->lasteventseqn = 0;
|
||||
rtp->lasteventendseqn = 0;
|
||||
rtp->lasttxformat = 0;
|
||||
@@ -2627,7 +2646,7 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
|
||||
mark = 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else if(f->subclass < AST_FORMAT_MAX_VIDEO) {
|
||||
mark = f->subclass & 0x1;
|
||||
pred = rtp->lastovidtimestamp + f->samples;
|
||||
/* Re-calculate last TS */
|
||||
@@ -2643,6 +2662,21 @@ static int ast_rtp_raw_write(struct ast_rtp *rtp, struct ast_frame *f, int codec
|
||||
rtp->lastovidtimestamp = rtp->lastts;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
pred = rtp->lastotexttimestamp + f->samples;
|
||||
/* Re-calculate last TS */
|
||||
rtp->lastts = rtp->lastts + ms * 90;
|
||||
/* If it's close to our prediction, go for it */
|
||||
if (ast_tvzero(f->delivery)) {
|
||||
if (abs(rtp->lastts - pred) < 7200) {
|
||||
rtp->lastts = pred;
|
||||
rtp->lastotexttimestamp += f->samples;
|
||||
} else {
|
||||
if (option_debug > 2)
|
||||
ast_log(LOG_DEBUG, "Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, ms * 90, rtp->lastts, pred, f->samples);
|
||||
rtp->lastotexttimestamp = rtp->lastts;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* If the timestamp for non-digit packets has moved beyond the timestamp
|
||||
for digits, update the digit timestamp.
|
||||
@@ -2736,11 +2770,12 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f)
|
||||
return 0;
|
||||
|
||||
/* Make sure we have enough space for RTP header */
|
||||
if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO)) {
|
||||
ast_log(LOG_WARNING, "RTP can only send voice and video\n");
|
||||
if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO) && (_f->frametype != AST_FRAME_TEXT)) {
|
||||
ast_log(LOG_WARNING, "RTP can only send voice, video and text\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The bottom bit of a video subclass contains the marker bit */
|
||||
subclass = _f->subclass;
|
||||
if (_f->frametype == AST_FRAME_VIDEO)
|
||||
subclass &= ~0x1;
|
||||
@@ -2825,29 +2860,33 @@ int ast_rtp_proto_register(struct ast_rtp_protocol *proto)
|
||||
}
|
||||
|
||||
/*! \brief Bridge loop for true native bridge (reinvite) */
|
||||
static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp *p0, struct ast_rtp *p1, struct ast_rtp *vp0, struct ast_rtp *vp1, struct ast_rtp_protocol *pr0, struct ast_rtp_protocol *pr1, int codec0, int codec1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
|
||||
static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct ast_channel *c1, struct ast_rtp *p0, struct ast_rtp *p1, struct ast_rtp *vp0, struct ast_rtp *vp1, struct ast_rtp *tp0, struct ast_rtp *tp1, struct ast_rtp_protocol *pr0, struct ast_rtp_protocol *pr1, int codec0, int codec1, int timeoutms, int flags, struct ast_frame **fo, struct ast_channel **rc, void *pvt0, void *pvt1)
|
||||
{
|
||||
struct ast_frame *fr = NULL;
|
||||
struct ast_channel *who = NULL, *other = NULL, *cs[3] = {NULL, };
|
||||
int oldcodec0 = codec0, oldcodec1 = codec1;
|
||||
struct sockaddr_in ac1 = {0,}, vac1 = {0,}, ac0 = {0,}, vac0 = {0,};
|
||||
struct sockaddr_in t1 = {0,}, vt1 = {0,}, t0 = {0,}, vt0 = {0,};
|
||||
struct sockaddr_in ac1 = {0,}, vac1 = {0,}, tac1 = {0,}, ac0 = {0,}, vac0 = {0,}, tac0 = {0,};
|
||||
struct sockaddr_in t1 = {0,}, vt1 = {0,}, tt1 = {0,}, t0 = {0,}, vt0 = {0,}, tt0 = {0,};
|
||||
|
||||
/* Set it up so audio goes directly between the two endpoints */
|
||||
|
||||
/* Test the first channel */
|
||||
if (!(pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))) {
|
||||
if (!(pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))) {
|
||||
ast_rtp_get_peer(p1, &ac1);
|
||||
if (vp1)
|
||||
ast_rtp_get_peer(vp1, &vac1);
|
||||
if (tp1)
|
||||
ast_rtp_get_peer(tp1, &tac1);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
|
||||
|
||||
/* Test the second channel */
|
||||
if (!(pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))) {
|
||||
if (!(pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))) {
|
||||
ast_rtp_get_peer(p0, &ac0);
|
||||
if (vp0)
|
||||
ast_rtp_get_peer(vp0, &vac0);
|
||||
if (tp0)
|
||||
ast_rtp_get_peer(tp0, &tac0);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c1->name, c0->name);
|
||||
|
||||
@@ -2867,10 +2906,10 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
|
||||
if (c0->tech_pvt == pvt0)
|
||||
if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0))
|
||||
if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
|
||||
if (c1->tech_pvt == pvt1)
|
||||
if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0))
|
||||
if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
|
||||
return AST_BRIDGE_RETRY;
|
||||
}
|
||||
@@ -2879,44 +2918,56 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
|
||||
ast_rtp_get_peer(p1, &t1);
|
||||
if (vp1)
|
||||
ast_rtp_get_peer(vp1, &vt1);
|
||||
if (tp1)
|
||||
ast_rtp_get_peer(tp1, &tt1);
|
||||
if (pr1->get_codec)
|
||||
codec1 = pr1->get_codec(c1);
|
||||
ast_rtp_get_peer(p0, &t0);
|
||||
if (vp0)
|
||||
ast_rtp_get_peer(vp0, &vt0);
|
||||
if (tp0)
|
||||
ast_rtp_get_peer(tp0, &tt0);
|
||||
if (pr0->get_codec)
|
||||
codec0 = pr0->get_codec(c0);
|
||||
if ((inaddrcmp(&t1, &ac1)) ||
|
||||
(vp1 && inaddrcmp(&vt1, &vac1)) ||
|
||||
(tp1 && inaddrcmp(&tt1, &tac1)) ||
|
||||
(codec1 != oldcodec1)) {
|
||||
if (option_debug > 1) {
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
|
||||
c1->name, ast_inet_ntoa(t1.sin_addr), ntohs(t1.sin_port), codec1);
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n",
|
||||
c1->name, ast_inet_ntoa(vt1.sin_addr), ntohs(vt1.sin_port), codec1);
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' changed end taddress to %s:%d (format %d)\n",
|
||||
c1->name, ast_inet_ntoa(tt1.sin_addr), ntohs(tt1.sin_port), codec1);
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
|
||||
c1->name, ast_inet_ntoa(ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
|
||||
c1->name, ast_inet_ntoa(vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
|
||||
c1->name, ast_inet_ntoa(tac1.sin_addr), ntohs(tac1.sin_port), oldcodec1);
|
||||
}
|
||||
if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
|
||||
if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, tt1.sin_addr.s_addr ? tp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
|
||||
memcpy(&ac1, &t1, sizeof(ac1));
|
||||
memcpy(&vac1, &vt1, sizeof(vac1));
|
||||
memcpy(&tac1, &tt1, sizeof(tac1));
|
||||
oldcodec1 = codec1;
|
||||
}
|
||||
if ((inaddrcmp(&t0, &ac0)) ||
|
||||
(vp0 && inaddrcmp(&vt0, &vac0))) {
|
||||
(vp0 && inaddrcmp(&vt0, &vac0)) ||
|
||||
(tp0 && inaddrcmp(&tt0, &tac0))) {
|
||||
if (option_debug > 1) {
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n",
|
||||
c0->name, ast_inet_ntoa(t0.sin_addr), ntohs(t0.sin_port), codec0);
|
||||
ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n",
|
||||
c0->name, ast_inet_ntoa(ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
|
||||
}
|
||||
if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
|
||||
if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, tt0.sin_addr.s_addr ? tp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
|
||||
memcpy(&ac0, &t0, sizeof(ac0));
|
||||
memcpy(&vac0, &vt0, sizeof(vac0));
|
||||
memcpy(&tac0, &tt0, sizeof(tac0));
|
||||
oldcodec0 = codec0;
|
||||
}
|
||||
|
||||
@@ -2941,10 +2992,10 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Oooh, got a %s\n", fr ? "digit" : "hangup");
|
||||
if (c0->tech_pvt == pvt0)
|
||||
if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0))
|
||||
if (pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
|
||||
if (c1->tech_pvt == pvt1)
|
||||
if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0))
|
||||
if (pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0))
|
||||
ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
|
||||
return AST_BRIDGE_COMPLETE;
|
||||
} else if ((fr->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
|
||||
@@ -2954,15 +3005,15 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
|
||||
if (fr->subclass == AST_CONTROL_HOLD) {
|
||||
/* If we someone went on hold we want the other side to reinvite back to us */
|
||||
if (who == c0)
|
||||
pr1->set_rtp_peer(c1, NULL, NULL, 0, 0);
|
||||
pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0);
|
||||
else
|
||||
pr0->set_rtp_peer(c0, NULL, NULL, 0, 0);
|
||||
pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0);
|
||||
} else if (fr->subclass == AST_CONTROL_UNHOLD) {
|
||||
/* If they went off hold they should go back to being direct */
|
||||
if (who == c0)
|
||||
pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE));
|
||||
pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE));
|
||||
else
|
||||
pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE));
|
||||
pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE));
|
||||
}
|
||||
ast_indicate_data(other, fr->subclass, fr->data, fr->datalen);
|
||||
ast_frfree(fr);
|
||||
@@ -3260,9 +3311,10 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
|
||||
{
|
||||
struct ast_rtp *p0 = NULL, *p1 = NULL; /* Audio RTP Channels */
|
||||
struct ast_rtp *vp0 = NULL, *vp1 = NULL; /* Video RTP channels */
|
||||
struct ast_rtp *tp0 = NULL, *tp1 = NULL; /* Text RTP channels */
|
||||
struct ast_rtp_protocol *pr0 = NULL, *pr1 = NULL;
|
||||
enum ast_rtp_get_result audio_p0_res = AST_RTP_GET_FAILED, video_p0_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_p1_res = AST_RTP_GET_FAILED, video_p1_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_p0_res = AST_RTP_GET_FAILED, video_p0_res = AST_RTP_GET_FAILED, text_p0_res = AST_RTP_GET_FAILED;
|
||||
enum ast_rtp_get_result audio_p1_res = AST_RTP_GET_FAILED, video_p1_res = AST_RTP_GET_FAILED, text_p1_res = AST_RTP_GET_FAILED;
|
||||
enum ast_bridge_result res = AST_BRIDGE_FAILED;
|
||||
int codec0 = 0, codec1 = 0;
|
||||
void *pvt0 = NULL, *pvt1 = NULL;
|
||||
@@ -3296,8 +3348,10 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
|
||||
/* Get audio and video interface (if native bridge is possible) */
|
||||
audio_p0_res = pr0->get_rtp_info(c0, &p0);
|
||||
video_p0_res = pr0->get_vrtp_info ? pr0->get_vrtp_info(c0, &vp0) : AST_RTP_GET_FAILED;
|
||||
text_p0_res = pr0->get_trtp_info ? pr0->get_trtp_info(c0, &vp0) : AST_RTP_GET_FAILED;
|
||||
audio_p1_res = pr1->get_rtp_info(c1, &p1);
|
||||
video_p1_res = pr1->get_vrtp_info ? pr1->get_vrtp_info(c1, &vp1) : AST_RTP_GET_FAILED;
|
||||
text_p1_res = pr1->get_trtp_info ? pr1->get_trtp_info(c1, &vp1) : AST_RTP_GET_FAILED;
|
||||
|
||||
/* If we are carrying video, and both sides are not reinviting... then fail the native bridge */
|
||||
if (video_p0_res != AST_RTP_GET_FAILED && (audio_p0_res != AST_RTP_TRY_NATIVE || video_p0_res != AST_RTP_TRY_NATIVE))
|
||||
@@ -3384,7 +3438,7 @@ enum ast_bridge_result ast_rtp_bridge(struct ast_channel *c0, struct ast_channel
|
||||
} else {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Native bridging %s and %s\n", c0->name, c1->name);
|
||||
res = bridge_native_loop(c0, c1, p0, p1, vp0, vp1, pr0, pr1, codec0, codec1, timeoutms, flags, fo, rc, pvt0, pvt1);
|
||||
res = bridge_native_loop(c0, c1, p0, p1, vp0, vp1, tp0, tp1, pr0, pr1, codec0, codec1, timeoutms, flags, fo, rc, pvt0, pvt1);
|
||||
}
|
||||
|
||||
return res;
|
||||
|
||||
Reference in New Issue
Block a user