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