[pulseaudio-commits] 22 commits - configure.ac m4/ax_check_compile_flag.m4 m4/ax_cxx_compile_stdcxx_11.m4 m4/ax_cxx_compile_stdcxx.m4 src/Makefile.am src/modules src/tests

Arun Raghavan arun at kemper.freedesktop.org
Thu Feb 25 12:31:34 UTC 2016


 configure.ac                                 |    9 
 m4/ax_check_compile_flag.m4                  |   74 +++
 m4/ax_cxx_compile_stdcxx.m4                  |  558 +++++++++++++++++++++++++++
 m4/ax_cxx_compile_stdcxx_11.m4               |   39 +
 src/Makefile.am                              |    5 
 src/modules/echo-cancel/adrian.c             |   18 
 src/modules/echo-cancel/echo-cancel.h        |   10 
 src/modules/echo-cancel/module-echo-cancel.c |   35 +
 src/modules/echo-cancel/null.c               |    4 
 src/modules/echo-cancel/speex.c              |   58 +-
 src/modules/echo-cancel/webrtc.cc            |  431 +++++++++++++++++---
 src/tests/connect-stress.c                   |    6 
 src/tests/cpu-mix-test.c                     |    2 
 src/tests/cpu-remap-test.c                   |    4 
 src/tests/cpu-sconv-test.c                   |    4 
 src/tests/cpu-volume-test.c                  |    2 
 src/tests/cpulimit-test.c                    |    4 
 src/tests/extended-test.c                    |    4 
 src/tests/get-binary-name-test.c             |    2 
 src/tests/interpol-test.c                    |    2 
 src/tests/mult-s16-test.c                    |    2 
 src/tests/sync-playback.c                    |    4 
 22 files changed, 1143 insertions(+), 134 deletions(-)

New commits:
commit 05a6af744b157d7a94649eaff9702d9588b0a08e
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:15 2016 +0530

    echo-cancel: Add beamforming support in the webrtc canceller

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 73aeda2..12bb556 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -53,6 +53,7 @@ PA_C_DECL_END
 #define DEFAULT_INTELLIGIBILITY_ENHANCER false
 #define DEFAULT_EXPERIMENTAL_AGC false
 #define DEFAULT_AGC_START_VOLUME 85
+#define DEFAULT_BEAMFORMING false
 #define DEFAULT_TRACE false
 
 #define WEBRTC_AGC_MAX_VOLUME 255
@@ -71,6 +72,9 @@ static const char* const valid_modargs[] = {
     "intelligibility_enhancer",
     "experimental_agc",
     "agc_start_volume",
+    "beamforming",
+    "mic_geometry", /* documented in parse_mic_geometry() */
+    "target_direction", /* documented in parse_mic_geometry() */
     "trace",
     NULL
 };
@@ -116,7 +120,8 @@ static pa_volume_t webrtc_volume_to_pa(int v)
 
 static void webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
                                   pa_sample_spec *play_ss, pa_channel_map *play_map,
-                                  pa_sample_spec *out_ss, pa_channel_map *out_map)
+                                  pa_sample_spec *out_ss, pa_channel_map *out_map,
+                                  bool beamforming)
 {
     rec_ss->format = PA_SAMPLE_FLOAT32NE;
     play_ss->format = PA_SAMPLE_FLOAT32NE;
@@ -134,10 +139,97 @@ static void webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_ma
     *out_ss = *rec_ss;
     *out_map = *rec_map;
 
+    if (beamforming) {
+        /* The beamformer gives us a single channel */
+        out_ss->channels = 1;
+        pa_channel_map_init_mono(out_map);
+    }
+
     /* Playback stream rate needs to be the same as capture */
     play_ss->rate = rec_ss->rate;
 }
 
+static bool parse_point(const char **point, float (&f)[3]) {
+    int ret, length;
+
+    ret = sscanf(*point, "%g,%g,%g%n", &f[0], &f[1], &f[2], &length);
+    if (ret != 3)
+        return false;
+
+    /* Consume the bytes we've read so far */
+    *point += length;
+
+    return true;
+}
+
+static bool parse_mic_geometry(const char **mic_geometry, std::vector<webrtc::Point>& geometry) {
+    /* The microphone geometry is expressed as cartesian point form:
+     *   x1,y1,z1,x2,y2,z2,...
+     *
+     * Where x1,y1,z1 is the position of the first microphone with regards to
+     * the array's "center", x2,y2,z2 the position of the second, and so on.
+     *
+     * 'x' is the horizontal coordinate, with positive values being to the
+     * right from the mic array's perspective.
+     *
+     * 'y' is the depth coordinate, with positive values being in front of the
+     * array.
+     *
+     * 'z' is the vertical coordinate, with positive values being above the
+     * array.
+     *
+     * All distances are in meters.
+     */
+
+    /* The target direction is expected to be in spherical point form:
+     *   a,e,r
+     *
+     * Where 'a is the azimuth of the first mic channel, 'e' its elevation,
+     * and 'r' the radius.
+     *
+     * 0 radians azimuth is to the right of the array, and positive angles
+     * move in a counter-clockwise direction.
+     *
+     * 0 radians elevation is horizontal w.r.t. the array, and positive
+     * angles go upwards.
+     *
+     * radius is distance from the array center in meters.
+     */
+
+    int i;
+    float f[3];
+
+    for (i = 0; i < geometry.size(); i++) {
+        if (!parse_point(mic_geometry, f)) {
+            pa_log("Failed to parse channel %d in mic_geometry", i);
+            return false;
+        }
+
+        /* Except for the last point, we should have a trailing comma */
+        if (i != geometry.size() - 1) {
+            if (**mic_geometry != ',') {
+                pa_log("Failed to parse channel %d in mic_geometry", i);
+                return false;
+            }
+
+            (*mic_geometry)++;
+        }
+
+        pa_log_debug("Got mic #%d position: (%g, %g, %g)", i, f[0], f[1], f[2]);
+
+        geometry[i].c[0] = f[0];
+        geometry[i].c[1] = f[1];
+        geometry[i].c[2] = f[2];
+    }
+
+    if (**mic_geometry != '\0') {
+        pa_log("Failed to parse mic_geometry value: more parameters than expected");
+        return false;
+    }
+
+    return true;
+}
+
 bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
                        pa_sample_spec *rec_ss, pa_channel_map *rec_map,
                        pa_sample_spec *play_ss, pa_channel_map *play_map,
@@ -146,7 +238,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     webrtc::AudioProcessing *apm = NULL;
     webrtc::ProcessingConfig pconfig;
     webrtc::Config config;
-    bool hpf, ns, agc, dgc, mobile, cn, vad, ext_filter, intelligibility, experimental_agc;
+    bool hpf, ns, agc, dgc, mobile, cn, vad, ext_filter, intelligibility, experimental_agc, beamforming;
     int rm = -1, i;
     uint32_t agc_start_volume;
     pa_modargs *ma;
@@ -256,6 +348,12 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     }
     ec->params.webrtc.agc_start_volume = agc_start_volume;
 
+    beamforming = DEFAULT_BEAMFORMING;
+    if (pa_modargs_get_value_boolean(ma, "beamforming", &beamforming) < 0) {
+        pa_log("Failed to parse beamforming value");
+        goto fail;
+    }
+
     if (ext_filter)
         config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true));
     if (intelligibility)
@@ -276,7 +374,54 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         webrtc::Trace::SetTraceCallback((PaWebrtcTraceCallback *) ec->params.webrtc.trace_callback);
     }
 
-    webrtc_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
+    webrtc_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map, beamforming);
+
+    /* We do this after fixate because we need the capture channel count */
+    if (beamforming) {
+        std::vector<webrtc::Point> geometry(rec_ss->channels);
+        webrtc::SphericalPointf direction(0.0f, 0.0f, 0.0f);
+        const char *mic_geometry, *target_direction;
+
+        if (!(mic_geometry = pa_modargs_get_value(ma, "mic_geometry", NULL))) {
+            pa_log("mic_geometry must be set if beamforming is enabled");
+            goto fail;
+        }
+
+        if (!parse_mic_geometry(&mic_geometry, geometry)) {
+            pa_log("Failed to parse mic_geometry value");
+            goto fail;
+        }
+
+        if ((target_direction = pa_modargs_get_value(ma, "target_direction", NULL))) {
+            float f[3];
+
+            if (!parse_point(&target_direction, f)) {
+                pa_log("Failed to parse target_direction value");
+                goto fail;
+            }
+
+            if (*target_direction != '\0') {
+                pa_log("Failed to parse target_direction value: more parameters than expected");
+                goto fail;
+            }
+
+#define IS_ZERO(f) ((f) < 0.000001 && (f) > -0.000001)
+
+            if (!IS_ZERO(f[1]) || !IS_ZERO(f[2])) {
+                pa_log("The beamformer currently only supports targeting along the azimuth");
+                goto fail;
+            }
+
+            direction.s[0] = f[0];
+            direction.s[1] = f[1];
+            direction.s[2] = f[2];
+        }
+
+        if (!target_direction)
+            config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
+        else
+            config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry, direction));
+    }
 
     apm = webrtc::AudioProcessing::Create(config);
 

commit cfd3a948deb4d2fc0f2a2d3a5de7f466311b6478
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:14 2016 +0530

    echo-cancel: Remove pa_ prefix on private functions

diff --git a/src/modules/echo-cancel/speex.c b/src/modules/echo-cancel/speex.c
index 08c1027..a3ae646 100644
--- a/src/modules/echo-cancel/speex.c
+++ b/src/modules/echo-cancel/speex.c
@@ -47,9 +47,9 @@ static const char* const valid_modargs[] = {
     NULL
 };
 
-static void pa_speex_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
-                                    pa_sample_spec *play_ss, pa_channel_map *play_map,
-                                    pa_sample_spec *out_ss, pa_channel_map *out_map) {
+static void speex_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
+                                 pa_sample_spec *play_ss, pa_channel_map *play_map,
+                                 pa_sample_spec *out_ss, pa_channel_map *out_map) {
     out_ss->format = PA_SAMPLE_S16NE;
 
     *play_ss = *out_ss;
@@ -170,7 +170,7 @@ bool pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
         goto fail;
     }
 
-    pa_speex_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
+    speex_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
 
     rate = out_ss->rate;
     *nframes = pa_echo_canceller_blocksize_power2(rate, frame_size_ms);
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 756d5f7..73aeda2 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -114,9 +114,9 @@ static pa_volume_t webrtc_volume_to_pa(int v)
     return (v * PA_VOLUME_NORM) / WEBRTC_AGC_MAX_VOLUME;
 }
 
-static void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
-                                     pa_sample_spec *play_ss, pa_channel_map *play_map,
-                                     pa_sample_spec *out_ss, pa_channel_map *out_map)
+static void webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
+                                  pa_sample_spec *play_ss, pa_channel_map *play_map,
+                                  pa_sample_spec *out_ss, pa_channel_map *out_map)
 {
     rec_ss->format = PA_SAMPLE_FLOAT32NE;
     play_ss->format = PA_SAMPLE_FLOAT32NE;
@@ -276,7 +276,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         webrtc::Trace::SetTraceCallback((PaWebrtcTraceCallback *) ec->params.webrtc.trace_callback);
     }
 
-    pa_webrtc_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
+    webrtc_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
 
     apm = webrtc::AudioProcessing::Create(config);
 

commit be5e196c1a6065529e44a49e78ca75050706e321
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:13 2016 +0530

    echo-cancel: Update a copyright notice

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 93af18f..756d5f7 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -2,8 +2,9 @@
     This file is part of PulseAudio.
 
     Copyright 2011 Collabora Ltd.
+              2015 Aldebaran SoftBank Group
 
-    Contributor: Arun Raghavan <arun.raghavan at collabora.co.uk>
+    Contributor: Arun Raghavan <mail at arunraghavan.net>
 
     PulseAudio is free software; you can redistribute it and/or modify
     it under the terms of the GNU Lesser General Public License as published

commit 07663b06b325eee5b434f15fe1cdde0e7dd7d02d
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:12 2016 +0530

    echo-cancel: Use webrtc's deinterleaved API
    
    This is required to have unequal channel counts on capture in and out
    streams, which is needed for beamforming to work. The deinterleaved API
    only works with floating point samples.

diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index ab0c5e9..83f8b85 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -66,6 +66,7 @@ struct pa_echo_canceller_params {
             void *apm;
             unsigned int blocksize; /* in frames */
             pa_sample_spec rec_ss, play_ss, out_ss;
+            float *rec_buffer[PA_CHANNELS_MAX], *play_buffer[PA_CHANNELS_MAX]; /* for deinterleaved buffers */
             void *trace_callback;
             bool agc;
             bool first;
diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 484281f..4e898d0 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -2158,12 +2158,12 @@ int main(int argc, char* argv[]) {
         goto fail;
     }
 
-    source_ss.format = PA_SAMPLE_S16LE;
+    source_ss.format = PA_SAMPLE_FLOAT32LE;
     source_ss.rate = DEFAULT_RATE;
     source_ss.channels = DEFAULT_CHANNELS;
     pa_channel_map_init_auto(&source_map, source_ss.channels, PA_CHANNEL_MAP_DEFAULT);
 
-    sink_ss.format = PA_SAMPLE_S16LE;
+    sink_ss.format = PA_SAMPLE_FLOAT32LE;
     sink_ss.rate = DEFAULT_RATE;
     sink_ss.channels = DEFAULT_CHANNELS;
     pa_channel_map_init_auto(&sink_map, sink_ss.channels, PA_CHANNEL_MAP_DEFAULT);
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 6c2dd99..93af18f 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -117,8 +117,8 @@ static void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec
                                      pa_sample_spec *play_ss, pa_channel_map *play_map,
                                      pa_sample_spec *out_ss, pa_channel_map *out_map)
 {
-    rec_ss->format = PA_SAMPLE_S16NE;
-    play_ss->format = PA_SAMPLE_S16NE;
+    rec_ss->format = PA_SAMPLE_FLOAT32NE;
+    play_ss->format = PA_SAMPLE_FLOAT32NE;
 
     /* AudioProcessing expects one of the following rates */
     if (rec_ss->rate >= 48000)
@@ -130,7 +130,6 @@ static void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec
     else
         rec_ss->rate = 8000;
 
-    /* In int16 mode, AudioProcessing will give us the same spec we give it */
     *out_ss = *rec_ss;
     *out_map = *rec_map;
 
@@ -147,7 +146,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     webrtc::ProcessingConfig pconfig;
     webrtc::Config config;
     bool hpf, ns, agc, dgc, mobile, cn, vad, ext_filter, intelligibility, experimental_agc;
-    int rm = -1;
+    int rm = -1, i;
     uint32_t agc_start_volume;
     pa_modargs *ma;
     bool trace = false;
@@ -340,6 +339,11 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     *nframes = ec->params.webrtc.blocksize;
     ec->params.webrtc.first = true;
 
+    for (i = 0; i < rec_ss->channels; i++)
+        ec->params.webrtc.rec_buffer[i] = pa_xnew(float, *nframes);
+    for (i = 0; i < play_ss->channels; i++)
+        ec->params.webrtc.play_buffer[i] = pa_xnew(float, *nframes);
+
     pa_modargs_free(ma);
     return true;
 
@@ -357,18 +361,14 @@ fail:
 
 void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
     webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
-    webrtc::AudioFrame play_frame;
     const pa_sample_spec *ss = &ec->params.webrtc.play_ss;
+    int n = ec->params.webrtc.blocksize;
+    float **buf = ec->params.webrtc.play_buffer;
+    webrtc::StreamConfig config(ss->rate, ss->channels, false);
 
-    play_frame.num_channels_ = ss->channels;
-    play_frame.sample_rate_hz_ = ss->rate;
-    play_frame.interleaved_ = true;
-    play_frame.samples_per_channel_ = ec->params.webrtc.blocksize;
-
-    pa_assert(play_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
-    memcpy(play_frame.data_, play, ec->params.webrtc.blocksize * pa_frame_size(ss));
+    pa_deinterleave(play, (void **) buf, ss->channels, pa_sample_size(ss), n);
 
-    pa_assert_se(apm->ProcessReverseStream(&play_frame) == webrtc::AudioProcessing::kNoError);
+    pa_assert_se(apm->ProcessReverseStream(buf, config, config, buf) == webrtc::AudioProcessing::kNoError);
 
     /* FIXME: If ProcessReverseStream() makes any changes to the audio, such as
      * applying intelligibility enhancement, those changes don't have any
@@ -379,19 +379,16 @@ void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
 
 void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out) {
     webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
-    webrtc::AudioFrame out_frame;
     const pa_sample_spec *rec_ss = &ec->params.webrtc.rec_ss;
     const pa_sample_spec *out_ss = &ec->params.webrtc.out_ss;
+    float **buf = ec->params.webrtc.rec_buffer;
+    int n = ec->params.webrtc.blocksize;
     pa_cvolume v;
     int old_volume, new_volume;
+    webrtc::StreamConfig rec_config(rec_ss->rate, rec_ss->channels, false);
+    webrtc::StreamConfig out_config(out_ss->rate, out_ss->channels, false);
 
-    out_frame.num_channels_ = rec_ss->channels;
-    out_frame.sample_rate_hz_ = rec_ss->rate;
-    out_frame.interleaved_ = true;
-    out_frame.samples_per_channel_ = ec->params.webrtc.blocksize;
-
-    pa_assert(out_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
-    memcpy(out_frame.data_, rec, ec->params.webrtc.blocksize * pa_frame_size(rec_ss));
+    pa_deinterleave(rec, (void **) buf, rec_ss->channels, pa_sample_size(rec_ss), n);
 
     if (ec->params.webrtc.agc) {
         pa_cvolume_init(&v);
@@ -401,7 +398,7 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     }
 
     apm->set_stream_delay_ms(0);
-    pa_assert_se(apm->ProcessStream(&out_frame) == webrtc::AudioProcessing::kNoError);
+    pa_assert_se(apm->ProcessStream(buf, rec_config, out_config, buf) == webrtc::AudioProcessing::kNoError);
 
     if (ec->params.webrtc.agc) {
         if (PA_UNLIKELY(ec->params.webrtc.first)) {
@@ -421,7 +418,7 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
         }
     }
 
-    memcpy(out, out_frame.data_, ec->params.webrtc.blocksize * pa_frame_size(out_ss));
+    pa_interleave((const void **) buf, out_ss->channels, out, pa_sample_size(out_ss), n);
 }
 
 void pa_webrtc_ec_set_drift(pa_echo_canceller *ec, float drift) {
@@ -436,6 +433,8 @@ void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *
 }
 
 void pa_webrtc_ec_done(pa_echo_canceller *ec) {
+    int i;
+
     if (ec->params.webrtc.trace_callback) {
         webrtc::Trace::ReturnTrace();
         delete ((PaWebrtcTraceCallback *) ec->params.webrtc.trace_callback);
@@ -445,4 +444,9 @@ void pa_webrtc_ec_done(pa_echo_canceller *ec) {
         delete (webrtc::AudioProcessing*)ec->params.webrtc.apm;
         ec->params.webrtc.apm = NULL;
     }
+
+    for (i = 0; i < ec->params.webrtc.rec_ss.channels; i++)
+        pa_xfree(ec->params.webrtc.rec_buffer[i]);
+    for (i = 0; i < ec->params.webrtc.play_ss.channels; i++)
+        pa_xfree(ec->params.webrtc.play_buffer[i]);
 }

commit 3133ff8e1110ae694070951fdfe37e63a58995cb
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:10 2016 +0530

    echo-cancel: webrtc canceller supports different in/out channel counts
    
    Needed for upcoming beamforming code.

diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index 4c15717..ab0c5e9 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -65,7 +65,7 @@ struct pa_echo_canceller_params {
              * to C++ linkage. apm is a pointer to an AudioProcessing object */
             void *apm;
             unsigned int blocksize; /* in frames */
-            pa_sample_spec rec_ss, play_ss;
+            pa_sample_spec rec_ss, play_ss, out_ss;
             void *trace_callback;
             bool agc;
             bool first;
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 1df9b61..6c2dd99 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -335,6 +335,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     ec->params.webrtc.apm = apm;
     ec->params.webrtc.rec_ss = *rec_ss;
     ec->params.webrtc.play_ss = *play_ss;
+    ec->params.webrtc.out_ss = *out_ss;
     ec->params.webrtc.blocksize = (uint64_t) out_ss->rate * BLOCK_SIZE_US / PA_USEC_PER_SEC;
     *nframes = ec->params.webrtc.blocksize;
     ec->params.webrtc.first = true;
@@ -379,17 +380,18 @@ void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
 void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out) {
     webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
     webrtc::AudioFrame out_frame;
-    const pa_sample_spec *ss = &ec->params.webrtc.rec_ss;
+    const pa_sample_spec *rec_ss = &ec->params.webrtc.rec_ss;
+    const pa_sample_spec *out_ss = &ec->params.webrtc.out_ss;
     pa_cvolume v;
     int old_volume, new_volume;
 
-    out_frame.num_channels_ = ss->channels;
-    out_frame.sample_rate_hz_ = ss->rate;
+    out_frame.num_channels_ = rec_ss->channels;
+    out_frame.sample_rate_hz_ = rec_ss->rate;
     out_frame.interleaved_ = true;
     out_frame.samples_per_channel_ = ec->params.webrtc.blocksize;
 
     pa_assert(out_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
-    memcpy(out_frame.data_, rec, ec->params.webrtc.blocksize * pa_frame_size(ss));
+    memcpy(out_frame.data_, rec, ec->params.webrtc.blocksize * pa_frame_size(rec_ss));
 
     if (ec->params.webrtc.agc) {
         pa_cvolume_init(&v);
@@ -414,12 +416,12 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
         }
 
         if (old_volume != new_volume) {
-            pa_cvolume_set(&v, ss->channels, webrtc_volume_to_pa(new_volume));
+            pa_cvolume_set(&v, rec_ss->channels, webrtc_volume_to_pa(new_volume));
             pa_echo_canceller_set_capture_volume(ec, &v);
         }
     }
 
-    memcpy(out, out_frame.data_, ec->params.webrtc.blocksize * pa_frame_size(ss));
+    memcpy(out, out_frame.data_, ec->params.webrtc.blocksize * pa_frame_size(out_ss));
 }
 
 void pa_webrtc_ec_set_drift(pa_echo_canceller *ec, float drift) {

commit 222a98846c8c0b0c2b1b6adccf248b6a181f634e
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:09 2016 +0530

    echo-cancel: Improve webrtc canceller error handling a bit

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 0bf31dc..1df9b61 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -286,7 +286,10 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         webrtc::StreamConfig(play_ss->rate, play_ss->channels, false), /* reverse input stream */
         webrtc::StreamConfig(play_ss->rate, play_ss->channels, false), /* reverse output stream */
     };
-    apm->Initialize(pconfig);
+    if (apm->Initialize(pconfig) != webrtc::AudioProcessing::kNoError) {
+        pa_log("Error initialising audio processing module");
+        goto fail;
+    }
 
     if (hpf)
         apm->high_pass_filter()->Enable(true);
@@ -315,7 +318,8 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
             ec->params.webrtc.agc = false;
         } else {
             apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveAnalog);
