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