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