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