-            if (apm->gain_control()->set_analog_level_limits(0, WEBRTC_AGC_MAX_VOLUME) != apm->kNoError) {
+            if (apm->gain_control()->set_analog_level_limits(0, WEBRTC_AGC_MAX_VOLUME) !=
+                    webrtc::AudioProcessing::kNoError) {
                 pa_log("Failed to initialise AGC");
                 goto fail;
             }
@@ -363,7 +367,7 @@ void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
     pa_assert(play_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
     memcpy(play_frame.data_, play, ec->params.webrtc.blocksize * pa_frame_size(ss));
 
-    apm->ProcessReverseStream(&play_frame);
+    pa_assert_se(apm->ProcessReverseStream(&play_frame) == webrtc::AudioProcessing::kNoError);
 
     /* FIXME: If ProcessReverseStream() makes any changes to the audio, such as
      * applying intelligibility enhancement, those changes don't have any
@@ -395,7 +399,7 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     }
 
     apm->set_stream_delay_ms(0);
-    apm->ProcessStream(&out_frame);
+    pa_assert_se(apm->ProcessStream(&out_frame) == webrtc::AudioProcessing::kNoError);
 
     if (ec->params.webrtc.agc) {
         if (PA_UNLIKELY(ec->params.webrtc.first)) {

commit 5baecd37c3e17f1a5f6a3ef2d38f2da20db498d7
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:08 2016 +0530

    echo-cancel: Fix webrtc canceller when rec channels != play channels
    
    The calculations around how many samples were sent to the canceller
    engine was not updated when we started supporting different channel
    counts for playback and capture.

diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index a38b8f8..4c15717 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -64,8 +64,8 @@ struct pa_echo_canceller_params {
             /* This is a void* so that we don't have to convert this whole file
              * to C++ linkage. apm is a pointer to an AudioProcessing object */
             void *apm;
-            uint32_t blocksize;
-            pa_sample_spec sample_spec;
+            unsigned int blocksize; /* in frames */
+            pa_sample_spec rec_ss, play_ss;
             void *trace_callback;
             bool agc;
             bool first;
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 54b3558..0bf31dc 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -329,9 +329,10 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         apm->voice_detection()->Enable(true);
 
     ec->params.webrtc.apm = apm;
-    ec->params.webrtc.sample_spec = *out_ss;
-    ec->params.webrtc.blocksize = (uint64_t)pa_bytes_per_second(out_ss) * BLOCK_SIZE_US / PA_USEC_PER_SEC;
-    *nframes = ec->params.webrtc.blocksize / pa_frame_size(out_ss);
+    ec->params.webrtc.rec_ss = *rec_ss;
+    ec->params.webrtc.play_ss = *play_ss;
+    ec->params.webrtc.blocksize = (uint64_t) out_ss->rate * BLOCK_SIZE_US / PA_USEC_PER_SEC;
+    *nframes = ec->params.webrtc.blocksize;
     ec->params.webrtc.first = true;
 
     pa_modargs_free(ma);
@@ -352,15 +353,15 @@ fail:
 void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
     webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
     webrtc::AudioFrame play_frame;
-    const pa_sample_spec *ss = &ec->params.webrtc.sample_spec;
+    const pa_sample_spec *ss = &ec->params.webrtc.play_ss;
 
     play_frame.num_channels_ = ss->channels;
     play_frame.sample_rate_hz_ = ss->rate;
     play_frame.interleaved_ = true;
-    play_frame.samples_per_channel_ = ec->params.webrtc.blocksize / pa_frame_size(ss);
+    play_frame.samples_per_channel_ = ec->params.webrtc.blocksize;
 
     pa_assert(play_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
-    memcpy(play_frame.data_, play, ec->params.webrtc.blocksize);
+    memcpy(play_frame.data_, play, ec->params.webrtc.blocksize * pa_frame_size(ss));
 
     apm->ProcessReverseStream(&play_frame);
 
@@ -374,17 +375,17 @@ void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
 void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out) {
     webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
     webrtc::AudioFrame out_frame;
-    const pa_sample_spec *ss = &ec->params.webrtc.sample_spec;
+    const pa_sample_spec *ss = &ec->params.webrtc.rec_ss;
     pa_cvolume v;
     int old_volume, new_volume;
 
     out_frame.num_channels_ = ss->channels;
     out_frame.sample_rate_hz_ = ss->rate;
     out_frame.interleaved_ = true;
-    out_frame.samples_per_channel_ = ec->params.webrtc.blocksize / pa_frame_size(ss);
+    out_frame.samples_per_channel_ = ec->params.webrtc.blocksize;
 
     pa_assert(out_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
-    memcpy(out_frame.data_, rec, ec->params.webrtc.blocksize);
+    memcpy(out_frame.data_, rec, ec->params.webrtc.blocksize * pa_frame_size(ss));
 
     if (ec->params.webrtc.agc) {
         pa_cvolume_init(&v);
@@ -414,14 +415,13 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
         }
     }
 
-    memcpy(out, out_frame.data_, ec->params.webrtc.blocksize);
+    memcpy(out, out_frame.data_, ec->params.webrtc.blocksize * pa_frame_size(ss));
 }
 
 void pa_webrtc_ec_set_drift(pa_echo_canceller *ec, float drift) {
     webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
-    const pa_sample_spec *ss = &ec->params.webrtc.sample_spec;
 
-    apm->echo_cancellation()->set_stream_drift_samples(drift * ec->params.webrtc.blocksize / pa_frame_size(ss));
+    apm->echo_cancellation()->set_stream_drift_samples(drift * ec->params.webrtc.blocksize);
 }
 
 void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {

commit 08afc36ae4cd678de842648874c6d7e4f5fa0a36
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:07 2016 +0530

    echo-cancel: Make webrtc AGC start volume a modarg
    
    Allows for tuning based on the target hardware.

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index b964495..54b3558 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -51,10 +51,10 @@ PA_C_DECL_END
 #define DEFAULT_EXTENDED_FILTER false
 #define DEFAULT_INTELLIGIBILITY_ENHANCER false
 #define DEFAULT_EXPERIMENTAL_AGC false
+#define DEFAULT_AGC_START_VOLUME 85
 #define DEFAULT_TRACE false
 
 #define WEBRTC_AGC_MAX_VOLUME 255
-#define WEBRTC_AGC_START_VOLUME 85
 
 static const char* const valid_modargs[] = {
     "high_pass_filter",
@@ -69,6 +69,7 @@ static const char* const valid_modargs[] = {
     "extended_filter",
     "intelligibility_enhancer",
     "experimental_agc",
+    "agc_start_volume",
     "trace",
     NULL
 };
@@ -147,6 +148,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     webrtc::Config config;
     bool hpf, ns, agc, dgc, mobile, cn, vad, ext_filter, intelligibility, experimental_agc;
     int rm = -1;
+    uint32_t agc_start_volume;
     pa_modargs *ma;
     bool trace = false;
 
@@ -243,12 +245,23 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         goto fail;
     }
 
+    agc_start_volume = DEFAULT_AGC_START_VOLUME;
+    if (pa_modargs_get_value_u32(ma, "agc_start_volume", &agc_start_volume) < 0) {
+        pa_log("Failed to parse agc_start_volume value");
+        goto fail;
+    }
+    if (agc_start_volume > WEBRTC_AGC_MAX_VOLUME) {
+        pa_log("AGC start volume must not exceed %u", WEBRTC_AGC_MAX_VOLUME);
+        goto fail;
+    }
+    ec->params.webrtc.agc_start_volume = agc_start_volume;
+
     if (ext_filter)
         config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true));
     if (intelligibility)
         pa_log_warn("The intelligibility enhancer is not currently supported");
     if (experimental_agc)
-        config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(true, WEBRTC_AGC_START_VOLUME));
+        config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(true, ec->params.webrtc.agc_start_volume));
 
     trace = DEFAULT_TRACE;
     if (pa_modargs_get_value_boolean(ma, "trace", &trace) < 0) {
@@ -390,7 +403,7 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
              * needed to make sure that there's enough energy in the capture
              * signal for the AGC to work */
             ec->params.webrtc.first = false;
-            new_volume = WEBRTC_AGC_START_VOLUME;
+            new_volume = ec->params.webrtc.agc_start_volume;
         } else {
             new_volume = apm->gain_control()->stream_analog_level();
         }

commit 8de7dfec142554e24506471118fe6a3eb2793fa5
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:06 2016 +0530

    echo-cancel: Use anonymous unions for echo canceller params
    
    Makes this part of the code just a little less verbose.

diff --git a/src/modules/echo-cancel/adrian.c b/src/modules/echo-cancel/adrian.c
index 60a2b66..3c47fae 100644
--- a/src/modules/echo-cancel/adrian.c
+++ b/src/modules/echo-cancel/adrian.c
@@ -78,16 +78,16 @@ bool pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec,
 
     rate = out_ss->rate;
     *nframes = (rate * frame_size_ms) / 1000;
-    ec->params.priv.adrian.blocksize = (*nframes) * pa_frame_size(out_ss);
+    ec->params.adrian.blocksize = (*nframes) * pa_frame_size(out_ss);
 
-    pa_log_debug ("Using nframes %d, blocksize %u, channels %d, rate %d", *nframes, ec->params.priv.adrian.blocksize, out_ss->channels, out_ss->rate);
+    pa_log_debug ("Using nframes %d, blocksize %u, channels %d, rate %d", *nframes, ec->params.adrian.blocksize, out_ss->channels, out_ss->rate);
 
     /* For now we only support SSE */
     if (c->cpu_info.cpu_type == PA_CPU_X86 && (c->cpu_info.flags.x86 & PA_CPU_X86_SSE))
         have_vector = 1;
 
-    ec->params.priv.adrian.aec = AEC_init(rate, have_vector);
-    if (!ec->params.priv.adrian.aec)
+    ec->params.adrian.aec = AEC_init(rate, have_vector);
+    if (!ec->params.adrian.aec)
         goto fail;
 
     pa_modargs_free(ma);
@@ -102,17 +102,17 @@ fail:
 void pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
     unsigned int i;
 
-    for (i = 0; i < ec->params.priv.adrian.blocksize; i += 2) {
+    for (i = 0; i < ec->params.adrian.blocksize; i += 2) {
         /* We know it's S16NE mono data */
         int r = *(int16_t *)(rec + i);
         int p = *(int16_t *)(play + i);
-        *(int16_t *)(out + i) = (int16_t) AEC_doAEC(ec->params.priv.adrian.aec, r, p);
+        *(int16_t *)(out + i) = (int16_t) AEC_doAEC(ec->params.adrian.aec, r, p);
     }
 }
 
 void pa_adrian_ec_done(pa_echo_canceller *ec) {
-    if (ec->params.priv.adrian.aec) {
-        AEC_done(ec->params.priv.adrian.aec);
-        ec->params.priv.adrian.aec = NULL;
+    if (ec->params.adrian.aec) {
+        AEC_done(ec->params.adrian.aec);
+        ec->params.adrian.aec = NULL;
     }
 }
diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index cc554d5..a38b8f8 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -69,10 +69,11 @@ struct pa_echo_canceller_params {
             void *trace_callback;
             bool agc;
             bool first;
+            unsigned int agc_start_volume;
         } webrtc;
 #endif
         /* each canceller-specific structure goes here */
-    } priv;
+    };
 
     /* Set this if canceller can do drift compensation. Also see set_drift()
      * below */
