blob: 4f51cb1b55cf0749d1b0df012f2e2a299ece41be [file] [log] [blame]
Garmond Leunge2433c32017-09-28 21:51:22 -07001/*
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002 * Copyright (c) 2017-2020, 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>
Weiyin Jiang2995f662019-04-17 14:25:12 +080042#include <cutils/str_parms.h>
Garmond Leunge2433c32017-09-28 21:51:22 -070043#include <stdlib.h>
44#include <dlfcn.h>
Weiyin Jiang2995f662019-04-17 14:25:12 +080045#include <log/log.h>
Garmond Leunge2433c32017-09-28 21:51:22 -070046#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
Saurav Kumardba3caf2020-05-29 20:53:55 +053064
65#define FFV_CONFIG_FILE_NAME "BF_1out.cfg"
66#define FFV_LIB_NAME "libffv.so"
Dhanalakshmi Siddani30e06a22018-03-27 23:11:34 +053067
Garmond Leunge2433c32017-09-28 21:51:22 -070068#define FFV_SAMPLING_RATE_16000 16000
69#define FFV_EC_REF_LOOPBACK_DEVICE_MONO "ec-ref-loopback-mono"
70#define FFV_EC_REF_LOOPBACK_DEVICE_STEREO "ec-ref-loopback-stereo"
71
72#define FFV_CHANNEL_MODE_MONO 1
73#define FFV_CHANNEL_MODE_STEREO 2
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +053074#define FFV_CHANNEL_MODE_QUAD 6
Garmond Leunge2433c32017-09-28 21:51:22 -070075#define FFV_CHANNEL_MODE_HEX 6
76#define FFV_CHANNEL_MODE_OCT 8
77
78#define FFV_PCM_BUFFER_DURATION_MS 160
79#define FFV_PCM_PERIOD_COUNT (8)
80#define FFV_PCM_PERIOD_SIZE \
81 ((((FFV_SAMPLING_RATE_16000 * FFV_PCM_BUFFER_DURATION_MS) \
82 /(FFV_PCM_PERIOD_COUNT * 1000)) + 0x1f) & ~0x1f)
83
84#define ALIGN(number, align) \
85 ((number + align - 1) & ~(align - 1))
86#define CALCULATE_PERIOD_SIZE(duration_ms, sample_rate, period_cnt, align) \
87 (ALIGN(((sample_rate * duration_ms) /(period_cnt * 1000)), align))
88
89#define FFV_PCM_MAX_RETRY 10
90#define FFV_PCM_SLEEP_WAIT 1000
91
92#define DLSYM(handle, name, err) \
93do {\
94 const char* error; \
95 *(void**)&name##_fn = dlsym(handle, #name);\
96 if ((error = dlerror())) {\
97 ALOGE("%s: dlsym failed for %s error %s", __func__, #name, error);\
98 err = -ENODEV;\
99 }\
100} while(0)\
101
102/* uncomment to collect pcm dumps */
103//#define FFV_PCM_DUMP
104
105static FfvStatusType (*ffv_init_fn)(void** handle, int num_tx_in_ch,
106 int num_out_ch, int num_ec_ref_ch, int frame_len, int sample_rate,
107 const char *config_file_name, char *svaModelBuffer,
Surendar karka30569792018-05-08 12:02:21 +0530108 uint32_t svaModelSize, int* totMemSize,
109 int product_id, const char* prduct_license);
Garmond Leunge2433c32017-09-28 21:51:22 -0700110static void (*ffv_deinit_fn)(void* handle);
111static void (*ffv_process_fn)(void *handle, const int16_t *in_pcm,
112 int16_t *out_pcm, const int16_t *ec_ref_pcm);
113static int (*ffv_read_fn)(void* handle, int16_t *buf_pcm,
114 int max_buf_len);
115static FfvStatusType (*ffv_get_param_fn)(void *handle, char *params_buffer_ptr,
116 int param_id, int buffer_size, int *param_size_ptr);
117static FfvStatusType (*ffv_set_param_fn)(void *handle, char *params_buffer_ptr,
118 int param_id, int param_size);
119static FfvStatusType (*ffv_register_event_callback_fn)(void *handle,
120 ffv_event_callback_fn_t *fun_ptr);
121
122struct ffvmodule {
123 void *ffv_lib_handle;
124 unsigned char *in_buf;
125 unsigned int in_buf_size;
126 unsigned char *ec_ref_buf;
127 unsigned int ec_ref_buf_size;
128 unsigned char *split_in_buf;
129 unsigned int split_in_buf_size;
130 unsigned char *out_buf;
131 unsigned int out_buf_size;
132
133 struct pcm_config capture_config;
134 struct pcm_config out_config;
135 struct pcm_config ec_ref_config;
136
137 int ec_ref_pcm_id;
138 struct pcm *ec_ref_pcm;
139 int ec_ref_ch_cnt;
140 audio_devices_t ec_ref_dev;
141 bool split_ec_ref_data;
142
143 bool is_ffv_enabled;
144 bool buffers_allocated;
145 struct stream_in *in;
146 bool is_ffvmode_on;
147 void *handle;
148 pthread_mutex_t init_lock;
149 bool capture_started;
150 int target_ch_idx;
151
152#ifdef FFV_PCM_DUMP
153 FILE *fp_input;
154 FILE *fp_ecref;
155 FILE *fp_split_input;
156 FILE *fp_output;
157#endif
158};
159
160static struct ffvmodule ffvmod = {
161 .ffv_lib_handle = NULL,
162 .in_buf = NULL,
163 .in_buf_size = 0,
164 .ec_ref_buf = NULL,
165 .ec_ref_buf_size = 0,
166 .split_in_buf = NULL,
167 .split_in_buf_size = 0,
168 .out_buf = NULL,
169 .out_buf_size = 0,
170
171 .ec_ref_pcm = NULL,
172 .ec_ref_ch_cnt = 1,
173 .ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER,
174 .is_ffv_enabled = false,
175 .buffers_allocated = false,
176 .in = NULL,
177 .is_ffvmode_on = false,
178 .handle = NULL,
179 .capture_started = false,
180 .target_ch_idx = -1,
181};
182
183static struct pcm_config ffv_pcm_config = {
184 .channels = FFV_CHANNEL_MODE_MONO,
185 .rate = FFV_SAMPLING_RATE_16000,
186 .period_size = FFV_PCM_PERIOD_SIZE,
187 .period_count = FFV_PCM_PERIOD_COUNT,
188 .format = PCM_FORMAT_S16_LE,
189};
190
Saurav Kumardba3caf2020-05-29 20:53:55 +0530191void audio_get_lib_path(char* lib_path, int path_size)
192{
193#ifdef LINUX_ENABLED
194#ifdef __LP64__
195 /* libs are stored in /usr/lib64 */
196 snprintf(lib_path, path_size, "%s", "/usr/lib64");
197#else
198 /* libs are stored in /usr/lib */
199 snprintf(lib_path, path_size, "%s", "/usr/lib");
200#endif
201#else
202#ifdef __LP64__
203 /* libs are stored in /vendor/lib64 */
204 snprintf(lib_path, path_size, "%s", "/vendor/lib64");
205#else
206 /* libs are stored in /vendor/lib */
207 snprintf(lib_path, path_size, "%s", "/vendor/lib");
208#endif
209#endif
210}
211
Garmond Leunge2433c32017-09-28 21:51:22 -0700212static int32_t ffv_init_lib()
213{
214 int status = 0;
Saurav Kumardba3caf2020-05-29 20:53:55 +0530215 char lib_path[VENDOR_CONFIG_PATH_MAX_LENGTH];
216 char lib_file[VENDOR_CONFIG_FILE_MAX_LENGTH];
Garmond Leunge2433c32017-09-28 21:51:22 -0700217
Saurav Kumardba3caf2020-05-29 20:53:55 +0530218 /* Get path for lib in vendor */
219 audio_get_lib_path(lib_path, sizeof(lib_path));
220
221 /* Get path for ffv_lib_file */
222 snprintf(lib_file, sizeof(lib_file), "%s/%s", lib_path, FFV_LIB_NAME);
Garmond Leunge2433c32017-09-28 21:51:22 -0700223 if (ffvmod.ffv_lib_handle) {
224 ALOGE("%s: FFV library is already initialized", __func__);
225 return 0;
226 }
227
Saurav Kumardba3caf2020-05-29 20:53:55 +0530228 ffvmod.ffv_lib_handle = dlopen(lib_file, RTLD_NOW);
Garmond Leunge2433c32017-09-28 21:51:22 -0700229 if (!ffvmod.ffv_lib_handle) {
Saurav Kumardba3caf2020-05-29 20:53:55 +0530230 ALOGE("%s: Unable to open %s, error %s", __func__, lib_file,
Garmond Leunge2433c32017-09-28 21:51:22 -0700231 dlerror());
232 status = -ENOENT;
233 goto exit;
234 }
235
236 dlerror(); /* clear errors */
237 DLSYM(ffvmod.ffv_lib_handle, ffv_init, status);
238 if (status)
239 goto exit;
240 DLSYM(ffvmod.ffv_lib_handle, ffv_deinit, status);
241 if (status)
242 goto exit;
243 DLSYM(ffvmod.ffv_lib_handle, ffv_process, status);
244 if (status)
245 goto exit;
246 DLSYM(ffvmod.ffv_lib_handle, ffv_read, status);
247 if (status)
248 goto exit;
249 DLSYM(ffvmod.ffv_lib_handle, ffv_get_param, status);
250 if (status)
251 goto exit;
252 DLSYM(ffvmod.ffv_lib_handle, ffv_set_param, status);
253 if (status)
254 goto exit;
255 DLSYM(ffvmod.ffv_lib_handle, ffv_register_event_callback, status);
256 if (status)
257 goto exit;
258
259 return status;
260
261exit:
262 if (ffvmod.ffv_lib_handle)
263 dlclose(ffvmod.ffv_lib_handle);
264 ffvmod.ffv_lib_handle = NULL;
265
266 return status;
267}
268
269static int deallocate_buffers()
270{
271 if (ffvmod.in_buf) {
272 free(ffvmod.in_buf);
273 ffvmod.in_buf = NULL;
274 }
275
276 if (ffvmod.split_in_buf) {
277 free(ffvmod.split_in_buf);
278 ffvmod.split_in_buf = NULL;
279 }
280
281 if (ffvmod.ec_ref_buf) {
282 free(ffvmod.ec_ref_buf);
283 ffvmod.ec_ref_buf = NULL;
284 }
285
286 if (ffvmod.out_buf) {
287 free(ffvmod.out_buf);
288 ffvmod.out_buf = NULL;
289 }
290
291 ffvmod.buffers_allocated = false;
292 return 0;
293}
294
295static int allocate_buffers()
296{
297 int status = 0;
298
299 /* in_buf - buffer read from capture session */
300 ffvmod.in_buf_size = ffvmod.capture_config.period_size * ffvmod.capture_config.channels *
301 (pcm_format_to_bits(ffvmod.capture_config.format) >> 3);
302 ffvmod.in_buf = (unsigned char *)calloc(1, ffvmod.in_buf_size);
303 if (!ffvmod.in_buf) {
304 ALOGE("%s: ERROR. Can not allocate in buffer size %d", __func__, ffvmod.in_buf_size);
305 status = -ENOMEM;
306 goto error_exit;
307 }
308 ALOGD("%s: Allocated in buffer size bytes =%d",
309 __func__, ffvmod.in_buf_size);
310
311 /* ec_buf - buffer read from ec ref capture session */
312 ffvmod.ec_ref_buf_size = ffvmod.ec_ref_config.period_size * ffvmod.ec_ref_config.channels *
313 (pcm_format_to_bits(ffvmod.ec_ref_config.format) >> 3);
314 ffvmod.ec_ref_buf = (unsigned char *)calloc(1, ffvmod.ec_ref_buf_size);
315 if (!ffvmod.ec_ref_buf) {
316 ALOGE("%s: ERROR. Can not allocate ec ref buffer size %d",
317 __func__, ffvmod.ec_ref_buf_size);
318 status = -ENOMEM;
319 goto error_exit;
320 }
321 ALOGD("%s: Allocated ec ref buffer size bytes =%d",
322 __func__, ffvmod.ec_ref_buf_size);
323
324 if (ffvmod.split_ec_ref_data) {
325 ffvmod.split_in_buf_size = ffvmod.in_buf_size - ffvmod.ec_ref_buf_size;
326 ffvmod.split_in_buf = (unsigned char *)calloc(1, ffvmod.split_in_buf_size);
327 if (!ffvmod.split_in_buf) {
328 ALOGE("%s: ERROR. Can not allocate split in buffer size %d",
329 __func__, ffvmod.split_in_buf_size);
330 status = -ENOMEM;
331 goto error_exit;
332 }
333 ALOGD("%s: Allocated split in buffer size bytes =%d",
334 __func__, ffvmod.split_in_buf_size);
335 }
336
337 /* out_buf - output buffer from FFV + SVA library */
338 ffvmod.out_buf_size = ffvmod.out_config.period_size * ffvmod.out_config.channels *
339 (pcm_format_to_bits(ffvmod.out_config.format) >> 3);
340 ffvmod.out_buf = (unsigned char *)calloc(1, ffvmod.out_buf_size);
341 if (!ffvmod.out_buf) {
342 ALOGE("%s: ERROR. Can not allocate out buffer size %d", __func__, ffvmod.out_buf_size);
343 status = -ENOMEM;
344 goto error_exit;
345 }
346 ALOGD("%s: Allocated out buffer size bytes =%d",
347 __func__, ffvmod.out_buf_size);
348
349 ffvmod.buffers_allocated = true;
350 return 0;
351
352error_exit:
353 deallocate_buffers();
354 return status;
355}
356
357void audio_extn_ffv_update_enabled()
358{
359 char ffv_enabled[PROPERTY_VALUE_MAX] = "false";
360
Chaithanya Krishna Bacharajuf5a1ce62018-02-02 11:34:11 +0530361 property_get("ro.vendor.audio.sdk.ffv", ffv_enabled, "0");
Garmond Leunge2433c32017-09-28 21:51:22 -0700362 if (!strncmp("true", ffv_enabled, 4)) {
363 ALOGD("%s: ffv is supported", __func__);
364 ffvmod.is_ffv_enabled = true;
365 } else {
366 ALOGD("%s: ffv is not supported", __func__);
367 ffvmod.is_ffv_enabled = false;
368 }
369}
370
371bool audio_extn_ffv_get_enabled()
372{
373 ALOGV("%s: is_ffv_enabled:%d is_ffvmode_on:%d ", __func__, ffvmod.is_ffv_enabled, ffvmod.is_ffvmode_on);
374
375 if(ffvmod.is_ffv_enabled && ffvmod.is_ffvmode_on)
376 return true;
377
378 return false;
379}
380
381bool audio_extn_ffv_check_usecase(struct stream_in *in) {
382 int ret = false;
383 int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
Garmond Leunge2433c32017-09-28 21:51:22 -0700384 audio_source_t source = in->source;
385
386 if ((audio_extn_ffv_get_enabled()) &&
387 (channel_count == 1) &&
388 (AUDIO_SOURCE_MIC == source) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800389 (is_single_device_type_equal(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
390 is_single_device_type_equal(&in->device_list, AUDIO_DEVICE_IN_BACK_MIC)) &&
Garmond Leunge2433c32017-09-28 21:51:22 -0700391 (in->format == AUDIO_FORMAT_PCM_16_BIT) &&
392 (in->sample_rate == FFV_SAMPLING_RATE_16000)) {
393 in->config.channels = channel_count;
394 in->config.period_count = FFV_PCM_PERIOD_COUNT;
395 in->config.period_size = FFV_PCM_PERIOD_SIZE;
396 ALOGD("%s: FFV enabled", __func__);
397 ret = true;
398 }
399 return ret;
400}
401
Surendar karka30569792018-05-08 12:02:21 +0530402int audio_extn_ffv_set_usecase(struct stream_in *in, int ffv_key, char* ffv_lic)
Garmond Leunge2433c32017-09-28 21:51:22 -0700403{
404 int ret = -EINVAL;
405
406 if (audio_extn_ffv_check_usecase(in)) {
Surendar karka30569792018-05-08 12:02:21 +0530407 if (!audio_extn_ffv_stream_init(in, ffv_key, ffv_lic)) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700408 ALOGD("%s: Created FFV session succesfully", __func__);
409 ret = 0;
410 } else {
411 ALOGE("%s: Unable to start FFV record session", __func__);
412 }
413 }
414 return ret;
415}
416
417struct stream_in *audio_extn_ffv_get_stream()
418{
419 return ffvmod.in;
420}
421
422void audio_extn_ffv_update_pcm_config(struct pcm_config *config)
423{
424 config->channels = ffvmod.capture_config.channels;
425 config->period_count = ffvmod.capture_config.period_count;
426 config->period_size = ffvmod.capture_config.period_size;
427}
428
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +0530429int32_t audio_extn_ffv_init(struct audio_device *adev __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700430{
431 int ret = 0;
432
433 ret = ffv_init_lib();
434 if (ret)
435 ALOGE("%s: ERROR. ffv_init_lib ret %d", __func__, ret);
436
437 pthread_mutex_init(&ffvmod.init_lock, NULL);
438 return ret;
439}
440
441int32_t audio_extn_ffv_deinit()
442{
443 pthread_mutex_destroy(&ffvmod.init_lock);
444 if (ffvmod.ffv_lib_handle) {
445 dlclose(ffvmod.ffv_lib_handle);
446 ffvmod.ffv_lib_handle = NULL;
447 }
448 return 0;
449}
450
Surendar karka30569792018-05-08 12:02:21 +0530451int32_t audio_extn_ffv_stream_init(struct stream_in *in, int key, char* lic)
Garmond Leunge2433c32017-09-28 21:51:22 -0700452{
453 uint32_t ret = -EINVAL;
454 int num_tx_in_ch, num_out_ch, num_ec_ref_ch;
455 int frame_len;
456 int sample_rate;
Saurav Kumardba3caf2020-05-29 20:53:55 +0530457 const char *config_file_path;
458 char vendor_config_path[VENDOR_CONFIG_PATH_MAX_LENGTH];
459 char platform_info_xml_path_file[VENDOR_CONFIG_FILE_MAX_LENGTH];
Garmond Leunge2433c32017-09-28 21:51:22 -0700460 int total_mem_size;
461 FfvStatusType status_type;
462 const char *sm_buffer = "DISABLE_KEYWORD_DETECTION";
463 ffv_target_channel_index_param_t ch_index_param;
464 char *params_buffer_ptr = NULL;
465 int param_size = 0;
466 int param_id;
467
Saurav Kumardba3caf2020-05-29 20:53:55 +0530468 audio_get_vendor_config_path(vendor_config_path, sizeof(vendor_config_path));
469 /* Get path for ffv_config_file_name in vendor */
470 snprintf(platform_info_xml_path_file, sizeof(platform_info_xml_path_file),
471 "%s/%s", vendor_config_path, FFV_CONFIG_FILE_NAME);
472 config_file_path = platform_info_xml_path_file;
Garmond Leunge2433c32017-09-28 21:51:22 -0700473 if (!audio_extn_ffv_get_enabled()) {
474 ALOGE("Rejecting FFV -- init is called without enabling FFV");
475 goto fail;
476 }
477
478 if (ffvmod.handle != NULL) {
479 ALOGV("%s: reinitializing ffv library", __func__);
480 audio_extn_ffv_stream_deinit();
481 }
482
483 ffvmod.capture_config = ffv_pcm_config;
484 ffvmod.ec_ref_config = ffv_pcm_config;
485 ffvmod.out_config = ffv_pcm_config;
486 /* configure capture session with 6/8 channels */
487 ffvmod.capture_config.channels = ffvmod.split_ec_ref_data ?
488 FFV_CHANNEL_MODE_OCT : FFV_CHANNEL_MODE_HEX;
489 ffvmod.capture_config.period_size =
490 CALCULATE_PERIOD_SIZE(FFV_PCM_BUFFER_DURATION_MS,
491 ffvmod.capture_config.rate,
492 FFV_PCM_PERIOD_COUNT, 32);
493
494 /* Update channels with ec ref channel count */
495 ffvmod.ec_ref_config.channels = ffvmod.ec_ref_ch_cnt;
496 ffvmod.ec_ref_config.period_size =
497 CALCULATE_PERIOD_SIZE(FFV_PCM_BUFFER_DURATION_MS,
498 ffvmod.ec_ref_config.rate,
499 FFV_PCM_PERIOD_COUNT, 32);
500 ret = allocate_buffers();
501 if (ret)
502 goto fail;
503
504 num_ec_ref_ch = ffvmod.ec_ref_config.channels;
505 num_tx_in_ch = ffvmod.split_ec_ref_data ?
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530506 (ffvmod.capture_config.channels - num_ec_ref_ch) :
507 ffvmod.capture_config.channels;
Garmond Leunge2433c32017-09-28 21:51:22 -0700508 num_out_ch = ffvmod.out_config.channels;
509 frame_len = ffvmod.capture_config.period_size;
510 sample_rate = ffvmod.capture_config.rate;
511
512 ALOGD("%s: ec_ref_ch %d, tx_in_ch %d, out_ch %d, frame_len %d, sample_rate %d",
513 __func__, num_ec_ref_ch, num_tx_in_ch, num_out_ch, frame_len, sample_rate);
514 ALOGD("%s: config file path %s", __func__, config_file_path);
515 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 +0530516 frame_len, sample_rate, config_file_path, (char *)sm_buffer, 0,
Surendar karka30569792018-05-08 12:02:21 +0530517 &total_mem_size, key, lic);
Garmond Leunge2433c32017-09-28 21:51:22 -0700518 if (status_type) {
519 ALOGE("%s: ERROR. ffv_init returned %d", __func__, status_type);
520 ret = -EINVAL;
521 goto fail;
522 }
523 ALOGD("%s: ffv_init success %p", __func__, ffvmod.handle);
524
525 /* set target channel index if received as part of setparams */
526 if (ffvmod.target_ch_idx != -1) {
527 ALOGD("%s: target channel index %d", __func__, ffvmod.target_ch_idx);
528 ch_index_param.target_chan_idx = ffvmod.target_ch_idx;
529 params_buffer_ptr = (char *)&ch_index_param;
530 param_size = sizeof(ch_index_param);
531 param_id = FFV_TARGET_CHANNEL_INDEX_PARAM;
532 status_type = ffv_set_param_fn(ffvmod.handle, params_buffer_ptr,
533 param_id, param_size);
534 if (status_type) {
535 ALOGE("%s: ERROR. ffv_set_param_fn ret %d", __func__, status_type);
536 ret = -EINVAL;
537 goto fail;
538 }
539 }
540
541 ffvmod.in = in;
Surendar Karka59c51072017-12-13 11:25:57 +0530542#ifdef RUN_KEEP_ALIVE_IN_ARM_FFV
543 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
544#endif
Garmond Leunge2433c32017-09-28 21:51:22 -0700545#ifdef FFV_PCM_DUMP
546 if (!ffvmod.fp_input) {
547 ALOGD("%s: Opening input dump file \n", __func__);
548 ffvmod.fp_input = fopen("/data/misc/audio/ffv_input.pcm", "wb");
549 }
550 if (!ffvmod.fp_ecref) {
551 ALOGD("%s: Opening ecref dump file \n", __func__);
552 ffvmod.fp_ecref = fopen("/data/misc/audio/ffv_ecref.pcm", "wb");
553 }
554 if (!ffvmod.fp_split_input && ffvmod.split_ec_ref_data) {
555 ALOGD("%s: Opening split input dump file \n", __func__);
556 ffvmod.fp_split_input = fopen("/data/misc/audio/ffv_split_input.pcm", "wb");
557 }
558 if (!ffvmod.fp_output) {
559 ALOGD("%s: Opening output dump file \n", __func__);
560 ffvmod.fp_output = fopen("/data/misc/audio/ffv_output.pcm", "wb");
561 }
562#endif
563 ALOGV("%s: exit", __func__);
564 return 0;
565
566fail:
567 audio_extn_ffv_stream_deinit();
568 return ret;
569}
570
571int32_t audio_extn_ffv_stream_deinit()
572{
573 ALOGV("%s: entry", __func__);
574
575#ifdef FFV_PCM_DUMP
576 if (ffvmod.fp_input)
577 fclose(ffvmod.fp_input);
578
579 if (ffvmod.fp_ecref)
580 fclose(ffvmod.fp_ecref);
581
582 if (ffvmod.fp_split_input)
583 fclose(ffvmod.fp_split_input);
584
585 if (ffvmod.fp_output)
586 fclose(ffvmod.fp_output);
587#endif
588
589 if (ffvmod.handle)
590 ffv_deinit_fn(ffvmod.handle);
591
592 if (ffvmod.buffers_allocated)
593 deallocate_buffers();
Surendar Karka59c51072017-12-13 11:25:57 +0530594#ifdef RUN_KEEP_ALIVE_IN_ARM_FFV
595 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
596#endif
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530597 ffvmod.handle = NULL;
Garmond Leunge2433c32017-09-28 21:51:22 -0700598 ffvmod.in = NULL;
599 ALOGV("%s: exit", __func__);
600 return 0;
601}
602
603snd_device_t audio_extn_ffv_get_capture_snd_device()
604{
605 if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_OCT) {
606 return SND_DEVICE_IN_HANDSET_8MIC;
607 } else if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_HEX) {
608 return SND_DEVICE_IN_HANDSET_6MIC;
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +0530609 } else if (ffvmod.capture_config.channels == FFV_CHANNEL_MODE_QUAD) {
610 return SND_DEVICE_IN_HANDSET_QMIC;
Garmond Leunge2433c32017-09-28 21:51:22 -0700611 } else {
612 ALOGE("%s: Invalid channels configured for capture", __func__);
613 return SND_DEVICE_NONE;
614 }
615}
616
617int audio_extn_ffv_init_ec_ref_loopback(struct audio_device *adev,
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +0530618 snd_device_t snd_device __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700619{
620 struct audio_usecase *uc_info_tx = NULL;
621 snd_device_t in_snd_device;
622 char *params_buffer_ptr = NULL;
623 int param_id = FFV_RESET_AEC_PARAM;
624 int param_size = 0;
625 FfvStatusType status_type;
626 int ret = 0;
Dhanalakshmi Siddani999d5642019-03-22 15:27:44 +0530627 ffv_quadrx_use_dwnmix_param_t quad_downmix;
Garmond Leunge2433c32017-09-28 21:51:22 -0700628
629 ALOGV("%s: entry", __func__);
630 /* notify library to reset AEC during each start */
631 status_type = ffv_set_param_fn(ffvmod.handle, params_buffer_ptr,
632 param_id, param_size);
633 if (status_type) {
634 ALOGE("%s: ERROR. ffv_set_param_fn ret %d", __func__, status_type);
635 return -EINVAL;
636 }
637
638 if (ffvmod.split_ec_ref_data) {
639 ALOGV("%s: Ignore ec ref loopback init", __func__);
640 return 0;
641 }
642
643 in_snd_device = platform_get_ec_ref_loopback_snd_device(ffvmod.ec_ref_ch_cnt);
644 uc_info_tx = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
645 if (!uc_info_tx) {
646 return -ENOMEM;
647 }
648
Dhanalakshmi Siddani999d5642019-03-22 15:27:44 +0530649 if (in_snd_device == SND_DEVICE_IN_EC_REF_LOOPBACK_QUAD) {
650 quad_downmix.quadrx_dwnmix_enable = true;
651 ALOGD("%s: set param for 4 ch ec, handle %p", __func__, ffvmod.handle);
652 status_type = ffv_set_param_fn(ffvmod.handle,
653 (char *)&quad_downmix,
654 FFV_QUADRX_USE_DWNMIX_PARAM,
655 sizeof(ffv_quadrx_use_dwnmix_param_t));
656 if (status_type) {
657 ALOGE("%s: ERROR. ffv_set_param_fn for quad channel ec ref %d",
658 __func__, status_type);
659 return -EINVAL;
660 }
661 }
662
Garmond Leunge2433c32017-09-28 21:51:22 -0700663 pthread_mutex_lock(&ffvmod.init_lock);
664 uc_info_tx->id = USECASE_AUDIO_EC_REF_LOOPBACK;
665 uc_info_tx->type = PCM_CAPTURE;
666 uc_info_tx->in_snd_device = in_snd_device;
667 uc_info_tx->out_snd_device = SND_DEVICE_NONE;
668 ffvmod.ec_ref_pcm = NULL;
669 list_add_tail(&adev->usecase_list, &uc_info_tx->list);
670 enable_snd_device(adev, in_snd_device);
671 enable_audio_route(adev, uc_info_tx);
672
673 ffvmod.ec_ref_pcm_id = platform_get_pcm_device_id(uc_info_tx->id, PCM_CAPTURE);
674 if (ffvmod.ec_ref_pcm_id < 0) {
675 ALOGE("%s: Invalid pcm device for usecase (%d)",
676 __func__, uc_info_tx->id);
677 ret = -ENODEV;
678 goto exit;
679 }
680
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530681 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d format %d",
682 __func__, adev->snd_card, ffvmod.ec_ref_pcm_id, ffvmod.ec_ref_config.channels,
683 ffvmod.ec_ref_config.format);
Garmond Leunge2433c32017-09-28 21:51:22 -0700684 ffvmod.ec_ref_pcm = pcm_open(adev->snd_card,
685 ffvmod.ec_ref_pcm_id,
686 PCM_IN, &ffvmod.ec_ref_config);
687 if (ffvmod.ec_ref_pcm && !pcm_is_ready(ffvmod.ec_ref_pcm)) {
688 ALOGE("%s: %s", __func__, pcm_get_error(ffvmod.ec_ref_pcm));
689 ret = -EIO;
690 goto exit;
691 }
692
Chaithanya Krishna Bacharaju4cdd5242017-09-18 14:00:17 +0530693 ALOGV("%s: pcm_prepare", __func__);
Garmond Leunge2433c32017-09-28 21:51:22 -0700694 if (pcm_prepare(ffvmod.ec_ref_pcm) < 0) {
695 ALOGE("%s: pcm prepare for ec ref loopback failed", __func__);
696 ret = -EINVAL;
697 }
698
699 ffvmod.capture_started = false;
700 pthread_mutex_unlock(&ffvmod.init_lock);
701 ALOGV("%s: exit", __func__);
702 return 0;
703
704exit:
705 if (ffvmod.ec_ref_pcm) {
706 pcm_close(ffvmod.ec_ref_pcm);
707 ffvmod.ec_ref_pcm = NULL;
708 }
709 list_remove(&uc_info_tx->list);
710 disable_snd_device(adev, in_snd_device);
711 disable_audio_route(adev, uc_info_tx);
712 free(uc_info_tx);
713 pthread_mutex_unlock(&ffvmod.init_lock);
714 return ret;
715}
716
717void audio_extn_ffv_append_ec_ref_dev_name(char *device_name)
718{
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530719 if (ffvmod.ec_ref_dev == AUDIO_DEVICE_OUT_LINE)
Garmond Leunge2433c32017-09-28 21:51:22 -0700720 strlcat(device_name, " lineout", DEVICE_NAME_MAX_SIZE);
721 ALOGD("%s: ec ref dev name %s", __func__, device_name);
722}
723
724int audio_extn_ffv_deinit_ec_ref_loopback(struct audio_device *adev,
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +0530725 snd_device_t snd_device __unused)
Garmond Leunge2433c32017-09-28 21:51:22 -0700726{
727 struct audio_usecase *uc_info_tx = NULL;
728 snd_device_t in_snd_device;
729 int ret = 0;
730
731 ALOGV("%s: entry", __func__);
732 if (ffvmod.split_ec_ref_data) {
733 ALOGV("%s: Ignore ec ref loopback init", __func__);
734 return 0;
735 }
736
737 in_snd_device = platform_get_ec_ref_loopback_snd_device(ffvmod.ec_ref_ch_cnt);
738 uc_info_tx = get_usecase_from_list(adev, USECASE_AUDIO_EC_REF_LOOPBACK);
739 pthread_mutex_lock(&ffvmod.init_lock);
740 if (ffvmod.ec_ref_pcm) {
741 pcm_close(ffvmod.ec_ref_pcm);
742 ffvmod.ec_ref_pcm = NULL;
743 }
744 disable_snd_device(adev, in_snd_device);
745 if (uc_info_tx) {
746 list_remove(&uc_info_tx->list);
747 disable_audio_route(adev, uc_info_tx);
748 free(uc_info_tx);
749 }
750 pthread_mutex_unlock(&ffvmod.init_lock);
751 ALOGV("%s: exit", __func__);
752 return ret;
753}
754
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +0530755int32_t audio_extn_ffv_read(struct audio_stream_in *stream __unused,
Garmond Leunge2433c32017-09-28 21:51:22 -0700756 void *buffer, size_t bytes)
757{
758 int status = 0;
759 int16_t *in_ptr = NULL, *process_in_ptr = NULL, *process_out_ptr = NULL;
760 int16_t *process_ec_ref_ptr = NULL;
761 size_t in_buf_size, out_buf_size, bytes_to_copy;
762 int retry_num = 0;
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +0530763 int i, ch;
Garmond Leunge2433c32017-09-28 21:51:22 -0700764 int total_in_ch, in_ch, ec_ref_ch;
765
766 if (!ffvmod.ffv_lib_handle) {
767 ALOGE("%s: ffv_lib_handle not initialized", __func__);
768 return -EINVAL;
769 }
770
771 if (!ffvmod.handle) {
772 ALOGE("%s: ffv module handle not initialized", __func__);
773 return -EINVAL;
774 }
775
776 if (!ffvmod.in || !ffvmod.in->pcm) {
777 ALOGE("%s: capture session not initiliazed", __func__);
778 return -EINVAL;
779 }
780
781 if (!ffvmod.split_ec_ref_data && !ffvmod.ec_ref_pcm) {
782 ALOGE("%s: ec ref session not initiliazed", __func__);
783 return -EINVAL;
784 }
785
786 if (!ffvmod.capture_started) {
787 /* pcm_start of capture and ec ref session before read to reduce drift */
788 pcm_start(ffvmod.in->pcm);
789 while (status && (retry_num < FFV_PCM_MAX_RETRY)) {
790 usleep(FFV_PCM_SLEEP_WAIT);
791 retry_num++;
792 ALOGI("%s: pcm_start retrying..status %d errno %d, retry cnt %d",
793 __func__, status, errno, retry_num);
794 status = pcm_start(ffvmod.in->pcm);
795 }
796 if (status) {
797 ALOGE("%s: ERROR. pcm_start failed, returned status %d - %s",
798 __func__, status, pcm_get_error(ffvmod.in->pcm));
799 return status;
800 }
801 retry_num = 0;
802
803 if (!ffvmod.split_ec_ref_data) {
804 pcm_start(ffvmod.ec_ref_pcm);
805 while (status && (retry_num < FFV_PCM_MAX_RETRY)) {
806 usleep(FFV_PCM_SLEEP_WAIT);
807 retry_num++;
808 ALOGI("%s: pcm_start retrying..status %d errno %d, retry cnt %d",
809 __func__, status, errno, retry_num);
810 status = pcm_start(ffvmod.ec_ref_pcm);
811 }
812 if (status) {
813 ALOGE("%s: ERROR. pcm_start failed, returned status %d - %s",
814 __func__, status, pcm_get_error(ffvmod.ec_ref_pcm));
815 return status;
816 }
817 }
Dhanalakshmi Siddani999d5642019-03-22 15:27:44 +0530818 audio_extn_set_cpu_affinity();
819 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Garmond Leunge2433c32017-09-28 21:51:22 -0700820 ffvmod.capture_started = true;
821 }
822
823 ALOGVV("%s: pcm_read reading bytes=%d", __func__, ffvmod.in_buf_size);
824 status = pcm_read(ffvmod.in->pcm, ffvmod.in_buf, ffvmod.in_buf_size);
825 if (status) {
826 ALOGE("%s: pcm read failed status %d - %s", __func__, status,
827 pcm_get_error(ffvmod.in->pcm));
828 goto exit;
829 }
830 ALOGVV("%s: pcm_read done", __func__);
831
832 if (!ffvmod.split_ec_ref_data) {
833 /* read EC ref data */
834 ALOGVV("%s: ec ref pcm_read reading bytes=%d", __func__, ffvmod.ec_ref_buf_size);
835 status = pcm_read(ffvmod.ec_ref_pcm, ffvmod.ec_ref_buf, ffvmod.ec_ref_buf_size);
836 if (status) {
837 ALOGE("%s: ec ref pcm read failed status %d - %s", __func__, status,
838 pcm_get_error(ffvmod.ec_ref_pcm));
839 goto exit;
840 }
841 ALOGVV("%s: ec ref pcm_read done", __func__);
842 process_in_ptr = (int16_t *)ffvmod.in_buf;
843 process_ec_ref_ptr = (int16_t *)ffvmod.ec_ref_buf;
844 in_buf_size = ffvmod.in_buf_size;
845 } else {
846 /* split input buffer into actual input channels and EC ref channels */
847 in_ptr = (int16_t *)ffvmod.in_buf;
848 process_in_ptr = (int16_t *)ffvmod.split_in_buf;
849 process_ec_ref_ptr = (int16_t *)ffvmod.ec_ref_buf;
850 total_in_ch = ffvmod.capture_config.channels;
851 ec_ref_ch = ffvmod.ec_ref_config.channels;
852 in_ch = total_in_ch - ec_ref_ch;
Dhanalakshmi Siddani57b014e2018-04-23 12:52:02 +0530853 for (i = 0; i < (int)ffvmod.capture_config.period_size; i++) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700854 for (ch = 0; ch < in_ch; ch++) {
855 process_in_ptr[i*in_ch+ch] =
856 in_ptr[i*total_in_ch+ch];
857 }
858 for (ch = 0; ch < ec_ref_ch; ch++) {
859 process_ec_ref_ptr[i*ec_ref_ch+ch] =
860 in_ptr[i*total_in_ch+in_ch+ch];
861 }
862 }
863 in_buf_size = ffvmod.split_in_buf_size;
864 }
865 process_out_ptr = (int16_t *)ffvmod.out_buf;
866
867 ffv_process_fn(ffvmod.handle, process_in_ptr,
868 process_out_ptr, process_ec_ref_ptr);
869 out_buf_size = ffvmod.out_buf_size;
870 bytes_to_copy = (bytes <= out_buf_size) ? bytes : out_buf_size;
871 memcpy(buffer, process_out_ptr, bytes_to_copy);
872 if (bytes_to_copy != out_buf_size)
Dhanalakshmi Siddani8d1b8c82018-06-13 15:41:29 +0530873 ALOGD("%s: out buffer data dropped, copied %zu bytes",
Garmond Leunge2433c32017-09-28 21:51:22 -0700874 __func__, bytes_to_copy);
875
876#ifdef FFV_PCM_DUMP
877 if (ffvmod.fp_input)
878 fwrite(ffvmod.in_buf, 1, ffvmod.in_buf_size, ffvmod.fp_input);
879 if (ffvmod.fp_ecref)
880 fwrite(ffvmod.ec_ref_buf, 1, ffvmod.ec_ref_buf_size, ffvmod.fp_ecref);
881 if (ffvmod.fp_split_input)
882 fwrite(ffvmod.split_in_buf, 1, ffvmod.split_in_buf_size, ffvmod.fp_split_input);
883 if (ffvmod.fp_output)
884 fwrite(process_out_ptr, 1, bytes_to_copy, ffvmod.fp_output);
885#endif
886
887exit:
888 return status;
889}
890
891void audio_extn_ffv_set_parameters(struct audio_device *adev __unused,
892 struct str_parms *parms)
893{
Garmond Leunge2433c32017-09-28 21:51:22 -0700894 int val;
895 int ret = 0;
896 char value[128];
897
898 /* FFV params are required to be set before start of recording */
899 if (!ffvmod.handle) {
900 ret = str_parms_get_str(parms, AUDIO_PARAMETER_FFV_MODE_ON, value,
901 sizeof(value));
902 if (ret >= 0) {
903 str_parms_del(parms, AUDIO_PARAMETER_FFV_MODE_ON);
904 if (strcmp(value, "true") == 0) {
905 ALOGD("%s: Setting FFV mode to true", __func__);
906 ffvmod.is_ffvmode_on = true;
907 } else {
908 ALOGD("%s: Resetting FFV mode to false", __func__);
909 ffvmod.is_ffvmode_on = false;
910 }
911 }
912
913 ret = str_parms_get_str(parms, AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA, value,
914 sizeof(value));
915 if (ret >= 0) {
916 str_parms_del(parms, AUDIO_PARAMETER_FFV_SPLIT_EC_REF_DATA);
917 if (strcmp(value, "true") == 0) {
918 ALOGD("%s: ec ref is packed with mic captured data", __func__);
919 ffvmod.split_ec_ref_data = true;
920 } else {
921 ALOGD("%s: ec ref is captured separately", __func__);
922 ffvmod.split_ec_ref_data = false;
923 }
924 }
925 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT, &val);
926 if (ret >= 0) {
927 str_parms_del(parms, AUDIO_PARAMETER_FFV_EC_REF_CHANNEL_COUNT);
928 if (val == 1) {
929 ALOGD("%s: mono ec ref", __func__);
930 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_MONO;
931 } else if (val == 2) {
932 ALOGD("%s: stereo ec ref", __func__);
933 ffvmod.ec_ref_ch_cnt = FFV_CHANNEL_MODE_STEREO;
934 } else {
935 ALOGE("%s: Invalid ec ref", __func__);
936 }
937 }
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +0530938 ret = -1;
939 if (str_parms_get_int(parms, AUDIO_PARAMETER_FFV_EC_REF_DEVICE, &val) >= 0) {
940 ret = 1;
Garmond Leunge2433c32017-09-28 21:51:22 -0700941 str_parms_del(parms, AUDIO_PARAMETER_FFV_EC_REF_DEVICE);
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +0530942 } else if (str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_CONNECT, &val) >= 0) {
943 ret = 1;
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +0530944 }
945 if (ret == 1) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700946 if (val & AUDIO_DEVICE_OUT_SPEAKER) {
947 ALOGD("%s: capture ec ref from speaker", __func__);
948 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530949 } else if (val & AUDIO_DEVICE_OUT_LINE) {
Garmond Leunge2433c32017-09-28 21:51:22 -0700950 ALOGD("%s: capture ec ref from line out", __func__);
Chaithanya Krishna Bacharaju95de8e22017-10-17 15:25:33 +0530951 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_LINE;
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +0530952 }
953 }
954
955 ret = str_parms_get_int(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, &val);
956 if (ret >= 0) {
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +0530957 if (val & AUDIO_DEVICE_OUT_LINE) {
958 ALOGD("%s: capture ec ref from speaker", __func__);
959 ffvmod.ec_ref_dev = AUDIO_DEVICE_OUT_SPEAKER;
Garmond Leunge2433c32017-09-28 21:51:22 -0700960 }
961 }
962
963 ret = str_parms_get_int(parms, AUDIO_PARAMETER_FFV_CHANNEL_INDEX, &val);
964 if (ret >= 0) {
965 str_parms_del(parms, AUDIO_PARAMETER_FFV_CHANNEL_INDEX);
966 ALOGD("%s: set target chan index %d", __func__, val);
967 ffvmod.target_ch_idx = val;
968 }
969 }
970}