aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--UPGRADE.txt12
-rw-r--r--apps/app_fax.c27
-rw-r--r--channels/chan_sip.c410
-rw-r--r--include/asterisk/frame.h18
-rw-r--r--include/asterisk/udptl.h40
-rw-r--r--main/channel.c9
-rw-r--r--main/frame.c18
-rw-r--r--main/rtp.c2
-rw-r--r--main/udptl.c271
9 files changed, 355 insertions, 452 deletions
diff --git a/UPGRADE.txt b/UPGRADE.txt
index 7c54d520a..9a2901b4a 100644
--- a/UPGRADE.txt
+++ b/UPGRADE.txt
@@ -18,6 +18,18 @@
===
===========================================================
+From 1.6.1.1 to 1.6.1.2:
+
+Beginning with this release, Asterisk's internal methods of
+negotiating T.38 (FAX over IP) sessions changed in
+non-backwards-compatible ways. Any applications that previously used
+AST_CONTROL_T38 control frames will have to be upgraded to use
+AST_CONTROL_T38_PARAMETERS control frames instead; app_fax.c is a good
+example of how to generate and respond to these frames. These changes
+were made to solve significant T.38 interoperability problems between
+Asterisk and various SIP/T.38 endpoints identified by many users of
+Asterisk.
+
From 1.6.0.1 to 1.6.1:
* The ast_agi_register_multiple() and ast_agi_unregister_multiple()
diff --git a/apps/app_fax.c b/apps/app_fax.c
index ab21c3bd6..4a4bf209b 100644
--- a/apps/app_fax.c
+++ b/apps/app_fax.c
@@ -412,11 +412,12 @@ static int transmit_audio(fax_session *s)
if (fr && fr->frametype == AST_FRAME_DTMF && fr->subclass == 'f') {
struct ast_control_t38_parameters parameters = { .request_response = AST_T38_REQUEST_NEGOTIATE,
.version = 0,
- .max_datagram = 400,
+ .max_ifp = 800,
.rate = AST_T38_RATE_9600,
.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
.fill_bit_removal = 1,
.transcoding_mmr = 1,
+ .transcoding_jbig = 1,
};
ast_debug(1, "Fax tone detected. Requesting T38\n");
ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
@@ -452,20 +453,18 @@ static int transmit_audio(fax_session *s)
res = 1;
break;
} else if (parameters->request_response == AST_T38_REQUEST_NEGOTIATE) {
+ struct ast_control_t38_parameters our_parameters = { .request_response = AST_T38_NEGOTIATED,
+ .version = 0,
+ .max_ifp = 800,
+ .rate = AST_T38_RATE_9600,
+ .rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF,
+ .fill_bit_removal = 1,
+ .transcoding_mmr = 1,
+ .transcoding_jbig = 1,
+ };
ast_debug(1, "T38 request received, accepting\n");
- if (parameters->version > 0) {
- /* Only T.38 Version 0 is supported at this time */
- parameters->version = 0;
- }
- if (parameters->max_datagram > 400) {
- /* Limit incoming datagram size to our default */
- /* TODO: this need to come from the udptl stack, not be hardcoded */
- parameters->max_datagram = 400;
- }
- /* we only support bit rates up to 9.6kbps */
- parameters->rate = AST_T38_RATE_9600;
/* Complete T38 switchover */
- ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, parameters, sizeof(*parameters));
+ ast_indicate_data(s->chan, AST_CONTROL_T38_PARAMETERS, &our_parameters, sizeof(our_parameters));
/* Do not break audio loop, wait until channel driver finally acks switchover
with AST_T38_NEGOTIATED */
}
@@ -545,7 +544,7 @@ static int transmit_t38(fax_session *s)
return -1;
}
- t38_set_max_datagram_size(t38state, s->t38parameters.max_datagram);
+ t38_set_max_datagram_size(t38state, s->t38parameters.max_ifp);
if (s->t38parameters.fill_bit_removal) {
t38_set_fill_bit_removal(t38state, TRUE);
diff --git a/channels/chan_sip.c b/channels/chan_sip.c
index 19dc43d44..2c06f676f 100644
--- a/channels/chan_sip.c
+++ b/channels/chan_sip.c
@@ -1068,10 +1068,10 @@ struct sip_auth {
#define SIP_PAGE2_SUBSCRIBEMWIONLY (1 << 18) /*!< GP: Only issue MWI notification if subscribed to */
#define SIP_PAGE2_IGNORESDPVERSION (1 << 19) /*!< GDP: Ignore the SDP session version number we receive and treat all sessions as new */
-#define SIP_PAGE2_T38SUPPORT (7 << 20) /*!< GDP: T38 Fax Passthrough Support */
-#define SIP_PAGE2_T38SUPPORT_UDPTL (1 << 20) /*!< GDP: T38 Fax Passthrough Support (no error correction) */
-#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC (2 << 20) /*!< GDP: T38 Fax Passthrough Support (FEC error correction) */
-#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY (4 << 20) /*!< GDP: T38 Fax Passthrough Support (redundancy error correction) */
+#define SIP_PAGE2_T38SUPPORT (7 << 20) /*!< GDP: T.38 Fax Support */
+#define SIP_PAGE2_T38SUPPORT_UDPTL (1 << 20) /*!< GDP: T.38 Fax Support (no error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_FEC (2 << 20) /*!< GDP: T.38 Fax Support (FEC error correction) */
+#define SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY (4 << 20) /*!< GDP: T.38 Fax Support (redundancy error correction) */
#define SIP_PAGE2_CALL_ONHOLD (3 << 23) /*!< D: Call hold states: */
#define SIP_PAGE2_CALL_ONHOLD_ACTIVE (1 << 23) /*!< D: Active hold */
@@ -1093,36 +1093,6 @@ struct sip_auth {
/*@}*/
-/*! \name SIPflagsT38
- 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_TRANSFERRED_TCF (0 << 3)
-#define T38FAX_RATE_MANAGEMENT_LOCAL_TCF (1 << 3) /*!< Unset for transferredTCF (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 */
-
-/*!< This is default: NO MMR and JBIG transcoding, NO fill bit removal, transferredTCF TCF, UDP FEC, Version 0 and 9600 max fax rate */
-static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_RATE_4800 | T38FAX_RATE_7200 | T38FAX_RATE_9600;
-/*@}*/
-
/*! \brief debugging state
* We store separately the debugging requests from the config file
* and requests from the CLI. Debugging is enabled if either is set
@@ -1153,11 +1123,9 @@ enum t38state {
/*! \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 */
+ struct ast_control_t38_parameters our_parms;
+ struct ast_control_t38_parameters their_parms;
};
/*! \brief Parameters to know status of transfer */
@@ -3607,7 +3575,7 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
sip_pvt_lock(p);
/* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
- if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT)) {
+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
switch (p->t38.state) {
case T38_LOCAL_REINVITE:
case T38_PEER_REINVITE:
@@ -4339,57 +4307,12 @@ static void do_setnat(struct sip_pvt *p, int natflags)
}
}
-/*! \brief Helper function which interprets T.38 capabilities and fills a parameters structure in */
-static void fill_t38_parameters(int capabilities, struct ast_control_t38_parameters *parameters, struct sip_pvt *p)
-{
- if (capabilities & T38FAX_VERSION_0) {
- parameters->version = 0;
- } else if (capabilities & T38FAX_VERSION_1) {
- parameters->version = 1;
- }
-
- if (capabilities & T38FAX_RATE_14400) {
- parameters->rate = AST_T38_RATE_14400;
- } else if (capabilities & T38FAX_RATE_12000) {
- parameters->rate = AST_T38_RATE_12000;
- } else if (capabilities & T38FAX_RATE_9600) {
- parameters->rate = AST_T38_RATE_9600;
- } else if (capabilities & T38FAX_RATE_7200) {
- parameters->rate = AST_T38_RATE_7200;
- } else if (capabilities & T38FAX_RATE_4800) {
- parameters->rate = AST_T38_RATE_4800;
- } else if (capabilities & T38FAX_RATE_2400) {
- parameters->rate = AST_T38_RATE_2400;
- }
-
- if (capabilities & T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF) {
- parameters->rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
- } else if (capabilities & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) {
- parameters->rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
- }
-
- if (capabilities & T38FAX_FILL_BIT_REMOVAL) {
- parameters->fill_bit_removal = 1;
- }
-
- if (capabilities & T38FAX_TRANSCODING_MMR) {
- parameters->transcoding_mmr = 1;
- }
-
- if (capabilities & T38FAX_TRANSCODING_JBIG) {
- parameters->transcoding_jbig = 1;
- }
-
- parameters->max_datagram = ast_udptl_get_far_max_datagram(p->udptl);
-}
-
/*! \brief Change the T38 state on a SIP dialog */
static void change_t38_state(struct sip_pvt *p, int state)
{
int old = p->t38.state;
struct ast_channel *chan = p->owner;
- enum ast_control_t38 message = 0;
- struct ast_control_t38_parameters parameters = { 0, };
+ struct ast_control_t38_parameters parameters = { .request_response = 0 };
/* Don't bother changing if we are already in the state wanted */
if (old == state)
@@ -4404,39 +4327,34 @@ static void change_t38_state(struct sip_pvt *p, int state)
/* Given the state requested and old state determine what control frame we want to queue up */
if (state == T38_PEER_REINVITE) {
- message = parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
- fill_t38_parameters(p->t38.peercapability, &parameters, p);
+ parameters = p->t38.their_parms;
+ parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+ parameters.request_response = AST_T38_REQUEST_NEGOTIATE;
} else if (state == T38_ENABLED) {
- message = parameters.request_response = AST_T38_NEGOTIATED;
- fill_t38_parameters(p->t38.jointcapability, &parameters, p);
+ parameters = p->t38.their_parms;
+ parameters.max_ifp = ast_udptl_get_far_max_ifp(p->udptl);
+ parameters.request_response = AST_T38_NEGOTIATED;
} else if (state == T38_DISABLED && old == T38_ENABLED)
- message = parameters.request_response = AST_T38_TERMINATED;
+ parameters.request_response = AST_T38_TERMINATED;
else if (state == T38_DISABLED && old == T38_LOCAL_REINVITE)
- message = parameters.request_response = AST_T38_REFUSED;
+ parameters.request_response = AST_T38_REFUSED;
/* Woot we got a message, create a control frame and send it on! */
if (parameters.request_response)
ast_queue_control_data(chan, AST_CONTROL_T38_PARAMETERS, &parameters, sizeof(parameters));
- if (message)
- ast_queue_control_data(chan, AST_CONTROL_T38, &message, sizeof(message));
}
/*! \brief Set the global T38 capabilities on a SIP dialog structure */
static void set_t38_capabilities(struct sip_pvt *p)
{
- p->t38.capability = global_t38_capability;
if (p->udptl) {
if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY) {
ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY);
- p->t38.capability |= T38FAX_UDP_EC_REDUNDANCY;
} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL_FEC) {
ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC);
- p->t38.capability |= T38FAX_UDP_EC_FEC;
} else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) == SIP_PAGE2_T38SUPPORT_UDPTL) {
ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE);
- p->t38.capability |= T38FAX_UDP_EC_NONE;
}
- p->t38.capability |= T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF;
}
}
@@ -4497,9 +4415,7 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
/* t38pt_udptl was enabled in the peer and not in [general] */
dialog->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr);
}
- ast_copy_flags(&dialog->t38.t38support, &peer->flags[1], SIP_PAGE2_T38SUPPORT);
set_t38_capabilities(dialog);
- dialog->t38.jointcapability = dialog->t38.capability;
} else if (dialog->udptl) {
ast_udptl_destroy(dialog->udptl);
dialog->udptl = NULL;
@@ -4789,9 +4705,6 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
} else {
int xmitres;
- p->t38.jointcapability = p->t38.capability;
- ast_debug(2, "Our T38 capability (%d), joint T38 capability (%d)\n", p->t38.capability, p->t38.jointcapability);
-
xmitres = transmit_invite(p, SIP_INVITE, 1, 2);
if (xmitres == XMIT_ERROR)
return -1;
@@ -5629,15 +5542,10 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
we simply forget the frames if we get modem frames before the bridge is up.
Fax will re-transmit.
*/
- if (ast->_state == AST_STATE_UP) {
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->t38.state == T38_DISABLED) {
- if (!p->pendinginvite) {
- change_t38_state(p, T38_LOCAL_REINVITE);
- transmit_reinvite_with_sdp(p, TRUE, FALSE);
- }
- } else if (p->udptl && p->t38.state == T38_ENABLED) {
- res = ast_udptl_write(p->udptl, frame);
- }
+ if ((ast->_state == AST_STATE_UP) &&
+ p->udptl &&
+ (p->t38.state == T38_ENABLED)) {
+ res = ast_udptl_write(p->udptl, frame);
}
sip_pvt_unlock(p);
}
@@ -5759,66 +5667,34 @@ static int sip_transfer(struct ast_channel *ast, const char *dest)
}
/*! \brief Helper function which updates T.38 capability information and triggers a reinvite */
-static void interpret_t38_parameters(struct sip_pvt *p, enum ast_control_t38 request_response, const struct ast_control_t38_parameters *parameters)
+static void interpret_t38_parameters(struct sip_pvt *p, const struct ast_control_t38_parameters *parameters)
{
- if (parameters) {
- if (!parameters->version) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_VERSION_0;
- } else if (parameters->version == 1) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_VERSION_1;
- }
-
- if (parameters->rate == AST_T38_RATE_14400) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- } else if (parameters->rate == AST_T38_RATE_12000) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- } else if (parameters->rate == AST_T38_RATE_9600) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- } else if (parameters->rate == AST_T38_RATE_7200) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
- } else if (parameters->rate == AST_T38_RATE_4800) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
- } else if (parameters->rate == AST_T38_RATE_2400) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_2400;
- }
-
- if (parameters->rate_management == AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF;
- } else if (parameters->rate_management == AST_T38_RATE_MANAGEMENT_LOCAL_TCF) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
- }
-
- if (parameters->fill_bit_removal) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_FILL_BIT_REMOVAL;
- } else {
- p->t38.capability = p->t38.jointcapability &= ~T38FAX_FILL_BIT_REMOVAL;
- }
-
- if (parameters->transcoding_mmr) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_TRANSCODING_MMR;
- } else {
- p->t38.capability = p->t38.jointcapability &= ~T38FAX_TRANSCODING_MMR;
- }
-
- if (parameters->transcoding_jbig) {
- p->t38.capability = p->t38.jointcapability |= T38FAX_TRANSCODING_JBIG;
- } else {
- p->t38.capability = p->t38.jointcapability &= ~T38FAX_TRANSCODING_JBIG;
- }
-
- if (p->udptl && request_response == AST_T38_REQUEST_NEGOTIATE) {
- ast_udptl_set_local_max_datagram(p->udptl, parameters->max_datagram ? parameters->max_datagram : 400);
- }
- }
-
- switch (request_response) {
+ switch (parameters->request_response) {
case AST_T38_NEGOTIATED:
case AST_T38_REQUEST_NEGOTIATE: /* Request T38 */
if (p->t38.state == T38_PEER_REINVITE) {
AST_SCHED_DEL_UNREF(sched, p->t38id, dialog_unref(p, "when you delete the t38id sched, you should dec the refcount for the stored dialog ptr"));
+ p->t38.our_parms = *parameters;
+ /* modify our parameters to conform to the peer's parameters,
+ * based on the rules in the ITU T.38 recommendation
+ */
+ if (!p->t38.their_parms.fill_bit_removal) {
+ p->t38.our_parms.fill_bit_removal = FALSE;
+ }
+ if (!p->t38.their_parms.transcoding_mmr) {
+ p->t38.our_parms.transcoding_mmr = FALSE;
+ }
+ if (!p->t38.their_parms.transcoding_jbig) {
+ p->t38.our_parms.transcoding_jbig = FALSE;
+ }
+ p->t38.our_parms.version = MIN(p->t38.our_parms.version, p->t38.their_parms.version);
+ p->t38.our_parms.rate_management = p->t38.their_parms.rate_management;
+ ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp);
change_t38_state(p, T38_ENABLED);
transmit_response_with_t38_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL);
- } else if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && p->t38.state != T38_ENABLED) {
+ } else if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->t38.state != T38_ENABLED) {
+ p->t38.our_parms = *parameters;
+ ast_udptl_set_local_max_ifp(p->udptl, p->t38.our_parms.max_ifp);
change_t38_state(p, T38_LOCAL_REINVITE);
if (!p->pendinginvite) {
transmit_reinvite_with_sdp(p, TRUE, FALSE);
@@ -5926,19 +5802,12 @@ static int sip_indicate(struct ast_channel *ast, int condition, const void *data
} else
res = -1;
break;
- case AST_CONTROL_T38: /* T38 control frame */
- if (datalen != sizeof(enum ast_control_t38)) {
- ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38. Expected %d, got %d\n", (int)sizeof(enum ast_control_t38), (int)datalen);
- } else {
- interpret_t38_parameters(p, *((enum ast_control_t38 *) data), NULL);
- }
- break;
case AST_CONTROL_T38_PARAMETERS:
if (datalen != sizeof(struct ast_control_t38_parameters)) {
- ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38_PARAMETERS. Expected %d, got %d\n", (int)sizeof(struct ast_control_t38_parameters), (int)datalen);
+ ast_log(LOG_ERROR, "Invalid datalen for AST_CONTROL_T38_PARAMETERS. Expected %d, got %d\n", (int) sizeof(struct ast_control_t38_parameters), (int) datalen);
} else {
const struct ast_control_t38_parameters *parameters = data;
- interpret_t38_parameters(p, parameters->request_response, parameters);
+ interpret_t38_parameters(p, parameters);
}
break;
case AST_CONTROL_SRCUPDATE:
@@ -6348,7 +6217,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
if (f && (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_INBAND) && p->vad) {
f = ast_dsp_process(p->owner, p->vad, f);
if (f && f->frametype == AST_FRAME_DTMF) {
- if (ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && f->subclass == 'f') {
+ if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && f->subclass == 'f') {
ast_debug(1, "Fax CNG detected on %s\n", ast->name);
*faxdetect = 1;
} else {
@@ -6373,7 +6242,7 @@ static struct ast_frame *sip_read(struct ast_channel *ast)
/* 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 the responsibility of the SIP device to issue T38 re-invite if it detects CNG or fax preamble */
- if (faxdetected && ast_test_flag(&p->t38.t38support, SIP_PAGE2_T38SUPPORT) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
+ if (faxdetected && ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && (p->t38.state == T38_DISABLED) && !(ast_bridged_channel(ast))) {
if (!ast_test_flag(&p->flags[0], SIP_GOTREFER)) {
if (!p->pendinginvite) {
ast_debug(3, "Sending reinvite on SIP (%s) for T.38 negotiation.\n", ast->name);
@@ -6586,9 +6455,7 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
(ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO))
p->noncodeccapability |= AST_RTP_DTMF;
if (p->udptl) {
- ast_copy_flags(&p->t38.t38support, &p->flags[1], SIP_PAGE2_T38SUPPORT);
set_t38_capabilities(p);
- p->t38.jointcapability = p->t38.capability;
}
ast_string_field_set(p, context, default_context);
ast_string_field_set(p, parkinglot, default_parkinglot);
@@ -7190,7 +7057,6 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
int vportno = -1; /*!< RTP Video port number */
int tportno = -1; /*!< RTP Text port number */
int udptlportno = -1;
- int peert38capability = 0;
char s[256];
int old = 0;
@@ -7703,6 +7569,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
int found = 0, x;
old = 0;
+ memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
/* Scan trough the a= lines for T38 attributes and set apropriate fileds */
iterator = req->sdp_start;
@@ -7715,110 +7582,92 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
ast_debug(3, "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;
+ p->t38.their_parms.rate = AST_T38_RATE_14400;
break;
case 12000:
- peert38capability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ p->t38.their_parms.rate = AST_T38_RATE_12000;
break;
case 9600:
- peert38capability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ p->t38.their_parms.rate = AST_T38_RATE_9600;
break;
case 7200:
- peert38capability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ p->t38.their_parms.rate = AST_T38_RATE_7200;
break;
case 4800:
- peert38capability |= T38FAX_RATE_4800 | T38FAX_RATE_2400;
+ p->t38.their_parms.rate = AST_T38_RATE_4800;
break;
case 2400:
- peert38capability |= T38FAX_RATE_2400;
+ p->t38.their_parms.rate = AST_T38_RATE_2400;
break;
}
} else if ((sscanf(a, "T38FaxVersion:%d", &x) == 1)) {
found = 1;
ast_debug(3, "FaxVersion: %d\n", x);
- if (x == 0)
- peert38capability |= T38FAX_VERSION_0;
- else if (x == 1)
- peert38capability |= T38FAX_VERSION_1;
+ p->t38.their_parms.version = x;
} else if ((sscanf(a, "T38FaxMaxDatagram:%d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%d", &x) == 1)) {
found = 1;
ast_debug(3, "FaxMaxDatagram: %d\n", x);
ast_udptl_set_far_max_datagram(p->udptl, x);
- if (!ast_udptl_get_local_max_datagram(p->udptl)) {
- ast_udptl_set_local_max_datagram(p->udptl, x);
- }
} else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) {
found = 1;
- if(sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1) {
- ast_debug(3, "FillBitRemoval: %d\n", x);
- if(x == 1)
- peert38capability |= T38FAX_FILL_BIT_REMOVAL;
+ if (sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1) {
+ ast_debug(3, "FillBitRemoval: %d\n", x);
+ if (x == 1) {
+ p->t38.their_parms.fill_bit_removal = TRUE;
+ }
} else {
- ast_debug(3, "FillBitRemoval\n");
- peert38capability |= T38FAX_FILL_BIT_REMOVAL;
+ ast_debug(3, "FillBitRemoval\n");
+ p->t38.their_parms.fill_bit_removal = TRUE;
}
} else if ((strncmp(a, "T38FaxTranscodingMMR", 20) == 0)) {
found = 1;
- if(sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1) {
- ast_debug(3, "Transcoding MMR: %d\n", x);
- if(x == 1)
- peert38capability |= T38FAX_TRANSCODING_MMR;
+ if (sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1) {
+ ast_debug(3, "Transcoding MMR: %d\n", x);
+ if (x == 1) {
+ p->t38.their_parms.transcoding_mmr = TRUE;
+ }
} else {
- ast_debug(3, "Transcoding MMR\n");
- peert38capability |= T38FAX_TRANSCODING_MMR;
+ ast_debug(3, "Transcoding MMR\n");
+ p->t38.their_parms.transcoding_mmr = TRUE;
}
} else if ((strncmp(a, "T38FaxTranscodingJBIG", 21) == 0)) {
found = 1;
- if(sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1) {
- ast_debug(3, "Transcoding JBIG: %d\n", x);
- if(x == 1)
- peert38capability |= T38FAX_TRANSCODING_JBIG;
+ if (sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1) {
+ ast_debug(3, "Transcoding JBIG: %d\n", x);
+ if (x == 1) {
+ p->t38.their_parms.transcoding_jbig = TRUE;
+ }
} else {
- ast_debug(3, "Transcoding JBIG\n");
- peert38capability |= T38FAX_TRANSCODING_JBIG;
+ ast_debug(3, "Transcoding JBIG\n");
+ p->t38.their_parms.transcoding_jbig = TRUE;
}
} else if ((sscanf(a, "T38FaxRateManagement:%255s", s) == 1)) {
found = 1;
ast_debug(3, "RateManagement: %s\n", s);
if (!strcasecmp(s, "localTCF"))
- peert38capability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF;
+ p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_LOCAL_TCF;
else if (!strcasecmp(s, "transferredTCF"))
- peert38capability |= T38FAX_RATE_MANAGEMENT_TRANSFERRED_TCF;
+ p->t38.their_parms.rate_management = AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF;
} else if ((sscanf(a, "T38FaxUdpEC:%255s", s) == 1)) {
found = 1;
ast_debug(3, "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);
- p->t38.jointcapability |= (peert38capability & p->t38.capability); /* Put the lower of our's and peer's speed */
- }
- if (debug)
- ast_debug(1, "Our T38 capability = (%d), peer T38 capability (%d), joint T38 capability (%d)\n",
- p->t38.capability,
- p->t38.peercapability,
- p->t38.jointcapability);
/* Remote party offers T38, we need to update state */
- if (t38action == SDP_T38_ACCEPT) {
- if (p->t38.state == T38_LOCAL_REINVITE)
- change_t38_state(p, T38_ENABLED);
- } else if (t38action == SDP_T38_INITIATE) {
- if (p->owner && p->lastinvite) {
- change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
- }
+ if ((t38action == SDP_T38_ACCEPT) &&
+ (p->t38.state == T38_LOCAL_REINVITE)) {
+ change_t38_state(p, T38_ENABLED);
+ } else if ((t38action == SDP_T38_INITIATE) &&
+ p->owner && p->lastinvite) {
+ change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
}
} else {
change_t38_state(p, T38_DISABLED);
@@ -7852,7 +7701,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
}
if (!newjointcapability) {
/* If T.38 was not negotiated either, totally bail out... */
- if (!p->t38.jointcapability || !udptlportno) {
+ if ((p->t38.state == T38_DISABLED) || !udptlportno) {
ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
/* Do NOT Change current setting */
return -1;
@@ -8872,30 +8721,22 @@ static void add_tcodec_to_sdp(const struct sip_pvt *p, int codec, int sample_rat
/*! \brief Get Max T.38 Transmission rate from T38 capabilities */
-static int t38_get_rate(int t38cap)
+static unsigned int t38_get_rate(enum ast_control_t38_rate rate)
{
- 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) {
- ast_debug(2, "T38MaxBitRate 14400 found\n");
- return 14400;
- } else if (maxrate & T38FAX_RATE_12000) {
- ast_debug(2, "T38MaxBitRate 12000 found\n");
- return 12000;
- } else if (maxrate & T38FAX_RATE_9600) {
- ast_debug(2, "T38MaxBitRate 9600 found\n");
- return 9600;
- } else if (maxrate & T38FAX_RATE_7200) {
- ast_debug(2, "T38MaxBitRate 7200 found\n");
- return 7200;
- } else if (maxrate & T38FAX_RATE_4800) {
- ast_debug(2, "T38MaxBitRate 4800 found\n");
- return 4800;
- } else if (maxrate & T38FAX_RATE_2400) {
- ast_debug(2, "T38MaxBitRate 2400 found\n");
+ switch (rate) {
+ case AST_T38_RATE_2400:
return 2400;
- } else {
- ast_debug(2, "Strange, T38MaxBitRate NOT found in peers T38 SDP.\n");
+ case AST_T38_RATE_4800:
+ return 4800;
+ case AST_T38_RATE_7200:
+ return 7200;
+ case AST_T38_RATE_9600:
+ return 9600;
+ case AST_T38_RATE_12000:
+ return 12000;
+ case AST_T38_RATE_14400:
+ return 14400;
+ default:
return 0;
}
}
@@ -9220,35 +9061,38 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
/* We break with the "recommendation" and send our IP, in order that our
peer doesn't have to ast_gethostbyname() us */
- if (debug) {
- ast_debug(1, "Our T38 capability (%d), peer T38 capability (%d), joint capability (%d)\n",
- p->t38.capability,
- p->t38.peercapability,
- p->t38.jointcapability);
- }
-
ast_str_append(&m_modem, 0, "m=image %d udptl t38\r\n", ntohs(udptldest.sin_port));
- if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_0)
- ast_str_append(&a_modem, 0, "a=T38FaxVersion:0\r\n");
- if ((p->t38.jointcapability & T38FAX_VERSION) == T38FAX_VERSION_1)
- ast_str_append(&a_modem, 0, "a=T38FaxVersion:1\r\n");
- if ((x = t38_get_rate(p->t38.jointcapability)))
- ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", x);
- if ((p->t38.jointcapability & T38FAX_FILL_BIT_REMOVAL) == T38FAX_FILL_BIT_REMOVAL)
+ ast_str_append(&a_modem, 0, "a=T38Faxversion:%d\r\n", p->t38.our_parms.version);
+ ast_str_append(&a_modem, 0, "a=T38MaxBitRate:%d\r\n", t38_get_rate(p->t38.our_parms.rate));
+ if (p->t38.our_parms.fill_bit_removal) {
ast_str_append(&a_modem, 0, "a=T38FaxFillBitRemoval\r\n");
- if ((p->t38.jointcapability & T38FAX_TRANSCODING_MMR) == T38FAX_TRANSCODING_MMR)
+ }
+ if (p->t38.our_parms.transcoding_mmr) {
ast_str_append(&a_modem, 0, "a=T38FaxTranscodingMMR\r\n");
- if ((p->t38.jointcapability & T38FAX_TRANSCODING_JBIG) == T38FAX_TRANSCODING_JBIG)
+ }
+ if (p->t38.our_parms.transcoding_jbig) {
ast_str_append(&a_modem, 0, "a=T38FaxTranscodingJBIG\r\n");
- ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:%s\r\n", (p->t38.jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF) ? "localTCF" : "transferredTCF");
- x = ast_udptl_get_local_max_datagram(p->udptl);
- ast_str_append(&a_modem, 0, "a=T38FaxMaxBuffer:%d\r\n", x);
- ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", x);
- if (p->t38.jointcapability & T38FAX_UDP_EC_REDUNDANCY)
- ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPRedundancy\r\n");
- else if (p->t38.jointcapability & T38FAX_UDP_EC_FEC)
+ }
+ switch (p->t38.our_parms.rate_management) {
+ case AST_T38_RATE_MANAGEMENT_TRANSFERRED_TCF:
+ ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:transferredTCF\r\n");
+ break;
+ case AST_T38_RATE_MANAGEMENT_LOCAL_TCF:
+ ast_str_append(&a_modem, 0, "a=T38FaxRateManagement:localTCF\r\n");
+ break;
+ }
+ ast_str_append(&a_modem, 0, "a=T38FaxMaxDatagram:%d\r\n", ast_udptl_get_local_max_datagram(p->udptl));
+ switch (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT)) {
+ case SIP_PAGE2_T38SUPPORT_UDPTL:
+ break;
+ case SIP_PAGE2_T38SUPPORT_UDPTL_FEC:
ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPFEC\r\n");
+ break;
+ case SIP_PAGE2_T38SUPPORT_UDPTL_REDUNDANCY:
+ ast_str_append(&a_modem, 0, "a=T38FaxUdpEC:t38UDPRedundancy\r\n");
+ break;
+ }
}
if (m_audio->len - m_audio->used < 2 || m_video->len - m_video->used < 2 ||
@@ -9334,7 +9178,6 @@ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct s
}
respprep(&resp, p, msg, req);
if (p->udptl) {
- ast_udptl_offered_from_local(p->udptl, 0);
add_sdp(&resp, p, 0, 0, 1);
} else
ast_log(LOG_ERROR, "Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s\n", p->callid);
@@ -9879,7 +9722,6 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
if (sdp) {
memset(p->offered_media, 0, sizeof(p->offered_media));
if (p->udptl && p->t38.state == T38_LOCAL_REINVITE) {
- ast_udptl_offered_from_local(p->udptl, 1);
ast_debug(1, "T38 is in state %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : "<none>");
add_sdp(&req, p, FALSE, FALSE, TRUE);
} else if (p->rtp)
@@ -12742,7 +12584,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && p->udptl) {
set_t38_capabilities(p);
- p->t38.jointcapability = p->t38.capability;
}
/* Copy SIP extensions profile to peer */
@@ -12843,8 +12684,6 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
else
p->noncodeccapability &= ~AST_RTP_DTMF;
p->jointnoncodeccapability = p->noncodeccapability;
- if (p->t38.peercapability)
- p->t38.jointcapability &= p->t38.peercapability;
}
unref_peer(peer, "check_peer_ok: unref_peer: tossing temp ptr to peer from find_peer");
return res;
@@ -18620,9 +18459,6 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
/* If T38 is needed but not present, then make it magically appear */
if (ast_test_flag(&p->flags[1], SIP_PAGE2_T38SUPPORT) && !p->udptl && (p->udptl = ast_udptl_new_with_bindaddr(sched, io, 0, bindaddr.sin_addr))) {
set_t38_capabilities(p);
- p->t38.jointcapability = p->t38.capability;
- set_t38_capabilities(p);
- p->t38.jointcapability = p->t38.capability;
}
/* We have a succesful authentication, process the SDP portion if there is one */
diff --git a/include/asterisk/frame.h b/include/asterisk/frame.h
index 70100773d..7196f91e5 100644
--- a/include/asterisk/frame.h
+++ b/include/asterisk/frame.h
@@ -315,7 +315,7 @@ enum ast_control_frame_type {
AST_CONTROL_HOLD = 16, /*!< Indicate call is placed on hold */
AST_CONTROL_UNHOLD = 17, /*!< Indicate call is left from hold */
AST_CONTROL_VIDUPDATE = 18, /*!< Indicate video frame update */
- AST_CONTROL_T38 = 19, /*!< T38 state change request/notification */
+ _XXX_AST_CONTROL_T38 = 19, /*!< T38 state change request/notification \deprecated This is no longer supported. Use AST_CONTROL_T38_PARAMETERS instead. */
AST_CONTROL_SRCUPDATE = 20, /*!< Indicate source of media has changed */
AST_CONTROL_T38_PARAMETERS = 24, /*!< T38 state change request/notification with parameters */
};
@@ -343,14 +343,14 @@ enum ast_control_t38_rate_management {
};
struct ast_control_t38_parameters {
- enum ast_control_t38 request_response; /*!< Request or response of the T38 control frame */
- unsigned int version; /*!< Supported T.38 version */
- unsigned int max_datagram; /*!< Maximum datagram size supported */
- enum ast_control_t38_rate rate; /*!< Maximum fax rate supported */
- enum ast_control_t38_rate_management rate_management; /*!< Rate management setting */
- unsigned int fill_bit_removal:1; /*!< Set if fill bit removal should be used */
- unsigned int transcoding_mmr:1; /*!< Set if MMR transcoding should be used */
- unsigned int transcoding_jbig:1; /*!< Set if JBIG transcoding should be used */
+ enum ast_control_t38 request_response; /*!< Request or response of the T38 control frame */
+ unsigned int version; /*!< Supported T.38 version */
+ unsigned int max_ifp; /*!< Maximum IFP size supported */
+ enum ast_control_t38_rate rate; /*!< Maximum fax rate supported */
+ enum ast_control_t38_rate_management rate_management; /*!< Rate management setting */
+ unsigned int fill_bit_removal:1; /*!< Set if fill bit removal can be used */
+ unsigned int transcoding_mmr:1; /*!< Set if MMR transcoding can be used */
+ unsigned int transcoding_jbig:1; /*!< Set if JBIG transcoding can be used */
};
#define AST_SMOOTHER_FLAG_G729 (1 << 0)
diff --git a/include/asterisk/udptl.h b/include/asterisk/udptl.h
index 4d6b89068..72b9af4aa 100644
--- a/include/asterisk/udptl.h
+++ b/include/asterisk/udptl.h
@@ -33,7 +33,7 @@
#include "asterisk/channel.h"
-enum {
+enum ast_t38_ec_modes {
UDPTL_ERROR_CORRECTION_NONE,
UDPTL_ERROR_CORRECTION_FEC,
UDPTL_ERROR_CORRECTION_REDUNDANCY
@@ -60,11 +60,11 @@ struct ast_udptl *ast_udptl_new(struct sched_context *sched, struct io_context *
struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int callbackmode, struct in_addr in);
-void ast_udptl_set_peer(struct ast_udptl *udptl, struct sockaddr_in *them);
+void ast_udptl_set_peer(struct ast_udptl *udptl, const struct sockaddr_in *them);
-void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them);
+void ast_udptl_get_peer(const struct ast_udptl *udptl, struct sockaddr_in *them);
-void ast_udptl_get_us(struct ast_udptl *udptl, struct sockaddr_in *us);
+void ast_udptl_get_us(const struct ast_udptl *udptl, struct sockaddr_in *us);
void ast_udptl_destroy(struct ast_udptl *udptl);
@@ -78,37 +78,33 @@ int ast_udptl_write(struct ast_udptl *udptl, struct ast_frame *f);
struct ast_frame *ast_udptl_read(struct ast_udptl *udptl);
-int ast_udptl_fd(struct ast_udptl *udptl);
+int ast_udptl_fd(const struct ast_udptl *udptl);
-int ast_udptl_setqos(struct ast_udptl *udptl, int tos, int cos);
+int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos);
-void ast_udptl_set_m_type(struct ast_udptl* udptl, int pt);
+void ast_udptl_set_m_type(struct ast_udptl *udptl, unsigned int pt);
-void ast_udptl_set_udptlmap_type(struct ast_udptl* udptl, int pt,
- char* mimeType, char* mimeSubtype);
+void ast_udptl_set_udptlmap_type(struct ast_udptl *udptl, unsigned int pt,
+ char *mimeType, char *mimeSubtype);
-int ast_udptl_lookup_code(struct ast_udptl* udptl, int isAstFormat, int code);
+int ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl);
-void ast_udptl_offered_from_local(struct ast_udptl* udptl, int local);
+void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec);
-int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl);
+void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp);
-void ast_udptl_set_error_correction_scheme(struct ast_udptl* udptl, int ec);
+unsigned int ast_udptl_get_local_max_datagram(const struct ast_udptl *udptl);
-int ast_udptl_get_local_max_datagram(struct ast_udptl* udptl);
+void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram);
-void ast_udptl_set_local_max_datagram(struct ast_udptl* udptl, int max_datagram);
+unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl);
-int ast_udptl_get_far_max_datagram(struct ast_udptl* udptl);
-
-void ast_udptl_set_far_max_datagram(struct ast_udptl* udptl, int max_datagram);
-
-void ast_udptl_get_current_formats(struct ast_udptl* udptl,
- int* astFormats, int* nonAstFormats);
+unsigned int ast_udptl_get_far_max_ifp(const struct ast_udptl *udptl);
void ast_udptl_setnat(struct ast_udptl *udptl, int nat);
-int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
+int ast_udptl_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags,
+ struct ast_frame **fo, struct ast_channel **rc);
int ast_udptl_proto_register(struct ast_udptl_protocol *proto);
diff --git a/main/channel.c b/main/channel.c
index f40099045..e054d7b95 100644
--- a/main/channel.c
+++ b/main/channel.c
@@ -3044,9 +3044,9 @@ static int attribute_const is_visible_indication(enum ast_control_frame_type con
case AST_CONTROL_TAKEOFFHOOK:
case AST_CONTROL_ANSWER:
case AST_CONTROL_HANGUP:
- case AST_CONTROL_T38:
case AST_CONTROL_T38_PARAMETERS:
- return 0;
+ case _XXX_AST_CONTROL_T38:
+ break;
case AST_CONTROL_CONGESTION:
case AST_CONTROL_BUSY:
@@ -3106,7 +3106,9 @@ int ast_indicate_data(struct ast_channel *chan, int _condition,
/* Handle conditions that we have tones for. */
switch (condition) {
- case AST_CONTROL_T38:
+ case _XXX_AST_CONTROL_T38:
+ /* deprecated T.38 control frame */
+ return -1;
case AST_CONTROL_T38_PARAMETERS:
/* there is no way to provide 'default' behavior for these
* control frames, so we need to return failure, but there
@@ -4764,7 +4766,6 @@ static enum ast_bridge_result ast_generic_bridge(struct ast_channel *c0, struct
case AST_CONTROL_UNHOLD:
case AST_CONTROL_VIDUPDATE:
case AST_CONTROL_SRCUPDATE:
- case AST_CONTROL_T38:
case AST_CONTROL_T38_PARAMETERS:
ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
if (jb_in_use) {
diff --git a/main/frame.c b/main/frame.c
index 976c537ff..83e8a0e91 100644
--- a/main/frame.c
+++ b/main/frame.c
@@ -835,24 +835,6 @@ void ast_frame_dump(const char *name, struct ast_frame *f, char *prefix)
case AST_CONTROL_UNHOLD:
strcpy(subclass, "Unhold");
break;
- case AST_CONTROL_T38:
- if (f->datalen != sizeof(enum ast_control_t38)) {
- message = "Invalid";
- } else {
- enum ast_control_t38 state = *((enum ast_control_t38 *) f->data.ptr);
- if (state == AST_T38_REQUEST_NEGOTIATE)
- message = "Negotiation Requested";
- else if (state == AST_T38_REQUEST_TERMINATE)
- message = "Negotiation Request Terminated";
- else if (state == AST_T38_NEGOTIATED)
- message = "Negotiated";
- else if (state == AST_T38_TERMINATED)
- message = "Terminated";
- else if (state == AST_T38_REFUSED)
- message = "Refused";
- }
- snprintf(subclass, sizeof(subclass), "T38/%s", message);
- break;
case AST_CONTROL_T38_PARAMETERS:
if (f->datalen != sizeof(struct ast_control_t38_parameters *)) {
message = "Invalid";
diff --git a/main/rtp.c b/main/rtp.c
index 641311f18..8a51050b9 100644
--- a/main/rtp.c
+++ b/main/rtp.c
@@ -4003,7 +4003,6 @@ static enum ast_bridge_result bridge_native_loop(struct ast_channel *c0, struct
if ((fr->subclass == AST_CONTROL_HOLD) ||
(fr->subclass == AST_CONTROL_UNHOLD) ||
(fr->subclass == AST_CONTROL_VIDUPDATE) ||
- (fr->subclass == AST_CONTROL_T38) ||
(fr->subclass == AST_CONTROL_SRCUPDATE) ||
(fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
if (fr->subclass == AST_CONTROL_HOLD) {
@@ -4244,7 +4243,6 @@ static enum ast_bridge_result bridge_p2p_loop(struct ast_channel *c0, struct ast
if ((fr->subclass == AST_CONTROL_HOLD) ||
(fr->subclass == AST_CONTROL_UNHOLD) ||
(fr->subclass == AST_CONTROL_VIDUPDATE) ||
- (fr->subclass == AST_CONTROL_T38) ||
(fr->subclass == AST_CONTROL_SRCUPDATE) ||
(fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
/* If we are going on hold, then break callback mode and P2P bridging */
diff --git a/main/udptl.c b/main/udptl.c
index e39a9e7f2..35211ccb0 100644
--- a/main/udptl.c
+++ b/main/udptl.c
@@ -81,7 +81,7 @@ static struct sockaddr_in udptldebugaddr; /*!< Debug packets to/from this host
#ifdef SO_NO_CHECK
static int nochecksums;
#endif
-static int udptlfectype;
+static enum ast_t38_ec_modes udptlfectype;
static int udptlfecentries;
static int udptlfecspan;
static int udptlmaxdatagram;
@@ -100,10 +100,10 @@ typedef struct {
typedef struct {
int buf_len;
uint8_t buf[LOCAL_FAX_MAX_DATAGRAM];
- int fec_len[MAX_FEC_ENTRIES];
+ unsigned int fec_len[MAX_FEC_ENTRIES];
uint8_t fec[MAX_FEC_ENTRIES][LOCAL_FAX_MAX_DATAGRAM];
- int fec_span;
- int fec_entries;
+ unsigned int fec_span;
+ unsigned int fec_entries;
} udptl_fec_rx_buffer_t;
/*! \brief Structure for an UDPTL session */
@@ -122,35 +122,51 @@ struct ast_udptl {
struct io_context *io;
void *data;
ast_udptl_callback callback;
- int udptl_offered_from_local;
/*! This option indicates the error correction scheme used in transmitted UDPTL
- packets. */
- int error_correction_scheme;
+ * packets and expected in received UDPTL packets.
+ */
+ enum ast_t38_ec_modes error_correction_scheme;
/*! This option indicates the number of error correction entries transmitted in
- UDPTL packets. */
- int error_correction_entries;
+ * UDPTL packets and expected in received UDPTL packets.
+ */
+ unsigned int error_correction_entries;
/*! This option indicates the span of the error correction entries in transmitted
- UDPTL packets (FEC only). */
- int error_correction_span;
-
- /*! This option indicates the maximum size of a UDPTL packet that can be accepted by
- the remote device. */
- int far_max_datagram_size;
-
- /*! This option indicates the maximum size of a UDPTL packet that we are prepared to
- accept. */
- int local_max_datagram_size;
+ * UDPTL packets (FEC only).
+ */
+ unsigned int error_correction_span;
+
+ /*! The maximum size UDPTL packet that can be accepted by
+ * the remote device.
+ */
+ unsigned int far_max_datagram;
+
+ /*! The maximum size UDPTL packet that we are prepared to
+ * accept.
+ */
+ unsigned int local_max_datagram;
+
+ /*! The maximum IFP that can be submitted for sending
+ * to the remote device. Calculated from far_max_datagram,
+ * error_correction_scheme and error_correction_entries.
+ */
+ unsigned int far_max_ifp;
+
+ /*! The maximum IFP that the local endpoint is prepared
+ * to accept. Along with error_correction_scheme and
+ * error_correction_entries, used to calculate local_max_datagram.
+ */
+ unsigned int local_max_ifp;
int verbose;
struct sockaddr_in far;
- int tx_seq_no;
- int rx_seq_no;
- int rx_expected_seq_no;
+ unsigned int tx_seq_no;
+ unsigned int rx_seq_no;
+ unsigned int rx_expected_seq_no;
udptl_fec_tx_buffer_t tx[UDPTL_BUF_MASK + 1];
udptl_fec_rx_buffer_t rx[UDPTL_BUF_MASK + 1];
@@ -158,23 +174,20 @@ struct ast_udptl {
static AST_RWLIST_HEAD_STATIC(protos, ast_udptl_protocol);
-static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len);
-static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len);
-
-static inline int udptl_debug_test_addr(struct sockaddr_in *addr)
+static inline int udptl_debug_test_addr(const struct sockaddr_in *addr)
{
if (udptldebug == 0)
return 0;
if (udptldebugaddr.sin_addr.s_addr) {
- if (((ntohs(udptldebugaddr.sin_port) != 0)
- && (udptldebugaddr.sin_port != addr->sin_port))
- || (udptldebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
+ if (((ntohs(udptldebugaddr.sin_port) != 0) &&
+ (udptldebugaddr.sin_port != addr->sin_port)) ||
+ (udptldebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
return 0;
}
return 1;
}
-static int decode_length(uint8_t *buf, int limit, int *len, int *pvalue)
+static int decode_length(uint8_t *buf, unsigned int limit, unsigned int *len, unsigned int *pvalue)
{
if (*len >= limit)
return -1;
@@ -199,15 +212,16 @@ static int decode_length(uint8_t *buf, int limit, int *len, int *pvalue)
}
/*- End of function --------------------------------------------------------*/
-static int decode_open_type(uint8_t *buf, int limit, int *len, const uint8_t **p_object, int *p_num_octets)
+static int decode_open_type(uint8_t *buf, unsigned int limit, unsigned int *len, const uint8_t **p_object, unsigned int *p_num_octets)
{
- int octet_cnt;
- int octet_idx;
- int length;
- int i;
+ unsigned int octet_cnt;
+ unsigned int octet_idx;
+ unsigned int length;
+ unsigned int i;
const uint8_t **pbuf;
for (octet_idx = 0, *p_num_octets = 0; ; octet_idx += octet_cnt) {
+ octet_cnt = 0;
if ((length = decode_length(buf, limit, len, &octet_cnt)) < 0)
return -1;
if (octet_cnt > 0) {
@@ -229,9 +243,9 @@ static int decode_open_type(uint8_t *buf, int limit, int *len, const uint8_t **p
}
/*- End of function --------------------------------------------------------*/
-static int encode_length(uint8_t *buf, int *len, int value)
+static unsigned int encode_length(uint8_t *buf, unsigned int *len, unsigned int value)
{
- int multiplier;
+ unsigned int multiplier;
if (value < 0x80) {
/* 1 octet */
@@ -257,10 +271,10 @@ static int encode_length(uint8_t *buf, int *len, int value)
}
/*- End of function --------------------------------------------------------*/
-static int encode_open_type(uint8_t *buf, int buflen, int *len, const uint8_t *data, int num_octets)
+static int encode_open_type(uint8_t *buf, unsigned int buflen, unsigned int *len, const uint8_t *data, unsigned int num_octets)
{
- int enclen;
- int octet_idx;
+ unsigned int enclen;
+ unsigned int octet_idx;
uint8_t zero_byte;
/* If open type is of zero length, add a single zero byte (10.1) */
@@ -289,7 +303,7 @@ static int encode_open_type(uint8_t *buf, int buflen, int *len, const uint8_t *d
}
/*- End of function --------------------------------------------------------*/
-static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len)
+static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, unsigned int len)
{
int stat1;
int stat2;
@@ -301,16 +315,16 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len)
int x;
int limit;
int which;
- int ptr;
- int count;
+ unsigned int ptr;
+ unsigned int count;
int total_count;
int seq_no;
const uint8_t *ifp;
const uint8_t *data;
- int ifp_len;
+ unsigned int ifp_len;
int repaired[16];
const uint8_t *bufs[16];
- int lengths[16];
+ unsigned int lengths[16];
int span;
int entries;
int ifp_no;
@@ -497,7 +511,7 @@ static int udptl_rx_packet(struct ast_udptl *s, uint8_t *buf, int len)
}
/*- End of function --------------------------------------------------------*/
-static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uint8_t *ifp, int ifp_len)
+static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, unsigned int buflen, uint8_t *ifp, unsigned int ifp_len)
{
uint8_t fec[LOCAL_FAX_MAX_DATAGRAM * 2];
int i;
@@ -507,7 +521,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uin
int entries;
int span;
int m;
- int len;
+ unsigned int len;
int limit;
int high_tide;
@@ -612,7 +626,7 @@ static int udptl_build_packet(struct ast_udptl *s, uint8_t *buf, int buflen, uin
return len;
}
-int ast_udptl_fd(struct ast_udptl *udptl)
+int ast_udptl_fd(const struct ast_udptl *udptl)
{
return udptl->fd;
}
@@ -695,15 +709,67 @@ struct ast_frame *ast_udptl_read(struct ast_udptl *udptl)
return &udptl->f[0];
}
-void ast_udptl_offered_from_local(struct ast_udptl* udptl, int local)
+static void calculate_local_max_datagram(struct ast_udptl *udptl)
{
- if (udptl)
- udptl->udptl_offered_from_local = local;
- else
- ast_log(LOG_WARNING, "udptl structure is null\n");
+ unsigned int new_max = 200;
+
+ /* calculate the amount of space required to receive an IFP
+ * using the current error correction mode, and ensure that our
+ * local max datagram size is at least that big
+ */
+ switch (udptl->error_correction_scheme) {
+ case UDPTL_ERROR_CORRECTION_NONE:
+ /* only need room for sequence number and length indicators */
+ new_max = 6 + udptl->local_max_ifp;
+ break;
+ case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+ /* need room for sequence number, length indicators and the
+ * configured number of redundant packets
+ */
+ new_max = 6 + udptl->local_max_ifp + 2 + (udptl->error_correction_entries * udptl->local_max_ifp);
+ break;
+ case UDPTL_ERROR_CORRECTION_FEC:
+ /* need room for sequence number, length indicators and a
+ * a single IFP of the maximum size expected
+ */
+ new_max = 6 + udptl->local_max_ifp + 4 + udptl->local_max_ifp;
+ break;
+ }
+ /* add 25% of extra space for insurance, but no larger than LOCAL_FAX_MAX_DATAGRAM */
+ udptl->local_max_datagram = MIN(new_max * 1.25, LOCAL_FAX_MAX_DATAGRAM);
+}
+
+static void calculate_far_max_ifp(struct ast_udptl *udptl)
+{
+ unsigned new_max = 40;
+
+ /* calculate the maximum IFP the local endpoint should
+ * generate based on the far end's maximum datagram size
+ * and the current error correction mode
+ */
+ switch (udptl->error_correction_scheme) {
+ case UDPTL_ERROR_CORRECTION_NONE:
+ /* only need room for sequence number and length indicators */
+ new_max = udptl->far_max_datagram - 6;
+ break;
+ case UDPTL_ERROR_CORRECTION_REDUNDANCY:
+ /* need room for sequence number, length indicators and the
+ * configured number of redundant packets
+ */
+ new_max = (udptl->far_max_datagram - 8) / (udptl->error_correction_entries + 1);
+ break;
+ case UDPTL_ERROR_CORRECTION_FEC:
+ /* need room for sequence number, length indicators and a
+ * a single IFP of the maximum size expected
+ */
+ new_max = (udptl->far_max_datagram - 10) / 2;
+ break;
+ }
+ /* subtract 25% of space for insurance */
+ udptl->far_max_ifp = new_max * 0.75;
}
-int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl)
+int ast_udptl_get_error_correction_scheme(const struct ast_udptl *udptl)
{
if (udptl)
return udptl->error_correction_scheme;
@@ -713,60 +779,75 @@ int ast_udptl_get_error_correction_scheme(struct ast_udptl* udptl)
}
}
-void ast_udptl_set_error_correction_scheme(struct ast_udptl* udptl, int ec)
+void ast_udptl_set_error_correction_scheme(struct ast_udptl *udptl, enum ast_t38_ec_modes ec)
{
if (udptl) {
+ udptl->error_correction_scheme = ec;
switch (ec) {
case UDPTL_ERROR_CORRECTION_FEC:
udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC;
+ if (udptl->error_correction_entries == 0) {
+ udptl->error_correction_entries = 3;
+ }
+ if (udptl->error_correction_span == 0) {
+ udptl->error_correction_span = 3;
+ }
break;
case UDPTL_ERROR_CORRECTION_REDUNDANCY:
udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY;
- break;
- case UDPTL_ERROR_CORRECTION_NONE:
- udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_NONE;
+ if (udptl->error_correction_entries == 0) {
+ udptl->error_correction_entries = 3;
+ }
break;
default:
- ast_log(LOG_WARNING, "error correction parameter invalid\n");
+ /* nothing to do */
+ break;
};
+ calculate_local_max_datagram(udptl);
+ calculate_far_max_ifp(udptl);
} else
ast_log(LOG_WARNING, "udptl structure is null\n");
}
-int ast_udptl_get_local_max_datagram(struct ast_udptl* udptl)
+unsigned int ast_udptl_get_local_max_datagram(const struct ast_udptl *udptl)
{
if (udptl)
- return udptl->local_max_datagram_size;
+ return udptl->local_max_datagram;
else {
ast_log(LOG_WARNING, "udptl structure is null\n");
- return -1;
+ return 0;
}
}
-int ast_udptl_get_far_max_datagram(struct ast_udptl* udptl)
+unsigned int ast_udptl_get_far_max_datagram(const struct ast_udptl *udptl)
{
if (udptl)
- return udptl->far_max_datagram_size;
+ return udptl->far_max_datagram;
else {
ast_log(LOG_WARNING, "udptl structure is null\n");
- return -1;
+ return 0;
}
}
-void ast_udptl_set_local_max_datagram(struct ast_udptl* udptl, int max_datagram)
+void ast_udptl_set_far_max_datagram(struct ast_udptl *udptl, unsigned int max_datagram)
{
- if (udptl)
- udptl->local_max_datagram_size = max_datagram;
- else
+ if (udptl) {
+ udptl->far_max_datagram = max_datagram;
+ calculate_far_max_ifp(udptl);
+ } else {
ast_log(LOG_WARNING, "udptl structure is null\n");
+ }
}
-void ast_udptl_set_far_max_datagram(struct ast_udptl* udptl, int max_datagram)
+void ast_udptl_set_local_max_ifp(struct ast_udptl *udptl, unsigned int max_ifp)
{
- if (udptl)
- udptl->far_max_datagram_size = max_datagram;
- else
- ast_log(LOG_WARNING, "udptl structure is null\n");
+ udptl->local_max_ifp = max_ifp;
+ calculate_local_max_datagram(udptl);
+}
+
+unsigned int ast_udptl_get_far_max_ifp(const struct ast_udptl *udptl)
+{
+ return udptl->far_max_ifp;
}
struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struct io_context *io, int callbackmode, struct in_addr addr)
@@ -780,20 +861,13 @@ struct ast_udptl *ast_udptl_new_with_bindaddr(struct sched_context *sched, struc
if (!(udptl = ast_calloc(1, sizeof(*udptl))))
return NULL;
- if (udptlfectype == 2)
- udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_FEC;
- else if (udptlfectype == 1)
- udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_REDUNDANCY;
- else
- udptl->error_correction_scheme = UDPTL_ERROR_CORRECTION_NONE;
+ udptl->error_correction_scheme = udptlfectype;
udptl->error_correction_span = udptlfecspan;
udptl->error_correction_entries = udptlfecentries;
- udptl->far_max_datagram_size = udptlmaxdatagram;
- udptl->local_max_datagram_size = udptlmaxdatagram;
+ udptl->far_max_datagram = udptlmaxdatagram;
+ udptl->local_max_datagram = udptlmaxdatagram;
- memset(&udptl->rx, 0, sizeof(udptl->rx));
- memset(&udptl->tx, 0, sizeof(udptl->tx));
for (i = 0; i <= UDPTL_BUF_MASK; i++) {
udptl->rx[i].buf_len = -1;
udptl->tx[i].buf_len = -1;
@@ -852,18 +926,18 @@ struct ast_udptl *ast_udptl_new(struct sched_context *sched, struct io_context *
return ast_udptl_new_with_bindaddr(sched, io, callbackmode, ia);
}
-int ast_udptl_setqos(struct ast_udptl *udptl, int tos, int cos)
+int ast_udptl_setqos(struct ast_udptl *udptl, unsigned int tos, unsigned int cos)
{
return ast_netsock_set_qos(udptl->fd, tos, cos, "UDPTL");
}
-void ast_udptl_set_peer(struct ast_udptl *udptl, struct sockaddr_in *them)
+void ast_udptl_set_peer(struct ast_udptl *udptl, const struct sockaddr_in *them)
{
udptl->them.sin_port = them->sin_port;
udptl->them.sin_addr = them->sin_addr;
}
-void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them)
+void ast_udptl_get_peer(const struct ast_udptl *udptl, struct sockaddr_in *them)
{
memset(them, 0, sizeof(*them));
them->sin_family = AF_INET;
@@ -871,7 +945,7 @@ void ast_udptl_get_peer(struct ast_udptl *udptl, struct sockaddr_in *them)
them->sin_addr = udptl->them.sin_addr;
}
-void ast_udptl_get_us(struct ast_udptl *udptl, struct sockaddr_in *us)
+void ast_udptl_get_us(const struct ast_udptl *udptl, struct sockaddr_in *us)
{
memcpy(us, &udptl->us, sizeof(udptl->us));
}
@@ -893,10 +967,10 @@ void ast_udptl_destroy(struct ast_udptl *udptl)
int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
{
- int seq;
- int len;
+ unsigned int seq;
+ unsigned int len;
int res;
- uint8_t buf[LOCAL_FAX_MAX_DATAGRAM * 2];
+ uint8_t buf[s->far_max_datagram];
/* If we have no peer, return immediately */
if (s->them.sin_addr.s_addr == INADDR_ANY)
@@ -906,11 +980,16 @@ int ast_udptl_write(struct ast_udptl *s, struct ast_frame *f)
if (f->datalen == 0)
return 0;
- if (f->frametype != AST_FRAME_MODEM) {
- ast_log(LOG_WARNING, "UDPTL can only send T.38 data\n");
+ if ((f->frametype != AST_FRAME_MODEM) ||
+ (f->subclass != AST_MODEM_T38)) {
+ ast_log(LOG_WARNING, "UDPTL can only send T.38 data.\n");
return -1;
}
+ if (f->datalen > s->far_max_ifp) {
+ ast_log(LOG_WARNING, "UDPTL asked to send %d bytes of IFP when far end only prepared to accept %d bytes; data loss may occur.\n", f->datalen, s->far_max_ifp);
+ }
+
/* Save seq_no for debug output because udptl_build_packet increments it */
seq = s->tx_seq_no & 0xFFFF;
@@ -1234,7 +1313,7 @@ static void __ast_udptl_reload(int reload)
udptlstart = 4500;
udptlend = 4999;
- udptlfectype = 0;
+ udptlfectype = UDPTL_ERROR_CORRECTION_NONE;
udptlfecentries = 0;
udptlfecspan = 0;
udptlmaxdatagram = 0;
@@ -1275,9 +1354,9 @@ static void __ast_udptl_reload(int reload)
}
if ((s = ast_variable_retrieve(cfg, "general", "T38FaxUdpEC"))) {
if (strcmp(s, "t38UDPFEC") == 0)
- udptlfectype = 2;
+ udptlfectype = UDPTL_ERROR_CORRECTION_FEC;
else if (strcmp(s, "t38UDPRedundancy") == 0)
- udptlfectype = 1;
+ udptlfectype = UDPTL_ERROR_CORRECTION_REDUNDANCY;
}
if ((s = ast_variable_retrieve(cfg, "general", "T38FaxMaxDatagram"))) {
udptlmaxdatagram = atoi(s);