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:
Michael Jerris committed 2009-05-14 21:52:52 +00:00
1 parent 92955376b2
commit 5d21a6e4b2
11 files changed
+618 -368

No files matched your search

+143 -39
View File
@@ -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 --------------------------------------------------------*/