diff --git a/src/modules/echo-cancel/null.c b/src/modules/echo-cancel/null.c
index 673b14f..c8ecf27 100644
--- a/src/modules/echo-cancel/null.c
+++ b/src/modules/echo-cancel/null.c
@@ -34,7 +34,7 @@ bool pa_null_ec_init(pa_core *c, pa_echo_canceller *ec,
     char strss_sink[PA_SAMPLE_SPEC_SNPRINT_MAX];
 
     *nframes = 256;
-    ec->params.priv.null.out_ss = *out_ss;
+    ec->params.null.out_ss = *out_ss;
 
     *rec_ss = *out_ss;
     *rec_map = *out_map;
@@ -49,7 +49,7 @@ bool pa_null_ec_init(pa_core *c, pa_echo_canceller *ec,
 void pa_null_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
     /* The null implementation simply copies the recorded buffer to the output
        buffer and ignores the play buffer. */
-    memcpy(out, rec, 256 * pa_frame_size(&ec->params.priv.null.out_ss));
+    memcpy(out, rec, 256 * pa_frame_size(&ec->params.null.out_ss));
 }
 
 void pa_null_ec_done(pa_echo_canceller *ec) {
diff --git a/src/modules/echo-cancel/speex.c b/src/modules/echo-cancel/speex.c
index 11e53b3..08c1027 100644
--- a/src/modules/echo-cancel/speex.c
+++ b/src/modules/echo-cancel/speex.c
@@ -111,26 +111,26 @@ static bool pa_speex_ec_preprocessor_init(pa_echo_canceller *ec, pa_sample_spec
             goto fail;
         }
 
-        ec->params.priv.speex.pp_state = speex_preprocess_state_init(nframes, out_ss->rate);
+        ec->params.speex.pp_state = speex_preprocess_state_init(nframes, out_ss->rate);
 
         tmp = agc;
-        speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_AGC, &tmp);
+        speex_preprocess_ctl(ec->params.speex.pp_state, SPEEX_PREPROCESS_SET_AGC, &tmp);
 
         tmp = denoise;
-        speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
+        speex_preprocess_ctl(ec->params.speex.pp_state, SPEEX_PREPROCESS_SET_DENOISE, &tmp);
 
         if (echo_suppress) {
             if (echo_suppress_attenuation)
-                speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS,
+                speex_preprocess_ctl(ec->params.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS,
                                      &echo_suppress_attenuation);
 
             if (echo_suppress_attenuation_active) {
-                speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE,
+                speex_preprocess_ctl(ec->params.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_SUPPRESS_ACTIVE,
                                      &echo_suppress_attenuation_active);
             }
 
-            speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_STATE,
-                                 ec->params.priv.speex.state);
+            speex_preprocess_ctl(ec->params.speex.pp_state, SPEEX_PREPROCESS_SET_ECHO_STATE,
+                                 ec->params.speex.state);
         }
 
         pa_log_info("Loaded speex preprocessor with params: agc=%s, denoise=%s, echo_suppress=%s", pa_yes_no(agc),
@@ -176,12 +176,12 @@ bool pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
     *nframes = pa_echo_canceller_blocksize_power2(rate, frame_size_ms);
 
     pa_log_debug ("Using nframes %d, channels %d, rate %d", *nframes, out_ss->channels, out_ss->rate);
-    ec->params.priv.speex.state = speex_echo_state_init_mc(*nframes, (rate * filter_size_ms) / 1000, out_ss->channels, out_ss->channels);
+    ec->params.speex.state = speex_echo_state_init_mc(*nframes, (rate * filter_size_ms) / 1000, out_ss->channels, out_ss->channels);
 
-    if (!ec->params.priv.speex.state)
+    if (!ec->params.speex.state)
         goto fail;
 
-    speex_echo_ctl(ec->params.priv.speex.state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate);
+    speex_echo_ctl(ec->params.speex.state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate);
 
     if (!pa_speex_ec_preprocessor_init(ec, out_ss, *nframes, ma))
         goto fail;
@@ -192,34 +192,34 @@ bool pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec,
 fail:
     if (ma)
         pa_modargs_free(ma);
-    if (ec->params.priv.speex.pp_state) {
-        speex_preprocess_state_destroy(ec->params.priv.speex.pp_state);
-        ec->params.priv.speex.pp_state = NULL;
+    if (ec->params.speex.pp_state) {
+        speex_preprocess_state_destroy(ec->params.speex.pp_state);
+        ec->params.speex.pp_state = NULL;
     }
-    if (ec->params.priv.speex.state) {
-        speex_echo_state_destroy(ec->params.priv.speex.state);
-        ec->params.priv.speex.state = NULL;
+    if (ec->params.speex.state) {
+        speex_echo_state_destroy(ec->params.speex.state);
+        ec->params.speex.state = NULL;
     }
     return false;
 }
 
 void pa_speex_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
-    speex_echo_cancellation(ec->params.priv.speex.state, (const spx_int16_t *) rec, (const spx_int16_t *) play,
+    speex_echo_cancellation(ec->params.speex.state, (const spx_int16_t *) rec, (const spx_int16_t *) play,
                             (spx_int16_t *) out);
 
     /* preprecessor is run after AEC. This is not a mistake! */
-    if (ec->params.priv.speex.pp_state)
-        speex_preprocess_run(ec->params.priv.speex.pp_state, (spx_int16_t *) out);
+    if (ec->params.speex.pp_state)
+        speex_preprocess_run(ec->params.speex.pp_state, (spx_int16_t *) out);
 }
 
 void pa_speex_ec_done(pa_echo_canceller *ec) {
-    if (ec->params.priv.speex.pp_state) {
-        speex_preprocess_state_destroy(ec->params.priv.speex.pp_state);
-        ec->params.priv.speex.pp_state = NULL;
+    if (ec->params.speex.pp_state) {
+        speex_preprocess_state_destroy(ec->params.speex.pp_state);
+        ec->params.speex.pp_state = NULL;
     }
 
-    if (ec->params.priv.speex.state) {
-        speex_echo_state_destroy(ec->params.priv.speex.state);
-        ec->params.priv.speex.state = NULL;
+    if (ec->params.speex.state) {
+        speex_echo_state_destroy(ec->params.speex.state);
+        ec->params.speex.state = NULL;
     }
 }
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index db2901f..b964495 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -259,8 +259,8 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     if (trace) {
         webrtc::Trace::CreateTrace();
         webrtc::Trace::set_level_filter(webrtc::kTraceAll);
-        ec->params.priv.webrtc.trace_callback = new PaWebrtcTraceCallback();
-        webrtc::Trace::SetTraceCallback((PaWebrtcTraceCallback *) ec->params.priv.webrtc.trace_callback);
+        ec->params.webrtc.trace_callback = new PaWebrtcTraceCallback();
+        webrtc::Trace::SetTraceCallback((PaWebrtcTraceCallback *) ec->params.webrtc.trace_callback);
     }
 
     pa_webrtc_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
@@ -296,17 +296,17 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         if (mobile && rm <= webrtc::EchoControlMobile::kEarpiece) {
             /* Maybe this should be a knob, but we've got a lot of knobs already */
             apm->gain_control()->set_mode(webrtc::GainControl::kFixedDigital);
-            ec->params.priv.webrtc.agc = false;
+            ec->params.webrtc.agc = false;
         } else if (dgc) {
             apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveDigital);
-            ec->params.priv.webrtc.agc = false;
+            ec->params.webrtc.agc = false;
         } else {
             apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveAnalog);
             if (apm->gain_control()->set_analog_level_limits(0, WEBRTC_AGC_MAX_VOLUME) != apm->kNoError) {
                 pa_log("Failed to initialise AGC");
                 goto fail;
             }
-            ec->params.priv.webrtc.agc = true;
+            ec->params.webrtc.agc = true;
         }
 
         apm->gain_control()->Enable(true);
@@ -315,11 +315,11 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     if (vad)
         apm->voice_detection()->Enable(true);
 
-    ec->params.priv.webrtc.apm = apm;
-    ec->params.priv.webrtc.sample_spec = *out_ss;
-    ec->params.priv.webrtc.blocksize = (uint64_t)pa_bytes_per_second(out_ss) * BLOCK_SIZE_US / PA_USEC_PER_SEC;
-    *nframes = ec->params.priv.webrtc.blocksize / pa_frame_size(out_ss);
-    ec->params.priv.webrtc.first = true;
+    ec->params.webrtc.apm = apm;
+    ec->params.webrtc.sample_spec = *out_ss;
+    ec->params.webrtc.blocksize = (uint64_t)pa_bytes_per_second(out_ss) * BLOCK_SIZE_US / PA_USEC_PER_SEC;
+    *nframes = ec->params.webrtc.blocksize / pa_frame_size(out_ss);
+    ec->params.webrtc.first = true;
 
     pa_modargs_free(ma);
     return true;
@@ -327,9 +327,9 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
 fail:
     if (ma)
         pa_modargs_free(ma);
-    if (ec->params.priv.webrtc.trace_callback) {
+    if (ec->params.webrtc.trace_callback) {
         webrtc::Trace::ReturnTrace();
-        delete ((PaWebrtcTraceCallback *) ec->params.priv.webrtc.trace_callback);
+        delete ((PaWebrtcTraceCallback *) ec->params.webrtc.trace_callback);
     } if (apm)
         delete apm;
 
@@ -337,17 +337,17 @@ fail:
 }
 
 void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
-    webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
+    webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
     webrtc::AudioFrame play_frame;
-    const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
+    const pa_sample_spec *ss = &ec->params.webrtc.sample_spec;
 
     play_frame.num_channels_ = ss->channels;
     play_frame.sample_rate_hz_ = ss->rate;
     play_frame.interleaved_ = true;
-    play_frame.samples_per_channel_ = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
+    play_frame.samples_per_channel_ = ec->params.webrtc.blocksize / pa_frame_size(ss);
 
     pa_assert(play_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
-    memcpy(play_frame.data_, play, ec->params.priv.webrtc.blocksize);
+    memcpy(play_frame.data_, play, ec->params.webrtc.blocksize);
 
     apm->ProcessReverseStream(&play_frame);
 
@@ -359,21 +359,21 @@ void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
 }
 
 void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out) {
-    webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
+    webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
     webrtc::AudioFrame out_frame;
-    const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
+    const pa_sample_spec *ss = &ec->params.webrtc.sample_spec;
     pa_cvolume v;
     int old_volume, new_volume;
 
     out_frame.num_channels_ = ss->channels;
     out_frame.sample_rate_hz_ = ss->rate;
     out_frame.interleaved_ = true;
-    out_frame.samples_per_channel_ = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
+    out_frame.samples_per_channel_ = ec->params.webrtc.blocksize / pa_frame_size(ss);
 
     pa_assert(out_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
-    memcpy(out_frame.data_, rec, ec->params.priv.webrtc.blocksize);
+    memcpy(out_frame.data_, rec, ec->params.webrtc.blocksize);
 
-    if (ec->params.priv.webrtc.agc) {
+    if (ec->params.webrtc.agc) {
         pa_cvolume_init(&v);
         pa_echo_canceller_get_capture_volume(ec, &v);
         old_volume = webrtc_volume_from_pa(pa_cvolume_avg(&v));
@@ -383,13 +383,13 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     apm->set_stream_delay_ms(0);
     apm->ProcessStream(&out_frame);
 
-    if (ec->params.priv.webrtc.agc) {
-        if (PA_UNLIKELY(ec->params.priv.webrtc.first)) {
+    if (ec->params.webrtc.agc) {
+        if (PA_UNLIKELY(ec->params.webrtc.first)) {
             /* We start at a sane default volume (taken from the Chromium
              * condition on the experimental AGC in audio_processing.h). This is
              * needed to make sure that there's enough energy in the capture
              * signal for the AGC to work */
-            ec->params.priv.webrtc.first = false;
+            ec->params.webrtc.first = false;
             new_volume = WEBRTC_AGC_START_VOLUME;
         } else {
             new_volume = apm->gain_control()->stream_analog_level();
@@ -401,14 +401,14 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
         }
     }
 
-    memcpy(out, out_frame.data_, ec->params.priv.webrtc.blocksize);
+    memcpy(out, out_frame.data_, ec->params.webrtc.blocksize);
 }
 
 void pa_webrtc_ec_set_drift(pa_echo_canceller *ec, float drift) {
-    webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
-    const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
+    webrtc::AudioProcessing *apm = (webrtc::AudioProcessing*)ec->params.webrtc.apm;
+    const pa_sample_spec *ss = &ec->params.webrtc.sample_spec;
 
-    apm->echo_cancellation()->set_stream_drift_samples(drift * ec->params.priv.webrtc.blocksize / pa_frame_size(ss));
+    apm->echo_cancellation()->set_stream_drift_samples(drift * ec->params.webrtc.blocksize / pa_frame_size(ss));
 }
 
 void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) {
@@ -417,13 +417,13 @@ void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *
 }
 
 void pa_webrtc_ec_done(pa_echo_canceller *ec) {
-    if (ec->params.priv.webrtc.trace_callback) {
+    if (ec->params.webrtc.trace_callback) {
         webrtc::Trace::ReturnTrace();
-        delete ((PaWebrtcTraceCallback *) ec->params.priv.webrtc.trace_callback);
+        delete ((PaWebrtcTraceCallback *) ec->params.webrtc.trace_callback);
     }
 
-    if (ec->params.priv.webrtc.apm) {
-        delete (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
-        ec->params.priv.webrtc.apm = NULL;
+    if (ec->params.webrtc.apm) {
+        delete (webrtc::AudioProcessing*)ec->params.webrtc.apm;
+        ec->params.webrtc.apm = NULL;
     }
 }

commit aa02e1654bcdfa0677e19ab9bb27b44dc8bf26b9
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:05 2016 +0530

    build-sys: Move to compiling with C11 support
    
    This is needed for building with anonymous unions. A bunch of calls to
    fail() that used to mysteriously work need fixing -- fail() is a macro
    that takes a printf-style message as an argument. Not passing this
    somehow worked with the previous compiler flags, but breaks with
    -std=c11.

diff --git a/configure.ac b/configure.ac
index 4553d71..8454e4c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,7 +80,6 @@ AC_PROG_LN_S
 # CC
 
 AC_PROG_CC
-AC_PROG_CC_C99
 AM_PROG_CC_C_O
 # Only required if you want the WebRTC canceller -- no runtime dep on
 # libstdc++ otherwise
@@ -177,6 +176,11 @@ esac
 
 #### Compiler flags ####
 
+AX_CHECK_COMPILE_FLAG([-std=c11],
+   [],
+   [AC_MSG_ERROR([*** Compiler does not support -std=c11])],
+   [-pedantic -Werror])
+
 AX_APPEND_COMPILE_FLAGS(
     [-Wall -W -Wextra -pipe -Wno-long-long -Wno-overlength-strings -Wunsafe-loop-optimizations -Wundef -Wformat=2 -Wlogical-op -Wsign-compare -Wformat-security -Wmissing-include-dirs -Wformat-nonliteral -Wold-style-definition -Wpointer-arith -Winit-self -Wdeclaration-after-statement -Wfloat-equal -Wmissing-prototypes -Wstrict-prototypes -Wredundant-decls -Wmissing-declarations -Wmissing-noreturn -Wshadow -Wendif-labels -Wcast-align -Wstrict-aliasing -Wwrite-strings -Wno-unused-parameter -ffast-math -fno-common -fdiagnostics-show-option -fdiagnostics-color=auto],
     [], [-pedantic -Werror])
diff --git a/m4/ax_check_compile_flag.m4 b/m4/ax_check_compile_flag.m4
new file mode 100644
index 0000000..ca36397
--- /dev/null
+++ b/m4/ax_check_compile_flag.m4
@@ -0,0 +1,74 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+#   Check whether the given FLAG works with the current language's compiler
+#   or gives an error.  (Warnings, however, are ignored)
+#
+#   ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+#   success/failure.
+#
+#   If EXTRA-FLAGS is defined, it is added to the current language's default
+#   flags (e.g. CFLAGS) when the check is done.  The check is thus made with
+#   the flags: "CFLAGS EXTRA-FLAGS FLAG".  This can for example be used to
+#   force the compiler to issue an error when a bad flag is given.
+#
+#   INPUT gives an alternative input source to AC_COMPILE_IFELSE.
+#
+#   NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+#   macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Guido U. Draheim <guidod at gmx.de>
+#   Copyright (c) 2011 Maarten Bosmans <mkbosmans at gmail.com>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   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, see <http://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 4
+
+AC_DEFUN([AX_CHECK_COMPILE_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
+  ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
+  _AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
+  AC_COMPILE_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+    [AS_VAR_SET(CACHEVAR,[yes])],
+    [AS_VAR_SET(CACHEVAR,[no])])
+  _AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+  [m4_default([$2], :)],
+  [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_COMPILE_FLAGS
diff --git a/src/Makefile.am b/src/Makefile.am
index 432d9c2..aa96999 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -48,7 +48,7 @@ AM_CPPFLAGS = \
 	-DPA_SRCDIR=\"$(abs_srcdir)\" \
 	-DPA_BUILDDIR=\"$(abs_builddir)\" \
 	-DPULSE_LOCALEDIR=\"$(localedir)\"
-AM_CFLAGS = \
+AM_CFLAGS = -std=c11 \
 	$(PTHREAD_CFLAGS)
 AM_CXXFLAGS = -std=c++11 \
 	$(PTHREAD_CFLAGS)
diff --git a/src/tests/connect-stress.c b/src/tests/connect-stress.c
index 7c755e9..055ef13 100644
--- a/src/tests/connect-stress.c
+++ b/src/tests/connect-stress.c
@@ -80,7 +80,7 @@ static void connect(const char *name, int *try) {
     /* Connect the context */
     if (pa_context_connect(context, NULL, 0, NULL) < 0) {
         fprintf(stderr, "pa_context_connect() failed.\n");
-        fail();
+        ck_abort();
     }
 
     ret = pa_threaded_mainloop_start(mainloop);
@@ -144,7 +144,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) {
         default:
         case PA_STREAM_FAILED:
             fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
-            fail();
+            ck_abort();
     }
 }
 
@@ -190,7 +190,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
         case PA_CONTEXT_FAILED:
         default:
             fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c)));
-            fail();
+            ck_abort();
     }
 }
 
diff --git a/src/tests/cpu-mix-test.c b/src/tests/cpu-mix-test.c
index f3bc0cc..f42530d 100644
--- a/src/tests/cpu-mix-test.c
+++ b/src/tests/cpu-mix-test.c
@@ -118,7 +118,7 @@ static void run_mix_test(
                     i,
                     samples[i], samples_ref[i],
                     samples0[i], samples1[i]);
-                fail();
+                ck_abort();
             }
         }
     }
diff --git a/src/tests/cpu-remap-test.c b/src/tests/cpu-remap-test.c
index cfe8647..7af5e29 100644
--- a/src/tests/cpu-remap-test.c
+++ b/src/tests/cpu-remap-test.c
@@ -70,7 +70,7 @@ static void run_remap_test_float(
                 pa_log_debug("Correctness test failed: align=%d", align);
                 pa_log_debug("%d: %.24f != %.24f\n", i,
                     out[i], out_ref[i]);
-                fail();
+                ck_abort();
             }
         }
     }
@@ -123,7 +123,7 @@ static void run_remap_test_s16(
             if (abs(out[i] - out_ref[i]) > 3) {
                 pa_log_debug("Correctness test failed: align=%d", align);
                 pa_log_debug("%d: %d != %d\n", i, out[i], out_ref[i]);
-                fail();
+                ck_abort();
             }
         }
     }
