blob: f0309c237a730c543cf33e7723337aff9c92aad1 [file] [log] [blame]
Garmond Leunge2433c32017-09-28 21:51:22 -07001/*
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +05302 * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
Garmond Leunge2433c32017-09-28 21:51:22 -07003 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above
10 * copyright notice, this list of conditions and the following
11 * disclaimer in the documentation and/or other materials provided
12 * with the distribution.
13 * * Neither the name of The Linux Foundation nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
18 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
21 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
24 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
26 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#define LOG_TAG "audio_hw_ffv"
31/*#define LOG_NDEBUG 0*/
32#define LOG_NDDEBUG 0
33/*#define VERY_VERY_VERBOSE_LOGGING*/
34#ifdef VERY_VERY_VERBOSE_LOGGING
35#define ALOGVV ALOGV
36#else
37#define ALOGVV(a...) do { } while(0)
38#endif
39
40#include <errno.h>
41#include <cutils/properties.h>
42#include <stdlib.h>
43#include <dlfcn.h>
44#include <cutils/str_parms.h>
45#include <cutils/log.h>
46#include <pthread.h>
47#include <sys/resource.h>
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +053048#include <unistd.h>
Dhanalakshmi Siddani6b2274c2019-03-22 15:27:44 +053049#include <system/thread_defs.h>
Garmond Leunge2433c32017-09-28 21:51:22 -070050
51#include "audio_hw.h"
Surendar Karka59c51072017-12-13 11:25:57 +053052#include "audio_extn.h"
Garmond Leunge2433c32017-09-28 21:51:22 -070053#include "platform.h"
54#include "platform_api.h"
55
56#include "ffv_interface.h"
57
58#define AUDIO_PARAMETER_FFV_MODE_ON "ffvOn"
59#define AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA "ffv_split_ec_ref_data"
60#define AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT "ffv_ec_ref_channel_count"
61#define AUDIO_PARAMETER_FFV_EC_REF_DEVICE "ffv_ec_ref_dev"
62#define AUDIO_PARAMETER_FFV_CHANNEL_INDEX "ffv_channel_index"
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +053063#define AUDIO_PARAMETER_FFV_CHANNEL_COUNT "ffv_channel_count"
Garmond Leunge2433c32017-09-28 21:51:22 -070064
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +053065#if LINUX_ENABLED
Garmond Leunge2433c32017-09-28 21:51:22 -070066#define FFV_CONFIG_FILE_PATH "/etc/BF_1out.cfg"
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +053067#ifdef __LP64__
68#define FFV_LIB "/usr/lib64/libffv.so"
69#else
70#define FFV_LIB "/usr/lib/libffv.so"
71#endif
72#else
73#define FFV_CONFIG_FILE_PATH "/vendor/etc/BF_1out.cfg"
74#ifdef __LP64__
75#define FFV_LIB "/vendor/lib64/libffv.so"
76#else
77#define FFV_LIB "/vendor/lib/libffv.so"
78#endif
79#endif
80
Garmond Leunge2433c32017-09-28 21:51:22 -070081#define FFV_SAMPLING_RATE_16000 16000
82#define FFV_EC_REF_LOOPBACK_DEVICE_MONO "ec-ref-loopback-mono"
83#define FFV_EC_REF_LOOPBACK_DEVICE_STEREO "ec-ref-loopback-stereo"
84
85#define FFV_CHANNEL_MODE_MONO 1
86#define FFV_CHANNEL_MODE_STEREO 2
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +053087#define FFV_CHANNEL_MODE_QUAD 4
Garmond Leunge2433c32017-09-28 21:51:22 -070088#define FFV_CHANNEL_MODE_HEX 6
89#define FFV_CHANNEL_MODE_OCT 8
90
91#define FFV_PCM_BUFFER_DURATION_MS 160
92#define FFV_PCM_PERIOD_COUNT (8)
93#define FFV_PCM_PERIOD_SIZE \
94 ((((FFV_SAMPLING_RATE_16000 * FFV_PCM_BUFFER_DURATION_MS) \
95 /(FFV_PCM_PERIOD_COUNT * 1000)) + 0x1f) & ~0x1f)
96
97#define ALIGN(number, align) \
98 ((number + align - 1) & ~(align - 1))
99#define CALCULATE_PERIOD_SIZE(duration_ms, sample_rate, period_cnt, align) \
100 (ALIGN(((sample_rate * duration_ms) /(period_cnt * 1000)), align))
101
102#define FFV_PCM_MAX_RETRY 10
103#define FFV_PCM_SLEEP_WAIT 1000
104
105#define DLSYM(handle, name, err) \
106do {\
107 const char* error; \
108 *(void**)&name##_fn = dlsym(handle, #name);\
109 if ((error = dlerror())) {\
110 ALOGE("%s: dlsym failed for %s error %s", __func__, #name, error);\
111 err = -ENODEV;\
112 }\
113} while(0)\
114
115/* uncomment to collect pcm dumps */
116//#define FFV_PCM_DUMP
117
118static FfvStatusType (*ffv_init_fn)(void** handle, int num_tx_in_ch,
119 int num_out_ch, int num_ec_ref_ch, int frame_len, int sample_rate,
120 const char *config_file_name, char *svaModelBuffer,
121 uint32_t svaModelSize, int* totMemSize);
122static void (*ffv_deinit_fn)(void* handle);
123static void (*ffv_process_fn)(void *handle, const int16_t *in_pcm,
124 int16_t *out_pcm, const int16_t *ec_ref_pcm);
125static int (*ffv_read_fn)(void* handle, int16_t *buf_pcm,
126 int max_buf_len);
127static FfvStatusType (*ffv_get_param_fn)(void *handle, char *params_buffer_ptr,
128 int param_id, int buffer_size, int *param_size_ptr);
129static FfvStatusType (*ffv_set_param_fn)(void *handle, char *params_buffer_ptr,
130 int param_id, int param_size);
131static FfvStatusType (*ffv_register_event_callback_fn)(void *handle,
132 ffv_event_callback_fn_t *fun_ptr);
133
134struct ffvmodule {
135 void *ffv_lib_handle;
136 unsigned char *in_buf;
137 unsigned int in_buf_size;
138 unsigned char *ec_ref_buf;
139 unsigned int ec_ref_buf_size;
140 unsigned char *split_in_buf;
141 unsigned int split_in_buf_size;
142 unsigned char *out_buf;
143 unsigned int out_buf_size;
144
145 struct pcm_config capture_config;
146 struct pcm_config out_config;
147 struct pcm_config ec_ref_config;
148
149 int ec_ref_pcm_id;
150 struct pcm *ec_ref_pcm;
151 int ec_ref_ch_cnt;
152 audio_devices_t ec_ref_dev;
153 bool split_ec_ref_data;
154
155 bool is_ffv_enabled;
156 bool buffers_allocated;
157 struct stream_in *in;
158 bool is_ffvmode_on;
159 void *handle;
160 pthread_mutex_t init_lock;
161 bool capture_started;
162 int target_ch_idx;
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530163 int ch_count;
Garmond Leunge2433c32017-09-28 21:51:22 -0700164
165#ifdef FFV_PCM_DUMP
166 FILE *fp_input;
167 FILE *fp_ecref;
168 FILE *fp_split_input;
169 FILE *fp_output;
170#endif
171};
172
173static struct ffvmodule ffvmod = {
174 .ffv_lib_handle = NULL,
175 .in_buf = NULL,
176 .in_buf_size = 0,
177 .ec_ref_buf = NULL,
178 .ec_ref_buf_size = 0,
179 .split_in_buf = NULL,
180 .split_in_buf_size = 0,
181 .out_buf = NULL,
182 .out_buf_size = 0,
183
184 .ec_ref_pcm = NULL,
185 .ec_ref_ch_cnt = 1,
186 .ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER,
187 .is_ffv_enabled = false,
188 .buffers_allocated = false,
189 .in = NULL,
190 .is_ffvmode_on = false,
191 .handle = NULL,
192 .capture_started = false,
193 .target_ch_idx = -1,
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530194 .ch_count = 6,
Garmond Leunge2433c32017-09-28 21:51:22 -0700195};
196
197static struct pcm_config ffv_pcm_config = {
198 .channels = FFV_CHANNEL_MODE_MONO,
199 .rate = FFV_SAMPLING_RATE_16000,
200 .period_size = FFV_PCM_PERIOD_SIZE,
201 .period_count = FFV_PCM_PERIOD_COUNT,
202 .format = PCM_FORMAT_S16_LE,
203};
204
205static int32_t ffv_init_lib()
206{
207 int status = 0;
208
209 if (ffvmod.ffv_lib_handle) {
210 ALOGE("%s: FFV library is already initialized", __func__);
211 return 0;
212 }
213
214 ffvmod.ffv_lib_handle = dlopen(FFV_LIB, RTLD_NOW);
215 if (!ffvmod.ffv_lib_handle) {
216 ALOGE("%s: Unable to open %s, error %s", __func__, FFV_LIB,
217 dlerror());
218 status = -ENOENT;
219 goto exit;
220 }
221
222 dlerror(); /* clear errors */
223 DLSYM(ffvmod.ffv_lib_handle, ffv_init, status);
224 if (status)
225 goto exit;
226 DLSYM(ffvmod.ffv_lib_handle, ffv_deinit, status);
227 if (status)
228 goto exit;
229 DLSYM(ffvmod.ffv_lib_handle, ffv_process, status);
230 if (status)
231 goto exit;
232 DLSYM(ffvmod.ffv_lib_handle, ffv_read, status);
233 if (status)
234 goto exit;
235 DLSYM(ffvmod.ffv_lib_handle, ffv_get_param, status);
236 if (status)
237 goto exit;
238 DLSYM(ffvmod.ffv_lib_handle, ffv_set_param, status);
239 if (status)
240 goto exit;
241 DLSYM(ffvmod.ffv_lib_handle, ffv_register_event_callback, status);
242 if (status)
243 goto exit;
244
245 return status;
246
247exit:
248 if (ffvmod.ffv_lib_handle)
249 dlclose(ffvmod.ffv_lib_handle);
250 ffvmod.ffv_lib_handle = NULL;
251
252 return status;
253}
254
255static int deallocate_buffers()
256{
257 if (ffvmod.in_buf) {
258 free(ffvmod.in_buf);
259 ffvmod.in_buf = NULL;
260 }
261
262 if (ffvmod.split_in_buf) {
263 free(ffvmod.split_in_buf);
264 ffvmod.split_in_buf = NULL;
265 }
266
267 if (ffvmod.ec_ref_buf) {
268 free(ffvmod.ec_ref_buf);
269 ffvmod.ec_ref_buf = NULL;
270 }
271
272 if (ffvmod.out_buf) {
273 free(ffvmod.out_buf);
274 ffvmod.out_buf = NULL;
275 }
276
277 ffvmod.buffers_allocated = false;
278 return 0;
279}
280
281static int allocate_buffers()
282{
283 int status = 0;
284
285 /* in_buf - buffer read from capture session */
286 ffvmod.in_buf_size = ffvmod.capture_config.period_size * ffvmod.capture_config.channels *
287 (pcm_format_to_bits(ffvmod.capture_config.format) >> 3);
288 ffvmod.in_buf = (unsigned char *)calloc(1, ffvmod.in_buf_size);
289 if (!ffvmod.in_buf) {
290 ALOGE("%s: ERROR. Can not allocate in buffer size %d", __func__, ffvmod.in_buf_size);
291 status = -ENOMEM;
292 goto error_exit;
293 }
294 ALOGD("%s: Allocated in buffer size bytes =%d",
295 __func__, ffvmod.in_buf_size);
296
297 /* ec_buf - buffer read from ec ref capture session */
298 ffvmod.ec_ref_buf_size = ffvmod.ec_ref_config.period_size * ffvmod.ec_ref_config.channels *
299 (pcm_format_to_bits(ffvmod.ec_ref_config.format) >> 3);
300 ffvmod.ec_ref_buf = (unsigned char *)calloc(1, ffvmod.ec_ref_buf_size);
301 if (!ffvmod.ec_ref_buf) {
302 ALOGE("%s: ERROR. Can not allocate ec ref buffer size %d",
303 __func__, ffvmod.ec_ref_buf_size);
304 status = -ENOMEM;
305 goto error_exit;
306 }
307 ALOGD("%s: Allocated ec ref buffer size bytes =%d",
308 __func__, ffvmod.ec_ref_buf_size);
309
310 if (ffvmod.split_ec_ref_data) {
311 ffvmod.split_in_buf_size = ffvmod.in_buf_size - ffvmod.ec_ref_buf_size;
312 ffvmod.split_in_buf = (unsigned char *)calloc(1, ffvmod.split_in_buf_size);
313 if (!ffvmod.split_in_buf) {
314 ALOGE("%s: ERROR. Can not allocate split in buffer size %d",
315 __func__, ffvmod.split_in_buf_size);
316 status = -ENOMEM;
317 goto error_exit;
318 }
319 ALOGD("%s: Allocated split in buffer size bytes =%d",
320 __func__, ffvmod.split_in_buf_size);
321 }
322
323 /* out_buf - output buffer from FFV + SVA library */
324 ffvmod.out_buf_size = ffvmod.out_config.period_size * ffvmod.out_config.channels *
325 (pcm_format_to_bits(ffvmod.out_config.format) >> 3);
326 ffvmod.out_buf = (unsigned char *)calloc(1, ffvmod.out_buf_size);
327 if (!ffvmod.out_buf) {
328 ALOGE("%s: ERROR. Can not allocate out buffer size %d", __func__, ffvmod.out_buf_size);
329 status = -ENOMEM;
330 goto error_exit;
331 }
332 ALOGD("%s: Allocated out buffer size bytes =%d",
333 __func__, ffvmod.out_buf_size);
334
335 ffvmod.buffers_allocated = true;
336 return 0;
337
338error_exit:
339 deallocate_buffers();
340 return status;
341}
342
343void audio_extn_ffv_update_enabled()
344{
345 char ffv_enabled[PROPERTY_VALUE_MAX] = "false";
346
Chaithanya Krishna Bacharajuf5a1ce62018-02-02 11:34:11 +0530347 property_get("ro.vendor.audio.sdk.ffv", ffv_enabled, "0");
Garmond Leunge2433c32017-09-28 21:51:22 -0700348 if (!strncmp("true", ffv_enabled, 4)) {
349 ALOGD("%s: ffv is supported", __func__);
350 ffvmod.is_ffv_enabled = true;
351 } else {
352 ALOGD("%s: ffv is not supported", __func__);
353 ffvmod.is_ffv_enabled = false;
354 }
355}
356
357bool audio_extn_ffv_get_enabled()
358{
359 ALOGV("%s: is_ffv_enabled:%d is_ffvmode_on:%d ", __func__, ffvmod.is_ffv_enabled, ffvmod.is_ffvmode_on);
360
361 if(ffvmod.is_ffv_enabled && ffvmod.is_ffvmode_on)
362 return true;
363
364 return false;
365}
366
367bool audio_extn_ffv_check_usecase(struct stream_in *in) {
368 int ret = false;
369 int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
370 audio_devices_t devices = in->device;
371 audio_source_t source = in->source;
372
373 if ((audio_extn_ffv_get_enabled()) &&
374 (channel_count == 1) &&
375 (AUDIO_SOURCE_MIC == source) &&
376 ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
377 (in->format == AUDIO_FORMAT_PCM_16_BIT) &&
378 (in->sample_rate == FFV_SAMPLING_RATE_16000)) {
379 in->config.channels = channel_count;
380 in->config.period_count = FFV_PCM_PERIOD_COUNT;
381 in->config.period_size = FFV_PCM_PERIOD_SIZE;
382 ALOGD("%s: FFV enabled", __func__);
383 ret = true;
384 }
385 return ret;
386}
387
388int audio_extn_ffv_set_usecase(struct stream_in *in)
389{
390 int ret = -EINVAL;
391
392 if (audio_extn_ffv_check_usecase(in)) {
393 if (!audio_extn_ffv_stream_init(in)) {
394 ALOGD("%s: Created FFV session succesfully", __func__);
395 ret = 0;
396 } else {
397 ALOGE("%s: Unable to start FFV record session", __func__);
398 }
399 }
400 return ret;
401}
402
403struct stream_in *audio_extn_ffv_get_stream()
404{
405 return ffvmod.in;
406}
407
408void audio_extn_ffv_update_pcm_config(struct pcm_config *config)
409{
410 config->channels = ffvmod.capture_config.channels;
411 config->period_count = ffvmod.capture_config.period_count;
412 config->period_size = ffvmod.capture_config.period_size;
413}
414
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530415int32_t audio_extn_ffv_init(struct audio_device *adev __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700416{
417 int ret = 0;
418
419 ret = ffv_init_lib();
420 if (ret)
421 ALOGE("%s: ERROR. ffv_init_lib ret %d", __func__, ret);
422
423 pthread_mutex_init(&ffvmod.init_lock, NULL);
424 return ret;
425}
426
427int32_t audio_extn_ffv_deinit()
428{
429 pthread_mutex_destroy(&ffvmod.init_lock);
430 if (ffvmod.ffv_lib_handle) {
431 dlclose(ffvmod.ffv_lib_handle);
432 ffvmod.ffv_lib_handle = NULL;
433 }
434 return 0;
435}
436
437int32_t audio_extn_ffv_stream_init(struct stream_in *in)
438{
439 uint32_t ret = -EINVAL;
440 int num_tx_in_ch, num_out_ch, num_ec_ref_ch;
441 int frame_len;
442 int sample_rate;
443 const char *config_file_path = FFV_CONFIG_FILE_PATH;
444 int total_mem_size;
445 FfvStatusType status_type;
446 const char *sm_buffer = "DISABLE_KEYWORD_DETECTION";
447 ffv_target_channel_index_param_t ch_index_param;
448 char *params_buffer_ptr = NULL;
449 int param_size = 0;
450 int param_id;
451
452 if (!audio_extn_ffv_get_enabled()) {
453 ALOGE("Rejecting FFV -- init is called without enabling FFV");
454 goto fail;
455 }
456
457 if (ffvmod.handle != NULL) {
458 ALOGV("%s: reinitializing ffv library", __func__);
459 audio_extn_ffv_stream_deinit();
460 }
461
462 ffvmod.capture_config = ffv_pcm_config;
463 ffvmod.ec_ref_config = ffv_pcm_config;
464 ffvmod.out_config = ffv_pcm_config;
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530465 /* configure capture session with 6/8/4 channels */
Garmond Leunge2433c32017-09-28 21:51:22 -0700466 ffvmod.capture_config.channels = ffvmod.split_ec_ref_data ?
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530467 FFV_CHANNEL_MODE_OCT : ffvmod.ch_count;
Garmond Leunge2433c32017-09-28 21:51:22 -0700468 ffvmod.capture_config.period_size =
469 CALCULATE_PERIOD_SIZE(FFV_PCM_BUFFER_DURATION_MS,
470 ffvmod.capture_config.rate,
471 FFV_PCM_PERIOD_COUNT, 32);
472
473 /* Update channels with ec ref channel count */
474 ffvmod.ec_ref_config.channels = ffvmod.ec_ref_ch_cnt;
475 ffvmod.ec_ref_config.period_size =
476 CALCULATE_PERIOD_SIZE(FFV_PCM_BUFFER_DURATION_MS,
477 ffvmod.ec_ref_config.rate,
478 FFV_PCM_PERIOD_COUNT, 32);
479 ret = allocate_buffers();
480 if (ret)
481 goto fail;
482
483 num_ec_ref_ch = ffvmod.ec_ref_config.channels;
484 num_tx_in_ch = ffvmod.split_ec_ref_data ?
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530485 (ffvmod.capture_config.channels - num_ec_ref_ch) :
486 ffvmod.capture_config.channels;
Garmond Leunge2433c32017-09-28 21:51:22 -0700487 num_out_ch = ffvmod.out_config.channels;
488 frame_len = ffvmod.capture_config.period_size;
489 sample_rate = ffvmod.capture_config.rate;
490
491 ALOGD("%s: ec_ref_ch %d, tx_in_ch %d, out_ch %d, frame_len %d, sample_rate %d",
492 __func__, num_ec_ref_ch, num_tx_in_ch, num_out_ch, frame_len, sample_rate);
493 ALOGD("%s: config file path %s", __func__, config_file_path);
494 status_type = ffv_init_fn(&ffvmod.handle, num_tx_in_ch, num_out_ch, num_ec_ref_ch,
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530495 frame_len, sample_rate, config_file_path, (char *)sm_buffer, 0,
Garmond Leunge2433c32017-09-28 21:51:22 -0700496 &total_mem_size);
497 if (status_type) {
498 ALOGE("%s: ERROR. ffv_init returned %d", __func__, status_type);
499 ret = -EINVAL;
500 goto fail;
501 }
502 ALOGD("%s: ffv_init success %p", __func__, ffvmod.handle);
503
504 /* set target channel index if received as part of setparams */
505 if (ffvmod.target_ch_idx != -1) {
506 ALOGD("%s: target channel index %d", __func__, ffvmod.target_ch_idx);
507 ch_index_param.target_chan_idx = ffvmod.target_ch_idx;
508 params_buffer_ptr = (char *)&ch_index_param;
509 param_size = sizeof(ch_index_param);
510 param_id = FFV_TARGET_CHANNEL_INDEX_PARAM;
511 status_type = ffv_set_param_fn(ffvmod.handle, params_buffer_ptr,
512 param_id, param_size);
513 if (status_type) {
514 ALOGE("%s: ERROR. ffv_set_param_fn ret %d", __func__, status_type);
515 ret = -EINVAL;
516 goto fail;
517 }
518 }
519
520 ffvmod.in = in;
Surendar Karka59c51072017-12-13 11:25:57 +0530521#ifdef RUN_KEEP_ALIVE_IN_ARM_FFV
522 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
523#endif
Garmond Leunge2433c32017-09-28 21:51:22 -0700524#ifdef FFV_PCM_DUMP
525 if (!ffvmod.fp_input) {
526 ALOGD("%s: Opening input dump file \n", __func__);
527 ffvmod.fp_input = fopen("/data/misc/audio/ffv_input.pcm", "wb");
528 }
529 if (!ffvmod.fp_ecref) {
530 ALOGD("%s: Opening ecref dump file \n", __func__);
531 ffvmod.fp_ecref = fopen("/data/misc/audio/ffv_ecref.pcm", "wb");
532 }
533 if (!ffvmod.fp_split_input && ffvmod.split_ec_ref_data) {
534 ALOGD("%s: Opening split input dump file \n", __func__);
535 ffvmod.fp_split_input = fopen("/data/misc/audio/ffv_split_input.pcm", "wb");
536 }
537 if (!ffvmod.fp_output) {
538 ALOGD("%s: Opening output dump file \n", __func__);
539 ffvmod.fp_output = fopen("/data/misc/audio/ffv_output.pcm", "wb");
540 }
541#endif
542 ALOGV("%s: exit", __func__);
543 return 0;
544
545fail:
546 audio_extn_ffv_stream_deinit();
547 return ret;
548}
549
550int32_t audio_extn_ffv_stream_deinit()
551{
552 ALOGV("%s: entry", __func__);
553
554#ifdef FFV_PCM_DUMP
555 if (ffvmod.fp_input)
556 fclose(ffvmod.fp_input);
557
558 if (ffvmod.fp_ecref)
559 fclose(ffvmod.fp_ecref);
560
561 if (ffvmod.fp_split_input)
562 fclose(ffvmod.fp_split_input);
563
564 if (ffvmod.fp_output)
565 fclose(ffvmod.fp_output);
566#endif
567
568 if (ffvmod.handle)
569 ffv_deinit_fn(ffvmod.handle);
570
571 if (ffvmod.buffers_allocated)
572 deallocate_buffers();
Surendar Karka59c51072017-12-13 11:25:57 +0530573#ifdef RUN_KEEP_ALIVE_IN_ARM_FFV
574 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
575#endif
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530576 ffvmod.handle = NULL;
Garmond Leunge2433c32017-09-28 21:51:22 -0700577 ffvmod.in = NULL;
578 ALOGV("%s: exit", __func__);
579 return 0;
580}
581
582snd_device_t audio_extn_ffv_get_capture_snd_device()
583{
584 if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_OCT) {
585 return SND_DEVICE_IN_HANDSET_8MIC;
586 } else if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_HEX) {
587 return SND_DEVICE_IN_HANDSET_6MIC;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530588 } else if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_QUAD) {
589 return SND_DEVICE_IN_HANDSET_QMIC;
Garmond Leunge2433c32017-09-28 21:51:22 -0700590 } else {
591 ALOGE("%s: Invalid channels configured for capture", __func__);
592 return SND_DEVICE_NONE;
593 }
594}
595
596int audio_extn_ffv_init_ec_ref_loopback(struct audio_device *adev,
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530597 snd_device_t snd_device __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700598{
599 struct audio_usecase *uc_info_tx = NULL;
600 snd_device_t in_snd_device;
601 char *params_buffer_ptr = NULL;
602 int param_id = FFV_RESET_AEC_PARAM;
603 int param_size = 0;
604 FfvStatusType status_type;
605 int ret = 0;
Dhanalakshmi Siddani6b2274c2019-03-22 15:27:44 +0530606 ffv_quadrx_use_dwnmix_param_t quad_downmix;
Garmond Leunge2433c32017-09-28 21:51:22 -0700607
608 ALOGV("%s: entry", __func__);
609 /* notify library to reset AEC during each start */
610 status_type = ffv_set_param_fn(ffvmod.handle, params_buffer_ptr,
611 param_id, param_size);
612 if (status_type) {
613 ALOGE("%s: ERROR. ffv_set_param_fn ret %d", __func__, status_type);
614 return -EINVAL;
615 }
616
617 if (ffvmod.split_ec_ref_data) {
618 ALOGV("%s: Ignore ec ref loopback init", __func__);
619 return 0;
620 }
621
622 in_snd_device = platform_get_ec_ref_loopback_snd_device(ffvmod.ec_ref_ch_cnt);
623 uc_info_tx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
624 if (!uc_info_tx) {
625 return -ENOMEM;
626 }
627
Dhanalakshmi Siddani6b2274c2019-03-22 15:27:44 +0530628 if (in_snd_device == SND_DEVICE_IN_EC_REF_LOOPBACK_QUAD) {
629 quad_downmix.quadrx_dwnmix_enable = true;
630 ALOGD("%s: set param for 4 ch ec, handle %p", __func__, ffvmod.handle);
631 status_type = ffv_set_param_fn(ffvmod.handle,
632 (char *)&quad_downmix,
633 FFV_QUADRX_USE_DWNMIX_PARAM,
634 sizeof(ffv_quadrx_use_dwnmix_param_t));
635 if (status_type) {
636 ALOGE("%s: ERROR. ffv_set_param_fn for quad channel ec ref %d",
637 __func__, status_type);
638 return -EINVAL;
639 }
640 }
641
Garmond Leunge2433c32017-09-28 21:51:22 -0700642 pthread_mutex_lock(&ffvmod.init_lock);
643 uc_info_tx->id = USECASE_AUDIO_EC_REF_LOOPBACK;
644 uc_info_tx->type = PCM_CAPTURE;
645 uc_info_tx->in_snd_device = in_snd_device;
646 uc_info_tx->out_snd_device = SND_DEVICE_NONE;
647 ffvmod.ec_ref_pcm = NULL;
648 list_add_tail(&adev->usecase_list, &uc_info_tx->list);
649 enable_snd_device(adev, in_snd_device);
650 enable_audio_route(adev, uc_info_tx);
651
652 ffvmod.ec_ref_pcm_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
653 if (ffvmod.ec_ref_pcm_id < 0) {
654 ALOGE("%s: Invalid pcm device for usecase (%d)",
655 __func__, uc_info_tx->id);
656 ret = -ENODEV;
657 goto exit;
658 }
659
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530660 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d format %d",
661 __func__, adev->snd_card, ffvmod.ec_ref_pcm_id, ffvmod.ec_ref_config.channels,
662 ffvmod.ec_ref_config.format);
Garmond Leunge2433c32017-09-28 21:51:22 -0700663 ffvmod.ec_ref_pcm = pcm_open(adev->snd_card,
664 ffvmod.ec_ref_pcm_id,
665 PCM_IN, &ffvmod.ec_ref_config);
666 if (ffvmod.ec_ref_pcm && !pcm_is_ready(ffvmod.ec_ref_pcm)) {
667 ALOGE("%s: %s", __func__, pcm_get_error(ffvmod.ec_ref_pcm));
668 ret = -EIO;
669 goto exit;
670 }
671
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530672 ALOGV("%s: pcm_prepare", __func__);
Garmond Leunge2433c32017-09-28 21:51:22 -0700673 if (pcm_prepare(ffvmod.ec_ref_pcm) < 0) {
674 ALOGE("%s: pcm prepare for ec ref loopback failed", __func__);
675 ret = -EINVAL;
676 }
677
678 ffvmod.capture_started = false;
679 pthread_mutex_unlock(&ffvmod.init_lock);
680 ALOGV("%s: exit", __func__);
681 return 0;
682
683exit:
684 if (ffvmod.ec_ref_pcm) {
685 pcm_close(ffvmod.ec_ref_pcm);
686 ffvmod.ec_ref_pcm = NULL;
687 }
688 list_remove(&uc_info_tx->list);
689 disable_snd_device(adev, in_snd_device);
690 disable_audio_route(adev, uc_info_tx);
691 free(uc_info_tx);
692 pthread_mutex_unlock(&ffvmod.init_lock);
693 return ret;
694}
695
696void audio_extn_ffv_append_ec_ref_dev_name(char *device_name)
697{
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530698 if (ffvmod.ec_ref_dev == AUDIO_DEVICE_OUT_LINE)
Garmond Leunge2433c32017-09-28 21:51:22 -0700699 strlcat(device_name, " lineout", DEVICE_NAME_MAX_SIZE);
700 ALOGD("%s: ec ref dev name %s", __func__, device_name);
701}
702
703int audio_extn_ffv_deinit_ec_ref_loopback(struct audio_device *adev,
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530704 snd_device_t snd_device __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700705{
706 struct audio_usecase *uc_info_tx = NULL;
707 snd_device_t in_snd_device;
708 int ret = 0;
709
710 ALOGV("%s: entry", __func__);
711 if (ffvmod.split_ec_ref_data) {
712 ALOGV("%s: Ignore ec ref loopback init", __func__);
713 return 0;
714 }
715
716 in_snd_device = platform_get_ec_ref_loopback_snd_device(ffvmod.ec_ref_ch_cnt);
717 uc_info_tx = get_usecase_from_list(adev, USECASE_AUDIO_EC_REF_LOOPBACK);
718 pthread_mutex_lock(&ffvmod.init_lock);
719 if (ffvmod.ec_ref_pcm) {
720 pcm_close(ffvmod.ec_ref_pcm);
721 ffvmod.ec_ref_pcm = NULL;
722 }
723 disable_snd_device(adev, in_snd_device);
724 if (uc_info_tx) {
725 list_remove(&uc_info_tx->list);
726 disable_audio_route(adev, uc_info_tx);
727 free(uc_info_tx);
728 }
729 pthread_mutex_unlock(&ffvmod.init_lock);
730 ALOGV("%s: exit", __func__);
731 return ret;
732}
733
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530734int32_t audio_extn_ffv_read(struct audio_stream_in *stream __unused,
Garmond Leunge2433c32017-09-28 21:51:22 -0700735 void *buffer, size_t bytes)
736{
737 int status = 0;
738 int16_t *in_ptr = NULL, *process_in_ptr = NULL, *process_out_ptr = NULL;
739 int16_t *process_ec_ref_ptr = NULL;
740 size_t in_buf_size, out_buf_size, bytes_to_copy;
741 int retry_num = 0;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530742 int i, ch;
Garmond Leunge2433c32017-09-28 21:51:22 -0700743 int total_in_ch, in_ch, ec_ref_ch;
744
745 if (!ffvmod.ffv_lib_handle) {
746 ALOGE("%s: ffv_lib_handle not initialized", __func__);
747 return -EINVAL;
748 }
749
750 if (!ffvmod.handle) {
751 ALOGE("%s: ffv module handle not initialized", __func__);
752 return -EINVAL;
753 }
754
755 if (!ffvmod.in || !ffvmod.in->pcm) {
756 ALOGE("%s: capture session not initiliazed", __func__);
757 return -EINVAL;
758 }
759
760 if (!ffvmod.split_ec_ref_data && !ffvmod.ec_ref_pcm) {
761 ALOGE("%s: ec ref session not initiliazed", __func__);
762 return -EINVAL;
763 }
764
765 if (!ffvmod.capture_started) {
766 /* pcm_start of capture and ec ref session before read to reduce drift */
767 pcm_start(ffvmod.in->pcm);
768 while (status && (retry_num < FFV_PCM_MAX_RETRY)) {
769 usleep(FFV_PCM_SLEEP_WAIT);
770 retry_num++;
771 ALOGI("%s: pcm_start retrying..status %d errno %d, retry cnt %d",
772 __func__, status, errno, retry_num);
773 status = pcm_start(ffvmod.in->pcm);
774 }
775 if (status) {
776 ALOGE("%s: ERROR. pcm_start failed, returned status %d - %s",
777 __func__, status, pcm_get_error(ffvmod.in->pcm));
778 return status;
779 }
780 retry_num = 0;
781
782 if (!ffvmod.split_ec_ref_data) {
783 pcm_start(ffvmod.ec_ref_pcm);
784 while (status && (retry_num < FFV_PCM_MAX_RETRY)) {
785 usleep(FFV_PCM_SLEEP_WAIT);
786 retry_num++;
787 ALOGI("%s: pcm_start retrying..status %d errno %d, retry cnt %d",
788 __func__, status, errno, retry_num);
789 status = pcm_start(ffvmod.ec_ref_pcm);
790 }
791 if (status) {
792 ALOGE("%s: ERROR. pcm_start failed, returned status %d - %s",
793 __func__, status, pcm_get_error(ffvmod.ec_ref_pcm));
794 return status;
795 }
796 }
Dhanalakshmi Siddani6b2274c2019-03-22 15:27:44 +0530797 audio_extn_set_cpu_affinity();
798 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Garmond Leunge2433c32017-09-28 21:51:22 -0700799 ffvmod.capture_started = true;
800 }
801
802 ALOGVV("%s: pcm_read reading bytes=%d", __func__, ffvmod.in_buf_size);
803 status = pcm_read(ffvmod.in->pcm, ffvmod.in_buf, ffvmod.in_buf_size);
804 if (status) {
805 ALOGE("%s: pcm read failed status %d - %s", __func__, status,
806 pcm_get_error(ffvmod.in->pcm));
807 goto exit;
808 }
809 ALOGVV("%s: pcm_read done", __func__);
810
811 if (!ffvmod.split_ec_ref_data) {
812 /* read EC ref data */
813 ALOGVV("%s: ec ref pcm_read reading bytes=%d", __func__, ffvmod.ec_ref_buf_size);
814 status = pcm_read(ffvmod.ec_ref_pcm, ffvmod.ec_ref_buf, ffvmod.ec_ref_buf_size);
815 if (status) {
816 ALOGE("%s: ec ref pcm read failed status %d - %s", __func__, status,
817 pcm_get_error(ffvmod.ec_ref_pcm));
818 goto exit;
819 }
820 ALOGVV("%s: ec ref pcm_read done", __func__);
821 process_in_ptr = (int16_t *)ffvmod.in_buf;
822 process_ec_ref_ptr = (int16_t *)ffvmod.ec_ref_buf;
823 in_buf_size = ffvmod.in_buf_size;
824 } else {
825 /* split input buffer into actual input channels and EC ref channels */
826 in_ptr = (int16_t *)ffvmod.in_buf;
827 process_in_ptr = (int16_t *)ffvmod.split_in_buf;
828 process_ec_ref_ptr = (int16_t *)ffvmod.ec_ref_buf;
829 total_in_ch = ffvmod.capture_config.channels;
830 ec_ref_ch = ffvmod.ec_ref_config.channels;
831 in_ch = total_in_ch - ec_ref_ch;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530832 for (i = 0; i < (int)ffvmod.capture_config.period_size; i++) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700833 for (ch = 0; ch < in_ch; ch++) {
834 process_in_ptr[i*in_ch+ch] =
835 in_ptr[i*total_in_ch+ch];
836 }
837 for (ch = 0; ch < ec_ref_ch; ch++) {
838 process_ec_ref_ptr[i*ec_ref_ch+ch] =
839 in_ptr[i*total_in_ch+in_ch+ch];
840 }
841 }
842 in_buf_size = ffvmod.split_in_buf_size;
843 }
844 process_out_ptr = (int16_t *)ffvmod.out_buf;
845
846 ffv_process_fn(ffvmod.handle, process_in_ptr,
847 process_out_ptr, process_ec_ref_ptr);
848 out_buf_size = ffvmod.out_buf_size;
849 bytes_to_copy = (bytes <= out_buf_size) ? bytes : out_buf_size;
850 memcpy(buffer, process_out_ptr, bytes_to_copy);
851 if (bytes_to_copy != out_buf_size)
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530852 ALOGD("%s: out buffer data dropped, copied %zu bytes",
Garmond Leunge2433c32017-09-28 21:51:22 -0700853 __func__, bytes_to_copy);
854
855#ifdef FFV_PCM_DUMP
856 if (ffvmod.fp_input)
857 fwrite(ffvmod.in_buf, 1, ffvmod.in_buf_size, ffvmod.fp_input);
858 if (ffvmod.fp_ecref)
859 fwrite(ffvmod.ec_ref_buf, 1, ffvmod.ec_ref_buf_size, ffvmod.fp_ecref);
860 if (ffvmod.fp_split_input)
861 fwrite(ffvmod.split_in_buf, 1, ffvmod.split_in_buf_size, ffvmod.fp_split_input);
862 if (ffvmod.fp_output)
863 fwrite(process_out_ptr, 1, bytes_to_copy, ffvmod.fp_output);
864#endif
865
866exit:
867 return status;
868}
869
870void audio_extn_ffv_set_parameters(struct audio_device *adev __unused,
871 struct str_parms *parms)
872{
Garmond Leunge2433c32017-09-28 21:51:22 -0700873 int val;
874 int ret = 0;
875 char value[128];
876
877 /* FFV params are required to be set before start of recording */
878 if (!ffvmod.handle) {
879 ret = str_parms_get_str(parms, AUDIO_PARAMETER_FFV_MODE_ON, value,
880 sizeof(value));
881 if (ret >= 0) {
882 str_parms_del(parms, AUDIO_PARAMETER_FFV_MODE_ON);
883 if (strcmp(value, "true") == 0) {
884 ALOGD("%s: Setting FFV mode to true", __func__);
885 ffvmod.is_ffvmode_on = true;
886 } else {
887 ALOGD("%s: Resetting FFV mode to false", __func__);
888 ffvmod.is_ffvmode_on = false;
889 }
890 }
891
892 ret = str_parms_get_str(parms, AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA, value,
893 sizeof(value));
894 if (ret >= 0) {
895 str_parms_del(parms, AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA);
896 if (strcmp(value, "true") == 0) {
897 ALOGD("%s: ec ref is packed with mic captured data", __func__);
898 ffvmod.split_ec_ref_data = true;
899 } else {
900 ALOGD("%s: ec ref is captured separately", __func__);
901 ffvmod.split_ec_ref_data = false;
902 }
903 }
904 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT, &val);
905 if (ret >= 0) {
906 str_parms_del(parms, AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT);
907 if (val == 1) {
908 ALOGD("%s: mono ec ref", __func__);
909 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_MONO;
910 } else if (val == 2) {
911 ALOGD("%s: stereo ec ref", __func__);
912 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_STEREO;
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530913 } else if (val == 4) {
914 ALOGD("%s: quad ec ref", __func__);
915 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_QUAD;
Garmond Leunge2433c32017-09-28 21:51:22 -0700916 } else {
917 ALOGE("%s: Invalid ec ref", __func__);
918 }
919 }
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530920 ret = -1;
921 if (str_parms_get_int(parms, AUDIO_PARAMETER_FFV_EC_REF_DEVICE, &val) >= 0) {
922 ret = 1;
Garmond Leunge2433c32017-09-28 21:51:22 -0700923 str_parms_del(parms, AUDIO_PARAMETER_FFV_EC_REF_DEVICE);
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530924 } else if (str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CONNECT, &val) >= 0) {
925 ret = 1;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530926 }
927 if (ret == 1) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700928 if (val & AUDIO_DEVICE_OUT_SPEAKER) {
929 ALOGD("%s: capture ec ref from speaker", __func__);
930 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530931 } else if (val & AUDIO_DEVICE_OUT_LINE) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700932 ALOGD("%s: capture ec ref from line out", __func__);
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530933 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_LINE;
Garmond Leunge2433c32017-09-28 21:51:22 -0700934 } else {
935 ALOGE("%s: Invalid ec ref out device", __func__);
936 }
937 }
938
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530939 ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
940 if (ret >= 0) {
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530941 if (val & AUDIO_DEVICE_OUT_LINE) {
942 ALOGD("%s: capture ec ref from speaker", __func__);
943 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER;
944 }
945 }
946
Garmond Leunge2433c32017-09-28 21:51:22 -0700947 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_CHANNEL_INDEX, &val);
948 if (ret >= 0) {
949 str_parms_del(parms, AUDIO_PARAMETER_FFV_CHANNEL_INDEX);
950 ALOGD("%s: set target chan index %d", __func__, val);
951 ffvmod.target_ch_idx = val;
952 }
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530953
954 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_CHANNEL_COUNT, &val);
955 if (ret >= 0) {
956 str_parms_del(parms, AUDIO_PARAMETER_FFV_CHANNEL_COUNT);
957 ALOGD("%s: set ffv channel count %d", __func__, val);
958 ffvmod.ch_count = val;
959 }
Garmond Leunge2433c32017-09-28 21:51:22 -0700960 }
961}