blob: ccabe3040da8e07b608cb74ff8e6a70b3c50d37c [file] [log] [blame]
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001/*
Ramu Gottipatifa5be522021-12-28 19:18:21 +05302 * Copyright (c) 2013-2022, The Linux Foundation. All rights reserved.
Apoorv Raghuvanshi9eaf94e2013-10-04 16:13:44 -07003 * Not a Contribution.
4 *
Shiv Maliyappanahalli8911f282014-01-10 15:56:19 -08005 * Copyright (C) 2013 The Android Open Source Project
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006 *
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.
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080018 *
19 * This file was modified by DTS, Inc. The portions of the
20 * code modified by DTS, Inc are copyrighted and
21 * licensed separately, as follows:
22 *
23 * (C) 2014 DTS, Inc.
24 *
25 * Licensed under the Apache License, Version 2.0 (the "License");
26 * you may not use this file except in compliance with the License.
27 * You may obtain a copy of the License at
28 *
29 * http://www.apache.org/licenses/LICENSE-2.0
30 *
31 * Unless required by applicable law or agreed to in writing, software
32 * distributed under the License is distributed on an "AS IS" BASIS,
33 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 * See the License for the specific language governing permissions and
35 * limitations under the License.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080036 */
37
38#define LOG_TAG "audio_hw_primary"
Haynes Mathew George5beddd42016-06-27 18:33:40 -070039#define ATRACE_TAG (ATRACE_TAG_AUDIO|ATRACE_TAG_HAL)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080040/*#define LOG_NDEBUG 0*/
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070041/*#define VERY_VERY_VERBOSE_LOGGING*/
42#ifdef VERY_VERY_VERBOSE_LOGGING
43#define ALOGVV ALOGV
44#else
45#define ALOGVV(a...) do { } while(0)
46#endif
George Gao3018ede2019-10-23 13:23:00 -070047#include <limits.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080048#include <errno.h>
49#include <pthread.h>
50#include <stdint.h>
51#include <sys/time.h>
52#include <stdlib.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080053#include <math.h>
Eric Laurentc4aef752013-09-12 17:45:53 -070054#include <dlfcn.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070055#include <sys/resource.h>
56#include <sys/prctl.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080057
Aalique Grahame22e49102018-12-18 14:23:57 -080058#include <log/log.h>
Haynes Mathew George5beddd42016-06-27 18:33:40 -070059#include <cutils/trace.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080060#include <cutils/str_parms.h>
61#include <cutils/properties.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070062#include <cutils/atomic.h>
63#include <cutils/sched_policy.h>
Eric Laurentb23d5282013-05-14 15:27:20 -070064#include <hardware/audio_effect.h>
Haynes Mathew George484e8d22017-07-31 18:55:17 -070065#include <hardware/audio_alsaops.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070066#include <system/thread_defs.h>
Haynes Mathew George16081042017-05-31 17:16:49 -070067#include <tinyalsa/asoundlib.h>
Andy Hunga1f48fa2019-07-01 18:14:53 -070068#include <utils/Timers.h> // systemTime
Eric Laurentb23d5282013-05-14 15:27:20 -070069#include <audio_effects/effect_aec.h>
70#include <audio_effects/effect_ns.h>
Ashish Jainf1eaa582016-05-23 20:54:24 +053071#include <audio_utils/format.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080072#include "audio_hw.h"
Wei Wangf7ca6c92017-11-21 14:51:20 -080073#include "audio_perf.h"
Eric Laurentb23d5282013-05-14 15:27:20 -070074#include "platform_api.h"
75#include <platform.h>
Apoorv Raghuvanshi9eaf94e2013-10-04 16:13:44 -070076#include "audio_extn.h"
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080077#include "voice_extn.h"
Ashish Jaind5694242017-09-05 20:09:06 +053078#include "ip_hdlr_intf.h"
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080079
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070080#include "sound/compress_params.h"
Xiaojun Sang782e5b12020-06-29 21:13:06 +080081
82#ifdef AUDIO_GKI_ENABLED
83#include "sound/audio_compressed_formats.h"
84#endif
85
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -080086#include "sound/asound.h"
ApurupaPattapu2e084df2013-12-18 15:47:59 -080087
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053088#ifdef DYNAMIC_LOG_ENABLED
89#include <log_xml_parser.h>
90#define LOG_MASK HAL_MOD_FILE_AUDIO_HW
91#include <log_utils.h>
92#endif
93
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070094#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
Ashish Jain5106d362016-05-11 19:23:33 +053095/*DIRECT PCM has same buffer sizes as DEEP Buffer*/
96#define DIRECT_PCM_NUM_FRAGMENTS 2
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070097#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
Vikram Panduranga93f080e2017-06-07 18:16:14 -070098#define VOIP_PLAYBACK_VOLUME_MAX 0x2000
Arun Mirpuri5d170872019-03-26 13:21:31 -070099#define MMAP_PLAYBACK_VOLUME_MAX 0x2000
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +0530100#define PCM_PLAYBACK_VOLUME_MAX 0x2000
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +0530101#define DSD_VOLUME_MIN_DB (-110)
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -0700102#define INVALID_OUT_VOLUME -1
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700103#define AUDIO_IO_PORTS_MAX 32
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700104
Zhou Songbaddf9f2020-11-20 13:57:39 +0800105#define PLAYBACK_GAIN_MAX 1.0f
Aalique Grahame22e49102018-12-18 14:23:57 -0800106#define RECORD_GAIN_MIN 0.0f
107#define RECORD_GAIN_MAX 1.0f
108#define RECORD_VOLUME_CTL_MAX 0x2000
109
110/* treat as unsigned Q1.13 */
111#define APP_TYPE_GAIN_DEFAULT 0x2000
112
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700113#define PROXY_OPEN_RETRY_COUNT 100
114#define PROXY_OPEN_WAIT_TIME 20
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -0800115
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800116#define GET_USECASE_AUDIO_PLAYBACK_PRIMARY(db) \
117 (db)? USECASE_AUDIO_PLAYBACK_DEEP_BUFFER : \
118 USECASE_AUDIO_PLAYBACK_LOW_LATENCY
119#define GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(db) \
120 (db)? pcm_config_deep_buffer : pcm_config_low_latency
Haynes Mathew Georgebf143712013-12-03 13:02:53 -0800121
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700122#define ULL_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700123#define DEFAULT_VOIP_BUF_DURATION_MS 20
124#define DEFAULT_VOIP_BIT_DEPTH_BYTE sizeof(int16_t)
125#define DEFAULT_VOIP_SAMP_RATE 48000
126
127#define VOIP_IO_BUF_SIZE(SR, DURATION_MS, BIT_DEPTH) (SR)/1000 * DURATION_MS * BIT_DEPTH
128
129struct pcm_config default_pcm_config_voip_copp = {
130 .channels = 1,
131 .rate = DEFAULT_VOIP_SAMP_RATE, /* changed when the stream is opened */
132 .period_size = VOIP_IO_BUF_SIZE(DEFAULT_VOIP_SAMP_RATE, DEFAULT_VOIP_BUF_DURATION_MS, DEFAULT_VOIP_BIT_DEPTH_BYTE)/2,
133 .period_count = 2,
134 .format = PCM_FORMAT_S16_LE,
kunleiz95b597a2017-10-23 17:07:33 +0800135 .avail_min = VOIP_IO_BUF_SIZE(DEFAULT_VOIP_SAMP_RATE, DEFAULT_VOIP_BUF_DURATION_MS, DEFAULT_VOIP_BIT_DEPTH_BYTE)/2,
136 .stop_threshold = INT_MAX,
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700137};
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700138
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700139#define MIN_CHANNEL_COUNT 1
140#define DEFAULT_CHANNEL_COUNT 2
141#define MAX_HIFI_CHANNEL_COUNT 8
142
Aalique Grahame22e49102018-12-18 14:23:57 -0800143#ifndef MAX_TARGET_SPECIFIC_CHANNEL_CNT
144#define MAX_CHANNEL_COUNT 1
145#else
146#define MAX_CHANNEL_COUNT atoi(XSTR(MAX_TARGET_SPECIFIC_CHANNEL_CNT))
147#define XSTR(x) STR(x)
148#define STR(x) #x
149#endif
150
Avinash Chandrad7296d42021-08-04 15:07:47 +0530151#define IS_USB_HIFI (MAX_HIFI_CHANNEL_COUNT >= MAX_CHANNEL_COUNT) ? \
152 true : false
153
Dechen Chai22768452021-07-30 09:29:16 +0530154#ifdef LINUX_ENABLED
155static inline int64_t audio_utils_ns_from_timespec(const struct timespec *ts)
156{
157 return ts->tv_sec * 1000000000LL + ts->tv_nsec;
158}
159#endif
160
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -0700161static unsigned int configured_low_latency_capture_period_size =
162 LOW_LATENCY_CAPTURE_PERIOD_SIZE;
163
Haynes Mathew George16081042017-05-31 17:16:49 -0700164#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
165#define MMAP_PERIOD_COUNT_MIN 32
166#define MMAP_PERIOD_COUNT_MAX 512
167#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
168
Aalique Grahame22e49102018-12-18 14:23:57 -0800169/* This constant enables extended precision handling.
170 * TODO The flag is off until more testing is done.
171 */
172static const bool k_enable_extended_precision = false;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700173extern int AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
Aalique Grahame22e49102018-12-18 14:23:57 -0800174
Eric Laurentb23d5282013-05-14 15:27:20 -0700175struct pcm_config pcm_config_deep_buffer = {
176 .channels = 2,
177 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
178 .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
179 .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
180 .format = PCM_FORMAT_S16_LE,
181 .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
182 .stop_threshold = INT_MAX,
183 .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
184};
185
186struct pcm_config pcm_config_low_latency = {
187 .channels = 2,
188 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
189 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
190 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
191 .format = PCM_FORMAT_S16_LE,
192 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
193 .stop_threshold = INT_MAX,
194 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
195};
196
Vignesh Kulothungana6927272019-02-20 15:17:07 -0800197struct pcm_config pcm_config_haptics_audio = {
198 .channels = 1,
199 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
200 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
201 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
202 .format = PCM_FORMAT_S16_LE,
203 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
204 .stop_threshold = INT_MAX,
205 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
206};
207
208struct pcm_config pcm_config_haptics = {
209 .channels = 1,
210 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
211 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
212 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
213 .format = PCM_FORMAT_S16_LE,
214 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
215 .stop_threshold = INT_MAX,
216 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
217};
218
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700219static int af_period_multiplier = 4;
220struct pcm_config pcm_config_rt = {
221 .channels = 2,
222 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
223 .period_size = ULL_PERIOD_SIZE, //1 ms
224 .period_count = 512, //=> buffer size is 512ms
225 .format = PCM_FORMAT_S16_LE,
226 .start_threshold = ULL_PERIOD_SIZE*8, //8ms
227 .stop_threshold = INT_MAX,
228 .silence_threshold = 0,
229 .silence_size = 0,
230 .avail_min = ULL_PERIOD_SIZE, //1 ms
231};
232
Eric Laurentb23d5282013-05-14 15:27:20 -0700233struct pcm_config pcm_config_hdmi_multi = {
234 .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
235 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
236 .period_size = HDMI_MULTI_PERIOD_SIZE,
237 .period_count = HDMI_MULTI_PERIOD_COUNT,
238 .format = PCM_FORMAT_S16_LE,
239 .start_threshold = 0,
240 .stop_threshold = INT_MAX,
241 .avail_min = 0,
242};
243
Haynes Mathew George16081042017-05-31 17:16:49 -0700244struct pcm_config pcm_config_mmap_playback = {
245 .channels = 2,
246 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
247 .period_size = MMAP_PERIOD_SIZE,
248 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
249 .format = PCM_FORMAT_S16_LE,
250 .start_threshold = MMAP_PERIOD_SIZE*8,
251 .stop_threshold = INT32_MAX,
252 .silence_threshold = 0,
253 .silence_size = 0,
254 .avail_min = MMAP_PERIOD_SIZE, //1 ms
255};
256
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700257struct pcm_config pcm_config_hifi = {
258 .channels = DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
259 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
260 .period_size = HIFI_BUFFER_OUTPUT_PERIOD_SIZE, /* change #define */
261 .period_count = HIFI_BUFFER_OUTPUT_PERIOD_COUNT,
262 .format = PCM_FORMAT_S24_3LE,
263 .start_threshold = 0,
264 .stop_threshold = INT_MAX,
265 .avail_min = 0,
266};
267
Eric Laurentb23d5282013-05-14 15:27:20 -0700268struct pcm_config pcm_config_audio_capture = {
269 .channels = 2,
Eric Laurentb23d5282013-05-14 15:27:20 -0700270 .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
271 .format = PCM_FORMAT_S16_LE,
272};
273
Haynes Mathew George16081042017-05-31 17:16:49 -0700274struct pcm_config pcm_config_mmap_capture = {
275 .channels = 2,
276 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
277 .period_size = MMAP_PERIOD_SIZE,
278 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
279 .format = PCM_FORMAT_S16_LE,
280 .start_threshold = 0,
281 .stop_threshold = INT_MAX,
282 .silence_threshold = 0,
283 .silence_size = 0,
284 .avail_min = MMAP_PERIOD_SIZE, //1 ms
285};
286
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700287#define AFE_PROXY_CHANNEL_COUNT 2
288#define AFE_PROXY_SAMPLING_RATE 48000
289
290#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768
291#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
292
293struct pcm_config pcm_config_afe_proxy_playback = {
294 .channels = AFE_PROXY_CHANNEL_COUNT,
295 .rate = AFE_PROXY_SAMPLING_RATE,
296 .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
297 .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
298 .format = PCM_FORMAT_S16_LE,
299 .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
300 .stop_threshold = INT_MAX,
301 .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
302};
303
304#define AFE_PROXY_RECORD_PERIOD_SIZE 768
305#define AFE_PROXY_RECORD_PERIOD_COUNT 4
306
Aalique Grahame22e49102018-12-18 14:23:57 -0800307struct pcm_config pcm_config_audio_capture_rt = {
308 .channels = 2,
309 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
310 .period_size = ULL_PERIOD_SIZE,
311 .period_count = 512,
312 .format = PCM_FORMAT_S16_LE,
313 .start_threshold = 0,
314 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
315 .silence_threshold = 0,
316 .silence_size = 0,
317 .avail_min = ULL_PERIOD_SIZE, //1 ms
318};
319
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +0530320struct pcm_config pcm_config_audio_capture_rt_48KHz = {
321 .channels = 2,
322 .rate = 48000,
323 .period_size = 48,
324 .period_count = 512,
325 .format = PCM_FORMAT_S16_LE,
326 .start_threshold = 0,
327 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
328 .silence_threshold = 0,
329 .silence_size = 0,
330 .avail_min = 48, //1 ms
331};
332struct pcm_config pcm_config_audio_capture_rt_32KHz = {
333 .channels = 2,
334 .rate = 32000,
335 .period_size = 32,
336 .period_count = 512,
337 .format = PCM_FORMAT_S16_LE,
338 .start_threshold = 0,
339 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
340 .silence_threshold = 0,
341 .silence_size = 0,
342 .avail_min = 32, //1 ms
343};
344struct pcm_config pcm_config_audio_capture_rt_24KHz = {
345 .channels = 2,
346 .rate = 24000,
347 .period_size = 24,
348 .period_count = 512,
349 .format = PCM_FORMAT_S16_LE,
350 .start_threshold = 0,
351 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
352 .silence_threshold = 0,
353 .silence_size = 0,
354 .avail_min = 24, //1 ms
355};
356struct pcm_config pcm_config_audio_capture_rt_16KHz = {
357 .channels = 2,
358 .rate = 16000,
359 .period_size = 16,
360 .period_count = 512,
361 .format = PCM_FORMAT_S16_LE,
362 .start_threshold = 0,
363 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
364 .silence_threshold = 0,
365 .silence_size = 0,
366 .avail_min = 16, //1 ms
367};
368struct pcm_config pcm_config_audio_capture_rt_8KHz = {
369 .channels = 2,
370 .rate = 8000,
371 .period_size = 8,
372 .period_count = 512,
373 .format = PCM_FORMAT_S16_LE,
374 .start_threshold = 0,
375 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
376 .silence_threshold = 0,
377 .silence_size = 0,
378 .avail_min = 8, //1 ms
379};
380
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700381struct pcm_config pcm_config_afe_proxy_record = {
382 .channels = AFE_PROXY_CHANNEL_COUNT,
383 .rate = AFE_PROXY_SAMPLING_RATE,
384 .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
385 .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
386 .format = PCM_FORMAT_S16_LE,
387 .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
388 .stop_threshold = INT_MAX,
389 .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
390};
391
Ashish Jainf1eaa582016-05-23 20:54:24 +0530392#define AUDIO_MAX_PCM_FORMATS 7
393
394const uint32_t format_to_bitwidth_table[AUDIO_MAX_PCM_FORMATS] = {
395 [AUDIO_FORMAT_DEFAULT] = 0,
396 [AUDIO_FORMAT_PCM_16_BIT] = sizeof(uint16_t),
397 [AUDIO_FORMAT_PCM_8_BIT] = sizeof(uint8_t),
398 [AUDIO_FORMAT_PCM_32_BIT] = sizeof(uint32_t),
399 [AUDIO_FORMAT_PCM_8_24_BIT] = sizeof(uint32_t),
400 [AUDIO_FORMAT_PCM_FLOAT] = sizeof(float),
401 [AUDIO_FORMAT_PCM_24_BIT_PACKED] = sizeof(uint8_t) * 3,
402};
403
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800404const char * const use_case_table[AUDIO_USECASE_MAX] = {
Eric Laurentb23d5282013-05-14 15:27:20 -0700405 [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
406 [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
Vignesh Kulothungana6927272019-02-20 15:17:07 -0800407 [USECASE_AUDIO_PLAYBACK_WITH_HAPTICS] = "audio-with-haptics-playback",
Meng Wang51d8c2a2020-04-27 15:23:21 +0800408 [USECASE_AUDIO_PLAYBACK_HAPTICS] = "haptics-playback",
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -0700409 [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
410 [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
Shruthi Krishnaace10852013-10-25 14:32:12 -0700411 [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
vivek mehta446c3962015-09-14 10:57:35 -0700412 //Enabled for Direct_PCM
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700413 [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
414 [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
415 [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
416 [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
417 [USECASE_AUDIO_PLAYBACK_OFFLOAD6] = "compress-offload-playback6",
418 [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
419 [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
420 [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
Haynes Mathew George16081042017-05-31 17:16:49 -0700421 [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
422 [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback",
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700423 [USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
Aalique Grahame22e49102018-12-18 14:23:57 -0800424 [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
vivek mehta0ea887a2015-08-26 14:01:20 -0700425
Eric Laurentb23d5282013-05-14 15:27:20 -0700426 [USECASE_AUDIO_RECORD] = "audio-record",
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530427 [USECASE_AUDIO_RECORD2] = "audio-record2",
428 [USECASE_AUDIO_RECORD3] = "audio-record3",
Mingming Yine62d7842013-10-25 16:26:03 -0700429 [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
Dhananjay Kumaree4d2002016-10-25 18:02:58 +0530430 [USECASE_AUDIO_RECORD_COMPRESS2] = "audio-record-compress2",
431 [USECASE_AUDIO_RECORD_COMPRESS3] = "audio-record-compress3",
432 [USECASE_AUDIO_RECORD_COMPRESS4] = "audio-record-compress4",
Dhananjay Kumar376e38b2017-09-28 22:26:23 +0530433 [USECASE_AUDIO_RECORD_COMPRESS5] = "audio-record-compress5",
434 [USECASE_AUDIO_RECORD_COMPRESS6] = "audio-record-compress6",
Eric Laurentb23d5282013-05-14 15:27:20 -0700435 [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
Preetam Singh Ranawatde84f1a2013-11-01 14:58:16 -0700436 [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700437 [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700438 [USECASE_AUDIO_RECORD_HIFI] = "hifi-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700439
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800440 [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800441 [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
Derek Chenf7092792017-05-23 12:23:53 -0400442 [USECASE_AUDIO_HFP_SCO_DOWNLINK] = "hfp-sco-downlink",
443 [USECASE_AUDIO_HFP_SCO_WB_DOWNLINK] = "hfp-sco-wb-downlink",
Mingming Yin3ee55c62014-08-04 14:23:35 -0700444
Derek Chenf7092792017-05-23 12:23:53 -0400445 [USECASE_VOICE_CALL] = "voice-call",
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700446 [USECASE_VOICE2_CALL] = "voice2-call",
447 [USECASE_VOLTE_CALL] = "volte-call",
448 [USECASE_QCHAT_CALL] = "qchat-call",
Vicky Sehrawat7e4fc152014-02-12 17:58:59 -0800449 [USECASE_VOWLAN_CALL] = "vowlan-call",
Vidyakumar Athota0e109352015-02-12 17:38:22 -0800450 [USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
451 [USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
Narsinga Rao Chella05573b72013-11-15 15:21:40 -0800452 [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
Shiv Maliyappanahallida107642013-10-17 11:16:13 -0700453 [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
454 [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
455 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
Helen Zenge56b4852013-12-03 16:54:40 -0800456 [USECASE_INCALL_REC_UPLINK_COMPRESS] = "incall-rec-uplink-compress",
457 [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = "incall-rec-downlink-compress",
458 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = "incall-rec-uplink-and-downlink-compress",
459
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700460 [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
461 [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -0700462 [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
463 [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700464
465 [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
466 [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
Zhou Song62ea0282020-03-22 19:53:01 +0800467 [USECASE_AUDIO_RECORD_AFE_PROXY2] = "afe-proxy-record2",
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +0530468 [USECASE_AUDIO_PLAYBACK_SILENCE] = "silence-playback",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700469
Siddartha Shaik31b530e2017-05-19 15:26:33 +0530470 /* Transcode loopback cases */
Surendar Karka93cd25a2018-08-28 14:21:37 +0530471 [USECASE_AUDIO_TRANSCODE_LOOPBACK_RX] = "audio-transcode-loopback-rx",
472 [USECASE_AUDIO_TRANSCODE_LOOPBACK_TX] = "audio-transcode-loopback-tx",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700473
474 [USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
475 [USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530476 [USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY] = "audio-record-voip-low-latency",
Varun Balaraje49253e2017-07-06 19:48:56 +0530477 /* For Interactive Audio Streams */
478 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] = "audio-interactive-stream1",
479 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] = "audio-interactive-stream2",
480 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] = "audio-interactive-stream3",
481 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] = "audio-interactive-stream4",
482 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] = "audio-interactive-stream5",
483 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] = "audio-interactive-stream6",
484 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
485 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
Garmond Leunge2433c32017-09-28 21:51:22 -0700486
Aniket Kumar Lata7fd86e12018-02-20 19:26:10 -0800487 [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",
488
Derek Chenf6318be2017-06-12 17:16:24 -0400489 [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback",
490
491 [USECASE_AUDIO_PLAYBACK_MEDIA] = "media-playback",
492 [USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION] = "sys-notification-playback",
493 [USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE] = "nav-guidance-playback",
494 [USECASE_AUDIO_PLAYBACK_PHONE] = "phone-playback",
Susan Wang117cf6f2022-04-06 20:11:46 -0400495 [USECASE_AUDIO_PLAYBACK_ALERTS] = "alerts-playback",
Derek Chen1bcdc6b2020-02-06 22:44:53 -0800496 [USECASE_AUDIO_PLAYBACK_FRONT_PASSENGER] = "front-passenger-playback",
Derek Chendf05eea2019-08-01 13:57:49 -0700497 [USECASE_AUDIO_PLAYBACK_REAR_SEAT] = "rear-seat-playback",
Rahul Sharma99770982019-03-06 17:05:26 +0530498 [USECASE_AUDIO_FM_TUNER_EXT] = "fm-tuner-ext",
Derek Chena30a5f42019-12-03 11:17:09 -0500499 [USECASE_ICC_CALL] = "icc-call",
Huicheng Liu1404ba12020-09-11 01:03:25 -0400500
501 [USECASE_AUDIO_RECORD_BUS] = "audio-record",
502 [USECASE_AUDIO_RECORD_BUS_FRONT_PASSENGER] = "front-passenger-record",
503 [USECASE_AUDIO_RECORD_BUS_REAR_SEAT] = "rear-seat-record",
Fei Tongaffdf732020-02-20 20:39:05 +0800504 [USECASE_AUDIO_PLAYBACK_SYNTHESIZER] = "synth-loopback",
Susan Wange3959562021-03-11 11:50:26 -0500505 [USECASE_AUDIO_RECORD_ECHO_REF_EXT] = "echo-reference-external",
Eric Laurentb23d5282013-05-14 15:27:20 -0700506};
507
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700508static const audio_usecase_t offload_usecases[] = {
509 USECASE_AUDIO_PLAYBACK_OFFLOAD,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700510 USECASE_AUDIO_PLAYBACK_OFFLOAD2,
511 USECASE_AUDIO_PLAYBACK_OFFLOAD3,
512 USECASE_AUDIO_PLAYBACK_OFFLOAD4,
513 USECASE_AUDIO_PLAYBACK_OFFLOAD5,
514 USECASE_AUDIO_PLAYBACK_OFFLOAD6,
515 USECASE_AUDIO_PLAYBACK_OFFLOAD7,
516 USECASE_AUDIO_PLAYBACK_OFFLOAD8,
517 USECASE_AUDIO_PLAYBACK_OFFLOAD9,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700518};
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800519
Varun Balaraje49253e2017-07-06 19:48:56 +0530520static const audio_usecase_t interactive_usecases[] = {
521 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
522 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
523 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
524 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
525 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
526 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
527 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
528 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
529};
530
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800531#define STRING_TO_ENUM(string) { #string, string }
532
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800533struct string_to_enum {
534 const char *name;
535 uint32_t value;
536};
537
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700538static const struct string_to_enum channels_name_to_enum_table[] = {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800539 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
Mingming Yin3a941d42016-02-17 18:08:05 -0800540 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
541 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
542 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -0700543 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
Mingming Yin3a941d42016-02-17 18:08:05 -0800544 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
545 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800546 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700547 STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
548 STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
549 STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
550 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
551 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
552 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
553 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
554 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
555 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
556 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
557 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800558};
559
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700560static const struct string_to_enum formats_name_to_enum_table[] = {
561 STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
562 STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
563 STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700564 STRING_TO_ENUM(AUDIO_FORMAT_AC3),
565 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
566 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
Ben Romberger1aaaf862017-04-06 17:49:46 -0700567 STRING_TO_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
Mingming Yin3a941d42016-02-17 18:08:05 -0800568 STRING_TO_ENUM(AUDIO_FORMAT_DTS),
569 STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
Naresh Tanniru928f0862017-04-07 16:44:23 -0700570 STRING_TO_ENUM(AUDIO_FORMAT_IEC61937)
Mingming Yin3a941d42016-02-17 18:08:05 -0800571};
572
573//list of all supported sample rates by HDMI specification.
574static const int out_hdmi_sample_rates[] = {
575 32000, 44100, 48000, 88200, 96000, 176400, 192000,
576};
577
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700578static const struct string_to_enum out_sample_rates_name_to_enum_table[] = {
Mingming Yin3a941d42016-02-17 18:08:05 -0800579 STRING_TO_ENUM(32000),
580 STRING_TO_ENUM(44100),
581 STRING_TO_ENUM(48000),
582 STRING_TO_ENUM(88200),
583 STRING_TO_ENUM(96000),
584 STRING_TO_ENUM(176400),
585 STRING_TO_ENUM(192000),
Mingshu pange8aedf12019-10-25 15:38:27 +0800586 STRING_TO_ENUM(352800),
587 STRING_TO_ENUM(384000),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700588};
589
Carter Hsu2e429db2019-05-14 18:50:52 +0800590struct in_effect_list {
591 struct listnode list;
592 effect_handle_t handle;
593};
594
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530595static const audio_usecase_t record_usecases[] = {
596 USECASE_AUDIO_RECORD,
597 USECASE_AUDIO_RECORD2,
598 USECASE_AUDIO_RECORD3,
599};
600
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -0700601static struct audio_device *adev = NULL;
Ben Romberger02ab1192018-05-24 12:10:08 -0700602static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
Kiran Kandi910e1862013-10-29 13:29:42 -0700603static unsigned int audio_device_ref_count;
vivek mehtab72d08d2016-04-29 03:16:47 -0700604//cache last MBDRC cal step level
605static int last_known_cal_step = -1 ;
Kiran Kandi910e1862013-10-29 13:29:42 -0700606
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +0530607static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
Arun Mirpuri5d170872019-03-26 13:21:31 -0700608static int out_set_mmap_volume(struct audio_stream_out *stream, float left, float right);
Zhou Song2b8f28f2017-09-11 10:51:38 +0800609static int out_set_voip_volume(struct audio_stream_out *stream, float left, float right);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +0530610static int out_set_pcm_volume(struct audio_stream_out *stream, float left, float right);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +0530611#ifdef SOFT_VOLUME
612static int out_set_soft_volume_params(struct audio_stream_out *stream);
613#endif
Derek Chen6f293672019-04-01 01:40:24 -0700614static void adev_snd_mon_cb(void *cookie, struct str_parms *parms);
615static void in_snd_mon_cb(void * stream, struct str_parms * parms);
616static void out_snd_mon_cb(void * stream, struct str_parms * parms);
617
Zhou Song331c8e52019-08-26 14:16:12 +0800618static int configure_btsco_sample_rate(snd_device_t snd_device);
619
Vatsal Buchac09ae062018-11-14 13:25:08 +0530620#ifdef AUDIO_FEATURE_ENABLED_GCOV
621extern void __gcov_flush();
622static void enable_gcov()
623{
624 __gcov_flush();
625}
626#else
627static void enable_gcov()
628{
629}
630#endif
631
justinweng20fb6d82019-02-21 18:49:00 -0700632static int in_set_microphone_direction(const struct audio_stream_in *stream,
633 audio_microphone_direction_t dir);
634static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom);
635
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530636static bool is_pcm_record_usecase(audio_usecase_t uc_id)
637{
638 unsigned int record_uc_index;
639 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
640
641 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
642 if (uc_id == record_usecases[record_uc_index])
643 return true;
644 }
645 return false;
646}
647
648static audio_usecase_t get_record_usecase(struct audio_device *adev)
649{
650 audio_usecase_t ret_uc = USECASE_INVALID;
651 unsigned int record_uc_index;
652 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
653
654 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
655 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
656 if (!(adev->pcm_record_uc_state & (0x1 << record_uc_index))) {
657 adev->pcm_record_uc_state |= 0x1 << record_uc_index;
658 ret_uc = record_usecases[record_uc_index];
659 break;
660 }
661 }
662
663 ALOGV("%s: pcm record usecase is %d", __func__, ret_uc);
664 return ret_uc;
665}
666
667static void free_record_usecase(struct audio_device *adev,
668 audio_usecase_t uc_id)
669{
670 unsigned int record_uc_index;
671 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
672
673 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
674 if (record_usecases[record_uc_index] == uc_id) {
675 adev->pcm_record_uc_state &= ~(0x1 << record_uc_index);
676 break;
677 }
678 }
679 ALOGV("%s: free pcm record usecase %d", __func__, uc_id);
680}
681
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700682static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id,
683 int flags __unused)
684{
685 int dir = 0;
686 switch (uc_id) {
687 case USECASE_AUDIO_RECORD_LOW_LATENCY:
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530688 case USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY:
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700689 dir = 1;
690 case USECASE_AUDIO_PLAYBACK_ULL:
691 break;
692 default:
693 return false;
694 }
695
696 int dev_id = platform_get_pcm_device_id(uc_id, dir == 0 ?
697 PCM_PLAYBACK : PCM_CAPTURE);
698 if (adev->adm_is_noirq_avail)
699 return adev->adm_is_noirq_avail(adev->adm_data,
700 adev->snd_card, dev_id, dir);
701 return false;
702}
703
704static void register_out_stream(struct stream_out *out)
705{
706 struct audio_device *adev = out->dev;
707 if (is_offload_usecase(out->usecase) ||
708 !adev->adm_register_output_stream)
709 return;
710
711 // register stream first for backward compatibility
712 adev->adm_register_output_stream(adev->adm_data,
713 out->handle,
714 out->flags);
715
716 if (!adev->adm_set_config)
717 return;
718
Kogara Naveen Kumar6db5fb02022-05-07 00:22:50 +0530719 if (out->realtime || (out->flags & AUDIO_OUTPUT_FLAG_SYS_NOTIFICATION))
720 adev->adm_set_config(adev->adm_data,
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700721 out->handle,
722 out->pcm, &out->config);
723}
724
725static void register_in_stream(struct stream_in *in)
726{
727 struct audio_device *adev = in->dev;
728 if (!adev->adm_register_input_stream)
729 return;
730
731 adev->adm_register_input_stream(adev->adm_data,
732 in->capture_handle,
733 in->flags);
734
735 if (!adev->adm_set_config)
736 return;
737
738 if (in->realtime)
739 adev->adm_set_config(adev->adm_data,
740 in->capture_handle,
741 in->pcm,
742 &in->config);
743}
744
745static void request_out_focus(struct stream_out *out, long ns)
746{
747 struct audio_device *adev = out->dev;
748
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700749 if (adev->adm_request_focus_v2)
750 adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
751 else if (adev->adm_request_focus)
752 adev->adm_request_focus(adev->adm_data, out->handle);
753}
754
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700755static int request_in_focus(struct stream_in *in, long ns)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700756{
757 struct audio_device *adev = in->dev;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700758 int ret = 0;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700759
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700760 if (adev->adm_request_focus_v2_1)
761 ret = adev->adm_request_focus_v2_1(adev->adm_data, in->capture_handle, ns);
762 else if (adev->adm_request_focus_v2)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700763 adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
764 else if (adev->adm_request_focus)
765 adev->adm_request_focus(adev->adm_data, in->capture_handle);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700766
767 return ret;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700768}
769
770static void release_out_focus(struct stream_out *out)
771{
772 struct audio_device *adev = out->dev;
773
774 if (adev->adm_abandon_focus)
775 adev->adm_abandon_focus(adev->adm_data, out->handle);
776}
777
778static void release_in_focus(struct stream_in *in)
779{
780 struct audio_device *adev = in->dev;
781 if (adev->adm_abandon_focus)
782 adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
783}
784
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530785static int parse_snd_card_status(struct str_parms *parms, int *card,
786 card_status_t *status)
787{
788 char value[32]={0};
789 char state[32]={0};
790
791 int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
792 if (ret < 0)
793 return -1;
794
795 // sscanf should be okay as value is of max length 32.
796 // same as sizeof state.
797 if (sscanf(value, "%d,%s", card, state) < 2)
798 return -1;
799
800 *status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
801 CARD_STATUS_OFFLINE;
802 return 0;
803}
804
Avinash Chandrad7296d42021-08-04 15:07:47 +0530805bool is_combo_audio_input_device(struct listnode *devices){
806
Sandhya Mutha Naga Venkata153d95e2022-07-12 14:54:43 +0530807 if ((devices == NULL) || (!list_empty(devices)))
Avinash Chandrad7296d42021-08-04 15:07:47 +0530808 return false;
809
810 if(compare_device_type(devices, AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_SPEAKER_MIC2))
811 return true;
812 else
813 return false;
814}
815
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700816static inline void adjust_frames_for_device_delay(struct stream_out *out,
817 uint32_t *dsp_frames) {
818 // Adjustment accounts for A2dp encoder latency with offload usecases
819 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800820 if (is_a2dp_out_device_type(&out->device_list)) {
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700821 unsigned long offset =
822 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
823 *dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
824 }
825}
826
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700827static inline bool free_entry(void *key __unused,
828 void *value, void *context __unused)
829{
830 free(value);
831 return true;
832}
833
834static inline void free_map(Hashmap *map)
835{
836 if (map) {
837 hashmapForEach(map, free_entry, (void *) NULL);
838 hashmapFree(map);
839 }
840}
841
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800842static inline void patch_map_remove_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700843 audio_patch_handle_t patch_handle)
844{
845 if (patch_handle == AUDIO_PATCH_HANDLE_NONE)
846 return;
847
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700848 struct audio_patch_info *p_info =
849 hashmapGet(adev->patch_map, (void *) (intptr_t) patch_handle);
850 if (p_info) {
851 ALOGV("%s: Remove patch %d", __func__, patch_handle);
852 hashmapRemove(adev->patch_map, (void *) (intptr_t) patch_handle);
853 free(p_info->patch);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700854 free(p_info);
855 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700856}
857
858static inline int io_streams_map_insert(struct audio_device *adev,
859 struct audio_stream *stream,
860 audio_io_handle_t handle,
861 audio_patch_handle_t patch_handle)
862{
863 struct audio_stream_info *s_info =
864 (struct audio_stream_info *) calloc(1, sizeof(struct audio_stream_info));
865
866 if (s_info == NULL) {
867 ALOGE("%s: Could not allocate stream info", __func__);
868 return -ENOMEM;
869 }
870 s_info->stream = stream;
871 s_info->patch_handle = patch_handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700872
873 pthread_mutex_lock(&adev->lock);
874 struct audio_stream_info *stream_info =
875 hashmapPut(adev->io_streams_map, (void *) (intptr_t) handle, (void *) s_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700876 if (stream_info != NULL)
877 free(stream_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800878 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700879 ALOGV("%s: Added stream in io_streams_map with handle %d", __func__, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700880 return 0;
881}
882
883static inline void io_streams_map_remove(struct audio_device *adev,
884 audio_io_handle_t handle)
885{
886 pthread_mutex_lock(&adev->lock);
887 struct audio_stream_info *s_info =
888 hashmapRemove(adev->io_streams_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700889 if (s_info == NULL)
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800890 goto done;
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700891 ALOGV("%s: Removed stream with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800892 patch_map_remove_l(adev, s_info->patch_handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700893 free(s_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800894done:
895 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700896 return;
897}
898
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800899static struct audio_patch_info* fetch_patch_info_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700900 audio_patch_handle_t handle)
901{
902 struct audio_patch_info *p_info = NULL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700903 p_info = (struct audio_patch_info *)
904 hashmapGet(adev->patch_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700905 return p_info;
906}
907
vivek mehtaa76401a2015-04-24 14:12:15 -0700908__attribute__ ((visibility ("default")))
909bool audio_hw_send_gain_dep_calibration(int level) {
910 bool ret_val = false;
vivek mehtab72d08d2016-04-29 03:16:47 -0700911 ALOGV("%s: called ...", __func__);
vivek mehtaa76401a2015-04-24 14:12:15 -0700912
913 pthread_mutex_lock(&adev_init_lock);
914
915 if (adev != NULL && adev->platform != NULL) {
916 pthread_mutex_lock(&adev->lock);
917 ret_val = platform_send_gain_dep_cal(adev->platform, level);
vivek mehtab72d08d2016-04-29 03:16:47 -0700918
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +0530919 // cache level info for any of the use case which
920 // was not started.
921 last_known_cal_step = level;;
vivek mehtab72d08d2016-04-29 03:16:47 -0700922
vivek mehtaa76401a2015-04-24 14:12:15 -0700923 pthread_mutex_unlock(&adev->lock);
924 } else {
925 ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
926 }
927
928 pthread_mutex_unlock(&adev_init_lock);
929
930 return ret_val;
931}
932
Ashish Jain5106d362016-05-11 19:23:33 +0530933static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless)
934{
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800935 bool gapless_enabled = false;
936 const char *mixer_ctl_name = "Compress Gapless Playback";
937 struct mixer_ctl *ctl;
938
939 ALOGV("%s:", __func__);
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700940 gapless_enabled = property_get_bool("vendor.audio.offload.gapless.enabled", false);
Ashish Jain5106d362016-05-11 19:23:33 +0530941
942 /*Disable gapless if its AV playback*/
943 gapless_enabled = gapless_enabled && enable_gapless;
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800944
945 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
946 if (!ctl) {
947 ALOGE("%s: Could not get ctl for mixer cmd - %s",
948 __func__, mixer_ctl_name);
949 return -EINVAL;
950 }
951
952 if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) {
953 ALOGE("%s: Could not set gapless mode %d",
954 __func__, gapless_enabled);
955 return -EINVAL;
956 }
957 return 0;
958}
Haynes Mathew George5191a852013-09-11 14:19:36 -0700959
Aniket Kumar Lataf56b6402016-10-27 12:03:18 -0700960__attribute__ ((visibility ("default")))
961int audio_hw_get_gain_level_mapping(struct amp_db_and_gain_table *mapping_tbl,
962 int table_size) {
963 int ret_val = 0;
964 ALOGV("%s: enter ... ", __func__);
965
966 pthread_mutex_lock(&adev_init_lock);
967 if (adev == NULL) {
968 ALOGW("%s: adev is NULL .... ", __func__);
969 goto done;
970 }
971
972 pthread_mutex_lock(&adev->lock);
973 ret_val = platform_get_gain_level_mapping(mapping_tbl, table_size);
974 pthread_mutex_unlock(&adev->lock);
975done:
976 pthread_mutex_unlock(&adev_init_lock);
977 ALOGV("%s: exit ... ", __func__);
978 return ret_val;
979}
980
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800981bool audio_hw_send_qdsp_parameter(int stream_type, float vol, bool active)
Aalique Grahame22e49102018-12-18 14:23:57 -0800982{
983 bool ret = false;
984 ALOGV("%s: enter ...", __func__);
985
986 pthread_mutex_lock(&adev_init_lock);
987
988 if (adev != NULL && adev->platform != NULL) {
989 pthread_mutex_lock(&adev->lock);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800990 ret = audio_extn_qdsp_set_state(adev, stream_type, vol, active);
Aalique Grahame22e49102018-12-18 14:23:57 -0800991 pthread_mutex_unlock(&adev->lock);
992 }
993
994 pthread_mutex_unlock(&adev_init_lock);
995
996 ALOGV("%s: exit with ret %d", __func__, ret);
997 return ret;
998}
Aalique Grahame22e49102018-12-18 14:23:57 -0800999
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001000static bool is_supported_format(audio_format_t format)
1001{
Eric Laurent86e17132013-09-12 17:49:30 -07001002 if (format == AUDIO_FORMAT_MP3 ||
Satish Babu Patakokila0c313922016-12-08 12:07:08 +05301003 format == AUDIO_FORMAT_MP2 ||
Ashish Jainf9b78162014-08-25 20:36:25 +05301004 format == AUDIO_FORMAT_AAC_LC ||
1005 format == AUDIO_FORMAT_AAC_HE_V1 ||
1006 format == AUDIO_FORMAT_AAC_HE_V2 ||
Manish Dewangana6fc5442015-08-24 20:30:31 +05301007 format == AUDIO_FORMAT_AAC_ADTS_LC ||
1008 format == AUDIO_FORMAT_AAC_ADTS_HE_V1 ||
1009 format == AUDIO_FORMAT_AAC_ADTS_HE_V2 ||
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05301010 format == AUDIO_FORMAT_AAC_LATM_LC ||
1011 format == AUDIO_FORMAT_AAC_LATM_HE_V1 ||
1012 format == AUDIO_FORMAT_AAC_LATM_HE_V2 ||
Ashish Jain5106d362016-05-11 19:23:33 +05301013 format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
1014 format == AUDIO_FORMAT_PCM_8_24_BIT ||
Ashish Jainf1eaa582016-05-23 20:54:24 +05301015 format == AUDIO_FORMAT_PCM_FLOAT ||
1016 format == AUDIO_FORMAT_PCM_32_BIT ||
vivek mehta0ea887a2015-08-26 14:01:20 -07001017 format == AUDIO_FORMAT_PCM_16_BIT ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05301018 format == AUDIO_FORMAT_AC3 ||
1019 format == AUDIO_FORMAT_E_AC3 ||
Ben Romberger1aaaf862017-04-06 17:49:46 -07001020 format == AUDIO_FORMAT_DOLBY_TRUEHD ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05301021 format == AUDIO_FORMAT_DTS ||
1022 format == AUDIO_FORMAT_DTS_HD ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08001023 format == AUDIO_FORMAT_FLAC ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05301024 format == AUDIO_FORMAT_ALAC ||
1025 format == AUDIO_FORMAT_APE ||
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05301026 format == AUDIO_FORMAT_DSD ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05301027 format == AUDIO_FORMAT_VORBIS ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08001028 format == AUDIO_FORMAT_WMA ||
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05301029 format == AUDIO_FORMAT_WMA_PRO ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07001030 format == AUDIO_FORMAT_APTX ||
1031 format == AUDIO_FORMAT_IEC61937)
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08001032 return true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001033
1034 return false;
1035}
1036
Kunlei Zhang67cc7072020-12-18 17:16:49 +08001037static bool is_supported_conc_usecase_for_power_mode_call(struct audio_device *adev)
1038{
1039 struct listnode *node;
1040 struct audio_usecase *usecase;
1041
1042 list_for_each(node, &adev->usecase_list) {
1043 usecase = node_to_item(node, struct audio_usecase, list);
1044 if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1045 ALOGD("%s: FM usecase is active, not setting power mode", __func__);
1046 return false;
1047 }
1048 }
1049
1050 return true;
1051}
Haynes Mathew George5beddd42016-06-27 18:33:40 -07001052static inline bool is_mmap_usecase(audio_usecase_t uc_id)
1053{
1054 return (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY) ||
Zhou Song62ea0282020-03-22 19:53:01 +08001055 (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY2) ||
Haynes Mathew George5beddd42016-06-27 18:33:40 -07001056 (uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
1057}
1058
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07001059static inline bool is_valid_volume(float left, float right)
1060{
1061 return ((left >= 0.0f && right >= 0.0f) ? true : false);
1062}
1063
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301064static void enable_asrc_mode(struct audio_device *adev)
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301065{
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301066 ALOGV("%s", __func__);
1067 audio_route_apply_and_update_path(adev->audio_route,
1068 "asrc-mode");
1069 adev->asrc_mode_enabled = true;
1070}
1071
1072static void disable_asrc_mode(struct audio_device *adev)
1073{
1074 ALOGV("%s", __func__);
1075 audio_route_reset_and_update_path(adev->audio_route,
1076 "asrc-mode");
1077 adev->asrc_mode_enabled = false;
1078}
1079
Saurav Kumarc1411662020-10-14 10:50:45 +05301080static void check_and_configure_headphone(struct audio_device *adev,
1081 struct audio_usecase *uc_info,
1082 snd_device_t snd_device)
1083{
1084 struct listnode *node;
1085 struct audio_usecase *usecase;
1086 int new_backend_idx, usecase_backend_idx;
1087 bool spkr_hph_single_be_native_concurrency;
1088
1089 new_backend_idx = platform_get_backend_index(snd_device);
1090 spkr_hph_single_be_native_concurrency = platform_get_spkr_hph_single_be_native_concurrency_flag();
Zhou Songd4b18c42021-01-14 15:15:29 +08001091 if ((spkr_hph_single_be_native_concurrency && (new_backend_idx == DEFAULT_CODEC_BACKEND)) ||
1092 uc_info->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
Saurav Kumarc1411662020-10-14 10:50:45 +05301093 list_for_each(node, &adev->usecase_list) {
1094 usecase = node_to_item(node, struct audio_usecase, list);
1095 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info)) {
1096 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1097 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1098 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1099 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1100 disable_audio_route(adev, usecase);
1101 disable_snd_device(adev, usecase->out_snd_device);
1102 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
Saurav Kumar70902382020-10-28 11:16:04 +05301103 platform_check_and_set_codec_backend_cfg(adev, usecase,
1104 usecase->out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05301105 enable_snd_device(adev, usecase->out_snd_device);
Zhou Songd4b18c42021-01-14 15:15:29 +08001106 enable_audio_route(adev, usecase);
Saurav Kumarc1411662020-10-14 10:50:45 +05301107 }
1108 }
Revathi Uddaraju2c0eac02021-07-27 02:06:42 -07001109 else if ((usecase->type != PCM_CAPTURE) && (usecase == uc_info)) {
1110 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1111 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1112 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1113 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1114 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
1115 platform_check_and_set_codec_backend_cfg(adev, usecase,
1116 usecase->out_snd_device);
1117 }
1118 }
Saurav Kumarc1411662020-10-14 10:50:45 +05301119 }
1120 }
1121}
1122
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301123/*
1124 * - Enable ASRC mode for incoming mix path use case(Headphone backend)if Headphone
1125 * 44.1 or Native DSD backends are enabled for any of current use case.
1126 * e.g. 48-> + (Naitve DSD or Headphone 44.1)
1127 * - Disable current mix path use case(Headphone backend) and re-enable it with
1128 * ASRC mode for incoming Headphone 44.1 or Native DSD use case.
1129 * e.g. Naitve DSD or Headphone 44.1 -> + 48
1130 */
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301131static void check_and_set_asrc_mode(struct audio_device *adev,
1132 struct audio_usecase *uc_info,
1133 snd_device_t snd_device)
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301134{
1135 ALOGV("%s snd device %d", __func__, snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301136 int i, num_new_devices = 0;
1137 snd_device_t split_new_snd_devices[SND_DEVICE_OUT_END];
1138 /*
1139 *Split snd device for new combo use case
1140 *e.g. Headphopne 44.1-> + Ringtone (Headphone + Speaker)
1141 */
1142 if (platform_split_snd_device(adev->platform,
1143 snd_device,
1144 &num_new_devices,
1145 split_new_snd_devices) == 0) {
1146 for (i = 0; i < num_new_devices; i++)
1147 check_and_set_asrc_mode(adev, uc_info, split_new_snd_devices[i]);
1148 } else {
1149 int new_backend_idx = platform_get_backend_index(snd_device);
1150 if (((new_backend_idx == HEADPHONE_BACKEND) ||
1151 (new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1152 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1153 !adev->asrc_mode_enabled) {
1154 struct listnode *node = NULL;
1155 struct audio_usecase *uc = NULL;
1156 struct stream_out *curr_out = NULL;
1157 int usecase_backend_idx = DEFAULT_CODEC_BACKEND;
1158 int i, num_devices, ret = 0;
1159 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301160
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301161 list_for_each(node, &adev->usecase_list) {
1162 uc = node_to_item(node, struct audio_usecase, list);
1163 curr_out = (struct stream_out*) uc->stream.out;
1164 if (curr_out && PCM_PLAYBACK == uc->type && uc != uc_info) {
1165 /*
1166 *Split snd device for existing combo use case
1167 *e.g. Ringtone (Headphone + Speaker) + Headphopne 44.1
1168 */
1169 ret = platform_split_snd_device(adev->platform,
1170 uc->out_snd_device,
1171 &num_devices,
1172 split_snd_devices);
1173 if (ret < 0 || num_devices == 0) {
1174 ALOGV("%s: Unable to split uc->out_snd_device: %d",__func__, uc->out_snd_device);
1175 split_snd_devices[0] = uc->out_snd_device;
1176 num_devices = 1;
Garmond Leung50058f62017-02-08 09:49:30 -08001177 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301178 for (i = 0; i < num_devices; i++) {
1179 usecase_backend_idx = platform_get_backend_index(split_snd_devices[i]);
1180 ALOGD("%s:snd_dev %d usecase_backend_idx %d",__func__, split_snd_devices[i],usecase_backend_idx);
1181 if((new_backend_idx == HEADPHONE_BACKEND) &&
1182 ((usecase_backend_idx == HEADPHONE_44_1_BACKEND) ||
1183 (usecase_backend_idx == DSD_NATIVE_BACKEND))) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001184 ALOGV("%s:DSD or native stream detected enabling asrcmode in hardware",
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301185 __func__);
1186 enable_asrc_mode(adev);
1187 break;
1188 } else if(((new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1189 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1190 (usecase_backend_idx == HEADPHONE_BACKEND)) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001191 ALOGV("%s: 48K stream detected, disabling and enabling it \
1192 with asrcmode in hardware", __func__);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301193 disable_audio_route(adev, uc);
1194 disable_snd_device(adev, uc->out_snd_device);
1195 // Apply true-high-quality-mode if DSD or > 44.1KHz or >=24-bit
1196 if (new_backend_idx == DSD_NATIVE_BACKEND)
1197 audio_route_apply_and_update_path(adev->audio_route,
1198 "hph-true-highquality-mode");
1199 else if ((new_backend_idx == HEADPHONE_44_1_BACKEND) &&
1200 (curr_out->bit_width >= 24))
1201 audio_route_apply_and_update_path(adev->audio_route,
1202 "hph-highquality-mode");
1203 enable_asrc_mode(adev);
1204 enable_snd_device(adev, uc->out_snd_device);
1205 enable_audio_route(adev, uc);
1206 break;
1207 }
1208 }
1209 // reset split devices count
1210 num_devices = 0;
Garmond Leung50058f62017-02-08 09:49:30 -08001211 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301212 if (adev->asrc_mode_enabled)
1213 break;
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301214 }
1215 }
1216 }
1217}
1218
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001219static int send_effect_enable_disable_mixer_ctl(struct audio_device *adev,
1220 struct audio_effect_config effect_config,
1221 unsigned int param_value)
1222{
1223 char mixer_ctl_name[] = "Audio Effect";
1224 struct mixer_ctl *ctl;
1225 long set_values[6];
Eric Laurent637e2d42018-11-15 12:24:31 -08001226 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001227
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001228 if (in == NULL) {
1229 ALOGE("%s: active input stream is NULL", __func__);
1230 return -EINVAL;
1231 }
1232
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001233 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
1234 if (!ctl) {
1235 ALOGE("%s: Could not get mixer ctl - %s",
1236 __func__, mixer_ctl_name);
1237 return -EINVAL;
1238 }
1239
1240 set_values[0] = 1; //0:Rx 1:Tx
1241 set_values[1] = in->app_type_cfg.app_type;
1242 set_values[2] = (long)effect_config.module_id;
1243 set_values[3] = (long)effect_config.instance_id;
1244 set_values[4] = (long)effect_config.param_id;
1245 set_values[5] = param_value;
1246
1247 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
1248
1249 return 0;
1250
1251}
1252
1253static int update_effect_param_ecns(struct audio_device *adev, unsigned int module_id,
1254 int effect_type, unsigned int *param_value)
1255{
1256 int ret = 0;
1257 struct audio_effect_config other_effect_config;
1258 struct audio_usecase *usecase = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08001259 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001260
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001261 if (in == NULL) {
1262 ALOGE("%s: active input stream is NULL", __func__);
1263 return -EINVAL;
1264 }
1265
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001266 usecase = get_usecase_from_list(adev, in->usecase);
1267 if (!usecase)
1268 return -EINVAL;
1269
1270 ret = platform_get_effect_config_data(usecase->in_snd_device, &other_effect_config,
1271 effect_type == EFFECT_AEC ? EFFECT_NS : EFFECT_AEC);
1272 if (ret < 0) {
1273 ALOGE("%s Failed to get effect params %d", __func__, ret);
1274 return ret;
1275 }
1276
1277 if (module_id == other_effect_config.module_id) {
1278 //Same module id for AEC/NS. Values need to be combined
1279 if (((effect_type == EFFECT_AEC) && (in->enable_ns)) ||
1280 ((effect_type == EFFECT_NS) && (in->enable_aec))) {
1281 *param_value |= other_effect_config.param_value;
1282 }
1283 }
1284
1285 return ret;
1286}
1287
1288static int enable_disable_effect(struct audio_device *adev, int effect_type, bool enable)
Gangadhar Sb0210342019-02-22 17:39:41 +05301289{
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001290 struct audio_effect_config effect_config;
1291 struct audio_usecase *usecase = NULL;
1292 int ret = 0;
1293 unsigned int param_value = 0;
Eric Laurent637e2d42018-11-15 12:24:31 -08001294 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001295
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001296 if(!voice_extn_is_dynamic_ecns_enabled())
1297 return ENOSYS;
1298
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001299 if (!in) {
1300 ALOGE("%s: Invalid input stream", __func__);
1301 return -EINVAL;
1302 }
1303
1304 ALOGD("%s: effect_type:%d enable:%d", __func__, effect_type, enable);
1305
1306 usecase = get_usecase_from_list(adev, in->usecase);
Weiyin Jiang20d3fa62018-08-01 18:06:27 +08001307 if (usecase == NULL) {
1308 ALOGE("%s: Could not find the usecase (%d) in the list",
1309 __func__, in->usecase);
1310 return -EINVAL;
1311 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001312
1313 ret = platform_get_effect_config_data(usecase->in_snd_device, &effect_config, effect_type);
1314 if (ret < 0) {
1315 ALOGE("%s Failed to get module id %d", __func__, ret);
1316 return ret;
1317 }
1318 ALOGV("%s: %d %d usecase->id:%d usecase->in_snd_device:%d", __func__, effect_config.module_id,
1319 in->app_type_cfg.app_type, usecase->id, usecase->in_snd_device);
1320
1321 if(enable)
1322 param_value = effect_config.param_value;
1323
1324 /*Special handling for AEC & NS effects Param values need to be
1325 updated if module ids are same*/
1326
1327 if ((effect_type == EFFECT_AEC) || (effect_type == EFFECT_NS)) {
1328 ret = update_effect_param_ecns(adev, effect_config.module_id, effect_type, &param_value);
1329 if (ret < 0)
1330 return ret;
1331 }
1332
1333 ret = send_effect_enable_disable_mixer_ctl(adev, effect_config, param_value);
1334
1335 return ret;
1336}
1337
1338static void check_and_enable_effect(struct audio_device *adev)
1339{
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001340 if(!voice_extn_is_dynamic_ecns_enabled())
1341 return;
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001342
Eric Laurent637e2d42018-11-15 12:24:31 -08001343 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001344
Eric Laurent637e2d42018-11-15 12:24:31 -08001345 if (in != NULL && !in->standby) {
1346 if (in->enable_aec)
1347 enable_disable_effect(adev, EFFECT_AEC, true);
1348
1349 if (in->enable_ns &&
1350 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
1351 enable_disable_effect(adev, EFFECT_NS, true);
1352 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001353 }
1354}
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001355
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07001356int pcm_ioctl(struct pcm *pcm, int request, ...)
1357{
1358 va_list ap;
1359 void * arg;
1360 int pcm_fd = *(int*)pcm;
1361
1362 va_start(ap, request);
1363 arg = va_arg(ap, void *);
1364 va_end(ap);
1365
1366 return ioctl(pcm_fd, request, arg);
1367}
1368
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001369int enable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001370 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001371{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001372 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001373 char mixer_path[MIXER_PATH_MAX_LENGTH];
Manish Dewangan58229382017-02-02 15:48:41 +05301374 struct stream_out *out = NULL;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301375 struct stream_in *in = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001376 struct listnode out_devices;
Soumya Managoli6993b762018-06-28 16:04:57 +05301377 int ret = 0;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001378
1379 if (usecase == NULL)
1380 return -EINVAL;
1381
1382 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
1383
Carter Hsu2e429db2019-05-14 18:50:52 +08001384 if (usecase->type == PCM_CAPTURE) {
1385 struct stream_in *in = usecase->stream.in;
1386 struct audio_usecase *uinfo;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001387 snd_device = usecase->in_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001388
1389 if (in) {
1390 if (in->enable_aec || in->enable_ec_port) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001391 list_init(&out_devices);
1392 update_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "", true);
Carter Hsu2e429db2019-05-14 18:50:52 +08001393 struct listnode *node;
1394 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
1395 USECASE_AUDIO_PLAYBACK_VOIP);
1396 if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001397 assign_devices(&out_devices,
1398 &voip_usecase->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001399 } else if (adev->primary_output &&
1400 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001401 assign_devices(&out_devices,
1402 &adev->primary_output->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001403 } else {
1404 list_for_each(node, &adev->usecase_list) {
1405 uinfo = node_to_item(node, struct audio_usecase, list);
1406 if (uinfo->type != PCM_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001407 assign_devices(&out_devices,
1408 &uinfo->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001409 break;
1410 }
1411 }
1412 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001413
1414 platform_set_echo_reference(adev, true, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001415 in->ec_opened = true;
Zhenlin Lian4f947842022-05-14 15:50:52 +05301416 clear_devices(&out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001417 }
1418 }
Guodong Huf5e614d2019-06-24 18:42:03 +08001419 } else if ((usecase->type == TRANSCODE_LOOPBACK_TX) || ((usecase->type == PCM_HFP_CALL) &&
1420 ((usecase->id == USECASE_AUDIO_HFP_SCO) || (usecase->id == USECASE_AUDIO_HFP_SCO_WB)) &&
1421 (usecase->in_snd_device == SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS))) {
Carter Hsu2e429db2019-05-14 18:50:52 +08001422 snd_device = usecase->in_snd_device;
1423 } else {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001424 snd_device = usecase->out_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001425 }
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001426
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001427 if (usecase->type == PCM_CAPTURE) {
1428 if (platform_get_fluence_nn_state(adev->platform) == 0) {
1429 platform_set_fluence_nn_state(adev->platform, true);
1430 ALOGD("%s: set fluence nn capture state", __func__);
1431 }
1432 }
1433
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08001434#ifdef DS1_DOLBY_DAP_ENABLED
1435 audio_extn_dolby_set_dmid(adev);
1436 audio_extn_dolby_set_endpoint(adev);
1437#endif
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -07001438 audio_extn_dolby_ds2_set_endpoint(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001439 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301440 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
Ben Romberger1fafdde2015-09-09 19:43:15 -07001441 audio_extn_utils_send_app_type_cfg(adev, usecase);
Jasmine Cha4dcc1092019-03-04 18:12:47 +08001442 if (audio_extn_is_maxx_audio_enabled())
1443 audio_extn_ma_set_device(usecase);
Dhananjay Kumar14170dd2015-08-28 13:24:16 +05301444 audio_extn_utils_send_audio_calibration(adev, usecase);
Zhou Songbaddf9f2020-11-20 13:57:39 +08001445 if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
1446 out = usecase->stream.out;
1447 if (out && out->compr)
Manish Dewangan58229382017-02-02 15:48:41 +05301448 audio_extn_utils_compress_set_clk_rec_mode(usecase);
1449 }
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301450
1451 if (usecase->type == PCM_CAPTURE) {
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001452 if (platform_get_fluence_nn_state(adev->platform) == 1 &&
1453 adev->fluence_nn_usecase_id == USECASE_INVALID ) {
1454 adev->fluence_nn_usecase_id = usecase->id;
1455 ALOGD("%s: assign fluence nn usecase %d", __func__, usecase->id);
1456 }
1457 }
1458
1459 if (usecase->type == PCM_CAPTURE) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301460 in = usecase->stream.in;
Avinash Chandrad7296d42021-08-04 15:07:47 +05301461 if ((in && is_loopback_input_device(get_device_types(&in->device_list))) ||
1462 (in && is_combo_audio_input_device(&in->device_list)) ||
1463 (in && ((compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
1464 compare_device_type(&in->device_list, AUDIO_DEVICE_IN_LINE)) &&
1465 (snd_device == SND_DEVICE_IN_HANDSET_GENERIC_6MIC)))) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301466 ALOGD("%s: set custom mtmx params v1", __func__);
1467 audio_extn_set_custom_mtmx_params_v1(adev, usecase, true);
1468 }
1469 } else {
1470 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
1471 }
Manish Dewangan58229382017-02-02 15:48:41 +05301472
Andy Hung756ecc12018-10-19 17:47:12 -07001473 // we shouldn't truncate mixer_path
1474 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1475 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1476 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001477 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001478 ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
Soumya Managoli6993b762018-06-28 16:04:57 +05301479 ret = audio_route_apply_and_update_path(adev->audio_route, mixer_path);
1480 if (!ret && usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1481 struct str_parms *parms = str_parms_create_str("fm_restore_volume=1");
1482 if (parms) {
1483 audio_extn_fm_set_parameters(adev, parms);
1484 str_parms_destroy(parms);
1485 }
1486 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001487 ALOGV("%s: exit", __func__);
1488 return 0;
1489}
1490
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001491int disable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001492 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001493{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001494 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001495 char mixer_path[MIXER_PATH_MAX_LENGTH];
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301496 struct stream_in *in = NULL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001497
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05301498 if (usecase == NULL || usecase->id == USECASE_INVALID)
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001499 return -EINVAL;
1500
1501 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
Surendar Karka93cd25a2018-08-28 14:21:37 +05301502 if (usecase->type == PCM_CAPTURE || usecase->type == TRANSCODE_LOOPBACK_TX)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001503 snd_device = usecase->in_snd_device;
1504 else
1505 snd_device = usecase->out_snd_device;
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001506
1507 /* disable island and power mode on supported device for voice call */
1508 if (usecase->type == VOICE_CALL) {
1509 if (usecase->in_snd_device != SND_DEVICE_NONE) {
1510 if (platform_get_island_cfg_on_device(adev->platform, usecase->in_snd_device) &&
1511 platform_get_power_mode_on_device(adev->platform, usecase->in_snd_device)) {
1512 platform_set_island_cfg_on_device(adev, usecase->in_snd_device, false);
1513 platform_set_power_mode_on_device(adev, usecase->in_snd_device, false);
1514 platform_reset_island_power_status(adev->platform, usecase->in_snd_device);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001515 if (voice_is_lte_call_active(adev))
1516 platform_set_tx_lpi_mode(adev->platform, false);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001517 ALOGD("%s: disable island cfg and power mode in voice tx path",
1518 __func__);
1519 }
1520 }
1521 if (usecase->out_snd_device != SND_DEVICE_NONE) {
1522 if (platform_get_island_cfg_on_device(adev->platform, usecase->out_snd_device) &&
1523 platform_get_power_mode_on_device(adev->platform, usecase->out_snd_device)) {
1524 platform_set_island_cfg_on_device(adev, usecase->out_snd_device, false);
1525 platform_set_power_mode_on_device(adev, usecase->out_snd_device, false);
1526 platform_reset_island_power_status(adev->platform, usecase->out_snd_device);
1527 ALOGD("%s: disable island cfg and power mode in voice rx path",
1528 __func__);
1529 }
1530 }
1531 }
1532
Andy Hung756ecc12018-10-19 17:47:12 -07001533 // we shouldn't truncate mixer_path
1534 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1535 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1536 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001537 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001538 ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001539 audio_route_reset_and_update_path(adev->audio_route, mixer_path);
Carter Hsu2e429db2019-05-14 18:50:52 +08001540 if (usecase->type == PCM_CAPTURE) {
1541 struct stream_in *in = usecase->stream.in;
1542 if (in && in->ec_opened) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001543 struct listnode out_devices;
1544 list_init(&out_devices);
1545 platform_set_echo_reference(in->dev, false, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001546 in->ec_opened = false;
Zhenlin Lian4f947842022-05-14 15:50:52 +05301547 clear_devices(&out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001548 }
1549 }
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001550 if (usecase->id == adev->fluence_nn_usecase_id) {
1551 platform_set_fluence_nn_state(adev->platform, false);
1552 adev->fluence_nn_usecase_id = USECASE_INVALID;
1553 ALOGD("%s: reset fluence nn capture state", __func__);
1554 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001555 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301556 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301557
1558 if (usecase->type == PCM_CAPTURE) {
1559 in = usecase->stream.in;
Avinash Chandrad7296d42021-08-04 15:07:47 +05301560 if ((in && is_loopback_input_device(get_device_types(&in->device_list))) ||
1561 (in && is_combo_audio_input_device(&in->device_list)) ||
1562 (in && ((compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
1563 compare_device_type(&in->device_list, AUDIO_DEVICE_IN_LINE)) &&
1564 (snd_device == SND_DEVICE_IN_HANDSET_GENERIC_6MIC)))){
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301565 ALOGD("%s: reset custom mtmx params v1", __func__);
1566 audio_extn_set_custom_mtmx_params_v1(adev, usecase, false);
1567 }
1568 } else {
1569 audio_extn_set_custom_mtmx_params_v2(adev, usecase, false);
1570 }
1571
Weiyin Jiang298ffd92019-06-03 14:29:30 +08001572 if ((usecase->type == PCM_PLAYBACK) &&
1573 (usecase->stream.out != NULL))
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05301574 usecase->stream.out->pspd_coeff_sent = false;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301575
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001576 ALOGV("%s: exit", __func__);
1577 return 0;
1578}
1579
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001580int enable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001581 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001582{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301583 int i, num_devices = 0;
1584 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001585 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1586
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001587 if (snd_device < SND_DEVICE_MIN ||
1588 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001589 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001590 return -EINVAL;
1591 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001592
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001593 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001594 ALOGE("%s: Invalid sound device returned", __func__);
1595 return -EINVAL;
1596 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001597
1598 adev->snd_dev_ref_cnt[snd_device]++;
1599
1600 if ((adev->snd_dev_ref_cnt[snd_device] > 1) &&
1601 (platform_split_snd_device(adev->platform,
1602 snd_device,
1603 &num_devices,
1604 new_snd_devices) != 0)) {
Eric Laurent994a6932013-07-17 11:51:42 -07001605 ALOGV("%s: snd_device(%d: %s) is already active",
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001606 __func__, snd_device, device_name);
Aniket Kumar Lata990de552019-07-11 14:20:23 -07001607 /* Set backend config for A2DP to ensure slimbus configuration
1608 is correct if A2DP is already active and backend is closed
1609 and re-opened */
1610 if (snd_device == SND_DEVICE_OUT_BT_A2DP)
1611 audio_extn_a2dp_set_source_backend_cfg();
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001612 return 0;
1613 }
1614
Gopikrishnaiah Anandane85d0462014-06-30 21:41:20 -07001615 if (audio_extn_spkr_prot_is_enabled())
1616 audio_extn_spkr_prot_calib_cancel(adev);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001617
Aalique Grahame22e49102018-12-18 14:23:57 -08001618 audio_extn_dsm_feedback_enable(adev, snd_device, true);
1619
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001620 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1621 audio_extn_spkr_prot_is_enabled()) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001622 if (platform_get_spkr_prot_acdb_id(snd_device) < 0) {
1623 goto err;
1624 }
1625 audio_extn_dev_arbi_acquire(snd_device);
1626 if (audio_extn_spkr_prot_start_processing(snd_device)) {
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001627 ALOGE("%s: spkr_start_processing failed", __func__);
Ravit Dennisaaee49c2015-02-04 21:26:22 +02001628 audio_extn_dev_arbi_release(snd_device);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001629 goto err;
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001630 }
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001631 } else if (platform_split_snd_device(adev->platform,
1632 snd_device,
1633 &num_devices,
1634 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301635 for (i = 0; i < num_devices; i++) {
1636 enable_snd_device(adev, new_snd_devices[i]);
1637 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001638 platform_set_speaker_gain_in_combo(adev, snd_device, true);
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001639 } else {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001640 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301641
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001642 /* enable island and power mode on supported device */
1643 if (platform_get_island_cfg_on_device(adev->platform, snd_device) &&
1644 platform_get_power_mode_on_device(adev->platform, snd_device)) {
1645 platform_set_island_cfg_on_device(adev, snd_device, true);
1646 platform_set_power_mode_on_device(adev, snd_device, true);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001647 if (voice_is_lte_call_active(adev) &&
1648 (snd_device >= SND_DEVICE_IN_BEGIN &&
1649 snd_device < SND_DEVICE_IN_END))
1650 platform_set_tx_lpi_mode(adev->platform, true);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001651 ALOGD("%s: enable island cfg and power mode on: %s",
1652 __func__, device_name);
1653 }
Preetam Singh Ranawatf1d417c2017-01-10 17:00:32 +05301654
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301655 if (SND_DEVICE_OUT_BT_A2DP == snd_device) {
Ramjee Singh2d2944a2021-12-14 14:13:41 +05301656
1657 struct audio_usecase *usecase;
1658 struct listnode *node;
1659 /* Disable SCO Devices and enable handset mic for active input stream */
1660 list_for_each(node, &adev->usecase_list) {
1661 usecase = node_to_item(node, struct audio_usecase, list);
1662 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
1663 is_sco_in_device_type(&usecase->stream.in->device_list)) {
1664 ALOGD("a2dp resumed, switch bt sco mic to handset mic");
1665 reassign_device_list(&usecase->stream.in->device_list,
1666 AUDIO_DEVICE_IN_BUILTIN_MIC, "");
1667 select_devices(adev, usecase->id);
1668 }
1669 }
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301670 if (audio_extn_a2dp_start_playback() < 0) {
1671 ALOGE(" fail to configure A2dp Source control path ");
1672 goto err;
1673 } else {
1674 adev->a2dp_started = true;
1675 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001676 }
Florian Pfister1a84f312018-07-19 14:38:18 +02001677
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001678 if ((SND_DEVICE_IN_BT_A2DP == snd_device) &&
1679 (audio_extn_a2dp_start_capture() < 0)) {
1680 ALOGE(" fail to configure A2dp Sink control path ");
1681 goto err;
1682 }
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301683
Mingshu Pang7be5b1d2020-03-04 15:24:38 +08001684 if ((SND_DEVICE_OUT_BT_SCO_SWB == snd_device) ||
1685 (SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC == snd_device) ||
1686 (SND_DEVICE_IN_BT_SCO_MIC_SWB == snd_device)) {
1687 if (!adev->bt_sco_on || (audio_extn_sco_start_configuration() < 0)) {
1688 ALOGE(" fail to configure sco control path ");
1689 goto err;
1690 }
Zhou Song12c29502019-03-16 10:37:18 +08001691 }
1692
Zhou Song331c8e52019-08-26 14:16:12 +08001693 configure_btsco_sample_rate(snd_device);
Bharath Ramachandramurthy0de16782014-03-28 21:34:33 -07001694 /* due to the possibility of calibration overwrite between listen
1695 and audio, notify listen hal before audio calibration is sent */
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001696 audio_extn_sound_trigger_update_device_status(snd_device,
1697 ST_EVENT_SND_DEVICE_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301698 audio_extn_listen_update_device_status(snd_device,
1699 LISTEN_EVENT_SND_DEVICE_BUSY);
Subhash Chandra Bose Naripeddy54274672014-03-10 14:51:02 -07001700 if (platform_get_snd_device_acdb_id(snd_device) < 0) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001701 audio_extn_sound_trigger_update_device_status(snd_device,
1702 ST_EVENT_SND_DEVICE_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301703 audio_extn_listen_update_device_status(snd_device,
1704 LISTEN_EVENT_SND_DEVICE_FREE);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001705 goto err;
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001706 }
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001707 audio_extn_dev_arbi_acquire(snd_device);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001708 audio_route_apply_and_update_path(adev->audio_route, device_name);
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301709
1710 if (SND_DEVICE_OUT_HEADPHONES == snd_device &&
1711 !adev->native_playback_enabled &&
1712 audio_is_true_native_stream_active(adev)) {
1713 ALOGD("%s: %d: napb: enabling native mode in hardware",
1714 __func__, __LINE__);
1715 audio_route_apply_and_update_path(adev->audio_route,
1716 "true-native-mode");
1717 adev->native_playback_enabled = true;
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301718 }
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +05301719 if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
1720 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001721 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001722 ALOGD("%s: init ec ref loopback", __func__);
1723 audio_extn_ffv_init_ec_ref_loopback(adev, snd_device);
1724 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001725 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001726 return 0;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001727err:
1728 adev->snd_dev_ref_cnt[snd_device]--;
1729 return -EINVAL;;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001730}
1731
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001732int disable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001733 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001734{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301735 int i, num_devices = 0;
1736 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001737 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1738
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001739 if (snd_device < SND_DEVICE_MIN ||
1740 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001741 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001742 return -EINVAL;
1743 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001744
1745 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
1746 ALOGE("%s: Invalid sound device returned", __func__);
1747 return -EINVAL;
1748 }
1749
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001750 if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
1751 ALOGE("%s: device ref cnt is already 0", __func__);
1752 return -EINVAL;
1753 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001754
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001755 adev->snd_dev_ref_cnt[snd_device]--;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001756
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001757
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001758 if (adev->snd_dev_ref_cnt[snd_device] == 0) {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001759 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301760
Aalique Grahame22e49102018-12-18 14:23:57 -08001761 audio_extn_dsm_feedback_enable(adev, snd_device, false);
1762
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001763 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1764 audio_extn_spkr_prot_is_enabled()) {
Anish Kumar46c7b872014-09-09 01:49:44 -07001765 audio_extn_spkr_prot_stop_processing(snd_device);
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07001766
1767 // when speaker device is disabled, reset swap.
1768 // will be renabled on usecase start
1769 platform_set_swap_channels(adev, false);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001770 } else if (platform_split_snd_device(adev->platform,
1771 snd_device,
1772 &num_devices,
1773 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301774 for (i = 0; i < num_devices; i++) {
1775 disable_snd_device(adev, new_snd_devices[i]);
1776 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001777 platform_set_speaker_gain_in_combo(adev, snd_device, false);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001778 } else {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001779 audio_route_reset_and_update_path(adev->audio_route, device_name);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001780 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001781
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301782 if (snd_device == SND_DEVICE_OUT_BT_A2DP) {
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301783 audio_extn_a2dp_stop_playback();
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301784 adev->a2dp_started = false;
1785 } else if (snd_device == SND_DEVICE_IN_BT_A2DP)
Florian Pfister1a84f312018-07-19 14:38:18 +02001786 audio_extn_a2dp_stop_capture();
Zhou Songd6d71752019-05-21 18:08:51 +08001787 else if ((snd_device == SND_DEVICE_OUT_HDMI) ||
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001788 (snd_device == SND_DEVICE_OUT_DISPLAY_PORT))
Ashish Jain81eb2a82015-05-13 10:52:34 +05301789 adev->is_channel_status_set = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001790 else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301791 adev->native_playback_enabled) {
1792 ALOGD("%s: %d: napb: disabling native mode in hardware",
1793 __func__, __LINE__);
1794 audio_route_reset_and_update_path(adev->audio_route,
1795 "true-native-mode");
1796 adev->native_playback_enabled = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001797 } else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301798 adev->asrc_mode_enabled) {
1799 ALOGD("%s: %d: disabling asrc mode in hardware", __func__, __LINE__);
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301800 disable_asrc_mode(adev);
1801 audio_route_apply_and_update_path(adev->audio_route, "hph-lowpower-mode");
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001802 } else if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
Dhanalakshmi Siddaniaf4bd622019-02-27 16:28:06 +05301803 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001804 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001805 ALOGD("%s: deinit ec ref loopback", __func__);
1806 audio_extn_ffv_deinit_ec_ref_loopback(adev, snd_device);
1807 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001808
1809 audio_extn_utils_release_snd_device(snd_device);
1810 } else {
1811 if (platform_split_snd_device(adev->platform,
1812 snd_device,
1813 &num_devices,
1814 new_snd_devices) == 0) {
1815 for (i = 0; i < num_devices; i++) {
1816 adev->snd_dev_ref_cnt[new_snd_devices[i]]--;
1817 }
1818 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001819 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001820
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001821 return 0;
1822}
1823
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001824/*
1825 legend:
1826 uc - existing usecase
1827 new_uc - new usecase
1828 d1, d11, d2 - SND_DEVICE enums
1829 a1, a2 - corresponding ANDROID device enums
1830 B1, B2 - backend strings
1831
1832case 1
1833 uc->dev d1 (a1) B1
1834 new_uc->dev d1 (a1), d2 (a2) B1, B2
1835
1836 resolution: disable and enable uc->dev on d1
1837
1838case 2
1839 uc->dev d1 (a1) B1
1840 new_uc->dev d11 (a1) B1
1841
1842 resolution: need to switch uc since d1 and d11 are related
1843 (e.g. speaker and voice-speaker)
1844 use ANDROID_DEVICE_OUT enums to match devices since SND_DEVICE enums may vary
1845
1846case 3
1847 uc->dev d1 (a1) B1
1848 new_uc->dev d2 (a2) B2
1849
1850 resolution: no need to switch uc
1851
1852case 4
1853 uc->dev d1 (a1) B1
1854 new_uc->dev d2 (a2) B1
1855
1856 resolution: disable enable uc-dev on d2 since backends match
1857 we cannot enable two streams on two different devices if they
1858 share the same backend. e.g. if offload is on speaker device using
1859 QUAD_MI2S backend and a low-latency stream is started on voice-handset
1860 using the same backend, offload must also be switched to voice-handset.
1861
1862case 5
1863 uc->dev d1 (a1) B1
1864 new_uc->dev d1 (a1), d2 (a2) B1
1865
1866 resolution: disable enable uc-dev on d2 since backends match
1867 we cannot enable two streams on two different devices if they
1868 share the same backend.
1869
1870case 6
1871 uc->dev d1 (a1) B1
1872 new_uc->dev d2 (a1) B2
1873
1874 resolution: no need to switch
1875
1876case 7
1877 uc->dev d1 (a1), d2 (a2) B1, B2
1878 new_uc->dev d1 (a1) B1
1879
1880 resolution: no need to switch
1881
Zhou Song4ba65882018-07-09 14:48:07 +08001882case 8
1883 uc->dev d1 (a1) B1
1884 new_uc->dev d11 (a1), d2 (a2) B1, B2
1885 resolution: compared to case 1, for this case, d1 and d11 are related
1886 then need to do the same as case 2 to siwtch to new uc
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301887
1888case 9
1889 uc->dev d1 (a1), d2(a2) B1 B2
1890 new_uc->dev d1 (a1), d22 (a2) B1, B2
1891 resolution: disable enable uc-dev on d2 since backends match
1892 we cannot enable two streams on two different devices if they
1893 share the same backend. This is special case for combo use case
1894 with a2dp and sco devices which uses same backend.
1895 e.g. speaker-a2dp and speaker-btsco
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001896*/
1897static snd_device_t derive_playback_snd_device(void * platform,
1898 struct audio_usecase *uc,
1899 struct audio_usecase *new_uc,
1900 snd_device_t new_snd_device)
1901{
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001902 struct listnode a1, a2;
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001903
1904 snd_device_t d1 = uc->out_snd_device;
1905 snd_device_t d2 = new_snd_device;
1906
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001907 list_init(&a1);
1908 list_init(&a2);
1909
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301910 switch (uc->type) {
Surendar Karka93cd25a2018-08-28 14:21:37 +05301911 case TRANSCODE_LOOPBACK_RX :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001912 assign_devices(&a1, &uc->stream.inout->out_config.device_list);
1913 assign_devices(&a2, &new_uc->stream.inout->out_config.device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301914 break;
1915 default :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001916 assign_devices(&a1, &uc->stream.out->device_list);
1917 assign_devices(&a2, &new_uc->stream.out->device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301918 break;
1919 }
1920
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001921 // Treat as a special case when a1 and a2 are not disjoint
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001922 if (!compare_devices(&a1, &a2) &&
1923 compare_devices_for_any_match(&a1 ,&a2)) {
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001924 snd_device_t d3[2];
1925 int num_devices = 0;
1926 int ret = platform_split_snd_device(platform,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001927 list_length(&a1) > 1 ? d1 : d2,
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001928 &num_devices,
1929 d3);
1930 if (ret < 0) {
1931 if (ret != -ENOSYS) {
1932 ALOGW("%s failed to split snd_device %d",
1933 __func__,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001934 list_length(&a1) > 1 ? d1 : d2);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001935 }
1936 goto end;
1937 }
1938
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001939 if (platform_check_backends_match(d3[0], d3[1])) {
1940 return d2; // case 5
1941 } else {
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301942 if ((list_length(&a1) > 1) && (list_length(&a2) > 1) &&
1943 platform_check_backends_match(d1, d2))
1944 return d2; //case 9
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001945 if (list_length(&a1) > 1)
Samyak Jaind826b502019-07-17 16:16:42 +05301946 return d1; //case 7
Garmond Leungb9eeba42018-09-18 11:10:41 -07001947 // check if d1 is related to any of d3's
1948 if (d1 == d3[0] || d1 == d3[1])
Zhou Song4ba65882018-07-09 14:48:07 +08001949 return d1; // case 1
1950 else
1951 return d3[1]; // case 8
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001952 }
1953 } else {
1954 if (platform_check_backends_match(d1, d2)) {
1955 return d2; // case 2, 4
1956 } else {
1957 return d1; // case 6, 3
1958 }
1959 }
1960
Zhenlin Lian4f947842022-05-14 15:50:52 +05301961 clear_devices(&a1);
1962 clear_devices(&a2);
1963
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001964end:
1965 return d2; // return whatever was calculated before.
1966}
1967
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001968static void check_usecases_codec_backend(struct audio_device *adev,
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301969 struct audio_usecase *uc_info,
1970 snd_device_t snd_device)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001971{
1972 struct listnode *node;
1973 struct audio_usecase *usecase;
1974 bool switch_device[AUDIO_USECASE_MAX];
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301975 snd_device_t uc_derive_snd_device;
1976 snd_device_t derive_snd_device[AUDIO_USECASE_MAX];
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001977 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
1978 int i, num_uc_to_switch = 0, num_devices = 0;
kunleiz5cd52b82016-11-07 17:22:52 +08001979 int status = 0;
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301980 bool force_restart_session = false;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001981 /*
1982 * This function is to make sure that all the usecases that are active on
1983 * the hardware codec backend are always routed to any one device that is
1984 * handled by the hardware codec.
1985 * For example, if low-latency and deep-buffer usecases are currently active
1986 * on speaker and out_set_parameters(headset) is received on low-latency
1987 * output, then we have to make sure deep-buffer is also switched to headset,
1988 * because of the limitation that both the devices cannot be enabled
1989 * at the same time as they share the same backend.
1990 */
Mingming Yin3ee55c62014-08-04 14:23:35 -07001991 /*
1992 * This call is to check if we need to force routing for a particular stream
1993 * If there is a backend configuration change for the device when a
1994 * new stream starts, then ADM needs to be closed and re-opened with the new
1995 * configuraion. This call check if we need to re-route all the streams
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001996 * associated with the backend. Touch tone + 24 bit + native playback.
Mingming Yin3ee55c62014-08-04 14:23:35 -07001997 */
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001998 bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info,
1999 snd_device);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302000 /* For a2dp device reconfigure all active sessions
2001 * with new AFE encoder format based on a2dp state
2002 */
2003 if ((SND_DEVICE_OUT_BT_A2DP == snd_device ||
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05302004 SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP == snd_device ||
2005 SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP == snd_device) &&
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302006 audio_extn_a2dp_is_force_device_switch()) {
2007 force_routing = true;
2008 force_restart_session = true;
2009 }
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002010
2011 /*
2012 * Island cfg and power mode config needs to set before AFE port start.
2013 * Set force routing in case of voice device was enable before.
2014 */
2015 if (uc_info->type == VOICE_CALL &&
2016 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002017 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002018 platform_check_and_update_island_power_status(adev->platform,
2019 uc_info,
2020 snd_device)) {
2021 force_routing = true;
2022 ALOGD("%s:becf: force routing %d for power mode supported device",
2023 __func__, force_routing);
2024 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302025 ALOGD("%s:becf: force routing %d", __func__, force_routing);
2026
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002027 /* Disable all the usecases on the shared backend other than the
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08002028 * specified usecase.
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08002029 */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002030 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2031 switch_device[i] = false;
2032
2033 list_for_each(node, &adev->usecase_list) {
2034 usecase = node_to_item(node, struct audio_usecase, list);
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08002035
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302036 ALOGD("%s:becf: (%d) check_usecases curr device: %s, usecase device:%s "
2037 "backends match %d",__func__, i,
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302038 platform_get_snd_device_name(snd_device),
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302039 platform_get_snd_device_name(usecase->out_snd_device),
2040 platform_check_backends_match(snd_device, usecase->out_snd_device));
Rahul Sharma99770982019-03-06 17:05:26 +05302041 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
2042 (usecase->type != PCM_PASSTHROUGH)) {
Ashish Jain6a65b352017-03-21 17:24:40 +05302043 uc_derive_snd_device = derive_playback_snd_device(adev->platform,
2044 usecase, uc_info, snd_device);
2045 if (((uc_derive_snd_device != usecase->out_snd_device) || force_routing) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002046 (is_codec_backend_out_device_type(&usecase->device_list) ||
2047 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
2048 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_DEVICE) ||
2049 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_HEADSET) ||
2050 is_a2dp_out_device_type(&usecase->device_list) ||
2051 is_sco_out_device_type(&usecase->device_list)) &&
Ashish Jain6a65b352017-03-21 17:24:40 +05302052 ((force_restart_session) ||
2053 (platform_check_backends_match(snd_device, usecase->out_snd_device)))) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302054 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
2055 __func__, use_case_table[usecase->id],
2056 platform_get_snd_device_name(usecase->out_snd_device));
2057 disable_audio_route(adev, usecase);
2058 switch_device[usecase->id] = true;
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05302059 /* Enable existing usecase on derived playback device */
2060 derive_snd_device[usecase->id] = uc_derive_snd_device;
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302061 num_uc_to_switch++;
Ashish Jain6a65b352017-03-21 17:24:40 +05302062 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002063 }
2064 }
2065
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302066 ALOGD("%s:becf: check_usecases num.of Usecases to switch %d", __func__,
2067 num_uc_to_switch);
2068
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002069 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002070 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002071
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302072 /* Make sure the previous devices to be disabled first and then enable the
2073 selected devices */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002074 list_for_each(node, &adev->usecase_list) {
2075 usecase = node_to_item(node, struct audio_usecase, list);
2076 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08002077 /* Check if output sound device to be switched can be split and if any
2078 of the split devices match with derived sound device */
2079 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
2080 &num_devices, split_snd_devices) == 0) {
2081 adev->snd_dev_ref_cnt[usecase->out_snd_device]--;
2082 for (i = 0; i < num_devices; i++) {
2083 /* Disable devices that do not match with derived sound device */
2084 if (split_snd_devices[i] != derive_snd_device[usecase->id])
2085 disable_snd_device(adev, split_snd_devices[i]);
2086 }
2087 } else {
2088 disable_snd_device(adev, usecase->out_snd_device);
2089 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002090 }
2091 }
2092
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002093 list_for_each(node, &adev->usecase_list) {
2094 usecase = node_to_item(node, struct audio_usecase, list);
2095 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08002096 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
2097 &num_devices, split_snd_devices) == 0) {
2098 /* Enable derived sound device only if it does not match with
2099 one of the split sound devices. This is because the matching
2100 sound device was not disabled */
2101 bool should_enable = true;
2102 for (i = 0; i < num_devices; i++) {
2103 if (derive_snd_device[usecase->id] == split_snd_devices[i]) {
2104 should_enable = false;
2105 break;
2106 }
2107 }
2108 if (should_enable)
2109 enable_snd_device(adev, derive_snd_device[usecase->id]);
2110 } else {
2111 enable_snd_device(adev, derive_snd_device[usecase->id]);
2112 }
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002113 }
2114 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002115
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002116 /* Re-route all the usecases on the shared backend other than the
2117 specified usecase to new snd devices */
2118 list_for_each(node, &adev->usecase_list) {
2119 usecase = node_to_item(node, struct audio_usecase, list);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302120 /* Update the out_snd_device only before enabling the audio route */
2121 if (switch_device[usecase->id]) {
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05302122 usecase->out_snd_device = derive_snd_device[usecase->id];
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302123 ALOGD("%s:becf: enabling usecase (%s) on (%s)", __func__,
2124 use_case_table[usecase->id],
2125 platform_get_snd_device_name(usecase->out_snd_device));
2126 /* Update voc calibration before enabling Voice/VoIP route */
2127 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
2128 status = platform_switch_voice_call_device_post(adev->platform,
2129 usecase->out_snd_device,
2130 platform_get_input_snd_device(
2131 adev->platform, NULL,
2132 &uc_info->device_list,
2133 usecase->type));
2134 enable_audio_route(adev, usecase);
2135 if (usecase->stream.out && usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
2136 out_set_voip_volume(&usecase->stream.out->stream,
2137 usecase->stream.out->volume_l,
2138 usecase->stream.out->volume_r);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302139 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002140 }
2141 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002142 }
2143}
2144
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302145static void check_usecases_capture_codec_backend(struct audio_device *adev,
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002146 struct audio_usecase *uc_info,
2147 snd_device_t snd_device)
2148{
2149 struct listnode *node;
2150 struct audio_usecase *usecase;
2151 bool switch_device[AUDIO_USECASE_MAX];
2152 int i, num_uc_to_switch = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002153 int backend_check_cond = is_codec_backend_out_device_type(&uc_info->device_list);
kunleiz5cd52b82016-11-07 17:22:52 +08002154 int status = 0;
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002155
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302156 bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
2157 snd_device);
2158 ALOGD("%s:becf: force routing %d", __func__, force_routing);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302159
2160 /*
2161 * Make sure out devices is checked against out codec backend device and
2162 * also in devices against in codec backend. Checking out device against in
2163 * codec backend or vice versa causes issues.
2164 */
2165 if (uc_info->type == PCM_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002166 backend_check_cond = is_codec_backend_in_device_type(&uc_info->device_list);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002167
2168 /*
2169 * Island cfg and power mode config needs to set before AFE port start.
2170 * Set force routing in case of voice device was enable before.
2171 */
2172
2173 if (uc_info->type == VOICE_CALL &&
2174 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002175 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002176 platform_check_and_update_island_power_status(adev->platform,
2177 uc_info,
2178 snd_device)) {
2179 force_routing = true;
2180 ALOGD("%s:becf: force routing %d for power mode supported device",
2181 __func__, force_routing);
2182 }
2183
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002184 /*
2185 * This function is to make sure that all the active capture usecases
2186 * are always routed to the same input sound device.
2187 * For example, if audio-record and voice-call usecases are currently
2188 * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
2189 * is received for voice call then we have to make sure that audio-record
2190 * usecase is also switched to earpiece i.e. voice-dmic-ef,
2191 * because of the limitation that two devices cannot be enabled
2192 * at the same time if they share the same backend.
2193 */
2194 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2195 switch_device[i] = false;
2196
2197 list_for_each(node, &adev->usecase_list) {
2198 usecase = node_to_item(node, struct audio_usecase, list);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302199 /*
2200 * TODO: Enhance below condition to handle BT sco/USB multi recording
2201 */
Jaideep Sharma477917f2020-03-13 18:13:33 +05302202
2203 bool capture_uc_needs_routing = usecase->type != PCM_PLAYBACK && (usecase != uc_info &&
2204 (usecase->in_snd_device != snd_device || force_routing));
2205 bool call_proxy_snd_device = platform_is_call_proxy_snd_device(snd_device) ||
2206 platform_is_call_proxy_snd_device(usecase->in_snd_device);
2207 if (capture_uc_needs_routing && !call_proxy_snd_device &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002208 ((backend_check_cond &&
2209 (is_codec_backend_in_device_type(&usecase->device_list) ||
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08002210 (usecase->type == VOIP_CALL))) ||
Carter Hsu1d2a0532018-10-04 09:24:36 +08002211 ((uc_info->type == VOICE_CALL &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002212 is_single_device_type_equal(&usecase->device_list,
2213 AUDIO_DEVICE_IN_VOICE_CALL)) ||
Anver sadhique4fdc6992022-01-21 12:26:28 +05302214 platform_check_all_backends_match(snd_device,\
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002215 usecase->in_snd_device))) &&
Anish Kumara020a7c2014-10-17 11:13:22 -07002216 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05302217 ALOGD("%s: Usecase (%s) is active on (%s) - disabling ..",
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002218 __func__, use_case_table[usecase->id],
Devin Kim1e5f3532013-08-09 07:48:29 -07002219 platform_get_snd_device_name(usecase->in_snd_device));
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002220 disable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002221 switch_device[usecase->id] = true;
2222 num_uc_to_switch++;
2223 }
2224 }
2225
2226 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002227 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002228
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302229 /* Make sure the previous devices to be disabled first and then enable the
2230 selected devices */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002231 list_for_each(node, &adev->usecase_list) {
2232 usecase = node_to_item(node, struct audio_usecase, list);
2233 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002234 disable_snd_device(adev, usecase->in_snd_device);
Shiv Maliyappanahalli80ac6282013-12-20 18:56:15 -08002235 }
2236 }
2237
2238 list_for_each(node, &adev->usecase_list) {
2239 usecase = node_to_item(node, struct audio_usecase, list);
2240 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002241 enable_snd_device(adev, snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002242 }
2243 }
2244
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002245 /* Re-route all the usecases on the shared backend other than the
2246 specified usecase to new snd devices */
2247 list_for_each(node, &adev->usecase_list) {
2248 usecase = node_to_item(node, struct audio_usecase, list);
2249 /* Update the in_snd_device only before enabling the audio route */
2250 if (switch_device[usecase->id] ) {
2251 usecase->in_snd_device = snd_device;
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302252 /* Update voc calibration before enabling Voice/VoIP route */
2253 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
2254 snd_device_t voip_snd_device;
2255 voip_snd_device = platform_get_output_snd_device(adev->platform,
2256 usecase->stream.out,
2257 usecase->type);
2258 status = platform_switch_voice_call_device_post(adev->platform,
2259 voip_snd_device,
2260 usecase->in_snd_device);
kunleiz5cd52b82016-11-07 17:22:52 +08002261 }
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302262 enable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002263 }
2264 }
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002265 }
2266}
2267
Mingming Yin3a941d42016-02-17 18:08:05 -08002268static void reset_hdmi_sink_caps(struct stream_out *out) {
2269 int i = 0;
2270
2271 for (i = 0; i<= MAX_SUPPORTED_CHANNEL_MASKS; i++) {
2272 out->supported_channel_masks[i] = 0;
2273 }
2274 for (i = 0; i<= MAX_SUPPORTED_FORMATS; i++) {
2275 out->supported_formats[i] = 0;
2276 }
2277 for (i = 0; i<= MAX_SUPPORTED_SAMPLE_RATES; i++) {
2278 out->supported_sample_rates[i] = 0;
2279 }
2280}
2281
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002282/* must be called with hw device mutex locked */
Mingming Yin3a941d42016-02-17 18:08:05 -08002283static int read_hdmi_sink_caps(struct stream_out *out)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002284{
Mingming Yin3a941d42016-02-17 18:08:05 -08002285 int ret = 0, i = 0, j = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002286 int channels = platform_edid_get_max_channels_v2(out->dev->platform,
2287 out->extconn.cs.controller,
2288 out->extconn.cs.stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002289
Mingming Yin3a941d42016-02-17 18:08:05 -08002290 reset_hdmi_sink_caps(out);
2291
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002292 /* Cache ext disp type */
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002293 ret = platform_get_ext_disp_type_v2(adev->platform,
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002294 out->extconn.cs.controller,
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002295 out->extconn.cs.stream);
2296 if(ret < 0) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002297 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Garmond Leung37850ab2016-10-06 11:42:18 -07002298 return -EINVAL;
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002299 }
2300
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002301 switch (channels) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002302 case 8:
Mingming Yin3a941d42016-02-17 18:08:05 -08002303 ALOGV("%s: HDMI supports 7.1 channels", __func__);
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07002304 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_7POINT1;
Mingming Yin3a941d42016-02-17 18:08:05 -08002305 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_6POINT1;
2306 case 6:
2307 ALOGV("%s: HDMI supports 5.1 channels", __func__);
2308 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
2309 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
2310 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
2311 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_SURROUND;
2312 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_2POINT1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002313 break;
2314 default:
Mingming Yin3a941d42016-02-17 18:08:05 -08002315 ALOGE("invalid/nonstandard channal count[%d]",channels);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002316 ret = -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002317 break;
2318 }
Mingming Yin3a941d42016-02-17 18:08:05 -08002319
2320 // check channel format caps
2321 i = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002322 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_AC3,
2323 out->extconn.cs.controller,
2324 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002325 ALOGV(":%s HDMI supports AC3/EAC3 formats", __func__);
2326 out->supported_formats[i++] = AUDIO_FORMAT_AC3;
2327 //Adding EAC3/EAC3_JOC formats if AC3 is supported by the sink.
2328 //EAC3/EAC3_JOC will be converted to AC3 for decoding if needed
2329 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
2330 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
2331 }
2332
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002333 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD,
2334 out->extconn.cs.controller,
2335 out->extconn.cs.stream)) {
Ben Romberger1aaaf862017-04-06 17:49:46 -07002336 ALOGV(":%s HDMI supports TRUE HD format", __func__);
2337 out->supported_formats[i++] = AUDIO_FORMAT_DOLBY_TRUEHD;
2338 }
2339
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002340 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS,
2341 out->extconn.cs.controller,
2342 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002343 ALOGV(":%s HDMI supports DTS format", __func__);
2344 out->supported_formats[i++] = AUDIO_FORMAT_DTS;
2345 }
2346
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002347 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS_HD,
2348 out->extconn.cs.controller,
2349 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002350 ALOGV(":%s HDMI supports DTS HD format", __func__);
2351 out->supported_formats[i++] = AUDIO_FORMAT_DTS_HD;
2352 }
2353
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002354 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_IEC61937,
2355 out->extconn.cs.controller,
2356 out->extconn.cs.stream)) {
Naresh Tanniru928f0862017-04-07 16:44:23 -07002357 ALOGV(":%s HDMI supports IEC61937 format", __func__);
2358 out->supported_formats[i++] = AUDIO_FORMAT_IEC61937;
2359 }
2360
Mingming Yin3a941d42016-02-17 18:08:05 -08002361
2362 // check sample rate caps
2363 i = 0;
2364 for (j = 0; j < MAX_SUPPORTED_SAMPLE_RATES; j++) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002365 if (platform_is_edid_supported_sample_rate_v2(out->dev->platform, out_hdmi_sample_rates[j],
2366 out->extconn.cs.controller,
2367 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002368 ALOGV(":%s HDMI supports sample rate:%d", __func__, out_hdmi_sample_rates[j]);
2369 out->supported_sample_rates[i++] = out_hdmi_sample_rates[j];
2370 }
2371 }
2372
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002373 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002374}
2375
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002376static inline ssize_t read_usb_sup_sample_rates(bool is_playback __unused,
2377 uint32_t *supported_sample_rates __unused,
2378 uint32_t max_rates __unused)
2379{
2380 ssize_t count = audio_extn_usb_get_sup_sample_rates(is_playback,
2381 supported_sample_rates,
2382 max_rates);
Ashish Jain4847e9d2017-08-17 19:16:57 +05302383 ssize_t i = 0;
2384
2385 for (i=0; i<count; i++) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002386 ALOGV("%s %s %d", __func__, is_playback ? "P" : "C",
2387 supported_sample_rates[i]);
2388 }
2389 return count;
2390}
2391
2392static inline int read_usb_sup_channel_masks(bool is_playback,
2393 audio_channel_mask_t *supported_channel_masks,
2394 uint32_t max_masks)
2395{
2396 int channels = audio_extn_usb_get_max_channels(is_playback);
2397 int channel_count;
2398 uint32_t num_masks = 0;
2399 if (channels > MAX_HIFI_CHANNEL_COUNT)
2400 channels = MAX_HIFI_CHANNEL_COUNT;
2401
2402 if (is_playback) {
Eric Laurent68a87112019-05-01 18:07:29 -07002403 // start from 2 channels as framework currently doesn't support mono.
2404 if (channels >= FCC_2) {
2405 supported_channel_masks[num_masks++] = audio_channel_out_mask_from_count(FCC_2);
2406 }
2407 for (channel_count = FCC_2;
2408 channel_count <= channels && num_masks < max_masks;
2409 ++channel_count) {
2410 supported_channel_masks[num_masks++] =
2411 audio_channel_mask_for_index_assignment_from_count(channel_count);
2412 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002413 } else {
vincenttewf51c94e2019-05-07 10:28:53 +08002414 // For capture we report all supported channel masks from 1 channel up.
2415 channel_count = MIN_CHANNEL_COUNT;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002416 // audio_channel_in_mask_from_count() does the right conversion to either positional or
2417 // indexed mask
Eric Laurent68a87112019-05-01 18:07:29 -07002418 for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
2419 audio_channel_mask_t mask = AUDIO_CHANNEL_NONE;
2420 if (channel_count <= FCC_2) {
2421 mask = audio_channel_in_mask_from_count(channel_count);
2422 supported_channel_masks[num_masks++] = mask;
2423 }
2424 const audio_channel_mask_t index_mask =
2425 audio_channel_mask_for_index_assignment_from_count(channel_count);
2426 if (mask != index_mask && num_masks < max_masks) { // ensure index mask added.
2427 supported_channel_masks[num_masks++] = index_mask;
2428 }
2429 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002430 }
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302431
vincenttewf51c94e2019-05-07 10:28:53 +08002432 for (size_t i = 0; i < num_masks; ++i) {
2433 ALOGV("%s: %s supported ch %d supported_channel_masks[%zu] %08x num_masks %d", __func__,
2434 is_playback ? "P" : "C", channels, i, supported_channel_masks[i], num_masks);
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302435 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002436 return num_masks;
2437}
2438
2439static inline int read_usb_sup_formats(bool is_playback __unused,
2440 audio_format_t *supported_formats,
2441 uint32_t max_formats __unused)
2442{
2443 int bitwidth = audio_extn_usb_get_max_bit_width(is_playback);
2444 switch (bitwidth) {
2445 case 24:
2446 // XXX : usb.c returns 24 for s24 and s24_le?
2447 supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
2448 break;
2449 case 32:
2450 supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
2451 break;
2452 case 16:
2453 default :
2454 supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
2455 break;
2456 }
2457 ALOGV("%s: %s supported format %d", __func__,
2458 is_playback ? "P" : "C", bitwidth);
2459 return 1;
2460}
2461
2462static inline int read_usb_sup_params_and_compare(bool is_playback,
2463 audio_format_t *format,
2464 audio_format_t *supported_formats,
2465 uint32_t max_formats,
2466 audio_channel_mask_t *mask,
2467 audio_channel_mask_t *supported_channel_masks,
2468 uint32_t max_masks,
2469 uint32_t *rate,
2470 uint32_t *supported_sample_rates,
2471 uint32_t max_rates) {
2472 int ret = 0;
2473 int num_formats;
2474 int num_masks;
2475 int num_rates;
2476 int i;
2477
2478 num_formats = read_usb_sup_formats(is_playback, supported_formats,
2479 max_formats);
2480 num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
2481 max_masks);
2482
2483 num_rates = read_usb_sup_sample_rates(is_playback,
2484 supported_sample_rates, max_rates);
2485
2486#define LUT(table, len, what, dflt) \
2487 for (i=0; i<len && (table[i] != what); i++); \
2488 if (i==len) { ret |= (what == dflt ? 0 : -1); what=table[0]; }
2489
2490 LUT(supported_formats, num_formats, *format, AUDIO_FORMAT_DEFAULT);
2491 LUT(supported_channel_masks, num_masks, *mask, AUDIO_CHANNEL_NONE);
2492 LUT(supported_sample_rates, num_rates, *rate, 0);
2493
2494#undef LUT
2495 return ret < 0 ? -EINVAL : 0; // HACK TBD
2496}
2497
Alexy Josephb1379942016-01-29 15:49:38 -08002498audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002499 usecase_type_t type)
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002500{
2501 struct audio_usecase *usecase;
2502 struct listnode *node;
2503
2504 list_for_each(node, &adev->usecase_list) {
2505 usecase = node_to_item(node, struct audio_usecase, list);
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002506 if (usecase->type == type) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002507 ALOGV("%s: usecase id %d", __func__, usecase->id);
2508 return usecase->id;
2509 }
2510 }
2511 return USECASE_INVALID;
2512}
2513
Alexy Josephb1379942016-01-29 15:49:38 -08002514struct audio_usecase *get_usecase_from_list(const struct audio_device *adev,
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002515 audio_usecase_t uc_id)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002516{
2517 struct audio_usecase *usecase;
2518 struct listnode *node;
2519
2520 list_for_each(node, &adev->usecase_list) {
2521 usecase = node_to_item(node, struct audio_usecase, list);
2522 if (usecase->id == uc_id)
2523 return usecase;
2524 }
2525 return NULL;
2526}
2527
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302528/*
2529 * is a true native playback active
2530 */
2531bool audio_is_true_native_stream_active(struct audio_device *adev)
2532{
2533 bool active = false;
2534 int i = 0;
2535 struct listnode *node;
2536
2537 if (NATIVE_AUDIO_MODE_TRUE_44_1 != platform_get_native_support()) {
2538 ALOGV("%s:napb: not in true mode or non hdphones device",
2539 __func__);
2540 active = false;
2541 goto exit;
2542 }
2543
2544 list_for_each(node, &adev->usecase_list) {
2545 struct audio_usecase *uc;
2546 uc = node_to_item(node, struct audio_usecase, list);
2547 struct stream_out *curr_out =
2548 (struct stream_out*) uc->stream.out;
2549
2550 if (curr_out && PCM_PLAYBACK == uc->type) {
2551 ALOGD("%s:napb: (%d) (%s)id (%d) sr %d bw "
2552 "(%d) device %s", __func__, i++, use_case_table[uc->id],
2553 uc->id, curr_out->sample_rate,
2554 curr_out->bit_width,
2555 platform_get_snd_device_name(uc->out_snd_device));
2556
2557 if (is_offload_usecase(uc->id) &&
2558 (curr_out->sample_rate == OUTPUT_SAMPLING_RATE_44100)) {
2559 active = true;
2560 ALOGD("%s:napb:native stream detected", __func__);
2561 }
2562 }
2563 }
2564exit:
2565 return active;
2566}
2567
Xiaojun Sang785b5da2017-08-03 15:52:29 +08002568uint32_t adev_get_dsp_bit_width_enforce_mode()
2569{
2570 if (adev == NULL) {
2571 ALOGE("%s: adev is null. Disable DSP bit width enforce mode.\n", __func__);
2572 return 0;
2573 }
2574 return adev->dsp_bit_width_enforce_mode;
2575}
2576
2577static uint32_t adev_init_dsp_bit_width_enforce_mode(struct mixer *mixer)
2578{
2579 char value[PROPERTY_VALUE_MAX];
2580 int trial;
2581 uint32_t dsp_bit_width_enforce_mode = 0;
2582
2583 if (!mixer) {
2584 ALOGE("%s: adev mixer is null. cannot update DSP bitwidth.\n",
2585 __func__);
2586 return 0;
2587 }
2588
2589 if (property_get("persist.vendor.audio_hal.dsp_bit_width_enforce_mode",
2590 value, NULL) > 0) {
2591 trial = atoi(value);
2592 switch (trial) {
2593 case 16:
2594 dsp_bit_width_enforce_mode = 16;
2595 break;
2596 case 24:
2597 dsp_bit_width_enforce_mode = 24;
2598 break;
2599 case 32:
2600 dsp_bit_width_enforce_mode = 32;
2601 break;
2602 default:
2603 dsp_bit_width_enforce_mode = 0;
2604 ALOGD("%s Dynamic DSP bitwidth config is disabled.", __func__);
2605 break;
2606 }
2607 }
2608
2609 return dsp_bit_width_enforce_mode;
2610}
2611
2612static void audio_enable_asm_bit_width_enforce_mode(struct mixer *mixer,
2613 uint32_t enforce_mode,
2614 bool enable)
2615{
2616 struct mixer_ctl *ctl = NULL;
2617 const char *mixer_ctl_name = "ASM Bit Width";
2618 uint32_t asm_bit_width_mode = 0;
2619
2620 if (enforce_mode == 0) {
2621 ALOGD("%s: DSP bitwidth feature is disabled.", __func__);
2622 return;
2623 }
2624
2625 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
2626 if (!ctl) {
2627 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2628 __func__, mixer_ctl_name);
2629 return;
2630 }
2631
2632 if (enable)
2633 asm_bit_width_mode = enforce_mode;
2634 else
2635 asm_bit_width_mode = 0;
2636
2637 ALOGV("%s DSP bit width feature status is %d width=%d",
2638 __func__, enable, asm_bit_width_mode);
2639 if (mixer_ctl_set_value(ctl, 0, asm_bit_width_mode) < 0)
2640 ALOGE("%s: Could not set ASM biwidth %d", __func__,
2641 asm_bit_width_mode);
2642
2643 return;
2644}
2645
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302646/*
2647 * if native DSD playback active
2648 */
2649bool audio_is_dsd_native_stream_active(struct audio_device *adev)
2650{
2651 bool active = false;
2652 struct listnode *node = NULL;
2653 struct audio_usecase *uc = NULL;
2654 struct stream_out *curr_out = NULL;
2655
2656 list_for_each(node, &adev->usecase_list) {
2657 uc = node_to_item(node, struct audio_usecase, list);
2658 curr_out = (struct stream_out*) uc->stream.out;
2659
2660 if (curr_out && PCM_PLAYBACK == uc->type &&
2661 (DSD_NATIVE_BACKEND == platform_get_backend_index(uc->out_snd_device))) {
2662 active = true;
2663 ALOGV("%s:DSD playback is active", __func__);
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05302664 break;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302665 }
2666 }
2667 return active;
2668}
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302669
2670static bool force_device_switch(struct audio_usecase *usecase)
2671{
2672 bool ret = false;
2673 bool is_it_true_mode = false;
2674
Zhou Song30f2c3e2018-02-08 14:02:15 +08002675 if (usecase->type == PCM_CAPTURE ||
Surendar Karka93cd25a2018-08-28 14:21:37 +05302676 usecase->type == TRANSCODE_LOOPBACK_RX ||
2677 usecase->type == TRANSCODE_LOOPBACK_TX) {
Zhou Song30f2c3e2018-02-08 14:02:15 +08002678 return false;
2679 }
2680
Aalique Grahamecbc46a22017-10-05 10:30:23 -07002681 if(usecase->stream.out == NULL) {
2682 ALOGE("%s: stream.out is NULL", __func__);
2683 return false;
2684 }
2685
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302686 if (is_offload_usecase(usecase->id) &&
Xiaojun Sang869f2012016-02-23 16:33:07 +08002687 (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002688 (compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
2689 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302690 is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
2691 if ((is_it_true_mode && !adev->native_playback_enabled) ||
2692 (!is_it_true_mode && adev->native_playback_enabled)){
2693 ret = true;
2694 ALOGD("napb: time to toggle native mode");
2695 }
2696 }
2697
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302698 // Force all a2dp output devices to reconfigure for proper AFE encode format
Ashish Jainc597d102016-12-12 10:31:34 +05302699 //Also handle a case where in earlier a2dp start failed as A2DP stream was
2700 //in suspended state, hence try to trigger a retry when we again get a routing request.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002701 if(is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Ashish Jainc597d102016-12-12 10:31:34 +05302702 audio_extn_a2dp_is_force_device_switch()) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302703 ALOGD("Force a2dp device switch to update new encoder config");
2704 ret = true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002705 }
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302706
Florian Pfister1a84f312018-07-19 14:38:18 +02002707 if (usecase->stream.out->stream_config_changed) {
Manish Dewangan671a4202017-08-18 17:30:46 +05302708 ALOGD("Force stream_config_changed to update iec61937 transmission config");
2709 return true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002710 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302711 return ret;
2712}
2713
Aalique Grahame22e49102018-12-18 14:23:57 -08002714static void stream_app_type_cfg_init(struct stream_app_type_cfg *cfg)
2715{
2716 cfg->gain[0] = cfg->gain[1] = APP_TYPE_GAIN_DEFAULT;
2717}
2718
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302719bool is_btsco_device(snd_device_t out_snd_device, snd_device_t in_snd_device)
2720{
2721 bool ret=false;
2722 if ((out_snd_device == SND_DEVICE_OUT_BT_SCO ||
Zhou Song5657f492019-08-07 11:30:39 +08002723 out_snd_device == SND_DEVICE_OUT_BT_SCO_WB ||
2724 out_snd_device == SND_DEVICE_OUT_BT_SCO_SWB) ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302725 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC ||
2726 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB ||
Zhou Song5657f492019-08-07 11:30:39 +08002727 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302728 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC ||
Mingshu Pang16093502020-04-20 11:21:16 +08002729 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC ||
2730 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC)
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302731 ret = true;
2732
2733 return ret;
2734}
2735
2736bool is_a2dp_device(snd_device_t out_snd_device)
2737{
2738 bool ret=false;
2739 if (out_snd_device == SND_DEVICE_OUT_BT_A2DP)
2740 ret = true;
2741
2742 return ret;
2743}
2744
2745bool is_bt_soc_on(struct audio_device *adev)
2746{
2747 struct mixer_ctl *ctl;
2748 char *mixer_ctl_name = "BT SOC status";
2749 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
2750 bool bt_soc_status = true;
2751 if (!ctl) {
2752 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2753 __func__, mixer_ctl_name);
2754 /*This is to ensure we dont break targets which dont have the kernel change*/
2755 return true;
2756 }
2757 bt_soc_status = mixer_ctl_get_value(ctl, 0);
2758 ALOGD("BT SOC status: %d",bt_soc_status);
2759 return bt_soc_status;
2760}
2761
Zhou Song331c8e52019-08-26 14:16:12 +08002762static int configure_btsco_sample_rate(snd_device_t snd_device)
2763{
2764 struct mixer_ctl *ctl = NULL;
2765 struct mixer_ctl *ctl_sr_rx = NULL, *ctl_sr_tx = NULL, *ctl_sr = NULL;
2766 char *rate_str = NULL;
2767 bool is_rx_dev = true;
2768
2769 if (is_btsco_device(snd_device, snd_device)) {
2770 ctl_sr_tx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate TX");
2771 ctl_sr_rx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate RX");
2772 if (!ctl_sr_tx || !ctl_sr_rx) {
2773 ctl_sr = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate");
2774 if (!ctl_sr)
2775 return -ENOSYS;
2776 }
2777
2778 switch (snd_device) {
2779 case SND_DEVICE_OUT_BT_SCO:
2780 rate_str = "KHZ_8";
2781 break;
2782 case SND_DEVICE_IN_BT_SCO_MIC_NREC:
2783 case SND_DEVICE_IN_BT_SCO_MIC:
2784 rate_str = "KHZ_8";
2785 is_rx_dev = false;
2786 break;
2787 case SND_DEVICE_OUT_BT_SCO_WB:
2788 rate_str = "KHZ_16";
2789 break;
2790 case SND_DEVICE_IN_BT_SCO_MIC_WB_NREC:
2791 case SND_DEVICE_IN_BT_SCO_MIC_WB:
2792 rate_str = "KHZ_16";
2793 is_rx_dev = false;
2794 break;
2795 default:
2796 return 0;
2797 }
2798
2799 ctl = (ctl_sr == NULL) ? (is_rx_dev ? ctl_sr_rx : ctl_sr_tx) : ctl_sr;
2800 if (mixer_ctl_set_enum_by_string(ctl, rate_str) != 0)
2801 return -ENOSYS;
2802 }
2803 return 0;
2804}
2805
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302806int out_standby_l(struct audio_stream *stream);
2807
Eric Laurent637e2d42018-11-15 12:24:31 -08002808struct stream_in *adev_get_active_input(const struct audio_device *adev)
2809{
2810 struct listnode *node;
2811 struct stream_in *last_active_in = NULL;
2812
2813 /* Get last added active input.
2814 * TODO: We may use a priority mechanism to pick highest priority active source */
2815 list_for_each(node, &adev->usecase_list)
2816 {
2817 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2818 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL)
2819 last_active_in = usecase->stream.in;
2820 }
2821
2822 return last_active_in;
2823}
2824
2825struct stream_in *get_voice_communication_input(const struct audio_device *adev)
2826{
2827 struct listnode *node;
2828
2829 /* First check active inputs with voice communication source and then
2830 * any input if audio mode is in communication */
2831 list_for_each(node, &adev->usecase_list)
2832 {
2833 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2834 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL &&
2835 usecase->stream.in->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
2836 return usecase->stream.in;
2837 }
2838 if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
2839 return adev_get_active_input(adev);
2840
2841 return NULL;
2842}
2843
Carter Hsu2e429db2019-05-14 18:50:52 +08002844/*
2845 * Aligned with policy.h
2846 */
2847static inline int source_priority(int inputSource)
2848{
2849 switch (inputSource) {
2850 case AUDIO_SOURCE_VOICE_COMMUNICATION:
2851 return 9;
2852 case AUDIO_SOURCE_CAMCORDER:
2853 return 8;
2854 case AUDIO_SOURCE_VOICE_PERFORMANCE:
2855 return 7;
2856 case AUDIO_SOURCE_UNPROCESSED:
2857 return 6;
2858 case AUDIO_SOURCE_MIC:
2859 return 5;
2860 case AUDIO_SOURCE_ECHO_REFERENCE:
2861 return 4;
2862 case AUDIO_SOURCE_FM_TUNER:
2863 return 3;
2864 case AUDIO_SOURCE_VOICE_RECOGNITION:
2865 return 2;
2866 case AUDIO_SOURCE_HOTWORD:
2867 return 1;
2868 default:
2869 break;
2870 }
2871 return 0;
2872}
2873
2874static struct stream_in *get_priority_input(struct audio_device *adev)
2875{
2876 struct listnode *node;
2877 struct audio_usecase *usecase;
2878 int last_priority = 0, priority;
2879 struct stream_in *priority_in = NULL;
2880 struct stream_in *in;
2881
2882 list_for_each(node, &adev->usecase_list) {
2883 usecase = node_to_item(node, struct audio_usecase, list);
2884 if (usecase->type == PCM_CAPTURE) {
2885 in = usecase->stream.in;
2886 if (!in)
2887 continue;
2888 priority = source_priority(in->source);
2889
2890 if (priority > last_priority) {
2891 last_priority = priority;
2892 priority_in = in;
2893 }
2894 }
2895 }
2896 return priority_in;
2897}
2898
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002899int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002900{
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08002901 snd_device_t out_snd_device = SND_DEVICE_NONE;
2902 snd_device_t in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002903 struct audio_usecase *usecase = NULL;
2904 struct audio_usecase *vc_usecase = NULL;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002905 struct audio_usecase *voip_usecase = NULL;
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002906 struct audio_usecase *hfp_usecase = NULL;
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302907 struct stream_out stream_out;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08002908 audio_usecase_t hfp_ucid;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002909 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002910
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302911 ALOGD("%s for use case (%s)", __func__, use_case_table[uc_id]);
2912
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002913 usecase = get_usecase_from_list(adev, uc_id);
2914 if (usecase == NULL) {
2915 ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
2916 return -EINVAL;
2917 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002918
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002919 if ((usecase->type == VOICE_CALL) ||
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08002920 (usecase->type == VOIP_CALL) ||
Derek Chena30a5f42019-12-03 11:17:09 -05002921 (usecase->type == PCM_HFP_CALL)||
Fei Tongaffdf732020-02-20 20:39:05 +08002922 (usecase->type == ICC_CALL) ||
2923 (usecase->type == SYNTH_LOOPBACK)) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302924 if(usecase->stream.out == NULL) {
2925 ALOGE("%s: stream.out is NULL", __func__);
2926 return -EINVAL;
2927 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002928 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS)) {
Guodong Hu267bdf82019-08-12 19:22:32 +08002929 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
2930 uc_id);
2931 in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
2932 uc_id);
2933 } else {
2934 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302935 usecase->stream.out, usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002936 in_snd_device = platform_get_input_snd_device(adev->platform,
2937 NULL,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302938 &usecase->stream.out->device_list,
2939 usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002940 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002941 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302942 } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
Siddartha Shaik31b530e2017-05-19 15:26:33 +05302943 if (usecase->stream.inout == NULL) {
2944 ALOGE("%s: stream.inout is NULL", __func__);
2945 return -EINVAL;
2946 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002947 assign_devices(&stream_out.device_list, &usecase->stream.inout->out_config.device_list);
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302948 stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
2949 stream_out.format = usecase->stream.inout->out_config.format;
2950 stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
Jaideep Sharma477917f2020-03-13 18:13:33 +05302951 out_snd_device = platform_get_output_snd_device(adev->platform, &stream_out, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002952 assign_devices(&usecase->device_list,
2953 &usecase->stream.inout->out_config.device_list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05302954 clear_devices(&stream_out.device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302955 } else if (usecase->type == TRANSCODE_LOOPBACK_TX ) {
2956 if (usecase->stream.inout == NULL) {
2957 ALOGE("%s: stream.inout is NULL", __func__);
2958 return -EINVAL;
2959 }
Manisha Agarwal03297972020-04-17 15:36:55 +05302960 struct listnode out_devices;
2961 list_init(&out_devices);
2962 in_snd_device = platform_get_input_snd_device(adev->platform, NULL,
2963 &out_devices, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002964 assign_devices(&usecase->device_list,
2965 &usecase->stream.inout->in_config.device_list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05302966 clear_devices(&out_devices);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002967 } else {
2968 /*
2969 * If the voice call is active, use the sound devices of voice call usecase
2970 * so that it would not result any device switch. All the usecases will
2971 * be switched to new device when select_devices() is called for voice call
2972 * usecase. This is to avoid switching devices for voice call when
2973 * check_usecases_codec_backend() is called below.
Alexy Joseph79dfa3c2016-04-20 18:44:56 -07002974 * choose voice call device only if the use case device is
2975 * also using the codec backend
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002976 */
Shiv Maliyappanahallibb4cf0b2016-01-21 11:30:06 -08002977 if (voice_is_in_call(adev) && adev->mode != AUDIO_MODE_NORMAL) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002978 vc_usecase = get_usecase_from_list(adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002979 get_usecase_id_from_usecase_type(adev, VOICE_CALL));
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002980 if ((vc_usecase) && ((is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2981 is_codec_backend_out_device_type(&usecase->device_list)) ||
2982 (is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2983 is_codec_backend_in_device_type(&usecase->device_list)) ||
2984 is_single_device_type_equal(&vc_usecase->device_list,
2985 AUDIO_DEVICE_OUT_HEARING_AID) ||
2986 is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002987 AUDIO_DEVICE_IN_VOICE_CALL) ||
2988 (is_single_device_type_equal(&usecase->device_list,
Gautam Manam8fa06162021-09-24 10:41:29 +05302989 AUDIO_DEVICE_IN_BUILTIN_MIC) &&
2990 is_single_device_type_equal(&vc_usecase->device_list,
2991 AUDIO_DEVICE_OUT_USB_HEADSET)) ||
2992 (is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002993 AUDIO_DEVICE_IN_USB_HEADSET) &&
2994 is_single_device_type_equal(&vc_usecase->device_list,
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05302995 AUDIO_DEVICE_OUT_USB_HEADSET))||
Gautam Manamf4002142021-09-13 22:05:56 +05302996 (is_single_device_type_equal(&usecase->device_list,
2997 AUDIO_DEVICE_IN_USB_HEADSET) &&
2998 is_codec_backend_out_device_type(&vc_usecase->device_list)) ||
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05302999 (is_single_device_type_equal(&usecase->device_list,
3000 AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) &&
3001 is_codec_backend_out_device_type(&vc_usecase->device_list)))) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003002 in_snd_device = vc_usecase->in_snd_device;
3003 out_snd_device = vc_usecase->out_snd_device;
3004 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08003005 } else if (voice_extn_compress_voip_is_active(adev)) {
yidongh02ef86f2017-04-21 15:36:04 +08003006 bool out_snd_device_backend_match = true;
yidongh47785a82017-05-08 19:29:29 +08003007 voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
yidongh6261d8e2017-05-15 17:04:02 +08003008 if ((voip_usecase != NULL) &&
3009 (usecase->type == PCM_PLAYBACK) &&
3010 (usecase->stream.out != NULL)) {
yidongh02ef86f2017-04-21 15:36:04 +08003011 out_snd_device_backend_match = platform_check_backends_match(
3012 voip_usecase->out_snd_device,
3013 platform_get_output_snd_device(
3014 adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05303015 usecase->stream.out, usecase->type));
yidongh02ef86f2017-04-21 15:36:04 +08003016 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003017 if ((voip_usecase) && (is_codec_backend_out_device_type(&voip_usecase->device_list) &&
3018 (is_codec_backend_out_device_type(&usecase->device_list) ||
3019 is_codec_backend_in_device_type(&usecase->device_list)) &&
yidongh02ef86f2017-04-21 15:36:04 +08003020 out_snd_device_backend_match &&
Mingming Yin2d8aa2e2014-08-14 00:00:51 -07003021 (voip_usecase->stream.out != adev->primary_output))) {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08003022 in_snd_device = voip_usecase->in_snd_device;
3023 out_snd_device = voip_usecase->out_snd_device;
3024 }
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08003025 } else if (audio_extn_hfp_is_active(adev)) {
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08003026 hfp_ucid = audio_extn_hfp_get_usecase();
3027 hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003028 if ((hfp_usecase) && is_codec_backend_out_device_type(&hfp_usecase->device_list)) {
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08003029 in_snd_device = hfp_usecase->in_snd_device;
3030 out_snd_device = hfp_usecase->out_snd_device;
3031 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003032 }
3033 if (usecase->type == PCM_PLAYBACK) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05303034 if (usecase->stream.out == NULL) {
3035 ALOGE("%s: stream.out is NULL", __func__);
3036 return -EINVAL;
3037 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003038 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003039 in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003040 if (out_snd_device == SND_DEVICE_NONE) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003041 struct stream_out *voip_out = adev->primary_output;
3042 struct stream_in *voip_in = get_voice_communication_input(adev);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003043 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
Guodong Hu267bdf82019-08-12 19:22:32 +08003044 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
3045 else
3046 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05303047 usecase->stream.out,
3048 usecase->type);
kunleizdcf967a2018-08-07 17:09:11 +08003049 voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP);
kunleizdcf967a2018-08-07 17:09:11 +08003050
Eric Laurent637e2d42018-11-15 12:24:31 -08003051 if (voip_usecase)
3052 voip_out = voip_usecase->stream.out;
3053
3054 if (usecase->stream.out == voip_out && voip_in != NULL)
3055 select_devices(adev, voip_in->usecase);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003056 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003057 } else if (usecase->type == PCM_CAPTURE) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05303058 if (usecase->stream.in == NULL) {
3059 ALOGE("%s: stream.in is NULL", __func__);
3060 return -EINVAL;
3061 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003062 assign_devices(&usecase->device_list, &usecase->stream.in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003063 out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003064 if (in_snd_device == SND_DEVICE_NONE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003065 struct listnode out_devices;
Eric Laurent637e2d42018-11-15 12:24:31 -08003066 struct stream_in *voip_in = get_voice_communication_input(adev);
Carter Hsu2e429db2019-05-14 18:50:52 +08003067 struct stream_in *priority_in = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08003068
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003069 list_init(&out_devices);
Eric Laurent637e2d42018-11-15 12:24:31 -08003070 if (voip_in != NULL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003071 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3072 USECASE_AUDIO_PLAYBACK_VOIP);
3073
Carter Hsu2e429db2019-05-14 18:50:52 +08003074 usecase->stream.in->enable_ec_port = false;
3075
Zhou Song503196b2021-07-23 17:31:05 +08003076 if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY ||
3077 usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY2) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003078 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08003079 } else if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003080 assign_devices(&out_devices, &voip_usecase->stream.out->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08003081 } else if (adev->primary_output &&
3082 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003083 assign_devices(&out_devices, &adev->primary_output->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08003084 } else {
3085 /* forcing speaker o/p device to get matching i/p pair
3086 in case o/p is not routed from same primary HAL */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003087 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08003088 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003089 priority_in = voip_in;
3090 } else {
3091 /* get the input with the highest priority source*/
3092 priority_in = get_priority_input(adev);
3093
Susan Wang727dd6b2021-03-26 11:28:59 -04003094 if (!priority_in ||
3095 audio_extn_auto_hal_overwrite_priority_for_auto(usecase->stream.in))
Carter Hsu2e429db2019-05-14 18:50:52 +08003096 priority_in = usecase->stream.in;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003097 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04003098 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_IN_BUS)){
3099 in_snd_device = audio_extn_auto_hal_get_snd_device_for_car_audio_stream(priority_in->car_audio_stream);
3100 }
3101 else
3102 in_snd_device = platform_get_input_snd_device(adev->platform,
3103 priority_in,
3104 &out_devices,
3105 usecase->type);
Zhenlin Lian4f947842022-05-14 15:50:52 +05303106 clear_devices(&out_devices);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003107 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003108 }
3109 }
3110
3111 if (out_snd_device == usecase->out_snd_device &&
3112 in_snd_device == usecase->in_snd_device) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05303113
3114 if (!force_device_switch(usecase))
3115 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003116 }
3117
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003118 if (!compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) &&
Guodong Hu267bdf82019-08-12 19:22:32 +08003119 ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003120 (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
Guodong Hu267bdf82019-08-12 19:22:32 +08003121 ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
3122 return 0;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303123 }
3124
Aalique Grahame22e49102018-12-18 14:23:57 -08003125 if (out_snd_device != SND_DEVICE_NONE &&
3126 out_snd_device != adev->last_logged_snd_device[uc_id][0]) {
3127 ALOGD("%s: changing use case %s output device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3128 __func__,
3129 use_case_table[uc_id],
3130 adev->last_logged_snd_device[uc_id][0],
3131 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][0]),
3132 adev->last_logged_snd_device[uc_id][0] != SND_DEVICE_NONE ?
3133 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][0]) :
3134 -1,
3135 out_snd_device,
3136 platform_get_snd_device_name(out_snd_device),
3137 platform_get_snd_device_acdb_id(out_snd_device));
3138 adev->last_logged_snd_device[uc_id][0] = out_snd_device;
3139 }
3140 if (in_snd_device != SND_DEVICE_NONE &&
3141 in_snd_device != adev->last_logged_snd_device[uc_id][1]) {
3142 ALOGD("%s: changing use case %s input device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3143 __func__,
3144 use_case_table[uc_id],
3145 adev->last_logged_snd_device[uc_id][1],
3146 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][1]),
3147 adev->last_logged_snd_device[uc_id][1] != SND_DEVICE_NONE ?
3148 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][1]) :
3149 -1,
3150 in_snd_device,
3151 platform_get_snd_device_name(in_snd_device),
3152 platform_get_snd_device_acdb_id(in_snd_device));
3153 adev->last_logged_snd_device[uc_id][1] = in_snd_device;
3154 }
3155
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08003156
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003157 /*
3158 * Limitation: While in call, to do a device switch we need to disable
3159 * and enable both RX and TX devices though one of them is same as current
3160 * device.
3161 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003162 if ((usecase->type == VOICE_CALL) &&
3163 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3164 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Eric Laurentb23d5282013-05-14 15:27:20 -07003165 status = platform_switch_voice_call_device_pre(adev->platform);
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003166 }
3167
3168 if (((usecase->type == VOICE_CALL) ||
3169 (usecase->type == VOIP_CALL)) &&
3170 (usecase->out_snd_device != SND_DEVICE_NONE)) {
3171 /* Disable sidetone only if voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303172 if (voice_is_call_state_active_in_call(adev) ||
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003173 voice_extn_compress_voip_is_started(adev))
Bhalchandra Gajare45fee282015-06-09 22:23:45 -07003174 voice_set_sidetone(adev, usecase->out_snd_device, false);
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003175
3176 /* Disable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303177 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003178 voice_check_and_update_aanc_path(adev, usecase->out_snd_device, false);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003179 }
3180
Aalique Grahame22e49102018-12-18 14:23:57 -08003181 if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
3182 out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02003183 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303184 ALOGW("%s: A2DP profile is not ready, routing to speaker only", __func__);
Aalique Grahame22e49102018-12-18 14:23:57 -08003185 if (out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)
3186 out_snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
3187 else
3188 out_snd_device = SND_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303189 }
3190
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003191 /* Disable current sound devices */
3192 if (usecase->out_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003193 disable_audio_route(adev, usecase);
3194 disable_snd_device(adev, usecase->out_snd_device);
Gautam Manam274f4752021-09-24 10:58:49 +05303195 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3196 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003197 }
3198
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003199 if (usecase->in_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003200 disable_audio_route(adev, usecase);
3201 disable_snd_device(adev, usecase->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003202 }
3203
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003204 /* Applicable only on the targets that has external modem.
3205 * New device information should be sent to modem before enabling
3206 * the devices to reduce in-call device switch time.
3207 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003208 if ((usecase->type == VOICE_CALL) &&
3209 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3210 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003211 status = platform_switch_voice_call_enable_device_config(adev->platform,
3212 out_snd_device,
3213 in_snd_device);
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003214 }
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003215
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003216 /* Enable new sound devices */
3217 if (out_snd_device != SND_DEVICE_NONE) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08003218 check_usecases_codec_backend(adev, usecase, out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05303219 check_and_configure_headphone(adev, usecase, out_snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05303220 if (platform_check_codec_asrc_support(adev->platform))
3221 check_and_set_asrc_mode(adev, usecase, out_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003222 enable_snd_device(adev, out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08003223 /* Enable haptics device for haptic usecase */
3224 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3225 enable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003226 }
3227
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003228 if (in_snd_device != SND_DEVICE_NONE) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05303229 check_usecases_capture_codec_backend(adev, usecase, in_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003230 enable_snd_device(adev, in_snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003231 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003232
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05303233 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
Eric Laurentb23d5282013-05-14 15:27:20 -07003234 status = platform_switch_voice_call_device_post(adev->platform,
3235 out_snd_device,
3236 in_snd_device);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003237
sangwoo170731f2013-06-08 15:36:36 +09003238 usecase->in_snd_device = in_snd_device;
3239 usecase->out_snd_device = out_snd_device;
3240
Dhananjay Kumard6d32152016-10-13 16:11:03 +05303241 audio_extn_utils_update_stream_app_type_cfg_for_usecase(adev,
3242 usecase);
Preetam Singh Ranawata4a37d82014-09-25 16:56:38 +05303243 if (usecase->type == PCM_PLAYBACK) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003244 if ((24 == usecase->stream.out->bit_width) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003245 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_SPEAKER)) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003246 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3247 } else if ((out_snd_device == SND_DEVICE_OUT_HDMI ||
3248 out_snd_device == SND_DEVICE_OUT_USB_HEADSET ||
3249 out_snd_device == SND_DEVICE_OUT_DISPLAY_PORT) &&
3250 (usecase->stream.out->sample_rate >= OUTPUT_SAMPLING_RATE_44100)) {
3251 /*
3252 * To best utlize DSP, check if the stream sample rate is supported/multiple of
3253 * configured device sample rate, if not update the COPP rate to be equal to the
3254 * device sample rate, else open COPP at stream sample rate
3255 */
3256 platform_check_and_update_copp_sample_rate(adev->platform, out_snd_device,
3257 usecase->stream.out->sample_rate,
3258 &usecase->stream.out->app_type_cfg.sample_rate);
Ashish Jain4826f6c2017-02-06 13:33:20 +05303259 } else if (((out_snd_device != SND_DEVICE_OUT_HEADPHONES_44_1 &&
Preetam Singh Ranawat590d0432019-09-30 14:39:47 +05303260 out_snd_device != SND_DEVICE_OUT_HEADPHONES &&
3261 out_snd_device != SND_DEVICE_OUT_HEADPHONES_HIFI_FILTER &&
Ashish Jain4826f6c2017-02-06 13:33:20 +05303262 !audio_is_true_native_stream_active(adev)) &&
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003263 usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) ||
3264 (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05303265 if (!(compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) && ((usecase->stream.out->flags &
3266 (audio_output_flags_t)AUDIO_OUTPUT_FLAG_SYS_NOTIFICATION) || (usecase->stream.out->flags &
3267 (audio_output_flags_t)AUDIO_OUTPUT_FLAG_PHONE)))) {
3268 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3269 }
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003270 }
Weiyin Jiangcdece202019-07-08 16:13:16 +08003271 }
3272 enable_audio_route(adev, usecase);
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003273
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303274 if (uc_id == USECASE_AUDIO_PLAYBACK_VOIP) {
3275 struct stream_in *voip_in = get_voice_communication_input(adev);
3276 struct audio_usecase *voip_in_usecase = NULL;
3277 voip_in_usecase = get_usecase_from_list(adev, USECASE_AUDIO_RECORD_VOIP);
3278 if (voip_in != NULL &&
3279 voip_in_usecase != NULL &&
3280 !(out_snd_device == AUDIO_DEVICE_OUT_SPEAKER ||
3281 out_snd_device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
3282 (voip_in_usecase->in_snd_device ==
3283 platform_get_input_snd_device(adev->platform, voip_in,
3284 &usecase->stream.out->device_list,usecase->type))) {
3285 /*
3286 * if VOIP TX is enabled before VOIP RX, needs to re-route the TX path
3287 * for enabling echo-reference-voip with correct port
3288 */
3289 ALOGD("%s: VOIP TX is enabled before VOIP RX,needs to re-route the TX path",__func__);
3290 disable_audio_route(adev, voip_in_usecase);
3291 disable_snd_device(adev, voip_in_usecase->in_snd_device);
3292 enable_snd_device(adev, voip_in_usecase->in_snd_device);
3293 enable_audio_route(adev, voip_in_usecase);
3294 }
3295 }
Ramjee Singhcdf67af2021-09-29 14:20:27 +05303296 if (voice_extn_compress_voip_is_active(adev)) {
3297 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3298 USECASE_COMPRESS_VOIP_CALL);
3299 /*
3300 * If only compress voip input is opened voip out will be primary out.
3301 * Need to consider re-routing to select correct i/p pair
3302 */
3303 if ((voip_usecase != NULL) &&
3304 (usecase->type == PCM_PLAYBACK) &&
3305 (usecase->stream.out == voip_usecase->stream.out)) {
3306 in_snd_device = platform_get_input_snd_device(adev->platform,
3307 NULL,
3308 &usecase->stream.out->device_list,
3309 usecase->type);
3310 if (voip_usecase->in_snd_device != in_snd_device ) {
3311 ALOGD("%s:Re routing compress voip tx snd device matching voip rx pair",
3312 __func__);
3313 disable_audio_route(adev, voip_usecase);
3314 disable_snd_device(adev, voip_usecase->in_snd_device);
3315 voip_usecase->in_snd_device = in_snd_device;
3316 voip_usecase->out_snd_device = usecase->out_snd_device;
3317 /* Route all TX usecase to Compress voip BE */
3318 check_usecases_capture_codec_backend(adev, voip_usecase, in_snd_device);
3319 enable_snd_device(adev, in_snd_device);
3320 /* Send Voice related calibration for RX /TX pair */
3321 status = platform_switch_voice_call_device_post(adev->platform,
3322 out_snd_device,
3323 in_snd_device);
3324 enable_audio_route(adev, voip_usecase);
3325 }
3326 }
3327 }
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303328
3329
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08003330 audio_extn_qdsp_set_device(usecase);
Aalique Grahame22e49102018-12-18 14:23:57 -08003331
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003332 /* If input stream is already running then effect needs to be
3333 applied on the new input device that's being enabled here. */
Eric Laurent637e2d42018-11-15 12:24:31 -08003334 if (in_snd_device != SND_DEVICE_NONE)
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003335 check_and_enable_effect(adev);
3336
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003337 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003338 /* Enable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303339 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003340 voice_check_and_update_aanc_path(adev, out_snd_device, true);
3341
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003342 /* Enable sidetone only if other voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303343 if (voice_is_call_state_active_in_call(adev) ||
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003344 voice_extn_compress_voip_is_started(adev))
3345 voice_set_sidetone(adev, out_snd_device, true);
3346 }
3347
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003348 /* Applicable only on the targets that has external modem.
3349 * Enable device command should be sent to modem only after
3350 * enabling voice call mixer controls
3351 */
Vidyakumar Athota339342f2014-07-01 15:30:57 -07003352 if (usecase->type == VOICE_CALL)
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003353 status = platform_switch_voice_call_usecase_route_post(adev->platform,
3354 out_snd_device,
3355 in_snd_device);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303356
3357 if (is_btsco_device(out_snd_device, in_snd_device) || is_a2dp_device(out_snd_device)) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003358 struct stream_in *in = adev_get_active_input(adev);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303359 if (usecase->type == VOIP_CALL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003360 if (in != NULL && !in->standby) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303361 if (is_bt_soc_on(adev) == false){
3362 ALOGD("BT SCO MIC disconnected while in connection");
Eric Laurent637e2d42018-11-15 12:24:31 -08003363 if (in->pcm != NULL)
3364 pcm_stop(in->pcm);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303365 }
3366 }
3367 if ((usecase->stream.out != NULL) && (usecase->stream.out != adev->primary_output)
3368 && usecase->stream.out->started) {
3369 if (is_bt_soc_on(adev) == false) {
3370 ALOGD("BT SCO/A2DP disconnected while in connection");
3371 out_standby_l(&usecase->stream.out->stream.common);
3372 }
3373 }
3374 } else if ((usecase->stream.out != NULL) &&
3375 !(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Surendar Karkae1dc8742018-11-19 16:23:14 +05303376 (usecase->type != TRANSCODE_LOOPBACK_TX) &&
3377 (usecase->type != TRANSCODE_LOOPBACK_RX) &&
Weiyin Jiang0d373242019-07-25 13:18:17 +08003378 (usecase->type != PCM_CAPTURE) &&
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303379 usecase->stream.out->started) {
3380 if (is_bt_soc_on(adev) == false) {
3381 ALOGD("BT SCO/A2dp disconnected while in connection");
3382 out_standby_l(&usecase->stream.out->stream.common);
3383 }
3384 }
3385 }
3386
Yung Ti Su70cb8242018-06-22 17:38:47 +08003387 if (usecase->type != PCM_CAPTURE && usecase == voip_usecase) {
Aalique Grahame22e49102018-12-18 14:23:57 -08003388 struct stream_out *voip_out = voip_usecase->stream.out;
3389 audio_extn_utils_send_app_type_gain(adev,
3390 voip_out->app_type_cfg.app_type,
3391 &voip_out->app_type_cfg.gain[0]);
3392 }
3393
Ajender Reddyb940b832021-07-07 11:51:42 +05303394 ALOGD("%s: done",__func__);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303395
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003396 return status;
3397}
3398
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003399static int stop_input_stream(struct stream_in *in)
3400{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303401 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003402 struct audio_usecase *uc_info;
Pallavid7c7a272018-01-16 11:22:55 +05303403
3404 if (in == NULL) {
3405 ALOGE("%s: stream_in ptr is NULL", __func__);
3406 return -EINVAL;
3407 }
3408
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003409 struct audio_device *adev = in->dev;
Carter Hsu2e429db2019-05-14 18:50:52 +08003410 struct stream_in *priority_in = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003411
Eric Laurent994a6932013-07-17 11:51:42 -07003412 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003413 in->usecase, use_case_table[in->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003414 uc_info = get_usecase_from_list(adev, in->usecase);
3415 if (uc_info == NULL) {
3416 ALOGE("%s: Could not find the usecase (%d) in the list",
3417 __func__, in->usecase);
3418 return -EINVAL;
3419 }
3420
Carter Hsu2e429db2019-05-14 18:50:52 +08003421 priority_in = get_priority_input(adev);
3422
Derek Chenea197282019-01-07 17:35:01 -08003423 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3424 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003425
Vidyakumar Athota2850d532013-11-19 16:02:12 -08003426 /* Close in-call recording streams */
3427 voice_check_and_stop_incall_rec_usecase(adev, in);
3428
Eric Laurent150dbfe2013-02-27 14:31:02 -08003429 /* 1. Disable stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003430 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003431
3432 /* 2. Disable the tx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003433 disable_snd_device(adev, uc_info->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003434
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003435 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303436 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
3437
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003438 list_remove(&uc_info->list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05303439 clear_devices(&uc_info->device_list);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003440 free(uc_info);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003441
Carter Hsu2e429db2019-05-14 18:50:52 +08003442 if (priority_in == in) {
3443 priority_in = get_priority_input(adev);
Sujin Panicker110f7942021-08-26 17:01:22 +05303444 if (priority_in) {
3445 if (is_usb_in_device_type(&priority_in->device_list)) {
3446 if (audio_extn_usb_connected(NULL))
3447 select_devices(adev, priority_in->usecase);
3448 } else {
3449 select_devices(adev, priority_in->usecase);
3450 }
3451 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003452 }
3453
Vatsal Buchac09ae062018-11-14 13:25:08 +05303454 enable_gcov();
Eric Laurent994a6932013-07-17 11:51:42 -07003455 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003456 return ret;
3457}
3458
3459int start_input_stream(struct stream_in *in)
3460{
3461 /* 1. Enable output device and stream routing controls */
Eric Laurentc8400632013-02-14 19:04:54 -08003462 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003463 struct audio_usecase *uc_info;
Preetam Singh Ranawata87e9742018-02-13 16:52:53 +05303464
3465 if (in == NULL) {
3466 ALOGE("%s: stream_in ptr is NULL", __func__);
3467 return -EINVAL;
3468 }
3469
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003470 struct audio_device *adev = in->dev;
Garmond Leunge2433c32017-09-28 21:51:22 -07003471 struct pcm_config config = in->config;
Garmond Leung438932f2017-10-04 19:35:18 -07003472 int usecase = platform_update_usecase_from_source(in->source,in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003473
Mingming Yin2664a5b2015-09-03 10:53:11 -07003474 if (get_usecase_from_list(adev, usecase) == NULL)
3475 in->usecase = usecase;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303476 ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
3477 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003478
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303479 if (CARD_STATUS_OFFLINE == in->card_status||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003480 CARD_STATUS_OFFLINE == adev->card_status ||
3481 POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
3482 ALOGW("in->card_status or adev->card_status or adev->input_power offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05303483 ret = -EIO;
Naresh Tanniru4c630392014-05-12 01:05:52 +05303484 goto error_config;
3485 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05303486
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003487 if (is_sco_in_device_type(&in->device_list)) {
Lakshman Chaluvaraju87f53aa2021-02-02 15:50:11 +05303488 if (!adev->bt_sco_on || audio_extn_a2dp_source_is_ready()) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303489 ALOGE("%s: SCO profile is not ready, return error", __func__);
3490 ret = -EIO;
3491 goto error_config;
3492 }
3493 }
3494
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003495 /* Check if source matches incall recording usecase criteria */
3496 ret = voice_check_and_set_incall_rec_usecase(adev, in);
3497 if (ret)
3498 goto error_config;
3499 else
Mingming Yin2664a5b2015-09-03 10:53:11 -07003500 ALOGV("%s: usecase(%d)", __func__, in->usecase);
3501
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303502 if (audio_extn_cin_attached_usecase(in))
3503 audio_extn_cin_acquire_usecase(in);
3504
Mingming Yin2664a5b2015-09-03 10:53:11 -07003505 if (get_usecase_from_list(adev, in->usecase) != NULL) {
3506 ALOGE("%s: use case assigned already in use, stream(%p)usecase(%d: %s)",
3507 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003508 ret = -EINVAL;
3509 goto error_config;
Mingming Yin2664a5b2015-09-03 10:53:11 -07003510 }
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003511
Eric Laurentb23d5282013-05-14 15:27:20 -07003512 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003513 if (in->pcm_device_id < 0) {
3514 ALOGE("%s: Could not find PCM device id for the usecase(%d)",
3515 __func__, in->usecase);
Eric Laurentc8400632013-02-14 19:04:54 -08003516 ret = -EINVAL;
3517 goto error_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003518 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003519
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003520 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003521
3522 if (!uc_info) {
3523 ret = -ENOMEM;
3524 goto error_config;
3525 }
3526
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003527 uc_info->id = in->usecase;
3528 uc_info->type = PCM_CAPTURE;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003529 uc_info->stream.in = in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003530 list_init(&uc_info->device_list);
3531 assign_devices(&uc_info->device_list, &in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003532 uc_info->in_snd_device = SND_DEVICE_NONE;
3533 uc_info->out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003534
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003535 list_add_tail(&adev->usecase_list, &uc_info->list);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003536 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303537 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
3538 adev->perf_lock_opts,
3539 adev->perf_lock_opts_size);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003540 select_devices(adev, in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003541
Derek Chenea197282019-01-07 17:35:01 -08003542 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
3543 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003544
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05303545 android_atomic_acquire_cas(true, false, &(in->capture_stopped));
3546
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303547 if (audio_extn_cin_attached_usecase(in)) {
Manish Dewangan46e07982018-12-13 18:18:59 +05303548 ret = audio_extn_cin_open_input_stream(in);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303549 if (ret)
3550 goto error_open;
3551 else
3552 goto done_open;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003553 }
3554
Haynes Mathew George16081042017-05-31 17:16:49 -07003555 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003556 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003557 ALOGE("%s: pcm stream not ready", __func__);
3558 goto error_open;
3559 }
3560 ret = pcm_start(in->pcm);
3561 if (ret < 0) {
3562 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
3563 goto error_open;
3564 }
3565 } else {
3566 unsigned int flags = PCM_IN | PCM_MONOTONIC;
3567 unsigned int pcm_open_retry_count = 0;
3568
Zhou Song62ea0282020-03-22 19:53:01 +08003569 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) ||
3570 (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003571 flags |= PCM_MMAP | PCM_NOIRQ;
3572 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
3573 } else if (in->realtime) {
3574 flags |= PCM_MMAP | PCM_NOIRQ;
3575 }
3576
Garmond Leunge2433c32017-09-28 21:51:22 -07003577 if (audio_extn_ffv_get_stream() == in) {
3578 ALOGD("%s: ffv stream, update pcm config", __func__);
3579 audio_extn_ffv_update_pcm_config(&config);
3580 }
Haynes Mathew George16081042017-05-31 17:16:49 -07003581 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
3582 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
3583
3584 while (1) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003585 ATRACE_BEGIN("pcm_in_open");
Haynes Mathew George16081042017-05-31 17:16:49 -07003586 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
Garmond Leung438932f2017-10-04 19:35:18 -07003587 flags, &config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003588 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05303589 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05303590 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
3591 adev->card_status = CARD_STATUS_OFFLINE;
3592 in->card_status = CARD_STATUS_OFFLINE;
3593 ret = -EIO;
3594 goto error_open;
3595 }
3596
Haynes Mathew George16081042017-05-31 17:16:49 -07003597 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
3598 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
3599 if (in->pcm != NULL) {
3600 pcm_close(in->pcm);
3601 in->pcm = NULL;
3602 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003603 if (pcm_open_retry_count == 0) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003604 ret = -EIO;
3605 goto error_open;
3606 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003607 pcm_open_retry_count--;
Haynes Mathew George16081042017-05-31 17:16:49 -07003608 usleep(PROXY_OPEN_WAIT_TIME * 1000);
3609 continue;
3610 }
3611 break;
3612 }
3613
3614 ALOGV("%s: pcm_prepare", __func__);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003615 ATRACE_BEGIN("pcm_in_prepare");
Haynes Mathew George16081042017-05-31 17:16:49 -07003616 ret = pcm_prepare(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003617 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003618 if (ret < 0) {
3619 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
3620 pcm_close(in->pcm);
3621 in->pcm = NULL;
3622 goto error_open;
3623 }
Narsinga Rao Chellaa6e1f702021-10-22 13:57:32 +05303624 if (in->flags == AUDIO_INPUT_FLAG_FAST)
3625 register_in_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07003626 if (in->realtime) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003627 ATRACE_BEGIN("pcm_in_start");
Haynes Mathew George16081042017-05-31 17:16:49 -07003628 ret = pcm_start(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003629 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003630 if (ret < 0) {
3631 ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003632 pcm_close(in->pcm);
3633 in->pcm = NULL;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003634 goto error_open;
3635 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003636 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07003637 }
3638
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003639 check_and_enable_effect(adev);
justinweng20fb6d82019-02-21 18:49:00 -07003640 audio_extn_audiozoom_set_microphone_direction(in, in->zoom);
3641 audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003642
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003643 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303644 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
3645
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303646done_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003647 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303648 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Manisha Agarwal4c2402e2020-10-21 12:02:57 +05303649 ALOGD("%s: exit", __func__);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303650 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003651 return ret;
3652
3653error_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003654 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303655 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003656 stop_input_stream(in);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003657
Eric Laurentc8400632013-02-14 19:04:54 -08003658error_config:
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003659 if (audio_extn_cin_attached_usecase(in))
3660 audio_extn_cin_close_input_stream(in);
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05303661 /*
3662 * sleep 50ms to allow sufficient time for kernel
3663 * drivers to recover incases like SSR.
3664 */
3665 usleep(50000);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003666 ALOGD("%s: exit: status(%d)", __func__, ret);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303667 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003668 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003669}
3670
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003671void lock_input_stream(struct stream_in *in)
3672{
3673 pthread_mutex_lock(&in->pre_lock);
3674 pthread_mutex_lock(&in->lock);
3675 pthread_mutex_unlock(&in->pre_lock);
3676}
3677
3678void lock_output_stream(struct stream_out *out)
3679{
3680 pthread_mutex_lock(&out->pre_lock);
3681 pthread_mutex_lock(&out->lock);
3682 pthread_mutex_unlock(&out->pre_lock);
3683}
3684
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003685/* must be called with out->lock locked */
3686static int send_offload_cmd_l(struct stream_out* out, int command)
3687{
3688 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
3689
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003690 if (!cmd) {
3691 ALOGE("failed to allocate mem for command 0x%x", command);
3692 return -ENOMEM;
3693 }
3694
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003695 ALOGVV("%s %d", __func__, command);
3696
3697 cmd->cmd = command;
3698 list_add_tail(&out->offload_cmd_list, &cmd->node);
3699 pthread_cond_signal(&out->offload_cond);
3700 return 0;
3701}
3702
Gautam Manam14c198b2020-12-24 14:08:04 +05303703/* must be called with out->lock */
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003704static void stop_compressed_output_l(struct stream_out *out)
3705{
Gautam Manam14c198b2020-12-24 14:08:04 +05303706 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003707 out->offload_state = OFFLOAD_STATE_IDLE;
Gautam Manam14c198b2020-12-24 14:08:04 +05303708 pthread_mutex_unlock(&out->latch_lock);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08003709
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003710 out->playback_started = 0;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07003711 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003712 if (out->compr != NULL) {
3713 compress_stop(out->compr);
3714 while (out->offload_thread_blocked) {
3715 pthread_cond_wait(&out->cond, &out->lock);
3716 }
3717 }
3718}
3719
Varun Balaraje49253e2017-07-06 19:48:56 +05303720bool is_interactive_usecase(audio_usecase_t uc_id)
3721{
3722 unsigned int i;
3723 for (i = 0; i < sizeof(interactive_usecases)/sizeof(interactive_usecases[0]); i++) {
3724 if (uc_id == interactive_usecases[i])
3725 return true;
3726 }
3727 return false;
3728}
3729
3730static audio_usecase_t get_interactive_usecase(struct audio_device *adev)
3731{
3732 audio_usecase_t ret_uc = USECASE_INVALID;
3733 unsigned int intract_uc_index;
3734 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3735
3736 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
3737 for (intract_uc_index = 0; intract_uc_index < num_usecase; intract_uc_index++) {
3738 if (!(adev->interactive_usecase_state & (0x1 << intract_uc_index))) {
3739 adev->interactive_usecase_state |= 0x1 << intract_uc_index;
3740 ret_uc = interactive_usecases[intract_uc_index];
3741 break;
3742 }
3743 }
3744
3745 ALOGV("%s: Interactive usecase is %d", __func__, ret_uc);
3746 return ret_uc;
3747}
3748
3749static void free_interactive_usecase(struct audio_device *adev,
3750 audio_usecase_t uc_id)
3751{
3752 unsigned int interact_uc_index;
3753 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3754
3755 for (interact_uc_index = 0; interact_uc_index < num_usecase; interact_uc_index++) {
3756 if (interactive_usecases[interact_uc_index] == uc_id) {
3757 adev->interactive_usecase_state &= ~(0x1 << interact_uc_index);
3758 break;
3759 }
3760 }
3761 ALOGV("%s: free Interactive usecase %d", __func__, uc_id);
3762}
3763
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003764bool is_offload_usecase(audio_usecase_t uc_id)
3765{
3766 unsigned int i;
3767 for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
3768 if (uc_id == offload_usecases[i])
3769 return true;
3770 }
3771 return false;
3772}
3773
Dhananjay Kumarac341582017-02-23 23:42:25 +05303774static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_compress)
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003775{
vivek mehta446c3962015-09-14 10:57:35 -07003776 audio_usecase_t ret_uc = USECASE_INVALID;
3777 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003778 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003779 if (!adev->multi_offload_enable) {
Dhananjay Kumarac341582017-02-23 23:42:25 +05303780 if (!is_compress)
vivek mehta446c3962015-09-14 10:57:35 -07003781 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
3782 else
3783 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003784
vivek mehta446c3962015-09-14 10:57:35 -07003785 pthread_mutex_lock(&adev->lock);
3786 if (get_usecase_from_list(adev, ret_uc) != NULL)
3787 ret_uc = USECASE_INVALID;
3788 pthread_mutex_unlock(&adev->lock);
3789
3790 return ret_uc;
3791 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003792
3793 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
vivek mehta446c3962015-09-14 10:57:35 -07003794 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3795 if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) {
3796 adev->offload_usecases_state |= 0x1 << offload_uc_index;
3797 ret_uc = offload_usecases[offload_uc_index];
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003798 break;
3799 }
3800 }
vivek mehta446c3962015-09-14 10:57:35 -07003801
3802 ALOGV("%s: offload usecase is %d", __func__, ret_uc);
3803 return ret_uc;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003804}
3805
3806static void free_offload_usecase(struct audio_device *adev,
3807 audio_usecase_t uc_id)
3808{
vivek mehta446c3962015-09-14 10:57:35 -07003809 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003810 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003811
3812 if (!adev->multi_offload_enable)
3813 return;
3814
3815 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3816 if (offload_usecases[offload_uc_index] == uc_id) {
3817 adev->offload_usecases_state &= ~(0x1 << offload_uc_index);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003818 break;
3819 }
3820 }
3821 ALOGV("%s: free offload usecase %d", __func__, uc_id);
3822}
3823
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003824static void *offload_thread_loop(void *context)
3825{
3826 struct stream_out *out = (struct stream_out *) context;
3827 struct listnode *item;
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003828 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003829
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003830 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08003831 set_sched_policy(0, SP_FOREGROUND);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003832 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
3833
3834 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003835 lock_output_stream(out);
juyuchen391b5fa2018-12-12 17:58:09 +08003836 out->offload_state = OFFLOAD_STATE_IDLE;
3837 out->playback_started = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003838 for (;;) {
3839 struct offload_cmd *cmd = NULL;
3840 stream_callback_event_t event;
3841 bool send_callback = false;
3842
3843 ALOGVV("%s offload_cmd_list %d out->offload_state %d",
3844 __func__, list_empty(&out->offload_cmd_list),
3845 out->offload_state);
3846 if (list_empty(&out->offload_cmd_list)) {
3847 ALOGV("%s SLEEPING", __func__);
3848 pthread_cond_wait(&out->offload_cond, &out->lock);
3849 ALOGV("%s RUNNING", __func__);
3850 continue;
3851 }
3852
3853 item = list_head(&out->offload_cmd_list);
3854 cmd = node_to_item(item, struct offload_cmd, node);
3855 list_remove(item);
3856
3857 ALOGVV("%s STATE %d CMD %d out->compr %p",
3858 __func__, out->offload_state, cmd->cmd, out->compr);
3859
3860 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
3861 free(cmd);
3862 break;
3863 }
3864
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08003865 // allow OFFLOAD_CMD_ERROR reporting during standby
3866 // this is needed to handle failures during compress_open
3867 // Note however that on a pause timeout, the stream is closed
3868 // and no offload usecase will be active. Therefore this
3869 // special case is needed for compress_open failures alone
3870 if (cmd->cmd != OFFLOAD_CMD_ERROR &&
3871 out->compr == NULL) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003872 ALOGE("%s: Compress handle is NULL", __func__);
Haynes Mathew Georgea9abb202016-06-02 14:13:20 -07003873 free(cmd);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003874 pthread_cond_signal(&out->cond);
3875 continue;
3876 }
3877 out->offload_thread_blocked = true;
3878 pthread_mutex_unlock(&out->lock);
3879 send_callback = false;
3880 switch(cmd->cmd) {
3881 case OFFLOAD_CMD_WAIT_FOR_BUFFER:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003882 ALOGD("copl(%p):calling compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003883 compress_wait(out->compr, -1);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003884 ALOGD("copl(%p):out of compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003885 send_callback = true;
3886 event = STREAM_CBK_EVENT_WRITE_READY;
3887 break;
3888 case OFFLOAD_CMD_PARTIAL_DRAIN:
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003889 ret = compress_next_track(out->compr);
Sidipotu Ashok55820562014-02-10 16:16:38 +05303890 if(ret == 0) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003891 ALOGD("copl(%p):calling compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303892 ret = compress_partial_drain(out->compr);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003893 ALOGD("copl(%p):out of compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303894 if (ret < 0)
3895 ret = -errno;
Sidipotu Ashok55820562014-02-10 16:16:38 +05303896 }
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303897 else if (ret == -ETIMEDOUT)
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003898 ret = compress_drain(out->compr);
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003899 else
3900 ALOGE("%s: Next track returned error %d",__func__, ret);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003901 if (-ENETRESET != ret && !(-EINTR == ret &&
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003902 (CARD_STATUS_OFFLINE == out->card_status ||
3903 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303904 send_callback = true;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05303905 pthread_mutex_lock(&out->lock);
3906 out->send_new_metadata = 1;
3907 out->send_next_track_params = true;
3908 pthread_mutex_unlock(&out->lock);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303909 event = STREAM_CBK_EVENT_DRAIN_READY;
3910 ALOGV("copl(%p):send drain callback, ret %d", out, ret);
3911 } else
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303912 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003913 break;
3914 case OFFLOAD_CMD_DRAIN:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003915 ALOGD("copl(%p):calling compress_drain", out);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003916 ret = compress_drain(out->compr);
3917 ALOGD("copl(%p):out of compress_drain", out);
3918 // EINTR check avoids drain interruption due to SSR
3919 if (-ENETRESET != ret && !(-EINTR == ret &&
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003920 (CARD_STATUS_OFFLINE == out->card_status ||
3921 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003922 send_callback = true;
3923 event = STREAM_CBK_EVENT_DRAIN_READY;
3924 } else
3925 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003926 break;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303927 case OFFLOAD_CMD_ERROR:
3928 ALOGD("copl(%p): sending error callback to AF", out);
3929 send_callback = true;
3930 event = STREAM_CBK_EVENT_ERROR;
3931 break;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003932 default:
3933 ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
3934 break;
3935 }
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003936 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003937 out->offload_thread_blocked = false;
3938 pthread_cond_signal(&out->cond);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08003939 if (send_callback && out->client_callback) {
3940 ALOGVV("%s: sending client_callback event %d", __func__, event);
3941 out->client_callback(event, NULL, out->client_cookie);
Eric Laurent6e895242013-09-05 16:10:57 -07003942 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003943 free(cmd);
3944 }
3945
3946 pthread_cond_signal(&out->cond);
3947 while (!list_empty(&out->offload_cmd_list)) {
3948 item = list_head(&out->offload_cmd_list);
3949 list_remove(item);
3950 free(node_to_item(item, struct offload_cmd, node));
3951 }
3952 pthread_mutex_unlock(&out->lock);
3953
3954 return NULL;
3955}
3956
3957static int create_offload_callback_thread(struct stream_out *out)
3958{
3959 pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
3960 list_init(&out->offload_cmd_list);
3961 pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
3962 offload_thread_loop, out);
3963 return 0;
3964}
3965
3966static int destroy_offload_callback_thread(struct stream_out *out)
3967{
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003968 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003969 stop_compressed_output_l(out);
3970 send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
3971
3972 pthread_mutex_unlock(&out->lock);
3973 pthread_join(out->offload_thread, (void **) NULL);
3974 pthread_cond_destroy(&out->offload_cond);
3975
3976 return 0;
3977}
3978
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003979static int stop_output_stream(struct stream_out *out)
3980{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303981 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003982 struct audio_usecase *uc_info;
3983 struct audio_device *adev = out->dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08003984 bool has_voip_usecase =
3985 get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP) != NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003986
Eric Laurent994a6932013-07-17 11:51:42 -07003987 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003988 out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003989 uc_info = get_usecase_from_list(adev, out->usecase);
3990 if (uc_info == NULL) {
3991 ALOGE("%s: Could not find the usecase (%d) in the list",
3992 __func__, out->usecase);
3993 return -EINVAL;
3994 }
3995
Zhou Songbaddf9f2020-11-20 13:57:39 +08003996 out->a2dp_muted = false;
3997
Derek Chenea197282019-01-07 17:35:01 -08003998 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3999 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004000
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004001 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304002 !(audio_extn_passthru_is_passthrough_stream(out))) {
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004003 if (adev->visualizer_stop_output != NULL)
4004 adev->visualizer_stop_output(out->handle, out->pcm_device_id);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004005
4006 audio_extn_dts_remove_state_notifier_node(out->usecase);
4007
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004008 if (adev->offload_effects_stop_output != NULL)
4009 adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
vivek mehtad15d2bf2019-05-17 13:35:10 -07004010 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4011 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4012 audio_low_latency_hint_end();
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004013 }
Eric Laurentc4aef752013-09-12 17:45:53 -07004014
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004015 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4016 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004017 voice_set_device_mute_flag(adev, false);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004018 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004019
Eric Laurent150dbfe2013-02-27 14:31:02 -08004020 /* 1. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07004021 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004022
4023 /* 2. Disable the rx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07004024 disable_snd_device(adev, uc_info->out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08004025 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
4026 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004027
Aalique Grahame22e49102018-12-18 14:23:57 -08004028 audio_extn_extspk_update(adev->extspk);
4029
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004030 if (is_offload_usecase(out->usecase)) {
4031 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4032 adev->dsp_bit_width_enforce_mode,
4033 false);
4034 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004035 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004036 ret = audio_extn_usb_check_and_set_svc_int(uc_info,
4037 false);
4038
4039 if (ret != 0)
4040 check_usecases_codec_backend(adev, uc_info, uc_info->out_snd_device);
4041 /* default service interval was successfully updated,
4042 reopen USB backend with new service interval */
4043 ret = 0;
4044 }
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004045
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004046 list_remove(&uc_info->list);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304047 out->started = 0;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004048 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304049 (audio_extn_passthru_is_passthrough_stream(out))) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004050 ALOGV("Disable passthrough , reset mixer to pcm");
4051 /* NO_PASSTHROUGH */
Meng Wang4c32fb42020-01-16 17:57:11 +08004052#ifdef AUDIO_GKI_ENABLED
4053 /* out->compr_config.codec->reserved[0] is for compr_passthr */
4054 out->compr_config.codec->reserved[0] = 0;
4055#else
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004056 out->compr_config.codec->compr_passthr = 0;
Meng Wang4c32fb42020-01-16 17:57:11 +08004057#endif
Mingming Yin21854652016-04-13 11:54:02 -07004058 audio_extn_passthru_on_stop(out);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004059 audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
4060 }
Eric Laurent07eeafd2013-10-06 12:52:49 -07004061
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304062 /* Must be called after removing the usecase from list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004063 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL))
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304064 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304065
Manish Dewangan21a850a2017-08-14 12:03:55 +05304066 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07004067 ret = audio_extn_ip_hdlr_intf_close(out->ip_hdlr_handle, true, out);
4068 if (ret < 0)
4069 ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
4070 }
4071
Zhou Song642ec432020-12-23 16:11:10 +08004072 /* trigger voip input to reroute when voip output changes to hearing aid */
Aalique Grahame22e49102018-12-18 14:23:57 -08004073 if (has_voip_usecase ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004074 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08004075 struct listnode *node;
4076 struct audio_usecase *usecase;
4077 list_for_each(node, &adev->usecase_list) {
4078 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Song642ec432020-12-23 16:11:10 +08004079 if (usecase->type == PCM_PLAYBACK || usecase == uc_info ||
4080 (usecase->type == PCM_CAPTURE &&
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05304081 usecase->id != USECASE_AUDIO_RECORD_VOIP &&
Zhou Song642ec432020-12-23 16:11:10 +08004082 usecase->id != USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY))
Aalique Grahame22e49102018-12-18 14:23:57 -08004083 continue;
4084
4085 ALOGD("%s: select_devices at usecase(%d: %s) after removing the usecase(%d: %s)",
4086 __func__, usecase->id, use_case_table[usecase->id],
4087 out->usecase, use_case_table[out->usecase]);
4088 select_devices(adev, usecase->id);
4089 }
4090 }
4091
Zhenlin Lian4f947842022-05-14 15:50:52 +05304092 clear_devices(&uc_info->device_list);
Garmond Leung5fd0b552018-04-17 11:56:12 -07004093 free(uc_info);
Eric Laurent994a6932013-07-17 11:51:42 -07004094 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004095 return ret;
4096}
4097
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004098struct pcm* pcm_open_prepare_helper(unsigned int snd_card, unsigned int pcm_device_id,
4099 unsigned int flags, unsigned int pcm_open_retry_count,
4100 struct pcm_config *config)
4101{
4102 struct pcm* pcm = NULL;
4103
4104 while (1) {
4105 pcm = pcm_open(snd_card, pcm_device_id, flags, config);
4106 if (pcm == NULL || !pcm_is_ready(pcm)) {
4107 ALOGE("%s: %s", __func__, pcm_get_error(pcm));
4108 if (pcm != NULL) {
4109 pcm_close(pcm);
4110 pcm = NULL;
4111 }
Weiyin Jiang72197252019-10-09 11:49:32 +08004112 if (pcm_open_retry_count == 0)
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004113 return NULL;
4114
Weiyin Jiang72197252019-10-09 11:49:32 +08004115 pcm_open_retry_count--;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004116 usleep(PROXY_OPEN_WAIT_TIME * 1000);
4117 continue;
4118 }
4119 break;
4120 }
4121
4122 if (pcm_is_ready(pcm)) {
4123 int ret = pcm_prepare(pcm);
4124 if (ret < 0) {
4125 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
4126 pcm_close(pcm);
4127 pcm = NULL;
4128 }
4129 }
4130
4131 return pcm;
4132}
4133
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004134int start_output_stream(struct stream_out *out)
4135{
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004136 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004137 struct audio_usecase *uc_info;
4138 struct audio_device *adev = out->dev;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004139 char mixer_ctl_name[128];
4140 struct mixer_ctl *ctl = NULL;
4141 char* perf_mode[] = {"ULL", "ULL_PP", "LL"};
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304142 bool a2dp_combo = false;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004143 bool is_haptic_usecase = (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) ? true: false;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004144
Haynes Mathew George380745d2017-10-04 15:27:45 -07004145 ATRACE_BEGIN("start_output_stream");
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004146 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
4147 ret = -EINVAL;
4148 goto error_config;
4149 }
4150
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004151 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x) is_haptic_usecase(%d)",
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304152 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004153 get_device_types(&out->device_list), is_haptic_usecase);
4154
4155 bool is_speaker_active = compare_device_type(&out->device_list,
4156 AUDIO_DEVICE_OUT_SPEAKER);
4157 bool is_speaker_safe_active = compare_device_type(&out->device_list,
4158 AUDIO_DEVICE_OUT_SPEAKER_SAFE);
Naresh Tanniru4c630392014-05-12 01:05:52 +05304159
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304160 if (CARD_STATUS_OFFLINE == out->card_status ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05004161 CARD_STATUS_OFFLINE == adev->card_status ||
4162 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304163 ALOGW("out->card_status or adev->card_status offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05304164 ret = -EIO;
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004165 goto error_fatal;
Naresh Tanniru4c630392014-05-12 01:05:52 +05304166 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05304167
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004168 //Update incall music usecase to reflect correct voice session
4169 if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
4170 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
4171 if (ret != 0) {
4172 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
4173 __func__, ret);
4174 goto error_config;
4175 }
4176 }
4177
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004178 if (is_a2dp_out_device_type(&out->device_list)) {
Florian Pfister1a84f312018-07-19 14:38:18 +02004179 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004180 if (is_speaker_active || is_speaker_safe_active) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304181 a2dp_combo = true;
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304182 } else {
Zhou Songd01e7a22020-09-23 22:49:01 +08004183 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304184 ALOGE("%s: A2DP profile is not ready, return error", __func__);
4185 ret = -EAGAIN;
4186 goto error_config;
4187 }
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304188 }
4189 }
4190 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004191 if (is_sco_out_device_type(&out->device_list)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304192 if (!adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004193 if (is_speaker_active) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304194 //combo usecase just by pass a2dp
4195 ALOGW("%s: SCO is not connected, route it to speaker", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004196 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304197 } else {
4198 ALOGE("%s: SCO profile is not ready, return error", __func__);
4199 ret = -EAGAIN;
4200 goto error_config;
4201 }
4202 }
4203 }
4204
Eric Laurentb23d5282013-05-14 15:27:20 -07004205 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004206 if (out->pcm_device_id < 0) {
4207 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
4208 __func__, out->pcm_device_id, out->usecase);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004209 ret = -EINVAL;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004210 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004211 }
4212
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004213 if (is_haptic_usecase) {
Meng Wang51d8c2a2020-04-27 15:23:21 +08004214 adev->haptic_pcm_device_id = platform_get_pcm_device_id(
4215 USECASE_AUDIO_PLAYBACK_HAPTICS, PCM_PLAYBACK);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004216 if (adev->haptic_pcm_device_id < 0) {
4217 ALOGE("%s: Invalid Haptics pcm device id(%d) for the usecase(%d)",
4218 __func__, adev->haptic_pcm_device_id, out->usecase);
4219 ret = -EINVAL;
4220 goto error_config;
4221 }
4222 }
4223
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004224 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004225
4226 if (!uc_info) {
4227 ret = -ENOMEM;
4228 goto error_config;
4229 }
4230
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004231 uc_info->id = out->usecase;
4232 uc_info->type = PCM_PLAYBACK;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08004233 uc_info->stream.out = out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004234 list_init(&uc_info->device_list);
4235 assign_devices(&uc_info->device_list, &out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004236 uc_info->in_snd_device = SND_DEVICE_NONE;
4237 uc_info->out_snd_device = SND_DEVICE_NONE;
Garmond Leung5fd0b552018-04-17 11:56:12 -07004238
4239 /* This must be called before adding this usecase to the list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004240 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004241 audio_extn_usb_check_and_set_svc_int(uc_info, true);
4242 /* USB backend is not reopened immediately.
4243 This is eventually done as part of select_devices */
4244 }
4245
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004246 list_add_tail(&adev->usecase_list, &uc_info->list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004247
Wei Wangf7ca6c92017-11-21 14:51:20 -08004248 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304249 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
4250 adev->perf_lock_opts,
4251 adev->perf_lock_opts_size);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304252
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004253 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304254 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304255 if (audio_extn_passthru_is_enabled() &&
4256 audio_extn_passthru_is_passthrough_stream(out)) {
4257 audio_extn_passthru_on_start(out);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304258 }
4259 }
4260
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004261 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02004262 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304263 if (!a2dp_combo) {
4264 check_a2dp_restore_l(adev, out, false);
4265 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004266 struct listnode dev;
4267 list_init(&dev);
4268 assign_devices(&dev, &out->device_list);
4269 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4270 reassign_device_list(&out->device_list,
4271 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aalique Grahame22e49102018-12-18 14:23:57 -08004272 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004273 reassign_device_list(&out->device_list,
4274 AUDIO_DEVICE_OUT_SPEAKER, "");
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304275 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004276 assign_devices(&out->device_list, &dev);
Zhenlin Lian4f947842022-05-14 15:50:52 +05304277 clear_devices(&dev);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304278 }
4279 } else {
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304280 select_devices(adev, out->usecase);
4281 if (is_a2dp_out_device_type(&out->device_list) &&
4282 !adev->a2dp_started) {
4283 if (is_speaker_active || is_speaker_safe_active) {
4284 struct listnode dev;
4285 list_init(&dev);
4286 assign_devices(&dev, &out->device_list);
4287 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4288 reassign_device_list(&out->device_list,
4289 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
4290 else
4291 reassign_device_list(&out->device_list,
4292 AUDIO_DEVICE_OUT_SPEAKER, "");
4293 select_devices(adev, out->usecase);
4294 assign_devices(&out->device_list, &dev);
Zhenlin Lian4f947842022-05-14 15:50:52 +05304295 clear_devices(&dev);
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304296 } else {
4297 ret = -EINVAL;
4298 goto error_open;
4299 }
4300 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304301 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004302
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004303 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4304 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004305 voice_set_device_mute_flag(adev, true);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004306 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004307
Derek Chenea197282019-01-07 17:35:01 -08004308 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
4309 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004310
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004311 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
4312 __func__, adev->snd_card, out->pcm_device_id, out->config.format);
Haynes Mathew George16081042017-05-31 17:16:49 -07004313
4314 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07004315 ALOGD("%s: Starting MMAP stream", __func__);
Haynes Mathew George16081042017-05-31 17:16:49 -07004316 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4317 ALOGE("%s: pcm stream not ready", __func__);
4318 goto error_open;
4319 }
4320 ret = pcm_start(out->pcm);
4321 if (ret < 0) {
4322 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
4323 goto error_open;
4324 }
Arun Mirpuri5d170872019-03-26 13:21:31 -07004325 out_set_mmap_volume(&out->stream, out->volume_l, out->volume_r);
Haynes Mathew George16081042017-05-31 17:16:49 -07004326 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004327 unsigned int flags = PCM_OUT;
4328 unsigned int pcm_open_retry_count = 0;
4329 if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
4330 flags |= PCM_MMAP | PCM_NOIRQ;
4331 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004332 } else if (out->realtime) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08004333 flags |= PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004334 } else
4335 flags |= PCM_MONOTONIC;
4336
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004337 if ((adev->vr_audio_mode_enabled) &&
4338 (out->flags & AUDIO_OUTPUT_FLAG_RAW)) {
4339 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
4340 "PCM_Dev %d Topology", out->pcm_device_id);
4341 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
4342 if (!ctl) {
4343 ALOGI("%s: Could not get ctl for mixer cmd might be ULL - %s",
4344 __func__, mixer_ctl_name);
4345 } else {
4346 //if success use ULLPP
4347 ALOGI("%s: mixer ctrl %s succeeded setting up ULL for %d",
4348 __func__, mixer_ctl_name, out->pcm_device_id);
4349 //There is a still a possibility that some sessions
4350 // that request for FAST|RAW when 3D audio is active
4351 //can go through ULLPP. Ideally we expects apps to
4352 //listen to audio focus and stop concurrent playback
4353 //Also, we will look for mode flag (voice_in_communication)
4354 //before enabling the realtime flag.
4355 mixer_ctl_set_enum_by_string(ctl, perf_mode[1]);
4356 }
4357 }
4358
Vatsal Bucha3f39f222021-06-29 16:16:55 +05304359 platform_set_stream_channel_map(adev->platform, out->channel_mask,
4360 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Surendar Karka91fa3682018-07-02 18:12:12 +05304361
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004362 out->pcm = pcm_open_prepare_helper(adev->snd_card, out->pcm_device_id,
4363 flags, pcm_open_retry_count,
4364 &(out->config));
4365 if (out->pcm == NULL) {
4366 ret = -EIO;
4367 goto error_open;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004368 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004369
4370 if (is_haptic_usecase) {
4371 adev->haptic_pcm = pcm_open_prepare_helper(adev->snd_card,
4372 adev->haptic_pcm_device_id,
4373 flags, pcm_open_retry_count,
4374 &(adev->haptics_config));
4375 // failure to open haptics pcm shouldnt stop audio,
4376 // so do not close audio pcm in case of error
Vignesh Kulothungane4039c12019-05-07 15:51:39 -07004377
4378 if (property_get_bool("vendor.audio.enable_haptic_audio_sync", false)) {
4379 ALOGD("%s: enable haptic audio synchronization", __func__);
4380 platform_set_qtime(adev->platform, out->pcm_device_id, adev->haptic_pcm_device_id);
4381 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004382 }
4383
Zhou Song2b8f28f2017-09-11 10:51:38 +08004384 // apply volume for voip playback after path is set up
4385 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
4386 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
Ramu Gottipati36547092018-12-28 11:32:09 +05304387 else if ((out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY || out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
4388 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) && (out->apply_volume)) {
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304389 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
4390 out->apply_volume = false;
Derek Chenf13dd492018-11-13 14:53:51 -08004391 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
4392 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05304393#ifdef SOFT_VOLUME
4394 out_set_soft_volume_params(&out->stream);
4395#endif
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304396 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004397 } else {
Zhou Song79929fe2020-01-20 17:57:43 +08004398 /*
4399 * set custom channel map if:
4400 * 1. neither mono nor stereo clips i.e. channels > 2 OR
4401 * 2. custom channel map has been set by client
4402 * else default channel map of FC/FR/FL can always be set to DSP
4403 */
4404 if (popcount(out->channel_mask) > 2 || out->channel_map_param.channel_map[0])
4405 platform_set_stream_channel_map(adev->platform, out->channel_mask,
Weiyin Jiang810a80d2021-01-18 16:04:31 +08004406 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004407 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4408 adev->dsp_bit_width_enforce_mode,
4409 true);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004410 out->pcm = NULL;
Haynes Mathew George380745d2017-10-04 15:27:45 -07004411 ATRACE_BEGIN("compress_open");
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -08004412 out->compr = compress_open(adev->snd_card,
4413 out->pcm_device_id,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004414 COMPRESS_IN, &out->compr_config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004415 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05304416 if (errno == ENETRESET && !is_compress_ready(out->compr)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05304417 ALOGE("%s: compress_open failed errno:%d\n", __func__, errno);
4418 adev->card_status = CARD_STATUS_OFFLINE;
4419 out->card_status = CARD_STATUS_OFFLINE;
4420 ret = -EIO;
4421 goto error_open;
4422 }
4423
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004424 if (out->compr && !is_compress_ready(out->compr)) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004425 ALOGE("%s: failed /w error %s", __func__, compress_get_error(out->compr));
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004426 compress_close(out->compr);
4427 out->compr = NULL;
4428 ret = -EIO;
4429 goto error_open;
4430 }
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304431 /* compress_open sends params of the track, so reset the flag here */
4432 out->is_compr_metadata_avail = false;
4433
Ben Rombergerd771a7c2017-02-22 18:05:17 -08004434 if (out->client_callback)
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004435 compress_nonblock(out->compr, out->non_blocking);
Eric Laurentc4aef752013-09-12 17:45:53 -07004436
Fred Oh3f43e742015-03-04 18:42:34 -08004437 /* Since small bufs uses blocking writes, a write will be blocked
4438 for the default max poll time (20s) in the event of an SSR.
4439 Reduce the poll time to observe and deal with SSR faster.
4440 */
Ashish Jain5106d362016-05-11 19:23:33 +05304441 if (!out->non_blocking) {
Fred Oh3f43e742015-03-04 18:42:34 -08004442 compress_set_max_poll_wait(out->compr, 1000);
4443 }
4444
Manish Dewangan69426c82017-01-30 17:35:36 +05304445 audio_extn_utils_compress_set_render_mode(out);
Manish Dewangan58229382017-02-02 15:48:41 +05304446 audio_extn_utils_compress_set_clk_rec_mode(uc_info);
Manish Dewangan69426c82017-01-30 17:35:36 +05304447
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004448 audio_extn_dts_create_state_notifier_node(out->usecase);
4449 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
4450 popcount(out->channel_mask),
4451 out->playback_started);
4452
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004453#ifdef DS1_DOLBY_DDP_ENABLED
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05304454 if (audio_extn_utils_is_dolby_format(out->format))
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004455 audio_extn_dolby_send_ddp_endp_params(adev);
4456#endif
Preetam Singh Ranawatd18d8832017-02-08 17:34:54 +05304457 if (!(audio_extn_passthru_is_passthrough_stream(out)) &&
4458 (out->sample_rate != 176400 && out->sample_rate <= 192000)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004459 if (adev->visualizer_start_output != NULL)
4460 adev->visualizer_start_output(out->handle, out->pcm_device_id);
4461 if (adev->offload_effects_start_output != NULL)
Ashish Jain5106d362016-05-11 19:23:33 +05304462 adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004463 audio_extn_check_and_set_dts_hpx_state(adev);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004464 }
Derek Chenf13dd492018-11-13 14:53:51 -08004465
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004466 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf13dd492018-11-13 14:53:51 -08004467 /* Update cached volume from media to offload/direct stream */
4468 struct listnode *node = NULL;
4469 list_for_each(node, &adev->active_outputs_list) {
4470 streams_output_ctxt_t *out_ctxt = node_to_item(node,
4471 streams_output_ctxt_t,
4472 list);
4473 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
4474 out->volume_l = out_ctxt->output->volume_l;
4475 out->volume_r = out_ctxt->output->volume_r;
4476 }
4477 }
4478 out_set_compr_volume(&out->stream,
4479 out->volume_l, out->volume_r);
4480 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004481 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004482
4483 if (ret == 0) {
Narsinga Rao Chellaa6e1f702021-10-22 13:57:32 +05304484 if (out->flags == AUDIO_OUTPUT_FLAG_FAST)
4485 register_out_stream(out);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004486 if (out->realtime) {
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07004487 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4488 ALOGE("%s: pcm stream not ready", __func__);
4489 goto error_open;
4490 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07004491 ATRACE_BEGIN("pcm_start");
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004492 ret = pcm_start(out->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004493 ATRACE_END();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004494 if (ret < 0)
4495 goto error_open;
4496 }
4497 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004498 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304499 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Jaideep Sharma0fa53812020-09-17 09:00:11 +05304500 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004501
vivek mehtad15d2bf2019-05-17 13:35:10 -07004502 if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4503 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4504 audio_low_latency_hint_start();
4505 }
4506
Manish Dewangan21a850a2017-08-14 12:03:55 +05304507 if (out->ip_hdlr_handle) {
Vidyakumar Athota6d655882017-05-22 18:26:24 -07004508 ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07004509 if (ret < 0)
4510 ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
4511 }
4512
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07004513 // consider a scenario where on pause lower layers are tear down.
4514 // so on resume, swap mixer control need to be sent only when
4515 // backend is active, hence rather than sending from enable device
4516 // sending it from start of streamtream
4517
4518 platform_set_swap_channels(adev, true);
4519
Haynes Mathew George380745d2017-10-04 15:27:45 -07004520 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304521 enable_gcov();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004522 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004523error_open:
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004524 if (adev->haptic_pcm) {
4525 pcm_close(adev->haptic_pcm);
4526 adev->haptic_pcm = NULL;
4527 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004528 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304529 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004530 stop_output_stream(out);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004531error_fatal:
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05304532 /*
4533 * sleep 50ms to allow sufficient time for kernel
4534 * drivers to recover incases like SSR.
4535 */
4536 usleep(50000);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004537error_config:
Haynes Mathew George380745d2017-10-04 15:27:45 -07004538 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304539 enable_gcov();
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004540 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004541}
4542
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004543static int check_input_parameters(uint32_t sample_rate,
4544 audio_format_t format,
Aalique Grahame22e49102018-12-18 14:23:57 -08004545 int channel_count,
4546 bool is_usb_hifi)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004547{
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004548 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004549
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304550 if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
4551 (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) &&
4552 (format != AUDIO_FORMAT_PCM_FLOAT)) &&
Mingming Yine62d7842013-10-25 16:26:03 -07004553 !voice_extn_compress_voip_is_format_supported(format) &&
Ralf Herzaec80262018-07-03 07:08:49 +02004554 !audio_extn_compr_cap_format_supported(format) &&
4555 !audio_extn_cin_format_supported(format))
Haynes Mathew George484e8d22017-07-31 18:55:17 -07004556 ret = -EINVAL;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004557
Aalique Grahame22e49102018-12-18 14:23:57 -08004558 int max_channel_count = is_usb_hifi ? MAX_HIFI_CHANNEL_COUNT : MAX_CHANNEL_COUNT;
4559 if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > max_channel_count)) {
4560 ALOGE("%s: unsupported channel count (%d) passed Min / Max (%d / %d)", __func__,
4561 channel_count, MIN_CHANNEL_COUNT, max_channel_count);
4562 return -EINVAL;
4563 }
4564
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004565 switch (channel_count) {
4566 case 1:
4567 case 2:
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05304568 case 3:
4569 case 4:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004570 case 6:
Karthikeyan Mani07faa602018-08-20 11:01:32 -07004571 case 8:
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05304572 case 10:
4573 case 12:
4574 case 14:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004575 break;
4576 default:
4577 ret = -EINVAL;
4578 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004579
4580 switch (sample_rate) {
4581 case 8000:
4582 case 11025:
4583 case 12000:
4584 case 16000:
4585 case 22050:
4586 case 24000:
4587 case 32000:
4588 case 44100:
4589 case 48000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004590 case 88200:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304591 case 96000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004592 case 176400:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304593 case 192000:
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004594 break;
4595 default:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004596 ret = -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004597 }
4598
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004599 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004600}
4601
Naresh Tanniru04f71882018-06-26 17:46:22 +05304602
4603/** Add a value in a list if not already present.
4604 * @return true if value was successfully inserted or already present,
4605 * false if the list is full and does not contain the value.
4606 */
4607static bool register_uint(uint32_t value, uint32_t* list, size_t list_length) {
4608 for (size_t i = 0; i < list_length; i++) {
4609 if (list[i] == value) return true; // value is already present
4610 if (list[i] == 0) { // no values in this slot
4611 list[i] = value;
4612 return true; // value inserted
4613 }
4614 }
4615 return false; // could not insert value
4616}
4617
4618/** Add channel_mask in supported_channel_masks if not already present.
4619 * @return true if channel_mask was successfully inserted or already present,
4620 * false if supported_channel_masks is full and does not contain channel_mask.
4621 */
4622static void register_channel_mask(audio_channel_mask_t channel_mask,
4623 audio_channel_mask_t supported_channel_masks[static MAX_SUPPORTED_CHANNEL_MASKS]) {
4624 ALOGE_IF(!register_uint(channel_mask, supported_channel_masks, MAX_SUPPORTED_CHANNEL_MASKS),
4625 "%s: stream can not declare supporting its channel_mask %x", __func__, channel_mask);
4626}
4627
4628/** Add format in supported_formats if not already present.
4629 * @return true if format was successfully inserted or already present,
4630 * false if supported_formats is full and does not contain format.
4631 */
4632static void register_format(audio_format_t format,
4633 audio_format_t supported_formats[static MAX_SUPPORTED_FORMATS]) {
4634 ALOGE_IF(!register_uint(format, supported_formats, MAX_SUPPORTED_FORMATS),
4635 "%s: stream can not declare supporting its format %x", __func__, format);
4636}
4637/** Add sample_rate in supported_sample_rates if not already present.
4638 * @return true if sample_rate was successfully inserted or already present,
4639 * false if supported_sample_rates is full and does not contain sample_rate.
4640 */
4641static void register_sample_rate(uint32_t sample_rate,
4642 uint32_t supported_sample_rates[static MAX_SUPPORTED_SAMPLE_RATES]) {
4643 ALOGE_IF(!register_uint(sample_rate, supported_sample_rates, MAX_SUPPORTED_SAMPLE_RATES),
4644 "%s: stream can not declare supporting its sample rate %x", __func__, sample_rate);
4645}
4646
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004647static inline uint32_t lcm(uint32_t num1, uint32_t num2)
4648{
4649 uint32_t high = num1, low = num2, temp = 0;
4650
4651 if (!num1 || !num2)
4652 return 0;
4653
4654 if (num1 < num2) {
4655 high = num2;
4656 low = num1;
4657 }
4658
4659 while (low != 0) {
4660 temp = low;
4661 low = high % low;
4662 high = temp;
4663 }
4664 return (num1 * num2)/high;
4665}
4666
4667static inline uint32_t nearest_multiple(uint32_t num, uint32_t multiplier)
4668{
4669 uint32_t remainder = 0;
4670
4671 if (!multiplier)
4672 return num;
4673
4674 remainder = num % multiplier;
4675 if (remainder)
4676 num += (multiplier - remainder);
4677
4678 return num;
4679}
4680
Aalique Grahame22e49102018-12-18 14:23:57 -08004681static size_t get_stream_buffer_size(size_t duration_ms,
4682 uint32_t sample_rate,
4683 audio_format_t format,
4684 int channel_count,
4685 bool is_low_latency)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004686{
4687 size_t size = 0;
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004688 uint32_t bytes_per_period_sample = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004689
Aalique Grahame22e49102018-12-18 14:23:57 -08004690 size = (sample_rate * duration_ms) / 1000;
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05304691 if (is_low_latency){
4692 switch(sample_rate) {
4693 case 48000:
4694 size = 240;
4695 break;
4696 case 32000:
4697 size = 160;
4698 break;
4699 case 24000:
4700 size = 120;
4701 break;
4702 case 16000:
4703 size = 80;
4704 break;
4705 case 8000:
4706 size = 40;
4707 break;
4708 default:
4709 size = 240;
4710 }
4711 }
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304712
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004713 bytes_per_period_sample = audio_bytes_per_sample(format) * channel_count;
Aalique Grahame22e49102018-12-18 14:23:57 -08004714 size *= audio_bytes_per_sample(format) * channel_count;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004715
Ralf Herzbd08d632018-09-28 15:50:49 +02004716 /* make sure the size is multiple of 32 bytes and additionally multiple of
4717 * the frame_size (required for 24bit samples and non-power-of-2 channel counts)
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004718 * At 48 kHz mono 16-bit PCM:
4719 * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
4720 * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004721 * Also, make sure the size is multiple of bytes per period sample
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004722 */
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004723 size = nearest_multiple(size, lcm(32, bytes_per_period_sample));
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07004724
4725 return size;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004726}
4727
Aalique Grahame22e49102018-12-18 14:23:57 -08004728static size_t get_input_buffer_size(uint32_t sample_rate,
4729 audio_format_t format,
4730 int channel_count,
4731 bool is_low_latency)
4732{
Avinash Chandrad7296d42021-08-04 15:07:47 +05304733 bool is_usb_hifi = IS_USB_HIFI;
Aalique Grahame22e49102018-12-18 14:23:57 -08004734 /* Don't know if USB HIFI in this context so use true to be conservative */
4735 if (check_input_parameters(sample_rate, format, channel_count,
Avinash Chandrad7296d42021-08-04 15:07:47 +05304736 is_usb_hifi) != 0)
Aalique Grahame22e49102018-12-18 14:23:57 -08004737 return 0;
4738
4739 return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
4740 sample_rate,
4741 format,
4742 channel_count,
4743 is_low_latency);
4744}
4745
Derek Chenf6318be2017-06-12 17:16:24 -04004746size_t get_output_period_size(uint32_t sample_rate,
4747 audio_format_t format,
4748 int channel_count,
4749 int duration /*in millisecs*/)
Ashish Jain058165c2016-09-28 23:18:48 +05304750{
4751 size_t size = 0;
4752 uint32_t bytes_per_sample = audio_bytes_per_sample(format);
4753
4754 if ((duration == 0) || (sample_rate == 0) ||
4755 (bytes_per_sample == 0) || (channel_count == 0)) {
4756 ALOGW("Invalid config duration %d sr %d bps %d ch %d", duration, sample_rate,
4757 bytes_per_sample, channel_count);
4758 return -EINVAL;
4759 }
4760
4761 size = (sample_rate *
4762 duration *
4763 bytes_per_sample *
4764 channel_count) / 1000;
4765 /*
4766 * To have same PCM samples for all channels, the buffer size requires to
4767 * be multiple of (number of channels * bytes per sample)
4768 * For writes to succeed, the buffer must be written at address which is multiple of 32
4769 */
4770 size = ALIGN(size, (bytes_per_sample * channel_count * 32));
4771
4772 return (size/(channel_count * bytes_per_sample));
4773}
4774
Zhou Song48453a02018-01-10 17:50:59 +08004775static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out, struct timespec *timestamp)
Ashish Jain5106d362016-05-11 19:23:33 +05304776{
4777 uint64_t actual_frames_rendered = 0;
Weiyin Jiang4813da12020-05-28 00:37:28 +08004778 uint64_t written_frames = 0;
4779 uint64_t kernel_frames = 0;
4780 uint64_t dsp_frames = 0;
4781 uint64_t signed_frames = 0;
4782 size_t kernel_buffer_size = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05304783
4784 /* This adjustment accounts for buffering after app processor.
4785 * It is based on estimated DSP latency per use case, rather than exact.
4786 */
George Gao9ba8a142020-07-23 14:30:03 -07004787 dsp_frames = platform_render_latency(out) *
Weiyin Jiang4813da12020-05-28 00:37:28 +08004788 out->sample_rate / 1000000LL;
Ashish Jain5106d362016-05-11 19:23:33 +05304789
Zhou Song48453a02018-01-10 17:50:59 +08004790 pthread_mutex_lock(&out->position_query_lock);
Weiyin Jiang4813da12020-05-28 00:37:28 +08004791 written_frames = out->written /
4792 (audio_bytes_per_sample(out->hal_ip_format) * popcount(out->channel_mask));
4793
Ashish Jain5106d362016-05-11 19:23:33 +05304794 /* not querying actual state of buffering in kernel as it would involve an ioctl call
4795 * which then needs protection, this causes delay in TS query for pcm_offload usecase
4796 * hence only estimate.
4797 */
Weiyin Jiang4813da12020-05-28 00:37:28 +08004798 kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments;
4799 kernel_frames = kernel_buffer_size /
4800 (audio_bytes_per_sample(out->hal_op_format) * popcount(out->channel_mask));
Ashish Jain5106d362016-05-11 19:23:33 +05304801
Weiyin Jiang4813da12020-05-28 00:37:28 +08004802 if (written_frames >= (kernel_frames + dsp_frames))
4803 signed_frames = written_frames - kernel_frames - dsp_frames;
Ashish Jain5106d362016-05-11 19:23:33 +05304804
Zhou Song48453a02018-01-10 17:50:59 +08004805 if (signed_frames > 0) {
Ashish Jain5106d362016-05-11 19:23:33 +05304806 actual_frames_rendered = signed_frames;
Zhou Song48453a02018-01-10 17:50:59 +08004807 if (timestamp != NULL )
4808 *timestamp = out->writeAt;
4809 } else if (timestamp != NULL) {
4810 clock_gettime(CLOCK_MONOTONIC, timestamp);
4811 }
4812 pthread_mutex_unlock(&out->position_query_lock);
Ashish Jain5106d362016-05-11 19:23:33 +05304813
Weiyin Jiang4813da12020-05-28 00:37:28 +08004814 ALOGVV("%s signed frames %lld written frames %lld kernel frames %lld dsp frames %lld",
4815 __func__, signed_frames, written_frames, kernel_frames, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05304816
4817 return actual_frames_rendered;
4818}
4819
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004820static uint32_t out_get_sample_rate(const struct audio_stream *stream)
4821{
4822 struct stream_out *out = (struct stream_out *)stream;
4823
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004824 return out->sample_rate;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004825}
4826
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004827static int out_set_sample_rate(struct audio_stream *stream __unused,
4828 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004829{
4830 return -ENOSYS;
4831}
4832
4833static size_t out_get_buffer_size(const struct audio_stream *stream)
4834{
4835 struct stream_out *out = (struct stream_out *)stream;
4836
Varun Balaraje49253e2017-07-06 19:48:56 +05304837 if (is_interactive_usecase(out->usecase)) {
Sri Karri27279e12017-08-07 16:05:20 +05304838 return out->config.period_size * out->config.period_count;
Varun Balaraje49253e2017-07-06 19:48:56 +05304839 } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Naresh Tanniruee3499a2017-01-05 14:05:35 +05304840 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
4841 return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
4842 else
4843 return out->compr_config.fragment_size;
4844 } else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08004845 return voice_extn_compress_voip_out_get_buffer_size(out);
Dhananjay Kumarac341582017-02-23 23:42:25 +05304846 else if (is_offload_usecase(out->usecase) &&
4847 out->flags == AUDIO_OUTPUT_FLAG_DIRECT)
Ashish Jain83a6cc22016-06-28 14:34:17 +05304848 return out->hal_fragment_size;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004849
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004850 return out->config.period_size * out->af_period_multiplier *
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07004851 audio_stream_out_frame_size((const struct audio_stream_out *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004852}
4853
4854static uint32_t out_get_channels(const struct audio_stream *stream)
4855{
4856 struct stream_out *out = (struct stream_out *)stream;
4857
4858 return out->channel_mask;
4859}
4860
4861static audio_format_t out_get_format(const struct audio_stream *stream)
4862{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004863 struct stream_out *out = (struct stream_out *)stream;
4864
4865 return out->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004866}
4867
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004868static int out_set_format(struct audio_stream *stream __unused,
4869 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004870{
4871 return -ENOSYS;
4872}
4873
4874static int out_standby(struct audio_stream *stream)
4875{
4876 struct stream_out *out = (struct stream_out *)stream;
4877 struct audio_device *adev = out->dev;
Haynes Mathew George16081042017-05-31 17:16:49 -07004878 bool do_stop = true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004879
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304880 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4881 stream, out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004882
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07004883 lock_output_stream(out);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004884 if (!out->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004885 if (adev->adm_deregister_stream)
4886 adev->adm_deregister_stream(adev->adm_data, out->handle);
4887
Weiyin Jiang280ea742020-09-08 20:28:22 +08004888 if (is_offload_usecase(out->usecase)) {
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004889 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08004890 }
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004891
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08004892 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004893 out->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08004894 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
4895 voice_extn_compress_voip_close_output_stream(stream);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304896 out->started = 0;
Zhou Songa8895042016-07-05 17:54:22 +08004897 pthread_mutex_unlock(&adev->lock);
4898 pthread_mutex_unlock(&out->lock);
4899 ALOGD("VOIP output entered standby");
4900 return 0;
4901 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004902 if (out->pcm) {
4903 pcm_close(out->pcm);
4904 out->pcm = NULL;
4905 }
Meng Wanga09da002020-04-20 12:56:04 +08004906 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
4907 if (adev->haptic_pcm) {
4908 pcm_close(adev->haptic_pcm);
4909 adev->haptic_pcm = NULL;
4910 }
4911
4912 if (adev->haptic_buffer != NULL) {
4913 free(adev->haptic_buffer);
4914 adev->haptic_buffer = NULL;
4915 adev->haptic_buffer_size = 0;
4916 }
4917 adev->haptic_pcm_device_id = 0;
4918 }
4919
Haynes Mathew George16081042017-05-31 17:16:49 -07004920 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4921 do_stop = out->playback_started;
4922 out->playback_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07004923
4924 if (out->mmap_shared_memory_fd >= 0) {
4925 ALOGV("%s: closing mmap_shared_memory_fd = %d",
4926 __func__, out->mmap_shared_memory_fd);
4927 close(out->mmap_shared_memory_fd);
4928 out->mmap_shared_memory_fd = -1;
4929 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004930 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004931 } else {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07004932 ALOGD("copl(%p):standby", out);
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304933 out->send_next_track_params = false;
4934 out->is_compr_metadata_avail = false;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004935 out->gapless_mdata.encoder_delay = 0;
4936 out->gapless_mdata.encoder_padding = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004937 if (out->compr != NULL) {
4938 compress_close(out->compr);
4939 out->compr = NULL;
4940 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08004941 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004942 if (do_stop) {
4943 stop_output_stream(out);
4944 }
Lakshman Chaluvaraju06677b42019-06-24 10:04:52 +05304945 // if fm is active route on selected device in UI
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004946 audio_extn_fm_route_on_selected_device(adev, &out->device_list);
Eric Laurent150dbfe2013-02-27 14:31:02 -08004947 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004948 }
4949 pthread_mutex_unlock(&out->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07004950 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004951 return 0;
4952}
4953
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304954static int out_on_error(struct audio_stream *stream)
4955{
4956 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004957 int status = 0;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304958
4959 lock_output_stream(out);
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004960 // always send CMD_ERROR for offload streams, this
4961 // is needed e.g. when SSR happens within compress_open
4962 // since the stream is active, offload_callback_thread is also active.
4963 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
4964 stop_compressed_output_l(out);
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004965 }
4966 pthread_mutex_unlock(&out->lock);
4967
4968 status = out_standby(&out->stream.common);
4969
4970 lock_output_stream(out);
4971 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004972 send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304973 }
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05304974
4975 if (is_offload_usecase(out->usecase) && out->card_status == CARD_STATUS_OFFLINE) {
4976 ALOGD("Setting previous card status if offline");
4977 out->prev_card_status_offline = true;
4978 }
4979
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304980 pthread_mutex_unlock(&out->lock);
4981
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004982 return status;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304983}
4984
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304985/*
Weiyin Jiang280ea742020-09-08 20:28:22 +08004986 * standby implementation without locks, assumes that the callee already
4987 * has taken adev and out lock.
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304988 */
4989int out_standby_l(struct audio_stream *stream)
4990{
4991 struct stream_out *out = (struct stream_out *)stream;
4992 struct audio_device *adev = out->dev;
4993
4994 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4995 stream, out->usecase, use_case_table[out->usecase]);
4996
4997 if (!out->standby) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07004998 ATRACE_BEGIN("out_standby_l");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304999 if (adev->adm_deregister_stream)
5000 adev->adm_deregister_stream(adev->adm_data, out->handle);
5001
Weiyin Jiang280ea742020-09-08 20:28:22 +08005002 if (is_offload_usecase(out->usecase)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305003 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005004 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305005
5006 out->standby = true;
5007 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
5008 voice_extn_compress_voip_close_output_stream(stream);
5009 out->started = 0;
5010 ALOGD("VOIP output entered standby");
Haynes Mathew George380745d2017-10-04 15:27:45 -07005011 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305012 return 0;
5013 } else if (!is_offload_usecase(out->usecase)) {
5014 if (out->pcm) {
5015 pcm_close(out->pcm);
5016 out->pcm = NULL;
5017 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08005018 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
5019 if (adev->haptic_pcm) {
5020 pcm_close(adev->haptic_pcm);
5021 adev->haptic_pcm = NULL;
5022 }
5023
5024 if (adev->haptic_buffer != NULL) {
5025 free(adev->haptic_buffer);
5026 adev->haptic_buffer = NULL;
5027 adev->haptic_buffer_size = 0;
5028 }
5029 adev->haptic_pcm_device_id = 0;
5030 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305031 } else {
5032 ALOGD("copl(%p):standby", out);
5033 out->send_next_track_params = false;
5034 out->is_compr_metadata_avail = false;
5035 out->gapless_mdata.encoder_delay = 0;
5036 out->gapless_mdata.encoder_padding = 0;
5037 if (out->compr != NULL) {
5038 compress_close(out->compr);
5039 out->compr = NULL;
5040 }
5041 }
5042 stop_output_stream(out);
Haynes Mathew George380745d2017-10-04 15:27:45 -07005043 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305044 }
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07005045 ALOGV("%s: exit", __func__);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305046 return 0;
5047}
5048
Aalique Grahame22e49102018-12-18 14:23:57 -08005049static int out_dump(const struct audio_stream *stream, int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005050{
Aalique Grahame22e49102018-12-18 14:23:57 -08005051 struct stream_out *out = (struct stream_out *)stream;
5052
5053 // We try to get the lock for consistency,
5054 // but it isn't necessary for these variables.
5055 // If we're not in standby, we may be blocked on a write.
5056 const bool locked = (pthread_mutex_trylock(&out->lock) == 0);
5057 dprintf(fd, " Standby: %s\n", out->standby ? "yes" : "no");
5058 dprintf(fd, " Frames written: %lld\n", (long long)out->written);
Dechen Chai22768452021-07-30 09:29:16 +05305059#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07005060 char buffer[256]; // for statistics formatting
5061 if (!is_offload_usecase(out->usecase)) {
5062 simple_stats_to_string(&out->fifo_underruns, buffer, sizeof(buffer));
5063 dprintf(fd, " Fifo frame underruns: %s\n", buffer);
5064 }
5065
Andy Hungc6bfd4a2019-07-01 18:26:00 -07005066 if (out->start_latency_ms.n > 0) {
5067 simple_stats_to_string(&out->start_latency_ms, buffer, sizeof(buffer));
5068 dprintf(fd, " Start latency ms: %s\n", buffer);
5069 }
Dechen Chai22768452021-07-30 09:29:16 +05305070#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08005071 if (locked) {
5072 pthread_mutex_unlock(&out->lock);
5073 }
5074
Dechen Chai22768452021-07-30 09:29:16 +05305075#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08005076 // dump error info
5077 (void)error_log_dump(
5078 out->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05305079#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005080 return 0;
5081}
5082
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005083static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
5084{
5085 int ret = 0;
5086 char value[32];
ApurupaPattapu2e084df2013-12-18 15:47:59 -08005087
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005088 if (!out || !parms) {
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005089 ALOGE("%s: return invalid ",__func__);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005090 return -EINVAL;
5091 }
5092
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305093 ret = audio_extn_parse_compress_metadata(out, parms);
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08005094
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005095 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
5096 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305097 out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005098 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005099 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
5100 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305101 out->gapless_mdata.encoder_padding = atoi(value);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005102 }
5103
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005104 ALOGV("%s new encoder delay %u and padding %u", __func__,
5105 out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
5106
5107 return 0;
5108}
5109
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07005110static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
5111{
5112 return out == adev->primary_output || out == adev->voice_tx_output;
5113}
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005114
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305115// note: this call is safe only if the stream_cb is
5116// removed first in close_output_stream (as is done now).
5117static void out_snd_mon_cb(void * stream, struct str_parms * parms)
5118{
5119 if (!stream || !parms)
5120 return;
5121
5122 struct stream_out *out = (struct stream_out *)stream;
5123 struct audio_device *adev = out->dev;
5124
5125 card_status_t status;
5126 int card;
5127 if (parse_snd_card_status(parms, &card, &status) < 0)
5128 return;
5129
5130 pthread_mutex_lock(&adev->lock);
5131 bool valid_cb = (card == adev->snd_card);
5132 pthread_mutex_unlock(&adev->lock);
5133
5134 if (!valid_cb)
5135 return;
5136
5137 lock_output_stream(out);
5138 if (out->card_status != status)
5139 out->card_status = status;
5140 pthread_mutex_unlock(&out->lock);
5141
5142 ALOGI("out_snd_mon_cb for card %d usecase %s, status %s", card,
5143 use_case_table[out->usecase],
5144 status == CARD_STATUS_OFFLINE ? "offline" : "online");
5145
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305146 if (status == CARD_STATUS_OFFLINE) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305147 out_on_error(stream);
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305148 if (voice_is_call_state_active(adev) &&
5149 out == adev->primary_output) {
5150 ALOGD("%s: SSR/PDR occurred, end all calls\n", __func__);
5151 pthread_mutex_lock(&adev->lock);
5152 voice_stop_call(adev);
5153 adev->mode = AUDIO_MODE_NORMAL;
5154 pthread_mutex_unlock(&adev->lock);
5155 }
5156 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305157 return;
5158}
5159
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005160int route_output_stream(struct stream_out *out,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005161 struct listnode *devices)
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005162{
5163 struct audio_device *adev = out->dev;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005164 int ret = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005165 struct listnode new_devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005166 bool bypass_a2dp = false;
5167 bool reconfig = false;
5168 unsigned long service_interval = 0;
5169
5170 ALOGD("%s: enter: usecase(%d: %s) devices %x",
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005171 __func__, out->usecase, use_case_table[out->usecase], get_device_types(devices));
5172
5173 list_init(&new_devices);
5174 assign_devices(&new_devices, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005175
5176 lock_output_stream(out);
5177 pthread_mutex_lock(&adev->lock);
5178
5179 /*
5180 * When HDMI cable is unplugged the music playback is paused and
5181 * the policy manager sends routing=0. But the audioflinger continues
5182 * to write data until standby time (3sec). As the HDMI core is
5183 * turned off, the write gets blocked.
5184 * Avoid this by routing audio to speaker until standby.
5185 */
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08005186 if (is_single_device_type_equal(&out->device_list,
5187 AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005188 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005189 !audio_extn_passthru_is_passthrough_stream(out) &&
5190 (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005191 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005192 }
5193 /*
5194 * When A2DP is disconnected the
5195 * music playback is paused and the policy manager sends routing=0
5196 * But the audioflinger continues to write data until standby time
5197 * (3sec). As BT is turned off, the write gets blocked.
5198 * Avoid this by routing audio to speaker until standby.
5199 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005200 if (is_a2dp_out_device_type(&out->device_list) &&
5201 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005202 !audio_extn_a2dp_source_is_ready() &&
5203 !adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005204 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005205 }
5206 /*
Weiyin Jiangabedea32020-12-09 12:49:19 +08005207 * When USB headset is disconnected the music playback paused
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005208 * and the policy manager send routing=0. But if the USB is connected
5209 * back before the standby time, AFE is not closed and opened
5210 * when USB is connected back. So routing to speker will guarantee
5211 * AFE reconfiguration and AFE will be opend once USB is connected again
5212 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005213 if (is_usb_out_device_type(&out->device_list) &&
5214 list_empty(&new_devices) &&
5215 !audio_extn_usb_connected(NULL)) {
Sujin Panicker84d953a2020-11-16 17:39:54 +05305216 if (adev->mode == AUDIO_MODE_IN_CALL || adev->mode == AUDIO_MODE_IN_COMMUNICATION)
5217 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_EARPIECE, "");
5218 else
5219 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005220 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005221 /* To avoid a2dp to sco overlapping / BT device improper state
5222 * check with BT lib about a2dp streaming support before routing
5223 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005224 if (is_a2dp_out_device_type(&new_devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005225 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005226 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
5227 compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005228 //combo usecase just by pass a2dp
5229 ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
5230 bypass_a2dp = true;
5231 } else {
5232 ALOGE("%s: A2DP profile is not ready,ignoring routing request", __func__);
5233 /* update device to a2dp and don't route as BT returned error
5234 * However it is still possible a2dp routing called because
5235 * of current active device disconnection (like wired headset)
5236 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005237 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005238 pthread_mutex_unlock(&adev->lock);
5239 pthread_mutex_unlock(&out->lock);
5240 goto error;
5241 }
5242 }
5243 }
5244
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005245 // Workaround: If routing to an non existing usb device, fail gracefully
5246 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005247 if (is_usb_out_device_type(&new_devices)) {
5248 struct str_parms *parms =
5249 str_parms_create_str(get_usb_device_address(&new_devices));
5250 if (!parms)
5251 goto error;
Weiyin Jiangabedea32020-12-09 12:49:19 +08005252 if (!audio_extn_usb_connected(NULL)) {
5253 ALOGW("%s: ignoring rerouting to non existing USB card", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005254 pthread_mutex_unlock(&adev->lock);
5255 pthread_mutex_unlock(&out->lock);
5256 str_parms_destroy(parms);
5257 ret = -ENOSYS;
5258 goto error;
5259 }
5260 str_parms_destroy(parms);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005261 }
5262
Weiyin Jiang80c8f9a2020-01-10 20:42:08 +08005263 // Workaround: If routing to an non existing hdmi device, fail gracefully
5264 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
5265 (platform_get_edid_info_v2(adev->platform,
5266 out->extconn.cs.controller,
5267 out->extconn.cs.stream) != 0)) {
5268 ALOGW("out_set_parameters() ignoring rerouting to non existing HDMI/DP");
5269 pthread_mutex_unlock(&adev->lock);
5270 pthread_mutex_unlock(&out->lock);
5271 ret = -ENOSYS;
5272 goto error;
5273 }
5274
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005275 /*
5276 * select_devices() call below switches all the usecases on the same
5277 * backend to the new device. Refer to check_usecases_codec_backend() in
5278 * the select_devices(). But how do we undo this?
5279 *
5280 * For example, music playback is active on headset (deep-buffer usecase)
5281 * and if we go to ringtones and select a ringtone, low-latency usecase
5282 * will be started on headset+speaker. As we can't enable headset+speaker
5283 * and headset devices at the same time, select_devices() switches the music
5284 * playback to headset+speaker while starting low-lateny usecase for ringtone.
5285 * So when the ringtone playback is completed, how do we undo the same?
5286 *
5287 * We are relying on the out_set_parameters() call on deep-buffer output,
5288 * once the ringtone playback is ended.
5289 * NOTE: We should not check if the current devices are same as new devices.
5290 * Because select_devices() must be called to switch back the music
5291 * playback to headset.
5292 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005293 if (!list_empty(&new_devices)) {
5294 bool same_dev = compare_devices(&out->device_list, &new_devices);
5295 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005296
5297 if (output_drives_call(adev, out)) {
5298 if (!voice_is_call_state_active(adev)) {
5299 if (adev->mode == AUDIO_MODE_IN_CALL) {
5300 adev->current_call_output = out;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005301 ret = voice_start_call(adev);
5302 }
5303 } else {
Kunlei Zhang253ad102020-10-14 16:21:28 +08005304 platform_is_volume_boost_supported_device(adev->platform, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005305 adev->current_call_output = out;
5306 voice_update_devices_for_all_voice_usecases(adev);
5307 }
5308 }
5309
Mingshu Pang971ff702020-09-09 15:28:22 +08005310 if (is_usb_out_device_type(&out->device_list)) {
5311 service_interval = audio_extn_usb_find_service_interval(false, true /*playback*/);
5312 audio_extn_usb_set_service_interval(true /*playback*/,
5313 service_interval,
5314 &reconfig);
5315 ALOGD("%s, svc_int(%ld),reconfig(%d)",__func__,service_interval, reconfig);
5316 }
5317
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005318 if (!out->standby) {
5319 if (!same_dev) {
5320 ALOGV("update routing change");
5321 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
5322 adev->perf_lock_opts,
5323 adev->perf_lock_opts_size);
5324 if (adev->adm_on_routing_change)
5325 adev->adm_on_routing_change(adev->adm_data,
5326 out->handle);
5327 }
5328 if (!bypass_a2dp) {
5329 select_devices(adev, out->usecase);
5330 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005331 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
5332 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005333 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005334 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005335 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005336 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005337 }
5338
5339 if (!same_dev) {
5340 // on device switch force swap, lower functions will make sure
5341 // to check if swap is allowed or not.
5342 platform_set_swap_channels(adev, true);
5343 audio_extn_perf_lock_release(&adev->perf_lock_handle);
5344 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005345 pthread_mutex_lock(&out->latch_lock);
5346 if (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready()) {
5347 if (out->a2dp_muted) {
5348 out->a2dp_muted = false;
5349 if (is_offload_usecase(out->usecase))
5350 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
5351 else if (out->usecase != USECASE_AUDIO_PLAYBACK_VOIP)
5352 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005353 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005354 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005355 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP && !out->a2dp_muted)
5356 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
5357 pthread_mutex_unlock(&out->latch_lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005358 }
5359 }
5360
5361 pthread_mutex_unlock(&adev->lock);
5362 pthread_mutex_unlock(&out->lock);
5363
5364 /*handles device and call state changes*/
5365 audio_extn_extspk_update(adev->extspk);
5366
Revathi Uddaraju4255a632021-12-02 05:11:13 -08005367 clear_devices(&new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005368error:
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005369 ALOGV("%s: exit: code(%d)", __func__, ret);
5370 return ret;
5371}
5372
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005373static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
5374{
5375 struct stream_out *out = (struct stream_out *)stream;
5376 struct audio_device *adev = out->dev;
5377 struct str_parms *parms;
5378 char value[32];
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005379 int ret = 0, err;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005380 int ext_controller = -1;
5381 int ext_stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005382
sangwoobc677242013-08-08 16:53:43 +09005383 ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07005384 __func__, out->usecase, use_case_table[out->usecase], kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005385 parms = str_parms_create_str(kvpairs);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305386 if (!parms)
5387 goto error;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005388
5389 err = platform_get_controller_stream_from_params(parms, &ext_controller,
5390 &ext_stream);
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08005391 if (err == 0) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005392 out->extconn.cs.controller = ext_controller;
5393 out->extconn.cs.stream = ext_stream;
5394 ALOGD("%s: usecase(%s) new controller/stream (%d/%d)", __func__,
5395 use_case_table[out->usecase], out->extconn.cs.controller,
5396 out->extconn.cs.stream);
5397 }
5398
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005399 if (out == adev->primary_output) {
5400 pthread_mutex_lock(&adev->lock);
5401 audio_extn_set_parameters(adev, parms);
5402 pthread_mutex_unlock(&adev->lock);
5403 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005404 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07005405 lock_output_stream(out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005406 parse_compress_metadata(out, parms);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08005407
5408 audio_extn_dts_create_state_notifier_node(out->usecase);
5409 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
5410 popcount(out->channel_mask),
5411 out->playback_started);
5412
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005413 pthread_mutex_unlock(&out->lock);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005414 }
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005415
Surendar Karkaf51b5842018-04-26 11:28:38 +05305416 err = str_parms_get_str(parms, AUDIO_PARAMETER_DUAL_MONO, value,
5417 sizeof(value));
5418 if (err >= 0) {
5419 if (!strncmp("true", value, sizeof("true")) || atoi(value))
5420 audio_extn_send_dual_mono_mixing_coefficients(out);
5421 }
5422
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305423 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
5424 if (err >= 0) {
5425 strlcpy(out->profile, value, sizeof(out->profile));
5426 ALOGV("updating stream profile with value '%s'", out->profile);
5427 lock_output_stream(out);
5428 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
5429 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005430 &out->device_list, out->flags,
5431 out->hal_op_format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305432 out->sample_rate, out->bit_width,
5433 out->channel_mask, out->profile,
5434 &out->app_type_cfg);
5435 pthread_mutex_unlock(&out->lock);
5436 }
5437
Alexy Joseph98988832017-01-13 14:56:59 -08005438 //suspend, resume handling block
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005439 //remove QOS only if vendor.audio.hal.dynamic.qos.config.supported is set to true
5440 // and vendor.audio.hal.output.suspend.supported is set to true
5441 if (out->hal_output_suspend_supported && out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08005442 //check suspend parameter only for low latency and if the property
5443 //is enabled
5444 if (str_parms_get_str(parms, "suspend_playback", value, sizeof(value)) >= 0) {
5445 ALOGI("%s: got suspend_playback %s", __func__, value);
5446 lock_output_stream(out);
5447 if (!strncmp(value, "false", 5)) {
5448 //suspend_playback=false is supposed to set QOS value back to 75%
5449 //the mixer control sent with value Enable will achieve that
5450 ret = audio_route_apply_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5451 } else if (!strncmp (value, "true", 4)) {
5452 //suspend_playback=true is supposed to remove QOS value
5453 //resetting the mixer control will set the default value
5454 //for the mixer control which is Disable and this removes the QOS vote
5455 ret = audio_route_reset_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5456 } else {
5457 ALOGE("%s: Wrong value sent for suspend_playback, expected true/false,"
5458 " got %s", __func__, value);
5459 ret = -1;
5460 }
5461
5462 if (ret != 0) {
5463 ALOGE("%s: %s mixer ctl failed with %d, ignore suspend/resume setparams",
5464 __func__, out->pm_qos_mixer_path, ret);
5465 }
5466
5467 pthread_mutex_unlock(&out->lock);
5468 }
5469 }
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005470
Alexy Joseph98988832017-01-13 14:56:59 -08005471 //end suspend, resume handling block
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005472 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305473error:
Eric Laurent994a6932013-07-17 11:51:42 -07005474 ALOGV("%s: exit: code(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005475 return ret;
5476}
5477
Paul McLeana50b7332018-12-17 08:24:21 -07005478static int in_set_microphone_direction(const struct audio_stream_in *stream,
5479 audio_microphone_direction_t dir) {
justinweng20fb6d82019-02-21 18:49:00 -07005480 struct stream_in *in = (struct stream_in *)stream;
5481
5482 ALOGVV("%s: standby %d source %d dir %d", __func__, in->standby, in->source, dir);
5483
5484 in->direction = dir;
5485
5486 if (in->standby)
5487 return 0;
5488
5489 return audio_extn_audiozoom_set_microphone_direction(in, dir);
Paul McLeana50b7332018-12-17 08:24:21 -07005490}
5491
5492static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom) {
justinweng20fb6d82019-02-21 18:49:00 -07005493 struct stream_in *in = (struct stream_in *)stream;
5494
5495 ALOGVV("%s: standby %d source %d zoom %f", __func__, in->standby, in->source, zoom);
5496
5497 if (zoom > 1.0 || zoom < -1.0)
5498 return -EINVAL;
5499
5500 in->zoom = zoom;
5501
5502 if (in->standby)
5503 return 0;
5504
5505 return audio_extn_audiozoom_set_microphone_field_dimension(in, zoom);
Paul McLeana50b7332018-12-17 08:24:21 -07005506}
5507
5508
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005509static bool stream_get_parameter_channels(struct str_parms *query,
5510 struct str_parms *reply,
5511 audio_channel_mask_t *supported_channel_masks) {
5512 int ret = -1;
5513 char value[512];
5514 bool first = true;
5515 size_t i, j;
5516
5517 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
5518 ret = 0;
5519 value[0] = '\0';
5520 i = 0;
5521 while (supported_channel_masks[i] != 0) {
5522 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5523 if (channels_name_to_enum_table[j].value == supported_channel_masks[i]) {
5524 if (!first)
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305525 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005526
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305527 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005528 first = false;
5529 break;
5530 }
5531 }
5532 i++;
5533 }
5534 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5535 }
5536 return ret == 0;
5537}
5538
5539static bool stream_get_parameter_formats(struct str_parms *query,
5540 struct str_parms *reply,
5541 audio_format_t *supported_formats) {
5542 int ret = -1;
5543 char value[256];
5544 size_t i, j;
5545 bool first = true;
5546
5547 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
5548 ret = 0;
5549 value[0] = '\0';
5550 i = 0;
5551 while (supported_formats[i] != 0) {
5552 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5553 if (formats_name_to_enum_table[j].value == supported_formats[i]) {
5554 if (!first) {
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305555 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005556 }
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305557 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005558 first = false;
5559 break;
5560 }
5561 }
5562 i++;
5563 }
5564 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
5565 }
5566 return ret == 0;
5567}
5568
5569static bool stream_get_parameter_rates(struct str_parms *query,
5570 struct str_parms *reply,
5571 uint32_t *supported_sample_rates) {
5572
5573 int i;
5574 char value[256];
5575 int ret = -1;
5576 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
5577 ret = 0;
5578 value[0] = '\0';
5579 i=0;
5580 int cursor = 0;
5581 while (supported_sample_rates[i]) {
5582 int avail = sizeof(value) - cursor;
5583 ret = snprintf(value + cursor, avail, "%s%d",
5584 cursor > 0 ? "|" : "",
5585 supported_sample_rates[i]);
5586 if (ret < 0 || ret >= avail) {
5587 // if cursor is at the last element of the array
5588 // overwrite with \0 is duplicate work as
5589 // snprintf already put a \0 in place.
5590 // else
5591 // we had space to write the '|' at value[cursor]
5592 // (which will be overwritten) or no space to fill
5593 // the first element (=> cursor == 0)
5594 value[cursor] = '\0';
5595 break;
5596 }
5597 cursor += ret;
5598 ++i;
5599 }
5600 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
5601 value);
5602 }
5603 return ret >= 0;
5604}
5605
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005606static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
5607{
5608 struct stream_out *out = (struct stream_out *)stream;
5609 struct str_parms *query = str_parms_create_str(keys);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005610 char *str = (char*) NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005611 char value[256];
5612 struct str_parms *reply = str_parms_create();
5613 size_t i, j;
5614 int ret;
5615 bool first = true;
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005616
5617 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005618 if (reply) {
5619 str_parms_destroy(reply);
5620 }
5621 if (query) {
5622 str_parms_destroy(query);
5623 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005624 ALOGE("out_get_parameters: failed to allocate mem for query or reply");
5625 return NULL;
5626 }
5627
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005628 ALOGV("%s: %s enter: keys - %s", __func__, use_case_table[out->usecase], keys);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005629 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
5630 if (ret >= 0) {
5631 value[0] = '\0';
5632 i = 0;
5633 while (out->supported_channel_masks[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005634 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5635 if (channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005636 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005637 strlcat(value, "|", sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005638 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005639 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005640 first = false;
5641 break;
5642 }
5643 }
5644 i++;
5645 }
5646 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5647 str = str_parms_to_str(reply);
5648 } else {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08005649 voice_extn_out_get_parameters(out, query, reply);
5650 str = str_parms_to_str(reply);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005651 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005652
Alexy Joseph62142aa2015-11-16 15:10:34 -08005653
5654 ret = str_parms_get_str(query, "is_direct_pcm_track", value, sizeof(value));
5655 if (ret >= 0) {
5656 value[0] = '\0';
Dhananjay Kumarac341582017-02-23 23:42:25 +05305657 if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
5658 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Alexy Joseph62142aa2015-11-16 15:10:34 -08005659 ALOGV("in direct_pcm");
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05305660 strlcat(value, "true", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005661 } else {
5662 ALOGV("not in direct_pcm");
Sharad Sangle3dd5a4a2015-12-10 18:39:17 +05305663 strlcat(value, "false", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005664 }
5665 str_parms_add_str(reply, "is_direct_pcm_track", value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005666 if (str)
5667 free(str);
Alexy Joseph62142aa2015-11-16 15:10:34 -08005668 str = str_parms_to_str(reply);
5669 }
5670
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005671 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
5672 if (ret >= 0) {
5673 value[0] = '\0';
5674 i = 0;
5675 first = true;
5676 while (out->supported_formats[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005677 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5678 if (formats_name_to_enum_table[j].value == out->supported_formats[i]) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005679 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005680 strlcat(value, "|", sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005681 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005682 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005683 first = false;
5684 break;
5685 }
5686 }
5687 i++;
5688 }
5689 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005690 if (str)
5691 free(str);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005692 str = str_parms_to_str(reply);
5693 }
Mingming Yin3a941d42016-02-17 18:08:05 -08005694
5695 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value, sizeof(value));
5696 if (ret >= 0) {
5697 value[0] = '\0';
5698 i = 0;
5699 first = true;
5700 while (out->supported_sample_rates[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005701 for (j = 0; j < ARRAY_SIZE(out_sample_rates_name_to_enum_table); j++) {
5702 if (out_sample_rates_name_to_enum_table[j].value == out->supported_sample_rates[i]) {
Mingming Yin3a941d42016-02-17 18:08:05 -08005703 if (!first) {
5704 strlcat(value, "|", sizeof(value));
5705 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005706 strlcat(value, out_sample_rates_name_to_enum_table[j].name, sizeof(value));
Mingming Yin3a941d42016-02-17 18:08:05 -08005707 first = false;
5708 break;
5709 }
5710 }
5711 i++;
5712 }
5713 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value);
5714 if (str)
5715 free(str);
5716 str = str_parms_to_str(reply);
5717 }
5718
Alexy Joseph98988832017-01-13 14:56:59 -08005719 if (str_parms_get_str(query, "supports_hw_suspend", value, sizeof(value)) >= 0) {
5720 //only low latency track supports suspend_resume
5721 str_parms_add_int(reply, "supports_hw_suspend",
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005722 (out->hal_output_suspend_supported));
Alexy Joseph98988832017-01-13 14:56:59 -08005723 if (str)
5724 free(str);
5725 str = str_parms_to_str(reply);
5726 }
5727
5728
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005729 str_parms_destroy(query);
5730 str_parms_destroy(reply);
Eric Laurent994a6932013-07-17 11:51:42 -07005731 ALOGV("%s: exit: returns - %s", __func__, str);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005732 return str;
5733}
5734
5735static uint32_t out_get_latency(const struct audio_stream_out *stream)
5736{
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005737 uint32_t period_ms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005738 struct stream_out *out = (struct stream_out *)stream;
Alexy Josephaa54c872014-12-03 02:46:47 -08005739 uint32_t latency = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005740
Alexy Josephaa54c872014-12-03 02:46:47 -08005741 if (is_offload_usecase(out->usecase)) {
Manish Dewangan07de2142017-02-27 19:27:20 +05305742 lock_output_stream(out);
5743 latency = audio_extn_utils_compress_get_dsp_latency(out);
5744 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07005745 } else if ((out->realtime) ||
5746 (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005747 // since the buffer won't be filled up faster than realtime,
5748 // return a smaller number
5749 if (out->config.rate)
5750 period_ms = (out->af_period_multiplier * out->config.period_size *
5751 1000) / (out->config.rate);
5752 else
5753 period_ms = 0;
George Gao9ba8a142020-07-23 14:30:03 -07005754 latency = period_ms + platform_render_latency(out) / 1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005755 } else {
5756 latency = (out->config.period_count * out->config.period_size * 1000) /
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005757 (out->config.rate);
pavanisra2d95d82022-02-09 18:55:58 +05305758 if (out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
5759 out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY)
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005760 latency += platform_render_latency(out)/1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005761 }
5762
Zhou Songd2537a02020-06-11 22:04:46 +08005763 if (!out->standby && is_a2dp_out_device_type(&out->device_list))
Aniket Kumar Latad5972fa2017-02-08 13:53:48 -08005764 latency += audio_extn_a2dp_get_encoder_latency();
5765
Anish Kumar50ebcbf2014-12-09 04:01:39 +05305766 ALOGV("%s: Latency %d", __func__, latency);
Alexy Josephaa54c872014-12-03 02:46:47 -08005767 return latency;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005768}
5769
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305770static float AmpToDb(float amplification)
5771{
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305772 float db = DSD_VOLUME_MIN_DB;
5773 if (amplification > 0) {
5774 db = 20 * log10(amplification);
5775 if(db < DSD_VOLUME_MIN_DB)
5776 return DSD_VOLUME_MIN_DB;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305777 }
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305778 return db;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305779}
5780
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305781#ifdef SOFT_VOLUME
5782static int out_set_soft_volume_params(struct audio_stream_out *stream)
5783{
5784 struct stream_out *out = (struct stream_out *)stream;
5785 int ret = 0;
5786 char mixer_ctl_name[128];
5787 struct audio_device *adev = out->dev;
5788 struct mixer_ctl *ctl = NULL;
5789 struct soft_step_volume_params *volume_params = NULL;
5790
5791 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5792 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Soft Vol Params", pcm_device_id);
5793 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5794 if (!ctl) {
5795 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5796 return -EINVAL;
5797 }
5798
5799 volume_params =(struct soft_step_volume_params * ) malloc(sizeof(struct soft_step_volume_params));
5800 if (volume_params == NULL){
5801 ALOGE("%s : malloc is failed for volume params", __func__);
5802 return -EINVAL;
5803 } else {
5804 ret = platform_get_soft_step_volume_params(volume_params,out->usecase);
5805 if (ret < 0) {
5806 ALOGE("%s : platform_get_soft_step_volume_params is fialed", __func__);
Karan Naidu28b335a2022-05-18 23:00:08 +05305807 ret = -EINVAL;
5808 goto ERR_EXIT;
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305809 }
5810
5811 }
5812 ret = mixer_ctl_set_array(ctl, volume_params, sizeof(struct soft_step_volume_params)/sizeof(int));
5813 if (ret < 0) {
5814 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
Karan Naidu28b335a2022-05-18 23:00:08 +05305815 ret = -EINVAL;
5816 goto ERR_EXIT;
5817 }
5818
5819 if (volume_params) {
5820 free(volume_params);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305821 }
5822 return 0;
Karan Naidu28b335a2022-05-18 23:00:08 +05305823
5824ERR_EXIT:
5825 if (volume_params) {
5826 free(volume_params);
5827 }
5828 return ret;
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305829}
5830#endif
5831
Arun Mirpuri5d170872019-03-26 13:21:31 -07005832static int out_set_mmap_volume(struct audio_stream_out *stream, float left,
5833 float right)
5834{
5835 struct stream_out *out = (struct stream_out *)stream;
5836 long volume = 0;
5837 char mixer_ctl_name[128] = "";
5838 struct audio_device *adev = out->dev;
5839 struct mixer_ctl *ctl = NULL;
5840 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5841 PCM_PLAYBACK);
5842
5843 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5844 "Playback %d Volume", pcm_device_id);
5845 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5846 if (!ctl) {
5847 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5848 __func__, mixer_ctl_name);
5849 return -EINVAL;
5850 }
5851 if (left != right)
5852 ALOGW("%s: Left and right channel volume mismatch:%f,%f",
5853 __func__, left, right);
5854 volume = (long)(left * (MMAP_PLAYBACK_VOLUME_MAX*1.0));
5855 if (mixer_ctl_set_value(ctl, 0, volume) < 0){
5856 ALOGE("%s:ctl for mixer cmd - %s, volume %ld returned error",
5857 __func__, mixer_ctl_name, volume);
5858 return -EINVAL;
5859 }
5860 return 0;
5861}
5862
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305863static int out_set_compr_volume(struct audio_stream_out *stream, float left,
5864 float right)
5865{
5866 struct stream_out *out = (struct stream_out *)stream;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305867 long volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305868 char mixer_ctl_name[128];
5869 struct audio_device *adev = out->dev;
5870 struct mixer_ctl *ctl;
5871 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5872 PCM_PLAYBACK);
5873
5874 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5875 "Compress Playback %d Volume", pcm_device_id);
5876 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5877 if (!ctl) {
5878 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5879 __func__, mixer_ctl_name);
5880 return -EINVAL;
5881 }
5882 ALOGE("%s:ctl for mixer cmd - %s, left %f, right %f",
5883 __func__, mixer_ctl_name, left, right);
5884 volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
5885 volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
5886 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5887
5888 return 0;
5889}
5890
Zhou Song2b8f28f2017-09-11 10:51:38 +08005891static int out_set_voip_volume(struct audio_stream_out *stream, float left,
5892 float right)
5893{
5894 struct stream_out *out = (struct stream_out *)stream;
5895 char mixer_ctl_name[] = "App Type Gain";
5896 struct audio_device *adev = out->dev;
5897 struct mixer_ctl *ctl;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305898 long set_values[4];
Zhou Song2b8f28f2017-09-11 10:51:38 +08005899
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07005900 if (!is_valid_volume(left, right)) {
5901 ALOGE("%s: Invalid stream volume for left=%f, right=%f",
5902 __func__, left, right);
5903 return -EINVAL;
5904 }
5905
Zhou Song2b8f28f2017-09-11 10:51:38 +08005906 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5907 if (!ctl) {
5908 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5909 __func__, mixer_ctl_name);
5910 return -EINVAL;
5911 }
5912
5913 set_values[0] = 0; //0: Rx Session 1:Tx Session
5914 set_values[1] = out->app_type_cfg.app_type;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305915 set_values[2] = (long)(left * VOIP_PLAYBACK_VOLUME_MAX);
5916 set_values[3] = (long)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Song2b8f28f2017-09-11 10:51:38 +08005917
5918 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
5919 return 0;
5920}
5921
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305922static int out_set_pcm_volume(struct audio_stream_out *stream, float left,
5923 float right)
5924{
5925 struct stream_out *out = (struct stream_out *)stream;
5926 /* Volume control for pcm playback */
5927 if (left != right) {
5928 return -EINVAL;
5929 } else {
5930 char mixer_ctl_name[128];
5931 struct audio_device *adev = out->dev;
5932 struct mixer_ctl *ctl;
5933 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5934 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Volume", pcm_device_id);
5935 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5936 if (!ctl) {
5937 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5938 return -EINVAL;
5939 }
5940
5941 int volume = (int) (left * PCM_PLAYBACK_VOLUME_MAX);
5942 int ret = mixer_ctl_set_value(ctl, 0, volume);
5943 if (ret < 0) {
5944 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
5945 return -EINVAL;
5946 }
5947
5948 ALOGV("%s : Pcm set volume value %d left %f", __func__, volume, left);
5949
5950 return 0;
5951 }
5952}
5953
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005954static int out_set_volume(struct audio_stream_out *stream, float left,
5955 float right)
5956{
Eric Laurenta9024de2013-04-04 09:19:12 -07005957 struct stream_out *out = (struct stream_out *)stream;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005958 int volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305959 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005960
Arun Mirpuri5d170872019-03-26 13:21:31 -07005961 ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
Eric Laurenta9024de2013-04-04 09:19:12 -07005962 if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
5963 /* only take left channel into account: the API is for stereo anyway */
5964 out->muted = (left == 0.0f);
5965 return 0;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005966 } else if (is_offload_usecase(out->usecase)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305967 if (audio_extn_passthru_is_passthrough_stream(out)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005968 /*
5969 * Set mute or umute on HDMI passthrough stream.
5970 * Only take left channel into account.
5971 * Mute is 0 and unmute 1
5972 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305973 audio_extn_passthru_set_volume(out, (left == 0.0f));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305974 } else if (out->format == AUDIO_FORMAT_DSD){
5975 char mixer_ctl_name[128] = "DSD Volume";
5976 struct audio_device *adev = out->dev;
5977 struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5978
5979 if (!ctl) {
5980 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5981 __func__, mixer_ctl_name);
5982 return -EINVAL;
5983 }
Manish Dewangan338c50a2017-09-12 15:22:03 +05305984 volume[0] = (long)(AmpToDb(left));
5985 volume[1] = (long)(AmpToDb(right));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305986 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5987 return 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005988 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS) &&
Derek Chendf05eea2019-08-01 13:57:49 -07005989 (out->car_audio_stream == CAR_AUDIO_STREAM_MEDIA)) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005990 ALOGD("%s: Overriding offload set volume for media bus stream", __func__);
5991 struct listnode *node = NULL;
5992 list_for_each(node, &adev->active_outputs_list) {
5993 streams_output_ctxt_t *out_ctxt = node_to_item(node,
5994 streams_output_ctxt_t,
5995 list);
5996 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
5997 out->volume_l = out_ctxt->output->volume_l;
5998 out->volume_r = out_ctxt->output->volume_r;
5999 }
6000 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006001 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006002 if (!out->a2dp_muted) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07006003 ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
6004 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006005 pthread_mutex_unlock(&out->latch_lock);
Philippe Gravel1c9ac352019-05-28 16:08:37 -07006006 return ret;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07006007 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +08006008 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006009 ALOGV("%s: compress mute %d", __func__, out->a2dp_muted);
6010 if (!out->a2dp_muted)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306011 ret = out_set_compr_volume(stream, left, right);
6012 out->volume_l = left;
6013 out->volume_r = right;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006014 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306015 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006016 }
Vikram Panduranga93f080e2017-06-07 18:16:14 -07006017 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
Aalique Grahame22e49102018-12-18 14:23:57 -08006018 out->app_type_cfg.gain[0] = (int)(left * VOIP_PLAYBACK_VOLUME_MAX);
6019 out->app_type_cfg.gain[1] = (int)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006020 pthread_mutex_lock(&out->latch_lock);
Aalique Grahame22e49102018-12-18 14:23:57 -08006021 if (!out->standby) {
6022 audio_extn_utils_send_app_type_gain(out->dev,
6023 out->app_type_cfg.app_type,
6024 &out->app_type_cfg.gain[0]);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006025 if (!out->a2dp_muted)
6026 ret = out_set_voip_volume(stream, left, right);
Aalique Grahame22e49102018-12-18 14:23:57 -08006027 }
Zhou Song2b8f28f2017-09-11 10:51:38 +08006028 out->volume_l = left;
6029 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006030 pthread_mutex_unlock(&out->latch_lock);
Zhou Song2b8f28f2017-09-11 10:51:38 +08006031 return ret;
Arun Mirpuri5d170872019-03-26 13:21:31 -07006032 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
6033 ALOGV("%s: MMAP set volume called", __func__);
6034 if (!out->standby)
6035 ret = out_set_mmap_volume(stream, left, right);
6036 out->volume_l = left;
6037 out->volume_r = right;
6038 return ret;
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306039 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
Ramu Gottipati36547092018-12-28 11:32:09 +05306040 out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
6041 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
Zhou Songbaddf9f2020-11-20 13:57:39 +08006042 pthread_mutex_lock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306043 /* Volume control for pcm playback */
Zhou Songbaddf9f2020-11-20 13:57:39 +08006044 if (!out->standby && !out->a2dp_muted)
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306045 ret = out_set_pcm_volume(stream, left, right);
6046 else
6047 out->apply_volume = true;
6048
6049 out->volume_l = left;
6050 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006051 pthread_mutex_unlock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306052 return ret;
Derek Chenf13dd492018-11-13 14:53:51 -08006053 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
6054 ALOGV("%s: bus device set volume called", __func__);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006055 pthread_mutex_lock(&out->latch_lock);
6056 if (!out->standby && !out->a2dp_muted)
Derek Chenf13dd492018-11-13 14:53:51 -08006057 ret = out_set_pcm_volume(stream, left, right);
6058 out->volume_l = left;
6059 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006060 pthread_mutex_unlock(&out->latch_lock);
Derek Chenf13dd492018-11-13 14:53:51 -08006061 return ret;
Eric Laurenta9024de2013-04-04 09:19:12 -07006062 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006063
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006064 return -ENOSYS;
6065}
6066
Zhou Songc9672822017-08-16 16:01:39 +08006067static void update_frames_written(struct stream_out *out, size_t bytes)
6068{
6069 size_t bpf = 0;
6070
6071 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
6072 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
6073 bpf = 1;
6074 else if (!is_offload_usecase(out->usecase))
6075 bpf = audio_bytes_per_sample(out->format) *
6076 audio_channel_count_from_out_mask(out->channel_mask);
Zhou Song48453a02018-01-10 17:50:59 +08006077
6078 pthread_mutex_lock(&out->position_query_lock);
6079 if (bpf != 0) {
Zhou Songc9672822017-08-16 16:01:39 +08006080 out->written += bytes / bpf;
Zhou Song48453a02018-01-10 17:50:59 +08006081 clock_gettime(CLOCK_MONOTONIC, &out->writeAt);
6082 }
6083 pthread_mutex_unlock(&out->position_query_lock);
Zhou Songc9672822017-08-16 16:01:39 +08006084}
6085
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006086int split_and_write_audio_haptic_data(struct stream_out *out,
6087 const void *buffer, size_t bytes_to_write)
6088{
6089 struct audio_device *adev = out->dev;
6090
6091 int ret = 0;
6092 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6093 size_t bytes_per_sample = audio_bytes_per_sample(out->format);
6094 size_t frame_size = channel_count * bytes_per_sample;
6095 size_t frame_count = bytes_to_write / frame_size;
6096
6097 bool force_haptic_path =
6098 property_get_bool("vendor.audio.test_haptic", false);
6099
6100 // extract Haptics data from Audio buffer
6101 bool alloc_haptic_buffer = false;
6102 int haptic_channel_count = adev->haptics_config.channels;
6103 size_t haptic_frame_size = bytes_per_sample * haptic_channel_count;
6104 size_t audio_frame_size = frame_size - haptic_frame_size;
6105 size_t total_haptic_buffer_size = frame_count * haptic_frame_size;
6106
6107 if (adev->haptic_buffer == NULL) {
6108 alloc_haptic_buffer = true;
6109 } else if (adev->haptic_buffer_size < total_haptic_buffer_size) {
6110 free(adev->haptic_buffer);
6111 adev->haptic_buffer_size = 0;
6112 alloc_haptic_buffer = true;
6113 }
6114
6115 if (alloc_haptic_buffer) {
6116 adev->haptic_buffer = (uint8_t *)calloc(1, total_haptic_buffer_size);
Mingshu Pang1513f972019-05-24 12:43:51 +08006117 if(adev->haptic_buffer == NULL) {
6118 ALOGE("%s: failed to allocate mem for dev->haptic_buffer", __func__);
6119 return -ENOMEM;
6120 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006121 adev->haptic_buffer_size = total_haptic_buffer_size;
6122 }
6123
6124 size_t src_index = 0, aud_index = 0, hap_index = 0;
6125 uint8_t *audio_buffer = (uint8_t *)buffer;
6126 uint8_t *haptic_buffer = adev->haptic_buffer;
6127
6128 // This is required for testing only. This works for stereo data only.
6129 // One channel is fed to audio stream and other to haptic stream for testing.
6130 if (force_haptic_path)
6131 audio_frame_size = haptic_frame_size = bytes_per_sample;
6132
6133 for (size_t i = 0; i < frame_count; i++) {
6134 memcpy(audio_buffer + aud_index, audio_buffer + src_index,
6135 audio_frame_size);
6136 aud_index += audio_frame_size;
6137 src_index += audio_frame_size;
6138
6139 if (adev->haptic_pcm)
6140 memcpy(haptic_buffer + hap_index, audio_buffer + src_index,
6141 haptic_frame_size);
6142 hap_index += haptic_frame_size;
6143 src_index += haptic_frame_size;
6144
6145 // This is required for testing only.
6146 // Discard haptic channel data.
6147 if (force_haptic_path)
6148 src_index += haptic_frame_size;
6149 }
6150
6151 // write to audio pipeline
6152 ret = pcm_write(out->pcm, (void *)audio_buffer,
6153 frame_count * audio_frame_size);
6154
6155 // write to haptics pipeline
6156 if (adev->haptic_pcm)
6157 ret = pcm_write(adev->haptic_pcm, (void *)adev->haptic_buffer,
6158 frame_count * haptic_frame_size);
6159
6160 return ret;
6161}
6162
Aalique Grahame22e49102018-12-18 14:23:57 -08006163#ifdef NO_AUDIO_OUT
6164static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
6165 const void *buffer __unused, size_t bytes)
6166{
6167 struct stream_out *out = (struct stream_out *)stream;
6168
6169 /* No Output device supported other than BT for playback.
6170 * Sleep for the amount of buffer duration
6171 */
6172 lock_output_stream(out);
6173 usleep(bytes * 1000000 / audio_stream_out_frame_size(
6174 (const struct audio_stream_out *)&out->stream) /
6175 out_get_sample_rate(&out->stream.common));
6176 pthread_mutex_unlock(&out->lock);
6177 return bytes;
6178}
6179#endif
6180
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006181static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
6182 size_t bytes)
6183{
6184 struct stream_out *out = (struct stream_out *)stream;
6185 struct audio_device *adev = out->dev;
Eric Laurent6e895242013-09-05 16:10:57 -07006186 ssize_t ret = 0;
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306187 int channels = 0;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006188 const size_t frame_size = audio_stream_out_frame_size(stream);
6189 const size_t frames = (frame_size != 0) ? bytes / frame_size : bytes;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306190 struct audio_usecase *usecase = NULL;
Meng Wang4c32fb42020-01-16 17:57:11 +08006191 uint32_t compr_passthr = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006192
Haynes Mathew George380745d2017-10-04 15:27:45 -07006193 ATRACE_BEGIN("out_write");
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006194 lock_output_stream(out);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306195
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006196 if (CARD_STATUS_OFFLINE == out->card_status ||
6197 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Zhou Song0b2e5dc2015-03-16 14:41:38 +08006198
Dhananjay Kumarac341582017-02-23 23:42:25 +05306199 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306200 /*during SSR for compress usecase we should return error to flinger*/
Naresh Tanniru80659832014-06-04 18:17:56 +05306201 ALOGD(" copl %s: sound card is not active/SSR state", __func__);
6202 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006203 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306204 return -ENETRESET;
Ashish Jainbbce4322016-02-16 13:25:27 +05306205 } else {
Ashish Jainbbce4322016-02-16 13:25:27 +05306206 ALOGD(" %s: sound card is not active/SSR state", __func__);
6207 ret= -EIO;
6208 goto exit;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306209 }
6210 }
6211
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306212 if (audio_extn_passthru_should_drop_data(out)) {
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306213 ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306214 ret = -EIO;
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306215 goto exit;
6216 }
6217
Haynes Mathew George16081042017-05-31 17:16:49 -07006218 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
6219 ret = -EINVAL;
6220 goto exit;
6221 }
6222
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006223 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306224 !out->is_iec61937_info_available) {
6225
6226 if (!audio_extn_passthru_is_passthrough_stream(out)) {
6227 out->is_iec61937_info_available = true;
6228 } else if (audio_extn_passthru_is_enabled()) {
6229 audio_extn_passthru_update_stream_configuration(adev, out, buffer, bytes);
Manish Dewangan37864bc2017-06-09 12:28:37 +05306230 out->is_iec61937_info_available = true;
Manish Dewangan671a4202017-08-18 17:30:46 +05306231
6232 if((out->format == AUDIO_FORMAT_DTS) ||
6233 (out->format == AUDIO_FORMAT_DTS_HD)) {
6234 ret = audio_extn_passthru_update_dts_stream_configuration(out,
6235 buffer, bytes);
6236 if (ret) {
6237 if (ret != -ENOSYS) {
6238 out->is_iec61937_info_available = false;
6239 ALOGD("iec61937 transmission info not yet updated retry");
6240 }
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306241 } else if (!out->standby) {
Manish Dewangan671a4202017-08-18 17:30:46 +05306242 /* if stream has started and after that there is
6243 * stream config change (iec transmission config)
6244 * then trigger select_device to update backend configuration.
6245 */
6246 out->stream_config_changed = true;
6247 pthread_mutex_lock(&adev->lock);
6248 select_devices(adev, out->usecase);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306249 if (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out)) {
Weiyin Jiang29c08a42019-04-30 17:11:10 +08006250 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306251 ret = -EINVAL;
6252 goto exit;
6253 }
Manish Dewangan671a4202017-08-18 17:30:46 +05306254 pthread_mutex_unlock(&adev->lock);
6255 out->stream_config_changed = false;
6256 out->is_iec61937_info_available = true;
6257 }
6258 }
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306259
Meng Wang4c32fb42020-01-16 17:57:11 +08006260#ifdef AUDIO_GKI_ENABLED
6261 /* out->compr_config.codec->reserved[0] is for compr_passthr */
6262 compr_passthr = out->compr_config.codec->reserved[0];
6263#else
6264 compr_passthr = out->compr_config.codec->compr_passthr;
6265#endif
6266
Garmond Leung317cbf12017-09-13 16:20:50 -07006267 if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
Meng Wang4c32fb42020-01-16 17:57:11 +08006268 (compr_passthr == PASSTHROUGH) &&
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306269 (out->is_iec61937_info_available == true)) {
6270 ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
6271 ret = -EINVAL;
6272 goto exit;
6273 }
Manish Dewangan37864bc2017-06-09 12:28:37 +05306274 }
6275 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306276
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006277 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02006278 (audio_extn_a2dp_source_is_suspended())) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006279 if (!(compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
6280 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
Zhou Songd01e7a22020-09-23 22:49:01 +08006281 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306282 ret = -EIO;
6283 goto exit;
6284 }
6285 }
6286 }
6287
Weiyin Jiangabedea32020-12-09 12:49:19 +08006288 if (is_usb_out_device_type(&out->device_list) &&
6289 !audio_extn_usb_connected(NULL)) {
6290 ret = -EIO;
6291 goto exit;
6292 }
6293
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006294 if (out->standby) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006295 out->standby = false;
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006296 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
6297
Eric Laurent150dbfe2013-02-27 14:31:02 -08006298 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006299 if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
6300 ret = voice_extn_compress_voip_start_output_stream(out);
6301 else
6302 ret = start_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006303 /* ToDo: If use case is compress offload should return 0 */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006304 if (ret != 0) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006305 out->standby = true;
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006306 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006307 goto exit;
6308 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306309 out->started = 1;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006310 out->last_fifo_valid = false; // we're coming out of standby, last_fifo isn't valid.
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006311
6312 if ((last_known_cal_step != -1) && (adev->platform != NULL)) {
vivek mehtab72d08d2016-04-29 03:16:47 -07006313 ALOGD("%s: retry previous failed cal level set", __func__);
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006314 platform_send_gain_dep_cal(adev->platform, last_known_cal_step);
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +05306315 last_known_cal_step = -1;
vivek mehtab72d08d2016-04-29 03:16:47 -07006316 }
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006317 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306318
6319 if ((out->is_iec61937_info_available == true) &&
6320 (audio_extn_passthru_is_passthrough_stream(out))&&
6321 (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out))) {
6322 ret = -EINVAL;
6323 goto exit;
6324 }
Surendar Karkaf51b5842018-04-26 11:28:38 +05306325 if (out->set_dual_mono)
6326 audio_extn_send_dual_mono_mixing_coefficients(out);
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006327
Dechen Chai22768452021-07-30 09:29:16 +05306328#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006329 // log startup time in ms.
6330 simple_stats_log(
6331 &out->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05306332#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006333 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006334
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006335 if (adev->is_channel_status_set == false &&
6336 compare_device_type(&out->device_list,
6337 AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Alexy Josephb1379942016-01-29 15:49:38 -08006338 audio_utils_set_hdmi_channel_status(out, (void *)buffer, bytes);
Ashish Jain81eb2a82015-05-13 10:52:34 +05306339 adev->is_channel_status_set = true;
6340 }
6341
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306342 if ((adev->use_old_pspd_mix_ctrl == true) &&
6343 (out->pspd_coeff_sent == false)) {
6344 /*
6345 * Need to resend pspd coefficients after stream started for
6346 * older kernel version as it does not save the coefficients
6347 * and also stream has to be started for coeff to apply.
6348 */
6349 usecase = get_usecase_from_list(adev, out->usecase);
6350 if (usecase != NULL) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05306351 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306352 out->pspd_coeff_sent = true;
6353 }
6354 }
6355
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006356 if (is_offload_usecase(out->usecase)) {
Alexy Joseph01e54e62015-03-03 19:01:03 -08006357 ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006358 if (out->send_new_metadata) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006359 ALOGD("copl(%p):send new gapless metadata", out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006360 compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
6361 out->send_new_metadata = 0;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306362 if (out->send_next_track_params && out->is_compr_metadata_avail) {
6363 ALOGD("copl(%p):send next track params in gapless", out);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08006364 compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306365 out->send_next_track_params = false;
6366 out->is_compr_metadata_avail = false;
6367 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006368 }
Dhananjay Kumarac341582017-02-23 23:42:25 +05306369 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306370 (out->convert_buffer) != NULL) {
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006371
Ashish Jain83a6cc22016-06-28 14:34:17 +05306372 if ((bytes > out->hal_fragment_size)) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05306373 ALOGW("Error written bytes %zu > %d (fragment_size)",
Ashish Jain83a6cc22016-06-28 14:34:17 +05306374 bytes, out->hal_fragment_size);
Ashish Jainf1eaa582016-05-23 20:54:24 +05306375 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006376 ATRACE_END();
Ashish Jainf1eaa582016-05-23 20:54:24 +05306377 return -EINVAL;
6378 } else {
Ashish Jain83a6cc22016-06-28 14:34:17 +05306379 audio_format_t dst_format = out->hal_op_format;
6380 audio_format_t src_format = out->hal_ip_format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05306381
Dieter Luecking5d57def2018-09-07 14:23:37 +02006382 /* prevent division-by-zero */
6383 uint32_t bitwidth_src = format_to_bitwidth_table[src_format];
6384 uint32_t bitwidth_dst = format_to_bitwidth_table[dst_format];
6385 if ((bitwidth_src == 0) || (bitwidth_dst == 0)) {
6386 ALOGE("%s: Error bitwidth == 0", __func__);
Ramu Gottipati02809682018-12-19 16:46:12 +05306387 pthread_mutex_unlock(&out->lock);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006388 ATRACE_END();
6389 return -EINVAL;
6390 }
6391
Ashish Jainf1eaa582016-05-23 20:54:24 +05306392 uint32_t frames = bytes / format_to_bitwidth_table[src_format];
6393 uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
6394
Ashish Jain83a6cc22016-06-28 14:34:17 +05306395 memcpy_by_audio_format(out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306396 dst_format,
6397 buffer,
6398 src_format,
6399 frames);
6400
Ashish Jain83a6cc22016-06-28 14:34:17 +05306401 ret = compress_write(out->compr, out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306402 bytes_to_write);
6403
6404 /*Convert written bytes in audio flinger format*/
6405 if (ret > 0)
6406 ret = ((ret * format_to_bitwidth_table[out->format]) /
6407 format_to_bitwidth_table[dst_format]);
6408 }
6409 } else
6410 ret = compress_write(out->compr, buffer, bytes);
6411
Zhou Songc9672822017-08-16 16:01:39 +08006412 if ((ret < 0 || ret == (ssize_t)bytes) && !out->non_blocking)
6413 update_frames_written(out, bytes);
6414
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306415 if (ret < 0)
6416 ret = -errno;
Weiyin Jiangcc60dbb2018-08-21 13:12:03 +08006417 ALOGVV("%s: writing buffer (%zu bytes) to compress device returned %d", __func__, bytes, (int)ret);
Ashish Jainb26edfb2016-08-25 00:10:11 +05306418 /*msg to cb thread only if non blocking write is enabled*/
6419 if (ret >= 0 && ret < (ssize_t)bytes && out->non_blocking) {
Sidipotu Ashok55820562014-02-10 16:16:38 +05306420 ALOGD("No space available in compress driver, post msg to cb thread");
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006421 send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
Naresh Tanniru80659832014-06-04 18:17:56 +05306422 } else if (-ENETRESET == ret) {
6423 ALOGE("copl %s: received sound card offline state on compress write", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306424 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru80659832014-06-04 18:17:56 +05306425 pthread_mutex_unlock(&out->lock);
Dhananjay Kumar1248dd82017-07-28 21:22:16 +05306426 out_on_error(&out->stream.common);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006427 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306428 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006429 }
Ashish Jain5106d362016-05-11 19:23:33 +05306430
Dhanalakshmi Siddania6b76c72016-09-09 18:10:31 +05306431 /* Call compr start only when non-zero bytes of data is there to be rendered */
6432 if (!out->playback_started && ret > 0) {
6433 int status = compress_start(out->compr);
6434 if (status < 0) {
6435 ret = status;
6436 ALOGE("%s: compr start failed with err %d", __func__, errno);
6437 goto exit;
6438 }
Alexy Joseph7de344d2015-03-30 10:40:03 -07006439 audio_extn_dts_eagle_fade(adev, true, out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006440 out->playback_started = 1;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006441 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006442 out->offload_state = OFFLOAD_STATE_PLAYING;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006443 pthread_mutex_unlock(&out->latch_lock);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006444
6445 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6446 popcount(out->channel_mask),
6447 out->playback_started);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006448 }
6449 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006450 ATRACE_END();
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006451 return ret;
6452 } else {
6453 if (out->pcm) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006454 size_t bytes_to_write = bytes;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006455 if (out->muted)
6456 memset((void *)buffer, 0, bytes);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006457 ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
6458 __func__, frames, frame_size, bytes_to_write);
6459
Aalique Grahame22e49102018-12-18 14:23:57 -08006460 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07006461 out->usecase == USECASE_INCALL_MUSIC_UPLINK2 ||
6462 (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP &&
6463 !audio_extn_utils_is_vendor_enhanced_fwk())) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006464 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6465 int16_t *src = (int16_t *)buffer;
6466 int16_t *dst = (int16_t *)buffer;
6467
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006468 LOG_ALWAYS_FATAL_IF(channel_count > 2 ||
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006469 out->format != AUDIO_FORMAT_PCM_16_BIT,
Aalique Grahame22e49102018-12-18 14:23:57 -08006470 "out_write called for %s use case with wrong properties",
6471 use_case_table[out->usecase]);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006472
6473 /*
6474 * FIXME: this can be removed once audio flinger mixer supports
6475 * mono output
6476 */
6477
6478 /*
6479 * Code below goes over each frame in the buffer and adds both
6480 * L and R samples and then divides by 2 to convert to mono
6481 */
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006482 if (channel_count == 2) {
6483 for (size_t i = 0; i < frames ; i++, dst++, src += 2) {
6484 *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
6485 }
6486 bytes_to_write /= 2;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006487 }
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006488 }
Andy Hunga1f48fa2019-07-01 18:14:53 -07006489
6490 // Note: since out_get_presentation_position() is called alternating with out_write()
6491 // by AudioFlinger, we can check underruns using the prior timestamp read.
6492 // (Alternately we could check if the buffer is empty using pcm_get_htimestamp().
6493 if (out->last_fifo_valid) {
6494 // compute drain to see if there is an underrun.
6495 const int64_t current_ns = systemTime(SYSTEM_TIME_MONOTONIC); // sys call
Dhananjay Kumara4429632020-07-11 02:53:37 +05306496 int64_t time_diff_ns = current_ns - out->last_fifo_time_ns;
6497 int64_t frames_by_time =
6498 ((time_diff_ns > 0) && (time_diff_ns < (INT64_MAX / out->config.rate))) ?
6499 (time_diff_ns * out->config.rate / NANOS_PER_SECOND) : 0;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006500 const int64_t underrun = frames_by_time - out->last_fifo_frames_remaining;
6501
6502 if (underrun > 0) {
Dechen Chai22768452021-07-30 09:29:16 +05306503#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07006504 simple_stats_log(&out->fifo_underruns, underrun);
Dechen Chai22768452021-07-30 09:29:16 +05306505#endif
Andy Hunga1f48fa2019-07-01 18:14:53 -07006506
6507 ALOGW("%s: underrun(%lld) "
6508 "frames_by_time(%lld) > out->last_fifo_frames_remaining(%lld)",
6509 __func__,
6510 (long long)out->fifo_underruns.n,
6511 (long long)frames_by_time,
6512 (long long)out->last_fifo_frames_remaining);
6513 }
6514 out->last_fifo_valid = false; // we're writing below, mark fifo info as stale.
6515 }
6516
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05306517 ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006518
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006519 long ns = 0;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006520
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006521 if (out->config.rate)
6522 ns = pcm_bytes_to_frames(out->pcm, bytes)*1000000000LL/
6523 out->config.rate;
6524
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006525 request_out_focus(out, ns);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006526 bool use_mmap = is_mmap_usecase(out->usecase) || out->realtime;
6527
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006528 if (use_mmap)
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006529 ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes_to_write);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006530 else if (out->hal_op_format != out->hal_ip_format &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306531 out->convert_buffer != NULL) {
6532
6533 memcpy_by_audio_format(out->convert_buffer,
6534 out->hal_op_format,
6535 buffer,
6536 out->hal_ip_format,
6537 out->config.period_size * out->config.channels);
6538
6539 ret = pcm_write(out->pcm, out->convert_buffer,
6540 (out->config.period_size *
6541 out->config.channels *
6542 format_to_bitwidth_table[out->hal_op_format]));
6543 } else {
Aditya Bavanarid4db8ee2017-05-29 21:08:03 +05306544 /*
6545 * To avoid underrun in DSP when the application is not pumping
6546 * data at required rate, check for the no. of bytes and ignore
6547 * pcm_write if it is less than actual buffer size.
6548 * It is a work around to a change in compress VOIP driver.
6549 */
6550 if ((out->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) &&
6551 bytes < (out->config.period_size * out->config.channels *
6552 audio_bytes_per_sample(out->format))) {
6553 size_t voip_buf_size =
6554 out->config.period_size * out->config.channels *
6555 audio_bytes_per_sample(out->format);
6556 ALOGE("%s:VOIP underrun: bytes received %zu, required:%zu\n",
6557 __func__, bytes, voip_buf_size);
6558 usleep(((uint64_t)voip_buf_size - bytes) *
6559 1000000 / audio_stream_out_frame_size(stream) /
6560 out_get_sample_rate(&out->stream.common));
6561 ret = 0;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006562 } else {
6563 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
6564 ret = split_and_write_audio_haptic_data(out, buffer, bytes);
6565 else
6566 ret = pcm_write(out->pcm, (void *)buffer, bytes_to_write);
6567 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05306568 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006569
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006570 release_out_focus(out);
6571
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306572 if (ret < 0)
6573 ret = -errno;
Zhou Songc9672822017-08-16 16:01:39 +08006574 else if (ret > 0)
Ashish Jain83a6cc22016-06-28 14:34:17 +05306575 ret = -EINVAL;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006576 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006577 }
6578
6579exit:
Zhou Songc9672822017-08-16 16:01:39 +08006580 update_frames_written(out, bytes);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306581 if (-ENETRESET == ret) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306582 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306583 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006584 pthread_mutex_unlock(&out->lock);
6585
6586 if (ret != 0) {
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07006587 if (out->pcm)
Alexy Josephb1379942016-01-29 15:49:38 -08006588 ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306589 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306590 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306591 voice_extn_compress_voip_close_output_stream(&out->stream.common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306592 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306593 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306594 out->standby = true;
6595 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306596 out_on_error(&out->stream.common);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006597 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
6598 /* prevent division-by-zero */
6599 uint32_t stream_size = audio_stream_out_frame_size(stream);
6600 uint32_t srate = out_get_sample_rate(&out->stream.common);
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006601
Dieter Luecking5d57def2018-09-07 14:23:37 +02006602 if ((stream_size == 0) || (srate == 0)) {
6603 ALOGE("%s: stream_size= %d, srate = %d", __func__, stream_size, srate);
6604 ATRACE_END();
6605 return -EINVAL;
6606 }
6607 usleep((uint64_t)bytes * 1000000 / stream_size / srate);
6608 }
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006609 if (audio_extn_passthru_is_passthrough_stream(out)) {
Rajshekar Eashwarappa88834522018-04-02 17:20:15 +05306610 //ALOGE("%s: write error, ret = %zd", __func__, ret);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006611 ATRACE_END();
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006612 return ret;
6613 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006614 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07006615 ATRACE_END();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006616 return bytes;
6617}
6618
6619static int out_get_render_position(const struct audio_stream_out *stream,
6620 uint32_t *dsp_frames)
6621{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006622 struct stream_out *out = (struct stream_out *)stream;
Zhou Song32a556e2015-05-05 10:46:56 +08006623
6624 if (dsp_frames == NULL)
6625 return -EINVAL;
6626
6627 *dsp_frames = 0;
6628 if (is_offload_usecase(out->usecase)) {
Mingming Yin9e348b52014-11-19 16:18:55 -08006629 ssize_t ret = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05306630
6631 /* Below piece of code is not guarded against any lock beacuse audioFliner serializes
6632 * this operation and adev_close_output_stream(where out gets reset).
6633 */
Dhananjay Kumarac341582017-02-23 23:42:25 +05306634 if (!out->non_blocking && !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006635 *dsp_frames = get_actual_pcm_frames_rendered(out, NULL);
Ashish Jain5106d362016-05-11 19:23:33 +05306636 ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate);
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006637 adjust_frames_for_device_delay(out, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05306638 return 0;
6639 }
6640
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006641 lock_output_stream(out);
Ashish Jain5106d362016-05-11 19:23:33 +05306642 if (out->compr != NULL && out->non_blocking) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306643 ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006644 &out->sample_rate);
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306645 if (ret < 0)
6646 ret = -errno;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006647 ALOGVV("%s rendered frames %d sample_rate %d",
Ashish Jain5106d362016-05-11 19:23:33 +05306648 __func__, *dsp_frames, out->sample_rate);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006649 }
Naresh Tanniru80659832014-06-04 18:17:56 +05306650 if (-ENETRESET == ret) {
6651 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306652 out->card_status = CARD_STATUS_OFFLINE;
6653 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306654 } else if(ret < 0) {
6655 ALOGE(" ERROR: Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306656 ret = -EINVAL;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006657 } else if (out->card_status == CARD_STATUS_OFFLINE ||
6658 adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05306659 /*
6660 * Handle corner case where compress session is closed during SSR
6661 * and timestamp is queried
6662 */
6663 ALOGE(" ERROR: sound card not active, return error");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306664 ret = -EINVAL;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306665 } else if (out->prev_card_status_offline) {
6666 ALOGE("ERROR: previously sound card was offline,return error");
6667 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306668 } else {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306669 ret = 0;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006670 adjust_frames_for_device_delay(out, dsp_frames);
Naresh Tanniru80659832014-06-04 18:17:56 +05306671 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306672 pthread_mutex_unlock(&out->lock);
6673 return ret;
Zhou Song32a556e2015-05-05 10:46:56 +08006674 } else if (audio_is_linear_pcm(out->format)) {
6675 *dsp_frames = out->written;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006676 adjust_frames_for_device_delay(out, dsp_frames);
Zhou Song32a556e2015-05-05 10:46:56 +08006677 return 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006678 } else
6679 return -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006680}
6681
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006682static int out_add_audio_effect(const struct audio_stream *stream __unused,
6683 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006684{
6685 return 0;
6686}
6687
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006688static int out_remove_audio_effect(const struct audio_stream *stream __unused,
6689 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006690{
6691 return 0;
6692}
6693
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006694static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
6695 int64_t *timestamp __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006696{
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05306697 return -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006698}
6699
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006700static int out_get_presentation_position(const struct audio_stream_out *stream,
6701 uint64_t *frames, struct timespec *timestamp)
6702{
6703 struct stream_out *out = (struct stream_out *)stream;
pavance65c2fe2017-10-18 17:52:01 +05306704 int ret = -ENODATA;
Eric Laurent949a0892013-09-20 09:20:13 -07006705 unsigned long dsp_frames;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006706
Ashish Jain5106d362016-05-11 19:23:33 +05306707 /* below piece of code is not guarded against any lock because audioFliner serializes
6708 * this operation and adev_close_output_stream( where out gets reset).
6709 */
6710 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
Dhananjay Kumarac341582017-02-23 23:42:25 +05306711 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006712 *frames = get_actual_pcm_frames_rendered(out, timestamp);
Ashish Jain5106d362016-05-11 19:23:33 +05306713 ALOGVV("frames %lld playedat %lld",(long long int)*frames,
6714 timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000);
6715 return 0;
6716 }
6717
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006718 lock_output_stream(out);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006719
Ashish Jain5106d362016-05-11 19:23:33 +05306720 if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) {
6721 ret = compress_get_tstamp(out->compr, &dsp_frames,
6722 &out->sample_rate);
yidongh0515e042017-07-06 15:00:34 +08006723 // Adjustment accounts for A2dp encoder latency with offload usecases
6724 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006725 if (is_a2dp_out_device_type(&out->device_list)) {
yidongh0515e042017-07-06 15:00:34 +08006726 unsigned long offset =
6727 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
6728 dsp_frames = (dsp_frames > offset) ? (dsp_frames - offset) : 0;
6729 }
Ashish Jain5106d362016-05-11 19:23:33 +05306730 ALOGVV("%s rendered frames %ld sample_rate %d",
6731 __func__, dsp_frames, out->sample_rate);
6732 *frames = dsp_frames;
6733 if (ret < 0)
6734 ret = -errno;
6735 if (-ENETRESET == ret) {
6736 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306737 out->card_status = CARD_STATUS_OFFLINE;
Ashish Jain5106d362016-05-11 19:23:33 +05306738 ret = -EINVAL;
6739 } else
6740 ret = 0;
6741 /* this is the best we can do */
6742 clock_gettime(CLOCK_MONOTONIC, timestamp);
Eric Laurent949a0892013-09-20 09:20:13 -07006743 } else {
6744 if (out->pcm) {
Weiyin Jiangd4633762018-03-16 12:05:03 +08006745 unsigned int avail;
6746 if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
George Gao62ebc722019-07-29 16:29:44 -07006747 uint64_t signed_frames = 0;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006748 uint64_t frames_temp = 0;
George Gao62ebc722019-07-29 16:29:44 -07006749
Andy Hunga1f48fa2019-07-01 18:14:53 -07006750 if (out->kernel_buffer_size > avail) {
6751 frames_temp = out->last_fifo_frames_remaining = out->kernel_buffer_size - avail;
6752 } else {
6753 ALOGW("%s: avail:%u > kernel_buffer_size:%zu clamping!",
6754 __func__, avail, out->kernel_buffer_size);
6755 avail = out->kernel_buffer_size;
6756 frames_temp = out->last_fifo_frames_remaining = 0;
6757 }
6758 out->last_fifo_valid = true;
6759 out->last_fifo_time_ns = audio_utils_ns_from_timespec(timestamp);
6760
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006761 if (out->written >= frames_temp)
6762 signed_frames = out->written - frames_temp;
George Gao62ebc722019-07-29 16:29:44 -07006763
Andy Hunga1f48fa2019-07-01 18:14:53 -07006764 ALOGVV("%s: frames:%lld avail:%u kernel_buffer_size:%zu",
6765 __func__, (long long)signed_frames, avail, out->kernel_buffer_size);
6766
Weiyin Jiangd4633762018-03-16 12:05:03 +08006767 // This adjustment accounts for buffering after app processor.
6768 // It is based on estimated DSP latency per use case, rather than exact.
George Gao9ba8a142020-07-23 14:30:03 -07006769 frames_temp = platform_render_latency(out) *
Robert Lee58215542019-07-15 20:55:12 +08006770 out->sample_rate / 1000000LL;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006771 if (signed_frames >= frames_temp)
6772 signed_frames -= frames_temp;
Aniket Kumar Lataff613152017-07-18 18:19:21 -07006773
Weiyin Jiangd4633762018-03-16 12:05:03 +08006774 // Adjustment accounts for A2dp encoder latency with non offload usecases
6775 // Note: Encoder latency is returned in ms, while platform_render_latency in us.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006776 if (is_a2dp_out_device_type(&out->device_list)) {
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006777 frames_temp = audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000;
6778 if (signed_frames >= frames_temp)
6779 signed_frames -= frames_temp;
Weiyin Jiangd4633762018-03-16 12:05:03 +08006780 }
6781
6782 // It would be unusual for this value to be negative, but check just in case ...
George Gao62ebc722019-07-29 16:29:44 -07006783 *frames = signed_frames;
6784 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006785 }
Eric Laurenta7a33042019-07-10 16:20:22 -07006786 } else if (out->card_status == CARD_STATUS_OFFLINE ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006787 adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE ||
Eric Laurenta7a33042019-07-10 16:20:22 -07006788 // audioflinger still needs position updates when A2DP is suspended
Jasmine Cha5c2517f2019-09-09 11:07:28 +08006789 (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306790 *frames = out->written;
6791 clock_gettime(CLOCK_MONOTONIC, timestamp);
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306792 if (is_offload_usecase(out->usecase))
6793 ret = -EINVAL;
6794 else
6795 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006796 }
6797 }
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006798 pthread_mutex_unlock(&out->lock);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006799 return ret;
6800}
6801
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006802static int out_set_callback(struct audio_stream_out *stream,
6803 stream_callback_t callback, void *cookie)
6804{
6805 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006806 int ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006807
6808 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006809 lock_output_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006810 out->client_callback = callback;
6811 out->client_cookie = cookie;
6812 if (out->adsp_hdlr_stream_handle) {
6813 ret = audio_extn_adsp_hdlr_stream_set_callback(
6814 out->adsp_hdlr_stream_handle,
6815 callback,
6816 cookie);
6817 if (ret)
6818 ALOGW("%s:adsp hdlr callback registration failed %d",
6819 __func__, ret);
6820 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006821 pthread_mutex_unlock(&out->lock);
6822 return 0;
6823}
6824
6825static int out_pause(struct audio_stream_out* stream)
6826{
6827 struct stream_out *out = (struct stream_out *)stream;
6828 int status = -ENOSYS;
6829 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006830 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006831 ALOGD("copl(%p):pause compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306832 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006833 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006834 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006835 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306836 if (out->card_status != CARD_STATUS_OFFLINE)
Naresh Tanniru80659832014-06-04 18:17:56 +05306837 status = compress_pause(out->compr);
6838
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006839 out->offload_state = OFFLOAD_STATE_PAUSED;
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006840
Mingming Yin21854652016-04-13 11:54:02 -07006841 if (audio_extn_passthru_is_active()) {
6842 ALOGV("offload use case, pause passthru");
6843 audio_extn_passthru_on_pause(out);
6844 }
6845
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306846 audio_extn_dts_eagle_fade(adev, false, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006847 audio_extn_dts_notify_playback_state(out->usecase, 0,
6848 out->sample_rate, popcount(out->channel_mask),
6849 0);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006850 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006851 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006852 pthread_mutex_unlock(&out->lock);
6853 }
6854 return status;
6855}
6856
6857static int out_resume(struct audio_stream_out* stream)
6858{
6859 struct stream_out *out = (struct stream_out *)stream;
6860 int status = -ENOSYS;
6861 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006862 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006863 ALOGD("copl(%p):resume compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306864 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006865 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006866 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006867 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306868 if (out->card_status != CARD_STATUS_OFFLINE) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306869 status = compress_resume(out->compr);
Mingming Yin21854652016-04-13 11:54:02 -07006870 }
6871 if (!status) {
6872 out->offload_state = OFFLOAD_STATE_PLAYING;
6873 }
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306874 audio_extn_dts_eagle_fade(adev, true, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006875 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6876 popcount(out->channel_mask), 1);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006877 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006878 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006879 pthread_mutex_unlock(&out->lock);
6880 }
6881 return status;
6882}
6883
6884static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
6885{
6886 struct stream_out *out = (struct stream_out *)stream;
6887 int status = -ENOSYS;
6888 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006889 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006890 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006891 if (type == AUDIO_DRAIN_EARLY_NOTIFY)
6892 status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
6893 else
6894 status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
6895 pthread_mutex_unlock(&out->lock);
6896 }
6897 return status;
6898}
6899
6900static int out_flush(struct audio_stream_out* stream)
6901{
6902 struct stream_out *out = (struct stream_out *)stream;
6903 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006904 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006905 ALOGD("copl(%p):calling compress flush", out);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006906 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006907 pthread_mutex_lock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006908 if (out->offload_state == OFFLOAD_STATE_PAUSED) {
Gautam Manam14c198b2020-12-24 14:08:04 +05306909 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006910 stop_compressed_output_l(out);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006911 } else {
6912 ALOGW("%s called in invalid state %d", __func__, out->offload_state);
Gautam Manam14c198b2020-12-24 14:08:04 +05306913 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006914 }
Weiyin Jiang547e4152017-09-14 17:24:18 +08006915 out->written = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006916 pthread_mutex_unlock(&out->lock);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006917 ALOGD("copl(%p):out of compress flush", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006918 return 0;
6919 }
6920 return -ENOSYS;
6921}
6922
Haynes Mathew George16081042017-05-31 17:16:49 -07006923static int out_stop(const struct audio_stream_out* stream)
6924{
6925 struct stream_out *out = (struct stream_out *)stream;
6926 struct audio_device *adev = out->dev;
6927 int ret = -ENOSYS;
6928
6929 ALOGV("%s", __func__);
6930 pthread_mutex_lock(&adev->lock);
6931 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6932 out->playback_started && out->pcm != NULL) {
6933 pcm_stop(out->pcm);
6934 ret = stop_output_stream(out);
6935 out->playback_started = false;
6936 }
6937 pthread_mutex_unlock(&adev->lock);
6938 return ret;
6939}
6940
6941static int out_start(const struct audio_stream_out* stream)
6942{
6943 struct stream_out *out = (struct stream_out *)stream;
6944 struct audio_device *adev = out->dev;
6945 int ret = -ENOSYS;
6946
6947 ALOGV("%s", __func__);
6948 pthread_mutex_lock(&adev->lock);
6949 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6950 !out->playback_started && out->pcm != NULL) {
6951 ret = start_output_stream(out);
6952 if (ret == 0) {
6953 out->playback_started = true;
6954 }
6955 }
6956 pthread_mutex_unlock(&adev->lock);
6957 return ret;
6958}
6959
6960/*
6961 * Modify config->period_count based on min_size_frames
6962 */
6963static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
6964{
6965 int periodCountRequested = (min_size_frames + config->period_size - 1)
6966 / config->period_size;
6967 int periodCount = MMAP_PERIOD_COUNT_MIN;
6968
6969 ALOGV("%s original config.period_size = %d config.period_count = %d",
6970 __func__, config->period_size, config->period_count);
6971
6972 while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
6973 periodCount *= 2;
6974 }
6975 config->period_count = periodCount;
6976
6977 ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
6978}
6979
Phil Burkfe17efd2019-03-25 10:23:35 -07006980// Read offset for the positional timestamp from a persistent vendor property.
6981// This is to workaround apparent inaccuracies in the timing information that
6982// is used by the AAudio timing model. The inaccuracies can cause glitches.
6983static int64_t get_mmap_out_time_offset() {
6984 const int32_t kDefaultOffsetMicros = 0;
6985 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08006986 "persist.vendor.audio.out_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burkfe17efd2019-03-25 10:23:35 -07006987 ALOGI("mmap_time_offset_micros = %d for output", mmap_time_offset_micros);
6988 return mmap_time_offset_micros * (int64_t)1000;
6989}
6990
Haynes Mathew George16081042017-05-31 17:16:49 -07006991static int out_create_mmap_buffer(const struct audio_stream_out *stream,
6992 int32_t min_size_frames,
6993 struct audio_mmap_buffer_info *info)
6994{
6995 struct stream_out *out = (struct stream_out *)stream;
6996 struct audio_device *adev = out->dev;
6997 int ret = 0;
Aalique Grahame1f123102017-10-12 10:38:32 -07006998 unsigned int offset1 = 0;
6999 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007000 const char *step = "";
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007001 uint32_t mmap_size;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007002 uint32_t buffer_size;
Haynes Mathew George16081042017-05-31 17:16:49 -07007003
Arun Mirpuri5d170872019-03-26 13:21:31 -07007004 ALOGD("%s", __func__);
Sharad Sanglec6f32552018-05-04 16:15:38 +05307005 lock_output_stream(out);
Haynes Mathew George16081042017-05-31 17:16:49 -07007006 pthread_mutex_lock(&adev->lock);
7007
Sharad Sanglec6f32552018-05-04 16:15:38 +05307008 if (CARD_STATUS_OFFLINE == out->card_status ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05007009 CARD_STATUS_OFFLINE == adev->card_status ||
7010 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307011 ALOGW("out->card_status or adev->card_status offline, try again");
7012 ret = -EIO;
7013 goto exit;
7014 }
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307015 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007016 ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
7017 ret = -EINVAL;
7018 goto exit;
7019 }
7020 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
7021 ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
7022 ret = -ENOSYS;
7023 goto exit;
7024 }
7025 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
7026 if (out->pcm_device_id < 0) {
7027 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7028 __func__, out->pcm_device_id, out->usecase);
7029 ret = -EINVAL;
7030 goto exit;
7031 }
7032
7033 adjust_mmap_period_count(&out->config, min_size_frames);
7034
Arun Mirpuri5d170872019-03-26 13:21:31 -07007035 ALOGD("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07007036 __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
7037 out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
7038 (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307039 if (errno == ENETRESET && !pcm_is_ready(out->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307040 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7041 out->card_status = CARD_STATUS_OFFLINE;
7042 adev->card_status = CARD_STATUS_OFFLINE;
7043 ret = -EIO;
7044 goto exit;
7045 }
7046
Haynes Mathew George16081042017-05-31 17:16:49 -07007047 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
7048 step = "open";
7049 ret = -ENODEV;
7050 goto exit;
7051 }
7052 ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
7053 if (ret < 0) {
7054 step = "begin";
7055 goto exit;
7056 }
juyuchen626833d2019-06-04 16:48:02 +08007057
7058 info->flags = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007059 info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
Arun Mirpuri5d170872019-03-26 13:21:31 -07007060 buffer_size = pcm_frames_to_bytes(out->pcm, info->buffer_size_frames);
Haynes Mathew George16081042017-05-31 17:16:49 -07007061 info->burst_size_frames = out->config.period_size;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007062 ret = platform_get_mmap_data_fd(adev->platform,
7063 out->pcm_device_id, 0 /*playback*/,
7064 &info->shared_memory_fd,
7065 &mmap_size);
7066 if (ret < 0) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07007067 // Fall back to non exclusive mode
7068 info->shared_memory_fd = pcm_get_poll_fd(out->pcm);
7069 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007070 out->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7071 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, out->mmap_shared_memory_fd);
7072
Arun Mirpuri5d170872019-03-26 13:21:31 -07007073 if (mmap_size < buffer_size) {
7074 step = "mmap";
7075 goto exit;
7076 }
juyuchen626833d2019-06-04 16:48:02 +08007077 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007078 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007079 memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007080 info->buffer_size_frames));
Haynes Mathew George16081042017-05-31 17:16:49 -07007081
7082 ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
7083 if (ret < 0) {
7084 step = "commit";
7085 goto exit;
7086 }
7087
Phil Burkfe17efd2019-03-25 10:23:35 -07007088 out->mmap_time_offset_nanos = get_mmap_out_time_offset();
7089
Haynes Mathew George16081042017-05-31 17:16:49 -07007090 out->standby = false;
7091 ret = 0;
7092
Arun Mirpuri5d170872019-03-26 13:21:31 -07007093 ALOGD("%s: got mmap buffer address %p info->buffer_size_frames %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07007094 __func__, info->shared_memory_address, info->buffer_size_frames);
7095
7096exit:
7097 if (ret != 0) {
7098 if (out->pcm == NULL) {
7099 ALOGE("%s: %s - %d", __func__, step, ret);
7100 } else {
7101 ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
7102 pcm_close(out->pcm);
7103 out->pcm = NULL;
7104 }
7105 }
7106 pthread_mutex_unlock(&adev->lock);
Sharad Sanglec6f32552018-05-04 16:15:38 +05307107 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007108 return ret;
7109}
7110
7111static int out_get_mmap_position(const struct audio_stream_out *stream,
7112 struct audio_mmap_position *position)
7113{
7114 struct stream_out *out = (struct stream_out *)stream;
7115 ALOGVV("%s", __func__);
7116 if (position == NULL) {
7117 return -EINVAL;
7118 }
7119 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08007120 ALOGE("%s: called on %s", __func__, use_case_table[out->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07007121 return -ENOSYS;
7122 }
7123 if (out->pcm == NULL) {
7124 return -ENOSYS;
7125 }
7126
7127 struct timespec ts = { 0, 0 };
7128 int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
7129 if (ret < 0) {
7130 ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
7131 return ret;
7132 }
Phil Burkfe17efd2019-03-25 10:23:35 -07007133 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
7134 + out->mmap_time_offset_nanos;
Haynes Mathew George16081042017-05-31 17:16:49 -07007135 return 0;
7136}
7137
7138
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007139/** audio_stream_in implementation **/
7140static uint32_t in_get_sample_rate(const struct audio_stream *stream)
7141{
7142 struct stream_in *in = (struct stream_in *)stream;
7143
7144 return in->config.rate;
7145}
7146
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007147static int in_set_sample_rate(struct audio_stream *stream __unused,
7148 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007149{
7150 return -ENOSYS;
7151}
7152
7153static size_t in_get_buffer_size(const struct audio_stream *stream)
7154{
7155 struct stream_in *in = (struct stream_in *)stream;
7156
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007157 if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
7158 return voice_extn_compress_voip_in_get_buffer_size(in);
Mingming Yine62d7842013-10-25 16:26:03 -07007159 else if(audio_extn_compr_cap_usecase_supported(in->usecase))
7160 return audio_extn_compr_cap_get_buffer_size(in->config.format);
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307161 else if(audio_extn_cin_attached_usecase(in))
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307162 return audio_extn_cin_get_buffer_size(in);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007163
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007164 return in->config.period_size * in->af_period_multiplier *
7165 audio_stream_in_frame_size((const struct audio_stream_in *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007166}
7167
7168static uint32_t in_get_channels(const struct audio_stream *stream)
7169{
7170 struct stream_in *in = (struct stream_in *)stream;
7171
7172 return in->channel_mask;
7173}
7174
7175static audio_format_t in_get_format(const struct audio_stream *stream)
7176{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007177 struct stream_in *in = (struct stream_in *)stream;
7178
7179 return in->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007180}
7181
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007182static int in_set_format(struct audio_stream *stream __unused,
7183 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007184{
7185 return -ENOSYS;
7186}
7187
7188static int in_standby(struct audio_stream *stream)
7189{
7190 struct stream_in *in = (struct stream_in *)stream;
7191 struct audio_device *adev = in->dev;
7192 int status = 0;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307193 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
7194 stream, in->usecase, use_case_table[in->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07007195 bool do_stop = true;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307196
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007197 lock_input_stream(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007198 if (!in->standby && in->is_st_session) {
7199 ALOGD("%s: sound trigger pcm stop lab", __func__);
7200 audio_extn_sound_trigger_stop_lab(in);
George Gao3018ede2019-10-23 13:23:00 -07007201 if (adev->num_va_sessions > 0)
7202 adev->num_va_sessions--;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007203 in->standby = 1;
7204 }
7205
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007206 if (!in->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007207 if (adev->adm_deregister_stream)
7208 adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
7209
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08007210 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007211 in->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08007212 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
kunleizbecba2d2017-09-07 13:37:16 +08007213 do_stop = false;
Zhou Songa8895042016-07-05 17:54:22 +08007214 voice_extn_compress_voip_close_input_stream(stream);
7215 ALOGD("VOIP input entered standby");
Haynes Mathew George16081042017-05-31 17:16:49 -07007216 } else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7217 do_stop = in->capture_started;
7218 in->capture_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07007219 if (in->mmap_shared_memory_fd >= 0) {
7220 ALOGV("%s: closing mmap_shared_memory_fd = %d",
7221 __func__, in->mmap_shared_memory_fd);
7222 close(in->mmap_shared_memory_fd);
7223 in->mmap_shared_memory_fd = -1;
7224 }
Zhou Songa8895042016-07-05 17:54:22 +08007225 } else {
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307226 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +05307227 audio_extn_cin_close_input_stream(in);
kunleizbecba2d2017-09-07 13:37:16 +08007228 }
7229
Arun Mirpuri5d170872019-03-26 13:21:31 -07007230 if (in->pcm) {
7231 ATRACE_BEGIN("pcm_in_close");
7232 pcm_close(in->pcm);
7233 ATRACE_END();
7234 in->pcm = NULL;
7235 }
7236
Carter Hsu2e429db2019-05-14 18:50:52 +08007237 if (do_stop)
Zhou Songa8895042016-07-05 17:54:22 +08007238 status = stop_input_stream(in);
Quinn Malef6050362019-01-30 15:55:40 -08007239
George Gao3018ede2019-10-23 13:23:00 -07007240 if (in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7241 if (adev->num_va_sessions > 0)
7242 adev->num_va_sessions--;
7243 }
Quinn Malef6050362019-01-30 15:55:40 -08007244
Eric Laurent150dbfe2013-02-27 14:31:02 -08007245 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007246 }
7247 pthread_mutex_unlock(&in->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07007248 ALOGV("%s: exit: status(%d)", __func__, status);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007249 return status;
7250}
7251
Aalique Grahame22e49102018-12-18 14:23:57 -08007252static int in_dump(const struct audio_stream *stream,
7253 int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007254{
Aalique Grahame22e49102018-12-18 14:23:57 -08007255 struct stream_in *in = (struct stream_in *)stream;
7256
7257 // We try to get the lock for consistency,
7258 // but it isn't necessary for these variables.
7259 // If we're not in standby, we may be blocked on a read.
7260 const bool locked = (pthread_mutex_trylock(&in->lock) == 0);
7261 dprintf(fd, " Standby: %s\n", in->standby ? "yes" : "no");
7262 dprintf(fd, " Frames read: %lld\n", (long long)in->frames_read);
7263 dprintf(fd, " Frames muted: %lld\n", (long long)in->frames_muted);
Dechen Chai22768452021-07-30 09:29:16 +05307264#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007265 char buffer[256]; // for statistics formatting
7266 if (in->start_latency_ms.n > 0) {
7267 simple_stats_to_string(&in->start_latency_ms, buffer, sizeof(buffer));
7268 dprintf(fd, " Start latency ms: %s\n", buffer);
7269 }
Dechen Chai22768452021-07-30 09:29:16 +05307270#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08007271 if (locked) {
7272 pthread_mutex_unlock(&in->lock);
7273 }
Dechen Chai22768452021-07-30 09:29:16 +05307274#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08007275 // dump error info
7276 (void)error_log_dump(
7277 in->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05307278#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007279 return 0;
7280}
7281
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307282static void in_snd_mon_cb(void * stream, struct str_parms * parms)
7283{
7284 if (!stream || !parms)
7285 return;
7286
7287 struct stream_in *in = (struct stream_in *)stream;
7288 struct audio_device *adev = in->dev;
7289
7290 card_status_t status;
7291 int card;
7292 if (parse_snd_card_status(parms, &card, &status) < 0)
7293 return;
7294
7295 pthread_mutex_lock(&adev->lock);
7296 bool valid_cb = (card == adev->snd_card);
7297 pthread_mutex_unlock(&adev->lock);
7298
7299 if (!valid_cb)
7300 return;
7301
7302 lock_input_stream(in);
7303 if (in->card_status != status)
7304 in->card_status = status;
7305 pthread_mutex_unlock(&in->lock);
7306
7307 ALOGW("in_snd_mon_cb for card %d usecase %s, status %s", card,
7308 use_case_table[in->usecase],
7309 status == CARD_STATUS_OFFLINE ? "offline" : "online");
7310
7311 // a better solution would be to report error back to AF and let
7312 // it put the stream to standby
7313 if (status == CARD_STATUS_OFFLINE)
7314 in_standby(&in->stream.common);
7315
7316 return;
7317}
7318
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007319int route_input_stream(struct stream_in *in,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007320 struct listnode *devices,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007321 audio_source_t source)
7322{
7323 struct audio_device *adev = in->dev;
7324 int ret = 0;
7325
7326 lock_input_stream(in);
7327 pthread_mutex_lock(&adev->lock);
7328
7329 /* no audio source uses val == 0 */
7330 if ((in->source != source) && (source != AUDIO_SOURCE_DEFAULT)) {
7331 in->source = source;
7332 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
7333 (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
7334 (voice_extn_compress_voip_is_format_supported(in->format)) &&
7335 (in->config.rate == 8000 || in->config.rate == 16000 ||
7336 in->config.rate == 32000 || in->config.rate == 48000 ) &&
7337 (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
7338 ret = voice_extn_compress_voip_open_input_stream(in);
7339 if (ret != 0) {
7340 ALOGE("%s: Compress voip input cannot be opened, error:%d",
7341 __func__, ret);
7342 }
7343 }
7344 }
7345
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007346 if (!compare_devices(&in->device_list, devices) && !list_empty(devices) &&
7347 is_audio_in_device_type(devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007348 // Workaround: If routing to an non existing usb device, fail gracefully
7349 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007350 struct str_parms *usb_addr =
7351 str_parms_create_str(get_usb_device_address(devices));
7352 if (is_usb_in_device_type(devices) && usb_addr &&
Weiyin Jiangabedea32020-12-09 12:49:19 +08007353 !audio_extn_usb_connected(NULL)) {
7354 ALOGW("%s: ignoring rerouting to non existing USB", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007355 ret = -ENOSYS;
7356 } else {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007357 /* If recording is in progress, change the tx device to new device */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007358 assign_devices(&in->device_list, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007359 if (!in->standby && !in->is_st_session) {
7360 ALOGV("update input routing change");
7361 // inform adm before actual routing to prevent glitches.
7362 if (adev->adm_on_routing_change) {
7363 adev->adm_on_routing_change(adev->adm_data,
7364 in->capture_handle);
7365 ret = select_devices(adev, in->usecase);
7366 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7367 adev->adm_routing_changed = true;
7368 }
7369 }
7370 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007371 if (usb_addr)
7372 str_parms_destroy(usb_addr);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007373 }
7374 pthread_mutex_unlock(&adev->lock);
7375 pthread_mutex_unlock(&in->lock);
7376
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07007377 ALOGV("%s: exit: status(%d)", __func__, ret);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007378 return ret;
7379}
7380
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007381static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
7382{
7383 struct stream_in *in = (struct stream_in *)stream;
7384 struct audio_device *adev = in->dev;
7385 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007386 char value[32];
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307387 int err = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007388
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307389 ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007390 parms = str_parms_create_str(kvpairs);
7391
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307392 if (!parms)
7393 goto error;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007394 lock_input_stream(in);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007395 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08007396
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307397 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
7398 if (err >= 0) {
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307399 strlcpy(in->profile, value, sizeof(in->profile));
7400 ALOGV("updating stream profile with value '%s'", in->profile);
7401 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
7402 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007403 &in->device_list, in->flags, in->format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307404 in->sample_rate, in->bit_width,
7405 in->profile, &in->app_type_cfg);
7406 }
7407
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007408 pthread_mutex_unlock(&adev->lock);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007409 pthread_mutex_unlock(&in->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007410
7411 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307412error:
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307413 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007414}
7415
7416static char* in_get_parameters(const struct audio_stream *stream,
7417 const char *keys)
7418{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007419 struct stream_in *in = (struct stream_in *)stream;
7420 struct str_parms *query = str_parms_create_str(keys);
7421 char *str;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007422 struct str_parms *reply = str_parms_create();
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007423
7424 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08007425 if (reply) {
7426 str_parms_destroy(reply);
7427 }
7428 if (query) {
7429 str_parms_destroy(query);
7430 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007431 ALOGE("in_get_parameters: failed to create query or reply");
7432 return NULL;
7433 }
7434
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007435 ALOGV("%s: enter: keys - %s %s ", __func__, use_case_table[in->usecase], keys);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007436
7437 voice_extn_in_get_parameters(in, query, reply);
7438
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007439 stream_get_parameter_channels(query, reply,
7440 &in->supported_channel_masks[0]);
7441 stream_get_parameter_formats(query, reply,
7442 &in->supported_formats[0]);
7443 stream_get_parameter_rates(query, reply,
7444 &in->supported_sample_rates[0]);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007445 str = str_parms_to_str(reply);
7446 str_parms_destroy(query);
7447 str_parms_destroy(reply);
7448
7449 ALOGV("%s: exit: returns - %s", __func__, str);
7450 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007451}
7452
Aalique Grahame22e49102018-12-18 14:23:57 -08007453static int in_set_gain(struct audio_stream_in *stream,
7454 float gain)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007455{
Aalique Grahame22e49102018-12-18 14:23:57 -08007456 struct stream_in *in = (struct stream_in *)stream;
7457 char mixer_ctl_name[128];
7458 struct mixer_ctl *ctl;
7459 int ctl_value;
7460
7461 ALOGV("%s: gain %f", __func__, gain);
7462
7463 if (stream == NULL)
7464 return -EINVAL;
7465
7466 /* in_set_gain() only used to silence MMAP capture for now */
7467 if (in->usecase != USECASE_AUDIO_RECORD_MMAP)
7468 return -ENOSYS;
7469
7470 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Capture %d Volume", in->pcm_device_id);
7471
7472 ctl = mixer_get_ctl_by_name(in->dev->mixer, mixer_ctl_name);
7473 if (!ctl) {
7474 ALOGW("%s: Could not get ctl for mixer cmd - %s",
7475 __func__, mixer_ctl_name);
7476 return -ENOSYS;
7477 }
7478
7479 if (gain < RECORD_GAIN_MIN)
7480 gain = RECORD_GAIN_MIN;
7481 else if (gain > RECORD_GAIN_MAX)
7482 gain = RECORD_GAIN_MAX;
7483 ctl_value = (int)(RECORD_VOLUME_CTL_MAX * gain);
7484
7485 mixer_ctl_set_value(ctl, 0, ctl_value);
7486
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007487 return 0;
7488}
7489
7490static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
7491 size_t bytes)
7492{
7493 struct stream_in *in = (struct stream_in *)stream;
Pallavid7c7a272018-01-16 11:22:55 +05307494
7495 if (in == NULL) {
7496 ALOGE("%s: stream_in ptr is NULL", __func__);
7497 return -EINVAL;
7498 }
7499
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007500 struct audio_device *adev = in->dev;
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05307501 int ret = -1;
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307502 size_t bytes_read = 0, frame_size = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007503
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007504 lock_input_stream(in);
Naresh Tanniru4c630392014-05-12 01:05:52 +05307505
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007506 if (in->is_st_session) {
7507 ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
7508 /* Read from sound trigger HAL */
7509 audio_extn_sound_trigger_read(in, buffer, bytes);
Quinn Malef6050362019-01-30 15:55:40 -08007510 if (in->standby) {
George Gao3018ede2019-10-23 13:23:00 -07007511 if (adev->num_va_sessions < UINT_MAX)
7512 adev->num_va_sessions++;
Quinn Malef6050362019-01-30 15:55:40 -08007513 in->standby = 0;
7514 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007515 pthread_mutex_unlock(&in->lock);
7516 return bytes;
7517 }
7518
Haynes Mathew George16081042017-05-31 17:16:49 -07007519 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7520 ret = -ENOSYS;
7521 goto exit;
7522 }
7523
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007524 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY &&
7525 !in->standby && adev->adm_routing_changed) {
7526 ret = -ENOSYS;
7527 goto exit;
7528 }
7529
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007530 if (in->standby) {
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007531 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
7532
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007533 pthread_mutex_lock(&adev->lock);
7534 if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
7535 ret = voice_extn_compress_voip_start_input_stream(in);
7536 else
7537 ret = start_input_stream(in);
George Gao3018ede2019-10-23 13:23:00 -07007538 if (!ret && in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7539 if (adev->num_va_sessions < UINT_MAX)
7540 adev->num_va_sessions++;
7541 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007542 pthread_mutex_unlock(&adev->lock);
7543 if (ret != 0) {
7544 goto exit;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007545 }
7546 in->standby = 0;
Dechen Chai22768452021-07-30 09:29:16 +05307547#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007548 // log startup time in ms.
7549 simple_stats_log(
7550 &in->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05307551#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007552 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007553
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05307554 /* Avoid read if capture_stopped is set */
7555 if (android_atomic_acquire_load(&(in->capture_stopped)) > 0) {
7556 ALOGD("%s: force stopped catpure session, ignoring read request", __func__);
7557 ret = -EINVAL;
7558 goto exit;
7559 }
7560
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007561 // what's the duration requested by the client?
7562 long ns = 0;
7563
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307564 if (in->pcm && in->config.rate)
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007565 ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
7566 in->config.rate;
7567
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007568 ret = request_in_focus(in, ns);
7569 if (ret != 0)
7570 goto exit;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007571 bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007572
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307573 if (audio_extn_cin_attached_usecase(in)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307574 ret = audio_extn_cin_read(in, buffer, bytes, &bytes_read);
7575 } else if (in->pcm) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307576 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007577 ret = audio_extn_ssr_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307578 } else if (audio_extn_compr_cap_usecase_supported(in->usecase)) {
Mingming Yine62d7842013-10-25 16:26:03 -07007579 ret = audio_extn_compr_cap_read(in, buffer, bytes);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007580 } else if (use_mmap) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07007581 ret = pcm_mmap_read(in->pcm, buffer, bytes);
Garmond Leunge2433c32017-09-28 21:51:22 -07007582 } else if (audio_extn_ffv_get_stream() == in) {
7583 ret = audio_extn_ffv_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307584 } else {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007585 ret = pcm_read(in->pcm, buffer, bytes);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307586 /* data from DSP comes in 24_8 format, convert it to 8_24 */
7587 if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
7588 if (audio_extn_utils_convert_format_24_8_to_8_24(buffer, bytes)
7589 != bytes) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307590 ret = -EINVAL;
7591 goto exit;
7592 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307593 } else if (ret < 0) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307594 ret = -errno;
7595 }
7596 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307597 /* bytes read is always set to bytes for non compress usecases */
7598 bytes_read = bytes;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007599 }
7600
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007601 release_in_focus(in);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007602
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007603 /*
Quinn Malef6050362019-01-30 15:55:40 -08007604 * Instead of writing zeroes here, we could trust the hardware to always
7605 * provide zeroes when muted. This is also muted with voice recognition
7606 * usecases so that other clients do not have access to voice recognition
7607 * data.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007608 */
Quinn Malef6050362019-01-30 15:55:40 -08007609 if ((ret == 0 && voice_get_mic_mute(adev) &&
7610 !voice_is_in_call_rec_stream(in) &&
Zhou Song62ea0282020-03-22 19:53:01 +08007611 (in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY &&
7612 in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY2)) ||
Quinn Malef6050362019-01-30 15:55:40 -08007613 (adev->num_va_sessions &&
7614 in->source != AUDIO_SOURCE_VOICE_RECOGNITION &&
7615 property_get_bool("persist.vendor.audio.va_concurrency_mute_enabled",
7616 false)))
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007617 memset(buffer, 0, bytes);
7618
7619exit:
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307620 frame_size = audio_stream_in_frame_size(stream);
7621 if (frame_size > 0)
7622 in->frames_read += bytes_read/frame_size;
7623
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007624 if (-ENETRESET == ret)
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307625 in->card_status = CARD_STATUS_OFFLINE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007626 pthread_mutex_unlock(&in->lock);
7627
7628 if (ret != 0) {
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307629 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307630 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307631 voice_extn_compress_voip_close_input_stream(&in->stream.common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307632 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307633 in->standby = true;
7634 }
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307635 if (!audio_extn_cin_attached_usecase(in)) {
Sharad Sangled17c9122017-03-20 15:58:52 +05307636 bytes_read = bytes;
7637 memset(buffer, 0, bytes);
7638 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007639 in_standby(&in->stream.common);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007640 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7641 adev->adm_routing_changed = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007642 ALOGV("%s: read failed status %d- sleeping for buffer duration", __func__, ret);
Ashish Jainbbce4322016-02-16 13:25:27 +05307643 usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
Naresh Tanniru4c630392014-05-12 01:05:52 +05307644 in_get_sample_rate(&in->stream.common));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007645 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307646 return bytes_read;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007647}
7648
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007649static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007650{
7651 return 0;
7652}
7653
Aalique Grahame22e49102018-12-18 14:23:57 -08007654static int in_get_capture_position(const struct audio_stream_in *stream,
7655 int64_t *frames, int64_t *time)
7656{
7657 if (stream == NULL || frames == NULL || time == NULL) {
7658 return -EINVAL;
7659 }
7660 struct stream_in *in = (struct stream_in *)stream;
7661 int ret = -ENOSYS;
7662
7663 lock_input_stream(in);
7664 // note: ST sessions do not close the alsa pcm driver synchronously
7665 // on standby. Therefore, we may return an error even though the
7666 // pcm stream is still opened.
7667 if (in->standby) {
7668 ALOGE_IF(in->pcm != NULL && !in->is_st_session,
7669 "%s stream in standby but pcm not NULL for non ST session", __func__);
7670 goto exit;
7671 }
7672 if (in->pcm) {
7673 struct timespec timestamp;
7674 unsigned int avail;
7675 if (pcm_get_htimestamp(in->pcm, &avail, &timestamp) == 0) {
7676 *frames = in->frames_read + avail;
Robert Lee58215542019-07-15 20:55:12 +08007677 *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec
George Gao9ba8a142020-07-23 14:30:03 -07007678 - platform_capture_latency(in) * 1000LL;
Kakanaboina Ramanjaneyulu8cedb092021-03-15 15:55:29 +05307679 //Adjustment accounts for A2dp decoder latency for recording usecase
7680 // Note: decoder latency is returned in ms, while platform_capture_latency in ns.
7681 if (is_a2dp_in_device_type(&in->device_list))
7682 *time -= audio_extn_a2dp_get_decoder_latency() * 1000000LL;
Aalique Grahame22e49102018-12-18 14:23:57 -08007683 ret = 0;
7684 }
7685 }
7686exit:
7687 pthread_mutex_unlock(&in->lock);
7688 return ret;
7689}
7690
Carter Hsu2e429db2019-05-14 18:50:52 +08007691static int in_update_effect_list(bool add, effect_handle_t effect,
7692 struct listnode *head)
7693{
7694 struct listnode *node;
7695 struct in_effect_list *elist = NULL;
7696 struct in_effect_list *target = NULL;
7697 int ret = 0;
7698
7699 if (!head)
7700 return ret;
7701
7702 list_for_each(node, head) {
7703 elist = node_to_item(node, struct in_effect_list, list);
7704 if (elist->handle == effect) {
7705 target = elist;
7706 break;
7707 }
7708 }
7709
7710 if (add) {
7711 if (target) {
7712 ALOGD("effect %p already exist", effect);
7713 return ret;
7714 }
7715
7716 target = (struct in_effect_list *)
7717 calloc(1, sizeof(struct in_effect_list));
7718
7719 if (!target) {
7720 ALOGE("%s:fail to allocate memory", __func__);
7721 return -ENOMEM;
7722 }
7723
7724 target->handle = effect;
7725 list_add_tail(head, &target->list);
7726 } else {
7727 if (target) {
7728 list_remove(&target->list);
7729 free(target);
7730 }
7731 }
7732
7733 return ret;
7734}
7735
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007736static int add_remove_audio_effect(const struct audio_stream *stream,
7737 effect_handle_t effect,
7738 bool enable)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007739{
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007740 struct stream_in *in = (struct stream_in *)stream;
7741 int status = 0;
7742 effect_descriptor_t desc;
7743
7744 status = (*effect)->get_descriptor(effect, &desc);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007745 ALOGV("%s: status %d in->standby %d enable:%d", __func__, status, in->standby, enable);
7746
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007747 if (status != 0)
7748 return status;
7749
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007750 lock_input_stream(in);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007751 pthread_mutex_lock(&in->dev->lock);
kunleizd96526c2018-04-09 11:12:32 +08007752 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Carter Hsu2e429db2019-05-14 18:50:52 +08007753 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
7754 adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007755 (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
Carter Hsu2e429db2019-05-14 18:50:52 +08007756
7757 in_update_effect_list(enable, effect, &in->aec_list);
7758 enable = !list_empty(&in->aec_list);
7759 if (enable == in->enable_aec)
7760 goto exit;
7761
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007762 in->enable_aec = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007763 ALOGD("AEC enable %d", enable);
7764
Aalique Grahame22e49102018-12-18 14:23:57 -08007765 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
7766 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
7767 in->dev->enable_voicerx = enable;
7768 struct audio_usecase *usecase;
7769 struct listnode *node;
7770 list_for_each(node, &in->dev->usecase_list) {
7771 usecase = node_to_item(node, struct audio_usecase, list);
7772 if (usecase->type == PCM_PLAYBACK)
7773 select_devices(in->dev, usecase->id);
7774 }
7775 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007776 if (!in->standby) {
7777 if (enable_disable_effect(in->dev, EFFECT_AEC, enable) == ENOSYS)
7778 select_devices(in->dev, in->usecase);
7779 }
7780
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007781 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007782 if (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
7783
7784 in_update_effect_list(enable, effect, &in->ns_list);
7785 enable = !list_empty(&in->ns_list);
7786 if (enable == in->enable_ns)
7787 goto exit;
7788
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007789 in->enable_ns = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007790 ALOGD("NS enable %d", enable);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007791 if (!in->standby) {
kunleizd96526c2018-04-09 11:12:32 +08007792 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Ramu Gottipatifa5be522021-12-28 19:18:21 +05307793 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
kunleizd96526c2018-04-09 11:12:32 +08007794 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007795 if (enable_disable_effect(in->dev, EFFECT_NS, enable) == ENOSYS)
7796 select_devices(in->dev, in->usecase);
7797 } else
7798 select_devices(in->dev, in->usecase);
7799 }
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007800 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007801exit:
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007802 pthread_mutex_unlock(&in->dev->lock);
7803 pthread_mutex_unlock(&in->lock);
7804
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007805 return 0;
7806}
7807
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007808static int in_add_audio_effect(const struct audio_stream *stream,
7809 effect_handle_t effect)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007810{
Eric Laurent994a6932013-07-17 11:51:42 -07007811 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007812 return add_remove_audio_effect(stream, effect, true);
7813}
7814
7815static int in_remove_audio_effect(const struct audio_stream *stream,
7816 effect_handle_t effect)
7817{
Eric Laurent994a6932013-07-17 11:51:42 -07007818 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007819 return add_remove_audio_effect(stream, effect, false);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007820}
7821
Haynes Mathew George16081042017-05-31 17:16:49 -07007822static int in_stop(const struct audio_stream_in* stream)
7823{
7824 struct stream_in *in = (struct stream_in *)stream;
7825 struct audio_device *adev = in->dev;
7826
7827 int ret = -ENOSYS;
7828 ALOGV("%s", __func__);
7829 pthread_mutex_lock(&adev->lock);
7830 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7831 in->capture_started && in->pcm != NULL) {
7832 pcm_stop(in->pcm);
7833 ret = stop_input_stream(in);
7834 in->capture_started = false;
7835 }
7836 pthread_mutex_unlock(&adev->lock);
7837 return ret;
7838}
7839
7840static int in_start(const struct audio_stream_in* stream)
7841{
7842 struct stream_in *in = (struct stream_in *)stream;
7843 struct audio_device *adev = in->dev;
7844 int ret = -ENOSYS;
7845
7846 ALOGV("%s in %p", __func__, in);
7847 pthread_mutex_lock(&adev->lock);
7848 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7849 !in->capture_started && in->pcm != NULL) {
7850 if (!in->capture_started) {
7851 ret = start_input_stream(in);
7852 if (ret == 0) {
7853 in->capture_started = true;
7854 }
7855 }
7856 }
7857 pthread_mutex_unlock(&adev->lock);
7858 return ret;
7859}
7860
Phil Burke0a86d12019-02-16 22:28:11 -08007861// Read offset for the positional timestamp from a persistent vendor property.
7862// This is to workaround apparent inaccuracies in the timing information that
7863// is used by the AAudio timing model. The inaccuracies can cause glitches.
7864static int64_t in_get_mmap_time_offset() {
7865 const int32_t kDefaultOffsetMicros = 0;
7866 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08007867 "persist.vendor.audio.in_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burke0a86d12019-02-16 22:28:11 -08007868 ALOGI("mmap_time_offset_micros = %d for input", mmap_time_offset_micros);
7869 return mmap_time_offset_micros * (int64_t)1000;
7870}
7871
Haynes Mathew George16081042017-05-31 17:16:49 -07007872static int in_create_mmap_buffer(const struct audio_stream_in *stream,
7873 int32_t min_size_frames,
7874 struct audio_mmap_buffer_info *info)
7875{
7876 struct stream_in *in = (struct stream_in *)stream;
7877 struct audio_device *adev = in->dev;
7878 int ret = 0;
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07007879 unsigned int offset1 = 0;
7880 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007881 const char *step = "";
Arun Mirpuri5d170872019-03-26 13:21:31 -07007882 uint32_t mmap_size = 0;
7883 uint32_t buffer_size = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007884
7885 pthread_mutex_lock(&adev->lock);
7886 ALOGV("%s in %p", __func__, in);
7887
Sharad Sanglec6f32552018-05-04 16:15:38 +05307888 if (CARD_STATUS_OFFLINE == in->card_status||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05007889 CARD_STATUS_OFFLINE == adev->card_status ||
7890 POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307891 ALOGW("in->card_status or adev->card_status offline, try again");
7892 ret = -EIO;
7893 goto exit;
7894 }
7895
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307896 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007897 ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
7898 ret = -EINVAL;
7899 goto exit;
7900 }
7901 if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
7902 ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
7903 ALOGV("%s in %p", __func__, in);
7904 ret = -ENOSYS;
7905 goto exit;
7906 }
7907 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
7908 if (in->pcm_device_id < 0) {
7909 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7910 __func__, in->pcm_device_id, in->usecase);
7911 ret = -EINVAL;
7912 goto exit;
7913 }
7914
7915 adjust_mmap_period_count(&in->config, min_size_frames);
7916
7917 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
7918 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
7919 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
7920 (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307921 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307922 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7923 in->card_status = CARD_STATUS_OFFLINE;
7924 adev->card_status = CARD_STATUS_OFFLINE;
7925 ret = -EIO;
7926 goto exit;
7927 }
7928
Haynes Mathew George16081042017-05-31 17:16:49 -07007929 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
7930 step = "open";
7931 ret = -ENODEV;
7932 goto exit;
7933 }
7934
7935 ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
7936 if (ret < 0) {
7937 step = "begin";
7938 goto exit;
7939 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007940
juyuchen626833d2019-06-04 16:48:02 +08007941 info->flags = 0;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007942 info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
7943 buffer_size = pcm_frames_to_bytes(in->pcm, info->buffer_size_frames);
7944 info->burst_size_frames = in->config.period_size;
7945 ret = platform_get_mmap_data_fd(adev->platform,
7946 in->pcm_device_id, 1 /*capture*/,
7947 &info->shared_memory_fd,
7948 &mmap_size);
7949 if (ret < 0) {
7950 // Fall back to non exclusive mode
7951 info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
7952 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007953 in->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7954 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, in->mmap_shared_memory_fd);
7955
Arun Mirpuri5d170872019-03-26 13:21:31 -07007956 if (mmap_size < buffer_size) {
7957 step = "mmap";
7958 goto exit;
7959 }
juyuchen626833d2019-06-04 16:48:02 +08007960 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007961 }
7962
7963 memset(info->shared_memory_address, 0, buffer_size);
Haynes Mathew George16081042017-05-31 17:16:49 -07007964
7965 ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
7966 if (ret < 0) {
7967 step = "commit";
7968 goto exit;
7969 }
7970
Phil Burke0a86d12019-02-16 22:28:11 -08007971 in->mmap_time_offset_nanos = in_get_mmap_time_offset();
7972
Haynes Mathew George16081042017-05-31 17:16:49 -07007973 in->standby = false;
7974 ret = 0;
7975
7976 ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
7977 __func__, info->shared_memory_address, info->buffer_size_frames);
7978
7979exit:
7980 if (ret != 0) {
7981 if (in->pcm == NULL) {
7982 ALOGE("%s: %s - %d", __func__, step, ret);
7983 } else {
7984 ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
7985 pcm_close(in->pcm);
7986 in->pcm = NULL;
7987 }
7988 }
7989 pthread_mutex_unlock(&adev->lock);
7990 return ret;
7991}
7992
7993static int in_get_mmap_position(const struct audio_stream_in *stream,
7994 struct audio_mmap_position *position)
7995{
7996 struct stream_in *in = (struct stream_in *)stream;
7997 ALOGVV("%s", __func__);
7998 if (position == NULL) {
7999 return -EINVAL;
8000 }
Gautam Manam34d1f542021-01-05 20:24:37 +05308001 lock_input_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07008002 if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
Gautam Manam34d1f542021-01-05 20:24:37 +05308003 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008004 return -ENOSYS;
8005 }
8006 if (in->pcm == NULL) {
Gautam Manam34d1f542021-01-05 20:24:37 +05308007 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008008 return -ENOSYS;
8009 }
8010 struct timespec ts = { 0, 0 };
8011 int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
8012 if (ret < 0) {
8013 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
Gautam Manam34d1f542021-01-05 20:24:37 +05308014 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008015 return ret;
8016 }
Phil Burke0a86d12019-02-16 22:28:11 -08008017 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
8018 + in->mmap_time_offset_nanos;
Gautam Manam34d1f542021-01-05 20:24:37 +05308019 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008020 return 0;
8021}
8022
Naresh Tannirudcb47c52018-06-25 16:23:32 +05308023static int in_get_active_microphones(const struct audio_stream_in *stream,
8024 struct audio_microphone_characteristic_t *mic_array,
8025 size_t *mic_count) {
8026 struct stream_in *in = (struct stream_in *)stream;
8027 struct audio_device *adev = in->dev;
8028 ALOGVV("%s", __func__);
8029
8030 lock_input_stream(in);
8031 pthread_mutex_lock(&adev->lock);
8032 int ret = platform_get_active_microphones(adev->platform,
8033 audio_channel_count_from_in_mask(in->channel_mask),
8034 in->usecase, mic_array, mic_count);
8035 pthread_mutex_unlock(&adev->lock);
8036 pthread_mutex_unlock(&in->lock);
8037
8038 return ret;
8039}
8040
8041static int adev_get_microphones(const struct audio_hw_device *dev,
8042 struct audio_microphone_characteristic_t *mic_array,
8043 size_t *mic_count) {
8044 struct audio_device *adev = (struct audio_device *)dev;
8045 ALOGVV("%s", __func__);
8046
8047 pthread_mutex_lock(&adev->lock);
8048 int ret = platform_get_microphones(adev->platform, mic_array, mic_count);
8049 pthread_mutex_unlock(&adev->lock);
8050
8051 return ret;
8052}
juyuchendb308c22019-01-21 11:57:17 -07008053
8054static void in_update_sink_metadata(struct audio_stream_in *stream,
8055 const struct sink_metadata *sink_metadata) {
8056
8057 if (stream == NULL
8058 || sink_metadata == NULL
8059 || sink_metadata->tracks == NULL) {
8060 return;
8061 }
8062
8063 int error = 0;
8064 struct stream_in *in = (struct stream_in *)stream;
8065 struct audio_device *adev = in->dev;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008066 struct listnode devices;
8067
8068 list_init(&devices);
juyuchendb308c22019-01-21 11:57:17 -07008069
8070 if (sink_metadata->track_count != 0)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008071 reassign_device_list(&devices, sink_metadata->tracks->dest_device, "");
juyuchendb308c22019-01-21 11:57:17 -07008072
8073 lock_input_stream(in);
8074 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008075 ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, get_device_types(&devices));
juyuchendb308c22019-01-21 11:57:17 -07008076
Zhou Song503196b2021-07-23 17:31:05 +08008077 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY ||
8078 in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2) &&
8079 !list_empty(&devices) &&
8080 adev->voice_tx_output != NULL) {
juyuchendb308c22019-01-21 11:57:17 -07008081 /* Use the rx device from afe-proxy record to route voice call because
8082 there is no routing if tx device is on primary hal and rx device
8083 is on other hal during voice call. */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008084 assign_devices(&adev->voice_tx_output->device_list, &devices);
juyuchendb308c22019-01-21 11:57:17 -07008085
8086 if (!voice_is_call_state_active(adev)) {
8087 if (adev->mode == AUDIO_MODE_IN_CALL) {
8088 adev->current_call_output = adev->voice_tx_output;
8089 error = voice_start_call(adev);
8090 if (error != 0)
8091 ALOGE("%s: start voice call failed %d", __func__, error);
8092 }
8093 } else {
8094 adev->current_call_output = adev->voice_tx_output;
8095 voice_update_devices_for_all_voice_usecases(adev);
8096 }
8097 }
8098
Zhenlin Lian4f947842022-05-14 15:50:52 +05308099 clear_devices(&devices);
juyuchendb308c22019-01-21 11:57:17 -07008100 pthread_mutex_unlock(&adev->lock);
8101 pthread_mutex_unlock(&in->lock);
8102}
8103
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05308104int adev_open_output_stream(struct audio_hw_device *dev,
Haynes Mathew George16081042017-05-31 17:16:49 -07008105 audio_io_handle_t handle,
8106 audio_devices_t devices,
8107 audio_output_flags_t flags,
8108 struct audio_config *config,
8109 struct audio_stream_out **stream_out,
Derek Chenf6318be2017-06-12 17:16:24 -04008110 const char *address)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008111{
8112 struct audio_device *adev = (struct audio_device *)dev;
8113 struct stream_out *out;
Gangadhar Sb0210342019-02-22 17:39:41 +05308114 int ret = 0, ip_hdlr_stream = 0, ip_hdlr_dev = 0;
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008115 audio_format_t format;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008116 struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
Manish Dewangan21a850a2017-08-14 12:03:55 +05308117 bool is_direct_passthough = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008118 bool is_hdmi = devices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
8119 bool is_usb_dev = audio_is_usb_out_device(devices) &&
8120 (devices != AUDIO_DEVICE_OUT_USB_ACCESSORY);
8121 bool direct_dev = is_hdmi || is_usb_dev;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008122 bool use_db_as_primary =
vivek mehtaae1018c2019-05-09 12:19:57 -07008123 property_get_bool("vendor.audio.feature.deepbuffer_as_primary.enable",
8124 false);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008125 bool force_haptic_path =
8126 property_get_bool("vendor.audio.test_haptic", false);
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008127 bool is_voip_rx = flags & AUDIO_OUTPUT_FLAG_VOIP_RX;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008128#ifdef AUDIO_GKI_ENABLED
8129 __s32 *generic_dec;
8130#endif
Weiyin Jiang906db3c2021-03-02 13:17:04 +08008131 pthread_mutexattr_t latch_attr;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008132
kunleizdff872d2018-08-20 14:40:33 +08008133 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08008134 is_usb_dev = false;
8135 devices = AUDIO_DEVICE_OUT_SPEAKER;
8136 ALOGW("%s: ignore set device to non existing USB card, use output device(%#x)",
8137 __func__, devices);
Mingshu Pangdbd20562019-11-25 18:04:39 +08008138 if (config->format == AUDIO_FORMAT_DEFAULT)
8139 config->format = AUDIO_FORMAT_PCM_16_BIT;
8140 if (config->sample_rate == 0)
8141 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8142 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8143 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
kunleizd6a9e0c2018-07-30 15:38:52 +08008144 }
8145
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008146 *stream_out = NULL;
Naresh Tanniru80659832014-06-04 18:17:56 +05308147
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008148 out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
8149
Mingming Yin3a941d42016-02-17 18:08:05 -08008150 ALOGD("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
Derek Chenf6318be2017-06-12 17:16:24 -04008151 stream_handle(%p) address(%s)", __func__, config->format, config->sample_rate, config->channel_mask,
8152 devices, flags, &out->stream, address);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308153
8154
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008155 if (!out) {
8156 return -ENOMEM;
8157 }
8158
Haynes Mathew George204045b2015-02-25 20:32:03 -08008159 pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07008160 pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08008161 pthread_mutexattr_init(&latch_attr);
8162 pthread_mutexattr_settype(&latch_attr, PTHREAD_MUTEX_RECURSIVE);
8163 pthread_mutex_init(&out->latch_lock, &latch_attr);
8164 pthread_mutexattr_destroy(&latch_attr);
Zhou Song48453a02018-01-10 17:50:59 +08008165 pthread_mutex_init(&out->position_query_lock, (const pthread_mutexattr_t *) NULL);
Haynes Mathew George204045b2015-02-25 20:32:03 -08008166 pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
8167
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008168 if (devices == AUDIO_DEVICE_NONE)
8169 devices = AUDIO_DEVICE_OUT_SPEAKER;
8170
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008171 out->flags = flags;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008172 list_init(&out->device_list);
8173 update_device_list(&out->device_list, devices, address, true /* add devices */);
Haynes Mathew George47cd4cb2013-07-19 11:58:50 -07008174 out->dev = adev;
Aalique Grahame65780b52017-09-27 14:59:56 -07008175 out->hal_op_format = out->hal_ip_format = format = out->format = config->format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008176 out->sample_rate = config->sample_rate;
Sachin Mohan Gadag3d09acd2017-06-19 12:43:44 +05308177 out->channel_mask = config->channel_mask;
Ramjee Singh5857aeb2017-08-03 19:18:50 +05308178 if (out->channel_mask == AUDIO_CHANNEL_NONE)
8179 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
8180 else
8181 out->supported_channel_masks[0] = out->channel_mask;
Eric Laurentc4aef752013-09-12 17:45:53 -07008182 out->handle = handle;
Mingming Yin3ee55c62014-08-04 14:23:35 -07008183 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Alexy Josephaa54c872014-12-03 02:46:47 -08008184 out->non_blocking = 0;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308185 out->convert_buffer = NULL;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308186 out->started = 0;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008187 out->a2dp_muted = false;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008188 out->hal_output_suspend_supported = 0;
8189 out->dynamic_pm_qos_config_supported = 0;
Surendar Karkaf51b5842018-04-26 11:28:38 +05308190 out->set_dual_mono = false;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05308191 out->prev_card_status_offline = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05308192 out->pspd_coeff_sent = false;
Phil Burkd898ba62019-06-20 12:49:01 -07008193 out->mmap_shared_memory_fd = -1; // not open
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008194
Nikhil Laturkar26b690b2017-07-25 11:06:14 +05308195 if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
Satish Babu Patakokila37e7c482018-02-02 11:50:06 +05308196 (property_get_bool("vendor.audio.matrix.limiter.enable", false)))
Ben Romberger6c4d3812017-06-13 17:46:45 -07008197 platform_set_device_params(out, DEVICE_PARAM_LIMITER_ID, 1);
8198
Aalique Grahame22e49102018-12-18 14:23:57 -08008199 if (direct_dev &&
8200 (audio_is_linear_pcm(out->format) ||
8201 config->format == AUDIO_FORMAT_DEFAULT) &&
8202 out->flags == AUDIO_OUTPUT_FLAG_NONE) {
8203 audio_format_t req_format = config->format;
8204 audio_channel_mask_t req_channel_mask = config->channel_mask;
8205 uint32_t req_sample_rate = config->sample_rate;
8206
8207 pthread_mutex_lock(&adev->lock);
8208 if (is_hdmi) {
8209 ALOGV("AUDIO_DEVICE_OUT_AUX_DIGITAL and DIRECT|OFFLOAD, check hdmi caps");
8210 ret = read_hdmi_sink_caps(out);
8211 if (config->sample_rate == 0)
8212 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8213 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8214 config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
8215 if (config->format == AUDIO_FORMAT_DEFAULT)
8216 config->format = AUDIO_FORMAT_PCM_16_BIT;
8217 } else if (is_usb_dev) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008218 ret = read_usb_sup_params_and_compare(true /*is_playback*/,
8219 &config->format,
8220 &out->supported_formats[0],
8221 MAX_SUPPORTED_FORMATS,
8222 &config->channel_mask,
8223 &out->supported_channel_masks[0],
8224 MAX_SUPPORTED_CHANNEL_MASKS,
8225 &config->sample_rate,
8226 &out->supported_sample_rates[0],
8227 MAX_SUPPORTED_SAMPLE_RATES);
8228 ALOGV("plugged dev USB ret %d", ret);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008229 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008230
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008231 pthread_mutex_unlock(&adev->lock);
8232 if (ret != 0) {
Mingming Yin3a941d42016-02-17 18:08:05 -08008233 if (ret == -ENOSYS) {
8234 /* ignore and go with default */
8235 ret = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08008236 }
8237 // For MMAP NO IRQ, allow conversions in ADSP
8238 else if (is_hdmi || (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0)
8239 goto error_open;
8240 else {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008241 ALOGE("error reading direct dev sink caps");
Mingming Yin3a941d42016-02-17 18:08:05 -08008242 goto error_open;
8243 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008244
8245 if (req_sample_rate != 0 && config->sample_rate != req_sample_rate)
8246 config->sample_rate = req_sample_rate;
8247 if (req_channel_mask != AUDIO_CHANNEL_NONE && config->channel_mask != req_channel_mask)
8248 config->channel_mask = req_channel_mask;
8249 if (req_format != AUDIO_FORMAT_DEFAULT && config->format != req_format)
8250 config->format = req_format;
Mingming Yin3a941d42016-02-17 18:08:05 -08008251 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008252
8253 out->sample_rate = config->sample_rate;
8254 out->channel_mask = config->channel_mask;
8255 out->format = config->format;
8256 if (is_hdmi) {
8257 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8258 out->config = pcm_config_hdmi_multi;
8259 } else if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8260 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8261 out->config = pcm_config_mmap_playback;
8262 out->stream.start = out_start;
8263 out->stream.stop = out_stop;
8264 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8265 out->stream.get_mmap_position = out_get_mmap_position;
8266 } else {
8267 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8268 out->config = pcm_config_hifi;
8269 }
8270
8271 out->config.rate = out->sample_rate;
8272 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8273 if (is_hdmi) {
8274 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8275 audio_bytes_per_sample(out->format));
8276 }
8277 out->config.format = pcm_format_from_audio_format(out->format);
Mingming Yin3a941d42016-02-17 18:08:05 -08008278 }
8279
Derek Chenf6318be2017-06-12 17:16:24 -04008280 /* validate bus device address */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008281 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008282 /* extract car audio stream index */
8283 out->car_audio_stream =
8284 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
8285 if (out->car_audio_stream < 0) {
8286 ALOGE("%s: invalid car audio stream %x",
8287 __func__, out->car_audio_stream);
8288 ret = -EINVAL;
8289 goto error_open;
8290 }
Derek Chen5f67a942020-02-24 23:08:13 -08008291 ALOGV("%s: car_audio_stream %x", __func__, out->car_audio_stream);
Derek Chenf6318be2017-06-12 17:16:24 -04008292 }
8293
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008294 /* Check for VOIP usecase */
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008295 if (is_voip_rx) {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008296 if (!voice_extn_is_compress_voip_supported()) {
8297 if (out->sample_rate == 8000 || out->sample_rate == 16000 ||
8298 out->sample_rate == 32000 || out->sample_rate == 48000) {
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07008299 out->channel_mask = audio_extn_utils_is_vendor_enhanced_fwk() ?
Lakshman Chaluvarajue7fc9482020-05-30 14:29:29 +05308300 config->channel_mask : AUDIO_CHANNEL_OUT_STEREO;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008301 out->usecase = USECASE_AUDIO_PLAYBACK_VOIP;
8302 out->format = AUDIO_FORMAT_PCM_16_BIT;
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07008303 out->volume_l = INVALID_OUT_VOLUME;
8304 out->volume_r = INVALID_OUT_VOLUME;
Vikram Panduranga93f080e2017-06-07 18:16:14 -07008305
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008306 out->config = default_pcm_config_voip_copp;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008307 out->config.rate = out->sample_rate;
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008308 uint32_t channel_count =
8309 audio_channel_count_from_out_mask(out->channel_mask);
Ramjee Singh968858a2020-08-06 16:30:48 +05308310 out->config.channels = channel_count;
8311
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008312 uint32_t buffer_size = get_stream_buffer_size(DEFAULT_VOIP_BUF_DURATION_MS,
8313 out->sample_rate, out->format,
8314 channel_count, false);
8315 uint32_t frame_size = audio_bytes_per_sample(out->format) * channel_count;
8316 if (frame_size != 0)
8317 out->config.period_size = buffer_size / frame_size;
8318 else
8319 ALOGW("%s: frame size is 0 for format %#x", __func__, out->format);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008320 }
8321 } else {
8322 if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
8323 voice_extn_compress_voip_is_active(out->dev)) &&
8324 (voice_extn_compress_voip_is_config_supported(config))) {
8325 ret = voice_extn_compress_voip_open_output_stream(out);
8326 if (ret != 0) {
8327 ALOGE("%s: Compress voip output cannot be opened, error:%d",
8328 __func__, ret);
8329 goto error_open;
8330 }
Sujin Panicker19027262019-09-16 18:28:06 +05308331 } else {
8332 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8333 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008334 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008335 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008336 } else if (audio_is_linear_pcm(out->format) &&
8337 out->flags == AUDIO_OUTPUT_FLAG_NONE && is_usb_dev) {
8338 out->channel_mask = config->channel_mask;
8339 out->sample_rate = config->sample_rate;
8340 out->format = config->format;
8341 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8342 // does this change?
8343 out->config = is_hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
8344 out->config.rate = config->sample_rate;
8345 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8346 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8347 audio_bytes_per_sample(config->format));
8348 out->config.format = pcm_format_from_audio_format(out->format);
vivek mehta0ea887a2015-08-26 14:01:20 -07008349 } else if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308350 (out->flags == AUDIO_OUTPUT_FLAG_DIRECT)) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308351 pthread_mutex_lock(&adev->lock);
8352 bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
8353 pthread_mutex_unlock(&adev->lock);
8354
8355 // reject offload during card offline to allow
8356 // fallback to s/w paths
8357 if (offline) {
8358 ret = -ENODEV;
8359 goto error_open;
8360 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008361
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008362 if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
8363 config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
8364 ALOGE("%s: Unsupported Offload information", __func__);
8365 ret = -EINVAL;
8366 goto error_open;
8367 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008368
Atul Khare3fa6e542017-08-09 00:56:17 +05308369 if (config->offload_info.format == 0)
8370 config->offload_info.format = config->format;
8371 if (config->offload_info.sample_rate == 0)
8372 config->offload_info.sample_rate = config->sample_rate;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008373
Mingming Yin90310102013-11-13 16:57:00 -08008374 if (!is_supported_format(config->offload_info.format) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308375 !audio_extn_passthru_is_supported_format(config->offload_info.format)) {
vivek mehta0ea887a2015-08-26 14:01:20 -07008376 ALOGE("%s: Unsupported audio format %x " , __func__, config->offload_info.format);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008377 ret = -EINVAL;
8378 goto error_open;
8379 }
8380
Ben Romberger0f8c87b2017-05-24 17:41:11 -07008381 /* TrueHD only supported for 48k multiples (48k, 96k, 192k) */
8382 if ((config->offload_info.format == AUDIO_FORMAT_DOLBY_TRUEHD) &&
8383 (audio_extn_passthru_is_passthrough_stream(out)) &&
8384 !((config->sample_rate == 48000) ||
8385 (config->sample_rate == 96000) ||
8386 (config->sample_rate == 192000))) {
8387 ALOGE("%s: Unsupported sample rate %d for audio format %x",
8388 __func__, config->sample_rate, config->offload_info.format);
8389 ret = -EINVAL;
8390 goto error_open;
8391 }
8392
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008393 out->compr_config.codec = (struct snd_codec *)
8394 calloc(1, sizeof(struct snd_codec));
8395
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07008396 if (!out->compr_config.codec) {
8397 ret = -ENOMEM;
8398 goto error_open;
8399 }
8400
Dhananjay Kumarac341582017-02-23 23:42:25 +05308401 out->stream.pause = out_pause;
8402 out->stream.resume = out_resume;
8403 out->stream.flush = out_flush;
Ashish Jain4847e9d2017-08-17 19:16:57 +05308404 out->stream.set_callback = out_set_callback;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308405 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Mingming Yin21d60472015-09-30 13:56:25 -07008406 out->stream.drain = out_drain;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308407 out->usecase = get_offload_usecase(adev, true /* is_compress */);
vivek mehta446c3962015-09-14 10:57:35 -07008408 ALOGV("Compress Offload usecase .. usecase selected %d", out->usecase);
Dhananjay Kumarac341582017-02-23 23:42:25 +05308409 } else {
8410 out->usecase = get_offload_usecase(adev, false /* is_compress */);
8411 ALOGV("non-offload DIRECT_usecase ... usecase selected %d ", out->usecase);
vivek mehta0ea887a2015-08-26 14:01:20 -07008412 }
vivek mehta446c3962015-09-14 10:57:35 -07008413
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308414 if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8415 ALOGD("%s: Setting latency mode to true", __func__);
Meng Wang4c32fb42020-01-16 17:57:11 +08008416#ifdef AUDIO_GKI_ENABLED
8417 /* out->compr_config.codec->reserved[1] is for flags */
8418 out->compr_config.codec->reserved[1] |= audio_extn_utils_get_perf_mode_flag();
8419#else
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308420 out->compr_config.codec->flags |= audio_extn_utils_get_perf_mode_flag();
Meng Wang4c32fb42020-01-16 17:57:11 +08008421#endif
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308422 }
8423
vivek mehta446c3962015-09-14 10:57:35 -07008424 if (out->usecase == USECASE_INVALID) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008425 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Mingming Yin3a941d42016-02-17 18:08:05 -08008426 config->format == 0 && config->sample_rate == 0 &&
8427 config->channel_mask == 0) {
Mingming Yin21854652016-04-13 11:54:02 -07008428 ALOGI("%s dummy open to query sink capability",__func__);
Mingming Yin3a941d42016-02-17 18:08:05 -08008429 out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
8430 } else {
8431 ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__);
8432 ret = -EEXIST;
8433 goto error_open;
8434 }
vivek mehta446c3962015-09-14 10:57:35 -07008435 }
8436
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008437 if (config->offload_info.channel_mask)
8438 out->channel_mask = config->offload_info.channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008439 else if (config->channel_mask) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008440 out->channel_mask = config->channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008441 config->offload_info.channel_mask = config->channel_mask;
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008442 } else {
Dhananjay Kumarac341582017-02-23 23:42:25 +05308443 ALOGE("out->channel_mask not set for OFFLOAD/DIRECT usecase");
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008444 ret = -EINVAL;
8445 goto error_open;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008446 }
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008447
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008448 format = out->format = config->offload_info.format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008449 out->sample_rate = config->offload_info.sample_rate;
8450
Mingming Yin3ee55c62014-08-04 14:23:35 -07008451 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008452
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308453 out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05308454 if (audio_extn_utils_is_dolby_format(config->offload_info.format)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308455 audio_extn_dolby_send_ddp_endp_params(adev);
8456 audio_extn_dolby_set_dmid(adev);
8457 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008458
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008459 out->compr_config.codec->sample_rate =
Ravi Kumar Alamandab91bff32014-11-14 12:05:54 -08008460 config->offload_info.sample_rate;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008461 out->compr_config.codec->bit_rate =
8462 config->offload_info.bit_rate;
8463 out->compr_config.codec->ch_in =
Dhanalakshmi Siddania15c6792016-08-10 15:33:53 +05308464 audio_channel_count_from_out_mask(out->channel_mask);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008465 out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
Satish Babu Patakokilaa395a9e2016-11-01 12:18:49 +05308466 /* Update bit width only for non passthrough usecases.
8467 * For passthrough usecases, the output will always be opened @16 bit
8468 */
8469 if (!audio_extn_passthru_is_passthrough_stream(out))
8470 out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308471
8472 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
Meng Wang4c32fb42020-01-16 17:57:11 +08008473#ifdef AUDIO_GKI_ENABLED
8474 /* out->compr_config.codec->reserved[1] is for flags */
8475 out->compr_config.codec->reserved[1] |= COMPRESSED_TIMESTAMP_FLAG;
8476 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->reserved[1]);
8477#else
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308478 out->compr_config.codec->flags |= COMPRESSED_TIMESTAMP_FLAG;
8479 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->flags);
Meng Wang4c32fb42020-01-16 17:57:11 +08008480#endif
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308481
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008482 /*TODO: Do we need to change it for passthrough */
8483 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008484
Manish Dewangana6fc5442015-08-24 20:30:31 +05308485 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC)
8486 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308487 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
Manish Dewangana6fc5442015-08-24 20:30:31 +05308488 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308489 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_LATM)
8490 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4LATM;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308491
8492 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) ==
8493 AUDIO_FORMAT_PCM) {
8494
8495 /*Based on platform support, configure appropriate alsa format for corresponding
8496 *hal input format.
8497 */
8498 out->compr_config.codec->format = hal_format_to_alsa(
8499 config->offload_info.format);
8500
Ashish Jain83a6cc22016-06-28 14:34:17 +05308501 out->hal_op_format = alsa_format_to_hal(
Ashish Jainf1eaa582016-05-23 20:54:24 +05308502 out->compr_config.codec->format);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308503 out->hal_ip_format = out->format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308504
Dhananjay Kumarac341582017-02-23 23:42:25 +05308505 /*for direct non-compress playback populate bit_width based on selected alsa format as
Ashish Jainf1eaa582016-05-23 20:54:24 +05308506 *hal input format and alsa format might differ based on platform support.
8507 */
8508 out->bit_width = audio_bytes_per_sample(
Ashish Jain83a6cc22016-06-28 14:34:17 +05308509 out->hal_op_format) << 3;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308510
8511 out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
8512
Deeraj Soman93155a62019-09-30 19:00:37 +05308513 if (property_get_bool("vendor.audio.offload.buffer.duration.enabled", false)) {
8514 if ((config->offload_info.duration_us >= MIN_OFFLOAD_BUFFER_DURATION_MS * 1000) &&
8515 (config->offload_info.duration_us <= MAX_OFFLOAD_BUFFER_DURATION_MS * 1000))
8516 out->info.duration_us = (int64_t)config->offload_info.duration_us;
8517 }
Deeraj Soman65358ab2019-02-07 15:40:49 +05308518
Ashish Jainf1eaa582016-05-23 20:54:24 +05308519 /* Check if alsa session is configured with the same format as HAL input format,
8520 * if not then derive correct fragment size needed to accomodate the
8521 * conversion of HAL input format to alsa format.
8522 */
8523 audio_extn_utils_update_direct_pcm_fragment_size(out);
8524
8525 /*if hal input and output fragment size is different this indicates HAL input format is
8526 *not same as the alsa format
8527 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308528 if (out->hal_fragment_size != out->compr_config.fragment_size) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05308529 /*Allocate a buffer to convert input data to the alsa configured format.
8530 *size of convert buffer is equal to the size required to hold one fragment size
8531 *worth of pcm data, this is because flinger does not write more than fragment_size
8532 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308533 out->convert_buffer = calloc(1,out->compr_config.fragment_size);
8534 if (out->convert_buffer == NULL){
Ashish Jainf1eaa582016-05-23 20:54:24 +05308535 ALOGE("Allocation failed for convert buffer for size %d", out->compr_config.fragment_size);
8536 ret = -ENOMEM;
8537 goto error_open;
8538 }
8539 }
8540 } else if (audio_extn_passthru_is_passthrough_stream(out)) {
8541 out->compr_config.fragment_size =
8542 audio_extn_passthru_get_buffer_size(&config->offload_info);
8543 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8544 } else {
8545 out->compr_config.fragment_size =
8546 platform_get_compress_offload_buffer_size(&config->offload_info);
8547 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8548 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008549
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308550 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8551 out->compr_config.fragment_size += sizeof(struct snd_codec_metadata);
8552 }
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008553 if (config->offload_info.format == AUDIO_FORMAT_FLAC) {
8554#ifdef AUDIO_GKI_ENABLED
8555 generic_dec =
8556 &(out->compr_config.codec->options.generic.reserved[1]);
8557 ((struct snd_generic_dec_flac *)generic_dec)->sample_size =
8558 AUDIO_OUTPUT_BIT_WIDTH;
8559#else
Satya Krishna Pindiproli5d82d012015-08-12 18:21:25 +05308560 out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008561#endif
8562 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008563
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05308564 if (config->offload_info.format == AUDIO_FORMAT_APTX) {
8565 audio_extn_send_aptx_dec_bt_addr_to_dsp(out);
8566 }
8567
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008568 if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
8569 out->non_blocking = 1;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008570
Manish Dewangan69426c82017-01-30 17:35:36 +05308571 if ((flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) &&
8572 (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
8573 out->render_mode = RENDER_MODE_AUDIO_STC_MASTER;
8574 } else if(flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8575 out->render_mode = RENDER_MODE_AUDIO_MASTER;
8576 } else {
8577 out->render_mode = RENDER_MODE_AUDIO_NO_TIMESTAMP;
8578 }
Alexy Josephaa54c872014-12-03 02:46:47 -08008579
Naresh Tanniru29bce4e2017-04-27 17:54:30 +05308580 memset(&out->channel_map_param, 0,
8581 sizeof(struct audio_out_channel_map_param));
8582
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008583 out->send_new_metadata = 1;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05308584 out->send_next_track_params = false;
8585 out->is_compr_metadata_avail = false;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008586 out->offload_state = OFFLOAD_STATE_IDLE;
8587 out->playback_started = 0;
Zhou Song48453a02018-01-10 17:50:59 +08008588 out->writeAt.tv_sec = 0;
8589 out->writeAt.tv_nsec = 0;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008590
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008591 audio_extn_dts_create_state_notifier_node(out->usecase);
8592
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008593 ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
8594 __func__, config->offload_info.version,
8595 config->offload_info.bit_rate);
Ashish Jain5106d362016-05-11 19:23:33 +05308596
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308597 /* Check if DSD audio format is supported in codec
8598 * and there is no active native DSD use case
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308599 */
8600
8601 if ((config->format == AUDIO_FORMAT_DSD) &&
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308602 (!platform_check_codec_dsd_support(adev->platform) ||
8603 audio_is_dsd_native_stream_active(adev))) {
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308604 ret = -EINVAL;
8605 goto error_open;
8606 }
8607
Ashish Jain5106d362016-05-11 19:23:33 +05308608 /* Disable gapless if any of the following is true
8609 * passthrough playback
8610 * AV playback
Dhananjay Kumarac341582017-02-23 23:42:25 +05308611 * non compressed Direct playback
Ashish Jain5106d362016-05-11 19:23:33 +05308612 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308613 if (audio_extn_passthru_is_passthrough_stream(out) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308614 (config->format == AUDIO_FORMAT_DSD) ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07008615 (config->format == AUDIO_FORMAT_IEC61937) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308616 config->offload_info.has_video ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308617 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Ashish Jain5106d362016-05-11 19:23:33 +05308618 check_and_set_gapless_mode(adev, false);
8619 } else
8620 check_and_set_gapless_mode(adev, true);
Mingming Yin21854652016-04-13 11:54:02 -07008621
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308622 if (audio_extn_passthru_is_passthrough_stream(out)) {
Mingming Yin21854652016-04-13 11:54:02 -07008623 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
8624 }
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308625 if (config->format == AUDIO_FORMAT_DSD) {
8626 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
Meng Wang4c32fb42020-01-16 17:57:11 +08008627#ifdef AUDIO_GKI_ENABLED
8628 /* out->compr_config.codec->reserved[0] is for compr_passthr */
8629 out->compr_config.codec->reserved[0] = PASSTHROUGH_DSD;
8630#else
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308631 out->compr_config.codec->compr_passthr = PASSTHROUGH_DSD;
Meng Wang4c32fb42020-01-16 17:57:11 +08008632#endif
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308633 }
Aalique Grahame0359a1f2016-09-08 16:54:22 -07008634
8635 create_offload_callback_thread(out);
8636
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008637 } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008638 switch (config->sample_rate) {
8639 case 0:
8640 out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8641 break;
8642 case 8000:
8643 case 16000:
8644 case 48000:
8645 out->sample_rate = config->sample_rate;
8646 break;
8647 default:
8648 ALOGE("%s: Unsupported sampling rate %d for Incall Music", __func__,
8649 config->sample_rate);
8650 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8651 ret = -EINVAL;
8652 goto error_open;
8653 }
8654 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8655 switch (config->channel_mask) {
8656 case AUDIO_CHANNEL_NONE:
8657 case AUDIO_CHANNEL_OUT_STEREO:
8658 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8659 break;
8660 default:
8661 ALOGE("%s: Unsupported channel mask %#x for Incall Music", __func__,
8662 config->channel_mask);
8663 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8664 ret = -EINVAL;
8665 goto error_open;
8666 }
8667 switch (config->format) {
8668 case AUDIO_FORMAT_DEFAULT:
8669 case AUDIO_FORMAT_PCM_16_BIT:
8670 out->format = AUDIO_FORMAT_PCM_16_BIT;
8671 break;
8672 default:
8673 ALOGE("%s: Unsupported format %#x for Incall Music", __func__,
8674 config->format);
8675 config->format = AUDIO_FORMAT_PCM_16_BIT;
8676 ret = -EINVAL;
8677 goto error_open;
8678 }
8679
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05308680 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008681 if (ret != 0) {
8682 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008683 __func__, ret);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008684 goto error_open;
8685 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008686 } else if (is_single_device_type_equal(&out->device_list,
8687 AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08008688 switch (config->sample_rate) {
8689 case 0:
8690 out->sample_rate = AFE_PROXY_SAMPLING_RATE;
8691 break;
8692 case 8000:
8693 case 16000:
8694 case 48000:
8695 out->sample_rate = config->sample_rate;
8696 break;
8697 default:
8698 ALOGE("%s: Unsupported sampling rate %d for Telephony TX", __func__,
8699 config->sample_rate);
8700 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
8701 ret = -EINVAL;
8702 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008703 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008704 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8705 switch (config->channel_mask) {
8706 case AUDIO_CHANNEL_NONE:
8707 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8708 break;
8709 case AUDIO_CHANNEL_OUT_STEREO:
8710 out->channel_mask = config->channel_mask;
8711 break;
8712 default:
8713 ALOGE("%s: Unsupported channel mask %#x for Telephony TX", __func__,
8714 config->channel_mask);
8715 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8716 ret = -EINVAL;
8717 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008718 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008719 switch (config->format) {
8720 case AUDIO_FORMAT_DEFAULT:
8721 out->format = AUDIO_FORMAT_PCM_16_BIT;
8722 break;
8723 case AUDIO_FORMAT_PCM_16_BIT:
8724 out->format = config->format;
8725 break;
8726 default:
8727 ALOGE("%s: Unsupported format %#x for Telephony TX", __func__,
8728 config->format);
8729 config->format = AUDIO_FORMAT_PCM_16_BIT;
8730 ret = -EINVAL;
8731 break;
8732 }
8733 if (ret != 0)
8734 goto error_open;
8735
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008736 out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
8737 out->config = pcm_config_afe_proxy_playback;
Aalique Grahame22e49102018-12-18 14:23:57 -08008738 out->config.rate = out->sample_rate;
8739 out->config.channels =
8740 audio_channel_count_from_out_mask(out->channel_mask);
8741 out->config.format = pcm_format_from_audio_format(out->format);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008742 adev->voice_tx_output = out;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008743 } else {
Ashish Jain058165c2016-09-28 23:18:48 +05308744 unsigned int channels = 0;
8745 /*Update config params to default if not set by the caller*/
8746 if (config->sample_rate == 0)
8747 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8748 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8749 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8750 if (config->format == AUDIO_FORMAT_DEFAULT)
8751 config->format = AUDIO_FORMAT_PCM_16_BIT;
8752
8753 channels = audio_channel_count_from_out_mask(out->channel_mask);
8754
Varun Balaraje49253e2017-07-06 19:48:56 +05308755 if (out->flags & AUDIO_OUTPUT_FLAG_INTERACTIVE) {
8756 out->usecase = get_interactive_usecase(adev);
8757 out->config = pcm_config_low_latency;
8758 } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
Ashish Jain83a6cc22016-06-28 14:34:17 +05308759 out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07008760 out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
8761 out->flags);
8762 out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
Haynes Mathew George16081042017-05-31 17:16:49 -07008763 } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8764 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8765 out->config = pcm_config_mmap_playback;
8766 out->stream.start = out_start;
8767 out->stream.stop = out_stop;
8768 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8769 out->stream.get_mmap_position = out_get_mmap_position;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308770 } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8771 out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008772 out->hal_output_suspend_supported =
8773 property_get_bool("vendor.audio.hal.output.suspend.supported", false);
8774 out->dynamic_pm_qos_config_supported =
8775 property_get_bool("vendor.audio.hal.dynamic.qos.config.supported", false);
8776 if (!out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08008777 ALOGI("%s: dynamic qos voting not enabled for platform", __func__);
8778 } else {
8779 ALOGI("%s: dynamic qos voting enabled for platform", __func__);
8780 //the mixer path will be a string similar to "low-latency-playback resume"
8781 strlcpy(out->pm_qos_mixer_path, use_case_table[out->usecase], MAX_MIXER_PATH_LEN);
8782 strlcat(out->pm_qos_mixer_path,
8783 " resume", MAX_MIXER_PATH_LEN);
8784 ALOGI("%s: created %s pm_qos_mixer_path" , __func__,
8785 out->pm_qos_mixer_path);
8786 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308787 out->config = pcm_config_low_latency;
8788 } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
8789 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
8790 out->config = pcm_config_deep_buffer;
Ashish Jain058165c2016-09-28 23:18:48 +05308791 out->config.period_size = get_output_period_size(config->sample_rate, out->format,
8792 channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
8793 if (out->config.period_size <= 0) {
8794 ALOGE("Invalid configuration period size is not valid");
8795 ret = -EINVAL;
8796 goto error_open;
8797 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008798 } else if (flags & AUDIO_OUTPUT_FLAG_TTS) {
8799 out->usecase = USECASE_AUDIO_PLAYBACK_TTS;
8800 out->config = pcm_config_deep_buffer;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008801 } else if (config->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL) {
8802 out->usecase = USECASE_AUDIO_PLAYBACK_WITH_HAPTICS;
8803 out->config = pcm_config_haptics_audio;
8804 if (force_haptic_path)
8805 adev->haptics_config = pcm_config_haptics_audio;
8806 else
8807 adev->haptics_config = pcm_config_haptics;
8808
Meng Wangd08ce322020-04-02 08:59:20 +08008809 channels =
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008810 audio_channel_count_from_out_mask(out->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL);
8811
8812 if (force_haptic_path) {
8813 out->config.channels = 1;
8814 adev->haptics_config.channels = 1;
8815 } else
8816 adev->haptics_config.channels = audio_channel_count_from_out_mask(out->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008817 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008818 ret = audio_extn_auto_hal_open_output_stream(out);
8819 if (ret) {
8820 ALOGE("%s: Failed to open output stream for bus device", __func__);
8821 ret = -EINVAL;
8822 goto error_open;
8823 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308824 } else {
8825 /* primary path is the default path selected if no other outputs are available/suitable */
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008826 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8827 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308828 }
8829 out->hal_ip_format = format = out->format;
8830 out->config.format = hal_format_to_pcm(out->hal_ip_format);
8831 out->hal_op_format = pcm_format_to_hal(out->config.format);
8832 out->bit_width = format_to_bitwidth_table[out->hal_op_format] << 3;
8833 out->config.rate = config->sample_rate;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008834 out->sample_rate = out->config.rate;
Ashish Jain058165c2016-09-28 23:18:48 +05308835 out->config.channels = channels;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308836 if (out->hal_ip_format != out->hal_op_format) {
8837 uint32_t buffer_size = out->config.period_size *
8838 format_to_bitwidth_table[out->hal_op_format] *
8839 out->config.channels;
8840 out->convert_buffer = calloc(1, buffer_size);
8841 if (out->convert_buffer == NULL){
8842 ALOGE("Allocation failed for convert buffer for size %d",
8843 out->compr_config.fragment_size);
8844 ret = -ENOMEM;
8845 goto error_open;
8846 }
8847 ALOGD("Convert buffer allocated of size %d", buffer_size);
8848 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008849 }
8850
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008851 ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags: %x usecase %d",
8852 __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags, out->usecase);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308853
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008854 /* TODO remove this hardcoding and check why width is zero*/
8855 if (out->bit_width == 0)
8856 out->bit_width = 16;
Dhananjay Kumard6d32152016-10-13 16:11:03 +05308857 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008858 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008859 &out->device_list, out->flags,
8860 out->hal_op_format, out->sample_rate,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05308861 out->bit_width, out->channel_mask, out->profile,
Manish Dewangan837dc462015-05-27 10:17:41 +05308862 &out->app_type_cfg);
Aalique Grahame6e763712019-01-31 16:18:17 -08008863 if ((out->usecase == (audio_usecase_t)(GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary))) ||
Haynes Mathew Georgebf143712013-12-03 13:02:53 -08008864 (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
8865 /* Ensure the default output is not selected twice */
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008866 if(adev->primary_output == NULL)
8867 adev->primary_output = out;
8868 else {
8869 ALOGE("%s: Primary output is already opened", __func__);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008870 ret = -EEXIST;
8871 goto error_open;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008872 }
8873 }
8874
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008875 /* Check if this usecase is already existing */
8876 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella7ce05352014-04-17 20:00:41 -07008877 if ((get_usecase_from_list(adev, out->usecase) != NULL) &&
8878 (out->usecase != USECASE_COMPRESS_VOIP_CALL)) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008879 ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008880 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008881 ret = -EEXIST;
8882 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008883 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008884
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008885 pthread_mutex_unlock(&adev->lock);
8886
8887 out->stream.common.get_sample_rate = out_get_sample_rate;
8888 out->stream.common.set_sample_rate = out_set_sample_rate;
8889 out->stream.common.get_buffer_size = out_get_buffer_size;
8890 out->stream.common.get_channels = out_get_channels;
8891 out->stream.common.get_format = out_get_format;
8892 out->stream.common.set_format = out_set_format;
8893 out->stream.common.standby = out_standby;
8894 out->stream.common.dump = out_dump;
8895 out->stream.common.set_parameters = out_set_parameters;
8896 out->stream.common.get_parameters = out_get_parameters;
8897 out->stream.common.add_audio_effect = out_add_audio_effect;
8898 out->stream.common.remove_audio_effect = out_remove_audio_effect;
8899 out->stream.get_latency = out_get_latency;
8900 out->stream.set_volume = out_set_volume;
Aalique Grahame22e49102018-12-18 14:23:57 -08008901#ifdef NO_AUDIO_OUT
8902 out->stream.write = out_write_for_no_output;
8903#else
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008904 out->stream.write = out_write;
Aalique Grahame22e49102018-12-18 14:23:57 -08008905#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008906 out->stream.get_render_position = out_get_render_position;
8907 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008908 out->stream.get_presentation_position = out_get_presentation_position;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008909
Haynes Mathew George16081042017-05-31 17:16:49 -07008910 if (out->realtime)
8911 out->af_period_multiplier = af_period_multiplier;
8912 else
8913 out->af_period_multiplier = 1;
8914
Andy Hunga1f48fa2019-07-01 18:14:53 -07008915 out->kernel_buffer_size = out->config.period_size * out->config.period_count;
8916
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008917 out->standby = 1;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008918 out->volume_l = PLAYBACK_GAIN_MAX;
8919 out->volume_r = PLAYBACK_GAIN_MAX;
Eric Laurenta9024de2013-04-04 09:19:12 -07008920 /* out->muted = false; by calloc() */
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008921 /* out->written = 0; by calloc() */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008922
8923 config->format = out->stream.common.get_format(&out->stream.common);
8924 config->channel_mask = out->stream.common.get_channels(&out->stream.common);
8925 config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
Naresh Tanniru04f71882018-06-26 17:46:22 +05308926 register_format(out->format, out->supported_formats);
8927 register_channel_mask(out->channel_mask, out->supported_channel_masks);
8928 register_sample_rate(out->sample_rate, out->supported_sample_rates);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008929
Dechen Chai22768452021-07-30 09:29:16 +05308930#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08008931 out->error_log = error_log_create(
8932 ERROR_LOG_ENTRIES,
8933 1000000000 /* aggregate consecutive identical errors within one second in ns */);
Dechen Chai22768452021-07-30 09:29:16 +05308934#endif
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308935 /*
8936 By locking output stream before registering, we allow the callback
8937 to update stream's state only after stream's initial state is set to
8938 adev state.
8939 */
8940 lock_output_stream(out);
8941 audio_extn_snd_mon_register_listener(out, out_snd_mon_cb);
8942 pthread_mutex_lock(&adev->lock);
8943 out->card_status = adev->card_status;
8944 pthread_mutex_unlock(&adev->lock);
8945 pthread_mutex_unlock(&out->lock);
8946
Aalique Grahame22e49102018-12-18 14:23:57 -08008947 stream_app_type_cfg_init(&out->app_type_cfg);
8948
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008949 *stream_out = &out->stream;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308950 ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
vivek mehta0ea887a2015-08-26 14:01:20 -07008951 use_case_table[out->usecase]);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008952
8953 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
8954 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
8955 popcount(out->channel_mask), out->playback_started);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008956 /* setup a channel for client <--> adsp communication for stream events */
Manish Dewangan21a850a2017-08-14 12:03:55 +05308957 is_direct_passthough = audio_extn_passthru_is_direct_passthrough(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008958 if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Naresh Tanniru85819452017-05-04 18:55:45 -07008959 (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) ||
Gangadhar Sb0210342019-02-22 17:39:41 +05308960 audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform) ||
8961 (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false))) {
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008962 hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
8963 out->usecase, PCM_PLAYBACK);
8964 hdlr_stream_cfg.flags = out->flags;
8965 hdlr_stream_cfg.type = PCM_PLAYBACK;
8966 ret = audio_extn_adsp_hdlr_stream_open(&out->adsp_hdlr_stream_handle,
8967 &hdlr_stream_cfg);
8968 if (ret) {
8969 ALOGE("%s: adsp_hdlr_stream_open failed %d",__func__, ret);
8970 out->adsp_hdlr_stream_handle = NULL;
8971 }
8972 }
Gangadhar Sb0210342019-02-22 17:39:41 +05308973 ip_hdlr_stream = audio_extn_ip_hdlr_intf_supported(config->format,
8974 is_direct_passthough, false);
8975 ip_hdlr_dev = audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform);
8976 if (ip_hdlr_stream || ip_hdlr_dev ) {
Vidyakumar Athota2062f912017-06-27 14:46:15 -07008977 ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL, adev, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07008978 if (ret < 0) {
8979 ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d",__func__, ret);
8980 out->ip_hdlr_handle = NULL;
8981 }
8982 }
Derek Chenf939fb72018-11-13 13:34:41 -08008983
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07008984 ret = io_streams_map_insert(adev, &out->stream.common,
8985 out->handle, AUDIO_PATCH_HANDLE_NONE);
8986 if (ret != 0)
8987 goto error_open;
8988
Susan Wang6dd13092021-01-25 10:27:11 -05008989 out->out_ctxt.output = out;
Derek Chenf939fb72018-11-13 13:34:41 -08008990
8991 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -05008992 list_add_tail(&adev->active_outputs_list, &out->out_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -08008993 pthread_mutex_unlock(&adev->lock);
8994
Eric Laurent994a6932013-07-17 11:51:42 -07008995 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008996 return 0;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008997
8998error_open:
Ashish Jain83a6cc22016-06-28 14:34:17 +05308999 if (out->convert_buffer)
9000 free(out->convert_buffer);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07009001 free(out);
9002 *stream_out = NULL;
9003 ALOGD("%s: exit: ret %d", __func__, ret);
9004 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009005}
9006
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05309007void adev_close_output_stream(struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009008 struct audio_stream_out *stream)
9009{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009010 struct stream_out *out = (struct stream_out *)stream;
9011 struct audio_device *adev = out->dev;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009012 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009013
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009014 ALOGD("%s: enter:stream_handle(%s)",__func__, use_case_table[out->usecase]);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309015
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009016 io_streams_map_remove(adev, out->handle);
9017
Susan Wang6dd13092021-01-25 10:27:11 -05009018 // remove out_ctxt early to prevent the stream
9019 // being opened in a race condition
9020 pthread_mutex_lock(&adev->lock);
9021 list_remove(&out->out_ctxt.list);
9022 pthread_mutex_unlock(&adev->lock);
9023
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05309024 // must deregister from sndmonitor first to prevent races
9025 // between the callback and close_stream
9026 audio_extn_snd_mon_unregister_listener(out);
9027
Ben Rombergerd771a7c2017-02-22 18:05:17 -08009028 /* close adsp hdrl session before standby */
9029 if (out->adsp_hdlr_stream_handle) {
9030 ret = audio_extn_adsp_hdlr_stream_close(out->adsp_hdlr_stream_handle);
9031 if (ret)
9032 ALOGE("%s: adsp_hdlr_stream_close failed %d",__func__, ret);
9033 out->adsp_hdlr_stream_handle = NULL;
9034 }
9035
Manish Dewangan21a850a2017-08-14 12:03:55 +05309036 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07009037 audio_extn_ip_hdlr_intf_deinit(out->ip_hdlr_handle);
9038 out->ip_hdlr_handle = NULL;
9039 }
9040
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009041 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309042 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009043 ret = voice_extn_compress_voip_close_output_stream(&stream->common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309044 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309045 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009046 if(ret != 0)
9047 ALOGE("%s: Compress voip output cannot be closed, error:%d",
9048 __func__, ret);
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009049 } else
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009050 out_standby(&stream->common);
9051
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07009052 if (is_offload_usecase(out->usecase)) {
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08009053 audio_extn_dts_remove_state_notifier_node(out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009054 destroy_offload_callback_thread(out);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07009055 free_offload_usecase(adev, out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009056 if (out->compr_config.codec != NULL)
9057 free(out->compr_config.codec);
9058 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009059
Zhou Songbaddf9f2020-11-20 13:57:39 +08009060 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05309061
Varun Balaraje49253e2017-07-06 19:48:56 +05309062 if (is_interactive_usecase(out->usecase))
9063 free_interactive_usecase(adev, out->usecase);
9064
Ashish Jain83a6cc22016-06-28 14:34:17 +05309065 if (out->convert_buffer != NULL) {
9066 free(out->convert_buffer);
9067 out->convert_buffer = NULL;
9068 }
9069
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009070 if (adev->voice_tx_output == out)
9071 adev->voice_tx_output = NULL;
9072
Dechen Chai22768452021-07-30 09:29:16 +05309073#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08009074 error_log_destroy(out->error_log);
9075 out->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +05309076#endif
Dhanalakshmi Siddani6c3d0992017-01-16 16:52:33 +05309077 if (adev->primary_output == out)
9078 adev->primary_output = NULL;
9079
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009080 pthread_cond_destroy(&out->cond);
9081 pthread_mutex_destroy(&out->lock);
Weiyin Jiang280ea742020-09-08 20:28:22 +08009082 pthread_mutex_destroy(&out->pre_lock);
9083 pthread_mutex_destroy(&out->latch_lock);
9084 pthread_mutex_destroy(&out->position_query_lock);
Derek Chenf939fb72018-11-13 13:34:41 -08009085
9086 pthread_mutex_lock(&adev->lock);
Zhenlin Lian4f947842022-05-14 15:50:52 +05309087 clear_devices(&out->device_list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009088 free(stream);
Derek Chenf939fb72018-11-13 13:34:41 -08009089 pthread_mutex_unlock(&adev->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07009090 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009091}
9092
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05009093void in_set_power_policy(uint8_t enable)
9094{
9095 struct listnode *node;
9096
9097 ALOGD("%s: Enter, state %d", __func__, enable);
9098
9099 pthread_mutex_lock(&adev->lock);
9100 adev->in_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_OFFLINE;
9101 pthread_mutex_unlock(&adev->lock);
9102
9103 if (!enable) {
9104 list_for_each(node, &adev->active_inputs_list) {
9105 streams_input_ctxt_t *in_ctxt = node_to_item(node,
9106 streams_input_ctxt_t,
9107 list);
9108 struct stream_in *in = in_ctxt->input;
9109 in_standby(&in->stream.common);
9110 }
9111 }
9112
9113 ALOGD("%s: Exit", __func__);
9114}
9115
9116void out_set_power_policy(uint8_t enable)
9117{
9118 struct listnode *node;
9119
9120 ALOGD("%s: Enter, state %d", __func__, enable);
9121
9122 pthread_mutex_lock(&adev->lock);
E V Ravi317be872022-02-23 19:08:15 +05309123 adev->out_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_OFFLINE;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05009124 pthread_mutex_unlock(&adev->lock);
9125
9126 if (!enable) {
9127 list_for_each(node, &adev->active_outputs_list) {
9128 streams_output_ctxt_t *out_ctxt = node_to_item(node,
9129 streams_output_ctxt_t,
9130 list);
9131 struct stream_out *out = out_ctxt->output;
9132 out_on_error(&out->stream.common);
9133 }
9134 }
9135
9136 ALOGD("%s: Exit", __func__);
9137}
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009138static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
9139{
9140 struct audio_device *adev = (struct audio_device *)dev;
9141 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009142 char value[32];
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009143 int val;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009144 int ret;
9145 int status = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08009146 bool a2dp_reconfig = false;
Zhou Songd6d71752019-05-21 18:08:51 +08009147 struct listnode *node;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009148 int controller = -1, stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009149
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009150 ALOGD("%s: enter: %s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009151 parms = str_parms_create_str(kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009152
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309153 if (!parms)
9154 goto error;
Naresh Tanniru4c630392014-05-12 01:05:52 +05309155
Derek Chen6f293672019-04-01 01:40:24 -07009156 /* notify adev and input/output streams on the snd card status */
9157 adev_snd_mon_cb((void *)adev, parms);
9158
Weiyin Jiang24f55292020-12-22 14:35:46 +08009159 ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
9160 if (ret >= 0) {
9161 list_for_each(node, &adev->active_outputs_list) {
9162 streams_output_ctxt_t *out_ctxt = node_to_item(node,
9163 streams_output_ctxt_t,
9164 list);
9165 out_snd_mon_cb((void *)out_ctxt->output, parms);
9166 }
Derek Chen6f293672019-04-01 01:40:24 -07009167
Weiyin Jiang24f55292020-12-22 14:35:46 +08009168 list_for_each(node, &adev->active_inputs_list) {
9169 streams_input_ctxt_t *in_ctxt = node_to_item(node,
9170 streams_input_ctxt_t,
9171 list);
9172 in_snd_mon_cb((void *)in_ctxt->input, parms);
9173 }
Derek Chen6f293672019-04-01 01:40:24 -07009174 }
9175
Zhou Songd6d71752019-05-21 18:08:51 +08009176 pthread_mutex_lock(&adev->lock);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309177 ret = str_parms_get_str(parms, "BT_SCO", value, sizeof(value));
9178 if (ret >= 0) {
9179 /* When set to false, HAL should disable EC and NS */
Zhou Songd6d71752019-05-21 18:08:51 +08009180 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0){
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309181 adev->bt_sco_on = true;
Shalini Manjunatha3a2e06e2021-02-01 12:23:49 +05309182 /*
9183 * When ever BT_SCO=ON arrives, make sure to route
9184 * all use cases to SCO device, otherwise due to delay in
9185 * BT_SCO=ON and lack of synchronization with create audio patch
9186 * request for SCO device, some times use case not routed properly to
9187 * SCO device
9188 */
9189 struct audio_usecase *usecase;
9190 struct listnode *node;
9191 list_for_each(node, &adev->usecase_list) {
9192 usecase = node_to_item(node, struct audio_usecase, list);
Anver sadhiquef0efca32021-09-03 15:25:44 +05309193 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05309194 (!is_btsco_device(SND_DEVICE_NONE, usecase->in_snd_device)) && (is_sco_in_device_type(&usecase->stream.in->device_list))) {
Shalini Manjunatha3a2e06e2021-02-01 12:23:49 +05309195 ALOGD("BT_SCO ON, switch all in use case to it");
9196 select_devices(adev, usecase->id);
9197 }
Mingshu Pangef517202021-04-22 10:35:00 +08009198 if (usecase->stream.out && (usecase->type == PCM_PLAYBACK ||
9199 usecase->type == VOICE_CALL) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05309200 (!is_btsco_device(usecase->out_snd_device, SND_DEVICE_NONE)) && (is_sco_out_device_type(&usecase->stream.out->device_list))) {
Shalini Manjunatha3a2e06e2021-02-01 12:23:49 +05309201 ALOGD("BT_SCO ON, switch all out use case to it");
9202 select_devices(adev, usecase->id);
9203 }
9204 }
9205 }
9206 else {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309207 adev->bt_sco_on = false;
Zhou Songd6d71752019-05-21 18:08:51 +08009208 audio_extn_sco_reset_configuration();
Kunlei Zhangd96af8f2019-08-27 16:33:29 +08009209 }
9210 }
9211
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009212 status = voice_set_parameters(adev, parms);
9213 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009214 goto done;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009215
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009216 status = platform_set_parameters(adev->platform, parms);
9217 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009218 goto done;
9219
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009220 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
9221 if (ret >= 0) {
Vicky Sehrawate240e5d2014-08-12 17:17:04 -07009222 /* When set to false, HAL should disable EC and NS */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009223 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9224 adev->bluetooth_nrec = true;
9225 else
9226 adev->bluetooth_nrec = false;
9227 }
9228
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009229 ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
9230 if (ret >= 0) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009231 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9232 adev->screen_off = false;
9233 else
9234 adev->screen_off = true;
Quinn Male70f20f32019-06-26 16:50:26 -07009235 audio_extn_sound_trigger_update_screen_status(adev->screen_off);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009236 }
9237
Eric Laurent4b084132018-10-19 17:33:43 -07009238 ret = str_parms_get_int(parms, "rotation", &val);
9239 if (ret >= 0) {
9240 bool reverse_speakers = false;
9241 int camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9242 switch (val) {
9243 // FIXME: note that the code below assumes that the speakers are in the correct placement
9244 // relative to the user when the device is rotated 90deg from its default rotation. This
9245 // assumption is device-specific, not platform-specific like this code.
9246 case 270:
9247 reverse_speakers = true;
9248 camera_rotation = CAMERA_ROTATION_INVERT_LANDSCAPE;
9249 break;
9250 case 0:
9251 case 180:
9252 camera_rotation = CAMERA_ROTATION_PORTRAIT;
9253 break;
9254 case 90:
9255 camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9256 break;
9257 default:
9258 ALOGE("%s: unexpected rotation of %d", __func__, val);
9259 status = -EINVAL;
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009260 }
Eric Laurent4b084132018-10-19 17:33:43 -07009261 if (status == 0) {
9262 // check and set swap
9263 // - check if orientation changed and speaker active
9264 // - set rotation and cache the rotation value
9265 adev->camera_orientation =
9266 (adev->camera_orientation & ~CAMERA_ROTATION_MASK) | camera_rotation;
9267 if (!audio_extn_is_maxx_audio_enabled())
9268 platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
9269 }
9270 }
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009271
Mingming Yin514a8bc2014-07-29 15:22:21 -07009272 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
9273 if (ret >= 0) {
9274 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9275 adev->bt_wb_speech_enabled = true;
9276 else
9277 adev->bt_wb_speech_enabled = false;
9278 }
9279
Zhou Song12c29502019-03-16 10:37:18 +08009280 ret = str_parms_get_str(parms, "bt_swb", value, sizeof(value));
9281 if (ret >= 0) {
9282 val = atoi(value);
9283 adev->swb_speech_mode = val;
9284 }
9285
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009286 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
9287 if (ret >= 0) {
9288 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309289 audio_devices_t device = (audio_devices_t) val;
Zhou Song681350a2017-10-19 16:28:42 +08009290 if (audio_is_output_device(val) &&
9291 (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009292 ALOGV("cache new ext disp type and edid");
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009293 platform_get_controller_stream_from_params(parms, &controller, &stream);
9294 platform_set_ext_display_device_v2(adev->platform, controller, stream);
9295 ret = platform_get_ext_disp_type_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009296 if (ret < 0) {
9297 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Manisha Agarwal2f5ff882018-08-08 17:09:29 +05309298 } else {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009299 platform_cache_edid_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009300 }
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309301 } else if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
vivek mehta344576a2016-04-12 18:56:03 -07009302 /*
9303 * Do not allow AFE proxy port usage by WFD source when USB headset is connected.
9304 * Per AudioPolicyManager, USB device is higher priority than WFD.
9305 * For Voice call over USB headset, voice call audio is routed to AFE proxy ports.
9306 * If WFD use case occupies AFE proxy, it may result unintended behavior while
9307 * starting voice call on USB
9308 */
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009309 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309310 if (ret >= 0)
9311 audio_extn_usb_add_device(device, atoi(value));
9312
Zhou Song6f862822017-11-06 17:27:57 +08009313 if (!audio_extn_usb_is_tunnel_supported()) {
9314 ALOGV("detected USB connect .. disable proxy");
9315 adev->allow_afe_proxy_usage = false;
9316 }
Zhou Song503196b2021-07-23 17:31:05 +08009317 } else if (audio_is_hearing_aid_out_device(device) &&
9318 property_get_bool("persist.vendor.audio.ha_proxy.enabled", false)) {
9319 adev->ha_proxy_enable = true;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009320 }
9321 }
9322
9323 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
9324 if (ret >= 0) {
9325 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309326 audio_devices_t device = (audio_devices_t) val;
Garmond Leunge3b6d482016-10-25 16:48:01 -07009327 /*
9328 * The HDMI / Displayport disconnect handling has been moved to
9329 * audio extension to ensure that its parameters are not
9330 * invalidated prior to updating sysfs of the disconnect event
9331 * Invalidate will be handled by audio_extn_ext_disp_set_parameters()
9332 */
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309333 if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009334 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309335 if (ret >= 0)
9336 audio_extn_usb_remove_device(device, atoi(value));
9337
Zhou Song6f862822017-11-06 17:27:57 +08009338 if (!audio_extn_usb_is_tunnel_supported()) {
9339 ALOGV("detected USB disconnect .. enable proxy");
9340 adev->allow_afe_proxy_usage = true;
9341 }
Zhou Song503196b2021-07-23 17:31:05 +08009342 } else if (audio_is_hearing_aid_out_device(device)) {
9343 adev->ha_proxy_enable = false;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009344 }
9345 }
9346
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009347 audio_extn_qdsp_set_parameters(adev, parms);
Aalique Grahame22e49102018-12-18 14:23:57 -08009348
9349 status = audio_extn_a2dp_set_parameters(parms, &a2dp_reconfig);
Aniket Kumar Lata23300322019-02-20 22:25:30 -08009350 if (status >= 0 && a2dp_reconfig) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309351 struct audio_usecase *usecase;
9352 struct listnode *node;
9353 list_for_each(node, &adev->usecase_list) {
9354 usecase = node_to_item(node, struct audio_usecase, list);
Weiyin Jiangff56ff32020-05-08 14:32:21 +08009355 if ((usecase->stream.out == NULL) || (usecase->type != PCM_PLAYBACK))
9356 continue;
9357
9358 if (is_a2dp_out_device_type(&usecase->device_list)) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309359 ALOGD("reconfigure a2dp... forcing device switch");
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309360 audio_extn_a2dp_set_handoff_mode(true);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309361 ALOGD("Switching to speaker and muting the stream before select_devices");
9362 check_a2dp_restore_l(adev, usecase->stream.out, false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309363 //force device switch to re configure encoder
9364 select_devices(adev, usecase->id);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309365 ALOGD("Unmuting the stream after select_devices");
Zhou Songbaddf9f2020-11-20 13:57:39 +08009366 check_a2dp_restore_l(adev, usecase->stream.out, true);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309367 audio_extn_a2dp_set_handoff_mode(false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309368 break;
Zhou Songd01e7a22020-09-23 22:49:01 +08009369 } else if (is_offload_usecase(usecase->stream.out->usecase)) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009370 pthread_mutex_lock(&usecase->stream.out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08009371 if (usecase->stream.out->a2dp_muted) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009372 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
9373 reassign_device_list(&usecase->stream.out->device_list,
9374 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
9375 check_a2dp_restore_l(adev, usecase->stream.out, true);
9376 break;
9377 }
9378 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309379 }
9380 }
9381 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009382
9383 //handle vr audio setparam
9384 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9385 value, sizeof(value));
9386 if (ret >= 0) {
9387 ALOGI("Setting vr mode to be %s", value);
9388 if (!strncmp(value, "true", 4)) {
9389 adev->vr_audio_mode_enabled = true;
9390 ALOGI("Setting vr mode to true");
9391 } else if (!strncmp(value, "false", 5)) {
9392 adev->vr_audio_mode_enabled = false;
9393 ALOGI("Setting vr mode to false");
9394 } else {
9395 ALOGI("wrong vr mode set");
9396 }
9397 }
9398
Eric Laurent4b084132018-10-19 17:33:43 -07009399 //FIXME: to be replaced by proper video capture properties API
9400 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_CAMERA_FACING, value, sizeof(value));
9401 if (ret >= 0) {
9402 int camera_facing = CAMERA_FACING_BACK;
9403 if (strcmp(value, AUDIO_PARAMETER_VALUE_FRONT) == 0)
9404 camera_facing = CAMERA_FACING_FRONT;
9405 else if (strcmp(value, AUDIO_PARAMETER_VALUE_BACK) == 0)
9406 camera_facing = CAMERA_FACING_BACK;
9407 else {
9408 ALOGW("%s: invalid camera facing value: %s", __func__, value);
9409 goto done;
9410 }
9411 adev->camera_orientation =
9412 (adev->camera_orientation & ~CAMERA_FACING_MASK) | camera_facing;
9413 struct audio_usecase *usecase;
9414 struct listnode *node;
9415 list_for_each(node, &adev->usecase_list) {
9416 usecase = node_to_item(node, struct audio_usecase, list);
9417 struct stream_in *in = usecase->stream.in;
9418 if (usecase->type == PCM_CAPTURE && in != NULL &&
9419 in->source == AUDIO_SOURCE_CAMCORDER && !in->standby) {
9420 select_devices(adev, in->usecase);
9421 }
9422 }
9423 }
9424
Tahir Dawson7fabad42022-06-21 12:37:55 -04009425 audio_extn_auto_hal_set_parameters(adev, parms);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309426 audio_extn_set_parameters(adev, parms);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009427done:
9428 str_parms_destroy(parms);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009429 pthread_mutex_unlock(&adev->lock);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309430error:
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009431 ALOGV("%s: exit with code(%d)", __func__, status);
9432 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009433}
9434
9435static char* adev_get_parameters(const struct audio_hw_device *dev,
9436 const char *keys)
9437{
Sidipotu Ashokaa4fa6a2018-12-21 09:19:26 +05309438 ALOGD("%s:%s", __func__, keys);
9439
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009440 struct audio_device *adev = (struct audio_device *)dev;
9441 struct str_parms *reply = str_parms_create();
9442 struct str_parms *query = str_parms_create_str(keys);
9443 char *str;
Naresh Tannirud7205b62014-06-20 02:54:48 +05309444 char value[256] = {0};
9445 int ret = 0;
9446
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009447 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08009448 if (reply) {
9449 str_parms_destroy(reply);
9450 }
9451 if (query) {
9452 str_parms_destroy(query);
9453 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009454 ALOGE("adev_get_parameters: failed to create query or reply");
9455 return NULL;
9456 }
9457
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009458 //handle vr audio getparam
9459
9460 ret = str_parms_get_str(query,
9461 AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9462 value, sizeof(value));
9463
9464 if (ret >= 0) {
9465 bool vr_audio_enabled = false;
9466 pthread_mutex_lock(&adev->lock);
9467 vr_audio_enabled = adev->vr_audio_mode_enabled;
9468 pthread_mutex_unlock(&adev->lock);
9469
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009470 ALOGV("getting vr mode to %d", vr_audio_enabled);
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009471
9472 if (vr_audio_enabled) {
9473 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9474 "true");
9475 goto exit;
9476 } else {
9477 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9478 "false");
9479 goto exit;
9480 }
9481 }
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009482
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009483 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009484 audio_extn_get_parameters(adev, query, reply);
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -08009485 voice_get_parameters(adev, query, reply);
Aalique Grahame22e49102018-12-18 14:23:57 -08009486 audio_extn_a2dp_get_parameters(query, reply);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009487 platform_get_parameters(adev->platform, query, reply);
justinwengd5395152019-11-04 12:23:09 +08009488 audio_extn_ma_get_parameters(adev, query, reply);
Naresh Tanniru80659832014-06-04 18:17:56 +05309489 pthread_mutex_unlock(&adev->lock);
9490
Naresh Tannirud7205b62014-06-20 02:54:48 +05309491exit:
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009492 str = str_parms_to_str(reply);
9493 str_parms_destroy(query);
9494 str_parms_destroy(reply);
9495
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009496 ALOGV("%s: exit: returns - %s", __func__, str);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009497 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009498}
9499
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009500static int adev_init_check(const struct audio_hw_device *dev __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009501{
9502 return 0;
9503}
9504
9505static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
9506{
Haynes Mathew George5191a852013-09-11 14:19:36 -07009507 int ret;
9508 struct audio_device *adev = (struct audio_device *)dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08009509
9510 audio_extn_extspk_set_voice_vol(adev->extspk, volume);
9511
Haynes Mathew George5191a852013-09-11 14:19:36 -07009512 pthread_mutex_lock(&adev->lock);
9513 /* cache volume */
Shruthi Krishnaace10852013-10-25 14:32:12 -07009514 ret = voice_set_volume(adev, volume);
Haynes Mathew George5191a852013-09-11 14:19:36 -07009515 pthread_mutex_unlock(&adev->lock);
9516 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009517}
9518
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009519static int adev_set_master_volume(struct audio_hw_device *dev __unused,
9520 float volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009521{
9522 return -ENOSYS;
9523}
9524
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009525static int adev_get_master_volume(struct audio_hw_device *dev __unused,
9526 float *volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009527{
9528 return -ENOSYS;
9529}
9530
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009531static int adev_set_master_mute(struct audio_hw_device *dev __unused,
9532 bool muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009533{
9534 return -ENOSYS;
9535}
9536
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009537static int adev_get_master_mute(struct audio_hw_device *dev __unused,
9538 bool *muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009539{
9540 return -ENOSYS;
9541}
9542
9543static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
9544{
9545 struct audio_device *adev = (struct audio_device *)dev;
Garmond Leung5fd0b552018-04-17 11:56:12 -07009546 struct listnode *node;
9547 struct audio_usecase *usecase = NULL;
9548 int ret = 0;
kunleizdc4af9d2017-05-04 12:15:35 +08009549
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009550 pthread_mutex_lock(&adev->lock);
9551 if (adev->mode != mode) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309552 ALOGD("%s: mode %d , prev_mode %d \n", __func__, mode , adev->mode);
9553 adev->prev_mode = adev->mode; /* prev_mode is kept to handle voip concurrency*/
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009554 adev->mode = mode;
Weiyin Jiang96b96f72020-09-22 16:48:19 +08009555 if (mode == AUDIO_MODE_CALL_SCREEN) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309556 adev->current_call_output = adev->primary_output;
9557 voice_start_call(adev);
9558 } else if (voice_is_in_call_or_call_screen(adev) &&
Kunlei Zhang1d5c7f22019-05-21 14:25:57 +08009559 (mode == AUDIO_MODE_NORMAL ||
9560 (mode == AUDIO_MODE_IN_COMMUNICATION && !voice_is_call_state_active(adev)))) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07009561 list_for_each(node, &adev->usecase_list) {
9562 usecase = node_to_item(node, struct audio_usecase, list);
9563 if (usecase->type == VOICE_CALL)
9564 break;
9565 }
9566 if (usecase &&
9567 audio_is_usb_out_device(usecase->out_snd_device & AUDIO_DEVICE_OUT_ALL_USB)) {
9568 ret = audio_extn_usb_check_and_set_svc_int(usecase,
9569 true);
9570 if (ret != 0) {
9571 /* default service interval was successfully updated,
9572 reopen USB backend with new service interval */
9573 check_usecases_codec_backend(adev,
9574 usecase,
9575 usecase->out_snd_device);
9576 }
9577 }
9578
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009579 voice_stop_call(adev);
Banajit Goswami20cdd212015-09-11 01:11:30 -07009580 platform_set_gsm_mode(adev->platform, false);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009581 adev->current_call_output = NULL;
kunleizdc4af9d2017-05-04 12:15:35 +08009582 // restore device for other active usecases after stop call
9583 list_for_each(node, &adev->usecase_list) {
9584 usecase = node_to_item(node, struct audio_usecase, list);
9585 select_devices(adev, usecase->id);
9586 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009587 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009588 }
9589 pthread_mutex_unlock(&adev->lock);
9590 return 0;
9591}
9592
9593static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
9594{
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009595 int ret;
Aalique Grahame22e49102018-12-18 14:23:57 -08009596 struct audio_device *adev = (struct audio_device *)dev;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009597
9598 pthread_mutex_lock(&adev->lock);
Vidyakumar Athota2850d532013-11-19 16:02:12 -08009599 ALOGD("%s state %d\n", __func__, state);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009600 ret = voice_set_mic_mute((struct audio_device *)dev, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009601
Derek Chend2530072014-11-24 12:39:14 -08009602 if (adev->ext_hw_plugin)
9603 ret = audio_extn_ext_hw_plugin_set_mic_mute(adev->ext_hw_plugin, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009604
9605 adev->mic_muted = state;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009606 pthread_mutex_unlock(&adev->lock);
9607
9608 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009609}
9610
9611static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
9612{
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009613 *state = voice_get_mic_mute((struct audio_device *)dev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009614 return 0;
9615}
9616
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009617static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009618 const struct audio_config *config)
9619{
Avinash Chandrad7296d42021-08-04 15:07:47 +05309620 bool is_usb_hifi = IS_USB_HIFI;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009621 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009622
Aalique Grahame22e49102018-12-18 14:23:57 -08009623 /* Don't know if USB HIFI in this context so use true to be conservative */
9624 if (check_input_parameters(config->sample_rate, config->format, channel_count,
Avinash Chandrad7296d42021-08-04 15:07:47 +05309625 is_usb_hifi) != 0)
Aalique Grahame22e49102018-12-18 14:23:57 -08009626 return 0;
9627
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009628 return get_input_buffer_size(config->sample_rate, config->format, channel_count,
9629 false /* is_low_latency: since we don't know, be conservative */);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009630}
9631
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009632static bool adev_input_allow_hifi_record(struct audio_device *adev,
9633 audio_devices_t devices,
9634 audio_input_flags_t flags,
9635 audio_source_t source) {
9636 const bool allowed = true;
9637
9638 if (!audio_is_usb_in_device(devices))
9639 return !allowed;
9640
9641 switch (flags) {
9642 case AUDIO_INPUT_FLAG_NONE:
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009643 break;
Haynes Mathew George59862182017-10-24 16:23:57 -07009644 case AUDIO_INPUT_FLAG_FAST: // disallow hifi record for FAST as
9645 // it affects RTD numbers over USB
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009646 default:
9647 return !allowed;
9648 }
9649
9650 switch (source) {
9651 case AUDIO_SOURCE_DEFAULT:
9652 case AUDIO_SOURCE_MIC:
9653 case AUDIO_SOURCE_UNPROCESSED:
9654 break;
9655 default:
9656 return !allowed;
9657 }
9658
9659 switch (adev->mode) {
9660 case 0:
9661 break;
9662 default:
9663 return !allowed;
9664 }
9665
9666 return allowed;
9667}
9668
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009669static int adev_update_voice_comm_input_stream(struct stream_in *in,
9670 struct audio_config *config)
9671{
9672 bool valid_rate = (config->sample_rate == 8000 ||
9673 config->sample_rate == 16000 ||
9674 config->sample_rate == 32000 ||
9675 config->sample_rate == 48000);
9676 bool valid_ch = audio_channel_count_from_in_mask(in->channel_mask) == 1;
9677
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009678 if(!voice_extn_is_compress_voip_supported()) {
kunleiz28c73e72019-03-27 17:24:04 +08009679 if (valid_rate && valid_ch) {
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009680 in->usecase = USECASE_AUDIO_RECORD_VOIP;
9681 in->config = default_pcm_config_voip_copp;
9682 in->config.period_size = VOIP_IO_BUF_SIZE(in->sample_rate,
9683 DEFAULT_VOIP_BUF_DURATION_MS,
9684 DEFAULT_VOIP_BIT_DEPTH_BYTE)/2;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009685 } else {
9686 ALOGW("%s No valid input in voip, use defaults"
9687 "sample rate %u, channel mask 0x%X",
9688 __func__, config->sample_rate, in->channel_mask);
9689 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009690 in->config.rate = config->sample_rate;
9691 in->sample_rate = config->sample_rate;
9692 } else {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009693 //XXX needed for voice_extn_compress_voip_open_input_stream
9694 in->config.rate = config->sample_rate;
9695 if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
Shalini Manjunathaa763cc42019-08-23 15:13:46 +05309696 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009697 voice_extn_compress_voip_is_active(in->dev)) &&
9698 (voice_extn_compress_voip_is_format_supported(in->format)) &&
9699 valid_rate && valid_ch) {
9700 voice_extn_compress_voip_open_input_stream(in);
9701 // update rate entries to match config from AF
9702 in->config.rate = config->sample_rate;
9703 in->sample_rate = config->sample_rate;
9704 } else {
9705 ALOGW("%s compress voip not active, use defaults", __func__);
9706 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009707 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009708 return 0;
9709}
9710
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009711static int adev_open_input_stream(struct audio_hw_device *dev,
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07009712 audio_io_handle_t handle,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009713 audio_devices_t devices,
9714 struct audio_config *config,
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009715 struct audio_stream_in **stream_in,
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309716 audio_input_flags_t flags,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009717 const char *address,
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009718 audio_source_t source)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009719{
9720 struct audio_device *adev = (struct audio_device *)dev;
9721 struct stream_in *in;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08009722 int ret = 0, buffer_size, frame_size;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009723 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009724 bool is_low_latency = false;
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +05309725 bool channel_mask_updated = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009726 bool is_usb_dev = audio_is_usb_in_device(devices);
9727 bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
9728 devices,
9729 flags,
9730 source);
Andy Hung94320602018-10-29 18:31:12 -07009731 ALOGV("%s: enter: flags %#x, is_usb_dev %d, may_use_hifi_record %d,"
9732 " sample_rate %u, channel_mask %#x, format %#x",
9733 __func__, flags, is_usb_dev, may_use_hifi_record,
9734 config->sample_rate, config->channel_mask, config->format);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309735
kunleizdff872d2018-08-20 14:40:33 +08009736 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08009737 is_usb_dev = false;
9738 devices = AUDIO_DEVICE_IN_BUILTIN_MIC;
9739 ALOGW("%s: ignore set device to non existing USB card, use input device(%#x)",
9740 __func__, devices);
9741 }
9742
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009743 *stream_in = NULL;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009744
9745 if (!(is_usb_dev && may_use_hifi_record)) {
9746 if (config->sample_rate == 0)
9747 config->sample_rate = 48000;
9748 if (config->channel_mask == AUDIO_CHANNEL_NONE)
9749 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9750 if (config->format == AUDIO_FORMAT_DEFAULT)
9751 config->format = AUDIO_FORMAT_PCM_16_BIT;
9752
9753 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
9754
Aalique Grahame22e49102018-12-18 14:23:57 -08009755 if (check_input_parameters(config->sample_rate, config->format, channel_count,
9756 false) != 0)
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009757 return -EINVAL;
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05309758 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009759
9760 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009761
9762 if (!in) {
9763 ALOGE("failed to allocate input stream");
9764 return -ENOMEM;
9765 }
9766
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309767 ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05309768 stream_handle(%p) io_handle(%d) source(%d) format %x",__func__, config->sample_rate,
9769 config->channel_mask, devices, &in->stream, handle, source, config->format);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009770 pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07009771 pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009772
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009773 in->stream.common.get_sample_rate = in_get_sample_rate;
9774 in->stream.common.set_sample_rate = in_set_sample_rate;
9775 in->stream.common.get_buffer_size = in_get_buffer_size;
9776 in->stream.common.get_channels = in_get_channels;
9777 in->stream.common.get_format = in_get_format;
9778 in->stream.common.set_format = in_set_format;
9779 in->stream.common.standby = in_standby;
9780 in->stream.common.dump = in_dump;
9781 in->stream.common.set_parameters = in_set_parameters;
9782 in->stream.common.get_parameters = in_get_parameters;
9783 in->stream.common.add_audio_effect = in_add_audio_effect;
9784 in->stream.common.remove_audio_effect = in_remove_audio_effect;
9785 in->stream.set_gain = in_set_gain;
9786 in->stream.read = in_read;
9787 in->stream.get_input_frames_lost = in_get_input_frames_lost;
Aalique Grahame22e49102018-12-18 14:23:57 -08009788 in->stream.get_capture_position = in_get_capture_position;
Naresh Tannirudcb47c52018-06-25 16:23:32 +05309789 in->stream.get_active_microphones = in_get_active_microphones;
Paul McLeana50b7332018-12-17 08:24:21 -07009790 in->stream.set_microphone_direction = in_set_microphone_direction;
9791 in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
juyuchendb308c22019-01-21 11:57:17 -07009792 in->stream.update_sink_metadata = in_update_sink_metadata;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009793
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009794 list_init(&in->device_list);
9795 update_device_list(&in->device_list, devices, address, true);
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009796 in->source = source;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009797 in->dev = adev;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009798 in->standby = 1;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009799 in->capture_handle = handle;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07009800 in->flags = flags;
Haynes Mathew George46740472017-10-27 18:40:12 -07009801 in->bit_width = 16;
9802 in->af_period_multiplier = 1;
justinweng20fb6d82019-02-21 18:49:00 -07009803 in->direction = MIC_DIRECTION_UNSPECIFIED;
9804 in->zoom = 0;
Carter Hsu2e429db2019-05-14 18:50:52 +08009805 list_init(&in->aec_list);
9806 list_init(&in->ns_list);
Phil Burkd898ba62019-06-20 12:49:01 -07009807 in->mmap_shared_memory_fd = -1; // not open
Haynes Mathew George46740472017-10-27 18:40:12 -07009808
Andy Hung94320602018-10-29 18:31:12 -07009809 ALOGV("%s: source %d, config->channel_mask %#x", __func__, source, config->channel_mask);
Aalique Grahame22e49102018-12-18 14:23:57 -08009810 if (source == AUDIO_SOURCE_VOICE_UPLINK ||
9811 source == AUDIO_SOURCE_VOICE_DOWNLINK) {
9812 /* Force channel config requested to mono if incall
9813 record is being requested for only uplink/downlink */
9814 if (config->channel_mask != AUDIO_CHANNEL_IN_MONO) {
9815 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9816 ret = -EINVAL;
9817 goto err_open;
9818 }
9819 }
9820
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009821 if (is_usb_dev && may_use_hifi_record) {
9822 /* HiFi record selects an appropriate format, channel, rate combo
9823 depending on sink capabilities*/
9824 ret = read_usb_sup_params_and_compare(false /*is_playback*/,
9825 &config->format,
9826 &in->supported_formats[0],
9827 MAX_SUPPORTED_FORMATS,
9828 &config->channel_mask,
9829 &in->supported_channel_masks[0],
9830 MAX_SUPPORTED_CHANNEL_MASKS,
9831 &config->sample_rate,
9832 &in->supported_sample_rates[0],
9833 MAX_SUPPORTED_SAMPLE_RATES);
9834 if (ret != 0) {
9835 ret = -EINVAL;
9836 goto err_open;
9837 }
9838 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009839 } else if (config->format == AUDIO_FORMAT_DEFAULT) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309840 config->format = AUDIO_FORMAT_PCM_16_BIT;
Surendar karkaaca3d082017-11-09 15:18:37 +05309841 } else if (property_get_bool("vendor.audio.capture.pcm.32bit.enable", false)
9842 && config->format == AUDIO_FORMAT_PCM_32_BIT) {
9843 in->config.format = PCM_FORMAT_S32_LE;
9844 in->bit_width = 32;
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309845 } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
9846 (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
9847 (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
9848 (config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
9849 bool ret_error = false;
9850 in->bit_width = 24;
9851 /* 24 bit is restricted to UNPROCESSED source only,also format supported
9852 from HAL is 24_packed and 8_24
9853 *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
9854 24_packed return error indicating supported format is 24_packed
9855 *> In case of any other source requesting 24 bit or float return error
9856 indicating format supported is 16 bit only.
9857
9858 on error flinger will retry with supported format passed
9859 */
9860 if ((source != AUDIO_SOURCE_UNPROCESSED) &&
9861 (source != AUDIO_SOURCE_CAMCORDER)) {
9862 config->format = AUDIO_FORMAT_PCM_16_BIT;
9863 if (config->sample_rate > 48000)
9864 config->sample_rate = 48000;
9865 ret_error = true;
Haynes Mathew George46740472017-10-27 18:40:12 -07009866 } else if (!(config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
9867 config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309868 config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
9869 ret_error = true;
9870 }
9871
9872 if (ret_error) {
9873 ret = -EINVAL;
9874 goto err_open;
9875 }
9876 }
9877
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009878 in->channel_mask = config->channel_mask;
9879 in->format = config->format;
9880
9881 in->usecase = USECASE_AUDIO_RECORD;
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309882
Huicheng Liu1404ba12020-09-11 01:03:25 -04009883 /* validate bus device address */
9884 if (compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUS)) {
9885 /* extract car audio stream index */
9886 in->car_audio_stream =
9887 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
9888 if (in->car_audio_stream < 0) {
9889 ALOGE("%s: invalid car audio stream %x",
9890 __func__, in->car_audio_stream);
9891 ret = -EINVAL;
9892 goto err_open;
9893 }
9894 ALOGV("%s: car_audio_stream 0x%x", __func__, in->car_audio_stream);
Huicheng Liuea4fd422021-01-12 18:34:50 -05009895 ret = audio_extn_auto_hal_open_input_stream(in);
9896 if (ret) {
9897 ALOGE("%s: Failed to open input stream for bus device", __func__);
9898 ret = -EINVAL;
9899 goto err_open;
9900 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04009901 }
9902
Susan Wange3959562021-03-11 11:50:26 -05009903 /* reassign use case for echo reference stream on automotive platforms */
9904 if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) {
9905 ret = audio_extn_auto_hal_open_echo_reference_stream(in);
9906 }
9907
Kogara Naveen Kumar379ff692022-01-31 11:56:51 +05309908 if ((in->source == AUDIO_SOURCE_FM_TUNER) || (devices == AUDIO_DEVICE_IN_FM_TUNER)) {
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309909 if(!get_usecase_from_list(adev, USECASE_AUDIO_RECORD_FM_VIRTUAL))
9910 in->usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
9911 else {
9912 ret = -EINVAL;
9913 goto err_open;
9914 }
9915 }
9916
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05309917 if ((config->sample_rate == 48000 ||
9918 config->sample_rate == 32000 ||
9919 config->sample_rate == 24000 ||
9920 config->sample_rate == 16000 ||
9921 config->sample_rate == 8000)&&
Deeraj Somanfa377bf2019-02-06 12:57:59 +05309922 (flags & AUDIO_INPUT_FLAG_TIMESTAMP) == 0 &&
9923 (flags & AUDIO_INPUT_FLAG_COMPRESS) == 0 &&
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009924 (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
9925 is_low_latency = true;
9926#if LOW_LATENCY_CAPTURE_USE_CASE
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05309927 if ((flags & AUDIO_INPUT_FLAG_VOIP_TX) != 0)
9928 in->usecase = USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY;
9929 else
9930 in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009931#endif
9932 in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
Aalique Grahame22e49102018-12-18 14:23:57 -08009933 if (!in->realtime) {
9934 in->config = pcm_config_audio_capture;
9935 frame_size = audio_stream_in_frame_size(&in->stream);
9936 buffer_size = get_input_buffer_size(config->sample_rate,
9937 config->format,
9938 channel_count,
9939 is_low_latency);
9940 in->config.period_size = buffer_size / frame_size;
9941 in->config.rate = config->sample_rate;
9942 in->af_period_multiplier = 1;
9943 } else {
9944 // period size is left untouched for rt mode playback
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05309945 switch(config->sample_rate)
9946 {
9947 case 48000:
9948 in->config = pcm_config_audio_capture_rt_48KHz;
9949 break;
9950 case 32000:
9951 in->config = pcm_config_audio_capture_rt_32KHz;
9952 break;
9953 case 24000:
9954 in->config = pcm_config_audio_capture_rt_24KHz;
9955 break;
9956 case 16000:
9957 in->config = pcm_config_audio_capture_rt_16KHz;
9958 break;
9959 case 8000:
9960 in->config = pcm_config_audio_capture_rt_8KHz;
9961 break;
9962 default:
9963 in->config = pcm_config_audio_capture_rt_48KHz;
9964 }
Aalique Grahame22e49102018-12-18 14:23:57 -08009965 in->af_period_multiplier = af_period_multiplier;
9966 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009967 }
9968
Susan Wangb803cb52021-10-14 12:03:36 -04009969 /* Additional sample rates added below must also be present
9970 in audio_policy_configuration.xml for mmap_no_irq_in */
9971 bool valid_mmap_record_rate = (config->sample_rate == 8000 ||
9972 config->sample_rate == 16000 ||
Susan Wang89da9042021-10-14 12:03:36 -04009973 config->sample_rate == 24000 ||
Susan Wangb803cb52021-10-14 12:03:36 -04009974 config->sample_rate == 32000 ||
9975 config->sample_rate == 48000);
9976 if (valid_mmap_record_rate &&
9977 ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009978 in->realtime = 0;
9979 in->usecase = USECASE_AUDIO_RECORD_MMAP;
9980 in->config = pcm_config_mmap_capture;
Haynes Mathew George46740472017-10-27 18:40:12 -07009981 in->config.format = pcm_format_from_audio_format(config->format);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009982 in->stream.start = in_start;
9983 in->stream.stop = in_stop;
9984 in->stream.create_mmap_buffer = in_create_mmap_buffer;
9985 in->stream.get_mmap_position = in_get_mmap_position;
Ramjee Singhbcb3b6c2021-11-17 13:19:16 +05309986 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009987 ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
Haynes Mathew George46740472017-10-27 18:40:12 -07009988 } else if (is_usb_dev && may_use_hifi_record) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009989 in->usecase = USECASE_AUDIO_RECORD_HIFI;
9990 in->config = pcm_config_audio_capture;
9991 frame_size = audio_stream_in_frame_size(&in->stream);
9992 buffer_size = get_input_buffer_size(config->sample_rate,
9993 config->format,
9994 channel_count,
9995 false /*is_low_latency*/);
9996 in->config.period_size = buffer_size / frame_size;
9997 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009998 in->config.format = pcm_format_from_audio_format(config->format);
Karthikeyan Mani07faa602018-08-20 11:01:32 -07009999 switch (config->format) {
10000 case AUDIO_FORMAT_PCM_32_BIT:
10001 in->bit_width = 32;
10002 break;
10003 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
10004 case AUDIO_FORMAT_PCM_8_24_BIT:
10005 in->bit_width = 24;
10006 break;
10007 default:
10008 in->bit_width = 16;
10009 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010010 } else if (is_single_device_type_equal(&in->device_list,
10011 AUDIO_DEVICE_IN_TELEPHONY_RX) ||
10012 is_single_device_type_equal(&in->device_list,
10013 AUDIO_DEVICE_IN_PROXY)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010014 if (config->sample_rate == 0)
10015 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
10016 if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
10017 config->sample_rate != 8000) {
10018 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
10019 ret = -EINVAL;
10020 goto err_open;
10021 }
10022 if (config->format == AUDIO_FORMAT_DEFAULT)
10023 config->format = AUDIO_FORMAT_PCM_16_BIT;
10024 if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
10025 config->format = AUDIO_FORMAT_PCM_16_BIT;
10026 ret = -EINVAL;
10027 goto err_open;
10028 }
10029
10030 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
Zhou Song62ea0282020-03-22 19:53:01 +080010031 if (adev->ha_proxy_enable &&
10032 is_single_device_type_equal(&in->device_list,
10033 AUDIO_DEVICE_IN_TELEPHONY_RX))
10034 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY2;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010035 in->config = pcm_config_afe_proxy_record;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010036 in->config.rate = config->sample_rate;
Aalique Grahame22e49102018-12-18 14:23:57 -080010037 in->af_period_multiplier = 1;
10038 } else if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
Shalini Manjunathaac412b32020-01-03 15:00:14 +053010039 (!voice_extn_is_compress_voip_supported()) &&
Aalique Grahame22e49102018-12-18 14:23:57 -080010040 in->flags & AUDIO_INPUT_FLAG_VOIP_TX &&
10041 (config->sample_rate == 8000 ||
10042 config->sample_rate == 16000 ||
10043 config->sample_rate == 32000 ||
10044 config->sample_rate == 48000) &&
10045 channel_count == 1) {
10046 in->usecase = USECASE_AUDIO_RECORD_VOIP;
10047 in->config = pcm_config_audio_capture;
10048 frame_size = audio_stream_in_frame_size(&in->stream);
10049 buffer_size = get_stream_buffer_size(VOIP_CAPTURE_PERIOD_DURATION_MSEC,
10050 config->sample_rate,
10051 config->format,
10052 channel_count, false /*is_low_latency*/);
10053 in->config.period_size = buffer_size / frame_size;
10054 in->config.period_count = VOIP_CAPTURE_PERIOD_COUNT;
10055 in->config.rate = config->sample_rate;
10056 in->af_period_multiplier = 1;
Mingshu Pangc2d65042021-01-14 16:19:10 +080010057 } else if (in->realtime) {
Kogara Naveen Kumara688a812022-04-27 16:45:59 +053010058 switch(config->sample_rate)
10059 {
10060 case 48000:
10061 in->config = pcm_config_audio_capture_rt_48KHz;
10062 break;
10063 case 32000:
10064 in->config = pcm_config_audio_capture_rt_32KHz;
10065 break;
10066 case 24000:
10067 in->config = pcm_config_audio_capture_rt_24KHz;
10068 break;
10069 case 16000:
10070 in->config = pcm_config_audio_capture_rt_16KHz;
10071 break;
10072 case 8000:
10073 in->config = pcm_config_audio_capture_rt_8KHz;
10074 break;
10075 default:
10076 in->config = pcm_config_audio_capture_rt_48KHz;
10077 }
Mingshu Pangc2d65042021-01-14 16:19:10 +080010078 in->config.format = pcm_format_from_audio_format(config->format);
10079 in->af_period_multiplier = af_period_multiplier;
Haynes Mathew George46740472017-10-27 18:40:12 -070010080 } else {
Revathi Uddarajud2634032017-12-07 14:42:34 +053010081 int ret_val;
10082 pthread_mutex_lock(&adev->lock);
10083 ret_val = audio_extn_check_and_set_multichannel_usecase(adev,
10084 in, config, &channel_mask_updated);
10085 pthread_mutex_unlock(&adev->lock);
10086
10087 if (!ret_val) {
10088 if (channel_mask_updated == true) {
10089 ALOGD("%s: return error to retry with updated channel mask (%#x)",
10090 __func__, config->channel_mask);
10091 ret = -EINVAL;
10092 goto err_open;
10093 }
10094 ALOGD("%s: created multi-channel session succesfully",__func__);
10095 } else if (audio_extn_compr_cap_enabled() &&
10096 audio_extn_compr_cap_format_supported(config->format) &&
10097 (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
10098 audio_extn_compr_cap_init(in);
10099 } else if (audio_extn_cin_applicable_stream(in)) {
Deeraj Soman14230922019-01-30 16:39:30 +053010100 ret = audio_extn_cin_configure_input_stream(in, config);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010101 if (ret)
10102 goto err_open;
10103 } else {
10104 in->config = pcm_config_audio_capture;
10105 in->config.rate = config->sample_rate;
10106 in->config.format = pcm_format_from_audio_format(config->format);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010107 in->format = config->format;
10108 frame_size = audio_stream_in_frame_size(&in->stream);
10109 buffer_size = get_input_buffer_size(config->sample_rate,
Haynes Mathew George46740472017-10-27 18:40:12 -070010110 config->format,
10111 channel_count,
10112 is_low_latency);
Dieter Luecking5d57def2018-09-07 14:23:37 +020010113 /* prevent division-by-zero */
10114 if (frame_size == 0) {
10115 ALOGE("%s: Error frame_size==0", __func__);
10116 ret = -EINVAL;
10117 goto err_open;
10118 }
10119
Revathi Uddarajud2634032017-12-07 14:42:34 +053010120 in->config.period_size = buffer_size / frame_size;
Aalique Grahame22e49102018-12-18 14:23:57 -080010121 in->af_period_multiplier = 1;
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010122
Revathi Uddarajud2634032017-12-07 14:42:34 +053010123 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
10124 /* optionally use VOIP usecase depending on config(s) */
10125 ret = adev_update_voice_comm_input_stream(in, config);
10126 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010127
Revathi Uddarajud2634032017-12-07 14:42:34 +053010128 if (ret) {
10129 ALOGE("%s AUDIO_SOURCE_VOICE_COMMUNICATION invalid args", __func__);
10130 goto err_open;
10131 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010132 }
Jaideep Sharmad305a4a2020-02-27 14:29:04 +053010133
10134 /* assign concurrent capture usecase if record has to caried out from
10135 * actual hardware input source */
10136 if (audio_extn_is_concurrent_capture_enabled() &&
10137 !audio_is_virtual_input_source(in->source)) {
Samyak Jainc37062f2019-04-25 18:41:06 +053010138 /* Acquire lock to avoid two concurrent use cases initialized to
10139 same pcm record use case */
kunleiz28c73e72019-03-27 17:24:04 +080010140
Samyak Jainc37062f2019-04-25 18:41:06 +053010141 if (in->usecase == USECASE_AUDIO_RECORD) {
10142 pthread_mutex_lock(&adev->lock);
10143 if (!(adev->pcm_record_uc_state)) {
10144 ALOGV("%s: using USECASE_AUDIO_RECORD",__func__);
10145 adev->pcm_record_uc_state = 1;
10146 pthread_mutex_unlock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010147 } else if (audio_extn_is_concurrent_pcm_record_enabled()) {
10148 in->usecase = get_record_usecase(adev);
10149 pthread_mutex_unlock(&adev->lock);
Samyak Jainc37062f2019-04-25 18:41:06 +053010150 } else {
10151 pthread_mutex_unlock(&adev->lock);
10152 /* Assign compress record use case for second record */
10153 in->usecase = USECASE_AUDIO_RECORD_COMPRESS2;
10154 in->flags |= AUDIO_INPUT_FLAG_COMPRESS;
10155 ALOGV("%s: overriding usecase with USECASE_AUDIO_RECORD_COMPRESS2 and appending compress flag", __func__);
10156 if (audio_extn_cin_applicable_stream(in)) {
10157 in->sample_rate = config->sample_rate;
Deeraj Soman14230922019-01-30 16:39:30 +053010158 ret = audio_extn_cin_configure_input_stream(in, config);
Samyak Jainc37062f2019-04-25 18:41:06 +053010159 if (ret)
10160 goto err_open;
10161 }
10162 }
10163 }
kunleiz28c73e72019-03-27 17:24:04 +080010164 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010165 }
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +053010166
Ramjee Singh82fd0c12019-08-21 16:31:33 +053010167 if (audio_extn_ssr_get_stream() != in)
10168 in->config.channels = channel_count;
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -070010169
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -070010170 in->sample_rate = in->config.rate;
10171
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010172 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
10173 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010174 &in->device_list, flags, in->format,
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010175 in->sample_rate, in->bit_width,
10176 in->profile, &in->app_type_cfg);
Naresh Tanniru04f71882018-06-26 17:46:22 +053010177 register_format(in->format, in->supported_formats);
10178 register_channel_mask(in->channel_mask, in->supported_channel_masks);
10179 register_sample_rate(in->sample_rate, in->supported_sample_rates);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010180
Dechen Chai22768452021-07-30 09:29:16 +053010181#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -080010182 in->error_log = error_log_create(
10183 ERROR_LOG_ENTRIES,
10184 1000000000 /* aggregate consecutive identical errors within one second */);
Dechen Chai22768452021-07-30 09:29:16 +053010185#endif
Aalique Grahame22e49102018-12-18 14:23:57 -080010186
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010187 /* This stream could be for sound trigger lab,
10188 get sound trigger pcm if present */
10189 audio_extn_sound_trigger_check_and_get_session(in);
10190
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010191 lock_input_stream(in);
10192 audio_extn_snd_mon_register_listener(in, in_snd_mon_cb);
10193 pthread_mutex_lock(&adev->lock);
10194 in->card_status = adev->card_status;
10195 pthread_mutex_unlock(&adev->lock);
10196 pthread_mutex_unlock(&in->lock);
10197
Aalique Grahame22e49102018-12-18 14:23:57 -080010198 stream_app_type_cfg_init(&in->app_type_cfg);
10199
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010200 *stream_in = &in->stream;
Derek Chenf939fb72018-11-13 13:34:41 -080010201
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010202 ret = io_streams_map_insert(adev, &in->stream.common,
10203 handle, AUDIO_PATCH_HANDLE_NONE);
10204 if (ret != 0)
10205 goto err_open;
10206
Susan Wang6dd13092021-01-25 10:27:11 -050010207 in->in_ctxt.input = in;
Derek Chenf939fb72018-11-13 13:34:41 -080010208
10209 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -050010210 list_add_tail(&adev->active_inputs_list, &in->in_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -080010211 pthread_mutex_unlock(&adev->lock);
10212
Eric Laurent994a6932013-07-17 11:51:42 -070010213 ALOGV("%s: exit", __func__);
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -080010214 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010215
10216err_open:
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010217 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
10218 free_record_usecase(adev, in->usecase);
10219 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jainc37062f2019-04-25 18:41:06 +053010220 pthread_mutex_lock(&adev->lock);
10221 adev->pcm_record_uc_state = 0;
10222 pthread_mutex_unlock(&adev->lock);
10223 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010224 free(in);
10225 *stream_in = NULL;
10226 return ret;
10227}
10228
10229static void adev_close_input_stream(struct audio_hw_device *dev,
10230 struct audio_stream_in *stream)
10231{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010232 int ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010233 struct stream_in *in = (struct stream_in *)stream;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010234 struct audio_device *adev = (struct audio_device *)dev;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010235
Sidipotu Ashokf43018c2014-05-02 16:21:50 +053010236 ALOGD("%s: enter:stream_handle(%p)",__func__, in);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080010237
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010238 if (in == NULL) {
10239 ALOGE("%s: audio_stream_in ptr is NULL", __func__);
10240 return;
10241 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010242 io_streams_map_remove(adev, in->capture_handle);
10243
Susan Wang6dd13092021-01-25 10:27:11 -050010244 // remove out_ctxt early to prevent the stream
10245 // being opened in a race condition
10246 pthread_mutex_lock(&adev->lock);
10247 list_remove(&in->in_ctxt.list);
10248 pthread_mutex_unlock(&adev->lock);
10249
kunleiz70e57612018-12-28 17:50:23 +080010250 /* must deregister from sndmonitor first to prevent races
10251 * between the callback and close_stream
10252 */
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010253 audio_extn_snd_mon_unregister_listener(stream);
10254
kunleiz70e57612018-12-28 17:50:23 +080010255 /* Disable echo reference if there are no active input, hfp call
10256 * and sound trigger while closing input stream
10257 */
Eric Laurent637e2d42018-11-15 12:24:31 -080010258 if (adev_get_active_input(adev) == NULL &&
kunleiz70e57612018-12-28 17:50:23 +080010259 !audio_extn_hfp_is_active(adev) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010260 !audio_extn_sound_trigger_check_ec_ref_enable()) {
10261 struct listnode out_devices;
10262 list_init(&out_devices);
10263 platform_set_echo_reference(adev, false, &out_devices);
Zhenlin Lian4f947842022-05-14 15:50:52 +053010264 clear_devices(&out_devices);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010265 } else
kunleiz70e57612018-12-28 17:50:23 +080010266 audio_extn_sound_trigger_update_ec_ref_status(false);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +053010267
Dechen Chai22768452021-07-30 09:29:16 +053010268#ifndef LINUX_ENABLED
Weiyin Jiang2995f662019-04-17 14:25:12 +080010269 error_log_destroy(in->error_log);
10270 in->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +053010271#endif
Pallavid7c7a272018-01-16 11:22:55 +053010272
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010273 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010274 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010275 ret = voice_extn_compress_voip_close_input_stream(&stream->common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010276 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010277 if (ret != 0)
10278 ALOGE("%s: Compress voip input cannot be closed, error:%d",
10279 __func__, ret);
10280 } else
10281 in_standby(&stream->common);
10282
Weiyin Jiang280ea742020-09-08 20:28:22 +080010283 pthread_mutex_destroy(&in->lock);
10284 pthread_mutex_destroy(&in->pre_lock);
10285
Revathi Uddarajud2634032017-12-07 14:42:34 +053010286 pthread_mutex_lock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010287 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
10288 free_record_usecase(adev, in->usecase);
10289 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jain15fda662018-12-18 16:40:52 +053010290 adev->pcm_record_uc_state = 0;
10291 }
10292
Kunlei Zhang5d5d8d92020-02-26 15:00:59 +080010293 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
10294 adev->enable_voicerx = false;
10295 }
10296
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070010297 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010298 audio_extn_ssr_deinit();
10299 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010300
Garmond Leunge2433c32017-09-28 21:51:22 -070010301 if (audio_extn_ffv_get_stream() == in) {
10302 audio_extn_ffv_stream_deinit();
10303 }
10304
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010305 if (audio_extn_compr_cap_enabled() &&
Mingming Yine62d7842013-10-25 16:26:03 -070010306 audio_extn_compr_cap_format_supported(in->config.format))
10307 audio_extn_compr_cap_deinit();
Dhanalakshmi Siddani74cf00b2016-12-02 13:55:57 +053010308
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +053010309 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +053010310 audio_extn_cin_free_input_stream_resources(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010311
Mingming Yinfd7607b2016-01-22 12:48:44 -080010312 if (in->is_st_session) {
10313 ALOGV("%s: sound trigger pcm stop lab", __func__);
10314 audio_extn_sound_trigger_stop_lab(in);
10315 }
Zhenlin Lian4f947842022-05-14 15:50:52 +053010316 clear_devices(&in->device_list);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010317 free(stream);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010318 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010319 return;
10320}
10321
Aalique Grahame22e49102018-12-18 14:23:57 -080010322/* verifies input and output devices and their capabilities.
10323 *
10324 * This verification is required when enabling extended bit-depth or
10325 * sampling rates, as not all qcom products support it.
10326 *
10327 * Suitable for calling only on initialization such as adev_open().
10328 * It fills the audio_device use_case_table[] array.
10329 *
10330 * Has a side-effect that it needs to configure audio routing / devices
10331 * in order to power up the devices and read the device parameters.
10332 * It does not acquire any hw device lock. Should restore the devices
10333 * back to "normal state" upon completion.
10334 */
10335static int adev_verify_devices(struct audio_device *adev)
10336{
10337 /* enumeration is a bit difficult because one really wants to pull
10338 * the use_case, device id, etc from the hidden pcm_device_table[].
10339 * In this case there are the following use cases and device ids.
10340 *
10341 * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
10342 * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
10343 * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
10344 * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
10345 * [USECASE_AUDIO_RECORD] = {0, 0},
10346 * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
10347 * [USECASE_VOICE_CALL] = {2, 2},
10348 *
10349 * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
10350 * USECASE_VOICE_CALL omitted, but possible for either input or output.
10351 */
10352
10353 /* should be the usecases enabled in adev_open_input_stream() */
10354 static const int test_in_usecases[] = {
10355 USECASE_AUDIO_RECORD,
10356 USECASE_AUDIO_RECORD_LOW_LATENCY, /* does not appear to be used */
10357 };
10358 /* should be the usecases enabled in adev_open_output_stream()*/
10359 static const int test_out_usecases[] = {
10360 USECASE_AUDIO_PLAYBACK_DEEP_BUFFER,
10361 USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
10362 };
10363 static const usecase_type_t usecase_type_by_dir[] = {
10364 PCM_PLAYBACK,
10365 PCM_CAPTURE,
10366 };
10367 static const unsigned flags_by_dir[] = {
10368 PCM_OUT,
10369 PCM_IN,
10370 };
10371
10372 size_t i;
10373 unsigned dir;
10374 const unsigned card_id = adev->snd_card;
10375
10376 for (dir = 0; dir < 2; ++dir) {
10377 const usecase_type_t usecase_type = usecase_type_by_dir[dir];
10378 const unsigned flags_dir = flags_by_dir[dir];
10379 const size_t testsize =
10380 dir ? ARRAY_SIZE(test_in_usecases) : ARRAY_SIZE(test_out_usecases);
10381 const int *testcases =
10382 dir ? test_in_usecases : test_out_usecases;
10383 const audio_devices_t audio_device =
10384 dir ? AUDIO_DEVICE_IN_BUILTIN_MIC : AUDIO_DEVICE_OUT_SPEAKER;
10385
10386 for (i = 0; i < testsize; ++i) {
10387 const audio_usecase_t audio_usecase = testcases[i];
10388 int device_id;
10389 struct pcm_params **pparams;
10390 struct stream_out out;
10391 struct stream_in in;
10392 struct audio_usecase uc_info;
10393 int retval;
10394
10395 pparams = &adev->use_case_table[audio_usecase];
10396 pcm_params_free(*pparams); /* can accept null input */
10397 *pparams = NULL;
10398
10399 /* find the device ID for the use case (signed, for error) */
10400 device_id = platform_get_pcm_device_id(audio_usecase, usecase_type);
10401 if (device_id < 0)
10402 continue;
10403
10404 /* prepare structures for device probing */
10405 memset(&uc_info, 0, sizeof(uc_info));
10406 uc_info.id = audio_usecase;
10407 uc_info.type = usecase_type;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010408 list_init(&uc_info.device_list);
Aalique Grahame22e49102018-12-18 14:23:57 -080010409 if (dir) {
Aalique Grahame22e49102018-12-18 14:23:57 -080010410 memset(&in, 0, sizeof(in));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010411 list_init(&in.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010412 update_device_list(&in.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010413 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
10414 uc_info.stream.in = &in;
Aalique Grahame22e49102018-12-18 14:23:57 -080010415 }
10416 memset(&out, 0, sizeof(out));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010417 list_init(&out.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010418 update_device_list(&out.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010419 uc_info.stream.out = &out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010420 update_device_list(&uc_info.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010421 uc_info.in_snd_device = SND_DEVICE_NONE;
10422 uc_info.out_snd_device = SND_DEVICE_NONE;
10423 list_add_tail(&adev->usecase_list, &uc_info.list);
10424
10425 /* select device - similar to start_(in/out)put_stream() */
10426 retval = select_devices(adev, audio_usecase);
10427 if (retval >= 0) {
10428 *pparams = pcm_params_get(card_id, device_id, flags_dir);
10429#if LOG_NDEBUG == 0
Aalique Grahame203bee02019-03-13 17:49:36 -070010430 char info[512]; /* for possible debug info */
Aalique Grahame22e49102018-12-18 14:23:57 -080010431 if (*pparams) {
10432 ALOGV("%s: (%s) card %d device %d", __func__,
10433 dir ? "input" : "output", card_id, device_id);
10434 pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
10435 } else {
10436 ALOGV("%s: cannot locate card %d device %d", __func__, card_id, device_id);
10437 }
10438#endif
10439 }
10440
10441 /* deselect device - similar to stop_(in/out)put_stream() */
10442 /* 1. Get and set stream specific mixer controls */
10443 retval = disable_audio_route(adev, &uc_info);
10444 /* 2. Disable the rx device */
10445 retval = disable_snd_device(adev,
10446 dir ? uc_info.in_snd_device : uc_info.out_snd_device);
10447 list_remove(&uc_info.list);
10448 }
10449 }
Aalique Grahame22e49102018-12-18 14:23:57 -080010450 return 0;
10451}
10452
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010453int update_patch(unsigned int num_sources,
10454 const struct audio_port_config *sources,
10455 unsigned int num_sinks,
10456 const struct audio_port_config *sinks,
10457 audio_patch_handle_t handle,
10458 struct audio_patch_info *p_info,
10459 patch_type_t patch_type, bool new_patch)
10460{
Aniket Kumar Latad13758f2020-08-06 15:11:36 -070010461 ALOGV("%s: enter", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010462
10463 if (p_info == NULL) {
10464 ALOGE("%s: Invalid patch pointer", __func__);
10465 return -EINVAL;
10466 }
10467
10468 if (new_patch) {
10469 p_info->patch = (struct audio_patch *) calloc(1, sizeof(struct audio_patch));
10470 if (p_info->patch == NULL) {
10471 ALOGE("%s: Could not allocate patch", __func__);
10472 return -ENOMEM;
10473 }
10474 }
10475
10476 p_info->patch->id = handle;
10477 p_info->patch->num_sources = num_sources;
10478 p_info->patch->num_sinks = num_sinks;
10479
10480 for (int i = 0; i < num_sources; i++)
10481 p_info->patch->sources[i] = sources[i];
10482 for (int i = 0; i < num_sinks; i++)
10483 p_info->patch->sinks[i] = sinks[i];
10484
10485 p_info->patch_type = patch_type;
10486 return 0;
10487}
10488
10489audio_patch_handle_t generate_patch_handle()
10490{
10491 static audio_patch_handle_t patch_handle = AUDIO_PATCH_HANDLE_NONE;
10492 if (++patch_handle < 0)
10493 patch_handle = AUDIO_PATCH_HANDLE_NONE + 1;
10494 return patch_handle;
10495}
10496
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010497int adev_create_audio_patch(struct audio_hw_device *dev,
10498 unsigned int num_sources,
10499 const struct audio_port_config *sources,
10500 unsigned int num_sinks,
10501 const struct audio_port_config *sinks,
10502 audio_patch_handle_t *handle)
10503{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010504 int ret = 0;
10505 struct audio_device *adev = (struct audio_device *)dev;
10506 struct audio_patch_info *p_info = NULL;
10507 patch_type_t patch_type = PATCH_NONE;
10508 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10509 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
10510 struct audio_stream_info *s_info = NULL;
10511 struct audio_stream *stream = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010512 struct listnode devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010513 audio_devices_t device_type = AUDIO_DEVICE_NONE;
10514 bool new_patch = false;
10515 char addr[AUDIO_DEVICE_MAX_ADDRESS_LEN];
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010516
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010517 ALOGD("%s: enter: num sources %d, num_sinks %d, handle %d", __func__,
10518 num_sources, num_sinks, *handle);
10519
10520 if (num_sources == 0 || num_sources > AUDIO_PATCH_PORTS_MAX ||
10521 num_sinks == 0 || num_sinks > AUDIO_PATCH_PORTS_MAX) {
10522 ALOGE("%s: Invalid patch arguments", __func__);
10523 ret = -EINVAL;
10524 goto done;
10525 }
10526
10527 if (num_sources > 1) {
10528 ALOGE("%s: Multiple sources are not supported", __func__);
10529 ret = -EINVAL;
10530 goto done;
10531 }
10532
10533 if (sources == NULL || sinks == NULL) {
10534 ALOGE("%s: Invalid sources or sinks port config", __func__);
10535 ret = -EINVAL;
10536 goto done;
10537 }
10538
10539 ALOGV("%s: source role %d, source type %d", __func__,
10540 sources[0].type, sources[0].role);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010541 list_init(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010542
10543 // Populate source/sink information and fetch stream info
10544 switch (sources[0].type) {
10545 case AUDIO_PORT_TYPE_DEVICE: // Patch for audio capture or loopback
10546 device_type = sources[0].ext.device.type;
10547 strlcpy(&addr[0], &sources[0].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010548 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010549 if (sinks[0].type == AUDIO_PORT_TYPE_MIX) {
10550 patch_type = PATCH_CAPTURE;
10551 io_handle = sinks[0].ext.mix.handle;
10552 input_source = sinks[0].ext.mix.usecase.source;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010553 ALOGD("%s: Capture patch from device %x to mix %d",
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010554 __func__, device_type, io_handle);
10555 } else {
10556 // Device to device patch is not implemented.
10557 // This space will need changes if audio HAL
10558 // handles device to device patches in the future.
10559 patch_type = PATCH_DEVICE_LOOPBACK;
10560 }
10561 break;
10562 case AUDIO_PORT_TYPE_MIX: // Patch for audio playback
10563 io_handle = sources[0].ext.mix.handle;
10564 for (int i = 0; i < num_sinks; i++) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010565 device_type = sinks[i].ext.device.type;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010566 strlcpy(&addr[0], &sinks[i].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010567 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010568 }
10569 patch_type = PATCH_PLAYBACK;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010570 ALOGD("%s: Playback patch from mix handle %d to device %x",
10571 __func__, io_handle, get_device_types(&devices));
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010572 break;
10573 case AUDIO_PORT_TYPE_SESSION:
10574 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010575 ALOGE("%s: Unsupported source type %d", __func__, sources[0].type);
10576 ret = -EINVAL;
10577 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010578 }
10579
10580 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010581
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010582 // Generate patch info and update patch
10583 if (*handle == AUDIO_PATCH_HANDLE_NONE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010584 *handle = generate_patch_handle();
10585 p_info = (struct audio_patch_info *)
10586 calloc(1, sizeof(struct audio_patch_info));
10587 if (p_info == NULL) {
10588 ALOGE("%s: Failed to allocate memory", __func__);
10589 pthread_mutex_unlock(&adev->lock);
10590 ret = -ENOMEM;
10591 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010592 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010593 new_patch = true;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010594 } else {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010595 p_info = fetch_patch_info_l(adev, *handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010596 if (p_info == NULL) {
10597 ALOGE("%s: Unable to fetch patch for received patch handle %d",
10598 __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010599 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010600 ret = -EINVAL;
10601 goto done;
10602 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010603 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010604 update_patch(num_sources, sources, num_sinks, sinks,
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010605 *handle, p_info, patch_type, new_patch);
10606
10607 // Fetch stream info of associated mix for playback or capture patches
10608 if (p_info->patch_type == PATCH_PLAYBACK ||
10609 p_info->patch_type == PATCH_CAPTURE) {
10610 s_info = hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10611 if (s_info == NULL) {
10612 ALOGE("%s: Failed to obtain stream info", __func__);
10613 if (new_patch)
10614 free(p_info);
10615 pthread_mutex_unlock(&adev->lock);
10616 ret = -EINVAL;
10617 goto done;
10618 }
10619 ALOGV("%s: Fetched stream info with io_handle %d", __func__, io_handle);
10620 s_info->patch_handle = *handle;
10621 stream = s_info->stream;
10622 }
10623 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010624
10625 // Update routing for stream
10626 if (stream != NULL) {
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010627 if (p_info->patch_type == PATCH_PLAYBACK) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010628 ret = route_output_stream((struct stream_out *) stream, &devices);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010629 } else if (p_info->patch_type == PATCH_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010630 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010631 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010632 if (ret < 0) {
10633 pthread_mutex_lock(&adev->lock);
10634 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10635 if (new_patch)
10636 free(p_info);
10637 pthread_mutex_unlock(&adev->lock);
10638 ALOGE("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10639 goto done;
10640 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010641 }
10642
10643 // Add new patch to patch map
10644 if (!ret && new_patch) {
10645 pthread_mutex_lock(&adev->lock);
10646 hashmapPut(adev->patch_map, (void *) (intptr_t) *handle, (void *) p_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010647 ALOGD("%s: Added a new patch with handle %d", __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010648 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010649 }
10650
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010651done:
Zhenlin Lian4f947842022-05-14 15:50:52 +053010652 clear_devices(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010653 audio_extn_hw_loopback_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010654 num_sources,
10655 sources,
10656 num_sinks,
10657 sinks,
10658 handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010659 audio_extn_auto_hal_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010660 num_sources,
10661 sources,
10662 num_sinks,
10663 sinks,
10664 handle);
10665 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010666}
10667
10668int adev_release_audio_patch(struct audio_hw_device *dev,
10669 audio_patch_handle_t handle)
10670{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010671 struct audio_device *adev = (struct audio_device *) dev;
10672 int ret = 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010673 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010674 struct audio_stream *stream = NULL;
Derek Chenf939fb72018-11-13 13:34:41 -080010675
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010676 if (handle == AUDIO_PATCH_HANDLE_NONE) {
10677 ALOGE("%s: Invalid patch handle %d", __func__, handle);
10678 ret = -EINVAL;
10679 goto done;
10680 }
10681
10682 ALOGD("%s: Remove patch with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010683 pthread_mutex_lock(&adev->lock);
10684 struct audio_patch_info *p_info = fetch_patch_info_l(adev, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010685 if (p_info == NULL) {
10686 ALOGE("%s: Patch info not found with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010687 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010688 ret = -EINVAL;
10689 goto done;
10690 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010691 struct audio_patch *patch = p_info->patch;
10692 if (patch == NULL) {
10693 ALOGE("%s: Patch not found for handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010694 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010695 ret = -EINVAL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010696 goto done;
10697 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010698 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10699 switch (patch->sources[0].type) {
10700 case AUDIO_PORT_TYPE_MIX:
10701 io_handle = patch->sources[0].ext.mix.handle;
10702 break;
10703 case AUDIO_PORT_TYPE_DEVICE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010704 if (p_info->patch_type == PATCH_CAPTURE)
10705 io_handle = patch->sinks[0].ext.mix.handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010706 break;
10707 case AUDIO_PORT_TYPE_SESSION:
10708 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010709 pthread_mutex_unlock(&adev->lock);
10710 ret = -EINVAL;
10711 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010712 }
10713
10714 // Remove patch and reset patch handle in stream info
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010715 patch_type_t patch_type = p_info->patch_type;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010716 patch_map_remove_l(adev, handle);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010717 if (patch_type == PATCH_PLAYBACK ||
10718 patch_type == PATCH_CAPTURE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010719 struct audio_stream_info *s_info =
10720 hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10721 if (s_info == NULL) {
10722 ALOGE("%s: stream for io_handle %d is not available", __func__, io_handle);
10723 pthread_mutex_unlock(&adev->lock);
10724 goto done;
10725 }
10726 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10727 stream = s_info->stream;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010728 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010729 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010730
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010731 if (stream != NULL) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010732 struct listnode devices;
10733 list_init(&devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010734 if (patch_type == PATCH_PLAYBACK)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010735 ret = route_output_stream((struct stream_out *) stream, &devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010736 else if (patch_type == PATCH_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010737 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Zhenlin Lian4f947842022-05-14 15:50:52 +053010738 clear_devices(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010739 }
10740
10741 if (ret < 0)
10742 ALOGW("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10743
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010744done:
10745 audio_extn_hw_loopback_release_audio_patch(dev, handle);
10746 audio_extn_auto_hal_release_audio_patch(dev, handle);
10747
10748 ALOGV("%s: Successfully released patch %d", __func__, handle);
Derek Chenf939fb72018-11-13 13:34:41 -080010749 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010750}
10751
10752int adev_get_audio_port(struct audio_hw_device *dev, struct audio_port *config)
10753{
Derek Chenf13dd492018-11-13 14:53:51 -080010754 int ret = 0;
10755
10756 ret = audio_extn_hw_loopback_get_audio_port(dev, config);
10757 ret |= audio_extn_auto_hal_get_audio_port(dev, config);
10758 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010759}
10760
10761int adev_set_audio_port_config(struct audio_hw_device *dev,
10762 const struct audio_port_config *config)
10763{
Derek Chenf13dd492018-11-13 14:53:51 -080010764 int ret = 0;
10765
10766 ret = audio_extn_hw_loopback_set_audio_port_config(dev, config);
10767 ret |= audio_extn_auto_hal_set_audio_port_config(dev, config);
10768 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010769}
10770
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010771static int adev_dump(const audio_hw_device_t *device __unused,
10772 int fd __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010773{
10774 return 0;
10775}
10776
10777static int adev_close(hw_device_t *device)
10778{
Aalique Grahame22e49102018-12-18 14:23:57 -080010779 size_t i;
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010780 struct audio_device *adev_temp = (struct audio_device *)device;
Kiran Kandi910e1862013-10-29 13:29:42 -070010781
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010782 if (!adev_temp)
Kiran Kandi910e1862013-10-29 13:29:42 -070010783 return 0;
10784
10785 pthread_mutex_lock(&adev_init_lock);
10786
10787 if ((--audio_device_ref_count) == 0) {
Sujin Panicker390724d2019-04-26 10:43:36 +053010788 if (audio_extn_spkr_prot_is_enabled())
10789 audio_extn_spkr_prot_deinit();
Jaideep Sharmaa2b49672019-09-10 20:37:03 +053010790 audio_extn_battery_properties_listener_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010791 audio_extn_snd_mon_unregister_listener(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010792 audio_extn_sound_trigger_deinit(adev);
Kiran Kandide144c82013-11-20 15:58:32 -080010793 audio_extn_listen_deinit(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010794 audio_extn_qdsp_deinit();
Aalique Grahame22e49102018-12-18 14:23:57 -080010795 audio_extn_extspk_deinit(adev->extspk);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010796 audio_extn_utils_release_streams_cfg_lists(
10797 &adev->streams_output_cfg_list,
10798 &adev->streams_input_cfg_list);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010799 if (audio_extn_qap_is_enabled())
10800 audio_extn_qap_deinit();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010801 if (audio_extn_qaf_is_enabled())
10802 audio_extn_qaf_deinit();
Kiran Kandi910e1862013-10-29 13:29:42 -070010803 audio_route_free(adev->audio_route);
Weiyin Jiangfa65d3e2019-03-05 23:39:45 +080010804 audio_extn_gef_deinit(adev);
Kiran Kandi910e1862013-10-29 13:29:42 -070010805 free(adev->snd_dev_ref_cnt);
10806 platform_deinit(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080010807 for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
10808 pcm_params_free(adev->use_case_table[i]);
10809 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010810 if (adev->adm_deinit)
10811 adev->adm_deinit(adev->adm_data);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010812 qahwi_deinit(device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080010813 audio_extn_adsp_hdlr_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010814 audio_extn_snd_mon_deinit();
Siddartha Shaik44dd7702017-06-14 12:13:25 +053010815 audio_extn_hw_loopback_deinit(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070010816 audio_extn_ffv_deinit();
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053010817 if (adev->device_cfg_params) {
10818 free(adev->device_cfg_params);
10819 adev->device_cfg_params = NULL;
10820 }
Derek Chend2530072014-11-24 12:39:14 -080010821 if(adev->ext_hw_plugin)
10822 audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
Derek Chenae7b0342019-02-08 15:17:04 -080010823 audio_extn_auto_hal_deinit();
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010824 free_map(adev->patch_map);
10825 free_map(adev->io_streams_map);
Kiran Kandi910e1862013-10-29 13:29:42 -070010826 free(device);
10827 adev = NULL;
10828 }
10829 pthread_mutex_unlock(&adev_init_lock);
Vatsal Buchac09ae062018-11-14 13:25:08 +053010830 enable_gcov();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010831 return 0;
10832}
10833
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010834/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
10835 * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
10836 * just that it _might_ work.
10837 */
10838static int period_size_is_plausible_for_low_latency(int period_size)
10839{
10840 switch (period_size) {
10841 case 160:
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -070010842 case 192:
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010843 case 240:
10844 case 320:
10845 case 480:
10846 return 1;
10847 default:
10848 return 0;
10849 }
10850}
10851
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010852static void adev_snd_mon_cb(void *cookie, struct str_parms *parms)
10853{
10854 bool is_snd_card_status = false;
10855 bool is_ext_device_status = false;
10856 char value[32];
10857 int card = -1;
10858 card_status_t status;
10859
10860 if (cookie != adev || !parms)
10861 return;
10862
10863 if (!parse_snd_card_status(parms, &card, &status)) {
10864 is_snd_card_status = true;
10865 } else if (0 < str_parms_get_str(parms, "ext_audio_device", value, sizeof(value))) {
10866 is_ext_device_status = true;
10867 } else {
10868 // not a valid event
10869 return;
10870 }
10871
10872 pthread_mutex_lock(&adev->lock);
10873 if (card == adev->snd_card || is_ext_device_status) {
10874 if (is_snd_card_status && adev->card_status != status) {
Jaideep Sharmacb402512020-09-24 17:51:07 +053010875 ALOGD("%s card_status %d", __func__, status);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010876 adev->card_status = status;
10877 platform_snd_card_update(adev->platform, status);
10878 audio_extn_fm_set_parameters(adev, parms);
Derek Chend6f371d2019-03-01 13:45:58 -080010879 audio_extn_auto_hal_set_parameters(adev, parms);
Zhou Song4f43e352019-07-02 00:32:23 +080010880 if (status == CARD_STATUS_OFFLINE)
10881 audio_extn_sco_reset_configuration();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010882 } else if (is_ext_device_status) {
10883 platform_set_parameters(adev->platform, parms);
10884 }
10885 }
10886 pthread_mutex_unlock(&adev->lock);
10887 return;
10888}
10889
Weiyin Jiang280ea742020-09-08 20:28:22 +080010890/* adev lock held */
10891int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010892{
10893 struct audio_usecase *uc_info;
Zhou Song407e5aa2020-12-27 19:13:04 +080010894 struct audio_usecase *usecase;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010895 struct listnode devices;
Zhou Song407e5aa2020-12-27 19:13:04 +080010896 struct listnode *node;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010897
10898 uc_info = get_usecase_from_list(adev, out->usecase);
10899 if (uc_info == NULL) {
10900 ALOGE("%s: Could not find the usecase (%d) in the list",
10901 __func__, out->usecase);
10902 return -EINVAL;
10903 }
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010904 list_init(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010905
Zhou Songbaddf9f2020-11-20 13:57:39 +080010906 ALOGD("%s: enter: usecase(%d: %s), a2dp muted %d", __func__,
10907 out->usecase, use_case_table[out->usecase], out->a2dp_muted);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010908
10909 if (restore) {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010910 pthread_mutex_lock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010911 // restore A2DP device for active usecases and unmute if required
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010912 if (is_a2dp_out_device_type(&out->device_list)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010913 ALOGD("%s: restoring A2dp and unmuting stream", __func__);
Zhou Songe5225132019-09-26 15:33:36 +080010914 if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
10915 select_devices(adev, uc_info->id);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010916
10917 if (is_offload_usecase(out->usecase)) {
10918 if (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)
Weiyin Jiang280ea742020-09-08 20:28:22 +080010919 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010920 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
10921 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
10922 } else {
10923 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010924 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010925 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010926 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010927 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010928 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010929 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010930 // mute stream and switch to speaker if suspended
10931 if (!out->a2dp_muted && !out->standby) {
Zhou Songbaddf9f2020-11-20 13:57:39 +080010932 assign_devices(&devices, &out->device_list);
10933 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Zhou Song407e5aa2020-12-27 19:13:04 +080010934 list_for_each(node, &adev->usecase_list) {
10935 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Songe63b6fe2021-04-15 13:54:46 +080010936 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
10937 !is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songcf77af02021-05-14 18:21:14 +080010938 !is_sco_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songe63b6fe2021-04-15 13:54:46 +080010939 platform_check_backends_match(SND_DEVICE_OUT_SPEAKER,
10940 usecase->out_snd_device)) {
Zhou Song407e5aa2020-12-27 19:13:04 +080010941 assign_devices(&out->device_list, &usecase->stream.out->device_list);
10942 break;
10943 }
10944 }
Zhou Songcf77af02021-05-14 18:21:14 +080010945 if ((is_a2dp_out_device_type(&devices) && list_length(&devices) == 1) ||
10946 (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
Zhou Song8edbbdb2021-01-14 16:48:03 +080010947 out->a2dp_muted = true;
10948 if (is_offload_usecase(out->usecase)) {
10949 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10950 compress_pause(out->compr);
10951 out_set_compr_volume(&out->stream, (float)0, (float)0);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010952 } else {
Weiyin Jiang906db3c2021-03-02 13:17:04 +080010953 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
10954 out_set_voip_volume(&out->stream, (float)0, (float)0);
10955 else
10956 out_set_pcm_volume(&out->stream, (float)0, (float)0);
10957
Zhou Song8edbbdb2021-01-14 16:48:03 +080010958 /* wait for stale pcm drained before switching to speaker */
10959 uint32_t latency =
10960 (out->config.period_count * out->config.period_size * 1000) /
10961 (out->config.rate);
10962 usleep(latency * 1000);
10963 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010964 }
10965 select_devices(adev, out->usecase);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010966 ALOGD("%s: switched to device:%s and stream muted:%d", __func__,
10967 platform_get_snd_device_name(uc_info->out_snd_device), out->a2dp_muted);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010968 if (is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010969 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10970 compress_resume(out->compr);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010971 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010972 assign_devices(&out->device_list, &devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010973 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010974 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010975 }
Zhenlin Lian4f947842022-05-14 15:50:52 +053010976 clear_devices(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010977 ALOGV("%s: exit", __func__);
10978 return 0;
10979}
10980
Haynes Mathew George01156f92018-04-13 15:29:54 -070010981void adev_on_battery_status_changed(bool charging)
10982{
10983 pthread_mutex_lock(&adev->lock);
10984 ALOGI("%s: battery status changed to %scharging", __func__, charging ? "" : "not ");
10985 adev->is_charging = charging;
Zhou Songc1088ea2018-06-12 00:17:29 +080010986 audio_extn_sound_trigger_update_battery_status(charging);
Haynes Mathew George01156f92018-04-13 15:29:54 -070010987 pthread_mutex_unlock(&adev->lock);
10988}
10989
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010990static int adev_open(const hw_module_t *module, const char *name,
10991 hw_device_t **device)
10992{
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010993 int ret;
Derek Chenf939fb72018-11-13 13:34:41 -080010994 char value[PROPERTY_VALUE_MAX] = {0};
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053010995 char mixer_ctl_name[128] = {0};
10996 struct mixer_ctl *ctl = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010997
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080010998 ALOGD("%s: enter", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010999 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
11000
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011001 pthread_mutex_lock(&adev_init_lock);
Kiran Kandi910e1862013-10-29 13:29:42 -070011002 if (audio_device_ref_count != 0){
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011003 *device = &adev->device.common;
Kiran Kandi910e1862013-10-29 13:29:42 -070011004 audio_device_ref_count++;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011005 ALOGD("%s: returning existing instance of adev", __func__);
11006 ALOGD("%s: exit", __func__);
11007 pthread_mutex_unlock(&adev_init_lock);
11008 return 0;
11009 }
11010
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011011 adev = calloc(1, sizeof(struct audio_device));
11012
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -070011013 if (!adev) {
11014 pthread_mutex_unlock(&adev_init_lock);
11015 return -ENOMEM;
11016 }
11017
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -070011018 pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
11019
Weiyin Jiange6ce6312019-01-28 18:28:22 +080011020 // register audio ext hidl at the earliest
11021 audio_extn_hidl_init();
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053011022#ifdef DYNAMIC_LOG_ENABLED
11023 register_for_dynamic_logging("hal");
11024#endif
11025
Derek Chenf939fb72018-11-13 13:34:41 -080011026 /* default audio HAL major version */
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011027 uint32_t maj_version = 3;
Derek Chenf939fb72018-11-13 13:34:41 -080011028 if(property_get("vendor.audio.hal.maj.version", value, NULL))
11029 maj_version = atoi(value);
11030
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011031 adev->device.common.tag = HARDWARE_DEVICE_TAG;
Derek Chenf939fb72018-11-13 13:34:41 -080011032 adev->device.common.version = HARDWARE_DEVICE_API_VERSION(maj_version, 0);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011033 adev->device.common.module = (struct hw_module_t *)module;
11034 adev->device.common.close = adev_close;
11035
11036 adev->device.init_check = adev_init_check;
11037 adev->device.set_voice_volume = adev_set_voice_volume;
11038 adev->device.set_master_volume = adev_set_master_volume;
11039 adev->device.get_master_volume = adev_get_master_volume;
11040 adev->device.set_master_mute = adev_set_master_mute;
11041 adev->device.get_master_mute = adev_get_master_mute;
11042 adev->device.set_mode = adev_set_mode;
11043 adev->device.set_mic_mute = adev_set_mic_mute;
11044 adev->device.get_mic_mute = adev_get_mic_mute;
11045 adev->device.set_parameters = adev_set_parameters;
11046 adev->device.get_parameters = adev_get_parameters;
11047 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
11048 adev->device.open_output_stream = adev_open_output_stream;
11049 adev->device.close_output_stream = adev_close_output_stream;
11050 adev->device.open_input_stream = adev_open_input_stream;
11051 adev->device.close_input_stream = adev_close_input_stream;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053011052 adev->device.create_audio_patch = adev_create_audio_patch;
11053 adev->device.release_audio_patch = adev_release_audio_patch;
11054 adev->device.get_audio_port = adev_get_audio_port;
11055 adev->device.set_audio_port_config = adev_set_audio_port_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011056 adev->device.dump = adev_dump;
Naresh Tannirudcb47c52018-06-25 16:23:32 +053011057 adev->device.get_microphones = adev_get_microphones;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011058
11059 /* Set the default route before the PCM stream is opened */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011060 adev->mode = AUDIO_MODE_NORMAL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -080011061 adev->primary_output = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011062 adev->out_device = AUDIO_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011063 adev->bluetooth_nrec = true;
Ravi Kumar Alamandaf9967042013-02-14 19:35:14 -080011064 adev->acdb_settings = TTY_MODE_OFF;
vivek mehta344576a2016-04-12 18:56:03 -070011065 adev->allow_afe_proxy_usage = true;
Ashish Jain1b9b30c2017-05-18 20:57:40 +053011066 adev->bt_sco_on = false;
Eric Laurent07eeafd2013-10-06 12:52:49 -070011067 /* adev->cur_hdmi_channels = 0; by calloc() */
Eric Laurentb23d5282013-05-14 15:27:20 -070011068 adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
vivek mehtaae1018c2019-05-09 12:19:57 -070011069 /* Init audio and voice feature */
11070 audio_extn_feature_init();
11071 voice_extn_feature_init();
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070011072 voice_init(adev);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -080011073 list_init(&adev->usecase_list);
Derek Chenf939fb72018-11-13 13:34:41 -080011074 list_init(&adev->active_inputs_list);
11075 list_init(&adev->active_outputs_list);
Rahul Sharma99770982019-03-06 17:05:26 +053011076 list_init(&adev->audio_patch_record_list);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011077 adev->io_streams_map = hashmapCreate(AUDIO_IO_PORTS_MAX, audio_extn_utils_hash_fn,
11078 audio_extn_utils_hash_eq);
11079 if (!adev->io_streams_map) {
11080 ALOGE("%s: Could not create io streams map", __func__);
11081 ret = -ENOMEM;
11082 goto adev_open_err;
11083 }
11084 adev->patch_map = hashmapCreate(AUDIO_PATCH_PORTS_MAX, audio_extn_utils_hash_fn,
11085 audio_extn_utils_hash_eq);
11086 if (!adev->patch_map) {
11087 ALOGE("%s: Could not create audio patch map", __func__);
11088 ret = -ENOMEM;
11089 goto adev_open_err;
11090 }
Krishnankutty Kolathappilly0b2de1c2014-02-14 14:45:49 -080011091 adev->cur_wfd_channels = 2;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -070011092 adev->offload_usecases_state = 0;
Samyak Jain15fda662018-12-18 16:40:52 +053011093 adev->pcm_record_uc_state = 0;
Ashish Jain81eb2a82015-05-13 10:52:34 +053011094 adev->is_channel_status_set = false;
Sudheer Papothifa9d2282015-09-17 01:53:25 +053011095 adev->perf_lock_opts[0] = 0x101;
11096 adev->perf_lock_opts[1] = 0x20E;
11097 adev->perf_lock_opts_size = 2;
Xiaojun Sang785b5da2017-08-03 15:52:29 +080011098 adev->dsp_bit_width_enforce_mode = 0;
Aalique Grahame552b0832019-03-11 10:16:38 -070011099 adev->enable_hfp = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011100 adev->use_old_pspd_mix_ctrl = false;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070011101 adev->adm_routing_changed = false;
Revathi Uddarajub26e3932020-06-10 14:51:02 +053011102 adev->a2dp_started = false;
Zhou Song503196b2021-07-23 17:31:05 +080011103 adev->ha_proxy_enable = false;
Naresh Tanniru4c630392014-05-12 01:05:52 +053011104
Zhou Song68ebc352019-12-05 17:11:15 +080011105 audio_extn_perf_lock_init();
11106
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011107 /* Loads platform specific libraries dynamically */
Eric Laurentb23d5282013-05-14 15:27:20 -070011108 adev->platform = platform_init(adev);
11109 if (!adev->platform) {
Eric Laurentb23d5282013-05-14 15:27:20 -070011110 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011111 ret = -EINVAL;
11112 goto adev_open_err;
Eric Laurentb23d5282013-05-14 15:27:20 -070011113 }
Eric Laurentc4aef752013-09-12 17:45:53 -070011114
Aalique Grahame22e49102018-12-18 14:23:57 -080011115 adev->extspk = audio_extn_extspk_init(adev);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011116 if (audio_extn_qap_is_enabled()) {
11117 ret = audio_extn_qap_init(adev);
11118 if (ret < 0) {
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011119 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011120 goto adev_open_err;
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011121 }
11122 adev->device.open_output_stream = audio_extn_qap_open_output_stream;
11123 adev->device.close_output_stream = audio_extn_qap_close_output_stream;
11124 }
Aalique Grahame22e49102018-12-18 14:23:57 -080011125
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011126 if (audio_extn_qaf_is_enabled()) {
11127 ret = audio_extn_qaf_init(adev);
11128 if (ret < 0) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011129 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011130 goto adev_open_err;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011131 }
11132
11133 adev->device.open_output_stream = audio_extn_qaf_open_output_stream;
11134 adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
11135 }
11136
Derek Chenae7b0342019-02-08 15:17:04 -080011137 audio_extn_auto_hal_init(adev);
Derek Chend2530072014-11-24 12:39:14 -080011138 adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);
11139
Eric Laurentc4aef752013-09-12 17:45:53 -070011140 if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
11141 adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
11142 if (adev->visualizer_lib == NULL) {
11143 ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
11144 } else {
11145 ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
11146 adev->visualizer_start_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011147 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070011148 "visualizer_hal_start_output");
11149 adev->visualizer_stop_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011150 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070011151 "visualizer_hal_stop_output");
11152 }
11153 }
Dhanalakshmi Siddani21be3ac2016-12-29 14:31:08 +053011154 audio_extn_init(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080011155 voice_extn_init(adev);
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -080011156 audio_extn_listen_init(adev, adev->snd_card);
Weiyin Jiangaa80acd2016-09-21 16:42:11 +080011157 audio_extn_gef_init(adev);
Siddartha Shaik44dd7702017-06-14 12:13:25 +053011158 audio_extn_hw_loopback_init(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070011159 audio_extn_ffv_init(adev);
Eric Laurentc4aef752013-09-12 17:45:53 -070011160
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011161 if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
11162 adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
11163 if (adev->offload_effects_lib == NULL) {
11164 ALOGE("%s: DLOPEN failed for %s", __func__,
11165 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
11166 } else {
11167 ALOGV("%s: DLOPEN successful for %s", __func__,
11168 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
11169 adev->offload_effects_start_output =
Ashish Jain5106d362016-05-11 19:23:33 +053011170 (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib,
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011171 "offload_effects_bundle_hal_start_output");
11172 adev->offload_effects_stop_output =
11173 (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
11174 "offload_effects_bundle_hal_stop_output");
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080011175 adev->offload_effects_set_hpx_state =
11176 (int (*)(bool))dlsym(adev->offload_effects_lib,
11177 "offload_effects_bundle_set_hpx_state");
Dhananjay Kumard68883d2015-09-04 13:39:26 +053011178 adev->offload_effects_get_parameters =
11179 (void (*)(struct str_parms *, struct str_parms *))
11180 dlsym(adev->offload_effects_lib,
11181 "offload_effects_bundle_get_parameters");
11182 adev->offload_effects_set_parameters =
11183 (void (*)(struct str_parms *))dlsym(adev->offload_effects_lib,
11184 "offload_effects_bundle_set_parameters");
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011185 }
11186 }
11187
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011188 if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
11189 adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
11190 if (adev->adm_lib == NULL) {
11191 ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
11192 } else {
11193 ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
11194 adev->adm_init = (adm_init_t)
11195 dlsym(adev->adm_lib, "adm_init");
11196 adev->adm_deinit = (adm_deinit_t)
11197 dlsym(adev->adm_lib, "adm_deinit");
11198 adev->adm_register_input_stream = (adm_register_input_stream_t)
11199 dlsym(adev->adm_lib, "adm_register_input_stream");
11200 adev->adm_register_output_stream = (adm_register_output_stream_t)
11201 dlsym(adev->adm_lib, "adm_register_output_stream");
11202 adev->adm_deregister_stream = (adm_deregister_stream_t)
11203 dlsym(adev->adm_lib, "adm_deregister_stream");
11204 adev->adm_request_focus = (adm_request_focus_t)
11205 dlsym(adev->adm_lib, "adm_request_focus");
11206 adev->adm_abandon_focus = (adm_abandon_focus_t)
11207 dlsym(adev->adm_lib, "adm_abandon_focus");
Haynes Mathew George5beddd42016-06-27 18:33:40 -070011208 adev->adm_set_config = (adm_set_config_t)
11209 dlsym(adev->adm_lib, "adm_set_config");
11210 adev->adm_request_focus_v2 = (adm_request_focus_v2_t)
11211 dlsym(adev->adm_lib, "adm_request_focus_v2");
11212 adev->adm_is_noirq_avail = (adm_is_noirq_avail_t)
11213 dlsym(adev->adm_lib, "adm_is_noirq_avail");
11214 adev->adm_on_routing_change = (adm_on_routing_change_t)
11215 dlsym(adev->adm_lib, "adm_on_routing_change");
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070011216 adev->adm_request_focus_v2_1 = (adm_request_focus_v2_1_t)
11217 dlsym(adev->adm_lib, "adm_request_focus_v2_1");
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011218 }
11219 }
11220
Aalique Grahame22e49102018-12-18 14:23:57 -080011221 adev->enable_voicerx = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070011222 adev->bt_wb_speech_enabled = false;
Zhou Song12c29502019-03-16 10:37:18 +080011223 adev->swb_speech_mode = SPEECH_MODE_INVALID;
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +080011224 adev->fluence_nn_usecase_id = USECASE_INVALID;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -080011225 //initialize this to false for now,
11226 //this will be set to true through set param
11227 adev->vr_audio_mode_enabled = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070011228
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -070011229 audio_extn_ds2_enable(adev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011230 *device = &adev->device.common;
Aalique Grahame22e49102018-12-18 14:23:57 -080011231
11232 if (k_enable_extended_precision)
11233 adev_verify_devices(adev);
11234
Xiaojun Sang785b5da2017-08-03 15:52:29 +080011235 adev->dsp_bit_width_enforce_mode =
11236 adev_init_dsp_bit_width_enforce_mode(adev->mixer);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011237
Dhananjay Kumard6d32152016-10-13 16:11:03 +053011238 audio_extn_utils_update_streams_cfg_lists(adev->platform, adev->mixer,
11239 &adev->streams_output_cfg_list,
11240 &adev->streams_input_cfg_list);
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -070011241
Kiran Kandi910e1862013-10-29 13:29:42 -070011242 audio_device_ref_count++;
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011243
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011244 int trial;
Manisha Agarwalc75a0202019-12-06 18:48:25 +053011245 if (property_get("vendor.audio_hal.period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011246 trial = atoi(value);
11247 if (period_size_is_plausible_for_low_latency(trial)) {
11248 pcm_config_low_latency.period_size = trial;
11249 pcm_config_low_latency.start_threshold = trial / 4;
11250 pcm_config_low_latency.avail_min = trial / 4;
11251 configured_low_latency_capture_period_size = trial;
11252 }
11253 }
ronghuiz93177262021-04-21 19:58:13 +080011254 if (property_get("vendor.audio_hal.in_period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011255 trial = atoi(value);
11256 if (period_size_is_plausible_for_low_latency(trial)) {
11257 configured_low_latency_capture_period_size = trial;
11258 }
11259 }
11260
Vignesh Kulothungan7d374312018-02-21 17:12:00 -080011261 adev->mic_break_enabled = property_get_bool("vendor.audio.mic_break", false);
11262
Eric Laurent4b084132018-10-19 17:33:43 -070011263 adev->camera_orientation = CAMERA_DEFAULT;
11264
Manisha Agarwalc75a0202019-12-06 18:48:25 +053011265 if (property_get("vendor.audio_hal.period_multiplier",value,NULL) > 0) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -070011266 af_period_multiplier = atoi(value);
11267 if (af_period_multiplier < 0)
11268 af_period_multiplier = 2;
11269 else if (af_period_multiplier > 4)
11270 af_period_multiplier = 4;
11271
11272 ALOGV("new period_multiplier = %d", af_period_multiplier);
11273 }
11274
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080011275 audio_extn_qdsp_init(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080011276
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -070011277 adev->multi_offload_enable = property_get_bool("vendor.audio.offload.multiple.enabled", false);
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011278 pthread_mutex_unlock(&adev_init_lock);
11279
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011280 if (adev->adm_init)
11281 adev->adm_data = adev->adm_init();
11282
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053011283 qahwi_init(*device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080011284 audio_extn_adsp_hdlr_init(adev->mixer);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011285
11286 audio_extn_snd_mon_init();
11287 pthread_mutex_lock(&adev->lock);
11288 audio_extn_snd_mon_register_listener(adev, adev_snd_mon_cb);
11289 adev->card_status = CARD_STATUS_ONLINE;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -050011290 adev->out_power_policy = POWER_POLICY_STATUS_ONLINE;
11291 adev->in_power_policy = POWER_POLICY_STATUS_ONLINE;
Haynes Mathew George01156f92018-04-13 15:29:54 -070011292 audio_extn_battery_properties_listener_init(adev_on_battery_status_changed);
11293 /*
11294 * if the battery state callback happens before charging can be queried,
11295 * it will be guarded with the adev->lock held in the cb function and so
11296 * the callback value will reflect the latest state
11297 */
11298 adev->is_charging = audio_extn_battery_properties_is_charging();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011299 audio_extn_sound_trigger_init(adev); /* dependent on snd_mon_init() */
Zhou Songc1088ea2018-06-12 00:17:29 +080011300 audio_extn_sound_trigger_update_battery_status(adev->is_charging);
justinweng20fb6d82019-02-21 18:49:00 -070011301 audio_extn_audiozoom_init();
Zhou Songc1088ea2018-06-12 00:17:29 +080011302 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053011303 /* Allocate memory for Device config params */
11304 adev->device_cfg_params = (struct audio_device_config_param*)
11305 calloc(platform_get_max_codec_backend(),
11306 sizeof(struct audio_device_config_param));
11307 if (adev->device_cfg_params == NULL)
11308 ALOGE("%s: Memory allocation failed for Device config params", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011309
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011310 /*
11311 * Check if new PSPD matrix mixer control is supported. If not
11312 * supported, then set flag so that old mixer ctrl is sent while
11313 * sending pspd coefficients on older kernel version. Query mixer
11314 * control for default pcm id and channel value one.
11315 */
11316 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
11317 "AudStr %d ChMixer Weight Ch %d", 0, 1);
11318
11319 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
11320 if (!ctl) {
11321 ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
11322 __func__, mixer_ctl_name);
11323 adev->use_old_pspd_mix_ctrl = true;
11324 }
11325
Jaideep Sharma0fa53812020-09-17 09:00:11 +053011326 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011327 return 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011328
11329adev_open_err:
11330 free_map(adev->patch_map);
11331 free_map(adev->io_streams_map);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080011332 free(adev->snd_dev_ref_cnt);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011333 pthread_mutex_destroy(&adev->lock);
11334 free(adev);
11335 adev = NULL;
11336 *device = NULL;
11337 pthread_mutex_unlock(&adev_init_lock);
11338 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011339}
11340
11341static struct hw_module_methods_t hal_module_methods = {
11342 .open = adev_open,
11343};
11344
11345struct audio_module HAL_MODULE_INFO_SYM = {
11346 .common = {
11347 .tag = HARDWARE_MODULE_TAG,
11348 .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
11349 .hal_api_version = HARDWARE_HAL_API_VERSION,
11350 .id = AUDIO_HARDWARE_MODULE_ID,
11351 .name = "QCOM Audio HAL",
Duy Truongfae19622013-11-24 02:17:54 -080011352 .author = "The Linux Foundation",
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011353 .methods = &hal_module_methods,
11354 },
11355};