diff --git a/src/tests/cpu-sconv-test.c b/src/tests/cpu-sconv-test.c
index 2eb51de..3f189d1 100644
--- a/src/tests/cpu-sconv-test.c
+++ b/src/tests/cpu-sconv-test.c
@@ -65,7 +65,7 @@ static void run_conv_test_float_to_s16(
             if (abs(samples[i] - samples_ref[i]) > 1) {
                 pa_log_debug("Correctness test failed: align=%d", align);
                 pa_log_debug("%d: %04hx != %04hx (%.24f)\n", i, samples[i], samples_ref[i], floats[i]);
-                fail();
+                ck_abort();
             }
         }
     }
@@ -115,7 +115,7 @@ static void run_conv_test_s16_to_float(
             if (fabsf(floats[i] - floats_ref[i]) > 0.0001f) {
                 pa_log_debug("Correctness test failed: align=%d", align);
                 pa_log_debug("%d: %.24f != %.24f (%d)\n", i, floats[i], floats_ref[i], samples[i]);
-                fail();
+                ck_abort();
             }
         }
     }
diff --git a/src/tests/cpu-volume-test.c b/src/tests/cpu-volume-test.c
index 01ac2fc..15f0658 100644
--- a/src/tests/cpu-volume-test.c
+++ b/src/tests/cpu-volume-test.c
@@ -78,7 +78,7 @@ static void run_volume_test(
                 pa_log_debug("Correctness test failed: align=%d, channels=%d", align, channels);
                 pa_log_debug("%d: %04hx != %04hx (%04hx * %08x)\n", i, samples[i], samples_ref[i],
                         samples_orig[i], volumes[i % channels]);
-                fail();
+                ck_abort();
             }
         }
     }
diff --git a/src/tests/cpulimit-test.c b/src/tests/cpulimit-test.c
index 3a8124f..e01a5b8 100644
--- a/src/tests/cpulimit-test.c
+++ b/src/tests/cpulimit-test.c
@@ -48,7 +48,7 @@ static void func(pa_mainloop_api *m, pa_signal_event *e, int sig, void *userdata
     if ((now - start) >= 30) {
         m->quit(m, 1);
         fprintf(stderr, "Test failed\n");
-        fail();
+        ck_abort();
     } else
         raise(SIGUSR1);
 }
@@ -78,7 +78,7 @@ START_TEST (cpulimit_test) {
 
         if ((now - start) >= 30) {
             fprintf(stderr, "Test failed\n");
-            fail();
+            ck_abort();
             break;
         }
     }
diff --git a/src/tests/extended-test.c b/src/tests/extended-test.c
index ee766b8..0d08fac 100644
--- a/src/tests/extended-test.c
+++ b/src/tests/extended-test.c
@@ -100,7 +100,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) {
         default:
         case PA_STREAM_FAILED:
             fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
-            fail();
+            ck_abort();
     }
 }
 
@@ -151,7 +151,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
         case PA_CONTEXT_FAILED:
         default:
             fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c)));
-            fail();
+            ck_abort();
     }
 }
 
diff --git a/src/tests/get-binary-name-test.c b/src/tests/get-binary-name-test.c
index 4c855bb..cd53bde 100644
--- a/src/tests/get-binary-name-test.c
+++ b/src/tests/get-binary-name-test.c
@@ -39,7 +39,7 @@ START_TEST (getbinaryname_test) {
         if (!pa_get_binary_name(exename, allocated)) {
             pa_log_error("failed to read binary name");
             pa_xfree(exename);
-            fail();
+            ck_abort();
         }
 
         if (strlen(exename) < allocated - 1) {
diff --git a/src/tests/interpol-test.c b/src/tests/interpol-test.c
index 7a7bffc..b4cf18c 100644
--- a/src/tests/interpol-test.c
+++ b/src/tests/interpol-test.c
@@ -144,7 +144,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
         case PA_CONTEXT_FAILED:
         default:
             pa_log_error("Context error: %s", pa_strerror(pa_context_errno(c)));
-            fail();
+            ck_abort();
     }
 }
 
diff --git a/src/tests/mult-s16-test.c b/src/tests/mult-s16-test.c
index 7340d85..91740c2 100644
--- a/src/tests/mult-s16-test.c
+++ b/src/tests/mult-s16-test.c
@@ -65,7 +65,7 @@ START_TEST (mult_s16_test) {
 
         if (a != b) {
             pa_log_debug("%d: %d != %d", i, a, b);
-            fail();
+            ck_abort();
         }
     }
 
diff --git a/src/tests/sync-playback.c b/src/tests/sync-playback.c
index f06b459..9ef038c 100644
--- a/src/tests/sync-playback.c
+++ b/src/tests/sync-playback.c
@@ -106,7 +106,7 @@ static void stream_state_callback(pa_stream *s, void *userdata) {
         default:
         case PA_STREAM_FAILED:
             fprintf(stderr, "Stream error: %s\n", pa_strerror(pa_context_errno(pa_stream_get_context(s))));
-            fail();
+            ck_abort();
     }
 }
 
@@ -148,7 +148,7 @@ static void context_state_callback(pa_context *c, void *userdata) {
         case PA_CONTEXT_FAILED:
         default:
             fprintf(stderr, "Context error: %s\n", pa_strerror(pa_context_errno(c)));
-            fail();
+            ck_abort();
     }
 }
 

commit 8949ed96c635959ea9d010c5d4b7fcc021486532
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:04 2016 +0530

    echo-cancel: Add a modarg toggle for VAD in the webrtc canceller

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 8e2967e..db2901f 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -47,6 +47,7 @@ PA_C_DECL_END
 #define DEFAULT_ROUTING_MODE "speakerphone"
 #define DEFAULT_COMFORT_NOISE true
 #define DEFAULT_DRIFT_COMPENSATION false
+#define DEFAULT_VAD true
 #define DEFAULT_EXTENDED_FILTER false
 #define DEFAULT_INTELLIGIBILITY_ENHANCER false
 #define DEFAULT_EXPERIMENTAL_AGC false
@@ -64,6 +65,7 @@ static const char* const valid_modargs[] = {
     "routing_mode",
     "comfort_noise",
     "drift_compensation",
+    "voice_detection",
     "extended_filter",
     "intelligibility_enhancer",
     "experimental_agc",
@@ -143,7 +145,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     webrtc::AudioProcessing *apm = NULL;
     webrtc::ProcessingConfig pconfig;
     webrtc::Config config;
-    bool hpf, ns, agc, dgc, mobile, cn, ext_filter, intelligibility, experimental_agc;
+    bool hpf, ns, agc, dgc, mobile, cn, vad, ext_filter, intelligibility, experimental_agc;
     int rm = -1;
     pa_modargs *ma;
     bool trace = false;
@@ -217,6 +219,12 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         }
     }
 
+    vad = DEFAULT_VAD;
+    if (pa_modargs_get_value_boolean(ma, "voice_detection", &vad) < 0) {
+        pa_log("Failed to parse voice_detection value");
+        goto fail;
+    }
+
     ext_filter = DEFAULT_EXTENDED_FILTER;
     if (pa_modargs_get_value_boolean(ma, "extended_filter", &ext_filter) < 0) {
         pa_log("Failed to parse extended_filter value");
@@ -304,7 +312,8 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         apm->gain_control()->Enable(true);
     }
 
-    apm->voice_detection()->Enable(true);
+    if (vad)
+        apm->voice_detection()->Enable(true);
 
     ec->params.priv.webrtc.apm = apm;
     ec->params.priv.webrtc.sample_spec = *out_ss;

commit 90608feac0a541ffc5ec97a7be25c76e8dfcb7e8
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:03 2016 +0530

    echo-cancel: Allow enabling of the webrtc experimental AGC mechanism

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index be13d75..8e2967e 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -49,6 +49,7 @@ PA_C_DECL_END
 #define DEFAULT_DRIFT_COMPENSATION false
 #define DEFAULT_EXTENDED_FILTER false
 #define DEFAULT_INTELLIGIBILITY_ENHANCER false
+#define DEFAULT_EXPERIMENTAL_AGC false
 #define DEFAULT_TRACE false
 
 #define WEBRTC_AGC_MAX_VOLUME 255
@@ -65,6 +66,7 @@ static const char* const valid_modargs[] = {
     "drift_compensation",
     "extended_filter",
     "intelligibility_enhancer",
+    "experimental_agc",
     "trace",
     NULL
 };
@@ -141,7 +143,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     webrtc::AudioProcessing *apm = NULL;
     webrtc::ProcessingConfig pconfig;
     webrtc::Config config;
-    bool hpf, ns, agc, dgc, mobile, cn, ext_filter, intelligibility;
+    bool hpf, ns, agc, dgc, mobile, cn, ext_filter, intelligibility, experimental_agc;
     int rm = -1;
     pa_modargs *ma;
     bool trace = false;
@@ -227,10 +229,18 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         goto fail;
     }
 
+    experimental_agc = DEFAULT_EXPERIMENTAL_AGC;
+    if (pa_modargs_get_value_boolean(ma, "experimental_agc", &experimental_agc) < 0) {
+        pa_log("Failed to parse experimental_agc value");
+        goto fail;
+    }
+
     if (ext_filter)
         config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true));
     if (intelligibility)
         pa_log_warn("The intelligibility enhancer is not currently supported");
