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