blob: d83b508f96727d003bde4a911117e04aeb76dc16 [file] [log] [blame]
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07001/*
Arun Mirpurib1416682018-03-07 19:13:53 -08002 * Copyright (c) 2013-2018, The Linux Foundation. All rights reserved.
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07003 * Not a Contribution.
4 *
5 * Copyright (C) 2013 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20#define LOG_TAG "audio_hw_ssr"
21/*#define LOG_NDEBUG 0*/
22#define LOG_NDDEBUG 0
23
24#include <errno.h>
25#include <cutils/properties.h>
26#include <stdlib.h>
27#include <dlfcn.h>
28#include <cutils/str_parms.h>
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080029#include <log/log.h>
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070030#include <pthread.h>
31#include <cutils/sched_policy.h>
32#include <sys/resource.h>
33#include <system/thread_defs.h>
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070034
35#include "audio_hw.h"
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070036#include "audio_extn.h"
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070037#include "platform.h"
38#include "platform_api.h"
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070039#include "surround_rec_interface.h"
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070040
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053041#ifdef DYNAMIC_LOG_ENABLED
42#include <log_xml_parser.h>
43#define LOG_MASK HAL_MOD_FILE_SSR
44#include <log_utils.h>
45#endif
46
Mingming Yin49be8032013-12-19 12:51:25 -080047#define COEFF_ARRAY_SIZE 4
48#define FILT_SIZE ((512+1)* 6) /* # ((FFT bins)/2+1)*numOutputs */
Mingming Yin49be8032013-12-19 12:51:25 -080049#define SSR_CHANNEL_OUTPUT_NUM 6
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070050#define SSR_PERIOD_SIZE 240
51
52#define NUM_IN_BUFS 4
53#define NUM_OUT_BUFS 4
Naresh Tanniruc9093982015-10-16 18:05:29 +053054#define NUM_IN_CHANNELS 3
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070055
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070056#define LIB_SURROUND_3MIC_PROC "libsurround_3mic_proc.so"
57#define LIB_DRC "libdrc.so"
58
59#define AUDIO_PARAMETER_SSRMODE_ON "ssrOn"
60
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070061
Naresh Tanniruc9093982015-10-16 18:05:29 +053062typedef short Word16;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070063typedef const get_param_data_t* (*surround_rec_get_get_param_data_t)(void);
64typedef const set_param_data_t* (*surround_rec_get_set_param_data_t)(void);
65typedef int (*surround_rec_init_t)(void **, int, int, int, int, const char *);
66typedef void (*surround_rec_deinit_t)(void *);
67typedef void (*surround_rec_process_t)(void *, const int16_t *, int16_t *);
68
69typedef int (*drc_init_t)(void **, int, int, const char *);
70typedef void (*drc_deinit_t)(void *);
71typedef int (*drc_process_t)(void *, const int16_t *, int16_t *);
72
73struct pcm_buffer {
74 void *data;
75 int length;
76};
77
78struct pcm_buffer_queue {
79 struct pcm_buffer_queue *next;
80 struct pcm_buffer buffer;
81};
82
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070083struct ssr_module {
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070084 int ssr_3mic;
85 int num_out_chan;
Naresh Tanniruc9093982015-10-16 18:05:29 +053086 FILE *fp_input;
87 FILE *fp_output;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070088 void *surround_obj;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070089 Word16 *surround_raw_buffer;
90 int surround_raw_buffer_size;
91 bool is_ssr_enabled;
92 struct stream_in *in;
93 void *drc_obj;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070094
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070095
96 void *surround_rec_handle;
97 surround_rec_get_get_param_data_t surround_rec_get_get_param_data;
98 surround_rec_get_set_param_data_t surround_rec_get_set_param_data;
99 surround_rec_init_t surround_rec_init;
100 surround_rec_deinit_t surround_rec_deinit;
101 surround_rec_process_t surround_rec_process;
102
103 void *drc_handle;
104 drc_init_t drc_init;
105 drc_deinit_t drc_deinit;
106 drc_process_t drc_process;
107
108 pthread_t ssr_process_thread;
109 bool ssr_process_thread_started;
110 bool ssr_process_thread_stop;
111 struct pcm_buffer_queue in_buf_nodes[NUM_IN_BUFS];
112 struct pcm_buffer_queue out_buf_nodes[NUM_OUT_BUFS];
113 void *in_buf_data;
114 void *out_buf_data;
115 struct pcm_buffer_queue *out_buf_free;
116 struct pcm_buffer_queue *out_buf;
117 struct pcm_buffer_queue *in_buf_free;
118 struct pcm_buffer_queue *in_buf;
119 pthread_mutex_t ssr_process_lock;
120 pthread_cond_t cond_process;
121 pthread_cond_t cond_read;
122 bool is_ssr_mode_on;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700123};
124
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700125static struct ssr_module ssrmod = {
Naresh Tanniruc9093982015-10-16 18:05:29 +0530126 .fp_input = NULL,
127 .fp_output = NULL,
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700128 .surround_obj = NULL,
Mingming Yin49be8032013-12-19 12:51:25 -0800129 .surround_raw_buffer = NULL,
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700130 .surround_raw_buffer_size = 0,
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700131 .is_ssr_enabled = 0,
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700132 .in = NULL,
133 .drc_obj = NULL,
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700134
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700135 .surround_rec_handle = NULL,
136 .surround_rec_get_get_param_data = NULL,
137 .surround_rec_get_set_param_data = NULL,
138 .surround_rec_init = NULL,
139 .surround_rec_deinit = NULL,
140 .surround_rec_process = NULL,
141
142 .drc_handle = NULL,
143 .drc_init = NULL,
144 .drc_deinit = NULL,
145 .drc_process = NULL,
146
147 .ssr_process_thread_stop = 0,
148 .ssr_process_thread_started = 0,
149 .in_buf_data = NULL,
150 .out_buf_data = NULL,
151 .out_buf_free = NULL,
152 .out_buf = NULL,
153 .in_buf_free = NULL,
154 .in_buf = NULL,
155 .cond_process = PTHREAD_COND_INITIALIZER,
156 .cond_read = PTHREAD_COND_INITIALIZER,
157 .ssr_process_lock = PTHREAD_MUTEX_INITIALIZER,
158 .is_ssr_mode_on = false,
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700159};
160
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700161static void *ssr_process_thread(void *context);
162
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700163static int32_t drc_init_lib(int num_chan, int sample_rate __unused)
164{
165 int ret = 0;
166 const char *cfgFileName = "";
167
168 if (ssrmod.drc_obj) {
169 ALOGE("%s: DRC library is already initialized", __func__);
170 return 0;
171 }
172
173 ssrmod.drc_handle = dlopen(LIB_DRC, RTLD_NOW);
174 if (ssrmod.drc_handle == NULL) {
175 ALOGE("%s: DLOPEN failed for %s", __func__, LIB_DRC);
176 ret = -ENOSYS;
177 goto init_fail;
178 }
179
180 ALOGV("%s: DLOPEN successful for %s", __func__, LIB_DRC);
181 ssrmod.drc_init = (drc_init_t)
182 dlsym(ssrmod.drc_handle, "DRC_init");
183 ssrmod.drc_deinit = (drc_deinit_t)
184 dlsym(ssrmod.drc_handle, "DRC_deinit");
185 ssrmod.drc_process = (drc_process_t)
186 dlsym(ssrmod.drc_handle, "DRC_process");
187
188 if (!ssrmod.drc_init ||
189 !ssrmod.drc_deinit ||
190 !ssrmod.drc_process){
191 ALOGW("%s: Could not find one of the symbols from %s",
192 __func__, LIB_DRC);
193 ret = -ENOSYS;
194 goto init_fail;
195 }
196
197 /* TO DO: different config files for different sample rates */
198 if (num_chan == 6) {
Naresh Tanniru10758b62017-06-05 21:05:53 +0530199 cfgFileName = "/vendor/etc/drc/drc_cfg_5.1.txt";
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700200 } else if (num_chan == 2) {
Naresh Tanniru10758b62017-06-05 21:05:53 +0530201 cfgFileName = "/vendor/etc/drc/drc_cfg_AZ.txt";
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700202 }
203
204 ALOGV("%s: Calling drc_init: num ch: %d, period: %d, cfg file: %s", __func__, num_chan, SSR_PERIOD_SIZE, cfgFileName);
205 ret = ssrmod.drc_init(&ssrmod.drc_obj, num_chan, SSR_PERIOD_SIZE, cfgFileName);
206 if (ret) {
207 ALOGE("drc_init failed with ret:%d",ret);
208 ret = -EINVAL;
209 goto init_fail;
210 }
211
212 return 0;
213
214init_fail:
215 if (ssrmod.drc_obj) {
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700216 ssrmod.drc_obj = NULL;
217 }
218 if(ssrmod.drc_handle) {
219 dlclose(ssrmod.drc_handle);
220 ssrmod.drc_handle = NULL;
221 }
222 return ret;
223}
224
225static int32_t ssr_init_surround_sound_3mic_lib(unsigned long buffersize, int num_in_chan, int num_out_chan, int sample_rate)
226{
227 int ret = 0;
228 const char *cfgFileName = NULL;
229
230 if ( ssrmod.surround_obj ) {
231 ALOGE("%s: surround sound library is already initialized", __func__);
232 return 0;
233 }
234
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700235 ssrmod.surround_rec_handle = dlopen(LIB_SURROUND_3MIC_PROC, RTLD_NOW);
236 if (ssrmod.surround_rec_handle == NULL) {
237 ALOGE("%s: DLOPEN failed for %s", __func__, LIB_SURROUND_3MIC_PROC);
Naresh Tanniruc9093982015-10-16 18:05:29 +0530238 goto init_fail;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700239 } else {
240 ALOGV("%s: DLOPEN successful for %s", __func__, LIB_SURROUND_3MIC_PROC);
241 ssrmod.surround_rec_get_get_param_data = (surround_rec_get_get_param_data_t)
242 dlsym(ssrmod.surround_rec_handle, "surround_rec_get_get_param_data");
243
244 ssrmod.surround_rec_get_set_param_data = (surround_rec_get_set_param_data_t)
245 dlsym(ssrmod.surround_rec_handle, "surround_rec_get_set_param_data");
246 ssrmod.surround_rec_init = (surround_rec_init_t)
247 dlsym(ssrmod.surround_rec_handle, "surround_rec_init");
248 ssrmod.surround_rec_deinit = (surround_rec_deinit_t)
249 dlsym(ssrmod.surround_rec_handle, "surround_rec_deinit");
250 ssrmod.surround_rec_process = (surround_rec_process_t)
251 dlsym(ssrmod.surround_rec_handle, "surround_rec_process");
252
253 if (!ssrmod.surround_rec_get_get_param_data ||
254 !ssrmod.surround_rec_get_set_param_data ||
255 !ssrmod.surround_rec_init ||
256 !ssrmod.surround_rec_deinit ||
257 !ssrmod.surround_rec_process){
258 ALOGW("%s: Could not find the one of the symbols from %s",
259 __func__, LIB_SURROUND_3MIC_PROC);
260 ret = -ENOSYS;
261 goto init_fail;
262 }
263 }
264
Naresh Tanniruc9093982015-10-16 18:05:29 +0530265 /* Allocate memory for input buffer */
266 ssrmod.surround_raw_buffer = (Word16 *) calloc(buffersize,
267 sizeof(Word16));
268 if (!ssrmod.surround_raw_buffer) {
269 ALOGE("%s: Memory allocation failure. Not able to allocate "
270 "memory for surroundInputBuffer", __func__);
271 ret = -ENOMEM;
272 goto init_fail;
273 }
274
275 ssrmod.surround_raw_buffer_size = buffersize;
276
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700277 ssrmod.num_out_chan = num_out_chan;
278
279 if (num_out_chan == 6) {
Naresh Tanniru10758b62017-06-05 21:05:53 +0530280 cfgFileName = "/vendor/etc/surround_sound_3mic/surround_sound_rec_5.1.cfg";
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700281 } else if (num_out_chan == 2) {
Naresh Tanniru10758b62017-06-05 21:05:53 +0530282 cfgFileName = "/vendor/etc/surround_sound_3mic/surround_sound_rec_AZ.cfg";
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700283 } else {
284 ALOGE("%s: No cfg file for num_out_chan: %d", __func__, num_out_chan);
285 }
286
287 ALOGV("%s: Calling surround_rec_init: in ch: %d, out ch: %d, period: %d, sample rate: %d, cfg file: %s",
288 __func__, num_in_chan, num_out_chan, SSR_PERIOD_SIZE, sample_rate, cfgFileName);
289 ret = ssrmod.surround_rec_init(&ssrmod.surround_obj,
290 num_in_chan, num_out_chan, SSR_PERIOD_SIZE, sample_rate, cfgFileName);
291 if (ret) {
292 ALOGE("surround_rec_init failed with ret:%d",ret);
293 ret = -EINVAL;
294 goto init_fail;
295 }
296
297 return 0;
298
299init_fail:
300 if (ssrmod.surround_obj) {
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700301 ssrmod.surround_obj = NULL;
302 }
303 if (ssrmod.surround_raw_buffer) {
304 free(ssrmod.surround_raw_buffer);
305 ssrmod.surround_raw_buffer = NULL;
306 ssrmod.surround_raw_buffer_size = 0;
307 }
308 if(ssrmod.surround_rec_handle) {
309 dlclose(ssrmod.surround_rec_handle);
310 ssrmod.surround_rec_handle = NULL;
311 }
312 return ret;
313}
314
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800315void ssr_update_enabled()
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700316{
317 char ssr_enabled[PROPERTY_VALUE_MAX] = "false";
318
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700319 property_get("ro.vendor.audio.sdk.ssr",ssr_enabled,"0");
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700320 if (!strncmp("true", ssr_enabled, 4)) {
321 ALOGD("%s: surround sound recording is supported", __func__);
322 ssrmod.is_ssr_enabled = true;
323 } else {
324 ALOGD("%s: surround sound recording is not supported", __func__);
325 ssrmod.is_ssr_enabled = false;
326 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700327}
328
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800329bool ssr_get_enabled()
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700330{
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700331 ALOGV("%s: is_ssr_enabled:%d is_ssr_mode_on:%d ", __func__, ssrmod.is_ssr_enabled, ssrmod.is_ssr_mode_on);
332
333 if(ssrmod.is_ssr_enabled && ssrmod.is_ssr_mode_on)
334 return true;
335
336 return false;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700337}
338
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800339bool ssr_check_usecase(struct stream_in *in) {
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +0530340 int ret = false;
Naresh Tanniruc9093982015-10-16 18:05:29 +0530341 int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
342 audio_devices_t devices = in->device;
343 audio_source_t source = in->source;
344
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800345 if ((ssr_get_enabled()) &&
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +0530346 ((channel_count == 2) || (channel_count == 6)) &&
347 ((AUDIO_SOURCE_MIC == source) || (AUDIO_SOURCE_CAMCORDER == source)) &&
348 ((AUDIO_DEVICE_IN_BUILTIN_MIC == devices) || (AUDIO_DEVICE_IN_BACK_MIC == devices)) &&
349 (in->format == AUDIO_FORMAT_PCM_16_BIT)) {
350 ALOGD("%s: SSR enabled with channel_count :%d",
Naresh Tanniruc9093982015-10-16 18:05:29 +0530351 __func__, channel_count);
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +0530352 ret = true;
353 }
354 return ret;
355}
Naresh Tanniruc9093982015-10-16 18:05:29 +0530356
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700357static void pcm_buffer_queue_push(struct pcm_buffer_queue **queue,
358 struct pcm_buffer_queue *node)
359{
360 struct pcm_buffer_queue *iter;
361
362 node->next = NULL;
363 if ((*queue) == NULL) {
364 *queue = node;
365 } else {
366 iter = *queue;
367 while (iter->next) {
368 iter = iter->next;
369 }
370 iter->next = node;
371 }
372}
373
374static struct pcm_buffer_queue *pcm_buffer_queue_pop(struct pcm_buffer_queue **queue)
375{
376 struct pcm_buffer_queue *node = (*queue);
377 if (node != NULL) {
378 *queue = node->next;
379 node->next = NULL;
380 }
381 return node;
382}
383
384static void deinit_ssr_process_thread()
385{
386 pthread_mutex_lock(&ssrmod.ssr_process_lock);
387 ssrmod.ssr_process_thread_stop = 1;
Naresh Tanniruc9093982015-10-16 18:05:29 +0530388
389 if(ssrmod.in_buf_data != NULL)
390 free(ssrmod.in_buf_data);
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700391 ssrmod.in_buf_data = NULL;
392 ssrmod.in_buf = NULL;
393 ssrmod.in_buf_free = NULL;
Naresh Tanniruc9093982015-10-16 18:05:29 +0530394
395 if(ssrmod.out_buf_data != NULL)
396 free(ssrmod.out_buf_data);
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700397 ssrmod.out_buf_data = NULL;
398 ssrmod.out_buf = NULL;
399 ssrmod.out_buf_free = NULL;
400 pthread_cond_broadcast(&ssrmod.cond_process);
401 pthread_cond_broadcast(&ssrmod.cond_read);
402 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
403 if (ssrmod.ssr_process_thread_started) {
404 pthread_join(ssrmod.ssr_process_thread, (void **)NULL);
405 ssrmod.ssr_process_thread_started = 0;
406 }
407}
408
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800409struct stream_in *ssr_get_stream()
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700410{
411 return ssrmod.in;
412}
413
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800414int32_t ssr_deinit()
415{
416 ALOGV("%s: entry", __func__);
417 deinit_ssr_process_thread();
418
419 if (ssrmod.drc_obj) {
420 ssrmod.drc_deinit(ssrmod.drc_obj);
421 ssrmod.drc_obj = NULL;
422 }
423
424 if (ssrmod.surround_obj) {
425
426 if (ssrmod.ssr_3mic) {
427 ssrmod.surround_rec_deinit(ssrmod.surround_obj);
428 ssrmod.surround_obj = NULL;
429 }
430 if (ssrmod.surround_raw_buffer) {
431 free(ssrmod.surround_raw_buffer);
432 ssrmod.surround_raw_buffer = NULL;
433 }
434 if (ssrmod.fp_input)
435 fclose(ssrmod.fp_input);
436 if (ssrmod.fp_output)
437 fclose(ssrmod.fp_output);
438 }
439
440 if(ssrmod.drc_handle) {
441 dlclose(ssrmod.drc_handle);
442 ssrmod.drc_handle = NULL;
443 }
444
445 if(ssrmod.surround_rec_handle) {
446 dlclose(ssrmod.surround_rec_handle);
447 ssrmod.surround_rec_handle = NULL;
448 }
449
450 ssrmod.in = NULL;
451 //SSR session can be closed due to device switch
452 //Do not force reset ssr mode
453
454 //ssrmod.is_ssr_mode_on = false;
455 ALOGV("%s: exit", __func__);
456
457 return 0;
458}
459
460int32_t ssr_init(struct stream_in *in, int num_out_chan)
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700461{
Naresh Tanniruc9093982015-10-16 18:05:29 +0530462 uint32_t ret = -1;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700463 char c_multi_ch_dump[128] = {0};
464 uint32_t buffer_size;
465
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700466 ALOGD("%s: ssr case, sample rate %d", __func__, in->config.rate);
467
468 if (ssrmod.surround_obj != NULL) {
469 ALOGV("%s: reinitializing surround sound library", __func__);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800470 ssr_deinit();
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700471 }
472
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800473 if (ssr_get_enabled()) {
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700474 ssrmod.ssr_3mic = 1;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700475 } else {
Naresh Tanniruc9093982015-10-16 18:05:29 +0530476 ALOGE(" Rejecting SSR -- init is called without enabling SSR");
477 goto fail;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700478 }
479
Naresh Tanniruc9093982015-10-16 18:05:29 +0530480 /* buffer size equals to period_size * period_count */
481 buffer_size = SSR_PERIOD_SIZE * NUM_IN_CHANNELS * sizeof(int16_t);
Mingming Yin49be8032013-12-19 12:51:25 -0800482 ALOGV("%s: buffer_size: %d", __func__, buffer_size);
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700483
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700484 if (ssrmod.ssr_3mic != 0) {
Naresh Tanniruc9093982015-10-16 18:05:29 +0530485 ret = ssr_init_surround_sound_3mic_lib(buffer_size, NUM_IN_CHANNELS, num_out_chan, in->config.rate);
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700486 if (0 != ret) {
487 ALOGE("%s: ssr_init_surround_sound_3mic_lib failed: %d "
488 "buffer_size:%d", __func__, ret, buffer_size);
489 goto fail;
490 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700491 }
492
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700493 /* Initialize DRC if available */
494 ret = drc_init_lib(num_out_chan, in->config.rate);
495 if (0 != ret) {
496 ALOGE("%s: drc_init_lib failed, ret %d", __func__, ret);
497 }
498
499 pthread_mutex_lock(&ssrmod.ssr_process_lock);
500 if (!ssrmod.ssr_process_thread_started) {
501 int i;
502 int output_buf_size = SSR_PERIOD_SIZE * sizeof(int16_t) * num_out_chan;
503
504 ssrmod.in_buf_data = (void *)calloc(buffer_size, NUM_IN_BUFS);
505 if (ssrmod.in_buf_data == NULL) {
506 ALOGE("%s: failed to allocate input buffer", __func__);
507 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
508 ret = -ENOMEM;
509 goto fail;
510 }
511 ssrmod.out_buf_data = (void *)calloc(output_buf_size, NUM_OUT_BUFS);
512 if (ssrmod.out_buf_data == NULL) {
513 ALOGE("%s: failed to allocate output buffer", __func__);
514 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
515 ret = -ENOMEM;
516 // ssrmod.in_buf_data will be freed in deinit_ssr_process_thread()
517 goto fail;
518 }
519
520 ssrmod.in_buf = NULL;
521 ssrmod.in_buf_free = NULL;
522 ssrmod.out_buf = NULL;
523 ssrmod.out_buf_free = NULL;
524
525 for (i=0; i < NUM_IN_BUFS; i++) {
526 struct pcm_buffer_queue *buf = &ssrmod.in_buf_nodes[i];
527 buf->buffer.data = &(((char *)ssrmod.in_buf_data)[i*buffer_size]);
528 buf->buffer.length = buffer_size;
529 pcm_buffer_queue_push(&ssrmod.in_buf_free, buf);
530 }
531
532 for (i=0; i < NUM_OUT_BUFS; i++) {
533 struct pcm_buffer_queue *buf = &ssrmod.out_buf_nodes[i];
534 buf->buffer.data = &(((char *)ssrmod.out_buf_data)[i*output_buf_size]);
535 buf->buffer.length = output_buf_size;
536 pcm_buffer_queue_push(&ssrmod.out_buf, buf);
537 }
538
539 ssrmod.ssr_process_thread_stop = 0;
540 ALOGV("%s: creating thread", __func__);
541 ret = pthread_create(&ssrmod.ssr_process_thread,
542 (const pthread_attr_t *) NULL,
543 ssr_process_thread, NULL);
544 if (ret != 0) {
545 ALOGE("%s: failed to create thread for surround sound recording.",
546 __func__);
547 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
548 goto fail;
549 }
550
551 ssrmod.ssr_process_thread_started = 1;
552 ALOGV("%s: done creating thread", __func__);
553 }
Naresh Tanniruc9093982015-10-16 18:05:29 +0530554
555 in->config.channels = NUM_IN_CHANNELS;
556 in->config.period_size = SSR_PERIOD_SIZE;
557 in->config.period_count = in->config.channels * sizeof(int16_t);
558
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700559 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
560
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700561 property_get("vendor.audio.ssr.pcmdump",c_multi_ch_dump,"0");
Mingming Yin49be8032013-12-19 12:51:25 -0800562 if (0 == strncmp("true", c_multi_ch_dump, sizeof("ssr.dump-pcm"))) {
563 /* Remember to change file system permission of data(e.g. chmod 777 data/),
564 otherwise, fopen may fail */
Naresh Tanniruc9093982015-10-16 18:05:29 +0530565 if ( !ssrmod.fp_input) {
566 ALOGD("%s: Opening ssr input dump file \n", __func__);
Arun Mirpurib1416682018-03-07 19:13:53 -0800567 ssrmod.fp_input = fopen("/data/vendor/audio/ssr_input_3ch.pcm", "wb");
Naresh Tanniruc9093982015-10-16 18:05:29 +0530568 }
569
570 if ( !ssrmod.fp_output) {
571 if(ssrmod.num_out_chan == 6) {
572 ALOGD("%s: Opening ssr input dump file for 6 channel\n", __func__);
Arun Mirpurib1416682018-03-07 19:13:53 -0800573 ssrmod.fp_output = fopen("/data/vendor/audio/ssr_output_6ch.pcm", "wb");
Naresh Tanniruc9093982015-10-16 18:05:29 +0530574 } else {
575 ALOGD("%s: Opening ssr input dump file for 2 channel\n", __func__);
Arun Mirpurib1416682018-03-07 19:13:53 -0800576 ssrmod.fp_output = fopen("/data/vendor/audio/ssr_output_2ch.pcm", "wb");
Naresh Tanniruc9093982015-10-16 18:05:29 +0530577 }
578 }
579
580 if ((!ssrmod.fp_input) || (!ssrmod.fp_output)) {
581 ALOGE("%s: input dump or ouput dump open failed: mfp_4ch:%p mfp_6ch:%p",
582 __func__, ssrmod.fp_input, ssrmod.fp_output);
583 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700584 }
585
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700586 ssrmod.in = in;
587
588 ALOGV("%s: exit", __func__);
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700589 return 0;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700590
591fail:
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800592 (void) ssr_deinit();
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700593 return ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700594}
595
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800596int ssr_set_usecase(struct stream_in *in,
597 struct audio_config *config,
598 bool *update_params)
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700599{
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800600 int ret = -EINVAL;
601 int channel_count = audio_channel_count_from_in_mask(in->channel_mask);
602 audio_channel_representation_t representation =
603 audio_channel_mask_get_representation(in->channel_mask);
604 *update_params = false;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700605
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800606 if (ssr_check_usecase(in)) {
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700607
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800608 if (representation == AUDIO_CHANNEL_REPRESENTATION_INDEX) {
609 /* update params in case channel representation index.
610 * on returning error, flinger will retry with supported representation passed
611 */
612 ALOGD("%s: SSR supports only channel representation position, channel_mask(%#x)"
613 ,__func__, config->channel_mask);
614 config->channel_mask = AUDIO_CHANNEL_IN_6;
615 ret = 0;
616 *update_params = true;
617 } else {
618 if (!ssr_init(in, channel_count)) {
619 ALOGD("%s: Created SSR session succesfully", __func__);
620 ret = 0;
621 } else {
622 ALOGE("%s: Unable to start SSR record session", __func__);
623 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700624 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700625 }
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800626 return ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700627}
628
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700629static void *ssr_process_thread(void *context __unused)
630{
631 int32_t ret;
632
633 ALOGV("%s: enter", __func__);
634
635 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_URGENT_AUDIO);
636 set_sched_policy(0, SP_FOREGROUND);
637
638 pthread_mutex_lock(&ssrmod.ssr_process_lock);
639 while (!ssrmod.ssr_process_thread_stop) {
640 struct pcm_buffer_queue *out_buf;
641 struct pcm_buffer_queue *in_buf;
642
643 while ((!ssrmod.ssr_process_thread_stop) &&
644 ((ssrmod.out_buf_free == NULL) ||
645 (ssrmod.in_buf == NULL))) {
646 ALOGV("%s: waiting for buffers", __func__);
647 pthread_cond_wait(&ssrmod.cond_process, &ssrmod.ssr_process_lock);
648 }
649 if (ssrmod.ssr_process_thread_stop) {
650 break;
651 }
652 ALOGV("%s: got buffers", __func__);
653
654 out_buf = pcm_buffer_queue_pop(&ssrmod.out_buf_free);
655 in_buf = pcm_buffer_queue_pop(&ssrmod.in_buf);
656
657 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
658
659 /* apply ssr libs to convert 4ch to 6ch */
660 if (ssrmod.ssr_3mic) {
661 ssrmod.surround_rec_process(ssrmod.surround_obj,
662 (int16_t *) in_buf->buffer.data,
663 (int16_t *) out_buf->buffer.data);
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700664 }
665
666 /* Run DRC if initialized */
667 if (ssrmod.drc_obj != NULL) {
668 ALOGV("%s: Running DRC", __func__);
669 ret = ssrmod.drc_process(ssrmod.drc_obj, out_buf->buffer.data, out_buf->buffer.data);
670 if (ret != 0) {
671 ALOGE("%s: drc_process returned %d", __func__, ret);
672 }
673 }
674
675 /*dump for raw pcm data*/
Naresh Tanniruc9093982015-10-16 18:05:29 +0530676 if (ssrmod.fp_input)
677 fwrite(in_buf->buffer.data, 1, in_buf->buffer.length, ssrmod.fp_input);
678 if (ssrmod.fp_output)
679 fwrite(out_buf->buffer.data, 1, out_buf->buffer.length, ssrmod.fp_output);
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700680
681 pthread_mutex_lock(&ssrmod.ssr_process_lock);
682
683 pcm_buffer_queue_push(&ssrmod.out_buf, out_buf);
684 pcm_buffer_queue_push(&ssrmod.in_buf_free, in_buf);
685
686 /* Read thread should go on without waiting for condition
687 * variable. If it has to wait (due to this thread not keeping
688 * up with the read requests), let this thread use the remainder
689 * of its buffers before waking up the read thread. */
690 if (ssrmod.in_buf == NULL) {
691 pthread_cond_signal(&ssrmod.cond_read);
692 }
693 }
694 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
695
696 ALOGV("%s: exit", __func__);
697
698 pthread_exit(NULL);
699}
700
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800701int32_t ssr_read(struct audio_stream_in *stream,
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700702 void *buffer, size_t bytes)
703{
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700704 struct stream_in *in = (struct stream_in *)stream;
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700705 int32_t ret = 0;
706 struct pcm_buffer_queue *in_buf;
707 struct pcm_buffer_queue *out_buf;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700708
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700709 ALOGV("%s: entry", __func__);
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700710
Mingming Yin49be8032013-12-19 12:51:25 -0800711 if (!ssrmod.surround_obj) {
712 ALOGE("%s: surround_obj not initialized", __func__);
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700713 return -ENOMEM;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700714 }
Mingming Yin49be8032013-12-19 12:51:25 -0800715
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700716 ret = pcm_read(in->pcm, ssrmod.surround_raw_buffer, ssrmod.surround_raw_buffer_size);
Mingming Yin49be8032013-12-19 12:51:25 -0800717 if (ret < 0) {
718 ALOGE("%s: %s ret:%d", __func__, pcm_get_error(in->pcm),ret);
719 return ret;
720 }
721
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700722 pthread_mutex_lock(&ssrmod.ssr_process_lock);
Mingming Yin49be8032013-12-19 12:51:25 -0800723
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700724 if (!ssrmod.ssr_process_thread_started) {
725 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
726 ALOGV("%s: ssr_process_thread not initialized", __func__);
727 return -EINVAL;
728 }
Mingming Yin49be8032013-12-19 12:51:25 -0800729
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700730 if ((ssrmod.in_buf_free == NULL) || (ssrmod.out_buf == NULL)) {
731 ALOGE("%s: waiting for buffers", __func__);
732 pthread_cond_wait(&ssrmod.cond_read, &ssrmod.ssr_process_lock);
733 if ((ssrmod.in_buf_free == NULL) || (ssrmod.out_buf == NULL)) {
734 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
735 ALOGE("%s: failed to acquire buffers", __func__);
736 return -EINVAL;
737 }
738 }
739
740 in_buf = pcm_buffer_queue_pop(&ssrmod.in_buf_free);
741 out_buf = pcm_buffer_queue_pop(&ssrmod.out_buf);
742
743 memcpy(in_buf->buffer.data, ssrmod.surround_raw_buffer, in_buf->buffer.length);
744 pcm_buffer_queue_push(&ssrmod.in_buf, in_buf);
745
746 memcpy(buffer, out_buf->buffer.data, bytes);
747 pcm_buffer_queue_push(&ssrmod.out_buf_free, out_buf);
748
749 pthread_cond_signal(&ssrmod.cond_process);
750
751 pthread_mutex_unlock(&ssrmod.ssr_process_lock);
752
753 ALOGV("%s: exit", __func__);
Mingming Yin49be8032013-12-19 12:51:25 -0800754 return ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -0700755}
Mingming Yin49be8032013-12-19 12:51:25 -0800756
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800757void ssr_set_parameters(struct audio_device *adev __unused,
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700758 struct str_parms *parms)
759{
760 int err;
761 char value[4096] = {0};
762
763 //Do not update SSR mode during recording
764 if ( !ssrmod.surround_obj) {
765 int ret = 0;
766 ret = str_parms_get_str(parms, AUDIO_PARAMETER_SSRMODE_ON, value,
767 sizeof(value));
768 if (ret >= 0) {
769 if (strcmp(value, "true") == 0) {
770 ALOGD("Received SSR session request..setting SSR mode to true");
771 ssrmod.is_ssr_mode_on = true;
772 } else {
773 ALOGD("resetting SSR mode to false");
774 ssrmod.is_ssr_mode_on = false;
775 }
776 }
777 }
778 if (ssrmod.ssr_3mic && ssrmod.surround_obj) {
779 const set_param_data_t *set_params = ssrmod.surround_rec_get_set_param_data();
780 if (set_params != NULL) {
781 while (set_params->name != NULL && set_params->set_param_fn != NULL) {
782 err = str_parms_get_str(parms, set_params->name, value, sizeof(value));
783 if (err >= 0) {
784 ALOGV("Set %s to %s\n", set_params->name, value);
785 set_params->set_param_fn(ssrmod.surround_obj, value);
786 }
787 set_params++;
788 }
789 }
790 }
791}
792
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800793void ssr_get_parameters(const struct audio_device *adev __unused,
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -0700794 struct str_parms *parms,
795 struct str_parms *reply)
796{
797 int err;
798 char value[4096] = {0};
799
800 if (ssrmod.ssr_3mic && ssrmod.surround_obj) {
801 const get_param_data_t *get_params = ssrmod.surround_rec_get_get_param_data();
802 int get_all = 0;
803 err = str_parms_get_str(parms, "ssr.all", value, sizeof(value));
804 if (err >= 0) {
805 get_all = 1;
806 }
807 if (get_params != NULL) {
808 while (get_params->name != NULL && get_params->get_param_fn != NULL) {
809 err = str_parms_get_str(parms, get_params->name, value, sizeof(value));
810 if (get_all || (err >= 0)) {
811 ALOGV("Getting parameter %s", get_params->name);
812 char *val = get_params->get_param_fn(ssrmod.surround_obj);
813 if (val != NULL) {
814 str_parms_add_str(reply, get_params->name, val);
815 free(val);
816 }
817 }
818 get_params++;
819 }
820 }
821 }
822}
823