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