diff --git a/src/modules/echo-cancel/adrian.c b/src/modules/echo-cancel/adrian.c index ab3858a4f..91e3b35f5 100644 --- a/src/modules/echo-cancel/adrian.c +++ b/src/modules/echo-cancel/adrian.c @@ -57,9 +57,9 @@ static void pa_adrian_ec_fixate_spec(pa_sample_spec *source_ss, pa_channel_map * pa_bool_t pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args) + uint32_t *nframes, const char *args) { - int framelen, rate, have_vector = 0; + int rate, have_vector = 0; uint32_t frame_size_ms; pa_modargs *ma; @@ -77,11 +77,10 @@ pa_bool_t pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec, pa_adrian_ec_fixate_spec(source_ss, source_map, sink_ss, sink_map); rate = source_ss->rate; - framelen = (rate * frame_size_ms) / 1000; + *nframes = (rate * frame_size_ms) / 1000; + ec->params.priv.adrian.blocksize = (*nframes) * pa_frame_size(source_ss); - *blocksize = ec->params.priv.adrian.blocksize = framelen * pa_frame_size (source_ss); - - pa_log_debug ("Using framelen %d, blocksize %u, channels %d, rate %d", framelen, ec->params.priv.adrian.blocksize, source_ss->channels, source_ss->rate); + pa_log_debug ("Using nframes %d, blocksize %u, channels %d, rate %d", *nframes, ec->params.priv.adrian.blocksize, source_ss->channels, source_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)) diff --git a/src/modules/echo-cancel/echo-cancel.h b/src/modules/echo-cancel/echo-cancel.h index 9ca78ff03..9f14adeac 100644 --- a/src/modules/echo-cancel/echo-cancel.h +++ b/src/modules/echo-cancel/echo-cancel.h @@ -86,7 +86,7 @@ struct pa_echo_canceller { pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, + uint32_t *nframes, const char *args); /* You should have only one of play()+record() or run() set. The first @@ -94,13 +94,13 @@ struct pa_echo_canceller { * samples yourself. If you set run(), module-echo-cancel will handle * synchronising the playback and record streams. */ - /* Feed the engine 'blocksize' playback bytes.. */ + /* Feed the engine 'nframes' playback frames. */ void (*play) (pa_echo_canceller *ec, const uint8_t *play); - /* Feed the engine 'blocksize' record bytes. blocksize processed bytes are + /* Feed the engine 'nframes' record frames. nframes processed frames are * returned in out. */ void (*record) (pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out); - /* Feed the engine blocksize playback and record streams, with a reasonable - * effort at keeping the two in sync. blocksize processed bytes are + /* Feed the engine nframes playback and record frames, with a reasonable + * effort at keeping the two in sync. nframes processed frames are * returned in out. */ void (*run) (pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); @@ -132,7 +132,7 @@ void pa_echo_canceller_set_capture_volume(pa_echo_canceller *ec, pa_cvolume *v); pa_bool_t pa_null_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args); + uint32_t *nframes, const char *args); void pa_null_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); void pa_null_ec_done(pa_echo_canceller *ec); @@ -141,7 +141,7 @@ void pa_null_ec_done(pa_echo_canceller *ec); pa_bool_t pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args); + uint32_t *nframes, const char *args); void pa_speex_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); void pa_speex_ec_done(pa_echo_canceller *ec); #endif @@ -151,7 +151,7 @@ void pa_speex_ec_done(pa_echo_canceller *ec); pa_bool_t pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args); + uint32_t *nframes, const char *args); void pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); void pa_adrian_ec_done(pa_echo_canceller *ec); #endif @@ -162,7 +162,7 @@ PA_C_DECL_BEGIN pa_bool_t pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args); + uint32_t *nframes, const char *args); 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); void pa_webrtc_ec_set_drift(pa_echo_canceller *ec, float drift); diff --git a/src/modules/echo-cancel/module-echo-cancel.c b/src/modules/echo-cancel/module-echo-cancel.c index 103aef0ef..11ad1de29 100644 --- a/src/modules/echo-cancel/module-echo-cancel.c +++ b/src/modules/echo-cancel/module-echo-cancel.c @@ -211,7 +211,8 @@ struct userdata { pa_bool_t save_aec; pa_echo_canceller *ec; - uint32_t blocksize; + uint32_t source_blocksize; + uint32_t sink_blocksize; pa_bool_t need_realign; @@ -417,7 +418,7 @@ static int source_process_msg_cb(pa_msgobject *o, int code, void *data, int64_t /* Add the latency internal to our source output on top */ pa_bytes_to_usec(pa_memblockq_get_length(u->source_output->thread_info.delay_memblockq), &u->source_output->source->sample_spec) + /* and the buffering we do on the source */ - pa_bytes_to_usec(u->blocksize, &u->source_output->source->sample_spec); + pa_bytes_to_usec(u->source_blocksize, &u->source_output->source->sample_spec); return 0; @@ -735,8 +736,8 @@ static void do_push_drift_comp(struct userdata *u) { * those remainder samples. */ drift = ((float)(plen - u->sink_rem) - (rlen - u->source_rem)) / ((float)(rlen - u->source_rem)); - u->sink_rem = plen % u->blocksize; - u->source_rem = rlen % u->blocksize; + u->sink_rem = plen % u->sink_blocksize; + u->source_rem = rlen % u->source_blocksize; /* Now let the canceller work its drift compensation magic */ u->ec->set_drift(u->ec, drift); @@ -747,8 +748,8 @@ static void do_push_drift_comp(struct userdata *u) { } /* Send in the playback samples first */ - while (plen >= u->blocksize) { - pa_memblockq_peek_fixed_size(u->sink_memblockq, u->blocksize, &pchunk); + while (plen >= u->sink_blocksize) { + pa_memblockq_peek_fixed_size(u->sink_memblockq, u->sink_blocksize, &pchunk); pdata = pa_memblock_acquire(pchunk.memblock); pdata += pchunk.index; @@ -756,27 +757,27 @@ static void do_push_drift_comp(struct userdata *u) { if (u->save_aec) { if (u->drift_file) - fprintf(u->drift_file, "p %d\n", u->blocksize); + fprintf(u->drift_file, "p %d\n", u->sink_blocksize); if (u->played_file) - unused = fwrite(pdata, 1, u->blocksize, u->played_file); + unused = fwrite(pdata, 1, u->sink_blocksize, u->played_file); } pa_memblock_release(pchunk.memblock); - pa_memblockq_drop(u->sink_memblockq, u->blocksize); + pa_memblockq_drop(u->sink_memblockq, u->sink_blocksize); pa_memblock_unref(pchunk.memblock); - plen -= u->blocksize; + plen -= u->sink_blocksize; } /* And now the capture samples */ - while (rlen >= u->blocksize) { - pa_memblockq_peek_fixed_size(u->source_memblockq, u->blocksize, &rchunk); + while (rlen >= u->source_blocksize) { + pa_memblockq_peek_fixed_size(u->source_memblockq, u->source_blocksize, &rchunk); rdata = pa_memblock_acquire(rchunk.memblock); rdata += rchunk.index; cchunk.index = 0; - cchunk.length = u->blocksize; + cchunk.length = u->source_blocksize; cchunk.memblock = pa_memblock_new(u->source->core->mempool, cchunk.length); cdata = pa_memblock_acquire(cchunk.memblock); @@ -784,11 +785,11 @@ static void do_push_drift_comp(struct userdata *u) { if (u->save_aec) { if (u->drift_file) - fprintf(u->drift_file, "c %d\n", u->blocksize); + fprintf(u->drift_file, "c %d\n", u->source_blocksize); if (u->captured_file) - unused = fwrite(rdata, 1, u->blocksize, u->captured_file); + unused = fwrite(rdata, 1, u->source_blocksize, u->captured_file); if (u->canceled_file) - unused = fwrite(cdata, 1, u->blocksize, u->canceled_file); + unused = fwrite(cdata, 1, u->source_blocksize, u->canceled_file); } pa_memblock_release(cchunk.memblock); @@ -799,8 +800,8 @@ static void do_push_drift_comp(struct userdata *u) { pa_source_post(u->source, &cchunk); pa_memblock_unref(cchunk.memblock); - pa_memblockq_drop(u->source_memblockq, u->blocksize); - rlen -= u->blocksize; + pa_memblockq_drop(u->source_memblockq, u->source_blocksize); + rlen -= u->source_blocksize; } } @@ -818,13 +819,13 @@ static void do_push(struct userdata *u) { rlen = pa_memblockq_get_length(u->source_memblockq); plen = pa_memblockq_get_length(u->sink_memblockq); - while (rlen >= u->blocksize) { + while (rlen >= u->source_blocksize) { /* take fixed block from recorded samples */ - pa_memblockq_peek_fixed_size(u->source_memblockq, u->blocksize, &rchunk); + pa_memblockq_peek_fixed_size(u->source_memblockq, u->source_blocksize, &rchunk); - if (plen >= u->blocksize) { + if (plen >= u->sink_blocksize) { /* take fixed block from played samples */ - pa_memblockq_peek_fixed_size(u->sink_memblockq, u->blocksize, &pchunk); + pa_memblockq_peek_fixed_size(u->sink_memblockq, u->sink_blocksize, &pchunk); rdata = pa_memblock_acquire(rchunk.memblock); rdata += rchunk.index; @@ -832,15 +833,15 @@ static void do_push(struct userdata *u) { pdata += pchunk.index; cchunk.index = 0; - cchunk.length = u->blocksize; + cchunk.length = u->source_blocksize; cchunk.memblock = pa_memblock_new(u->source->core->mempool, cchunk.length); cdata = pa_memblock_acquire(cchunk.memblock); if (u->save_aec) { if (u->captured_file) - unused = fwrite(rdata, 1, u->blocksize, u->captured_file); + unused = fwrite(rdata, 1, u->source_blocksize, u->captured_file); if (u->played_file) - unused = fwrite(pdata, 1, u->blocksize, u->played_file); + unused = fwrite(pdata, 1, u->sink_blocksize, u->played_file); } /* perform echo cancellation */ @@ -848,7 +849,7 @@ static void do_push(struct userdata *u) { if (u->save_aec) { if (u->canceled_file) - unused = fwrite(cdata, 1, u->blocksize, u->canceled_file); + unused = fwrite(cdata, 1, u->source_blocksize, u->canceled_file); } pa_memblock_release(cchunk.memblock); @@ -856,7 +857,7 @@ static void do_push(struct userdata *u) { pa_memblock_release(rchunk.memblock); /* drop consumed sink samples */ - pa_memblockq_drop(u->sink_memblockq, u->blocksize); + pa_memblockq_drop(u->sink_memblockq, u->sink_blocksize); pa_memblock_unref(pchunk.memblock); pa_memblock_unref(rchunk.memblock); @@ -864,15 +865,15 @@ static void do_push(struct userdata *u) { * source */ rchunk = cchunk; - plen -= u->blocksize; + plen -= u->sink_blocksize; } /* forward the (echo-canceled) data to the virtual source */ pa_source_post(u->source, &rchunk); pa_memblock_unref(rchunk.memblock); - pa_memblockq_drop(u->source_memblockq, u->blocksize); - rlen -= u->blocksize; + pa_memblockq_drop(u->source_memblockq, u->source_blocksize); + rlen -= u->source_blocksize; } } @@ -907,7 +908,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) plen = pa_memblockq_get_length(u->sink_memblockq); /* Let's not do anything else till we have enough data to process */ - if (rlen < u->blocksize) + if (rlen < u->source_blocksize) return; /* See if we need to drop samples in order to sync */ @@ -923,7 +924,7 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) * means the only way to try to catch up is drop sink samples and let * the canceller cope up with this. */ to_skip = rlen >= u->source_skip ? u->source_skip : rlen; - to_skip -= to_skip % u->blocksize; + to_skip -= to_skip % u->source_blocksize; if (to_skip) { pa_memblockq_peek_fixed_size(u->source_memblockq, to_skip, &rchunk); @@ -936,9 +937,9 @@ static void source_output_push_cb(pa_source_output *o, const pa_memchunk *chunk) u->source_skip -= to_skip; } - if (rlen && u->source_skip % u->blocksize) { - u->sink_skip += u->blocksize - (u->source_skip % u->blocksize); - u->source_skip -= (u->source_skip % u->blocksize); + if (rlen && u->source_skip % u->source_blocksize) { + u->sink_skip += (uint64_t) (u->source_blocksize - (u->source_skip % u->source_blocksize)) * u->sink_blocksize / u->source_blocksize; + u->source_skip -= (u->source_skip % u->source_blocksize); } } @@ -1640,6 +1641,7 @@ int pa__init(pa_module*m) { pa_sink_new_data sink_data; pa_memchunk silence; uint32_t temp; + uint32_t nframes = 0; pa_assert(m); @@ -1729,13 +1731,15 @@ int pa__init(pa_module*m) { u->asyncmsgq = pa_asyncmsgq_new(0); u->need_realign = TRUE; - if (u->ec->init) { - if (!u->ec->init(u->core, u->ec, &source_ss, &source_map, &sink_ss, &sink_map, &u->blocksize, pa_modargs_get_value(ma, "aec_args", NULL))) { - pa_log("Failed to init AEC engine"); - goto fail; - } + pa_assert(u->ec->init); + if (!u->ec->init(u->core, u->ec, &source_ss, &source_map, &sink_ss, &sink_map, &nframes, pa_modargs_get_value(ma, "aec_args", NULL))) { + pa_log("Failed to init AEC engine"); + goto fail; } + u->source_blocksize = nframes * pa_frame_size(&source_ss); + u->sink_blocksize = nframes * pa_frame_size(&sink_ss); + if (u->ec->params.drift_compensation) pa_assert(u->ec->set_drift); @@ -2071,6 +2075,7 @@ int main(int argc, char* argv[]) { int ret = 0, i; char c; float drift; + uint32_t nframes; pa_memzero(&u, sizeof(u)); @@ -2116,11 +2121,13 @@ int main(int argc, char* argv[]) { if (init_common(ma, &u, &source_ss, &source_map) < 0) goto fail; - if (!u.ec->init(u.core, u.ec, &source_ss, &source_map, &sink_ss, &sink_map, &u.blocksize, + if (!u.ec->init(u.core, u.ec, &source_ss, &source_map, &sink_ss, &sink_map, &nframes, (argc > 5) ? argv[5] : NULL )) { pa_log("Failed to init AEC engine"); goto fail; } + u.source_blocksize = nframes * pa_frame_size(&source_ss); + u.sink_blocksize = nframes * pa_frame_size(&sink_ss); if (u.ec->params.drift_compensation) { if (argc < 7) { @@ -2136,20 +2143,20 @@ int main(int argc, char* argv[]) { } } - rdata = pa_xmalloc(u.blocksize); - pdata = pa_xmalloc(u.blocksize); - cdata = pa_xmalloc(u.blocksize); + rdata = pa_xmalloc(u.source_blocksize); + pdata = pa_xmalloc(u.sink_blocksize); + cdata = pa_xmalloc(u.source_blocksize); if (!u.ec->params.drift_compensation) { - while (fread(rdata, u.blocksize, 1, u.captured_file) > 0) { - if (fread(pdata, u.blocksize, 1, u.played_file) == 0) { + while (fread(rdata, u.source_blocksize, 1, u.captured_file) > 0) { + if (fread(pdata, u.sink_blocksize, 1, u.played_file) == 0) { perror("Played file ended before captured file"); goto fail; } u.ec->run(u.ec, rdata, pdata, cdata); - unused = fwrite(cdata, u.blocksize, 1, u.canceled_file); + unused = fwrite(cdata, u.source_blocksize, 1, u.canceled_file); } } else { while (fscanf(u.drift_file, "%c", &c) > 0) { diff --git a/src/modules/echo-cancel/null.c b/src/modules/echo-cancel/null.c index 1820661b2..bfd6c30ae 100644 --- a/src/modules/echo-cancel/null.c +++ b/src/modules/echo-cancel/null.c @@ -28,8 +28,8 @@ PA_C_DECL_END pa_bool_t pa_null_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args) { - unsigned framelen = 256; + uint32_t *nframes, const char *args) { + *nframes = 256; source_ss->format = PA_SAMPLE_S16NE; source_ss->channels = 1; @@ -37,14 +37,13 @@ pa_bool_t pa_null_ec_init(pa_core *c, pa_echo_canceller *ec, *sink_ss = *source_ss; *sink_map = *source_map; - *blocksize = framelen * pa_frame_size(source_ss); - - pa_log_debug("null AEC: framelen %u, blocksize %u, channels %d, rate %d", framelen, *blocksize, source_ss->channels, source_ss->rate); + pa_log_debug("null AEC: nframes %u, channels %d, rate %d", *nframes, source_ss->channels, source_ss->rate); return TRUE; } void pa_null_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) { + // blocksize is nframes * frame-size memcpy(out, rec, 256 * 2); } diff --git a/src/modules/echo-cancel/speex.c b/src/modules/echo-cancel/speex.c index d6331fc56..5ebd0b3f7 100644 --- a/src/modules/echo-cancel/speex.c +++ b/src/modules/echo-cancel/speex.c @@ -58,7 +58,7 @@ static void pa_speex_ec_fixate_spec(pa_sample_spec *source_ss, pa_channel_map *s *sink_map = *source_map; } -static pa_bool_t pa_speex_ec_preprocessor_init(pa_echo_canceller *ec, pa_sample_spec *source_ss, uint32_t blocksize, pa_modargs *ma) { +static pa_bool_t pa_speex_ec_preprocessor_init(pa_echo_canceller *ec, pa_sample_spec *source_ss, uint32_t nframes, pa_modargs *ma) { pa_bool_t agc; pa_bool_t denoise; pa_bool_t echo_suppress; @@ -111,7 +111,7 @@ static pa_bool_t pa_speex_ec_preprocessor_init(pa_echo_canceller *ec, pa_sample_ goto fail; } - ec->params.priv.speex.pp_state = speex_preprocess_state_init(blocksize / pa_frame_size(source_ss), source_ss->rate); + ec->params.priv.speex.pp_state = speex_preprocess_state_init(nframes, source_ss->rate); tmp = agc; speex_preprocess_ctl(ec->params.priv.speex.pp_state, SPEEX_PREPROCESS_SET_AGC, &tmp); @@ -148,10 +148,10 @@ fail: pa_bool_t pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args) + uint32_t *nframes, const char *args) { - int framelen, y, rate; - uint32_t frame_size_ms, filter_size_ms; + int rate; + uint32_t y, frame_size_ms, filter_size_ms; pa_modargs *ma; if (!(ma = pa_modargs_new(args, valid_modargs))) { @@ -174,25 +174,23 @@ pa_bool_t pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec, pa_speex_ec_fixate_spec(source_ss, source_map, sink_ss, sink_map); rate = source_ss->rate; - framelen = (rate * frame_size_ms) / 1000; - /* framelen should be a power of 2, round down to nearest power of two */ - y = 1 << ((8 * sizeof (int)) - 2); - while (y > framelen) + *nframes = (rate * frame_size_ms) / 1000; + /* nframes should be a power of 2, round down to nearest power of two */ + y = 1 << ((8 * sizeof (uint32_t)) - 2); + while (y > *nframes) y >>= 1; - framelen = y; + *nframes = y; - *blocksize = framelen * pa_frame_size (source_ss); + pa_log_debug ("Using nframes %d, channels %d, rate %d", *nframes, source_ss->channels, source_ss->rate); - pa_log_debug ("Using framelen %d, blocksize %u, channels %d, rate %d", framelen, *blocksize, source_ss->channels, source_ss->rate); - - ec->params.priv.speex.state = speex_echo_state_init_mc (framelen, (rate * filter_size_ms) / 1000, source_ss->channels, source_ss->channels); + ec->params.priv.speex.state = speex_echo_state_init_mc (*nframes, (rate * filter_size_ms) / 1000, source_ss->channels, source_ss->channels); if (!ec->params.priv.speex.state) goto fail; speex_echo_ctl(ec->params.priv.speex.state, SPEEX_ECHO_SET_SAMPLING_RATE, &rate); - if (!pa_speex_ec_preprocessor_init(ec, source_ss, *blocksize, ma)) + if (!pa_speex_ec_preprocessor_init(ec, source_ss, *nframes, ma)) goto fail; pa_modargs_free(ma); diff --git a/src/modules/echo-cancel/webrtc.cc b/src/modules/echo-cancel/webrtc.cc index 633b7232e..6ced28ce7 100644 --- a/src/modules/echo-cancel/webrtc.cc +++ b/src/modules/echo-cancel/webrtc.cc @@ -79,7 +79,7 @@ static int routing_mode_from_string(const char *rmode) { pa_bool_t pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec, pa_sample_spec *source_ss, pa_channel_map *source_map, pa_sample_spec *sink_ss, pa_channel_map *sink_map, - uint32_t *blocksize, const char *args) + uint32_t *nframes, const char *args) { webrtc::AudioProcessing *apm = NULL; pa_bool_t hpf, ns, agc, dgc, mobile, cn; @@ -216,7 +216,8 @@ pa_bool_t pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec, ec->params.priv.webrtc.apm = apm; ec->params.priv.webrtc.sample_spec = *source_ss; - ec->params.priv.webrtc.blocksize = *blocksize = (uint64_t)pa_bytes_per_second(source_ss) * BLOCK_SIZE_US / PA_USEC_PER_SEC; + ec->params.priv.webrtc.blocksize = (uint64_t)pa_bytes_per_second(source_ss) * BLOCK_SIZE_US / PA_USEC_PER_SEC; + *nframes = ec->params.priv.webrtc.blocksize / pa_frame_size(source_ss); pa_modargs_free(ma); return TRUE;