blob: fac40c5869985aefa19b78e98f3b88ec8abb19f1 [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>
Garmond Leunge2433c32017-09-28 21:51:22 -070049
50#include "audio_hw.h"
Surendar Karka59c51072017-12-13 11:25:57 +053051#include "audio_extn.h"
Garmond Leunge2433c32017-09-28 21:51:22 -070052#include "platform.h"
53#include "platform_api.h"
54
55#include "ffv_interface.h"
56
57#define AUDIO_PARAMETER_FFV_MODE_ON "ffvOn"
58#define AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA "ffv_split_ec_ref_data"
59#define AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT "ffv_ec_ref_channel_count"
60#define AUDIO_PARAMETER_FFV_EC_REF_DEVICE "ffv_ec_ref_dev"
61#define AUDIO_PARAMETER_FFV_CHANNEL_INDEX "ffv_channel_index"
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +053062#define AUDIO_PARAMETER_FFV_CHANNEL_COUNT "ffv_channel_count"
Garmond Leunge2433c32017-09-28 21:51:22 -070063
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +053064#if LINUX_ENABLED
Garmond Leunge2433c32017-09-28 21:51:22 -070065#define FFV_CONFIG_FILE_PATH "/etc/BF_1out.cfg"
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +053066#ifdef __LP64__
67#define FFV_LIB "/usr/lib64/libffv.so"
68#else
69#define FFV_LIB "/usr/lib/libffv.so"
70#endif
71#else
72#define FFV_CONFIG_FILE_PATH "/vendor/etc/BF_1out.cfg"
73#ifdef __LP64__
74#define FFV_LIB "/vendor/lib64/libffv.so"
75#else
76#define FFV_LIB "/vendor/lib/libffv.so"
77#endif
78#endif
79
Garmond Leunge2433c32017-09-28 21:51:22 -070080#define FFV_SAMPLING_RATE_16000 16000
81#define FFV_EC_REF_LOOPBACK_DEVICE_MONO "ec-ref-loopback-mono"
82#define FFV_EC_REF_LOOPBACK_DEVICE_STEREO "ec-ref-loopback-stereo"
83
84#define FFV_CHANNEL_MODE_MONO 1
85#define FFV_CHANNEL_MODE_STEREO 2
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +053086#define FFV_CHANNEL_MODE_QUAD 4
Garmond Leunge2433c32017-09-28 21:51:22 -070087#define FFV_CHANNEL_MODE_HEX 6
88#define FFV_CHANNEL_MODE_OCT 8
89
90#define FFV_PCM_BUFFER_DURATION_MS 160
91#define FFV_PCM_PERIOD_COUNT (8)
92#define FFV_PCM_PERIOD_SIZE \
93 ((((FFV_SAMPLING_RATE_16000 * FFV_PCM_BUFFER_DURATION_MS) \
94 /(FFV_PCM_PERIOD_COUNT * 1000)) + 0x1f) & ~0x1f)
95
96#define ALIGN(number, align) \
97 ((number + align - 1) & ~(align - 1))
98#define CALCULATE_PERIOD_SIZE(duration_ms, sample_rate, period_cnt, align) \
99 (ALIGN(((sample_rate * duration_ms) /(period_cnt * 1000)), align))
100
101#define FFV_PCM_MAX_RETRY 10
102#define FFV_PCM_SLEEP_WAIT 1000
103
104#define DLSYM(handle, name, err) \
105do {\
106 const char* error; \
107 *(void**)&name##_fn = dlsym(handle, #name);\
108 if ((error = dlerror())) {\
109 ALOGE("%s: dlsym failed for %s error %s", __func__, #name, error);\
110 err = -ENODEV;\
111 }\
112} while(0)\
113
114/* uncomment to collect pcm dumps */
115//#define FFV_PCM_DUMP
116
117static FfvStatusType (*ffv_init_fn)(void** handle, int num_tx_in_ch,
118 int num_out_ch, int num_ec_ref_ch, int frame_len, int sample_rate,
119 const char *config_file_name, char *svaModelBuffer,
120 uint32_t svaModelSize, int* totMemSize);
121static void (*ffv_deinit_fn)(void* handle);
122static void (*ffv_process_fn)(void *handle, const int16_t *in_pcm,
123 int16_t *out_pcm, const int16_t *ec_ref_pcm);
124static int (*ffv_read_fn)(void* handle, int16_t *buf_pcm,
125 int max_buf_len);
126static FfvStatusType (*ffv_get_param_fn)(void *handle, char *params_buffer_ptr,
127 int param_id, int buffer_size, int *param_size_ptr);
128static FfvStatusType (*ffv_set_param_fn)(void *handle, char *params_buffer_ptr,
129 int param_id, int param_size);
130static FfvStatusType (*ffv_register_event_callback_fn)(void *handle,
131 ffv_event_callback_fn_t *fun_ptr);
132
133struct ffvmodule {
134 void *ffv_lib_handle;
135 unsigned char *in_buf;
136 unsigned int in_buf_size;
137 unsigned char *ec_ref_buf;
138 unsigned int ec_ref_buf_size;
139 unsigned char *split_in_buf;
140 unsigned int split_in_buf_size;
141 unsigned char *out_buf;
142 unsigned int out_buf_size;
143
144 struct pcm_config capture_config;
145 struct pcm_config out_config;
146 struct pcm_config ec_ref_config;
147
148 int ec_ref_pcm_id;
149 struct pcm *ec_ref_pcm;
150 int ec_ref_ch_cnt;
151 audio_devices_t ec_ref_dev;
152 bool split_ec_ref_data;
153
154 bool is_ffv_enabled;
155 bool buffers_allocated;
156 struct stream_in *in;
157 bool is_ffvmode_on;
158 void *handle;
159 pthread_mutex_t init_lock;
160 bool capture_started;
161 int target_ch_idx;
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530162 int ch_count;
Garmond Leunge2433c32017-09-28 21:51:22 -0700163
164#ifdef FFV_PCM_DUMP
165 FILE *fp_input;
166 FILE *fp_ecref;
167 FILE *fp_split_input;
168 FILE *fp_output;
169#endif
170};
171
172static struct ffvmodule ffvmod = {
173 .ffv_lib_handle = NULL,
174 .in_buf = NULL,
175 .in_buf_size = 0,
176 .ec_ref_buf = NULL,
177 .ec_ref_buf_size = 0,
178 .split_in_buf = NULL,
179 .split_in_buf_size = 0,
180 .out_buf = NULL,
181 .out_buf_size = 0,
182
183 .ec_ref_pcm = NULL,
184 .ec_ref_ch_cnt = 1,
185 .ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER,
186 .is_ffv_enabled = false,
187 .buffers_allocated = false,
188 .in = NULL,
189 .is_ffvmode_on = false,
190 .handle = NULL,
191 .capture_started = false,
192 .target_ch_idx = -1,
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530193 .ch_count = 6,
Garmond Leunge2433c32017-09-28 21:51:22 -0700194};
195
196static struct pcm_config ffv_pcm_config = {
197 .channels = FFV_CHANNEL_MODE_MONO,
198 .rate = FFV_SAMPLING_RATE_16000,
199 .period_size = FFV_PCM_PERIOD_SIZE,
200 .period_count = FFV_PCM_PERIOD_COUNT,
201 .format = PCM_FORMAT_S16_LE,
202};
203
204static int32_t ffv_init_lib()
205{
206 int status = 0;
207
208 if (ffvmod.ffv_lib_handle) {
209 ALOGE("%s: FFV library is already initialized", __func__);
210 return 0;
211 }
212
213 ffvmod.ffv_lib_handle = dlopen(FFV_LIB, RTLD_NOW);
214 if (!ffvmod.ffv_lib_handle) {
215 ALOGE("%s: Unable to open %s, error %s", __func__, FFV_LIB,
216 dlerror());
217 status = -ENOENT;
218 goto exit;
219 }
220
221 dlerror(); /* clear errors */
222 DLSYM(ffvmod.ffv_lib_handle, ffv_init, status);
223 if (status)
224 goto exit;
225 DLSYM(ffvmod.ffv_lib_handle, ffv_deinit, status);
226 if (status)
227 goto exit;
228 DLSYM(ffvmod.ffv_lib_handle, ffv_process, status);
229 if (status)
230 goto exit;
231 DLSYM(ffvmod.ffv_lib_handle, ffv_read, status);
232 if (status)
233 goto exit;
234 DLSYM(ffvmod.ffv_lib_handle, ffv_get_param, status);
235 if (status)
236 goto exit;
237 DLSYM(ffvmod.ffv_lib_handle, ffv_set_param, status);
238 if (status)
239 goto exit;
240 DLSYM(ffvmod.ffv_lib_handle, ffv_register_event_callback, status);
241 if (status)
242 goto exit;
243
244 return status;
245
246exit:
247 if (ffvmod.ffv_lib_handle)
248 dlclose(ffvmod.ffv_lib_handle);
249 ffvmod.ffv_lib_handle = NULL;
250
251 return status;
252}
253
254static int deallocate_buffers()
255{
256 if (ffvmod.in_buf) {
257 free(ffvmod.in_buf);
258 ffvmod.in_buf = NULL;
259 }
260
261 if (ffvmod.split_in_buf) {
262 free(ffvmod.split_in_buf);
263 ffvmod.split_in_buf = NULL;
264 }
265
266 if (ffvmod.ec_ref_buf) {
267 free(ffvmod.ec_ref_buf);
268 ffvmod.ec_ref_buf = NULL;
269 }
270
271 if (ffvmod.out_buf) {
272 free(ffvmod.out_buf);
273 ffvmod.out_buf = NULL;
274 }
275
276 ffvmod.buffers_allocated = false;
277 return 0;
278}
279
280static int allocate_buffers()
281{
282 int status = 0;
283
284 /* in_buf - buffer read from capture session */
285 ffvmod.in_buf_size = ffvmod.capture_config.period_size * ffvmod.capture_config.channels *
286 (pcm_format_to_bits(ffvmod.capture_config.format) >> 3);
287 ffvmod.in_buf = (unsigned char *)calloc(1, ffvmod.in_buf_size);
288 if (!ffvmod.in_buf) {
289 ALOGE("%s: ERROR. Can not allocate in buffer size %d", __func__, ffvmod.in_buf_size);
290 status = -ENOMEM;
291 goto error_exit;
292 }
293 ALOGD("%s: Allocated in buffer size bytes =%d",
294 __func__, ffvmod.in_buf_size);
295
296 /* ec_buf - buffer read from ec ref capture session */
297 ffvmod.ec_ref_buf_size = ffvmod.ec_ref_config.period_size * ffvmod.ec_ref_config.channels *
298 (pcm_format_to_bits(ffvmod.ec_ref_config.format) >> 3);
299 ffvmod.ec_ref_buf = (unsigned char *)calloc(1, ffvmod.ec_ref_buf_size);
300 if (!ffvmod.ec_ref_buf) {
301 ALOGE("%s: ERROR. Can not allocate ec ref buffer size %d",
302 __func__, ffvmod.ec_ref_buf_size);
303 status = -ENOMEM;
304 goto error_exit;
305 }
306 ALOGD("%s: Allocated ec ref buffer size bytes =%d",
307 __func__, ffvmod.ec_ref_buf_size);
308
309 if (ffvmod.split_ec_ref_data) {
310 ffvmod.split_in_buf_size = ffvmod.in_buf_size - ffvmod.ec_ref_buf_size;
311 ffvmod.split_in_buf = (unsigned char *)calloc(1, ffvmod.split_in_buf_size);
312 if (!ffvmod.split_in_buf) {
313 ALOGE("%s: ERROR. Can not allocate split in buffer size %d",
314 __func__, ffvmod.split_in_buf_size);
315 status = -ENOMEM;
316 goto error_exit;
317 }
318 ALOGD("%s: Allocated split in buffer size bytes =%d",
319 __func__, ffvmod.split_in_buf_size);
320 }
321
322 /* out_buf - output buffer from FFV + SVA library */
323 ffvmod.out_buf_size = ffvmod.out_config.period_size * ffvmod.out_config.channels *
324 (pcm_format_to_bits(ffvmod.out_config.format) >> 3);
325 ffvmod.out_buf = (unsigned char *)calloc(1, ffvmod.out_buf_size);
326 if (!ffvmod.out_buf) {
327 ALOGE("%s: ERROR. Can not allocate out buffer size %d", __func__, ffvmod.out_buf_size);
328 status = -ENOMEM;
329 goto error_exit;
330 }
331 ALOGD("%s: Allocated out buffer size bytes =%d",
332 __func__, ffvmod.out_buf_size);
333
334 ffvmod.buffers_allocated = true;
335 return 0;
336
337error_exit:
338 deallocate_buffers();
339 return status;
340}
341
342void audio_extn_ffv_update_enabled()
343{
344 char ffv_enabled[PROPERTY_VALUE_MAX] = "false";
345
Chaithanya Krishna Bacharajuf5a1ce62018-02-02 11:34:11 +0530346 property_get("ro.vendor.audio.sdk.ffv", ffv_enabled, "0");
Garmond Leunge2433c32017-09-28 21:51:22 -0700347 if (!strncmp("true", ffv_enabled, 4)) {
348 ALOGD("%s: ffv is supported", __func__);
349 ffvmod.is_ffv_enabled = true;
350 } else {
351 ALOGD("%s: ffv is not supported", __func__);
352 ffvmod.is_ffv_enabled = false;
353 }
354}
355
356bool audio_extn_ffv_get_enabled()
357{
358 ALOGV("%s: is_ffv_enabled:%d is_ffvmode_on:%d ", __func__, ffvmod.is_ffv_enabled, ffvmod.is_ffvmode_on);
359
360 if(ffvmod.is_ffv_enabled && ffvmod.is_ffvmode_on)
361 return true;
362
363 return false;
364}
365
366bool audio_extn_ffv_check_usecase(struct stream_in *in) {
367 int ret = false;
368 int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
369 audio_devices_t devices = in->device;
370 audio_source_t source = in->source;
371
372 if ((audio_extn_ffv_get_enabled()) &&
373 (channel_count == 1) &&
374 (AUDIO_SOURCE_MIC == source) &&
375 ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
376 (in->format == AUDIO_FORMAT_PCM_16_BIT) &&
377 (in->sample_rate == FFV_SAMPLING_RATE_16000)) {
378 in->config.channels = channel_count;
379 in->config.period_count = FFV_PCM_PERIOD_COUNT;
380 in->config.period_size = FFV_PCM_PERIOD_SIZE;
381 ALOGD("%s: FFV enabled", __func__);
382 ret = true;
383 }
384 return ret;
385}
386
387int audio_extn_ffv_set_usecase(struct stream_in *in)
388{
389 int ret = -EINVAL;
390
391 if (audio_extn_ffv_check_usecase(in)) {
392 if (!audio_extn_ffv_stream_init(in)) {
393 ALOGD("%s: Created FFV session succesfully", __func__);
394 ret = 0;
395 } else {
396 ALOGE("%s: Unable to start FFV record session", __func__);
397 }
398 }
399 return ret;
400}
401
402struct stream_in *audio_extn_ffv_get_stream()
403{
404 return ffvmod.in;
405}
406
407void audio_extn_ffv_update_pcm_config(struct pcm_config *config)
408{
409 config->channels = ffvmod.capture_config.channels;
410 config->period_count = ffvmod.capture_config.period_count;
411 config->period_size = ffvmod.capture_config.period_size;
412}
413
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530414int32_t audio_extn_ffv_init(struct audio_device *adev __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700415{
416 int ret = 0;
417
418 ret = ffv_init_lib();
419 if (ret)
420 ALOGE("%s: ERROR. ffv_init_lib ret %d", __func__, ret);
421
422 pthread_mutex_init(&ffvmod.init_lock, NULL);
423 return ret;
424}
425
426int32_t audio_extn_ffv_deinit()
427{
428 pthread_mutex_destroy(&ffvmod.init_lock);
429 if (ffvmod.ffv_lib_handle) {
430 dlclose(ffvmod.ffv_lib_handle);
431 ffvmod.ffv_lib_handle = NULL;
432 }
433 return 0;
434}
435
436int32_t audio_extn_ffv_stream_init(struct stream_in *in)
437{
438 uint32_t ret = -EINVAL;
439 int num_tx_in_ch, num_out_ch, num_ec_ref_ch;
440 int frame_len;
441 int sample_rate;
442 const char *config_file_path = FFV_CONFIG_FILE_PATH;
443 int total_mem_size;
444 FfvStatusType status_type;
445 const char *sm_buffer = "DISABLE_KEYWORD_DETECTION";
446 ffv_target_channel_index_param_t ch_index_param;
447 char *params_buffer_ptr = NULL;
448 int param_size = 0;
449 int param_id;
450
451 if (!audio_extn_ffv_get_enabled()) {
452 ALOGE("Rejecting FFV -- init is called without enabling FFV");
453 goto fail;
454 }
455
456 if (ffvmod.handle != NULL) {
457 ALOGV("%s: reinitializing ffv library", __func__);
458 audio_extn_ffv_stream_deinit();
459 }
460
461 ffvmod.capture_config = ffv_pcm_config;
462 ffvmod.ec_ref_config = ffv_pcm_config;
463 ffvmod.out_config = ffv_pcm_config;
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530464 /* configure capture session with 6/8/4 channels */
Garmond Leunge2433c32017-09-28 21:51:22 -0700465 ffvmod.capture_config.channels = ffvmod.split_ec_ref_data ?
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530466 FFV_CHANNEL_MODE_OCT : ffvmod.ch_count;
Garmond Leunge2433c32017-09-28 21:51:22 -0700467 ffvmod.capture_config.period_size =
468 CALCULATE_PERIOD_SIZE(FFV_PCM_BUFFER_DURATION_MS,
469 ffvmod.capture_config.rate,
470 FFV_PCM_PERIOD_COUNT, 32);
471
472 /* Update channels with ec ref channel count */
473 ffvmod.ec_ref_config.channels = ffvmod.ec_ref_ch_cnt;
474 ffvmod.ec_ref_config.period_size =
475 CALCULATE_PERIOD_SIZE(FFV_PCM_BUFFER_DURATION_MS,
476 ffvmod.ec_ref_config.rate,
477 FFV_PCM_PERIOD_COUNT, 32);
478 ret = allocate_buffers();
479 if (ret)
480 goto fail;
481
482 num_ec_ref_ch = ffvmod.ec_ref_config.channels;
483 num_tx_in_ch = ffvmod.split_ec_ref_data ?
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530484 (ffvmod.capture_config.channels - num_ec_ref_ch) :
485 ffvmod.capture_config.channels;
Garmond Leunge2433c32017-09-28 21:51:22 -0700486 num_out_ch = ffvmod.out_config.channels;
487 frame_len = ffvmod.capture_config.period_size;
488 sample_rate = ffvmod.capture_config.rate;
489
490 ALOGD("%s: ec_ref_ch %d, tx_in_ch %d, out_ch %d, frame_len %d, sample_rate %d",
491 __func__, num_ec_ref_ch, num_tx_in_ch, num_out_ch, frame_len, sample_rate);
492 ALOGD("%s: config file path %s", __func__, config_file_path);
493 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 +0530494 frame_len, sample_rate, config_file_path, (char *)sm_buffer, 0,
Garmond Leunge2433c32017-09-28 21:51:22 -0700495 &total_mem_size);
496 if (status_type) {
497 ALOGE("%s: ERROR. ffv_init returned %d", __func__, status_type);
498 ret = -EINVAL;
499 goto fail;
500 }
501 ALOGD("%s: ffv_init success %p", __func__, ffvmod.handle);
502
503 /* set target channel index if received as part of setparams */
504 if (ffvmod.target_ch_idx != -1) {
505 ALOGD("%s: target channel index %d", __func__, ffvmod.target_ch_idx);
506 ch_index_param.target_chan_idx = ffvmod.target_ch_idx;
507 params_buffer_ptr = (char *)&ch_index_param;
508 param_size = sizeof(ch_index_param);
509 param_id = FFV_TARGET_CHANNEL_INDEX_PARAM;
510 status_type = ffv_set_param_fn(ffvmod.handle, params_buffer_ptr,
511 param_id, param_size);
512 if (status_type) {
513 ALOGE("%s: ERROR. ffv_set_param_fn ret %d", __func__, status_type);
514 ret = -EINVAL;
515 goto fail;
516 }
517 }
518
519 ffvmod.in = in;
Surendar Karka59c51072017-12-13 11:25:57 +0530520#ifdef RUN_KEEP_ALIVE_IN_ARM_FFV
521 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
522#endif
Garmond Leunge2433c32017-09-28 21:51:22 -0700523#ifdef FFV_PCM_DUMP
524 if (!ffvmod.fp_input) {
525 ALOGD("%s: Opening input dump file \n", __func__);
526 ffvmod.fp_input = fopen("/data/misc/audio/ffv_input.pcm", "wb");
527 }
528 if (!ffvmod.fp_ecref) {
529 ALOGD("%s: Opening ecref dump file \n", __func__);
530 ffvmod.fp_ecref = fopen("/data/misc/audio/ffv_ecref.pcm", "wb");
531 }
532 if (!ffvmod.fp_split_input && ffvmod.split_ec_ref_data) {
533 ALOGD("%s: Opening split input dump file \n", __func__);
534 ffvmod.fp_split_input = fopen("/data/misc/audio/ffv_split_input.pcm", "wb");
535 }
536 if (!ffvmod.fp_output) {
537 ALOGD("%s: Opening output dump file \n", __func__);
538 ffvmod.fp_output = fopen("/data/misc/audio/ffv_output.pcm", "wb");
539 }
540#endif
541 ALOGV("%s: exit", __func__);
542 return 0;
543
544fail:
545 audio_extn_ffv_stream_deinit();
546 return ret;
547}
548
549int32_t audio_extn_ffv_stream_deinit()
550{
551 ALOGV("%s: entry", __func__);
552
553#ifdef FFV_PCM_DUMP
554 if (ffvmod.fp_input)
555 fclose(ffvmod.fp_input);
556
557 if (ffvmod.fp_ecref)
558 fclose(ffvmod.fp_ecref);
559
560 if (ffvmod.fp_split_input)
561 fclose(ffvmod.fp_split_input);
562
563 if (ffvmod.fp_output)
564 fclose(ffvmod.fp_output);
565#endif
566
567 if (ffvmod.handle)
568 ffv_deinit_fn(ffvmod.handle);
569
570 if (ffvmod.buffers_allocated)
571 deallocate_buffers();
Surendar Karka59c51072017-12-13 11:25:57 +0530572#ifdef RUN_KEEP_ALIVE_IN_ARM_FFV
573 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
574#endif
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530575 ffvmod.handle = NULL;
Garmond Leunge2433c32017-09-28 21:51:22 -0700576 ffvmod.in = NULL;
577 ALOGV("%s: exit", __func__);
578 return 0;
579}
580
581snd_device_t audio_extn_ffv_get_capture_snd_device()
582{
583 if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_OCT) {
584 return SND_DEVICE_IN_HANDSET_8MIC;
585 } else if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_HEX) {
586 return SND_DEVICE_IN_HANDSET_6MIC;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530587 } else if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_QUAD) {
588 return SND_DEVICE_IN_HANDSET_QMIC;
Garmond Leunge2433c32017-09-28 21:51:22 -0700589 } else {
590 ALOGE("%s: Invalid channels configured for capture", __func__);
591 return SND_DEVICE_NONE;
592 }
593}
594
595int audio_extn_ffv_init_ec_ref_loopback(struct audio_device *adev,
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530596 snd_device_t snd_device __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700597{
598 struct audio_usecase *uc_info_tx = NULL;
599 snd_device_t in_snd_device;
600 char *params_buffer_ptr = NULL;
601 int param_id = FFV_RESET_AEC_PARAM;
602 int param_size = 0;
603 FfvStatusType status_type;
604 int ret = 0;
605
606 ALOGV("%s: entry", __func__);
607 /* notify library to reset AEC during each start */
608 status_type = ffv_set_param_fn(ffvmod.handle, params_buffer_ptr,
609 param_id, param_size);
610 if (status_type) {
611 ALOGE("%s: ERROR. ffv_set_param_fn ret %d", __func__, status_type);
612 return -EINVAL;
613 }
614
615 if (ffvmod.split_ec_ref_data) {
616 ALOGV("%s: Ignore ec ref loopback init", __func__);
617 return 0;
618 }
619
620 in_snd_device = platform_get_ec_ref_loopback_snd_device(ffvmod.ec_ref_ch_cnt);
621 uc_info_tx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
622 if (!uc_info_tx) {
623 return -ENOMEM;
624 }
625
626 pthread_mutex_lock(&ffvmod.init_lock);
627 uc_info_tx->id = USECASE_AUDIO_EC_REF_LOOPBACK;
628 uc_info_tx->type = PCM_CAPTURE;
629 uc_info_tx->in_snd_device = in_snd_device;
630 uc_info_tx->out_snd_device = SND_DEVICE_NONE;
631 ffvmod.ec_ref_pcm = NULL;
632 list_add_tail(&adev->usecase_list, &uc_info_tx->list);
633 enable_snd_device(adev, in_snd_device);
634 enable_audio_route(adev, uc_info_tx);
635
636 ffvmod.ec_ref_pcm_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
637 if (ffvmod.ec_ref_pcm_id < 0) {
638 ALOGE("%s: Invalid pcm device for usecase (%d)",
639 __func__, uc_info_tx->id);
640 ret = -ENODEV;
641 goto exit;
642 }
643
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530644 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d format %d",
645 __func__, adev->snd_card, ffvmod.ec_ref_pcm_id, ffvmod.ec_ref_config.channels,
646 ffvmod.ec_ref_config.format);
Garmond Leunge2433c32017-09-28 21:51:22 -0700647 ffvmod.ec_ref_pcm = pcm_open(adev->snd_card,
648 ffvmod.ec_ref_pcm_id,
649 PCM_IN, &ffvmod.ec_ref_config);
650 if (ffvmod.ec_ref_pcm && !pcm_is_ready(ffvmod.ec_ref_pcm)) {
651 ALOGE("%s: %s", __func__, pcm_get_error(ffvmod.ec_ref_pcm));
652 ret = -EIO;
653 goto exit;
654 }
655
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530656 ALOGV("%s: pcm_prepare", __func__);
Garmond Leunge2433c32017-09-28 21:51:22 -0700657 if (pcm_prepare(ffvmod.ec_ref_pcm) < 0) {
658 ALOGE("%s: pcm prepare for ec ref loopback failed", __func__);
659 ret = -EINVAL;
660 }
661
662 ffvmod.capture_started = false;
663 pthread_mutex_unlock(&ffvmod.init_lock);
664 ALOGV("%s: exit", __func__);
665 return 0;
666
667exit:
668 if (ffvmod.ec_ref_pcm) {
669 pcm_close(ffvmod.ec_ref_pcm);
670 ffvmod.ec_ref_pcm = NULL;
671 }
672 list_remove(&uc_info_tx->list);
673 disable_snd_device(adev, in_snd_device);
674 disable_audio_route(adev, uc_info_tx);
675 free(uc_info_tx);
676 pthread_mutex_unlock(&ffvmod.init_lock);
677 return ret;
678}
679
680void audio_extn_ffv_append_ec_ref_dev_name(char *device_name)
681{
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530682 if (ffvmod.ec_ref_dev == AUDIO_DEVICE_OUT_LINE)
Garmond Leunge2433c32017-09-28 21:51:22 -0700683 strlcat(device_name, " lineout", DEVICE_NAME_MAX_SIZE);
684 ALOGD("%s: ec ref dev name %s", __func__, device_name);
685}
686
687int audio_extn_ffv_deinit_ec_ref_loopback(struct audio_device *adev,
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530688 snd_device_t snd_device __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700689{
690 struct audio_usecase *uc_info_tx = NULL;
691 snd_device_t in_snd_device;
692 int ret = 0;
693
694 ALOGV("%s: entry", __func__);
695 if (ffvmod.split_ec_ref_data) {
696 ALOGV("%s: Ignore ec ref loopback init", __func__);
697 return 0;
698 }
699
700 in_snd_device = platform_get_ec_ref_loopback_snd_device(ffvmod.ec_ref_ch_cnt);
701 uc_info_tx = get_usecase_from_list(adev, USECASE_AUDIO_EC_REF_LOOPBACK);
702 pthread_mutex_lock(&ffvmod.init_lock);
703 if (ffvmod.ec_ref_pcm) {
704 pcm_close(ffvmod.ec_ref_pcm);
705 ffvmod.ec_ref_pcm = NULL;
706 }
707 disable_snd_device(adev, in_snd_device);
708 if (uc_info_tx) {
709 list_remove(&uc_info_tx->list);
710 disable_audio_route(adev, uc_info_tx);
711 free(uc_info_tx);
712 }
713 pthread_mutex_unlock(&ffvmod.init_lock);
714 ALOGV("%s: exit", __func__);
715 return ret;
716}
717
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530718int32_t audio_extn_ffv_read(struct audio_stream_in *stream __unused,
Garmond Leunge2433c32017-09-28 21:51:22 -0700719 void *buffer, size_t bytes)
720{
721 int status = 0;
722 int16_t *in_ptr = NULL, *process_in_ptr = NULL, *process_out_ptr = NULL;
723 int16_t *process_ec_ref_ptr = NULL;
724 size_t in_buf_size, out_buf_size, bytes_to_copy;
725 int retry_num = 0;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530726 int i, ch;
Garmond Leunge2433c32017-09-28 21:51:22 -0700727 int total_in_ch, in_ch, ec_ref_ch;
728
729 if (!ffvmod.ffv_lib_handle) {
730 ALOGE("%s: ffv_lib_handle not initialized", __func__);
731 return -EINVAL;
732 }
733
734 if (!ffvmod.handle) {
735 ALOGE("%s: ffv module handle not initialized", __func__);
736 return -EINVAL;
737 }
738
739 if (!ffvmod.in || !ffvmod.in->pcm) {
740 ALOGE("%s: capture session not initiliazed", __func__);
741 return -EINVAL;
742 }
743
744 if (!ffvmod.split_ec_ref_data && !ffvmod.ec_ref_pcm) {
745 ALOGE("%s: ec ref session not initiliazed", __func__);
746 return -EINVAL;
747 }
748
749 if (!ffvmod.capture_started) {
750 /* pcm_start of capture and ec ref session before read to reduce drift */
751 pcm_start(ffvmod.in->pcm);
752 while (status && (retry_num < FFV_PCM_MAX_RETRY)) {
753 usleep(FFV_PCM_SLEEP_WAIT);
754 retry_num++;
755 ALOGI("%s: pcm_start retrying..status %d errno %d, retry cnt %d",
756 __func__, status, errno, retry_num);
757 status = pcm_start(ffvmod.in->pcm);
758 }
759 if (status) {
760 ALOGE("%s: ERROR. pcm_start failed, returned status %d - %s",
761 __func__, status, pcm_get_error(ffvmod.in->pcm));
762 return status;
763 }
764 retry_num = 0;
765
766 if (!ffvmod.split_ec_ref_data) {
767 pcm_start(ffvmod.ec_ref_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.ec_ref_pcm);
774 }
775 if (status) {
776 ALOGE("%s: ERROR. pcm_start failed, returned status %d - %s",
777 __func__, status, pcm_get_error(ffvmod.ec_ref_pcm));
778 return status;
779 }
780 }
781 ffvmod.capture_started = true;
782 }
783
784 ALOGVV("%s: pcm_read reading bytes=%d", __func__, ffvmod.in_buf_size);
785 status = pcm_read(ffvmod.in->pcm, ffvmod.in_buf, ffvmod.in_buf_size);
786 if (status) {
787 ALOGE("%s: pcm read failed status %d - %s", __func__, status,
788 pcm_get_error(ffvmod.in->pcm));
789 goto exit;
790 }
791 ALOGVV("%s: pcm_read done", __func__);
792
793 if (!ffvmod.split_ec_ref_data) {
794 /* read EC ref data */
795 ALOGVV("%s: ec ref pcm_read reading bytes=%d", __func__, ffvmod.ec_ref_buf_size);
796 status = pcm_read(ffvmod.ec_ref_pcm, ffvmod.ec_ref_buf, ffvmod.ec_ref_buf_size);
797 if (status) {
798 ALOGE("%s: ec ref pcm read failed status %d - %s", __func__, status,
799 pcm_get_error(ffvmod.ec_ref_pcm));
800 goto exit;
801 }
802 ALOGVV("%s: ec ref pcm_read done", __func__);
803 process_in_ptr = (int16_t *)ffvmod.in_buf;
804 process_ec_ref_ptr = (int16_t *)ffvmod.ec_ref_buf;
805 in_buf_size = ffvmod.in_buf_size;
806 } else {
807 /* split input buffer into actual input channels and EC ref channels */
808 in_ptr = (int16_t *)ffvmod.in_buf;
809 process_in_ptr = (int16_t *)ffvmod.split_in_buf;
810 process_ec_ref_ptr = (int16_t *)ffvmod.ec_ref_buf;
811 total_in_ch = ffvmod.capture_config.channels;
812 ec_ref_ch = ffvmod.ec_ref_config.channels;
813 in_ch = total_in_ch - ec_ref_ch;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530814 for (i = 0; i < (int)ffvmod.capture_config.period_size; i++) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700815 for (ch = 0; ch < in_ch; ch++) {
816 process_in_ptr[i*in_ch+ch] =
817 in_ptr[i*total_in_ch+ch];
818 }
819 for (ch = 0; ch < ec_ref_ch; ch++) {
820 process_ec_ref_ptr[i*ec_ref_ch+ch] =
821 in_ptr[i*total_in_ch+in_ch+ch];
822 }
823 }
824 in_buf_size = ffvmod.split_in_buf_size;
825 }
826 process_out_ptr = (int16_t *)ffvmod.out_buf;
827
828 ffv_process_fn(ffvmod.handle, process_in_ptr,
829 process_out_ptr, process_ec_ref_ptr);
830 out_buf_size = ffvmod.out_buf_size;
831 bytes_to_copy = (bytes <= out_buf_size) ? bytes : out_buf_size;
832 memcpy(buffer, process_out_ptr, bytes_to_copy);
833 if (bytes_to_copy != out_buf_size)
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530834 ALOGD("%s: out buffer data dropped, copied %zu bytes",
Garmond Leunge2433c32017-09-28 21:51:22 -0700835 __func__, bytes_to_copy);
836
837#ifdef FFV_PCM_DUMP
838 if (ffvmod.fp_input)
839 fwrite(ffvmod.in_buf, 1, ffvmod.in_buf_size, ffvmod.fp_input);
840 if (ffvmod.fp_ecref)
841 fwrite(ffvmod.ec_ref_buf, 1, ffvmod.ec_ref_buf_size, ffvmod.fp_ecref);
842 if (ffvmod.fp_split_input)
843 fwrite(ffvmod.split_in_buf, 1, ffvmod.split_in_buf_size, ffvmod.fp_split_input);
844 if (ffvmod.fp_output)
845 fwrite(process_out_ptr, 1, bytes_to_copy, ffvmod.fp_output);
846#endif
847
848exit:
849 return status;
850}
851
852void audio_extn_ffv_set_parameters(struct audio_device *adev __unused,
853 struct str_parms *parms)
854{
Garmond Leunge2433c32017-09-28 21:51:22 -0700855 int val;
856 int ret = 0;
857 char value[128];
858
859 /* FFV params are required to be set before start of recording */
860 if (!ffvmod.handle) {
861 ret = str_parms_get_str(parms, AUDIO_PARAMETER_FFV_MODE_ON, value,
862 sizeof(value));
863 if (ret >= 0) {
864 str_parms_del(parms, AUDIO_PARAMETER_FFV_MODE_ON);
865 if (strcmp(value, "true") == 0) {
866 ALOGD("%s: Setting FFV mode to true", __func__);
867 ffvmod.is_ffvmode_on = true;
868 } else {
869 ALOGD("%s: Resetting FFV mode to false", __func__);
870 ffvmod.is_ffvmode_on = false;
871 }
872 }
873
874 ret = str_parms_get_str(parms, AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA, value,
875 sizeof(value));
876 if (ret >= 0) {
877 str_parms_del(parms, AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA);
878 if (strcmp(value, "true") == 0) {
879 ALOGD("%s: ec ref is packed with mic captured data", __func__);
880 ffvmod.split_ec_ref_data = true;
881 } else {
882 ALOGD("%s: ec ref is captured separately", __func__);
883 ffvmod.split_ec_ref_data = false;
884 }
885 }
886 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT, &val);
887 if (ret >= 0) {
888 str_parms_del(parms, AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT);
889 if (val == 1) {
890 ALOGD("%s: mono ec ref", __func__);
891 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_MONO;
892 } else if (val == 2) {
893 ALOGD("%s: stereo ec ref", __func__);
894 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_STEREO;
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530895 } else if (val == 4) {
896 ALOGD("%s: quad ec ref", __func__);
897 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_QUAD;
Garmond Leunge2433c32017-09-28 21:51:22 -0700898 } else {
899 ALOGE("%s: Invalid ec ref", __func__);
900 }
901 }
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530902 ret = -1;
903 if (str_parms_get_int(parms, AUDIO_PARAMETER_FFV_EC_REF_DEVICE, &val) >= 0) {
904 ret = 1;
Garmond Leunge2433c32017-09-28 21:51:22 -0700905 str_parms_del(parms, AUDIO_PARAMETER_FFV_EC_REF_DEVICE);
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530906 } else if (str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CONNECT, &val) >= 0) {
907 ret = 1;
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530908 }
909 if (ret == 1) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700910 if (val & AUDIO_DEVICE_OUT_SPEAKER) {
911 ALOGD("%s: capture ec ref from speaker", __func__);
912 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530913 } else if (val & AUDIO_DEVICE_OUT_LINE) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700914 ALOGD("%s: capture ec ref from line out", __func__);
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530915 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_LINE;
Garmond Leunge2433c32017-09-28 21:51:22 -0700916 } else {
917 ALOGE("%s: Invalid ec ref out device", __func__);
918 }
919 }
920
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530921 ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
922 if (ret >= 0) {
Dhanalakshmi Siddani0f1dfd52019-01-09 12:38:13 +0530923 if (val & AUDIO_DEVICE_OUT_LINE) {
924 ALOGD("%s: capture ec ref from speaker", __func__);
925 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER;
926 }
927 }
928
Garmond Leunge2433c32017-09-28 21:51:22 -0700929 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_CHANNEL_INDEX, &val);
930 if (ret >= 0) {
931 str_parms_del(parms, AUDIO_PARAMETER_FFV_CHANNEL_INDEX);
932 ALOGD("%s: set target chan index %d", __func__, val);
933 ffvmod.target_ch_idx = val;
934 }
Dhanalakshmi Siddania63a0652019-01-26 01:04:26 +0530935
936 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_CHANNEL_COUNT, &val);
937 if (ret >= 0) {
938 str_parms_del(parms, AUDIO_PARAMETER_FFV_CHANNEL_COUNT);
939 ALOGD("%s: set ffv channel count %d", __func__, val);
940 ffvmod.ch_count = val;
941 }
Garmond Leunge2433c32017-09-28 21:51:22 -0700942 }
943}