mirror of
https://github.com/signalwire/freeswitch.git
synced 2026-11-14 13:28:31 +00:00
update to spandsp-0.0.6pre12
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@13311 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
1 parent
92955376b2
commit
5d21a6e4b2
11 files changed
+618
-368
No files matched your search
+143
-39
@@ -5,7 +5,7 @@
|
||||
*
|
||||
* Written by Steve Underwood <steveu@coppice.org>
|
||||
*
|
||||
* Copyright (C) 2003, 2004, 2005, 2006, 2007 Steve Underwood
|
||||
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Steve Underwood
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
@@ -22,7 +22,7 @@
|
||||
* License along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
* $Id: t30.c,v 1.291 2009/04/23 15:40:32 steveu Exp $
|
||||
* $Id: t30.c,v 1.298 2009/04/30 18:46:14 steveu Exp $
|
||||
*/
|
||||
|
||||
/*! \file */
|
||||
@@ -73,8 +73,13 @@
|
||||
|
||||
#include "t30_local.h"
|
||||
|
||||
/*! The maximum number of consecutive retries allowed. */
|
||||
#define MAX_MESSAGE_TRIES 3
|
||||
/*! The maximum permitted number of retries of a single command allowed. */
|
||||
#define MAX_COMMAND_TRIES 3
|
||||
|
||||
/*! The maximum permitted number of retries of a single response request allowed. This
|
||||
is not specified in T.30. However, if you don't apply some limit a messed up FAX
|
||||
terminal could keep you retrying all day. Its a backstop protection. */
|
||||
#define MAX_RESPONSE_TRIES 6
|
||||
|
||||
/*! Conversion between milliseconds and audio samples. */
|
||||
#define ms_to_samples(t) (((t)*SAMPLE_RATE)/1000)
|
||||
@@ -245,7 +250,7 @@ term it T2A. No tolerance is specified for this timer. T2A specifies the maximum
|
||||
end of a frame, after the initial flag has been seen. */
|
||||
#define DEFAULT_TIMER_T2A 3000
|
||||
|
||||
/*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. if we
|
||||
/*! If the HDLC carrier falls during reception, we need to apply a minimum time before continuing. If we
|
||||
don't, there are circumstances where we could continue and reply before the incoming signals have
|
||||
really finished. E.g. if a bad DCS is received in a DCS-TCF sequence, we need wait for the TCF
|
||||
carrier to pass, before continuing. This timer is specified as 200ms, but no tolerance is specified.
|
||||
@@ -316,14 +321,16 @@ received. If the timer T8 expires, a DCN command is transmitted for call release
|
||||
|
||||
enum
|
||||
{
|
||||
TIMER_IS_T2 = 0,
|
||||
TIMER_IS_T2A = 1,
|
||||
TIMER_IS_T2B = 2,
|
||||
TIMER_IS_T2C = 3,
|
||||
TIMER_IS_T4 = 4,
|
||||
TIMER_IS_T4A = 5,
|
||||
TIMER_IS_T4B = 6,
|
||||
TIMER_IS_T4C = 7
|
||||
TIMER_IS_IDLE = 0,
|
||||
TIMER_IS_T2,
|
||||
TIMER_IS_T1A,
|
||||
TIMER_IS_T2A,
|
||||
TIMER_IS_T2B,
|
||||
TIMER_IS_T2C,
|
||||
TIMER_IS_T4,
|
||||
TIMER_IS_T4A,
|
||||
TIMER_IS_T4B,
|
||||
TIMER_IS_T4C
|
||||
};
|
||||
|
||||
/* Start points in the fallback table for different capabilities */
|
||||
@@ -2507,6 +2514,9 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len)
|
||||
{
|
||||
unexpected_frame_length(s, msg, len);
|
||||
}
|
||||
/* We have received something, so any missing carrier status is out of date */
|
||||
if (s->current_status == T30_ERR_RX_NOCARRIER)
|
||||
s->current_status = T30_ERR_OK;
|
||||
break;
|
||||
default:
|
||||
unexpected_non_final_frame(s, msg, len);
|
||||
@@ -2517,16 +2527,21 @@ static void process_rx_fcd(t30_state_t *s, const uint8_t *msg, int len)
|
||||
|
||||
static void process_rx_rcp(t30_state_t *s, const uint8_t *msg, int len)
|
||||
{
|
||||
/* Return to control for partial page. These might come through with or without the final frame tag,
|
||||
so we have this routine to deal with the "no final frame tag" case. */
|
||||
/* Return to control for partial page. These might come through with or without the final frame tag.
|
||||
Here we deal with the "no final frame tag" case. */
|
||||
switch (s->state)
|
||||
{
|
||||
case T30_STATE_F_DOC_ECM:
|
||||
set_state(s, T30_STATE_F_POST_DOC_ECM);
|
||||
queue_phase(s, T30_PHASE_D_RX);
|
||||
timer_t2_start(s);
|
||||
/* We have received something, so any missing carrier status is out of date */
|
||||
if (s->current_status == T30_ERR_RX_NOCARRIER)
|
||||
s->current_status = T30_ERR_OK;
|
||||
break;
|
||||
case T30_STATE_F_POST_DOC_ECM:
|
||||
/* Just ignore this */
|
||||
/* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance
|
||||
of receiving a correct one. */
|
||||
break;
|
||||
default:
|
||||
unexpected_non_final_frame(s, msg, len);
|
||||
@@ -2773,7 +2788,7 @@ static void process_state_d_post_tcf(t30_state_t *s, const uint8_t *msg, int len
|
||||
break;
|
||||
case T30_DIS:
|
||||
/* It appears they didn't see what we sent - retry the TCF */
|
||||
if (++s->retries >= MAX_MESSAGE_TRIES)
|
||||
if (++s->retries >= MAX_COMMAND_TRIES)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Too many retries. Giving up.\n");
|
||||
s->current_status = T30_ERR_RETRYDCN;
|
||||
@@ -2827,6 +2842,10 @@ static void process_state_f_cfr(t30_state_t *s, const uint8_t *msg, int len)
|
||||
/* We're waiting for a response to the CFR we sent */
|
||||
switch (msg[2] & 0xFE)
|
||||
{
|
||||
case T30_DCS:
|
||||
/* If we received another DCS, they must have missed our CFR */
|
||||
process_rx_dcs(s, msg, len);
|
||||
break;
|
||||
case T30_CRP:
|
||||
repeat_last_command(s);
|
||||
break;
|
||||
@@ -3150,7 +3169,7 @@ static void process_state_f_post_doc_non_ecm(t30_state_t *s, const uint8_t *msg,
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void process_state_f_doc_ecm(t30_state_t *s, const uint8_t *msg, int len)
|
||||
static void process_state_f_doc_and_post_doc_ecm(t30_state_t *s, const uint8_t *msg, int len)
|
||||
{
|
||||
uint8_t fcf2;
|
||||
|
||||
@@ -3164,16 +3183,22 @@ static void process_state_f_doc_ecm(t30_state_t *s, const uint8_t *msg, int len)
|
||||
process_rx_dcs(s, msg, len);
|
||||
break;
|
||||
case T4_RCP:
|
||||
/* Return to control for partial page. These might come through with or without the final frame tag.
|
||||
Here we deal with the "final frame tag" case. */
|
||||
if (s->state == T30_STATE_F_DOC_ECM)
|
||||
{
|
||||
/* Return to control for partial page */
|
||||
queue_phase(s, T30_PHASE_D_RX);
|
||||
set_state(s, T30_STATE_F_POST_DOC_ECM);
|
||||
queue_phase(s, T30_PHASE_D_RX);
|
||||
timer_t2_start(s);
|
||||
/* We have received something, so any missing carrier status is out of date */
|
||||
if (s->current_status == T30_ERR_RX_NOCARRIER)
|
||||
s->current_status = T30_ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ignore extra RCP frames. The source will usually send several to maximise the chance of
|
||||
one getting through OK. */
|
||||
/* Just ignore this. It must be an extra RCP. Several are usually sent, to maximise the chance
|
||||
of receiving a correct one. */
|
||||
}
|
||||
break;
|
||||
case T30_EOR:
|
||||
@@ -4166,6 +4191,7 @@ static void process_rx_control_msg(t30_state_t *s, const uint8_t *msg, int len)
|
||||
/* Restart the command or response timer, T2 or T4 */
|
||||
switch (s->timer_t2_t4_is)
|
||||
{
|
||||
case TIMER_IS_T1A:
|
||||
case TIMER_IS_T2:
|
||||
case TIMER_IS_T2A:
|
||||
case TIMER_IS_T2B:
|
||||
@@ -4358,7 +4384,7 @@ static void process_rx_control_msg(t30_state_t *s, const uint8_t *msg, int len)
|
||||
break;
|
||||
case T30_STATE_F_DOC_ECM:
|
||||
case T30_STATE_F_POST_DOC_ECM:
|
||||
process_state_f_doc_ecm(s, msg, len);
|
||||
process_state_f_doc_and_post_doc_ecm(s, msg, len);
|
||||
break;
|
||||
case T30_STATE_F_POST_RCP_MCF:
|
||||
process_state_f_post_rcp_mcf(s, msg, len);
|
||||
@@ -4564,7 +4590,7 @@ static void set_state(t30_state_t *s, int state)
|
||||
static void repeat_last_command(t30_state_t *s)
|
||||
{
|
||||
s->step = 0;
|
||||
if (++s->retries >= MAX_MESSAGE_TRIES)
|
||||
if (++s->retries >= MAX_COMMAND_TRIES)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Too many retries. Giving up.\n");
|
||||
switch (s->state)
|
||||
@@ -4670,13 +4696,14 @@ static void timer_t2a_start(t30_state_t *s)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Start T1A\n");
|
||||
s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T1A);
|
||||
s->timer_t2_t4_is = TIMER_IS_T1A;
|
||||
}
|
||||
else
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Start T2A\n");
|
||||
s->timer_t2_t4 = ms_to_samples(DEFAULT_TIMER_T2A);
|
||||
s->timer_t2_t4_is = TIMER_IS_T2A;
|
||||
}
|
||||
s->timer_t2_t4_is = TIMER_IS_T2A;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
@@ -4714,8 +4741,47 @@ static void timer_t4b_start(t30_state_t *s)
|
||||
|
||||
static void timer_t2_t4_stop(t30_state_t *s)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Stop T2/T4\n");
|
||||
const char *tag;
|
||||
|
||||
switch (s->timer_t2_t4_is)
|
||||
{
|
||||
case TIMER_IS_IDLE:
|
||||
tag = "none";
|
||||
break;
|
||||
case TIMER_IS_T1A:
|
||||
tag = "T1A";
|
||||
break;
|
||||
case TIMER_IS_T2:
|
||||
tag = "T2";
|
||||
break;
|
||||
case TIMER_IS_T2A:
|
||||
tag = "T2A";
|
||||
break;
|
||||
case TIMER_IS_T2B:
|
||||
tag = "T2B";
|
||||
break;
|
||||
case TIMER_IS_T2C:
|
||||
tag = "T2C";
|
||||
break;
|
||||
case TIMER_IS_T4:
|
||||
tag = "T4";
|
||||
break;
|
||||
case TIMER_IS_T4A:
|
||||
tag = "T4A";
|
||||
break;
|
||||
case TIMER_IS_T4B:
|
||||
tag = "T4B";
|
||||
break;
|
||||
case TIMER_IS_T4C:
|
||||
tag = "T4C";
|
||||
break;
|
||||
default:
|
||||
tag = "T2/T4";
|
||||
break;
|
||||
}
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "Stop %s (%d remaining)\n", tag, s->timer_t2_t4);
|
||||
s->timer_t2_t4 = 0;
|
||||
s->timer_t2_t4_is = TIMER_IS_IDLE;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
@@ -4754,7 +4820,8 @@ static void timer_t1_expired(t30_state_t *s)
|
||||
|
||||
static void timer_t2_expired(t30_state_t *s)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "T2 expired in phase %s, state %d\n", phase_names[s->phase], s->state);
|
||||
if (s->timer_t2_t4_is != TIMER_IS_T2B)
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "T2 expired in phase %s, state %d\n", phase_names[s->phase], s->state);
|
||||
switch (s->state)
|
||||
{
|
||||
case T30_STATE_III_Q_MCF:
|
||||
@@ -4820,6 +4887,14 @@ static void timer_t2_expired(t30_state_t *s)
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void timer_t1a_expired(t30_state_t *s)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "T1A expired in phase %s, state %d. An HDLC frame lasted too long.\n", phase_names[s->phase], s->state);
|
||||
s->current_status = T30_ERR_HDLC_CARRIER;
|
||||
disconnect(s);
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
static void timer_t2a_expired(t30_state_t *s)
|
||||
{
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "T2A expired in phase %s, state %d. An HDLC frame lasted too long.\n", phase_names[s->phase], s->state);
|
||||
@@ -5273,6 +5348,7 @@ SPAN_DECLARE(int) t30_non_ecm_get_chunk(void *user_data, uint8_t buf[], int max_
|
||||
static void t30_hdlc_rx_status(void *user_data, int status)
|
||||
{
|
||||
t30_state_t *s;
|
||||
int was_trained;
|
||||
|
||||
s = (t30_state_t *) user_data;
|
||||
span_log(&s->logging, SPAN_LOG_FLOW, "HDLC signal status is %s (%d) in state %d\n", signal_status_to_str(status), status, s->state);
|
||||
@@ -5293,32 +5369,56 @@ static void t30_hdlc_rx_status(void *user_data, int status)
|
||||
switch (s->timer_t2_t4_is)
|
||||
{
|
||||
case TIMER_IS_T2B:
|
||||
s->timer_t2_t4_is = TIMER_IS_T2C;
|
||||
timer_t2_t4_stop(s);
|
||||
s->timer_t2_t4_is = TIMER_IS_T2C;
|
||||
break;
|
||||
case TIMER_IS_T4B:
|
||||
s->timer_t2_t4_is = TIMER_IS_T4C;
|
||||
timer_t2_t4_stop(s);
|
||||
s->timer_t2_t4_is = TIMER_IS_T4C;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case SIG_STATUS_CARRIER_DOWN:
|
||||
was_trained = s->rx_trained;
|
||||
s->rx_signal_present = FALSE;
|
||||
s->rx_trained = FALSE;
|
||||
/* If a phase change has been queued to occur after the receive signal drops,
|
||||
its time to change. */
|
||||
if (s->state == T30_STATE_F_DOC_ECM)
|
||||
{
|
||||
/* We should be receiving a document right now, but we haven't seen an RCP at the end of
|
||||
transmission. */
|
||||
if (was_trained)
|
||||
{
|
||||
/* We trained OK, so we should have some kind of received page, possibly with
|
||||
zero good HDLC frames. It just did'nt end cleanly with an RCP. */
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "ECM signal did not end cleanly\n");
|
||||
/* Fake the existance of an RCP, and proceed */
|
||||
set_state(s, T30_STATE_F_POST_DOC_ECM);
|
||||
queue_phase(s, T30_PHASE_D_RX);
|
||||
timer_t2_start(s);
|
||||
/* We at least trained, so any missing carrier status is out of date */
|
||||
if (s->current_status == T30_ERR_RX_NOCARRIER)
|
||||
s->current_status = T30_ERR_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Either there was no image carrier, or we failed to train to it. */
|
||||
span_log(&s->logging, SPAN_LOG_WARNING, "ECM carrier not found\n");
|
||||
s->current_status = T30_ERR_RX_NOCARRIER;
|
||||
}
|
||||
}
|
||||
if (s->next_phase != T30_PHASE_IDLE)
|
||||
{
|
||||
timer_t2_t4_stop(s);
|
||||
/* The appropriate timer for the next phase should already be in progress */
|
||||
set_phase(s, s->next_phase);
|
||||
if (s->next_phase == T30_PHASE_C_NON_ECM_RX)
|
||||
timer_t2_start(s);
|
||||
s->next_phase = T30_PHASE_IDLE;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (s->timer_t2_t4_is)
|
||||
{
|
||||
case TIMER_IS_T1A:
|
||||
case TIMER_IS_T2A:
|
||||
case TIMER_IS_T2C:
|
||||
timer_t2b_start(s);
|
||||
@@ -5344,6 +5444,7 @@ static void t30_hdlc_rx_status(void *user_data, int status)
|
||||
{
|
||||
switch(s->timer_t2_t4_is)
|
||||
{
|
||||
case TIMER_IS_T1A:
|
||||
case TIMER_IS_T2:
|
||||
case TIMER_IS_T2A:
|
||||
timer_t2a_start(s);
|
||||
@@ -5416,7 +5517,7 @@ SPAN_DECLARE_NONSTD(void) t30_hdlc_accept(void *user_data, const uint8_t *msg, i
|
||||
return;
|
||||
}
|
||||
s->rx_frame_received = TRUE;
|
||||
/* Cancel the command or response timer */
|
||||
/* Cancel the command or response timer (if one is running) */
|
||||
timer_t2_t4_stop(s);
|
||||
process_rx_control_msg(s, msg, len);
|
||||
}
|
||||
@@ -5760,6 +5861,9 @@ SPAN_DECLARE(void) t30_timer_update(t30_state_t *s, int samples)
|
||||
{
|
||||
switch (s->timer_t2_t4_is)
|
||||
{
|
||||
case TIMER_IS_T1A:
|
||||
timer_t1a_expired(s);
|
||||
break;
|
||||
case TIMER_IS_T2:
|
||||
timer_t2_expired(s);
|
||||
break;
|
||||
@@ -5869,6 +5973,13 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s)
|
||||
s->far_dis_dtc_len = 0;
|
||||
memset(&s->far_dis_dtc_frame, 0, sizeof(s->far_dis_dtc_frame));
|
||||
t30_build_dis_or_dtc(s);
|
||||
memset(&s->rx_info, 0, sizeof(s->rx_info));
|
||||
release_resources(s);
|
||||
/* The ECM page number is only reset at call establishment */
|
||||
s->ecm_rx_page = 0;
|
||||
s->ecm_tx_page = 0;
|
||||
s->far_end_detected = FALSE;
|
||||
s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0);
|
||||
if (s->calling_party)
|
||||
{
|
||||
set_state(s, T30_STATE_T);
|
||||
@@ -5879,13 +5990,6 @@ SPAN_DECLARE(int) t30_restart(t30_state_t *s)
|
||||
set_state(s, T30_STATE_ANSWERING);
|
||||
set_phase(s, T30_PHASE_A_CED);
|
||||
}
|
||||
memset(&s->rx_info, 0, sizeof(s->rx_info));
|
||||
s->far_end_detected = FALSE;
|
||||
s->timer_t0_t1 = ms_to_samples(DEFAULT_TIMER_T0);
|
||||
release_resources(s);
|
||||
/* The ECM page number is only reset at call establishment */
|
||||
s->ecm_rx_page = 0;
|
||||
s->ecm_tx_page = 0;
|
||||
return 0;
|
||||
}
|
||||
/*- End of function --------------------------------------------------------*/
|
||||
|
||||
Reference in new issue
Block a user