+    if (experimental_agc)
+        config.Set<webrtc::ExperimentalAgc>(new webrtc::ExperimentalAgc(true, WEBRTC_AGC_START_VOLUME));
 
     trace = DEFAULT_TRACE;
     if (pa_modargs_get_value_boolean(ma, "trace", &trace) < 0) {

commit 19fb2481ea389d0f3e5f45e4bf5b94a7ac1fd399
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:02 2016 +0530

    echo-cancel: Start capture at a sane volume if we're doing webrtc AGC
    
    This is required to make sure the capture output has sufficient energy
    for the AGC to do its job.

diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index 2a0dee2..cc554d5 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -68,6 +68,7 @@ struct pa_echo_canceller_params {
             pa_sample_spec sample_spec;
             void *trace_callback;
             bool agc;
+            bool first;
         } webrtc;
 #endif
         /* each canceller-specific structure goes here */
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index d818fc0..be13d75 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -52,6 +52,7 @@ PA_C_DECL_END
 #define DEFAULT_TRACE false
 
 #define WEBRTC_AGC_MAX_VOLUME 255
+#define WEBRTC_AGC_START_VOLUME 85
 
 static const char* const valid_modargs[] = {
     "high_pass_filter",
@@ -299,6 +300,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     ec->params.priv.webrtc.sample_spec = *out_ss;
     ec->params.priv.webrtc.blocksize = (uint64_t)pa_bytes_per_second(out_ss) * BLOCK_SIZE_US / PA_USEC_PER_SEC;
     *nframes = ec->params.priv.webrtc.blocksize / pa_frame_size(out_ss);
+    ec->params.priv.webrtc.first = true;
 
     pa_modargs_free(ma);
     return true;
@@ -363,7 +365,17 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     apm->ProcessStream(&out_frame);
 
     if (ec->params.priv.webrtc.agc) {
-        new_volume = apm->gain_control()->stream_analog_level();
+        if (PA_UNLIKELY(ec->params.priv.webrtc.first)) {
+            /* We start at a sane default volume (taken from the Chromium
+             * condition on the experimental AGC in audio_processing.h). This is
+             * needed to make sure that there's enough energy in the capture
+             * signal for the AGC to work */
+            ec->params.priv.webrtc.first = false;
+            new_volume = WEBRTC_AGC_START_VOLUME;
+        } else {
+            new_volume = apm->gain_control()->stream_analog_level();
+        }
+
         if (old_volume != new_volume) {
             pa_cvolume_set(&v, ss->channels, webrtc_volume_to_pa(new_volume));
             pa_echo_canceller_set_capture_volume(ec, &v);

commit a84d65d74805367f35048fa1734dfd1436246042
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:01 2016 +0530

    echo-cancel: Deal with volume limit breakage in webrtc AGC
    
    The AGC code no longer seems to honour the analog volume limits we set,
    and internally uses 0-255 as the volume range. So we switch to use that
    (keeping the old API usage as is in case this gets fixed upstream).

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index bee930b..d818fc0 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -51,6 +51,8 @@ PA_C_DECL_END
 #define DEFAULT_INTELLIGIBILITY_ENHANCER false
 #define DEFAULT_TRACE false
 
+#define WEBRTC_AGC_MAX_VOLUME 255
+
 static const char* const valid_modargs[] = {
     "high_pass_filter",
     "noise_suppression",
@@ -95,6 +97,16 @@ class PaWebrtcTraceCallback : public webrtc::TraceCallback {
     }
 };
 
+static int webrtc_volume_from_pa(pa_volume_t v)
+{
+    return (v * WEBRTC_AGC_MAX_VOLUME) / PA_VOLUME_NORM;
+}
+
+static pa_volume_t webrtc_volume_to_pa(int v)
+{
+    return (v * PA_VOLUME_NORM) / WEBRTC_AGC_MAX_VOLUME;
+}
+
 static void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
                                      pa_sample_spec *play_ss, pa_channel_map *play_map,
                                      pa_sample_spec *out_ss, pa_channel_map *out_map)
@@ -271,7 +283,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
             ec->params.priv.webrtc.agc = false;
         } else {
             apm->gain_control()->set_mode(webrtc::GainControl::kAdaptiveAnalog);
-            if (apm->gain_control()->set_analog_level_limits(0, PA_VOLUME_NORM-1) != apm->kNoError) {
+            if (apm->gain_control()->set_analog_level_limits(0, WEBRTC_AGC_MAX_VOLUME) != apm->kNoError) {
                 pa_log("Failed to initialise AGC");
                 goto fail;
             }
@@ -330,6 +342,7 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     webrtc::AudioFrame out_frame;
     const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
     pa_cvolume v;
+    int old_volume, new_volume;
 
     out_frame.num_channels_ = ss->channels;
     out_frame.sample_rate_hz_ = ss->rate;
@@ -342,15 +355,19 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     if (ec->params.priv.webrtc.agc) {
         pa_cvolume_init(&v);
         pa_echo_canceller_get_capture_volume(ec, &v);
-        apm->gain_control()->set_stream_analog_level(pa_cvolume_avg(&v));
+        old_volume = webrtc_volume_from_pa(pa_cvolume_avg(&v));
+        apm->gain_control()->set_stream_analog_level(old_volume);
     }
 
     apm->set_stream_delay_ms(0);
     apm->ProcessStream(&out_frame);
 
     if (ec->params.priv.webrtc.agc) {
-        pa_cvolume_set(&v, ss->channels, apm->gain_control()->stream_analog_level());
-        pa_echo_canceller_set_capture_volume(ec, &v);
+        new_volume = apm->gain_control()->stream_analog_level();
+        if (old_volume != new_volume) {
+            pa_cvolume_set(&v, ss->channels, webrtc_volume_to_pa(new_volume));
+            pa_echo_canceller_set_capture_volume(ec, &v);
+        }
     }
 
     memcpy(out, out_frame.data_, ec->params.priv.webrtc.blocksize);

commit 426c98acbb75db09781c2bab254be34f316327d1
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:47:00 2016 +0530

    echo-cancel: Allow enabling tracing output from the webrtc canceller

diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h
index 29d1574..2a0dee2 100644
--- a/src/modules/echo-cancel/echo-cancel.h
+++ b/src/modules/echo-cancel/echo-cancel.h
@@ -66,6 +66,7 @@ struct pa_echo_canceller_params {
             void *apm;
             uint32_t blocksize;
             pa_sample_spec sample_spec;
+            void *trace_callback;
             bool agc;
         } webrtc;
 #endif
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index cc8cc34..bee930b 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -35,6 +35,7 @@ PA_C_DECL_END
 
 #include <webrtc/modules/audio_processing/include/audio_processing.h>
 #include <webrtc/modules/interface/module_common_types.h>
+#include <webrtc/system_wrappers/include/trace.h>
 
 #define BLOCK_SIZE_US 10000
 
@@ -48,6 +49,7 @@ PA_C_DECL_END
 #define DEFAULT_DRIFT_COMPENSATION false
 #define DEFAULT_EXTENDED_FILTER false
 #define DEFAULT_INTELLIGIBILITY_ENHANCER false
+#define DEFAULT_TRACE false
 
 static const char* const valid_modargs[] = {
     "high_pass_filter",
@@ -60,6 +62,7 @@ static const char* const valid_modargs[] = {
     "drift_compensation",
     "extended_filter",
     "intelligibility_enhancer",
+    "trace",
     NULL
 };
 
@@ -78,6 +81,20 @@ static int routing_mode_from_string(const char *rmode) {
         return -1;
 }
 
+class PaWebrtcTraceCallback : public webrtc::TraceCallback {
+    void Print(webrtc::TraceLevel level, const char *message, int length)
+    {
+        if (level & webrtc::kTraceError || level & webrtc::kTraceCritical)
+            pa_log(message);
+        else if (level & webrtc::kTraceWarning)
+            pa_log_warn(message);
+        else if (level & webrtc::kTraceInfo)
+            pa_log_info(message);
+        else
+            pa_log_debug(message);
+    }
+};
+
 static void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
                                      pa_sample_spec *play_ss, pa_channel_map *play_map,
                                      pa_sample_spec *out_ss, pa_channel_map *out_map)
@@ -114,6 +131,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     bool hpf, ns, agc, dgc, mobile, cn, ext_filter, intelligibility;
     int rm = -1;
     pa_modargs *ma;
+    bool trace = false;
 
     if (!(ma = pa_modargs_new(args, valid_modargs))) {
         pa_log("Failed to parse submodule arguments.");
@@ -201,6 +219,19 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     if (intelligibility)
         pa_log_warn("The intelligibility enhancer is not currently supported");
 
+    trace = DEFAULT_TRACE;
+    if (pa_modargs_get_value_boolean(ma, "trace", &trace) < 0) {
+        pa_log("Failed to parse trace value");
+        goto fail;
+    }
+
+    if (trace) {
+        webrtc::Trace::CreateTrace();
+        webrtc::Trace::set_level_filter(webrtc::kTraceAll);
+        ec->params.priv.webrtc.trace_callback = new PaWebrtcTraceCallback();
+        webrtc::Trace::SetTraceCallback((PaWebrtcTraceCallback *) ec->params.priv.webrtc.trace_callback);
+    }
+
     pa_webrtc_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
 
     apm = webrtc::AudioProcessing::Create(config);
@@ -263,7 +294,10 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
 fail:
     if (ma)
         pa_modargs_free(ma);
-    if (apm)
+    if (ec->params.priv.webrtc.trace_callback) {
+        webrtc::Trace::ReturnTrace();
+        delete ((PaWebrtcTraceCallback *) ec->params.priv.webrtc.trace_callback);
+    } if (apm)
         delete apm;
 
     return false;
@@ -335,6 +369,11 @@ void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *
 }
 
 void pa_webrtc_ec_done(pa_echo_canceller *ec) {
+    if (ec->params.priv.webrtc.trace_callback) {
+        webrtc::Trace::ReturnTrace();
+        delete ((PaWebrtcTraceCallback *) ec->params.priv.webrtc.trace_callback);
+    }
+
     if (ec->params.priv.webrtc.apm) {
         delete (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
         ec->params.priv.webrtc.apm = NULL;

commit 6431636fe10cfda2eaa5104a8b67c68f3e01f254
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:46:59 2016 +0530

    echo-cancel: Mark private function as static

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 0d357fb..cc8cc34 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -78,9 +78,9 @@ static int routing_mode_from_string(const char *rmode) {
         return -1;
 }
 
-void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
-                              pa_sample_spec *play_ss, pa_channel_map *play_map,
-                              pa_sample_spec *out_ss, pa_channel_map *out_map)
+static void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
+                                     pa_sample_spec *play_ss, pa_channel_map *play_map,
+                                     pa_sample_spec *out_ss, pa_channel_map *out_map)
 {
     rec_ss->format = PA_SAMPLE_S16NE;
     play_ss->format = PA_SAMPLE_S16NE;

commit 0c86543c5105c1e1d690af121ac60d2743e58055
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:46:58 2016 +0530

    echo-cancel: Add a modarg to use sink/source master format and spec
    
    This allows us to inherit the sample spec parameters from the sink and
    source master (rather than forcing 32 kHz / mono). It is still possible
    to override some of the parameters for the source side with modargs.
    
    My original testing showed that these parameters provided a decent
    perf/quality trade-off on lower end hardware (which I no longer have
    access to). I figure it makes sense to continue with that for now, and
    in the future this can be relaxed (use_master_format=yes could be the
    default, and resource-constrained systems can disable it).

diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index c3a6a1c..484281f 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -75,6 +75,7 @@ PA_MODULE_USAGE(
           "save_aec=<save AEC data in /tmp> "
           "autoloaded=<set if this module is being loaded automatically> "
           "use_volume_sharing=<yes or no> "
+          "use_master_format=<yes or no> "
         ));
 
 /* NOTE: Make sure the enum and ec_table are maintained in the correct order */
@@ -140,6 +141,7 @@ static const pa_echo_canceller ec_table[] = {
 #define DEFAULT_ADJUST_TOLERANCE (5*PA_USEC_PER_MSEC)
 #define DEFAULT_SAVE_AEC false
 #define DEFAULT_AUTOLOADED false
+#define DEFAULT_USE_MASTER_FORMAT false
 
 #define MEMBLOCKQ_MAXLENGTH (16*1024*1024)
 
@@ -275,6 +277,7 @@ static const char* const valid_modargs[] = {
     "save_aec",
     "autoloaded",
     "use_volume_sharing",
+    "use_master_format",
     NULL
 };
 
@@ -1659,6 +1662,7 @@ int pa__init(pa_module*m) {
     pa_memchunk silence;
     uint32_t temp;
     uint32_t nframes = 0;
+    bool use_master_format;
 
     pa_assert(m);
 
@@ -1684,15 +1688,30 @@ int pa__init(pa_module*m) {
         goto fail;
     }
 
-    source_ss = source_master->sample_spec;
-    source_ss.rate = DEFAULT_RATE;
-    source_ss.channels = DEFAULT_CHANNELS;
-    pa_channel_map_init_auto(&source_map, source_ss.channels, PA_CHANNEL_MAP_DEFAULT);
+    /* Set to true if we just want to inherit sample spec and channel map from the sink and source master */
+    use_master_format = DEFAULT_USE_MASTER_FORMAT;
+    if (pa_modargs_get_value_boolean(ma, "use_master_format", &use_master_format) < 0) {
+        pa_log("use_master_format= expects a boolean argument");
+        goto fail;
+    }
 
+    source_ss = source_master->sample_spec;
     sink_ss = sink_master->sample_spec;
-    sink_ss.rate = DEFAULT_RATE;
-    sink_ss.channels = DEFAULT_CHANNELS;
-    pa_channel_map_init_auto(&sink_map, sink_ss.channels, PA_CHANNEL_MAP_DEFAULT);
+
+    if (use_master_format) {
+        source_map = source_master->channel_map;
+        sink_map = sink_master->channel_map;
+    } else {
+        source_ss = source_master->sample_spec;
+        source_ss.rate = DEFAULT_RATE;
+        source_ss.channels = DEFAULT_CHANNELS;
+        pa_channel_map_init_auto(&source_map, source_ss.channels, PA_CHANNEL_MAP_DEFAULT);
+
+        sink_ss = sink_master->sample_spec;
+        sink_ss.rate = DEFAULT_RATE;
+        sink_ss.channels = DEFAULT_CHANNELS;
+        pa_channel_map_init_auto(&sink_map, sink_ss.channels, PA_CHANNEL_MAP_DEFAULT);
+    }
 
     u = pa_xnew0(struct userdata, 1);
     if (!u) {

commit 23ef4911227e69fb0c289a991e2b5d61bb1b0dd6
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:46:57 2016 +0530

    echo-cancel: Express restrictions correctly on webrtc AEC stream config
    
    In the refactoring, I'm expressing the constraints in what I see to be a
    more natural way -- rec_ss expresses what we're feeding the canceller,
    so it makes sense to apply the constraints on what the canceller accepts
    there. This then propagates to the output spec.
    
    This also exposes the range of sample rates that the library actually
    supports (8, 16, 32 and 48 kHz).

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 7e4e952..0d357fb 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -78,6 +78,31 @@ static int routing_mode_from_string(const char *rmode) {
         return -1;
 }
 
+void pa_webrtc_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map,
+                              pa_sample_spec *play_ss, pa_channel_map *play_map,
+                              pa_sample_spec *out_ss, pa_channel_map *out_map)
+{
+    rec_ss->format = PA_SAMPLE_S16NE;
+    play_ss->format = PA_SAMPLE_S16NE;
+
+    /* AudioProcessing expects one of the following rates */
+    if (rec_ss->rate >= 48000)
+        rec_ss->rate = 48000;
+    else if (rec_ss->rate >= 32000)
+        rec_ss->rate = 32000;
+    else if (rec_ss->rate >= 16000)
+        rec_ss->rate = 16000;
+    else
+        rec_ss->rate = 8000;
+
+    /* In int16 mode, AudioProcessing will give us the same spec we give it */
+    *out_ss = *rec_ss;
+    *out_map = *rec_map;
+
+    /* Playback stream rate needs to be the same as capture */
+    play_ss->rate = rec_ss->rate;
+}
+
 bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
                        pa_sample_spec *rec_ss, pa_channel_map *rec_map,
                        pa_sample_spec *play_ss, pa_channel_map *play_map,
@@ -176,15 +201,9 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     if (intelligibility)
         pa_log_warn("The intelligibility enhancer is not currently supported");
 
-    apm = webrtc::AudioProcessing::Create(config);
+    pa_webrtc_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map);
 
-    out_ss->format = PA_SAMPLE_S16NE;
-    *play_ss = *out_ss;
-    /* FIXME: the implementation actually allows a different number of
-     * source/sink channels. Do we want to support that? */
-    *play_map = *out_map;
-    *rec_ss = *out_ss;
-    *rec_map = *out_map;
+    apm = webrtc::AudioProcessing::Create(config);
 
     pconfig = {
         webrtc::StreamConfig(rec_ss->rate, rec_ss->channels, false), /* input stream */

commit d777838fbb1a8e1f012e249bb1a0816d9141dd45
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:46:56 2016 +0530

    echo-cancel: Canceller may use different spec for playback and capture
    
    The original intention was to configure low enough parameters to keep
    CPU consumption down. Prior to this change, we assumed that the EC
    backend would override the sink parameters based on the source
    parameters to achieve this goal, and with this change we remove that
    assumption by forcing the default parameters for the sink to be low
    enough.

diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c
index 18fe5dc..c3a6a1c 100644
--- a/src/modules/echo-cancel/module-echo-cancel.c
+++ b/src/modules/echo-cancel/module-echo-cancel.c
@@ -1690,7 +1690,9 @@ int pa__init(pa_module*m) {
     pa_channel_map_init_auto(&source_map, source_ss.channels, PA_CHANNEL_MAP_DEFAULT);
 
     sink_ss = sink_master->sample_spec;
-    sink_map = sink_master->channel_map;
+    sink_ss.rate = DEFAULT_RATE;
+    sink_ss.channels = DEFAULT_CHANNELS;
+    pa_channel_map_init_auto(&sink_map, sink_ss.channels, PA_CHANNEL_MAP_DEFAULT);
 
     u = pa_xnew0(struct userdata, 1);
     if (!u) {

commit fab8a16b0f1fe55c0ac209a486f7a7546768867d
Author: Tanu Kaskinen <tanuk at iki.fi>
Date:   Sat Feb 20 14:32:59 2016 +0200

    echo-cancel: Add some bits for webrtc intelligibility enhancer
    
    It's not possible to enable the intelligibility enhancer at the
    moment, because the feature would require modifying the audio that we
    play to speakers, which we don't do currently. All audio processing is
    done at the source side, and it's not easy to change that.
    
    This patch is based on Arun Raghavan's code, I just reordered things
    a bit and reworded the FIXME comment.

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index ee3075f..7e4e952 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -47,6 +47,7 @@ PA_C_DECL_END
 #define DEFAULT_COMFORT_NOISE true
 #define DEFAULT_DRIFT_COMPENSATION false
 #define DEFAULT_EXTENDED_FILTER false
+#define DEFAULT_INTELLIGIBILITY_ENHANCER false
 
 static const char* const valid_modargs[] = {
     "high_pass_filter",
@@ -58,6 +59,7 @@ static const char* const valid_modargs[] = {
     "comfort_noise",
     "drift_compensation",
     "extended_filter",
+    "intelligibility_enhancer",
     NULL
 };
 
@@ -84,7 +86,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     webrtc::AudioProcessing *apm = NULL;
     webrtc::ProcessingConfig pconfig;
     webrtc::Config config;
-    bool hpf, ns, agc, dgc, mobile, cn, ext_filter;
+    bool hpf, ns, agc, dgc, mobile, cn, ext_filter, intelligibility;
     int rm = -1;
     pa_modargs *ma;
 
@@ -163,8 +165,16 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         goto fail;
     }
 
+    intelligibility = DEFAULT_INTELLIGIBILITY_ENHANCER;
+    if (pa_modargs_get_value_boolean(ma, "intelligibility_enhancer", &intelligibility) < 0) {
+        pa_log("Failed to parse intelligibility_enhancer value");
+        goto fail;
+    }
+
     if (ext_filter)
         config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true));
+    if (intelligibility)
+        pa_log_warn("The intelligibility enhancer is not currently supported");
 
     apm = webrtc::AudioProcessing::Create(config);
 
@@ -253,7 +263,13 @@ void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
     pa_assert(play_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
     memcpy(play_frame.data_, play, ec->params.priv.webrtc.blocksize);
 
-    apm->AnalyzeReverseStream(&play_frame);
+    apm->ProcessReverseStream(&play_frame);
+
+    /* FIXME: If ProcessReverseStream() makes any changes to the audio, such as
+     * applying intelligibility enhancement, those changes don't have any
+     * effect. This function is called at the source side, but the processing
+     * would have to be done in the sink to be able to feed the processed audio
+     * to speakers. */
 }
 
 void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out) {

commit a14db55c2bc912ed68eeb5059d2abc75e9ad9a47
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:46:54 2016 +0530

    echo-cancel: Allow enabling the extended filter in webrtc AEC
    
    This creates a longer filter that is more complex and less sensitive to
    incorrect delay reporting from the hardware. There is also a
    delay-agnostic mode that can eventually be enabled if required.
    
    In some very quick testing, not enabling this seems to provide better
    results during double-talk.

diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index ace5150..ee3075f 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -46,6 +46,7 @@ PA_C_DECL_END
 #define DEFAULT_ROUTING_MODE "speakerphone"
 #define DEFAULT_COMFORT_NOISE true
 #define DEFAULT_DRIFT_COMPENSATION false
+#define DEFAULT_EXTENDED_FILTER false
 
 static const char* const valid_modargs[] = {
     "high_pass_filter",
@@ -56,6 +57,7 @@ static const char* const valid_modargs[] = {
     "routing_mode",
     "comfort_noise",
     "drift_compensation",
+    "extended_filter",
     NULL
 };
 
@@ -81,7 +83,8 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
                        uint32_t *nframes, const char *args) {
     webrtc::AudioProcessing *apm = NULL;
     webrtc::ProcessingConfig pconfig;
-    bool hpf, ns, agc, dgc, mobile, cn;
+    webrtc::Config config;
+    bool hpf, ns, agc, dgc, mobile, cn, ext_filter;
     int rm = -1;
     pa_modargs *ma;
 
@@ -154,7 +157,16 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         }
     }
 
-    apm = webrtc::AudioProcessing::Create();
+    ext_filter = DEFAULT_EXTENDED_FILTER;
+    if (pa_modargs_get_value_boolean(ma, "extended_filter", &ext_filter) < 0) {
+        pa_log("Failed to parse extended_filter value");
+        goto fail;
+    }
+
+    if (ext_filter)
+        config.Set<webrtc::ExtendedFilter>(new webrtc::ExtendedFilter(true));
+
+    apm = webrtc::AudioProcessing::Create(config);
 
     out_ss->format = PA_SAMPLE_S16NE;
     *play_ss = *out_ss;

commit f8beaae23885da189a8de8194fc6674d89dd4d46
Author: Arun Raghavan <git at arunraghavan.net>
Date:   Wed Feb 17 19:46:53 2016 +0530

    echo-cancel: Update webrtc-audio-processing usage to new API
    
    The code now needs C++11 support to compile with the updated
    webrtc-audio-processing library.

diff --git a/configure.ac b/configure.ac
index 99c425d..4553d71 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,6 +85,7 @@ AM_PROG_CC_C_O
 # Only required if you want the WebRTC canceller -- no runtime dep on
 # libstdc++ otherwise
 AC_PROG_CXX
+AX_CXX_COMPILE_STDCXX_11
 AC_PROG_GCC_TRADITIONAL
 AC_USE_SYSTEM_EXTENSIONS
 
@@ -1397,7 +1398,7 @@ AC_ARG_ENABLE([webrtc-aec],
     AS_HELP_STRING([--enable-webrtc-aec], [Enable the optional WebRTC-based echo canceller]))
 
 AS_IF([test "x$enable_webrtc_aec" != "xno"],
-    [PKG_CHECK_MODULES(WEBRTC, [ webrtc-audio-processing ], [HAVE_WEBRTC=1], [HAVE_WEBRTC=0])],
+    [PKG_CHECK_MODULES(WEBRTC, [ webrtc-audio-processing >= 0.2 ], [HAVE_WEBRTC=1], [HAVE_WEBRTC=0])],
     [HAVE_WEBRTC=0])
 
 AS_IF([test "x$enable_webrtc_aec" = "xyes" && test "x$HAVE_WEBRTC" = "x0"],
diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4
new file mode 100644
index 0000000..079e17d
--- /dev/null
+++ b/m4/ax_cxx_compile_stdcxx.m4
@@ -0,0 +1,558 @@
+# ===========================================================================
+#   http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the specified
+#   version of the C++ standard.  If necessary, add switches to CXXFLAGS to
+#   enable support.  VERSION may be '11' (for the C++11 standard) or '14'
+#   (for the C++14 standard).
+#
+#   The second argument, if specified, indicates whether you insist on an
+#   extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+#   -std=c++11).  If neither is specified, you get whatever works, with
+#   preference for an extended mode.
+#
+#   The third argument, if specified 'mandatory' or if left unspecified,
+#   indicates that baseline support for the specified C++ standard is
+#   required and that the macro should error out if no mode with that
+#   support is found.  If specified 'optional', then configuration proceeds
+#   regardless, after defining HAVE_CXX${VERSION} if and only if a
+#   supporting mode is found.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz at redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw at panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr at ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov at google.com>
+#   Copyright (c) 2015 Paul Norman <penorman at mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz at klammler.eu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved.  This file is offered as-is, without any
+#   warranty.
+
+#serial 1
+
+dnl  This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
+dnl  (serial version number 13).
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
+  m4_if([$1], [11], [],
+        [$1], [14], [],
+        [$1], [17], [m4_fatal([support for C++17 not yet implemented in AX_CXX_COMPILE_STDCXX])],
+        [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$2], [], [],
+        [$2], [ext], [],
+        [$2], [noext], [],
+        [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
+  m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
+        [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
+        [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
+  AC_LANG_PUSH([C++])dnl
+  ac_success=no
+  AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
+  ax_cv_cxx_compile_cxx$1,
+  [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+    [ax_cv_cxx_compile_cxx$1=yes],
+    [ax_cv_cxx_compile_cxx$1=no])])
+  if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
+    ac_success=yes
+  fi
+
+  m4_if([$2], [noext], [], [dnl
+  if test x$ac_success = xno; then
+    for switch in -std=gnu++$1 -std=gnu++0x; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+
+  m4_if([$2], [ext], [], [dnl
+  if test x$ac_success = xno; then
+    dnl HP's aCC needs +std=c++11 according to:
+    dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
+    dnl Cray's crayCC needs "-h std=c++11"
+    for switch in -std=c++$1 -std=c++0x +std=c++$1 "-h std=c++$1"; do
+      cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
+      AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
+                     $cachevar,
+        [ac_save_CXXFLAGS="$CXXFLAGS"
+         CXXFLAGS="$CXXFLAGS $switch"
+         AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
+          [eval $cachevar=yes],
+          [eval $cachevar=no])
+         CXXFLAGS="$ac_save_CXXFLAGS"])
+      if eval test x\$$cachevar = xyes; then
+        CXXFLAGS="$CXXFLAGS $switch"
+        ac_success=yes
+        break
+      fi
+    done
+  fi])
+  AC_LANG_POP([C++])
+  if test x$ax_cxx_compile_cxx$1_required = xtrue; then
+    if test x$ac_success = xno; then
+      AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
+    fi
+  else
+    if test x$ac_success = xno; then
+      HAVE_CXX$1=0
+      AC_MSG_NOTICE([No compiler with C++$1 support was found])
+    else
+      HAVE_CXX$1=1
+      AC_DEFINE(HAVE_CXX$1,1,
+                [define if the compiler supports basic C++$1 syntax])
+    fi
+
+    AC_SUBST(HAVE_CXX$1)
+  fi
+])
+
+
+dnl  Test body for checking C++11 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+)
+
+
+dnl  Test body for checking C++14 support
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
+  _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
+)
+
+
+dnl  Tests for new features in C++11
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
+
+// If the compiler admits that it is not ready for C++11, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201103L
+
+#error "This is not a C++11 compiler"
+
+#else
+
+namespace cxx11
+{
+
+  namespace test_static_assert
+  {
+
+    template <typename T>
+    struct check
+    {
+      static_assert(sizeof(int) <= sizeof(T), "not big enough");
+    };
+
+  }
+
+  namespace test_final_override
+  {
+
+    struct Base
+    {
+      virtual void f() {}
+    };
+
+    struct Derived : public Base
+    {
+      virtual void f() override {}
+    };
+
+  }
+
+  namespace test_double_right_angle_brackets
+  {
+
+    template < typename T >
+    struct check {};
+
+    typedef check<void> single_type;
+    typedef check<check<void>> double_type;
+    typedef check<check<check<void>>> triple_type;
+    typedef check<check<check<check<void>>>> quadruple_type;
+
+  }
+
+  namespace test_decltype
+  {
+
+    int
+    f()
+    {
+      int a = 1;
+      decltype(a) b = 2;
+      return a + b;
+    }
+
+  }
+
+  namespace test_type_deduction
+  {
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static const bool value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static const bool value = true;
+    };
+
+    template < typename T1, typename T2 >
+    auto
+    add(T1 a1, T2 a2) -> decltype(a1 + a2)
+    {
+      return a1 + a2;
+    }
+
+    int
+    test(const int c, volatile int v)
+    {
+      static_assert(is_same<int, decltype(0)>::value == true, "");
+      static_assert(is_same<int, decltype(c)>::value == false, "");
+      static_assert(is_same<int, decltype(v)>::value == false, "");
+      auto ac = c;
+      auto av = v;
+      auto sumi = ac + av + 'x';
+      auto sumf = ac + av + 1.0;
+      static_assert(is_same<int, decltype(ac)>::value == true, "");
+      static_assert(is_same<int, decltype(av)>::value == true, "");
+      static_assert(is_same<int, decltype(sumi)>::value == true, "");
+      static_assert(is_same<int, decltype(sumf)>::value == false, "");
+      static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
+      return (sumf > 0.0) ? sumi : add(c, v);
+    }
+
+  }
+
+  namespace test_noexcept
+  {
+
+    int f() { return 0; }
+    int g() noexcept { return 0; }
+
+    static_assert(noexcept(f()) == false, "");
+    static_assert(noexcept(g()) == true, "");
+
+  }
+
+  namespace test_constexpr
+  {
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
+    {
+      return *s ? strlen_c_r(s + 1, acc + 1) : acc;
+    }
+
+    template < typename CharT >
+    unsigned long constexpr
+    strlen_c(const CharT *const s) noexcept
+    {
+      return strlen_c_r(s, 0UL);
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("1") == 1UL, "");
+    static_assert(strlen_c("example") == 7UL, "");
+    static_assert(strlen_c("another\0example") == 7UL, "");
+
+  }
+
+  namespace test_rvalue_references
+  {
+
+    template < int N >
+    struct answer
+    {
+      static constexpr int value = N;
+    };
+
+    answer<1> f(int&)       { return answer<1>(); }
+    answer<2> f(const int&) { return answer<2>(); }
+    answer<3> f(int&&)      { return answer<3>(); }
+
+    void
+    test()
+    {
+      int i = 0;
+      const int c = 0;
+      static_assert(decltype(f(i))::value == 1, "");
+      static_assert(decltype(f(c))::value == 2, "");
+      static_assert(decltype(f(0))::value == 3, "");
+    }
+
+  }
+
+  namespace test_uniform_initialization
+  {
+
+    struct test
+    {
+      static const int zero {};
+      static const int one {1};
+    };
+
+    static_assert(test::zero == 0, "");
+    static_assert(test::one == 1, "");
+
+  }
+
+  namespace test_lambdas
+  {
+
+    void
+    test1()
+    {
+      auto lambda1 = [](){};
+      auto lambda2 = lambda1;
+      lambda1();
+      lambda2();
+    }
+
+    int
+    test2()
+    {
+      auto a = [](int i, int j){ return i + j; }(1, 2);
+      auto b = []() -> int { return '0'; }();
+      auto c = [=](){ return a + b; }();
+      auto d = [&](){ return c; }();
+      auto e = [a, &b](int x) mutable {
+        const auto identity = [](int y){ return y; };
+        for (auto i = 0; i < a; ++i)
+          a += b--;
+        return x + identity(a + b);
+      }(0);
+      return a + b + c + d + e;
+    }
+
+    int
+    test3()
+    {
+      const auto nullary = [](){ return 0; };
+      const auto unary = [](int x){ return x; };
+      using nullary_t = decltype(nullary);
+      using unary_t = decltype(unary);
+      const auto higher1st = [](nullary_t f){ return f(); };
+      const auto higher2nd = [unary](nullary_t f1){
+        return [unary, f1](unary_t f2){ return f2(unary(f1())); };
+      };
+      return higher1st(nullary) + higher2nd(nullary)(unary);
+    }
+
+  }
+
+  namespace test_variadic_templates
+  {
+
+    template <int...>
+    struct sum;
+
+    template <int N0, int... N1toN>
+    struct sum<N0, N1toN...>
+    {
+      static constexpr auto value = N0 + sum<N1toN...>::value;
+    };
+
+    template <>
+    struct sum<>
+    {
+      static constexpr auto value = 0;
+    };
+
+    static_assert(sum<>::value == 0, "");
+    static_assert(sum<1>::value == 1, "");
+    static_assert(sum<23>::value == 23, "");
+    static_assert(sum<1, 2>::value == 3, "");
+    static_assert(sum<5, 5, 11>::value == 21, "");
+    static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
+
+  }
+
+  // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+  // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
+  // because of this.
+  namespace test_template_alias_sfinae
+  {
+
+    struct foo {};
+
+    template<typename T>
+    using member = typename T::member_type;
+
+    template<typename T>
+    void func(...) {}
+
+    template<typename T>
+    void func(member<T>*) {}
+
+    void test();
+
+    void test() { func<foo>(0); }
+
+  }
+
+}  // namespace cxx11
+
+#endif  // __cplusplus >= 201103L
+
+]])
+
+
+dnl  Tests for new features in C++14
+
+m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
+
+// If the compiler admits that it is not ready for C++14, why torture it?
+// Hopefully, this will speed up the test.
+
+#ifndef __cplusplus
+
+#error "This is not a C++ compiler"
+
+#elif __cplusplus < 201402L
+
+#error "This is not a C++14 compiler"
+
+#else
+
+namespace cxx14
+{
+
+  namespace test_polymorphic_lambdas
+  {
+
+    int
+    test()
+    {
+      const auto lambda = [](auto&&... args){
+        const auto istiny = [](auto x){
+          return (sizeof(x) == 1UL) ? 1 : 0;
+        };
+        const int aretiny[] = { istiny(args)... };
+        return aretiny[0];
+      };
+      return lambda(1, 1L, 1.0f, '1');
+    }
+
+  }
+
+  namespace test_binary_literals
+  {
+
+    constexpr auto ivii = 0b0000000000101010;
+    static_assert(ivii == 42, "wrong value");
+
+  }
+
+  namespace test_generalized_constexpr
+  {
+
+    template < typename CharT >
+    constexpr unsigned long
+    strlen_c(const CharT *const s) noexcept
+    {
+      auto length = 0UL;
+      for (auto p = s; *p; ++p)
+        ++length;
+      return length;
+    }
+
+    static_assert(strlen_c("") == 0UL, "");
+    static_assert(strlen_c("x") == 1UL, "");
+    static_assert(strlen_c("test") == 4UL, "");
+    static_assert(strlen_c("another\0test") == 7UL, "");
+
+  }
+
+  namespace test_lambda_init_capture
+  {
+
+    int
+    test()
+    {
+      auto x = 0;
+      const auto lambda1 = [a = x](int b){ return a + b; };
+      const auto lambda2 = [a = lambda1(x)](){ return a; };
+      return lambda2();
+    }
+
+  }
+
+  namespace test_digit_seperators
+  {
+
+    constexpr auto ten_million = 100'000'000;
+    static_assert(ten_million == 100000000, "");
+
+  }
+
+  namespace test_return_type_deduction
+  {
+
+    auto f(int& x) { return x; }
+    decltype(auto) g(int& x) { return x; }
+
+    template < typename T1, typename T2 >
+    struct is_same
+    {
+      static constexpr auto value = false;
+    };
+
+    template < typename T >
+    struct is_same<T, T>
+    {
+      static constexpr auto value = true;
+    };
+
+    int
+    test()
+    {
+      auto x = 0;
+      static_assert(is_same<int, decltype(f(x))>::value, "");
+      static_assert(is_same<int&, decltype(g(x))>::value, "");
+      return x;
+    }
+
+  }
+
+}  // namespace cxx14
+
+#endif  // __cplusplus >= 201402L
+
+]])
diff --git a/m4/ax_cxx_compile_stdcxx_11.m4 b/m4/ax_cxx_compile_stdcxx_11.m4
new file mode 100644
index 0000000..09db383
--- /dev/null
+++ b/m4/ax_cxx_compile_stdcxx_11.m4
@@ -0,0 +1,39 @@
+# ============================================================================
+#  http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+#   AX_CXX_COMPILE_STDCXX_11([ext|noext], [mandatory|optional])
+#
+# DESCRIPTION
+#
+#   Check for baseline language coverage in the compiler for the C++11
+#   standard; if necessary, add switches to CXXFLAGS to enable support.
+#
+#   This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX
+#   macro with the version set to C++11.  The two optional arguments are
+#   forwarded literally as the second and third argument respectively.
+#   Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for
+#   more information.  If you want to use this macro, you also need to
+#   download the ax_cxx_compile_stdcxx.m4 file.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Benjamin Kosnik <bkoz at redhat.com>
+#   Copyright (c) 2012 Zack Weinberg <zackw at panix.com>
+#   Copyright (c) 2013 Roy Stogner <roystgnr at ices.utexas.edu>
+#   Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov at google.com>
+#   Copyright (c) 2015 Paul Norman <penorman at mac.com>
+#   Copyright (c) 2015 Moritz Klammler <moritz at klammler.eu>
+#
+#   Copying and distribution of this file, with or without modification, are
+#   permitted in any medium without royalty provided the copyright notice
+#   and this notice are preserved. This file is offered as-is, without any
+#   warranty.
+
+#serial 14
+
+include([ax_cxx_compile_stdcxx.m4])
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [AX_CXX_COMPILE_STDCXX([11], [$1], [$2])])
diff --git a/src/Makefile.am b/src/Makefile.am
index b0ca2bc..432d9c2 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -50,7 +50,8 @@ AM_CPPFLAGS = \
 	-DPULSE_LOCALEDIR=\"$(localedir)\"
 AM_CFLAGS = \
 	$(PTHREAD_CFLAGS)
