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 PulseAudio is free software; you can redistribute it and/or modify 753a5a1b3Sopenharmony_ci it under the terms of the GNU Lesser General Public License as published 853a5a1b3Sopenharmony_ci by the Free Software Foundation; either version 2.1 of the License, 953a5a1b3Sopenharmony_ci or (at your option) any later version. 1053a5a1b3Sopenharmony_ci 1153a5a1b3Sopenharmony_ci PulseAudio is distributed in the hope that it will be useful, but 1253a5a1b3Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 1353a5a1b3Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1453a5a1b3Sopenharmony_ci General Public License for more details. 1553a5a1b3Sopenharmony_ci 1653a5a1b3Sopenharmony_ci You should have received a copy of the GNU Lesser General Public License 1753a5a1b3Sopenharmony_ci along with PulseAudio; if not, see <http://www.gnu.org/licenses/>. 1853a5a1b3Sopenharmony_ci***/ 1953a5a1b3Sopenharmony_ci 2053a5a1b3Sopenharmony_ci#ifndef fooechocancelhfoo 2153a5a1b3Sopenharmony_ci#define fooechocancelhfoo 2253a5a1b3Sopenharmony_ci 2353a5a1b3Sopenharmony_ci#ifdef HAVE_CONFIG_H 2453a5a1b3Sopenharmony_ci#include <config.h> 2553a5a1b3Sopenharmony_ci#endif 2653a5a1b3Sopenharmony_ci 2753a5a1b3Sopenharmony_ci#include <pulse/sample.h> 2853a5a1b3Sopenharmony_ci#include <pulse/channelmap.h> 2953a5a1b3Sopenharmony_ci#include <pulsecore/core.h> 3053a5a1b3Sopenharmony_ci#include <pulsecore/macro.h> 3153a5a1b3Sopenharmony_ci 3253a5a1b3Sopenharmony_ci#ifdef HAVE_SPEEX 3353a5a1b3Sopenharmony_ci#include <speex/speex_echo.h> 3453a5a1b3Sopenharmony_ci#include <speex/speex_preprocess.h> 3553a5a1b3Sopenharmony_ci#endif 3653a5a1b3Sopenharmony_ci 3753a5a1b3Sopenharmony_ci#include "adrian.h" 3853a5a1b3Sopenharmony_ci 3953a5a1b3Sopenharmony_ci/* Common data structures */ 4053a5a1b3Sopenharmony_ci 4153a5a1b3Sopenharmony_citypedef struct pa_echo_canceller_msg pa_echo_canceller_msg; 4253a5a1b3Sopenharmony_ci 4353a5a1b3Sopenharmony_citypedef struct pa_echo_canceller_params pa_echo_canceller_params; 4453a5a1b3Sopenharmony_ci 4553a5a1b3Sopenharmony_cistruct pa_echo_canceller_params { 4653a5a1b3Sopenharmony_ci union { 4753a5a1b3Sopenharmony_ci struct { 4853a5a1b3Sopenharmony_ci pa_sample_spec out_ss; 4953a5a1b3Sopenharmony_ci } null; 5053a5a1b3Sopenharmony_ci#ifdef HAVE_SPEEX 5153a5a1b3Sopenharmony_ci struct { 5253a5a1b3Sopenharmony_ci SpeexEchoState *state; 5353a5a1b3Sopenharmony_ci SpeexPreprocessState *pp_state; 5453a5a1b3Sopenharmony_ci } speex; 5553a5a1b3Sopenharmony_ci#endif 5653a5a1b3Sopenharmony_ci#ifdef HAVE_ADRIAN_EC 5753a5a1b3Sopenharmony_ci struct { 5853a5a1b3Sopenharmony_ci uint32_t blocksize; 5953a5a1b3Sopenharmony_ci AEC *aec; 6053a5a1b3Sopenharmony_ci } adrian; 6153a5a1b3Sopenharmony_ci#endif 6253a5a1b3Sopenharmony_ci#ifdef HAVE_WEBRTC 6353a5a1b3Sopenharmony_ci struct { 6453a5a1b3Sopenharmony_ci /* This is a void* so that we don't have to convert this whole file 6553a5a1b3Sopenharmony_ci * to C++ linkage. apm is a pointer to an AudioProcessing object */ 6653a5a1b3Sopenharmony_ci void *apm; 6753a5a1b3Sopenharmony_ci unsigned int blocksize; /* in frames */ 6853a5a1b3Sopenharmony_ci pa_sample_spec rec_ss, play_ss, out_ss; 6953a5a1b3Sopenharmony_ci float *rec_buffer[PA_CHANNELS_MAX], *play_buffer[PA_CHANNELS_MAX]; /* for deinterleaved buffers */ 7053a5a1b3Sopenharmony_ci void *trace_callback; 7153a5a1b3Sopenharmony_ci bool agc; 7253a5a1b3Sopenharmony_ci bool first; 7353a5a1b3Sopenharmony_ci unsigned int agc_start_volume; 7453a5a1b3Sopenharmony_ci } webrtc; 7553a5a1b3Sopenharmony_ci#endif 7653a5a1b3Sopenharmony_ci /* each canceller-specific structure goes here */ 7753a5a1b3Sopenharmony_ci }; 7853a5a1b3Sopenharmony_ci 7953a5a1b3Sopenharmony_ci /* Set this if canceller can do drift compensation. Also see set_drift() 8053a5a1b3Sopenharmony_ci * below */ 8153a5a1b3Sopenharmony_ci bool drift_compensation; 8253a5a1b3Sopenharmony_ci}; 8353a5a1b3Sopenharmony_ci 8453a5a1b3Sopenharmony_citypedef struct pa_echo_canceller pa_echo_canceller; 8553a5a1b3Sopenharmony_ci 8653a5a1b3Sopenharmony_cistruct pa_echo_canceller { 8753a5a1b3Sopenharmony_ci /* Initialise canceller engine. */ 8853a5a1b3Sopenharmony_ci bool (*init) (pa_core *c, 8953a5a1b3Sopenharmony_ci pa_echo_canceller *ec, 9053a5a1b3Sopenharmony_ci pa_sample_spec *rec_ss, 9153a5a1b3Sopenharmony_ci pa_channel_map *rec_map, 9253a5a1b3Sopenharmony_ci pa_sample_spec *play_ss, 9353a5a1b3Sopenharmony_ci pa_channel_map *play_map, 9453a5a1b3Sopenharmony_ci pa_sample_spec *out_ss, 9553a5a1b3Sopenharmony_ci pa_channel_map *out_map, 9653a5a1b3Sopenharmony_ci uint32_t *nframes, 9753a5a1b3Sopenharmony_ci const char *args); 9853a5a1b3Sopenharmony_ci 9953a5a1b3Sopenharmony_ci /* You should have only one of play()+record() or run() set. The first 10053a5a1b3Sopenharmony_ci * works under the assumption that you'll handle buffering and matching up 10153a5a1b3Sopenharmony_ci * samples yourself. If you set run(), module-echo-cancel will handle 10253a5a1b3Sopenharmony_ci * synchronising the playback and record streams. */ 10353a5a1b3Sopenharmony_ci 10453a5a1b3Sopenharmony_ci /* Feed the engine 'nframes' playback frames. */ 10553a5a1b3Sopenharmony_ci void (*play) (pa_echo_canceller *ec, const uint8_t *play); 10653a5a1b3Sopenharmony_ci /* Feed the engine 'nframes' record frames. nframes processed frames are 10753a5a1b3Sopenharmony_ci * returned in out. */ 10853a5a1b3Sopenharmony_ci void (*record) (pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out); 10953a5a1b3Sopenharmony_ci /* Feed the engine nframes playback and record frames, with a reasonable 11053a5a1b3Sopenharmony_ci * effort at keeping the two in sync. nframes processed frames are 11153a5a1b3Sopenharmony_ci * returned in out. */ 11253a5a1b3Sopenharmony_ci void (*run) (pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); 11353a5a1b3Sopenharmony_ci 11453a5a1b3Sopenharmony_ci /* Optional callback to set the drift, expressed as the ratio of the 11553a5a1b3Sopenharmony_ci * difference in number of playback and capture samples to the number of 11653a5a1b3Sopenharmony_ci * capture samples, for some instant of time. This is used only if the 11753a5a1b3Sopenharmony_ci * canceller signals that it supports drift compensation, and is called 11853a5a1b3Sopenharmony_ci * before record(). The actual implementation needs to derive drift based 11953a5a1b3Sopenharmony_ci * on point samples -- the individual values are not accurate enough to use 12053a5a1b3Sopenharmony_ci * as-is. */ 12153a5a1b3Sopenharmony_ci /* NOTE: the semantics of this function might change in the future. */ 12253a5a1b3Sopenharmony_ci void (*set_drift) (pa_echo_canceller *ec, float drift); 12353a5a1b3Sopenharmony_ci 12453a5a1b3Sopenharmony_ci /* Free up resources. */ 12553a5a1b3Sopenharmony_ci void (*done) (pa_echo_canceller *ec); 12653a5a1b3Sopenharmony_ci 12753a5a1b3Sopenharmony_ci /* Structure with common and engine-specific canceller parameters. */ 12853a5a1b3Sopenharmony_ci pa_echo_canceller_params params; 12953a5a1b3Sopenharmony_ci 13053a5a1b3Sopenharmony_ci /* msgobject that can be used to send messages back to the main thread */ 13153a5a1b3Sopenharmony_ci pa_echo_canceller_msg *msg; 13253a5a1b3Sopenharmony_ci}; 13353a5a1b3Sopenharmony_ci 13453a5a1b3Sopenharmony_ci/* Functions to be used by the canceller analog gain control routines */ 13553a5a1b3Sopenharmony_cipa_volume_t pa_echo_canceller_get_capture_volume(pa_echo_canceller *ec); 13653a5a1b3Sopenharmony_civoid pa_echo_canceller_set_capture_volume(pa_echo_canceller *ec, pa_volume_t volume); 13753a5a1b3Sopenharmony_ci 13853a5a1b3Sopenharmony_ci/* Computes EC block size in frames (rounded down to nearest power-of-2) based 13953a5a1b3Sopenharmony_ci * on sample rate and milliseconds. */ 14053a5a1b3Sopenharmony_ciuint32_t pa_echo_canceller_blocksize_power2(unsigned rate, unsigned ms); 14153a5a1b3Sopenharmony_ci 14253a5a1b3Sopenharmony_ci/* Null canceller functions */ 14353a5a1b3Sopenharmony_cibool pa_null_ec_init(pa_core *c, pa_echo_canceller *ec, 14453a5a1b3Sopenharmony_ci pa_sample_spec *rec_ss, pa_channel_map *rec_map, 14553a5a1b3Sopenharmony_ci pa_sample_spec *play_ss, pa_channel_map *play_map, 14653a5a1b3Sopenharmony_ci pa_sample_spec *out_ss, pa_channel_map *out_map, 14753a5a1b3Sopenharmony_ci uint32_t *nframes, const char *args); 14853a5a1b3Sopenharmony_civoid pa_null_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); 14953a5a1b3Sopenharmony_civoid pa_null_ec_done(pa_echo_canceller *ec); 15053a5a1b3Sopenharmony_ci 15153a5a1b3Sopenharmony_ci#ifdef HAVE_SPEEX 15253a5a1b3Sopenharmony_ci/* Speex canceller functions */ 15353a5a1b3Sopenharmony_cibool pa_speex_ec_init(pa_core *c, pa_echo_canceller *ec, 15453a5a1b3Sopenharmony_ci pa_sample_spec *rec_ss, pa_channel_map *rec_map, 15553a5a1b3Sopenharmony_ci pa_sample_spec *play_ss, pa_channel_map *play_map, 15653a5a1b3Sopenharmony_ci pa_sample_spec *out_ss, pa_channel_map *out_map, 15753a5a1b3Sopenharmony_ci uint32_t *nframes, const char *args); 15853a5a1b3Sopenharmony_civoid pa_speex_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); 15953a5a1b3Sopenharmony_civoid pa_speex_ec_done(pa_echo_canceller *ec); 16053a5a1b3Sopenharmony_ci#endif 16153a5a1b3Sopenharmony_ci 16253a5a1b3Sopenharmony_ci#ifdef HAVE_ADRIAN_EC 16353a5a1b3Sopenharmony_ci/* Adrian Andre's echo canceller */ 16453a5a1b3Sopenharmony_cibool pa_adrian_ec_init(pa_core *c, pa_echo_canceller *ec, 16553a5a1b3Sopenharmony_ci pa_sample_spec *rec_ss, pa_channel_map *rec_map, 16653a5a1b3Sopenharmony_ci pa_sample_spec *play_ss, pa_channel_map *play_map, 16753a5a1b3Sopenharmony_ci pa_sample_spec *out_ss, pa_channel_map *out_map, 16853a5a1b3Sopenharmony_ci uint32_t *nframes, const char *args); 16953a5a1b3Sopenharmony_civoid pa_adrian_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); 17053a5a1b3Sopenharmony_civoid pa_adrian_ec_done(pa_echo_canceller *ec); 17153a5a1b3Sopenharmony_ci#endif 17253a5a1b3Sopenharmony_ci 17353a5a1b3Sopenharmony_ci#ifdef HAVE_WEBRTC 17453a5a1b3Sopenharmony_ci/* WebRTC canceller functions */ 17553a5a1b3Sopenharmony_ciPA_C_DECL_BEGIN 17653a5a1b3Sopenharmony_cibool pa_webrtc_ec_init(pa_core *c, pa_echo_canceller *ec, 17753a5a1b3Sopenharmony_ci pa_sample_spec *rec_ss, pa_channel_map *rec_map, 17853a5a1b3Sopenharmony_ci pa_sample_spec *play_ss, pa_channel_map *play_map, 17953a5a1b3Sopenharmony_ci pa_sample_spec *out_ss, pa_channel_map *out_map, 18053a5a1b3Sopenharmony_ci uint32_t *nframes, const char *args); 18153a5a1b3Sopenharmony_civoid pa_webrtc_ec_play(pa_echo_canceller *ec, const uint8_t *play); 18253a5a1b3Sopenharmony_civoid pa_webrtc_ec_record(pa_echo_canceller *ec, const uint8_t *rec, uint8_t *out); 18353a5a1b3Sopenharmony_civoid pa_webrtc_ec_set_drift(pa_echo_canceller *ec, float drift); 18453a5a1b3Sopenharmony_civoid pa_webrtc_ec_run(pa_echo_canceller *ec, const uint8_t *rec, const uint8_t *play, uint8_t *out); 18553a5a1b3Sopenharmony_civoid pa_webrtc_ec_done(pa_echo_canceller *ec); 18653a5a1b3Sopenharmony_ciPA_C_DECL_END 18753a5a1b3Sopenharmony_ci#endif 18853a5a1b3Sopenharmony_ci 18953a5a1b3Sopenharmony_ci#endif /* fooechocancelhfoo */ 190