1 /*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 // clang-format off
18 /*
19 * Typical AEC signal flow:
20 *
21 * Microphone Audio
22 * Timestamps
23 * +--------------------------------------+
24 * | | +---------------+
25 * | Microphone +---------------+ | | |
26 * O|====== | Audio | Sample Rate | +-------> |
27 * (from . +--+ Samples | + | | |
28 * mic . +==================> Format |==============> |
29 * codec) . | Conversion | | | Cleaned
30 * O|====== | (if required) | | Acoustic | Audio
31 * +---------------+ | Echo | Samples
32 * | Canceller |===================>
33 * | (AEC) |
34 * Reference +---------------+ | |
35 * Audio | Sample Rate | | |
36 * Samples | + | | |
37 * +=============> Format |==============> |
38 * | | Conversion | | |
39 * | | (if required) | +-------> |
40 * | +---------------+ | | |
41 * | | +---------------+
42 * | +-------------------------------+
43 * | | Reference Audio
44 * | | Timestamps
45 * | |
46 * +--+----+---------+ AUDIO CAPTURE
47 * | Speaker |
48 * +------------+ Audio/Timestamp +---------------------------------------------------------------------------+
49 * | Buffer |
50 * +--^----^---------+ AUDIO PLAYBACK
51 * | |
52 * | |
53 * | |
54 * | |
55 * |\ | |
56 * | +-+ | |
57 * (to | | +-----C----+
58 * speaker | | | | Playback
59 * codec) | | <=====+================================================================+ Audio
60 * | +-+ Samples
61 * |/
62 *
63 */
64 // clang-format on
65
66 #define LOG_TAG "audio_hw_aec"
67 // #define LOG_NDEBUG 0
68
69 #include <audio_utils/primitives.h>
70 #include <stdio.h>
71 #include <inttypes.h>
72 #include <errno.h>
73 #include <malloc.h>
74 #include <sys/time.h>
75 #include <tinyalsa/asoundlib.h>
76 #include <unistd.h>
77 #include <log/log.h>
78 #include "audio_aec.h"
79
80 #ifdef AEC_HAL
81 #include "audio_aec_process.h"
82 #else
83 #define aec_spk_mic_init(...) ((int)0)
84 #define aec_spk_mic_reset(...) ((void)0)
85 #define aec_spk_mic_process(...) ((int32_t)0)
86 #define aec_spk_mic_release(...) ((void)0)
87 #endif
88
89 #define MAX_TIMESTAMP_DIFF_USEC 200000
90
91 #define MAX_READ_WAIT_TIME_MSEC 80
92
timespec_to_usec(struct timespec ts)93 uint64_t timespec_to_usec(struct timespec ts) {
94 return (ts.tv_sec * 1e6L + ts.tv_nsec/1000);
95 }
96
get_reference_audio_in_place(struct aec_t * aec,size_t frames)97 void get_reference_audio_in_place(struct aec_t *aec, size_t frames) {
98 if (aec->num_reference_channels == aec->spk_num_channels) {
99 /* Reference count equals speaker channels, nothing to do here. */
100 return;
101 } else if (aec->num_reference_channels != 1) {
102 /* We don't have a rule for non-mono references, show error on log */
103 ALOGE("Invalid reference count - must be 1 or match number of playback channels!");
104 return;
105 }
106 int16_t *src_Nch = &aec->spk_buf_playback_format[0];
107 int16_t *dst_1ch = &aec->spk_buf_playback_format[0];
108 int32_t num_channels = (int32_t)aec->spk_num_channels;
109 size_t frame, ch;
110 for (frame = 0; frame < frames; frame++) {
111 int32_t acc = 0;
112 for (ch = 0; ch < aec->spk_num_channels; ch++) {
113 acc += src_Nch[ch];
114 }
115 *dst_1ch++ = clamp16(acc/num_channels);
116 src_Nch += aec->spk_num_channels;
117 }
118 }
119
print_queue_status_to_log(struct aec_t * aec,bool write_side)120 void print_queue_status_to_log(struct aec_t *aec, bool write_side) {
121 ssize_t q1 = fifo_available_to_read(aec->spk_fifo);
122 ssize_t q2 = fifo_available_to_read(aec->ts_fifo);
123
124 ALOGV("Queue available %s: Spk %zd (count %zd) TS %zd (count %zd)",
125 (write_side) ? "(POST-WRITE)" : "(PRE-READ)",
126 q1, q1/aec->spk_frame_size_bytes/PLAYBACK_PERIOD_SIZE,
127 q2, q2/sizeof(struct aec_info));
128 }
129
flush_aec_fifos(struct aec_t * aec)130 void flush_aec_fifos(struct aec_t *aec) {
131 if (aec == NULL) {
132 return;
133 }
134 if (aec->spk_fifo != NULL) {
135 ALOGV("Flushing AEC Spk FIFO...");
136 fifo_flush(aec->spk_fifo);
137 }
138 if (aec->ts_fifo != NULL) {
139 ALOGV("Flushing AEC Timestamp FIFO...");
140 fifo_flush(aec->ts_fifo);
141 }
142 /* Reset FIFO read-write offset tracker */
143 aec->read_write_diff_bytes = 0;
144 }
145
aec_set_spk_running_no_lock(struct aec_t * aec,bool state)146 void aec_set_spk_running_no_lock(struct aec_t* aec, bool state) {
147 aec->spk_running = state;
148 }
149
aec_get_spk_running_no_lock(struct aec_t * aec)150 bool aec_get_spk_running_no_lock(struct aec_t* aec) {
151 return aec->spk_running;
152 }
153
destroy_aec_reference_config_no_lock(struct aec_t * aec)154 void destroy_aec_reference_config_no_lock(struct aec_t* aec) {
155 if (!aec->spk_initialized) {
156 return;
157 }
158 aec_set_spk_running_no_lock(aec, false);
159 fifo_release(aec->spk_fifo);
160 fifo_release(aec->ts_fifo);
161 memset(&aec->last_spk_info, 0, sizeof(struct aec_info));
162 aec->spk_initialized = false;
163 }
164
destroy_aec_mic_config_no_lock(struct aec_t * aec)165 void destroy_aec_mic_config_no_lock(struct aec_t* aec) {
166 if (!aec->mic_initialized) {
167 return;
168 }
169 release_resampler(aec->spk_resampler);
170 free(aec->mic_buf);
171 free(aec->spk_buf);
172 free(aec->spk_buf_playback_format);
173 free(aec->spk_buf_resampler_out);
174 memset(&aec->last_mic_info, 0, sizeof(struct aec_info));
175 aec->mic_initialized = false;
176 }
177
init_aec_interface(struct aec_params * params)178 struct aec_t* init_aec_interface(struct aec_params* params) {
179 ALOGV("%s enter", __func__);
180 struct aec_t *aec = (struct aec_t *)calloc(1, sizeof(struct aec_t));
181 if (aec == NULL) {
182 ALOGE("%s: Failed to allocate memory for AEC interface!", __func__);
183 ALOGV("%s exit", __func__);
184 return NULL;
185 }
186 pthread_mutex_init(&aec->lock, NULL);
187
188 aec->num_reference_channels = params->num_reference_channels;
189 /* Set defaults, will be overridden by settings in init_aec_(mic|referece_config) */
190 /* Capture settings */
191 aec->mic_sampling_rate = params->mic_sampling_rate_hz;
192 aec->mic_frame_size_bytes = params->num_mic_channels * sizeof(int32_t);
193 aec->mic_num_channels = params->num_mic_channels;
194
195 /* Playback settings (before conversion to reference) */
196 aec->spk_sampling_rate = params->playback_sampling_rate_hz;
197 aec->spk_frame_size_bytes = params->num_playback_channels * sizeof(int32_t);
198 aec->spk_num_channels = params->num_playback_channels;
199
200 ALOGV("%s exit", __func__);
201 return aec;
202 }
203
release_aec_interface(struct aec_t * aec)204 void release_aec_interface(struct aec_t *aec) {
205 ALOGV("%s enter", __func__);
206 pthread_mutex_lock(&aec->lock);
207 destroy_aec_mic_config_no_lock(aec);
208 destroy_aec_reference_config_no_lock(aec);
209 pthread_mutex_unlock(&aec->lock);
210 free(aec);
211 ALOGV("%s exit", __func__);
212 }
213
init_aec(struct aec_params * params,struct aec_t ** aec_ptr)214 int init_aec(struct aec_params* params, struct aec_t** aec_ptr) {
215 ALOGV("%s enter", __func__);
216 if ((params == NULL) || (aec_ptr == NULL)) {
217 ALOGE("%s: Invalid input arguments!", __func__);
218 return -EINVAL;
219 }
220 if (aec_spk_mic_init(params->mic_sampling_rate, params->num_reference_channels,
221 params->num_mic_channels)) {
222 ALOGE("%s: AEC object failed to initialize!", __func__);
223 return -EINVAL;
224 }
225 struct aec_t* aec = init_aec_interface(params);
226 if (aec == NULL) {
227 ALOGE("%s: Failed to allocate AEC struct!", __func__);
228 goto error_1;
229 }
230 (*aec_ptr) = aec;
231 ALOGV("%s exit", __func__);
232 return 0;
233
234 error_1:
235 aec_spk_mic_release();
236 return -EINVAL;
237 }
238
release_aec(struct aec_t * aec)239 void release_aec(struct aec_t *aec) {
240 ALOGV("%s enter", __func__);
241 if (aec == NULL) {
242 return;
243 }
244 release_aec_interface(aec);
245 aec_spk_mic_release();
246 ALOGV("%s exit", __func__);
247 }
248
init_aec_reference_config(struct aec_t * aec,struct alsa_stream_out * out)249 int init_aec_reference_config(struct aec_t *aec, struct alsa_stream_out *out) {
250 ALOGV("%s enter", __func__);
251 if (!aec) {
252 ALOGE("AEC: No valid interface found!");
253 return -EINVAL;
254 }
255
256 int ret = 0;
257 pthread_mutex_lock(&aec->lock);
258 if (aec->spk_initialized) {
259 destroy_aec_reference_config_no_lock(aec);
260 }
261
262 aec->spk_fifo = fifo_init(
263 out->config.period_count * out->config.period_size *
264 audio_stream_out_frame_size(&out->stream),
265 false /* reader_throttles_writer */);
266 if (aec->spk_fifo == NULL) {
267 ALOGE("AEC: Speaker loopback FIFO Init failed!");
268 ret = -EINVAL;
269 goto exit;
270 }
271 aec->ts_fifo = fifo_init(
272 out->config.period_count * sizeof(struct aec_info),
273 false /* reader_throttles_writer */);
274 if (aec->ts_fifo == NULL) {
275 ALOGE("AEC: Speaker timestamp FIFO Init failed!");
276 ret = -EINVAL;
277 fifo_release(aec->spk_fifo);
278 goto exit;
279 }
280
281 aec->spk_sampling_rate = out->config.rate;
282 aec->spk_frame_size_bytes = audio_stream_out_frame_size(&out->stream);
283 aec->spk_num_channels = out->config.channels;
284 aec->spk_initialized = true;
285 exit:
286 pthread_mutex_unlock(&aec->lock);
287 ALOGV("%s exit", __func__);
288 return ret;
289 }
290
destroy_aec_reference_config(struct aec_t * aec)291 void destroy_aec_reference_config(struct aec_t* aec) {
292 ALOGV("%s enter", __func__);
293 if (aec == NULL) {
294 ALOGV("%s exit", __func__);
295 return;
296 }
297 pthread_mutex_lock(&aec->lock);
298 destroy_aec_reference_config_no_lock(aec);
299 pthread_mutex_unlock(&aec->lock);
300 ALOGV("%s exit", __func__);
301 }
302
write_to_reference_fifo(struct aec_t * aec,void * buffer,struct aec_info * info)303 int write_to_reference_fifo(struct aec_t* aec, void* buffer, struct aec_info* info) {
304 ALOGV("%s enter", __func__);
305 int ret = 0;
306 size_t bytes = info->bytes;
307
308 /* Write audio samples to FIFO */
309 ssize_t written_bytes = fifo_write(aec->spk_fifo, buffer, bytes);
310 if (written_bytes != bytes) {
311 ALOGE("Could only write %zu of %zu bytes", written_bytes, bytes);
312 ret = -ENOMEM;
313 }
314
315 /* Write timestamp to FIFO */
316 info->bytes = written_bytes;
317 ALOGV("Speaker timestamp: %ld s, %ld nsec", info->timestamp.tv_sec, info->timestamp.tv_nsec);
318 ssize_t ts_bytes = fifo_write(aec->ts_fifo, info, sizeof(struct aec_info));
319 ALOGV("Wrote TS bytes: %zu", ts_bytes);
320 print_queue_status_to_log(aec, true);
321 ALOGV("%s exit", __func__);
322 return ret;
323 }
324
get_spk_timestamp(struct aec_t * aec,ssize_t read_bytes,uint64_t * spk_time)325 void get_spk_timestamp(struct aec_t* aec, ssize_t read_bytes, uint64_t* spk_time) {
326 *spk_time = 0;
327 uint64_t spk_time_offset = 0;
328 float usec_per_byte = 1E6 / ((float)(aec->spk_frame_size_bytes * aec->spk_sampling_rate));
329 if (aec->read_write_diff_bytes < 0) {
330 /* We're still reading a previous write packet. (We only need the first sample's timestamp,
331 * so even if we straddle packets we only care about the first one)
332 * So we just use the previous timestamp, with an appropriate offset
333 * based on the number of bytes remaining to be read from that write packet. */
334 spk_time_offset = (aec->last_spk_info.bytes + aec->read_write_diff_bytes) * usec_per_byte;
335 ALOGV("Reusing previous timestamp, calculated offset (usec) %" PRIu64, spk_time_offset);
336 } else {
337 /* If read_write_diff_bytes > 0, there are no new writes, so there won't be timestamps in
338 * the FIFO, and the check below will fail. */
339 if (!fifo_available_to_read(aec->ts_fifo)) {
340 ALOGE("Timestamp error: no new timestamps!");
341 return;
342 }
343 /* We just read valid data, so if we're here, we should have a valid timestamp to use. */
344 ssize_t ts_bytes = fifo_read(aec->ts_fifo, &aec->last_spk_info, sizeof(struct aec_info));
345 ALOGV("Read TS bytes: %zd, expected %zu", ts_bytes, sizeof(struct aec_info));
346 aec->read_write_diff_bytes -= aec->last_spk_info.bytes;
347 }
348
349 *spk_time = timespec_to_usec(aec->last_spk_info.timestamp) + spk_time_offset;
350
351 aec->read_write_diff_bytes += read_bytes;
352 struct aec_info spk_info = aec->last_spk_info;
353 while (aec->read_write_diff_bytes > 0) {
354 /* If read_write_diff_bytes > 0, it means that there are more write packet timestamps
355 * in FIFO (since there we read more valid data the size of the current timestamp's
356 * packet). Keep reading timestamps from FIFO to get to the most recent one. */
357 if (!fifo_available_to_read(aec->ts_fifo)) {
358 /* There are no more timestamps, we have the most recent one. */
359 ALOGV("At the end of timestamp FIFO, breaking...");
360 break;
361 }
362 fifo_read(aec->ts_fifo, &spk_info, sizeof(struct aec_info));
363 ALOGV("Fast-forwarded timestamp by %zd bytes, remaining bytes: %zd,"
364 " new timestamp (usec) %" PRIu64,
365 spk_info.bytes, aec->read_write_diff_bytes, timespec_to_usec(spk_info.timestamp));
366 aec->read_write_diff_bytes -= spk_info.bytes;
367 }
368 aec->last_spk_info = spk_info;
369 }
370
get_reference_samples(struct aec_t * aec,void * buffer,struct aec_info * info)371 int get_reference_samples(struct aec_t* aec, void* buffer, struct aec_info* info) {
372 ALOGV("%s enter", __func__);
373
374 if (!aec->spk_initialized) {
375 ALOGE("%s called with no reference initialized", __func__);
376 return -EINVAL;
377 }
378
379 size_t bytes = info->bytes;
380 const size_t frames =
381 bytes * aec->num_reference_channels / aec->mic_num_channels / aec->mic_frame_size_bytes;
382 const size_t sample_rate_ratio = aec->spk_sampling_rate / aec->mic_sampling_rate;
383 const size_t resampler_in_frames = frames * sample_rate_ratio;
384
385 /* Read audio samples from FIFO */
386 const size_t req_bytes = resampler_in_frames * aec->spk_frame_size_bytes;
387 ssize_t available_bytes = 0;
388 unsigned int wait_count = MAX_READ_WAIT_TIME_MSEC;
389 while (true) {
390 available_bytes = fifo_available_to_read(aec->spk_fifo);
391 if (available_bytes >= req_bytes) {
392 break;
393 } else if (available_bytes < 0) {
394 ALOGE("fifo_read returned code %zu ", available_bytes);
395 return -ENOMEM;
396 }
397
398 ALOGV("Sleeping, required bytes: %zu, available bytes: %zd", req_bytes, available_bytes);
399 usleep(1000);
400 if ((wait_count--) == 0) {
401 ALOGE("Timed out waiting for read from reference FIFO");
402 return -ETIMEDOUT;
403 }
404 }
405
406 const size_t read_bytes = fifo_read(aec->spk_fifo, aec->spk_buf_playback_format, req_bytes);
407
408 /* Get timestamp*/
409 get_spk_timestamp(aec, read_bytes, &info->timestamp_usec);
410
411 /* Get reference - could be mono, downmixed from multichannel.
412 * Reference stored at spk_buf_playback_format */
413 get_reference_audio_in_place(aec, resampler_in_frames);
414
415 int16_t* resampler_out_buf;
416 /* Resample to mic sampling rate (16-bit resampler) */
417 if (aec->spk_resampler != NULL) {
418 size_t in_frame_count = resampler_in_frames;
419 size_t out_frame_count = frames;
420 aec->spk_resampler->resample_from_input(aec->spk_resampler, aec->spk_buf_playback_format,
421 &in_frame_count, aec->spk_buf_resampler_out,
422 &out_frame_count);
423 resampler_out_buf = aec->spk_buf_resampler_out;
424 } else {
425 if (sample_rate_ratio != 1) {
426 ALOGE("Speaker sample rate %d, mic sample rate %d but no resampler defined!",
427 aec->spk_sampling_rate, aec->mic_sampling_rate);
428 }
429 resampler_out_buf = aec->spk_buf_playback_format;
430 }
431
432 /* Convert to 32 bit */
433 int16_t* src16 = resampler_out_buf;
434 int32_t* dst32 = buffer;
435 size_t frame, ch;
436 for (frame = 0; frame < frames; frame++) {
437 for (ch = 0; ch < aec->num_reference_channels; ch++) {
438 *dst32++ = ((int32_t)*src16++) << 16;
439 }
440 }
441
442 info->bytes = bytes;
443
444 ALOGV("%s exit", __func__);
445 return 0;
446 }
447
init_aec_mic_config(struct aec_t * aec,struct alsa_stream_in * in)448 int init_aec_mic_config(struct aec_t *aec, struct alsa_stream_in *in) {
449 ALOGV("%s enter", __func__);
450 #if DEBUG_AEC
451 remove("/data/local/traces/aec_in.pcm");
452 remove("/data/local/traces/aec_out.pcm");
453 remove("/data/local/traces/aec_ref.pcm");
454 remove("/data/local/traces/aec_timestamps.txt");
455 #endif /* #if DEBUG_AEC */
456
457 if (!aec) {
458 ALOGE("AEC: No valid interface found!");
459 return -EINVAL;
460 }
461
462 int ret = 0;
463 pthread_mutex_lock(&aec->lock);
464 if (aec->mic_initialized) {
465 destroy_aec_mic_config_no_lock(aec);
466 }
467 aec->mic_sampling_rate = in->config.rate;
468 aec->mic_frame_size_bytes = audio_stream_in_frame_size(&in->stream);
469 aec->mic_num_channels = in->config.channels;
470
471 aec->mic_buf_size_bytes = in->config.period_size * aec->mic_frame_size_bytes;
472 aec->mic_buf = (int32_t *)malloc(aec->mic_buf_size_bytes);
473 if (aec->mic_buf == NULL) {
474 ret = -ENOMEM;
475 goto exit;
476 }
477 memset(aec->mic_buf, 0, aec->mic_buf_size_bytes);
478 /* Reference buffer is the same number of frames as mic,
479 * only with a different number of channels in the frame. */
480 aec->spk_buf_size_bytes = in->config.period_size * aec->spk_num_channels *
481 aec->mic_frame_size_bytes / aec->mic_num_channels;
482 aec->spk_buf = (int32_t *)malloc(aec->spk_buf_size_bytes);
483 if (aec->spk_buf == NULL) {
484 ret = -ENOMEM;
485 goto exit_1;
486 }
487 memset(aec->spk_buf, 0, aec->spk_buf_size_bytes);
488
489 /* Pre-resampler buffer */
490 size_t spk_frame_out_format_bytes =
491 aec->spk_buf_size_bytes * aec->spk_sampling_rate / aec->mic_sampling_rate;
492 aec->spk_buf_playback_format = (int16_t *)malloc(spk_frame_out_format_bytes);
493 if (aec->spk_buf_playback_format == NULL) {
494 ret = -ENOMEM;
495 goto exit_2;
496 }
497 /* Resampler is 16-bit */
498 aec->spk_buf_resampler_out = (int16_t *)malloc(aec->spk_buf_size_bytes);
499 if (aec->spk_buf_resampler_out == NULL) {
500 ret = -ENOMEM;
501 goto exit_3;
502 }
503
504 /* Don't use resampler if it's not required */
505 if (in->config.rate == aec->spk_sampling_rate) {
506 aec->spk_resampler = NULL;
507 } else {
508 int resampler_ret = create_resampler(
509 aec->spk_sampling_rate, in->config.rate, aec->num_reference_channels,
510 RESAMPLER_QUALITY_MAX - 1, /* MAX - 1 is the real max */
511 NULL, /* resampler_buffer_provider */
512 &aec->spk_resampler);
513 if (resampler_ret) {
514 ALOGE("AEC: Resampler initialization failed! Error code %d", resampler_ret);
515 ret = resampler_ret;
516 goto exit_4;
517 }
518 }
519
520 flush_aec_fifos(aec);
521 aec_spk_mic_reset();
522 aec->mic_initialized = true;
523
524 exit:
525 pthread_mutex_unlock(&aec->lock);
526 ALOGV("%s exit", __func__);
527 return ret;
528
529 exit_4:
530 free(aec->spk_buf_resampler_out);
531 exit_3:
532 free(aec->spk_buf_playback_format);
533 exit_2:
534 free(aec->spk_buf);
535 exit_1:
536 free(aec->mic_buf);
537 pthread_mutex_unlock(&aec->lock);
538 ALOGV("%s exit", __func__);
539 return ret;
540 }
541
aec_set_spk_running(struct aec_t * aec,bool state)542 void aec_set_spk_running(struct aec_t *aec, bool state) {
543 ALOGV("%s enter", __func__);
544 pthread_mutex_lock(&aec->lock);
545 aec_set_spk_running_no_lock(aec, state);
546 pthread_mutex_unlock(&aec->lock);
547 ALOGV("%s exit", __func__);
548 }
549
aec_get_spk_running(struct aec_t * aec)550 bool aec_get_spk_running(struct aec_t *aec) {
551 ALOGV("%s enter", __func__);
552 pthread_mutex_lock(&aec->lock);
553 bool state = aec_get_spk_running_no_lock(aec);
554 pthread_mutex_unlock(&aec->lock);
555 ALOGV("%s exit", __func__);
556 return state;
557 }
558
destroy_aec_mic_config(struct aec_t * aec)559 void destroy_aec_mic_config(struct aec_t* aec) {
560 ALOGV("%s enter", __func__);
561 if (aec == NULL) {
562 ALOGV("%s exit", __func__);
563 return;
564 }
565
566 pthread_mutex_lock(&aec->lock);
567 destroy_aec_mic_config_no_lock(aec);
568 pthread_mutex_unlock(&aec->lock);
569 ALOGV("%s exit", __func__);
570 }
571
572 #ifdef AEC_HAL
process_aec(struct aec_t * aec,void * buffer,struct aec_info * info)573 int process_aec(struct aec_t *aec, void* buffer, struct aec_info *info) {
574 ALOGV("%s enter", __func__);
575 int ret = 0;
576
577 if (aec == NULL) {
578 ALOGE("AEC: Interface uninitialized! Cannot process.");
579 return -EINVAL;
580 }
581
582 if ((!aec->mic_initialized) || (!aec->spk_initialized)) {
583 ALOGE("%s called with initialization: mic: %d, spk: %d", __func__, aec->mic_initialized,
584 aec->spk_initialized);
585 return -EINVAL;
586 }
587
588 size_t bytes = info->bytes;
589
590 size_t frame_size = aec->mic_frame_size_bytes;
591 size_t in_frames = bytes / frame_size;
592
593 /* Copy raw mic samples to AEC input buffer */
594 memcpy(aec->mic_buf, buffer, bytes);
595
596 uint64_t mic_time = timespec_to_usec(info->timestamp);
597 uint64_t spk_time = 0;
598
599 /*
600 * Only run AEC if there is speaker playback.
601 * The first time speaker state changes to running, flush FIFOs, so we're not stuck
602 * processing stale reference input.
603 */
604 bool spk_running = aec_get_spk_running(aec);
605
606 if (!spk_running) {
607 /* No new playback samples, so don't run AEC.
608 * 'buffer' already contains input samples. */
609 ALOGV("Speaker not running, skipping AEC..");
610 goto exit;
611 }
612
613 if (!aec->prev_spk_running) {
614 flush_aec_fifos(aec);
615 }
616
617 /* If there's no data in FIFO, exit */
618 if (fifo_available_to_read(aec->spk_fifo) <= 0) {
619 ALOGV("Echo reference buffer empty, zeroing reference....");
620 goto exit;
621 }
622
623 print_queue_status_to_log(aec, false);
624
625 /* Get reference, with format and sample rate required by AEC */
626 struct aec_info spk_info;
627 spk_info.bytes = bytes;
628 int ref_ret = get_reference_samples(aec, aec->spk_buf, &spk_info);
629 spk_time = spk_info.timestamp_usec;
630
631 if (ref_ret) {
632 ALOGE("get_reference_samples returned code %d", ref_ret);
633 ret = -ENOMEM;
634 goto exit;
635 }
636
637 int64_t time_diff = (mic_time > spk_time) ? (mic_time - spk_time) : (spk_time - mic_time);
638 if ((spk_time == 0) || (mic_time == 0) || (time_diff > MAX_TIMESTAMP_DIFF_USEC)) {
639 ALOGV("Speaker-mic timestamps diverged, skipping AEC");
640 flush_aec_fifos(aec);
641 aec_spk_mic_reset();
642 goto exit;
643 }
644
645 ALOGV("Mic time: %"PRIu64", spk time: %"PRIu64, mic_time, spk_time);
646
647 /*
648 * AEC processing call - output stored at 'buffer'
649 */
650 int32_t aec_status = aec_spk_mic_process(
651 aec->spk_buf, spk_time,
652 aec->mic_buf, mic_time,
653 in_frames,
654 buffer);
655
656 if (!aec_status) {
657 ALOGE("AEC processing failed!");
658 ret = -EINVAL;
659 }
660
661 exit:
662 aec->prev_spk_running = spk_running;
663 ALOGV("Mic time: %"PRIu64", spk time: %"PRIu64, mic_time, spk_time);
664 if (ret) {
665 /* Best we can do is copy over the raw mic signal */
666 memcpy(buffer, aec->mic_buf, bytes);
667 flush_aec_fifos(aec);
668 aec_spk_mic_reset();
669 }
670
671 #if DEBUG_AEC
672 /* ref data is 32-bit at this point */
673 size_t ref_bytes = in_frames*aec->num_reference_channels*sizeof(int32_t);
674
675 FILE *fp_in = fopen("/data/local/traces/aec_in.pcm", "a+");
676 if (fp_in) {
677 fwrite((char *)aec->mic_buf, 1, bytes, fp_in);
678 fclose(fp_in);
679 } else {
680 ALOGE("AEC debug: Could not open file aec_in.pcm!");
681 }
682 FILE *fp_out = fopen("/data/local/traces/aec_out.pcm", "a+");
683 if (fp_out) {
684 fwrite((char *)buffer, 1, bytes, fp_out);
685 fclose(fp_out);
686 } else {
687 ALOGE("AEC debug: Could not open file aec_out.pcm!");
688 }
689 FILE *fp_ref = fopen("/data/local/traces/aec_ref.pcm", "a+");
690 if (fp_ref) {
691 fwrite((char *)aec->spk_buf, 1, ref_bytes, fp_ref);
692 fclose(fp_ref);
693 } else {
694 ALOGE("AEC debug: Could not open file aec_ref.pcm!");
695 }
696 FILE *fp_ts = fopen("/data/local/traces/aec_timestamps.txt", "a+");
697 if (fp_ts) {
698 fprintf(fp_ts, "%"PRIu64",%"PRIu64"\n", mic_time, spk_time);
699 fclose(fp_ts);
700 } else {
701 ALOGE("AEC debug: Could not open file aec_timestamps.txt!");
702 }
703 #endif /* #if DEBUG_AEC */
704 ALOGV("%s exit", __func__);
705 return ret;
706 }
707
708 #endif /*#ifdef AEC_HAL*/
709