-AM_CXXFLAGS = $(AM_CFLAGS)
+AM_CXXFLAGS = -std=c++11 \
+	$(PTHREAD_CFLAGS)
 SERVER_CFLAGS = -D__INCLUDED_FROM_PULSE_AUDIO
 
 AM_LIBADD = $(PTHREAD_LIBS) $(INTLLIBS)
diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc
index 511c7ee..ace5150 100644
--- a/src/modules/echo-cancel/webrtc.cc
+++ b/src/modules/echo-cancel/webrtc.cc
@@ -33,8 +33,8 @@ PA_C_DECL_BEGIN
 #include "echo-cancel.h"
 PA_C_DECL_END
 
-#include <audio_processing.h>
-#include <module_common_types.h>
+#include <webrtc/modules/audio_processing/include/audio_processing.h>
+#include <webrtc/modules/interface/module_common_types.h>
 
 #define BLOCK_SIZE_US 10000
 
@@ -80,6 +80,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
                        pa_sample_spec *out_ss, pa_channel_map *out_map,
                        uint32_t *nframes, const char *args) {
     webrtc::AudioProcessing *apm = NULL;
+    webrtc::ProcessingConfig pconfig;
     bool hpf, ns, agc, dgc, mobile, cn;
     int rm = -1;
     pa_modargs *ma;
@@ -153,7 +154,7 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
         }
     }
 
