153a5a1b3Sopenharmony_ci/*** 253a5a1b3Sopenharmony_ci This file is part of PulseAudio. 353a5a1b3Sopenharmony_ci 453a5a1b3Sopenharmony_ci Copyright 2010 Arun Raghavan <arun.raghavan@collabora.co.uk> 553a5a1b3Sopenharmony_ci 653a5a1b3Sopenharmony_ci Contributor: Wim Taymans <wim.taymans@gmail.com> 753a5a1b3Sopenharmony_ci 853a5a1b3Sopenharmony_ci The actual implementation is taken from the sources at 953a5a1b3Sopenharmony_ci http://andreadrian.de/intercom/ - for the license, look for 1053a5a1b3Sopenharmony_ci adrian-license.txt in the same directory as this file. 1153a5a1b3Sopenharmony_ci 1253a5a1b3Sopenharmony_ci PulseAudio is free software; you can redistribute it and/or modify 1353a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 1453a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 1553a5a1b3Sopenharmony_ci or (at your option) any later version. 1653a5a1b3Sopenharmony_ci 1753a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1853a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1953a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 2053a5a1b3Sopenharmony_ci General Public License for more details. 2153a5a1b3Sopenharmony_ci 2253a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 2353a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 2453a5a1b3Sopenharmony_ci***/ 2553a5a1b3Sopenharmony_ci 2653a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2753a5a1b3Sopenharmony_ci#include <config.h> 2853a5a1b3Sopenharmony_ci#endif 2953a5a1b3Sopenharmony_ci 3053a5a1b3Sopenharmony_ci#include <pulse/xmalloc.h> 3153a5a1b3Sopenharmony_ci 3253a5a1b3Sopenharmony_ci#include <pulsecore/modargs.h> 3353a5a1b3Sopenharmony_ci 3453a5a1b3Sopenharmony_ci#include "echo-cancel.h" 3553a5a1b3Sopenharmony_ci 3653a5a1b3Sopenharmony_ci/* should be between 10-20 ms */ 3753a5a1b3Sopenharmony_ci#define DEFAULT_FRAME_SIZE_MS 20 3853a5a1b3Sopenharmony_ci 3953a5a1b3Sopenharmony_cistatic const char* const valid_modargs[] = { 4053a5a1b3Sopenharmony_ci "frame_size_ms", 4153a5a1b3Sopenharmony_ci NULL 4253a5a1b3Sopenharmony_ci}; 4353a5a1b3Sopenharmony_ci 4453a5a1b3Sopenharmony_cistatic void pa_adrian_ec_fixate_spec(pa_sample_spec *rec_ss, pa_channel_map *rec_map, 4553a5a1b3Sopenharmony_ci pa_sample_spec *play_ss, pa_channel_map *play_map, 4653a5a1b3Sopenharmony_ci pa_sample_spec *out_ss, pa_channel_map *out_map) { 4753a5a1b3Sopenharmony_ci out_ss->format = PA_SAMPLE_S16NE; 4853a5a1b3Sopenharmony_ci out_ss->channels = 1; 4953a5a1b3Sopenharmony_ci pa_channel_map_init_mono(out_map); 5053a5a1b3Sopenharmony_ci 5153a5a1b3Sopenharmony_ci *play_ss = *out_ss; 5253a5a1b3Sopenharmony_ci *play_map = *out_map; 5353a5a1b3Sopenharmony_ci *rec_ss = *out_ss; 5453a5a1b3Sopenharmony_ci *rec_map = *out_map; 5553a5a1b3Sopenharmony_ci} 5653a5a1b3Sopenharmony_ci 5753a5a1b3Sopenharmony_cibool pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec, 5853a5a1b3Sopenharmony_ci pa_sample_spec *rec_ss, pa_channel_map *rec_map, 5953a5a1b3Sopenharmony_ci pa_sample_spec *play_ss, pa_channel_map *play_map, 6053a5a1b3Sopenharmony_ci pa_sample_spec *out_ss, pa_channel_map *out_map, 6153a5a1b3Sopenharmony_ci uint32_t *nframes, const char *args) { 6253a5a1b3Sopenharmony_ci int rate, have_vector = 0; 6353a5a1b3Sopenharmony_ci uint32_t frame_size_ms; 6453a5a1b3Sopenharmony_ci pa_modargs *ma; 6553a5a1b3Sopenharmony_ci 6653a5a1b3Sopenharmony_ci if (!(ma = pa_modargs_new(args, valid_modargs))) { 6753a5a1b3Sopenharmony_ci pa_log("Failed to parse submodule arguments."); 6853a5a1b3Sopenharmony_ci goto fail; 6953a5a1b3Sopenharmony_ci } 7053a5a1b3Sopenharmony_ci 7153a5a1b3Sopenharmony_ci frame_size_ms = DEFAULT_FRAME_SIZE_MS; 7253a5a1b3Sopenharmony_ci if (pa_modargs_get_value_u32(ma, "frame_size_ms", &frame_size_ms) < 0 || frame_size_ms < 1 || frame_size_ms > 200) { 7353a5a1b3Sopenharmony_ci pa_log("Invalid frame_size_ms specification"); 7453a5a1b3Sopenharmony_ci goto fail; 7553a5a1b3Sopenharmony_ci } 7653a5a1b3Sopenharmony_ci 7753a5a1b3Sopenharmony_ci pa_adrian_ec_fixate_spec(rec_ss, rec_map, play_ss, play_map, out_ss, out_map); 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci rate = out_ss->rate; 8053a5a1b3Sopenharmony_ci *nframes = (rate * frame_size_ms) / 1000; 8153a5a1b3Sopenharmony_ci ec->params.adrian.blocksize = (*nframes) * pa_frame_size(out_ss); 8253a5a1b3Sopenharmony_ci 8353a5a1b3Sopenharmony_ci pa_log_debug ("Using nframes %d, blocksize %u, channels %d, rate %d", *nframes, ec->params.adrian.blocksize, out_ss->channels, out_ss->rate); 8453a5a1b3Sopenharmony_ci 8553a5a1b3Sopenharmony_ci /* For now we only support SSE */ 8653a5a1b3Sopenharmony_ci if (c->cpu_info.cpu_type == PA_CPU_X86 && (c->cpu_info.flags.x86 & PA_CPU_X86_SSE)) 8753a5a1b3Sopenharmony_ci have_vector = 1; 8853a5a1b3Sopenharmony_ci 8953a5a1b3Sopenharmony_ci ec->params.adrian.aec = AEC_init(rate, have_vector); 9053a5a1b3Sopenharmony_ci if (!ec->params.adrian.aec) 9153a5a1b3Sopenharmony_ci goto fail; 9253a5a1b3Sopenharmony_ci 9353a5a1b3Sopenharmony_ci pa_modargs_free(ma); 9453a5a1b3Sopenharmony_ci return true; 9553a5a1b3Sopenharmony_ci 9653a5a1b3Sopenharmony_cifail: 9753a5a1b3Sopenharmony_ci if (ma) 9853a5a1b3Sopenharmony_ci pa_modargs_free(ma); 9953a5a1b3Sopenharmony_ci return false; 10053a5a1b3Sopenharmony_ci} 10153a5a1b3Sopenharmony_ci 10253a5a1b3Sopenharmony_civoid pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out) { 10353a5a1b3Sopenharmony_ci unsigned int i; 10453a5a1b3Sopenharmony_ci 10553a5a1b3Sopenharmony_ci for (i = 0; i < ec->params.adrian.blocksize; i += 2) { 10653a5a1b3Sopenharmony_ci /* We know it's S16NE mono data */ 10753a5a1b3Sopenharmony_ci int r = *(int16_t *)(rec + i); 10853a5a1b3Sopenharmony_ci int p = *(int16_t *)(play + i); 10953a5a1b3Sopenharmony_ci *(int16_t *)(out + i) = (int16_t) AEC_doAEC(ec->params.adrian.aec, r, p); 11053a5a1b3Sopenharmony_ci } 11153a5a1b3Sopenharmony_ci} 11253a5a1b3Sopenharmony_ci 11353a5a1b3Sopenharmony_civoid pa_adrian_ec_done(pa_echo_canceller *ec) { 11453a5a1b3Sopenharmony_ci if (ec->params.adrian.aec) { 11553a5a1b3Sopenharmony_ci AEC_done(ec->params.adrian.aec); 11653a5a1b3Sopenharmony_ci ec->params.adrian.aec = NULL; 11753a5a1b3Sopenharmony_ci } 11853a5a1b3Sopenharmony_ci} 119