[svn-commits] branch oej/test-this-branch r13354 - in
/team/oej/test-this-branch: ./ channe...
svn-commits at lists.digium.com
svn-commits at lists.digium.com
Fri Mar 17 03:17:52 MST 2006
Author: oej
Date: Fri Mar 17 04:17:43 2006
New Revision: 13354
URL: http://svn.digium.com/view/asterisk?rev=13354&view=rev
Log:
Adding T38 passthrough support
Added:
team/oej/test-this-branch/doc/sipt38support.txt (with props)
Modified:
team/oej/test-this-branch/Makefile
team/oej/test-this-branch/README.test-this-branch
team/oej/test-this-branch/asterisk.c
team/oej/test-this-branch/channel.c
team/oej/test-this-branch/channels/chan_sip.c
team/oej/test-this-branch/configs/sip.conf.sample
team/oej/test-this-branch/frame.c
team/oej/test-this-branch/include/asterisk/channel.h
team/oej/test-this-branch/include/asterisk/frame.h
Modified: team/oej/test-this-branch/Makefile
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/Makefile?rev=13354&r1=13353&r2=13354&view=diff
==============================================================================
--- team/oej/test-this-branch/Makefile (original)
+++ team/oej/test-this-branch/Makefile Fri Mar 17 04:17:43 2006
@@ -434,8 +434,6 @@
endif
INSTALL=install
-
-CFLAGS+=-DT38_SUPPORT
_all: all
@echo " +--------- Asterisk Build Complete ---------+"
Modified: team/oej/test-this-branch/README.test-this-branch
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/README.test-this-branch?rev=13354&r1=13353&r2=13354&view=diff
==============================================================================
--- team/oej/test-this-branch/README.test-this-branch (original)
+++ team/oej/test-this-branch/README.test-this-branch Fri Mar 17 04:17:43 2006
@@ -34,6 +34,7 @@
- filenamelen: Some code changes for file name lengths (oej)
- disable-ol-and-sub: Settings for disabling sip subscriptions and overlap
dialing (#6705, oej)
+- t38passthrough: Support for Fax passthrough in SIP (#5090, Steve Underwood)
And the following stand-alone patches
- Additional options for the CHANNEL dialplan function (oej, #6670)
@@ -66,8 +67,9 @@
* Open BUGS (fixes welcome!)
----------------------------
-- res_features with multiparking craches on AMD64
-- res_features have problems with reload
+- func_realtime doesn't load properly on some systems.
+ add noload=func_realtime.so in modules.conf if you see this
+ and report to the bug tracker
* Metermaids
------------
Modified: team/oej/test-this-branch/asterisk.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/asterisk.c?rev=13354&r1=13353&r2=13354&view=diff
==============================================================================
--- team/oej/test-this-branch/asterisk.c (original)
+++ team/oej/test-this-branch/asterisk.c Fri Mar 17 04:17:43 2006
@@ -107,9 +107,7 @@
#include "asterisk/pbx.h"
#include "asterisk/enum.h"
#include "asterisk/rtp.h"
-#if defined(T38_SUPPORT)
#include "asterisk/udptl.h"
-#endif
#include "asterisk/app.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
@@ -2442,9 +2440,7 @@
exit(1);
}
ast_rtp_init();
-#if defined(T38_SUPPORT)
ast_udptl_init();
-#endif
if (ast_image_init()) {
printf(term_quit());
exit(1);
Modified: team/oej/test-this-branch/channel.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/channel.c?rev=13354&r1=13353&r2=13354&view=diff
==============================================================================
--- team/oej/test-this-branch/channel.c (original)
+++ team/oej/test-this-branch/channel.c Fri Mar 17 04:17:43 2006
@@ -2303,6 +2303,12 @@
else
res = 0;
break;
+ case AST_FRAME_MODEM:
+ if (chan->tech->write)
+ res = chan->tech->write(chan, fr);
+ else
+ res = 0;
+ break;
case AST_FRAME_VOICE:
if (chan->tech->write) {
/* Bypass translator if we're writing format in the raw write format. This
@@ -3365,9 +3371,7 @@
(f->frametype == AST_FRAME_VIDEO) ||
(f->frametype == AST_FRAME_IMAGE) ||
(f->frametype == AST_FRAME_HTML) ||
-#if defined(T38_SUPPORT)
(f->frametype == AST_FRAME_MODEM) ||
-#endif
(f->frametype == AST_FRAME_TEXT)) {
if (f->frametype == AST_FRAME_DTMF) {
if (((who == c0) && watch_c0_dtmf) ||
Modified: team/oej/test-this-branch/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/oej/test-this-branch/channels/chan_sip.c?rev=13354&r1=13353&r2=13354&view=diff
==============================================================================
--- team/oej/test-this-branch/channels/chan_sip.c (original)
+++ team/oej/test-this-branch/channels/chan_sip.c Fri Mar 17 04:17:43 2006
@@ -37,7 +37,6 @@
*
*/
-
#include <stdio.h>
#include <ctype.h>
#include <string.h>
@@ -72,6 +71,7 @@
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
+#include "asterisk/udptl.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
#include "asterisk/callerid.h"
@@ -483,6 +483,32 @@
static int sip_reloading = FALSE; /*!< Flag for avoiding multiple reloads at the same time */
static enum channelreloadreason sip_reloadreason; /*!< Reason for last reload/load of configuration */
+/* T.38 set of flags */
+#define T38FAX_FILL_BIT_REMOVAL (1 << 0) /*!< Default: 0 (unset)*/
+#define T38FAX_TRANSCODING_MMR (1 << 1) /*!< Default: 0 (unset)*/
+#define T38FAX_TRANSCODING_JBIG (1 << 2) /*!< Default: 0 (unset)*/
+/* Rate management */
+#define T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF (0 << 3)
+#define T38FAX_RATE_MANAGEMENT_LOCAL_TCF (1 << 3) /*!< Unset for transferedTCF (UDPTL), set for localTCF (TPKT) */
+/* UDP Error correction */
+#define T38FAX_UDP_EC_NONE (0 << 4) /*!< two bits, if unset NO t38UDPEC field in T38 SDP*/
+#define T38FAX_UDP_EC_FEC (1 << 4) /*!< Set for t38UDPFEC */
+#define T38FAX_UDP_EC_REDUNDANCY (2 << 4) /*!< Set for t38UDPRedundancy */
+/* T38 Spec version */
+#define T38FAX_VERSION (3 << 6) /*!< two bits, 2 values so far, up to 4 values max */
+#define T38FAX_VERSION_0 (0 << 6) /*!< Version 0 */
+#define T38FAX_VERSION_1 (1 << 6) /*!< Version 1 */
+/* Maximum Fax Rate */
+#define T38FAX_RATE_2400 (1 << 8) /*!< 2400 bps t38FaxRate */
+#define T38FAX_RATE_4800 (1 << 9) /*!< 4800 bps t38FaxRate */
+#define T38FAX_RATE_7200 (1 << 10) /*!< 7200 bps t38FaxRate */
+#define T38FAX_RATE_9600 (1 << 11) /*!< 9600 bps t38FaxRate */
+#define T38FAX_RATE_12000 (1 << 12) /*!< 12000 bps t38FaxRate */
+#define T38FAX_RATE_14400 (1 << 13) /*!< 14400 bps t38FaxRate */
+
+static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_RATE_4800 | T38FAX_RATE_7200 | T38FAX_RATE_9600; /*!< This is default: NO MMR and JBIG trancoding, NO fill bit removal, transfered TCF, UDP FEC, Version 0 and 9600 max fax rate */
+
+/*! \brief Codecs that we support by default: */
static struct sched_context *sched; /*!< The scheduling context */
static struct io_context *io; /*!< The IO context */
@@ -532,10 +558,29 @@
char hop[0];
};
+/*! \brief T38 Sates for a call */
+enum t38state {
+ T38_DISABLED = 0, /*! Not enabled */
+ T38_LOCAL_DIRECT, /*! Offered from local */
+ T38_LOCAL_REINVITE, /*! Offered from local - REINVITE */
+ T38_PEER_DIRECT, /*! Offered from peer */
+ T38_PEER_REINVITE, /*! Offered from peer - REINVITE */
+ T38_ENABLED /*! Negotiated (enabled) */
+};
+
+/*! \brief T.38 channel settings (at some point we need to make this alloc'ed */
+struct t38properties {
+ struct ast_flags t38support; /*!< Flag for udptl, rtp or tcp support for this session */
+ int capability; /*!< Our T38 capability */
+ int peercapability; /*!< Peers T38 capability */
+ int jointcapability; /*!< Supported T38 capability at both ends */
+ enum t38state state; /*!< T.38 state */
+};
+
/*! \brief Modes for SIP domain handling in the PBX */
enum domain_mode {
- SIP_DOMAIN_AUTO, /*!< This domain is auto-configured */
- SIP_DOMAIN_CONFIG, /*!< This domain is from configuration */
+ SIP_DOMAIN_AUTO, /*!< This domain is auto-configured */
+ SIP_DOMAIN_CONFIG, /*!< This domain is from configuration */
};
struct domain {
@@ -642,9 +687,14 @@
#define SIP_PAGE2_PEER_REGISTER (1 << 11) /*!< Register this peer with service */
#define SIP_PAGE2_ALLOWOVERLAP (1 << 12) /*!< Allow overlap dialing */
#define SIP_PAGE2_ALLOWSUBSCRIBE (1 << 13) /*!< Allow SUBSCRIBE */
+#define SIP_PAGE2_T38SUPPORT (3 << 14) /*!< T38 Fax Passthrough Support */
+#define SIP_PAGE2_T38SUPPORT_UDPTL (0 << 14) /*!< 15: T38 Fax Passthrough Support */
+#define SIP_PAGE2_T38SUPPORT_RTP (1 << 14) /*!< 16: T38 Fax Passthrough Support */
+#define SIP_PAGE2_T38SUPPORT_TCP (2 << 14) /*!< 17: T38 Fax Passthrough Support */
#define SIP_PAGE2_FLAGS_TO_COPY \
- (SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_ALLOWSUBSCRIBE)
+ (SIP_PAGE2_VIDEOSUPPORT | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_ALLOWSUBSCRIBE \
+ | SIP_PAGE2_T38SUPPORT)
/* SIP packet flags */
#define SIP_PKT_DEBUG (1 << 0) /*!< Debug this packet */
@@ -716,6 +766,10 @@
int peercapability; /*!< Supported peer capability */
int prefcodec; /*!< Preferred codec (outbound only) */
int noncodeccapability;
+ struct t38properties t38; /*!< T38 settings */
+ struct sockaddr_in udptlredirip; /*!< NAT support: Where our T.38 UDPTL should be going if not to us */
+ struct ast_udptl *udptl; /*!< T.38 UDPTL session */
+
int maxcallbitrate; /*!< Maximum Call Bitrate for Video Calls */
int callingpres; /*!< Calling presentation */
int authtries; /*!< Times we've tried to authenticate */
@@ -1006,6 +1060,13 @@
static int sip_send_mwi_to_peer(struct sip_peer *peer);
static int sip_scheddestroy(struct sip_pvt *p, int ms);
+/*------ T38 Support --------- */
+static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo,struct ast_channel **rc, int timeoutms); /*!< Function to bridge to SIP channels if NOT T.38 enabled */
+static int sip_handle_t38_reinvite(struct ast_channel *chan, struct sip_pvt *pvt, int reinvite); /*!< T38 negotiation helper function */
+static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans);
+static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p);
+static struct ast_udptl *sip_get_udptl_peer(struct ast_channel *chan);
+static int sip_set_udptl_peer(struct ast_channel *chan, struct ast_udptl *udptl);
/*----- RTP interface functions */
static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active);
@@ -1035,7 +1096,7 @@
.transfer = sip_transfer,
.fixup = sip_fixup,
.send_digit = sip_senddigit,
- .bridge = ast_rtp_bridge,
+ .bridge = sip_bridge,
.send_text = sip_sendtext,
};
@@ -1046,6 +1107,13 @@
get_vrtp_info: sip_get_vrtp_peer,
set_rtp_peer: sip_set_rtp_peer,
get_codec: sip_get_codec,
+};
+
+/*! \brief Interface structure with callbacks used to connect to UDPTL module*/
+static struct ast_udptl_protocol sip_udptl = {
+ type: "SIP",
+ get_udptl_info: sip_get_udptl_peer,
+ set_udptl_peer: sip_set_udptl_peer,
};
@@ -1949,6 +2017,26 @@
r->vrtp = NULL;
}
r->prefs = peer->prefs;
+ if (ast_test_flag(&peer->flags_page2, SIP_PAGE2_T38SUPPORT)) {
+ ast_copy_flags(&r->t38.t38support, &peer->flags_page2, SIP_PAGE2_T38SUPPORT);
+ r->t38.capability = global_t38_capability;
+ if (r->udptl) {
+ if (ast_udptl_get_error_correction_scheme(r->udptl) == UDPTL_ERROR_CORRECTION_FEC )
+ r->t38.capability |= T38FAX_UDP_EC_FEC;
+ else if (ast_udptl_get_error_correction_scheme(r->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY )
+ r->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
+ else if (ast_udptl_get_error_correction_scheme(r->udptl) == UDPTL_ERROR_CORRECTION_NONE )
+ r->t38.capability |= T38FAX_UDP_EC_NONE;
+ r->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG,"Our T38 capability (%d)\n", r->t38.capability);
+ }
+ r->t38.jointcapability = r->t38.capability;
+ } else {
+ /* Destroy udptl stream handle since it's no longer needed */
+ if (r->udptl)
+ ast_udptl_destroy(r->udptl);
+ }
if (r->rtp) {
if (option_debug)
ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
@@ -1958,6 +2046,11 @@
if (option_debug)
ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
ast_rtp_setnat(r->vrtp, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
+ }
+ if (r->udptl) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
+ ast_udptl_setnat(r->udptl, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE));
}
ast_string_field_set(r, peername, peer->username);
ast_string_field_set(r, authname, peer->username);
@@ -2132,6 +2225,11 @@
} else if (!p->options->addsipheaders && !strncasecmp(ast_var_name(current), "SIPADDHEADER", strlen("SIPADDHEADER"))) {
/* Check whether there is a variable with a name starting with SIPADDHEADER */
p->options->addsipheaders = 1;
+ } else if (!strncasecmp(ast_var_name(current), "T38CALL", strlen("T38CALL"))) {
+ /* Check whether there is a variable with a name starting with T38CALL */
+ p->t38.state = T38_LOCAL_DIRECT;
+ if (option_debug)
+ ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
}
@@ -2161,6 +2259,9 @@
if ( res != -1 ) {
p->callingpres = ast->cid.cid_pres;
p->jointcapability = p->capability;
+ p->t38.jointcapability = p->t38.capability;
+ if (option_debug)
+ ast_log(LOG_DEBUG,"Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
transmit_invite(p, SIP_INVITE, 1, 2);
if (p->maxtime) {
/* Initialize auto-congest time */
@@ -2229,6 +2330,9 @@
}
if (p->vrtp) {
ast_rtp_destroy(p->vrtp);
+ }
+ if (p->udptl) {
+ ast_udptl_destroy(p->udptl);
}
if (p->route) {
free_old_route(p->route);
@@ -2680,7 +2784,13 @@
ast_setstate(ast, AST_STATE_UP);
if (option_debug)
ast_log(LOG_DEBUG, "SIP answering channel: %s\n", ast->name);
- res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_RELIABLE);
+ if (p->t38.state == T38_PEER_DIRECT) {
+ p->t38.state = T38_ENABLED;
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG,"T38State change to %d on channel %s\n", p->t38.state, ast->name);
+ res = transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, 1);
+ } else
+ res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_RELIABLE);
}
ast_mutex_unlock(&p->lock);
return res;
@@ -2730,6 +2840,19 @@
break;
case AST_FRAME_IMAGE:
return 0;
+ break;
+ case AST_FRAME_MODEM:
+ if (p) {
+ ast_mutex_lock(&p->lock);
+ if (p->udptl) {
+ if ((ast->_state != AST_STATE_UP) && !ast_test_flag(p, SIP_PROGRESS_SENT) && !ast_test_flag(p, SIP_OUTGOING)) {
+ transmit_response_with_t38_sdp(p, "183 Session Progress", &p->initreq, 0);
+ ast_set_flag(p, SIP_PROGRESS_SENT);
+ }
+ res = ast_udptl_write(p->udptl, frame);
+ }
+ ast_mutex_unlock(&p->lock);
+ }
break;
default:
ast_log(LOG_WARNING, "Can't send %d type frames with SIP write\n", frame->frametype);
@@ -2884,7 +3007,27 @@
return res;
}
-
+/*! \brief SIP bridge
+\note Because attempt to do a native RTP bridge between peers happens before T38 re-invites
+ and that one time only, and at that moment neither peers have T38 enabled, this will
+ lead to the native RTP bridge always (if canreinvite is set to yes).
+ Since this is not good for T38 bridging, we have to disable native bridging entirely if
+ t38 support is enabled - not good, but working.
+ */
+static int sip_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms) {
+ struct sip_pvt *p0 = c0->tech_pvt;
+ struct sip_pvt *p1 = c1->tech_pvt;
+
+ /* If both legs of the call support UDPTL, disable native RTP bridge */
+ /* XXXX Should we check for TCP and RTP as well here ???? */
+ if (ast_test_flag(&p0->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && ast_test_flag(&p1->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL)) {
+ ast_log(LOG_NOTICE, "T38 UDPTL support enabled, native RTP bridging disabled\n");
+ return AST_BRIDGE_FAILED_NOWARN;
+ }
+
+ /* We can't do T38 passthrough, so go ahead with RTP bridge and possibly reinvites */
+ return ast_rtp_bridge(c0, c1, flags, fo, rc, timeoutms);
+}
/*! \brief Initiate a call in the SIP channel
called from sip_request_call (calls from the pbx ) */
@@ -2928,7 +3071,10 @@
if (ast_test_flag(i, SIP_DTMF) == SIP_DTMF_INBAND) {
i->vad = ast_dsp_new();
- ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
+ if (ast_test_flag(&i->t38.t38support, SIP_PAGE2_T38SUPPORT))
+ ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT | DSP_FEATURE_FAX_DETECT);
+ else
+ ast_dsp_set_features(i->vad, DSP_FEATURE_DTMF_DETECT);
if (global_relaxdtmf)
ast_dsp_digitmode(i->vad, DSP_DIGITMODE_DTMF | DSP_DIGITMODE_RELAXDTMF);
}
@@ -2939,6 +3085,9 @@
if (i->vrtp) {
tmp->fds[2] = ast_rtp_fd(i->vrtp);
tmp->fds[3] = ast_rtcp_fd(i->vrtp);
+ }
+ if (i->udptl) {
+ tmp->fds[4] = ast_udptl_fd(i->udptl);
}
if (state == AST_STATE_RING)
tmp->rings = 1;
@@ -3116,7 +3265,7 @@
}
/*! \brief Read RTP from network */
-static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p)
+static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect)
{
/* Retrieve audio/etc from channel. Assumes p->lock is already held. */
struct ast_frame *f;
@@ -3139,6 +3288,9 @@
case 3:
f = ast_rtcp_read(p->vrtp); /* RTCP Control Channel for video */
break;
+ case 4:
+ f = ast_udptl_read(p->udptl); /* UDPTL for T.38 */
+ break;
default:
f = &ast_null_frame;
}
@@ -3158,8 +3310,17 @@
}
if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
f = ast_dsp_process(p->owner, p->vad, f);
- if (option_debug && f && (f->frametype == AST_FRAME_DTMF))
- ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
+ if (f && (f->frametype == AST_FRAME_DTMF)) {
+ if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && f->subclass == 'f') {
+ /* Fax tone */
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Fax CNG detected on %s\n", ast->name);
+
+ *faxdetect = 1;
+ }
+ if (option_debug)
+ ast_log(LOG_DEBUG, "* Detected inband DTMF '%c'\n", f->subclass);
+ }
}
}
}
@@ -3171,11 +3332,32 @@
{
struct ast_frame *fr;
struct sip_pvt *p = ast->tech_pvt;
+ int faxdetected = FALSE;
ast_mutex_lock(&p->lock);
- fr = sip_rtp_read(ast, p);
+ fr = sip_rtp_read(ast, p, &faxdetected);
time(&p->lastrtprx);
ast_mutex_unlock(&p->lock);
+
+ /* If we are NOT bridged to another channel, and we have detected fax tone we issue T38 re-invite to a peer */
+ /* If we are bridged then it is responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preabmle */
+ if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
+ if (!ast_test_flag(p, SIP_GOTREFER)) {
+ if (!p->pendinginvite) {
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG, "Sending reinvite on SIP (%s) for T.38 negotiation.\n",ast->name);
+ p->t38.state = T38_LOCAL_REINVITE;
+ transmit_reinvite_with_t38_sdp(p);
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s", p->t38.state, ast->name);
+ }
+ } else if (!ast_test_flag(p, SIP_PENDINGBYE)) {
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG, "Deferring reinvite on SIP (%s) - it will be re-negotiated for T.38\n",ast->name);
+ ast_set_flag(p, SIP_NEEDREINVITE);
+ }
+ }
+
return fr;
}
@@ -3271,6 +3453,10 @@
p->rtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
if (ast_test_flag((&p->flags_page2), SIP_PAGE2_VIDEOSUPPORT))
p->vrtp = ast_rtp_new_with_bindaddr(sched, io, 1, 0, bindaddr.sin_addr);
+ if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL) )
+ /* TODO: Need to check for error - or ?? */
+ p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
+
if (!p->rtp || (ast_test_flag((&p->flags_page2), SIP_PAGE2_VIDEOSUPPORT) && !p->vrtp)) {
ast_log(LOG_WARNING, "Unable to create RTP audio %s session: %s\n", ast_test_flag((&p->flags_page2), SIP_PAGE2_VIDEOSUPPORT) ? "and video" : "", strerror(errno));
ast_mutex_destroy(&p->lock);
@@ -3284,6 +3470,9 @@
ast_rtp_settos(p->rtp, global_tos_audio);
if (p->vrtp)
ast_rtp_settos(p->vrtp, global_tos_video);
+ if (p->udptl)
+ ast_udptl_settos(p->udptl, global_tos_sip); /* Oej's choice - it's really a data stream that
+ should not need higher TOS */
p->rtptimeout = global_rtptimeout;
p->rtpholdtimeout = global_rtpholdtimeout;
p->rtpkeepalive = global_rtpkeepalive;
@@ -3298,6 +3487,8 @@
ast_rtp_setnat(p->rtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
if (p->vrtp)
ast_rtp_setnat(p->vrtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
+ if (p->udptl)
+ ast_udptl_setnat(p->udptl, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
}
if (p->method != SIP_REGISTER)
@@ -3313,6 +3504,17 @@
p->capability = global_capability;
if ((ast_test_flag(p, SIP_DTMF) == SIP_DTMF_RFC2833) || (ast_test_flag(p, SIP_DTMF) == SIP_DTMF_AUTO))
p->noncodeccapability |= AST_RTP_DTMF;
+ if (p->udptl) {
+ p->t38.capability = global_t38_capability;
+ if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_REDUNDANCY)
+ p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
+ else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_FEC)
+ p->t38.capability |= T38FAX_UDP_EC_FEC;
+ else if (ast_udptl_get_error_correction_scheme(p->udptl) == UDPTL_ERROR_CORRECTION_NONE)
+ p->t38.capability |= T38FAX_UDP_EC_NONE;
+ p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+ p->t38.jointcapability = p->t38.capability;
+ }
ast_string_field_set(p, context, default_context);
#ifdef AST_JB
@@ -3630,6 +3832,10 @@
int len = -1;
int portno = -1;
int vportno = -1;
+ int udptlportno = -1;
+ int peert38capability = 0;
+ char s[256];
+ int old = 0;
int peercapability, peernoncodeccapability;
int vpeercapability=0, vpeernoncodeccapability=0;
struct sockaddr_in sin;
@@ -3697,6 +3903,24 @@
codecs = ast_skip_blanks(codecs + len);
}
}
+
+ if (p->udptl && (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL)) && (sscanf(m, "image %d udptl t38 %n", &x, &len) == 1)) {
+ if (debug)
+ ast_verbose("Got T.38 offer in SDP\n");
+ found = 1;
+ udptlportno = x;
+
+ if (p->owner && p->lastinvite) {
+ p->t38.state = T38_PEER_REINVITE; /* T38 Offered in re-invite from remote party */
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>" );
+ } else {
+ p->t38.state = T38_PEER_DIRECT; /* T38 Offered directly from peer in first invite */
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+ }
+ }
+
if (p->vrtp)
ast_rtp_pt_clear(p->vrtp); /* Must be cleared in case no m=video line exists */
@@ -3720,7 +3944,7 @@
if (!found )
ast_log(LOG_WARNING, "Unknown SDP media type in offer: %s\n", m);
}
- if (portno == -1 && vportno == -1) {
+ if (portno == -1 && vportno == -1 && udptlportno == -1) {
/* No acceptable offer found in SDP */
return -2;
}
@@ -3744,11 +3968,18 @@
memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
/* Setup audio port number */
- sin.sin_port = htons(portno);
- if (p->rtp && sin.sin_port) {
- ast_rtp_set_peer(p->rtp, &sin);
- if (debug) {
- ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+ if (p->rtp) {
+ if (portno > 0) {
+ sin.sin_port = htons(portno);
+ ast_rtp_set_peer(p->rtp, &sin);
+ if (debug) {
+ ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+ }
+ } else {
+ ast_rtp_stop(p->rtp);
+ if (debug) {
+ ast_verbose("Peer doesn't provide audio\n");
+ }
}
}
/* Check for Media-description-level-address for video */
@@ -3767,11 +3998,32 @@
}
}
/* Setup video port number */
- sin.sin_port = htons(vportno);
- if (p->vrtp && sin.sin_port) {
- ast_rtp_set_peer(p->vrtp, &sin);
- if (debug) {
- ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+ if (p->vrtp) {
+ if (vportno > 0) {
+ sin.sin_port = htons(vportno);
+ ast_rtp_set_peer(p->vrtp, &sin);
+ if (debug) {
+ ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(iabuf,sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+ }
+ } else {
+ ast_rtp_stop(p->vrtp);
+ if (debug) {
+ ast_verbose("Peer doesn't provide video\n");
+ }
+ }
+ }
+ /* Setup UDPTL port number */
+ if (p->udptl && (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_UDPTL))) {
+ if (udptlportno > 0) {
+ sin.sin_port = htons(udptlportno);
+ ast_udptl_set_peer(p->udptl, &sin);
+ if (debug) {
+ ast_log(LOG_DEBUG,"Peer T.38 UDPTL is at port %s:%d\n",ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port));
+ }
+ } else {
+ ast_udptl_stop(p->udptl);
+ if (debug)
+ ast_log(LOG_DEBUG, "Peer doesn't provide T.38 UDPTL\n");
}
}
@@ -3795,6 +4047,127 @@
ast_rtp_set_rtpmap_type(p->rtp, codec, "audio", mimeSubtype);
if (p->vrtp)
ast_rtp_set_rtpmap_type(p->vrtp, codec, "video", mimeSubtype);
+ }
+
+ if (udptlportno != -1) {
+ int found = 0;
+
+ old = 0;
+
+ /* Scan trough the a= lines for T38 attributes and set apropriate fileds */
+ sdpLineNum_iterator_init(&iterator);
+ while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') {
+ if (old && (iterator-old != 1))
+ break;
+ old = iterator;
+
+ if ((sscanf(a, "T38FaxMaxBuffer:%d", &x) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"MaxBufferSize:%d\n",x);
+ }
+ if ((sscanf(a, "T38MaxBitRate:%d", &x) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"T38MaxBitRate: %d\n",x);
+ switch (x) {
+ case 14400:
+ peert38capability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ break;
+ case 12000:
+ peert38capability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ break;
+ case 9600:
+ peert38capability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ break;
+ case 7200:
+ peert38capability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ break;
+ case 4800:
+ peert38capability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ break;
+ case 2400:
+ peert38capability |= T38FAX_RATE_2400;
+ break;
+ }
+ }
+ if ((sscanf(a, "T38FaxVersion:%d", &x) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"FaxVerison: %d\n",x);
+ if (x == 0)
+ peert38capability |= T38FAX_VERSION_0;
+ else if (x == 1)
+ peert38capability |= T38FAX_VERSION_1;
+ }
+ if ((sscanf(a, "T38FaxMaxDatagram:%d", &x) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"FaxMaxDatagram: %d\n",x);
+ ast_udptl_set_far_max_datagram(p->udptl, x);
+ ast_udptl_set_local_max_datagram(p->udptl, x);
+ }
+ if ((sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"FillBitRemoval: %d\n",x);
+ if (x == 1)
+ peert38capability |= T38FAX_FILL_BIT_REMOVAL;
+ }
+ if ((sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"Transcoding MMR: %d\n",x);
+ if (x == 1)
+ peert38capability |= T38FAX_TRANSCODING_MMR;
+ }
+ if ((sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"Transcoding JBIG: %d\n",x);
+ if (x == 1)
+ peert38capability |= T38FAX_TRANSCODING_JBIG;
+ }
+ if ((sscanf(a, "T38FaxRateManagement:%s", s) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"RateMangement: %s\n", s);
+ if (!strcasecmp(s, "localTCF"))
+ peert38capability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
+ else if (!strcasecmp(s, "transferedTCF"))
+ peert38capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF;
+ }
+ if ((sscanf(a, "T38FaxUdpEC:%s", s) == 1)) {
+ found = 1;
+ if (option_debug > 2)
+ ast_log(LOG_DEBUG,"UDP EC: %s\n", s);
+ if (!strcasecmp(s, "t38UDPRedundancy")) {
+ peert38capability |= T38FAX_UDP_EC_REDUNDANCY;
+ ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
+ } else if (!strcasecmp(s, "t38UDPFEC")) {
+ peert38capability |= T38FAX_UDP_EC_FEC;
+ ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
+ } else {
+ peert38capability |= T38FAX_UDP_EC_NONE;
+ ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
+ }
+ }
+ }
+ if (found) { /* Some cisco equipment returns nothing beside c= and m= lines in 200 OK T38 SDP */
+ p->t38.peercapability = peert38capability;
+ p->t38.jointcapability = (peert38capability & 255); /* Put everything beside supported speeds settings */
+ peert38capability &= (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400); /* Mask speeds only */
+ p->t38.jointcapability |= (peert38capability & p->t38.capability); /* Put the lower of our's and peer's speed */
+ }
+ if (debug)
+ ast_log(LOG_DEBUG,"Our T38 capability = (%d), peer T38 capability (%d), joint T38 capability (%d)\n",
+ p->t38.capability,
+ p->t38.peercapability,
+ p->t38.jointcapability);
+ } else {
+ p->t38.state = T38_DISABLED;
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
}
/* Now gather all of the codecs that were asked for: */
@@ -4541,6 +4914,142 @@
if (format == AST_RTP_DTMF)
/* Indicate we support DTMF and FLASH... */
ast_build_string(a_buf, a_size, "a=fmtp:%d 0-16\r\n", rtp_code);
+}
+
+/*! \brief Get Max T.38 Transmision rate from T38 capabilities */
+int t38_get_rate(int t38cap)
+{
+ int maxrate = (t38cap & (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400));
+
+ if (maxrate & T38FAX_RATE_14400) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38MaxFaxRate 14400 found\n");
+ return 14400;
+ } else if (maxrate & T38FAX_RATE_12000) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38MaxFaxRate 12000 found\n");
+ return 12000;
+ } else if (maxrate & T38FAX_RATE_9600) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38MaxFaxRate 9600 found\n");
+ return 9600;
+ } else if (maxrate & T38FAX_RATE_7200) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38MaxFaxRate 7200 found\n");
+ return 7200;
+ } else if (maxrate & T38FAX_RATE_4800) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38MaxFaxRate 4800 found\n");
+ return 4800;
+ } else if (maxrate & T38FAX_RATE_2400) {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "T38MaxFaxRate 2400 found\n");
+ return 2400;
+ } else {
+ if (option_debug > 1)
+ ast_log(LOG_DEBUG, "Strange, T38MaxFaxRate NOT found in peers T38 SDP.\n");
+ return 0;
+ }
+}
+
+/*! \brief Add T.38 Session Description Protocol message */
+static int add_t38_sdp(struct sip_request *resp, struct sip_pvt *p)
+{
+ int len = 0;
+ int x = 0;
+ struct sockaddr_in udptlsin;
+ char v[256] = "";
+ char s[256] = "";
+ char o[256] = "";
+ char c[256] = "";
+ char t[256] = "";
+ char m_modem[256];
+ char a_modem[1024];
+ char *m_modem_next = m_modem;
+ size_t m_modem_left = sizeof(m_modem);
+ char *a_modem_next = a_modem;
+ size_t a_modem_left = sizeof(a_modem);
+ char iabuf[INET_ADDRSTRLEN];
+ struct sockaddr_in udptldest = { 0, };
+ int debug;
+
+ debug = sip_debug_test_pvt(p);
+ len = 0;
+ if (!p->udptl) {
+ ast_log(LOG_WARNING, "No way to add SDP without an UDPTL structure\n");
+ return -1;
+ }
+
+ if (!p->sessionid) {
+ p->sessionid = getpid();
+ p->sessionversion = p->sessionid;
+ } else
+ p->sessionversion++;
+
+ /* Our T.38 end is */
+ ast_udptl_get_us(p->udptl, &udptlsin);
+
+ /* Determine T.38 UDPTL destination */
+ if (p->udptlredirip.sin_addr.s_addr) {
+ udptldest.sin_port = p->udptlredirip.sin_port;
+ udptldest.sin_addr = p->udptlredirip.sin_addr;
+ } else {
+ udptldest.sin_addr = p->ourip;
+ udptldest.sin_port = udptlsin.sin_port;
+ }
+
+ if (debug) {
+ ast_log(LOG_DEBUG, "T.38 UDPTL is at %s port %d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ntohs(udptlsin.sin_port));
+ }
+
+ /* We break with the "recommendation" and send our IP, in order that our
+ peer doesn't have to ast_gethostbyname() us */
+
+ if (debug) {
+ ast_log(LOG_DEBUG, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
+ p->t38.capability,
+ p->t38.peercapability,
+ p->t38.jointcapability);
+ }
+ snprintf(v, sizeof(v), "v=0\r\n");
+ snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", p->sessionid, p->sessionversion, ast_inet_ntoa(iabuf, sizeof(iabuf), udptldest.sin_addr));
+ snprintf(s, sizeof(s), "s=session\r\n");
+ snprintf(c, sizeof(c), "c=IN IP4 %s\r\n", ast_inet_ntoa(iabuf, sizeof(iabuf), udptldest.sin_addr));
+ snprintf(t, sizeof(t), "t=0 0\r\n");
+ ast_build_string(&m_modem_next, &m_modem_left, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
+
+ if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVerison:0\r\n");
+ if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxVerison:1\r\n");
+ if ((x = t38_get_rate(p->t38.jointcapability)))
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38MaxBitRate:%d\r\n",x);
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxFillBitRemoval:%d\r\n", (p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) ? 1 : 0);
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingMMR:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_MMR) ? 1 : 0);
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxTranscodingJBIG:%d\r\n", (p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) ? 1 : 0);
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferedTCF");
+ x = ast_udptl_get_local_max_datagram(p->udptl);
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxBuffer:%d\r\n",x);
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxMaxDatagram:%d\r\n",x);
+ if (p->t38.jointcapability != T38FAX_UDP_EC_NONE)
+ ast_build_string(&a_modem_next, &a_modem_left, "a=T38FaxUdpEC:%s\r\n", (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY) ? "t38UDPRedundancy" : "t38UDPFEC");
+ if (p->udptl)
+ len = strlen(m_modem) + strlen(a_modem);
+ add_header(resp, "Content-Type", "application/sdp");
+ add_header_contentLength(resp, len);
+ add_line(resp, v);
+ add_line(resp, o);
+ add_line(resp, s);
+ add_line(resp, c);
+ add_line(resp, t);
+ add_line(resp, m_modem);
+ add_line(resp, a_modem);
+
+ /* Update lastrtprx when we send our SDP */
+ time(&p->lastrtprx);
+ time(&p->lastrtptx);
+
+ return 0;
}
/*! \brief Add Session Description Protocol message */
@@ -4649,6 +5158,11 @@
alreadysent |= p->prefcodec;
}
+ if ((ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT_RTP))) {
+ ast_build_string(&m_audio_next, &m_audio_left, " %d", 191);
+ ast_build_string(&a_audio_next, &a_audio_left, "a=rtpmap:%d %s/%d\r\n", 191, "t38", 8000);
+ }
+
/* Start by sending our preferred codecs */
for (x = 0; x < 32; x++) {
if (!(pref_codec = ast_codec_pref_index(&p->prefs, x)))
@@ -4772,6 +5286,26 @@
return send_response(p, &resp, reliable, seqno);
}
+/*--- transmit_response_with_t38_sdp: Used for 200 OK and 183 early media ---*/
+static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans)
+{
+ struct sip_request resp;
+ int seqno;
+
+ if (sscanf(get_header(req, "CSeq"), "%d ", &seqno) != 1) {
+ ast_log(LOG_WARNING, "Unable to get seqno from '%s'\n", get_header(req, "CSeq"));
+ return -1;
+ }
+ respprep(&resp, p, msg, req);
+ if (p->udptl) {
+ ast_udptl_offered_from_local(p->udptl, 0);
+ add_t38_sdp(&resp, p);
+ } else {
+ ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
+ }
+ return send_response(p, &resp, retrans, seqno);
+}
+
/*! \brief Parse first line of incoming SIP request */
static int determine_firstline_parts( struct sip_request *req )
{
@@ -4839,6 +5373,35 @@
if (sipdebug)
add_header(&req, "X-asterisk-info", "SIP re-invite (RTP bridge)");
add_sdp(&req, p);
+ /* Use this as the basis */
+ copy_request(&p->initreq, &req);
+ parse_request(&p->initreq);
+ if (sip_debug_test_pvt(p))
+ ast_verbose("%d headers, %d lines\n", p->initreq.headers, p->initreq.lines);
+ p->lastinvite = p->ocseq;
+ ast_set_flag(p, SIP_OUTGOING);
+ return send_request(p, &req, 1, p->ocseq);
+}
+
+/*--- transmit_reinvite_with_t38_sdp: Transmit reinvite with T38 SDP ---*/
+/* A re-invite is basically a new INVITE with the same CALL-ID and TAG as the
+ INVITE that opened the SIP dialogue
+ We reinvite so that the T38 processing can take place.
+ SIP Signalling stays with * in the path.
+*/
+static int transmit_reinvite_with_t38_sdp(struct sip_pvt *p)
+{
+ struct sip_request req;
+ if (ast_test_flag(p, SIP_REINVITE_UPDATE))
+ reqprep(&req, p, SIP_UPDATE, 0, 1);
+ else
+ reqprep(&req, p, SIP_INVITE, 0, 1);
+
+ add_header(&req, "Allow", ALLOWED_METHODS);
+ if (sipdebug)
+ add_header(&req, "X-asterisk-info", "SIP re-invite (T38 switchover)");
+ ast_udptl_offered_from_local(p->udptl, 1);
+ add_t38_sdp(&req, p);
/* Use this as the basis */
copy_request(&p->initreq, &req);
parse_request(&p->initreq);
@@ -5173,7 +5736,13 @@
}
}
}
- if (sdp && p->rtp) {
+
+ if (sdp && (p->udptl) && (p->t38.state == T38_LOCAL_DIRECT)) {
+ ast_udptl_offered_from_local(p->udptl, 1);
+ if (option_debug)
+ ast_log(LOG_DEBUG, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
+ add_t38_sdp(&req, p);
+ } else if (sdp && p->rtp) {
add_sdp(&req, p);
} else {
add_header_contentLength(&req, 0);
@@ -7415,6 +7984,11 @@
ast_log(LOG_DEBUG, "Setting NAT on VRTP to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
ast_rtp_setnat(p->vrtp, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
}
+ if (p->udptl) {
+ if (option_debug)
+ ast_log(LOG_DEBUG, "Setting NAT on UDPTL to %d\n", (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
+ ast_udptl_setnat(p->udptl, (ast_test_flag(p, SIP_NAT) & SIP_NAT_ROUTE));
+ }
if (device->maxms && device->lastms)
p->timer_t1 = device->lastms;
if (ast_test_flag(device, SIP_INSECURE_INVITE)) {
@@ -7479,6 +8053,8 @@
p->noncodeccapability |= AST_RTP_DTMF;
else
p->noncodeccapability &= ~AST_RTP_DTMF;
+ if (p->t38.peercapability)
+ p->t38.jointcapability &= p->t38.peercapability;
/* copy channel vars */
for (v = device->chanvars ; v ; v = v->next) {
@@ -7787,6 +8363,7 @@
[... 635 lines stripped ...]
More information about the svn-commits
mailing list