-    apm = webrtc::AudioProcessing::Create(0);
+    apm = webrtc::AudioProcessing::Create();
 
     out_ss->format = PA_SAMPLE_S16NE;
     *play_ss = *out_ss;
@@ -163,22 +164,19 @@ bool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec,
     *rec_ss = *out_ss;
     *rec_map = *out_map;
 
-    apm->set_sample_rate_hz(out_ss->rate);
-
-    apm->set_num_channels(out_ss->channels, out_ss->channels);
-    apm->set_num_reverse_channels(play_ss->channels);
+    pconfig = {
+        webrtc::StreamConfig(rec_ss->rate, rec_ss->channels, false), /* input stream */
+        webrtc::StreamConfig(out_ss->rate, out_ss->channels, false), /* output stream */
+        webrtc::StreamConfig(play_ss->rate, play_ss->channels, false), /* reverse input stream */
+        webrtc::StreamConfig(play_ss->rate, play_ss->channels, false), /* reverse output stream */
+    };
+    apm->Initialize(pconfig);
 
     if (hpf)
         apm->high_pass_filter()->Enable(true);
 
     if (!mobile) {
-        if (ec->params.drift_compensation) {
-            apm->echo_cancellation()->set_device_sample_rate_hz(out_ss->rate);
-            apm->echo_cancellation()->enable_drift_compensation(true);
-        } else {
-            apm->echo_cancellation()->enable_drift_compensation(false);
-        }
-
+        apm->echo_cancellation()->enable_drift_compensation(ec->params.drift_compensation);
         apm->echo_cancellation()->Enable(true);
     } else {
         apm->echo_control_mobile()->set_routing_mode(static_cast<webrtc::EchoControlMobile::RoutingMode>(rm));
@@ -225,7 +223,7 @@ fail:
     if (ma)
         pa_modargs_free(ma);
     if (apm)
-        webrtc::AudioProcessing::Destroy(apm);
+        delete apm;
 
     return false;
 }
@@ -235,10 +233,13 @@ void pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play) {
     webrtc::AudioFrame play_frame;
     const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
 
-    play_frame._audioChannel = ss->channels;
-    play_frame._frequencyInHz = ss->rate;
-    play_frame._payloadDataLengthInSamples = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
-    memcpy(play_frame._payloadData, play, ec->params.priv.webrtc.blocksize);
+    play_frame.num_channels_ = ss->channels;
+    play_frame.sample_rate_hz_ = ss->rate;
+    play_frame.interleaved_ = true;
+    play_frame.samples_per_channel_ = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
+
+    pa_assert(play_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
+    memcpy(play_frame.data_, play, ec->params.priv.webrtc.blocksize);
 
     apm->AnalyzeReverseStream(&play_frame);
 }
@@ -249,10 +250,13 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
     const pa_sample_spec *ss = &ec->params.priv.webrtc.sample_spec;
     pa_cvolume v;
 
-    out_frame._audioChannel = ss->channels;
-    out_frame._frequencyInHz = ss->rate;
-    out_frame._payloadDataLengthInSamples = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
-    memcpy(out_frame._payloadData, rec, ec->params.priv.webrtc.blocksize);
+    out_frame.num_channels_ = ss->channels;
+    out_frame.sample_rate_hz_ = ss->rate;
+    out_frame.interleaved_ = true;
+    out_frame.samples_per_channel_ = ec->params.priv.webrtc.blocksize / pa_frame_size(ss);
+
+    pa_assert(out_frame.samples_per_channel_ <= webrtc::AudioFrame::kMaxDataSizeSamples);
+    memcpy(out_frame.data_, rec, ec->params.priv.webrtc.blocksize);
 
     if (ec->params.priv.webrtc.agc) {
         pa_cvolume_init(&v);
@@ -268,7 +272,7 @@ void pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out
         pa_echo_canceller_set_capture_volume(ec, &v);
     }
 
-    memcpy(out, out_frame._payloadData, ec->params.priv.webrtc.blocksize);
+    memcpy(out, out_frame.data_, ec->params.priv.webrtc.blocksize);
 }
 
 void pa_webrtc_ec_set_drift(pa_echo_canceller *ec, float drift) {
@@ -285,7 +289,7 @@ void pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *
 
 void pa_webrtc_ec_done(pa_echo_canceller *ec) {
     if (ec->params.priv.webrtc.apm) {
-        webrtc::AudioProcessing::Destroy((webrtc::AudioProcessing*)ec->params.priv.webrtc.apm);
+        delete (webrtc::AudioProcessing*)ec->params.priv.webrtc.apm;
         ec->params.priv.webrtc.apm = NULL;
     }
 }



More information about the pulseaudio-commits mailing list