]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
A typo fixed in the OKI ADPCM codec
authorSteve Underwood <steveu@coppice.org>
Wed, 16 Jun 2010 13:34:57 +0000 (21:34 +0800)
committerSteve Underwood <steveu@coppice.org>
Wed, 16 Jun 2010 13:34:57 +0000 (21:34 +0800)
The V.17 modem has been modified, so it will not clear the most recent
saved AGC value if long training is requested.
The T.38 gateway codec now has fillin implemented properly

libs/spandsp/src/oki_adpcm.c
libs/spandsp/src/spandsp/private/t38_gateway.h
libs/spandsp/src/spandsp/private/v17rx.h
libs/spandsp/src/spandsp/v17rx.h
libs/spandsp/src/t38_gateway.c
libs/spandsp/src/v17rx.c
libs/spandsp/tests/oki_adpcm_tests.c

index 787df3e32239f5509a7464c1daccb41e33aec7a4..09aea00a27ed05cbbb032eaca603ea373b2d5d31 100644 (file)
@@ -26,8 +26,6 @@
  *
  * The actual OKI ADPCM encode and decode method is derived from freely
  * available code, whose exact origins seem uncertain.
- *
- * $Id: oki_adpcm.c,v 1.32 2009/02/10 13:06:46 steveu Exp $
  */
 
 /*! \file */
@@ -153,7 +151,7 @@ static const float cutoff_coeffs[] =
 
 static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm)
 {
-    int16_t e;
+    int16_t d;
     int16_t ss;
     int16_t linear;
 
@@ -170,20 +168,20 @@ static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm)
      */
 
     ss = step_size[s->step_index];
-    e = ss >> 3;
+    d = ss >> 3;
     if (adpcm & 0x01)
-        e += (ss >> 2);
+        d += (ss >> 2);
     /*endif*/
     if (adpcm & 0x02)
-        e += (ss >> 1);
+        d += (ss >> 1);
     /*endif*/
     if (adpcm & 0x04)
-        e += ss;
+        d += ss;
     /*endif*/
     if (adpcm & 0x08)
-        e = -e;
+        d = -d;
     /*endif*/
-    linear = s->last + e;
+    linear = s->last + d;
 
     /* Saturate the values to +/- 2^11 (supposed to be 12 bits) */
     if (linear > 2047)
