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