<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[Freeswitch-trunk][16375] </title>
</head>
<body>
<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; }
#msg dl a { font-weight: bold}
#msg dl a:link { color:#fc3; }
#msg dl a:active { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<div id="header">FreeSWITCH Subversion</div>
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://fisheye.freeswitch.org/changelog/FreeSWITCH?cs=16375">16375</a></dd>
<dt>Author</dt> <dd>gmaruzz</dd>
<dt>Date</dt> <dd>2010-01-18 07:17:28 -0600 (Mon, 18 Jan 2010)</dd>
</dl>
<h3>Log Message</h3>
<pre>gsmopen: megapatch for dtmf detection, portaudio support, speex dsp support, echo canceling of sidetone</pre>
<h3>Modified Paths</h3>
<ul>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenMakefile">freeswitch/branches/gmaruzz/mod_gsmopen/Makefile</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopengsmopenh">freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopengsmopen_protocolcpp">freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.cpp</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenmod_gsmopencpp">freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.cpp</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenMakefile">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/Makefile</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenpablioc">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenpablioh">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopenpablioc">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopenpablioh">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.h</a></li>
</ul>
<h3>Added Paths</h3>
<ul>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopencelliax_spandspc">freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopencelliax_spandsph">freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenfiltra48down8c">freeswitch/branches/gmaruzz/mod_gsmopen/filtra48down8.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenfiltra8up48c">freeswitch/branches/gmaruzz/mod_gsmopen/filtra8up48.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopennoalsamod_gsmopencelliax_spandspc">freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopennoalsamod_gsmopencelliax_spandsph">freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopennogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandspc">freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopennogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandsph">freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopennogsmlib_nocplusplusmod_gsmopencelliax_spandspc">freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopennogsmlib_nocplusplusmod_gsmopencelliax_spandsph">freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenpa_ringbufferc">freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenpa_ringbufferh">freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenpablioc">freeswitch/branches/gmaruzz/mod_gsmopen/pablio.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenpablioh">freeswitch/branches/gmaruzz/mod_gsmopen/pablio.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_devlistc">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_devlist.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopencelliax_spandspc">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopencelliax_spandsph">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.h</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenusbcm1082txt">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/usb-cm-108-2.txt</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandspc">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c</a></li>
<li><a href="#freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandsph">freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h</a></li>
</ul>
</div>
<div id="patch">
<h3>Diff</h3>
<a id="freeswitchbranchesgmaruzzmod_gsmopenMakefile"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/Makefile (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/Makefile        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/Makefile        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -4,6 +4,6 @@
</span><span class="cx"> LOCAL_CFLAGS += $(SVNDEF)
</span><span class="cx"> #LOCAL_LDFLAGS=-lasound -L/usr/src/gsmlib-1.10/gsmlib/.libs -lgsmme
</span><span class="cx"> LOCAL_LDFLAGS=-lasound -lgsmme
</span><del>-LOCAL_OBJS=gsmopen_protocol.o
</del><ins>+LOCAL_OBJS=gsmopen_protocol.o celliax_spandsp.o
</ins><span class="cx"> #OUR_OBJS += /usr/src/gsmlib-1.10/gsmlib/libgsmme.la
</span><span class="cx"> include ../../../../build/modmake.rules
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopencelliax_spandspc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,1059 @@
</span><ins>+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - An echo cancellor, suitable for electrical and acoustic
+ * cancellation. This code does not currently comply with
+ * any relevant standards (e.g. G.164/5/7/8). One day....
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001, 2003 Steve Underwood
+ *
+ * Based on a bit from here, a bit from there, eye of toad,
+ * ear of bat, etc - plus, of course, my own 2 cents.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: echo.c,v 1.20 2006/12/01 18:00:48 steveu Exp $
+ */
+
+/*! \file */
+
+/* TODO:
+ Finish the echo suppressor option, however nasty suppression may be.
+ Add an option to reintroduce side tone at -24dB under appropriate conditions.
+ Improve double talk detector (iterative!)
+*/
+
+/* We need to differentiate between transmitted energy which will train the echo
+ canceller well (voice, white noise, and other broadband sources) and energy
+ which will train it badly (supervisory tones, DTMF, whistles, and other
+ narrowband sources). There are many ways this might be done. This canceller uses
+ a method based on the autocorrelation qualities of the transmitted signal. A rather
+ peaky autocorrelation function is a clear sign of a narrowband signal. We only need
+ perform the autocorrelation at well spaced intervals, so the compute load is not too
+ great. Multiple successive autocorrelation functions with a similar peaky shape are a
+ clear indication of a stationary narrowband signal. Using TKEO, it should be possible to
+ greatly reduce the compute requirement for narrowband detection. */
+
+/* The FIR taps must be adapted as 32 bit values, to get the necessary finesse
+ in the adaption process. However, they are applied as 16 bit values (bits 30-15
+ of the 32 bit values) in the FIR. For the working 16 bit values, we need 4 sets.
+
+ 3 of the 16 bit sets are used on a rotating basis. Normally the canceller steps
+ round these 3 sets at regular intervals. Any time we detect double talk, we can go
+ back to the set from two steps ago with reasonable assurance it is a well adapted
+ set. We cannot just go back one step, as we may have rotated the sets just before
+ double talk or tone was detected, and that set may already be somewhat corrupted.
+
+ When narrowband energy is detected we need to continue adapting to it, to echo
+ cancel it. However, the adaption will almost certainly be going astray. Broadband
+ (or even complex sequences of narrowband) energy will normally lead to a well
+ trained cancellor, with taps matching the impulse response of the channel.
+ For stationary narrowband energy, there is usually has an infinite number of
+ alternative tap sets which will cancel it well. A previously well trained set of
+ taps will tend to drift amongst the alternatives. When broadband energy resumes, the
+ taps may be a total mismatch for the signal, and could even amplify rather than
+ attenuate the echo. The solution is to use a fourth set of 16 bit taps. When we first
+ detect the narrowband energy we save the oldest of the group of three sets, but do
+ not change back to an older set. We let the canceller cancel, and it adaption drift
+ while the narrowband energy is present. When we detect the narrowband energy has ceased,
+ we switch to using the fourth set of taps which was saved.
+
+ When we revert to an older set of taps, we must replace both the 16 bit and 32 bit
+ working tap sets. The saved 16 bit values are good enough to also be used as a replacement
+ for the 32 bit values. We loose the fractions, but they should soon settle down in a
+ reasonable way. */
+
+#ifdef HAVE_CONFIG_H
+//#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "celliax_spandsp.h"
+
+//#include "spandsp/telephony.h"
+//#include "spandsp/logging.h"
+//#include "spandsp/bit_operations.h"
+//#include "spandsp/echo.h"
+
+//#include "bit_operations.h"
+//#include "giova.h"
+
+#if !defined(NULL)
+#define NULL (void *) 0
+#endif
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE (!FALSE)
+#endif
+
+#if 0
+#define MIN_TX_POWER_FOR_ADAPTION 64*64
+#define MIN_RX_POWER_FOR_ADAPTION 64*64
+
+static int narrowband_detect(echo_can_state_t * ec)
+{
+ int k;
+ int i;
+ float temp;
+ float scale;
+ float sf[128];
+ float f_acf[128];
+ int32_t acf[28];
+ int score;
+ int len = 32;
+ int alen = 9;
+
+ k = ec->curr_pos;
+ for (i = 0; i < len; i++) {
+ sf[i] = ec->fir_state.history[k++];
+ if (k >= 256)
+ k = 0;
+ }
+ for (k = 0; k < alen; k++) {
+ temp = 0;
+ for (i = k; i < len; i++)
+ temp += sf[i] * sf[i - k];
+ f_acf[k] = temp;
+ }
+ scale = 0x1FFFFFFF / f_acf[0];
+ for (k = 0; k < alen; k++)
+ acf[k] = (int32_t) (f_acf[k] * scale);
+ score = 0;
+ for (i = 0; i < 9; i++) {
+ if (ec->last_acf[i] >= 0 && acf[i] >= 0) {
+ if ((ec->last_acf[i] >> 1) < acf[i] && acf[i] < (ec->last_acf[i] << 1))
+ score++;
+ } else if (ec->last_acf[i] < 0 && acf[i] < 0) {
+ if ((ec->last_acf[i] >> 1) > acf[i] && acf[i] > (ec->last_acf[i] << 1))
+ score++;
+ }
+ }
+ memcpy(ec->last_acf, acf, alen * sizeof(ec->last_acf[0]));
+ return score;
+}
+
+static __inline__ void lms_adapt(echo_can_state_t * ec, int factor)
+{
+ int i;
+
+#if 0
+ mmx_t *mmx_taps;
+ mmx_t *mmx_coeffs;
+ mmx_t *mmx_hist;
+ mmx_t mmx;
+
+ mmx.w[0] = mmx.w[1] = mmx.w[2] = mmx.w[3] = factor;
+ mmx_hist = (mmx_t *) & fir->history[fir->curr_pos];
+ mmx_taps = (mmx_t *) & fir->taps;
+ mmx_coeffs = (mmx_t *) fir->coeffs;
+ i = fir->taps;
+ movq_m2r(mmx, mm0);
+ while (i > 0) {
+ movq_m2r(mmx_hist[0], mm1);
+ movq_m2r(mmx_taps[0], mm0);
+ movq_m2r(mmx_taps[1], mm1);
+ movq_r2r(mm1, mm2);
+ pmulhw(mm0, mm1);
+ pmullw(mm0, mm2);
+
+ pmaddwd_r2r(mm1, mm0);
+ pmaddwd_r2r(mm3, mm2);
+ paddd_r2r(mm0, mm4);
+ paddd_r2r(mm2, mm4);
+ movq_r2m(mm0, mmx_taps[0]);
+ movq_r2m(mm1, mmx_taps[0]);
+ movq_r2m(mm2, mmx_coeffs[0]);
+ mmx_taps += 2;
+ mmx_coeffs += 1;
+ mmx_hist += 1;
+ i -= 4;
+ )
+ emms();
+#elif 0
+ /* Update the FIR taps */
+ for (i = ec->taps - 1; i >= 0; i--) {
+ /* Leak to avoid the coefficients drifting beyond the ability of the
+ adaption process to bring them back under control. */
+ ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23);
+ ec->fir_taps32[i] += (ec->fir_state.history[i + ec->curr_pos] * factor);
+ ec->latest_correction = (ec->fir_state.history[i + ec->curr_pos] * factor);
+ ec->fir_taps16[ec->tap_set][i] = ec->fir_taps32[i] >> 15;
+ }
+#else
+ int offset1;
+ int offset2;
+
+ /* Update the FIR taps */
+ offset2 = ec->curr_pos;
+ offset1 = ec->taps - offset2;
+ for (i = ec->taps - 1; i >= offset1; i--) {
+ ec->fir_taps32[i] += (ec->fir_state.history[i - offset1] * factor);
+ ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15);
+ }
+ for (; i >= 0; i--) {
+ ec->fir_taps32[i] += (ec->fir_state.history[i + offset2] * factor);
+ ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15);
+ }
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+#ifdef NOT_NEEDED
+echo_can_state_t *echo_can_create(int len, int adaption_mode)
+{
+ echo_can_state_t *ec;
+ int i;
+ int j;
+
+ ec = (echo_can_state_t *) malloc(sizeof(*ec));
+ if (ec == NULL)
+ return NULL;
+ memset(ec, 0, sizeof(*ec));
+ ec->taps = len;
+ ec->curr_pos = ec->taps - 1;
+ ec->tap_mask = ec->taps - 1;
+ if ((ec->fir_taps32 = (int32_t *) malloc(ec->taps * sizeof(int32_t))) == NULL) {
+ free(ec);
+ return NULL;
+ }
+ memset(ec->fir_taps32, 0, ec->taps * sizeof(int32_t));
+ for (i = 0; i < 4; i++) {
+ if ((ec->fir_taps16[i] = (int16_t *) malloc(ec->taps * sizeof(int16_t))) == NULL) {
+ for (j = 0; j < i; j++)
+ free(ec->fir_taps16[j]);
+ free(ec->fir_taps32);
+ free(ec);
+ return NULL;
+ }
+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
+ }
+ fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps);
+ ec->rx_power_threshold = 10000000;
+ ec->geigel_max = 0;
+ ec->geigel_lag = 0;
+ ec->dtd_onset = FALSE;
+ ec->tap_set = 0;
+ ec->tap_rotate_counter = 1600;
+ ec->cng_level = 1000;
+ echo_can_adaption_mode(ec, adaption_mode);
+ return ec;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_free(echo_can_state_t * ec)
+{
+ int i;
+
+ fir16_free(&ec->fir_state);
+ free(ec->fir_taps32);
+ for (i = 0; i < 4; i++)
+ free(ec->fir_taps16[i]);
+ free(ec);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_adaption_mode(echo_can_state_t * ec, int adaption_mode)
+{
+ ec->adaption_mode = adaption_mode;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_flush(echo_can_state_t * ec)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ ec->tx_power[i] = 0;
+ for (i = 0; i < 3; i++)
+ ec->rx_power[i] = 0;
+ ec->clean_rx_power = 0;
+ ec->nonupdate_dwell = 0;
+
+ fir16_flush(&ec->fir_state);
+ ec->fir_state.curr_pos = ec->taps - 1;
+ memset(ec->fir_taps32, 0, ec->taps * sizeof(int32_t));
+ for (i = 0; i < 4; i++)
+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
+
+ ec->curr_pos = ec->taps - 1;
+
+ ec->supp_test1 = 0;
+ ec->supp_test2 = 0;
+ ec->supp1 = 0;
+ ec->supp2 = 0;
+ ec->vad = 0;
+ ec->cng_level = 1000;
+ ec->cng_filter = 0;
+
+ ec->geigel_max = 0;
+ ec->geigel_lag = 0;
+ ec->dtd_onset = FALSE;
+ ec->tap_set = 0;
+ ec->tap_rotate_counter = 1600;
+
+ ec->latest_correction = 0;
+
+ memset(ec->last_acf, 0, sizeof(ec->last_acf));
+ ec->narrowband_count = 0;
+ ec->narrowband_score = 0;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+int sample_no = 0;
+
+int16_t echo_can_update(echo_can_state_t * ec, int16_t tx, int16_t rx)
+{
+ int32_t echo_value;
+ int clean_rx;
+ int nsuppr;
+ int score;
+ int i;
+
+ sample_no++;
+ ec->latest_correction = 0;
+ /* Evaluate the echo - i.e. apply the FIR filter */
+ /* Assume the gain of the FIR does not exceed unity. Exceeding unity
+ would seem like a rather poor thing for an echo cancellor to do :)
+ This means we can compute the result with a total disregard for
+ overflows. 16bits x 16bits -> 31bits, so no overflow can occur in
+ any multiply. While accumulating we may overflow and underflow the
+ 32 bit scale often. However, if the gain does not exceed unity,
+ everything should work itself out, and the final result will be
+ OK, without any saturation logic. */
+ /* Overflow is very much possible here, and we do nothing about it because
+ of the compute costs */
+ /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound
+ bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems
+ best */
+ echo_value = fir16(&ec->fir_state, tx);
+
+ /* And the answer is..... */
+ clean_rx = rx - echo_value;
+//printf("echo is %" PRId32 "\n", echo_value);
+ /* That was the easy part. Now we need to adapt! */
+ if (ec->nonupdate_dwell > 0)
+ ec->nonupdate_dwell--;
+
+ /* Calculate short term power levels using very simple single pole IIRs */
+ /* TODO: Is the nasty modulus approach the fastest, or would a real
+ tx*tx power calculation actually be faster? Using the squares
+ makes the numbers grow a lot! */
+ ec->tx_power[3] += ((abs(tx) - ec->tx_power[3]) >> 5);
+ ec->tx_power[2] += ((tx * tx - ec->tx_power[2]) >> 8);
+ ec->tx_power[1] += ((tx * tx - ec->tx_power[1]) >> 5);
+ ec->tx_power[0] += ((tx * tx - ec->tx_power[0]) >> 3);
+ ec->rx_power[1] += ((rx * rx - ec->rx_power[1]) >> 6);
+ ec->rx_power[0] += ((rx * rx - ec->rx_power[0]) >> 3);
+ ec->clean_rx_power += ((clean_rx * clean_rx - ec->clean_rx_power) >> 6);
+
+ score = 0;
+ /* If there is very little being transmitted, any attempt to train is
+ futile. We would either be training on the far end's noise or signal,
+ the channel's own noise, or our noise. Either way, this is hardly good
+ training, so don't do it (avoid trouble). */
+ if (ec->tx_power[0] > MIN_TX_POWER_FOR_ADAPTION) {
+ /* If the received power is very low, either we are sending very little or
+ we are already well adapted. There is little point in trying to improve
+ the adaption under these circumstances, so don't do it (reduce the
+ compute load). */
+ if (ec->tx_power[1] > ec->rx_power[0]) {
+ /* There is no (or little) far-end speech. */
+ if (ec->nonupdate_dwell == 0) {
+ if (++ec->narrowband_count >= 160) {
+ ec->narrowband_count = 0;
+ score = narrowband_detect(ec);
+//printf("Do the narrowband test %d at %d\n", score, ec->curr_pos);
+ if (score > 6) {
+ if (ec->narrowband_score == 0)
+ memcpy(ec->fir_taps16[3], ec->fir_taps16[(ec->tap_set + 1) % 3],
+ ec->taps * sizeof(int16_t));
+ ec->narrowband_score += score;
+ } else {
+ if (ec->narrowband_score > 200) {
+//printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no);
+ memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[3],
+ ec->taps * sizeof(int16_t));
+ memcpy(ec->fir_taps16[(ec->tap_set - 1) % 3], ec->fir_taps16[3],
+ ec->taps * sizeof(int16_t));
+ for (i = 0; i < ec->taps; i++)
+ ec->fir_taps32[i] = ec->fir_taps16[3][i] << 15;
+ ec->tap_rotate_counter = 1600;
+ }
+ ec->narrowband_score = 0;
+ }
+ }
+ ec->dtd_onset = FALSE;
+ if (--ec->tap_rotate_counter <= 0) {
+//printf("Rotate to %d at %d\n", ec->tap_set, sample_no);
+ ec->tap_rotate_counter = 1600;
+ ec->tap_set++;
+ if (ec->tap_set > 2)
+ ec->tap_set = 0;
+ ec->fir_state.coeffs = ec->fir_taps16[ec->tap_set];
+ }
+ /* ... and we are not in the dwell time from previous speech. */
+ if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) && ec->narrowband_score == 0) {
+ //nsuppr = saturate((clean_rx << 16)/ec->tx_power[1]);
+ //nsuppr = clean_rx/ec->tx_power[1];
+ /* If a sudden surge in signal level (e.g. the onset of a tone
+ burst) cause an abnormally high instantaneous to average
+ signal power ratio, we could kick the adaption badly in the
+ wrong direction. This is because the tx_power takes too long
+ to react and rise. We need to stop too rapid adaption to the
+ new signal. We normalise to a value derived from the
+ instantaneous signal if it exceeds the peak by too much. */
+ nsuppr = clean_rx;
+ /* Divide isn't very quick, but the "where is the top bit" and shift
+ instructions are single cycle. */
+ if (tx > 4 * ec->tx_power[3])
+ i = top_bit(tx) - 8;
+ else
+ i = top_bit(ec->tx_power[3]) - 8;
+ if (i > 0)
+ nsuppr >>= i;
+ lms_adapt(ec, nsuppr);
+ }
+ }
+ //printf("%10d %10d %10d %10d %10d\n", rx, clean_rx, nsuppr, ec->tx_power[1], ec->rx_power[1]);
+ //printf("%.4f\n", (float) ec->rx_power[1]/(float) ec->clean_rx_power);
+ } else {
+ if (!ec->dtd_onset) {
+//printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no);
+ memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[(ec->tap_set + 1) % 3],
+ ec->taps * sizeof(int16_t));
+ memcpy(ec->fir_taps16[(ec->tap_set - 1) % 3],
+ ec->fir_taps16[(ec->tap_set + 1) % 3], ec->taps * sizeof(int16_t));
+ for (i = 0; i < ec->taps; i++)
+ ec->fir_taps32[i] = ec->fir_taps16[(ec->tap_set + 1) % 3][i] << 15;
+ ec->tap_rotate_counter = 1600;
+ ec->dtd_onset = TRUE;
+ }
+ ec->nonupdate_dwell = NONUPDATE_DWELL_TIME;
+ }
+ }
+
+ if (ec->rx_power[1])
+ ec->vad = (8000 * ec->clean_rx_power) / ec->rx_power[1];
+ else
+ ec->vad = 0;
+ if (ec->rx_power[1] > 2048 * 2048 && ec->clean_rx_power > 4 * ec->rx_power[1]) {
+ /* The EC seems to be making things worse, instead of better. Zap it! */
+ memset(ec->fir_taps32, 0, ec->taps * sizeof(int32_t));
+ for (i = 0; i < 4; i++)
+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
+ }
+#if defined(XYZZY)
+ if ((ec->adaption_mode & ECHO_CAN_USE_SUPPRESSOR)) {
+ ec->supp_test1 +=
+ (ec->fir_state.history[ec->curr_pos] -
+ ec->fir_state.history[(ec->curr_pos - 7) & ec->tap_mask]);
+ ec->supp_test2 +=
+ (ec->fir_state.history[(ec->curr_pos - 24) & ec->tap_mask] -
+ ec->fir_state.history[(ec->curr_pos - 31) & ec->tap_mask]);
+ if (ec->supp_test1 > 42 && ec->supp_test2 > 42)
+ supp_change = 25;
+ else
+ supp_change = 50;
+ supp = supp_change + k1 * ec->supp1 + k2 * ec->supp2;
+ ec->supp2 = ec->supp1;
+ ec->supp1 = supp;
+ clean_rx *= (1 - supp);
+ }
+#endif
+
+ if ((ec->adaption_mode & ECHO_CAN_USE_NLP)) {
+ /* Non-linear processor - a fancy way to say "zap small signals, to avoid
+ residual echo due to (uLaw/ALaw) non-linearity in the channel.". */
+ if (ec->rx_power[1] < 30000000) {
+ if (!ec->cng) {
+ ec->cng_level = ec->clean_rx_power;
+ ec->cng = TRUE;
+ }
+ if ((ec->adaption_mode & ECHO_CAN_USE_CNG)) {
+ /* Very elementary comfort noise generation */
+ /* Just random numbers rolled off very vaguely Hoth-like */
+ ec->cng_rndnum = 1664525U * ec->cng_rndnum + 1013904223U;
+ ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5 * ec->cng_filter) >> 3;
+ clean_rx = (ec->cng_filter * ec->cng_level) >> 17;
+ /* TODO: A better CNG, with more accurate (tracking) spectral shaping! */
+ } else {
+ clean_rx = 0;
+ }
+//clean_rx = -16000;
+ } else {
+ ec->cng = FALSE;
+ }
+ } else {
+ ec->cng = FALSE;
+ }
+
+//printf("Narrowband score %4d %5d at %d\n", ec->narrowband_score, score, sample_no);
+ /* Roll around the rolling buffer */
+ if (ec->curr_pos <= 0)
+ ec->curr_pos = ec->taps;
+ ec->curr_pos--;
+ return (int16_t) clean_rx;
+}
+
+#endif //NOT_NEEDED
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <math.h>
+
+//#include "spandsp/telephony.h"
+//#include "spandsp/tone_detect.h"
+//#include "spandsp/tone_generate.h"
+//#include "spandsp/super_tone_rx.h"
+//#include "giova.h"
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+
+//#define USE_3DNOW
+
+#define DEFAULT_DTMF_TX_LEVEL -10
+#define DEFAULT_DTMF_TX_ON_TIME 50
+#define DEFAULT_DTMF_TX_OFF_TIME 55
+
+#define DTMF_THRESHOLD 8.0e7f
+#define DTMF_NORMAL_TWIST 6.3f /* 8dB */
+#define DTMF_REVERSE_TWIST 2.5f /* 4dB */
+#define DTMF_RELATIVE_PEAK_ROW 6.3f /* 8dB */
+#define DTMF_RELATIVE_PEAK_COL 6.3f /* 8dB */
+#define DTMF_TO_TOTAL_ENERGY 42.0f
+
+static const float dtmf_row[] = {
+ 697.0f, 770.0f, 852.0f, 941.0f
+};
+static const float dtmf_col[] = {
+ 1209.0f, 1336.0f, 1477.0f, 1633.0f
+};
+
+static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+
+static goertzel_descriptor_t dtmf_detect_row[4];
+static goertzel_descriptor_t dtmf_detect_col[4];
+
+//
+//static int dtmf_tx_inited = 0;
+//static tone_gen_descriptor_t dtmf_digit_tones[16];
+
+#if defined(USE_3DNOW)
+static __inline__ void _dtmf_goertzel_update(goertzel_state_t * s, float x[], int samples)
+{
+ int n;
+ float v;
+ int i;
+ float vv[16];
+
+ vv[4] = s[0].v2;
+ vv[5] = s[1].v2;
+ vv[6] = s[2].v2;
+ vv[7] = s[3].v2;
+ vv[8] = s[0].v3;
+ vv[9] = s[1].v3;
+ vv[10] = s[2].v3;
+ vv[11] = s[3].v3;
+ vv[12] = s[0].fac;
+ vv[13] = s[1].fac;
+ vv[14] = s[2].fac;
+ vv[15] = s[3].fac;
+
+ //v1 = s->v2;
+ //s->v2 = s->v3;
+ //s->v3 = s->fac*s->v2 - v1 + x[0];
+
+ __asm__ __volatile__(" femms;\n" " movq 16(%%edx),%%mm2;\n"
+ " movq 24(%%edx),%%mm3;\n" " movq 32(%%edx),%%mm4;\n"
+ " movq 40(%%edx),%%mm5;\n" " movq 48(%%edx),%%mm6;\n"
+ " movq 56(%%edx),%%mm7;\n" " jmp 1f;\n"
+ " .align 32;\n" " 1: ;\n" " prefetch (%%eax);\n"
+ " movq %%mm3,%%mm1;\n" " movq %%mm2,%%mm0;\n"
+ " movq %%mm5,%%mm3;\n" " movq %%mm4,%%mm2;\n"
+ " pfmul %%mm7,%%mm5;\n" " pfmul %%mm6,%%mm4;\n"
+ " pfsub %%mm1,%%mm5;\n" " pfsub %%mm0,%%mm4;\n"
+ " movq (%%eax),%%mm0;\n" " movq %%mm0,%%mm1;\n"
+ " punpckldq %%mm0,%%mm1;\n" " add $4,%%eax;\n"
+ " pfadd %%mm1,%%mm5;\n" " pfadd %%mm1,%%mm4;\n"
+ " dec %%ecx;\n" " jnz 1b;\n"
+ " movq %%mm2,16(%%edx);\n" " movq %%mm3,24(%%edx);\n"
+ " movq %%mm4,32(%%edx);\n" " movq %%mm5,40(%%edx);\n"
+ " femms;\n"::"c"(samples), "a"(x), "d"(vv)
+ :"memory", "eax", "ecx");
+
+ s[0].v2 = vv[4];
+ s[1].v2 = vv[5];
+ s[2].v2 = vv[6];
+ s[3].v2 = vv[7];
+ s[0].v3 = vv[8];
+ s[1].v3 = vv[9];
+ s[2].v3 = vv[10];
+ s[3].v3 = vv[11];
+}
+
+/*- End of function --------------------------------------------------------*/
+#endif
+
+int dtmf_rx(dtmf_rx_state_t * s, const int16_t amp[], int samples)
+{
+ float row_energy[4];
+ float col_energy[4];
+ float famp;
+ float v1;
+ int i;
+ int j;
+ int sample;
+ int best_row;
+ int best_col;
+ int limit;
+ uint8_t hit;
+
+ hit = 0;
+ for (sample = 0; sample < samples; sample = limit) {
+ /* The block length is optimised to meet the DTMF specs. */
+ if ((samples - sample) >= (102 - s->current_sample))
+ limit = sample + (102 - s->current_sample);
+ else
+ limit = samples;
+#if defined(USE_3DNOW)
+ _dtmf_goertzel_update(s->row_out, amp + sample, limit - sample);
+ _dtmf_goertzel_update(s->col_out, amp + sample, limit - sample);
+#else
+ /* The following unrolled loop takes only 35% (rough estimate) of the
+ time of a rolled loop on the machine on which it was developed */
+ for (j = sample; j < limit; j++) {
+ famp = amp[j];
+ if (s->filter_dialtone) {
+ /* Sharp notches applied at 350Hz and 440Hz - the two common dialtone frequencies.
+ These are rather high Q, to achieve the required narrowness, without using lots of
+ sections. */
+ v1 = 0.98356f * famp + 1.8954426f * s->z350_1 - 0.9691396f * s->z350_2;
+ famp = v1 - 1.9251480f * s->z350_1 + s->z350_2;
+ s->z350_2 = s->z350_1;
+ s->z350_1 = v1;
+
+ v1 = 0.98456f * famp + 1.8529543f * s->z440_1 - 0.9691396f * s->z440_2;
+ famp = v1 - 1.8819938f * s->z440_1 + s->z440_2;
+ s->z440_2 = s->z440_1;
+ s->z440_1 = v1;
+ }
+ s->energy += famp * famp;
+ /* With GCC 2.95, the following unrolled code seems to take about 35%
+ (rough estimate) as long as a neat little 0-3 loop */
+ v1 = s->row_out[0].v2;
+ s->row_out[0].v2 = s->row_out[0].v3;
+ s->row_out[0].v3 = s->row_out[0].fac * s->row_out[0].v2 - v1 + famp;
+
+ v1 = s->col_out[0].v2;
+ s->col_out[0].v2 = s->col_out[0].v3;
+ s->col_out[0].v3 = s->col_out[0].fac * s->col_out[0].v2 - v1 + famp;
+
+ v1 = s->row_out[1].v2;
+ s->row_out[1].v2 = s->row_out[1].v3;
+ s->row_out[1].v3 = s->row_out[1].fac * s->row_out[1].v2 - v1 + famp;
+
+ v1 = s->col_out[1].v2;
+ s->col_out[1].v2 = s->col_out[1].v3;
+ s->col_out[1].v3 = s->col_out[1].fac * s->col_out[1].v2 - v1 + famp;
+
+ v1 = s->row_out[2].v2;
+ s->row_out[2].v2 = s->row_out[2].v3;
+ s->row_out[2].v3 = s->row_out[2].fac * s->row_out[2].v2 - v1 + famp;
+
+ v1 = s->col_out[2].v2;
+ s->col_out[2].v2 = s->col_out[2].v3;
+ s->col_out[2].v3 = s->col_out[2].fac * s->col_out[2].v2 - v1 + famp;
+
+ v1 = s->row_out[3].v2;
+ s->row_out[3].v2 = s->row_out[3].v3;
+ s->row_out[3].v3 = s->row_out[3].fac * s->row_out[3].v2 - v1 + famp;
+
+ v1 = s->col_out[3].v2;
+ s->col_out[3].v2 = s->col_out[3].v3;
+ s->col_out[3].v3 = s->col_out[3].fac * s->col_out[3].v2 - v1 + famp;
+ }
+#endif
+ s->current_sample += (limit - sample);
+ if (s->current_sample < 102)
+ continue;
+
+ /* We are at the end of a DTMF detection block */
+ /* Find the peak row and the peak column */
+ row_energy[0] = goertzel_result(&s->row_out[0]);
+ best_row = 0;
+ col_energy[0] = goertzel_result(&s->col_out[0]);
+ best_col = 0;
+
+ for (i = 1; i < 4; i++) {
+ row_energy[i] = goertzel_result(&s->row_out[i]);
+ if (row_energy[i] > row_energy[best_row])
+ best_row = i;
+ col_energy[i] = goertzel_result(&s->col_out[i]);
+ if (col_energy[i] > col_energy[best_col])
+ best_col = i;
+ }
+ hit = 0;
+ /* Basic signal level test and the twist test */
+ if (row_energy[best_row] >= DTMF_THRESHOLD && col_energy[best_col] >= DTMF_THRESHOLD
+ && col_energy[best_col] < row_energy[best_row] * s->reverse_twist
+ && col_energy[best_col] * s->normal_twist > row_energy[best_row]) {
+ /* Relative peak test ... */
+ for (i = 0; i < 4; i++) {
+ if ((i != best_col
+ && col_energy[i] * DTMF_RELATIVE_PEAK_COL > col_energy[best_col])
+ || (i != best_row
+ && row_energy[i] * DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
+ break;
+ }
+ }
+ /* ... and fraction of total energy test */
+ if (i >= 4
+ && (row_energy[best_row] + col_energy[best_col]) >
+ DTMF_TO_TOTAL_ENERGY * s->energy) {
+ hit = dtmf_positions[(best_row << 2) + best_col];
+ }
+ }
+ /* The logic in the next test should ensure the following for different successive hit patterns:
+ -----ABB = start of digit B.
+ ----B-BB = start of digit B
+ ----A-BB = start of digit B
+ BBBBBABB = still in digit B.
+ BBBBBB-- = end of digit B
+ BBBBBBC- = end of digit B
+ BBBBACBB = B ends, then B starts again.
+ BBBBBBCC = B ends, then C starts.
+ BBBBBCDD = B ends, then D starts.
+ This can work with:
+ - Back to back differing digits. Back-to-back digits should
+ not happen. The spec. says there should be a gap between digits.
+ However, many real phones do not impose a gap, and rolling across
+ the keypad can produce little or no gap.
+ - It tolerates nasty phones that give a very wobbly start to a digit.
+ - VoIP can give sample slips. The phase jumps that produces will cause
+ the block it is in to give no detection. This logic will ride over a
+ single missed block, and not falsely declare a second digit. If the
+ hiccup happens in the wrong place on a minimum length digit, however
+ we would still fail to detect that digit. Could anything be done to
+ deal with that? Packet loss is clearly a no-go zone.
+ Note this is only relevant to VoIP using A-law, u-law or similar.
+ Low bit rate codecs scramble DTMF too much for it to be recognised,
+ and often slip in units larger than a sample. */
+ if (hit != s->in_digit) {
+ if (s->last_hit != s->in_digit) {
+ /* We have two successive indications that something has changed. */
+ /* To declare digit on, the hits must agree. Otherwise we declare tone off. */
+ hit = (hit && hit == s->last_hit) ? hit : 0;
+#if 0
+ if (s->realtime_callback) {
+ /* Avoid reporting multiple no digit conditions on flaky hits */
+ if (s->in_digit || hit) {
+ i = (s->in_digit
+ && !hit) ? -99 : rint(log10f(s->energy) * 10.0f - 20.08f - 90.30F +
+ DBM0_MAX_POWER);
+ s->realtime_callback(s->realtime_callback_data, hit, i);
+ }
+ } else {
+#endif
+ if (hit) {
+ if (s->current_digits < MAX_DTMF_DIGITS) {
+ s->digits[s->current_digits++] = (char) hit;
+ s->digits[s->current_digits] = '\0';
+ if (s->callback) {
+ s->callback(s->callback_data, s->digits, s->current_digits);
+ s->current_digits = 0;
+ }
+ } else {
+ s->lost_digits++;
+ }
+ }
+#if 0
+ }
+#endif
+ s->in_digit = hit;
+ }
+ }
+ s->last_hit = hit;
+ /* Reinitialise the detector for the next block */
+ for (i = 0; i < 4; i++) {
+ goertzel_reset(&s->row_out[i]);
+ goertzel_reset(&s->col_out[i]);
+ }
+ s->energy = 0.0f;
+ s->current_sample = 0;
+ }
+ if (s->current_digits && s->callback) {
+ s->callback(s->callback_data, s->digits, s->current_digits);
+ s->digits[0] = '\0';
+ s->current_digits = 0;
+ }
+ return 0;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+size_t dtmf_rx_get(dtmf_rx_state_t * s, char *buf, int max)
+{
+ if (max > s->current_digits)
+ max = s->current_digits;
+ if (max > 0) {
+ memcpy(buf, s->digits, max);
+ memmove(s->digits, s->digits + max, s->current_digits - max);
+ s->current_digits -= max;
+ }
+ buf[max] = '\0';
+ return max;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+#if 0
+void dtmf_rx_set_realtime_callback(dtmf_rx_state_t * s, tone_report_func_t callback,
+ void *user_data)
+{
+ s->realtime_callback = callback;
+ s->realtime_callback_data = user_data;
+}
+#endif
+/*- End of function --------------------------------------------------------*/
+
+void dtmf_rx_parms(dtmf_rx_state_t * s, int filter_dialtone, int twist, int reverse_twist)
+{
+ if (filter_dialtone >= 0) {
+ s->z350_1 = 0.0f;
+ s->z350_2 = 0.0f;
+ s->z440_1 = 0.0f;
+ s->z440_2 = 0.0f;
+ s->filter_dialtone = filter_dialtone;
+ }
+ if (twist >= 0)
+ s->normal_twist = powf(10.0f, twist / 10.0f);
+ if (reverse_twist >= 0)
+ s->reverse_twist = powf(10.0f, reverse_twist / 10.0f);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+dtmf_rx_state_t *dtmf_rx_init(dtmf_rx_state_t * s, dtmf_rx_callback_t callback,
+ void *user_data)
+{
+ int i;
+ static int initialised = 0;
+
+ s->callback = callback;
+ s->callback_data = user_data;
+ s->realtime_callback = NULL;
+ s->realtime_callback_data = NULL;
+ s->filter_dialtone = 0;
+ s->normal_twist = DTMF_NORMAL_TWIST;
+ s->reverse_twist = DTMF_REVERSE_TWIST;
+
+ s->in_digit = 0;
+ s->last_hit = 0;
+
+ if (!initialised) {
+ for (i = 0; i < 4; i++) {
+ make_goertzel_descriptor(&dtmf_detect_row[i], dtmf_row[i], 102);
+ make_goertzel_descriptor(&dtmf_detect_col[i], dtmf_col[i], 102);
+ }
+ initialised = 1;
+ }
+ for (i = 0; i < 4; i++) {
+ goertzel_init(&s->row_out[i], &dtmf_detect_row[i]);
+ goertzel_init(&s->col_out[i], &dtmf_detect_col[i]);
+ }
+ s->energy = 0.0f;
+ s->current_sample = 0;
+ s->lost_digits = 0;
+ s->current_digits = 0;
+ s->digits[0] = '\0';
+ return s;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+#if 0
+static void dtmf_tx_initialise(void)
+{
+ int row;
+ int col;
+
+ if (dtmf_tx_inited)
+ return;
+ for (row = 0; row < 4; row++) {
+ for (col = 0; col < 4; col++) {
+ make_tone_gen_descriptor(&dtmf_digit_tones[row * 4 + col], (int) dtmf_row[row],
+ DEFAULT_DTMF_TX_LEVEL, (int) dtmf_col[col],
+ DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME,
+ DEFAULT_DTMF_TX_OFF_TIME, 0, 0, FALSE);
+ }
+ }
+ dtmf_tx_inited = TRUE;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+int dtmf_tx(dtmf_tx_state_t * s, int16_t amp[], int max_samples)
+{
+ int len;
+ size_t dig;
+ char *cp;
+
+ len = 0;
+ if (s->tones.current_section >= 0) {
+ /* Deal with the fragment left over from last time */
+ len = tone_gen(&(s->tones), amp, max_samples);
+ }
+ dig = 0;
+ while (dig < s->current_digits && len < max_samples) {
+ /* Step to the next digit */
+ if ((cp = strchr(dtmf_positions, s->digits[dig++])) == NULL)
+ continue;
+ tone_gen_init(&(s->tones), &(s->tone_descriptors[cp - dtmf_positions]));
+ len += tone_gen(&(s->tones), amp + len, max_samples - len);
+ }
+ if (dig) {
+ /* Shift out the consumed digits */
+ s->current_digits -= dig;
+ memmove(s->digits, s->digits + dig, s->current_digits);
+ }
+ return len;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+size_t dtmf_tx_put(dtmf_tx_state_t * s, const char *digits)
+{
+ size_t len;
+
+ /* This returns the number of characters that would not fit in the buffer.
+ The buffer will only be loaded if the whole string of digits will fit,
+ in which case zero is returned. */
+ if ((len = strlen(digits)) > 0) {
+ if (s->current_digits + len <= MAX_DTMF_DIGITS) {
+ memcpy(s->digits + s->current_digits, digits, len);
+ s->current_digits += len;
+ len = 0;
+ } else {
+ len = MAX_DTMF_DIGITS - s->current_digits;
+ }
+ }
+ return len;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+dtmf_tx_state_t *dtmf_tx_init(dtmf_tx_state_t * s)
+{
+ if (!dtmf_tx_inited)
+ dtmf_tx_initialise();
+ s->tone_descriptors = dtmf_digit_tones;
+ tone_gen_init(&(s->tones), &dtmf_digit_tones[0]);
+ s->current_sample = 0;
+ s->current_digits = 0;
+ s->tones.current_section = -1;
+ return s;
+}
+#endif //NO TX
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+
+void make_goertzel_descriptor(goertzel_descriptor_t * t, float freq, int samples)
+{
+ //t->fac = 2.0f*cosf(2.0f*M_PI*(freq/(float) SAMPLE_RATE));
+ t->fac = 2.0f * cosf(2.0f * M_PI * (freq / (float) 8000));
+ t->samples = samples;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+goertzel_state_t *goertzel_init(goertzel_state_t * s, goertzel_descriptor_t * t)
+{
+ if (s || (s = malloc(sizeof(goertzel_state_t)))) {
+ s->v2 = s->v3 = 0.0;
+ s->fac = t->fac;
+ s->samples = t->samples;
+ s->current_sample = 0;
+ }
+ return s;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void goertzel_reset(goertzel_state_t * s)
+{
+ s->v2 = s->v3 = 0.0;
+ s->current_sample = 0;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+int goertzel_update(goertzel_state_t * s, const int16_t amp[], int samples)
+{
+ int i;
+ float v1;
+
+ if (samples > s->samples - s->current_sample)
+ samples = s->samples - s->current_sample;
+ for (i = 0; i < samples; i++) {
+ v1 = s->v2;
+ s->v2 = s->v3;
+ s->v3 = s->fac * s->v2 - v1 + amp[i];
+ }
+ s->current_sample += samples;
+ return samples;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+float goertzel_result(goertzel_state_t * s)
+{
+ float v1;
+
+ /* Push a zero through the process to finish things off. */
+ v1 = s->v2;
+ s->v2 = s->v3;
+ s->v3 = s->fac * s->v2 - v1;
+ /* Now calculate the non-recursive side of the filter. */
+ /* The result here is not scaled down to allow for the magnification
+ effect of the filter (the usual DFT magnification effect). */
+ return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac;
+}
+
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopencelliax_spandsph"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/celliax_spandsp.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,1034 @@
</span><ins>+
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * bit_operations.h - Various bit level operations, such as bit reversal
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: bit_operations.h,v 1.15 2007/02/23 13:16:13 steveu Exp $
+ */
+
+/*! \file */
+
+#ifndef _CELLIAX_SPANDSP_H
+#define _CELLIAX_SPANDSP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif                                                        /* __cplusplus */
+#include <math.h>
+
+/*! \brief Find the bit position of the highest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the highest set bit, or -1 if the word is zero. */
+static __inline__ int top_bit(unsigned int bits)
+{
+ int res;
+
+#if defined(__i386__) || defined(__x86_64__)
+__asm__(" xorl %[res],%[res];\n" " decl %[res];\n" " bsrl %[bits],%[res]\n":[res] "=&r"
+ (res)
+: [bits] "rm"(bits));
+ return res;
+#elif defined(__ppc__) || defined(__powerpc__)
+__asm__("cntlzw %[res],%[bits];\n":[res] "=&r"(res)
+: [bits] "r"(bits));
+ return 31 - res;
+#else
+ if (bits == 0)
+ return -1;
+ res = 0;
+ if (bits & 0xFFFF0000) {
+ bits &= 0xFFFF0000;
+ res += 16;
+ }
+ if (bits & 0xFF00FF00) {
+ bits &= 0xFF00FF00;
+ res += 8;
+ }
+ if (bits & 0xF0F0F0F0) {
+ bits &= 0xF0F0F0F0;
+ res += 4;
+ }
+ if (bits & 0xCCCCCCCC) {
+ bits &= 0xCCCCCCCC;
+ res += 2;
+ }
+ if (bits & 0xAAAAAAAA) {
+ bits &= 0xAAAAAAAA;
+ res += 1;
+ }
+ return res;
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the bit position of the lowest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the lowest set bit, or -1 if the word is zero. */
+static __inline__ int bottom_bit(unsigned int bits)
+{
+ int res;
+
+#if defined(__i386__) || defined(__x86_64__)
+__asm__(" xorl %[res],%[res];\n" " decl %[res];\n" " bsfl %[bits],%[res]\n":[res] "=&r"
+ (res)
+: [bits] "rm"(bits));
+ return res;
+#else
+ if (bits == 0)
+ return -1;
+ res = 31;
+ if (bits & 0x0000FFFF) {
+ bits &= 0x0000FFFF;
+ res -= 16;
+ }
+ if (bits & 0x00FF00FF) {
+ bits &= 0x00FF00FF;
+ res -= 8;
+ }
+ if (bits & 0x0F0F0F0F) {
+ bits &= 0x0F0F0F0F;
+ res -= 4;
+ }
+ if (bits & 0x33333333) {
+ bits &= 0x33333333;
+ res -= 2;
+ }
+ if (bits & 0x55555555) {
+ bits &= 0x55555555;
+ res -= 1;
+ }
+ return res;
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Bit reverse a byte.
+ \param data The byte to be reversed.
+ \return The bit reversed version of data. */
+static __inline__ uint8_t bit_reverse8(uint8_t x)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
+ /* If multiply is fast */
+ return ((x * 0x0802U & 0x22110U) | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16;
+#else
+ /* If multiply is slow, but we have a barrel shifter */
+ x = (x >> 4) | (x << 4);
+ x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
+ return ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Bit reverse a 16 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint16_t bit_reverse16(uint16_t data);
+
+/*! \brief Bit reverse a 32 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint32_t bit_reverse32(uint32_t data);
+
+/*! \brief Bit reverse each of the four bytes in a 32 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint32_t bit_reverse_4bytes(uint32_t data);
+
+#if defined(__x86_64__)
+/*! \brief Bit reverse each of the eight bytes in a 64 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint64_t bit_reverse_8bytes(uint64_t data);
+#endif
+
+/*! \brief Bit reverse each bytes in a buffer.
+ \param to The buffer to place the reversed data in.
+ \param from The buffer containing the data to be reversed.
+ \param The length of the data in the buffer. */
+void bit_reverse(uint8_t to[], const uint8_t from[], int len);
+
+/*! \brief Find the number of set bits in a 32 bit word.
+ \param x The word to be searched.
+ \return The number of set bits. */
+int one_bits32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 32 bit word.
+ \param x The word to be searched.
+ \return The mask. */
+uint32_t make_mask32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 16 bit word.
+ \param x The word to be searched.
+ \return The mask. */
+uint16_t make_mask16(uint16_t x);
+
+/*! \brief Find the least significant one in a word, and return a word
+ with just that bit set.
+ \param x The word to be searched.
+ \return The word with the single set bit. */
+static __inline__ uint32_t least_significant_one32(uint32_t x)
+{
+ return (x & (-(int32_t) x));
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the most significant one in a word, and return a word
+ with just that bit set.
+ \param x The word to be searched.
+ \return The word with the single set bit. */
+static __inline__ uint32_t most_significant_one32(uint32_t x)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
+ return 1 << top_bit(x);
+#else
+ x = make_mask32(x);
+ return (x ^ (x >> 1));
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a byte.
+ \param x The byte to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity8(uint8_t x)
+{
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 16 bit word.
+ \param x The word to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity16(uint16_t x)
+{
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 32 bit word.
+ \param x The word to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity32(uint32_t x)
+{
+ x ^= (x >> 16);
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*- End of file ------------------------------------------------------------*/
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * fir.h - General telephony FIR routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2002 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: fir.h,v 1.8 2006/10/24 13:45:28 steveu Exp $
+ */
+
+/*! \page fir_page FIR filtering
+\section fir_page_sec_1 What does it do?
+???.
+
+\section fir_page_sec_2 How does it work?
+???.
+*/
+
+#if 0
+#if defined(USE_MMX) || defined(USE_SSE2)
+#include "mmx.h"
+#endif
+
+/*!
+ 16 bit integer FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using 16 bit integer coefficients.
+*/
+typedef struct {
+ int taps;
+ int curr_pos;
+ const int16_t *coeffs;
+ int16_t *history;
+} fir16_state_t;
+
+/*!
+ 32 bit integer FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using 32 bit integer coefficients, and filtering
+ 16 bit integer data.
+*/
+typedef struct {
+ int taps;
+ int curr_pos;
+ const int32_t *coeffs;
+ int16_t *history;
+} fir32_state_t;
+
+/*!
+ Floating point FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using floating point coefficients and data.
+*/
+typedef struct {
+ int taps;
+ int curr_pos;
+ const float *coeffs;
+ float *history;
+} fir_float_state_t;
+
+static __inline__ const int16_t *fir16_create(fir16_state_t * fir, const int16_t * coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+#if defined(USE_MMX) || defined(USE_SSE2)
+ if ((fir->history = malloc(2 * taps * sizeof(int16_t))))
+ memset(fir->history, 0, 2 * taps * sizeof(int16_t));
+#else
+ if ((fir->history = (int16_t *) malloc(taps * sizeof(int16_t))))
+ memset(fir->history, 0, taps * sizeof(int16_t));
+#endif
+ return fir->history;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_flush(fir16_state_t * fir)
+{
+#if defined(USE_MMX) || defined(USE_SSE2)
+ memset(fir->history, 0, 2 * fir->taps * sizeof(int16_t));
+#else
+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_free(fir16_state_t * fir)
+{
+ free(fir->history);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir16(fir16_state_t * fir, int16_t sample)
+{
+ int i;
+ int32_t y;
+#if defined(USE_MMX)
+ mmx_t *mmx_coeffs;
+ mmx_t *mmx_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ mmx_coeffs = (mmx_t *) fir->coeffs;
+ mmx_hist = (mmx_t *) & fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(mm4, mm4);
+ /* 8 samples per iteration, so the filter must be a multiple of 8 long. */
+ while (i > 0) {
+ movq_m2r(mmx_coeffs[0], mm0);
+ movq_m2r(mmx_coeffs[1], mm2);
+ movq_m2r(mmx_hist[0], mm1);
+ movq_m2r(mmx_hist[1], mm3);
+ mmx_coeffs += 2;
+ mmx_hist += 2;
+ pmaddwd_r2r(mm1, mm0);
+ pmaddwd_r2r(mm3, mm2);
+ paddd_r2r(mm0, mm4);
+ paddd_r2r(mm2, mm4);
+ i -= 8;
+ }
+ movq_r2r(mm4, mm0);
+ psrlq_i2r(32, mm0);
+ paddd_r2r(mm0, mm4);
+ movd_r2m(mm4, y);
+ emms();
+#elif defined(USE_SSE2)
+ xmm_t *xmm_coeffs;
+ xmm_t *xmm_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ xmm_coeffs = (xmm_t *) fir->coeffs;
+ xmm_hist = (xmm_t *) & fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(xmm4, xmm4);
+ /* 16 samples per iteration, so the filter must be a multiple of 16 long. */
+ while (i > 0) {
+ movdqu_m2r(xmm_coeffs[0], xmm0);
+ movdqu_m2r(xmm_coeffs[1], xmm2);
+ movdqu_m2r(xmm_hist[0], xmm1);
+ movdqu_m2r(xmm_hist[1], xmm3);
+ xmm_coeffs += 2;
+ xmm_hist += 2;
+ pmaddwd_r2r(xmm1, xmm0);
+ pmaddwd_r2r(xmm3, xmm2);
+ paddd_r2r(xmm0, xmm4);
+ paddd_r2r(xmm2, xmm4);
+ i -= 16;
+ }
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(8, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(4, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movd_r2m(xmm4, y);
+#else
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
+#endif
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ const int16_t *fir32_create(fir32_state_t * fir, const int32_t * coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = (int16_t *) malloc(taps * sizeof(int16_t));
+ if (fir->history)
+ memset(fir->history, '\0', taps * sizeof(int16_t));
+ return fir->history;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_flush(fir32_state_t * fir)
+{
+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_free(fir32_state_t * fir)
+{
+ free(fir->history);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir32(fir32_state_t * fir, int16_t sample)
+{
+ int i;
+ int32_t y;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ const float *fir_float_create(fir_float_state_t * fir,
+ const float *coeffs, int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = (float *) malloc(taps * sizeof(float));
+ if (fir->history)
+ memset(fir->history, '\0', taps * sizeof(float));
+ return fir->history;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir_float_free(fir_float_state_t * fir)
+{
+ free(fir->history);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir_float(fir_float_state_t * fir, int16_t sample)
+{
+ int i;
+ float y;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) y;
+}
+
+/*- End of function --------------------------------------------------------*/
+#endif
+
+/*- End of file ------------------------------------------------------------*/
+
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.h - An echo cancellor, suitable for electrical and acoustic
+ *         cancellation. This code does not currently comply with
+ *         any relevant standards (e.g. G.164/5/7/8).
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * Based on a bit from here, a bit from there, eye of toad,
+ * ear of bat, etc - plus, of course, my own 2 cents.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: echo.h,v 1.9 2006/10/24 13:45:28 steveu Exp $
+ */
+
+/*! \file */
+
+/*! \page echo_can_page Line echo cancellation for voice
+
+\section echo_can_page_sec_1 What does it do?
+This module aims to provide G.168-2002 compliant echo cancellation, to remove
+electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
+
+\section echo_can_page_sec_2 How does it work?
+The heart of the echo cancellor is FIR filter. This is adapted to match the echo
+impulse response of the telephone line. It must be long enough to adequately cover
+the duration of that impulse response. The signal transmitted to the telephone line
+is passed through the FIR filter. Once the FIR is properly adapted, the resulting
+output is an estimate of the echo signal received from the line. This is subtracted
+from the received signal. The result is an estimate of the signal which originated
+at the far end of the line, free from echos of our own transmitted signal.
+
+The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and was
+introduced in 1960. It is the commonest form of filter adaption used in things
+like modem line equalisers and line echo cancellers. There it works very well.
+However, it only works well for signals of constant amplitude. It works very poorly
+for things like speech echo cancellation, where the signal level varies widely.
+This is quite easy to fix. If the signal level is normalised - similar to applying
+AGC - LMS can work as well for a signal of varying amplitude as it does for a modem
+signal. This normalised least mean squares (NLMS) algorithm is the commonest one used
+for speech echo cancellation. Many other algorithms exist - e.g. RLS (essentially
+the same as Kalman filtering), FAP, etc. Some perform significantly better than NLMS.
+However, factors such as computational complexity and patents favour the use of NLMS.
+
+A simple refinement to NLMS can improve its performance with speech. NLMS tends
+to adapt best to the strongest parts of a signal. If the signal is white noise,
+the NLMS algorithm works very well. However, speech has more low frequency than
+high frequency content. Pre-whitening (i.e. filtering the signal to flatten
+its spectrum) the echo signal improves the adapt rate for speech, and ensures the
+final residual signal is not heavily biased towards high frequencies. A very low
+complexity filter is adequate for this, so pre-whitening adds little to the
+compute requirements of the echo canceller.
+
+An FIR filter adapted using pre-whitened NLMS performs well, provided certain
+conditions are met:
+
+ - The transmitted signal has poor self-correlation.
+ - There is no signal being generated within the environment being cancelled.
+
+The difficulty is that neither of these can be guaranteed.
+
+If the adaption is performed while transmitting noise (or something fairly noise
+like, such as voice) the adaption works very well. If the adaption is performed
+while transmitting something highly correlative (typically narrow band energy
+such as signalling tones or DTMF), the adaption can go seriously wrong. The reason
+is there is only one solution for the adaption on a near random signal - the impulse
+response of the line. For a repetitive signal, there are any number of solutions
+which converge the adaption, and nothing guides the adaption to choose the generalised
+one. Allowing an untrained canceller to converge on this kind of narrowband
+energy probably a good thing, since at least it cancels the tones. Allowing a well
+converged canceller to continue converging on such energy is just a way to ruin
+its generalised adaption. A narrowband detector is needed, so adapation can be
+suspended at appropriate times.
+
+The adaption process is based on trying to eliminate the received signal. When
+there is any signal from within the environment being cancelled it may upset the
+adaption process. Similarly, if the signal we are transmitting is small, noise
+may dominate and disturb the adaption process. If we can ensure that the
+adaption is only performed when we are transmitting a significant signal level,
+and the environment is not, things will be OK. Clearly, it is easy to tell when
+we are sending a significant signal. Telling, if the environment is generating a
+significant signal, and doing it with sufficient speed that the adaption will
+not have diverged too much more we stop it, is a little harder.
+
+The key problem in detecting when the environment is sourcing significant energy
+is that we must do this very quickly. Given a reasonably long sample of the
+received signal, there are a number of strategies which may be used to assess
+whether that signal contains a strong far end component. However, by the time
+that assessment is complete the far end signal will have already caused major
+mis-convergence in the adaption process. An assessment algorithm is needed which
+produces a fairly accurate result from a very short burst of far end energy.
+
+\section echo_can_page_sec_3 How do I use it?
+The echo cancellor processes both the transmit and receive streams sample by
+sample. The processing function is not declared inline. Unfortunately,
+cancellation requires many operations per sample, so the call overhead is only a
+minor burden.
+*/
+
+#define NONUPDATE_DWELL_TIME        600 /* 600 samples, or 75ms */
+
+#if 0
+/* Mask bits for the adaption mode */
+#define ECHO_CAN_USE_NLP 0x01
+#define ECHO_CAN_USE_SUPPRESSOR 0x02
+#define ECHO_CAN_USE_CNG 0x04
+#define ECHO_CAN_USE_ADAPTION 0x08
+
+/*!
+ G.168 echo canceller descriptor. This defines the working state for a line
+ echo canceller.
+*/
+typedef struct {
+ int tx_power[4];
+ int rx_power[3];
+ int clean_rx_power;
+
+ int rx_power_threshold;
+ int nonupdate_dwell;
+
+ fir16_state_t fir_state;
+ /*! Echo FIR taps (16 bit version) */
+ int16_t *fir_taps16[4];
+ /*! Echo FIR taps (32 bit version) */
+ int32_t *fir_taps32;
+
+ int curr_pos;
+
+ int taps;
+ int tap_mask;
+ int adaption_mode;
+
+ int32_t supp_test1;
+ int32_t supp_test2;
+ int32_t supp1;
+ int32_t supp2;
+ int vad;
+ int cng;
+ /* Parameters for the Hoth noise generator */
+ int cng_level;
+ int cng_rndnum;
+ int cng_filter;
+
+ int16_t geigel_max;
+ int geigel_lag;
+ int dtd_onset;
+ int tap_set;
+ int tap_rotate_counter;
+
+ int32_t latest_correction; /* Indication of the magnitude of the latest
+ adaption, or a code to indicate why adaption
+ was skipped, for test purposes */
+ int32_t last_acf[28];
+ int narrowband_count;
+ int narrowband_score;
+} echo_can_state_t;
+
+/*! Create a voice echo canceller context.
+ \param len The length of the canceller, in samples.
+ \return The new canceller context, or NULL if the canceller could not be created.
+*/
+echo_can_state_t *echo_can_create(int len, int adaption_mode);
+
+/*! Free a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void echo_can_free(echo_can_state_t * ec);
+
+/*! Flush (reinitialise) a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void echo_can_flush(echo_can_state_t * ec);
+
+/*! Set the adaption mode of a voice echo canceller context.
+ \param ec The echo canceller context.
+ \param adapt The mode.
+*/
+void echo_can_adaption_mode(echo_can_state_t * ec, int adaption_mode);
+
+/*! Process a sample through a voice echo canceller.
+ \param ec The echo canceller context.
+ \param tx The transmitted audio sample.
+ \param rx The received audio sample.
+ \return The clean (echo cancelled) received sample.
+*/
+int16_t echo_can_update(echo_can_state_t * ec, int16_t tx, int16_t rx);
+
+#endif
+/*- End of file ------------------------------------------------------------*/
+
+/*!
+ Floating point Goertzel filter descriptor.
+*/
+typedef struct {
+ float fac;
+ int samples;
+} goertzel_descriptor_t;
+
+/*!
+ Floating point Goertzel filter state descriptor.
+*/
+typedef struct {
+ float v2;
+ float v3;
+ float fac;
+ int samples;
+ int current_sample;
+} goertzel_state_t;
+
+/*! \brief Create a descriptor for use with either a Goertzel transform */
+void make_goertzel_descriptor(goertzel_descriptor_t * t, float freq, int samples);
+
+/*! \brief Initialise the state of a Goertzel transform.
+ \param s The Goertzel context. If NULL, a context is allocated with malloc.
+ \param t The Goertzel descriptor.
+ \return A pointer to the Goertzel state. */
+goertzel_state_t *goertzel_init(goertzel_state_t * s, goertzel_descriptor_t * t);
+
+/*! \brief Reset the state of a Goertzel transform.
+ \param s The Goertzel context.
+ \param t The Goertzel descriptor.
+ \return A pointer to the Goertzel state. */
+void goertzel_reset(goertzel_state_t * s);
+
+/*! \brief Update the state of a Goertzel transform.
+ \param s The Goertzel context
+ \param amp The samples to be transformed
+ \param samples The number of samples
+ \return The number of samples unprocessed */
+int goertzel_update(goertzel_state_t * s, const int16_t amp[], int samples);
+
+/*! \brief Evaluate the final result of a Goertzel transform.
+ \param s The Goertzel context
+ \return The result of the transform. */
+float goertzel_result(goertzel_state_t * s);
+
+/*! \brief Update the state of a Goertzel transform.
+ \param s The Goertzel context
+ \param amp The sample to be transformed. */
+static __inline__ void goertzel_sample(goertzel_state_t * s, int16_t amp)
+{
+ float v1;
+
+ v1 = s->v2;
+ s->v2 = s->v3;
+ s->v3 = s->fac * s->v2 - v1 + amp;
+ s->current_sample++;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * tone_detect.c - General telephony tone detection.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001-2003, 2005 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: tone_detect.c,v 1.31 2007/03/03 10:40:33 steveu Exp $
+ */
+
+/*! \file tone_detect.h */
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+/*! \page dtmf_rx_page DTMF receiver
+\section dtmf_rx_page_sec_1 What does it do?
+The DTMF receiver detects the standard DTMF digits. It is compliant with
+ITU-T Q.23, ITU-T Q.24, and the local DTMF specifications of most administrations.
+Its passes the test suites. It also scores *very* well on the standard
+talk-off tests.
+
+The current design uses floating point extensively. It is not tolerant of DC.
+It is expected that a DC restore stage will be placed before the DTMF detector.
+Unless the dial tone filter is switched on, the detector has poor tolerance
+of dial tone. Whether this matter depends on your application. If you are using
+the detector in an IVR application you will need proper echo cancellation to
+get good performance in the presence of speech prompts, so dial tone will not
+exist. If you do need good dial tone tolerance, a dial tone filter can be
+enabled in the detector.
+
+\section dtmf_rx_page_sec_2 How does it work?
+Like most other DSP based DTMF detector's, this one uses the Goertzel algorithm
+to look for the DTMF tones. What makes each detector design different is just how
+that algorithm is used.
+
+Basic DTMF specs:
+ - Minimum tone on = 40ms
+ - Minimum tone off = 50ms
+ - Maximum digit rate = 10 per second
+ - Normal twist <= 8dB accepted
+ - Reverse twist <= 4dB accepted
+ - S/N >= 15dB will detect OK
+ - Attenuation <= 26dB will detect OK
+ - Frequency tolerance +- 1.5% will detect, +-3.5% will reject
+
+TODO:
+*/
+
+/*! \page dtmf_tx_page DTMF tone generation
+\section dtmf_tx_page_sec_1 What does it do?
+
+The DTMF tone generation module provides for the generation of the
+repertoire of 16 DTMF dual tones.
+
+\section dtmf_tx_page_sec_2 How does it work?
+*/
+
+#define MAX_DTMF_DIGITS 128
+
+typedef void (*dtmf_rx_callback_t) (void *user_data, const char *digits, int len);
+
+/*!
+ DTMF generator state descriptor. This defines the state of a single
+ working instance of a DTMF generator.
+*/
+#if 0
+typedef struct {
+ tone_gen_descriptor_t *tone_descriptors;
+ tone_gen_state_t tones;
+ char digits[MAX_DTMF_DIGITS + 1];
+ int current_sample;
+ size_t current_digits;
+} dtmf_tx_state_t;
+
+#endif
+
+/*!
+ DTMF digit detector descriptor.
+*/
+typedef struct {
+ /*! Optional callback funcion to deliver received digits. */
+ dtmf_rx_callback_t callback;
+ /*! An opaque pointer passed to the callback function. */
+ void *callback_data;
+ /*! Optional callback funcion to deliver real time digit state changes. */
+ //tone_report_func_t realtime_callback;
+ void *realtime_callback;
+ /*! An opaque pointer passed to the real time callback function. */
+ void *realtime_callback_data;
+ /*! TRUE if dialtone should be filtered before processing */
+ int filter_dialtone;
+ /*! Maximum acceptable "normal" (lower bigger than higher) twist ratio */
+ float normal_twist;
+ /*! Maximum acceptable "reverse" (higher bigger than lower) twist ratio */
+ float reverse_twist;
+
+ /*! 350Hz filter state for the optional dialtone filter */
+ float z350_1;
+ float z350_2;
+ /*! 440Hz filter state for the optional dialtone filter */
+ float z440_1;
+ float z440_2;
+
+ /*! Tone detector working states */
+ goertzel_state_t row_out[4];
+ goertzel_state_t col_out[4];
+ /*! The accumlating total energy on the same period over which the Goertzels work. */
+ float energy;
+ /*! The result of the last tone analysis. */
+ uint8_t last_hit;
+ /*! The confirmed digit we are currently receiving */
+ uint8_t in_digit;
+ /*! The current sample number within a processing block. */
+ int current_sample;
+
+ /*! The received digits buffer. This is a NULL terminated string. */
+ char digits[MAX_DTMF_DIGITS + 1];
+ /*! The number of digits currently in the digit buffer. */
+ int current_digits;
+ /*! The number of digits which have been lost due to buffer overflows. */
+ int lost_digits;
+} dtmf_rx_state_t;
+
+#if 0
+/*! \brief Generate a buffer of DTMF tones.
+ \param s The DTMF generator context.
+ \param amp The buffer for the generated signal.
+ \param max_samples The required number of generated samples.
+ \return The number of samples actually generated. This may be less than
+ samples if the input buffer empties. */
+int dtmf_tx(dtmf_tx_state_t * s, int16_t amp[], int max_samples);
+
+/*! \brief Put a string of digits in a DTMF generator's input buffer.
+ \param s The DTMF generator context.
+ \param digits The string of digits to be added.
+ \return The number of digits actually added. This may be less than the
+ length of the digit string, if the buffer fills up. */
+size_t dtmf_tx_put(dtmf_tx_state_t * s, const char *digits);
+
+/*! \brief Initialise a DTMF tone generator context.
+ \param s The DTMF generator context.
+ \return A pointer to the DTMF generator context. */
+dtmf_tx_state_t *dtmf_tx_init(dtmf_tx_state_t * s);
+#endif
+
+/*! Set a optional realtime callback for a DTMF receiver context. This function
+ is called immediately a confirmed state change occurs in the received DTMF. It
+ is called with the ASCII value for a DTMF tone pair, or zero to indicate no tone
+ is being received.
+ \brief Set a realtime callback for a DTMF receiver context.
+ \param s The DTMF receiver context.
+ \param callback Callback routine used to report the start and end of digits.
+ \param user_data An opaque pointer which is associated with the context,
+ and supplied in callbacks. */
+void dtmf_rx_set_realtime_callback(dtmf_rx_state_t * s,
+ //tone_report_func_t callback,
+ void *callback, void *user_data);
+
+/*! \brief Adjust a DTMF receiver context.
+ \param s The DTMF receiver context.
+ \param filter_dialtone TRUE to enable filtering of dialtone, FALSE
+ to disable, < 0 to leave unchanged.
+ \param twist Acceptable twist, in dB. < 0 to leave unchanged.
+ \param reverse_twist Acceptable reverse twist, in dB. < 0 to leave unchanged. */
+void dtmf_rx_parms(dtmf_rx_state_t * s, int filter_dialtone, int twist,
+ int reverse_twist);
+
+/*! Process a block of received DTMF audio samples.
+ \brief Process a block of received DTMF audio samples.
+ \param s The DTMF receiver context.
+ \param amp The audio sample buffer.
+ \param samples The number of samples in the buffer.
+ \return The number of samples unprocessed. */
+int dtmf_rx(dtmf_rx_state_t * s, const int16_t amp[], int samples);
+
+/*! \brief Get a string of digits from a DTMF receiver's output buffer.
+ \param s The DTMF receiver context.
+ \param digits The buffer for the received digits.
+ \param max The maximum number of digits to be returned,
+ \return The number of digits actually returned. */
+size_t dtmf_rx_get(dtmf_rx_state_t * s, char *digits, int max);
+
+/*! \brief Initialise a DTMF receiver context.
+ \param s The DTMF receiver context.
+ \param callback An optional callback routine, used to report received digits. If
+ no callback routine is set, digits may be collected, using the dtmf_rx_get()
+ function.
+ \param user_data An opaque pointer which is associated with the context,
+ and supplied in callbacks.
+ \return A pointer to the DTMF receiver context. */
+dtmf_rx_state_t *dtmf_rx_init(dtmf_rx_state_t * s, dtmf_rx_callback_t callback,
+ void *user_data);
+
+/*- End of file ------------------------------------------------------------*/
+
+#ifdef __cplusplus
+} //extern "C"
+#endif                                                        /* __cplusplus */
+#endif /* _CELLIAX_SPANDSP_H */
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenfiltra48down8c"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/filtra48down8.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/filtra48down8.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/filtra48down8.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,71 @@
</span><ins>+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: testresample.c
+ Testing the resampling code
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <stdio.h>
+#include <math.h>
+#include <stdlib.h>
+
+#define NN 256
+
+int main()
+{
+ short *in;
+ short *out;
+ int i;
+ int a;
+
+ in = malloc(NN*sizeof(short));
+ out = malloc(NN*sizeof(short)/6);
+ while (1)
+ {
+ fread(in, sizeof(short), NN, stdin);
+ if (feof(stdin))
+ break;
+
+ a=0;
+ for (i=0;i<NN;i++){
+ out[a]=in[i];
+ i++;
+ i++;
+ i++;
+ i++;
+ i++;
+ a++;
+ }
+
+ fwrite(out, sizeof(short), NN/6, stdout);
+ }
+ free(in);
+ free(out);
+ return 0;
+}
+
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenfiltra8up48c"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/filtra8up48.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/filtra8up48.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/filtra8up48.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,81 @@
</span><ins>+/* Copyright (C) 2007 Jean-Marc Valin
+
+ File: testresample.c
+ Testing the resampling code
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ 3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+//#include "speex/speex_resampler.h"
+#include <math.h>
+#include <stdlib.h>
+
+#define NN 256
+
+int main()
+{
+ short *in;
+ short *out;
+ int i;
+ int a;
+
+ in = malloc(NN*sizeof(short));
+ out = malloc(NN*sizeof(short)*6);
+ while (1)
+ {
+ fread(in, sizeof(short), NN, stdin);
+ if (feof(stdin))
+ break;
+
+ a=0;
+ for (i=0;i<NN;i++){
+ out[a]=in[i];
+ a++;
+ out[a]=in[i];
+ a++;
+ out[a]=in[i];
+ a++;
+ out[a]=in[i];
+ a++;
+ out[a]=in[i];
+ a++;
+ out[a]=in[i];
+ a++;
+ }
+
+ fwrite(out, sizeof(short), NN*6, stdout);
+ }
+ free(in);
+ free(out);
+ return 0;
+}
+
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopengsmopenh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -77,8 +77,14 @@
</span><span class="cx">
</span><span class="cx"> #ifdef GSMOPEN_PORTAUDIO
</span><span class="cx"> #include "pablio.h"
</span><ins>+#undef WANT_SPEEX
+#ifdef WANT_SPEEX
+#include "speex/speex_preprocess.h"
+#include "speex/speex_echo.h"
+#endif /* WANT_SPEEX */
</ins><span class="cx"> #endif// GSMOPEN_PORTAUDIO
</span><span class="cx">
</span><ins>+#include "celliax_spandsp.h"
</ins><span class="cx"> #ifndef WIN32
</span><span class="cx"> #include <sys/time.h>
</span><span class="cx"> //#include <X11/Xlib.h>
</span><span class="lines">@@ -471,7 +477,12 @@
</span><span class="cx">          int portaudiopindex; /*!< \brief Index of the Portaudio playback audio device */
</span><span class="cx">          PABLIO_Stream *stream;
</span><span class="cx">
</span><ins>+#ifdef WANT_SPEEX
+ SpeexPreprocessState *preprocess;
+ SpeexEchoState *echo_state;
+#endif// WANT_SPEEX
</ins><span class="cx"> #endif// GSMOPEN_PORTAUDIO
</span><ins>+                 dtmf_rx_state_t dtmf_state;
</ins><span class="cx">
</span><span class="cx"> };
</span><span class="cx">
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopengsmopen_protocolcpp"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.cpp (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.cpp        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/gsmopen_protocol.cpp        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -124,7 +124,6 @@
</span><span class="cx"> PaStreamParameters inputParameters, outputParameters;
</span><span class="cx"> int numdevices;
</span><span class="cx"> const PaDeviceInfo *deviceInfo;
</span><del>- long owner=1;
</del><span class="cx">
</span><span class="cx"> #ifndef GIOVA48
</span><span class="cx"> setenv("PA_ALSA_PLUGHW", "1", 1);
</span><span class="lines">@@ -211,8 +210,7 @@
</span><span class="cx"> err =
</span><span class="cx"> #ifndef GIOVA48
</span><span class="cx"> OpenAudioStream(&tech_pvt->stream, &inputParameters, &outputParameters, 8000,
</span><del>- paDitherOff | paClipOff, SAMPLES_PER_FRAME, tech_pvt->audiopipe[1],
- &tech_pvt->speexecho, &tech_pvt->speexpreprocess, &owner);
</del><ins>+ paClipOff|paDitherOff, SAMPLES_PER_FRAME, 0);
</ins><span class="cx"> //&tech_pvt->speexecho, &tech_pvt->speexpreprocess, &tech_pvt->owner);
</span><span class="cx">
</span><span class="cx"> #else // GIOVA48
</span><span class="lines">@@ -289,18 +287,19 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx"> samples =
</span><del>- WriteAudioStream(tech_pvt->stream, (short *) data, (int) (datalen / sizeof(short)));
</del><ins>+ WriteAudioStream(tech_pvt->stream, (short *) data, (int) (datalen / sizeof(short)), &tech_pvt->timer_write);
</ins><span class="cx">
</span><span class="cx"> if (samples != (int) (datalen / sizeof(short)))
</span><span class="cx"> ERRORA("WriteAudioStream wrote: %d of %d\n", GSMOPEN_P_LOG, samples,
</span><span class="cx"> (int) (datalen / sizeof(short)));
</span><span class="cx">
</span><del>- return 0;
</del><ins>+ return samples;
</ins><span class="cx"> }
</span><span class="cx"> //struct ast_frame *gsmopen_portaudio_read(private_t *tech_pvt)
</span><span class="cx"> #define AST_FRIENDLY_OFFSET 0
</span><span class="cx"> int gsmopen_portaudio_read(private_t * tech_pvt, short *data, int datalen)
</span><span class="cx"> {
</span><ins>+#if 0
</ins><span class="cx"> //static struct ast_frame f;
</span><span class="cx"> static short __buf[GSMOPEN_FRAME_SIZE + AST_FRIENDLY_OFFSET / 2];
</span><span class="cx"> short *buf;
</span><span class="lines">@@ -337,7 +336,7 @@
</span><span class="cx">
</span><span class="cx"> //if ((samples = ReadAudioStream(tech_pvt->stream, buf, SAMPLES_PER_FRAME)) == 0)
</span><span class="cx"> //if ((samples = ReadAudioStream(tech_pvt->stream, data, datalen/sizeof(short))) == 0)
</span><del>- if ((samples = ReadAudioStream(tech_pvt->stream, data, datalen)) == 0) {
</del><ins>+ if (samples = ReadAudioStream(tech_pvt->stream, (short *)data, datalen, &tech_pvt->timer_read) == 0) {
</ins><span class="cx"> //do nothing
</span><span class="cx"> } else {
</span><span class="cx"> #ifdef GIOVA48
</span><span class="lines">@@ -384,6 +383,12 @@
</span><span class="cx">
</span><span class="cx"> return &f;
</span><span class="cx"> #endif //0
</span><ins>+#endif //0
+
+ int samples;
+ samples = ReadAudioStream(tech_pvt->stream, (short *)data, datalen, &tech_pvt->timer_read);
+ //WARNINGA("samples=%d\n", GSMOPEN_P_LOG, samples);
+
</ins><span class="cx"> return samples;
</span><span class="cx"> }
</span><span class="cx"> int gsmopen_portaudio_shutdown(private_t *tech_pvt)
</span><span class="lines">@@ -2655,7 +2660,7 @@
</span><span class="cx">                         DEBUGA_PBX("call answered\n", GSMOPEN_P_LOG);
</span><span class="cx">                 res = 0;
</span><span class="cx"> #ifdef GSMOPEN_PORTAUDIO
</span><del>-                speex_echo_state_reset(tech_pvt->stream->echo_state);
</del><ins>+                //speex_echo_state_reset(tech_pvt->stream->echo_state);
</ins><span class="cx"> #endif // GSMOPEN_PORTAUDIO
</span><span class="cx">
</span><span class="cx">                 new_inbound_channel(tech_pvt);
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenmod_gsmopencpp"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.cpp (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.cpp        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/mod_gsmopen.cpp        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -248,6 +248,11 @@
</span><span class="cx"> switch_status_t gsmopen_tech_init(private_t * tech_pvt, switch_core_session_t *session)
</span><span class="cx"> {
</span><span class="cx">
</span><ins>+#ifdef WANT_SPEEX
+        int ciapa;
+        long level;
+        int tmp;
+#endif// WANT_SPEEX
</ins><span class="cx">         switch_assert(tech_pvt != NULL);
</span><span class="cx">         switch_assert(session != NULL);
</span><span class="cx">         tech_pvt->read_frame.data = tech_pvt->databuf;
</span><span class="lines">@@ -265,7 +270,9 @@
</span><span class="cx">                 return SWITCH_STATUS_FALSE;
</span><span class="cx">         }
</span><span class="cx">         //teletone_dtmf_detect_init(&tech_pvt->dtmf_detect, tech_pvt->read_codec.implementation->actual_samples_per_second);
</span><del>-        teletone_dtmf_detect_init(&tech_pvt->dtmf_detect, 8000);
</del><ins>+        //teletone_dtmf_detect_init(&tech_pvt->dtmf_detect, 8000);
+ dtmf_rx_init(&tech_pvt->dtmf_state, NULL, NULL);
+ dtmf_rx_parms(&tech_pvt->dtmf_state, 0, 10, 10);
</ins><span class="cx">
</span><span class="cx"> #ifdef GSMOPEN_ALSA
</span><span class="cx">         if(tech_pvt->no_sound==0){
</span><span class="lines">@@ -302,7 +309,97 @@
</span><span class="cx">
</span><span class="cx">         switch_core_timer_sync(&tech_pvt->timer_write);
</span><span class="cx">
</span><ins>+#ifdef WANT_SPEEX
+ /* Echo canceller with 100 ms tail length */
+#ifndef GIOVA48
+ tech_pvt->echo_state = speex_echo_state_init(160, 1024);
+ ciapa = 8000;
+#else// GIOVA48
+ tech_pvt->echo_state = speex_echo_state_init(960, 4800);
+ ciapa = 48000;
+#endif // GIOVA48
+ speex_echo_ctl(tech_pvt->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &ciapa);
</ins><span class="cx">
</span><ins>+#if 1 //NO MORE
+ /* Setup preprocessor and associate with echo canceller for residual echo suppression */
+#ifndef GIOVA48
+ tech_pvt->preprocess = speex_preprocess_state_init(160, 8000);
+#else// GIOVA48
+ tech_pvt->preprocess = speex_preprocess_state_init(960, 48000);
+#endif // GIOVA48
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
+ tech_pvt->echo_state);
+
+#if 0
+ /* Setup preprocessor various other goodies */
+ tmp = 0;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_SET_AGC, &tmp);
+ //level=8000.1;
+ //speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_SET_AGC_LEVEL, &level);
+
+ // Let's turn off all of the 'denoisers' (eg denoise and dereverb, and vad too) because they start automatic gain on mic input on cm108 usb, also if it (the agc on usb) disbled through mixer
+ tmp = 0;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_SET_VAD, &tmp);
+#endif
+
+ tmp = 0;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_AGC, &tmp);
+ fprintf(stderr, "AGC is: %d\n", tmp);
+ level = 1.0;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
+ fprintf(stderr, "AGC_LEVEL is: %f\n", level);
+ //tmp=1;
+ //speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
+ //fprintf( stderr, "AGC_TARGET is: %d\n", tmp );
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
+ fprintf(stderr, "DENOISE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
+ fprintf(stderr, "DEREVERB is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_VAD, &tmp);
+ fprintf(stderr, "VAD is: %d\n", tmp);
+
+#if 0
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_NOISE_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
+ &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_START is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(tech_pvt->preprocess, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_CONTINUE is: %d\n", tmp);
+#endif //0
+#endif// 0 //NO MORE
+
+#endif // WANT_SPEEX
+
+
+
</ins><span class="cx">         switch_clear_flag(tech_pvt, TFLAG_HANGUP);
</span><span class="cx">         DEBUGA_GSMOPEN("gsmopen_codec SUCCESS\n", GSMOPEN_P_LOG);
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="lines">@@ -712,7 +809,15 @@
</span><span class="cx">         int samples;
</span><span class="cx">         char digit_str[256];
</span><span class="cx"> #endif // defined(GSMOPEN_ALSA) || defined(GSMOPEN_PORTAUDIO)
</span><ins>+#ifdef GSMOPEN_PORTAUDIO
+#ifdef WANT_SPEEX
+ spx_int16_t *speexptr;
+ spx_int16_t pcm2[160];
+ int i;
+#endif// GSMOPEN_ALSA
+#endif// WANT_SPEEX
</ins><span class="cx">
</span><ins>+
</ins><span class="cx">         channel = switch_core_session_get_channel(session);
</span><span class="cx">         switch_assert(channel != NULL);
</span><span class="cx">
</span><span class="lines">@@ -734,7 +839,7 @@
</span><span class="cx">         }
</span><span class="cx">
</span><span class="cx">
</span><del>-        switch_core_timer_next(&tech_pvt->timer_read);
</del><ins>+        //switch_core_timer_next(&tech_pvt->timer_read);
</ins><span class="cx">
</span><span class="cx">                 if(tech_pvt->no_sound==1){
</span><span class="cx">                 goto cng;
</span><span class="lines">@@ -749,17 +854,39 @@
</span><span class="cx"> #endif// GSMOPEN_PORTAUDIO
</span><span class="cx">         {
</span><span class="cx">
</span><del>-                tech_pvt->read_frame.datalen = samples * 2;
-                tech_pvt->read_frame.samples = samples;
</del><ins>+#ifdef GSMOPEN_PORTAUDIO
+#ifdef WANT_SPEEX
</ins><span class="cx">
</span><del>-                //switch_core_timer_check(&tech_pvt->timer, SWITCH_TRUE);
-                tech_pvt->read_frame.timestamp = tech_pvt->timer_read.samplecount;
</del><ins>+ if (tech_pvt->speexecho) {
+ speexptr = ((spx_int16_t *) tech_pvt->read_frame.data);
+ /* Perform echo cancellation */
+ speex_echo_capture(tech_pvt->echo_state, speexptr, pcm2);
+#ifndef GIOVA48
+ for (i = 0; i < 160; i++)
+#else //GIOVA48
+ for (i = 0; i < 960; i++)
+#endif //GIOVA48
+ speexptr[i] = pcm2[i];
+ }
+ /* Apply noise/echo residual suppression */
+ if (tech_pvt->speexpreprocess) {
+ speex_preprocess_run(tech_pvt->preprocess, speexptr);
+ }
</ins><span class="cx">
</span><del>-                gsmopen_sound_boost(tech_pvt->read_frame.data, tech_pvt->read_frame.samples, tech_pvt->capture_boost);
</del><ins>+                DEBUGA_GSMOPEN("read\n", GSMOPEN_P_LOG);
+#endif //WANT_SPEEX
+#endif // GSMOPEN_PORTAUDIO
</ins><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">
</span><ins>+
+                tech_pvt->read_frame.datalen = samples * 2;
+                tech_pvt->read_frame.samples = samples;
+
+                //switch_core_timer_check(&tech_pvt->timer, SWITCH_TRUE);
+                //tech_pvt->read_frame.timestamp = tech_pvt->timer_read.samplecount;
+
</ins><span class="cx">                 *frame = &tech_pvt->read_frame;
</span><span class="cx">
</span><span class="cx">                 //status = SWITCH_STATUS_SUCCESS;
</span><span class="lines">@@ -781,9 +908,13 @@
</span><span class="cx">
</span><span class="cx">
</span><span class="cx">         memset(digit_str, 0, sizeof(digit_str));
</span><del>-        teletone_dtmf_detect(&tech_pvt->dtmf_detect, (int16_t *) tech_pvt->read_frame.data, tech_pvt->read_frame.samples);
-        teletone_dtmf_get(&tech_pvt->dtmf_detect, digit_str, sizeof(digit_str));
</del><ins>+        //teletone_dtmf_detect(&tech_pvt->dtmf_detect, (int16_t *) tech_pvt->read_frame.data, tech_pvt->read_frame.samples);
+        //teletone_dtmf_get(&tech_pvt->dtmf_detect, digit_str, sizeof(digit_str));
+ dtmf_rx(&tech_pvt->dtmf_state, (int16_t *) tech_pvt->read_frame.data, tech_pvt->read_frame.samples);
+ dtmf_rx_get(&tech_pvt->dtmf_state, digit_str, sizeof(digit_str));
</ins><span class="cx">
</span><ins>+                gsmopen_sound_boost(tech_pvt->read_frame.data, tech_pvt->read_frame.samples, tech_pvt->capture_boost);
+
</ins><span class="cx">         if (digit_str[0]) {
</span><span class="cx">                 switch_time_t new_dtmf_timestamp = switch_time_now();
</span><span class="cx">                 if ((new_dtmf_timestamp - tech_pvt->old_dtmf_timestamp) > 350000) {        //FIXME: make it configurable
</span><span class="lines">@@ -847,7 +978,7 @@
</span><span class="cx">         tech_pvt->read_frame.flags = SFF_CNG;
</span><span class="cx">         *frame = &tech_pvt->read_frame;
</span><span class="cx"> #ifdef GSMOPEN_PORTAUDIO
</span><del>-                speex_echo_state_reset(tech_pvt->stream->echo_state);
</del><ins>+                //speex_echo_state_reset(tech_pvt->stream->echo_state);
</ins><span class="cx"> #endif // GSMOPEN_PORTAUDIO
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="cx">
</span><span class="lines">@@ -860,6 +991,11 @@
</span><span class="cx"> #if defined(GSMOPEN_ALSA) || defined(GSMOPEN_PORTAUDIO)
</span><span class="cx">         unsigned int sent;
</span><span class="cx"> #endif // defined(GSMOPEN_ALSA) || defined(GSMOPEN_PORTAUDIO)
</span><ins>+#ifdef GSMOPEN_PORTAUDIO
+#ifdef WANT_SPEEX
+ spx_int16_t *speexptr;
+#endif// GSMOPEN_ALSA
+#endif// WANT_SPEEX
</ins><span class="cx">
</span><span class="cx">         channel = switch_core_session_get_channel(session);
</span><span class="cx">         switch_assert(channel != NULL);
</span><span class="lines">@@ -882,7 +1018,7 @@
</span><span class="cx">         }
</span><span class="cx"> #endif
</span><span class="cx">
</span><del>-        switch_core_timer_next(&tech_pvt->timer_write);
</del><ins>+        //switch_core_timer_next(&tech_pvt->timer_write);
</ins><span class="cx">         //sent = frame->datalen;
</span><span class="cx">
</span><span class="cx">         //ERRORA("PLAY \n", GSMOPEN_P_LOG);
</span><span class="lines">@@ -890,6 +1026,7 @@
</span><span class="cx">
</span><span class="cx">         gsmopen_sound_boost(frame->data, frame->samples, tech_pvt->playback_boost);
</span><span class="cx"> #ifdef GSMOPEN_ALSA
</span><ins>+
</ins><span class="cx">         sent = alsa_write(tech_pvt, (short *) frame->data, (int) (frame->datalen));
</span><span class="cx"> //DEBUGA_GSMOPEN("sent=%d \n", GSMOPEN_P_LOG, sent);
</span><span class="cx">
</span><span class="lines">@@ -905,6 +1042,14 @@
</span><span class="cx">                 DEBUGA_GSMOPEN("sent %d\n", GSMOPEN_P_LOG, sent);
</span><span class="cx">         }
</span><span class="cx">
</span><ins>+#ifdef WANT_SPEEX
+ if (tech_pvt->speexecho) {
+ speexptr = (spx_int16_t *) frame->data;
+ /* Put frame into playback buffer */
+ speex_echo_playback(tech_pvt->echo_state, speexptr);
+                DEBUGA_GSMOPEN("write\n", GSMOPEN_P_LOG);
+ }
+#endif //WANT_SPEEX
</ins><span class="cx"> #endif // GSMOPEN_PORTAUDIO
</span><span class="cx">         //NOTICA("sent=%d\n", GSMOPEN_P_LOG, sent);
</span><span class="cx">         return SWITCH_STATUS_SUCCESS;
</span><span class="lines">@@ -960,7 +1105,7 @@
</span><span class="cx"> {
</span><span class="cx">         switch_channel_t *channel;
</span><span class="cx">         private_t *tech_pvt;
</span><del>-#if defined(GSMOPEN_ALSA) || defined(GSMOPEN_PORTAUDIO)
</del><ins>+#if defined(GSMOPEN_ALSA)
</ins><span class="cx">         int samples;
</span><span class="cx">         short tmp_buffer[1280];
</span><span class="cx"> #endif // defined(GSMOPEN_ALSA) || defined(GSMOPEN_PORTAUDIO)
</span><span class="lines">@@ -981,20 +1126,22 @@
</span><span class="cx">         case SWITCH_MESSAGE_INDICATE_AUDIO_SYNC:
</span><span class="cx">
</span><span class="cx">                 WARNINGA("%s CHANNEL got SWITCH_MESSAGE_INDICATE_AUDIO_SYNC\n", GSMOPEN_P_LOG, switch_channel_get_name(channel));
</span><ins>+                switch_core_timer_sync(&tech_pvt->timer_read);
+                switch_core_timer_sync(&tech_pvt->timer_write);
+
</ins><span class="cx"> #ifdef GSMOPEN_ALSA
</span><span class="cx">                 while ((samples = alsa_read(tech_pvt, tmp_buffer, tech_pvt->read_codec.implementation->samples_per_packet * 4)) > 160) {
</span><span class="cx">                         //WARNINGA("read %d samples\n", GSMOPEN_P_LOG, samples);
</span><span class="cx">                 }
</span><span class="cx"> #endif// GSMOPEN_ALSA
</span><span class="cx"> #ifdef GSMOPEN_PORTAUDIO
</span><del>-                while ((samples = gsmopen_portaudio_read(tech_pvt, tmp_buffer, tech_pvt->read_codec.implementation->samples_per_packet * 4)) > 160) {
</del><ins>+                //while ((samples = gsmopen_portaudio_read(tech_pvt, tmp_buffer, tech_pvt->read_codec.implementation->samples_per_packet * 2)) > 160) {
</ins><span class="cx">                         //WARNINGA("read %d samples\n", GSMOPEN_P_LOG, samples);
</span><del>-                }
-
</del><ins>+                //}
+#ifdef WANT_SPEEX
+                speex_echo_state_reset(tech_pvt->echo_state);
+#endif// WANT_SPEEX
</ins><span class="cx"> #endif// GSMOPEN_PORTAUDIO
</span><del>-                switch_core_timer_sync(&tech_pvt->timer_read);
-                switch_core_timer_sync(&tech_pvt->timer_write);
-
</del><span class="cx">                 break;
</span><span class="cx">
</span><span class="cx">
</span><span class="lines">@@ -2599,7 +2746,7 @@
</span><span class="cx">
</span><span class="cx">                         if ((now_timestamp - tech_pvt->gsmopen_serial_synced_timestamp) > 30) {        //TODO find a sensible period. 5min? in config?
</span><span class="cx">                                 gsmopen_serial_sync(tech_pvt);
</span><del>-                                gsmopen_serial_getstatus_AT(tech_pvt);
</del><ins>+                                //gsmopen_serial_getstatus_AT(tech_pvt);
</ins><span class="cx">                         }
</span><span class="cx">                 }
</span><span class="cx">         WARNINGA("EXIT\n", GSMOPEN_P_LOG);
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopennoalsamod_gsmopencelliax_spandspc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.c
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.c
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopennoalsamod_gsmopencelliax_spandsph"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.h
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/noalsa/mod_gsmopen/celliax_spandsp.h
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopennogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandspc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.c
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopennogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandsph"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.h
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopennogsmlib_nocplusplusmod_gsmopencelliax_spandspc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.c
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.c
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopennogsmlib_nocplusplusmod_gsmopencelliax_spandsph"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.h
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/nogsmlib_nocplusplus/mod_gsmopen/celliax_spandsp.h
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenpa_ringbufferc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,275 @@
</span><ins>+/*
+ * $Id: pa_ringbuffer.c 1164 2006-12-21 15:34:50Z bjornroche $
+ * Portable Audio I/O Library
+ * Ring Buffer utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ * modified for SMP safety on Mac OS X by Bjorn Roche
+ * modified for SMP safety on Linux by Leland Lucius
+ * also, allowed for const where possible
+ * Note that this is safe only for a single-thread reader and a
+ * single-thread writer.
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The text above constitutes the entire PortAudio license; however,
+ * the PortAudio community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the
+ * license above.
+ */
+
+/**
+ @file
+ @ingroup common_src
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pa_ringbuffer.h"
+#include <string.h>
+
+/****************
+ * First, we'll define some memory barrier primitives based on the system.
+ * right now only OS X, FreeBSD, and Linux are supported. In addition to providing
+ * memory barriers, these functions should ensure that data cached in registers
+ * is written out to cache where it can be snooped by other CPUs. (ie, the volatile
+ * keyword should not be required)
+ *
+ * the primitives that must be defined are:
+ *
+ * PaUtil_FullMemoryBarrier()
+ * PaUtil_ReadMemoryBarrier()
+ * PaUtil_WriteMemoryBarrier()
+ *
+ ****************/
+#define __VIA_HACK__
+#if defined(__VIA_HACK__)
+#define NO_BARRIER
+#endif
+
+#if defined(NO_BARRIER)
+# define PaUtil_FullMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier()
+#else
+
+#if defined(__APPLE__)                        //|| defined(__FreeBSD__)
+# include <libkern/OSAtomic.h>
+        /* Here are the memory barrier functions. Mac OS X and FreeBSD only provide
+         full memory barriers, so the three types of barriers are the same. */
+# define PaUtil_FullMemoryBarrier() OSMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier() OSMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier() OSMemoryBarrier()
+#elif defined(__GNUC__)
+
+        /* GCC understands volatile asm and "memory" to mean it
+         * should not reorder memory read/writes */
+# if defined( __PPC__ )
+# define PaUtil_FullMemoryBarrier() __asm__ volatile("sync":::"memory")
+# define PaUtil_ReadMemoryBarrier() __asm__ volatile("sync":::"memory")
+# define PaUtil_WriteMemoryBarrier() __asm__ volatile("sync":::"memory")
+# elif defined( __i386__ ) || defined( __i486__ ) || defined( __i586__ ) || defined( __i686__ ) || defined(__x86_64__)
+# define PaUtil_FullMemoryBarrier() __asm__ volatile("mfence":::"memory")
+# define PaUtil_ReadMemoryBarrier() __asm__ volatile("lfence":::"memory")
+# define PaUtil_WriteMemoryBarrier() __asm__ volatile("sfence":::"memory")
+# else
+# define PaUtil_FullMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier()
+# endif
+#elif defined(_MSC_VER)
+# include <intrin.h>
+# pragma intrinsic(_ReadWriteBarrier)
+# pragma intrinsic(_ReadBarrier)
+# pragma intrinsic(_WriteBarrier)
+# define PaUtil_FullMemoryBarrier() _ReadWriteBarrier()
+# define PaUtil_ReadMemoryBarrier() _ReadBarrier()
+# define PaUtil_WriteMemoryBarrier() _WriteBarrier()
+#else
+# define PaUtil_FullMemoryBarrier()
+# define PaUtil_ReadMemoryBarrier()
+# define PaUtil_WriteMemoryBarrier()
+#endif
+#endif
+/***************************************************************************
+ * Initialize FIFO.
+ * numBytes must be power of 2, returns -1 if not.
+ */
+long PaUtil_InitializeRingBuffer(PaUtilRingBuffer * rbuf, long numBytes, void *dataPtr)
+{
+        if (((numBytes - 1) & numBytes) != 0)
+                return -1;                                /* Not Power of two. */
+        rbuf->bufferSize = numBytes;
+        rbuf->buffer = (char *) dataPtr;
+        PaUtil_FlushRingBuffer(rbuf);
+        rbuf->bigMask = (numBytes * 2) - 1;
+        rbuf->smallMask = (numBytes) - 1;
+        return 0;
+}
+
+/***************************************************************************
+** Return number of bytes available for reading. */
+long PaUtil_GetRingBufferReadAvailable(PaUtilRingBuffer * rbuf)
+{
+        PaUtil_ReadMemoryBarrier();
+        return ((rbuf->writeIndex - rbuf->readIndex) & rbuf->bigMask);
+}
+
+/***************************************************************************
+** Return number of bytes available for writing. */
+long PaUtil_GetRingBufferWriteAvailable(PaUtilRingBuffer * rbuf)
+{
+        /* Since we are calling PaUtil_GetRingBufferReadAvailable, we don't need an aditional MB */
+        return (rbuf->bufferSize - PaUtil_GetRingBufferReadAvailable(rbuf));
+}
+
+/***************************************************************************
+** Clear buffer. Should only be called when buffer is NOT being read. */
+void PaUtil_FlushRingBuffer(PaUtilRingBuffer * rbuf)
+{
+        rbuf->writeIndex = rbuf->readIndex = 0;
+}
+
+/***************************************************************************
+** Get address of region(s) to which we can write data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long PaUtil_GetRingBufferWriteRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2)
+{
+        long index;
+        long available = PaUtil_GetRingBufferWriteAvailable(rbuf);
+        if (numBytes > available)
+                numBytes = available;
+        /* Check to see if write is not contiguous. */
+        index = rbuf->writeIndex & rbuf->smallMask;
+        if ((index + numBytes) > rbuf->bufferSize) {
+                /* Write data in two blocks that wrap the buffer. */
+                long firstHalf = rbuf->bufferSize - index;
+                *dataPtr1 = &rbuf->buffer[index];
+                *sizePtr1 = firstHalf;
+                *dataPtr2 = &rbuf->buffer[0];
+                *sizePtr2 = numBytes - firstHalf;
+        } else {
+                *dataPtr1 = &rbuf->buffer[index];
+                *sizePtr1 = numBytes;
+                *dataPtr2 = NULL;
+                *sizePtr2 = 0;
+        }
+        return numBytes;
+}
+
+
+/***************************************************************************
+*/
+long PaUtil_AdvanceRingBufferWriteIndex(PaUtilRingBuffer * rbuf, long numBytes)
+{
+        /* we need to ensure that previous writes are seen before we update the write index */
+        PaUtil_WriteMemoryBarrier();
+        return rbuf->writeIndex = (rbuf->writeIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Get address of region(s) from which we can read data.
+** If the region is contiguous, size2 will be zero.
+** If non-contiguous, size2 will be the size of second region.
+** Returns room available to be written or numBytes, whichever is smaller.
+*/
+long PaUtil_GetRingBufferReadRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2)
+{
+        long index;
+        long available = PaUtil_GetRingBufferReadAvailable(rbuf);
+        if (numBytes > available)
+                numBytes = available;
+        /* Check to see if read is not contiguous. */
+        index = rbuf->readIndex & rbuf->smallMask;
+        if ((index + numBytes) > rbuf->bufferSize) {
+                /* Write data in two blocks that wrap the buffer. */
+                long firstHalf = rbuf->bufferSize - index;
+                *dataPtr1 = &rbuf->buffer[index];
+                *sizePtr1 = firstHalf;
+                *dataPtr2 = &rbuf->buffer[0];
+                *sizePtr2 = numBytes - firstHalf;
+        } else {
+                *dataPtr1 = &rbuf->buffer[index];
+                *sizePtr1 = numBytes;
+                *dataPtr2 = NULL;
+                *sizePtr2 = 0;
+        }
+        return numBytes;
+}
+
+/***************************************************************************
+*/
+long PaUtil_AdvanceRingBufferReadIndex(PaUtilRingBuffer * rbuf, long numBytes)
+{
+        /* we need to ensure that previous writes are always seen before updating the index. */
+        PaUtil_WriteMemoryBarrier();
+        return rbuf->readIndex = (rbuf->readIndex + numBytes) & rbuf->bigMask;
+}
+
+/***************************************************************************
+** Return bytes written. */
+long PaUtil_WriteRingBuffer(PaUtilRingBuffer * rbuf, const void *data, long numBytes)
+{
+        long size1, size2, numWritten;
+        void *data1, *data2;
+        numWritten = PaUtil_GetRingBufferWriteRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
+        if (size2 > 0) {
+
+                memcpy(data1, data, size1);
+                data = ((char *) data) + size1;
+                memcpy(data2, data, size2);
+        } else {
+                memcpy(data1, data, size1);
+        }
+        PaUtil_AdvanceRingBufferWriteIndex(rbuf, numWritten);
+        return numWritten;
+}
+
+/***************************************************************************
+** Return bytes read. */
+long PaUtil_ReadRingBuffer(PaUtilRingBuffer * rbuf, void *data, long numBytes)
+{
+        long size1, size2, numRead;
+        void *data1, *data2;
+        numRead = PaUtil_GetRingBufferReadRegions(rbuf, numBytes, &data1, &size1, &data2, &size2);
+        if (size2 > 0) {
+                memcpy(data, data1, size1);
+                data = ((char *) data) + size1;
+                memcpy(data, data2, size2);
+        } else {
+                memcpy(data, data1, size1);
+        }
+        PaUtil_AdvanceRingBufferReadIndex(rbuf, numRead);
+        return numRead;
+}
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenpa_ringbufferh"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/pa_ringbuffer.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,192 @@
</span><ins>+#ifndef PA_RINGBUFFER_H
+#define PA_RINGBUFFER_H
+/*
+ * $Id: pa_ringbuffer.h 1151 2006-11-29 02:11:16Z leland_lucius $
+ * Portable Audio I/O Library
+ * Ring Buffer utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ * modified for SMP safety on OS X by Bjorn Roche.
+ * also allowed for const where possible.
+ * Note that this is safe only for a single-thread reader
+ * and a single-thread writer.
+ *
+ * This program is distributed with the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The text above constitutes the entire PortAudio license; however,
+ * the PortAudio community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the
+ * license above.
+ */
+
+/** @file
+ @ingroup common_src
+*/
+
+#ifdef __cplusplus
+extern "C" {
+#endif                                                        /* __cplusplus */
+
+        typedef struct PaUtilRingBuffer {
+                long bufferSize;                /* Number of bytes in FIFO. Power of 2. Set by PaUtil_InitRingBuffer. */
+                long writeIndex;                /* Index of next writable byte. Set by PaUtil_AdvanceRingBufferWriteIndex. */
+                long readIndex;                        /* Index of next readable byte. Set by PaUtil_AdvanceRingBufferReadIndex. */
+                long bigMask;                        /* Used for wrapping indices with extra bit to distinguish full/empty. */
+                long smallMask;                        /* Used for fitting indices to buffer. */
+                char *buffer;
+        } PaUtilRingBuffer;
+
+/** Initialize Ring Buffer.
+
+ @param rbuf The ring buffer.
+
+ @param numBytes The number of bytes in the buffer and must be power of 2.
+
+ @param dataPtr A pointer to a previously allocated area where the data
+ will be maintained. It must be numBytes long.
+
+ @return -1 if numBytes is not a power of 2, otherwise 0.
+*/
+        long PaUtil_InitializeRingBuffer(PaUtilRingBuffer * rbuf, long numBytes, void *dataPtr);
+
+/** Clear buffer. Should only be called when buffer is NOT being read.
+
+ @param rbuf The ring buffer.
+*/
+        void PaUtil_FlushRingBuffer(PaUtilRingBuffer * rbuf);
+
+/** Retrieve the number of bytes available in the ring buffer for writing.
+
+ @param rbuf The ring buffer.
+
+ @return The number of bytes available for writing.
+*/
+        long PaUtil_GetRingBufferWriteAvailable(PaUtilRingBuffer * rbuf);
+
+/** Retrieve the number of bytes available in the ring buffer for reading.
+
+ @param rbuf The ring buffer.
+
+ @return The number of bytes available for reading.
+*/
+        long PaUtil_GetRingBufferReadAvailable(PaUtilRingBuffer * rbuf);
+
+/** Write data to the ring buffer.
+
+ @param rbuf The ring buffer.
+
+ @param data The address of new data to write to the buffer.
+
+ @param numBytes The number of bytes to be written.
+
+ @return The number of bytes written.
+*/
+        long PaUtil_WriteRingBuffer(PaUtilRingBuffer * rbuf, const void *data, long numBytes);
+
+/** Read data from the ring buffer.
+
+ @param rbuf The ring buffer.
+
+ @param data The address where the data should be stored.
+
+ @param numBytes The number of bytes to be read.
+
+ @return The number of bytes read.
+*/
+        long PaUtil_ReadRingBuffer(PaUtilRingBuffer * rbuf, void *data, long numBytes);
+
+/** Get address of region(s) to which we can write data.
+
+ @param rbuf The ring buffer.
+
+ @param numBytes The number of bytes desired.
+
+ @param dataPtr1 The address where the first (or only) region pointer will be
+ stored.
+
+ @param sizePtr1 The address where the first (or only) region length will be
+ stored.
+
+ @param dataPtr2 The address where the second region pointer will be stored if
+ the first region is too small to satisfy numBytes.
+
+ @param sizePtr2 The address where the second region length will be stored if
+ the first region is too small to satisfy numBytes.
+
+ @return The room available to be written or numBytes, whichever is smaller.
+*/
+        long PaUtil_GetRingBufferWriteRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2);
+
+/** Advance the write index to the next location to be written.
+
+ @param rbuf The ring buffer.
+
+ @param numBytes The number of bytes to advance.
+
+ @return The new position.
+*/
+        long PaUtil_AdvanceRingBufferWriteIndex(PaUtilRingBuffer * rbuf, long numBytes);
+
+/** Get address of region(s) from which we can write data.
+
+ @param rbuf The ring buffer.
+
+ @param numBytes The number of bytes desired.
+
+ @param dataPtr1 The address where the first (or only) region pointer will be
+ stored.
+
+ @param sizePtr1 The address where the first (or only) region length will be
+ stored.
+
+ @param dataPtr2 The address where the second region pointer will be stored if
+ the first region is too small to satisfy numBytes.
+
+ @param sizePtr2 The address where the second region length will be stored if
+ the first region is too small to satisfy numBytes.
+
+ @return The number of bytes available for reading.
+*/
+        long PaUtil_GetRingBufferReadRegions(PaUtilRingBuffer * rbuf, long numBytes, void **dataPtr1, long *sizePtr1, void **dataPtr2, long *sizePtr2);
+
+/** Advance the read index to the next location to be read.
+
+ @param rbuf The ring buffer.
+
+ @param numBytes The number of bytes to advance.
+
+ @return The new position.
+*/
+        long PaUtil_AdvanceRingBufferReadIndex(PaUtilRingBuffer * rbuf, long numBytes);
+
+#ifdef __cplusplus
+}
+#endif                                                        /* __cplusplus */
+#endif                                                        /* PA_RINGBUFFER_H */
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenpablioc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/pablio.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/pablio.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/pablio.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,720 @@
</span><ins>+/*
+ * $Id: pablio.c 1151 2006-11-29 02:11:16Z leland_lucius $
+ * pablio.c
+ * Portable Audio Blocking Input/Output utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com
+ *
+ * This program uses the PortAudio Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The text above constitutes the entire PortAudio license; however,
+ * the PortAudio community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the
+ * license above.
+ */
+#define WANT_SPEEX
+#include <switch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "portaudio.h"
+#include "pa_ringbuffer.h"
+#include "pablio.h"
+#include <string.h>
+#include <time.h>
+#ifdef WANT_SPEEX
+#include "speex/speex_preprocess.h"
+#include "speex/speex_echo.h"
+ SpeexPreprocessState *preprocess;
+ SpeexPreprocessState *preprocess2;
+ SpeexEchoState *echo_state;
+
+         int speexecho=1;
+         int speexpreprocess=1;
+#endif// WANT_SPEEX
+
+/************************************************************************/
+/******** Prototypes ****************************************************/
+/************************************************************************/
+
+static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+
+static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                                unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+
+static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame);
+static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf);
+
+/************************************************************************/
+/******** Functions *****************************************************/
+/************************************************************************/
+
+/* Called from PortAudio.
+ * Read and write data
+ */
+static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
+{
+        PABLIO_Stream *data = (PABLIO_Stream *) userData;
+        long numBytes = data->bytesPerFrame * framesPerBuffer;
+#ifdef WANT_SPEEX
+ spx_int16_t *speexptr=NULL;
+ spx_int16_t pcm2[160];
+ int i;
+#endif// WANT_SPEEX
+
+        /* This may get called with NULL inputBuffer during initial setup. */
+        if (inputBuffer != NULL) {
+#ifdef WANT_SPEEX
+        //FIXME speex_echo_cancellation(echo_state, inputBuffer, outputBuffer, pcm2);
+        //FIXME speexptr=(spx_int16_t *)inputBuffer;
+ //FIXME for (i = 0; i < 160; i++)
+ //FIXME speexptr[i] = pcm2[i];
+ //FIXME speex_preprocess_run(preprocess, speexptr);
+#if 1
+ if (speexecho) {
+ speexptr = ((spx_int16_t *) inputBuffer);
+
+ /* Perform echo cancellation */
+ speex_echo_capture(echo_state, speexptr, pcm2);
+#ifndef GIOVA48
+ for (i = 0; i < 160; i++)
+#else //GIOVA48
+ for (i = 0; i < 960; i++)
+#endif //GIOVA48
+ speexptr[i] = pcm2[i];
+ //printf("read\n");
+ }
+ if (speexpreprocess) {
+ speex_preprocess_run(preprocess, speexptr);
+ }
+ /* Apply noise/echo residual suppression */
+#endif
+#endif //WANT_SPEEX
+
+
+                if (PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes) != numBytes) {
+                        PaUtil_FlushRingBuffer(&data->inFIFO);
+                        PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes);
+ printf("HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                }
+        }
+
+        return 0;
+}
+
+static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
+{
+        PABLIO_Stream *data = (PABLIO_Stream *) userData;
+        long numBytes = data->bytesPerFrame * framesPerBuffer;
+#ifdef WANT_SPEEX
+ spx_int16_t *speexptr=NULL;
+ //spx_int16_t pcm2[160];
+ //int i;
+#endif// WANT_SPEEX
+
+
+        if (outputBuffer != NULL) {
+                int i;
+                int numRead = PaUtil_ReadRingBuffer(&data->outFIFO, outputBuffer, numBytes);
+                /* Zero out remainder of buffer if we run out of data. */
+                for (i = numRead; i < numBytes; i++) {
+                        ((char *) outputBuffer)[i] = 0;
+                }
+
+                if(numRead == 0){
+                        //printf("ZERO\n");
+                        //usleep(60000);
+                //speex_echo_state_reset(echo_state);
+                }
+#ifdef WANT_SPEEX
+ //FIXME speexptr = (spx_int16_t *) outputBuffer;
+ //FIXME speex_preprocess_run(preprocess2, speexptr);
+#if 1
+ if (speexecho ) {
+ speexptr = (spx_int16_t *) outputBuffer;
+ if (speexpreprocess && numRead) {
+ //speex_preprocess_run(preprocess2, speexptr);
+ }
+
+
+
+ /* Put frame into playback buffer */
+ speex_echo_playback(echo_state, speexptr);
+ //printf("write\n");
+ }
+
+#endif
+#endif //WANT_SPEEX
+
+
+        }
+
+        return 0;
+}
+
+static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
+{
+
+
+//write
+        oblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
+//read
+        iblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
+
+        return 0;
+}
+
+/* Allocate buffer. */
+static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame)
+{
+        long numBytes = numFrames * bytesPerFrame;
+        char *buffer = (char *) malloc(numBytes);
+        if (buffer == NULL)
+                return paInsufficientMemory;
+        memset(buffer, 0, numBytes);
+        return (PaError) PaUtil_InitializeRingBuffer(rbuf, numBytes, buffer);
+}
+
+/* Free buffer. */
+static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf)
+{
+        if (rbuf->buffer)
+                free(rbuf->buffer);
+        rbuf->buffer = NULL;
+        return paNoError;
+}
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer)
+{
+        long bytesWritten;
+        char *p = (char *) data;
+        long numBytes = aStream->bytesPerFrame * numFrames;
+
+        switch_core_timer_next(timer);
+
+        bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFO, p, numBytes);
+        numBytes -= bytesWritten;
+        p += bytesWritten;
+        
+        if (numBytes > 0) {
+                PaUtil_FlushRingBuffer(&aStream->outFIFO);
+ printf("2HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                return 0;
+        }
+        return numFrames;
+}
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer)
+{
+        long bytesRead = 0;
+        char *p = (char *) data;
+        long avail, totalBytes = 0, neededBytes = aStream->bytesPerFrame * numFrames;
+        int max = 5000;
+
+        switch_core_timer_next(timer);
+
+        while(totalBytes < neededBytes && --max > 0) {
+
+                avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
+                //printf("AVAILABLE BYTES %ld , neededBytes %ld, pass %d\n", avail, neededBytes, 5000 - max);
+                if (avail >= neededBytes * 6) {
+                        PaUtil_FlushRingBuffer(&aStream->inFIFO);
+ printf("3HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                        avail = 0;
+                } else {
+
+                        bytesRead = 0;
+                        
+                        if (totalBytes < neededBytes && avail >= neededBytes) {
+                                bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFO, p, neededBytes);
+                                totalBytes += bytesRead;
+                        }
+
+                        if (bytesRead) {
+                                p += bytesRead;
+                        } else {
+                                switch_cond_next();
+                        }
+                }
+        }
+
+                //printf("return=%ld\n", totalBytes / aStream->bytesPerFrame);
+        return totalBytes / aStream->bytesPerFrame;
+}
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+long GetAudioStreamWriteable(PABLIO_Stream * aStream)
+{
+        int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+        return bytesEmpty / aStream->bytesPerFrame;
+}
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+long GetAudioStreamReadable(PABLIO_Stream * aStream)
+{
+        int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
+        return bytesFull / aStream->bytesPerFrame;
+}
+
+/***********************************************************/
+static unsigned long RoundUpToNextPowerOf2(unsigned long n)
+{
+        long numBits = 0;
+        if (((n - 1) & n) == 0)
+                return n;
+        while (n > 0) {
+                n = n >> 1;
+                numBits++;
+        }
+        return (1 << numBits);
+}
+
+
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ */
+PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
+                                                const PaStreamParameters * inputParameters,
+                                                const PaStreamParameters * outputParameters,
+                                                double sampleRate, PaStreamFlags streamFlags,
+                                                long samples_per_packet,
+                                                int do_dual)
+{
+        long bytesPerSample = 2;
+        PaError err;
+        PABLIO_Stream *aStream;
+        long numFrames;
+        //long numBytes;
+        int channels = 1;
+#ifdef WANT_SPEEX
+        int ciapa;
+        float level;
+        int tmp;
+#endif //WANT_SPEEX
+
+
+        if (!(inputParameters || outputParameters)) {
+                return -1;
+        }
+
+        /* Allocate PABLIO_Stream structure for caller. */
+        aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
+        switch_assert(aStream);
+        memset(aStream, 0, sizeof(PABLIO_Stream));
+        
+        if (inputParameters) {
+                channels = inputParameters->channelCount;
+        } else if (outputParameters) {
+                channels = outputParameters->channelCount;
+        }
+
+        numFrames = RoundUpToNextPowerOf2(samples_per_packet * 5);
+        aStream->bytesPerFrame = bytesPerSample;
+
+        /* Initialize Ring Buffers */
+
+        if (inputParameters) {
+                err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
+                if (err != paNoError) {
+                        goto error;
+                }
+                aStream-> has_in = 1;
+        }
+
+        if (outputParameters) {
+                err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
+                if (err != paNoError) {
+                        goto error;
+                }
+                aStream-> has_out = 1;
+        }
+#ifdef WANT_SPEEX
+ /* Echo canceller with 100 ms tail length */
+#ifndef GIOVA48
+ echo_state = speex_echo_state_init(160, 1600);
+ ciapa = 8000;
+#else// GIOVA48
+ echo_state = speex_echo_state_init(960, 4800);
+ ciapa = 48000;
+#endif // GIOVA48
+ speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &ciapa);
+
+#if 1 //NO MORE
+ /* Setup preprocessor and associate with echo canceller for residual echo suppression */
+#ifndef GIOVA48
+ preprocess = speex_preprocess_state_init(160, 8000);
+#else// GIOVA48
+ preprocess = speex_preprocess_state_init(960, 48000);
+#endif // GIOVA48
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
+ echo_state);
+
+#if 0
+ /* Setup preprocessor various other goodies */
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC, &tmp);
+ level=8000.1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_LEVEL, &level);
+
+ tmp = 8000;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_TARGET, &tmp);
+
+ //FIXME tmp = 60;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ //FIXME tmp = 40;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ //FIXME tmp = -40;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
+ // Let's turn off all of the 'denoisers' (eg denoise and dereverb, and vad too) because they start automatic gain on mic input on cm108 usb, also if it (the agc on usb) disbled through mixer
+ tmp = 0;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_VAD, &tmp);
+#endif
+
+ //tmp = 0;
+ //speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 1;
+#endif //0
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC, &tmp);
+ fprintf(stderr, "AGC is: %d\n", tmp);
+ level = 1.0;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
+ fprintf(stderr, "AGC_LEVEL is: %f\n", level);
+ //tmp=1;
+ //speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
+ //fprintf( stderr, "AGC_TARGET is: %d\n", tmp );
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
+ fprintf(stderr, "DENOISE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
+ fprintf(stderr, "DEREVERB is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_VAD, &tmp);
+ fprintf(stderr, "VAD is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_NOISE_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
+ &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_START is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_CONTINUE is: %d\n", tmp);
+#endif //0
+#endif// 0 //NO MORE
+
+
+
+
+
+
+
+
+
+#if 1 //NO MORE
+ /* Setup preprocessor and associate with echo canceller for residual echo suppression */
+#ifndef GIOVA48
+ preprocess2 = speex_preprocess_state_init(160, 8000);
+#else// GIOVA48
+ preprocess = speex_preprocess_state_init(960, 48000);
+#endif // GIOVA48
+
+ /* Setup preprocessor various other goodies */
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC, &tmp);
+
+ tmp = 24000;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_TARGET, &tmp);
+
+ //tmp = 60;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &tmp);
+ tmp = 40;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &tmp);
+ tmp = -40;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &tmp);
+
+#if 0
+ // Let's turn off all of the 'denoisers' (eg denoise and dereverb, and vad too) because they start automatic gain on mic input on cm108 usb, also if it (the agc on usb) disbled through mixer
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_VAD, &tmp);
+#endif
+
+ //tmp = 0;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC, &tmp);
+ fprintf(stderr, "AGC is: %d\n", tmp);
+ level = 1.0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
+ fprintf(stderr, "AGC_LEVEL is: %f\n", level);
+ //tmp=1;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
+ //fprintf( stderr, "AGC_TARGET is: %d\n", tmp );
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
+ fprintf(stderr, "DENOISE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
+ fprintf(stderr, "DEREVERB is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_VAD, &tmp);
+ fprintf(stderr, "VAD is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_NOISE_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
+ &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_START is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_CONTINUE is: %d\n", tmp);
+#endif //0
+#endif// 0 //NO MORE
+
+
+
+
+#endif // WANT_SPEEX
+
+
+        /* Open a PortAudio stream that we will use to communicate with the underlying
+         * audio drivers. */
+
+        aStream->do_dual = do_dual;        
+
+        if (aStream->do_dual) {
+                err = Pa_OpenStream(&aStream->istream, inputParameters, NULL, sampleRate, samples_per_packet, streamFlags, iblockingIOCallback, aStream);
+                if (err != paNoError) {
+                        goto error;
+                }
+                err = Pa_OpenStream(&aStream->ostream, NULL, outputParameters, sampleRate, samples_per_packet, streamFlags, oblockingIOCallback, aStream);
+                if (err != paNoError) {
+                        goto error;
+                }
+        } else {
+                err = Pa_OpenStream(&aStream->iostream, inputParameters, outputParameters, sampleRate, samples_per_packet, streamFlags, ioblockingIOCallback, aStream);
+        }
+
+        if (err != paNoError) {
+                goto error;
+        }
+        
+        if (aStream->do_dual) {
+                err = Pa_StartStream(aStream->istream);
+                
+                if (err != paNoError) {
+                        goto error;
+                }
+
+                err = Pa_StartStream(aStream->ostream);
+
+                if (err != paNoError) {
+                        goto error;
+                }
+
+        } else {
+                err = Pa_StartStream(aStream->iostream);
+        }
+
+        if (err != paNoError) {
+                goto error;
+        }
+
+        *rwblPtr = aStream;
+
+        //switch_yield(500000);
+        
+        return paNoError;
+
+ error:
+
+        CloseAudioStream(aStream);
+
+        *rwblPtr = NULL;
+        return err;
+}
+
+/************************************************************/
+PaError CloseAudioStream(PABLIO_Stream * aStream)
+{
+        int bytesEmpty;
+        int byteSize;
+
+        
+        byteSize = aStream->outFIFO.bufferSize;
+
+        if (aStream->has_out) {
+                /* If we are writing data, make sure we play everything written. */
+                if (byteSize > 0) {
+                        bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+                        while (bytesEmpty < byteSize) {
+                                Pa_Sleep(10);
+                                bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+                        }
+                }
+        }
+
+        if (aStream->do_dual) {
+                if (aStream->has_in && aStream->istream) {
+                        if (Pa_IsStreamActive(aStream->istream)) {
+                                Pa_StopStream(aStream->istream);
+                        }
+
+                        Pa_CloseStream(aStream->istream);
+                        aStream->istream = NULL;
+                }
+                
+                if (aStream->has_out && aStream->ostream) {
+                        if (Pa_IsStreamActive(aStream->ostream)) {
+                                Pa_StopStream(aStream->ostream);
+                        }
+
+                        Pa_CloseStream(aStream->ostream);
+                        aStream->ostream = NULL;
+                }
+                
+        } else {
+                if (aStream->iostream) {
+                        if (Pa_IsStreamActive(aStream->iostream)) {
+                                Pa_StopStream(aStream->iostream);
+                        }
+
+                        Pa_CloseStream(aStream->iostream);
+                        aStream->iostream = NULL;
+                }
+        }
+
+        if (aStream->has_in) {        
+                PABLIO_TermFIFO(&aStream->inFIFO);
+        }
+        
+        if (aStream->has_out) {
+                PABLIO_TermFIFO(&aStream->outFIFO);
+        }
+
+        free(aStream);
+        //switch_yield(500000);
+
+        return paNoError;
+}
+
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenpablioh"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/pablio.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/pablio.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/pablio.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,120 @@
</span><ins>+#ifndef _PABLIO_H
+#define _PABLIO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif                                                        /* __cplusplus */
+
+/*
+ * $Id: pablio.h 1083 2006-08-23 07:30:49Z rossb $
+ * PABLIO.h
+ * Portable Audio Blocking read/write utility.
+ *
+ * Author: Phil Burk, http://www.softsynth.com/portaudio/
+ *
+ * Include file for PABLIO, the Portable Audio Blocking I/O Library.
+ * PABLIO is built on top of PortAudio, the Portable Audio Library.
+ * For more information see: http://www.portaudio.com
+ * Copyright (c) 1999-2000 Ross Bencina and Phil Burk
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
+ * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
+ * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * The text above constitutes the entire PortAudio license; however,
+ * the PortAudio community also makes the following non-binding requests:
+ *
+ * Any person wishing to distribute modifications to the Software is
+ * requested to send the modifications to the original developer so that
+ * they can be incorporated into the canonical version. It is also
+ * requested that these non-binding requests be included along with the
+ * license above.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include "pa_ringbuffer.h"
+#include "portaudio.h"
+
+#include <string.h>
+
+        typedef struct {
+                PaUtilRingBuffer inFIFO;
+                PaUtilRingBuffer outFIFO;
+                PaStream *istream;
+                PaStream *ostream;
+                PaStream *iostream;
+                int bytesPerFrame;
+                int do_dual;
+                int has_in;
+                int has_out;
+        } PABLIO_Stream;
+
+/* Values for flags for OpenAudioStream(). */
+#define PABLIO_READ (1<<0)
+#define PABLIO_WRITE (1<<1)
+#define PABLIO_READ_WRITE (PABLIO_READ|PABLIO_WRITE)
+#define PABLIO_MONO (1<<2)
+#define PABLIO_STEREO (1<<3)
+
+/************************************************************
+ * Write data to ring buffer.
+ * Will not return until all the data has been written.
+ */
+        long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
+
+/************************************************************
+ * Read data from ring buffer.
+ * Will not return until all the data has been read.
+ */
+        long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
+
+/************************************************************
+ * Return the number of frames that could be written to the stream without
+ * having to wait.
+ */
+        long GetAudioStreamWriteable(PABLIO_Stream * aStream);
+
+/************************************************************
+ * Return the number of frames that are available to be read from the
+ * stream without having to wait.
+ */
+        long GetAudioStreamReadable(PABLIO_Stream * aStream);
+
+/************************************************************
+ * Opens a PortAudio stream with default characteristics.
+ * Allocates PABLIO_Stream structure.
+ *
+ * flags parameter can be an ORed combination of:
+ * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
+ * and either PABLIO_MONO or PABLIO_STEREO
+ */
+        PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
+                                                        const PaStreamParameters * inputParameters,
+                                                        const PaStreamParameters * outputParameters,
+                                                        double sampleRate, PaStreamCallbackFlags statusFlags, long samples_per_packet, int do_dual);
+
+        PaError CloseAudioStream(PABLIO_Stream * aStream);
+
+#ifdef __cplusplus
+}
+#endif                                                        /* __cplusplus */
+#endif                                                        /* _PABLIO_H */
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_devlistc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_devlist.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_devlist.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_devlist.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,54 @@
</span><ins>+/*
+ * gcc -Wall portaudio_devlist.c -o portaudio_devlist -lportaudio
+ */
+#include <stdio.h>
+#include <string.h>
+#include <portaudio.h>
+
+int main(int argc, char **argv)
+{
+        int i, c, numDevices;
+        const PaDeviceInfo *deviceInfo;
+        PaError err;
+        char name[256];
+
+        err = Pa_Initialize();
+        if (err != paNoError)
+                return err;
+
+
+        numDevices = Pa_GetDeviceCount();
+        if (numDevices < 0) {
+                return 0;
+        }
+        if(argc==1){
+                printf("usage: %s [input | output]\n", argv[0]);
+                return 1;
+        }
+        for (i = 0; i < numDevices; i++) {
+                deviceInfo = Pa_GetDeviceInfo(i);
+                memset(name, '\0', sizeof(name));
+                for(c=0; c<strlen( deviceInfo->name); c++){
+                        if( deviceInfo->name[c] == ' ')
+                                name[c]='_';
+                        else
+                                name[c]= deviceInfo->name[c];
+                }
+                if( !strcmp(argv[1], "input")&& deviceInfo->maxInputChannels)
+                {
+                        printf("%d \"%s\" \n",
+                                        i,
+                                        name);
+                }
+                else if( !strcmp(argv[1], "output")&& deviceInfo->maxOutputChannels)
+                {
+                        printf("%d \"%s\" \n",
+                                        i,
+                                        name);
+                }
+        }
+
+        return numDevices;
+}
+
+
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenMakefile"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/Makefile (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/Makefile        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/Makefile        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -2,5 +2,5 @@
</span><span class="cx"> SVNDEF := -D'GSMOPEN_SVN_VERSION="$(shell svnversion -n .)"'
</span><span class="cx"> LOCAL_CFLAGS += $(SVNDEF) -DNO_ALSA -DGSMOPEN_PORTAUDIO
</span><span class="cx"> LOCAL_LDFLAGS=-lportaudio -lspeex -lspeexdsp -lgsmme
</span><del>-LOCAL_OBJS=gsmopen_protocol.o pablio.o pa_ringbuffer.o
</del><ins>+LOCAL_OBJS=gsmopen_protocol.o pablio.o pa_ringbuffer.o celliax_spandsp.o
</ins><span class="cx"> include ../../../../../../build/modmake.rules
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopencelliax_spandspc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,1059 @@
</span><ins>+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.c - An echo cancellor, suitable for electrical and acoustic
+ * cancellation. This code does not currently comply with
+ * any relevant standards (e.g. G.164/5/7/8). One day....
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001, 2003 Steve Underwood
+ *
+ * Based on a bit from here, a bit from there, eye of toad,
+ * ear of bat, etc - plus, of course, my own 2 cents.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: echo.c,v 1.20 2006/12/01 18:00:48 steveu Exp $
+ */
+
+/*! \file */
+
+/* TODO:
+ Finish the echo suppressor option, however nasty suppression may be.
+ Add an option to reintroduce side tone at -24dB under appropriate conditions.
+ Improve double talk detector (iterative!)
+*/
+
+/* We need to differentiate between transmitted energy which will train the echo
+ canceller well (voice, white noise, and other broadband sources) and energy
+ which will train it badly (supervisory tones, DTMF, whistles, and other
+ narrowband sources). There are many ways this might be done. This canceller uses
+ a method based on the autocorrelation qualities of the transmitted signal. A rather
+ peaky autocorrelation function is a clear sign of a narrowband signal. We only need
+ perform the autocorrelation at well spaced intervals, so the compute load is not too
+ great. Multiple successive autocorrelation functions with a similar peaky shape are a
+ clear indication of a stationary narrowband signal. Using TKEO, it should be possible to
+ greatly reduce the compute requirement for narrowband detection. */
+
+/* The FIR taps must be adapted as 32 bit values, to get the necessary finesse
+ in the adaption process. However, they are applied as 16 bit values (bits 30-15
+ of the 32 bit values) in the FIR. For the working 16 bit values, we need 4 sets.
+
+ 3 of the 16 bit sets are used on a rotating basis. Normally the canceller steps
+ round these 3 sets at regular intervals. Any time we detect double talk, we can go
+ back to the set from two steps ago with reasonable assurance it is a well adapted
+ set. We cannot just go back one step, as we may have rotated the sets just before
+ double talk or tone was detected, and that set may already be somewhat corrupted.
+
+ When narrowband energy is detected we need to continue adapting to it, to echo
+ cancel it. However, the adaption will almost certainly be going astray. Broadband
+ (or even complex sequences of narrowband) energy will normally lead to a well
+ trained cancellor, with taps matching the impulse response of the channel.
+ For stationary narrowband energy, there is usually has an infinite number of
+ alternative tap sets which will cancel it well. A previously well trained set of
+ taps will tend to drift amongst the alternatives. When broadband energy resumes, the
+ taps may be a total mismatch for the signal, and could even amplify rather than
+ attenuate the echo. The solution is to use a fourth set of 16 bit taps. When we first
+ detect the narrowband energy we save the oldest of the group of three sets, but do
+ not change back to an older set. We let the canceller cancel, and it adaption drift
+ while the narrowband energy is present. When we detect the narrowband energy has ceased,
+ we switch to using the fourth set of taps which was saved.
+
+ When we revert to an older set of taps, we must replace both the 16 bit and 32 bit
+ working tap sets. The saved 16 bit values are good enough to also be used as a replacement
+ for the 32 bit values. We loose the fractions, but they should soon settle down in a
+ reasonable way. */
+
+#ifdef HAVE_CONFIG_H
+//#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <inttypes.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "celliax_spandsp.h"
+
+//#include "spandsp/telephony.h"
+//#include "spandsp/logging.h"
+//#include "spandsp/bit_operations.h"
+//#include "spandsp/echo.h"
+
+//#include "bit_operations.h"
+//#include "giova.h"
+
+#if !defined(NULL)
+#define NULL (void *) 0
+#endif
+#if !defined(FALSE)
+#define FALSE 0
+#endif
+#if !defined(TRUE)
+#define TRUE (!FALSE)
+#endif
+
+#if 0
+#define MIN_TX_POWER_FOR_ADAPTION 64*64
+#define MIN_RX_POWER_FOR_ADAPTION 64*64
+
+static int narrowband_detect(echo_can_state_t * ec)
+{
+ int k;
+ int i;
+ float temp;
+ float scale;
+ float sf[128];
+ float f_acf[128];
+ int32_t acf[28];
+ int score;
+ int len = 32;
+ int alen = 9;
+
+ k = ec->curr_pos;
+ for (i = 0; i < len; i++) {
+ sf[i] = ec->fir_state.history[k++];
+ if (k >= 256)
+ k = 0;
+ }
+ for (k = 0; k < alen; k++) {
+ temp = 0;
+ for (i = k; i < len; i++)
+ temp += sf[i] * sf[i - k];
+ f_acf[k] = temp;
+ }
+ scale = 0x1FFFFFFF / f_acf[0];
+ for (k = 0; k < alen; k++)
+ acf[k] = (int32_t) (f_acf[k] * scale);
+ score = 0;
+ for (i = 0; i < 9; i++) {
+ if (ec->last_acf[i] >= 0 && acf[i] >= 0) {
+ if ((ec->last_acf[i] >> 1) < acf[i] && acf[i] < (ec->last_acf[i] << 1))
+ score++;
+ } else if (ec->last_acf[i] < 0 && acf[i] < 0) {
+ if ((ec->last_acf[i] >> 1) > acf[i] && acf[i] > (ec->last_acf[i] << 1))
+ score++;
+ }
+ }
+ memcpy(ec->last_acf, acf, alen * sizeof(ec->last_acf[0]));
+ return score;
+}
+
+static __inline__ void lms_adapt(echo_can_state_t * ec, int factor)
+{
+ int i;
+
+#if 0
+ mmx_t *mmx_taps;
+ mmx_t *mmx_coeffs;
+ mmx_t *mmx_hist;
+ mmx_t mmx;
+
+ mmx.w[0] = mmx.w[1] = mmx.w[2] = mmx.w[3] = factor;
+ mmx_hist = (mmx_t *) & fir->history[fir->curr_pos];
+ mmx_taps = (mmx_t *) & fir->taps;
+ mmx_coeffs = (mmx_t *) fir->coeffs;
+ i = fir->taps;
+ movq_m2r(mmx, mm0);
+ while (i > 0) {
+ movq_m2r(mmx_hist[0], mm1);
+ movq_m2r(mmx_taps[0], mm0);
+ movq_m2r(mmx_taps[1], mm1);
+ movq_r2r(mm1, mm2);
+ pmulhw(mm0, mm1);
+ pmullw(mm0, mm2);
+
+ pmaddwd_r2r(mm1, mm0);
+ pmaddwd_r2r(mm3, mm2);
+ paddd_r2r(mm0, mm4);
+ paddd_r2r(mm2, mm4);
+ movq_r2m(mm0, mmx_taps[0]);
+ movq_r2m(mm1, mmx_taps[0]);
+ movq_r2m(mm2, mmx_coeffs[0]);
+ mmx_taps += 2;
+ mmx_coeffs += 1;
+ mmx_hist += 1;
+ i -= 4;
+ )
+ emms();
+#elif 0
+ /* Update the FIR taps */
+ for (i = ec->taps - 1; i >= 0; i--) {
+ /* Leak to avoid the coefficients drifting beyond the ability of the
+ adaption process to bring them back under control. */
+ ec->fir_taps32[i] -= (ec->fir_taps32[i] >> 23);
+ ec->fir_taps32[i] += (ec->fir_state.history[i + ec->curr_pos] * factor);
+ ec->latest_correction = (ec->fir_state.history[i + ec->curr_pos] * factor);
+ ec->fir_taps16[ec->tap_set][i] = ec->fir_taps32[i] >> 15;
+ }
+#else
+ int offset1;
+ int offset2;
+
+ /* Update the FIR taps */
+ offset2 = ec->curr_pos;
+ offset1 = ec->taps - offset2;
+ for (i = ec->taps - 1; i >= offset1; i--) {
+ ec->fir_taps32[i] += (ec->fir_state.history[i - offset1] * factor);
+ ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15);
+ }
+ for (; i >= 0; i--) {
+ ec->fir_taps32[i] += (ec->fir_state.history[i + offset2] * factor);
+ ec->fir_taps16[ec->tap_set][i] = (int16_t) (ec->fir_taps32[i] >> 15);
+ }
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+#ifdef NOT_NEEDED
+echo_can_state_t *echo_can_create(int len, int adaption_mode)
+{
+ echo_can_state_t *ec;
+ int i;
+ int j;
+
+ ec = (echo_can_state_t *) malloc(sizeof(*ec));
+ if (ec == NULL)
+ return NULL;
+ memset(ec, 0, sizeof(*ec));
+ ec->taps = len;
+ ec->curr_pos = ec->taps - 1;
+ ec->tap_mask = ec->taps - 1;
+ if ((ec->fir_taps32 = (int32_t *) malloc(ec->taps * sizeof(int32_t))) == NULL) {
+ free(ec);
+ return NULL;
+ }
+ memset(ec->fir_taps32, 0, ec->taps * sizeof(int32_t));
+ for (i = 0; i < 4; i++) {
+ if ((ec->fir_taps16[i] = (int16_t *) malloc(ec->taps * sizeof(int16_t))) == NULL) {
+ for (j = 0; j < i; j++)
+ free(ec->fir_taps16[j]);
+ free(ec->fir_taps32);
+ free(ec);
+ return NULL;
+ }
+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
+ }
+ fir16_create(&ec->fir_state, ec->fir_taps16[0], ec->taps);
+ ec->rx_power_threshold = 10000000;
+ ec->geigel_max = 0;
+ ec->geigel_lag = 0;
+ ec->dtd_onset = FALSE;
+ ec->tap_set = 0;
+ ec->tap_rotate_counter = 1600;
+ ec->cng_level = 1000;
+ echo_can_adaption_mode(ec, adaption_mode);
+ return ec;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_free(echo_can_state_t * ec)
+{
+ int i;
+
+ fir16_free(&ec->fir_state);
+ free(ec->fir_taps32);
+ for (i = 0; i < 4; i++)
+ free(ec->fir_taps16[i]);
+ free(ec);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_adaption_mode(echo_can_state_t * ec, int adaption_mode)
+{
+ ec->adaption_mode = adaption_mode;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void echo_can_flush(echo_can_state_t * ec)
+{
+ int i;
+
+ for (i = 0; i < 4; i++)
+ ec->tx_power[i] = 0;
+ for (i = 0; i < 3; i++)
+ ec->rx_power[i] = 0;
+ ec->clean_rx_power = 0;
+ ec->nonupdate_dwell = 0;
+
+ fir16_flush(&ec->fir_state);
+ ec->fir_state.curr_pos = ec->taps - 1;
+ memset(ec->fir_taps32, 0, ec->taps * sizeof(int32_t));
+ for (i = 0; i < 4; i++)
+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
+
+ ec->curr_pos = ec->taps - 1;
+
+ ec->supp_test1 = 0;
+ ec->supp_test2 = 0;
+ ec->supp1 = 0;
+ ec->supp2 = 0;
+ ec->vad = 0;
+ ec->cng_level = 1000;
+ ec->cng_filter = 0;
+
+ ec->geigel_max = 0;
+ ec->geigel_lag = 0;
+ ec->dtd_onset = FALSE;
+ ec->tap_set = 0;
+ ec->tap_rotate_counter = 1600;
+
+ ec->latest_correction = 0;
+
+ memset(ec->last_acf, 0, sizeof(ec->last_acf));
+ ec->narrowband_count = 0;
+ ec->narrowband_score = 0;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+int sample_no = 0;
+
+int16_t echo_can_update(echo_can_state_t * ec, int16_t tx, int16_t rx)
+{
+ int32_t echo_value;
+ int clean_rx;
+ int nsuppr;
+ int score;
+ int i;
+
+ sample_no++;
+ ec->latest_correction = 0;
+ /* Evaluate the echo - i.e. apply the FIR filter */
+ /* Assume the gain of the FIR does not exceed unity. Exceeding unity
+ would seem like a rather poor thing for an echo cancellor to do :)
+ This means we can compute the result with a total disregard for
+ overflows. 16bits x 16bits -> 31bits, so no overflow can occur in
+ any multiply. While accumulating we may overflow and underflow the
+ 32 bit scale often. However, if the gain does not exceed unity,
+ everything should work itself out, and the final result will be
+ OK, without any saturation logic. */
+ /* Overflow is very much possible here, and we do nothing about it because
+ of the compute costs */
+ /* 16 bit coeffs for the LMS give lousy results (maths good, actual sound
+ bad!), but 32 bit coeffs require some shifting. On balance 32 bit seems
+ best */
+ echo_value = fir16(&ec->fir_state, tx);
+
+ /* And the answer is..... */
+ clean_rx = rx - echo_value;
+//printf("echo is %" PRId32 "\n", echo_value);
+ /* That was the easy part. Now we need to adapt! */
+ if (ec->nonupdate_dwell > 0)
+ ec->nonupdate_dwell--;
+
+ /* Calculate short term power levels using very simple single pole IIRs */
+ /* TODO: Is the nasty modulus approach the fastest, or would a real
+ tx*tx power calculation actually be faster? Using the squares
+ makes the numbers grow a lot! */
+ ec->tx_power[3] += ((abs(tx) - ec->tx_power[3]) >> 5);
+ ec->tx_power[2] += ((tx * tx - ec->tx_power[2]) >> 8);
+ ec->tx_power[1] += ((tx * tx - ec->tx_power[1]) >> 5);
+ ec->tx_power[0] += ((tx * tx - ec->tx_power[0]) >> 3);
+ ec->rx_power[1] += ((rx * rx - ec->rx_power[1]) >> 6);
+ ec->rx_power[0] += ((rx * rx - ec->rx_power[0]) >> 3);
+ ec->clean_rx_power += ((clean_rx * clean_rx - ec->clean_rx_power) >> 6);
+
+ score = 0;
+ /* If there is very little being transmitted, any attempt to train is
+ futile. We would either be training on the far end's noise or signal,
+ the channel's own noise, or our noise. Either way, this is hardly good
+ training, so don't do it (avoid trouble). */
+ if (ec->tx_power[0] > MIN_TX_POWER_FOR_ADAPTION) {
+ /* If the received power is very low, either we are sending very little or
+ we are already well adapted. There is little point in trying to improve
+ the adaption under these circumstances, so don't do it (reduce the
+ compute load). */
+ if (ec->tx_power[1] > ec->rx_power[0]) {
+ /* There is no (or little) far-end speech. */
+ if (ec->nonupdate_dwell == 0) {
+ if (++ec->narrowband_count >= 160) {
+ ec->narrowband_count = 0;
+ score = narrowband_detect(ec);
+//printf("Do the narrowband test %d at %d\n", score, ec->curr_pos);
+ if (score > 6) {
+ if (ec->narrowband_score == 0)
+ memcpy(ec->fir_taps16[3], ec->fir_taps16[(ec->tap_set + 1) % 3],
+ ec->taps * sizeof(int16_t));
+ ec->narrowband_score += score;
+ } else {
+ if (ec->narrowband_score > 200) {
+//printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no);
+ memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[3],
+ ec->taps * sizeof(int16_t));
+ memcpy(ec->fir_taps16[(ec->tap_set - 1) % 3], ec->fir_taps16[3],
+ ec->taps * sizeof(int16_t));
+ for (i = 0; i < ec->taps; i++)
+ ec->fir_taps32[i] = ec->fir_taps16[3][i] << 15;
+ ec->tap_rotate_counter = 1600;
+ }
+ ec->narrowband_score = 0;
+ }
+ }
+ ec->dtd_onset = FALSE;
+ if (--ec->tap_rotate_counter <= 0) {
+//printf("Rotate to %d at %d\n", ec->tap_set, sample_no);
+ ec->tap_rotate_counter = 1600;
+ ec->tap_set++;
+ if (ec->tap_set > 2)
+ ec->tap_set = 0;
+ ec->fir_state.coeffs = ec->fir_taps16[ec->tap_set];
+ }
+ /* ... and we are not in the dwell time from previous speech. */
+ if ((ec->adaption_mode & ECHO_CAN_USE_ADAPTION) && ec->narrowband_score == 0) {
+ //nsuppr = saturate((clean_rx << 16)/ec->tx_power[1]);
+ //nsuppr = clean_rx/ec->tx_power[1];
+ /* If a sudden surge in signal level (e.g. the onset of a tone
+ burst) cause an abnormally high instantaneous to average
+ signal power ratio, we could kick the adaption badly in the
+ wrong direction. This is because the tx_power takes too long
+ to react and rise. We need to stop too rapid adaption to the
+ new signal. We normalise to a value derived from the
+ instantaneous signal if it exceeds the peak by too much. */
+ nsuppr = clean_rx;
+ /* Divide isn't very quick, but the "where is the top bit" and shift
+ instructions are single cycle. */
+ if (tx > 4 * ec->tx_power[3])
+ i = top_bit(tx) - 8;
+ else
+ i = top_bit(ec->tx_power[3]) - 8;
+ if (i > 0)
+ nsuppr >>= i;
+ lms_adapt(ec, nsuppr);
+ }
+ }
+ //printf("%10d %10d %10d %10d %10d\n", rx, clean_rx, nsuppr, ec->tx_power[1], ec->rx_power[1]);
+ //printf("%.4f\n", (float) ec->rx_power[1]/(float) ec->clean_rx_power);
+ } else {
+ if (!ec->dtd_onset) {
+//printf("Revert to %d at %d\n", (ec->tap_set + 1)%3, sample_no);
+ memcpy(ec->fir_taps16[ec->tap_set], ec->fir_taps16[(ec->tap_set + 1) % 3],
+ ec->taps * sizeof(int16_t));
+ memcpy(ec->fir_taps16[(ec->tap_set - 1) % 3],
+ ec->fir_taps16[(ec->tap_set + 1) % 3], ec->taps * sizeof(int16_t));
+ for (i = 0; i < ec->taps; i++)
+ ec->fir_taps32[i] = ec->fir_taps16[(ec->tap_set + 1) % 3][i] << 15;
+ ec->tap_rotate_counter = 1600;
+ ec->dtd_onset = TRUE;
+ }
+ ec->nonupdate_dwell = NONUPDATE_DWELL_TIME;
+ }
+ }
+
+ if (ec->rx_power[1])
+ ec->vad = (8000 * ec->clean_rx_power) / ec->rx_power[1];
+ else
+ ec->vad = 0;
+ if (ec->rx_power[1] > 2048 * 2048 && ec->clean_rx_power > 4 * ec->rx_power[1]) {
+ /* The EC seems to be making things worse, instead of better. Zap it! */
+ memset(ec->fir_taps32, 0, ec->taps * sizeof(int32_t));
+ for (i = 0; i < 4; i++)
+ memset(ec->fir_taps16[i], 0, ec->taps * sizeof(int16_t));
+ }
+#if defined(XYZZY)
+ if ((ec->adaption_mode & ECHO_CAN_USE_SUPPRESSOR)) {
+ ec->supp_test1 +=
+ (ec->fir_state.history[ec->curr_pos] -
+ ec->fir_state.history[(ec->curr_pos - 7) & ec->tap_mask]);
+ ec->supp_test2 +=
+ (ec->fir_state.history[(ec->curr_pos - 24) & ec->tap_mask] -
+ ec->fir_state.history[(ec->curr_pos - 31) & ec->tap_mask]);
+ if (ec->supp_test1 > 42 && ec->supp_test2 > 42)
+ supp_change = 25;
+ else
+ supp_change = 50;
+ supp = supp_change + k1 * ec->supp1 + k2 * ec->supp2;
+ ec->supp2 = ec->supp1;
+ ec->supp1 = supp;
+ clean_rx *= (1 - supp);
+ }
+#endif
+
+ if ((ec->adaption_mode & ECHO_CAN_USE_NLP)) {
+ /* Non-linear processor - a fancy way to say "zap small signals, to avoid
+ residual echo due to (uLaw/ALaw) non-linearity in the channel.". */
+ if (ec->rx_power[1] < 30000000) {
+ if (!ec->cng) {
+ ec->cng_level = ec->clean_rx_power;
+ ec->cng = TRUE;
+ }
+ if ((ec->adaption_mode & ECHO_CAN_USE_CNG)) {
+ /* Very elementary comfort noise generation */
+ /* Just random numbers rolled off very vaguely Hoth-like */
+ ec->cng_rndnum = 1664525U * ec->cng_rndnum + 1013904223U;
+ ec->cng_filter = ((ec->cng_rndnum & 0xFFFF) - 32768 + 5 * ec->cng_filter) >> 3;
+ clean_rx = (ec->cng_filter * ec->cng_level) >> 17;
+ /* TODO: A better CNG, with more accurate (tracking) spectral shaping! */
+ } else {
+ clean_rx = 0;
+ }
+//clean_rx = -16000;
+ } else {
+ ec->cng = FALSE;
+ }
+ } else {
+ ec->cng = FALSE;
+ }
+
+//printf("Narrowband score %4d %5d at %d\n", ec->narrowband_score, score, sample_no);
+ /* Roll around the rolling buffer */
+ if (ec->curr_pos <= 0)
+ ec->curr_pos = ec->taps;
+ ec->curr_pos--;
+ return (int16_t) clean_rx;
+}
+
+#endif //NOT_NEEDED
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+#endif
+
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <time.h>
+#include <fcntl.h>
+#include <math.h>
+
+//#include "spandsp/telephony.h"
+//#include "spandsp/tone_detect.h"
+//#include "spandsp/tone_generate.h"
+//#include "spandsp/super_tone_rx.h"
+//#include "giova.h"
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+
+//#define USE_3DNOW
+
+#define DEFAULT_DTMF_TX_LEVEL -10
+#define DEFAULT_DTMF_TX_ON_TIME 50
+#define DEFAULT_DTMF_TX_OFF_TIME 55
+
+#define DTMF_THRESHOLD 8.0e7f
+#define DTMF_NORMAL_TWIST 6.3f /* 8dB */
+#define DTMF_REVERSE_TWIST 2.5f /* 4dB */
+#define DTMF_RELATIVE_PEAK_ROW 6.3f /* 8dB */
+#define DTMF_RELATIVE_PEAK_COL 6.3f /* 8dB */
+#define DTMF_TO_TOTAL_ENERGY 42.0f
+
+static const float dtmf_row[] = {
+ 697.0f, 770.0f, 852.0f, 941.0f
+};
+static const float dtmf_col[] = {
+ 1209.0f, 1336.0f, 1477.0f, 1633.0f
+};
+
+static const char dtmf_positions[] = "123A" "456B" "789C" "*0#D";
+
+static goertzel_descriptor_t dtmf_detect_row[4];
+static goertzel_descriptor_t dtmf_detect_col[4];
+
+//
+//static int dtmf_tx_inited = 0;
+//static tone_gen_descriptor_t dtmf_digit_tones[16];
+
+#if defined(USE_3DNOW)
+static __inline__ void _dtmf_goertzel_update(goertzel_state_t * s, float x[], int samples)
+{
+ int n;
+ float v;
+ int i;
+ float vv[16];
+
+ vv[4] = s[0].v2;
+ vv[5] = s[1].v2;
+ vv[6] = s[2].v2;
+ vv[7] = s[3].v2;
+ vv[8] = s[0].v3;
+ vv[9] = s[1].v3;
+ vv[10] = s[2].v3;
+ vv[11] = s[3].v3;
+ vv[12] = s[0].fac;
+ vv[13] = s[1].fac;
+ vv[14] = s[2].fac;
+ vv[15] = s[3].fac;
+
+ //v1 = s->v2;
+ //s->v2 = s->v3;
+ //s->v3 = s->fac*s->v2 - v1 + x[0];
+
+ __asm__ __volatile__(" femms;\n" " movq 16(%%edx),%%mm2;\n"
+ " movq 24(%%edx),%%mm3;\n" " movq 32(%%edx),%%mm4;\n"
+ " movq 40(%%edx),%%mm5;\n" " movq 48(%%edx),%%mm6;\n"
+ " movq 56(%%edx),%%mm7;\n" " jmp 1f;\n"
+ " .align 32;\n" " 1: ;\n" " prefetch (%%eax);\n"
+ " movq %%mm3,%%mm1;\n" " movq %%mm2,%%mm0;\n"
+ " movq %%mm5,%%mm3;\n" " movq %%mm4,%%mm2;\n"
+ " pfmul %%mm7,%%mm5;\n" " pfmul %%mm6,%%mm4;\n"
+ " pfsub %%mm1,%%mm5;\n" " pfsub %%mm0,%%mm4;\n"
+ " movq (%%eax),%%mm0;\n" " movq %%mm0,%%mm1;\n"
+ " punpckldq %%mm0,%%mm1;\n" " add $4,%%eax;\n"
+ " pfadd %%mm1,%%mm5;\n" " pfadd %%mm1,%%mm4;\n"
+ " dec %%ecx;\n" " jnz 1b;\n"
+ " movq %%mm2,16(%%edx);\n" " movq %%mm3,24(%%edx);\n"
+ " movq %%mm4,32(%%edx);\n" " movq %%mm5,40(%%edx);\n"
+ " femms;\n"::"c"(samples), "a"(x), "d"(vv)
+ :"memory", "eax", "ecx");
+
+ s[0].v2 = vv[4];
+ s[1].v2 = vv[5];
+ s[2].v2 = vv[6];
+ s[3].v2 = vv[7];
+ s[0].v3 = vv[8];
+ s[1].v3 = vv[9];
+ s[2].v3 = vv[10];
+ s[3].v3 = vv[11];
+}
+
+/*- End of function --------------------------------------------------------*/
+#endif
+
+int dtmf_rx(dtmf_rx_state_t * s, const int16_t amp[], int samples)
+{
+ float row_energy[4];
+ float col_energy[4];
+ float famp;
+ float v1;
+ int i;
+ int j;
+ int sample;
+ int best_row;
+ int best_col;
+ int limit;
+ uint8_t hit;
+
+ hit = 0;
+ for (sample = 0; sample < samples; sample = limit) {
+ /* The block length is optimised to meet the DTMF specs. */
+ if ((samples - sample) >= (102 - s->current_sample))
+ limit = sample + (102 - s->current_sample);
+ else
+ limit = samples;
+#if defined(USE_3DNOW)
+ _dtmf_goertzel_update(s->row_out, amp + sample, limit - sample);
+ _dtmf_goertzel_update(s->col_out, amp + sample, limit - sample);
+#else
+ /* The following unrolled loop takes only 35% (rough estimate) of the
+ time of a rolled loop on the machine on which it was developed */
+ for (j = sample; j < limit; j++) {
+ famp = amp[j];
+ if (s->filter_dialtone) {
+ /* Sharp notches applied at 350Hz and 440Hz - the two common dialtone frequencies.
+ These are rather high Q, to achieve the required narrowness, without using lots of
+ sections. */
+ v1 = 0.98356f * famp + 1.8954426f * s->z350_1 - 0.9691396f * s->z350_2;
+ famp = v1 - 1.9251480f * s->z350_1 + s->z350_2;
+ s->z350_2 = s->z350_1;
+ s->z350_1 = v1;
+
+ v1 = 0.98456f * famp + 1.8529543f * s->z440_1 - 0.9691396f * s->z440_2;
+ famp = v1 - 1.8819938f * s->z440_1 + s->z440_2;
+ s->z440_2 = s->z440_1;
+ s->z440_1 = v1;
+ }
+ s->energy += famp * famp;
+ /* With GCC 2.95, the following unrolled code seems to take about 35%
+ (rough estimate) as long as a neat little 0-3 loop */
+ v1 = s->row_out[0].v2;
+ s->row_out[0].v2 = s->row_out[0].v3;
+ s->row_out[0].v3 = s->row_out[0].fac * s->row_out[0].v2 - v1 + famp;
+
+ v1 = s->col_out[0].v2;
+ s->col_out[0].v2 = s->col_out[0].v3;
+ s->col_out[0].v3 = s->col_out[0].fac * s->col_out[0].v2 - v1 + famp;
+
+ v1 = s->row_out[1].v2;
+ s->row_out[1].v2 = s->row_out[1].v3;
+ s->row_out[1].v3 = s->row_out[1].fac * s->row_out[1].v2 - v1 + famp;
+
+ v1 = s->col_out[1].v2;
+ s->col_out[1].v2 = s->col_out[1].v3;
+ s->col_out[1].v3 = s->col_out[1].fac * s->col_out[1].v2 - v1 + famp;
+
+ v1 = s->row_out[2].v2;
+ s->row_out[2].v2 = s->row_out[2].v3;
+ s->row_out[2].v3 = s->row_out[2].fac * s->row_out[2].v2 - v1 + famp;
+
+ v1 = s->col_out[2].v2;
+ s->col_out[2].v2 = s->col_out[2].v3;
+ s->col_out[2].v3 = s->col_out[2].fac * s->col_out[2].v2 - v1 + famp;
+
+ v1 = s->row_out[3].v2;
+ s->row_out[3].v2 = s->row_out[3].v3;
+ s->row_out[3].v3 = s->row_out[3].fac * s->row_out[3].v2 - v1 + famp;
+
+ v1 = s->col_out[3].v2;
+ s->col_out[3].v2 = s->col_out[3].v3;
+ s->col_out[3].v3 = s->col_out[3].fac * s->col_out[3].v2 - v1 + famp;
+ }
+#endif
+ s->current_sample += (limit - sample);
+ if (s->current_sample < 102)
+ continue;
+
+ /* We are at the end of a DTMF detection block */
+ /* Find the peak row and the peak column */
+ row_energy[0] = goertzel_result(&s->row_out[0]);
+ best_row = 0;
+ col_energy[0] = goertzel_result(&s->col_out[0]);
+ best_col = 0;
+
+ for (i = 1; i < 4; i++) {
+ row_energy[i] = goertzel_result(&s->row_out[i]);
+ if (row_energy[i] > row_energy[best_row])
+ best_row = i;
+ col_energy[i] = goertzel_result(&s->col_out[i]);
+ if (col_energy[i] > col_energy[best_col])
+ best_col = i;
+ }
+ hit = 0;
+ /* Basic signal level test and the twist test */
+ if (row_energy[best_row] >= DTMF_THRESHOLD && col_energy[best_col] >= DTMF_THRESHOLD
+ && col_energy[best_col] < row_energy[best_row] * s->reverse_twist
+ && col_energy[best_col] * s->normal_twist > row_energy[best_row]) {
+ /* Relative peak test ... */
+ for (i = 0; i < 4; i++) {
+ if ((i != best_col
+ && col_energy[i] * DTMF_RELATIVE_PEAK_COL > col_energy[best_col])
+ || (i != best_row
+ && row_energy[i] * DTMF_RELATIVE_PEAK_ROW > row_energy[best_row])) {
+ break;
+ }
+ }
+ /* ... and fraction of total energy test */
+ if (i >= 4
+ && (row_energy[best_row] + col_energy[best_col]) >
+ DTMF_TO_TOTAL_ENERGY * s->energy) {
+ hit = dtmf_positions[(best_row << 2) + best_col];
+ }
+ }
+ /* The logic in the next test should ensure the following for different successive hit patterns:
+ -----ABB = start of digit B.
+ ----B-BB = start of digit B
+ ----A-BB = start of digit B
+ BBBBBABB = still in digit B.
+ BBBBBB-- = end of digit B
+ BBBBBBC- = end of digit B
+ BBBBACBB = B ends, then B starts again.
+ BBBBBBCC = B ends, then C starts.
+ BBBBBCDD = B ends, then D starts.
+ This can work with:
+ - Back to back differing digits. Back-to-back digits should
+ not happen. The spec. says there should be a gap between digits.
+ However, many real phones do not impose a gap, and rolling across
+ the keypad can produce little or no gap.
+ - It tolerates nasty phones that give a very wobbly start to a digit.
+ - VoIP can give sample slips. The phase jumps that produces will cause
+ the block it is in to give no detection. This logic will ride over a
+ single missed block, and not falsely declare a second digit. If the
+ hiccup happens in the wrong place on a minimum length digit, however
+ we would still fail to detect that digit. Could anything be done to
+ deal with that? Packet loss is clearly a no-go zone.
+ Note this is only relevant to VoIP using A-law, u-law or similar.
+ Low bit rate codecs scramble DTMF too much for it to be recognised,
+ and often slip in units larger than a sample. */
+ if (hit != s->in_digit) {
+ if (s->last_hit != s->in_digit) {
+ /* We have two successive indications that something has changed. */
+ /* To declare digit on, the hits must agree. Otherwise we declare tone off. */
+ hit = (hit && hit == s->last_hit) ? hit : 0;
+#if 0
+ if (s->realtime_callback) {
+ /* Avoid reporting multiple no digit conditions on flaky hits */
+ if (s->in_digit || hit) {
+ i = (s->in_digit
+ && !hit) ? -99 : rint(log10f(s->energy) * 10.0f - 20.08f - 90.30F +
+ DBM0_MAX_POWER);
+ s->realtime_callback(s->realtime_callback_data, hit, i);
+ }
+ } else {
+#endif
+ if (hit) {
+ if (s->current_digits < MAX_DTMF_DIGITS) {
+ s->digits[s->current_digits++] = (char) hit;
+ s->digits[s->current_digits] = '\0';
+ if (s->callback) {
+ s->callback(s->callback_data, s->digits, s->current_digits);
+ s->current_digits = 0;
+ }
+ } else {
+ s->lost_digits++;
+ }
+ }
+#if 0
+ }
+#endif
+ s->in_digit = hit;
+ }
+ }
+ s->last_hit = hit;
+ /* Reinitialise the detector for the next block */
+ for (i = 0; i < 4; i++) {
+ goertzel_reset(&s->row_out[i]);
+ goertzel_reset(&s->col_out[i]);
+ }
+ s->energy = 0.0f;
+ s->current_sample = 0;
+ }
+ if (s->current_digits && s->callback) {
+ s->callback(s->callback_data, s->digits, s->current_digits);
+ s->digits[0] = '\0';
+ s->current_digits = 0;
+ }
+ return 0;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+size_t dtmf_rx_get(dtmf_rx_state_t * s, char *buf, int max)
+{
+ if (max > s->current_digits)
+ max = s->current_digits;
+ if (max > 0) {
+ memcpy(buf, s->digits, max);
+ memmove(s->digits, s->digits + max, s->current_digits - max);
+ s->current_digits -= max;
+ }
+ buf[max] = '\0';
+ return max;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+#if 0
+void dtmf_rx_set_realtime_callback(dtmf_rx_state_t * s, tone_report_func_t callback,
+ void *user_data)
+{
+ s->realtime_callback = callback;
+ s->realtime_callback_data = user_data;
+}
+#endif
+/*- End of function --------------------------------------------------------*/
+
+void dtmf_rx_parms(dtmf_rx_state_t * s, int filter_dialtone, int twist, int reverse_twist)
+{
+ if (filter_dialtone >= 0) {
+ s->z350_1 = 0.0f;
+ s->z350_2 = 0.0f;
+ s->z440_1 = 0.0f;
+ s->z440_2 = 0.0f;
+ s->filter_dialtone = filter_dialtone;
+ }
+ if (twist >= 0)
+ s->normal_twist = powf(10.0f, twist / 10.0f);
+ if (reverse_twist >= 0)
+ s->reverse_twist = powf(10.0f, reverse_twist / 10.0f);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+dtmf_rx_state_t *dtmf_rx_init(dtmf_rx_state_t * s, dtmf_rx_callback_t callback,
+ void *user_data)
+{
+ int i;
+ static int initialised = 0;
+
+ s->callback = callback;
+ s->callback_data = user_data;
+ s->realtime_callback = NULL;
+ s->realtime_callback_data = NULL;
+ s->filter_dialtone = 0;
+ s->normal_twist = DTMF_NORMAL_TWIST;
+ s->reverse_twist = DTMF_REVERSE_TWIST;
+
+ s->in_digit = 0;
+ s->last_hit = 0;
+
+ if (!initialised) {
+ for (i = 0; i < 4; i++) {
+ make_goertzel_descriptor(&dtmf_detect_row[i], dtmf_row[i], 102);
+ make_goertzel_descriptor(&dtmf_detect_col[i], dtmf_col[i], 102);
+ }
+ initialised = 1;
+ }
+ for (i = 0; i < 4; i++) {
+ goertzel_init(&s->row_out[i], &dtmf_detect_row[i]);
+ goertzel_init(&s->col_out[i], &dtmf_detect_col[i]);
+ }
+ s->energy = 0.0f;
+ s->current_sample = 0;
+ s->lost_digits = 0;
+ s->current_digits = 0;
+ s->digits[0] = '\0';
+ return s;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+#if 0
+static void dtmf_tx_initialise(void)
+{
+ int row;
+ int col;
+
+ if (dtmf_tx_inited)
+ return;
+ for (row = 0; row < 4; row++) {
+ for (col = 0; col < 4; col++) {
+ make_tone_gen_descriptor(&dtmf_digit_tones[row * 4 + col], (int) dtmf_row[row],
+ DEFAULT_DTMF_TX_LEVEL, (int) dtmf_col[col],
+ DEFAULT_DTMF_TX_LEVEL, DEFAULT_DTMF_TX_ON_TIME,
+ DEFAULT_DTMF_TX_OFF_TIME, 0, 0, FALSE);
+ }
+ }
+ dtmf_tx_inited = TRUE;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+int dtmf_tx(dtmf_tx_state_t * s, int16_t amp[], int max_samples)
+{
+ int len;
+ size_t dig;
+ char *cp;
+
+ len = 0;
+ if (s->tones.current_section >= 0) {
+ /* Deal with the fragment left over from last time */
+ len = tone_gen(&(s->tones), amp, max_samples);
+ }
+ dig = 0;
+ while (dig < s->current_digits && len < max_samples) {
+ /* Step to the next digit */
+ if ((cp = strchr(dtmf_positions, s->digits[dig++])) == NULL)
+ continue;
+ tone_gen_init(&(s->tones), &(s->tone_descriptors[cp - dtmf_positions]));
+ len += tone_gen(&(s->tones), amp + len, max_samples - len);
+ }
+ if (dig) {
+ /* Shift out the consumed digits */
+ s->current_digits -= dig;
+ memmove(s->digits, s->digits + dig, s->current_digits);
+ }
+ return len;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+size_t dtmf_tx_put(dtmf_tx_state_t * s, const char *digits)
+{
+ size_t len;
+
+ /* This returns the number of characters that would not fit in the buffer.
+ The buffer will only be loaded if the whole string of digits will fit,
+ in which case zero is returned. */
+ if ((len = strlen(digits)) > 0) {
+ if (s->current_digits + len <= MAX_DTMF_DIGITS) {
+ memcpy(s->digits + s->current_digits, digits, len);
+ s->current_digits += len;
+ len = 0;
+ } else {
+ len = MAX_DTMF_DIGITS - s->current_digits;
+ }
+ }
+ return len;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+dtmf_tx_state_t *dtmf_tx_init(dtmf_tx_state_t * s)
+{
+ if (!dtmf_tx_inited)
+ dtmf_tx_initialise();
+ s->tone_descriptors = dtmf_digit_tones;
+ tone_gen_init(&(s->tones), &dtmf_digit_tones[0]);
+ s->current_sample = 0;
+ s->current_digits = 0;
+ s->tones.current_section = -1;
+ return s;
+}
+#endif //NO TX
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
+
+void make_goertzel_descriptor(goertzel_descriptor_t * t, float freq, int samples)
+{
+ //t->fac = 2.0f*cosf(2.0f*M_PI*(freq/(float) SAMPLE_RATE));
+ t->fac = 2.0f * cosf(2.0f * M_PI * (freq / (float) 8000));
+ t->samples = samples;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+goertzel_state_t *goertzel_init(goertzel_state_t * s, goertzel_descriptor_t * t)
+{
+ if (s || (s = malloc(sizeof(goertzel_state_t)))) {
+ s->v2 = s->v3 = 0.0;
+ s->fac = t->fac;
+ s->samples = t->samples;
+ s->current_sample = 0;
+ }
+ return s;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+void goertzel_reset(goertzel_state_t * s)
+{
+ s->v2 = s->v3 = 0.0;
+ s->current_sample = 0;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+int goertzel_update(goertzel_state_t * s, const int16_t amp[], int samples)
+{
+ int i;
+ float v1;
+
+ if (samples > s->samples - s->current_sample)
+ samples = s->samples - s->current_sample;
+ for (i = 0; i < samples; i++) {
+ v1 = s->v2;
+ s->v2 = s->v3;
+ s->v3 = s->fac * s->v2 - v1 + amp[i];
+ }
+ s->current_sample += samples;
+ return samples;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+float goertzel_result(goertzel_state_t * s)
+{
+ float v1;
+
+ /* Push a zero through the process to finish things off. */
+ v1 = s->v2;
+ s->v2 = s->v3;
+ s->v3 = s->fac * s->v2 - v1;
+ /* Now calculate the non-recursive side of the filter. */
+ /* The result here is not scaled down to allow for the magnification
+ effect of the filter (the usual DFT magnification effect). */
+ return s->v3 * s->v3 + s->v2 * s->v2 - s->v2 * s->v3 * s->fac;
+}
+
+/*- End of function --------------------------------------------------------*/
+/*- End of file ------------------------------------------------------------*/
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopencelliax_spandsph"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/celliax_spandsp.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,1034 @@
</span><ins>+
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * bit_operations.h - Various bit level operations, such as bit reversal
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2006 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: bit_operations.h,v 1.15 2007/02/23 13:16:13 steveu Exp $
+ */
+
+/*! \file */
+
+#ifndef _CELLIAX_SPANDSP_H
+#define _CELLIAX_SPANDSP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif                                                        /* __cplusplus */
+#include <math.h>
+
+/*! \brief Find the bit position of the highest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the highest set bit, or -1 if the word is zero. */
+static __inline__ int top_bit(unsigned int bits)
+{
+ int res;
+
+#if defined(__i386__) || defined(__x86_64__)
+__asm__(" xorl %[res],%[res];\n" " decl %[res];\n" " bsrl %[bits],%[res]\n":[res] "=&r"
+ (res)
+: [bits] "rm"(bits));
+ return res;
+#elif defined(__ppc__) || defined(__powerpc__)
+__asm__("cntlzw %[res],%[bits];\n":[res] "=&r"(res)
+: [bits] "r"(bits));
+ return 31 - res;
+#else
+ if (bits == 0)
+ return -1;
+ res = 0;
+ if (bits & 0xFFFF0000) {
+ bits &= 0xFFFF0000;
+ res += 16;
+ }
+ if (bits & 0xFF00FF00) {
+ bits &= 0xFF00FF00;
+ res += 8;
+ }
+ if (bits & 0xF0F0F0F0) {
+ bits &= 0xF0F0F0F0;
+ res += 4;
+ }
+ if (bits & 0xCCCCCCCC) {
+ bits &= 0xCCCCCCCC;
+ res += 2;
+ }
+ if (bits & 0xAAAAAAAA) {
+ bits &= 0xAAAAAAAA;
+ res += 1;
+ }
+ return res;
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the bit position of the lowest set bit in a word
+ \param bits The word to be searched
+ \return The bit number of the lowest set bit, or -1 if the word is zero. */
+static __inline__ int bottom_bit(unsigned int bits)
+{
+ int res;
+
+#if defined(__i386__) || defined(__x86_64__)
+__asm__(" xorl %[res],%[res];\n" " decl %[res];\n" " bsfl %[bits],%[res]\n":[res] "=&r"
+ (res)
+: [bits] "rm"(bits));
+ return res;
+#else
+ if (bits == 0)
+ return -1;
+ res = 31;
+ if (bits & 0x0000FFFF) {
+ bits &= 0x0000FFFF;
+ res -= 16;
+ }
+ if (bits & 0x00FF00FF) {
+ bits &= 0x00FF00FF;
+ res -= 8;
+ }
+ if (bits & 0x0F0F0F0F) {
+ bits &= 0x0F0F0F0F;
+ res -= 4;
+ }
+ if (bits & 0x33333333) {
+ bits &= 0x33333333;
+ res -= 2;
+ }
+ if (bits & 0x55555555) {
+ bits &= 0x55555555;
+ res -= 1;
+ }
+ return res;
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Bit reverse a byte.
+ \param data The byte to be reversed.
+ \return The bit reversed version of data. */
+static __inline__ uint8_t bit_reverse8(uint8_t x)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
+ /* If multiply is fast */
+ return ((x * 0x0802U & 0x22110U) | (x * 0x8020U & 0x88440U)) * 0x10101U >> 16;
+#else
+ /* If multiply is slow, but we have a barrel shifter */
+ x = (x >> 4) | (x << 4);
+ x = ((x & 0xCC) >> 2) | ((x & 0x33) << 2);
+ return ((x & 0xAA) >> 1) | ((x & 0x55) << 1);
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Bit reverse a 16 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint16_t bit_reverse16(uint16_t data);
+
+/*! \brief Bit reverse a 32 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint32_t bit_reverse32(uint32_t data);
+
+/*! \brief Bit reverse each of the four bytes in a 32 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint32_t bit_reverse_4bytes(uint32_t data);
+
+#if defined(__x86_64__)
+/*! \brief Bit reverse each of the eight bytes in a 64 bit word.
+ \param data The word to be reversed.
+ \return The bit reversed version of data. */
+uint64_t bit_reverse_8bytes(uint64_t data);
+#endif
+
+/*! \brief Bit reverse each bytes in a buffer.
+ \param to The buffer to place the reversed data in.
+ \param from The buffer containing the data to be reversed.
+ \param The length of the data in the buffer. */
+void bit_reverse(uint8_t to[], const uint8_t from[], int len);
+
+/*! \brief Find the number of set bits in a 32 bit word.
+ \param x The word to be searched.
+ \return The number of set bits. */
+int one_bits32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 32 bit word.
+ \param x The word to be searched.
+ \return The mask. */
+uint32_t make_mask32(uint32_t x);
+
+/*! \brief Create a mask as wide as the number in a 16 bit word.
+ \param x The word to be searched.
+ \return The mask. */
+uint16_t make_mask16(uint16_t x);
+
+/*! \brief Find the least significant one in a word, and return a word
+ with just that bit set.
+ \param x The word to be searched.
+ \return The word with the single set bit. */
+static __inline__ uint32_t least_significant_one32(uint32_t x)
+{
+ return (x & (-(int32_t) x));
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the most significant one in a word, and return a word
+ with just that bit set.
+ \param x The word to be searched.
+ \return The word with the single set bit. */
+static __inline__ uint32_t most_significant_one32(uint32_t x)
+{
+#if defined(__i386__) || defined(__x86_64__) || defined(__ppc__) || defined(__powerpc__)
+ return 1 << top_bit(x);
+#else
+ x = make_mask32(x);
+ return (x ^ (x >> 1));
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a byte.
+ \param x The byte to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity8(uint8_t x)
+{
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 16 bit word.
+ \param x The word to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity16(uint16_t x)
+{
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*! \brief Find the parity of a 32 bit word.
+ \param x The word to be checked.
+ \return 1 for odd, or 0 for even. */
+static __inline__ int parity32(uint32_t x)
+{
+ x ^= (x >> 16);
+ x ^= (x >> 8);
+ x = (x ^ (x >> 4)) & 0x0F;
+ return (0x6996 >> x) & 1;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*- End of file ------------------------------------------------------------*/
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * fir.h - General telephony FIR routines
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2002 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: fir.h,v 1.8 2006/10/24 13:45:28 steveu Exp $
+ */
+
+/*! \page fir_page FIR filtering
+\section fir_page_sec_1 What does it do?
+???.
+
+\section fir_page_sec_2 How does it work?
+???.
+*/
+
+#if 0
+#if defined(USE_MMX) || defined(USE_SSE2)
+#include "mmx.h"
+#endif
+
+/*!
+ 16 bit integer FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using 16 bit integer coefficients.
+*/
+typedef struct {
+ int taps;
+ int curr_pos;
+ const int16_t *coeffs;
+ int16_t *history;
+} fir16_state_t;
+
+/*!
+ 32 bit integer FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using 32 bit integer coefficients, and filtering
+ 16 bit integer data.
+*/
+typedef struct {
+ int taps;
+ int curr_pos;
+ const int32_t *coeffs;
+ int16_t *history;
+} fir32_state_t;
+
+/*!
+ Floating point FIR descriptor. This defines the working state for a single
+ instance of an FIR filter using floating point coefficients and data.
+*/
+typedef struct {
+ int taps;
+ int curr_pos;
+ const float *coeffs;
+ float *history;
+} fir_float_state_t;
+
+static __inline__ const int16_t *fir16_create(fir16_state_t * fir, const int16_t * coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+#if defined(USE_MMX) || defined(USE_SSE2)
+ if ((fir->history = malloc(2 * taps * sizeof(int16_t))))
+ memset(fir->history, 0, 2 * taps * sizeof(int16_t));
+#else
+ if ((fir->history = (int16_t *) malloc(taps * sizeof(int16_t))))
+ memset(fir->history, 0, taps * sizeof(int16_t));
+#endif
+ return fir->history;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_flush(fir16_state_t * fir)
+{
+#if defined(USE_MMX) || defined(USE_SSE2)
+ memset(fir->history, 0, 2 * fir->taps * sizeof(int16_t));
+#else
+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
+#endif
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir16_free(fir16_state_t * fir)
+{
+ free(fir->history);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir16(fir16_state_t * fir, int16_t sample)
+{
+ int i;
+ int32_t y;
+#if defined(USE_MMX)
+ mmx_t *mmx_coeffs;
+ mmx_t *mmx_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ mmx_coeffs = (mmx_t *) fir->coeffs;
+ mmx_hist = (mmx_t *) & fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(mm4, mm4);
+ /* 8 samples per iteration, so the filter must be a multiple of 8 long. */
+ while (i > 0) {
+ movq_m2r(mmx_coeffs[0], mm0);
+ movq_m2r(mmx_coeffs[1], mm2);
+ movq_m2r(mmx_hist[0], mm1);
+ movq_m2r(mmx_hist[1], mm3);
+ mmx_coeffs += 2;
+ mmx_hist += 2;
+ pmaddwd_r2r(mm1, mm0);
+ pmaddwd_r2r(mm3, mm2);
+ paddd_r2r(mm0, mm4);
+ paddd_r2r(mm2, mm4);
+ i -= 8;
+ }
+ movq_r2r(mm4, mm0);
+ psrlq_i2r(32, mm0);
+ paddd_r2r(mm0, mm4);
+ movd_r2m(mm4, y);
+ emms();
+#elif defined(USE_SSE2)
+ xmm_t *xmm_coeffs;
+ xmm_t *xmm_hist;
+
+ fir->history[fir->curr_pos] = sample;
+ fir->history[fir->curr_pos + fir->taps] = sample;
+
+ xmm_coeffs = (xmm_t *) fir->coeffs;
+ xmm_hist = (xmm_t *) & fir->history[fir->curr_pos];
+ i = fir->taps;
+ pxor_r2r(xmm4, xmm4);
+ /* 16 samples per iteration, so the filter must be a multiple of 16 long. */
+ while (i > 0) {
+ movdqu_m2r(xmm_coeffs[0], xmm0);
+ movdqu_m2r(xmm_coeffs[1], xmm2);
+ movdqu_m2r(xmm_hist[0], xmm1);
+ movdqu_m2r(xmm_hist[1], xmm3);
+ xmm_coeffs += 2;
+ xmm_hist += 2;
+ pmaddwd_r2r(xmm1, xmm0);
+ pmaddwd_r2r(xmm3, xmm2);
+ paddd_r2r(xmm0, xmm4);
+ paddd_r2r(xmm2, xmm4);
+ i -= 16;
+ }
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(8, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movdqa_r2r(xmm4, xmm0);
+ psrldq_i2r(4, xmm0);
+ paddd_r2r(xmm0, xmm4);
+ movd_r2m(xmm4, y);
+#else
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
+#endif
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ const int16_t *fir32_create(fir32_state_t * fir, const int32_t * coeffs,
+ int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = (int16_t *) malloc(taps * sizeof(int16_t));
+ if (fir->history)
+ memset(fir->history, '\0', taps * sizeof(int16_t));
+ return fir->history;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_flush(fir32_state_t * fir)
+{
+ memset(fir->history, 0, fir->taps * sizeof(int16_t));
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir32_free(fir32_state_t * fir)
+{
+ free(fir->history);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir32(fir32_state_t * fir, int16_t sample)
+{
+ int i;
+ int32_t y;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) (y >> 15);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ const float *fir_float_create(fir_float_state_t * fir,
+ const float *coeffs, int taps)
+{
+ fir->taps = taps;
+ fir->curr_pos = taps - 1;
+ fir->coeffs = coeffs;
+ fir->history = (float *) malloc(taps * sizeof(float));
+ if (fir->history)
+ memset(fir->history, '\0', taps * sizeof(float));
+ return fir->history;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ void fir_float_free(fir_float_state_t * fir)
+{
+ free(fir->history);
+}
+
+/*- End of function --------------------------------------------------------*/
+
+static __inline__ int16_t fir_float(fir_float_state_t * fir, int16_t sample)
+{
+ int i;
+ float y;
+ int offset1;
+ int offset2;
+
+ fir->history[fir->curr_pos] = sample;
+
+ offset2 = fir->curr_pos;
+ offset1 = fir->taps - offset2;
+ y = 0;
+ for (i = fir->taps - 1; i >= offset1; i--)
+ y += fir->coeffs[i] * fir->history[i - offset1];
+ for (; i >= 0; i--)
+ y += fir->coeffs[i] * fir->history[i + offset2];
+ if (fir->curr_pos <= 0)
+ fir->curr_pos = fir->taps;
+ fir->curr_pos--;
+ return (int16_t) y;
+}
+
+/*- End of function --------------------------------------------------------*/
+#endif
+
+/*- End of file ------------------------------------------------------------*/
+
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * echo.h - An echo cancellor, suitable for electrical and acoustic
+ *         cancellation. This code does not currently comply with
+ *         any relevant standards (e.g. G.164/5/7/8).
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001 Steve Underwood
+ *
+ * Based on a bit from here, a bit from there, eye of toad,
+ * ear of bat, etc - plus, of course, my own 2 cents.
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: echo.h,v 1.9 2006/10/24 13:45:28 steveu Exp $
+ */
+
+/*! \file */
+
+/*! \page echo_can_page Line echo cancellation for voice
+
+\section echo_can_page_sec_1 What does it do?
+This module aims to provide G.168-2002 compliant echo cancellation, to remove
+electrical echoes (e.g. from 2-4 wire hybrids) from voice calls.
+
+\section echo_can_page_sec_2 How does it work?
+The heart of the echo cancellor is FIR filter. This is adapted to match the echo
+impulse response of the telephone line. It must be long enough to adequately cover
+the duration of that impulse response. The signal transmitted to the telephone line
+is passed through the FIR filter. Once the FIR is properly adapted, the resulting
+output is an estimate of the echo signal received from the line. This is subtracted
+from the received signal. The result is an estimate of the signal which originated
+at the far end of the line, free from echos of our own transmitted signal.
+
+The least mean squares (LMS) algorithm is attributed to Widrow and Hoff, and was
+introduced in 1960. It is the commonest form of filter adaption used in things
+like modem line equalisers and line echo cancellers. There it works very well.
+However, it only works well for signals of constant amplitude. It works very poorly
+for things like speech echo cancellation, where the signal level varies widely.
+This is quite easy to fix. If the signal level is normalised - similar to applying
+AGC - LMS can work as well for a signal of varying amplitude as it does for a modem
+signal. This normalised least mean squares (NLMS) algorithm is the commonest one used
+for speech echo cancellation. Many other algorithms exist - e.g. RLS (essentially
+the same as Kalman filtering), FAP, etc. Some perform significantly better than NLMS.
+However, factors such as computational complexity and patents favour the use of NLMS.
+
+A simple refinement to NLMS can improve its performance with speech. NLMS tends
+to adapt best to the strongest parts of a signal. If the signal is white noise,
+the NLMS algorithm works very well. However, speech has more low frequency than
+high frequency content. Pre-whitening (i.e. filtering the signal to flatten
+its spectrum) the echo signal improves the adapt rate for speech, and ensures the
+final residual signal is not heavily biased towards high frequencies. A very low
+complexity filter is adequate for this, so pre-whitening adds little to the
+compute requirements of the echo canceller.
+
+An FIR filter adapted using pre-whitened NLMS performs well, provided certain
+conditions are met:
+
+ - The transmitted signal has poor self-correlation.
+ - There is no signal being generated within the environment being cancelled.
+
+The difficulty is that neither of these can be guaranteed.
+
+If the adaption is performed while transmitting noise (or something fairly noise
+like, such as voice) the adaption works very well. If the adaption is performed
+while transmitting something highly correlative (typically narrow band energy
+such as signalling tones or DTMF), the adaption can go seriously wrong. The reason
+is there is only one solution for the adaption on a near random signal - the impulse
+response of the line. For a repetitive signal, there are any number of solutions
+which converge the adaption, and nothing guides the adaption to choose the generalised
+one. Allowing an untrained canceller to converge on this kind of narrowband
+energy probably a good thing, since at least it cancels the tones. Allowing a well
+converged canceller to continue converging on such energy is just a way to ruin
+its generalised adaption. A narrowband detector is needed, so adapation can be
+suspended at appropriate times.
+
+The adaption process is based on trying to eliminate the received signal. When
+there is any signal from within the environment being cancelled it may upset the
+adaption process. Similarly, if the signal we are transmitting is small, noise
+may dominate and disturb the adaption process. If we can ensure that the
+adaption is only performed when we are transmitting a significant signal level,
+and the environment is not, things will be OK. Clearly, it is easy to tell when
+we are sending a significant signal. Telling, if the environment is generating a
+significant signal, and doing it with sufficient speed that the adaption will
+not have diverged too much more we stop it, is a little harder.
+
+The key problem in detecting when the environment is sourcing significant energy
+is that we must do this very quickly. Given a reasonably long sample of the
+received signal, there are a number of strategies which may be used to assess
+whether that signal contains a strong far end component. However, by the time
+that assessment is complete the far end signal will have already caused major
+mis-convergence in the adaption process. An assessment algorithm is needed which
+produces a fairly accurate result from a very short burst of far end energy.
+
+\section echo_can_page_sec_3 How do I use it?
+The echo cancellor processes both the transmit and receive streams sample by
+sample. The processing function is not declared inline. Unfortunately,
+cancellation requires many operations per sample, so the call overhead is only a
+minor burden.
+*/
+
+#define NONUPDATE_DWELL_TIME        600 /* 600 samples, or 75ms */
+
+#if 0
+/* Mask bits for the adaption mode */
+#define ECHO_CAN_USE_NLP 0x01
+#define ECHO_CAN_USE_SUPPRESSOR 0x02
+#define ECHO_CAN_USE_CNG 0x04
+#define ECHO_CAN_USE_ADAPTION 0x08
+
+/*!
+ G.168 echo canceller descriptor. This defines the working state for a line
+ echo canceller.
+*/
+typedef struct {
+ int tx_power[4];
+ int rx_power[3];
+ int clean_rx_power;
+
+ int rx_power_threshold;
+ int nonupdate_dwell;
+
+ fir16_state_t fir_state;
+ /*! Echo FIR taps (16 bit version) */
+ int16_t *fir_taps16[4];
+ /*! Echo FIR taps (32 bit version) */
+ int32_t *fir_taps32;
+
+ int curr_pos;
+
+ int taps;
+ int tap_mask;
+ int adaption_mode;
+
+ int32_t supp_test1;
+ int32_t supp_test2;
+ int32_t supp1;
+ int32_t supp2;
+ int vad;
+ int cng;
+ /* Parameters for the Hoth noise generator */
+ int cng_level;
+ int cng_rndnum;
+ int cng_filter;
+
+ int16_t geigel_max;
+ int geigel_lag;
+ int dtd_onset;
+ int tap_set;
+ int tap_rotate_counter;
+
+ int32_t latest_correction; /* Indication of the magnitude of the latest
+ adaption, or a code to indicate why adaption
+ was skipped, for test purposes */
+ int32_t last_acf[28];
+ int narrowband_count;
+ int narrowband_score;
+} echo_can_state_t;
+
+/*! Create a voice echo canceller context.
+ \param len The length of the canceller, in samples.
+ \return The new canceller context, or NULL if the canceller could not be created.
+*/
+echo_can_state_t *echo_can_create(int len, int adaption_mode);
+
+/*! Free a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void echo_can_free(echo_can_state_t * ec);
+
+/*! Flush (reinitialise) a voice echo canceller context.
+ \param ec The echo canceller context.
+*/
+void echo_can_flush(echo_can_state_t * ec);
+
+/*! Set the adaption mode of a voice echo canceller context.
+ \param ec The echo canceller context.
+ \param adapt The mode.
+*/
+void echo_can_adaption_mode(echo_can_state_t * ec, int adaption_mode);
+
+/*! Process a sample through a voice echo canceller.
+ \param ec The echo canceller context.
+ \param tx The transmitted audio sample.
+ \param rx The received audio sample.
+ \return The clean (echo cancelled) received sample.
+*/
+int16_t echo_can_update(echo_can_state_t * ec, int16_t tx, int16_t rx);
+
+#endif
+/*- End of file ------------------------------------------------------------*/
+
+/*!
+ Floating point Goertzel filter descriptor.
+*/
+typedef struct {
+ float fac;
+ int samples;
+} goertzel_descriptor_t;
+
+/*!
+ Floating point Goertzel filter state descriptor.
+*/
+typedef struct {
+ float v2;
+ float v3;
+ float fac;
+ int samples;
+ int current_sample;
+} goertzel_state_t;
+
+/*! \brief Create a descriptor for use with either a Goertzel transform */
+void make_goertzel_descriptor(goertzel_descriptor_t * t, float freq, int samples);
+
+/*! \brief Initialise the state of a Goertzel transform.
+ \param s The Goertzel context. If NULL, a context is allocated with malloc.
+ \param t The Goertzel descriptor.
+ \return A pointer to the Goertzel state. */
+goertzel_state_t *goertzel_init(goertzel_state_t * s, goertzel_descriptor_t * t);
+
+/*! \brief Reset the state of a Goertzel transform.
+ \param s The Goertzel context.
+ \param t The Goertzel descriptor.
+ \return A pointer to the Goertzel state. */
+void goertzel_reset(goertzel_state_t * s);
+
+/*! \brief Update the state of a Goertzel transform.
+ \param s The Goertzel context
+ \param amp The samples to be transformed
+ \param samples The number of samples
+ \return The number of samples unprocessed */
+int goertzel_update(goertzel_state_t * s, const int16_t amp[], int samples);
+
+/*! \brief Evaluate the final result of a Goertzel transform.
+ \param s The Goertzel context
+ \return The result of the transform. */
+float goertzel_result(goertzel_state_t * s);
+
+/*! \brief Update the state of a Goertzel transform.
+ \param s The Goertzel context
+ \param amp The sample to be transformed. */
+static __inline__ void goertzel_sample(goertzel_state_t * s, int16_t amp)
+{
+ float v1;
+
+ v1 = s->v2;
+ s->v2 = s->v3;
+ s->v3 = s->fac * s->v2 - v1 + amp;
+ s->current_sample++;
+}
+
+/*- End of function --------------------------------------------------------*/
+
+/*
+ * SpanDSP - a series of DSP components for telephony
+ *
+ * tone_detect.c - General telephony tone detection.
+ *
+ * Written by Steve Underwood <steveu@coppice.org>
+ *
+ * Copyright (C) 2001-2003, 2005 Steve Underwood
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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: tone_detect.c,v 1.31 2007/03/03 10:40:33 steveu Exp $
+ */
+
+/*! \file tone_detect.h */
+
+#if !defined(M_PI)
+/* C99 systems may not define M_PI */
+#define M_PI 3.14159265358979323846264338327
+#endif
+/*! \page dtmf_rx_page DTMF receiver
+\section dtmf_rx_page_sec_1 What does it do?
+The DTMF receiver detects the standard DTMF digits. It is compliant with
+ITU-T Q.23, ITU-T Q.24, and the local DTMF specifications of most administrations.
+Its passes the test suites. It also scores *very* well on the standard
+talk-off tests.
+
+The current design uses floating point extensively. It is not tolerant of DC.
+It is expected that a DC restore stage will be placed before the DTMF detector.
+Unless the dial tone filter is switched on, the detector has poor tolerance
+of dial tone. Whether this matter depends on your application. If you are using
+the detector in an IVR application you will need proper echo cancellation to
+get good performance in the presence of speech prompts, so dial tone will not
+exist. If you do need good dial tone tolerance, a dial tone filter can be
+enabled in the detector.
+
+\section dtmf_rx_page_sec_2 How does it work?
+Like most other DSP based DTMF detector's, this one uses the Goertzel algorithm
+to look for the DTMF tones. What makes each detector design different is just how
+that algorithm is used.
+
+Basic DTMF specs:
+ - Minimum tone on = 40ms
+ - Minimum tone off = 50ms
+ - Maximum digit rate = 10 per second
+ - Normal twist <= 8dB accepted
+ - Reverse twist <= 4dB accepted
+ - S/N >= 15dB will detect OK
+ - Attenuation <= 26dB will detect OK
+ - Frequency tolerance +- 1.5% will detect, +-3.5% will reject
+
+TODO:
+*/
+
+/*! \page dtmf_tx_page DTMF tone generation
+\section dtmf_tx_page_sec_1 What does it do?
+
+The DTMF tone generation module provides for the generation of the
+repertoire of 16 DTMF dual tones.
+
+\section dtmf_tx_page_sec_2 How does it work?
+*/
+
+#define MAX_DTMF_DIGITS 128
+
+typedef void (*dtmf_rx_callback_t) (void *user_data, const char *digits, int len);
+
+/*!
+ DTMF generator state descriptor. This defines the state of a single
+ working instance of a DTMF generator.
+*/
+#if 0
+typedef struct {
+ tone_gen_descriptor_t *tone_descriptors;
+ tone_gen_state_t tones;
+ char digits[MAX_DTMF_DIGITS + 1];
+ int current_sample;
+ size_t current_digits;
+} dtmf_tx_state_t;
+
+#endif
+
+/*!
+ DTMF digit detector descriptor.
+*/
+typedef struct {
+ /*! Optional callback funcion to deliver received digits. */
+ dtmf_rx_callback_t callback;
+ /*! An opaque pointer passed to the callback function. */
+ void *callback_data;
+ /*! Optional callback funcion to deliver real time digit state changes. */
+ //tone_report_func_t realtime_callback;
+ void *realtime_callback;
+ /*! An opaque pointer passed to the real time callback function. */
+ void *realtime_callback_data;
+ /*! TRUE if dialtone should be filtered before processing */
+ int filter_dialtone;
+ /*! Maximum acceptable "normal" (lower bigger than higher) twist ratio */
+ float normal_twist;
+ /*! Maximum acceptable "reverse" (higher bigger than lower) twist ratio */
+ float reverse_twist;
+
+ /*! 350Hz filter state for the optional dialtone filter */
+ float z350_1;
+ float z350_2;
+ /*! 440Hz filter state for the optional dialtone filter */
+ float z440_1;
+ float z440_2;
+
+ /*! Tone detector working states */
+ goertzel_state_t row_out[4];
+ goertzel_state_t col_out[4];
+ /*! The accumlating total energy on the same period over which the Goertzels work. */
+ float energy;
+ /*! The result of the last tone analysis. */
+ uint8_t last_hit;
+ /*! The confirmed digit we are currently receiving */
+ uint8_t in_digit;
+ /*! The current sample number within a processing block. */
+ int current_sample;
+
+ /*! The received digits buffer. This is a NULL terminated string. */
+ char digits[MAX_DTMF_DIGITS + 1];
+ /*! The number of digits currently in the digit buffer. */
+ int current_digits;
+ /*! The number of digits which have been lost due to buffer overflows. */
+ int lost_digits;
+} dtmf_rx_state_t;
+
+#if 0
+/*! \brief Generate a buffer of DTMF tones.
+ \param s The DTMF generator context.
+ \param amp The buffer for the generated signal.
+ \param max_samples The required number of generated samples.
+ \return The number of samples actually generated. This may be less than
+ samples if the input buffer empties. */
+int dtmf_tx(dtmf_tx_state_t * s, int16_t amp[], int max_samples);
+
+/*! \brief Put a string of digits in a DTMF generator's input buffer.
+ \param s The DTMF generator context.
+ \param digits The string of digits to be added.
+ \return The number of digits actually added. This may be less than the
+ length of the digit string, if the buffer fills up. */
+size_t dtmf_tx_put(dtmf_tx_state_t * s, const char *digits);
+
+/*! \brief Initialise a DTMF tone generator context.
+ \param s The DTMF generator context.
+ \return A pointer to the DTMF generator context. */
+dtmf_tx_state_t *dtmf_tx_init(dtmf_tx_state_t * s);
+#endif
+
+/*! Set a optional realtime callback for a DTMF receiver context. This function
+ is called immediately a confirmed state change occurs in the received DTMF. It
+ is called with the ASCII value for a DTMF tone pair, or zero to indicate no tone
+ is being received.
+ \brief Set a realtime callback for a DTMF receiver context.
+ \param s The DTMF receiver context.
+ \param callback Callback routine used to report the start and end of digits.
+ \param user_data An opaque pointer which is associated with the context,
+ and supplied in callbacks. */
+void dtmf_rx_set_realtime_callback(dtmf_rx_state_t * s,
+ //tone_report_func_t callback,
+ void *callback, void *user_data);
+
+/*! \brief Adjust a DTMF receiver context.
+ \param s The DTMF receiver context.
+ \param filter_dialtone TRUE to enable filtering of dialtone, FALSE
+ to disable, < 0 to leave unchanged.
+ \param twist Acceptable twist, in dB. < 0 to leave unchanged.
+ \param reverse_twist Acceptable reverse twist, in dB. < 0 to leave unchanged. */
+void dtmf_rx_parms(dtmf_rx_state_t * s, int filter_dialtone, int twist,
+ int reverse_twist);
+
+/*! Process a block of received DTMF audio samples.
+ \brief Process a block of received DTMF audio samples.
+ \param s The DTMF receiver context.
+ \param amp The audio sample buffer.
+ \param samples The number of samples in the buffer.
+ \return The number of samples unprocessed. */
+int dtmf_rx(dtmf_rx_state_t * s, const int16_t amp[], int samples);
+
+/*! \brief Get a string of digits from a DTMF receiver's output buffer.
+ \param s The DTMF receiver context.
+ \param digits The buffer for the received digits.
+ \param max The maximum number of digits to be returned,
+ \return The number of digits actually returned. */
+size_t dtmf_rx_get(dtmf_rx_state_t * s, char *digits, int max);
+
+/*! \brief Initialise a DTMF receiver context.
+ \param s The DTMF receiver context.
+ \param callback An optional callback routine, used to report received digits. If
+ no callback routine is set, digits may be collected, using the dtmf_rx_get()
+ function.
+ \param user_data An opaque pointer which is associated with the context,
+ and supplied in callbacks.
+ \return A pointer to the DTMF receiver context. */
+dtmf_rx_state_t *dtmf_rx_init(dtmf_rx_state_t * s, dtmf_rx_callback_t callback,
+ void *user_data);
+
+/*- End of file ------------------------------------------------------------*/
+
+#ifdef __cplusplus
+} //extern "C"
+#endif                                                        /* __cplusplus */
+#endif /* _CELLIAX_SPANDSP_H */
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenpablioc"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.c (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.c        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -39,9 +39,8 @@
</span><span class="cx"> * requested that these non-binding requests be included along with the
</span><span class="cx"> * license above.
</span><span class="cx"> */
</span><del>-
-#undef GIOVA48
-
</del><ins>+#define WANT_SPEEX
+#include <switch.h>
</ins><span class="cx"> #include <stdio.h>
</span><span class="cx"> #include <stdlib.h>
</span><span class="cx"> #include <math.h>
</span><span class="lines">@@ -50,17 +49,30 @@
</span><span class="cx"> #include "pablio.h"
</span><span class="cx"> #include <string.h>
</span><span class="cx"> #include <time.h>
</span><ins>+#ifdef WANT_SPEEX
+#include "speex/speex_preprocess.h"
+#include "speex/speex_echo.h"
+ SpeexPreprocessState *preprocess;
+ SpeexPreprocessState *preprocess2;
+ SpeexEchoState *echo_state;
</ins><span class="cx">
</span><ins>+         int speexecho=1;
+         int speexpreprocess=1;
+#endif// WANT_SPEEX
+
</ins><span class="cx"> /************************************************************************/
</span><span class="cx"> /******** Prototypes ****************************************************/
</span><span class="cx"> /************************************************************************/
</span><span class="cx">
</span><del>-static int blockingIOCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo * timeInfo,
- PaStreamCallbackFlags statusFlags, void *userData);
-static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames,
- long bytesPerFrame);
</del><ins>+static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+
+static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                                unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+
+static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame);
</ins><span class="cx"> static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf);
</span><span class="cx">
</span><span class="cx"> /************************************************************************/
</span><span class="lines">@@ -70,189 +82,208 @@
</span><span class="cx"> /* Called from PortAudio.
</span><span class="cx"> * Read and write data
</span><span class="cx"> */
</span><del>-static int blockingIOCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo * timeInfo,
- PaStreamCallbackFlags statusFlags, void *userData)
</del><ins>+static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
</ins><span class="cx"> {
</span><del>- PABLIO_Stream *data = (PABLIO_Stream *) userData;
- long numBytes = data->bytesPerFrame * framesPerBuffer;
- char c = 'M';
</del><ins>+        PABLIO_Stream *data = (PABLIO_Stream *) userData;
+        long numBytes = data->bytesPerFrame * framesPerBuffer;
</ins><span class="cx"> #ifdef WANT_SPEEX
</span><del>- spx_int16_t *in;
- spx_int16_t *out;
- unsigned int i = 0;
-#ifndef GIOVA48
</del><ins>+ spx_int16_t *speexptr=NULL;
</ins><span class="cx"> spx_int16_t pcm2[160];
</span><del>-#else //GIOVA48
- spx_int16_t pcm2[960];
-#endif //GIOVA48
-#endif // WANT_SPEEX
</del><ins>+ int i;
+#endif// WANT_SPEEX
</ins><span class="cx">
</span><del>- /* This may get called with NULL inputBuffer during initial setup. */
- if (inputBuffer == NULL) {
- fprintf(stderr, "INPUT NULL\n\n\n\n");
- return 0;
- }
- if (outputBuffer == NULL) {
- fprintf(stderr, "OUTPUT NULL\n\n\n\n");
- return 0;
- }
-
</del><ins>+        /* This may get called with NULL inputBuffer during initial setup. */
+        if (inputBuffer != NULL) {
</ins><span class="cx"> #ifdef WANT_SPEEX
</span><del>- in = ((spx_int16_t *) inputBuffer);
- out = ((spx_int16_t *) outputBuffer);
-#endif // WANT_SPEEX
</del><ins>+        //FIXME speex_echo_cancellation(echo_state, inputBuffer, outputBuffer, pcm2);
+        //FIXME speexptr=(spx_int16_t *)inputBuffer;
+ //FIXME for (i = 0; i < 160; i++)
+ //FIXME speexptr[i] = pcm2[i];
+ //FIXME speex_preprocess_run(preprocess, speexptr);
+#if 1
+ if (speexecho) {
+ speexptr = ((spx_int16_t *) inputBuffer);
</ins><span class="cx">
</span><del>-/****************
- * THIS IS SPK (RX data from network)
- ****************/
- if (outputBuffer != NULL) {
- int i;
- int numRead = PaUtil_ReadRingBuffer(&data->outFIFO, outputBuffer, numBytes);
- /* Zero out remainder of buffer if we run out of data. */
- for (i = numRead; i < numBytes; i++) {
- ((char *) outputBuffer)[i] = 0;
- }
- }
-#ifdef WANT_SPEEX
- if (*data->speexecho && *(long *) data->owner) {
- /* Put frame into playback buffer */
- speex_echo_playback(data->echo_state, out);
- }
- if (*data->speexecho && *(long *) data->owner) {
</del><span class="cx"> /* Perform echo cancellation */
</span><del>- speex_echo_capture(data->echo_state, in, pcm2);
</del><ins>+ speex_echo_capture(echo_state, speexptr, pcm2);
</ins><span class="cx"> #ifndef GIOVA48
</span><span class="cx"> for (i = 0; i < 160; i++)
</span><span class="cx"> #else //GIOVA48
</span><span class="cx"> for (i = 0; i < 960; i++)
</span><span class="cx"> #endif //GIOVA48
</span><del>- in[i] = pcm2[i];
</del><ins>+ speexptr[i] = pcm2[i];
+ //printf("read\n");
</ins><span class="cx"> }
</span><ins>+ if (speexpreprocess) {
+ speex_preprocess_run(preprocess, speexptr);
+ }
</ins><span class="cx"> /* Apply noise/echo residual suppression */
</span><del>- if (*data->speexpreprocess && *(long *) data->owner) {
- speex_preprocess_run(data->preprocess, in);
</del><ins>+#endif
+#endif //WANT_SPEEX
+
+
+                if (PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes) != numBytes) {
+                        PaUtil_FlushRingBuffer(&data->inFIFO);
+                        PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes);
+ printf("HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                }
+        }
+
+        return 0;
+}
+
+static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
+{
+        PABLIO_Stream *data = (PABLIO_Stream *) userData;
+        long numBytes = data->bytesPerFrame * framesPerBuffer;
+#ifdef WANT_SPEEX
+ spx_int16_t *speexptr=NULL;
+ //spx_int16_t pcm2[160];
+ //int i;
+#endif// WANT_SPEEX
+
+
+        if (outputBuffer != NULL) {
+                int i;
+                int numRead = PaUtil_ReadRingBuffer(&data->outFIFO, outputBuffer, numBytes);
+                /* Zero out remainder of buffer if we run out of data. */
+                for (i = numRead; i < numBytes; i++) {
+                        ((char *) outputBuffer)[i] = 0;
+                }
+
+                if(numRead == 0){
+                        //printf("ZERO\n");
+                        //usleep(60000);
+                //speex_echo_state_reset(echo_state);
+                }
+#ifdef WANT_SPEEX
+ //FIXME speexptr = (spx_int16_t *) outputBuffer;
+ //FIXME speex_preprocess_run(preprocess2, speexptr);
+#if 1
+ if (speexecho ) {
+ speexptr = (spx_int16_t *) outputBuffer;
+ if (speexpreprocess && numRead) {
+ //speex_preprocess_run(preprocess2, speexptr);
</ins><span class="cx"> }
</span><del>-#endif // WANT_SPEEX
</del><span class="cx">
</span><del>-/***************
- * THIS IS MIC (TX data to network)
- ***************/
- /* This may get called with NULL inputBuffer during initial setup. */
- if (inputBuffer != NULL) {
- if (PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes) != numBytes) {
- PaUtil_FlushRingBuffer(&data->inFIFO);
- PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes);
- }
</del><ins>+
+
+ /* Put frame into playback buffer */
+ speex_echo_playback(echo_state, speexptr);
+ //printf("write\n");
</ins><span class="cx"> }
</span><del>- write(data->audioreadpipe, &c, 1);
- return 0;
</del><ins>+
+#endif
+#endif //WANT_SPEEX
+
+
+        }
+
+        return 0;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
+{
+
+
+//write
+        oblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
+//read
+        iblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
+
+        return 0;
+}
+
</ins><span class="cx"> /* Allocate buffer. */
</span><del>-static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames,
- long bytesPerFrame)
</del><ins>+static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame)
</ins><span class="cx"> {
</span><del>- long numBytes = numFrames * bytesPerFrame;
- char *buffer = (char *) malloc(numBytes);
- if (buffer == NULL)
- return paInsufficientMemory;
- memset(buffer, 0, numBytes);
- return (PaError) PaUtil_InitializeRingBuffer(rbuf, numBytes, buffer);
</del><ins>+        long numBytes = numFrames * bytesPerFrame;
+        char *buffer = (char *) malloc(numBytes);
+        if (buffer == NULL)
+                return paInsufficientMemory;
+        memset(buffer, 0, numBytes);
+        return (PaError) PaUtil_InitializeRingBuffer(rbuf, numBytes, buffer);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* Free buffer. */
</span><span class="cx"> static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf)
</span><span class="cx"> {
</span><del>- if (rbuf->buffer)
- free(rbuf->buffer);
- rbuf->buffer = NULL;
- return paNoError;
</del><ins>+        if (rbuf->buffer)
+                free(rbuf->buffer);
+        rbuf->buffer = NULL;
+        return paNoError;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Write data to ring buffer.
</span><span class="cx"> * Will not return until all the data has been written.
</span><span class="cx"> */
</span><del>-long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
</del><ins>+long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer)
</ins><span class="cx"> {
</span><del>- long bytesWritten;
- char *p = (char *) data;
- long numBytes = aStream->bytesPerFrame * numFrames;
- int tried = 0;
</del><ins>+        long bytesWritten;
+        char *p = (char *) data;
+        long numBytes = aStream->bytesPerFrame * numFrames;
</ins><span class="cx">
</span><del>- //printf("numBytes=%d, aStream->bytesPerFrame=%d, numFrames=%d\n", numBytes, aStream->bytesPerFrame, numFrames);
-
- while (numBytes > 0) {
- bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFO, p, numBytes);
- numBytes -= bytesWritten;
- p += bytesWritten;
- if (numBytes > 0 && tried == 10) {
- PaUtil_FlushRingBuffer(&aStream->outFIFO);
- fprintf(stderr, "=========================>FLUSH tried: %d, numBytes: %ld, bytesWritten: %lu\n\n\n", tried, numBytes, bytesWritten);
- tried = 0;
-#ifdef WANT_SPEEX
- speex_echo_state_reset(aStream->echo_state);
-#endif// WANT_SPEEX
- }
- if (tried) {
- fprintf(stderr, "============>FLUSHINO tried: %d, numBytes: %ld, bytesWritten: %lu\n\n\n", tried, numBytes, bytesWritten);
- //usleep(1000 * 2 * tried);
- //usleep( (1000*tried > 4000) ? 4000 : 1000*tried);
- usleep(2000);
- }
- tried++;
- }
- return numFrames;
</del><ins>+        switch_core_timer_next(timer);
+
+        bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFO, p, numBytes);
+        numBytes -= bytesWritten;
+        p += bytesWritten;
+        
+        if (numBytes > 0) {
+                PaUtil_FlushRingBuffer(&aStream->outFIFO);
+ printf("2HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                return 0;
+        }
+        return numFrames;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Read data from ring buffer.
</span><ins>+ * Will not return until all the data has been read.
</ins><span class="cx"> */
</span><del>-long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
</del><ins>+long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer)
</ins><span class="cx"> {
</span><del>- long bytesRead;
- char *p = (char *) data;
- long numBytes = aStream->bytesPerFrame * numFrames;
- int tried = 0;
- long avail;
</del><ins>+        long bytesRead = 0;
+        char *p = (char *) data;
+        long avail, totalBytes = 0, neededBytes = aStream->bytesPerFrame * numFrames;
+        int max = 5000;
</ins><span class="cx">
</span><del>- avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
</del><ins>+        switch_core_timer_next(timer);
</ins><span class="cx">
</span><del>- if (avail < numBytes) {
- //fprintf(stderr, "<<<<<<<<<<<<<<<< avail: %ld, numBytes: %ld\n\n", avail, numBytes);
- usleep(5000);
- return 0;
- }
-#if 1
- if (avail >= numBytes * 7) {
- PaUtil_FlushRingBuffer(&aStream->inFIFO);
- fprintf(stderr, ">>>>>>>>>>>>>>>> avail: %ld, numBytes*7: %ld\n\n", avail,
- numBytes * 7);
- return 0;
- }
-#endif
</del><ins>+        while(totalBytes < neededBytes && --max > 0) {
</ins><span class="cx">
</span><del>- while (numBytes > 0) {
- bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFO, p, numBytes);
- numBytes -= bytesRead;
- if (numBytes > 0 && tried == 3) {
- PaUtil_FlushRingBuffer(&aStream->inFIFO);
- fprintf(stderr, "=========================>FLUSH2\n\n\n");
- usleep(2000);
- tried = 0;
- return 0;
- }
- if (tried) {
- fprintf(stderr,
- "============>FLUSHINO 2 tried: %d, numBytes: %ld, bytesRead: %lu\n\n\n",
- tried, numBytes, bytesRead);
- usleep(2000);
- }
- tried++;
- }
- return numFrames;
</del><ins>+                avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
+                //printf("AVAILABLE BYTES %ld , neededBytes %ld, pass %d\n", avail, neededBytes, 5000 - max);
+                if (avail >= neededBytes * 6) {
+                        PaUtil_FlushRingBuffer(&aStream->inFIFO);
+ printf("3HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                        avail = 0;
+                } else {
+
+                        bytesRead = 0;
+                        
+                        if (totalBytes < neededBytes && avail >= neededBytes) {
+                                bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFO, p, neededBytes);
+                                totalBytes += bytesRead;
+                        }
+
+                        if (bytesRead) {
+                                p += bytesRead;
+                        } else {
+                                switch_cond_next();
+                        }
+                }
+        }
+
+                //printf("return=%ld\n", totalBytes / aStream->bytesPerFrame);
+        return totalBytes / aStream->bytesPerFrame;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="lines">@@ -261,8 +292,8 @@
</span><span class="cx"> */
</span><span class="cx"> long GetAudioStreamWriteable(PABLIO_Stream * aStream)
</span><span class="cx"> {
</span><del>- int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- return bytesEmpty / aStream->bytesPerFrame;
</del><ins>+        int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+        return bytesEmpty / aStream->bytesPerFrame;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="lines">@@ -271,221 +302,419 @@
</span><span class="cx"> */
</span><span class="cx"> long GetAudioStreamReadable(PABLIO_Stream * aStream)
</span><span class="cx"> {
</span><del>- int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
- return bytesFull / aStream->bytesPerFrame;
</del><ins>+        int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
+        return bytesFull / aStream->bytesPerFrame;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /***********************************************************/
</span><span class="cx"> static unsigned long RoundUpToNextPowerOf2(unsigned long n)
</span><span class="cx"> {
</span><del>- long numBits = 0;
- if (((n - 1) & n) == 0)
- return n;
- while (n > 0) {
- n = n >> 1;
- numBits++;
- }
- return (1 << numBits);
</del><ins>+        long numBits = 0;
+        if (((n - 1) & n) == 0)
+                return n;
+        while (n > 0) {
+                n = n >> 1;
+                numBits++;
+        }
+        return (1 << numBits);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+
+
</ins><span class="cx"> /************************************************************
</span><span class="cx"> * Opens a PortAudio stream with default characteristics.
</span><span class="cx"> * Allocates PABLIO_Stream structure.
</span><span class="cx"> *
</span><span class="cx"> */
</span><span class="cx"> PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
</span><del>- const PaStreamParameters * inputParameters,
- const PaStreamParameters * outputParameters, double sampleRate,
- PaStreamFlags streamFlags, long samples_per_frame,
- int audioreadpipe, int *speexecho,
- int *speexpreprocess, void *owner)
</del><ins>+                                                const PaStreamParameters * inputParameters,
+                                                const PaStreamParameters * outputParameters,
+                                                double sampleRate, PaStreamFlags streamFlags,
+                                                long samples_per_packet,
+                                                int do_dual)
</ins><span class="cx"> {
</span><del>- long bytesPerSample = 2;
- PaError err;
- PABLIO_Stream *aStream;
- long numFrames;
- //long numBytes;
- int channels = 1;
- short tmp;
- //float level;
- int ciapa;
</del><ins>+        long bytesPerSample = 2;
+        PaError err;
+        PABLIO_Stream *aStream;
+        long numFrames;
+        //long numBytes;
+        int channels = 1;
+#ifdef WANT_SPEEX
+        int ciapa;
+        float level;
+        int tmp;
+#endif //WANT_SPEEX
</ins><span class="cx">
</span><del>- /* Allocate PABLIO_Stream structure for caller. */
- aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
- if (aStream == NULL)
- return paInsufficientMemory;
- memset(aStream, 0, sizeof(PABLIO_Stream));
</del><span class="cx">
</span><del>- /* Initialize PortAudio */
- err = Pa_Initialize();
- if (err != paNoError)
- goto error;
</del><ins>+        if (!(inputParameters || outputParameters)) {
+                return -1;
+        }
</ins><span class="cx">
</span><del>- if (inputParameters) {
- channels = inputParameters->channelCount;
- } else if (outputParameters) {
- channels = outputParameters->channelCount;
- }
</del><ins>+        /* Allocate PABLIO_Stream structure for caller. */
+        aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
+        switch_assert(aStream);
+        memset(aStream, 0, sizeof(PABLIO_Stream));
+        
+        if (inputParameters) {
+                channels = inputParameters->channelCount;
+        } else if (outputParameters) {
+                channels = outputParameters->channelCount;
+        }
</ins><span class="cx">
</span><del>- numFrames = RoundUpToNextPowerOf2(samples_per_frame * 5);
- aStream->bytesPerFrame = bytesPerSample;
</del><ins>+        numFrames = RoundUpToNextPowerOf2(samples_per_packet * 5);
+        aStream->bytesPerFrame = bytesPerSample;
</ins><span class="cx">
</span><del>- /* Initialize Ring Buffers */
</del><ins>+        /* Initialize Ring Buffers */
</ins><span class="cx">
</span><del>- if (inputParameters) {
- err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
- if (err != paNoError)
- goto error;
- }
</del><ins>+        if (inputParameters) {
+                err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
+                if (err != paNoError) {
+                        goto error;
+                }
+                aStream-> has_in = 1;
+        }
</ins><span class="cx">
</span><del>- if (outputParameters) {
- err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
- if (err != paNoError)
- goto error;
- }
-
- /* Make Write FIFO appear full initially. */
- //numBytes = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- //PaUtil_AdvanceRingBufferWriteIndex(&aStream->outFIFO, numBytes);
-
</del><ins>+        if (outputParameters) {
+                err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
+                if (err != paNoError) {
+                        goto error;
+                }
+                aStream-> has_out = 1;
+        }
</ins><span class="cx"> #ifdef WANT_SPEEX
</span><del>- /* Echo canceller with 200 ms tail length */
</del><ins>+ /* Echo canceller with 100 ms tail length */
</ins><span class="cx"> #ifndef GIOVA48
</span><del>- aStream->echo_state = speex_echo_state_init(160, 1024);
</del><ins>+ echo_state = speex_echo_state_init(160, 1600);
</ins><span class="cx"> ciapa = 8000;
</span><span class="cx"> #else// GIOVA48
</span><del>- aStream->echo_state = speex_echo_state_init(960, 1024);
</del><ins>+ echo_state = speex_echo_state_init(960, 4800);
</ins><span class="cx"> ciapa = 48000;
</span><span class="cx"> #endif // GIOVA48
</span><del>- speex_echo_ctl(aStream->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &ciapa);
</del><ins>+ speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &ciapa);
</ins><span class="cx">
</span><ins>+#if 1 //NO MORE
</ins><span class="cx"> /* Setup preprocessor and associate with echo canceller for residual echo suppression */
</span><span class="cx"> #ifndef GIOVA48
</span><del>- aStream->preprocess = speex_preprocess_state_init(160, 8000);
</del><ins>+ preprocess = speex_preprocess_state_init(160, 8000);
</ins><span class="cx"> #else// GIOVA48
</span><del>- aStream->preprocess = speex_preprocess_state_init(960, 48000);
</del><ins>+ preprocess = speex_preprocess_state_init(960, 48000);
</ins><span class="cx"> #endif // GIOVA48
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
- aStream->echo_state);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
+ echo_state);
</ins><span class="cx">
</span><ins>+#if 0
</ins><span class="cx"> /* Setup preprocessor various other goodies */
</span><del>- tmp = 0;
- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_AGC, &tmp);
- //level=8000.1;
- //speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_AGC_LEVEL, &level);
</del><ins>+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC, &tmp);
+ level=8000.1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_LEVEL, &level);
</ins><span class="cx">
</span><ins>+ tmp = 8000;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_TARGET, &tmp);
+
+ //FIXME tmp = 60;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ //FIXME tmp = 40;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ //FIXME tmp = -40;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
</ins><span class="cx"> // Let's turn off all of the 'denoisers' (eg denoise and dereverb, and vad too) because they start automatic gain on mic input on cm108 usb, also if it (the agc on usb) disbled through mixer
</span><span class="cx"> tmp = 0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</ins><span class="cx"> tmp = 0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
</ins><span class="cx"> tmp = 0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_VAD, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_VAD, &tmp);
+#endif
</ins><span class="cx">
</span><del>-#if 0
</del><ins>+ //tmp = 0;
+ //speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</ins><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC, &tmp);
</del><ins>+#endif //0
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC, &tmp);
</ins><span class="cx"> fprintf(stderr, "AGC is: %d\n", tmp);
</span><span class="cx"> level = 1.0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
</ins><span class="cx"> fprintf(stderr, "AGC_LEVEL is: %f\n", level);
</span><span class="cx"> //tmp=1;
</span><del>- //speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
</del><ins>+ //speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
</ins><span class="cx"> //fprintf( stderr, "AGC_TARGET is: %d\n", tmp );
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
</ins><span class="cx"> fprintf(stderr, "DENOISE is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
</ins><span class="cx"> fprintf(stderr, "DEREVERB is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_VAD, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_VAD, &tmp);
</ins><span class="cx"> fprintf(stderr, "VAD is: %d\n", tmp);
</span><ins>+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_NOISE_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
+ &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_START is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_CONTINUE is: %d\n", tmp);
+#endif //0
+#endif// 0 //NO MORE
</ins><span class="cx">
</span><ins>+
+
+
+
+
+
+
+
+#if 1 //NO MORE
+ /* Setup preprocessor and associate with echo canceller for residual echo suppression */
+#ifndef GIOVA48
+ preprocess2 = speex_preprocess_state_init(160, 8000);
+#else// GIOVA48
+ preprocess = speex_preprocess_state_init(960, 48000);
+#endif // GIOVA48
+
+ /* Setup preprocessor various other goodies */
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC, &tmp);
+
+ tmp = 24000;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_TARGET, &tmp);
+
+ //tmp = 60;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &tmp);
+ tmp = 40;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &tmp);
+ tmp = -40;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &tmp);
+
+#if 0
+ // Let's turn off all of the 'denoisers' (eg denoise and dereverb, and vad too) because they start automatic gain on mic input on cm108 usb, also if it (the agc on usb) disbled through mixer
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_VAD, &tmp);
+#endif
+
+ //tmp = 0;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</ins><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC, &tmp);
+ fprintf(stderr, "AGC is: %d\n", tmp);
+ level = 1.0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
+ fprintf(stderr, "AGC_LEVEL is: %f\n", level);
+ //tmp=1;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
+ //fprintf( stderr, "AGC_TARGET is: %d\n", tmp );
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
+ fprintf(stderr, "DENOISE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
+ fprintf(stderr, "DEREVERB is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_VAD, &tmp);
+ fprintf(stderr, "VAD is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_NOISE_SUPPRESS is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
</ins><span class="cx"> &tmp);
</span><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_START is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_CONTINUE is: %d\n", tmp);
</span><span class="cx"> #endif //0
</span><ins>+#endif// 0 //NO MORE
</ins><span class="cx">
</span><del>- sleep(1);
</del><ins>+
+
+
</ins><span class="cx"> #endif // WANT_SPEEX
</span><span class="cx">
</span><del>- aStream->audioreadpipe = audioreadpipe;
- aStream->speexecho = speexecho;
- aStream->speexpreprocess = speexpreprocess;
- aStream->owner = owner;
</del><span class="cx">
</span><del>- /* Open a PortAudio stream that we will use to communicate with the underlying
- * audio drivers. */
- err =
- Pa_OpenStream(&aStream->stream, inputParameters, outputParameters, sampleRate,
- samples_per_frame, streamFlags, blockingIOCallback, aStream);
</del><ins>+        /* Open a PortAudio stream that we will use to communicate with the underlying
+         * audio drivers. */
</ins><span class="cx">
</span><del>- if (err != paNoError)
- goto error;
</del><ins>+        aStream->do_dual = do_dual;        
</ins><span class="cx">
</span><del>- err = Pa_StartStream(aStream->stream);
</del><ins>+        if (aStream->do_dual) {
+                err = Pa_OpenStream(&aStream->istream, inputParameters, NULL, sampleRate, samples_per_packet, streamFlags, iblockingIOCallback, aStream);
+                if (err != paNoError) {
+                        goto error;
+                }
+                err = Pa_OpenStream(&aStream->ostream, NULL, outputParameters, sampleRate, samples_per_packet, streamFlags, oblockingIOCallback, aStream);
+                if (err != paNoError) {
+                        goto error;
+                }
+        } else {
+                err = Pa_OpenStream(&aStream->iostream, inputParameters, outputParameters, sampleRate, samples_per_packet, streamFlags, ioblockingIOCallback, aStream);
+        }
</ins><span class="cx">
</span><del>- if (err != paNoError)
- goto error;
- *rwblPtr = aStream;
- return paNoError;
</del><ins>+        if (err != paNoError) {
+                goto error;
+        }
+        
+        if (aStream->do_dual) {
+                err = Pa_StartStream(aStream->istream);
+                
+                if (err != paNoError) {
+                        goto error;
+                }
</ins><span class="cx">
</span><del>-error:
- CloseAudioStream(aStream);
- *rwblPtr = NULL;
- return err;
</del><ins>+                err = Pa_StartStream(aStream->ostream);
+
+                if (err != paNoError) {
+                        goto error;
+                }
+
+        } else {
+                err = Pa_StartStream(aStream->iostream);
+        }
+
+        if (err != paNoError) {
+                goto error;
+        }
+
+        *rwblPtr = aStream;
+
+        //switch_yield(500000);
+        
+        return paNoError;
+
+ error:
+
+        CloseAudioStream(aStream);
+
+        *rwblPtr = NULL;
+        return err;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************/
</span><span class="cx"> PaError CloseAudioStream(PABLIO_Stream * aStream)
</span><span class="cx"> {
</span><del>- PaError err;
- int bytesEmpty;
- int byteSize = aStream->outFIFO.bufferSize;
</del><ins>+        int bytesEmpty;
+        int byteSize;
</ins><span class="cx">
</span><del>- /* If we are writing data, make sure we play everything written. */
- if (byteSize > 0) {
- bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- while (bytesEmpty < byteSize) {
- Pa_Sleep(10);
- bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- }
- }
</del><ins>+        
+        byteSize = aStream->outFIFO.bufferSize;
</ins><span class="cx">
</span><del>- err = Pa_StopStream(aStream->stream);
- if (err != paNoError)
- goto error;
- err = Pa_CloseStream(aStream->stream);
- if (err != paNoError)
- goto error;
- Pa_Terminate();
</del><ins>+        if (aStream->has_out) {
+                /* If we are writing data, make sure we play everything written. */
+                if (byteSize > 0) {
+                        bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+                        while (bytesEmpty < byteSize) {
+                                Pa_Sleep(10);
+                                bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+                        }
+                }
+        }
</ins><span class="cx">
</span><del>-error:
- PABLIO_TermFIFO(&aStream->inFIFO);
- PABLIO_TermFIFO(&aStream->outFIFO);
- free(aStream);
- return err;
</del><ins>+        if (aStream->do_dual) {
+                if (aStream->has_in && aStream->istream) {
+                        if (Pa_IsStreamActive(aStream->istream)) {
+                                Pa_StopStream(aStream->istream);
+                        }
+
+                        Pa_CloseStream(aStream->istream);
+                        aStream->istream = NULL;
+                }
+                
+                if (aStream->has_out && aStream->ostream) {
+                        if (Pa_IsStreamActive(aStream->ostream)) {
+                                Pa_StopStream(aStream->ostream);
+                        }
+
+                        Pa_CloseStream(aStream->ostream);
+                        aStream->ostream = NULL;
+                }
+                
+        } else {
+                if (aStream->iostream) {
+                        if (Pa_IsStreamActive(aStream->iostream)) {
+                                Pa_StopStream(aStream->iostream);
+                        }
+
+                        Pa_CloseStream(aStream->iostream);
+                        aStream->iostream = NULL;
+                }
+        }
+
+        if (aStream->has_in) {        
+                PABLIO_TermFIFO(&aStream->inFIFO);
+        }
+        
+        if (aStream->has_out) {
+                PABLIO_TermFIFO(&aStream->outFIFO);
+        }
+
+        free(aStream);
+        //switch_yield(500000);
+
+        return paNoError;
</ins><span class="cx"> }
</span><ins>+
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenpablioh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.h (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.h        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/pablio.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -1,10 +1,9 @@
</span><del>-#define WANT_SPEEX
</del><span class="cx"> #ifndef _PABLIO_H
</span><span class="cx"> #define _PABLIO_H
</span><span class="cx">
</span><span class="cx"> #ifdef __cplusplus
</span><span class="cx"> extern "C" {
</span><del>-#endif /* __cplusplus */
</del><ins>+#endif                                                        /* __cplusplus */
</ins><span class="cx">
</span><span class="cx"> /*
</span><span class="cx"> * $Id: pablio.h 1083 2006-08-23 07:30:49Z rossb $
</span><span class="lines">@@ -49,42 +48,25 @@
</span><span class="cx"> * license above.
</span><span class="cx"> */
</span><span class="cx">
</span><del>-#undef WANT_OSLEC
-
</del><span class="cx"> #include <stdio.h>
</span><span class="cx"> #include <stdlib.h>
</span><span class="cx"> #include <math.h>
</span><del>-#include <unistd.h>
-#include <string.h>
</del><span class="cx"> #include "pa_ringbuffer.h"
</span><span class="cx"> #include "portaudio.h"
</span><del>-#ifdef WANT_SPEEX
-#include "speex/speex_preprocess.h"
-#include "speex/speex_echo.h"
-#endif /* WANT_SPEEX */
-#ifdef WANT_OSLEC
-#include "spandsp/echo.h"
-#endif /* WANT_OSLEC */
</del><span class="cx">
</span><span class="cx"> #include <string.h>
</span><span class="cx">
</span><del>- typedef struct {
- PaUtilRingBuffer inFIFO;
- PaUtilRingBuffer outFIFO;
- PaStream *stream;
- int bytesPerFrame;
-#ifdef WANT_SPEEX
- SpeexPreprocessState *preprocess;
- SpeexEchoState *echo_state;
-#endif /* WANT_SPEEX */
-#ifdef WANT_OSLEC
- echo_can_state_t *ec;
-#endif /* WANT_OSLEC */
- int audioreadpipe;
- int *speexecho;
- int *speexpreprocess;
- void *owner;
- } PABLIO_Stream;
</del><ins>+        typedef struct {
+                PaUtilRingBuffer inFIFO;
+                PaUtilRingBuffer outFIFO;
+                PaStream *istream;
+                PaStream *ostream;
+                PaStream *iostream;
+                int bytesPerFrame;
+                int do_dual;
+                int has_in;
+                int has_out;
+        } PABLIO_Stream;
</ins><span class="cx">
</span><span class="cx"> /* Values for flags for OpenAudioStream(). */
</span><span class="cx"> #define PABLIO_READ (1<<0)
</span><span class="lines">@@ -97,27 +79,25 @@
</span><span class="cx"> * Write data to ring buffer.
</span><span class="cx"> * Will not return until all the data has been written.
</span><span class="cx"> */
</span><del>- //long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
- long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames);
</del><ins>+        long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Read data from ring buffer.
</span><span class="cx"> * Will not return until all the data has been read.
</span><span class="cx"> */
</span><del>- //long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
- long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames);
</del><ins>+        long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Return the number of frames that could be written to the stream without
</span><span class="cx"> * having to wait.
</span><span class="cx"> */
</span><del>- long GetAudioStreamWriteable(PABLIO_Stream * aStream);
</del><ins>+        long GetAudioStreamWriteable(PABLIO_Stream * aStream);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Return the number of frames that are available to be read from the
</span><span class="cx"> * stream without having to wait.
</span><span class="cx"> */
</span><del>- long GetAudioStreamReadable(PABLIO_Stream * aStream);
</del><ins>+        long GetAudioStreamReadable(PABLIO_Stream * aStream);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Opens a PortAudio stream with default characteristics.
</span><span class="lines">@@ -127,16 +107,14 @@
</span><span class="cx"> * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
</span><span class="cx"> * and either PABLIO_MONO or PABLIO_STEREO
</span><span class="cx"> */
</span><del>- PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
- const PaStreamParameters * inputParameters,
- const PaStreamParameters * outputParameters, double sampleRate,
- PaStreamCallbackFlags statusFlags, long samples_per_frame,
- int audioreadpipe, int *speexecho,
- int *speexpreprocess, void *owner);
</del><ins>+        PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
+                                                        const PaStreamParameters * inputParameters,
+                                                        const PaStreamParameters * outputParameters,
+                                                        double sampleRate, PaStreamCallbackFlags statusFlags, long samples_per_packet, int do_dual);
</ins><span class="cx">
</span><del>- PaError CloseAudioStream(PABLIO_Stream * aStream);
</del><ins>+        PaError CloseAudioStream(PABLIO_Stream * aStream);
</ins><span class="cx">
</span><span class="cx"> #ifdef __cplusplus
</span><span class="cx"> }
</span><del>-#endif /* __cplusplus */
-#endif /* _PABLIO_H */
</del><ins>+#endif                                                        /* __cplusplus */
+#endif                                                        /* _PABLIO_H */
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_gsmlib_cplusplus_noalsamod_gsmopenusbcm1082txt"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/usb-cm-108-2.txt (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/usb-cm-108-2.txt         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_gsmlib_cplusplus_noalsa/mod_gsmopen/usb-cm-108-2.txt        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1,62 @@
</span><ins>+state.default {
+        control.1 {
+                comment.access 'read write'
+                comment.type BOOLEAN
+                comment.count 1
+                iface MIXER
+                name 'Mic Playback Switch'
+                value false
+        }
+        control.2 {
+                comment.access 'read write'
+                comment.type INTEGER
+                comment.count 1
+                comment.range '0 - 32'
+                iface MIXER
+                name 'Mic Playback Volume'
+                value 0
+        }
+        control.3 {
+                comment.access 'read write'
+                comment.type BOOLEAN
+                comment.count 1
+                iface MIXER
+                name 'Speaker Playback Switch'
+                value true
+        }
+        control.4 {
+                comment.access 'read write'
+                comment.type INTEGER
+                comment.count 2
+                comment.range '0 - 151'
+                iface MIXER
+                name 'Speaker Playback Volume'
+                value.0 6
+                value.1 6
+        }
+        control.5 {
+                comment.access 'read write'
+                comment.type BOOLEAN
+                comment.count 1
+                iface MIXER
+                name 'Mic Capture Switch'
+                value true
+        }
+        control.6 {
+                comment.access 'read write'
+                comment.type INTEGER
+                comment.count 1
+                comment.range '0 - 16'
+                iface MIXER
+                name 'Mic Capture Volume'
+                value 5
+        }
+        control.7 {
+                comment.access 'read write'
+                comment.type BOOLEAN
+                comment.count 1
+                iface MIXER
+                name 'Auto Gain Control'
+                value false
+        }
+}
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandspc"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.c
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.c
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopencelliax_spandsph"></a>
<div class="addfile"><h4>Added: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h (0 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h         (rev 0)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -0,0 +1 @@
</span><ins>+link ../../celliax_spandsp.h
</ins><span class="cx">\ No newline at end of file
</span><span class="cx">Property changes on: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/celliax_spandsp.h
</span><span class="cx">___________________________________________________________________
</span><span class="cx">Name: svn:special
</span><span class="cx"> + *
</span></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopenpablioc"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.c (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.c        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.c        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -39,9 +39,8 @@
</span><span class="cx"> * requested that these non-binding requests be included along with the
</span><span class="cx"> * license above.
</span><span class="cx"> */
</span><del>-
-#undef GIOVA48
-
</del><ins>+#define WANT_SPEEX
+#include <switch.h>
</ins><span class="cx"> #include <stdio.h>
</span><span class="cx"> #include <stdlib.h>
</span><span class="cx"> #include <math.h>
</span><span class="lines">@@ -50,17 +49,30 @@
</span><span class="cx"> #include "pablio.h"
</span><span class="cx"> #include <string.h>
</span><span class="cx"> #include <time.h>
</span><ins>+#ifdef WANT_SPEEX
+#include "speex/speex_preprocess.h"
+#include "speex/speex_echo.h"
+ SpeexPreprocessState *preprocess;
+ SpeexPreprocessState *preprocess2;
+ SpeexEchoState *echo_state;
</ins><span class="cx">
</span><ins>+         int speexecho=1;
+         int speexpreprocess=1;
+#endif// WANT_SPEEX
+
</ins><span class="cx"> /************************************************************************/
</span><span class="cx"> /******** Prototypes ****************************************************/
</span><span class="cx"> /************************************************************************/
</span><span class="cx">
</span><del>-static int blockingIOCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo * timeInfo,
- PaStreamCallbackFlags statusFlags, void *userData);
-static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames,
- long bytesPerFrame);
</del><ins>+static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+
+static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                                unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData);
+
+static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame);
</ins><span class="cx"> static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf);
</span><span class="cx">
</span><span class="cx"> /************************************************************************/
</span><span class="lines">@@ -70,189 +82,208 @@
</span><span class="cx"> /* Called from PortAudio.
</span><span class="cx"> * Read and write data
</span><span class="cx"> */
</span><del>-static int blockingIOCallback(const void *inputBuffer, void *outputBuffer,
- unsigned long framesPerBuffer,
- const PaStreamCallbackTimeInfo * timeInfo,
- PaStreamCallbackFlags statusFlags, void *userData)
</del><ins>+static int iblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
</ins><span class="cx"> {
</span><del>- PABLIO_Stream *data = (PABLIO_Stream *) userData;
- long numBytes = data->bytesPerFrame * framesPerBuffer;
- char c = 'M';
</del><ins>+        PABLIO_Stream *data = (PABLIO_Stream *) userData;
+        long numBytes = data->bytesPerFrame * framesPerBuffer;
</ins><span class="cx"> #ifdef WANT_SPEEX
</span><del>- spx_int16_t *in;
- spx_int16_t *out;
- unsigned int i = 0;
-#ifndef GIOVA48
</del><ins>+ spx_int16_t *speexptr=NULL;
</ins><span class="cx"> spx_int16_t pcm2[160];
</span><del>-#else //GIOVA48
- spx_int16_t pcm2[960];
-#endif //GIOVA48
-#endif // WANT_SPEEX
</del><ins>+ int i;
+#endif// WANT_SPEEX
</ins><span class="cx">
</span><del>- /* This may get called with NULL inputBuffer during initial setup. */
- if (inputBuffer == NULL) {
- fprintf(stderr, "INPUT NULL\n\n\n\n");
- return 0;
- }
- if (outputBuffer == NULL) {
- fprintf(stderr, "OUTPUT NULL\n\n\n\n");
- return 0;
- }
-
</del><ins>+        /* This may get called with NULL inputBuffer during initial setup. */
+        if (inputBuffer != NULL) {
</ins><span class="cx"> #ifdef WANT_SPEEX
</span><del>- in = ((spx_int16_t *) inputBuffer);
- out = ((spx_int16_t *) outputBuffer);
-#endif // WANT_SPEEX
</del><ins>+        //FIXME speex_echo_cancellation(echo_state, inputBuffer, outputBuffer, pcm2);
+        //FIXME speexptr=(spx_int16_t *)inputBuffer;
+ //FIXME for (i = 0; i < 160; i++)
+ //FIXME speexptr[i] = pcm2[i];
+ //FIXME speex_preprocess_run(preprocess, speexptr);
+#if 1
+ if (speexecho) {
+ speexptr = ((spx_int16_t *) inputBuffer);
</ins><span class="cx">
</span><del>-/****************
- * THIS IS SPK (RX data from network)
- ****************/
- if (outputBuffer != NULL) {
- int i;
- int numRead = PaUtil_ReadRingBuffer(&data->outFIFO, outputBuffer, numBytes);
- /* Zero out remainder of buffer if we run out of data. */
- for (i = numRead; i < numBytes; i++) {
- ((char *) outputBuffer)[i] = 0;
- }
- }
-#ifdef WANT_SPEEX
- if (*data->speexecho && *(long *) data->owner) {
- /* Put frame into playback buffer */
- speex_echo_playback(data->echo_state, out);
- }
- if (*data->speexecho && *(long *) data->owner) {
</del><span class="cx"> /* Perform echo cancellation */
</span><del>- speex_echo_capture(data->echo_state, in, pcm2);
</del><ins>+ speex_echo_capture(echo_state, speexptr, pcm2);
</ins><span class="cx"> #ifndef GIOVA48
</span><span class="cx"> for (i = 0; i < 160; i++)
</span><span class="cx"> #else //GIOVA48
</span><span class="cx"> for (i = 0; i < 960; i++)
</span><span class="cx"> #endif //GIOVA48
</span><del>- in[i] = pcm2[i];
</del><ins>+ speexptr[i] = pcm2[i];
+ //printf("read\n");
</ins><span class="cx"> }
</span><ins>+ if (speexpreprocess) {
+ speex_preprocess_run(preprocess, speexptr);
+ }
</ins><span class="cx"> /* Apply noise/echo residual suppression */
</span><del>- if (*data->speexpreprocess && *(long *) data->owner) {
- speex_preprocess_run(data->preprocess, in);
</del><ins>+#endif
+#endif //WANT_SPEEX
+
+
+                if (PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes) != numBytes) {
+                        PaUtil_FlushRingBuffer(&data->inFIFO);
+                        PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes);
+ printf("HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                }
+        }
+
+        return 0;
+}
+
+static int oblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
+{
+        PABLIO_Stream *data = (PABLIO_Stream *) userData;
+        long numBytes = data->bytesPerFrame * framesPerBuffer;
+#ifdef WANT_SPEEX
+ spx_int16_t *speexptr=NULL;
+ //spx_int16_t pcm2[160];
+ //int i;
+#endif// WANT_SPEEX
+
+
+        if (outputBuffer != NULL) {
+                int i;
+                int numRead = PaUtil_ReadRingBuffer(&data->outFIFO, outputBuffer, numBytes);
+                /* Zero out remainder of buffer if we run out of data. */
+                for (i = numRead; i < numBytes; i++) {
+                        ((char *) outputBuffer)[i] = 0;
+                }
+
+                if(numRead == 0){
+                        //printf("ZERO\n");
+                        //usleep(60000);
+                //speex_echo_state_reset(echo_state);
+                }
+#ifdef WANT_SPEEX
+ //FIXME speexptr = (spx_int16_t *) outputBuffer;
+ //FIXME speex_preprocess_run(preprocess2, speexptr);
+#if 1
+ if (speexecho ) {
+ speexptr = (spx_int16_t *) outputBuffer;
+ if (speexpreprocess && numRead) {
+ //speex_preprocess_run(preprocess2, speexptr);
</ins><span class="cx"> }
</span><del>-#endif // WANT_SPEEX
</del><span class="cx">
</span><del>-/***************
- * THIS IS MIC (TX data to network)
- ***************/
- /* This may get called with NULL inputBuffer during initial setup. */
- if (inputBuffer != NULL) {
- if (PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes) != numBytes) {
- PaUtil_FlushRingBuffer(&data->inFIFO);
- PaUtil_WriteRingBuffer(&data->inFIFO, inputBuffer, numBytes);
- }
</del><ins>+
+
+ /* Put frame into playback buffer */
+ speex_echo_playback(echo_state, speexptr);
+ //printf("write\n");
</ins><span class="cx"> }
</span><del>- write(data->audioreadpipe, &c, 1);
- return 0;
</del><ins>+
+#endif
+#endif //WANT_SPEEX
+
+
+        }
+
+        return 0;
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+static int ioblockingIOCallback(const void *inputBuffer, void *outputBuffer,
+                                                         unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo * timeInfo, PaStreamCallbackFlags statusFlags, void *userData)
+{
+
+
+//write
+        oblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
+//read
+        iblockingIOCallback(inputBuffer, outputBuffer, framesPerBuffer, timeInfo, statusFlags, userData);
+
+        return 0;
+}
+
</ins><span class="cx"> /* Allocate buffer. */
</span><del>-static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames,
- long bytesPerFrame)
</del><ins>+static PaError PABLIO_InitFIFO(PaUtilRingBuffer * rbuf, long numFrames, long bytesPerFrame)
</ins><span class="cx"> {
</span><del>- long numBytes = numFrames * bytesPerFrame;
- char *buffer = (char *) malloc(numBytes);
- if (buffer == NULL)
- return paInsufficientMemory;
- memset(buffer, 0, numBytes);
- return (PaError) PaUtil_InitializeRingBuffer(rbuf, numBytes, buffer);
</del><ins>+        long numBytes = numFrames * bytesPerFrame;
+        char *buffer = (char *) malloc(numBytes);
+        if (buffer == NULL)
+                return paInsufficientMemory;
+        memset(buffer, 0, numBytes);
+        return (PaError) PaUtil_InitializeRingBuffer(rbuf, numBytes, buffer);
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /* Free buffer. */
</span><span class="cx"> static PaError PABLIO_TermFIFO(PaUtilRingBuffer * rbuf)
</span><span class="cx"> {
</span><del>- if (rbuf->buffer)
- free(rbuf->buffer);
- rbuf->buffer = NULL;
- return paNoError;
</del><ins>+        if (rbuf->buffer)
+                free(rbuf->buffer);
+        rbuf->buffer = NULL;
+        return paNoError;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Write data to ring buffer.
</span><span class="cx"> * Will not return until all the data has been written.
</span><span class="cx"> */
</span><del>-long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
</del><ins>+long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer)
</ins><span class="cx"> {
</span><del>- long bytesWritten;
- char *p = (char *) data;
- long numBytes = aStream->bytesPerFrame * numFrames;
- int tried = 0;
</del><ins>+        long bytesWritten;
+        char *p = (char *) data;
+        long numBytes = aStream->bytesPerFrame * numFrames;
</ins><span class="cx">
</span><del>- //printf("numBytes=%d, aStream->bytesPerFrame=%d, numFrames=%d\n", numBytes, aStream->bytesPerFrame, numFrames);
-
- while (numBytes > 0) {
- bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFO, p, numBytes);
- numBytes -= bytesWritten;
- p += bytesWritten;
- if (numBytes > 0 && tried == 10) {
- PaUtil_FlushRingBuffer(&aStream->outFIFO);
- fprintf(stderr, "=========================>FLUSH tried: %d, numBytes: %ld, bytesWritten: %lu\n\n\n", tried, numBytes, bytesWritten);
- tried = 0;
-#ifdef WANT_SPEEX
- speex_echo_state_reset(aStream->echo_state);
-#endif// WANT_SPEEX
- }
- if (tried) {
- fprintf(stderr, "============>FLUSHINO tried: %d, numBytes: %ld, bytesWritten: %lu\n\n\n", tried, numBytes, bytesWritten);
- //usleep(1000 * 2 * tried);
- //usleep( (1000*tried > 4000) ? 4000 : 1000*tried);
- usleep(2000);
- }
- tried++;
- }
- return numFrames;
</del><ins>+        switch_core_timer_next(timer);
+
+        bytesWritten = PaUtil_WriteRingBuffer(&aStream->outFIFO, p, numBytes);
+        numBytes -= bytesWritten;
+        p += bytesWritten;
+        
+        if (numBytes > 0) {
+                PaUtil_FlushRingBuffer(&aStream->outFIFO);
+ printf("2HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                return 0;
+        }
+        return numFrames;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Read data from ring buffer.
</span><ins>+ * Will not return until all the data has been read.
</ins><span class="cx"> */
</span><del>-long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames)
</del><ins>+long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer)
</ins><span class="cx"> {
</span><del>- long bytesRead;
- char *p = (char *) data;
- long numBytes = aStream->bytesPerFrame * numFrames;
- int tried = 0;
- long avail;
</del><ins>+        long bytesRead = 0;
+        char *p = (char *) data;
+        long avail, totalBytes = 0, neededBytes = aStream->bytesPerFrame * numFrames;
+        int max = 5000;
</ins><span class="cx">
</span><del>- avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
</del><ins>+        switch_core_timer_next(timer);
</ins><span class="cx">
</span><del>- if (avail < numBytes) {
- //fprintf(stderr, "<<<<<<<<<<<<<<<< avail: %ld, numBytes: %ld\n\n", avail, numBytes);
- usleep(5000);
- return 0;
- }
-#if 1
- if (avail >= numBytes * 7) {
- PaUtil_FlushRingBuffer(&aStream->inFIFO);
- fprintf(stderr, ">>>>>>>>>>>>>>>> avail: %ld, numBytes*7: %ld\n\n", avail,
- numBytes * 7);
- return 0;
- }
-#endif
</del><ins>+        while(totalBytes < neededBytes && --max > 0) {
</ins><span class="cx">
</span><del>- while (numBytes > 0) {
- bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFO, p, numBytes);
- numBytes -= bytesRead;
- if (numBytes > 0 && tried == 3) {
- PaUtil_FlushRingBuffer(&aStream->inFIFO);
- fprintf(stderr, "=========================>FLUSH2\n\n\n");
- usleep(2000);
- tried = 0;
- return 0;
- }
- if (tried) {
- fprintf(stderr,
- "============>FLUSHINO 2 tried: %d, numBytes: %ld, bytesRead: %lu\n\n\n",
- tried, numBytes, bytesRead);
- usleep(2000);
- }
- tried++;
- }
- return numFrames;
</del><ins>+                avail = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
+                //printf("AVAILABLE BYTES %ld , neededBytes %ld, pass %d\n", avail, neededBytes, 5000 - max);
+                if (avail >= neededBytes * 6) {
+                        PaUtil_FlushRingBuffer(&aStream->inFIFO);
+ printf("3HEEEEEEEEEEEj\n");
+                speex_echo_state_reset(echo_state);
+                        avail = 0;
+                } else {
+
+                        bytesRead = 0;
+                        
+                        if (totalBytes < neededBytes && avail >= neededBytes) {
+                                bytesRead = PaUtil_ReadRingBuffer(&aStream->inFIFO, p, neededBytes);
+                                totalBytes += bytesRead;
+                        }
+
+                        if (bytesRead) {
+                                p += bytesRead;
+                        } else {
+                                switch_cond_next();
+                        }
+                }
+        }
+
+                //printf("return=%ld\n", totalBytes / aStream->bytesPerFrame);
+        return totalBytes / aStream->bytesPerFrame;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="lines">@@ -261,8 +292,8 @@
</span><span class="cx"> */
</span><span class="cx"> long GetAudioStreamWriteable(PABLIO_Stream * aStream)
</span><span class="cx"> {
</span><del>- int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- return bytesEmpty / aStream->bytesPerFrame;
</del><ins>+        int bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+        return bytesEmpty / aStream->bytesPerFrame;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="lines">@@ -271,221 +302,419 @@
</span><span class="cx"> */
</span><span class="cx"> long GetAudioStreamReadable(PABLIO_Stream * aStream)
</span><span class="cx"> {
</span><del>- int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
- return bytesFull / aStream->bytesPerFrame;
</del><ins>+        int bytesFull = PaUtil_GetRingBufferReadAvailable(&aStream->inFIFO);
+        return bytesFull / aStream->bytesPerFrame;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /***********************************************************/
</span><span class="cx"> static unsigned long RoundUpToNextPowerOf2(unsigned long n)
</span><span class="cx"> {
</span><del>- long numBits = 0;
- if (((n - 1) & n) == 0)
- return n;
- while (n > 0) {
- n = n >> 1;
- numBits++;
- }
- return (1 << numBits);
</del><ins>+        long numBits = 0;
+        if (((n - 1) & n) == 0)
+                return n;
+        while (n > 0) {
+                n = n >> 1;
+                numBits++;
+        }
+        return (1 << numBits);
</ins><span class="cx"> }
</span><span class="cx">
</span><ins>+
+
</ins><span class="cx"> /************************************************************
</span><span class="cx"> * Opens a PortAudio stream with default characteristics.
</span><span class="cx"> * Allocates PABLIO_Stream structure.
</span><span class="cx"> *
</span><span class="cx"> */
</span><span class="cx"> PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
</span><del>- const PaStreamParameters * inputParameters,
- const PaStreamParameters * outputParameters, double sampleRate,
- PaStreamFlags streamFlags, long samples_per_frame,
- int audioreadpipe, int *speexecho,
- int *speexpreprocess, void *owner)
</del><ins>+                                                const PaStreamParameters * inputParameters,
+                                                const PaStreamParameters * outputParameters,
+                                                double sampleRate, PaStreamFlags streamFlags,
+                                                long samples_per_packet,
+                                                int do_dual)
</ins><span class="cx"> {
</span><del>- long bytesPerSample = 2;
- PaError err;
- PABLIO_Stream *aStream;
- long numFrames;
- //long numBytes;
- int channels = 1;
- short tmp;
- //float level;
- int ciapa;
</del><ins>+        long bytesPerSample = 2;
+        PaError err;
+        PABLIO_Stream *aStream;
+        long numFrames;
+        //long numBytes;
+        int channels = 1;
+#ifdef WANT_SPEEX
+        int ciapa;
+        float level;
+        int tmp;
+#endif //WANT_SPEEX
</ins><span class="cx">
</span><del>- /* Allocate PABLIO_Stream structure for caller. */
- aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
- if (aStream == NULL)
- return paInsufficientMemory;
- memset(aStream, 0, sizeof(PABLIO_Stream));
</del><span class="cx">
</span><del>- /* Initialize PortAudio */
- err = Pa_Initialize();
- if (err != paNoError)
- goto error;
</del><ins>+        if (!(inputParameters || outputParameters)) {
+                return -1;
+        }
</ins><span class="cx">
</span><del>- if (inputParameters) {
- channels = inputParameters->channelCount;
- } else if (outputParameters) {
- channels = outputParameters->channelCount;
- }
</del><ins>+        /* Allocate PABLIO_Stream structure for caller. */
+        aStream = (PABLIO_Stream *) malloc(sizeof(PABLIO_Stream));
+        switch_assert(aStream);
+        memset(aStream, 0, sizeof(PABLIO_Stream));
+        
+        if (inputParameters) {
+                channels = inputParameters->channelCount;
+        } else if (outputParameters) {
+                channels = outputParameters->channelCount;
+        }
</ins><span class="cx">
</span><del>- numFrames = RoundUpToNextPowerOf2(samples_per_frame * 5);
- aStream->bytesPerFrame = bytesPerSample;
</del><ins>+        numFrames = RoundUpToNextPowerOf2(samples_per_packet * 5);
+        aStream->bytesPerFrame = bytesPerSample;
</ins><span class="cx">
</span><del>- /* Initialize Ring Buffers */
</del><ins>+        /* Initialize Ring Buffers */
</ins><span class="cx">
</span><del>- if (inputParameters) {
- err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
- if (err != paNoError)
- goto error;
- }
</del><ins>+        if (inputParameters) {
+                err = PABLIO_InitFIFO(&aStream->inFIFO, numFrames, aStream->bytesPerFrame);
+                if (err != paNoError) {
+                        goto error;
+                }
+                aStream-> has_in = 1;
+        }
</ins><span class="cx">
</span><del>- if (outputParameters) {
- err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
- if (err != paNoError)
- goto error;
- }
-
- /* Make Write FIFO appear full initially. */
- //numBytes = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- //PaUtil_AdvanceRingBufferWriteIndex(&aStream->outFIFO, numBytes);
-
</del><ins>+        if (outputParameters) {
+                err = PABLIO_InitFIFO(&aStream->outFIFO, numFrames, aStream->bytesPerFrame);
+                if (err != paNoError) {
+                        goto error;
+                }
+                aStream-> has_out = 1;
+        }
</ins><span class="cx"> #ifdef WANT_SPEEX
</span><del>- /* Echo canceller with 200 ms tail length */
</del><ins>+ /* Echo canceller with 100 ms tail length */
</ins><span class="cx"> #ifndef GIOVA48
</span><del>- aStream->echo_state = speex_echo_state_init(160, 1024);
</del><ins>+ echo_state = speex_echo_state_init(160, 1600);
</ins><span class="cx"> ciapa = 8000;
</span><span class="cx"> #else// GIOVA48
</span><del>- aStream->echo_state = speex_echo_state_init(960, 1024);
</del><ins>+ echo_state = speex_echo_state_init(960, 4800);
</ins><span class="cx"> ciapa = 48000;
</span><span class="cx"> #endif // GIOVA48
</span><del>- speex_echo_ctl(aStream->echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &ciapa);
</del><ins>+ speex_echo_ctl(echo_state, SPEEX_ECHO_SET_SAMPLING_RATE, &ciapa);
</ins><span class="cx">
</span><ins>+#if 1 //NO MORE
</ins><span class="cx"> /* Setup preprocessor and associate with echo canceller for residual echo suppression */
</span><span class="cx"> #ifndef GIOVA48
</span><del>- aStream->preprocess = speex_preprocess_state_init(160, 8000);
</del><ins>+ preprocess = speex_preprocess_state_init(160, 8000);
</ins><span class="cx"> #else// GIOVA48
</span><del>- aStream->preprocess = speex_preprocess_state_init(960, 48000);
</del><ins>+ preprocess = speex_preprocess_state_init(960, 48000);
</ins><span class="cx"> #endif // GIOVA48
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
- aStream->echo_state);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_ECHO_STATE,
+ echo_state);
</ins><span class="cx">
</span><ins>+#if 0
</ins><span class="cx"> /* Setup preprocessor various other goodies */
</span><del>- tmp = 0;
- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_AGC, &tmp);
- //level=8000.1;
- //speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_AGC_LEVEL, &level);
</del><ins>+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC, &tmp);
+ level=8000.1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_LEVEL, &level);
</ins><span class="cx">
</span><ins>+ tmp = 8000;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_TARGET, &tmp);
+
+ //FIXME tmp = 60;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ //FIXME tmp = 40;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ //FIXME tmp = -40;
+ //FIXME speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &tmp);
+ //FIXME fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
</ins><span class="cx"> // Let's turn off all of the 'denoisers' (eg denoise and dereverb, and vad too) because they start automatic gain on mic input on cm108 usb, also if it (the agc on usb) disbled through mixer
</span><span class="cx"> tmp = 0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</ins><span class="cx"> tmp = 0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
</ins><span class="cx"> tmp = 0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_SET_VAD, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_VAD, &tmp);
+#endif
</ins><span class="cx">
</span><del>-#if 0
</del><ins>+ //tmp = 0;
+ //speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</ins><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC, &tmp);
</del><ins>+#endif //0
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC, &tmp);
</ins><span class="cx"> fprintf(stderr, "AGC is: %d\n", tmp);
</span><span class="cx"> level = 1.0;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
</ins><span class="cx"> fprintf(stderr, "AGC_LEVEL is: %f\n", level);
</span><span class="cx"> //tmp=1;
</span><del>- //speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
</del><ins>+ //speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
</ins><span class="cx"> //fprintf( stderr, "AGC_TARGET is: %d\n", tmp );
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
</ins><span class="cx"> fprintf(stderr, "DENOISE is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
</ins><span class="cx"> fprintf(stderr, "DEREVERB is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_VAD, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_VAD, &tmp);
</ins><span class="cx"> fprintf(stderr, "VAD is: %d\n", tmp);
</span><ins>+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_NOISE_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
+ &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_START is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_CONTINUE is: %d\n", tmp);
+#endif //0
+#endif// 0 //NO MORE
</ins><span class="cx">
</span><ins>+
+
+
+
+
+
+
+
+#if 1 //NO MORE
+ /* Setup preprocessor and associate with echo canceller for residual echo suppression */
+#ifndef GIOVA48
+ preprocess2 = speex_preprocess_state_init(160, 8000);
+#else// GIOVA48
+ preprocess = speex_preprocess_state_init(960, 48000);
+#endif // GIOVA48
+
+ /* Setup preprocessor various other goodies */
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC, &tmp);
+
+ tmp = 24000;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_TARGET, &tmp);
+
+ //tmp = 60;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &tmp);
+ tmp = 40;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_INCREMENT, &tmp);
+ tmp = -40;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_AGC_DECREMENT, &tmp);
+
+#if 0
+ // Let's turn off all of the 'denoisers' (eg denoise and dereverb, and vad too) because they start automatic gain on mic input on cm108 usb, also if it (the agc on usb) disbled through mixer
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DEREVERB, &tmp);
+ tmp = 0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_VAD, &tmp);
+#endif
+
+ //tmp = 0;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
</ins><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC, &tmp);
+ fprintf(stderr, "AGC is: %d\n", tmp);
+ level = 1.0;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_LEVEL, &level);
+ fprintf(stderr, "AGC_LEVEL is: %f\n", level);
+ //tmp=1;
+ //speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_TARGET, &tmp);
+ //fprintf( stderr, "AGC_TARGET is: %d\n", tmp );
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_DENOISE, &tmp);
+ fprintf(stderr, "DENOISE is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_DEREVERB, &tmp);
+ fprintf(stderr, "DEREVERB is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_VAD, &tmp);
+ fprintf(stderr, "VAD is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
+ fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
+
+#if 0
+ tmp = 1;
+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_NOISE_SUPPRESS, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_NOISE_SUPPRESS is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE,
</ins><span class="cx"> &tmp);
</span><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_ECHO_SUPPRESS_ACTIVE is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_MAX_GAIN, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_MAX_GAIN is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_INCREMENT, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_INCREMENT is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_AGC_DECREMENT, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_AGC_DECREMENT is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_PROB_START, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_START is: %d\n", tmp);
</span><span class="cx"> tmp = 1;
</span><del>- speex_preprocess_ctl(aStream->preprocess, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
</del><ins>+ speex_preprocess_ctl(preprocess2, SPEEX_PREPROCESS_GET_PROB_CONTINUE, &tmp);
</ins><span class="cx"> fprintf(stderr, "SPEEX_PREPROCESS_GET_PROB_CONTINUE is: %d\n", tmp);
</span><span class="cx"> #endif //0
</span><ins>+#endif// 0 //NO MORE
</ins><span class="cx">
</span><del>- sleep(1);
</del><ins>+
+
+
</ins><span class="cx"> #endif // WANT_SPEEX
</span><span class="cx">
</span><del>- aStream->audioreadpipe = audioreadpipe;
- aStream->speexecho = speexecho;
- aStream->speexpreprocess = speexpreprocess;
- aStream->owner = owner;
</del><span class="cx">
</span><del>- /* Open a PortAudio stream that we will use to communicate with the underlying
- * audio drivers. */
- err =
- Pa_OpenStream(&aStream->stream, inputParameters, outputParameters, sampleRate,
- samples_per_frame, streamFlags, blockingIOCallback, aStream);
</del><ins>+        /* Open a PortAudio stream that we will use to communicate with the underlying
+         * audio drivers. */
</ins><span class="cx">
</span><del>- if (err != paNoError)
- goto error;
</del><ins>+        aStream->do_dual = do_dual;        
</ins><span class="cx">
</span><del>- err = Pa_StartStream(aStream->stream);
</del><ins>+        if (aStream->do_dual) {
+                err = Pa_OpenStream(&aStream->istream, inputParameters, NULL, sampleRate, samples_per_packet, streamFlags, iblockingIOCallback, aStream);
+                if (err != paNoError) {
+                        goto error;
+                }
+                err = Pa_OpenStream(&aStream->ostream, NULL, outputParameters, sampleRate, samples_per_packet, streamFlags, oblockingIOCallback, aStream);
+                if (err != paNoError) {
+                        goto error;
+                }
+        } else {
+                err = Pa_OpenStream(&aStream->iostream, inputParameters, outputParameters, sampleRate, samples_per_packet, streamFlags, ioblockingIOCallback, aStream);
+        }
</ins><span class="cx">
</span><del>- if (err != paNoError)
- goto error;
- *rwblPtr = aStream;
- return paNoError;
</del><ins>+        if (err != paNoError) {
+                goto error;
+        }
+        
+        if (aStream->do_dual) {
+                err = Pa_StartStream(aStream->istream);
+                
+                if (err != paNoError) {
+                        goto error;
+                }
</ins><span class="cx">
</span><del>-error:
- CloseAudioStream(aStream);
- *rwblPtr = NULL;
- return err;
</del><ins>+                err = Pa_StartStream(aStream->ostream);
+
+                if (err != paNoError) {
+                        goto error;
+                }
+
+        } else {
+                err = Pa_StartStream(aStream->iostream);
+        }
+
+        if (err != paNoError) {
+                goto error;
+        }
+
+        *rwblPtr = aStream;
+
+        //switch_yield(500000);
+        
+        return paNoError;
+
+ error:
+
+        CloseAudioStream(aStream);
+
+        *rwblPtr = NULL;
+        return err;
</ins><span class="cx"> }
</span><span class="cx">
</span><span class="cx"> /************************************************************/
</span><span class="cx"> PaError CloseAudioStream(PABLIO_Stream * aStream)
</span><span class="cx"> {
</span><del>- PaError err;
- int bytesEmpty;
- int byteSize = aStream->outFIFO.bufferSize;
</del><ins>+        int bytesEmpty;
+        int byteSize;
</ins><span class="cx">
</span><del>- /* If we are writing data, make sure we play everything written. */
- if (byteSize > 0) {
- bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- while (bytesEmpty < byteSize) {
- Pa_Sleep(10);
- bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
- }
- }
</del><ins>+        
+        byteSize = aStream->outFIFO.bufferSize;
</ins><span class="cx">
</span><del>- err = Pa_StopStream(aStream->stream);
- if (err != paNoError)
- goto error;
- err = Pa_CloseStream(aStream->stream);
- if (err != paNoError)
- goto error;
- Pa_Terminate();
</del><ins>+        if (aStream->has_out) {
+                /* If we are writing data, make sure we play everything written. */
+                if (byteSize > 0) {
+                        bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+                        while (bytesEmpty < byteSize) {
+                                Pa_Sleep(10);
+                                bytesEmpty = PaUtil_GetRingBufferWriteAvailable(&aStream->outFIFO);
+                        }
+                }
+        }
</ins><span class="cx">
</span><del>-error:
- PABLIO_TermFIFO(&aStream->inFIFO);
- PABLIO_TermFIFO(&aStream->outFIFO);
- free(aStream);
- return err;
</del><ins>+        if (aStream->do_dual) {
+                if (aStream->has_in && aStream->istream) {
+                        if (Pa_IsStreamActive(aStream->istream)) {
+                                Pa_StopStream(aStream->istream);
+                        }
+
+                        Pa_CloseStream(aStream->istream);
+                        aStream->istream = NULL;
+                }
+                
+                if (aStream->has_out && aStream->ostream) {
+                        if (Pa_IsStreamActive(aStream->ostream)) {
+                                Pa_StopStream(aStream->ostream);
+                        }
+
+                        Pa_CloseStream(aStream->ostream);
+                        aStream->ostream = NULL;
+                }
+                
+        } else {
+                if (aStream->iostream) {
+                        if (Pa_IsStreamActive(aStream->iostream)) {
+                                Pa_StopStream(aStream->iostream);
+                        }
+
+                        Pa_CloseStream(aStream->iostream);
+                        aStream->iostream = NULL;
+                }
+        }
+
+        if (aStream->has_in) {        
+                PABLIO_TermFIFO(&aStream->inFIFO);
+        }
+        
+        if (aStream->has_out) {
+                PABLIO_TermFIFO(&aStream->outFIFO);
+        }
+
+        free(aStream);
+        //switch_yield(500000);
+
+        return paNoError;
</ins><span class="cx"> }
</span><ins>+
</ins></span></pre></div>
<a id="freeswitchbranchesgmaruzzmod_gsmopenportaudio_nogsmlib_noalsa_nocplusplusmod_gsmopenpablioh"></a>
<div class="modfile"><h4>Modified: freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.h (16374 => 16375)</h4>
<pre class="diff"><span>
<span class="info">--- freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.h        2010-01-18 11:30:37 UTC (rev 16374)
+++ freeswitch/branches/gmaruzz/mod_gsmopen/portaudio_nogsmlib_noalsa_nocplusplus/mod_gsmopen/pablio.h        2010-01-18 13:17:28 UTC (rev 16375)
</span><span class="lines">@@ -1,10 +1,9 @@
</span><del>-#define WANT_SPEEX
</del><span class="cx"> #ifndef _PABLIO_H
</span><span class="cx"> #define _PABLIO_H
</span><span class="cx">
</span><span class="cx"> #ifdef __cplusplus
</span><span class="cx"> extern "C" {
</span><del>-#endif /* __cplusplus */
</del><ins>+#endif                                                        /* __cplusplus */
</ins><span class="cx">
</span><span class="cx"> /*
</span><span class="cx"> * $Id: pablio.h 1083 2006-08-23 07:30:49Z rossb $
</span><span class="lines">@@ -49,42 +48,25 @@
</span><span class="cx"> * license above.
</span><span class="cx"> */
</span><span class="cx">
</span><del>-#undef WANT_OSLEC
-
</del><span class="cx"> #include <stdio.h>
</span><span class="cx"> #include <stdlib.h>
</span><span class="cx"> #include <math.h>
</span><del>-#include <unistd.h>
-#include <string.h>
</del><span class="cx"> #include "pa_ringbuffer.h"
</span><span class="cx"> #include "portaudio.h"
</span><del>-#ifdef WANT_SPEEX
-#include "speex/speex_preprocess.h"
-#include "speex/speex_echo.h"
-#endif /* WANT_SPEEX */
-#ifdef WANT_OSLEC
-#include "spandsp/echo.h"
-#endif /* WANT_OSLEC */
</del><span class="cx">
</span><span class="cx"> #include <string.h>
</span><span class="cx">
</span><del>- typedef struct {
- PaUtilRingBuffer inFIFO;
- PaUtilRingBuffer outFIFO;
- PaStream *stream;
- int bytesPerFrame;
-#ifdef WANT_SPEEX
- SpeexPreprocessState *preprocess;
- SpeexEchoState *echo_state;
-#endif /* WANT_SPEEX */
-#ifdef WANT_OSLEC
- echo_can_state_t *ec;
-#endif /* WANT_OSLEC */
- int audioreadpipe;
- int *speexecho;
- int *speexpreprocess;
- void *owner;
- } PABLIO_Stream;
</del><ins>+        typedef struct {
+                PaUtilRingBuffer inFIFO;
+                PaUtilRingBuffer outFIFO;
+                PaStream *istream;
+                PaStream *ostream;
+                PaStream *iostream;
+                int bytesPerFrame;
+                int do_dual;
+                int has_in;
+                int has_out;
+        } PABLIO_Stream;
</ins><span class="cx">
</span><span class="cx"> /* Values for flags for OpenAudioStream(). */
</span><span class="cx"> #define PABLIO_READ (1<<0)
</span><span class="lines">@@ -97,27 +79,25 @@
</span><span class="cx"> * Write data to ring buffer.
</span><span class="cx"> * Will not return until all the data has been written.
</span><span class="cx"> */
</span><del>- //long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
- long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames);
</del><ins>+        long WriteAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Read data from ring buffer.
</span><span class="cx"> * Will not return until all the data has been read.
</span><span class="cx"> */
</span><del>- //long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
- long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames);
</del><ins>+        long ReadAudioStream(PABLIO_Stream * aStream, void *data, long numFrames, switch_timer_t *timer);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Return the number of frames that could be written to the stream without
</span><span class="cx"> * having to wait.
</span><span class="cx"> */
</span><del>- long GetAudioStreamWriteable(PABLIO_Stream * aStream);
</del><ins>+        long GetAudioStreamWriteable(PABLIO_Stream * aStream);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Return the number of frames that are available to be read from the
</span><span class="cx"> * stream without having to wait.
</span><span class="cx"> */
</span><del>- long GetAudioStreamReadable(PABLIO_Stream * aStream);
</del><ins>+        long GetAudioStreamReadable(PABLIO_Stream * aStream);
</ins><span class="cx">
</span><span class="cx"> /************************************************************
</span><span class="cx"> * Opens a PortAudio stream with default characteristics.
</span><span class="lines">@@ -127,16 +107,14 @@
</span><span class="cx"> * PABLIO_READ, PABLIO_WRITE, or PABLIO_READ_WRITE,
</span><span class="cx"> * and either PABLIO_MONO or PABLIO_STEREO
</span><span class="cx"> */
</span><del>- PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
- const PaStreamParameters * inputParameters,
- const PaStreamParameters * outputParameters, double sampleRate,
- PaStreamCallbackFlags statusFlags, long samples_per_frame,
- int audioreadpipe, int *speexecho,
- int *speexpreprocess, void *owner);
</del><ins>+        PaError OpenAudioStream(PABLIO_Stream ** rwblPtr,
+                                                        const PaStreamParameters * inputParameters,
+                                                        const PaStreamParameters * outputParameters,
+                                                        double sampleRate, PaStreamCallbackFlags statusFlags, long samples_per_packet, int do_dual);
</ins><span class="cx">
</span><del>- PaError CloseAudioStream(PABLIO_Stream * aStream);
</del><ins>+        PaError CloseAudioStream(PABLIO_Stream * aStream);
</ins><span class="cx">
</span><span class="cx"> #ifdef __cplusplus
</span><span class="cx"> }
</span><del>-#endif /* __cplusplus */
-#endif /* _PABLIO_H */
</del><ins>+#endif                                                        /* __cplusplus */
+#endif                                                        /* _PABLIO_H */
</ins></span></pre>
</div>
</div>
<div id="footer">See you at ClueCon</div>
</body>
</html>