@@ -206,32 +204,32 @@ static int16_t decode(oki_adpcm_state_t *s, uint8_t adpcm)
 
 static uint8_t encode(oki_adpcm_state_t *s, int16_t linear)
 {
-    int16_t e;
+    int16_t d;
     int16_t ss;
     uint8_t adpcm;
 
     ss = step_size[s->step_index];
-    e = (linear >> 4) - s->last;
+    d = (linear >> 4) - s->last;
     adpcm = (uint8_t) 0x00;
-    if (e < 0)
+    if (d < 0)
     {
         adpcm = (uint8_t) 0x08;
-        e = -e;
+        d = -d;
     }
     /*endif*/
-    if (e >= ss)
+    if (d >= ss)
     {
         adpcm |= (uint8_t) 0x04;
-        e -= ss;
+        d -= ss;
     }
     /*endif*/
-    if (e >= (ss >> 1))
+    if (d >= (ss >> 1))
     {
         adpcm |= (uint8_t) 0x02;
-        e -= ss;
+        d -= (ss >> 1);
     }
     /*endif*/
-    if (e >= (ss >> 2))
+    if (d >= (ss >> 2))
         adpcm |= (uint8_t) 0x01;
     /*endif*/
 
index 9f4eed57e0fd336de36acaf664d4df4315030cc5..54a935a2701e83e6c6292ccd7713db543cdab4ab 100644 (file)
@@ -21,8 +21,6 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: t38_gateway.h,v 1.5 2009/11/07 08:58:58 steveu Exp $
  */
 
 /*! \file */
@@ -35,7 +33,7 @@
 */
 typedef struct
 {
-    /*! Core T.38 IFP support */
+    /*! \brief Core T.38 IFP support */
     t38_core_state_t t38;
 
     /*! \brief TRUE if the NSF, NSC, and NSS are to be suppressed by altering
@@ -61,9 +59,10 @@ typedef struct
 {
     /*! \brief The FAX modem set for the audio side fo the gateway. */
     fax_modems_state_t modems;
-    /*! \brief The current receive signal handler. Actual receiving hop between this
+    /*! \brief The current receive signal handler. Actual receiving hops between this
                and a dummy receive routine. */
     span_rx_handler_t *base_rx_handler;
+    span_rx_fillin_handler_t *base_rx_fillin_handler;
 } t38_gateway_audio_state_t;
 
 /*!
@@ -144,6 +143,8 @@ typedef struct
     int supported_modems;
     /*! \brief TRUE if ECM FAX mode is allowed through the gateway. */
     int ecm_allowed;
+    /*! \brief Required time between T.38 transmissions, in ms. */
+    int ms_per_tx_chunk;
 
     /*! \brief TRUE if in image data modem is to use short training. This usually
                follows image_data_mode, but in ECM mode T.30 defines recovery
index 87931b1d899a945659c57e9de21166483cf49140..bc8ad1b63c49d96bf4cf04032bdf6b2f97f0713d 100644 (file)
@@ -21,8 +21,6 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: v17rx.h,v 1.2.4.1 2009/12/24 16:52:30 steveu Exp $
  */
 
 #if !defined(_SPANDSP_PRIVATE_V17RX_H_)
 
 /* Target length for the equalizer is about 63 taps, to deal with the worst stuff
    in V.56bis. */
+/*! The length of the equalizer buffer */
+#define V17_EQUALIZER_LEN           33
+
 /*! Samples before the target position in the equalizer buffer */
-#define V17_EQUALIZER_PRE_LEN       8
-/*! Samples after the target position in the equalizer buffer */
-#define V17_EQUALIZER_POST_LEN      8
+#define V17_EQUALIZER_PRE_LEN       16
 
 /*! The number of taps in the pulse shaping/bandpass filter */
 #define V17_RX_FILTER_STEPS         27
@@ -137,7 +136,7 @@ struct v17_rx_state_s
     int eq_step;
     /*! \brief Current write offset into the equalizer buffer. */
     int eq_put_step;
-    /*! \brief Symbol counter to the next equalizer update. */
+    /*! \brief Symbol count to the next equalizer update. */
     int eq_skip;
 
     /*! \brief The current half of the baud. */
@@ -152,11 +151,11 @@ struct v17_rx_state_s
     /*! \brief The current delta factor for updating the equalizer coefficients. */
     float eq_delta;
     /*! \brief The adaptive equalizer coefficients. */
-    complexi16_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
+    complexi16_t eq_coeff[V17_EQUALIZER_LEN];
     /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
-    complexi16_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
+    complexi16_t eq_coeff_save[V17_EQUALIZER_LEN];
     /*! \brief The equalizer signal buffer. */
-    complexi16_t eq_buf[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
+    complexi16_t eq_buf[V17_EQUALIZER_LEN];
 
     /*! Low band edge filter for symbol sync. */
     int32_t symbol_sync_low[2];
@@ -175,11 +174,11 @@ struct v17_rx_state_s
     /*! \brief The current delta factor for updating the equalizer coefficients. */
     float eq_delta;
     /*! \brief The adaptive equalizer coefficients. */
-    complexf_t eq_coeff[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
+    complexf_t eq_coeff[V17_EQUALIZER_LEN];
     /*! \brief A saved set of adaptive equalizer coefficients for use after restarts. */
-    complexf_t eq_coeff_save[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
+    complexf_t eq_coeff_save[V17_EQUALIZER_LEN];
     /*! \brief The equalizer signal buffer. */
-    complexf_t eq_buf[V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN];
+    complexf_t eq_buf[V17_EQUALIZER_LEN];
 
     /*! Low band edge filter for symbol sync. */
     float symbol_sync_low[2];
index 2ab84151d3a9f5b1da0fc4686f1de959b4e60225..da4514d316237327839e6d833ce3ea724e9aff3f 100644 (file)
@@ -287,7 +287,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
     \param len The number of samples to fake.
     \return The number of samples unprocessed.
 */
-SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len);
+SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len);
 
 /*! Get a snapshot of the current equalizer coefficients.
     \brief Get a snapshot of the current equalizer coefficients.
index 6e542f3e3995af952760f8c7471efc4add26c86e..824ee16e4b30f6bdb1447565ad0d184fcaf654b0 100644 (file)
@@ -22,8 +22,6 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: t38_gateway.c,v 1.171.4.2 2009/12/19 10:44:10 steveu Exp $
  */
 
 /*! \file */
 /* This is the target time per transmission chunk. The actual
    packet timing will sync to the data octets. */
 /*! The default number of milliseconds per transmitted IFP when sending bulk T.38 data */
-#define MS_PER_TX_CHUNK                         30
+#define DEFAULT_MS_PER_TX_CHUNK                 30
+
 /*! The number of bytes which must be in the audio to T.38 HDLC buffer before we start
     outputting them as IFP messages. */
 #define HDLC_START_BUFFER_LEVEL                 8
@@ -185,11 +184,15 @@ static void non_ecm_remove_fill_and_put_bit(void *user_data, int bit);
 static void non_ecm_push_residue(t38_gateway_state_t *s);
 static void tone_detected(void *user_data, int tone, int level, int delay);
 
-static void set_rx_handler(t38_gateway_state_t *s, span_rx_handler_t *handler, void *user_data)
+static void set_rx_handler(t38_gateway_state_t *s, span_rx_handler_t *handler, span_rx_fillin_handler_t *fillin_handler, void *user_data)
 {
     if (s->audio.modems.rx_handler != span_dummy_rx)
+    {
         s->audio.modems.rx_handler = handler;
+        s->audio.modems.rx_fillin_handler = fillin_handler;
+    }
     s->audio.base_rx_handler = handler;
+    s->audio.base_rx_fillin_handler = fillin_handler;
     s->audio.modems.rx_user_data = user_data;
 }
 /*- End of function --------------------------------------------------------*/
@@ -211,6 +214,20 @@ static void set_next_tx_handler(t38_gateway_state_t *s, span_tx_handler_t *handl
 static void set_rx_active(t38_gateway_state_t *s, int active)
 {
     s->audio.modems.rx_handler = (active)  ?  s->audio.base_rx_handler  :  span_dummy_rx;
+    s->audio.modems.rx_fillin_handler = (active)  ?  s->audio.base_rx_fillin_handler  :  span_dummy_rx_fillin;
+}
+/*- End of function --------------------------------------------------------*/
+
+static int v17_v21_rx_fillin(void *user_data, int len)
+{
+    t38_gateway_state_t *t;
+    fax_modems_state_t *s;
+
+    t = (t38_gateway_state_t *) user_data;
+    s = &t->audio.modems;
+    v17_rx_fillin(&s->v17_rx, len);
+    fsk_rx_fillin(&s->v21_rx, len);
+    return 0;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -227,7 +244,7 @@ static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
         /* The fast modem has trained, so we no longer need to run the slow
            one in parallel. */
         span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.17 (%.2fdBm0)\n", v17_rx_signal_power(&s->v17_rx));
-        set_rx_handler(t, (span_rx_handler_t *) &v17_rx, &s->v17_rx);
+        set_rx_handler(t, (span_rx_handler_t *) &v17_rx, (span_rx_fillin_handler_t *) &v17_rx_fillin, &s->v17_rx);
     }
     else
     {
@@ -235,7 +252,7 @@ static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
         if (s->rx_signal_present)
         {
             span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.17 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
-            set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, &s->v21_rx);
+            set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &s->v21_rx);
         }
         /*endif*/
     }
@@ -244,6 +261,19 @@ static int v17_v21_rx(void *user_data, const int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
+static int v27ter_v21_rx_fillin(void *user_data, int len)
+{
+    t38_gateway_state_t *t;
+    fax_modems_state_t *s;
+
+    t = (t38_gateway_state_t *) user_data;
+    s = &t->audio.modems;
+    v27ter_rx_fillin(&s->v27ter_rx, len);
+    fsk_rx_fillin(&s->v21_rx, len);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
 static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
 {
     t38_gateway_state_t *t;
@@ -257,7 +287,7 @@ static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
         /* The fast modem has trained, so we no longer need to run the slow
            one in parallel. */
         span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.27ter (%.2fdBm0)\n", v27ter_rx_signal_power(&s->v27ter_rx));
-        set_rx_handler(t, (span_rx_handler_t *) &v27ter_rx, &s->v27ter_rx);
+        set_rx_handler(t, (span_rx_handler_t *) &v27ter_rx, (span_rx_fillin_handler_t *) &v27ter_v21_rx_fillin, &s->v27ter_rx);
     }
     else
     {
@@ -265,7 +295,7 @@ static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
         if (s->rx_signal_present)
         {
             span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.27ter + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
-            set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, &s->v21_rx);
+            set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &s->v21_rx);
         }
         /*endif*/
     }
@@ -274,6 +304,19 @@ static int v27ter_v21_rx(void *user_data, const int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
+static int v29_v21_rx_fillin(void *user_data, int len)
+{
+    t38_gateway_state_t *t;
+    fax_modems_state_t *s;
+
+    t = (t38_gateway_state_t *) user_data;
+    s = &t->audio.modems;
+    v29_rx_fillin(&s->v29_rx, len);
+    fsk_rx_fillin(&s->v21_rx, len);
+    return 0;
+}
+/*- End of function --------------------------------------------------------*/
+
 static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
 {
     t38_gateway_state_t *t;
@@ -287,7 +330,7 @@ static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
         /* The fast modem has trained, so we no longer need to run the slow
            one in parallel. */
         span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.29 (%.2fdBm0)\n", v29_rx_signal_power(&s->v29_rx));
-        set_rx_handler(t, (span_rx_handler_t *) &v29_rx, &s->v29_rx);
+        set_rx_handler(t, (span_rx_handler_t *) &v29_rx, (span_rx_fillin_handler_t *) &v29_rx_fillin, &s->v29_rx);
     }
     else
     {
@@ -295,7 +338,7 @@ static int v29_v21_rx(void *user_data, const int16_t amp[], int len)
         if (s->rx_signal_present)
         {
             span_log(&t->logging, SPAN_LOG_FLOW, "Switching from V.29 + V.21 to V.21 (%.2fdBm0)\n", fsk_rx_signal_power(&s->v21_rx));
-            set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, &s->v21_rx);
+            set_rx_handler(t, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &s->v21_rx);
         }
         /*endif*/
     }
@@ -651,7 +694,7 @@ static void edit_control_messages(t38_gateway_state_t *s, int from_modem, uint8_
         {
         case T30_DIS:
             /* Make sure the V.8 capability doesn't pass through. If it
-               did then two V.34 capable FAX machines might start some
+               did, two V.34 capable FAX machines might start some
                V.8 re-negotiation. */
             buf[3] &= ~DISBIT6;
             break;
@@ -827,7 +870,6 @@ static void monitor_control_messages(t38_gateway_state_t *s,
         if (len >= 6)
         {
             j = (buf[5] & (DISBIT7 | DISBIT6 | DISBIT5)) >> 4;
-            span_log(&s->logging, SPAN_LOG_FLOW, "Min bits test = 0x%X\n", buf[5]);
             s->core.min_row_bits = (s->core.fast_bit_rate*minimum_scan_line_times[j])/1000;
         }
         else
@@ -1468,7 +1510,7 @@ static void set_octets_per_data_packet(t38_gateway_state_t *s, int bit_rate)
 {
     int octets;
     
-    octets = MS_PER_TX_CHUNK*bit_rate/(8*1000);
+    octets = s->core.ms_per_tx_chunk*bit_rate/(8*1000);
     if (octets < 1)
         octets = 1;
     /*endif*/
@@ -2029,23 +2071,23 @@ static int restart_rx_modem(t38_gateway_state_t *s)
     case T38_V17_RX:
         v17_rx_restart(&s->audio.modems.v17_rx, s->core.fast_bit_rate, s->core.short_train);
         v17_rx_set_put_bit(&s->audio.modems.v17_rx, put_bit_func, put_bit_user_data);
-        set_rx_handler(s, (span_rx_handler_t *) &v17_v21_rx, s);
+        set_rx_handler(s, &v17_v21_rx, &v17_v21_rx_fillin, s);
         s->core.fast_rx_active = T38_V17_RX;
         break;
     case T38_V27TER_RX:
         v27ter_rx_restart(&s->audio.modems.v27ter_rx, s->core.fast_bit_rate, FALSE);
         v27ter_rx_set_put_bit(&s->audio.modems.v27ter_rx, put_bit_func, put_bit_user_data);
-        set_rx_handler(s, (span_rx_handler_t *) &v27ter_v21_rx, s);
+        set_rx_handler(s, &v27ter_v21_rx, &v27ter_v21_rx_fillin, s);
         s->core.fast_rx_active = T38_V27TER_RX;
         break;
     case T38_V29_RX:
         v29_rx_restart(&s->audio.modems.v29_rx, s->core.fast_bit_rate, FALSE);
         v29_rx_set_put_bit(&s->audio.modems.v29_rx, put_bit_func, put_bit_user_data);
-        set_rx_handler(s, (span_rx_handler_t *) &v29_v21_rx, s);
+        set_rx_handler(s, &v29_v21_rx, &v29_v21_rx_fillin, s);
         s->core.fast_rx_active = T38_V29_RX;
         break;
     default:
-        set_rx_handler(s, (span_rx_handler_t *) &fsk_rx, &(s->audio.modems.v21_rx));
+        set_rx_handler(s, (span_rx_handler_t *) &fsk_rx, (span_rx_fillin_handler_t *) &fsk_rx_fillin, &(s->audio.modems.v21_rx));
         s->core.fast_rx_active = T38_NONE;
         break;
     }
@@ -2054,15 +2096,8 @@ static int restart_rx_modem(t38_gateway_state_t *s)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
+static void update_rx_timing(t38_gateway_state_t *s, int len)
 {
-    int i;
-
-#if defined(LOG_FAX_AUDIO)
-    if (s->audio.modems.audio_rx_log >= 0)
-        write(s->audio.modems.audio_rx_log, amp, len*sizeof(int16_t));
-    /*endif*/
-#endif
     if (s->core.samples_to_timeout > 0)
     {
         if ((s->core.samples_to_timeout -= len) <= 0)
@@ -2096,6 +2131,19 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
         /*endif*/
     }
     /*endif*/
+}
+/*- End of function --------------------------------------------------------*/
+
+SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], int len)
+{
+    int i;
+
+#if defined(LOG_FAX_AUDIO)
+    if (s->audio.modems.audio_rx_log >= 0)
+        write(s->audio.modems.audio_rx_log, amp, len*sizeof(int16_t));
+    /*endif*/
+#endif
+    update_rx_timing(s, len);
     for (i = 0;  i < len;  i++)
         amp[i] = dc_restore(&(s->audio.modems.dc_restore), amp[i]);
     /*endfor*/
@@ -2106,7 +2154,28 @@ SPAN_DECLARE_NONSTD(int) t38_gateway_rx(t38_gateway_state_t *s, int16_t amp[], i
 
 SPAN_DECLARE_NONSTD(int) t38_gateway_rx_fillin(t38_gateway_state_t *s, int len)
 {
-    /* TODO: handle things properly */
+    /* To mitigate the effect of lost packets on a packet network we should
+       try to sustain the status quo. If there is no receive modem running, keep
+       things that way. If there is a receive modem running, try to sustain its
+       operation, without causing a phase hop, or letting its adaptive functions
+       diverge. */
+#if defined(LOG_FAX_AUDIO)
+    if (s->audio.modems.audio_rx_log >= 0)
+    {
+        int i;
+#if defined(_MSC_VER)
+        int16_t *amp = (int16_t *) _alloca(sizeof(int16_t)*len);
+#else
+        int16_t amp[len];
+#endif
+
+        vec_zeroi16(amp, len);
+        write(s->modems.audio_rx_log, amp, len*sizeof(int16_t));
+    }
+#endif
+    update_rx_timing(s, len);
+    /* TODO: handle the modems properly */
+    s->audio.modems.rx_fillin_handler(s->audio.modems.rx_user_data, len);
     return  0;
 }
 /*- End of function --------------------------------------------------------*/
@@ -2301,11 +2370,12 @@ SPAN_DECLARE(t38_gateway_state_t *) t38_gateway_init(t38_gateway_state_t *s,
     t38_gateway_t38_init(s, tx_packet_handler, tx_packet_user_data);
     
     set_rx_active(s, TRUE);
-    t38_gateway_set_supported_modems(s, T30_SUPPORT_V27TER | T30_SUPPORT_V29);
+    t38_gateway_set_supported_modems(s, T30_SUPPORT_V27TER | T30_SUPPORT_V29 | T30_SUPPORT_V17);
     t38_gateway_set_nsx_suppression(s, (const uint8_t *) "\x00\x00\x00", 3, (const uint8_t *) "\x00\x00\x00", 3);
 
     s->core.to_t38.octets_per_data_packet = 1;
     s->core.ecm_allowed = TRUE;
+    s->core.ms_per_tx_chunk = DEFAULT_MS_PER_TX_CHUNK;
     t38_non_ecm_buffer_init(&s->core.non_ecm_to_modem, FALSE, 0);
     restart_rx_modem(s);
     s->core.timed_mode = TIMED_MODE_STARTUP;
index 3620bc83f6ef5626caeae72bfe906a926e30ffe0..b5ba221cae9bfeebfd5a3c6f64585f38b69409d7 100644 (file)
@@ -22,8 +22,6 @@
  * You should have received a copy of the GNU Lesser General Public
  * License along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: v17rx.c,v 1.153.4.6 2009/12/28 12:20:46 steveu Exp $
  */
 
 /*! \file */
@@ -98,9 +96,6 @@
 /*! The 16 bit pattern used in the bridge section of the training sequence */
 #define V17_BRIDGE_WORD                 0x8880
 
-/*! The length of the equalizer buffer */
-#define V17_EQUALIZER_LEN    (V17_EQUALIZER_PRE_LEN + 1 + V17_EQUALIZER_POST_LEN)
-
 enum
 {
     TRAINING_STAGE_NORMAL_OPERATION = 0,
@@ -233,6 +228,7 @@ static void equalizer_restore(v17_rx_state_t *s)
 
     s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
     s->eq_step = 0;
+    s->eq_skip = 0;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -253,6 +249,7 @@ static void equalizer_reset(v17_rx_state_t *s)
 
     s->eq_put_step = RX_PULSESHAPER_COEFF_SETS*10/(3*2) - 1;
     s->eq_step = 0;
+    s->eq_skip = 0;
 }
 /*- End of function --------------------------------------------------------*/
 
@@ -565,7 +562,7 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
         Passband Timing Recovery in an All-Digital Modem Receiver
         IEEE TRANSACTIONS ON COMMUNICATIONS, VOL. COM-26, NO. 5, MAY 1978 */
 
-    /* This is slightly rearranged for figure 3b of the Godard paper, as this saves a couple of
+    /* This is slightly rearranged from figure 3b of the Godard paper, as this saves a couple of
        maths operations */
 #if defined(SPANDSP_USE_FIXED_POINTx)
     /* TODO: The scalings used here need more thorough evaluation, to see if overflows are possible. */
@@ -579,12 +576,12 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
     s->symbol_sync_dc_filter[0] = v;
     /* A little integration will now filter away much of the HF noise */
     s->baud_phase -= p;
-    if (abs(s->baud_phase) > 100*FP_FACTOR)
+    v = labs(s->baud_phase);
+    if (v > 100*FP_FACTOR)
     {
-        if (s->baud_phase > 0)
-            i = (s->baud_phase > 1000*FP_FACTOR)  ?  15  :  1;
-        else
-            i = (s->baud_phase < -1000*FP_FACTOR)  ?  -15  :  -1;
+        i = (v > 1000*FP_FACTOR)  ?  15  :  1;
+        if (s->baud_phase < 0)
+            i = -i;
         //printf("v = %10.5f %5d - %f %f %d %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
         s->eq_put_step += i;
         s->total_baud_timing_correction += i;
@@ -600,12 +597,12 @@ static __inline__ void symbol_sync(v17_rx_state_t *s)
     s->symbol_sync_dc_filter[0] = v;
     /* A little integration will now filter away much of the HF noise */
     s->baud_phase -= p;
-    if (fabsf(s->baud_phase) > 100.0f)
+    v = fabsf(s->baud_phase);
+    if (v > 100.0f)
     {
-        if (s->baud_phase > 0.0f)
-            i = (s->baud_phase > 1000.0f)  ?  15  :  1;
-        else
-            i = (s->baud_phase < -1000.0f)  ?  -15  :  -1;
+        i = (v > 1000.0f)  ?  15  :  1;
+        if (s->baud_phase < 0.0f)
+            i = -i;
         //printf("v = %10.5f %5d - %f %f %d\n", v, i, p, s->baud_phase, s->total_baud_timing_correction);
         s->eq_put_step += i;
         s->total_baud_timing_correction += i;
@@ -732,18 +729,14 @@ static void process_half_baud(v17_rx_state_t *s, const complexf_t *sample)
         if (s->training_count == 100)
         {
             i = s->training_count;
-            /* Avoid the possibility of a divide by zero */
-            if (i)
-            {
-                j = i & 0xF;
-                ang = (s->angles[j] - s->start_angles[0])/i
-                    + (s->angles[j | 0x1] - s->start_angles[1])/i;
-                s->carrier_phase_rate += 3*(ang/20);
-                //span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, %x, %x, dist %d\n", s->angles[j], s->start_angles[0], s->angles[j | 0x1], s->start_angles[1], i);
-
-                s->start_angles[0] = s->angles[j];
-                s->start_angles[1] = s->angles[j | 0x1];
-            }
+            j = i & 0xF;
+            ang = (s->angles[j] - s->start_angles[0])/i
+                + (s->angles[j | 0x1] - s->start_angles[1])/i;
+            s->carrier_phase_rate += 3*(ang/20);
+            //span_log(&s->logging, SPAN_LOG_FLOW, "Angles %x, %x, %x, %x, dist %d\n", s->angles[j], s->start_angles[0], s->angles[j | 0x1], s->start_angles[1], i);
+
+            s->start_angles[0] = s->angles[j];
+            s->start_angles[1] = s->angles[j | 0x1];
             //span_log(&s->logging, SPAN_LOG_FLOW, "%d %d %d %d %d\n", s->angles[s->training_count & 0xF], s->start_angles[0], s->angles[(s->training_count | 0x1) & 0xF], s->start_angles[1], s->training_count);
             span_log(&s->logging, SPAN_LOG_FLOW, "First coarse carrier frequency %7.2f (%d)\n", dds_frequencyf(s->carrier_phase_rate), s->training_count);
 
@@ -1219,7 +1212,7 @@ SPAN_DECLARE_NONSTD(int) v17_rx(v17_rx_state_t *s, const int16_t amp[], int len)
 }
 /*- End of function --------------------------------------------------------*/
 
-SPAN_DECLARE(int) v17_rx_fillin(v17_rx_state_t *s, int len)
+SPAN_DECLARE_NONSTD(int) v17_rx_fillin(v17_rx_state_t *s, int len)
 {
     int i;
 
@@ -1343,15 +1336,14 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
     s->distances[0] = 0;
     s->trellis_ptr = 14;
 
-    span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save));
     s->carrier_phase = 0;
     power_meter_init(&(s->power), 4);
 
     if (s->short_train)
     {
         s->carrier_phase_rate = s->carrier_phase_rate_save;
-        s->agc_scaling = s->agc_scaling_save;
         equalizer_restore(s);
+        s->agc_scaling = s->agc_scaling_save;
         /* Don't allow any frequency correction at all, until we start to pull the phase in. */
 #if defined(SPANDSP_USE_FIXED_POINTx)
         s->carrier_track_i = 0;
@@ -1366,18 +1358,19 @@ SPAN_DECLARE(int) v17_rx_restart(v17_rx_state_t *s, int bit_rate, int short_trai
         s->carrier_phase_rate = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
         equalizer_reset(s);
 #if defined(SPANDSP_USE_FIXED_POINTx)
-        s->agc_scaling_save = 0;
+        //s->agc_scaling_save = 0;
         s->agc_scaling = (float) FP_FACTOR*32768.0f*0.0017f/RX_PULSESHAPER_GAIN;
         s->carrier_track_i = 5000;
         s->carrier_track_p = 40000;
 #else
-        s->agc_scaling_save = 0.0f;
+        //s->agc_scaling_save = 0.0f;
         s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
         s->carrier_track_i = 5000.0f;
         s->carrier_track_p = 40000.0f;
 #endif
     }
     s->last_sample = 0;
+    span_log(&s->logging, SPAN_LOG_FLOW, "Phase rates %f %f\n", dds_frequencyf(s->carrier_phase_rate), dds_frequencyf(s->carrier_phase_rate_save));
 
     /* Initialise the working data for symbol timing synchronisation */
 #if defined(SPANDSP_USE_FIXED_POINTx)
@@ -1432,8 +1425,13 @@ SPAN_DECLARE(v17_rx_state_t *) v17_rx_init(v17_rx_state_t *s, int bit_rate, put_
     s->short_train = FALSE;
     //s->scrambler_tap = 18 - 1;
     v17_rx_signal_cutoff(s, -45.5f);
-    s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
+#if defined(SPANDSP_USE_FIXED_POINTx)
+    s->agc_scaling_save = 0;
+    s->agc_scaling = (float) FP_FACTOR*32768.0f*0.0017f/RX_PULSESHAPER_GAIN;
+#else
     s->agc_scaling_save = 0.0f;
+    s->agc_scaling = 0.0017f/RX_PULSESHAPER_GAIN;
+#endif
     s->carrier_phase_rate_save = dds_phase_ratef(CARRIER_NOMINAL_FREQ);
     v17_rx_restart(s, bit_rate, s->short_train);
     return s;
index 9bb72521dc6d6772799f6952445cdaf4dfa74289..0b761d9607ca4b4719b6058d70aa6bc451e1eda8 100644 (file)
@@ -22,8 +22,6 @@
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * $Id: oki_adpcm_tests.c,v 1.37 2009/05/30 15:23:14 steveu Exp $
  */
 
 /*! \file */
@@ -85,24 +83,33 @@ int main(int argc, char *argv[])
     int hist_out;
     oki_adpcm_state_t *oki_enc_state;
     oki_adpcm_state_t *oki_dec_state;
+    oki_adpcm_state_t *oki_dec_state2;
     int xx;
     int total_pre_samples;
     int total_compressed_bytes;
     int total_post_samples;
+    int successive_08_bytes;
+    int successive_80_bytes;
+    int encoded_fd;
+    const char *encoded_file_name;
     const char *in_file_name;
     int log_encoded_data;
     int opt;
 
     bit_rate = 32000;
+    encoded_file_name = NULL;
     in_file_name = IN_FILE_NAME;
     log_encoded_data = FALSE;
-    while ((opt = getopt(argc, argv, "2i:l")) != -1)
+    while ((opt = getopt(argc, argv, "2d:i:l")) != -1)
     {
         switch (opt)
         {
         case '2':
             bit_rate = 24000;
             break;
+        case 'd':
+            encoded_file_name = optarg;
+            break;
         case 'i':
             in_file_name = optarg;
             break;
@@ -116,24 +123,39 @@ int main(int argc, char *argv[])
         }
     }
 
-    if ((inhandle = sf_open_telephony_read(in_file_name, 1)) == NULL)
+    if (encoded_file_name)
     {
-        fprintf(stderr, "    Cannot open audio file '%s'\n", in_file_name);
-        exit(2);
+        if ((encoded_fd = open(encoded_file_name, O_RDONLY)) < 0)
+        {
+            fprintf(stderr, "    Cannot open encoded file '%s'\n", encoded_file_name);
+            exit(2);
+        }
+    }
+    else
+    {
+        if ((inhandle = sf_open_telephony_read(in_file_name, 1)) == NULL)
+        {
+            fprintf(stderr, "    Cannot open audio file '%s'\n", in_file_name);
+            exit(2);
+        }
+        if ((oki_enc_state = oki_adpcm_init(NULL, bit_rate)) == NULL)
+        {
+            fprintf(stderr, "    Cannot create encoder\n");
+            exit(2);
+        }
     }
+
     if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL)
     {
         fprintf(stderr, "    Cannot create audio file '%s'\n", OUT_FILE_NAME);
         exit(2);
     }
-
-    if ((oki_enc_state = oki_adpcm_init(NULL, bit_rate)) == NULL)
+    if ((oki_dec_state = oki_adpcm_init(NULL, bit_rate)) == NULL)
     {
-        fprintf(stderr, "    Cannot create encoder\n");
+        fprintf(stderr, "    Cannot create decoder\n");
         exit(2);
     }
-        
-    if ((oki_dec_state = oki_adpcm_init(NULL, bit_rate)) == NULL)
+    if ((oki_dec_state2 = oki_adpcm_init(NULL, bit_rate)) == NULL)
     {
         fprintf(stderr, "    Cannot create decoder\n");
         exit(2);
@@ -151,71 +173,124 @@ int main(int argc, char *argv[])
     total_pre_samples = 0;
     total_compressed_bytes = 0;
     total_post_samples = 0;
-    while ((frames = sf_readf_short(inhandle, pre_amp, 159)))
+    if (encoded_file_name)
     {
-        total_pre_samples += frames;
-        oki_bytes = oki_adpcm_encode(oki_enc_state, oki_data, pre_amp, frames);
-        if (log_encoded_data)
-            write(1, oki_data, oki_bytes);
-        total_compressed_bytes += oki_bytes;
-        dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes);
-        total_post_samples += dec_frames;
-        for (i = 0;  i < frames;  i++)
-        {
-            history[hist_in++] = pre_amp[i];
-            if (hist_in >= HIST_LEN)
-                hist_in = 0;
-            pre_energy += (double) pre_amp[i] * (double) pre_amp[i];
-        }
-        for (i = 0;  i < dec_frames;  i++)
+        /* Decode a file of OKI ADPCM code to a linear wave file */
+        while ((oki_bytes = read(encoded_fd, oki_data, 80)) > 0)
         {
-            post_energy += (double) post_amp[i] * (double) post_amp[i];
-            xx = post_amp[i] - history[hist_out++];
-            if (hist_out >= HIST_LEN)
-                hist_out = 0;
-            diff_energy += (double) xx * (double) xx;
-            //post_amp[i] = xx;
+            total_compressed_bytes += oki_bytes;
+            dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes);
+            total_post_samples += dec_frames;
+            for (i = 0;  i < dec_frames;  i++)
+            {
+                post_energy += (double) post_amp[i] * (double) post_amp[i];
+                xx = post_amp[i] - history[hist_out++];
+                if (hist_out >= HIST_LEN)
+                    hist_out = 0;
+                diff_energy += (double) xx * (double) xx;
+            }
+            outframes = sf_writef_short(outhandle, post_amp, dec_frames);
         }
-        outframes = sf_writef_short(outhandle, post_amp, dec_frames);
-    }
-    if (sf_close(inhandle) != 0)
-    {
-        fprintf(stderr, "    Cannot close audio file '%s'\n", in_file_name);
-        exit(2);
+        close(encoded_fd);
     }
-    if (sf_close(outhandle) != 0)
+    else
     {
-        fprintf(stderr, "    Cannot close audio file '%s'\n", OUT_FILE_NAME);
-        exit(2);
-    }
-    oki_adpcm_release(oki_enc_state);
-    oki_adpcm_release(oki_dec_state);
+        /* Perform a linear wave file -> OKI ADPCM -> linear wave file cycle. Along the way
+           check the decoder resets on the sequence specified for this codec, and the gain
+           and worst case sample distortion. */
+        successive_08_bytes = 0;
+        successive_80_bytes = 0;
+        while ((frames = sf_readf_short(inhandle, pre_amp, 159)))
+        {
+            total_pre_samples += frames;
+            oki_bytes = oki_adpcm_encode(oki_enc_state, oki_data, pre_amp, frames);
+            if (log_encoded_data)
+                write(1, oki_data, oki_bytes);
+            total_compressed_bytes += oki_bytes;
+            /* Look for a condition which is defined as something which should cause a reset of
+               the decoder (48 samples of 0, 8, 0, 8, etc.), and verify that it really does. Use
+               a second decode, which we feed byte by byte, for this. */
+            for (i = 0;  i < oki_bytes;  i++)
+            {
+                oki_adpcm_decode(oki_dec_state2, post_amp, &oki_data[i], 1);
+                if (oki_data[i] == 0x08)
+                    successive_08_bytes++;
+                else
+                    successive_08_bytes = 0;
+                if (oki_data[i] == 0x80)
+                    successive_80_bytes++;
+                else
+                    successive_80_bytes = 0;
+                if (successive_08_bytes == 24  ||  successive_80_bytes == 24)
+                {
+                    if (oki_dec_state2->step_index != 0)
+                    {
+                        fprintf(stderr, "Decoder reset failure\n");
+                        exit(2);
+                    }
+                }
+            }
+            dec_frames = oki_adpcm_decode(oki_dec_state, post_amp, oki_data, oki_bytes);
+            total_post_samples += dec_frames;
+            for (i = 0;  i < frames;  i++)
+            {
+                history[hist_in++] = pre_amp[i];
+                if (hist_in >= HIST_LEN)
+                    hist_in = 0;
+                pre_energy += (double) pre_amp[i] * (double) pre_amp[i];
+            }
+            for (i = 0;  i < dec_frames;  i++)
+            {
+                post_energy += (double) post_amp[i] * (double) post_amp[i];
+                xx = post_amp[i] - history[hist_out++];
+                if (hist_out >= HIST_LEN)
+                    hist_out = 0;
+                diff_energy += (double) xx * (double) xx;
+                //post_amp[i] = xx;
+            }
+            outframes = sf_writef_short(outhandle, post_amp, dec_frames);
+        }
+        printf("Pre samples: %d\n", total_pre_samples);
+        printf("Compressed bytes: %d\n", total_compressed_bytes);
+        printf("Post samples: %d\n", total_post_samples);
+
+        printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy);
+        printf("Residual energy is %f%% of the total.\n", 100.0*diff_energy/post_energy);
+        if (bit_rate == 32000)
+        {
+            if (fabs(1.0 - post_energy/pre_energy) > 0.01
+                ||
+                fabs(diff_energy/post_energy) > 0.01)
+            {
+                printf("Tests failed.\n");
+                exit(2);
+            }
+        }
+        else
+        {
+            if (fabs(1.0 - post_energy/pre_energy) > 0.11
+                ||
+                fabs(diff_energy/post_energy) > 0.05)
+            {
+                printf("Tests failed.\n");
+                exit(2);
+            }
+        }
 
-    printf("Pre samples: %d\n", total_pre_samples);
-    printf("Compressed bytes: %d\n", total_compressed_bytes);
-    printf("Post samples: %d\n", total_post_samples);
 
-    printf("Output energy is %f%% of input energy.\n", 100.0*post_energy/pre_energy);
-    printf("Residual energy is %f%% of the total.\n", 100.0*diff_energy/post_energy);
-    if (bit_rate == 32000)
-    {
-        if (fabs(1.0 - post_energy/pre_energy) > 0.05
-            ||
-            fabs(diff_energy/post_energy) > 0.03)
+        oki_adpcm_release(oki_enc_state);
+        if (sf_close(inhandle) != 0)
         {
-            printf("Tests failed.\n");
+            fprintf(stderr, "    Cannot close audio file '%s'\n", in_file_name);
             exit(2);
         }
     }
-    else
+    oki_adpcm_release(oki_dec_state);
+    oki_adpcm_release(oki_dec_state2);
+    if (sf_close(outhandle) != 0)
     {
-        if (fabs(1.0 - post_energy/pre_energy) > 0.20
-            ||
-            fabs(diff_energy/post_energy) > 0.10)
-        {
-            printf("Tests failed.\n");
-            exit(2);
-        }
+        fprintf(stderr, "    Cannot close audio file '%s'\n", OUT_FILE_NAME);
+        exit(2);
     }
 
     printf("Tests passed.\n");