blob: df3d21ad271903b75f471e910137964bab8bff94 [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;
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +0530718#ifdef PLATFORM_AUTO
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);
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +0530723#else
724 if (out->realtime)
725 adev->adm_set_config(adev->adm_data,
726 out->handle,
727 out->pcm, &out->config);
728#endif
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700729}
730
731static void register_in_stream(struct stream_in *in)
732{
733 struct audio_device *adev = in->dev;
734 if (!adev->adm_register_input_stream)
735 return;
736
737 adev->adm_register_input_stream(adev->adm_data,
738 in->capture_handle,
739 in->flags);
740
741 if (!adev->adm_set_config)
742 return;
743
744 if (in->realtime)
745 adev->adm_set_config(adev->adm_data,
746 in->capture_handle,
747 in->pcm,
748 &in->config);
749}
750
751static void request_out_focus(struct stream_out *out, long ns)
752{
753 struct audio_device *adev = out->dev;
754
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700755 if (adev->adm_request_focus_v2)
756 adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
757 else if (adev->adm_request_focus)
758 adev->adm_request_focus(adev->adm_data, out->handle);
759}
760
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700761static int request_in_focus(struct stream_in *in, long ns)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700762{
763 struct audio_device *adev = in->dev;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700764 int ret = 0;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700765
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700766 if (adev->adm_request_focus_v2_1)
767 ret = adev->adm_request_focus_v2_1(adev->adm_data, in->capture_handle, ns);
768 else if (adev->adm_request_focus_v2)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700769 adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
770 else if (adev->adm_request_focus)
771 adev->adm_request_focus(adev->adm_data, in->capture_handle);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700772
773 return ret;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700774}
775
776static void release_out_focus(struct stream_out *out)
777{
778 struct audio_device *adev = out->dev;
779
780 if (adev->adm_abandon_focus)
781 adev->adm_abandon_focus(adev->adm_data, out->handle);
782}
783
784static void release_in_focus(struct stream_in *in)
785{
786 struct audio_device *adev = in->dev;
787 if (adev->adm_abandon_focus)
788 adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
789}
790
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530791static int parse_snd_card_status(struct str_parms *parms, int *card,
792 card_status_t *status)
793{
794 char value[32]={0};
795 char state[32]={0};
796
797 int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
798 if (ret < 0)
799 return -1;
800
801 // sscanf should be okay as value is of max length 32.
802 // same as sizeof state.
803 if (sscanf(value, "%d,%s", card, state) < 2)
804 return -1;
805
806 *status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
807 CARD_STATUS_OFFLINE;
808 return 0;
809}
810
Avinash Chandrad7296d42021-08-04 15:07:47 +0530811bool is_combo_audio_input_device(struct listnode *devices){
812
Sandhya Mutha Naga Venkata153d95e2022-07-12 14:54:43 +0530813 if ((devices == NULL) || (!list_empty(devices)))
Avinash Chandrad7296d42021-08-04 15:07:47 +0530814 return false;
815
816 if(compare_device_type(devices, AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_SPEAKER_MIC2))
817 return true;
818 else
819 return false;
820}
821
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700822static inline void adjust_frames_for_device_delay(struct stream_out *out,
823 uint32_t *dsp_frames) {
824 // Adjustment accounts for A2dp encoder latency with offload usecases
825 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800826 if (is_a2dp_out_device_type(&out->device_list)) {
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700827 unsigned long offset =
828 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
829 *dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
830 }
831}
832
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700833static inline bool free_entry(void *key __unused,
834 void *value, void *context __unused)
835{
836 free(value);
837 return true;
838}
839
840static inline void free_map(Hashmap *map)
841{
842 if (map) {
843 hashmapForEach(map, free_entry, (void *) NULL);
844 hashmapFree(map);
845 }
846}
847
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800848static inline void patch_map_remove_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700849 audio_patch_handle_t patch_handle)
850{
851 if (patch_handle == AUDIO_PATCH_HANDLE_NONE)
852 return;
853
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700854 struct audio_patch_info *p_info =
855 hashmapGet(adev->patch_map, (void *) (intptr_t) patch_handle);
856 if (p_info) {
857 ALOGV("%s: Remove patch %d", __func__, patch_handle);
858 hashmapRemove(adev->patch_map, (void *) (intptr_t) patch_handle);
859 free(p_info->patch);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700860 free(p_info);
861 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700862}
863
864static inline int io_streams_map_insert(struct audio_device *adev,
865 struct audio_stream *stream,
866 audio_io_handle_t handle,
867 audio_patch_handle_t patch_handle)
868{
869 struct audio_stream_info *s_info =
870 (struct audio_stream_info *) calloc(1, sizeof(struct audio_stream_info));
871
872 if (s_info == NULL) {
873 ALOGE("%s: Could not allocate stream info", __func__);
874 return -ENOMEM;
875 }
876 s_info->stream = stream;
877 s_info->patch_handle = patch_handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700878
879 pthread_mutex_lock(&adev->lock);
880 struct audio_stream_info *stream_info =
881 hashmapPut(adev->io_streams_map, (void *) (intptr_t) handle, (void *) s_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700882 if (stream_info != NULL)
883 free(stream_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800884 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700885 ALOGV("%s: Added stream in io_streams_map with handle %d", __func__, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700886 return 0;
887}
888
889static inline void io_streams_map_remove(struct audio_device *adev,
890 audio_io_handle_t handle)
891{
892 pthread_mutex_lock(&adev->lock);
893 struct audio_stream_info *s_info =
894 hashmapRemove(adev->io_streams_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700895 if (s_info == NULL)
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800896 goto done;
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700897 ALOGV("%s: Removed stream with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800898 patch_map_remove_l(adev, s_info->patch_handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700899 free(s_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800900done:
901 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700902 return;
903}
904
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800905static struct audio_patch_info* fetch_patch_info_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700906 audio_patch_handle_t handle)
907{
908 struct audio_patch_info *p_info = NULL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700909 p_info = (struct audio_patch_info *)
910 hashmapGet(adev->patch_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700911 return p_info;
912}
913
vivek mehtaa76401a2015-04-24 14:12:15 -0700914__attribute__ ((visibility ("default")))
915bool audio_hw_send_gain_dep_calibration(int level) {
916 bool ret_val = false;
vivek mehtab72d08d2016-04-29 03:16:47 -0700917 ALOGV("%s: called ...", __func__);
vivek mehtaa76401a2015-04-24 14:12:15 -0700918
919 pthread_mutex_lock(&adev_init_lock);
920
921 if (adev != NULL && adev->platform != NULL) {
922 pthread_mutex_lock(&adev->lock);
923 ret_val = platform_send_gain_dep_cal(adev->platform, level);
vivek mehtab72d08d2016-04-29 03:16:47 -0700924
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +0530925 // cache level info for any of the use case which
926 // was not started.
927 last_known_cal_step = level;;
vivek mehtab72d08d2016-04-29 03:16:47 -0700928
vivek mehtaa76401a2015-04-24 14:12:15 -0700929 pthread_mutex_unlock(&adev->lock);
930 } else {
931 ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
932 }
933
934 pthread_mutex_unlock(&adev_init_lock);
935
936 return ret_val;
937}
938
Ashish Jain5106d362016-05-11 19:23:33 +0530939static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless)
940{
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800941 bool gapless_enabled = false;
942 const char *mixer_ctl_name = "Compress Gapless Playback";
943 struct mixer_ctl *ctl;
944
945 ALOGV("%s:", __func__);
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700946 gapless_enabled = property_get_bool("vendor.audio.offload.gapless.enabled", false);
Ashish Jain5106d362016-05-11 19:23:33 +0530947
948 /*Disable gapless if its AV playback*/
949 gapless_enabled = gapless_enabled && enable_gapless;
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800950
951 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
952 if (!ctl) {
953 ALOGE("%s: Could not get ctl for mixer cmd - %s",
954 __func__, mixer_ctl_name);
955 return -EINVAL;
956 }
957
958 if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) {
959 ALOGE("%s: Could not set gapless mode %d",
960 __func__, gapless_enabled);
961 return -EINVAL;
962 }
963 return 0;
964}
Haynes Mathew George5191a852013-09-11 14:19:36 -0700965
Aniket Kumar Lataf56b6402016-10-27 12:03:18 -0700966__attribute__ ((visibility ("default")))
967int audio_hw_get_gain_level_mapping(struct amp_db_and_gain_table *mapping_tbl,
968 int table_size) {
969 int ret_val = 0;
970 ALOGV("%s: enter ... ", __func__);
971
972 pthread_mutex_lock(&adev_init_lock);
973 if (adev == NULL) {
974 ALOGW("%s: adev is NULL .... ", __func__);
975 goto done;
976 }
977
978 pthread_mutex_lock(&adev->lock);
979 ret_val = platform_get_gain_level_mapping(mapping_tbl, table_size);
980 pthread_mutex_unlock(&adev->lock);
981done:
982 pthread_mutex_unlock(&adev_init_lock);
983 ALOGV("%s: exit ... ", __func__);
984 return ret_val;
985}
986
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800987bool audio_hw_send_qdsp_parameter(int stream_type, float vol, bool active)
Aalique Grahame22e49102018-12-18 14:23:57 -0800988{
989 bool ret = false;
990 ALOGV("%s: enter ...", __func__);
991
992 pthread_mutex_lock(&adev_init_lock);
993
994 if (adev != NULL && adev->platform != NULL) {
995 pthread_mutex_lock(&adev->lock);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800996 ret = audio_extn_qdsp_set_state(adev, stream_type, vol, active);
Aalique Grahame22e49102018-12-18 14:23:57 -0800997 pthread_mutex_unlock(&adev->lock);
998 }
999
1000 pthread_mutex_unlock(&adev_init_lock);
1001
1002 ALOGV("%s: exit with ret %d", __func__, ret);
1003 return ret;
1004}
Aalique Grahame22e49102018-12-18 14:23:57 -08001005
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001006static bool is_supported_format(audio_format_t format)
1007{
Eric Laurent86e17132013-09-12 17:49:30 -07001008 if (format == AUDIO_FORMAT_MP3 ||
Satish Babu Patakokila0c313922016-12-08 12:07:08 +05301009 format == AUDIO_FORMAT_MP2 ||
Ashish Jainf9b78162014-08-25 20:36:25 +05301010 format == AUDIO_FORMAT_AAC_LC ||
1011 format == AUDIO_FORMAT_AAC_HE_V1 ||
1012 format == AUDIO_FORMAT_AAC_HE_V2 ||
Manish Dewangana6fc5442015-08-24 20:30:31 +05301013 format == AUDIO_FORMAT_AAC_ADTS_LC ||
1014 format == AUDIO_FORMAT_AAC_ADTS_HE_V1 ||
1015 format == AUDIO_FORMAT_AAC_ADTS_HE_V2 ||
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05301016 format == AUDIO_FORMAT_AAC_LATM_LC ||
1017 format == AUDIO_FORMAT_AAC_LATM_HE_V1 ||
1018 format == AUDIO_FORMAT_AAC_LATM_HE_V2 ||
Ashish Jain5106d362016-05-11 19:23:33 +05301019 format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
1020 format == AUDIO_FORMAT_PCM_8_24_BIT ||
Ashish Jainf1eaa582016-05-23 20:54:24 +05301021 format == AUDIO_FORMAT_PCM_FLOAT ||
1022 format == AUDIO_FORMAT_PCM_32_BIT ||
vivek mehta0ea887a2015-08-26 14:01:20 -07001023 format == AUDIO_FORMAT_PCM_16_BIT ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05301024 format == AUDIO_FORMAT_AC3 ||
1025 format == AUDIO_FORMAT_E_AC3 ||
Ben Romberger1aaaf862017-04-06 17:49:46 -07001026 format == AUDIO_FORMAT_DOLBY_TRUEHD ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05301027 format == AUDIO_FORMAT_DTS ||
1028 format == AUDIO_FORMAT_DTS_HD ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08001029 format == AUDIO_FORMAT_FLAC ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05301030 format == AUDIO_FORMAT_ALAC ||
1031 format == AUDIO_FORMAT_APE ||
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05301032 format == AUDIO_FORMAT_DSD ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05301033 format == AUDIO_FORMAT_VORBIS ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08001034 format == AUDIO_FORMAT_WMA ||
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05301035 format == AUDIO_FORMAT_WMA_PRO ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07001036 format == AUDIO_FORMAT_APTX ||
1037 format == AUDIO_FORMAT_IEC61937)
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08001038 return true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001039
1040 return false;
1041}
1042
Kunlei Zhang67cc7072020-12-18 17:16:49 +08001043static bool is_supported_conc_usecase_for_power_mode_call(struct audio_device *adev)
1044{
1045 struct listnode *node;
1046 struct audio_usecase *usecase;
1047
1048 list_for_each(node, &adev->usecase_list) {
1049 usecase = node_to_item(node, struct audio_usecase, list);
1050 if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1051 ALOGD("%s: FM usecase is active, not setting power mode", __func__);
1052 return false;
1053 }
1054 }
1055
1056 return true;
1057}
Haynes Mathew George5beddd42016-06-27 18:33:40 -07001058static inline bool is_mmap_usecase(audio_usecase_t uc_id)
1059{
1060 return (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY) ||
Zhou Song62ea0282020-03-22 19:53:01 +08001061 (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY2) ||
Haynes Mathew George5beddd42016-06-27 18:33:40 -07001062 (uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
1063}
1064
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07001065static inline bool is_valid_volume(float left, float right)
1066{
1067 return ((left >= 0.0f && right >= 0.0f) ? true : false);
1068}
1069
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301070static void enable_asrc_mode(struct audio_device *adev)
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301071{
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301072 ALOGV("%s", __func__);
1073 audio_route_apply_and_update_path(adev->audio_route,
1074 "asrc-mode");
1075 adev->asrc_mode_enabled = true;
1076}
1077
1078static void disable_asrc_mode(struct audio_device *adev)
1079{
1080 ALOGV("%s", __func__);
1081 audio_route_reset_and_update_path(adev->audio_route,
1082 "asrc-mode");
1083 adev->asrc_mode_enabled = false;
1084}
1085
Saurav Kumarc1411662020-10-14 10:50:45 +05301086static void check_and_configure_headphone(struct audio_device *adev,
1087 struct audio_usecase *uc_info,
1088 snd_device_t snd_device)
1089{
1090 struct listnode *node;
1091 struct audio_usecase *usecase;
1092 int new_backend_idx, usecase_backend_idx;
1093 bool spkr_hph_single_be_native_concurrency;
1094
1095 new_backend_idx = platform_get_backend_index(snd_device);
1096 spkr_hph_single_be_native_concurrency = platform_get_spkr_hph_single_be_native_concurrency_flag();
Zhou Songd4b18c42021-01-14 15:15:29 +08001097 if ((spkr_hph_single_be_native_concurrency && (new_backend_idx == DEFAULT_CODEC_BACKEND)) ||
1098 uc_info->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
Saurav Kumarc1411662020-10-14 10:50:45 +05301099 list_for_each(node, &adev->usecase_list) {
1100 usecase = node_to_item(node, struct audio_usecase, list);
1101 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info)) {
1102 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1103 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1104 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1105 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1106 disable_audio_route(adev, usecase);
1107 disable_snd_device(adev, usecase->out_snd_device);
1108 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
Saurav Kumar70902382020-10-28 11:16:04 +05301109 platform_check_and_set_codec_backend_cfg(adev, usecase,
1110 usecase->out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05301111 enable_snd_device(adev, usecase->out_snd_device);
Zhou Songd4b18c42021-01-14 15:15:29 +08001112 enable_audio_route(adev, usecase);
Saurav Kumarc1411662020-10-14 10:50:45 +05301113 }
1114 }
Revathi Uddaraju2c0eac02021-07-27 02:06:42 -07001115 else if ((usecase->type != PCM_CAPTURE) && (usecase == uc_info)) {
1116 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1117 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1118 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1119 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1120 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
1121 platform_check_and_set_codec_backend_cfg(adev, usecase,
1122 usecase->out_snd_device);
1123 }
1124 }
Saurav Kumarc1411662020-10-14 10:50:45 +05301125 }
1126 }
1127}
1128
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301129/*
1130 * - Enable ASRC mode for incoming mix path use case(Headphone backend)if Headphone
1131 * 44.1 or Native DSD backends are enabled for any of current use case.
1132 * e.g. 48-> + (Naitve DSD or Headphone 44.1)
1133 * - Disable current mix path use case(Headphone backend) and re-enable it with
1134 * ASRC mode for incoming Headphone 44.1 or Native DSD use case.
1135 * e.g. Naitve DSD or Headphone 44.1 -> + 48
1136 */
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301137static void check_and_set_asrc_mode(struct audio_device *adev,
1138 struct audio_usecase *uc_info,
1139 snd_device_t snd_device)
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301140{
1141 ALOGV("%s snd device %d", __func__, snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301142 int i, num_new_devices = 0;
1143 snd_device_t split_new_snd_devices[SND_DEVICE_OUT_END];
1144 /*
1145 *Split snd device for new combo use case
1146 *e.g. Headphopne 44.1-> + Ringtone (Headphone + Speaker)
1147 */
1148 if (platform_split_snd_device(adev->platform,
1149 snd_device,
1150 &num_new_devices,
1151 split_new_snd_devices) == 0) {
1152 for (i = 0; i < num_new_devices; i++)
1153 check_and_set_asrc_mode(adev, uc_info, split_new_snd_devices[i]);
1154 } else {
1155 int new_backend_idx = platform_get_backend_index(snd_device);
1156 if (((new_backend_idx == HEADPHONE_BACKEND) ||
1157 (new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1158 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1159 !adev->asrc_mode_enabled) {
1160 struct listnode *node = NULL;
1161 struct audio_usecase *uc = NULL;
1162 struct stream_out *curr_out = NULL;
1163 int usecase_backend_idx = DEFAULT_CODEC_BACKEND;
1164 int i, num_devices, ret = 0;
1165 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301166
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301167 list_for_each(node, &adev->usecase_list) {
1168 uc = node_to_item(node, struct audio_usecase, list);
1169 curr_out = (struct stream_out*) uc->stream.out;
1170 if (curr_out && PCM_PLAYBACK == uc->type && uc != uc_info) {
1171 /*
1172 *Split snd device for existing combo use case
1173 *e.g. Ringtone (Headphone + Speaker) + Headphopne 44.1
1174 */
1175 ret = platform_split_snd_device(adev->platform,
1176 uc->out_snd_device,
1177 &num_devices,
1178 split_snd_devices);
1179 if (ret < 0 || num_devices == 0) {
1180 ALOGV("%s: Unable to split uc->out_snd_device: %d",__func__, uc->out_snd_device);
1181 split_snd_devices[0] = uc->out_snd_device;
1182 num_devices = 1;
Garmond Leung50058f62017-02-08 09:49:30 -08001183 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301184 for (i = 0; i < num_devices; i++) {
1185 usecase_backend_idx = platform_get_backend_index(split_snd_devices[i]);
1186 ALOGD("%s:snd_dev %d usecase_backend_idx %d",__func__, split_snd_devices[i],usecase_backend_idx);
1187 if((new_backend_idx == HEADPHONE_BACKEND) &&
1188 ((usecase_backend_idx == HEADPHONE_44_1_BACKEND) ||
1189 (usecase_backend_idx == DSD_NATIVE_BACKEND))) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001190 ALOGV("%s:DSD or native stream detected enabling asrcmode in hardware",
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301191 __func__);
1192 enable_asrc_mode(adev);
1193 break;
1194 } else if(((new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1195 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1196 (usecase_backend_idx == HEADPHONE_BACKEND)) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001197 ALOGV("%s: 48K stream detected, disabling and enabling it \
1198 with asrcmode in hardware", __func__);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301199 disable_audio_route(adev, uc);
1200 disable_snd_device(adev, uc->out_snd_device);
1201 // Apply true-high-quality-mode if DSD or > 44.1KHz or >=24-bit
1202 if (new_backend_idx == DSD_NATIVE_BACKEND)
1203 audio_route_apply_and_update_path(adev->audio_route,
1204 "hph-true-highquality-mode");
1205 else if ((new_backend_idx == HEADPHONE_44_1_BACKEND) &&
1206 (curr_out->bit_width >= 24))
1207 audio_route_apply_and_update_path(adev->audio_route,
1208 "hph-highquality-mode");
1209 enable_asrc_mode(adev);
1210 enable_snd_device(adev, uc->out_snd_device);
1211 enable_audio_route(adev, uc);
1212 break;
1213 }
1214 }
1215 // reset split devices count
1216 num_devices = 0;
Garmond Leung50058f62017-02-08 09:49:30 -08001217 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301218 if (adev->asrc_mode_enabled)
1219 break;
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301220 }
1221 }
1222 }
1223}
1224
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001225static int send_effect_enable_disable_mixer_ctl(struct audio_device *adev,
1226 struct audio_effect_config effect_config,
1227 unsigned int param_value)
1228{
1229 char mixer_ctl_name[] = "Audio Effect";
1230 struct mixer_ctl *ctl;
1231 long set_values[6];
Eric Laurent637e2d42018-11-15 12:24:31 -08001232 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001233
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001234 if (in == NULL) {
1235 ALOGE("%s: active input stream is NULL", __func__);
1236 return -EINVAL;
1237 }
1238
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001239 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
1240 if (!ctl) {
1241 ALOGE("%s: Could not get mixer ctl - %s",
1242 __func__, mixer_ctl_name);
1243 return -EINVAL;
1244 }
1245
1246 set_values[0] = 1; //0:Rx 1:Tx
1247 set_values[1] = in->app_type_cfg.app_type;
1248 set_values[2] = (long)effect_config.module_id;
1249 set_values[3] = (long)effect_config.instance_id;
1250 set_values[4] = (long)effect_config.param_id;
1251 set_values[5] = param_value;
1252
1253 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
1254
1255 return 0;
1256
1257}
1258
1259static int update_effect_param_ecns(struct audio_device *adev, unsigned int module_id,
1260 int effect_type, unsigned int *param_value)
1261{
1262 int ret = 0;
1263 struct audio_effect_config other_effect_config;
1264 struct audio_usecase *usecase = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08001265 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001266
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001267 if (in == NULL) {
1268 ALOGE("%s: active input stream is NULL", __func__);
1269 return -EINVAL;
1270 }
1271
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001272 usecase = get_usecase_from_list(adev, in->usecase);
1273 if (!usecase)
1274 return -EINVAL;
1275
1276 ret = platform_get_effect_config_data(usecase->in_snd_device, &other_effect_config,
1277 effect_type == EFFECT_AEC ? EFFECT_NS : EFFECT_AEC);
1278 if (ret < 0) {
1279 ALOGE("%s Failed to get effect params %d", __func__, ret);
1280 return ret;
1281 }
1282
1283 if (module_id == other_effect_config.module_id) {
1284 //Same module id for AEC/NS. Values need to be combined
1285 if (((effect_type == EFFECT_AEC) && (in->enable_ns)) ||
1286 ((effect_type == EFFECT_NS) && (in->enable_aec))) {
1287 *param_value |= other_effect_config.param_value;
1288 }
1289 }
1290
1291 return ret;
1292}
1293
1294static int enable_disable_effect(struct audio_device *adev, int effect_type, bool enable)
Gangadhar Sb0210342019-02-22 17:39:41 +05301295{
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001296 struct audio_effect_config effect_config;
1297 struct audio_usecase *usecase = NULL;
1298 int ret = 0;
1299 unsigned int param_value = 0;
Eric Laurent637e2d42018-11-15 12:24:31 -08001300 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001301
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001302 if(!voice_extn_is_dynamic_ecns_enabled())
1303 return ENOSYS;
1304
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001305 if (!in) {
1306 ALOGE("%s: Invalid input stream", __func__);
1307 return -EINVAL;
1308 }
1309
1310 ALOGD("%s: effect_type:%d enable:%d", __func__, effect_type, enable);
1311
1312 usecase = get_usecase_from_list(adev, in->usecase);
Weiyin Jiang20d3fa62018-08-01 18:06:27 +08001313 if (usecase == NULL) {
1314 ALOGE("%s: Could not find the usecase (%d) in the list",
1315 __func__, in->usecase);
1316 return -EINVAL;
1317 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001318
1319 ret = platform_get_effect_config_data(usecase->in_snd_device, &effect_config, effect_type);
1320 if (ret < 0) {
1321 ALOGE("%s Failed to get module id %d", __func__, ret);
1322 return ret;
1323 }
1324 ALOGV("%s: %d %d usecase->id:%d usecase->in_snd_device:%d", __func__, effect_config.module_id,
1325 in->app_type_cfg.app_type, usecase->id, usecase->in_snd_device);
1326
1327 if(enable)
1328 param_value = effect_config.param_value;
1329
1330 /*Special handling for AEC & NS effects Param values need to be
1331 updated if module ids are same*/
1332
1333 if ((effect_type == EFFECT_AEC) || (effect_type == EFFECT_NS)) {
1334 ret = update_effect_param_ecns(adev, effect_config.module_id, effect_type, &param_value);
1335 if (ret < 0)
1336 return ret;
1337 }
1338
1339 ret = send_effect_enable_disable_mixer_ctl(adev, effect_config, param_value);
1340
1341 return ret;
1342}
1343
1344static void check_and_enable_effect(struct audio_device *adev)
1345{
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001346 if(!voice_extn_is_dynamic_ecns_enabled())
1347 return;
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001348
Eric Laurent637e2d42018-11-15 12:24:31 -08001349 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001350
Eric Laurent637e2d42018-11-15 12:24:31 -08001351 if (in != NULL && !in->standby) {
1352 if (in->enable_aec)
1353 enable_disable_effect(adev, EFFECT_AEC, true);
1354
1355 if (in->enable_ns &&
1356 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
1357 enable_disable_effect(adev, EFFECT_NS, true);
1358 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001359 }
1360}
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001361
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07001362int pcm_ioctl(struct pcm *pcm, int request, ...)
1363{
1364 va_list ap;
1365 void * arg;
1366 int pcm_fd = *(int*)pcm;
1367
1368 va_start(ap, request);
1369 arg = va_arg(ap, void *);
1370 va_end(ap);
1371
1372 return ioctl(pcm_fd, request, arg);
1373}
1374
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001375int enable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001376 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001377{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001378 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001379 char mixer_path[MIXER_PATH_MAX_LENGTH];
Manish Dewangan58229382017-02-02 15:48:41 +05301380 struct stream_out *out = NULL;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301381 struct stream_in *in = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001382 struct listnode out_devices;
Soumya Managoli6993b762018-06-28 16:04:57 +05301383 int ret = 0;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001384
1385 if (usecase == NULL)
1386 return -EINVAL;
1387
1388 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
1389
Carter Hsu2e429db2019-05-14 18:50:52 +08001390 if (usecase->type == PCM_CAPTURE) {
1391 struct stream_in *in = usecase->stream.in;
1392 struct audio_usecase *uinfo;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001393 snd_device = usecase->in_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001394
1395 if (in) {
1396 if (in->enable_aec || in->enable_ec_port) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001397 list_init(&out_devices);
1398 update_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "", true);
Carter Hsu2e429db2019-05-14 18:50:52 +08001399 struct listnode *node;
1400 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
1401 USECASE_AUDIO_PLAYBACK_VOIP);
1402 if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001403 assign_devices(&out_devices,
1404 &voip_usecase->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001405 } else if (adev->primary_output &&
1406 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001407 assign_devices(&out_devices,
1408 &adev->primary_output->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001409 } else {
1410 list_for_each(node, &adev->usecase_list) {
1411 uinfo = node_to_item(node, struct audio_usecase, list);
1412 if (uinfo->type != PCM_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001413 assign_devices(&out_devices,
1414 &uinfo->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001415 break;
1416 }
1417 }
1418 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001419
1420 platform_set_echo_reference(adev, true, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001421 in->ec_opened = true;
Zhenlin Lian4f947842022-05-14 15:50:52 +05301422 clear_devices(&out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001423 }
1424 }
Guodong Huf5e614d2019-06-24 18:42:03 +08001425 } else if ((usecase->type == TRANSCODE_LOOPBACK_TX) || ((usecase->type == PCM_HFP_CALL) &&
1426 ((usecase->id == USECASE_AUDIO_HFP_SCO) || (usecase->id == USECASE_AUDIO_HFP_SCO_WB)) &&
1427 (usecase->in_snd_device == SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS))) {
Carter Hsu2e429db2019-05-14 18:50:52 +08001428 snd_device = usecase->in_snd_device;
1429 } else {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001430 snd_device = usecase->out_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001431 }
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001432
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001433 if (usecase->type == PCM_CAPTURE) {
1434 if (platform_get_fluence_nn_state(adev->platform) == 0) {
1435 platform_set_fluence_nn_state(adev->platform, true);
1436 ALOGD("%s: set fluence nn capture state", __func__);
1437 }
1438 }
1439
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08001440#ifdef DS1_DOLBY_DAP_ENABLED
1441 audio_extn_dolby_set_dmid(adev);
1442 audio_extn_dolby_set_endpoint(adev);
1443#endif
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -07001444 audio_extn_dolby_ds2_set_endpoint(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001445 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301446 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
Ben Romberger1fafdde2015-09-09 19:43:15 -07001447 audio_extn_utils_send_app_type_cfg(adev, usecase);
Jasmine Cha4dcc1092019-03-04 18:12:47 +08001448 if (audio_extn_is_maxx_audio_enabled())
1449 audio_extn_ma_set_device(usecase);
Dhananjay Kumar14170dd2015-08-28 13:24:16 +05301450 audio_extn_utils_send_audio_calibration(adev, usecase);
Zhou Songbaddf9f2020-11-20 13:57:39 +08001451 if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
1452 out = usecase->stream.out;
1453 if (out && out->compr)
Manish Dewangan58229382017-02-02 15:48:41 +05301454 audio_extn_utils_compress_set_clk_rec_mode(usecase);
1455 }
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301456
1457 if (usecase->type == PCM_CAPTURE) {
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001458 if (platform_get_fluence_nn_state(adev->platform) == 1 &&
1459 adev->fluence_nn_usecase_id == USECASE_INVALID ) {
1460 adev->fluence_nn_usecase_id = usecase->id;
1461 ALOGD("%s: assign fluence nn usecase %d", __func__, usecase->id);
1462 }
1463 }
1464
1465 if (usecase->type == PCM_CAPTURE) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301466 in = usecase->stream.in;
Avinash Chandrad7296d42021-08-04 15:07:47 +05301467 if ((in && is_loopback_input_device(get_device_types(&in->device_list))) ||
1468 (in && is_combo_audio_input_device(&in->device_list)) ||
1469 (in && ((compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
1470 compare_device_type(&in->device_list, AUDIO_DEVICE_IN_LINE)) &&
1471 (snd_device == SND_DEVICE_IN_HANDSET_GENERIC_6MIC)))) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301472 ALOGD("%s: set custom mtmx params v1", __func__);
1473 audio_extn_set_custom_mtmx_params_v1(adev, usecase, true);
1474 }
1475 } else {
1476 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
1477 }
Manish Dewangan58229382017-02-02 15:48:41 +05301478
Andy Hung756ecc12018-10-19 17:47:12 -07001479 // we shouldn't truncate mixer_path
1480 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1481 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1482 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001483 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001484 ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
Soumya Managoli6993b762018-06-28 16:04:57 +05301485 ret = audio_route_apply_and_update_path(adev->audio_route, mixer_path);
1486 if (!ret && usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1487 struct str_parms *parms = str_parms_create_str("fm_restore_volume=1");
1488 if (parms) {
1489 audio_extn_fm_set_parameters(adev, parms);
1490 str_parms_destroy(parms);
1491 }
1492 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001493 ALOGV("%s: exit", __func__);
1494 return 0;
1495}
1496
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001497int disable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001498 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001499{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001500 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001501 char mixer_path[MIXER_PATH_MAX_LENGTH];
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301502 struct stream_in *in = NULL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001503
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05301504 if (usecase == NULL || usecase->id == USECASE_INVALID)
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001505 return -EINVAL;
1506
1507 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
Surendar Karka93cd25a2018-08-28 14:21:37 +05301508 if (usecase->type == PCM_CAPTURE || usecase->type == TRANSCODE_LOOPBACK_TX)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001509 snd_device = usecase->in_snd_device;
1510 else
1511 snd_device = usecase->out_snd_device;
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001512
1513 /* disable island and power mode on supported device for voice call */
1514 if (usecase->type == VOICE_CALL) {
1515 if (usecase->in_snd_device != SND_DEVICE_NONE) {
1516 if (platform_get_island_cfg_on_device(adev->platform, usecase->in_snd_device) &&
1517 platform_get_power_mode_on_device(adev->platform, usecase->in_snd_device)) {
1518 platform_set_island_cfg_on_device(adev, usecase->in_snd_device, false);
1519 platform_set_power_mode_on_device(adev, usecase->in_snd_device, false);
1520 platform_reset_island_power_status(adev->platform, usecase->in_snd_device);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001521 if (voice_is_lte_call_active(adev))
1522 platform_set_tx_lpi_mode(adev->platform, false);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001523 ALOGD("%s: disable island cfg and power mode in voice tx path",
1524 __func__);
1525 }
1526 }
1527 if (usecase->out_snd_device != SND_DEVICE_NONE) {
1528 if (platform_get_island_cfg_on_device(adev->platform, usecase->out_snd_device) &&
1529 platform_get_power_mode_on_device(adev->platform, usecase->out_snd_device)) {
1530 platform_set_island_cfg_on_device(adev, usecase->out_snd_device, false);
1531 platform_set_power_mode_on_device(adev, usecase->out_snd_device, false);
1532 platform_reset_island_power_status(adev->platform, usecase->out_snd_device);
1533 ALOGD("%s: disable island cfg and power mode in voice rx path",
1534 __func__);
1535 }
1536 }
1537 }
1538
Andy Hung756ecc12018-10-19 17:47:12 -07001539 // we shouldn't truncate mixer_path
1540 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1541 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1542 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001543 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001544 ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001545 audio_route_reset_and_update_path(adev->audio_route, mixer_path);
Carter Hsu2e429db2019-05-14 18:50:52 +08001546 if (usecase->type == PCM_CAPTURE) {
1547 struct stream_in *in = usecase->stream.in;
1548 if (in && in->ec_opened) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001549 struct listnode out_devices;
1550 list_init(&out_devices);
1551 platform_set_echo_reference(in->dev, false, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001552 in->ec_opened = false;
Zhenlin Lian4f947842022-05-14 15:50:52 +05301553 clear_devices(&out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001554 }
1555 }
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001556 if (usecase->id == adev->fluence_nn_usecase_id) {
1557 platform_set_fluence_nn_state(adev->platform, false);
1558 adev->fluence_nn_usecase_id = USECASE_INVALID;
1559 ALOGD("%s: reset fluence nn capture state", __func__);
1560 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001561 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301562 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301563
1564 if (usecase->type == PCM_CAPTURE) {
1565 in = usecase->stream.in;
Avinash Chandrad7296d42021-08-04 15:07:47 +05301566 if ((in && is_loopback_input_device(get_device_types(&in->device_list))) ||
1567 (in && is_combo_audio_input_device(&in->device_list)) ||
1568 (in && ((compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
1569 compare_device_type(&in->device_list, AUDIO_DEVICE_IN_LINE)) &&
1570 (snd_device == SND_DEVICE_IN_HANDSET_GENERIC_6MIC)))){
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301571 ALOGD("%s: reset custom mtmx params v1", __func__);
1572 audio_extn_set_custom_mtmx_params_v1(adev, usecase, false);
1573 }
1574 } else {
1575 audio_extn_set_custom_mtmx_params_v2(adev, usecase, false);
1576 }
1577
Weiyin Jiang298ffd92019-06-03 14:29:30 +08001578 if ((usecase->type == PCM_PLAYBACK) &&
1579 (usecase->stream.out != NULL))
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05301580 usecase->stream.out->pspd_coeff_sent = false;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301581
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001582 ALOGV("%s: exit", __func__);
1583 return 0;
1584}
1585
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001586int enable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001587 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001588{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301589 int i, num_devices = 0;
1590 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001591 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1592
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001593 if (snd_device < SND_DEVICE_MIN ||
1594 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001595 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001596 return -EINVAL;
1597 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001598
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001599 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001600 ALOGE("%s: Invalid sound device returned", __func__);
1601 return -EINVAL;
1602 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001603
1604 adev->snd_dev_ref_cnt[snd_device]++;
1605
1606 if ((adev->snd_dev_ref_cnt[snd_device] > 1) &&
1607 (platform_split_snd_device(adev->platform,
1608 snd_device,
1609 &num_devices,
1610 new_snd_devices) != 0)) {
Eric Laurent994a6932013-07-17 11:51:42 -07001611 ALOGV("%s: snd_device(%d: %s) is already active",
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001612 __func__, snd_device, device_name);
Aniket Kumar Lata990de552019-07-11 14:20:23 -07001613 /* Set backend config for A2DP to ensure slimbus configuration
1614 is correct if A2DP is already active and backend is closed
1615 and re-opened */
1616 if (snd_device == SND_DEVICE_OUT_BT_A2DP)
1617 audio_extn_a2dp_set_source_backend_cfg();
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001618 return 0;
1619 }
1620
Gopikrishnaiah Anandane85d0462014-06-30 21:41:20 -07001621 if (audio_extn_spkr_prot_is_enabled())
1622 audio_extn_spkr_prot_calib_cancel(adev);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001623
Aalique Grahame22e49102018-12-18 14:23:57 -08001624 audio_extn_dsm_feedback_enable(adev, snd_device, true);
1625
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001626 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1627 audio_extn_spkr_prot_is_enabled()) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001628 if (platform_get_spkr_prot_acdb_id(snd_device) < 0) {
1629 goto err;
1630 }
1631 audio_extn_dev_arbi_acquire(snd_device);
1632 if (audio_extn_spkr_prot_start_processing(snd_device)) {
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001633 ALOGE("%s: spkr_start_processing failed", __func__);
Ravit Dennisaaee49c2015-02-04 21:26:22 +02001634 audio_extn_dev_arbi_release(snd_device);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001635 goto err;
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001636 }
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001637 } else if (platform_split_snd_device(adev->platform,
1638 snd_device,
1639 &num_devices,
1640 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301641 for (i = 0; i < num_devices; i++) {
1642 enable_snd_device(adev, new_snd_devices[i]);
1643 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001644 platform_set_speaker_gain_in_combo(adev, snd_device, true);
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001645 } else {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001646 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301647
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001648 /* enable island and power mode on supported device */
1649 if (platform_get_island_cfg_on_device(adev->platform, snd_device) &&
1650 platform_get_power_mode_on_device(adev->platform, snd_device)) {
1651 platform_set_island_cfg_on_device(adev, snd_device, true);
1652 platform_set_power_mode_on_device(adev, snd_device, true);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001653 if (voice_is_lte_call_active(adev) &&
1654 (snd_device >= SND_DEVICE_IN_BEGIN &&
1655 snd_device < SND_DEVICE_IN_END))
1656 platform_set_tx_lpi_mode(adev->platform, true);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001657 ALOGD("%s: enable island cfg and power mode on: %s",
1658 __func__, device_name);
1659 }
Preetam Singh Ranawatf1d417c2017-01-10 17:00:32 +05301660
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301661 if (SND_DEVICE_OUT_BT_A2DP == snd_device) {
Ramjee Singh2d2944a2021-12-14 14:13:41 +05301662
1663 struct audio_usecase *usecase;
1664 struct listnode *node;
1665 /* Disable SCO Devices and enable handset mic for active input stream */
1666 list_for_each(node, &adev->usecase_list) {
1667 usecase = node_to_item(node, struct audio_usecase, list);
1668 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
1669 is_sco_in_device_type(&usecase->stream.in->device_list)) {
1670 ALOGD("a2dp resumed, switch bt sco mic to handset mic");
1671 reassign_device_list(&usecase->stream.in->device_list,
1672 AUDIO_DEVICE_IN_BUILTIN_MIC, "");
1673 select_devices(adev, usecase->id);
1674 }
1675 }
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301676 if (audio_extn_a2dp_start_playback() < 0) {
1677 ALOGE(" fail to configure A2dp Source control path ");
1678 goto err;
1679 } else {
1680 adev->a2dp_started = true;
1681 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001682 }
Florian Pfister1a84f312018-07-19 14:38:18 +02001683
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001684 if ((SND_DEVICE_IN_BT_A2DP == snd_device) &&
1685 (audio_extn_a2dp_start_capture() < 0)) {
1686 ALOGE(" fail to configure A2dp Sink control path ");
1687 goto err;
1688 }
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301689
Mingshu Pang7be5b1d2020-03-04 15:24:38 +08001690 if ((SND_DEVICE_OUT_BT_SCO_SWB == snd_device) ||
1691 (SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC == snd_device) ||
1692 (SND_DEVICE_IN_BT_SCO_MIC_SWB == snd_device)) {
1693 if (!adev->bt_sco_on || (audio_extn_sco_start_configuration() < 0)) {
1694 ALOGE(" fail to configure sco control path ");
1695 goto err;
1696 }
Zhou Song12c29502019-03-16 10:37:18 +08001697 }
1698
Zhou Song331c8e52019-08-26 14:16:12 +08001699 configure_btsco_sample_rate(snd_device);
Bharath Ramachandramurthy0de16782014-03-28 21:34:33 -07001700 /* due to the possibility of calibration overwrite between listen
1701 and audio, notify listen hal before audio calibration is sent */
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001702 audio_extn_sound_trigger_update_device_status(snd_device,
1703 ST_EVENT_SND_DEVICE_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301704 audio_extn_listen_update_device_status(snd_device,
1705 LISTEN_EVENT_SND_DEVICE_BUSY);
Subhash Chandra Bose Naripeddy54274672014-03-10 14:51:02 -07001706 if (platform_get_snd_device_acdb_id(snd_device) < 0) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001707 audio_extn_sound_trigger_update_device_status(snd_device,
1708 ST_EVENT_SND_DEVICE_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301709 audio_extn_listen_update_device_status(snd_device,
1710 LISTEN_EVENT_SND_DEVICE_FREE);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001711 goto err;
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001712 }
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001713 audio_extn_dev_arbi_acquire(snd_device);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001714 audio_route_apply_and_update_path(adev->audio_route, device_name);
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301715
1716 if (SND_DEVICE_OUT_HEADPHONES == snd_device &&
1717 !adev->native_playback_enabled &&
1718 audio_is_true_native_stream_active(adev)) {
1719 ALOGD("%s: %d: napb: enabling native mode in hardware",
1720 __func__, __LINE__);
1721 audio_route_apply_and_update_path(adev->audio_route,
1722 "true-native-mode");
1723 adev->native_playback_enabled = true;
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301724 }
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +05301725 if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
1726 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001727 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001728 ALOGD("%s: init ec ref loopback", __func__);
1729 audio_extn_ffv_init_ec_ref_loopback(adev, snd_device);
1730 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001731 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001732 return 0;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001733err:
1734 adev->snd_dev_ref_cnt[snd_device]--;
1735 return -EINVAL;;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001736}
1737
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001738int disable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001739 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001740{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301741 int i, num_devices = 0;
1742 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001743 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1744
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001745 if (snd_device < SND_DEVICE_MIN ||
1746 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001747 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001748 return -EINVAL;
1749 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001750
1751 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
1752 ALOGE("%s: Invalid sound device returned", __func__);
1753 return -EINVAL;
1754 }
1755
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001756 if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
1757 ALOGE("%s: device ref cnt is already 0", __func__);
1758 return -EINVAL;
1759 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001760
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001761 adev->snd_dev_ref_cnt[snd_device]--;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001762
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001763
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001764 if (adev->snd_dev_ref_cnt[snd_device] == 0) {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001765 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301766
Aalique Grahame22e49102018-12-18 14:23:57 -08001767 audio_extn_dsm_feedback_enable(adev, snd_device, false);
1768
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001769 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1770 audio_extn_spkr_prot_is_enabled()) {
Anish Kumar46c7b872014-09-09 01:49:44 -07001771 audio_extn_spkr_prot_stop_processing(snd_device);
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07001772
1773 // when speaker device is disabled, reset swap.
1774 // will be renabled on usecase start
1775 platform_set_swap_channels(adev, false);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001776 } else if (platform_split_snd_device(adev->platform,
1777 snd_device,
1778 &num_devices,
1779 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301780 for (i = 0; i < num_devices; i++) {
1781 disable_snd_device(adev, new_snd_devices[i]);
1782 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001783 platform_set_speaker_gain_in_combo(adev, snd_device, false);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001784 } else {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001785 audio_route_reset_and_update_path(adev->audio_route, device_name);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001786 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001787
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301788 if (snd_device == SND_DEVICE_OUT_BT_A2DP) {
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301789 audio_extn_a2dp_stop_playback();
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301790 adev->a2dp_started = false;
1791 } else if (snd_device == SND_DEVICE_IN_BT_A2DP)
Florian Pfister1a84f312018-07-19 14:38:18 +02001792 audio_extn_a2dp_stop_capture();
Zhou Songd6d71752019-05-21 18:08:51 +08001793 else if ((snd_device == SND_DEVICE_OUT_HDMI) ||
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001794 (snd_device == SND_DEVICE_OUT_DISPLAY_PORT))
Ashish Jain81eb2a82015-05-13 10:52:34 +05301795 adev->is_channel_status_set = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001796 else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301797 adev->native_playback_enabled) {
1798 ALOGD("%s: %d: napb: disabling native mode in hardware",
1799 __func__, __LINE__);
1800 audio_route_reset_and_update_path(adev->audio_route,
1801 "true-native-mode");
1802 adev->native_playback_enabled = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001803 } else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301804 adev->asrc_mode_enabled) {
1805 ALOGD("%s: %d: disabling asrc mode in hardware", __func__, __LINE__);
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301806 disable_asrc_mode(adev);
1807 audio_route_apply_and_update_path(adev->audio_route, "hph-lowpower-mode");
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001808 } else if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
Dhanalakshmi Siddaniaf4bd622019-02-27 16:28:06 +05301809 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001810 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001811 ALOGD("%s: deinit ec ref loopback", __func__);
1812 audio_extn_ffv_deinit_ec_ref_loopback(adev, snd_device);
1813 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001814
1815 audio_extn_utils_release_snd_device(snd_device);
1816 } else {
1817 if (platform_split_snd_device(adev->platform,
1818 snd_device,
1819 &num_devices,
1820 new_snd_devices) == 0) {
1821 for (i = 0; i < num_devices; i++) {
1822 adev->snd_dev_ref_cnt[new_snd_devices[i]]--;
1823 }
1824 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001825 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001826
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001827 return 0;
1828}
1829
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001830/*
1831 legend:
1832 uc - existing usecase
1833 new_uc - new usecase
1834 d1, d11, d2 - SND_DEVICE enums
1835 a1, a2 - corresponding ANDROID device enums
1836 B1, B2 - backend strings
1837
1838case 1
1839 uc->dev d1 (a1) B1
1840 new_uc->dev d1 (a1), d2 (a2) B1, B2
1841
1842 resolution: disable and enable uc->dev on d1
1843
1844case 2
1845 uc->dev d1 (a1) B1
1846 new_uc->dev d11 (a1) B1
1847
1848 resolution: need to switch uc since d1 and d11 are related
1849 (e.g. speaker and voice-speaker)
1850 use ANDROID_DEVICE_OUT enums to match devices since SND_DEVICE enums may vary
1851
1852case 3
1853 uc->dev d1 (a1) B1
1854 new_uc->dev d2 (a2) B2
1855
1856 resolution: no need to switch uc
1857
1858case 4
1859 uc->dev d1 (a1) B1
1860 new_uc->dev d2 (a2) B1
1861
1862 resolution: disable enable uc-dev on d2 since backends match
1863 we cannot enable two streams on two different devices if they
1864 share the same backend. e.g. if offload is on speaker device using
1865 QUAD_MI2S backend and a low-latency stream is started on voice-handset
1866 using the same backend, offload must also be switched to voice-handset.
1867
1868case 5
1869 uc->dev d1 (a1) B1
1870 new_uc->dev d1 (a1), d2 (a2) B1
1871
1872 resolution: disable enable uc-dev on d2 since backends match
1873 we cannot enable two streams on two different devices if they
1874 share the same backend.
1875
1876case 6
1877 uc->dev d1 (a1) B1
1878 new_uc->dev d2 (a1) B2
1879
1880 resolution: no need to switch
1881
1882case 7
1883 uc->dev d1 (a1), d2 (a2) B1, B2
1884 new_uc->dev d1 (a1) B1
1885
1886 resolution: no need to switch
1887
Zhou Song4ba65882018-07-09 14:48:07 +08001888case 8
1889 uc->dev d1 (a1) B1
1890 new_uc->dev d11 (a1), d2 (a2) B1, B2
1891 resolution: compared to case 1, for this case, d1 and d11 are related
1892 then need to do the same as case 2 to siwtch to new uc
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301893
1894case 9
1895 uc->dev d1 (a1), d2(a2) B1 B2
1896 new_uc->dev d1 (a1), d22 (a2) B1, B2
1897 resolution: disable enable uc-dev on d2 since backends match
1898 we cannot enable two streams on two different devices if they
1899 share the same backend. This is special case for combo use case
1900 with a2dp and sco devices which uses same backend.
1901 e.g. speaker-a2dp and speaker-btsco
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001902*/
1903static snd_device_t derive_playback_snd_device(void * platform,
1904 struct audio_usecase *uc,
1905 struct audio_usecase *new_uc,
1906 snd_device_t new_snd_device)
1907{
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001908 struct listnode a1, a2;
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001909
1910 snd_device_t d1 = uc->out_snd_device;
1911 snd_device_t d2 = new_snd_device;
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301912 snd_device_t ret = 0;
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001913
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001914 list_init(&a1);
1915 list_init(&a2);
1916
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301917 switch (uc->type) {
Surendar Karka93cd25a2018-08-28 14:21:37 +05301918 case TRANSCODE_LOOPBACK_RX :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001919 assign_devices(&a1, &uc->stream.inout->out_config.device_list);
1920 assign_devices(&a2, &new_uc->stream.inout->out_config.device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301921 break;
1922 default :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001923 assign_devices(&a1, &uc->stream.out->device_list);
1924 assign_devices(&a2, &new_uc->stream.out->device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301925 break;
1926 }
1927
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001928 // Treat as a special case when a1 and a2 are not disjoint
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001929 if (!compare_devices(&a1, &a2) &&
1930 compare_devices_for_any_match(&a1 ,&a2)) {
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001931 snd_device_t d3[2];
1932 int num_devices = 0;
1933 int ret = platform_split_snd_device(platform,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001934 list_length(&a1) > 1 ? d1 : d2,
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001935 &num_devices,
1936 d3);
1937 if (ret < 0) {
1938 if (ret != -ENOSYS) {
1939 ALOGW("%s failed to split snd_device %d",
1940 __func__,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001941 list_length(&a1) > 1 ? d1 : d2);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001942 }
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301943 ret = d2;
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001944 goto end;
1945 }
1946
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001947 if (platform_check_backends_match(d3[0], d3[1])) {
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301948 ret = d2;
1949 goto end; // case 5
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001950 } else {
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301951 if ((list_length(&a1) > 1) && (list_length(&a2) > 1) &&
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301952 platform_check_backends_match(d1, d2)) {
1953 ret = d2;
1954 goto end; //case 9
1955 }
1956 if (list_length(&a1) > 1) {
1957 ret = d1;
1958 goto end; //case 7
1959 }
Garmond Leungb9eeba42018-09-18 11:10:41 -07001960 // check if d1 is related to any of d3's
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301961 if (d1 == d3[0] || d1 == d3[1]) {
1962 ret = d1;
1963 goto end; // case 1
1964 } else {
1965 ret = d3[1];
1966 goto end; // case 8
1967 }
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001968 }
1969 } else {
1970 if (platform_check_backends_match(d1, d2)) {
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301971 ret = d2;
1972 goto end; // case 2, 4
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001973 } else {
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301974 ret = d1;
1975 goto end; // case 6, 3
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001976 }
1977 }
1978
Zhenlin Lian4f947842022-05-14 15:50:52 +05301979 clear_devices(&a1);
1980 clear_devices(&a2);
1981
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001982end:
Sandhya Mutha Naga Venkata4c6fc9f2022-10-14 19:38:02 +05301983 clear_devices(&a1);
1984 clear_devices(&a2);
1985 return ret; // return whatever was calculated before.
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001986}
1987
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001988static void check_usecases_codec_backend(struct audio_device *adev,
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301989 struct audio_usecase *uc_info,
1990 snd_device_t snd_device)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001991{
1992 struct listnode *node;
1993 struct audio_usecase *usecase;
1994 bool switch_device[AUDIO_USECASE_MAX];
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301995 snd_device_t uc_derive_snd_device;
1996 snd_device_t derive_snd_device[AUDIO_USECASE_MAX];
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001997 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
1998 int i, num_uc_to_switch = 0, num_devices = 0;
kunleiz5cd52b82016-11-07 17:22:52 +08001999 int status = 0;
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302000 bool force_restart_session = false;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002001 /*
2002 * This function is to make sure that all the usecases that are active on
2003 * the hardware codec backend are always routed to any one device that is
2004 * handled by the hardware codec.
2005 * For example, if low-latency and deep-buffer usecases are currently active
2006 * on speaker and out_set_parameters(headset) is received on low-latency
2007 * output, then we have to make sure deep-buffer is also switched to headset,
2008 * because of the limitation that both the devices cannot be enabled
2009 * at the same time as they share the same backend.
2010 */
Mingming Yin3ee55c62014-08-04 14:23:35 -07002011 /*
2012 * This call is to check if we need to force routing for a particular stream
2013 * If there is a backend configuration change for the device when a
2014 * new stream starts, then ADM needs to be closed and re-opened with the new
2015 * configuraion. This call check if we need to re-route all the streams
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08002016 * associated with the backend. Touch tone + 24 bit + native playback.
Mingming Yin3ee55c62014-08-04 14:23:35 -07002017 */
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08002018 bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info,
2019 snd_device);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302020 /* For a2dp device reconfigure all active sessions
2021 * with new AFE encoder format based on a2dp state
2022 */
2023 if ((SND_DEVICE_OUT_BT_A2DP == snd_device ||
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05302024 SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP == snd_device ||
2025 SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP == snd_device) &&
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302026 audio_extn_a2dp_is_force_device_switch()) {
2027 force_routing = true;
2028 force_restart_session = true;
2029 }
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002030
2031 /*
2032 * Island cfg and power mode config needs to set before AFE port start.
2033 * Set force routing in case of voice device was enable before.
2034 */
2035 if (uc_info->type == VOICE_CALL &&
2036 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002037 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002038 platform_check_and_update_island_power_status(adev->platform,
2039 uc_info,
2040 snd_device)) {
2041 force_routing = true;
2042 ALOGD("%s:becf: force routing %d for power mode supported device",
2043 __func__, force_routing);
2044 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302045 ALOGD("%s:becf: force routing %d", __func__, force_routing);
2046
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002047 /* Disable all the usecases on the shared backend other than the
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08002048 * specified usecase.
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08002049 */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002050 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2051 switch_device[i] = false;
2052
2053 list_for_each(node, &adev->usecase_list) {
2054 usecase = node_to_item(node, struct audio_usecase, list);
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08002055
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302056 ALOGD("%s:becf: (%d) check_usecases curr device: %s, usecase device:%s "
2057 "backends match %d",__func__, i,
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302058 platform_get_snd_device_name(snd_device),
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302059 platform_get_snd_device_name(usecase->out_snd_device),
2060 platform_check_backends_match(snd_device, usecase->out_snd_device));
Rahul Sharma99770982019-03-06 17:05:26 +05302061 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
2062 (usecase->type != PCM_PASSTHROUGH)) {
Ashish Jain6a65b352017-03-21 17:24:40 +05302063 uc_derive_snd_device = derive_playback_snd_device(adev->platform,
2064 usecase, uc_info, snd_device);
2065 if (((uc_derive_snd_device != usecase->out_snd_device) || force_routing) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002066 (is_codec_backend_out_device_type(&usecase->device_list) ||
2067 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
2068 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_DEVICE) ||
2069 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_HEADSET) ||
2070 is_a2dp_out_device_type(&usecase->device_list) ||
2071 is_sco_out_device_type(&usecase->device_list)) &&
Ashish Jain6a65b352017-03-21 17:24:40 +05302072 ((force_restart_session) ||
2073 (platform_check_backends_match(snd_device, usecase->out_snd_device)))) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302074 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
2075 __func__, use_case_table[usecase->id],
2076 platform_get_snd_device_name(usecase->out_snd_device));
2077 disable_audio_route(adev, usecase);
2078 switch_device[usecase->id] = true;
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05302079 /* Enable existing usecase on derived playback device */
2080 derive_snd_device[usecase->id] = uc_derive_snd_device;
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302081 num_uc_to_switch++;
Ashish Jain6a65b352017-03-21 17:24:40 +05302082 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002083 }
2084 }
2085
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302086 ALOGD("%s:becf: check_usecases num.of Usecases to switch %d", __func__,
2087 num_uc_to_switch);
2088
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002089 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002090 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002091
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302092 /* Make sure the previous devices to be disabled first and then enable the
2093 selected devices */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002094 list_for_each(node, &adev->usecase_list) {
2095 usecase = node_to_item(node, struct audio_usecase, list);
2096 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08002097 /* Check if output sound device to be switched can be split and if any
2098 of the split devices match with derived sound device */
2099 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
2100 &num_devices, split_snd_devices) == 0) {
2101 adev->snd_dev_ref_cnt[usecase->out_snd_device]--;
2102 for (i = 0; i < num_devices; i++) {
2103 /* Disable devices that do not match with derived sound device */
2104 if (split_snd_devices[i] != derive_snd_device[usecase->id])
2105 disable_snd_device(adev, split_snd_devices[i]);
2106 }
2107 } else {
2108 disable_snd_device(adev, usecase->out_snd_device);
2109 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002110 }
2111 }
2112
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002113 list_for_each(node, &adev->usecase_list) {
2114 usecase = node_to_item(node, struct audio_usecase, list);
2115 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08002116 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
2117 &num_devices, split_snd_devices) == 0) {
2118 /* Enable derived sound device only if it does not match with
2119 one of the split sound devices. This is because the matching
2120 sound device was not disabled */
2121 bool should_enable = true;
2122 for (i = 0; i < num_devices; i++) {
2123 if (derive_snd_device[usecase->id] == split_snd_devices[i]) {
2124 should_enable = false;
2125 break;
2126 }
2127 }
2128 if (should_enable)
2129 enable_snd_device(adev, derive_snd_device[usecase->id]);
2130 } else {
2131 enable_snd_device(adev, derive_snd_device[usecase->id]);
2132 }
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002133 }
2134 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002135
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002136 /* Re-route all the usecases on the shared backend other than the
2137 specified usecase to new snd devices */
2138 list_for_each(node, &adev->usecase_list) {
2139 usecase = node_to_item(node, struct audio_usecase, list);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302140 /* Update the out_snd_device only before enabling the audio route */
2141 if (switch_device[usecase->id]) {
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05302142 usecase->out_snd_device = derive_snd_device[usecase->id];
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302143 ALOGD("%s:becf: enabling usecase (%s) on (%s)", __func__,
2144 use_case_table[usecase->id],
2145 platform_get_snd_device_name(usecase->out_snd_device));
2146 /* Update voc calibration before enabling Voice/VoIP route */
2147 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
2148 status = platform_switch_voice_call_device_post(adev->platform,
2149 usecase->out_snd_device,
2150 platform_get_input_snd_device(
2151 adev->platform, NULL,
2152 &uc_info->device_list,
2153 usecase->type));
2154 enable_audio_route(adev, usecase);
2155 if (usecase->stream.out && usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
2156 out_set_voip_volume(&usecase->stream.out->stream,
2157 usecase->stream.out->volume_l,
2158 usecase->stream.out->volume_r);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302159 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002160 }
2161 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002162 }
2163}
2164
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302165static void check_usecases_capture_codec_backend(struct audio_device *adev,
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002166 struct audio_usecase *uc_info,
2167 snd_device_t snd_device)
2168{
2169 struct listnode *node;
2170 struct audio_usecase *usecase;
2171 bool switch_device[AUDIO_USECASE_MAX];
2172 int i, num_uc_to_switch = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002173 int backend_check_cond = is_codec_backend_out_device_type(&uc_info->device_list);
kunleiz5cd52b82016-11-07 17:22:52 +08002174 int status = 0;
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002175
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302176 bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
2177 snd_device);
2178 ALOGD("%s:becf: force routing %d", __func__, force_routing);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302179
2180 /*
2181 * Make sure out devices is checked against out codec backend device and
2182 * also in devices against in codec backend. Checking out device against in
2183 * codec backend or vice versa causes issues.
2184 */
2185 if (uc_info->type == PCM_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002186 backend_check_cond = is_codec_backend_in_device_type(&uc_info->device_list);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002187
2188 /*
2189 * Island cfg and power mode config needs to set before AFE port start.
2190 * Set force routing in case of voice device was enable before.
2191 */
2192
2193 if (uc_info->type == VOICE_CALL &&
2194 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002195 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002196 platform_check_and_update_island_power_status(adev->platform,
2197 uc_info,
2198 snd_device)) {
2199 force_routing = true;
2200 ALOGD("%s:becf: force routing %d for power mode supported device",
2201 __func__, force_routing);
2202 }
2203
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002204 /*
2205 * This function is to make sure that all the active capture usecases
2206 * are always routed to the same input sound device.
2207 * For example, if audio-record and voice-call usecases are currently
2208 * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
2209 * is received for voice call then we have to make sure that audio-record
2210 * usecase is also switched to earpiece i.e. voice-dmic-ef,
2211 * because of the limitation that two devices cannot be enabled
2212 * at the same time if they share the same backend.
2213 */
2214 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2215 switch_device[i] = false;
2216
2217 list_for_each(node, &adev->usecase_list) {
2218 usecase = node_to_item(node, struct audio_usecase, list);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302219 /*
2220 * TODO: Enhance below condition to handle BT sco/USB multi recording
2221 */
Jaideep Sharma477917f2020-03-13 18:13:33 +05302222
2223 bool capture_uc_needs_routing = usecase->type != PCM_PLAYBACK && (usecase != uc_info &&
2224 (usecase->in_snd_device != snd_device || force_routing));
2225 bool call_proxy_snd_device = platform_is_call_proxy_snd_device(snd_device) ||
2226 platform_is_call_proxy_snd_device(usecase->in_snd_device);
2227 if (capture_uc_needs_routing && !call_proxy_snd_device &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002228 ((backend_check_cond &&
2229 (is_codec_backend_in_device_type(&usecase->device_list) ||
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08002230 (usecase->type == VOIP_CALL))) ||
Carter Hsu1d2a0532018-10-04 09:24:36 +08002231 ((uc_info->type == VOICE_CALL &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002232 is_single_device_type_equal(&usecase->device_list,
2233 AUDIO_DEVICE_IN_VOICE_CALL)) ||
Anver sadhique4fdc6992022-01-21 12:26:28 +05302234 platform_check_all_backends_match(snd_device,\
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002235 usecase->in_snd_device))) &&
Anish Kumara020a7c2014-10-17 11:13:22 -07002236 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05302237 ALOGD("%s: Usecase (%s) is active on (%s) - disabling ..",
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002238 __func__, use_case_table[usecase->id],
Devin Kim1e5f3532013-08-09 07:48:29 -07002239 platform_get_snd_device_name(usecase->in_snd_device));
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002240 disable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002241 switch_device[usecase->id] = true;
2242 num_uc_to_switch++;
2243 }
2244 }
2245
2246 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002247 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002248
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302249 /* Make sure the previous devices to be disabled first and then enable the
2250 selected devices */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002251 list_for_each(node, &adev->usecase_list) {
2252 usecase = node_to_item(node, struct audio_usecase, list);
2253 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002254 disable_snd_device(adev, usecase->in_snd_device);
Shiv Maliyappanahalli80ac6282013-12-20 18:56:15 -08002255 }
2256 }
2257
2258 list_for_each(node, &adev->usecase_list) {
2259 usecase = node_to_item(node, struct audio_usecase, list);
2260 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002261 enable_snd_device(adev, snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002262 }
2263 }
2264
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002265 /* Re-route all the usecases on the shared backend other than the
2266 specified usecase to new snd devices */
2267 list_for_each(node, &adev->usecase_list) {
2268 usecase = node_to_item(node, struct audio_usecase, list);
2269 /* Update the in_snd_device only before enabling the audio route */
2270 if (switch_device[usecase->id] ) {
2271 usecase->in_snd_device = snd_device;
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302272 /* Update voc calibration before enabling Voice/VoIP route */
2273 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
2274 snd_device_t voip_snd_device;
2275 voip_snd_device = platform_get_output_snd_device(adev->platform,
2276 usecase->stream.out,
2277 usecase->type);
2278 status = platform_switch_voice_call_device_post(adev->platform,
2279 voip_snd_device,
2280 usecase->in_snd_device);
kunleiz5cd52b82016-11-07 17:22:52 +08002281 }
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302282 enable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002283 }
2284 }
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002285 }
2286}
2287
Mingming Yin3a941d42016-02-17 18:08:05 -08002288static void reset_hdmi_sink_caps(struct stream_out *out) {
2289 int i = 0;
2290
2291 for (i = 0; i<= MAX_SUPPORTED_CHANNEL_MASKS; i++) {
2292 out->supported_channel_masks[i] = 0;
2293 }
2294 for (i = 0; i<= MAX_SUPPORTED_FORMATS; i++) {
2295 out->supported_formats[i] = 0;
2296 }
2297 for (i = 0; i<= MAX_SUPPORTED_SAMPLE_RATES; i++) {
2298 out->supported_sample_rates[i] = 0;
2299 }
2300}
2301
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002302/* must be called with hw device mutex locked */
Mingming Yin3a941d42016-02-17 18:08:05 -08002303static int read_hdmi_sink_caps(struct stream_out *out)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002304{
Mingming Yin3a941d42016-02-17 18:08:05 -08002305 int ret = 0, i = 0, j = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002306 int channels = platform_edid_get_max_channels_v2(out->dev->platform,
2307 out->extconn.cs.controller,
2308 out->extconn.cs.stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002309
Mingming Yin3a941d42016-02-17 18:08:05 -08002310 reset_hdmi_sink_caps(out);
2311
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002312 /* Cache ext disp type */
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002313 ret = platform_get_ext_disp_type_v2(adev->platform,
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002314 out->extconn.cs.controller,
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002315 out->extconn.cs.stream);
2316 if(ret < 0) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002317 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Garmond Leung37850ab2016-10-06 11:42:18 -07002318 return -EINVAL;
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002319 }
2320
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002321 switch (channels) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002322 case 8:
Mingming Yin3a941d42016-02-17 18:08:05 -08002323 ALOGV("%s: HDMI supports 7.1 channels", __func__);
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07002324 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_7POINT1;
Mingming Yin3a941d42016-02-17 18:08:05 -08002325 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_6POINT1;
2326 case 6:
2327 ALOGV("%s: HDMI supports 5.1 channels", __func__);
2328 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
2329 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
2330 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
2331 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_SURROUND;
2332 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_2POINT1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002333 break;
2334 default:
Mingming Yin3a941d42016-02-17 18:08:05 -08002335 ALOGE("invalid/nonstandard channal count[%d]",channels);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002336 ret = -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002337 break;
2338 }
Mingming Yin3a941d42016-02-17 18:08:05 -08002339
2340 // check channel format caps
2341 i = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002342 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_AC3,
2343 out->extconn.cs.controller,
2344 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002345 ALOGV(":%s HDMI supports AC3/EAC3 formats", __func__);
2346 out->supported_formats[i++] = AUDIO_FORMAT_AC3;
2347 //Adding EAC3/EAC3_JOC formats if AC3 is supported by the sink.
2348 //EAC3/EAC3_JOC will be converted to AC3 for decoding if needed
2349 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
2350 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
2351 }
2352
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002353 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD,
2354 out->extconn.cs.controller,
2355 out->extconn.cs.stream)) {
Ben Romberger1aaaf862017-04-06 17:49:46 -07002356 ALOGV(":%s HDMI supports TRUE HD format", __func__);
2357 out->supported_formats[i++] = AUDIO_FORMAT_DOLBY_TRUEHD;
2358 }
2359
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002360 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS,
2361 out->extconn.cs.controller,
2362 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002363 ALOGV(":%s HDMI supports DTS format", __func__);
2364 out->supported_formats[i++] = AUDIO_FORMAT_DTS;
2365 }
2366
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002367 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS_HD,
2368 out->extconn.cs.controller,
2369 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002370 ALOGV(":%s HDMI supports DTS HD format", __func__);
2371 out->supported_formats[i++] = AUDIO_FORMAT_DTS_HD;
2372 }
2373
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002374 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_IEC61937,
2375 out->extconn.cs.controller,
2376 out->extconn.cs.stream)) {
Naresh Tanniru928f0862017-04-07 16:44:23 -07002377 ALOGV(":%s HDMI supports IEC61937 format", __func__);
2378 out->supported_formats[i++] = AUDIO_FORMAT_IEC61937;
2379 }
2380
Mingming Yin3a941d42016-02-17 18:08:05 -08002381
2382 // check sample rate caps
2383 i = 0;
2384 for (j = 0; j < MAX_SUPPORTED_SAMPLE_RATES; j++) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002385 if (platform_is_edid_supported_sample_rate_v2(out->dev->platform, out_hdmi_sample_rates[j],
2386 out->extconn.cs.controller,
2387 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002388 ALOGV(":%s HDMI supports sample rate:%d", __func__, out_hdmi_sample_rates[j]);
2389 out->supported_sample_rates[i++] = out_hdmi_sample_rates[j];
2390 }
2391 }
2392
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002393 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002394}
2395
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002396static inline ssize_t read_usb_sup_sample_rates(bool is_playback __unused,
2397 uint32_t *supported_sample_rates __unused,
2398 uint32_t max_rates __unused)
2399{
2400 ssize_t count = audio_extn_usb_get_sup_sample_rates(is_playback,
2401 supported_sample_rates,
2402 max_rates);
Ashish Jain4847e9d2017-08-17 19:16:57 +05302403 ssize_t i = 0;
2404
2405 for (i=0; i<count; i++) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002406 ALOGV("%s %s %d", __func__, is_playback ? "P" : "C",
2407 supported_sample_rates[i]);
2408 }
2409 return count;
2410}
2411
2412static inline int read_usb_sup_channel_masks(bool is_playback,
2413 audio_channel_mask_t *supported_channel_masks,
2414 uint32_t max_masks)
2415{
2416 int channels = audio_extn_usb_get_max_channels(is_playback);
2417 int channel_count;
2418 uint32_t num_masks = 0;
2419 if (channels > MAX_HIFI_CHANNEL_COUNT)
2420 channels = MAX_HIFI_CHANNEL_COUNT;
2421
2422 if (is_playback) {
Eric Laurent68a87112019-05-01 18:07:29 -07002423 // start from 2 channels as framework currently doesn't support mono.
2424 if (channels >= FCC_2) {
2425 supported_channel_masks[num_masks++] = audio_channel_out_mask_from_count(FCC_2);
2426 }
2427 for (channel_count = FCC_2;
2428 channel_count <= channels && num_masks < max_masks;
2429 ++channel_count) {
2430 supported_channel_masks[num_masks++] =
2431 audio_channel_mask_for_index_assignment_from_count(channel_count);
2432 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002433 } else {
vincenttewf51c94e2019-05-07 10:28:53 +08002434 // For capture we report all supported channel masks from 1 channel up.
2435 channel_count = MIN_CHANNEL_COUNT;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002436 // audio_channel_in_mask_from_count() does the right conversion to either positional or
2437 // indexed mask
Eric Laurent68a87112019-05-01 18:07:29 -07002438 for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
2439 audio_channel_mask_t mask = AUDIO_CHANNEL_NONE;
2440 if (channel_count <= FCC_2) {
2441 mask = audio_channel_in_mask_from_count(channel_count);
2442 supported_channel_masks[num_masks++] = mask;
2443 }
2444 const audio_channel_mask_t index_mask =
2445 audio_channel_mask_for_index_assignment_from_count(channel_count);
2446 if (mask != index_mask && num_masks < max_masks) { // ensure index mask added.
2447 supported_channel_masks[num_masks++] = index_mask;
2448 }
2449 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002450 }
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302451
vincenttewf51c94e2019-05-07 10:28:53 +08002452 for (size_t i = 0; i < num_masks; ++i) {
2453 ALOGV("%s: %s supported ch %d supported_channel_masks[%zu] %08x num_masks %d", __func__,
2454 is_playback ? "P" : "C", channels, i, supported_channel_masks[i], num_masks);
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302455 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002456 return num_masks;
2457}
2458
2459static inline int read_usb_sup_formats(bool is_playback __unused,
2460 audio_format_t *supported_formats,
2461 uint32_t max_formats __unused)
2462{
2463 int bitwidth = audio_extn_usb_get_max_bit_width(is_playback);
2464 switch (bitwidth) {
2465 case 24:
2466 // XXX : usb.c returns 24 for s24 and s24_le?
2467 supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
2468 break;
2469 case 32:
2470 supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
2471 break;
2472 case 16:
2473 default :
2474 supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
2475 break;
2476 }
2477 ALOGV("%s: %s supported format %d", __func__,
2478 is_playback ? "P" : "C", bitwidth);
2479 return 1;
2480}
2481
2482static inline int read_usb_sup_params_and_compare(bool is_playback,
2483 audio_format_t *format,
2484 audio_format_t *supported_formats,
2485 uint32_t max_formats,
2486 audio_channel_mask_t *mask,
2487 audio_channel_mask_t *supported_channel_masks,
2488 uint32_t max_masks,
2489 uint32_t *rate,
2490 uint32_t *supported_sample_rates,
2491 uint32_t max_rates) {
2492 int ret = 0;
2493 int num_formats;
2494 int num_masks;
2495 int num_rates;
2496 int i;
2497
2498 num_formats = read_usb_sup_formats(is_playback, supported_formats,
2499 max_formats);
2500 num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
2501 max_masks);
2502
2503 num_rates = read_usb_sup_sample_rates(is_playback,
2504 supported_sample_rates, max_rates);
2505
2506#define LUT(table, len, what, dflt) \
2507 for (i=0; i<len && (table[i] != what); i++); \
2508 if (i==len) { ret |= (what == dflt ? 0 : -1); what=table[0]; }
2509
2510 LUT(supported_formats, num_formats, *format, AUDIO_FORMAT_DEFAULT);
2511 LUT(supported_channel_masks, num_masks, *mask, AUDIO_CHANNEL_NONE);
2512 LUT(supported_sample_rates, num_rates, *rate, 0);
2513
2514#undef LUT
2515 return ret < 0 ? -EINVAL : 0; // HACK TBD
2516}
2517
Alexy Josephb1379942016-01-29 15:49:38 -08002518audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002519 usecase_type_t type)
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002520{
2521 struct audio_usecase *usecase;
2522 struct listnode *node;
2523
2524 list_for_each(node, &adev->usecase_list) {
2525 usecase = node_to_item(node, struct audio_usecase, list);
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002526 if (usecase->type == type) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002527 ALOGV("%s: usecase id %d", __func__, usecase->id);
2528 return usecase->id;
2529 }
2530 }
2531 return USECASE_INVALID;
2532}
2533
Alexy Josephb1379942016-01-29 15:49:38 -08002534struct audio_usecase *get_usecase_from_list(const struct audio_device *adev,
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002535 audio_usecase_t uc_id)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002536{
2537 struct audio_usecase *usecase;
2538 struct listnode *node;
2539
2540 list_for_each(node, &adev->usecase_list) {
2541 usecase = node_to_item(node, struct audio_usecase, list);
2542 if (usecase->id == uc_id)
2543 return usecase;
2544 }
2545 return NULL;
2546}
2547
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302548/*
2549 * is a true native playback active
2550 */
2551bool audio_is_true_native_stream_active(struct audio_device *adev)
2552{
2553 bool active = false;
2554 int i = 0;
2555 struct listnode *node;
2556
2557 if (NATIVE_AUDIO_MODE_TRUE_44_1 != platform_get_native_support()) {
2558 ALOGV("%s:napb: not in true mode or non hdphones device",
2559 __func__);
2560 active = false;
2561 goto exit;
2562 }
2563
2564 list_for_each(node, &adev->usecase_list) {
2565 struct audio_usecase *uc;
2566 uc = node_to_item(node, struct audio_usecase, list);
2567 struct stream_out *curr_out =
2568 (struct stream_out*) uc->stream.out;
2569
2570 if (curr_out && PCM_PLAYBACK == uc->type) {
2571 ALOGD("%s:napb: (%d) (%s)id (%d) sr %d bw "
2572 "(%d) device %s", __func__, i++, use_case_table[uc->id],
2573 uc->id, curr_out->sample_rate,
2574 curr_out->bit_width,
2575 platform_get_snd_device_name(uc->out_snd_device));
2576
2577 if (is_offload_usecase(uc->id) &&
2578 (curr_out->sample_rate == OUTPUT_SAMPLING_RATE_44100)) {
2579 active = true;
2580 ALOGD("%s:napb:native stream detected", __func__);
2581 }
2582 }
2583 }
2584exit:
2585 return active;
2586}
2587
Xiaojun Sang785b5da2017-08-03 15:52:29 +08002588uint32_t adev_get_dsp_bit_width_enforce_mode()
2589{
2590 if (adev == NULL) {
2591 ALOGE("%s: adev is null. Disable DSP bit width enforce mode.\n", __func__);
2592 return 0;
2593 }
2594 return adev->dsp_bit_width_enforce_mode;
2595}
2596
2597static uint32_t adev_init_dsp_bit_width_enforce_mode(struct mixer *mixer)
2598{
2599 char value[PROPERTY_VALUE_MAX];
2600 int trial;
2601 uint32_t dsp_bit_width_enforce_mode = 0;
2602
2603 if (!mixer) {
2604 ALOGE("%s: adev mixer is null. cannot update DSP bitwidth.\n",
2605 __func__);
2606 return 0;
2607 }
2608
2609 if (property_get("persist.vendor.audio_hal.dsp_bit_width_enforce_mode",
2610 value, NULL) > 0) {
2611 trial = atoi(value);
2612 switch (trial) {
2613 case 16:
2614 dsp_bit_width_enforce_mode = 16;
2615 break;
2616 case 24:
2617 dsp_bit_width_enforce_mode = 24;
2618 break;
2619 case 32:
2620 dsp_bit_width_enforce_mode = 32;
2621 break;
2622 default:
2623 dsp_bit_width_enforce_mode = 0;
2624 ALOGD("%s Dynamic DSP bitwidth config is disabled.", __func__);
2625 break;
2626 }
2627 }
2628
2629 return dsp_bit_width_enforce_mode;
2630}
2631
2632static void audio_enable_asm_bit_width_enforce_mode(struct mixer *mixer,
2633 uint32_t enforce_mode,
2634 bool enable)
2635{
2636 struct mixer_ctl *ctl = NULL;
2637 const char *mixer_ctl_name = "ASM Bit Width";
2638 uint32_t asm_bit_width_mode = 0;
2639
2640 if (enforce_mode == 0) {
2641 ALOGD("%s: DSP bitwidth feature is disabled.", __func__);
2642 return;
2643 }
2644
2645 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
2646 if (!ctl) {
2647 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2648 __func__, mixer_ctl_name);
2649 return;
2650 }
2651
2652 if (enable)
2653 asm_bit_width_mode = enforce_mode;
2654 else
2655 asm_bit_width_mode = 0;
2656
2657 ALOGV("%s DSP bit width feature status is %d width=%d",
2658 __func__, enable, asm_bit_width_mode);
2659 if (mixer_ctl_set_value(ctl, 0, asm_bit_width_mode) < 0)
2660 ALOGE("%s: Could not set ASM biwidth %d", __func__,
2661 asm_bit_width_mode);
2662
2663 return;
2664}
2665
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302666/*
2667 * if native DSD playback active
2668 */
2669bool audio_is_dsd_native_stream_active(struct audio_device *adev)
2670{
2671 bool active = false;
2672 struct listnode *node = NULL;
2673 struct audio_usecase *uc = NULL;
2674 struct stream_out *curr_out = NULL;
2675
2676 list_for_each(node, &adev->usecase_list) {
2677 uc = node_to_item(node, struct audio_usecase, list);
2678 curr_out = (struct stream_out*) uc->stream.out;
2679
2680 if (curr_out && PCM_PLAYBACK == uc->type &&
2681 (DSD_NATIVE_BACKEND == platform_get_backend_index(uc->out_snd_device))) {
2682 active = true;
2683 ALOGV("%s:DSD playback is active", __func__);
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05302684 break;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302685 }
2686 }
2687 return active;
2688}
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302689
2690static bool force_device_switch(struct audio_usecase *usecase)
2691{
2692 bool ret = false;
2693 bool is_it_true_mode = false;
2694
Zhou Song30f2c3e2018-02-08 14:02:15 +08002695 if (usecase->type == PCM_CAPTURE ||
Surendar Karka93cd25a2018-08-28 14:21:37 +05302696 usecase->type == TRANSCODE_LOOPBACK_RX ||
2697 usecase->type == TRANSCODE_LOOPBACK_TX) {
Zhou Song30f2c3e2018-02-08 14:02:15 +08002698 return false;
2699 }
2700
Aalique Grahamecbc46a22017-10-05 10:30:23 -07002701 if(usecase->stream.out == NULL) {
2702 ALOGE("%s: stream.out is NULL", __func__);
2703 return false;
2704 }
2705
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302706 if (is_offload_usecase(usecase->id) &&
Xiaojun Sang869f2012016-02-23 16:33:07 +08002707 (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002708 (compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
2709 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302710 is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
2711 if ((is_it_true_mode && !adev->native_playback_enabled) ||
2712 (!is_it_true_mode && adev->native_playback_enabled)){
2713 ret = true;
2714 ALOGD("napb: time to toggle native mode");
2715 }
2716 }
2717
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302718 // Force all a2dp output devices to reconfigure for proper AFE encode format
Ashish Jainc597d102016-12-12 10:31:34 +05302719 //Also handle a case where in earlier a2dp start failed as A2DP stream was
2720 //in suspended state, hence try to trigger a retry when we again get a routing request.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002721 if(is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Ashish Jainc597d102016-12-12 10:31:34 +05302722 audio_extn_a2dp_is_force_device_switch()) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302723 ALOGD("Force a2dp device switch to update new encoder config");
2724 ret = true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002725 }
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302726
Florian Pfister1a84f312018-07-19 14:38:18 +02002727 if (usecase->stream.out->stream_config_changed) {
Manish Dewangan671a4202017-08-18 17:30:46 +05302728 ALOGD("Force stream_config_changed to update iec61937 transmission config");
2729 return true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002730 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302731 return ret;
2732}
2733
Aalique Grahame22e49102018-12-18 14:23:57 -08002734static void stream_app_type_cfg_init(struct stream_app_type_cfg *cfg)
2735{
2736 cfg->gain[0] = cfg->gain[1] = APP_TYPE_GAIN_DEFAULT;
2737}
2738
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302739bool is_btsco_device(snd_device_t out_snd_device, snd_device_t in_snd_device)
2740{
2741 bool ret=false;
2742 if ((out_snd_device == SND_DEVICE_OUT_BT_SCO ||
Zhou Song5657f492019-08-07 11:30:39 +08002743 out_snd_device == SND_DEVICE_OUT_BT_SCO_WB ||
2744 out_snd_device == SND_DEVICE_OUT_BT_SCO_SWB) ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302745 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC ||
2746 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB ||
Zhou Song5657f492019-08-07 11:30:39 +08002747 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302748 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC ||
Mingshu Pang16093502020-04-20 11:21:16 +08002749 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC ||
2750 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC)
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302751 ret = true;
2752
2753 return ret;
2754}
2755
2756bool is_a2dp_device(snd_device_t out_snd_device)
2757{
2758 bool ret=false;
2759 if (out_snd_device == SND_DEVICE_OUT_BT_A2DP)
2760 ret = true;
2761
2762 return ret;
2763}
2764
2765bool is_bt_soc_on(struct audio_device *adev)
2766{
2767 struct mixer_ctl *ctl;
2768 char *mixer_ctl_name = "BT SOC status";
2769 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
2770 bool bt_soc_status = true;
2771 if (!ctl) {
2772 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2773 __func__, mixer_ctl_name);
2774 /*This is to ensure we dont break targets which dont have the kernel change*/
2775 return true;
2776 }
2777 bt_soc_status = mixer_ctl_get_value(ctl, 0);
2778 ALOGD("BT SOC status: %d",bt_soc_status);
2779 return bt_soc_status;
2780}
2781
Zhou Song331c8e52019-08-26 14:16:12 +08002782static int configure_btsco_sample_rate(snd_device_t snd_device)
2783{
2784 struct mixer_ctl *ctl = NULL;
2785 struct mixer_ctl *ctl_sr_rx = NULL, *ctl_sr_tx = NULL, *ctl_sr = NULL;
2786 char *rate_str = NULL;
2787 bool is_rx_dev = true;
2788
2789 if (is_btsco_device(snd_device, snd_device)) {
2790 ctl_sr_tx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate TX");
2791 ctl_sr_rx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate RX");
2792 if (!ctl_sr_tx || !ctl_sr_rx) {
2793 ctl_sr = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate");
2794 if (!ctl_sr)
2795 return -ENOSYS;
2796 }
2797
2798 switch (snd_device) {
2799 case SND_DEVICE_OUT_BT_SCO:
2800 rate_str = "KHZ_8";
2801 break;
2802 case SND_DEVICE_IN_BT_SCO_MIC_NREC:
2803 case SND_DEVICE_IN_BT_SCO_MIC:
2804 rate_str = "KHZ_8";
2805 is_rx_dev = false;
2806 break;
2807 case SND_DEVICE_OUT_BT_SCO_WB:
2808 rate_str = "KHZ_16";
2809 break;
2810 case SND_DEVICE_IN_BT_SCO_MIC_WB_NREC:
2811 case SND_DEVICE_IN_BT_SCO_MIC_WB:
2812 rate_str = "KHZ_16";
2813 is_rx_dev = false;
2814 break;
2815 default:
2816 return 0;
2817 }
2818
2819 ctl = (ctl_sr == NULL) ? (is_rx_dev ? ctl_sr_rx : ctl_sr_tx) : ctl_sr;
2820 if (mixer_ctl_set_enum_by_string(ctl, rate_str) != 0)
2821 return -ENOSYS;
2822 }
2823 return 0;
2824}
2825
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302826int out_standby_l(struct audio_stream *stream);
2827
Eric Laurent637e2d42018-11-15 12:24:31 -08002828struct stream_in *adev_get_active_input(const struct audio_device *adev)
2829{
2830 struct listnode *node;
2831 struct stream_in *last_active_in = NULL;
2832
2833 /* Get last added active input.
2834 * TODO: We may use a priority mechanism to pick highest priority active source */
2835 list_for_each(node, &adev->usecase_list)
2836 {
2837 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2838 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL)
2839 last_active_in = usecase->stream.in;
2840 }
2841
2842 return last_active_in;
2843}
2844
2845struct stream_in *get_voice_communication_input(const struct audio_device *adev)
2846{
2847 struct listnode *node;
2848
2849 /* First check active inputs with voice communication source and then
2850 * any input if audio mode is in communication */
2851 list_for_each(node, &adev->usecase_list)
2852 {
2853 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2854 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL &&
2855 usecase->stream.in->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
2856 return usecase->stream.in;
2857 }
2858 if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
2859 return adev_get_active_input(adev);
2860
2861 return NULL;
2862}
2863
Carter Hsu2e429db2019-05-14 18:50:52 +08002864/*
2865 * Aligned with policy.h
2866 */
2867static inline int source_priority(int inputSource)
2868{
2869 switch (inputSource) {
2870 case AUDIO_SOURCE_VOICE_COMMUNICATION:
2871 return 9;
2872 case AUDIO_SOURCE_CAMCORDER:
2873 return 8;
2874 case AUDIO_SOURCE_VOICE_PERFORMANCE:
2875 return 7;
2876 case AUDIO_SOURCE_UNPROCESSED:
2877 return 6;
2878 case AUDIO_SOURCE_MIC:
2879 return 5;
2880 case AUDIO_SOURCE_ECHO_REFERENCE:
2881 return 4;
2882 case AUDIO_SOURCE_FM_TUNER:
2883 return 3;
2884 case AUDIO_SOURCE_VOICE_RECOGNITION:
2885 return 2;
2886 case AUDIO_SOURCE_HOTWORD:
2887 return 1;
2888 default:
2889 break;
2890 }
2891 return 0;
2892}
2893
2894static struct stream_in *get_priority_input(struct audio_device *adev)
2895{
2896 struct listnode *node;
2897 struct audio_usecase *usecase;
2898 int last_priority = 0, priority;
2899 struct stream_in *priority_in = NULL;
2900 struct stream_in *in;
2901
2902 list_for_each(node, &adev->usecase_list) {
2903 usecase = node_to_item(node, struct audio_usecase, list);
2904 if (usecase->type == PCM_CAPTURE) {
2905 in = usecase->stream.in;
2906 if (!in)
2907 continue;
Krishna Kishor Jha0b7175d2022-07-28 22:33:46 +05302908
2909 if (USECASE_AUDIO_RECORD_FM_VIRTUAL == usecase->id)
2910 continue;
Carter Hsu2e429db2019-05-14 18:50:52 +08002911 priority = source_priority(in->source);
2912
2913 if (priority > last_priority) {
2914 last_priority = priority;
2915 priority_in = in;
2916 }
2917 }
2918 }
2919 return priority_in;
2920}
2921
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002922int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002923{
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08002924 snd_device_t out_snd_device = SND_DEVICE_NONE;
2925 snd_device_t in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002926 struct audio_usecase *usecase = NULL;
2927 struct audio_usecase *vc_usecase = NULL;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002928 struct audio_usecase *voip_usecase = NULL;
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002929 struct audio_usecase *hfp_usecase = NULL;
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302930 struct stream_out stream_out;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08002931 audio_usecase_t hfp_ucid;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002932 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002933
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302934 ALOGD("%s for use case (%s)", __func__, use_case_table[uc_id]);
2935
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002936 usecase = get_usecase_from_list(adev, uc_id);
2937 if (usecase == NULL) {
2938 ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
2939 return -EINVAL;
2940 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002941
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002942 if ((usecase->type == VOICE_CALL) ||
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08002943 (usecase->type == VOIP_CALL) ||
Derek Chena30a5f42019-12-03 11:17:09 -05002944 (usecase->type == PCM_HFP_CALL)||
Fei Tongaffdf732020-02-20 20:39:05 +08002945 (usecase->type == ICC_CALL) ||
2946 (usecase->type == SYNTH_LOOPBACK)) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302947 if(usecase->stream.out == NULL) {
2948 ALOGE("%s: stream.out is NULL", __func__);
2949 return -EINVAL;
2950 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002951 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS)) {
Guodong Hu267bdf82019-08-12 19:22:32 +08002952 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
2953 uc_id);
2954 in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
2955 uc_id);
2956 } else {
2957 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302958 usecase->stream.out, usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002959 in_snd_device = platform_get_input_snd_device(adev->platform,
2960 NULL,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302961 &usecase->stream.out->device_list,
2962 usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002963 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002964 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302965 } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
Siddartha Shaik31b530e2017-05-19 15:26:33 +05302966 if (usecase->stream.inout == NULL) {
2967 ALOGE("%s: stream.inout is NULL", __func__);
2968 return -EINVAL;
2969 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002970 assign_devices(&stream_out.device_list, &usecase->stream.inout->out_config.device_list);
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302971 stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
2972 stream_out.format = usecase->stream.inout->out_config.format;
2973 stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
Jaideep Sharma477917f2020-03-13 18:13:33 +05302974 out_snd_device = platform_get_output_snd_device(adev->platform, &stream_out, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002975 assign_devices(&usecase->device_list,
2976 &usecase->stream.inout->out_config.device_list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05302977 clear_devices(&stream_out.device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302978 } else if (usecase->type == TRANSCODE_LOOPBACK_TX ) {
2979 if (usecase->stream.inout == NULL) {
2980 ALOGE("%s: stream.inout is NULL", __func__);
2981 return -EINVAL;
2982 }
Manisha Agarwal03297972020-04-17 15:36:55 +05302983 struct listnode out_devices;
2984 list_init(&out_devices);
2985 in_snd_device = platform_get_input_snd_device(adev->platform, NULL,
2986 &out_devices, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002987 assign_devices(&usecase->device_list,
2988 &usecase->stream.inout->in_config.device_list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05302989 clear_devices(&out_devices);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002990 } else {
2991 /*
2992 * If the voice call is active, use the sound devices of voice call usecase
2993 * so that it would not result any device switch. All the usecases will
2994 * be switched to new device when select_devices() is called for voice call
2995 * usecase. This is to avoid switching devices for voice call when
2996 * check_usecases_codec_backend() is called below.
Alexy Joseph79dfa3c2016-04-20 18:44:56 -07002997 * choose voice call device only if the use case device is
2998 * also using the codec backend
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002999 */
Shiv Maliyappanahallibb4cf0b2016-01-21 11:30:06 -08003000 if (voice_is_in_call(adev) && adev->mode != AUDIO_MODE_NORMAL) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07003001 vc_usecase = get_usecase_from_list(adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08003002 get_usecase_id_from_usecase_type(adev, VOICE_CALL));
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003003 if ((vc_usecase) && ((is_codec_backend_out_device_type(&vc_usecase->device_list) &&
3004 is_codec_backend_out_device_type(&usecase->device_list)) ||
3005 (is_codec_backend_out_device_type(&vc_usecase->device_list) &&
3006 is_codec_backend_in_device_type(&usecase->device_list)) ||
3007 is_single_device_type_equal(&vc_usecase->device_list,
3008 AUDIO_DEVICE_OUT_HEARING_AID) ||
3009 is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08003010 AUDIO_DEVICE_IN_VOICE_CALL) ||
3011 (is_single_device_type_equal(&usecase->device_list,
Gautam Manam8fa06162021-09-24 10:41:29 +05303012 AUDIO_DEVICE_IN_BUILTIN_MIC) &&
3013 is_single_device_type_equal(&vc_usecase->device_list,
3014 AUDIO_DEVICE_OUT_USB_HEADSET)) ||
3015 (is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08003016 AUDIO_DEVICE_IN_USB_HEADSET) &&
3017 is_single_device_type_equal(&vc_usecase->device_list,
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05303018 AUDIO_DEVICE_OUT_USB_HEADSET))||
Gautam Manamf4002142021-09-13 22:05:56 +05303019 (is_single_device_type_equal(&usecase->device_list,
3020 AUDIO_DEVICE_IN_USB_HEADSET) &&
3021 is_codec_backend_out_device_type(&vc_usecase->device_list)) ||
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05303022 (is_single_device_type_equal(&usecase->device_list,
3023 AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) &&
3024 is_codec_backend_out_device_type(&vc_usecase->device_list)))) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003025 in_snd_device = vc_usecase->in_snd_device;
3026 out_snd_device = vc_usecase->out_snd_device;
3027 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08003028 } else if (voice_extn_compress_voip_is_active(adev)) {
yidongh02ef86f2017-04-21 15:36:04 +08003029 bool out_snd_device_backend_match = true;
yidongh47785a82017-05-08 19:29:29 +08003030 voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
yidongh6261d8e2017-05-15 17:04:02 +08003031 if ((voip_usecase != NULL) &&
3032 (usecase->type == PCM_PLAYBACK) &&
3033 (usecase->stream.out != NULL)) {
yidongh02ef86f2017-04-21 15:36:04 +08003034 out_snd_device_backend_match = platform_check_backends_match(
3035 voip_usecase->out_snd_device,
3036 platform_get_output_snd_device(
3037 adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05303038 usecase->stream.out, usecase->type));
yidongh02ef86f2017-04-21 15:36:04 +08003039 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003040 if ((voip_usecase) && (is_codec_backend_out_device_type(&voip_usecase->device_list) &&
3041 (is_codec_backend_out_device_type(&usecase->device_list) ||
3042 is_codec_backend_in_device_type(&usecase->device_list)) &&
yidongh02ef86f2017-04-21 15:36:04 +08003043 out_snd_device_backend_match &&
Mingming Yin2d8aa2e2014-08-14 00:00:51 -07003044 (voip_usecase->stream.out != adev->primary_output))) {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08003045 in_snd_device = voip_usecase->in_snd_device;
3046 out_snd_device = voip_usecase->out_snd_device;
3047 }
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08003048 } else if (audio_extn_hfp_is_active(adev)) {
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08003049 hfp_ucid = audio_extn_hfp_get_usecase();
3050 hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003051 if ((hfp_usecase) && is_codec_backend_out_device_type(&hfp_usecase->device_list)) {
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08003052 in_snd_device = hfp_usecase->in_snd_device;
3053 out_snd_device = hfp_usecase->out_snd_device;
3054 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003055 }
3056 if (usecase->type == PCM_PLAYBACK) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05303057 if (usecase->stream.out == NULL) {
3058 ALOGE("%s: stream.out is NULL", __func__);
3059 return -EINVAL;
3060 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003061 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003062 in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003063 if (out_snd_device == SND_DEVICE_NONE) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003064 struct stream_out *voip_out = adev->primary_output;
3065 struct stream_in *voip_in = get_voice_communication_input(adev);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003066 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
Guodong Hu267bdf82019-08-12 19:22:32 +08003067 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
3068 else
3069 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05303070 usecase->stream.out,
3071 usecase->type);
kunleizdcf967a2018-08-07 17:09:11 +08003072 voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP);
kunleizdcf967a2018-08-07 17:09:11 +08003073
Eric Laurent637e2d42018-11-15 12:24:31 -08003074 if (voip_usecase)
3075 voip_out = voip_usecase->stream.out;
3076
3077 if (usecase->stream.out == voip_out && voip_in != NULL)
3078 select_devices(adev, voip_in->usecase);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003079 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003080 } else if (usecase->type == PCM_CAPTURE) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05303081 if (usecase->stream.in == NULL) {
3082 ALOGE("%s: stream.in is NULL", __func__);
3083 return -EINVAL;
3084 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003085 assign_devices(&usecase->device_list, &usecase->stream.in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003086 out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003087 if (in_snd_device == SND_DEVICE_NONE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003088 struct listnode out_devices;
Eric Laurent637e2d42018-11-15 12:24:31 -08003089 struct stream_in *voip_in = get_voice_communication_input(adev);
Carter Hsu2e429db2019-05-14 18:50:52 +08003090 struct stream_in *priority_in = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08003091
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003092 list_init(&out_devices);
Eric Laurent637e2d42018-11-15 12:24:31 -08003093 if (voip_in != NULL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003094 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3095 USECASE_AUDIO_PLAYBACK_VOIP);
3096
Carter Hsu2e429db2019-05-14 18:50:52 +08003097 usecase->stream.in->enable_ec_port = false;
3098
Zhou Song503196b2021-07-23 17:31:05 +08003099 if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY ||
3100 usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY2) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003101 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08003102 } else if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003103 assign_devices(&out_devices, &voip_usecase->stream.out->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08003104 } else if (adev->primary_output &&
3105 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003106 assign_devices(&out_devices, &adev->primary_output->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08003107 } else {
3108 /* forcing speaker o/p device to get matching i/p pair
3109 in case o/p is not routed from same primary HAL */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003110 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08003111 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003112 priority_in = voip_in;
3113 } else {
3114 /* get the input with the highest priority source*/
3115 priority_in = get_priority_input(adev);
3116
Susan Wang727dd6b2021-03-26 11:28:59 -04003117 if (!priority_in ||
3118 audio_extn_auto_hal_overwrite_priority_for_auto(usecase->stream.in))
Carter Hsu2e429db2019-05-14 18:50:52 +08003119 priority_in = usecase->stream.in;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003120 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04003121 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_IN_BUS)){
3122 in_snd_device = audio_extn_auto_hal_get_snd_device_for_car_audio_stream(priority_in->car_audio_stream);
3123 }
3124 else
3125 in_snd_device = platform_get_input_snd_device(adev->platform,
3126 priority_in,
3127 &out_devices,
3128 usecase->type);
Zhenlin Lian4f947842022-05-14 15:50:52 +05303129 clear_devices(&out_devices);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003130 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003131 }
3132 }
3133
3134 if (out_snd_device == usecase->out_snd_device &&
3135 in_snd_device == usecase->in_snd_device) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05303136
3137 if (!force_device_switch(usecase))
3138 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003139 }
3140
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003141 if (!compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) &&
Guodong Hu267bdf82019-08-12 19:22:32 +08003142 ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003143 (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
Guodong Hu267bdf82019-08-12 19:22:32 +08003144 ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
3145 return 0;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303146 }
3147
Aalique Grahame22e49102018-12-18 14:23:57 -08003148 if (out_snd_device != SND_DEVICE_NONE &&
3149 out_snd_device != adev->last_logged_snd_device[uc_id][0]) {
3150 ALOGD("%s: changing use case %s output device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3151 __func__,
3152 use_case_table[uc_id],
3153 adev->last_logged_snd_device[uc_id][0],
3154 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][0]),
3155 adev->last_logged_snd_device[uc_id][0] != SND_DEVICE_NONE ?
3156 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][0]) :
3157 -1,
3158 out_snd_device,
3159 platform_get_snd_device_name(out_snd_device),
3160 platform_get_snd_device_acdb_id(out_snd_device));
3161 adev->last_logged_snd_device[uc_id][0] = out_snd_device;
3162 }
3163 if (in_snd_device != SND_DEVICE_NONE &&
3164 in_snd_device != adev->last_logged_snd_device[uc_id][1]) {
3165 ALOGD("%s: changing use case %s input device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3166 __func__,
3167 use_case_table[uc_id],
3168 adev->last_logged_snd_device[uc_id][1],
3169 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][1]),
3170 adev->last_logged_snd_device[uc_id][1] != SND_DEVICE_NONE ?
3171 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][1]) :
3172 -1,
3173 in_snd_device,
3174 platform_get_snd_device_name(in_snd_device),
3175 platform_get_snd_device_acdb_id(in_snd_device));
3176 adev->last_logged_snd_device[uc_id][1] = in_snd_device;
3177 }
3178
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08003179
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003180 /*
3181 * Limitation: While in call, to do a device switch we need to disable
3182 * and enable both RX and TX devices though one of them is same as current
3183 * device.
3184 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003185 if ((usecase->type == VOICE_CALL) &&
3186 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3187 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Eric Laurentb23d5282013-05-14 15:27:20 -07003188 status = platform_switch_voice_call_device_pre(adev->platform);
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003189 }
3190
3191 if (((usecase->type == VOICE_CALL) ||
3192 (usecase->type == VOIP_CALL)) &&
3193 (usecase->out_snd_device != SND_DEVICE_NONE)) {
3194 /* Disable sidetone only if voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303195 if (voice_is_call_state_active_in_call(adev) ||
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003196 voice_extn_compress_voip_is_started(adev))
Bhalchandra Gajare45fee282015-06-09 22:23:45 -07003197 voice_set_sidetone(adev, usecase->out_snd_device, false);
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003198
3199 /* Disable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303200 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003201 voice_check_and_update_aanc_path(adev, usecase->out_snd_device, false);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003202 }
3203
Aalique Grahame22e49102018-12-18 14:23:57 -08003204 if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
3205 out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02003206 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303207 ALOGW("%s: A2DP profile is not ready, routing to speaker only", __func__);
Aalique Grahame22e49102018-12-18 14:23:57 -08003208 if (out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)
3209 out_snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
3210 else
3211 out_snd_device = SND_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303212 }
3213
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003214 /* Disable current sound devices */
3215 if (usecase->out_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003216 disable_audio_route(adev, usecase);
3217 disable_snd_device(adev, usecase->out_snd_device);
Gautam Manam274f4752021-09-24 10:58:49 +05303218 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3219 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003220 }
3221
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003222 if (usecase->in_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003223 disable_audio_route(adev, usecase);
3224 disable_snd_device(adev, usecase->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003225 }
3226
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003227 /* Applicable only on the targets that has external modem.
3228 * New device information should be sent to modem before enabling
3229 * the devices to reduce in-call device switch time.
3230 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003231 if ((usecase->type == VOICE_CALL) &&
3232 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3233 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003234 status = platform_switch_voice_call_enable_device_config(adev->platform,
3235 out_snd_device,
3236 in_snd_device);
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003237 }
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003238
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003239 /* Enable new sound devices */
3240 if (out_snd_device != SND_DEVICE_NONE) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08003241 check_usecases_codec_backend(adev, usecase, out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05303242 check_and_configure_headphone(adev, usecase, out_snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05303243 if (platform_check_codec_asrc_support(adev->platform))
3244 check_and_set_asrc_mode(adev, usecase, out_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003245 enable_snd_device(adev, out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08003246 /* Enable haptics device for haptic usecase */
3247 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3248 enable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003249 }
3250
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003251 if (in_snd_device != SND_DEVICE_NONE) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05303252 check_usecases_capture_codec_backend(adev, usecase, in_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003253 enable_snd_device(adev, in_snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003254 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003255
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05303256 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
Eric Laurentb23d5282013-05-14 15:27:20 -07003257 status = platform_switch_voice_call_device_post(adev->platform,
3258 out_snd_device,
3259 in_snd_device);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003260
sangwoo170731f2013-06-08 15:36:36 +09003261 usecase->in_snd_device = in_snd_device;
3262 usecase->out_snd_device = out_snd_device;
3263
Dhananjay Kumard6d32152016-10-13 16:11:03 +05303264 audio_extn_utils_update_stream_app_type_cfg_for_usecase(adev,
3265 usecase);
Preetam Singh Ranawata4a37d82014-09-25 16:56:38 +05303266 if (usecase->type == PCM_PLAYBACK) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003267 if ((24 == usecase->stream.out->bit_width) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003268 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_SPEAKER)) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003269 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3270 } else if ((out_snd_device == SND_DEVICE_OUT_HDMI ||
3271 out_snd_device == SND_DEVICE_OUT_USB_HEADSET ||
3272 out_snd_device == SND_DEVICE_OUT_DISPLAY_PORT) &&
3273 (usecase->stream.out->sample_rate >= OUTPUT_SAMPLING_RATE_44100)) {
3274 /*
3275 * To best utlize DSP, check if the stream sample rate is supported/multiple of
3276 * configured device sample rate, if not update the COPP rate to be equal to the
3277 * device sample rate, else open COPP at stream sample rate
3278 */
3279 platform_check_and_update_copp_sample_rate(adev->platform, out_snd_device,
3280 usecase->stream.out->sample_rate,
3281 &usecase->stream.out->app_type_cfg.sample_rate);
Ashish Jain4826f6c2017-02-06 13:33:20 +05303282 } else if (((out_snd_device != SND_DEVICE_OUT_HEADPHONES_44_1 &&
Preetam Singh Ranawat590d0432019-09-30 14:39:47 +05303283 out_snd_device != SND_DEVICE_OUT_HEADPHONES &&
3284 out_snd_device != SND_DEVICE_OUT_HEADPHONES_HIFI_FILTER &&
Ashish Jain4826f6c2017-02-06 13:33:20 +05303285 !audio_is_true_native_stream_active(adev)) &&
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003286 usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) ||
3287 (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +05303288#ifdef PLATFORM_AUTO
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05303289 if (!(compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) && ((usecase->stream.out->flags &
3290 (audio_output_flags_t)AUDIO_OUTPUT_FLAG_SYS_NOTIFICATION) || (usecase->stream.out->flags &
3291 (audio_output_flags_t)AUDIO_OUTPUT_FLAG_PHONE)))) {
3292 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3293 }
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +05303294#else
3295 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3296#endif
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003297 }
Weiyin Jiangcdece202019-07-08 16:13:16 +08003298 }
3299 enable_audio_route(adev, usecase);
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003300
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303301 if (uc_id == USECASE_AUDIO_PLAYBACK_VOIP) {
3302 struct stream_in *voip_in = get_voice_communication_input(adev);
3303 struct audio_usecase *voip_in_usecase = NULL;
3304 voip_in_usecase = get_usecase_from_list(adev, USECASE_AUDIO_RECORD_VOIP);
3305 if (voip_in != NULL &&
3306 voip_in_usecase != NULL &&
3307 !(out_snd_device == AUDIO_DEVICE_OUT_SPEAKER ||
3308 out_snd_device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
3309 (voip_in_usecase->in_snd_device ==
3310 platform_get_input_snd_device(adev->platform, voip_in,
3311 &usecase->stream.out->device_list,usecase->type))) {
3312 /*
3313 * if VOIP TX is enabled before VOIP RX, needs to re-route the TX path
3314 * for enabling echo-reference-voip with correct port
3315 */
3316 ALOGD("%s: VOIP TX is enabled before VOIP RX,needs to re-route the TX path",__func__);
3317 disable_audio_route(adev, voip_in_usecase);
3318 disable_snd_device(adev, voip_in_usecase->in_snd_device);
3319 enable_snd_device(adev, voip_in_usecase->in_snd_device);
3320 enable_audio_route(adev, voip_in_usecase);
3321 }
3322 }
Ramjee Singhcdf67af2021-09-29 14:20:27 +05303323 if (voice_extn_compress_voip_is_active(adev)) {
3324 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3325 USECASE_COMPRESS_VOIP_CALL);
3326 /*
3327 * If only compress voip input is opened voip out will be primary out.
3328 * Need to consider re-routing to select correct i/p pair
3329 */
3330 if ((voip_usecase != NULL) &&
3331 (usecase->type == PCM_PLAYBACK) &&
3332 (usecase->stream.out == voip_usecase->stream.out)) {
3333 in_snd_device = platform_get_input_snd_device(adev->platform,
3334 NULL,
3335 &usecase->stream.out->device_list,
3336 usecase->type);
3337 if (voip_usecase->in_snd_device != in_snd_device ) {
3338 ALOGD("%s:Re routing compress voip tx snd device matching voip rx pair",
3339 __func__);
3340 disable_audio_route(adev, voip_usecase);
3341 disable_snd_device(adev, voip_usecase->in_snd_device);
3342 voip_usecase->in_snd_device = in_snd_device;
3343 voip_usecase->out_snd_device = usecase->out_snd_device;
3344 /* Route all TX usecase to Compress voip BE */
3345 check_usecases_capture_codec_backend(adev, voip_usecase, in_snd_device);
3346 enable_snd_device(adev, in_snd_device);
3347 /* Send Voice related calibration for RX /TX pair */
3348 status = platform_switch_voice_call_device_post(adev->platform,
3349 out_snd_device,
3350 in_snd_device);
3351 enable_audio_route(adev, voip_usecase);
3352 }
3353 }
3354 }
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303355
3356
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08003357 audio_extn_qdsp_set_device(usecase);
Aalique Grahame22e49102018-12-18 14:23:57 -08003358
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003359 /* If input stream is already running then effect needs to be
3360 applied on the new input device that's being enabled here. */
Eric Laurent637e2d42018-11-15 12:24:31 -08003361 if (in_snd_device != SND_DEVICE_NONE)
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003362 check_and_enable_effect(adev);
3363
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003364 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003365 /* Enable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303366 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003367 voice_check_and_update_aanc_path(adev, out_snd_device, true);
3368
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003369 /* Enable sidetone only if other voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303370 if (voice_is_call_state_active_in_call(adev) ||
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003371 voice_extn_compress_voip_is_started(adev))
3372 voice_set_sidetone(adev, out_snd_device, true);
3373 }
3374
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003375 /* Applicable only on the targets that has external modem.
3376 * Enable device command should be sent to modem only after
3377 * enabling voice call mixer controls
3378 */
Vidyakumar Athota339342f2014-07-01 15:30:57 -07003379 if (usecase->type == VOICE_CALL)
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003380 status = platform_switch_voice_call_usecase_route_post(adev->platform,
3381 out_snd_device,
3382 in_snd_device);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303383
3384 if (is_btsco_device(out_snd_device, in_snd_device) || is_a2dp_device(out_snd_device)) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003385 struct stream_in *in = adev_get_active_input(adev);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303386 if (usecase->type == VOIP_CALL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003387 if (in != NULL && !in->standby) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303388 if (is_bt_soc_on(adev) == false){
3389 ALOGD("BT SCO MIC disconnected while in connection");
Eric Laurent637e2d42018-11-15 12:24:31 -08003390 if (in->pcm != NULL)
3391 pcm_stop(in->pcm);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303392 }
3393 }
3394 if ((usecase->stream.out != NULL) && (usecase->stream.out != adev->primary_output)
3395 && usecase->stream.out->started) {
3396 if (is_bt_soc_on(adev) == false) {
3397 ALOGD("BT SCO/A2DP disconnected while in connection");
3398 out_standby_l(&usecase->stream.out->stream.common);
3399 }
3400 }
3401 } else if ((usecase->stream.out != NULL) &&
3402 !(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Surendar Karkae1dc8742018-11-19 16:23:14 +05303403 (usecase->type != TRANSCODE_LOOPBACK_TX) &&
3404 (usecase->type != TRANSCODE_LOOPBACK_RX) &&
Weiyin Jiang0d373242019-07-25 13:18:17 +08003405 (usecase->type != PCM_CAPTURE) &&
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303406 usecase->stream.out->started) {
3407 if (is_bt_soc_on(adev) == false) {
3408 ALOGD("BT SCO/A2dp disconnected while in connection");
3409 out_standby_l(&usecase->stream.out->stream.common);
3410 }
3411 }
3412 }
3413
Yung Ti Su70cb8242018-06-22 17:38:47 +08003414 if (usecase->type != PCM_CAPTURE && usecase == voip_usecase) {
Aalique Grahame22e49102018-12-18 14:23:57 -08003415 struct stream_out *voip_out = voip_usecase->stream.out;
3416 audio_extn_utils_send_app_type_gain(adev,
3417 voip_out->app_type_cfg.app_type,
3418 &voip_out->app_type_cfg.gain[0]);
3419 }
3420
Ajender Reddyb940b832021-07-07 11:51:42 +05303421 ALOGD("%s: done",__func__);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303422
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003423 return status;
3424}
3425
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003426static int stop_input_stream(struct stream_in *in)
3427{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303428 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003429 struct audio_usecase *uc_info;
Pallavid7c7a272018-01-16 11:22:55 +05303430
3431 if (in == NULL) {
3432 ALOGE("%s: stream_in ptr is NULL", __func__);
3433 return -EINVAL;
3434 }
3435
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003436 struct audio_device *adev = in->dev;
Carter Hsu2e429db2019-05-14 18:50:52 +08003437 struct stream_in *priority_in = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003438
Eric Laurent994a6932013-07-17 11:51:42 -07003439 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003440 in->usecase, use_case_table[in->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003441 uc_info = get_usecase_from_list(adev, in->usecase);
3442 if (uc_info == NULL) {
3443 ALOGE("%s: Could not find the usecase (%d) in the list",
3444 __func__, in->usecase);
3445 return -EINVAL;
3446 }
3447
Carter Hsu2e429db2019-05-14 18:50:52 +08003448 priority_in = get_priority_input(adev);
3449
Derek Chenea197282019-01-07 17:35:01 -08003450 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3451 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003452
Vidyakumar Athota2850d532013-11-19 16:02:12 -08003453 /* Close in-call recording streams */
3454 voice_check_and_stop_incall_rec_usecase(adev, in);
3455
Eric Laurent150dbfe2013-02-27 14:31:02 -08003456 /* 1. Disable stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003457 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003458
3459 /* 2. Disable the tx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003460 disable_snd_device(adev, uc_info->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003461
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003462 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303463 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
3464
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003465 list_remove(&uc_info->list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05303466 clear_devices(&uc_info->device_list);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003467 free(uc_info);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003468
Carter Hsu2e429db2019-05-14 18:50:52 +08003469 if (priority_in == in) {
3470 priority_in = get_priority_input(adev);
Sujin Panicker110f7942021-08-26 17:01:22 +05303471 if (priority_in) {
3472 if (is_usb_in_device_type(&priority_in->device_list)) {
3473 if (audio_extn_usb_connected(NULL))
3474 select_devices(adev, priority_in->usecase);
3475 } else {
3476 select_devices(adev, priority_in->usecase);
3477 }
3478 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003479 }
3480
Vatsal Buchac09ae062018-11-14 13:25:08 +05303481 enable_gcov();
Eric Laurent994a6932013-07-17 11:51:42 -07003482 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003483 return ret;
3484}
3485
3486int start_input_stream(struct stream_in *in)
3487{
3488 /* 1. Enable output device and stream routing controls */
Eric Laurentc8400632013-02-14 19:04:54 -08003489 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003490 struct audio_usecase *uc_info;
Preetam Singh Ranawata87e9742018-02-13 16:52:53 +05303491
3492 if (in == NULL) {
3493 ALOGE("%s: stream_in ptr is NULL", __func__);
3494 return -EINVAL;
3495 }
3496
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003497 struct audio_device *adev = in->dev;
Garmond Leunge2433c32017-09-28 21:51:22 -07003498 struct pcm_config config = in->config;
Garmond Leung438932f2017-10-04 19:35:18 -07003499 int usecase = platform_update_usecase_from_source(in->source,in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003500
Mingming Yin2664a5b2015-09-03 10:53:11 -07003501 if (get_usecase_from_list(adev, usecase) == NULL)
3502 in->usecase = usecase;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303503 ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
3504 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003505
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303506 if (CARD_STATUS_OFFLINE == in->card_status||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003507 CARD_STATUS_OFFLINE == adev->card_status ||
3508 POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
3509 ALOGW("in->card_status or adev->card_status or adev->input_power offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05303510 ret = -EIO;
Naresh Tanniru4c630392014-05-12 01:05:52 +05303511 goto error_config;
3512 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05303513
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003514 if (is_sco_in_device_type(&in->device_list)) {
Lakshman Chaluvaraju87f53aa2021-02-02 15:50:11 +05303515 if (!adev->bt_sco_on || audio_extn_a2dp_source_is_ready()) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303516 ALOGE("%s: SCO profile is not ready, return error", __func__);
3517 ret = -EIO;
3518 goto error_config;
3519 }
3520 }
3521
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003522 /* Check if source matches incall recording usecase criteria */
3523 ret = voice_check_and_set_incall_rec_usecase(adev, in);
3524 if (ret)
3525 goto error_config;
3526 else
Mingming Yin2664a5b2015-09-03 10:53:11 -07003527 ALOGV("%s: usecase(%d)", __func__, in->usecase);
3528
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303529 if (audio_extn_cin_attached_usecase(in))
3530 audio_extn_cin_acquire_usecase(in);
3531
Mingming Yin2664a5b2015-09-03 10:53:11 -07003532 if (get_usecase_from_list(adev, in->usecase) != NULL) {
3533 ALOGE("%s: use case assigned already in use, stream(%p)usecase(%d: %s)",
3534 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003535 ret = -EINVAL;
3536 goto error_config;
Mingming Yin2664a5b2015-09-03 10:53:11 -07003537 }
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003538
Eric Laurentb23d5282013-05-14 15:27:20 -07003539 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003540 if (in->pcm_device_id < 0) {
3541 ALOGE("%s: Could not find PCM device id for the usecase(%d)",
3542 __func__, in->usecase);
Eric Laurentc8400632013-02-14 19:04:54 -08003543 ret = -EINVAL;
3544 goto error_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003545 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003546
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003547 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003548
3549 if (!uc_info) {
3550 ret = -ENOMEM;
3551 goto error_config;
3552 }
3553
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003554 uc_info->id = in->usecase;
3555 uc_info->type = PCM_CAPTURE;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003556 uc_info->stream.in = in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003557 list_init(&uc_info->device_list);
3558 assign_devices(&uc_info->device_list, &in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003559 uc_info->in_snd_device = SND_DEVICE_NONE;
3560 uc_info->out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003561
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003562 list_add_tail(&adev->usecase_list, &uc_info->list);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003563 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303564 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
3565 adev->perf_lock_opts,
3566 adev->perf_lock_opts_size);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003567 select_devices(adev, in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003568
Derek Chenea197282019-01-07 17:35:01 -08003569 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
3570 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003571
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05303572 android_atomic_acquire_cas(true, false, &(in->capture_stopped));
3573
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303574 if (audio_extn_cin_attached_usecase(in)) {
Manish Dewangan46e07982018-12-13 18:18:59 +05303575 ret = audio_extn_cin_open_input_stream(in);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303576 if (ret)
3577 goto error_open;
3578 else
3579 goto done_open;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003580 }
3581
Haynes Mathew George16081042017-05-31 17:16:49 -07003582 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003583 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003584 ALOGE("%s: pcm stream not ready", __func__);
3585 goto error_open;
3586 }
3587 ret = pcm_start(in->pcm);
3588 if (ret < 0) {
3589 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
3590 goto error_open;
3591 }
3592 } else {
3593 unsigned int flags = PCM_IN | PCM_MONOTONIC;
3594 unsigned int pcm_open_retry_count = 0;
3595
Zhou Song62ea0282020-03-22 19:53:01 +08003596 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) ||
3597 (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003598 flags |= PCM_MMAP | PCM_NOIRQ;
3599 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
3600 } else if (in->realtime) {
3601 flags |= PCM_MMAP | PCM_NOIRQ;
3602 }
3603
Garmond Leunge2433c32017-09-28 21:51:22 -07003604 if (audio_extn_ffv_get_stream() == in) {
3605 ALOGD("%s: ffv stream, update pcm config", __func__);
3606 audio_extn_ffv_update_pcm_config(&config);
3607 }
Haynes Mathew George16081042017-05-31 17:16:49 -07003608 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
3609 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
3610
3611 while (1) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003612 ATRACE_BEGIN("pcm_in_open");
Haynes Mathew George16081042017-05-31 17:16:49 -07003613 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
Garmond Leung438932f2017-10-04 19:35:18 -07003614 flags, &config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003615 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05303616 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05303617 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
3618 adev->card_status = CARD_STATUS_OFFLINE;
3619 in->card_status = CARD_STATUS_OFFLINE;
3620 ret = -EIO;
3621 goto error_open;
3622 }
3623
Haynes Mathew George16081042017-05-31 17:16:49 -07003624 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
3625 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
3626 if (in->pcm != NULL) {
3627 pcm_close(in->pcm);
3628 in->pcm = NULL;
3629 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003630 if (pcm_open_retry_count == 0) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003631 ret = -EIO;
3632 goto error_open;
3633 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003634 pcm_open_retry_count--;
Haynes Mathew George16081042017-05-31 17:16:49 -07003635 usleep(PROXY_OPEN_WAIT_TIME * 1000);
3636 continue;
3637 }
3638 break;
3639 }
3640
3641 ALOGV("%s: pcm_prepare", __func__);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003642 ATRACE_BEGIN("pcm_in_prepare");
Haynes Mathew George16081042017-05-31 17:16:49 -07003643 ret = pcm_prepare(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003644 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003645 if (ret < 0) {
3646 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
3647 pcm_close(in->pcm);
3648 in->pcm = NULL;
3649 goto error_open;
3650 }
Narsinga Rao Chellaa6e1f702021-10-22 13:57:32 +05303651 if (in->flags == AUDIO_INPUT_FLAG_FAST)
3652 register_in_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07003653 if (in->realtime) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003654 ATRACE_BEGIN("pcm_in_start");
Haynes Mathew George16081042017-05-31 17:16:49 -07003655 ret = pcm_start(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003656 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003657 if (ret < 0) {
3658 ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003659 pcm_close(in->pcm);
3660 in->pcm = NULL;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003661 goto error_open;
3662 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003663 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07003664 }
3665
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003666 check_and_enable_effect(adev);
justinweng20fb6d82019-02-21 18:49:00 -07003667 audio_extn_audiozoom_set_microphone_direction(in, in->zoom);
3668 audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003669
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003670 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303671 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
3672
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303673done_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003674 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303675 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Manisha Agarwal4c2402e2020-10-21 12:02:57 +05303676 ALOGD("%s: exit", __func__);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303677 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003678 return ret;
3679
3680error_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003681 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303682 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003683 stop_input_stream(in);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003684
Eric Laurentc8400632013-02-14 19:04:54 -08003685error_config:
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003686 if (audio_extn_cin_attached_usecase(in))
3687 audio_extn_cin_close_input_stream(in);
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05303688 /*
3689 * sleep 50ms to allow sufficient time for kernel
3690 * drivers to recover incases like SSR.
3691 */
3692 usleep(50000);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003693 ALOGD("%s: exit: status(%d)", __func__, ret);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303694 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003695 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003696}
3697
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003698void lock_input_stream(struct stream_in *in)
3699{
3700 pthread_mutex_lock(&in->pre_lock);
3701 pthread_mutex_lock(&in->lock);
3702 pthread_mutex_unlock(&in->pre_lock);
3703}
3704
3705void lock_output_stream(struct stream_out *out)
3706{
3707 pthread_mutex_lock(&out->pre_lock);
3708 pthread_mutex_lock(&out->lock);
3709 pthread_mutex_unlock(&out->pre_lock);
3710}
3711
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003712/* must be called with out->lock locked */
3713static int send_offload_cmd_l(struct stream_out* out, int command)
3714{
3715 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
3716
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003717 if (!cmd) {
3718 ALOGE("failed to allocate mem for command 0x%x", command);
3719 return -ENOMEM;
3720 }
3721
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003722 ALOGVV("%s %d", __func__, command);
3723
3724 cmd->cmd = command;
3725 list_add_tail(&out->offload_cmd_list, &cmd->node);
3726 pthread_cond_signal(&out->offload_cond);
3727 return 0;
3728}
3729
Gautam Manam14c198b2020-12-24 14:08:04 +05303730/* must be called with out->lock */
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003731static void stop_compressed_output_l(struct stream_out *out)
3732{
Gautam Manam14c198b2020-12-24 14:08:04 +05303733 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003734 out->offload_state = OFFLOAD_STATE_IDLE;
Gautam Manam14c198b2020-12-24 14:08:04 +05303735 pthread_mutex_unlock(&out->latch_lock);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08003736
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003737 out->playback_started = 0;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07003738 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003739 if (out->compr != NULL) {
3740 compress_stop(out->compr);
3741 while (out->offload_thread_blocked) {
3742 pthread_cond_wait(&out->cond, &out->lock);
3743 }
3744 }
3745}
3746
Varun Balaraje49253e2017-07-06 19:48:56 +05303747bool is_interactive_usecase(audio_usecase_t uc_id)
3748{
3749 unsigned int i;
3750 for (i = 0; i < sizeof(interactive_usecases)/sizeof(interactive_usecases[0]); i++) {
3751 if (uc_id == interactive_usecases[i])
3752 return true;
3753 }
3754 return false;
3755}
3756
3757static audio_usecase_t get_interactive_usecase(struct audio_device *adev)
3758{
3759 audio_usecase_t ret_uc = USECASE_INVALID;
3760 unsigned int intract_uc_index;
3761 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3762
3763 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
3764 for (intract_uc_index = 0; intract_uc_index < num_usecase; intract_uc_index++) {
3765 if (!(adev->interactive_usecase_state & (0x1 << intract_uc_index))) {
3766 adev->interactive_usecase_state |= 0x1 << intract_uc_index;
3767 ret_uc = interactive_usecases[intract_uc_index];
3768 break;
3769 }
3770 }
3771
3772 ALOGV("%s: Interactive usecase is %d", __func__, ret_uc);
3773 return ret_uc;
3774}
3775
3776static void free_interactive_usecase(struct audio_device *adev,
3777 audio_usecase_t uc_id)
3778{
3779 unsigned int interact_uc_index;
3780 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3781
3782 for (interact_uc_index = 0; interact_uc_index < num_usecase; interact_uc_index++) {
3783 if (interactive_usecases[interact_uc_index] == uc_id) {
3784 adev->interactive_usecase_state &= ~(0x1 << interact_uc_index);
3785 break;
3786 }
3787 }
3788 ALOGV("%s: free Interactive usecase %d", __func__, uc_id);
3789}
3790
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003791bool is_offload_usecase(audio_usecase_t uc_id)
3792{
3793 unsigned int i;
3794 for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
3795 if (uc_id == offload_usecases[i])
3796 return true;
3797 }
3798 return false;
3799}
3800
Dhananjay Kumarac341582017-02-23 23:42:25 +05303801static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_compress)
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003802{
vivek mehta446c3962015-09-14 10:57:35 -07003803 audio_usecase_t ret_uc = USECASE_INVALID;
3804 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003805 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003806 if (!adev->multi_offload_enable) {
Dhananjay Kumarac341582017-02-23 23:42:25 +05303807 if (!is_compress)
vivek mehta446c3962015-09-14 10:57:35 -07003808 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
3809 else
3810 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003811
vivek mehta446c3962015-09-14 10:57:35 -07003812 pthread_mutex_lock(&adev->lock);
3813 if (get_usecase_from_list(adev, ret_uc) != NULL)
3814 ret_uc = USECASE_INVALID;
3815 pthread_mutex_unlock(&adev->lock);
3816
3817 return ret_uc;
3818 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003819
3820 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
vivek mehta446c3962015-09-14 10:57:35 -07003821 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3822 if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) {
3823 adev->offload_usecases_state |= 0x1 << offload_uc_index;
3824 ret_uc = offload_usecases[offload_uc_index];
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003825 break;
3826 }
3827 }
vivek mehta446c3962015-09-14 10:57:35 -07003828
3829 ALOGV("%s: offload usecase is %d", __func__, ret_uc);
3830 return ret_uc;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003831}
3832
3833static void free_offload_usecase(struct audio_device *adev,
3834 audio_usecase_t uc_id)
3835{
vivek mehta446c3962015-09-14 10:57:35 -07003836 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003837 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003838
3839 if (!adev->multi_offload_enable)
3840 return;
3841
3842 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3843 if (offload_usecases[offload_uc_index] == uc_id) {
3844 adev->offload_usecases_state &= ~(0x1 << offload_uc_index);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003845 break;
3846 }
3847 }
3848 ALOGV("%s: free offload usecase %d", __func__, uc_id);
3849}
3850
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003851static void *offload_thread_loop(void *context)
3852{
3853 struct stream_out *out = (struct stream_out *) context;
3854 struct listnode *item;
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003855 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003856
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003857 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08003858 set_sched_policy(0, SP_FOREGROUND);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003859 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
3860
3861 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003862 lock_output_stream(out);
juyuchen391b5fa2018-12-12 17:58:09 +08003863 out->offload_state = OFFLOAD_STATE_IDLE;
3864 out->playback_started = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003865 for (;;) {
3866 struct offload_cmd *cmd = NULL;
3867 stream_callback_event_t event;
3868 bool send_callback = false;
3869
3870 ALOGVV("%s offload_cmd_list %d out->offload_state %d",
3871 __func__, list_empty(&out->offload_cmd_list),
3872 out->offload_state);
3873 if (list_empty(&out->offload_cmd_list)) {
3874 ALOGV("%s SLEEPING", __func__);
3875 pthread_cond_wait(&out->offload_cond, &out->lock);
3876 ALOGV("%s RUNNING", __func__);
3877 continue;
3878 }
3879
3880 item = list_head(&out->offload_cmd_list);
3881 cmd = node_to_item(item, struct offload_cmd, node);
3882 list_remove(item);
3883
3884 ALOGVV("%s STATE %d CMD %d out->compr %p",
3885 __func__, out->offload_state, cmd->cmd, out->compr);
3886
3887 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
3888 free(cmd);
3889 break;
3890 }
3891
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08003892 // allow OFFLOAD_CMD_ERROR reporting during standby
3893 // this is needed to handle failures during compress_open
3894 // Note however that on a pause timeout, the stream is closed
3895 // and no offload usecase will be active. Therefore this
3896 // special case is needed for compress_open failures alone
3897 if (cmd->cmd != OFFLOAD_CMD_ERROR &&
3898 out->compr == NULL) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003899 ALOGE("%s: Compress handle is NULL", __func__);
Haynes Mathew Georgea9abb202016-06-02 14:13:20 -07003900 free(cmd);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003901 pthread_cond_signal(&out->cond);
3902 continue;
3903 }
3904 out->offload_thread_blocked = true;
3905 pthread_mutex_unlock(&out->lock);
3906 send_callback = false;
3907 switch(cmd->cmd) {
3908 case OFFLOAD_CMD_WAIT_FOR_BUFFER:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003909 ALOGD("copl(%p):calling compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003910 compress_wait(out->compr, -1);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003911 ALOGD("copl(%p):out of compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003912 send_callback = true;
3913 event = STREAM_CBK_EVENT_WRITE_READY;
3914 break;
3915 case OFFLOAD_CMD_PARTIAL_DRAIN:
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003916 ret = compress_next_track(out->compr);
Sidipotu Ashok55820562014-02-10 16:16:38 +05303917 if(ret == 0) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003918 ALOGD("copl(%p):calling compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303919 ret = compress_partial_drain(out->compr);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003920 ALOGD("copl(%p):out of compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303921 if (ret < 0)
3922 ret = -errno;
Sidipotu Ashok55820562014-02-10 16:16:38 +05303923 }
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303924 else if (ret == -ETIMEDOUT)
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003925 ret = compress_drain(out->compr);
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003926 else
3927 ALOGE("%s: Next track returned error %d",__func__, ret);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003928 if (-ENETRESET != ret && !(-EINTR == ret &&
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003929 (CARD_STATUS_OFFLINE == out->card_status ||
3930 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303931 send_callback = true;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05303932 pthread_mutex_lock(&out->lock);
3933 out->send_new_metadata = 1;
3934 out->send_next_track_params = true;
3935 pthread_mutex_unlock(&out->lock);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303936 event = STREAM_CBK_EVENT_DRAIN_READY;
3937 ALOGV("copl(%p):send drain callback, ret %d", out, ret);
3938 } else
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303939 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003940 break;
3941 case OFFLOAD_CMD_DRAIN:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003942 ALOGD("copl(%p):calling compress_drain", out);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003943 ret = compress_drain(out->compr);
3944 ALOGD("copl(%p):out of compress_drain", out);
3945 // EINTR check avoids drain interruption due to SSR
3946 if (-ENETRESET != ret && !(-EINTR == ret &&
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003947 (CARD_STATUS_OFFLINE == out->card_status ||
3948 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003949 send_callback = true;
3950 event = STREAM_CBK_EVENT_DRAIN_READY;
3951 } else
3952 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003953 break;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303954 case OFFLOAD_CMD_ERROR:
3955 ALOGD("copl(%p): sending error callback to AF", out);
3956 send_callback = true;
3957 event = STREAM_CBK_EVENT_ERROR;
3958 break;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003959 default:
3960 ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
3961 break;
3962 }
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003963 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003964 out->offload_thread_blocked = false;
3965 pthread_cond_signal(&out->cond);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08003966 if (send_callback && out->client_callback) {
3967 ALOGVV("%s: sending client_callback event %d", __func__, event);
3968 out->client_callback(event, NULL, out->client_cookie);
Eric Laurent6e895242013-09-05 16:10:57 -07003969 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003970 free(cmd);
3971 }
3972
3973 pthread_cond_signal(&out->cond);
3974 while (!list_empty(&out->offload_cmd_list)) {
3975 item = list_head(&out->offload_cmd_list);
3976 list_remove(item);
3977 free(node_to_item(item, struct offload_cmd, node));
3978 }
3979 pthread_mutex_unlock(&out->lock);
3980
3981 return NULL;
3982}
3983
3984static int create_offload_callback_thread(struct stream_out *out)
3985{
3986 pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
3987 list_init(&out->offload_cmd_list);
3988 pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
3989 offload_thread_loop, out);
3990 return 0;
3991}
3992
3993static int destroy_offload_callback_thread(struct stream_out *out)
3994{
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003995 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003996 stop_compressed_output_l(out);
3997 send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
3998
3999 pthread_mutex_unlock(&out->lock);
4000 pthread_join(out->offload_thread, (void **) NULL);
4001 pthread_cond_destroy(&out->offload_cond);
4002
4003 return 0;
4004}
4005
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004006static int stop_output_stream(struct stream_out *out)
4007{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05304008 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004009 struct audio_usecase *uc_info;
4010 struct audio_device *adev = out->dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08004011 bool has_voip_usecase =
4012 get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP) != NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004013
Eric Laurent994a6932013-07-17 11:51:42 -07004014 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004015 out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004016 uc_info = get_usecase_from_list(adev, out->usecase);
4017 if (uc_info == NULL) {
4018 ALOGE("%s: Could not find the usecase (%d) in the list",
4019 __func__, out->usecase);
4020 return -EINVAL;
4021 }
4022
Zhou Songbaddf9f2020-11-20 13:57:39 +08004023 out->a2dp_muted = false;
4024
Derek Chenea197282019-01-07 17:35:01 -08004025 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
4026 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004027
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004028 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304029 !(audio_extn_passthru_is_passthrough_stream(out))) {
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004030 if (adev->visualizer_stop_output != NULL)
4031 adev->visualizer_stop_output(out->handle, out->pcm_device_id);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004032
4033 audio_extn_dts_remove_state_notifier_node(out->usecase);
4034
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004035 if (adev->offload_effects_stop_output != NULL)
4036 adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
vivek mehtad15d2bf2019-05-17 13:35:10 -07004037 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4038 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4039 audio_low_latency_hint_end();
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004040 }
Eric Laurentc4aef752013-09-12 17:45:53 -07004041
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004042 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4043 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004044 voice_set_device_mute_flag(adev, false);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004045 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004046
Eric Laurent150dbfe2013-02-27 14:31:02 -08004047 /* 1. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07004048 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004049
4050 /* 2. Disable the rx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07004051 disable_snd_device(adev, uc_info->out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08004052 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
4053 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004054
Aalique Grahame22e49102018-12-18 14:23:57 -08004055 audio_extn_extspk_update(adev->extspk);
4056
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004057 if (is_offload_usecase(out->usecase)) {
4058 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4059 adev->dsp_bit_width_enforce_mode,
4060 false);
4061 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004062 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004063 ret = audio_extn_usb_check_and_set_svc_int(uc_info,
4064 false);
4065
4066 if (ret != 0)
4067 check_usecases_codec_backend(adev, uc_info, uc_info->out_snd_device);
4068 /* default service interval was successfully updated,
4069 reopen USB backend with new service interval */
4070 ret = 0;
4071 }
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004072
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004073 list_remove(&uc_info->list);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304074 out->started = 0;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004075 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304076 (audio_extn_passthru_is_passthrough_stream(out))) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004077 ALOGV("Disable passthrough , reset mixer to pcm");
4078 /* NO_PASSTHROUGH */
Meng Wang4c32fb42020-01-16 17:57:11 +08004079#ifdef AUDIO_GKI_ENABLED
4080 /* out->compr_config.codec->reserved[0] is for compr_passthr */
4081 out->compr_config.codec->reserved[0] = 0;
4082#else
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004083 out->compr_config.codec->compr_passthr = 0;
Meng Wang4c32fb42020-01-16 17:57:11 +08004084#endif
Mingming Yin21854652016-04-13 11:54:02 -07004085 audio_extn_passthru_on_stop(out);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004086 audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
4087 }
Eric Laurent07eeafd2013-10-06 12:52:49 -07004088
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304089 /* Must be called after removing the usecase from list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004090 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL))
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304091 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304092
Manish Dewangan21a850a2017-08-14 12:03:55 +05304093 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07004094 ret = audio_extn_ip_hdlr_intf_close(out->ip_hdlr_handle, true, out);
4095 if (ret < 0)
4096 ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
4097 }
4098
Zhou Song642ec432020-12-23 16:11:10 +08004099 /* trigger voip input to reroute when voip output changes to hearing aid */
Aalique Grahame22e49102018-12-18 14:23:57 -08004100 if (has_voip_usecase ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004101 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08004102 struct listnode *node;
4103 struct audio_usecase *usecase;
4104 list_for_each(node, &adev->usecase_list) {
4105 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Song642ec432020-12-23 16:11:10 +08004106 if (usecase->type == PCM_PLAYBACK || usecase == uc_info ||
4107 (usecase->type == PCM_CAPTURE &&
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05304108 usecase->id != USECASE_AUDIO_RECORD_VOIP &&
Zhou Song642ec432020-12-23 16:11:10 +08004109 usecase->id != USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY))
Aalique Grahame22e49102018-12-18 14:23:57 -08004110 continue;
4111
4112 ALOGD("%s: select_devices at usecase(%d: %s) after removing the usecase(%d: %s)",
4113 __func__, usecase->id, use_case_table[usecase->id],
4114 out->usecase, use_case_table[out->usecase]);
4115 select_devices(adev, usecase->id);
4116 }
4117 }
4118
Zhenlin Lian4f947842022-05-14 15:50:52 +05304119 clear_devices(&uc_info->device_list);
Garmond Leung5fd0b552018-04-17 11:56:12 -07004120 free(uc_info);
Eric Laurent994a6932013-07-17 11:51:42 -07004121 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004122 return ret;
4123}
4124
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004125struct pcm* pcm_open_prepare_helper(unsigned int snd_card, unsigned int pcm_device_id,
4126 unsigned int flags, unsigned int pcm_open_retry_count,
4127 struct pcm_config *config)
4128{
4129 struct pcm* pcm = NULL;
4130
4131 while (1) {
4132 pcm = pcm_open(snd_card, pcm_device_id, flags, config);
4133 if (pcm == NULL || !pcm_is_ready(pcm)) {
4134 ALOGE("%s: %s", __func__, pcm_get_error(pcm));
4135 if (pcm != NULL) {
4136 pcm_close(pcm);
4137 pcm = NULL;
4138 }
Weiyin Jiang72197252019-10-09 11:49:32 +08004139 if (pcm_open_retry_count == 0)
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004140 return NULL;
4141
Weiyin Jiang72197252019-10-09 11:49:32 +08004142 pcm_open_retry_count--;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004143 usleep(PROXY_OPEN_WAIT_TIME * 1000);
4144 continue;
4145 }
4146 break;
4147 }
4148
4149 if (pcm_is_ready(pcm)) {
4150 int ret = pcm_prepare(pcm);
4151 if (ret < 0) {
4152 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
4153 pcm_close(pcm);
4154 pcm = NULL;
4155 }
4156 }
4157
4158 return pcm;
4159}
4160
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004161int start_output_stream(struct stream_out *out)
4162{
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004163 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004164 struct audio_usecase *uc_info;
4165 struct audio_device *adev = out->dev;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004166 char mixer_ctl_name[128];
4167 struct mixer_ctl *ctl = NULL;
4168 char* perf_mode[] = {"ULL", "ULL_PP", "LL"};
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304169 bool a2dp_combo = false;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004170 bool is_haptic_usecase = (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) ? true: false;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004171
Haynes Mathew George380745d2017-10-04 15:27:45 -07004172 ATRACE_BEGIN("start_output_stream");
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004173 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
4174 ret = -EINVAL;
4175 goto error_config;
4176 }
4177
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004178 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x) is_haptic_usecase(%d)",
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304179 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004180 get_device_types(&out->device_list), is_haptic_usecase);
4181
4182 bool is_speaker_active = compare_device_type(&out->device_list,
4183 AUDIO_DEVICE_OUT_SPEAKER);
4184 bool is_speaker_safe_active = compare_device_type(&out->device_list,
4185 AUDIO_DEVICE_OUT_SPEAKER_SAFE);
Naresh Tanniru4c630392014-05-12 01:05:52 +05304186
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304187 if (CARD_STATUS_OFFLINE == out->card_status ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05004188 CARD_STATUS_OFFLINE == adev->card_status ||
4189 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304190 ALOGW("out->card_status or adev->card_status offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05304191 ret = -EIO;
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004192 goto error_fatal;
Naresh Tanniru4c630392014-05-12 01:05:52 +05304193 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05304194
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004195 //Update incall music usecase to reflect correct voice session
4196 if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
4197 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
4198 if (ret != 0) {
4199 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
4200 __func__, ret);
4201 goto error_config;
4202 }
4203 }
4204
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004205 if (is_a2dp_out_device_type(&out->device_list)) {
Florian Pfister1a84f312018-07-19 14:38:18 +02004206 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004207 if (is_speaker_active || is_speaker_safe_active) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304208 a2dp_combo = true;
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304209 } else {
Zhou Songd01e7a22020-09-23 22:49:01 +08004210 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304211 ALOGE("%s: A2DP profile is not ready, return error", __func__);
4212 ret = -EAGAIN;
4213 goto error_config;
4214 }
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304215 }
4216 }
4217 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004218 if (is_sco_out_device_type(&out->device_list)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304219 if (!adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004220 if (is_speaker_active) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304221 //combo usecase just by pass a2dp
4222 ALOGW("%s: SCO is not connected, route it to speaker", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004223 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304224 } else {
4225 ALOGE("%s: SCO profile is not ready, return error", __func__);
4226 ret = -EAGAIN;
4227 goto error_config;
4228 }
4229 }
4230 }
4231
Eric Laurentb23d5282013-05-14 15:27:20 -07004232 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004233 if (out->pcm_device_id < 0) {
4234 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
4235 __func__, out->pcm_device_id, out->usecase);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004236 ret = -EINVAL;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004237 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004238 }
4239
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004240 if (is_haptic_usecase) {
Meng Wang51d8c2a2020-04-27 15:23:21 +08004241 adev->haptic_pcm_device_id = platform_get_pcm_device_id(
4242 USECASE_AUDIO_PLAYBACK_HAPTICS, PCM_PLAYBACK);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004243 if (adev->haptic_pcm_device_id < 0) {
4244 ALOGE("%s: Invalid Haptics pcm device id(%d) for the usecase(%d)",
4245 __func__, adev->haptic_pcm_device_id, out->usecase);
4246 ret = -EINVAL;
4247 goto error_config;
4248 }
4249 }
4250
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004251 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004252
4253 if (!uc_info) {
4254 ret = -ENOMEM;
4255 goto error_config;
4256 }
4257
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004258 uc_info->id = out->usecase;
4259 uc_info->type = PCM_PLAYBACK;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08004260 uc_info->stream.out = out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004261 list_init(&uc_info->device_list);
4262 assign_devices(&uc_info->device_list, &out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004263 uc_info->in_snd_device = SND_DEVICE_NONE;
4264 uc_info->out_snd_device = SND_DEVICE_NONE;
Garmond Leung5fd0b552018-04-17 11:56:12 -07004265
4266 /* This must be called before adding this usecase to the list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004267 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004268 audio_extn_usb_check_and_set_svc_int(uc_info, true);
4269 /* USB backend is not reopened immediately.
4270 This is eventually done as part of select_devices */
4271 }
4272
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004273 list_add_tail(&adev->usecase_list, &uc_info->list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004274
Wei Wangf7ca6c92017-11-21 14:51:20 -08004275 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304276 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
4277 adev->perf_lock_opts,
4278 adev->perf_lock_opts_size);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304279
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004280 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304281 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304282 if (audio_extn_passthru_is_enabled() &&
4283 audio_extn_passthru_is_passthrough_stream(out)) {
4284 audio_extn_passthru_on_start(out);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304285 }
4286 }
4287
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004288 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02004289 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304290 if (!a2dp_combo) {
4291 check_a2dp_restore_l(adev, out, false);
4292 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004293 struct listnode dev;
4294 list_init(&dev);
4295 assign_devices(&dev, &out->device_list);
4296 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4297 reassign_device_list(&out->device_list,
4298 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aalique Grahame22e49102018-12-18 14:23:57 -08004299 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004300 reassign_device_list(&out->device_list,
4301 AUDIO_DEVICE_OUT_SPEAKER, "");
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304302 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004303 assign_devices(&out->device_list, &dev);
Zhenlin Lian4f947842022-05-14 15:50:52 +05304304 clear_devices(&dev);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304305 }
4306 } else {
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304307 select_devices(adev, out->usecase);
4308 if (is_a2dp_out_device_type(&out->device_list) &&
4309 !adev->a2dp_started) {
4310 if (is_speaker_active || is_speaker_safe_active) {
4311 struct listnode dev;
4312 list_init(&dev);
4313 assign_devices(&dev, &out->device_list);
4314 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4315 reassign_device_list(&out->device_list,
4316 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
4317 else
4318 reassign_device_list(&out->device_list,
4319 AUDIO_DEVICE_OUT_SPEAKER, "");
4320 select_devices(adev, out->usecase);
4321 assign_devices(&out->device_list, &dev);
Zhenlin Lian4f947842022-05-14 15:50:52 +05304322 clear_devices(&dev);
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304323 } else {
4324 ret = -EINVAL;
4325 goto error_open;
4326 }
4327 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304328 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004329
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004330 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4331 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004332 voice_set_device_mute_flag(adev, true);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004333 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004334
Derek Chenea197282019-01-07 17:35:01 -08004335 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
4336 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004337
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004338 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
4339 __func__, adev->snd_card, out->pcm_device_id, out->config.format);
Haynes Mathew George16081042017-05-31 17:16:49 -07004340
4341 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07004342 ALOGD("%s: Starting MMAP stream", __func__);
Haynes Mathew George16081042017-05-31 17:16:49 -07004343 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4344 ALOGE("%s: pcm stream not ready", __func__);
4345 goto error_open;
4346 }
4347 ret = pcm_start(out->pcm);
4348 if (ret < 0) {
4349 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
4350 goto error_open;
4351 }
Arun Mirpuri5d170872019-03-26 13:21:31 -07004352 out_set_mmap_volume(&out->stream, out->volume_l, out->volume_r);
Haynes Mathew George16081042017-05-31 17:16:49 -07004353 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004354 unsigned int flags = PCM_OUT;
4355 unsigned int pcm_open_retry_count = 0;
4356 if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
4357 flags |= PCM_MMAP | PCM_NOIRQ;
4358 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004359 } else if (out->realtime) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08004360 flags |= PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004361 } else
4362 flags |= PCM_MONOTONIC;
4363
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004364 if ((adev->vr_audio_mode_enabled) &&
4365 (out->flags & AUDIO_OUTPUT_FLAG_RAW)) {
4366 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
4367 "PCM_Dev %d Topology", out->pcm_device_id);
4368 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
4369 if (!ctl) {
4370 ALOGI("%s: Could not get ctl for mixer cmd might be ULL - %s",
4371 __func__, mixer_ctl_name);
4372 } else {
4373 //if success use ULLPP
4374 ALOGI("%s: mixer ctrl %s succeeded setting up ULL for %d",
4375 __func__, mixer_ctl_name, out->pcm_device_id);
4376 //There is a still a possibility that some sessions
4377 // that request for FAST|RAW when 3D audio is active
4378 //can go through ULLPP. Ideally we expects apps to
4379 //listen to audio focus and stop concurrent playback
4380 //Also, we will look for mode flag (voice_in_communication)
4381 //before enabling the realtime flag.
4382 mixer_ctl_set_enum_by_string(ctl, perf_mode[1]);
4383 }
4384 }
4385
Vatsal Bucha3f39f222021-06-29 16:16:55 +05304386 platform_set_stream_channel_map(adev->platform, out->channel_mask,
4387 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Surendar Karka91fa3682018-07-02 18:12:12 +05304388
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004389 out->pcm = pcm_open_prepare_helper(adev->snd_card, out->pcm_device_id,
4390 flags, pcm_open_retry_count,
4391 &(out->config));
4392 if (out->pcm == NULL) {
4393 ret = -EIO;
4394 goto error_open;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004395 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004396
4397 if (is_haptic_usecase) {
4398 adev->haptic_pcm = pcm_open_prepare_helper(adev->snd_card,
4399 adev->haptic_pcm_device_id,
4400 flags, pcm_open_retry_count,
4401 &(adev->haptics_config));
4402 // failure to open haptics pcm shouldnt stop audio,
4403 // so do not close audio pcm in case of error
Vignesh Kulothungane4039c12019-05-07 15:51:39 -07004404
4405 if (property_get_bool("vendor.audio.enable_haptic_audio_sync", false)) {
4406 ALOGD("%s: enable haptic audio synchronization", __func__);
4407 platform_set_qtime(adev->platform, out->pcm_device_id, adev->haptic_pcm_device_id);
4408 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004409 }
4410
Zhou Song2b8f28f2017-09-11 10:51:38 +08004411 // apply volume for voip playback after path is set up
4412 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
4413 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
Ramu Gottipati36547092018-12-28 11:32:09 +05304414 else if ((out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY || out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
4415 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) && (out->apply_volume)) {
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304416 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
4417 out->apply_volume = false;
Derek Chenf13dd492018-11-13 14:53:51 -08004418 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
4419 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05304420#ifdef SOFT_VOLUME
4421 out_set_soft_volume_params(&out->stream);
4422#endif
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304423 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004424 } else {
Zhou Song79929fe2020-01-20 17:57:43 +08004425 /*
4426 * set custom channel map if:
4427 * 1. neither mono nor stereo clips i.e. channels > 2 OR
4428 * 2. custom channel map has been set by client
4429 * else default channel map of FC/FR/FL can always be set to DSP
4430 */
4431 if (popcount(out->channel_mask) > 2 || out->channel_map_param.channel_map[0])
4432 platform_set_stream_channel_map(adev->platform, out->channel_mask,
Weiyin Jiang810a80d2021-01-18 16:04:31 +08004433 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004434 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4435 adev->dsp_bit_width_enforce_mode,
4436 true);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004437 out->pcm = NULL;
Haynes Mathew George380745d2017-10-04 15:27:45 -07004438 ATRACE_BEGIN("compress_open");
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -08004439 out->compr = compress_open(adev->snd_card,
4440 out->pcm_device_id,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004441 COMPRESS_IN, &out->compr_config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004442 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05304443 if (errno == ENETRESET && !is_compress_ready(out->compr)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05304444 ALOGE("%s: compress_open failed errno:%d\n", __func__, errno);
4445 adev->card_status = CARD_STATUS_OFFLINE;
4446 out->card_status = CARD_STATUS_OFFLINE;
4447 ret = -EIO;
4448 goto error_open;
4449 }
4450
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004451 if (out->compr && !is_compress_ready(out->compr)) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004452 ALOGE("%s: failed /w error %s", __func__, compress_get_error(out->compr));
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004453 compress_close(out->compr);
4454 out->compr = NULL;
4455 ret = -EIO;
4456 goto error_open;
4457 }
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304458 /* compress_open sends params of the track, so reset the flag here */
4459 out->is_compr_metadata_avail = false;
4460
Ben Rombergerd771a7c2017-02-22 18:05:17 -08004461 if (out->client_callback)
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004462 compress_nonblock(out->compr, out->non_blocking);
Eric Laurentc4aef752013-09-12 17:45:53 -07004463
Fred Oh3f43e742015-03-04 18:42:34 -08004464 /* Since small bufs uses blocking writes, a write will be blocked
4465 for the default max poll time (20s) in the event of an SSR.
4466 Reduce the poll time to observe and deal with SSR faster.
4467 */
Ashish Jain5106d362016-05-11 19:23:33 +05304468 if (!out->non_blocking) {
Fred Oh3f43e742015-03-04 18:42:34 -08004469 compress_set_max_poll_wait(out->compr, 1000);
4470 }
4471
Manish Dewangan69426c82017-01-30 17:35:36 +05304472 audio_extn_utils_compress_set_render_mode(out);
Manish Dewangan58229382017-02-02 15:48:41 +05304473 audio_extn_utils_compress_set_clk_rec_mode(uc_info);
Manish Dewangan69426c82017-01-30 17:35:36 +05304474
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004475 audio_extn_dts_create_state_notifier_node(out->usecase);
4476 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
4477 popcount(out->channel_mask),
4478 out->playback_started);
4479
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004480#ifdef DS1_DOLBY_DDP_ENABLED
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05304481 if (audio_extn_utils_is_dolby_format(out->format))
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004482 audio_extn_dolby_send_ddp_endp_params(adev);
4483#endif
Preetam Singh Ranawatd18d8832017-02-08 17:34:54 +05304484 if (!(audio_extn_passthru_is_passthrough_stream(out)) &&
4485 (out->sample_rate != 176400 && out->sample_rate <= 192000)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004486 if (adev->visualizer_start_output != NULL)
4487 adev->visualizer_start_output(out->handle, out->pcm_device_id);
4488 if (adev->offload_effects_start_output != NULL)
Ashish Jain5106d362016-05-11 19:23:33 +05304489 adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004490 audio_extn_check_and_set_dts_hpx_state(adev);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004491 }
Derek Chenf13dd492018-11-13 14:53:51 -08004492
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004493 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf13dd492018-11-13 14:53:51 -08004494 /* Update cached volume from media to offload/direct stream */
4495 struct listnode *node = NULL;
4496 list_for_each(node, &adev->active_outputs_list) {
4497 streams_output_ctxt_t *out_ctxt = node_to_item(node,
4498 streams_output_ctxt_t,
4499 list);
4500 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
4501 out->volume_l = out_ctxt->output->volume_l;
4502 out->volume_r = out_ctxt->output->volume_r;
4503 }
4504 }
4505 out_set_compr_volume(&out->stream,
4506 out->volume_l, out->volume_r);
4507 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004508 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004509
4510 if (ret == 0) {
Narsinga Rao Chellaa6e1f702021-10-22 13:57:32 +05304511 if (out->flags == AUDIO_OUTPUT_FLAG_FAST)
4512 register_out_stream(out);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004513 if (out->realtime) {
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07004514 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4515 ALOGE("%s: pcm stream not ready", __func__);
4516 goto error_open;
4517 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07004518 ATRACE_BEGIN("pcm_start");
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004519 ret = pcm_start(out->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004520 ATRACE_END();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004521 if (ret < 0)
4522 goto error_open;
4523 }
4524 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004525 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304526 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Jaideep Sharma0fa53812020-09-17 09:00:11 +05304527 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004528
vivek mehtad15d2bf2019-05-17 13:35:10 -07004529 if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4530 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4531 audio_low_latency_hint_start();
4532 }
4533
Manish Dewangan21a850a2017-08-14 12:03:55 +05304534 if (out->ip_hdlr_handle) {
Vidyakumar Athota6d655882017-05-22 18:26:24 -07004535 ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07004536 if (ret < 0)
4537 ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
4538 }
4539
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07004540 // consider a scenario where on pause lower layers are tear down.
4541 // so on resume, swap mixer control need to be sent only when
4542 // backend is active, hence rather than sending from enable device
4543 // sending it from start of streamtream
4544
4545 platform_set_swap_channels(adev, true);
4546
Haynes Mathew George380745d2017-10-04 15:27:45 -07004547 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304548 enable_gcov();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004549 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004550error_open:
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004551 if (adev->haptic_pcm) {
4552 pcm_close(adev->haptic_pcm);
4553 adev->haptic_pcm = NULL;
4554 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004555 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304556 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004557 stop_output_stream(out);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004558error_fatal:
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05304559 /*
4560 * sleep 50ms to allow sufficient time for kernel
4561 * drivers to recover incases like SSR.
4562 */
4563 usleep(50000);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004564error_config:
Haynes Mathew George380745d2017-10-04 15:27:45 -07004565 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304566 enable_gcov();
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004567 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004568}
4569
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004570static int check_input_parameters(uint32_t sample_rate,
4571 audio_format_t format,
Aalique Grahame22e49102018-12-18 14:23:57 -08004572 int channel_count,
4573 bool is_usb_hifi)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004574{
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004575 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004576
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304577 if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
4578 (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) &&
4579 (format != AUDIO_FORMAT_PCM_FLOAT)) &&
Mingming Yine62d7842013-10-25 16:26:03 -07004580 !voice_extn_compress_voip_is_format_supported(format) &&
Ralf Herzaec80262018-07-03 07:08:49 +02004581 !audio_extn_compr_cap_format_supported(format) &&
4582 !audio_extn_cin_format_supported(format))
Haynes Mathew George484e8d22017-07-31 18:55:17 -07004583 ret = -EINVAL;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004584
Aalique Grahame22e49102018-12-18 14:23:57 -08004585 int max_channel_count = is_usb_hifi ? MAX_HIFI_CHANNEL_COUNT : MAX_CHANNEL_COUNT;
4586 if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > max_channel_count)) {
4587 ALOGE("%s: unsupported channel count (%d) passed Min / Max (%d / %d)", __func__,
4588 channel_count, MIN_CHANNEL_COUNT, max_channel_count);
4589 return -EINVAL;
4590 }
4591
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004592 switch (channel_count) {
4593 case 1:
4594 case 2:
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05304595 case 3:
4596 case 4:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004597 case 6:
Karthikeyan Mani07faa602018-08-20 11:01:32 -07004598 case 8:
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05304599 case 10:
4600 case 12:
4601 case 14:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004602 break;
4603 default:
4604 ret = -EINVAL;
4605 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004606
4607 switch (sample_rate) {
4608 case 8000:
4609 case 11025:
4610 case 12000:
4611 case 16000:
4612 case 22050:
4613 case 24000:
4614 case 32000:
4615 case 44100:
4616 case 48000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004617 case 88200:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304618 case 96000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004619 case 176400:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304620 case 192000:
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004621 break;
4622 default:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004623 ret = -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004624 }
4625
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004626 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004627}
4628
Naresh Tanniru04f71882018-06-26 17:46:22 +05304629
4630/** Add a value in a list if not already present.
4631 * @return true if value was successfully inserted or already present,
4632 * false if the list is full and does not contain the value.
4633 */
4634static bool register_uint(uint32_t value, uint32_t* list, size_t list_length) {
4635 for (size_t i = 0; i < list_length; i++) {
4636 if (list[i] == value) return true; // value is already present
4637 if (list[i] == 0) { // no values in this slot
4638 list[i] = value;
4639 return true; // value inserted
4640 }
4641 }
4642 return false; // could not insert value
4643}
4644
4645/** Add channel_mask in supported_channel_masks if not already present.
4646 * @return true if channel_mask was successfully inserted or already present,
4647 * false if supported_channel_masks is full and does not contain channel_mask.
4648 */
4649static void register_channel_mask(audio_channel_mask_t channel_mask,
4650 audio_channel_mask_t supported_channel_masks[static MAX_SUPPORTED_CHANNEL_MASKS]) {
4651 ALOGE_IF(!register_uint(channel_mask, supported_channel_masks, MAX_SUPPORTED_CHANNEL_MASKS),
4652 "%s: stream can not declare supporting its channel_mask %x", __func__, channel_mask);
4653}
4654
4655/** Add format in supported_formats if not already present.
4656 * @return true if format was successfully inserted or already present,
4657 * false if supported_formats is full and does not contain format.
4658 */
4659static void register_format(audio_format_t format,
4660 audio_format_t supported_formats[static MAX_SUPPORTED_FORMATS]) {
4661 ALOGE_IF(!register_uint(format, supported_formats, MAX_SUPPORTED_FORMATS),
4662 "%s: stream can not declare supporting its format %x", __func__, format);
4663}
4664/** Add sample_rate in supported_sample_rates if not already present.
4665 * @return true if sample_rate was successfully inserted or already present,
4666 * false if supported_sample_rates is full and does not contain sample_rate.
4667 */
4668static void register_sample_rate(uint32_t sample_rate,
4669 uint32_t supported_sample_rates[static MAX_SUPPORTED_SAMPLE_RATES]) {
4670 ALOGE_IF(!register_uint(sample_rate, supported_sample_rates, MAX_SUPPORTED_SAMPLE_RATES),
4671 "%s: stream can not declare supporting its sample rate %x", __func__, sample_rate);
4672}
4673
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004674static inline uint32_t lcm(uint32_t num1, uint32_t num2)
4675{
4676 uint32_t high = num1, low = num2, temp = 0;
4677
4678 if (!num1 || !num2)
4679 return 0;
4680
4681 if (num1 < num2) {
4682 high = num2;
4683 low = num1;
4684 }
4685
4686 while (low != 0) {
4687 temp = low;
4688 low = high % low;
4689 high = temp;
4690 }
4691 return (num1 * num2)/high;
4692}
4693
4694static inline uint32_t nearest_multiple(uint32_t num, uint32_t multiplier)
4695{
4696 uint32_t remainder = 0;
4697
4698 if (!multiplier)
4699 return num;
4700
4701 remainder = num % multiplier;
4702 if (remainder)
4703 num += (multiplier - remainder);
4704
4705 return num;
4706}
4707
Aalique Grahame22e49102018-12-18 14:23:57 -08004708static size_t get_stream_buffer_size(size_t duration_ms,
4709 uint32_t sample_rate,
4710 audio_format_t format,
4711 int channel_count,
4712 bool is_low_latency)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004713{
4714 size_t size = 0;
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004715 uint32_t bytes_per_period_sample = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004716
Aalique Grahame22e49102018-12-18 14:23:57 -08004717 size = (sample_rate * duration_ms) / 1000;
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05304718 if (is_low_latency){
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +05304719#ifndef PLATFORM_AUTO
4720 size = configured_low_latency_capture_period_size;
4721#else
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05304722 switch(sample_rate) {
4723 case 48000:
4724 size = 240;
4725 break;
4726 case 32000:
4727 size = 160;
4728 break;
4729 case 24000:
4730 size = 120;
4731 break;
4732 case 16000:
4733 size = 80;
4734 break;
4735 case 8000:
4736 size = 40;
4737 break;
4738 default:
4739 size = 240;
4740 }
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +05304741#endif
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05304742 }
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304743
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004744 bytes_per_period_sample = audio_bytes_per_sample(format) * channel_count;
Aalique Grahame22e49102018-12-18 14:23:57 -08004745 size *= audio_bytes_per_sample(format) * channel_count;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004746
Ralf Herzbd08d632018-09-28 15:50:49 +02004747 /* make sure the size is multiple of 32 bytes and additionally multiple of
4748 * the frame_size (required for 24bit samples and non-power-of-2 channel counts)
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004749 * At 48 kHz mono 16-bit PCM:
4750 * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
4751 * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004752 * Also, make sure the size is multiple of bytes per period sample
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004753 */
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004754 size = nearest_multiple(size, lcm(32, bytes_per_period_sample));
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07004755
4756 return size;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004757}
4758
Aalique Grahame22e49102018-12-18 14:23:57 -08004759static size_t get_input_buffer_size(uint32_t sample_rate,
4760 audio_format_t format,
4761 int channel_count,
4762 bool is_low_latency)
4763{
Avinash Chandrad7296d42021-08-04 15:07:47 +05304764 bool is_usb_hifi = IS_USB_HIFI;
Aalique Grahame22e49102018-12-18 14:23:57 -08004765 /* Don't know if USB HIFI in this context so use true to be conservative */
4766 if (check_input_parameters(sample_rate, format, channel_count,
Avinash Chandrad7296d42021-08-04 15:07:47 +05304767 is_usb_hifi) != 0)
Aalique Grahame22e49102018-12-18 14:23:57 -08004768 return 0;
4769
4770 return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
4771 sample_rate,
4772 format,
4773 channel_count,
4774 is_low_latency);
4775}
4776
Derek Chenf6318be2017-06-12 17:16:24 -04004777size_t get_output_period_size(uint32_t sample_rate,
4778 audio_format_t format,
4779 int channel_count,
4780 int duration /*in millisecs*/)
Ashish Jain058165c2016-09-28 23:18:48 +05304781{
4782 size_t size = 0;
4783 uint32_t bytes_per_sample = audio_bytes_per_sample(format);
4784
4785 if ((duration == 0) || (sample_rate == 0) ||
4786 (bytes_per_sample == 0) || (channel_count == 0)) {
4787 ALOGW("Invalid config duration %d sr %d bps %d ch %d", duration, sample_rate,
4788 bytes_per_sample, channel_count);
4789 return -EINVAL;
4790 }
4791
4792 size = (sample_rate *
4793 duration *
4794 bytes_per_sample *
4795 channel_count) / 1000;
4796 /*
4797 * To have same PCM samples for all channels, the buffer size requires to
4798 * be multiple of (number of channels * bytes per sample)
4799 * For writes to succeed, the buffer must be written at address which is multiple of 32
4800 */
4801 size = ALIGN(size, (bytes_per_sample * channel_count * 32));
4802
4803 return (size/(channel_count * bytes_per_sample));
4804}
4805
Zhou Song48453a02018-01-10 17:50:59 +08004806static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out, struct timespec *timestamp)
Ashish Jain5106d362016-05-11 19:23:33 +05304807{
4808 uint64_t actual_frames_rendered = 0;
Weiyin Jiang4813da12020-05-28 00:37:28 +08004809 uint64_t written_frames = 0;
4810 uint64_t kernel_frames = 0;
4811 uint64_t dsp_frames = 0;
4812 uint64_t signed_frames = 0;
4813 size_t kernel_buffer_size = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05304814
4815 /* This adjustment accounts for buffering after app processor.
4816 * It is based on estimated DSP latency per use case, rather than exact.
4817 */
George Gao9ba8a142020-07-23 14:30:03 -07004818 dsp_frames = platform_render_latency(out) *
Weiyin Jiang4813da12020-05-28 00:37:28 +08004819 out->sample_rate / 1000000LL;
Ashish Jain5106d362016-05-11 19:23:33 +05304820
Zhou Song48453a02018-01-10 17:50:59 +08004821 pthread_mutex_lock(&out->position_query_lock);
Weiyin Jiang4813da12020-05-28 00:37:28 +08004822 written_frames = out->written /
4823 (audio_bytes_per_sample(out->hal_ip_format) * popcount(out->channel_mask));
4824
Ashish Jain5106d362016-05-11 19:23:33 +05304825 /* not querying actual state of buffering in kernel as it would involve an ioctl call
4826 * which then needs protection, this causes delay in TS query for pcm_offload usecase
4827 * hence only estimate.
4828 */
Weiyin Jiang4813da12020-05-28 00:37:28 +08004829 kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments;
4830 kernel_frames = kernel_buffer_size /
4831 (audio_bytes_per_sample(out->hal_op_format) * popcount(out->channel_mask));
Ashish Jain5106d362016-05-11 19:23:33 +05304832
Weiyin Jiang4813da12020-05-28 00:37:28 +08004833 if (written_frames >= (kernel_frames + dsp_frames))
4834 signed_frames = written_frames - kernel_frames - dsp_frames;
Ashish Jain5106d362016-05-11 19:23:33 +05304835
Zhou Song48453a02018-01-10 17:50:59 +08004836 if (signed_frames > 0) {
Ashish Jain5106d362016-05-11 19:23:33 +05304837 actual_frames_rendered = signed_frames;
Zhou Song48453a02018-01-10 17:50:59 +08004838 if (timestamp != NULL )
4839 *timestamp = out->writeAt;
4840 } else if (timestamp != NULL) {
4841 clock_gettime(CLOCK_MONOTONIC, timestamp);
4842 }
4843 pthread_mutex_unlock(&out->position_query_lock);
Ashish Jain5106d362016-05-11 19:23:33 +05304844
Weiyin Jiang4813da12020-05-28 00:37:28 +08004845 ALOGVV("%s signed frames %lld written frames %lld kernel frames %lld dsp frames %lld",
4846 __func__, signed_frames, written_frames, kernel_frames, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05304847
4848 return actual_frames_rendered;
4849}
4850
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004851static uint32_t out_get_sample_rate(const struct audio_stream *stream)
4852{
4853 struct stream_out *out = (struct stream_out *)stream;
4854
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004855 return out->sample_rate;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004856}
4857
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004858static int out_set_sample_rate(struct audio_stream *stream __unused,
4859 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004860{
4861 return -ENOSYS;
4862}
4863
4864static size_t out_get_buffer_size(const struct audio_stream *stream)
4865{
4866 struct stream_out *out = (struct stream_out *)stream;
4867
Varun Balaraje49253e2017-07-06 19:48:56 +05304868 if (is_interactive_usecase(out->usecase)) {
Sri Karri27279e12017-08-07 16:05:20 +05304869 return out->config.period_size * out->config.period_count;
Varun Balaraje49253e2017-07-06 19:48:56 +05304870 } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Naresh Tanniruee3499a2017-01-05 14:05:35 +05304871 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
4872 return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
4873 else
4874 return out->compr_config.fragment_size;
4875 } else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08004876 return voice_extn_compress_voip_out_get_buffer_size(out);
Dhananjay Kumarac341582017-02-23 23:42:25 +05304877 else if (is_offload_usecase(out->usecase) &&
4878 out->flags == AUDIO_OUTPUT_FLAG_DIRECT)
Ashish Jain83a6cc22016-06-28 14:34:17 +05304879 return out->hal_fragment_size;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004880
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004881 return out->config.period_size * out->af_period_multiplier *
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07004882 audio_stream_out_frame_size((const struct audio_stream_out *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004883}
4884
4885static uint32_t out_get_channels(const struct audio_stream *stream)
4886{
4887 struct stream_out *out = (struct stream_out *)stream;
4888
4889 return out->channel_mask;
4890}
4891
4892static audio_format_t out_get_format(const struct audio_stream *stream)
4893{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004894 struct stream_out *out = (struct stream_out *)stream;
4895
4896 return out->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004897}
4898
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004899static int out_set_format(struct audio_stream *stream __unused,
4900 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004901{
4902 return -ENOSYS;
4903}
4904
4905static int out_standby(struct audio_stream *stream)
4906{
4907 struct stream_out *out = (struct stream_out *)stream;
4908 struct audio_device *adev = out->dev;
Haynes Mathew George16081042017-05-31 17:16:49 -07004909 bool do_stop = true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004910
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304911 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4912 stream, out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004913
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07004914 lock_output_stream(out);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004915 if (!out->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004916 if (adev->adm_deregister_stream)
4917 adev->adm_deregister_stream(adev->adm_data, out->handle);
4918
Weiyin Jiang280ea742020-09-08 20:28:22 +08004919 if (is_offload_usecase(out->usecase)) {
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004920 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08004921 }
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004922
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08004923 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004924 out->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08004925 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
4926 voice_extn_compress_voip_close_output_stream(stream);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304927 out->started = 0;
Zhou Songa8895042016-07-05 17:54:22 +08004928 pthread_mutex_unlock(&adev->lock);
4929 pthread_mutex_unlock(&out->lock);
4930 ALOGD("VOIP output entered standby");
4931 return 0;
4932 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004933 if (out->pcm) {
4934 pcm_close(out->pcm);
4935 out->pcm = NULL;
4936 }
Meng Wanga09da002020-04-20 12:56:04 +08004937 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
4938 if (adev->haptic_pcm) {
4939 pcm_close(adev->haptic_pcm);
4940 adev->haptic_pcm = NULL;
4941 }
4942
4943 if (adev->haptic_buffer != NULL) {
4944 free(adev->haptic_buffer);
4945 adev->haptic_buffer = NULL;
4946 adev->haptic_buffer_size = 0;
4947 }
4948 adev->haptic_pcm_device_id = 0;
4949 }
4950
Haynes Mathew George16081042017-05-31 17:16:49 -07004951 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4952 do_stop = out->playback_started;
4953 out->playback_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07004954
4955 if (out->mmap_shared_memory_fd >= 0) {
4956 ALOGV("%s: closing mmap_shared_memory_fd = %d",
4957 __func__, out->mmap_shared_memory_fd);
4958 close(out->mmap_shared_memory_fd);
4959 out->mmap_shared_memory_fd = -1;
4960 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004961 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004962 } else {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07004963 ALOGD("copl(%p):standby", out);
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304964 out->send_next_track_params = false;
4965 out->is_compr_metadata_avail = false;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004966 out->gapless_mdata.encoder_delay = 0;
4967 out->gapless_mdata.encoder_padding = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004968 if (out->compr != NULL) {
4969 compress_close(out->compr);
4970 out->compr = NULL;
4971 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08004972 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004973 if (do_stop) {
4974 stop_output_stream(out);
4975 }
Lakshman Chaluvaraju06677b42019-06-24 10:04:52 +05304976 // if fm is active route on selected device in UI
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004977 audio_extn_fm_route_on_selected_device(adev, &out->device_list);
Eric Laurent150dbfe2013-02-27 14:31:02 -08004978 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004979 }
4980 pthread_mutex_unlock(&out->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07004981 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004982 return 0;
4983}
4984
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304985static int out_on_error(struct audio_stream *stream)
4986{
4987 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004988 int status = 0;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304989
4990 lock_output_stream(out);
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004991 // always send CMD_ERROR for offload streams, this
4992 // is needed e.g. when SSR happens within compress_open
4993 // since the stream is active, offload_callback_thread is also active.
4994 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
4995 stop_compressed_output_l(out);
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004996 }
4997 pthread_mutex_unlock(&out->lock);
4998
4999 status = out_standby(&out->stream.common);
5000
5001 lock_output_stream(out);
5002 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08005003 send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305004 }
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05305005
5006 if (is_offload_usecase(out->usecase) && out->card_status == CARD_STATUS_OFFLINE) {
5007 ALOGD("Setting previous card status if offline");
5008 out->prev_card_status_offline = true;
5009 }
5010
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305011 pthread_mutex_unlock(&out->lock);
5012
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07005013 return status;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305014}
5015
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305016/*
Weiyin Jiang280ea742020-09-08 20:28:22 +08005017 * standby implementation without locks, assumes that the callee already
5018 * has taken adev and out lock.
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305019 */
5020int out_standby_l(struct audio_stream *stream)
5021{
5022 struct stream_out *out = (struct stream_out *)stream;
5023 struct audio_device *adev = out->dev;
5024
5025 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
5026 stream, out->usecase, use_case_table[out->usecase]);
5027
5028 if (!out->standby) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07005029 ATRACE_BEGIN("out_standby_l");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305030 if (adev->adm_deregister_stream)
5031 adev->adm_deregister_stream(adev->adm_data, out->handle);
5032
Weiyin Jiang280ea742020-09-08 20:28:22 +08005033 if (is_offload_usecase(out->usecase)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305034 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005035 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305036
5037 out->standby = true;
5038 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
5039 voice_extn_compress_voip_close_output_stream(stream);
5040 out->started = 0;
5041 ALOGD("VOIP output entered standby");
Haynes Mathew George380745d2017-10-04 15:27:45 -07005042 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305043 return 0;
5044 } else if (!is_offload_usecase(out->usecase)) {
5045 if (out->pcm) {
5046 pcm_close(out->pcm);
5047 out->pcm = NULL;
5048 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08005049 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
5050 if (adev->haptic_pcm) {
5051 pcm_close(adev->haptic_pcm);
5052 adev->haptic_pcm = NULL;
5053 }
5054
5055 if (adev->haptic_buffer != NULL) {
5056 free(adev->haptic_buffer);
5057 adev->haptic_buffer = NULL;
5058 adev->haptic_buffer_size = 0;
5059 }
5060 adev->haptic_pcm_device_id = 0;
5061 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305062 } else {
5063 ALOGD("copl(%p):standby", out);
5064 out->send_next_track_params = false;
5065 out->is_compr_metadata_avail = false;
5066 out->gapless_mdata.encoder_delay = 0;
5067 out->gapless_mdata.encoder_padding = 0;
5068 if (out->compr != NULL) {
5069 compress_close(out->compr);
5070 out->compr = NULL;
5071 }
5072 }
5073 stop_output_stream(out);
Haynes Mathew George380745d2017-10-04 15:27:45 -07005074 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305075 }
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07005076 ALOGV("%s: exit", __func__);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305077 return 0;
5078}
5079
Aalique Grahame22e49102018-12-18 14:23:57 -08005080static int out_dump(const struct audio_stream *stream, int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005081{
Aalique Grahame22e49102018-12-18 14:23:57 -08005082 struct stream_out *out = (struct stream_out *)stream;
5083
5084 // We try to get the lock for consistency,
5085 // but it isn't necessary for these variables.
5086 // If we're not in standby, we may be blocked on a write.
5087 const bool locked = (pthread_mutex_trylock(&out->lock) == 0);
5088 dprintf(fd, " Standby: %s\n", out->standby ? "yes" : "no");
5089 dprintf(fd, " Frames written: %lld\n", (long long)out->written);
Dechen Chai22768452021-07-30 09:29:16 +05305090#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07005091 char buffer[256]; // for statistics formatting
5092 if (!is_offload_usecase(out->usecase)) {
5093 simple_stats_to_string(&out->fifo_underruns, buffer, sizeof(buffer));
5094 dprintf(fd, " Fifo frame underruns: %s\n", buffer);
5095 }
5096
Andy Hungc6bfd4a2019-07-01 18:26:00 -07005097 if (out->start_latency_ms.n > 0) {
5098 simple_stats_to_string(&out->start_latency_ms, buffer, sizeof(buffer));
5099 dprintf(fd, " Start latency ms: %s\n", buffer);
5100 }
Dechen Chai22768452021-07-30 09:29:16 +05305101#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08005102 if (locked) {
5103 pthread_mutex_unlock(&out->lock);
5104 }
5105
Dechen Chai22768452021-07-30 09:29:16 +05305106#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08005107 // dump error info
5108 (void)error_log_dump(
5109 out->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05305110#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005111 return 0;
5112}
5113
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005114static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
5115{
5116 int ret = 0;
5117 char value[32];
ApurupaPattapu2e084df2013-12-18 15:47:59 -08005118
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005119 if (!out || !parms) {
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005120 ALOGE("%s: return invalid ",__func__);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005121 return -EINVAL;
5122 }
5123
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305124 ret = audio_extn_parse_compress_metadata(out, parms);
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08005125
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005126 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
5127 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305128 out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005129 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005130 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
5131 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305132 out->gapless_mdata.encoder_padding = atoi(value);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005133 }
5134
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005135 ALOGV("%s new encoder delay %u and padding %u", __func__,
5136 out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
5137
5138 return 0;
5139}
5140
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07005141static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
5142{
5143 return out == adev->primary_output || out == adev->voice_tx_output;
5144}
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005145
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305146// note: this call is safe only if the stream_cb is
5147// removed first in close_output_stream (as is done now).
5148static void out_snd_mon_cb(void * stream, struct str_parms * parms)
5149{
5150 if (!stream || !parms)
5151 return;
5152
5153 struct stream_out *out = (struct stream_out *)stream;
5154 struct audio_device *adev = out->dev;
5155
5156 card_status_t status;
5157 int card;
5158 if (parse_snd_card_status(parms, &card, &status) < 0)
5159 return;
5160
5161 pthread_mutex_lock(&adev->lock);
5162 bool valid_cb = (card == adev->snd_card);
5163 pthread_mutex_unlock(&adev->lock);
5164
5165 if (!valid_cb)
5166 return;
5167
5168 lock_output_stream(out);
5169 if (out->card_status != status)
5170 out->card_status = status;
5171 pthread_mutex_unlock(&out->lock);
5172
5173 ALOGI("out_snd_mon_cb for card %d usecase %s, status %s", card,
5174 use_case_table[out->usecase],
5175 status == CARD_STATUS_OFFLINE ? "offline" : "online");
5176
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305177 if (status == CARD_STATUS_OFFLINE) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305178 out_on_error(stream);
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305179 if (voice_is_call_state_active(adev) &&
5180 out == adev->primary_output) {
5181 ALOGD("%s: SSR/PDR occurred, end all calls\n", __func__);
5182 pthread_mutex_lock(&adev->lock);
5183 voice_stop_call(adev);
5184 adev->mode = AUDIO_MODE_NORMAL;
5185 pthread_mutex_unlock(&adev->lock);
5186 }
5187 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305188 return;
5189}
5190
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005191int route_output_stream(struct stream_out *out,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005192 struct listnode *devices)
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005193{
5194 struct audio_device *adev = out->dev;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005195 int ret = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005196 struct listnode new_devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005197 bool bypass_a2dp = false;
5198 bool reconfig = false;
5199 unsigned long service_interval = 0;
5200
5201 ALOGD("%s: enter: usecase(%d: %s) devices %x",
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005202 __func__, out->usecase, use_case_table[out->usecase], get_device_types(devices));
5203
5204 list_init(&new_devices);
5205 assign_devices(&new_devices, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005206
5207 lock_output_stream(out);
5208 pthread_mutex_lock(&adev->lock);
5209
5210 /*
5211 * When HDMI cable is unplugged the music playback is paused and
5212 * the policy manager sends routing=0. But the audioflinger continues
5213 * to write data until standby time (3sec). As the HDMI core is
5214 * turned off, the write gets blocked.
5215 * Avoid this by routing audio to speaker until standby.
5216 */
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08005217 if (is_single_device_type_equal(&out->device_list,
5218 AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005219 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005220 !audio_extn_passthru_is_passthrough_stream(out) &&
5221 (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005222 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005223 }
5224 /*
5225 * When A2DP is disconnected the
5226 * music playback is paused and the policy manager sends routing=0
5227 * But the audioflinger continues to write data until standby time
5228 * (3sec). As BT is turned off, the write gets blocked.
5229 * Avoid this by routing audio to speaker until standby.
5230 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005231 if (is_a2dp_out_device_type(&out->device_list) &&
5232 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005233 !audio_extn_a2dp_source_is_ready() &&
5234 !adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005235 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005236 }
5237 /*
Weiyin Jiangabedea32020-12-09 12:49:19 +08005238 * When USB headset is disconnected the music playback paused
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005239 * and the policy manager send routing=0. But if the USB is connected
5240 * back before the standby time, AFE is not closed and opened
5241 * when USB is connected back. So routing to speker will guarantee
5242 * AFE reconfiguration and AFE will be opend once USB is connected again
5243 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005244 if (is_usb_out_device_type(&out->device_list) &&
5245 list_empty(&new_devices) &&
5246 !audio_extn_usb_connected(NULL)) {
Sujin Panicker84d953a2020-11-16 17:39:54 +05305247 if (adev->mode == AUDIO_MODE_IN_CALL || adev->mode == AUDIO_MODE_IN_COMMUNICATION)
5248 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_EARPIECE, "");
5249 else
5250 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005251 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005252 /* To avoid a2dp to sco overlapping / BT device improper state
5253 * check with BT lib about a2dp streaming support before routing
5254 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005255 if (is_a2dp_out_device_type(&new_devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005256 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005257 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
5258 compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005259 //combo usecase just by pass a2dp
5260 ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
5261 bypass_a2dp = true;
5262 } else {
5263 ALOGE("%s: A2DP profile is not ready,ignoring routing request", __func__);
5264 /* update device to a2dp and don't route as BT returned error
5265 * However it is still possible a2dp routing called because
5266 * of current active device disconnection (like wired headset)
5267 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005268 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005269 pthread_mutex_unlock(&adev->lock);
5270 pthread_mutex_unlock(&out->lock);
5271 goto error;
5272 }
5273 }
5274 }
5275
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005276 // Workaround: If routing to an non existing usb device, fail gracefully
5277 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005278 if (is_usb_out_device_type(&new_devices)) {
5279 struct str_parms *parms =
5280 str_parms_create_str(get_usb_device_address(&new_devices));
5281 if (!parms)
5282 goto error;
Weiyin Jiangabedea32020-12-09 12:49:19 +08005283 if (!audio_extn_usb_connected(NULL)) {
5284 ALOGW("%s: ignoring rerouting to non existing USB card", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005285 pthread_mutex_unlock(&adev->lock);
5286 pthread_mutex_unlock(&out->lock);
5287 str_parms_destroy(parms);
5288 ret = -ENOSYS;
5289 goto error;
5290 }
5291 str_parms_destroy(parms);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005292 }
5293
Weiyin Jiang80c8f9a2020-01-10 20:42:08 +08005294 // Workaround: If routing to an non existing hdmi device, fail gracefully
5295 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
5296 (platform_get_edid_info_v2(adev->platform,
5297 out->extconn.cs.controller,
5298 out->extconn.cs.stream) != 0)) {
5299 ALOGW("out_set_parameters() ignoring rerouting to non existing HDMI/DP");
5300 pthread_mutex_unlock(&adev->lock);
5301 pthread_mutex_unlock(&out->lock);
5302 ret = -ENOSYS;
5303 goto error;
5304 }
5305
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005306 /*
5307 * select_devices() call below switches all the usecases on the same
5308 * backend to the new device. Refer to check_usecases_codec_backend() in
5309 * the select_devices(). But how do we undo this?
5310 *
5311 * For example, music playback is active on headset (deep-buffer usecase)
5312 * and if we go to ringtones and select a ringtone, low-latency usecase
5313 * will be started on headset+speaker. As we can't enable headset+speaker
5314 * and headset devices at the same time, select_devices() switches the music
5315 * playback to headset+speaker while starting low-lateny usecase for ringtone.
5316 * So when the ringtone playback is completed, how do we undo the same?
5317 *
5318 * We are relying on the out_set_parameters() call on deep-buffer output,
5319 * once the ringtone playback is ended.
5320 * NOTE: We should not check if the current devices are same as new devices.
5321 * Because select_devices() must be called to switch back the music
5322 * playback to headset.
5323 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005324 if (!list_empty(&new_devices)) {
5325 bool same_dev = compare_devices(&out->device_list, &new_devices);
5326 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005327
5328 if (output_drives_call(adev, out)) {
5329 if (!voice_is_call_state_active(adev)) {
5330 if (adev->mode == AUDIO_MODE_IN_CALL) {
5331 adev->current_call_output = out;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005332 ret = voice_start_call(adev);
5333 }
5334 } else {
Kunlei Zhang253ad102020-10-14 16:21:28 +08005335 platform_is_volume_boost_supported_device(adev->platform, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005336 adev->current_call_output = out;
5337 voice_update_devices_for_all_voice_usecases(adev);
5338 }
5339 }
5340
Mingshu Pang971ff702020-09-09 15:28:22 +08005341 if (is_usb_out_device_type(&out->device_list)) {
5342 service_interval = audio_extn_usb_find_service_interval(false, true /*playback*/);
5343 audio_extn_usb_set_service_interval(true /*playback*/,
5344 service_interval,
5345 &reconfig);
5346 ALOGD("%s, svc_int(%ld),reconfig(%d)",__func__,service_interval, reconfig);
5347 }
5348
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005349 if (!out->standby) {
5350 if (!same_dev) {
5351 ALOGV("update routing change");
5352 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
5353 adev->perf_lock_opts,
5354 adev->perf_lock_opts_size);
5355 if (adev->adm_on_routing_change)
5356 adev->adm_on_routing_change(adev->adm_data,
5357 out->handle);
5358 }
5359 if (!bypass_a2dp) {
5360 select_devices(adev, out->usecase);
5361 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005362 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
5363 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005364 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005365 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005366 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005367 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005368 }
5369
5370 if (!same_dev) {
5371 // on device switch force swap, lower functions will make sure
5372 // to check if swap is allowed or not.
5373 platform_set_swap_channels(adev, true);
5374 audio_extn_perf_lock_release(&adev->perf_lock_handle);
5375 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005376 pthread_mutex_lock(&out->latch_lock);
5377 if (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready()) {
5378 if (out->a2dp_muted) {
5379 out->a2dp_muted = false;
5380 if (is_offload_usecase(out->usecase))
5381 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
5382 else if (out->usecase != USECASE_AUDIO_PLAYBACK_VOIP)
5383 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005384 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005385 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005386 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP && !out->a2dp_muted)
5387 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
5388 pthread_mutex_unlock(&out->latch_lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005389 }
5390 }
5391
5392 pthread_mutex_unlock(&adev->lock);
5393 pthread_mutex_unlock(&out->lock);
5394
5395 /*handles device and call state changes*/
5396 audio_extn_extspk_update(adev->extspk);
5397
Revathi Uddaraju4255a632021-12-02 05:11:13 -08005398 clear_devices(&new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005399error:
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005400 ALOGV("%s: exit: code(%d)", __func__, ret);
5401 return ret;
5402}
5403
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005404static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
5405{
5406 struct stream_out *out = (struct stream_out *)stream;
5407 struct audio_device *adev = out->dev;
5408 struct str_parms *parms;
5409 char value[32];
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005410 int ret = 0, err;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005411 int ext_controller = -1;
5412 int ext_stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005413
sangwoobc677242013-08-08 16:53:43 +09005414 ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07005415 __func__, out->usecase, use_case_table[out->usecase], kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005416 parms = str_parms_create_str(kvpairs);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305417 if (!parms)
5418 goto error;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005419
5420 err = platform_get_controller_stream_from_params(parms, &ext_controller,
5421 &ext_stream);
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08005422 if (err == 0) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005423 out->extconn.cs.controller = ext_controller;
5424 out->extconn.cs.stream = ext_stream;
5425 ALOGD("%s: usecase(%s) new controller/stream (%d/%d)", __func__,
5426 use_case_table[out->usecase], out->extconn.cs.controller,
5427 out->extconn.cs.stream);
5428 }
5429
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005430 if (out == adev->primary_output) {
5431 pthread_mutex_lock(&adev->lock);
5432 audio_extn_set_parameters(adev, parms);
5433 pthread_mutex_unlock(&adev->lock);
5434 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005435 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07005436 lock_output_stream(out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005437 parse_compress_metadata(out, parms);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08005438
5439 audio_extn_dts_create_state_notifier_node(out->usecase);
5440 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
5441 popcount(out->channel_mask),
5442 out->playback_started);
5443
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005444 pthread_mutex_unlock(&out->lock);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005445 }
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005446
Surendar Karkaf51b5842018-04-26 11:28:38 +05305447 err = str_parms_get_str(parms, AUDIO_PARAMETER_DUAL_MONO, value,
5448 sizeof(value));
5449 if (err >= 0) {
5450 if (!strncmp("true", value, sizeof("true")) || atoi(value))
5451 audio_extn_send_dual_mono_mixing_coefficients(out);
5452 }
5453
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305454 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
5455 if (err >= 0) {
5456 strlcpy(out->profile, value, sizeof(out->profile));
5457 ALOGV("updating stream profile with value '%s'", out->profile);
5458 lock_output_stream(out);
5459 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
5460 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005461 &out->device_list, out->flags,
5462 out->hal_op_format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305463 out->sample_rate, out->bit_width,
5464 out->channel_mask, out->profile,
5465 &out->app_type_cfg);
5466 pthread_mutex_unlock(&out->lock);
5467 }
5468
Alexy Joseph98988832017-01-13 14:56:59 -08005469 //suspend, resume handling block
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005470 //remove QOS only if vendor.audio.hal.dynamic.qos.config.supported is set to true
5471 // and vendor.audio.hal.output.suspend.supported is set to true
5472 if (out->hal_output_suspend_supported && out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08005473 //check suspend parameter only for low latency and if the property
5474 //is enabled
5475 if (str_parms_get_str(parms, "suspend_playback", value, sizeof(value)) >= 0) {
5476 ALOGI("%s: got suspend_playback %s", __func__, value);
5477 lock_output_stream(out);
5478 if (!strncmp(value, "false", 5)) {
5479 //suspend_playback=false is supposed to set QOS value back to 75%
5480 //the mixer control sent with value Enable will achieve that
5481 ret = audio_route_apply_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5482 } else if (!strncmp (value, "true", 4)) {
5483 //suspend_playback=true is supposed to remove QOS value
5484 //resetting the mixer control will set the default value
5485 //for the mixer control which is Disable and this removes the QOS vote
5486 ret = audio_route_reset_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5487 } else {
5488 ALOGE("%s: Wrong value sent for suspend_playback, expected true/false,"
5489 " got %s", __func__, value);
5490 ret = -1;
5491 }
5492
5493 if (ret != 0) {
5494 ALOGE("%s: %s mixer ctl failed with %d, ignore suspend/resume setparams",
5495 __func__, out->pm_qos_mixer_path, ret);
5496 }
5497
5498 pthread_mutex_unlock(&out->lock);
5499 }
5500 }
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005501
Alexy Joseph98988832017-01-13 14:56:59 -08005502 //end suspend, resume handling block
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005503 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305504error:
Eric Laurent994a6932013-07-17 11:51:42 -07005505 ALOGV("%s: exit: code(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005506 return ret;
5507}
5508
Paul McLeana50b7332018-12-17 08:24:21 -07005509static int in_set_microphone_direction(const struct audio_stream_in *stream,
5510 audio_microphone_direction_t dir) {
justinweng20fb6d82019-02-21 18:49:00 -07005511 struct stream_in *in = (struct stream_in *)stream;
5512
5513 ALOGVV("%s: standby %d source %d dir %d", __func__, in->standby, in->source, dir);
5514
5515 in->direction = dir;
5516
5517 if (in->standby)
5518 return 0;
5519
5520 return audio_extn_audiozoom_set_microphone_direction(in, dir);
Paul McLeana50b7332018-12-17 08:24:21 -07005521}
5522
5523static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom) {
justinweng20fb6d82019-02-21 18:49:00 -07005524 struct stream_in *in = (struct stream_in *)stream;
5525
5526 ALOGVV("%s: standby %d source %d zoom %f", __func__, in->standby, in->source, zoom);
5527
5528 if (zoom > 1.0 || zoom < -1.0)
5529 return -EINVAL;
5530
5531 in->zoom = zoom;
5532
5533 if (in->standby)
5534 return 0;
5535
5536 return audio_extn_audiozoom_set_microphone_field_dimension(in, zoom);
Paul McLeana50b7332018-12-17 08:24:21 -07005537}
5538
5539
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005540static bool stream_get_parameter_channels(struct str_parms *query,
5541 struct str_parms *reply,
5542 audio_channel_mask_t *supported_channel_masks) {
5543 int ret = -1;
5544 char value[512];
5545 bool first = true;
5546 size_t i, j;
5547
5548 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
5549 ret = 0;
5550 value[0] = '\0';
5551 i = 0;
5552 while (supported_channel_masks[i] != 0) {
5553 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5554 if (channels_name_to_enum_table[j].value == supported_channel_masks[i]) {
5555 if (!first)
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305556 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005557
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305558 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005559 first = false;
5560 break;
5561 }
5562 }
5563 i++;
5564 }
5565 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5566 }
5567 return ret == 0;
5568}
5569
5570static bool stream_get_parameter_formats(struct str_parms *query,
5571 struct str_parms *reply,
5572 audio_format_t *supported_formats) {
5573 int ret = -1;
5574 char value[256];
5575 size_t i, j;
5576 bool first = true;
5577
5578 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
5579 ret = 0;
5580 value[0] = '\0';
5581 i = 0;
5582 while (supported_formats[i] != 0) {
5583 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5584 if (formats_name_to_enum_table[j].value == supported_formats[i]) {
5585 if (!first) {
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305586 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005587 }
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305588 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005589 first = false;
5590 break;
5591 }
5592 }
5593 i++;
5594 }
5595 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
5596 }
5597 return ret == 0;
5598}
5599
5600static bool stream_get_parameter_rates(struct str_parms *query,
5601 struct str_parms *reply,
5602 uint32_t *supported_sample_rates) {
5603
5604 int i;
5605 char value[256];
5606 int ret = -1;
5607 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
5608 ret = 0;
5609 value[0] = '\0';
5610 i=0;
5611 int cursor = 0;
5612 while (supported_sample_rates[i]) {
5613 int avail = sizeof(value) - cursor;
5614 ret = snprintf(value + cursor, avail, "%s%d",
5615 cursor > 0 ? "|" : "",
5616 supported_sample_rates[i]);
5617 if (ret < 0 || ret >= avail) {
5618 // if cursor is at the last element of the array
5619 // overwrite with \0 is duplicate work as
5620 // snprintf already put a \0 in place.
5621 // else
5622 // we had space to write the '|' at value[cursor]
5623 // (which will be overwritten) or no space to fill
5624 // the first element (=> cursor == 0)
5625 value[cursor] = '\0';
5626 break;
5627 }
5628 cursor += ret;
5629 ++i;
5630 }
5631 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
5632 value);
5633 }
5634 return ret >= 0;
5635}
5636
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005637static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
5638{
5639 struct stream_out *out = (struct stream_out *)stream;
5640 struct str_parms *query = str_parms_create_str(keys);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005641 char *str = (char*) NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005642 char value[256];
5643 struct str_parms *reply = str_parms_create();
5644 size_t i, j;
5645 int ret;
5646 bool first = true;
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005647
5648 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005649 if (reply) {
5650 str_parms_destroy(reply);
5651 }
5652 if (query) {
5653 str_parms_destroy(query);
5654 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005655 ALOGE("out_get_parameters: failed to allocate mem for query or reply");
5656 return NULL;
5657 }
5658
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005659 ALOGV("%s: %s enter: keys - %s", __func__, use_case_table[out->usecase], keys);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005660 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
5661 if (ret >= 0) {
5662 value[0] = '\0';
5663 i = 0;
5664 while (out->supported_channel_masks[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005665 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5666 if (channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005667 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005668 strlcat(value, "|", sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005669 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005670 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005671 first = false;
5672 break;
5673 }
5674 }
5675 i++;
5676 }
5677 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5678 str = str_parms_to_str(reply);
5679 } else {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08005680 voice_extn_out_get_parameters(out, query, reply);
5681 str = str_parms_to_str(reply);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005682 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005683
Alexy Joseph62142aa2015-11-16 15:10:34 -08005684
5685 ret = str_parms_get_str(query, "is_direct_pcm_track", value, sizeof(value));
5686 if (ret >= 0) {
5687 value[0] = '\0';
Dhananjay Kumarac341582017-02-23 23:42:25 +05305688 if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
5689 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Alexy Joseph62142aa2015-11-16 15:10:34 -08005690 ALOGV("in direct_pcm");
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05305691 strlcat(value, "true", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005692 } else {
5693 ALOGV("not in direct_pcm");
Sharad Sangle3dd5a4a2015-12-10 18:39:17 +05305694 strlcat(value, "false", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005695 }
5696 str_parms_add_str(reply, "is_direct_pcm_track", value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005697 if (str)
5698 free(str);
Alexy Joseph62142aa2015-11-16 15:10:34 -08005699 str = str_parms_to_str(reply);
5700 }
5701
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005702 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
5703 if (ret >= 0) {
5704 value[0] = '\0';
5705 i = 0;
5706 first = true;
5707 while (out->supported_formats[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005708 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5709 if (formats_name_to_enum_table[j].value == out->supported_formats[i]) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005710 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005711 strlcat(value, "|", sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005712 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005713 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005714 first = false;
5715 break;
5716 }
5717 }
5718 i++;
5719 }
5720 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005721 if (str)
5722 free(str);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005723 str = str_parms_to_str(reply);
5724 }
Mingming Yin3a941d42016-02-17 18:08:05 -08005725
5726 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value, sizeof(value));
5727 if (ret >= 0) {
5728 value[0] = '\0';
5729 i = 0;
5730 first = true;
5731 while (out->supported_sample_rates[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005732 for (j = 0; j < ARRAY_SIZE(out_sample_rates_name_to_enum_table); j++) {
5733 if (out_sample_rates_name_to_enum_table[j].value == out->supported_sample_rates[i]) {
Mingming Yin3a941d42016-02-17 18:08:05 -08005734 if (!first) {
5735 strlcat(value, "|", sizeof(value));
5736 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005737 strlcat(value, out_sample_rates_name_to_enum_table[j].name, sizeof(value));
Mingming Yin3a941d42016-02-17 18:08:05 -08005738 first = false;
5739 break;
5740 }
5741 }
5742 i++;
5743 }
5744 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value);
5745 if (str)
5746 free(str);
5747 str = str_parms_to_str(reply);
5748 }
5749
Alexy Joseph98988832017-01-13 14:56:59 -08005750 if (str_parms_get_str(query, "supports_hw_suspend", value, sizeof(value)) >= 0) {
5751 //only low latency track supports suspend_resume
5752 str_parms_add_int(reply, "supports_hw_suspend",
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005753 (out->hal_output_suspend_supported));
Alexy Joseph98988832017-01-13 14:56:59 -08005754 if (str)
5755 free(str);
5756 str = str_parms_to_str(reply);
5757 }
5758
5759
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005760 str_parms_destroy(query);
5761 str_parms_destroy(reply);
Eric Laurent994a6932013-07-17 11:51:42 -07005762 ALOGV("%s: exit: returns - %s", __func__, str);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005763 return str;
5764}
5765
5766static uint32_t out_get_latency(const struct audio_stream_out *stream)
5767{
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005768 uint32_t period_ms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005769 struct stream_out *out = (struct stream_out *)stream;
Alexy Josephaa54c872014-12-03 02:46:47 -08005770 uint32_t latency = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005771
Alexy Josephaa54c872014-12-03 02:46:47 -08005772 if (is_offload_usecase(out->usecase)) {
Manish Dewangan07de2142017-02-27 19:27:20 +05305773 lock_output_stream(out);
5774 latency = audio_extn_utils_compress_get_dsp_latency(out);
5775 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07005776 } else if ((out->realtime) ||
5777 (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005778 // since the buffer won't be filled up faster than realtime,
5779 // return a smaller number
5780 if (out->config.rate)
5781 period_ms = (out->af_period_multiplier * out->config.period_size *
5782 1000) / (out->config.rate);
5783 else
5784 period_ms = 0;
George Gao9ba8a142020-07-23 14:30:03 -07005785 latency = period_ms + platform_render_latency(out) / 1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005786 } else {
5787 latency = (out->config.period_count * out->config.period_size * 1000) /
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005788 (out->config.rate);
pavanisra2d95d82022-02-09 18:55:58 +05305789 if (out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
5790 out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY)
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005791 latency += platform_render_latency(out)/1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005792 }
5793
Zhou Songd2537a02020-06-11 22:04:46 +08005794 if (!out->standby && is_a2dp_out_device_type(&out->device_list))
Aniket Kumar Latad5972fa2017-02-08 13:53:48 -08005795 latency += audio_extn_a2dp_get_encoder_latency();
5796
Anish Kumar50ebcbf2014-12-09 04:01:39 +05305797 ALOGV("%s: Latency %d", __func__, latency);
Alexy Josephaa54c872014-12-03 02:46:47 -08005798 return latency;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005799}
5800
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305801static float AmpToDb(float amplification)
5802{
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305803 float db = DSD_VOLUME_MIN_DB;
5804 if (amplification > 0) {
5805 db = 20 * log10(amplification);
5806 if(db < DSD_VOLUME_MIN_DB)
5807 return DSD_VOLUME_MIN_DB;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305808 }
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305809 return db;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305810}
5811
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305812#ifdef SOFT_VOLUME
5813static int out_set_soft_volume_params(struct audio_stream_out *stream)
5814{
5815 struct stream_out *out = (struct stream_out *)stream;
5816 int ret = 0;
5817 char mixer_ctl_name[128];
5818 struct audio_device *adev = out->dev;
5819 struct mixer_ctl *ctl = NULL;
5820 struct soft_step_volume_params *volume_params = NULL;
5821
5822 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5823 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Soft Vol Params", pcm_device_id);
5824 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5825 if (!ctl) {
5826 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5827 return -EINVAL;
5828 }
5829
5830 volume_params =(struct soft_step_volume_params * ) malloc(sizeof(struct soft_step_volume_params));
5831 if (volume_params == NULL){
5832 ALOGE("%s : malloc is failed for volume params", __func__);
5833 return -EINVAL;
5834 } else {
5835 ret = platform_get_soft_step_volume_params(volume_params,out->usecase);
5836 if (ret < 0) {
5837 ALOGE("%s : platform_get_soft_step_volume_params is fialed", __func__);
Karan Naidu28b335a2022-05-18 23:00:08 +05305838 ret = -EINVAL;
5839 goto ERR_EXIT;
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305840 }
5841
5842 }
5843 ret = mixer_ctl_set_array(ctl, volume_params, sizeof(struct soft_step_volume_params)/sizeof(int));
5844 if (ret < 0) {
5845 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
Karan Naidu28b335a2022-05-18 23:00:08 +05305846 ret = -EINVAL;
5847 goto ERR_EXIT;
5848 }
5849
5850 if (volume_params) {
5851 free(volume_params);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305852 }
5853 return 0;
Karan Naidu28b335a2022-05-18 23:00:08 +05305854
5855ERR_EXIT:
5856 if (volume_params) {
5857 free(volume_params);
5858 }
5859 return ret;
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305860}
5861#endif
5862
Arun Mirpuri5d170872019-03-26 13:21:31 -07005863static int out_set_mmap_volume(struct audio_stream_out *stream, float left,
5864 float right)
5865{
5866 struct stream_out *out = (struct stream_out *)stream;
5867 long volume = 0;
5868 char mixer_ctl_name[128] = "";
5869 struct audio_device *adev = out->dev;
5870 struct mixer_ctl *ctl = NULL;
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 "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 if (left != right)
5883 ALOGW("%s: Left and right channel volume mismatch:%f,%f",
5884 __func__, left, right);
5885 volume = (long)(left * (MMAP_PLAYBACK_VOLUME_MAX*1.0));
5886 if (mixer_ctl_set_value(ctl, 0, volume) < 0){
5887 ALOGE("%s:ctl for mixer cmd - %s, volume %ld returned error",
5888 __func__, mixer_ctl_name, volume);
5889 return -EINVAL;
5890 }
5891 return 0;
5892}
5893
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305894static int out_set_compr_volume(struct audio_stream_out *stream, float left,
5895 float right)
5896{
5897 struct stream_out *out = (struct stream_out *)stream;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305898 long volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305899 char mixer_ctl_name[128];
5900 struct audio_device *adev = out->dev;
5901 struct mixer_ctl *ctl;
5902 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5903 PCM_PLAYBACK);
5904
5905 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5906 "Compress Playback %d Volume", pcm_device_id);
5907 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5908 if (!ctl) {
5909 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5910 __func__, mixer_ctl_name);
5911 return -EINVAL;
5912 }
5913 ALOGE("%s:ctl for mixer cmd - %s, left %f, right %f",
5914 __func__, mixer_ctl_name, left, right);
5915 volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
5916 volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
5917 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5918
5919 return 0;
5920}
5921
Zhou Song2b8f28f2017-09-11 10:51:38 +08005922static int out_set_voip_volume(struct audio_stream_out *stream, float left,
5923 float right)
5924{
5925 struct stream_out *out = (struct stream_out *)stream;
5926 char mixer_ctl_name[] = "App Type Gain";
5927 struct audio_device *adev = out->dev;
5928 struct mixer_ctl *ctl;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305929 long set_values[4];
Zhou Song2b8f28f2017-09-11 10:51:38 +08005930
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07005931 if (!is_valid_volume(left, right)) {
5932 ALOGE("%s: Invalid stream volume for left=%f, right=%f",
5933 __func__, left, right);
5934 return -EINVAL;
5935 }
5936
Zhou Song2b8f28f2017-09-11 10:51:38 +08005937 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5938 if (!ctl) {
5939 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5940 __func__, mixer_ctl_name);
5941 return -EINVAL;
5942 }
5943
5944 set_values[0] = 0; //0: Rx Session 1:Tx Session
5945 set_values[1] = out->app_type_cfg.app_type;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305946 set_values[2] = (long)(left * VOIP_PLAYBACK_VOLUME_MAX);
5947 set_values[3] = (long)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Song2b8f28f2017-09-11 10:51:38 +08005948
5949 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
5950 return 0;
5951}
5952
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305953static int out_set_pcm_volume(struct audio_stream_out *stream, float left,
5954 float right)
5955{
5956 struct stream_out *out = (struct stream_out *)stream;
5957 /* Volume control for pcm playback */
5958 if (left != right) {
5959 return -EINVAL;
5960 } else {
5961 char mixer_ctl_name[128];
5962 struct audio_device *adev = out->dev;
5963 struct mixer_ctl *ctl;
5964 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5965 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Volume", pcm_device_id);
5966 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5967 if (!ctl) {
5968 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5969 return -EINVAL;
5970 }
5971
5972 int volume = (int) (left * PCM_PLAYBACK_VOLUME_MAX);
5973 int ret = mixer_ctl_set_value(ctl, 0, volume);
5974 if (ret < 0) {
5975 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
5976 return -EINVAL;
5977 }
5978
5979 ALOGV("%s : Pcm set volume value %d left %f", __func__, volume, left);
5980
5981 return 0;
5982 }
5983}
5984
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005985static int out_set_volume(struct audio_stream_out *stream, float left,
5986 float right)
5987{
Eric Laurenta9024de2013-04-04 09:19:12 -07005988 struct stream_out *out = (struct stream_out *)stream;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005989 int volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305990 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005991
Arun Mirpuri5d170872019-03-26 13:21:31 -07005992 ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
Eric Laurenta9024de2013-04-04 09:19:12 -07005993 if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
5994 /* only take left channel into account: the API is for stereo anyway */
5995 out->muted = (left == 0.0f);
5996 return 0;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005997 } else if (is_offload_usecase(out->usecase)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305998 if (audio_extn_passthru_is_passthrough_stream(out)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005999 /*
6000 * Set mute or umute on HDMI passthrough stream.
6001 * Only take left channel into account.
6002 * Mute is 0 and unmute 1
6003 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306004 audio_extn_passthru_set_volume(out, (left == 0.0f));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05306005 } else if (out->format == AUDIO_FORMAT_DSD){
6006 char mixer_ctl_name[128] = "DSD Volume";
6007 struct audio_device *adev = out->dev;
6008 struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
6009
6010 if (!ctl) {
6011 ALOGE("%s: Could not get ctl for mixer cmd - %s",
6012 __func__, mixer_ctl_name);
6013 return -EINVAL;
6014 }
Manish Dewangan338c50a2017-09-12 15:22:03 +05306015 volume[0] = (long)(AmpToDb(left));
6016 volume[1] = (long)(AmpToDb(right));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05306017 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
6018 return 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006019 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS) &&
Derek Chendf05eea2019-08-01 13:57:49 -07006020 (out->car_audio_stream == CAR_AUDIO_STREAM_MEDIA)) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07006021 ALOGD("%s: Overriding offload set volume for media bus stream", __func__);
6022 struct listnode *node = NULL;
6023 list_for_each(node, &adev->active_outputs_list) {
6024 streams_output_ctxt_t *out_ctxt = node_to_item(node,
6025 streams_output_ctxt_t,
6026 list);
6027 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
6028 out->volume_l = out_ctxt->output->volume_l;
6029 out->volume_r = out_ctxt->output->volume_r;
6030 }
6031 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006032 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006033 if (!out->a2dp_muted) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07006034 ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
6035 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006036 pthread_mutex_unlock(&out->latch_lock);
Philippe Gravel1c9ac352019-05-28 16:08:37 -07006037 return ret;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07006038 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +08006039 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006040 ALOGV("%s: compress mute %d", __func__, out->a2dp_muted);
6041 if (!out->a2dp_muted)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306042 ret = out_set_compr_volume(stream, left, right);
6043 out->volume_l = left;
6044 out->volume_r = right;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006045 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306046 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006047 }
Vikram Panduranga93f080e2017-06-07 18:16:14 -07006048 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
Aalique Grahame22e49102018-12-18 14:23:57 -08006049 out->app_type_cfg.gain[0] = (int)(left * VOIP_PLAYBACK_VOLUME_MAX);
6050 out->app_type_cfg.gain[1] = (int)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006051 pthread_mutex_lock(&out->latch_lock);
Aalique Grahame22e49102018-12-18 14:23:57 -08006052 if (!out->standby) {
6053 audio_extn_utils_send_app_type_gain(out->dev,
6054 out->app_type_cfg.app_type,
6055 &out->app_type_cfg.gain[0]);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006056 if (!out->a2dp_muted)
6057 ret = out_set_voip_volume(stream, left, right);
Aalique Grahame22e49102018-12-18 14:23:57 -08006058 }
Zhou Song2b8f28f2017-09-11 10:51:38 +08006059 out->volume_l = left;
6060 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006061 pthread_mutex_unlock(&out->latch_lock);
Zhou Song2b8f28f2017-09-11 10:51:38 +08006062 return ret;
Arun Mirpuri5d170872019-03-26 13:21:31 -07006063 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
6064 ALOGV("%s: MMAP set volume called", __func__);
6065 if (!out->standby)
6066 ret = out_set_mmap_volume(stream, left, right);
6067 out->volume_l = left;
6068 out->volume_r = right;
6069 return ret;
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306070 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
Ramu Gottipati36547092018-12-28 11:32:09 +05306071 out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
6072 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
Zhou Songbaddf9f2020-11-20 13:57:39 +08006073 pthread_mutex_lock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306074 /* Volume control for pcm playback */
Zhou Songbaddf9f2020-11-20 13:57:39 +08006075 if (!out->standby && !out->a2dp_muted)
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306076 ret = out_set_pcm_volume(stream, left, right);
6077 else
6078 out->apply_volume = true;
6079
6080 out->volume_l = left;
6081 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006082 pthread_mutex_unlock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306083 return ret;
Derek Chenf13dd492018-11-13 14:53:51 -08006084 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
6085 ALOGV("%s: bus device set volume called", __func__);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006086 pthread_mutex_lock(&out->latch_lock);
6087 if (!out->standby && !out->a2dp_muted)
Derek Chenf13dd492018-11-13 14:53:51 -08006088 ret = out_set_pcm_volume(stream, left, right);
6089 out->volume_l = left;
6090 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006091 pthread_mutex_unlock(&out->latch_lock);
Derek Chenf13dd492018-11-13 14:53:51 -08006092 return ret;
Eric Laurenta9024de2013-04-04 09:19:12 -07006093 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006094
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006095 return -ENOSYS;
6096}
6097
Zhou Songc9672822017-08-16 16:01:39 +08006098static void update_frames_written(struct stream_out *out, size_t bytes)
6099{
6100 size_t bpf = 0;
6101
6102 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
6103 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
6104 bpf = 1;
6105 else if (!is_offload_usecase(out->usecase))
6106 bpf = audio_bytes_per_sample(out->format) *
6107 audio_channel_count_from_out_mask(out->channel_mask);
Zhou Song48453a02018-01-10 17:50:59 +08006108
6109 pthread_mutex_lock(&out->position_query_lock);
6110 if (bpf != 0) {
Zhou Songc9672822017-08-16 16:01:39 +08006111 out->written += bytes / bpf;
Zhou Song48453a02018-01-10 17:50:59 +08006112 clock_gettime(CLOCK_MONOTONIC, &out->writeAt);
6113 }
6114 pthread_mutex_unlock(&out->position_query_lock);
Zhou Songc9672822017-08-16 16:01:39 +08006115}
6116
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006117int split_and_write_audio_haptic_data(struct stream_out *out,
6118 const void *buffer, size_t bytes_to_write)
6119{
6120 struct audio_device *adev = out->dev;
6121
6122 int ret = 0;
6123 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6124 size_t bytes_per_sample = audio_bytes_per_sample(out->format);
6125 size_t frame_size = channel_count * bytes_per_sample;
6126 size_t frame_count = bytes_to_write / frame_size;
6127
6128 bool force_haptic_path =
6129 property_get_bool("vendor.audio.test_haptic", false);
6130
6131 // extract Haptics data from Audio buffer
6132 bool alloc_haptic_buffer = false;
6133 int haptic_channel_count = adev->haptics_config.channels;
6134 size_t haptic_frame_size = bytes_per_sample * haptic_channel_count;
6135 size_t audio_frame_size = frame_size - haptic_frame_size;
6136 size_t total_haptic_buffer_size = frame_count * haptic_frame_size;
6137
6138 if (adev->haptic_buffer == NULL) {
6139 alloc_haptic_buffer = true;
6140 } else if (adev->haptic_buffer_size < total_haptic_buffer_size) {
6141 free(adev->haptic_buffer);
6142 adev->haptic_buffer_size = 0;
6143 alloc_haptic_buffer = true;
6144 }
6145
6146 if (alloc_haptic_buffer) {
6147 adev->haptic_buffer = (uint8_t *)calloc(1, total_haptic_buffer_size);
Mingshu Pang1513f972019-05-24 12:43:51 +08006148 if(adev->haptic_buffer == NULL) {
6149 ALOGE("%s: failed to allocate mem for dev->haptic_buffer", __func__);
6150 return -ENOMEM;
6151 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006152 adev->haptic_buffer_size = total_haptic_buffer_size;
6153 }
6154
6155 size_t src_index = 0, aud_index = 0, hap_index = 0;
6156 uint8_t *audio_buffer = (uint8_t *)buffer;
6157 uint8_t *haptic_buffer = adev->haptic_buffer;
6158
6159 // This is required for testing only. This works for stereo data only.
6160 // One channel is fed to audio stream and other to haptic stream for testing.
6161 if (force_haptic_path)
6162 audio_frame_size = haptic_frame_size = bytes_per_sample;
6163
6164 for (size_t i = 0; i < frame_count; i++) {
6165 memcpy(audio_buffer + aud_index, audio_buffer + src_index,
6166 audio_frame_size);
6167 aud_index += audio_frame_size;
6168 src_index += audio_frame_size;
6169
6170 if (adev->haptic_pcm)
6171 memcpy(haptic_buffer + hap_index, audio_buffer + src_index,
6172 haptic_frame_size);
6173 hap_index += haptic_frame_size;
6174 src_index += haptic_frame_size;
6175
6176 // This is required for testing only.
6177 // Discard haptic channel data.
6178 if (force_haptic_path)
6179 src_index += haptic_frame_size;
6180 }
6181
6182 // write to audio pipeline
6183 ret = pcm_write(out->pcm, (void *)audio_buffer,
6184 frame_count * audio_frame_size);
6185
6186 // write to haptics pipeline
6187 if (adev->haptic_pcm)
6188 ret = pcm_write(adev->haptic_pcm, (void *)adev->haptic_buffer,
6189 frame_count * haptic_frame_size);
6190
6191 return ret;
6192}
6193
Aalique Grahame22e49102018-12-18 14:23:57 -08006194#ifdef NO_AUDIO_OUT
6195static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
6196 const void *buffer __unused, size_t bytes)
6197{
6198 struct stream_out *out = (struct stream_out *)stream;
6199
6200 /* No Output device supported other than BT for playback.
6201 * Sleep for the amount of buffer duration
6202 */
6203 lock_output_stream(out);
6204 usleep(bytes * 1000000 / audio_stream_out_frame_size(
6205 (const struct audio_stream_out *)&out->stream) /
6206 out_get_sample_rate(&out->stream.common));
6207 pthread_mutex_unlock(&out->lock);
6208 return bytes;
6209}
6210#endif
6211
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006212static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
6213 size_t bytes)
6214{
6215 struct stream_out *out = (struct stream_out *)stream;
6216 struct audio_device *adev = out->dev;
Eric Laurent6e895242013-09-05 16:10:57 -07006217 ssize_t ret = 0;
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306218 int channels = 0;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006219 const size_t frame_size = audio_stream_out_frame_size(stream);
6220 const size_t frames = (frame_size != 0) ? bytes / frame_size : bytes;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306221 struct audio_usecase *usecase = NULL;
Meng Wang4c32fb42020-01-16 17:57:11 +08006222 uint32_t compr_passthr = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006223
Haynes Mathew George380745d2017-10-04 15:27:45 -07006224 ATRACE_BEGIN("out_write");
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006225 lock_output_stream(out);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306226
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006227 if (CARD_STATUS_OFFLINE == out->card_status ||
6228 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Zhou Song0b2e5dc2015-03-16 14:41:38 +08006229
Dhananjay Kumarac341582017-02-23 23:42:25 +05306230 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306231 /*during SSR for compress usecase we should return error to flinger*/
Naresh Tanniru80659832014-06-04 18:17:56 +05306232 ALOGD(" copl %s: sound card is not active/SSR state", __func__);
6233 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006234 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306235 return -ENETRESET;
Ashish Jainbbce4322016-02-16 13:25:27 +05306236 } else {
Ashish Jainbbce4322016-02-16 13:25:27 +05306237 ALOGD(" %s: sound card is not active/SSR state", __func__);
6238 ret= -EIO;
6239 goto exit;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306240 }
6241 }
6242
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306243 if (audio_extn_passthru_should_drop_data(out)) {
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306244 ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306245 ret = -EIO;
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306246 goto exit;
6247 }
6248
Haynes Mathew George16081042017-05-31 17:16:49 -07006249 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
6250 ret = -EINVAL;
6251 goto exit;
6252 }
6253
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006254 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306255 !out->is_iec61937_info_available) {
6256
6257 if (!audio_extn_passthru_is_passthrough_stream(out)) {
6258 out->is_iec61937_info_available = true;
6259 } else if (audio_extn_passthru_is_enabled()) {
6260 audio_extn_passthru_update_stream_configuration(adev, out, buffer, bytes);
Manish Dewangan37864bc2017-06-09 12:28:37 +05306261 out->is_iec61937_info_available = true;
Manish Dewangan671a4202017-08-18 17:30:46 +05306262
6263 if((out->format == AUDIO_FORMAT_DTS) ||
6264 (out->format == AUDIO_FORMAT_DTS_HD)) {
6265 ret = audio_extn_passthru_update_dts_stream_configuration(out,
6266 buffer, bytes);
6267 if (ret) {
6268 if (ret != -ENOSYS) {
6269 out->is_iec61937_info_available = false;
6270 ALOGD("iec61937 transmission info not yet updated retry");
6271 }
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306272 } else if (!out->standby) {
Manish Dewangan671a4202017-08-18 17:30:46 +05306273 /* if stream has started and after that there is
6274 * stream config change (iec transmission config)
6275 * then trigger select_device to update backend configuration.
6276 */
6277 out->stream_config_changed = true;
6278 pthread_mutex_lock(&adev->lock);
6279 select_devices(adev, out->usecase);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306280 if (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out)) {
Weiyin Jiang29c08a42019-04-30 17:11:10 +08006281 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306282 ret = -EINVAL;
6283 goto exit;
6284 }
Manish Dewangan671a4202017-08-18 17:30:46 +05306285 pthread_mutex_unlock(&adev->lock);
6286 out->stream_config_changed = false;
6287 out->is_iec61937_info_available = true;
6288 }
6289 }
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306290
Meng Wang4c32fb42020-01-16 17:57:11 +08006291#ifdef AUDIO_GKI_ENABLED
6292 /* out->compr_config.codec->reserved[0] is for compr_passthr */
6293 compr_passthr = out->compr_config.codec->reserved[0];
6294#else
6295 compr_passthr = out->compr_config.codec->compr_passthr;
6296#endif
6297
Garmond Leung317cbf12017-09-13 16:20:50 -07006298 if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
Meng Wang4c32fb42020-01-16 17:57:11 +08006299 (compr_passthr == PASSTHROUGH) &&
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306300 (out->is_iec61937_info_available == true)) {
6301 ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
6302 ret = -EINVAL;
6303 goto exit;
6304 }
Manish Dewangan37864bc2017-06-09 12:28:37 +05306305 }
6306 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306307
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006308 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02006309 (audio_extn_a2dp_source_is_suspended())) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006310 if (!(compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
6311 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
Zhou Songd01e7a22020-09-23 22:49:01 +08006312 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306313 ret = -EIO;
6314 goto exit;
6315 }
6316 }
6317 }
6318
Weiyin Jiangabedea32020-12-09 12:49:19 +08006319 if (is_usb_out_device_type(&out->device_list) &&
6320 !audio_extn_usb_connected(NULL)) {
6321 ret = -EIO;
6322 goto exit;
6323 }
6324
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006325 if (out->standby) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006326 out->standby = false;
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006327 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
6328
Eric Laurent150dbfe2013-02-27 14:31:02 -08006329 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006330 if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
6331 ret = voice_extn_compress_voip_start_output_stream(out);
6332 else
6333 ret = start_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006334 /* ToDo: If use case is compress offload should return 0 */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006335 if (ret != 0) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006336 out->standby = true;
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006337 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006338 goto exit;
6339 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306340 out->started = 1;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006341 out->last_fifo_valid = false; // we're coming out of standby, last_fifo isn't valid.
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006342
6343 if ((last_known_cal_step != -1) && (adev->platform != NULL)) {
vivek mehtab72d08d2016-04-29 03:16:47 -07006344 ALOGD("%s: retry previous failed cal level set", __func__);
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006345 platform_send_gain_dep_cal(adev->platform, last_known_cal_step);
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +05306346 last_known_cal_step = -1;
vivek mehtab72d08d2016-04-29 03:16:47 -07006347 }
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006348 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306349
6350 if ((out->is_iec61937_info_available == true) &&
6351 (audio_extn_passthru_is_passthrough_stream(out))&&
6352 (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out))) {
6353 ret = -EINVAL;
6354 goto exit;
6355 }
Surendar Karkaf51b5842018-04-26 11:28:38 +05306356 if (out->set_dual_mono)
6357 audio_extn_send_dual_mono_mixing_coefficients(out);
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006358
Dechen Chai22768452021-07-30 09:29:16 +05306359#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006360 // log startup time in ms.
6361 simple_stats_log(
6362 &out->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05306363#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006364 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006365
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006366 if (adev->is_channel_status_set == false &&
6367 compare_device_type(&out->device_list,
6368 AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Alexy Josephb1379942016-01-29 15:49:38 -08006369 audio_utils_set_hdmi_channel_status(out, (void *)buffer, bytes);
Ashish Jain81eb2a82015-05-13 10:52:34 +05306370 adev->is_channel_status_set = true;
6371 }
6372
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306373 if ((adev->use_old_pspd_mix_ctrl == true) &&
6374 (out->pspd_coeff_sent == false)) {
6375 /*
6376 * Need to resend pspd coefficients after stream started for
6377 * older kernel version as it does not save the coefficients
6378 * and also stream has to be started for coeff to apply.
6379 */
6380 usecase = get_usecase_from_list(adev, out->usecase);
6381 if (usecase != NULL) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05306382 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306383 out->pspd_coeff_sent = true;
6384 }
6385 }
6386
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006387 if (is_offload_usecase(out->usecase)) {
Alexy Joseph01e54e62015-03-03 19:01:03 -08006388 ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006389 if (out->send_new_metadata) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006390 ALOGD("copl(%p):send new gapless metadata", out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006391 compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
6392 out->send_new_metadata = 0;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306393 if (out->send_next_track_params && out->is_compr_metadata_avail) {
6394 ALOGD("copl(%p):send next track params in gapless", out);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08006395 compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306396 out->send_next_track_params = false;
6397 out->is_compr_metadata_avail = false;
6398 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006399 }
Dhananjay Kumarac341582017-02-23 23:42:25 +05306400 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306401 (out->convert_buffer) != NULL) {
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006402
Ashish Jain83a6cc22016-06-28 14:34:17 +05306403 if ((bytes > out->hal_fragment_size)) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05306404 ALOGW("Error written bytes %zu > %d (fragment_size)",
Ashish Jain83a6cc22016-06-28 14:34:17 +05306405 bytes, out->hal_fragment_size);
Ashish Jainf1eaa582016-05-23 20:54:24 +05306406 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006407 ATRACE_END();
Ashish Jainf1eaa582016-05-23 20:54:24 +05306408 return -EINVAL;
6409 } else {
Ashish Jain83a6cc22016-06-28 14:34:17 +05306410 audio_format_t dst_format = out->hal_op_format;
6411 audio_format_t src_format = out->hal_ip_format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05306412
Dieter Luecking5d57def2018-09-07 14:23:37 +02006413 /* prevent division-by-zero */
6414 uint32_t bitwidth_src = format_to_bitwidth_table[src_format];
6415 uint32_t bitwidth_dst = format_to_bitwidth_table[dst_format];
6416 if ((bitwidth_src == 0) || (bitwidth_dst == 0)) {
6417 ALOGE("%s: Error bitwidth == 0", __func__);
Ramu Gottipati02809682018-12-19 16:46:12 +05306418 pthread_mutex_unlock(&out->lock);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006419 ATRACE_END();
6420 return -EINVAL;
6421 }
6422
Ashish Jainf1eaa582016-05-23 20:54:24 +05306423 uint32_t frames = bytes / format_to_bitwidth_table[src_format];
6424 uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
6425
Ashish Jain83a6cc22016-06-28 14:34:17 +05306426 memcpy_by_audio_format(out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306427 dst_format,
6428 buffer,
6429 src_format,
6430 frames);
6431
Ashish Jain83a6cc22016-06-28 14:34:17 +05306432 ret = compress_write(out->compr, out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306433 bytes_to_write);
6434
6435 /*Convert written bytes in audio flinger format*/
6436 if (ret > 0)
6437 ret = ((ret * format_to_bitwidth_table[out->format]) /
6438 format_to_bitwidth_table[dst_format]);
6439 }
6440 } else
6441 ret = compress_write(out->compr, buffer, bytes);
6442
Zhou Songc9672822017-08-16 16:01:39 +08006443 if ((ret < 0 || ret == (ssize_t)bytes) && !out->non_blocking)
6444 update_frames_written(out, bytes);
6445
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306446 if (ret < 0)
6447 ret = -errno;
Weiyin Jiangcc60dbb2018-08-21 13:12:03 +08006448 ALOGVV("%s: writing buffer (%zu bytes) to compress device returned %d", __func__, bytes, (int)ret);
Ashish Jainb26edfb2016-08-25 00:10:11 +05306449 /*msg to cb thread only if non blocking write is enabled*/
6450 if (ret >= 0 && ret < (ssize_t)bytes && out->non_blocking) {
Sidipotu Ashok55820562014-02-10 16:16:38 +05306451 ALOGD("No space available in compress driver, post msg to cb thread");
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006452 send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
Naresh Tanniru80659832014-06-04 18:17:56 +05306453 } else if (-ENETRESET == ret) {
6454 ALOGE("copl %s: received sound card offline state on compress write", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306455 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru80659832014-06-04 18:17:56 +05306456 pthread_mutex_unlock(&out->lock);
Dhananjay Kumar1248dd82017-07-28 21:22:16 +05306457 out_on_error(&out->stream.common);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006458 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306459 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006460 }
Ashish Jain5106d362016-05-11 19:23:33 +05306461
Dhanalakshmi Siddania6b76c72016-09-09 18:10:31 +05306462 /* Call compr start only when non-zero bytes of data is there to be rendered */
6463 if (!out->playback_started && ret > 0) {
6464 int status = compress_start(out->compr);
6465 if (status < 0) {
6466 ret = status;
6467 ALOGE("%s: compr start failed with err %d", __func__, errno);
6468 goto exit;
6469 }
Alexy Joseph7de344d2015-03-30 10:40:03 -07006470 audio_extn_dts_eagle_fade(adev, true, out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006471 out->playback_started = 1;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006472 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006473 out->offload_state = OFFLOAD_STATE_PLAYING;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006474 pthread_mutex_unlock(&out->latch_lock);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006475
6476 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6477 popcount(out->channel_mask),
6478 out->playback_started);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006479 }
6480 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006481 ATRACE_END();
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006482 return ret;
6483 } else {
6484 if (out->pcm) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006485 size_t bytes_to_write = bytes;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006486 if (out->muted)
6487 memset((void *)buffer, 0, bytes);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006488 ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
6489 __func__, frames, frame_size, bytes_to_write);
6490
Aalique Grahame22e49102018-12-18 14:23:57 -08006491 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07006492 out->usecase == USECASE_INCALL_MUSIC_UPLINK2 ||
6493 (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP &&
6494 !audio_extn_utils_is_vendor_enhanced_fwk())) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006495 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6496 int16_t *src = (int16_t *)buffer;
6497 int16_t *dst = (int16_t *)buffer;
6498
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006499 LOG_ALWAYS_FATAL_IF(channel_count > 2 ||
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006500 out->format != AUDIO_FORMAT_PCM_16_BIT,
Aalique Grahame22e49102018-12-18 14:23:57 -08006501 "out_write called for %s use case with wrong properties",
6502 use_case_table[out->usecase]);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006503
6504 /*
6505 * FIXME: this can be removed once audio flinger mixer supports
6506 * mono output
6507 */
6508
6509 /*
6510 * Code below goes over each frame in the buffer and adds both
6511 * L and R samples and then divides by 2 to convert to mono
6512 */
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006513 if (channel_count == 2) {
6514 for (size_t i = 0; i < frames ; i++, dst++, src += 2) {
6515 *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
6516 }
6517 bytes_to_write /= 2;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006518 }
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006519 }
Andy Hunga1f48fa2019-07-01 18:14:53 -07006520
6521 // Note: since out_get_presentation_position() is called alternating with out_write()
6522 // by AudioFlinger, we can check underruns using the prior timestamp read.
6523 // (Alternately we could check if the buffer is empty using pcm_get_htimestamp().
6524 if (out->last_fifo_valid) {
6525 // compute drain to see if there is an underrun.
6526 const int64_t current_ns = systemTime(SYSTEM_TIME_MONOTONIC); // sys call
Dhananjay Kumara4429632020-07-11 02:53:37 +05306527 int64_t time_diff_ns = current_ns - out->last_fifo_time_ns;
6528 int64_t frames_by_time =
6529 ((time_diff_ns > 0) && (time_diff_ns < (INT64_MAX / out->config.rate))) ?
6530 (time_diff_ns * out->config.rate / NANOS_PER_SECOND) : 0;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006531 const int64_t underrun = frames_by_time - out->last_fifo_frames_remaining;
6532
6533 if (underrun > 0) {
Dechen Chai22768452021-07-30 09:29:16 +05306534#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07006535 simple_stats_log(&out->fifo_underruns, underrun);
Dechen Chai22768452021-07-30 09:29:16 +05306536#endif
Andy Hunga1f48fa2019-07-01 18:14:53 -07006537
6538 ALOGW("%s: underrun(%lld) "
6539 "frames_by_time(%lld) > out->last_fifo_frames_remaining(%lld)",
6540 __func__,
6541 (long long)out->fifo_underruns.n,
6542 (long long)frames_by_time,
6543 (long long)out->last_fifo_frames_remaining);
6544 }
6545 out->last_fifo_valid = false; // we're writing below, mark fifo info as stale.
6546 }
6547
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05306548 ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006549
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006550 long ns = 0;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006551
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006552 if (out->config.rate)
6553 ns = pcm_bytes_to_frames(out->pcm, bytes)*1000000000LL/
6554 out->config.rate;
6555
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006556 request_out_focus(out, ns);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006557 bool use_mmap = is_mmap_usecase(out->usecase) || out->realtime;
6558
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006559 if (use_mmap)
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006560 ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes_to_write);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006561 else if (out->hal_op_format != out->hal_ip_format &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306562 out->convert_buffer != NULL) {
6563
6564 memcpy_by_audio_format(out->convert_buffer,
6565 out->hal_op_format,
6566 buffer,
6567 out->hal_ip_format,
6568 out->config.period_size * out->config.channels);
6569
6570 ret = pcm_write(out->pcm, out->convert_buffer,
6571 (out->config.period_size *
6572 out->config.channels *
6573 format_to_bitwidth_table[out->hal_op_format]));
6574 } else {
Aditya Bavanarid4db8ee2017-05-29 21:08:03 +05306575 /*
6576 * To avoid underrun in DSP when the application is not pumping
6577 * data at required rate, check for the no. of bytes and ignore
6578 * pcm_write if it is less than actual buffer size.
6579 * It is a work around to a change in compress VOIP driver.
6580 */
6581 if ((out->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) &&
6582 bytes < (out->config.period_size * out->config.channels *
6583 audio_bytes_per_sample(out->format))) {
6584 size_t voip_buf_size =
6585 out->config.period_size * out->config.channels *
6586 audio_bytes_per_sample(out->format);
6587 ALOGE("%s:VOIP underrun: bytes received %zu, required:%zu\n",
6588 __func__, bytes, voip_buf_size);
6589 usleep(((uint64_t)voip_buf_size - bytes) *
6590 1000000 / audio_stream_out_frame_size(stream) /
6591 out_get_sample_rate(&out->stream.common));
6592 ret = 0;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006593 } else {
6594 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
6595 ret = split_and_write_audio_haptic_data(out, buffer, bytes);
6596 else
6597 ret = pcm_write(out->pcm, (void *)buffer, bytes_to_write);
6598 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05306599 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006600
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006601 release_out_focus(out);
6602
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306603 if (ret < 0)
6604 ret = -errno;
Zhou Songc9672822017-08-16 16:01:39 +08006605 else if (ret > 0)
Ashish Jain83a6cc22016-06-28 14:34:17 +05306606 ret = -EINVAL;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006607 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006608 }
6609
6610exit:
Zhou Songc9672822017-08-16 16:01:39 +08006611 update_frames_written(out, bytes);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306612 if (-ENETRESET == ret) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306613 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306614 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006615 pthread_mutex_unlock(&out->lock);
6616
6617 if (ret != 0) {
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07006618 if (out->pcm)
Alexy Josephb1379942016-01-29 15:49:38 -08006619 ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306620 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306621 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306622 voice_extn_compress_voip_close_output_stream(&out->stream.common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306623 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306624 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306625 out->standby = true;
6626 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306627 out_on_error(&out->stream.common);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006628 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
6629 /* prevent division-by-zero */
6630 uint32_t stream_size = audio_stream_out_frame_size(stream);
6631 uint32_t srate = out_get_sample_rate(&out->stream.common);
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006632
Dieter Luecking5d57def2018-09-07 14:23:37 +02006633 if ((stream_size == 0) || (srate == 0)) {
6634 ALOGE("%s: stream_size= %d, srate = %d", __func__, stream_size, srate);
6635 ATRACE_END();
6636 return -EINVAL;
6637 }
6638 usleep((uint64_t)bytes * 1000000 / stream_size / srate);
6639 }
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006640 if (audio_extn_passthru_is_passthrough_stream(out)) {
Rajshekar Eashwarappa88834522018-04-02 17:20:15 +05306641 //ALOGE("%s: write error, ret = %zd", __func__, ret);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006642 ATRACE_END();
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006643 return ret;
6644 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006645 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07006646 ATRACE_END();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006647 return bytes;
6648}
6649
6650static int out_get_render_position(const struct audio_stream_out *stream,
6651 uint32_t *dsp_frames)
6652{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006653 struct stream_out *out = (struct stream_out *)stream;
Zhou Song32a556e2015-05-05 10:46:56 +08006654
6655 if (dsp_frames == NULL)
6656 return -EINVAL;
6657
6658 *dsp_frames = 0;
6659 if (is_offload_usecase(out->usecase)) {
Mingming Yin9e348b52014-11-19 16:18:55 -08006660 ssize_t ret = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05306661
6662 /* Below piece of code is not guarded against any lock beacuse audioFliner serializes
6663 * this operation and adev_close_output_stream(where out gets reset).
6664 */
Dhananjay Kumarac341582017-02-23 23:42:25 +05306665 if (!out->non_blocking && !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006666 *dsp_frames = get_actual_pcm_frames_rendered(out, NULL);
Ashish Jain5106d362016-05-11 19:23:33 +05306667 ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate);
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006668 adjust_frames_for_device_delay(out, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05306669 return 0;
6670 }
6671
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006672 lock_output_stream(out);
Ashish Jain5106d362016-05-11 19:23:33 +05306673 if (out->compr != NULL && out->non_blocking) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306674 ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006675 &out->sample_rate);
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306676 if (ret < 0)
6677 ret = -errno;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006678 ALOGVV("%s rendered frames %d sample_rate %d",
Ashish Jain5106d362016-05-11 19:23:33 +05306679 __func__, *dsp_frames, out->sample_rate);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006680 }
Naresh Tanniru80659832014-06-04 18:17:56 +05306681 if (-ENETRESET == ret) {
6682 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306683 out->card_status = CARD_STATUS_OFFLINE;
6684 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306685 } else if(ret < 0) {
6686 ALOGE(" ERROR: Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306687 ret = -EINVAL;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006688 } else if (out->card_status == CARD_STATUS_OFFLINE ||
6689 adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05306690 /*
6691 * Handle corner case where compress session is closed during SSR
6692 * and timestamp is queried
6693 */
6694 ALOGE(" ERROR: sound card not active, return error");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306695 ret = -EINVAL;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306696 } else if (out->prev_card_status_offline) {
6697 ALOGE("ERROR: previously sound card was offline,return error");
6698 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306699 } else {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306700 ret = 0;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006701 adjust_frames_for_device_delay(out, dsp_frames);
Naresh Tanniru80659832014-06-04 18:17:56 +05306702 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306703 pthread_mutex_unlock(&out->lock);
6704 return ret;
Zhou Song32a556e2015-05-05 10:46:56 +08006705 } else if (audio_is_linear_pcm(out->format)) {
6706 *dsp_frames = out->written;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006707 adjust_frames_for_device_delay(out, dsp_frames);
Zhou Song32a556e2015-05-05 10:46:56 +08006708 return 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006709 } else
6710 return -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006711}
6712
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006713static int out_add_audio_effect(const struct audio_stream *stream __unused,
6714 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006715{
6716 return 0;
6717}
6718
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006719static int out_remove_audio_effect(const struct audio_stream *stream __unused,
6720 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006721{
6722 return 0;
6723}
6724
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006725static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
6726 int64_t *timestamp __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006727{
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05306728 return -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006729}
6730
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006731static int out_get_presentation_position(const struct audio_stream_out *stream,
6732 uint64_t *frames, struct timespec *timestamp)
6733{
6734 struct stream_out *out = (struct stream_out *)stream;
pavance65c2fe2017-10-18 17:52:01 +05306735 int ret = -ENODATA;
Eric Laurent949a0892013-09-20 09:20:13 -07006736 unsigned long dsp_frames;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006737
Ashish Jain5106d362016-05-11 19:23:33 +05306738 /* below piece of code is not guarded against any lock because audioFliner serializes
6739 * this operation and adev_close_output_stream( where out gets reset).
6740 */
6741 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
Dhananjay Kumarac341582017-02-23 23:42:25 +05306742 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006743 *frames = get_actual_pcm_frames_rendered(out, timestamp);
Ashish Jain5106d362016-05-11 19:23:33 +05306744 ALOGVV("frames %lld playedat %lld",(long long int)*frames,
6745 timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000);
6746 return 0;
6747 }
6748
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006749 lock_output_stream(out);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006750
Ashish Jain5106d362016-05-11 19:23:33 +05306751 if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) {
6752 ret = compress_get_tstamp(out->compr, &dsp_frames,
6753 &out->sample_rate);
yidongh0515e042017-07-06 15:00:34 +08006754 // Adjustment accounts for A2dp encoder latency with offload usecases
6755 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006756 if (is_a2dp_out_device_type(&out->device_list)) {
yidongh0515e042017-07-06 15:00:34 +08006757 unsigned long offset =
6758 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
6759 dsp_frames = (dsp_frames > offset) ? (dsp_frames - offset) : 0;
6760 }
Ashish Jain5106d362016-05-11 19:23:33 +05306761 ALOGVV("%s rendered frames %ld sample_rate %d",
6762 __func__, dsp_frames, out->sample_rate);
6763 *frames = dsp_frames;
6764 if (ret < 0)
6765 ret = -errno;
6766 if (-ENETRESET == ret) {
6767 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306768 out->card_status = CARD_STATUS_OFFLINE;
Ashish Jain5106d362016-05-11 19:23:33 +05306769 ret = -EINVAL;
6770 } else
6771 ret = 0;
6772 /* this is the best we can do */
6773 clock_gettime(CLOCK_MONOTONIC, timestamp);
Eric Laurent949a0892013-09-20 09:20:13 -07006774 } else {
6775 if (out->pcm) {
Weiyin Jiangd4633762018-03-16 12:05:03 +08006776 unsigned int avail;
6777 if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
George Gao62ebc722019-07-29 16:29:44 -07006778 uint64_t signed_frames = 0;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006779 uint64_t frames_temp = 0;
George Gao62ebc722019-07-29 16:29:44 -07006780
Andy Hunga1f48fa2019-07-01 18:14:53 -07006781 if (out->kernel_buffer_size > avail) {
6782 frames_temp = out->last_fifo_frames_remaining = out->kernel_buffer_size - avail;
6783 } else {
6784 ALOGW("%s: avail:%u > kernel_buffer_size:%zu clamping!",
6785 __func__, avail, out->kernel_buffer_size);
6786 avail = out->kernel_buffer_size;
6787 frames_temp = out->last_fifo_frames_remaining = 0;
6788 }
6789 out->last_fifo_valid = true;
6790 out->last_fifo_time_ns = audio_utils_ns_from_timespec(timestamp);
6791
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006792 if (out->written >= frames_temp)
6793 signed_frames = out->written - frames_temp;
George Gao62ebc722019-07-29 16:29:44 -07006794
Andy Hunga1f48fa2019-07-01 18:14:53 -07006795 ALOGVV("%s: frames:%lld avail:%u kernel_buffer_size:%zu",
6796 __func__, (long long)signed_frames, avail, out->kernel_buffer_size);
6797
Weiyin Jiangd4633762018-03-16 12:05:03 +08006798 // This adjustment accounts for buffering after app processor.
6799 // It is based on estimated DSP latency per use case, rather than exact.
George Gao9ba8a142020-07-23 14:30:03 -07006800 frames_temp = platform_render_latency(out) *
Robert Lee58215542019-07-15 20:55:12 +08006801 out->sample_rate / 1000000LL;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006802 if (signed_frames >= frames_temp)
6803 signed_frames -= frames_temp;
Aniket Kumar Lataff613152017-07-18 18:19:21 -07006804
Weiyin Jiangd4633762018-03-16 12:05:03 +08006805 // Adjustment accounts for A2dp encoder latency with non offload usecases
6806 // Note: Encoder latency is returned in ms, while platform_render_latency in us.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006807 if (is_a2dp_out_device_type(&out->device_list)) {
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006808 frames_temp = audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000;
6809 if (signed_frames >= frames_temp)
6810 signed_frames -= frames_temp;
Weiyin Jiangd4633762018-03-16 12:05:03 +08006811 }
6812
6813 // It would be unusual for this value to be negative, but check just in case ...
George Gao62ebc722019-07-29 16:29:44 -07006814 *frames = signed_frames;
6815 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006816 }
Eric Laurenta7a33042019-07-10 16:20:22 -07006817 } else if (out->card_status == CARD_STATUS_OFFLINE ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006818 adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE ||
Eric Laurenta7a33042019-07-10 16:20:22 -07006819 // audioflinger still needs position updates when A2DP is suspended
Jasmine Cha5c2517f2019-09-09 11:07:28 +08006820 (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306821 *frames = out->written;
6822 clock_gettime(CLOCK_MONOTONIC, timestamp);
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306823 if (is_offload_usecase(out->usecase))
6824 ret = -EINVAL;
6825 else
6826 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006827 }
6828 }
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006829 pthread_mutex_unlock(&out->lock);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006830 return ret;
6831}
6832
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006833static int out_set_callback(struct audio_stream_out *stream,
6834 stream_callback_t callback, void *cookie)
6835{
6836 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006837 int ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006838
6839 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006840 lock_output_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006841 out->client_callback = callback;
6842 out->client_cookie = cookie;
6843 if (out->adsp_hdlr_stream_handle) {
6844 ret = audio_extn_adsp_hdlr_stream_set_callback(
6845 out->adsp_hdlr_stream_handle,
6846 callback,
6847 cookie);
6848 if (ret)
6849 ALOGW("%s:adsp hdlr callback registration failed %d",
6850 __func__, ret);
6851 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006852 pthread_mutex_unlock(&out->lock);
6853 return 0;
6854}
6855
6856static int out_pause(struct audio_stream_out* stream)
6857{
6858 struct stream_out *out = (struct stream_out *)stream;
6859 int status = -ENOSYS;
6860 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006861 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006862 ALOGD("copl(%p):pause compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306863 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006864 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006865 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006866 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306867 if (out->card_status != CARD_STATUS_OFFLINE)
Naresh Tanniru80659832014-06-04 18:17:56 +05306868 status = compress_pause(out->compr);
6869
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006870 out->offload_state = OFFLOAD_STATE_PAUSED;
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006871
Mingming Yin21854652016-04-13 11:54:02 -07006872 if (audio_extn_passthru_is_active()) {
6873 ALOGV("offload use case, pause passthru");
6874 audio_extn_passthru_on_pause(out);
6875 }
6876
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306877 audio_extn_dts_eagle_fade(adev, false, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006878 audio_extn_dts_notify_playback_state(out->usecase, 0,
6879 out->sample_rate, popcount(out->channel_mask),
6880 0);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006881 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006882 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006883 pthread_mutex_unlock(&out->lock);
6884 }
6885 return status;
6886}
6887
6888static int out_resume(struct audio_stream_out* stream)
6889{
6890 struct stream_out *out = (struct stream_out *)stream;
6891 int status = -ENOSYS;
6892 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006893 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006894 ALOGD("copl(%p):resume compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306895 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006896 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006897 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006898 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306899 if (out->card_status != CARD_STATUS_OFFLINE) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306900 status = compress_resume(out->compr);
Mingming Yin21854652016-04-13 11:54:02 -07006901 }
6902 if (!status) {
6903 out->offload_state = OFFLOAD_STATE_PLAYING;
6904 }
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306905 audio_extn_dts_eagle_fade(adev, true, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006906 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6907 popcount(out->channel_mask), 1);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006908 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006909 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006910 pthread_mutex_unlock(&out->lock);
6911 }
6912 return status;
6913}
6914
6915static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
6916{
6917 struct stream_out *out = (struct stream_out *)stream;
6918 int status = -ENOSYS;
6919 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006920 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006921 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006922 if (type == AUDIO_DRAIN_EARLY_NOTIFY)
6923 status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
6924 else
6925 status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
6926 pthread_mutex_unlock(&out->lock);
6927 }
6928 return status;
6929}
6930
6931static int out_flush(struct audio_stream_out* stream)
6932{
6933 struct stream_out *out = (struct stream_out *)stream;
6934 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006935 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006936 ALOGD("copl(%p):calling compress flush", out);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006937 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006938 pthread_mutex_lock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006939 if (out->offload_state == OFFLOAD_STATE_PAUSED) {
Gautam Manam14c198b2020-12-24 14:08:04 +05306940 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006941 stop_compressed_output_l(out);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006942 } else {
6943 ALOGW("%s called in invalid state %d", __func__, out->offload_state);
Gautam Manam14c198b2020-12-24 14:08:04 +05306944 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006945 }
Weiyin Jiang547e4152017-09-14 17:24:18 +08006946 out->written = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006947 pthread_mutex_unlock(&out->lock);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006948 ALOGD("copl(%p):out of compress flush", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006949 return 0;
6950 }
6951 return -ENOSYS;
6952}
6953
Haynes Mathew George16081042017-05-31 17:16:49 -07006954static int out_stop(const struct audio_stream_out* stream)
6955{
6956 struct stream_out *out = (struct stream_out *)stream;
6957 struct audio_device *adev = out->dev;
6958 int ret = -ENOSYS;
6959
6960 ALOGV("%s", __func__);
6961 pthread_mutex_lock(&adev->lock);
6962 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6963 out->playback_started && out->pcm != NULL) {
6964 pcm_stop(out->pcm);
6965 ret = stop_output_stream(out);
6966 out->playback_started = false;
6967 }
6968 pthread_mutex_unlock(&adev->lock);
6969 return ret;
6970}
6971
6972static int out_start(const struct audio_stream_out* stream)
6973{
6974 struct stream_out *out = (struct stream_out *)stream;
6975 struct audio_device *adev = out->dev;
6976 int ret = -ENOSYS;
6977
6978 ALOGV("%s", __func__);
6979 pthread_mutex_lock(&adev->lock);
6980 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6981 !out->playback_started && out->pcm != NULL) {
6982 ret = start_output_stream(out);
6983 if (ret == 0) {
6984 out->playback_started = true;
6985 }
6986 }
6987 pthread_mutex_unlock(&adev->lock);
6988 return ret;
6989}
6990
6991/*
6992 * Modify config->period_count based on min_size_frames
6993 */
6994static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
6995{
6996 int periodCountRequested = (min_size_frames + config->period_size - 1)
6997 / config->period_size;
6998 int periodCount = MMAP_PERIOD_COUNT_MIN;
6999
7000 ALOGV("%s original config.period_size = %d config.period_count = %d",
7001 __func__, config->period_size, config->period_count);
7002
7003 while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
7004 periodCount *= 2;
7005 }
7006 config->period_count = periodCount;
7007
7008 ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
7009}
7010
Phil Burkfe17efd2019-03-25 10:23:35 -07007011// Read offset for the positional timestamp from a persistent vendor property.
7012// This is to workaround apparent inaccuracies in the timing information that
7013// is used by the AAudio timing model. The inaccuracies can cause glitches.
7014static int64_t get_mmap_out_time_offset() {
7015 const int32_t kDefaultOffsetMicros = 0;
7016 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08007017 "persist.vendor.audio.out_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burkfe17efd2019-03-25 10:23:35 -07007018 ALOGI("mmap_time_offset_micros = %d for output", mmap_time_offset_micros);
7019 return mmap_time_offset_micros * (int64_t)1000;
7020}
7021
Haynes Mathew George16081042017-05-31 17:16:49 -07007022static int out_create_mmap_buffer(const struct audio_stream_out *stream,
7023 int32_t min_size_frames,
7024 struct audio_mmap_buffer_info *info)
7025{
7026 struct stream_out *out = (struct stream_out *)stream;
7027 struct audio_device *adev = out->dev;
7028 int ret = 0;
Aalique Grahame1f123102017-10-12 10:38:32 -07007029 unsigned int offset1 = 0;
7030 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007031 const char *step = "";
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007032 uint32_t mmap_size;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007033 uint32_t buffer_size;
Haynes Mathew George16081042017-05-31 17:16:49 -07007034
Arun Mirpuri5d170872019-03-26 13:21:31 -07007035 ALOGD("%s", __func__);
Sharad Sanglec6f32552018-05-04 16:15:38 +05307036 lock_output_stream(out);
Haynes Mathew George16081042017-05-31 17:16:49 -07007037 pthread_mutex_lock(&adev->lock);
7038
Sharad Sanglec6f32552018-05-04 16:15:38 +05307039 if (CARD_STATUS_OFFLINE == out->card_status ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05007040 CARD_STATUS_OFFLINE == adev->card_status ||
7041 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307042 ALOGW("out->card_status or adev->card_status offline, try again");
7043 ret = -EIO;
7044 goto exit;
7045 }
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307046 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007047 ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
7048 ret = -EINVAL;
7049 goto exit;
7050 }
7051 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
7052 ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
7053 ret = -ENOSYS;
7054 goto exit;
7055 }
7056 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
7057 if (out->pcm_device_id < 0) {
7058 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7059 __func__, out->pcm_device_id, out->usecase);
7060 ret = -EINVAL;
7061 goto exit;
7062 }
7063
7064 adjust_mmap_period_count(&out->config, min_size_frames);
7065
Arun Mirpuri5d170872019-03-26 13:21:31 -07007066 ALOGD("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07007067 __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
7068 out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
7069 (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307070 if (errno == ENETRESET && !pcm_is_ready(out->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307071 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7072 out->card_status = CARD_STATUS_OFFLINE;
7073 adev->card_status = CARD_STATUS_OFFLINE;
7074 ret = -EIO;
7075 goto exit;
7076 }
7077
Haynes Mathew George16081042017-05-31 17:16:49 -07007078 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
7079 step = "open";
7080 ret = -ENODEV;
7081 goto exit;
7082 }
7083 ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
7084 if (ret < 0) {
7085 step = "begin";
7086 goto exit;
7087 }
juyuchen626833d2019-06-04 16:48:02 +08007088
7089 info->flags = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007090 info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
Arun Mirpuri5d170872019-03-26 13:21:31 -07007091 buffer_size = pcm_frames_to_bytes(out->pcm, info->buffer_size_frames);
Haynes Mathew George16081042017-05-31 17:16:49 -07007092 info->burst_size_frames = out->config.period_size;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007093 ret = platform_get_mmap_data_fd(adev->platform,
7094 out->pcm_device_id, 0 /*playback*/,
7095 &info->shared_memory_fd,
7096 &mmap_size);
7097 if (ret < 0) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07007098 // Fall back to non exclusive mode
7099 info->shared_memory_fd = pcm_get_poll_fd(out->pcm);
7100 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007101 out->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7102 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, out->mmap_shared_memory_fd);
7103
Arun Mirpuri5d170872019-03-26 13:21:31 -07007104 if (mmap_size < buffer_size) {
7105 step = "mmap";
7106 goto exit;
7107 }
juyuchen626833d2019-06-04 16:48:02 +08007108 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007109 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007110 memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007111 info->buffer_size_frames));
Haynes Mathew George16081042017-05-31 17:16:49 -07007112
7113 ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
7114 if (ret < 0) {
7115 step = "commit";
7116 goto exit;
7117 }
7118
Phil Burkfe17efd2019-03-25 10:23:35 -07007119 out->mmap_time_offset_nanos = get_mmap_out_time_offset();
7120
Haynes Mathew George16081042017-05-31 17:16:49 -07007121 out->standby = false;
7122 ret = 0;
7123
Arun Mirpuri5d170872019-03-26 13:21:31 -07007124 ALOGD("%s: got mmap buffer address %p info->buffer_size_frames %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07007125 __func__, info->shared_memory_address, info->buffer_size_frames);
7126
7127exit:
7128 if (ret != 0) {
7129 if (out->pcm == NULL) {
7130 ALOGE("%s: %s - %d", __func__, step, ret);
7131 } else {
7132 ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
7133 pcm_close(out->pcm);
7134 out->pcm = NULL;
7135 }
7136 }
7137 pthread_mutex_unlock(&adev->lock);
Sharad Sanglec6f32552018-05-04 16:15:38 +05307138 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007139 return ret;
7140}
7141
7142static int out_get_mmap_position(const struct audio_stream_out *stream,
7143 struct audio_mmap_position *position)
7144{
7145 struct stream_out *out = (struct stream_out *)stream;
7146 ALOGVV("%s", __func__);
7147 if (position == NULL) {
7148 return -EINVAL;
7149 }
7150 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08007151 ALOGE("%s: called on %s", __func__, use_case_table[out->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07007152 return -ENOSYS;
7153 }
7154 if (out->pcm == NULL) {
7155 return -ENOSYS;
7156 }
7157
7158 struct timespec ts = { 0, 0 };
7159 int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
7160 if (ret < 0) {
7161 ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
7162 return ret;
7163 }
Phil Burkfe17efd2019-03-25 10:23:35 -07007164 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
7165 + out->mmap_time_offset_nanos;
Haynes Mathew George16081042017-05-31 17:16:49 -07007166 return 0;
7167}
7168
7169
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007170/** audio_stream_in implementation **/
7171static uint32_t in_get_sample_rate(const struct audio_stream *stream)
7172{
7173 struct stream_in *in = (struct stream_in *)stream;
7174
7175 return in->config.rate;
7176}
7177
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007178static int in_set_sample_rate(struct audio_stream *stream __unused,
7179 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007180{
7181 return -ENOSYS;
7182}
7183
7184static size_t in_get_buffer_size(const struct audio_stream *stream)
7185{
7186 struct stream_in *in = (struct stream_in *)stream;
7187
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007188 if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
7189 return voice_extn_compress_voip_in_get_buffer_size(in);
Mingming Yine62d7842013-10-25 16:26:03 -07007190 else if(audio_extn_compr_cap_usecase_supported(in->usecase))
Raghu Bankapur37cbf382022-12-01 09:30:00 +05307191 return audio_extn_compr_cap_get_buffer_size(pcm_format_to_audio_format(in->config.format));
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307192 else if(audio_extn_cin_attached_usecase(in))
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307193 return audio_extn_cin_get_buffer_size(in);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007194
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007195 return in->config.period_size * in->af_period_multiplier *
7196 audio_stream_in_frame_size((const struct audio_stream_in *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007197}
7198
7199static uint32_t in_get_channels(const struct audio_stream *stream)
7200{
7201 struct stream_in *in = (struct stream_in *)stream;
7202
7203 return in->channel_mask;
7204}
7205
7206static audio_format_t in_get_format(const struct audio_stream *stream)
7207{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007208 struct stream_in *in = (struct stream_in *)stream;
7209
7210 return in->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007211}
7212
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007213static int in_set_format(struct audio_stream *stream __unused,
7214 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007215{
7216 return -ENOSYS;
7217}
7218
7219static int in_standby(struct audio_stream *stream)
7220{
7221 struct stream_in *in = (struct stream_in *)stream;
7222 struct audio_device *adev = in->dev;
7223 int status = 0;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307224 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
7225 stream, in->usecase, use_case_table[in->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07007226 bool do_stop = true;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307227
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007228 lock_input_stream(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007229 if (!in->standby && in->is_st_session) {
7230 ALOGD("%s: sound trigger pcm stop lab", __func__);
7231 audio_extn_sound_trigger_stop_lab(in);
George Gao3018ede2019-10-23 13:23:00 -07007232 if (adev->num_va_sessions > 0)
7233 adev->num_va_sessions--;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007234 in->standby = 1;
7235 }
7236
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007237 if (!in->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007238 if (adev->adm_deregister_stream)
7239 adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
7240
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08007241 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007242 in->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08007243 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
kunleizbecba2d2017-09-07 13:37:16 +08007244 do_stop = false;
Zhou Songa8895042016-07-05 17:54:22 +08007245 voice_extn_compress_voip_close_input_stream(stream);
7246 ALOGD("VOIP input entered standby");
Haynes Mathew George16081042017-05-31 17:16:49 -07007247 } else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7248 do_stop = in->capture_started;
7249 in->capture_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07007250 if (in->mmap_shared_memory_fd >= 0) {
7251 ALOGV("%s: closing mmap_shared_memory_fd = %d",
7252 __func__, in->mmap_shared_memory_fd);
7253 close(in->mmap_shared_memory_fd);
7254 in->mmap_shared_memory_fd = -1;
7255 }
Zhou Songa8895042016-07-05 17:54:22 +08007256 } else {
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307257 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +05307258 audio_extn_cin_close_input_stream(in);
kunleizbecba2d2017-09-07 13:37:16 +08007259 }
7260
Arun Mirpuri5d170872019-03-26 13:21:31 -07007261 if (in->pcm) {
7262 ATRACE_BEGIN("pcm_in_close");
7263 pcm_close(in->pcm);
7264 ATRACE_END();
7265 in->pcm = NULL;
7266 }
7267
Carter Hsu2e429db2019-05-14 18:50:52 +08007268 if (do_stop)
Zhou Songa8895042016-07-05 17:54:22 +08007269 status = stop_input_stream(in);
Quinn Malef6050362019-01-30 15:55:40 -08007270
George Gao3018ede2019-10-23 13:23:00 -07007271 if (in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7272 if (adev->num_va_sessions > 0)
7273 adev->num_va_sessions--;
7274 }
Quinn Malef6050362019-01-30 15:55:40 -08007275
Eric Laurent150dbfe2013-02-27 14:31:02 -08007276 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007277 }
7278 pthread_mutex_unlock(&in->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07007279 ALOGV("%s: exit: status(%d)", __func__, status);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007280 return status;
7281}
7282
Aalique Grahame22e49102018-12-18 14:23:57 -08007283static int in_dump(const struct audio_stream *stream,
7284 int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007285{
Aalique Grahame22e49102018-12-18 14:23:57 -08007286 struct stream_in *in = (struct stream_in *)stream;
7287
7288 // We try to get the lock for consistency,
7289 // but it isn't necessary for these variables.
7290 // If we're not in standby, we may be blocked on a read.
7291 const bool locked = (pthread_mutex_trylock(&in->lock) == 0);
7292 dprintf(fd, " Standby: %s\n", in->standby ? "yes" : "no");
7293 dprintf(fd, " Frames read: %lld\n", (long long)in->frames_read);
7294 dprintf(fd, " Frames muted: %lld\n", (long long)in->frames_muted);
Dechen Chai22768452021-07-30 09:29:16 +05307295#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007296 char buffer[256]; // for statistics formatting
7297 if (in->start_latency_ms.n > 0) {
7298 simple_stats_to_string(&in->start_latency_ms, buffer, sizeof(buffer));
7299 dprintf(fd, " Start latency ms: %s\n", buffer);
7300 }
Dechen Chai22768452021-07-30 09:29:16 +05307301#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08007302 if (locked) {
7303 pthread_mutex_unlock(&in->lock);
7304 }
Dechen Chai22768452021-07-30 09:29:16 +05307305#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08007306 // dump error info
7307 (void)error_log_dump(
7308 in->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05307309#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007310 return 0;
7311}
7312
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307313static void in_snd_mon_cb(void * stream, struct str_parms * parms)
7314{
7315 if (!stream || !parms)
7316 return;
7317
7318 struct stream_in *in = (struct stream_in *)stream;
7319 struct audio_device *adev = in->dev;
7320
7321 card_status_t status;
7322 int card;
7323 if (parse_snd_card_status(parms, &card, &status) < 0)
7324 return;
7325
7326 pthread_mutex_lock(&adev->lock);
7327 bool valid_cb = (card == adev->snd_card);
7328 pthread_mutex_unlock(&adev->lock);
7329
7330 if (!valid_cb)
7331 return;
7332
7333 lock_input_stream(in);
7334 if (in->card_status != status)
7335 in->card_status = status;
7336 pthread_mutex_unlock(&in->lock);
7337
7338 ALOGW("in_snd_mon_cb for card %d usecase %s, status %s", card,
7339 use_case_table[in->usecase],
7340 status == CARD_STATUS_OFFLINE ? "offline" : "online");
7341
7342 // a better solution would be to report error back to AF and let
7343 // it put the stream to standby
7344 if (status == CARD_STATUS_OFFLINE)
7345 in_standby(&in->stream.common);
7346
7347 return;
7348}
7349
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007350int route_input_stream(struct stream_in *in,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007351 struct listnode *devices,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007352 audio_source_t source)
7353{
7354 struct audio_device *adev = in->dev;
7355 int ret = 0;
7356
7357 lock_input_stream(in);
7358 pthread_mutex_lock(&adev->lock);
7359
7360 /* no audio source uses val == 0 */
7361 if ((in->source != source) && (source != AUDIO_SOURCE_DEFAULT)) {
7362 in->source = source;
7363 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
7364 (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
7365 (voice_extn_compress_voip_is_format_supported(in->format)) &&
7366 (in->config.rate == 8000 || in->config.rate == 16000 ||
7367 in->config.rate == 32000 || in->config.rate == 48000 ) &&
7368 (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
7369 ret = voice_extn_compress_voip_open_input_stream(in);
7370 if (ret != 0) {
7371 ALOGE("%s: Compress voip input cannot be opened, error:%d",
7372 __func__, ret);
7373 }
7374 }
7375 }
7376
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007377 if (!compare_devices(&in->device_list, devices) && !list_empty(devices) &&
7378 is_audio_in_device_type(devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007379 // Workaround: If routing to an non existing usb device, fail gracefully
7380 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007381 struct str_parms *usb_addr =
7382 str_parms_create_str(get_usb_device_address(devices));
7383 if (is_usb_in_device_type(devices) && usb_addr &&
Weiyin Jiangabedea32020-12-09 12:49:19 +08007384 !audio_extn_usb_connected(NULL)) {
7385 ALOGW("%s: ignoring rerouting to non existing USB", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007386 ret = -ENOSYS;
7387 } else {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007388 /* If recording is in progress, change the tx device to new device */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007389 assign_devices(&in->device_list, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007390 if (!in->standby && !in->is_st_session) {
7391 ALOGV("update input routing change");
7392 // inform adm before actual routing to prevent glitches.
7393 if (adev->adm_on_routing_change) {
7394 adev->adm_on_routing_change(adev->adm_data,
7395 in->capture_handle);
7396 ret = select_devices(adev, in->usecase);
7397 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7398 adev->adm_routing_changed = true;
7399 }
7400 }
7401 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007402 if (usb_addr)
7403 str_parms_destroy(usb_addr);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007404 }
7405 pthread_mutex_unlock(&adev->lock);
7406 pthread_mutex_unlock(&in->lock);
7407
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07007408 ALOGV("%s: exit: status(%d)", __func__, ret);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007409 return ret;
7410}
7411
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007412static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
7413{
7414 struct stream_in *in = (struct stream_in *)stream;
7415 struct audio_device *adev = in->dev;
7416 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007417 char value[32];
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307418 int err = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007419
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307420 ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007421 parms = str_parms_create_str(kvpairs);
7422
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307423 if (!parms)
7424 goto error;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007425 lock_input_stream(in);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007426 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08007427
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307428 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
7429 if (err >= 0) {
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307430 strlcpy(in->profile, value, sizeof(in->profile));
7431 ALOGV("updating stream profile with value '%s'", in->profile);
7432 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
7433 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007434 &in->device_list, in->flags, in->format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307435 in->sample_rate, in->bit_width,
7436 in->profile, &in->app_type_cfg);
7437 }
7438
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007439 pthread_mutex_unlock(&adev->lock);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007440 pthread_mutex_unlock(&in->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007441
7442 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307443error:
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307444 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007445}
7446
7447static char* in_get_parameters(const struct audio_stream *stream,
7448 const char *keys)
7449{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007450 struct stream_in *in = (struct stream_in *)stream;
7451 struct str_parms *query = str_parms_create_str(keys);
7452 char *str;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007453 struct str_parms *reply = str_parms_create();
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007454
7455 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08007456 if (reply) {
7457 str_parms_destroy(reply);
7458 }
7459 if (query) {
7460 str_parms_destroy(query);
7461 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007462 ALOGE("in_get_parameters: failed to create query or reply");
7463 return NULL;
7464 }
7465
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007466 ALOGV("%s: enter: keys - %s %s ", __func__, use_case_table[in->usecase], keys);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007467
7468 voice_extn_in_get_parameters(in, query, reply);
7469
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007470 stream_get_parameter_channels(query, reply,
7471 &in->supported_channel_masks[0]);
7472 stream_get_parameter_formats(query, reply,
7473 &in->supported_formats[0]);
7474 stream_get_parameter_rates(query, reply,
7475 &in->supported_sample_rates[0]);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007476 str = str_parms_to_str(reply);
7477 str_parms_destroy(query);
7478 str_parms_destroy(reply);
7479
7480 ALOGV("%s: exit: returns - %s", __func__, str);
7481 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007482}
7483
Aalique Grahame22e49102018-12-18 14:23:57 -08007484static int in_set_gain(struct audio_stream_in *stream,
7485 float gain)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007486{
Aalique Grahame22e49102018-12-18 14:23:57 -08007487 struct stream_in *in = (struct stream_in *)stream;
7488 char mixer_ctl_name[128];
7489 struct mixer_ctl *ctl;
7490 int ctl_value;
7491
7492 ALOGV("%s: gain %f", __func__, gain);
7493
7494 if (stream == NULL)
7495 return -EINVAL;
7496
7497 /* in_set_gain() only used to silence MMAP capture for now */
7498 if (in->usecase != USECASE_AUDIO_RECORD_MMAP)
7499 return -ENOSYS;
7500
7501 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Capture %d Volume", in->pcm_device_id);
7502
7503 ctl = mixer_get_ctl_by_name(in->dev->mixer, mixer_ctl_name);
7504 if (!ctl) {
7505 ALOGW("%s: Could not get ctl for mixer cmd - %s",
7506 __func__, mixer_ctl_name);
7507 return -ENOSYS;
7508 }
7509
7510 if (gain < RECORD_GAIN_MIN)
7511 gain = RECORD_GAIN_MIN;
7512 else if (gain > RECORD_GAIN_MAX)
7513 gain = RECORD_GAIN_MAX;
7514 ctl_value = (int)(RECORD_VOLUME_CTL_MAX * gain);
7515
7516 mixer_ctl_set_value(ctl, 0, ctl_value);
7517
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007518 return 0;
7519}
7520
7521static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
7522 size_t bytes)
7523{
7524 struct stream_in *in = (struct stream_in *)stream;
Pallavid7c7a272018-01-16 11:22:55 +05307525
7526 if (in == NULL) {
7527 ALOGE("%s: stream_in ptr is NULL", __func__);
7528 return -EINVAL;
7529 }
7530
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007531 struct audio_device *adev = in->dev;
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05307532 int ret = -1;
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307533 size_t bytes_read = 0, frame_size = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007534
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007535 lock_input_stream(in);
Naresh Tanniru4c630392014-05-12 01:05:52 +05307536
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007537 if (in->is_st_session) {
7538 ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
7539 /* Read from sound trigger HAL */
7540 audio_extn_sound_trigger_read(in, buffer, bytes);
Quinn Malef6050362019-01-30 15:55:40 -08007541 if (in->standby) {
George Gao3018ede2019-10-23 13:23:00 -07007542 if (adev->num_va_sessions < UINT_MAX)
7543 adev->num_va_sessions++;
Quinn Malef6050362019-01-30 15:55:40 -08007544 in->standby = 0;
7545 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007546 pthread_mutex_unlock(&in->lock);
7547 return bytes;
7548 }
7549
Haynes Mathew George16081042017-05-31 17:16:49 -07007550 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7551 ret = -ENOSYS;
7552 goto exit;
7553 }
7554
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007555 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY &&
7556 !in->standby && adev->adm_routing_changed) {
7557 ret = -ENOSYS;
7558 goto exit;
7559 }
7560
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007561 if (in->standby) {
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007562 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
7563
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007564 pthread_mutex_lock(&adev->lock);
7565 if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
7566 ret = voice_extn_compress_voip_start_input_stream(in);
7567 else
7568 ret = start_input_stream(in);
George Gao3018ede2019-10-23 13:23:00 -07007569 if (!ret && in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7570 if (adev->num_va_sessions < UINT_MAX)
7571 adev->num_va_sessions++;
7572 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007573 pthread_mutex_unlock(&adev->lock);
7574 if (ret != 0) {
7575 goto exit;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007576 }
7577 in->standby = 0;
Dechen Chai22768452021-07-30 09:29:16 +05307578#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007579 // log startup time in ms.
7580 simple_stats_log(
7581 &in->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05307582#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007583 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007584
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05307585 /* Avoid read if capture_stopped is set */
7586 if (android_atomic_acquire_load(&(in->capture_stopped)) > 0) {
7587 ALOGD("%s: force stopped catpure session, ignoring read request", __func__);
7588 ret = -EINVAL;
7589 goto exit;
7590 }
7591
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007592 // what's the duration requested by the client?
7593 long ns = 0;
7594
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307595 if (in->pcm && in->config.rate)
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007596 ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
7597 in->config.rate;
7598
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007599 ret = request_in_focus(in, ns);
7600 if (ret != 0)
7601 goto exit;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007602 bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007603
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307604 if (audio_extn_cin_attached_usecase(in)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307605 ret = audio_extn_cin_read(in, buffer, bytes, &bytes_read);
7606 } else if (in->pcm) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307607 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007608 ret = audio_extn_ssr_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307609 } else if (audio_extn_compr_cap_usecase_supported(in->usecase)) {
Mingming Yine62d7842013-10-25 16:26:03 -07007610 ret = audio_extn_compr_cap_read(in, buffer, bytes);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007611 } else if (use_mmap) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07007612 ret = pcm_mmap_read(in->pcm, buffer, bytes);
Garmond Leunge2433c32017-09-28 21:51:22 -07007613 } else if (audio_extn_ffv_get_stream() == in) {
7614 ret = audio_extn_ffv_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307615 } else {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007616 ret = pcm_read(in->pcm, buffer, bytes);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307617 /* data from DSP comes in 24_8 format, convert it to 8_24 */
7618 if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
7619 if (audio_extn_utils_convert_format_24_8_to_8_24(buffer, bytes)
7620 != bytes) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307621 ret = -EINVAL;
7622 goto exit;
7623 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307624 } else if (ret < 0) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307625 ret = -errno;
7626 }
7627 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307628 /* bytes read is always set to bytes for non compress usecases */
7629 bytes_read = bytes;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007630 }
7631
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007632 release_in_focus(in);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007633
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007634 /*
Quinn Malef6050362019-01-30 15:55:40 -08007635 * Instead of writing zeroes here, we could trust the hardware to always
7636 * provide zeroes when muted. This is also muted with voice recognition
7637 * usecases so that other clients do not have access to voice recognition
7638 * data.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007639 */
Quinn Malef6050362019-01-30 15:55:40 -08007640 if ((ret == 0 && voice_get_mic_mute(adev) &&
7641 !voice_is_in_call_rec_stream(in) &&
Zhou Song62ea0282020-03-22 19:53:01 +08007642 (in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY &&
7643 in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY2)) ||
Quinn Malef6050362019-01-30 15:55:40 -08007644 (adev->num_va_sessions &&
7645 in->source != AUDIO_SOURCE_VOICE_RECOGNITION &&
7646 property_get_bool("persist.vendor.audio.va_concurrency_mute_enabled",
7647 false)))
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007648 memset(buffer, 0, bytes);
7649
7650exit:
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307651 frame_size = audio_stream_in_frame_size(stream);
7652 if (frame_size > 0)
7653 in->frames_read += bytes_read/frame_size;
7654
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007655 if (-ENETRESET == ret)
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307656 in->card_status = CARD_STATUS_OFFLINE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007657 pthread_mutex_unlock(&in->lock);
7658
7659 if (ret != 0) {
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307660 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307661 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307662 voice_extn_compress_voip_close_input_stream(&in->stream.common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307663 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307664 in->standby = true;
7665 }
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307666 if (!audio_extn_cin_attached_usecase(in)) {
Sharad Sangled17c9122017-03-20 15:58:52 +05307667 bytes_read = bytes;
7668 memset(buffer, 0, bytes);
7669 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007670 in_standby(&in->stream.common);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007671 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7672 adev->adm_routing_changed = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007673 ALOGV("%s: read failed status %d- sleeping for buffer duration", __func__, ret);
Ashish Jainbbce4322016-02-16 13:25:27 +05307674 usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
Naresh Tanniru4c630392014-05-12 01:05:52 +05307675 in_get_sample_rate(&in->stream.common));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007676 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307677 return bytes_read;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007678}
7679
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007680static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007681{
7682 return 0;
7683}
7684
Aalique Grahame22e49102018-12-18 14:23:57 -08007685static int in_get_capture_position(const struct audio_stream_in *stream,
7686 int64_t *frames, int64_t *time)
7687{
7688 if (stream == NULL || frames == NULL || time == NULL) {
7689 return -EINVAL;
7690 }
7691 struct stream_in *in = (struct stream_in *)stream;
7692 int ret = -ENOSYS;
7693
7694 lock_input_stream(in);
7695 // note: ST sessions do not close the alsa pcm driver synchronously
7696 // on standby. Therefore, we may return an error even though the
7697 // pcm stream is still opened.
7698 if (in->standby) {
7699 ALOGE_IF(in->pcm != NULL && !in->is_st_session,
7700 "%s stream in standby but pcm not NULL for non ST session", __func__);
7701 goto exit;
7702 }
7703 if (in->pcm) {
7704 struct timespec timestamp;
7705 unsigned int avail;
7706 if (pcm_get_htimestamp(in->pcm, &avail, &timestamp) == 0) {
7707 *frames = in->frames_read + avail;
Robert Lee58215542019-07-15 20:55:12 +08007708 *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec
George Gao9ba8a142020-07-23 14:30:03 -07007709 - platform_capture_latency(in) * 1000LL;
Kakanaboina Ramanjaneyulu8cedb092021-03-15 15:55:29 +05307710 //Adjustment accounts for A2dp decoder latency for recording usecase
7711 // Note: decoder latency is returned in ms, while platform_capture_latency in ns.
7712 if (is_a2dp_in_device_type(&in->device_list))
7713 *time -= audio_extn_a2dp_get_decoder_latency() * 1000000LL;
Aalique Grahame22e49102018-12-18 14:23:57 -08007714 ret = 0;
7715 }
7716 }
7717exit:
7718 pthread_mutex_unlock(&in->lock);
7719 return ret;
7720}
7721
Carter Hsu2e429db2019-05-14 18:50:52 +08007722static int in_update_effect_list(bool add, effect_handle_t effect,
7723 struct listnode *head)
7724{
7725 struct listnode *node;
7726 struct in_effect_list *elist = NULL;
7727 struct in_effect_list *target = NULL;
7728 int ret = 0;
7729
7730 if (!head)
7731 return ret;
7732
7733 list_for_each(node, head) {
7734 elist = node_to_item(node, struct in_effect_list, list);
7735 if (elist->handle == effect) {
7736 target = elist;
7737 break;
7738 }
7739 }
7740
7741 if (add) {
7742 if (target) {
7743 ALOGD("effect %p already exist", effect);
7744 return ret;
7745 }
7746
7747 target = (struct in_effect_list *)
7748 calloc(1, sizeof(struct in_effect_list));
7749
7750 if (!target) {
7751 ALOGE("%s:fail to allocate memory", __func__);
7752 return -ENOMEM;
7753 }
7754
7755 target->handle = effect;
7756 list_add_tail(head, &target->list);
7757 } else {
7758 if (target) {
7759 list_remove(&target->list);
7760 free(target);
7761 }
7762 }
7763
7764 return ret;
7765}
7766
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007767static int add_remove_audio_effect(const struct audio_stream *stream,
7768 effect_handle_t effect,
7769 bool enable)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007770{
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007771 struct stream_in *in = (struct stream_in *)stream;
7772 int status = 0;
7773 effect_descriptor_t desc;
7774
7775 status = (*effect)->get_descriptor(effect, &desc);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007776 ALOGV("%s: status %d in->standby %d enable:%d", __func__, status, in->standby, enable);
7777
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007778 if (status != 0)
7779 return status;
7780
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007781 lock_input_stream(in);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007782 pthread_mutex_lock(&in->dev->lock);
kunleizd96526c2018-04-09 11:12:32 +08007783 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Carter Hsu2e429db2019-05-14 18:50:52 +08007784 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
7785 adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007786 (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
Carter Hsu2e429db2019-05-14 18:50:52 +08007787
7788 in_update_effect_list(enable, effect, &in->aec_list);
7789 enable = !list_empty(&in->aec_list);
7790 if (enable == in->enable_aec)
7791 goto exit;
7792
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007793 in->enable_aec = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007794 ALOGD("AEC enable %d", enable);
7795
Aalique Grahame22e49102018-12-18 14:23:57 -08007796 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
7797 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
7798 in->dev->enable_voicerx = enable;
7799 struct audio_usecase *usecase;
7800 struct listnode *node;
7801 list_for_each(node, &in->dev->usecase_list) {
7802 usecase = node_to_item(node, struct audio_usecase, list);
7803 if (usecase->type == PCM_PLAYBACK)
7804 select_devices(in->dev, usecase->id);
7805 }
7806 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007807 if (!in->standby) {
7808 if (enable_disable_effect(in->dev, EFFECT_AEC, enable) == ENOSYS)
7809 select_devices(in->dev, in->usecase);
7810 }
7811
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007812 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007813 if (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
7814
7815 in_update_effect_list(enable, effect, &in->ns_list);
7816 enable = !list_empty(&in->ns_list);
7817 if (enable == in->enable_ns)
7818 goto exit;
7819
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007820 in->enable_ns = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007821 ALOGD("NS enable %d", enable);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007822 if (!in->standby) {
kunleizd96526c2018-04-09 11:12:32 +08007823 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Ramu Gottipatifa5be522021-12-28 19:18:21 +05307824 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
kunleizd96526c2018-04-09 11:12:32 +08007825 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007826 if (enable_disable_effect(in->dev, EFFECT_NS, enable) == ENOSYS)
7827 select_devices(in->dev, in->usecase);
7828 } else
7829 select_devices(in->dev, in->usecase);
7830 }
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007831 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007832exit:
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007833 pthread_mutex_unlock(&in->dev->lock);
7834 pthread_mutex_unlock(&in->lock);
7835
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007836 return 0;
7837}
7838
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007839static int in_add_audio_effect(const struct audio_stream *stream,
7840 effect_handle_t effect)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007841{
Eric Laurent994a6932013-07-17 11:51:42 -07007842 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007843 return add_remove_audio_effect(stream, effect, true);
7844}
7845
7846static int in_remove_audio_effect(const struct audio_stream *stream,
7847 effect_handle_t effect)
7848{
Eric Laurent994a6932013-07-17 11:51:42 -07007849 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007850 return add_remove_audio_effect(stream, effect, false);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007851}
7852
Haynes Mathew George16081042017-05-31 17:16:49 -07007853static int in_stop(const struct audio_stream_in* stream)
7854{
7855 struct stream_in *in = (struct stream_in *)stream;
7856 struct audio_device *adev = in->dev;
7857
7858 int ret = -ENOSYS;
7859 ALOGV("%s", __func__);
7860 pthread_mutex_lock(&adev->lock);
7861 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7862 in->capture_started && in->pcm != NULL) {
7863 pcm_stop(in->pcm);
7864 ret = stop_input_stream(in);
7865 in->capture_started = false;
7866 }
7867 pthread_mutex_unlock(&adev->lock);
7868 return ret;
7869}
7870
7871static int in_start(const struct audio_stream_in* stream)
7872{
7873 struct stream_in *in = (struct stream_in *)stream;
7874 struct audio_device *adev = in->dev;
7875 int ret = -ENOSYS;
7876
7877 ALOGV("%s in %p", __func__, in);
7878 pthread_mutex_lock(&adev->lock);
7879 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7880 !in->capture_started && in->pcm != NULL) {
7881 if (!in->capture_started) {
7882 ret = start_input_stream(in);
7883 if (ret == 0) {
7884 in->capture_started = true;
7885 }
7886 }
7887 }
7888 pthread_mutex_unlock(&adev->lock);
7889 return ret;
7890}
7891
Phil Burke0a86d12019-02-16 22:28:11 -08007892// Read offset for the positional timestamp from a persistent vendor property.
7893// This is to workaround apparent inaccuracies in the timing information that
7894// is used by the AAudio timing model. The inaccuracies can cause glitches.
7895static int64_t in_get_mmap_time_offset() {
7896 const int32_t kDefaultOffsetMicros = 0;
7897 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08007898 "persist.vendor.audio.in_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burke0a86d12019-02-16 22:28:11 -08007899 ALOGI("mmap_time_offset_micros = %d for input", mmap_time_offset_micros);
7900 return mmap_time_offset_micros * (int64_t)1000;
7901}
7902
Haynes Mathew George16081042017-05-31 17:16:49 -07007903static int in_create_mmap_buffer(const struct audio_stream_in *stream,
7904 int32_t min_size_frames,
7905 struct audio_mmap_buffer_info *info)
7906{
7907 struct stream_in *in = (struct stream_in *)stream;
7908 struct audio_device *adev = in->dev;
7909 int ret = 0;
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07007910 unsigned int offset1 = 0;
7911 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007912 const char *step = "";
Arun Mirpuri5d170872019-03-26 13:21:31 -07007913 uint32_t mmap_size = 0;
7914 uint32_t buffer_size = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007915
7916 pthread_mutex_lock(&adev->lock);
7917 ALOGV("%s in %p", __func__, in);
7918
Sharad Sanglec6f32552018-05-04 16:15:38 +05307919 if (CARD_STATUS_OFFLINE == in->card_status||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05007920 CARD_STATUS_OFFLINE == adev->card_status ||
7921 POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307922 ALOGW("in->card_status or adev->card_status offline, try again");
7923 ret = -EIO;
7924 goto exit;
7925 }
7926
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307927 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007928 ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
7929 ret = -EINVAL;
7930 goto exit;
7931 }
7932 if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
7933 ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
7934 ALOGV("%s in %p", __func__, in);
7935 ret = -ENOSYS;
7936 goto exit;
7937 }
7938 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
7939 if (in->pcm_device_id < 0) {
7940 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7941 __func__, in->pcm_device_id, in->usecase);
7942 ret = -EINVAL;
7943 goto exit;
7944 }
7945
7946 adjust_mmap_period_count(&in->config, min_size_frames);
7947
7948 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
7949 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
7950 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
7951 (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307952 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307953 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7954 in->card_status = CARD_STATUS_OFFLINE;
7955 adev->card_status = CARD_STATUS_OFFLINE;
7956 ret = -EIO;
7957 goto exit;
7958 }
7959
Haynes Mathew George16081042017-05-31 17:16:49 -07007960 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
7961 step = "open";
7962 ret = -ENODEV;
7963 goto exit;
7964 }
7965
7966 ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
7967 if (ret < 0) {
7968 step = "begin";
7969 goto exit;
7970 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007971
juyuchen626833d2019-06-04 16:48:02 +08007972 info->flags = 0;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007973 info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
7974 buffer_size = pcm_frames_to_bytes(in->pcm, info->buffer_size_frames);
7975 info->burst_size_frames = in->config.period_size;
7976 ret = platform_get_mmap_data_fd(adev->platform,
7977 in->pcm_device_id, 1 /*capture*/,
7978 &info->shared_memory_fd,
7979 &mmap_size);
7980 if (ret < 0) {
7981 // Fall back to non exclusive mode
7982 info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
7983 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007984 in->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7985 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, in->mmap_shared_memory_fd);
7986
Arun Mirpuri5d170872019-03-26 13:21:31 -07007987 if (mmap_size < buffer_size) {
7988 step = "mmap";
7989 goto exit;
7990 }
juyuchen626833d2019-06-04 16:48:02 +08007991 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007992 }
7993
7994 memset(info->shared_memory_address, 0, buffer_size);
Haynes Mathew George16081042017-05-31 17:16:49 -07007995
7996 ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
7997 if (ret < 0) {
7998 step = "commit";
7999 goto exit;
8000 }
8001
Phil Burke0a86d12019-02-16 22:28:11 -08008002 in->mmap_time_offset_nanos = in_get_mmap_time_offset();
8003
Haynes Mathew George16081042017-05-31 17:16:49 -07008004 in->standby = false;
8005 ret = 0;
8006
8007 ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
8008 __func__, info->shared_memory_address, info->buffer_size_frames);
8009
8010exit:
8011 if (ret != 0) {
8012 if (in->pcm == NULL) {
8013 ALOGE("%s: %s - %d", __func__, step, ret);
8014 } else {
8015 ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
8016 pcm_close(in->pcm);
8017 in->pcm = NULL;
8018 }
8019 }
8020 pthread_mutex_unlock(&adev->lock);
8021 return ret;
8022}
8023
8024static int in_get_mmap_position(const struct audio_stream_in *stream,
8025 struct audio_mmap_position *position)
8026{
8027 struct stream_in *in = (struct stream_in *)stream;
8028 ALOGVV("%s", __func__);
8029 if (position == NULL) {
8030 return -EINVAL;
8031 }
Gautam Manam34d1f542021-01-05 20:24:37 +05308032 lock_input_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07008033 if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
Gautam Manam34d1f542021-01-05 20:24:37 +05308034 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008035 return -ENOSYS;
8036 }
8037 if (in->pcm == NULL) {
Gautam Manam34d1f542021-01-05 20:24:37 +05308038 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008039 return -ENOSYS;
8040 }
8041 struct timespec ts = { 0, 0 };
8042 int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
8043 if (ret < 0) {
8044 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
Gautam Manam34d1f542021-01-05 20:24:37 +05308045 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008046 return ret;
8047 }
Phil Burke0a86d12019-02-16 22:28:11 -08008048 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
8049 + in->mmap_time_offset_nanos;
Gautam Manam34d1f542021-01-05 20:24:37 +05308050 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008051 return 0;
8052}
8053
Naresh Tannirudcb47c52018-06-25 16:23:32 +05308054static int in_get_active_microphones(const struct audio_stream_in *stream,
8055 struct audio_microphone_characteristic_t *mic_array,
8056 size_t *mic_count) {
8057 struct stream_in *in = (struct stream_in *)stream;
8058 struct audio_device *adev = in->dev;
8059 ALOGVV("%s", __func__);
8060
8061 lock_input_stream(in);
8062 pthread_mutex_lock(&adev->lock);
8063 int ret = platform_get_active_microphones(adev->platform,
8064 audio_channel_count_from_in_mask(in->channel_mask),
8065 in->usecase, mic_array, mic_count);
8066 pthread_mutex_unlock(&adev->lock);
8067 pthread_mutex_unlock(&in->lock);
8068
8069 return ret;
8070}
8071
8072static int adev_get_microphones(const struct audio_hw_device *dev,
8073 struct audio_microphone_characteristic_t *mic_array,
8074 size_t *mic_count) {
8075 struct audio_device *adev = (struct audio_device *)dev;
8076 ALOGVV("%s", __func__);
8077
8078 pthread_mutex_lock(&adev->lock);
8079 int ret = platform_get_microphones(adev->platform, mic_array, mic_count);
8080 pthread_mutex_unlock(&adev->lock);
8081
8082 return ret;
8083}
juyuchendb308c22019-01-21 11:57:17 -07008084
8085static void in_update_sink_metadata(struct audio_stream_in *stream,
8086 const struct sink_metadata *sink_metadata) {
8087
8088 if (stream == NULL
8089 || sink_metadata == NULL
8090 || sink_metadata->tracks == NULL) {
8091 return;
8092 }
8093
8094 int error = 0;
8095 struct stream_in *in = (struct stream_in *)stream;
8096 struct audio_device *adev = in->dev;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008097 struct listnode devices;
8098
8099 list_init(&devices);
juyuchendb308c22019-01-21 11:57:17 -07008100
8101 if (sink_metadata->track_count != 0)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008102 reassign_device_list(&devices, sink_metadata->tracks->dest_device, "");
juyuchendb308c22019-01-21 11:57:17 -07008103
8104 lock_input_stream(in);
8105 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008106 ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, get_device_types(&devices));
juyuchendb308c22019-01-21 11:57:17 -07008107
Zhou Song503196b2021-07-23 17:31:05 +08008108 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY ||
8109 in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2) &&
8110 !list_empty(&devices) &&
8111 adev->voice_tx_output != NULL) {
juyuchendb308c22019-01-21 11:57:17 -07008112 /* Use the rx device from afe-proxy record to route voice call because
8113 there is no routing if tx device is on primary hal and rx device
8114 is on other hal during voice call. */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008115 assign_devices(&adev->voice_tx_output->device_list, &devices);
juyuchendb308c22019-01-21 11:57:17 -07008116
8117 if (!voice_is_call_state_active(adev)) {
8118 if (adev->mode == AUDIO_MODE_IN_CALL) {
8119 adev->current_call_output = adev->voice_tx_output;
8120 error = voice_start_call(adev);
8121 if (error != 0)
8122 ALOGE("%s: start voice call failed %d", __func__, error);
8123 }
8124 } else {
8125 adev->current_call_output = adev->voice_tx_output;
8126 voice_update_devices_for_all_voice_usecases(adev);
8127 }
8128 }
8129
Zhenlin Lian4f947842022-05-14 15:50:52 +05308130 clear_devices(&devices);
juyuchendb308c22019-01-21 11:57:17 -07008131 pthread_mutex_unlock(&adev->lock);
8132 pthread_mutex_unlock(&in->lock);
8133}
8134
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05308135int adev_open_output_stream(struct audio_hw_device *dev,
Haynes Mathew George16081042017-05-31 17:16:49 -07008136 audio_io_handle_t handle,
8137 audio_devices_t devices,
8138 audio_output_flags_t flags,
8139 struct audio_config *config,
8140 struct audio_stream_out **stream_out,
Derek Chenf6318be2017-06-12 17:16:24 -04008141 const char *address)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008142{
8143 struct audio_device *adev = (struct audio_device *)dev;
8144 struct stream_out *out;
Gangadhar Sb0210342019-02-22 17:39:41 +05308145 int ret = 0, ip_hdlr_stream = 0, ip_hdlr_dev = 0;
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008146 audio_format_t format;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008147 struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
Manish Dewangan21a850a2017-08-14 12:03:55 +05308148 bool is_direct_passthough = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008149 bool is_hdmi = devices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
8150 bool is_usb_dev = audio_is_usb_out_device(devices) &&
8151 (devices != AUDIO_DEVICE_OUT_USB_ACCESSORY);
8152 bool direct_dev = is_hdmi || is_usb_dev;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008153 bool use_db_as_primary =
vivek mehtaae1018c2019-05-09 12:19:57 -07008154 property_get_bool("vendor.audio.feature.deepbuffer_as_primary.enable",
8155 false);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008156 bool force_haptic_path =
8157 property_get_bool("vendor.audio.test_haptic", false);
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008158 bool is_voip_rx = flags & AUDIO_OUTPUT_FLAG_VOIP_RX;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008159#ifdef AUDIO_GKI_ENABLED
8160 __s32 *generic_dec;
8161#endif
Weiyin Jiang906db3c2021-03-02 13:17:04 +08008162 pthread_mutexattr_t latch_attr;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008163
kunleizdff872d2018-08-20 14:40:33 +08008164 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08008165 is_usb_dev = false;
8166 devices = AUDIO_DEVICE_OUT_SPEAKER;
8167 ALOGW("%s: ignore set device to non existing USB card, use output device(%#x)",
8168 __func__, devices);
Mingshu Pangdbd20562019-11-25 18:04:39 +08008169 if (config->format == AUDIO_FORMAT_DEFAULT)
8170 config->format = AUDIO_FORMAT_PCM_16_BIT;
8171 if (config->sample_rate == 0)
8172 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8173 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8174 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
kunleizd6a9e0c2018-07-30 15:38:52 +08008175 }
8176
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008177 *stream_out = NULL;
Naresh Tanniru80659832014-06-04 18:17:56 +05308178
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008179 out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
8180
Mingming Yin3a941d42016-02-17 18:08:05 -08008181 ALOGD("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
Derek Chenf6318be2017-06-12 17:16:24 -04008182 stream_handle(%p) address(%s)", __func__, config->format, config->sample_rate, config->channel_mask,
8183 devices, flags, &out->stream, address);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308184
8185
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008186 if (!out) {
8187 return -ENOMEM;
8188 }
8189
Haynes Mathew George204045b2015-02-25 20:32:03 -08008190 pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07008191 pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08008192 pthread_mutexattr_init(&latch_attr);
8193 pthread_mutexattr_settype(&latch_attr, PTHREAD_MUTEX_RECURSIVE);
8194 pthread_mutex_init(&out->latch_lock, &latch_attr);
8195 pthread_mutexattr_destroy(&latch_attr);
Zhou Song48453a02018-01-10 17:50:59 +08008196 pthread_mutex_init(&out->position_query_lock, (const pthread_mutexattr_t *) NULL);
Haynes Mathew George204045b2015-02-25 20:32:03 -08008197 pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
8198
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008199 if (devices == AUDIO_DEVICE_NONE)
8200 devices = AUDIO_DEVICE_OUT_SPEAKER;
8201
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008202 out->flags = flags;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008203 list_init(&out->device_list);
8204 update_device_list(&out->device_list, devices, address, true /* add devices */);
Haynes Mathew George47cd4cb2013-07-19 11:58:50 -07008205 out->dev = adev;
Aalique Grahame65780b52017-09-27 14:59:56 -07008206 out->hal_op_format = out->hal_ip_format = format = out->format = config->format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008207 out->sample_rate = config->sample_rate;
Sachin Mohan Gadag3d09acd2017-06-19 12:43:44 +05308208 out->channel_mask = config->channel_mask;
Ramjee Singh5857aeb2017-08-03 19:18:50 +05308209 if (out->channel_mask == AUDIO_CHANNEL_NONE)
8210 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
8211 else
8212 out->supported_channel_masks[0] = out->channel_mask;
Eric Laurentc4aef752013-09-12 17:45:53 -07008213 out->handle = handle;
Mingming Yin3ee55c62014-08-04 14:23:35 -07008214 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Alexy Josephaa54c872014-12-03 02:46:47 -08008215 out->non_blocking = 0;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308216 out->convert_buffer = NULL;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308217 out->started = 0;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008218 out->a2dp_muted = false;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008219 out->hal_output_suspend_supported = 0;
8220 out->dynamic_pm_qos_config_supported = 0;
Surendar Karkaf51b5842018-04-26 11:28:38 +05308221 out->set_dual_mono = false;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05308222 out->prev_card_status_offline = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05308223 out->pspd_coeff_sent = false;
Phil Burkd898ba62019-06-20 12:49:01 -07008224 out->mmap_shared_memory_fd = -1; // not open
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008225
Nikhil Laturkar26b690b2017-07-25 11:06:14 +05308226 if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
Satish Babu Patakokila37e7c482018-02-02 11:50:06 +05308227 (property_get_bool("vendor.audio.matrix.limiter.enable", false)))
Ben Romberger6c4d3812017-06-13 17:46:45 -07008228 platform_set_device_params(out, DEVICE_PARAM_LIMITER_ID, 1);
8229
Aalique Grahame22e49102018-12-18 14:23:57 -08008230 if (direct_dev &&
8231 (audio_is_linear_pcm(out->format) ||
8232 config->format == AUDIO_FORMAT_DEFAULT) &&
8233 out->flags == AUDIO_OUTPUT_FLAG_NONE) {
8234 audio_format_t req_format = config->format;
8235 audio_channel_mask_t req_channel_mask = config->channel_mask;
8236 uint32_t req_sample_rate = config->sample_rate;
8237
8238 pthread_mutex_lock(&adev->lock);
8239 if (is_hdmi) {
8240 ALOGV("AUDIO_DEVICE_OUT_AUX_DIGITAL and DIRECT|OFFLOAD, check hdmi caps");
8241 ret = read_hdmi_sink_caps(out);
8242 if (config->sample_rate == 0)
8243 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8244 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8245 config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
8246 if (config->format == AUDIO_FORMAT_DEFAULT)
8247 config->format = AUDIO_FORMAT_PCM_16_BIT;
8248 } else if (is_usb_dev) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008249 ret = read_usb_sup_params_and_compare(true /*is_playback*/,
8250 &config->format,
8251 &out->supported_formats[0],
8252 MAX_SUPPORTED_FORMATS,
8253 &config->channel_mask,
8254 &out->supported_channel_masks[0],
8255 MAX_SUPPORTED_CHANNEL_MASKS,
8256 &config->sample_rate,
8257 &out->supported_sample_rates[0],
8258 MAX_SUPPORTED_SAMPLE_RATES);
8259 ALOGV("plugged dev USB ret %d", ret);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008260 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008261
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008262 pthread_mutex_unlock(&adev->lock);
8263 if (ret != 0) {
Mingming Yin3a941d42016-02-17 18:08:05 -08008264 if (ret == -ENOSYS) {
8265 /* ignore and go with default */
8266 ret = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08008267 }
8268 // For MMAP NO IRQ, allow conversions in ADSP
8269 else if (is_hdmi || (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0)
8270 goto error_open;
8271 else {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008272 ALOGE("error reading direct dev sink caps");
Mingming Yin3a941d42016-02-17 18:08:05 -08008273 goto error_open;
8274 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008275
8276 if (req_sample_rate != 0 && config->sample_rate != req_sample_rate)
8277 config->sample_rate = req_sample_rate;
8278 if (req_channel_mask != AUDIO_CHANNEL_NONE && config->channel_mask != req_channel_mask)
8279 config->channel_mask = req_channel_mask;
8280 if (req_format != AUDIO_FORMAT_DEFAULT && config->format != req_format)
8281 config->format = req_format;
Mingming Yin3a941d42016-02-17 18:08:05 -08008282 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008283
8284 out->sample_rate = config->sample_rate;
8285 out->channel_mask = config->channel_mask;
8286 out->format = config->format;
8287 if (is_hdmi) {
8288 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8289 out->config = pcm_config_hdmi_multi;
8290 } else if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8291 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8292 out->config = pcm_config_mmap_playback;
8293 out->stream.start = out_start;
8294 out->stream.stop = out_stop;
8295 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8296 out->stream.get_mmap_position = out_get_mmap_position;
8297 } else {
8298 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8299 out->config = pcm_config_hifi;
8300 }
8301
8302 out->config.rate = out->sample_rate;
8303 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8304 if (is_hdmi) {
8305 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8306 audio_bytes_per_sample(out->format));
8307 }
8308 out->config.format = pcm_format_from_audio_format(out->format);
Mingming Yin3a941d42016-02-17 18:08:05 -08008309 }
8310
Derek Chenf6318be2017-06-12 17:16:24 -04008311 /* validate bus device address */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008312 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008313 /* extract car audio stream index */
8314 out->car_audio_stream =
8315 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
8316 if (out->car_audio_stream < 0) {
8317 ALOGE("%s: invalid car audio stream %x",
8318 __func__, out->car_audio_stream);
8319 ret = -EINVAL;
8320 goto error_open;
8321 }
Derek Chen5f67a942020-02-24 23:08:13 -08008322 ALOGV("%s: car_audio_stream %x", __func__, out->car_audio_stream);
Derek Chenf6318be2017-06-12 17:16:24 -04008323 }
8324
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008325 /* Check for VOIP usecase */
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008326 if (is_voip_rx) {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008327 if (!voice_extn_is_compress_voip_supported()) {
8328 if (out->sample_rate == 8000 || out->sample_rate == 16000 ||
8329 out->sample_rate == 32000 || out->sample_rate == 48000) {
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07008330 out->channel_mask = audio_extn_utils_is_vendor_enhanced_fwk() ?
Lakshman Chaluvarajue7fc9482020-05-30 14:29:29 +05308331 config->channel_mask : AUDIO_CHANNEL_OUT_STEREO;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008332 out->usecase = USECASE_AUDIO_PLAYBACK_VOIP;
8333 out->format = AUDIO_FORMAT_PCM_16_BIT;
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07008334 out->volume_l = INVALID_OUT_VOLUME;
8335 out->volume_r = INVALID_OUT_VOLUME;
Vikram Panduranga93f080e2017-06-07 18:16:14 -07008336
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008337 out->config = default_pcm_config_voip_copp;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008338 out->config.rate = out->sample_rate;
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008339 uint32_t channel_count =
8340 audio_channel_count_from_out_mask(out->channel_mask);
Ramjee Singh968858a2020-08-06 16:30:48 +05308341 out->config.channels = channel_count;
8342
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008343 uint32_t buffer_size = get_stream_buffer_size(DEFAULT_VOIP_BUF_DURATION_MS,
8344 out->sample_rate, out->format,
8345 channel_count, false);
8346 uint32_t frame_size = audio_bytes_per_sample(out->format) * channel_count;
8347 if (frame_size != 0)
8348 out->config.period_size = buffer_size / frame_size;
8349 else
8350 ALOGW("%s: frame size is 0 for format %#x", __func__, out->format);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008351 }
8352 } else {
8353 if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
8354 voice_extn_compress_voip_is_active(out->dev)) &&
8355 (voice_extn_compress_voip_is_config_supported(config))) {
8356 ret = voice_extn_compress_voip_open_output_stream(out);
8357 if (ret != 0) {
8358 ALOGE("%s: Compress voip output cannot be opened, error:%d",
8359 __func__, ret);
8360 goto error_open;
8361 }
Sujin Panicker19027262019-09-16 18:28:06 +05308362 } else {
8363 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8364 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008365 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008366 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008367 } else if (audio_is_linear_pcm(out->format) &&
8368 out->flags == AUDIO_OUTPUT_FLAG_NONE && is_usb_dev) {
8369 out->channel_mask = config->channel_mask;
8370 out->sample_rate = config->sample_rate;
8371 out->format = config->format;
8372 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8373 // does this change?
8374 out->config = is_hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
8375 out->config.rate = config->sample_rate;
8376 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8377 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8378 audio_bytes_per_sample(config->format));
8379 out->config.format = pcm_format_from_audio_format(out->format);
vivek mehta0ea887a2015-08-26 14:01:20 -07008380 } else if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308381 (out->flags == AUDIO_OUTPUT_FLAG_DIRECT)) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308382 pthread_mutex_lock(&adev->lock);
8383 bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
8384 pthread_mutex_unlock(&adev->lock);
8385
8386 // reject offload during card offline to allow
8387 // fallback to s/w paths
8388 if (offline) {
8389 ret = -ENODEV;
8390 goto error_open;
8391 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008392
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008393 if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
8394 config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
8395 ALOGE("%s: Unsupported Offload information", __func__);
8396 ret = -EINVAL;
8397 goto error_open;
8398 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008399
Atul Khare3fa6e542017-08-09 00:56:17 +05308400 if (config->offload_info.format == 0)
8401 config->offload_info.format = config->format;
8402 if (config->offload_info.sample_rate == 0)
8403 config->offload_info.sample_rate = config->sample_rate;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008404
Mingming Yin90310102013-11-13 16:57:00 -08008405 if (!is_supported_format(config->offload_info.format) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308406 !audio_extn_passthru_is_supported_format(config->offload_info.format)) {
vivek mehta0ea887a2015-08-26 14:01:20 -07008407 ALOGE("%s: Unsupported audio format %x " , __func__, config->offload_info.format);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008408 ret = -EINVAL;
8409 goto error_open;
8410 }
8411
Ben Romberger0f8c87b2017-05-24 17:41:11 -07008412 /* TrueHD only supported for 48k multiples (48k, 96k, 192k) */
8413 if ((config->offload_info.format == AUDIO_FORMAT_DOLBY_TRUEHD) &&
8414 (audio_extn_passthru_is_passthrough_stream(out)) &&
8415 !((config->sample_rate == 48000) ||
8416 (config->sample_rate == 96000) ||
8417 (config->sample_rate == 192000))) {
8418 ALOGE("%s: Unsupported sample rate %d for audio format %x",
8419 __func__, config->sample_rate, config->offload_info.format);
8420 ret = -EINVAL;
8421 goto error_open;
8422 }
8423
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008424 out->compr_config.codec = (struct snd_codec *)
8425 calloc(1, sizeof(struct snd_codec));
8426
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07008427 if (!out->compr_config.codec) {
8428 ret = -ENOMEM;
8429 goto error_open;
8430 }
8431
Dhananjay Kumarac341582017-02-23 23:42:25 +05308432 out->stream.pause = out_pause;
8433 out->stream.resume = out_resume;
8434 out->stream.flush = out_flush;
Ashish Jain4847e9d2017-08-17 19:16:57 +05308435 out->stream.set_callback = out_set_callback;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308436 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Mingming Yin21d60472015-09-30 13:56:25 -07008437 out->stream.drain = out_drain;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308438 out->usecase = get_offload_usecase(adev, true /* is_compress */);
vivek mehta446c3962015-09-14 10:57:35 -07008439 ALOGV("Compress Offload usecase .. usecase selected %d", out->usecase);
Dhananjay Kumarac341582017-02-23 23:42:25 +05308440 } else {
8441 out->usecase = get_offload_usecase(adev, false /* is_compress */);
8442 ALOGV("non-offload DIRECT_usecase ... usecase selected %d ", out->usecase);
vivek mehta0ea887a2015-08-26 14:01:20 -07008443 }
vivek mehta446c3962015-09-14 10:57:35 -07008444
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308445 if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8446 ALOGD("%s: Setting latency mode to true", __func__);
Meng Wang4c32fb42020-01-16 17:57:11 +08008447#ifdef AUDIO_GKI_ENABLED
8448 /* out->compr_config.codec->reserved[1] is for flags */
8449 out->compr_config.codec->reserved[1] |= audio_extn_utils_get_perf_mode_flag();
8450#else
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308451 out->compr_config.codec->flags |= audio_extn_utils_get_perf_mode_flag();
Meng Wang4c32fb42020-01-16 17:57:11 +08008452#endif
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308453 }
8454
vivek mehta446c3962015-09-14 10:57:35 -07008455 if (out->usecase == USECASE_INVALID) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008456 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Mingming Yin3a941d42016-02-17 18:08:05 -08008457 config->format == 0 && config->sample_rate == 0 &&
8458 config->channel_mask == 0) {
Mingming Yin21854652016-04-13 11:54:02 -07008459 ALOGI("%s dummy open to query sink capability",__func__);
Mingming Yin3a941d42016-02-17 18:08:05 -08008460 out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
8461 } else {
8462 ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__);
8463 ret = -EEXIST;
8464 goto error_open;
8465 }
vivek mehta446c3962015-09-14 10:57:35 -07008466 }
8467
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008468 if (config->offload_info.channel_mask)
8469 out->channel_mask = config->offload_info.channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008470 else if (config->channel_mask) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008471 out->channel_mask = config->channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008472 config->offload_info.channel_mask = config->channel_mask;
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008473 } else {
Dhananjay Kumarac341582017-02-23 23:42:25 +05308474 ALOGE("out->channel_mask not set for OFFLOAD/DIRECT usecase");
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008475 ret = -EINVAL;
8476 goto error_open;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008477 }
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008478
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008479 format = out->format = config->offload_info.format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008480 out->sample_rate = config->offload_info.sample_rate;
8481
Mingming Yin3ee55c62014-08-04 14:23:35 -07008482 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008483
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308484 out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05308485 if (audio_extn_utils_is_dolby_format(config->offload_info.format)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308486 audio_extn_dolby_send_ddp_endp_params(adev);
8487 audio_extn_dolby_set_dmid(adev);
8488 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008489
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008490 out->compr_config.codec->sample_rate =
Ravi Kumar Alamandab91bff32014-11-14 12:05:54 -08008491 config->offload_info.sample_rate;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008492 out->compr_config.codec->bit_rate =
8493 config->offload_info.bit_rate;
8494 out->compr_config.codec->ch_in =
Dhanalakshmi Siddania15c6792016-08-10 15:33:53 +05308495 audio_channel_count_from_out_mask(out->channel_mask);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008496 out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
Satish Babu Patakokilaa395a9e2016-11-01 12:18:49 +05308497 /* Update bit width only for non passthrough usecases.
8498 * For passthrough usecases, the output will always be opened @16 bit
8499 */
8500 if (!audio_extn_passthru_is_passthrough_stream(out))
8501 out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308502
8503 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
Meng Wang4c32fb42020-01-16 17:57:11 +08008504#ifdef AUDIO_GKI_ENABLED
8505 /* out->compr_config.codec->reserved[1] is for flags */
8506 out->compr_config.codec->reserved[1] |= COMPRESSED_TIMESTAMP_FLAG;
8507 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->reserved[1]);
8508#else
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308509 out->compr_config.codec->flags |= COMPRESSED_TIMESTAMP_FLAG;
8510 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->flags);
Meng Wang4c32fb42020-01-16 17:57:11 +08008511#endif
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308512
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008513 /*TODO: Do we need to change it for passthrough */
8514 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008515
Manish Dewangana6fc5442015-08-24 20:30:31 +05308516 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC)
8517 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308518 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
Manish Dewangana6fc5442015-08-24 20:30:31 +05308519 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308520 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_LATM)
8521 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4LATM;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308522
8523 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) ==
8524 AUDIO_FORMAT_PCM) {
8525
8526 /*Based on platform support, configure appropriate alsa format for corresponding
8527 *hal input format.
8528 */
8529 out->compr_config.codec->format = hal_format_to_alsa(
8530 config->offload_info.format);
8531
Ashish Jain83a6cc22016-06-28 14:34:17 +05308532 out->hal_op_format = alsa_format_to_hal(
Ashish Jainf1eaa582016-05-23 20:54:24 +05308533 out->compr_config.codec->format);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308534 out->hal_ip_format = out->format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308535
Dhananjay Kumarac341582017-02-23 23:42:25 +05308536 /*for direct non-compress playback populate bit_width based on selected alsa format as
Ashish Jainf1eaa582016-05-23 20:54:24 +05308537 *hal input format and alsa format might differ based on platform support.
8538 */
8539 out->bit_width = audio_bytes_per_sample(
Ashish Jain83a6cc22016-06-28 14:34:17 +05308540 out->hal_op_format) << 3;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308541
8542 out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
8543
Deeraj Soman93155a62019-09-30 19:00:37 +05308544 if (property_get_bool("vendor.audio.offload.buffer.duration.enabled", false)) {
8545 if ((config->offload_info.duration_us >= MIN_OFFLOAD_BUFFER_DURATION_MS * 1000) &&
8546 (config->offload_info.duration_us <= MAX_OFFLOAD_BUFFER_DURATION_MS * 1000))
8547 out->info.duration_us = (int64_t)config->offload_info.duration_us;
8548 }
Deeraj Soman65358ab2019-02-07 15:40:49 +05308549
Ashish Jainf1eaa582016-05-23 20:54:24 +05308550 /* Check if alsa session is configured with the same format as HAL input format,
8551 * if not then derive correct fragment size needed to accomodate the
8552 * conversion of HAL input format to alsa format.
8553 */
8554 audio_extn_utils_update_direct_pcm_fragment_size(out);
8555
8556 /*if hal input and output fragment size is different this indicates HAL input format is
8557 *not same as the alsa format
8558 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308559 if (out->hal_fragment_size != out->compr_config.fragment_size) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05308560 /*Allocate a buffer to convert input data to the alsa configured format.
8561 *size of convert buffer is equal to the size required to hold one fragment size
8562 *worth of pcm data, this is because flinger does not write more than fragment_size
8563 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308564 out->convert_buffer = calloc(1,out->compr_config.fragment_size);
8565 if (out->convert_buffer == NULL){
Ashish Jainf1eaa582016-05-23 20:54:24 +05308566 ALOGE("Allocation failed for convert buffer for size %d", out->compr_config.fragment_size);
8567 ret = -ENOMEM;
8568 goto error_open;
8569 }
8570 }
8571 } else if (audio_extn_passthru_is_passthrough_stream(out)) {
8572 out->compr_config.fragment_size =
8573 audio_extn_passthru_get_buffer_size(&config->offload_info);
8574 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8575 } else {
8576 out->compr_config.fragment_size =
8577 platform_get_compress_offload_buffer_size(&config->offload_info);
8578 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8579 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008580
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308581 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8582 out->compr_config.fragment_size += sizeof(struct snd_codec_metadata);
8583 }
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008584 if (config->offload_info.format == AUDIO_FORMAT_FLAC) {
8585#ifdef AUDIO_GKI_ENABLED
8586 generic_dec =
8587 &(out->compr_config.codec->options.generic.reserved[1]);
8588 ((struct snd_generic_dec_flac *)generic_dec)->sample_size =
8589 AUDIO_OUTPUT_BIT_WIDTH;
8590#else
Satya Krishna Pindiproli5d82d012015-08-12 18:21:25 +05308591 out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008592#endif
8593 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008594
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05308595 if (config->offload_info.format == AUDIO_FORMAT_APTX) {
8596 audio_extn_send_aptx_dec_bt_addr_to_dsp(out);
8597 }
8598
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008599 if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
8600 out->non_blocking = 1;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008601
Manish Dewangan69426c82017-01-30 17:35:36 +05308602 if ((flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) &&
8603 (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
8604 out->render_mode = RENDER_MODE_AUDIO_STC_MASTER;
8605 } else if(flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8606 out->render_mode = RENDER_MODE_AUDIO_MASTER;
8607 } else {
8608 out->render_mode = RENDER_MODE_AUDIO_NO_TIMESTAMP;
8609 }
Alexy Josephaa54c872014-12-03 02:46:47 -08008610
Naresh Tanniru29bce4e2017-04-27 17:54:30 +05308611 memset(&out->channel_map_param, 0,
8612 sizeof(struct audio_out_channel_map_param));
8613
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008614 out->send_new_metadata = 1;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05308615 out->send_next_track_params = false;
8616 out->is_compr_metadata_avail = false;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008617 out->offload_state = OFFLOAD_STATE_IDLE;
8618 out->playback_started = 0;
Zhou Song48453a02018-01-10 17:50:59 +08008619 out->writeAt.tv_sec = 0;
8620 out->writeAt.tv_nsec = 0;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008621
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008622 audio_extn_dts_create_state_notifier_node(out->usecase);
8623
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008624 ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
8625 __func__, config->offload_info.version,
8626 config->offload_info.bit_rate);
Ashish Jain5106d362016-05-11 19:23:33 +05308627
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308628 /* Check if DSD audio format is supported in codec
8629 * and there is no active native DSD use case
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308630 */
8631
8632 if ((config->format == AUDIO_FORMAT_DSD) &&
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308633 (!platform_check_codec_dsd_support(adev->platform) ||
8634 audio_is_dsd_native_stream_active(adev))) {
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308635 ret = -EINVAL;
8636 goto error_open;
8637 }
8638
Ashish Jain5106d362016-05-11 19:23:33 +05308639 /* Disable gapless if any of the following is true
8640 * passthrough playback
8641 * AV playback
Dhananjay Kumarac341582017-02-23 23:42:25 +05308642 * non compressed Direct playback
Ashish Jain5106d362016-05-11 19:23:33 +05308643 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308644 if (audio_extn_passthru_is_passthrough_stream(out) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308645 (config->format == AUDIO_FORMAT_DSD) ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07008646 (config->format == AUDIO_FORMAT_IEC61937) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308647 config->offload_info.has_video ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308648 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Ashish Jain5106d362016-05-11 19:23:33 +05308649 check_and_set_gapless_mode(adev, false);
8650 } else
8651 check_and_set_gapless_mode(adev, true);
Mingming Yin21854652016-04-13 11:54:02 -07008652
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308653 if (audio_extn_passthru_is_passthrough_stream(out)) {
Mingming Yin21854652016-04-13 11:54:02 -07008654 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
8655 }
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308656 if (config->format == AUDIO_FORMAT_DSD) {
8657 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
Meng Wang4c32fb42020-01-16 17:57:11 +08008658#ifdef AUDIO_GKI_ENABLED
8659 /* out->compr_config.codec->reserved[0] is for compr_passthr */
8660 out->compr_config.codec->reserved[0] = PASSTHROUGH_DSD;
8661#else
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308662 out->compr_config.codec->compr_passthr = PASSTHROUGH_DSD;
Meng Wang4c32fb42020-01-16 17:57:11 +08008663#endif
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308664 }
Aalique Grahame0359a1f2016-09-08 16:54:22 -07008665
8666 create_offload_callback_thread(out);
8667
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008668 } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008669 switch (config->sample_rate) {
8670 case 0:
8671 out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8672 break;
8673 case 8000:
8674 case 16000:
8675 case 48000:
8676 out->sample_rate = config->sample_rate;
8677 break;
8678 default:
8679 ALOGE("%s: Unsupported sampling rate %d for Incall Music", __func__,
8680 config->sample_rate);
8681 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8682 ret = -EINVAL;
8683 goto error_open;
8684 }
8685 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8686 switch (config->channel_mask) {
8687 case AUDIO_CHANNEL_NONE:
8688 case AUDIO_CHANNEL_OUT_STEREO:
8689 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8690 break;
8691 default:
8692 ALOGE("%s: Unsupported channel mask %#x for Incall Music", __func__,
8693 config->channel_mask);
8694 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8695 ret = -EINVAL;
8696 goto error_open;
8697 }
8698 switch (config->format) {
8699 case AUDIO_FORMAT_DEFAULT:
8700 case AUDIO_FORMAT_PCM_16_BIT:
8701 out->format = AUDIO_FORMAT_PCM_16_BIT;
8702 break;
8703 default:
8704 ALOGE("%s: Unsupported format %#x for Incall Music", __func__,
8705 config->format);
8706 config->format = AUDIO_FORMAT_PCM_16_BIT;
8707 ret = -EINVAL;
8708 goto error_open;
8709 }
8710
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05308711 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008712 if (ret != 0) {
8713 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008714 __func__, ret);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008715 goto error_open;
8716 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008717 } else if (is_single_device_type_equal(&out->device_list,
8718 AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08008719 switch (config->sample_rate) {
8720 case 0:
8721 out->sample_rate = AFE_PROXY_SAMPLING_RATE;
8722 break;
8723 case 8000:
8724 case 16000:
8725 case 48000:
8726 out->sample_rate = config->sample_rate;
8727 break;
8728 default:
8729 ALOGE("%s: Unsupported sampling rate %d for Telephony TX", __func__,
8730 config->sample_rate);
8731 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
8732 ret = -EINVAL;
8733 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008734 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008735 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8736 switch (config->channel_mask) {
8737 case AUDIO_CHANNEL_NONE:
8738 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8739 break;
8740 case AUDIO_CHANNEL_OUT_STEREO:
8741 out->channel_mask = config->channel_mask;
8742 break;
8743 default:
8744 ALOGE("%s: Unsupported channel mask %#x for Telephony TX", __func__,
8745 config->channel_mask);
8746 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8747 ret = -EINVAL;
8748 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008749 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008750 switch (config->format) {
8751 case AUDIO_FORMAT_DEFAULT:
8752 out->format = AUDIO_FORMAT_PCM_16_BIT;
8753 break;
8754 case AUDIO_FORMAT_PCM_16_BIT:
8755 out->format = config->format;
8756 break;
8757 default:
8758 ALOGE("%s: Unsupported format %#x for Telephony TX", __func__,
8759 config->format);
8760 config->format = AUDIO_FORMAT_PCM_16_BIT;
8761 ret = -EINVAL;
8762 break;
8763 }
8764 if (ret != 0)
8765 goto error_open;
8766
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008767 out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
8768 out->config = pcm_config_afe_proxy_playback;
Aalique Grahame22e49102018-12-18 14:23:57 -08008769 out->config.rate = out->sample_rate;
8770 out->config.channels =
8771 audio_channel_count_from_out_mask(out->channel_mask);
8772 out->config.format = pcm_format_from_audio_format(out->format);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008773 adev->voice_tx_output = out;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008774 } else {
Ashish Jain058165c2016-09-28 23:18:48 +05308775 unsigned int channels = 0;
8776 /*Update config params to default if not set by the caller*/
8777 if (config->sample_rate == 0)
8778 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8779 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8780 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8781 if (config->format == AUDIO_FORMAT_DEFAULT)
8782 config->format = AUDIO_FORMAT_PCM_16_BIT;
8783
8784 channels = audio_channel_count_from_out_mask(out->channel_mask);
8785
Varun Balaraje49253e2017-07-06 19:48:56 +05308786 if (out->flags & AUDIO_OUTPUT_FLAG_INTERACTIVE) {
8787 out->usecase = get_interactive_usecase(adev);
8788 out->config = pcm_config_low_latency;
8789 } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
Ashish Jain83a6cc22016-06-28 14:34:17 +05308790 out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07008791 out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
8792 out->flags);
8793 out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
Haynes Mathew George16081042017-05-31 17:16:49 -07008794 } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8795 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8796 out->config = pcm_config_mmap_playback;
8797 out->stream.start = out_start;
8798 out->stream.stop = out_stop;
8799 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8800 out->stream.get_mmap_position = out_get_mmap_position;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308801 } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8802 out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008803 out->hal_output_suspend_supported =
8804 property_get_bool("vendor.audio.hal.output.suspend.supported", false);
8805 out->dynamic_pm_qos_config_supported =
8806 property_get_bool("vendor.audio.hal.dynamic.qos.config.supported", false);
8807 if (!out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08008808 ALOGI("%s: dynamic qos voting not enabled for platform", __func__);
8809 } else {
8810 ALOGI("%s: dynamic qos voting enabled for platform", __func__);
8811 //the mixer path will be a string similar to "low-latency-playback resume"
8812 strlcpy(out->pm_qos_mixer_path, use_case_table[out->usecase], MAX_MIXER_PATH_LEN);
8813 strlcat(out->pm_qos_mixer_path,
8814 " resume", MAX_MIXER_PATH_LEN);
8815 ALOGI("%s: created %s pm_qos_mixer_path" , __func__,
8816 out->pm_qos_mixer_path);
8817 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308818 out->config = pcm_config_low_latency;
8819 } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
8820 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
8821 out->config = pcm_config_deep_buffer;
Ashish Jain058165c2016-09-28 23:18:48 +05308822 out->config.period_size = get_output_period_size(config->sample_rate, out->format,
8823 channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
8824 if (out->config.period_size <= 0) {
8825 ALOGE("Invalid configuration period size is not valid");
8826 ret = -EINVAL;
8827 goto error_open;
8828 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008829 } else if (flags & AUDIO_OUTPUT_FLAG_TTS) {
8830 out->usecase = USECASE_AUDIO_PLAYBACK_TTS;
8831 out->config = pcm_config_deep_buffer;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008832 } else if (config->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL) {
8833 out->usecase = USECASE_AUDIO_PLAYBACK_WITH_HAPTICS;
8834 out->config = pcm_config_haptics_audio;
8835 if (force_haptic_path)
8836 adev->haptics_config = pcm_config_haptics_audio;
8837 else
8838 adev->haptics_config = pcm_config_haptics;
8839
Meng Wangd08ce322020-04-02 08:59:20 +08008840 channels =
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008841 audio_channel_count_from_out_mask(out->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL);
8842
8843 if (force_haptic_path) {
8844 out->config.channels = 1;
8845 adev->haptics_config.channels = 1;
8846 } else
8847 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 -08008848 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008849 ret = audio_extn_auto_hal_open_output_stream(out);
8850 if (ret) {
8851 ALOGE("%s: Failed to open output stream for bus device", __func__);
8852 ret = -EINVAL;
8853 goto error_open;
8854 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308855 } else {
8856 /* primary path is the default path selected if no other outputs are available/suitable */
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008857 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8858 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308859 }
8860 out->hal_ip_format = format = out->format;
8861 out->config.format = hal_format_to_pcm(out->hal_ip_format);
8862 out->hal_op_format = pcm_format_to_hal(out->config.format);
8863 out->bit_width = format_to_bitwidth_table[out->hal_op_format] << 3;
8864 out->config.rate = config->sample_rate;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008865 out->sample_rate = out->config.rate;
Ashish Jain058165c2016-09-28 23:18:48 +05308866 out->config.channels = channels;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308867 if (out->hal_ip_format != out->hal_op_format) {
8868 uint32_t buffer_size = out->config.period_size *
8869 format_to_bitwidth_table[out->hal_op_format] *
8870 out->config.channels;
8871 out->convert_buffer = calloc(1, buffer_size);
8872 if (out->convert_buffer == NULL){
8873 ALOGE("Allocation failed for convert buffer for size %d",
8874 out->compr_config.fragment_size);
8875 ret = -ENOMEM;
8876 goto error_open;
8877 }
8878 ALOGD("Convert buffer allocated of size %d", buffer_size);
8879 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008880 }
8881
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008882 ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags: %x usecase %d",
8883 __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags, out->usecase);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308884
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008885 /* TODO remove this hardcoding and check why width is zero*/
8886 if (out->bit_width == 0)
8887 out->bit_width = 16;
Dhananjay Kumard6d32152016-10-13 16:11:03 +05308888 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008889 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008890 &out->device_list, out->flags,
8891 out->hal_op_format, out->sample_rate,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05308892 out->bit_width, out->channel_mask, out->profile,
Manish Dewangan837dc462015-05-27 10:17:41 +05308893 &out->app_type_cfg);
Aalique Grahame6e763712019-01-31 16:18:17 -08008894 if ((out->usecase == (audio_usecase_t)(GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary))) ||
Haynes Mathew Georgebf143712013-12-03 13:02:53 -08008895 (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
8896 /* Ensure the default output is not selected twice */
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008897 if(adev->primary_output == NULL)
8898 adev->primary_output = out;
8899 else {
8900 ALOGE("%s: Primary output is already opened", __func__);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008901 ret = -EEXIST;
8902 goto error_open;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008903 }
8904 }
8905
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008906 /* Check if this usecase is already existing */
8907 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella7ce05352014-04-17 20:00:41 -07008908 if ((get_usecase_from_list(adev, out->usecase) != NULL) &&
8909 (out->usecase != USECASE_COMPRESS_VOIP_CALL)) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008910 ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008911 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008912 ret = -EEXIST;
8913 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008914 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008915
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008916 pthread_mutex_unlock(&adev->lock);
8917
8918 out->stream.common.get_sample_rate = out_get_sample_rate;
8919 out->stream.common.set_sample_rate = out_set_sample_rate;
8920 out->stream.common.get_buffer_size = out_get_buffer_size;
8921 out->stream.common.get_channels = out_get_channels;
8922 out->stream.common.get_format = out_get_format;
8923 out->stream.common.set_format = out_set_format;
8924 out->stream.common.standby = out_standby;
8925 out->stream.common.dump = out_dump;
8926 out->stream.common.set_parameters = out_set_parameters;
8927 out->stream.common.get_parameters = out_get_parameters;
8928 out->stream.common.add_audio_effect = out_add_audio_effect;
8929 out->stream.common.remove_audio_effect = out_remove_audio_effect;
8930 out->stream.get_latency = out_get_latency;
8931 out->stream.set_volume = out_set_volume;
Aalique Grahame22e49102018-12-18 14:23:57 -08008932#ifdef NO_AUDIO_OUT
8933 out->stream.write = out_write_for_no_output;
8934#else
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008935 out->stream.write = out_write;
Aalique Grahame22e49102018-12-18 14:23:57 -08008936#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008937 out->stream.get_render_position = out_get_render_position;
8938 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008939 out->stream.get_presentation_position = out_get_presentation_position;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008940
Haynes Mathew George16081042017-05-31 17:16:49 -07008941 if (out->realtime)
8942 out->af_period_multiplier = af_period_multiplier;
8943 else
8944 out->af_period_multiplier = 1;
8945
Andy Hunga1f48fa2019-07-01 18:14:53 -07008946 out->kernel_buffer_size = out->config.period_size * out->config.period_count;
8947
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008948 out->standby = 1;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008949 out->volume_l = PLAYBACK_GAIN_MAX;
8950 out->volume_r = PLAYBACK_GAIN_MAX;
Eric Laurenta9024de2013-04-04 09:19:12 -07008951 /* out->muted = false; by calloc() */
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008952 /* out->written = 0; by calloc() */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008953
8954 config->format = out->stream.common.get_format(&out->stream.common);
8955 config->channel_mask = out->stream.common.get_channels(&out->stream.common);
8956 config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
Naresh Tanniru04f71882018-06-26 17:46:22 +05308957 register_format(out->format, out->supported_formats);
8958 register_channel_mask(out->channel_mask, out->supported_channel_masks);
8959 register_sample_rate(out->sample_rate, out->supported_sample_rates);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008960
Dechen Chai22768452021-07-30 09:29:16 +05308961#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08008962 out->error_log = error_log_create(
8963 ERROR_LOG_ENTRIES,
8964 1000000000 /* aggregate consecutive identical errors within one second in ns */);
Dechen Chai22768452021-07-30 09:29:16 +05308965#endif
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308966 /*
8967 By locking output stream before registering, we allow the callback
8968 to update stream's state only after stream's initial state is set to
8969 adev state.
8970 */
8971 lock_output_stream(out);
8972 audio_extn_snd_mon_register_listener(out, out_snd_mon_cb);
8973 pthread_mutex_lock(&adev->lock);
8974 out->card_status = adev->card_status;
8975 pthread_mutex_unlock(&adev->lock);
8976 pthread_mutex_unlock(&out->lock);
8977
Aalique Grahame22e49102018-12-18 14:23:57 -08008978 stream_app_type_cfg_init(&out->app_type_cfg);
8979
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008980 *stream_out = &out->stream;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308981 ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
vivek mehta0ea887a2015-08-26 14:01:20 -07008982 use_case_table[out->usecase]);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008983
8984 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
8985 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
8986 popcount(out->channel_mask), out->playback_started);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008987 /* setup a channel for client <--> adsp communication for stream events */
Manish Dewangan21a850a2017-08-14 12:03:55 +05308988 is_direct_passthough = audio_extn_passthru_is_direct_passthrough(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008989 if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Naresh Tanniru85819452017-05-04 18:55:45 -07008990 (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) ||
Gangadhar Sb0210342019-02-22 17:39:41 +05308991 audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform) ||
8992 (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false))) {
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008993 hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
8994 out->usecase, PCM_PLAYBACK);
8995 hdlr_stream_cfg.flags = out->flags;
8996 hdlr_stream_cfg.type = PCM_PLAYBACK;
8997 ret = audio_extn_adsp_hdlr_stream_open(&out->adsp_hdlr_stream_handle,
8998 &hdlr_stream_cfg);
8999 if (ret) {
9000 ALOGE("%s: adsp_hdlr_stream_open failed %d",__func__, ret);
9001 out->adsp_hdlr_stream_handle = NULL;
9002 }
9003 }
Gangadhar Sb0210342019-02-22 17:39:41 +05309004 ip_hdlr_stream = audio_extn_ip_hdlr_intf_supported(config->format,
9005 is_direct_passthough, false);
9006 ip_hdlr_dev = audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform);
9007 if (ip_hdlr_stream || ip_hdlr_dev ) {
Vidyakumar Athota2062f912017-06-27 14:46:15 -07009008 ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL, adev, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07009009 if (ret < 0) {
9010 ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d",__func__, ret);
9011 out->ip_hdlr_handle = NULL;
9012 }
9013 }
Derek Chenf939fb72018-11-13 13:34:41 -08009014
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009015 ret = io_streams_map_insert(adev, &out->stream.common,
9016 out->handle, AUDIO_PATCH_HANDLE_NONE);
9017 if (ret != 0)
9018 goto error_open;
9019
Susan Wang6dd13092021-01-25 10:27:11 -05009020 out->out_ctxt.output = out;
Derek Chenf939fb72018-11-13 13:34:41 -08009021
9022 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -05009023 list_add_tail(&adev->active_outputs_list, &out->out_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -08009024 pthread_mutex_unlock(&adev->lock);
9025
Eric Laurent994a6932013-07-17 11:51:42 -07009026 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009027 return 0;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07009028
9029error_open:
Ashish Jain83a6cc22016-06-28 14:34:17 +05309030 if (out->convert_buffer)
9031 free(out->convert_buffer);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07009032 free(out);
9033 *stream_out = NULL;
9034 ALOGD("%s: exit: ret %d", __func__, ret);
9035 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009036}
9037
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05309038void adev_close_output_stream(struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009039 struct audio_stream_out *stream)
9040{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009041 struct stream_out *out = (struct stream_out *)stream;
9042 struct audio_device *adev = out->dev;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009043 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009044
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009045 ALOGD("%s: enter:stream_handle(%s)",__func__, use_case_table[out->usecase]);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309046
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009047 io_streams_map_remove(adev, out->handle);
9048
Susan Wang6dd13092021-01-25 10:27:11 -05009049 // remove out_ctxt early to prevent the stream
9050 // being opened in a race condition
9051 pthread_mutex_lock(&adev->lock);
9052 list_remove(&out->out_ctxt.list);
9053 pthread_mutex_unlock(&adev->lock);
9054
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05309055 // must deregister from sndmonitor first to prevent races
9056 // between the callback and close_stream
9057 audio_extn_snd_mon_unregister_listener(out);
9058
Ben Rombergerd771a7c2017-02-22 18:05:17 -08009059 /* close adsp hdrl session before standby */
9060 if (out->adsp_hdlr_stream_handle) {
9061 ret = audio_extn_adsp_hdlr_stream_close(out->adsp_hdlr_stream_handle);
9062 if (ret)
9063 ALOGE("%s: adsp_hdlr_stream_close failed %d",__func__, ret);
9064 out->adsp_hdlr_stream_handle = NULL;
9065 }
9066
Manish Dewangan21a850a2017-08-14 12:03:55 +05309067 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07009068 audio_extn_ip_hdlr_intf_deinit(out->ip_hdlr_handle);
9069 out->ip_hdlr_handle = NULL;
9070 }
9071
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009072 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309073 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009074 ret = voice_extn_compress_voip_close_output_stream(&stream->common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309075 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309076 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009077 if(ret != 0)
9078 ALOGE("%s: Compress voip output cannot be closed, error:%d",
9079 __func__, ret);
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009080 } else
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009081 out_standby(&stream->common);
9082
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07009083 if (is_offload_usecase(out->usecase)) {
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08009084 audio_extn_dts_remove_state_notifier_node(out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009085 destroy_offload_callback_thread(out);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07009086 free_offload_usecase(adev, out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009087 if (out->compr_config.codec != NULL)
9088 free(out->compr_config.codec);
9089 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009090
Zhou Songbaddf9f2020-11-20 13:57:39 +08009091 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05309092
Varun Balaraje49253e2017-07-06 19:48:56 +05309093 if (is_interactive_usecase(out->usecase))
9094 free_interactive_usecase(adev, out->usecase);
9095
Ashish Jain83a6cc22016-06-28 14:34:17 +05309096 if (out->convert_buffer != NULL) {
9097 free(out->convert_buffer);
9098 out->convert_buffer = NULL;
9099 }
9100
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009101 if (adev->voice_tx_output == out)
9102 adev->voice_tx_output = NULL;
9103
Dechen Chai22768452021-07-30 09:29:16 +05309104#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08009105 error_log_destroy(out->error_log);
9106 out->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +05309107#endif
Dhanalakshmi Siddani6c3d0992017-01-16 16:52:33 +05309108 if (adev->primary_output == out)
9109 adev->primary_output = NULL;
9110
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009111 pthread_cond_destroy(&out->cond);
9112 pthread_mutex_destroy(&out->lock);
Weiyin Jiang280ea742020-09-08 20:28:22 +08009113 pthread_mutex_destroy(&out->pre_lock);
9114 pthread_mutex_destroy(&out->latch_lock);
9115 pthread_mutex_destroy(&out->position_query_lock);
Derek Chenf939fb72018-11-13 13:34:41 -08009116
9117 pthread_mutex_lock(&adev->lock);
Zhenlin Lian4f947842022-05-14 15:50:52 +05309118 clear_devices(&out->device_list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009119 free(stream);
Derek Chenf939fb72018-11-13 13:34:41 -08009120 pthread_mutex_unlock(&adev->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07009121 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009122}
9123
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05009124void in_set_power_policy(uint8_t enable)
9125{
9126 struct listnode *node;
9127
9128 ALOGD("%s: Enter, state %d", __func__, enable);
9129
9130 pthread_mutex_lock(&adev->lock);
9131 adev->in_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_OFFLINE;
9132 pthread_mutex_unlock(&adev->lock);
9133
9134 if (!enable) {
9135 list_for_each(node, &adev->active_inputs_list) {
9136 streams_input_ctxt_t *in_ctxt = node_to_item(node,
9137 streams_input_ctxt_t,
9138 list);
9139 struct stream_in *in = in_ctxt->input;
9140 in_standby(&in->stream.common);
9141 }
9142 }
9143
9144 ALOGD("%s: Exit", __func__);
9145}
9146
9147void out_set_power_policy(uint8_t enable)
9148{
9149 struct listnode *node;
9150
9151 ALOGD("%s: Enter, state %d", __func__, enable);
9152
9153 pthread_mutex_lock(&adev->lock);
E V Ravi317be872022-02-23 19:08:15 +05309154 adev->out_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_OFFLINE;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05009155 pthread_mutex_unlock(&adev->lock);
9156
9157 if (!enable) {
9158 list_for_each(node, &adev->active_outputs_list) {
9159 streams_output_ctxt_t *out_ctxt = node_to_item(node,
9160 streams_output_ctxt_t,
9161 list);
9162 struct stream_out *out = out_ctxt->output;
9163 out_on_error(&out->stream.common);
9164 }
9165 }
9166
9167 ALOGD("%s: Exit", __func__);
9168}
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009169static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
9170{
9171 struct audio_device *adev = (struct audio_device *)dev;
9172 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009173 char value[32];
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009174 int val;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009175 int ret;
9176 int status = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08009177 bool a2dp_reconfig = false;
Zhou Songd6d71752019-05-21 18:08:51 +08009178 struct listnode *node;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009179 int controller = -1, stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009180
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009181 ALOGD("%s: enter: %s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009182 parms = str_parms_create_str(kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009183
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309184 if (!parms)
9185 goto error;
Naresh Tanniru4c630392014-05-12 01:05:52 +05309186
Derek Chen6f293672019-04-01 01:40:24 -07009187 /* notify adev and input/output streams on the snd card status */
9188 adev_snd_mon_cb((void *)adev, parms);
9189
Weiyin Jiang24f55292020-12-22 14:35:46 +08009190 ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
9191 if (ret >= 0) {
9192 list_for_each(node, &adev->active_outputs_list) {
9193 streams_output_ctxt_t *out_ctxt = node_to_item(node,
9194 streams_output_ctxt_t,
9195 list);
9196 out_snd_mon_cb((void *)out_ctxt->output, parms);
9197 }
Derek Chen6f293672019-04-01 01:40:24 -07009198
Weiyin Jiang24f55292020-12-22 14:35:46 +08009199 list_for_each(node, &adev->active_inputs_list) {
9200 streams_input_ctxt_t *in_ctxt = node_to_item(node,
9201 streams_input_ctxt_t,
9202 list);
9203 in_snd_mon_cb((void *)in_ctxt->input, parms);
9204 }
Derek Chen6f293672019-04-01 01:40:24 -07009205 }
9206
Zhou Songd6d71752019-05-21 18:08:51 +08009207 pthread_mutex_lock(&adev->lock);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309208 ret = str_parms_get_str(parms, "BT_SCO", value, sizeof(value));
9209 if (ret >= 0) {
9210 /* When set to false, HAL should disable EC and NS */
Zhou Songd6d71752019-05-21 18:08:51 +08009211 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0){
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309212 adev->bt_sco_on = true;
Shalini Manjunatha3a2e06e2021-02-01 12:23:49 +05309213 /*
9214 * When ever BT_SCO=ON arrives, make sure to route
9215 * all use cases to SCO device, otherwise due to delay in
9216 * BT_SCO=ON and lack of synchronization with create audio patch
9217 * request for SCO device, some times use case not routed properly to
9218 * SCO device
9219 */
9220 struct audio_usecase *usecase;
9221 struct listnode *node;
9222 list_for_each(node, &adev->usecase_list) {
9223 usecase = node_to_item(node, struct audio_usecase, list);
Anver sadhiquef0efca32021-09-03 15:25:44 +05309224 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05309225 (!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 +05309226 ALOGD("BT_SCO ON, switch all in use case to it");
9227 select_devices(adev, usecase->id);
9228 }
Mingshu Pangef517202021-04-22 10:35:00 +08009229 if (usecase->stream.out && (usecase->type == PCM_PLAYBACK ||
9230 usecase->type == VOICE_CALL) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05309231 (!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 +05309232 ALOGD("BT_SCO ON, switch all out use case to it");
9233 select_devices(adev, usecase->id);
9234 }
9235 }
9236 }
9237 else {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309238 adev->bt_sco_on = false;
Zhou Songd6d71752019-05-21 18:08:51 +08009239 audio_extn_sco_reset_configuration();
Kunlei Zhangd96af8f2019-08-27 16:33:29 +08009240 }
9241 }
9242
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009243 status = voice_set_parameters(adev, parms);
9244 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009245 goto done;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009246
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009247 status = platform_set_parameters(adev->platform, parms);
9248 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009249 goto done;
9250
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009251 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
9252 if (ret >= 0) {
Vicky Sehrawate240e5d2014-08-12 17:17:04 -07009253 /* When set to false, HAL should disable EC and NS */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009254 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9255 adev->bluetooth_nrec = true;
9256 else
9257 adev->bluetooth_nrec = false;
9258 }
9259
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009260 ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
9261 if (ret >= 0) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009262 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9263 adev->screen_off = false;
9264 else
9265 adev->screen_off = true;
Quinn Male70f20f32019-06-26 16:50:26 -07009266 audio_extn_sound_trigger_update_screen_status(adev->screen_off);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009267 }
9268
Eric Laurent4b084132018-10-19 17:33:43 -07009269 ret = str_parms_get_int(parms, "rotation", &val);
9270 if (ret >= 0) {
9271 bool reverse_speakers = false;
9272 int camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9273 switch (val) {
9274 // FIXME: note that the code below assumes that the speakers are in the correct placement
9275 // relative to the user when the device is rotated 90deg from its default rotation. This
9276 // assumption is device-specific, not platform-specific like this code.
9277 case 270:
9278 reverse_speakers = true;
9279 camera_rotation = CAMERA_ROTATION_INVERT_LANDSCAPE;
9280 break;
9281 case 0:
9282 case 180:
9283 camera_rotation = CAMERA_ROTATION_PORTRAIT;
9284 break;
9285 case 90:
9286 camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9287 break;
9288 default:
9289 ALOGE("%s: unexpected rotation of %d", __func__, val);
9290 status = -EINVAL;
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009291 }
Eric Laurent4b084132018-10-19 17:33:43 -07009292 if (status == 0) {
9293 // check and set swap
9294 // - check if orientation changed and speaker active
9295 // - set rotation and cache the rotation value
9296 adev->camera_orientation =
9297 (adev->camera_orientation & ~CAMERA_ROTATION_MASK) | camera_rotation;
9298 if (!audio_extn_is_maxx_audio_enabled())
9299 platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
9300 }
9301 }
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009302
Mingming Yin514a8bc2014-07-29 15:22:21 -07009303 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
9304 if (ret >= 0) {
9305 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9306 adev->bt_wb_speech_enabled = true;
9307 else
9308 adev->bt_wb_speech_enabled = false;
9309 }
9310
Zhou Song12c29502019-03-16 10:37:18 +08009311 ret = str_parms_get_str(parms, "bt_swb", value, sizeof(value));
9312 if (ret >= 0) {
9313 val = atoi(value);
9314 adev->swb_speech_mode = val;
9315 }
9316
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009317 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
9318 if (ret >= 0) {
9319 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309320 audio_devices_t device = (audio_devices_t) val;
Zhou Song681350a2017-10-19 16:28:42 +08009321 if (audio_is_output_device(val) &&
9322 (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009323 ALOGV("cache new ext disp type and edid");
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009324 platform_get_controller_stream_from_params(parms, &controller, &stream);
9325 platform_set_ext_display_device_v2(adev->platform, controller, stream);
9326 ret = platform_get_ext_disp_type_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009327 if (ret < 0) {
9328 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Manisha Agarwal2f5ff882018-08-08 17:09:29 +05309329 } else {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009330 platform_cache_edid_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009331 }
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309332 } else if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
vivek mehta344576a2016-04-12 18:56:03 -07009333 /*
9334 * Do not allow AFE proxy port usage by WFD source when USB headset is connected.
9335 * Per AudioPolicyManager, USB device is higher priority than WFD.
9336 * For Voice call over USB headset, voice call audio is routed to AFE proxy ports.
9337 * If WFD use case occupies AFE proxy, it may result unintended behavior while
9338 * starting voice call on USB
9339 */
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009340 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309341 if (ret >= 0)
9342 audio_extn_usb_add_device(device, atoi(value));
9343
Zhou Song6f862822017-11-06 17:27:57 +08009344 if (!audio_extn_usb_is_tunnel_supported()) {
9345 ALOGV("detected USB connect .. disable proxy");
9346 adev->allow_afe_proxy_usage = false;
9347 }
Zhou Song503196b2021-07-23 17:31:05 +08009348 } else if (audio_is_hearing_aid_out_device(device) &&
9349 property_get_bool("persist.vendor.audio.ha_proxy.enabled", false)) {
9350 adev->ha_proxy_enable = true;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009351 }
9352 }
9353
9354 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
9355 if (ret >= 0) {
9356 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309357 audio_devices_t device = (audio_devices_t) val;
Garmond Leunge3b6d482016-10-25 16:48:01 -07009358 /*
9359 * The HDMI / Displayport disconnect handling has been moved to
9360 * audio extension to ensure that its parameters are not
9361 * invalidated prior to updating sysfs of the disconnect event
9362 * Invalidate will be handled by audio_extn_ext_disp_set_parameters()
9363 */
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309364 if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009365 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309366 if (ret >= 0)
9367 audio_extn_usb_remove_device(device, atoi(value));
9368
Zhou Song6f862822017-11-06 17:27:57 +08009369 if (!audio_extn_usb_is_tunnel_supported()) {
9370 ALOGV("detected USB disconnect .. enable proxy");
9371 adev->allow_afe_proxy_usage = true;
9372 }
Zhou Song503196b2021-07-23 17:31:05 +08009373 } else if (audio_is_hearing_aid_out_device(device)) {
9374 adev->ha_proxy_enable = false;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009375 }
9376 }
9377
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009378 audio_extn_qdsp_set_parameters(adev, parms);
Aalique Grahame22e49102018-12-18 14:23:57 -08009379
9380 status = audio_extn_a2dp_set_parameters(parms, &a2dp_reconfig);
Aniket Kumar Lata23300322019-02-20 22:25:30 -08009381 if (status >= 0 && a2dp_reconfig) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309382 struct audio_usecase *usecase;
9383 struct listnode *node;
9384 list_for_each(node, &adev->usecase_list) {
9385 usecase = node_to_item(node, struct audio_usecase, list);
Weiyin Jiangff56ff32020-05-08 14:32:21 +08009386 if ((usecase->stream.out == NULL) || (usecase->type != PCM_PLAYBACK))
9387 continue;
9388
9389 if (is_a2dp_out_device_type(&usecase->device_list)) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309390 ALOGD("reconfigure a2dp... forcing device switch");
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309391 audio_extn_a2dp_set_handoff_mode(true);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309392 ALOGD("Switching to speaker and muting the stream before select_devices");
9393 check_a2dp_restore_l(adev, usecase->stream.out, false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309394 //force device switch to re configure encoder
9395 select_devices(adev, usecase->id);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309396 ALOGD("Unmuting the stream after select_devices");
Zhou Songbaddf9f2020-11-20 13:57:39 +08009397 check_a2dp_restore_l(adev, usecase->stream.out, true);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309398 audio_extn_a2dp_set_handoff_mode(false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309399 break;
Zhou Songd01e7a22020-09-23 22:49:01 +08009400 } else if (is_offload_usecase(usecase->stream.out->usecase)) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009401 pthread_mutex_lock(&usecase->stream.out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08009402 if (usecase->stream.out->a2dp_muted) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009403 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
9404 reassign_device_list(&usecase->stream.out->device_list,
9405 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
9406 check_a2dp_restore_l(adev, usecase->stream.out, true);
9407 break;
9408 }
9409 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309410 }
9411 }
9412 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009413
9414 //handle vr audio setparam
9415 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9416 value, sizeof(value));
9417 if (ret >= 0) {
9418 ALOGI("Setting vr mode to be %s", value);
9419 if (!strncmp(value, "true", 4)) {
9420 adev->vr_audio_mode_enabled = true;
9421 ALOGI("Setting vr mode to true");
9422 } else if (!strncmp(value, "false", 5)) {
9423 adev->vr_audio_mode_enabled = false;
9424 ALOGI("Setting vr mode to false");
9425 } else {
9426 ALOGI("wrong vr mode set");
9427 }
9428 }
9429
Eric Laurent4b084132018-10-19 17:33:43 -07009430 //FIXME: to be replaced by proper video capture properties API
9431 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_CAMERA_FACING, value, sizeof(value));
9432 if (ret >= 0) {
9433 int camera_facing = CAMERA_FACING_BACK;
9434 if (strcmp(value, AUDIO_PARAMETER_VALUE_FRONT) == 0)
9435 camera_facing = CAMERA_FACING_FRONT;
9436 else if (strcmp(value, AUDIO_PARAMETER_VALUE_BACK) == 0)
9437 camera_facing = CAMERA_FACING_BACK;
9438 else {
9439 ALOGW("%s: invalid camera facing value: %s", __func__, value);
9440 goto done;
9441 }
9442 adev->camera_orientation =
9443 (adev->camera_orientation & ~CAMERA_FACING_MASK) | camera_facing;
9444 struct audio_usecase *usecase;
9445 struct listnode *node;
9446 list_for_each(node, &adev->usecase_list) {
9447 usecase = node_to_item(node, struct audio_usecase, list);
9448 struct stream_in *in = usecase->stream.in;
9449 if (usecase->type == PCM_CAPTURE && in != NULL &&
9450 in->source == AUDIO_SOURCE_CAMCORDER && !in->standby) {
9451 select_devices(adev, in->usecase);
9452 }
9453 }
9454 }
9455
Tahir Dawson7fabad42022-06-21 12:37:55 -04009456 audio_extn_auto_hal_set_parameters(adev, parms);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309457 audio_extn_set_parameters(adev, parms);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009458done:
9459 str_parms_destroy(parms);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009460 pthread_mutex_unlock(&adev->lock);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309461error:
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009462 ALOGV("%s: exit with code(%d)", __func__, status);
9463 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009464}
9465
9466static char* adev_get_parameters(const struct audio_hw_device *dev,
9467 const char *keys)
9468{
Sidipotu Ashokaa4fa6a2018-12-21 09:19:26 +05309469 ALOGD("%s:%s", __func__, keys);
9470
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009471 struct audio_device *adev = (struct audio_device *)dev;
9472 struct str_parms *reply = str_parms_create();
9473 struct str_parms *query = str_parms_create_str(keys);
9474 char *str;
Naresh Tannirud7205b62014-06-20 02:54:48 +05309475 char value[256] = {0};
9476 int ret = 0;
9477
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009478 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08009479 if (reply) {
9480 str_parms_destroy(reply);
9481 }
9482 if (query) {
9483 str_parms_destroy(query);
9484 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009485 ALOGE("adev_get_parameters: failed to create query or reply");
9486 return NULL;
9487 }
9488
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009489 //handle vr audio getparam
9490
9491 ret = str_parms_get_str(query,
9492 AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9493 value, sizeof(value));
9494
9495 if (ret >= 0) {
9496 bool vr_audio_enabled = false;
9497 pthread_mutex_lock(&adev->lock);
9498 vr_audio_enabled = adev->vr_audio_mode_enabled;
9499 pthread_mutex_unlock(&adev->lock);
9500
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009501 ALOGV("getting vr mode to %d", vr_audio_enabled);
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009502
9503 if (vr_audio_enabled) {
9504 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9505 "true");
9506 goto exit;
9507 } else {
9508 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9509 "false");
9510 goto exit;
9511 }
9512 }
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009513
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009514 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009515 audio_extn_get_parameters(adev, query, reply);
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -08009516 voice_get_parameters(adev, query, reply);
Aalique Grahame22e49102018-12-18 14:23:57 -08009517 audio_extn_a2dp_get_parameters(query, reply);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009518 platform_get_parameters(adev->platform, query, reply);
justinwengd5395152019-11-04 12:23:09 +08009519 audio_extn_ma_get_parameters(adev, query, reply);
Naresh Tanniru80659832014-06-04 18:17:56 +05309520 pthread_mutex_unlock(&adev->lock);
9521
Naresh Tannirud7205b62014-06-20 02:54:48 +05309522exit:
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009523 str = str_parms_to_str(reply);
9524 str_parms_destroy(query);
9525 str_parms_destroy(reply);
9526
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009527 ALOGV("%s: exit: returns - %s", __func__, str);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009528 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009529}
9530
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009531static int adev_init_check(const struct audio_hw_device *dev __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009532{
9533 return 0;
9534}
9535
9536static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
9537{
Haynes Mathew George5191a852013-09-11 14:19:36 -07009538 int ret;
9539 struct audio_device *adev = (struct audio_device *)dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08009540
9541 audio_extn_extspk_set_voice_vol(adev->extspk, volume);
9542
Haynes Mathew George5191a852013-09-11 14:19:36 -07009543 pthread_mutex_lock(&adev->lock);
9544 /* cache volume */
Shruthi Krishnaace10852013-10-25 14:32:12 -07009545 ret = voice_set_volume(adev, volume);
Haynes Mathew George5191a852013-09-11 14:19:36 -07009546 pthread_mutex_unlock(&adev->lock);
9547 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009548}
9549
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009550static int adev_set_master_volume(struct audio_hw_device *dev __unused,
9551 float volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009552{
9553 return -ENOSYS;
9554}
9555
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009556static int adev_get_master_volume(struct audio_hw_device *dev __unused,
9557 float *volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009558{
9559 return -ENOSYS;
9560}
9561
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009562static int adev_set_master_mute(struct audio_hw_device *dev __unused,
9563 bool muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009564{
9565 return -ENOSYS;
9566}
9567
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009568static int adev_get_master_mute(struct audio_hw_device *dev __unused,
9569 bool *muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009570{
9571 return -ENOSYS;
9572}
9573
9574static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
9575{
9576 struct audio_device *adev = (struct audio_device *)dev;
Garmond Leung5fd0b552018-04-17 11:56:12 -07009577 struct listnode *node;
9578 struct audio_usecase *usecase = NULL;
9579 int ret = 0;
kunleizdc4af9d2017-05-04 12:15:35 +08009580
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009581 pthread_mutex_lock(&adev->lock);
9582 if (adev->mode != mode) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309583 ALOGD("%s: mode %d , prev_mode %d \n", __func__, mode , adev->mode);
9584 adev->prev_mode = adev->mode; /* prev_mode is kept to handle voip concurrency*/
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009585 adev->mode = mode;
Weiyin Jiang96b96f72020-09-22 16:48:19 +08009586 if (mode == AUDIO_MODE_CALL_SCREEN) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309587 adev->current_call_output = adev->primary_output;
9588 voice_start_call(adev);
9589 } else if (voice_is_in_call_or_call_screen(adev) &&
Kunlei Zhang1d5c7f22019-05-21 14:25:57 +08009590 (mode == AUDIO_MODE_NORMAL ||
9591 (mode == AUDIO_MODE_IN_COMMUNICATION && !voice_is_call_state_active(adev)))) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07009592 list_for_each(node, &adev->usecase_list) {
9593 usecase = node_to_item(node, struct audio_usecase, list);
9594 if (usecase->type == VOICE_CALL)
9595 break;
9596 }
9597 if (usecase &&
9598 audio_is_usb_out_device(usecase->out_snd_device & AUDIO_DEVICE_OUT_ALL_USB)) {
9599 ret = audio_extn_usb_check_and_set_svc_int(usecase,
9600 true);
9601 if (ret != 0) {
9602 /* default service interval was successfully updated,
9603 reopen USB backend with new service interval */
9604 check_usecases_codec_backend(adev,
9605 usecase,
9606 usecase->out_snd_device);
9607 }
9608 }
9609
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009610 voice_stop_call(adev);
Banajit Goswami20cdd212015-09-11 01:11:30 -07009611 platform_set_gsm_mode(adev->platform, false);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009612 adev->current_call_output = NULL;
kunleizdc4af9d2017-05-04 12:15:35 +08009613 // restore device for other active usecases after stop call
9614 list_for_each(node, &adev->usecase_list) {
9615 usecase = node_to_item(node, struct audio_usecase, list);
9616 select_devices(adev, usecase->id);
9617 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009618 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009619 }
9620 pthread_mutex_unlock(&adev->lock);
9621 return 0;
9622}
9623
9624static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
9625{
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009626 int ret;
Aalique Grahame22e49102018-12-18 14:23:57 -08009627 struct audio_device *adev = (struct audio_device *)dev;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009628
9629 pthread_mutex_lock(&adev->lock);
Vidyakumar Athota2850d532013-11-19 16:02:12 -08009630 ALOGD("%s state %d\n", __func__, state);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009631 ret = voice_set_mic_mute((struct audio_device *)dev, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009632
Derek Chend2530072014-11-24 12:39:14 -08009633 if (adev->ext_hw_plugin)
9634 ret = audio_extn_ext_hw_plugin_set_mic_mute(adev->ext_hw_plugin, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009635
9636 adev->mic_muted = state;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009637 pthread_mutex_unlock(&adev->lock);
9638
9639 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009640}
9641
9642static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
9643{
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009644 *state = voice_get_mic_mute((struct audio_device *)dev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009645 return 0;
9646}
9647
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009648static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009649 const struct audio_config *config)
9650{
Avinash Chandrad7296d42021-08-04 15:07:47 +05309651 bool is_usb_hifi = IS_USB_HIFI;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009652 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009653
Aalique Grahame22e49102018-12-18 14:23:57 -08009654 /* Don't know if USB HIFI in this context so use true to be conservative */
9655 if (check_input_parameters(config->sample_rate, config->format, channel_count,
Avinash Chandrad7296d42021-08-04 15:07:47 +05309656 is_usb_hifi) != 0)
Aalique Grahame22e49102018-12-18 14:23:57 -08009657 return 0;
9658
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009659 return get_input_buffer_size(config->sample_rate, config->format, channel_count,
9660 false /* is_low_latency: since we don't know, be conservative */);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009661}
9662
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009663static bool adev_input_allow_hifi_record(struct audio_device *adev,
9664 audio_devices_t devices,
9665 audio_input_flags_t flags,
9666 audio_source_t source) {
9667 const bool allowed = true;
9668
9669 if (!audio_is_usb_in_device(devices))
9670 return !allowed;
9671
9672 switch (flags) {
9673 case AUDIO_INPUT_FLAG_NONE:
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009674 break;
Haynes Mathew George59862182017-10-24 16:23:57 -07009675 case AUDIO_INPUT_FLAG_FAST: // disallow hifi record for FAST as
9676 // it affects RTD numbers over USB
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009677 default:
9678 return !allowed;
9679 }
9680
9681 switch (source) {
9682 case AUDIO_SOURCE_DEFAULT:
9683 case AUDIO_SOURCE_MIC:
9684 case AUDIO_SOURCE_UNPROCESSED:
9685 break;
9686 default:
9687 return !allowed;
9688 }
9689
9690 switch (adev->mode) {
9691 case 0:
9692 break;
9693 default:
9694 return !allowed;
9695 }
9696
9697 return allowed;
9698}
9699
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009700static int adev_update_voice_comm_input_stream(struct stream_in *in,
9701 struct audio_config *config)
9702{
9703 bool valid_rate = (config->sample_rate == 8000 ||
9704 config->sample_rate == 16000 ||
9705 config->sample_rate == 32000 ||
9706 config->sample_rate == 48000);
9707 bool valid_ch = audio_channel_count_from_in_mask(in->channel_mask) == 1;
9708
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009709 if(!voice_extn_is_compress_voip_supported()) {
kunleiz28c73e72019-03-27 17:24:04 +08009710 if (valid_rate && valid_ch) {
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009711 in->usecase = USECASE_AUDIO_RECORD_VOIP;
9712 in->config = default_pcm_config_voip_copp;
9713 in->config.period_size = VOIP_IO_BUF_SIZE(in->sample_rate,
9714 DEFAULT_VOIP_BUF_DURATION_MS,
9715 DEFAULT_VOIP_BIT_DEPTH_BYTE)/2;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009716 } else {
9717 ALOGW("%s No valid input in voip, use defaults"
9718 "sample rate %u, channel mask 0x%X",
9719 __func__, config->sample_rate, in->channel_mask);
9720 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009721 in->config.rate = config->sample_rate;
9722 in->sample_rate = config->sample_rate;
9723 } else {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009724 //XXX needed for voice_extn_compress_voip_open_input_stream
9725 in->config.rate = config->sample_rate;
9726 if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
Shalini Manjunathaa763cc42019-08-23 15:13:46 +05309727 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009728 voice_extn_compress_voip_is_active(in->dev)) &&
9729 (voice_extn_compress_voip_is_format_supported(in->format)) &&
9730 valid_rate && valid_ch) {
9731 voice_extn_compress_voip_open_input_stream(in);
9732 // update rate entries to match config from AF
9733 in->config.rate = config->sample_rate;
9734 in->sample_rate = config->sample_rate;
9735 } else {
9736 ALOGW("%s compress voip not active, use defaults", __func__);
9737 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009738 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009739 return 0;
9740}
9741
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009742static int adev_open_input_stream(struct audio_hw_device *dev,
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07009743 audio_io_handle_t handle,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009744 audio_devices_t devices,
9745 struct audio_config *config,
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009746 struct audio_stream_in **stream_in,
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309747 audio_input_flags_t flags,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009748 const char *address,
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009749 audio_source_t source)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009750{
9751 struct audio_device *adev = (struct audio_device *)dev;
9752 struct stream_in *in;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08009753 int ret = 0, buffer_size, frame_size;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009754 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009755 bool is_low_latency = false;
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +05309756 bool channel_mask_updated = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009757 bool is_usb_dev = audio_is_usb_in_device(devices);
9758 bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
9759 devices,
9760 flags,
9761 source);
Andy Hung94320602018-10-29 18:31:12 -07009762 ALOGV("%s: enter: flags %#x, is_usb_dev %d, may_use_hifi_record %d,"
9763 " sample_rate %u, channel_mask %#x, format %#x",
9764 __func__, flags, is_usb_dev, may_use_hifi_record,
9765 config->sample_rate, config->channel_mask, config->format);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309766
kunleizdff872d2018-08-20 14:40:33 +08009767 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08009768 is_usb_dev = false;
9769 devices = AUDIO_DEVICE_IN_BUILTIN_MIC;
9770 ALOGW("%s: ignore set device to non existing USB card, use input device(%#x)",
9771 __func__, devices);
9772 }
9773
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009774 *stream_in = NULL;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009775
9776 if (!(is_usb_dev && may_use_hifi_record)) {
9777 if (config->sample_rate == 0)
9778 config->sample_rate = 48000;
9779 if (config->channel_mask == AUDIO_CHANNEL_NONE)
9780 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9781 if (config->format == AUDIO_FORMAT_DEFAULT)
9782 config->format = AUDIO_FORMAT_PCM_16_BIT;
9783
9784 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
9785
Aalique Grahame22e49102018-12-18 14:23:57 -08009786 if (check_input_parameters(config->sample_rate, config->format, channel_count,
9787 false) != 0)
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009788 return -EINVAL;
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05309789 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009790
9791 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009792
9793 if (!in) {
9794 ALOGE("failed to allocate input stream");
9795 return -ENOMEM;
9796 }
9797
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309798 ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05309799 stream_handle(%p) io_handle(%d) source(%d) format %x",__func__, config->sample_rate,
9800 config->channel_mask, devices, &in->stream, handle, source, config->format);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009801 pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07009802 pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009803
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009804 in->stream.common.get_sample_rate = in_get_sample_rate;
9805 in->stream.common.set_sample_rate = in_set_sample_rate;
9806 in->stream.common.get_buffer_size = in_get_buffer_size;
9807 in->stream.common.get_channels = in_get_channels;
9808 in->stream.common.get_format = in_get_format;
9809 in->stream.common.set_format = in_set_format;
9810 in->stream.common.standby = in_standby;
9811 in->stream.common.dump = in_dump;
9812 in->stream.common.set_parameters = in_set_parameters;
9813 in->stream.common.get_parameters = in_get_parameters;
9814 in->stream.common.add_audio_effect = in_add_audio_effect;
9815 in->stream.common.remove_audio_effect = in_remove_audio_effect;
9816 in->stream.set_gain = in_set_gain;
9817 in->stream.read = in_read;
9818 in->stream.get_input_frames_lost = in_get_input_frames_lost;
Aalique Grahame22e49102018-12-18 14:23:57 -08009819 in->stream.get_capture_position = in_get_capture_position;
Naresh Tannirudcb47c52018-06-25 16:23:32 +05309820 in->stream.get_active_microphones = in_get_active_microphones;
Paul McLeana50b7332018-12-17 08:24:21 -07009821 in->stream.set_microphone_direction = in_set_microphone_direction;
9822 in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
juyuchendb308c22019-01-21 11:57:17 -07009823 in->stream.update_sink_metadata = in_update_sink_metadata;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009824
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009825 list_init(&in->device_list);
9826 update_device_list(&in->device_list, devices, address, true);
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009827 in->source = source;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009828 in->dev = adev;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009829 in->standby = 1;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009830 in->capture_handle = handle;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07009831 in->flags = flags;
Haynes Mathew George46740472017-10-27 18:40:12 -07009832 in->bit_width = 16;
9833 in->af_period_multiplier = 1;
justinweng20fb6d82019-02-21 18:49:00 -07009834 in->direction = MIC_DIRECTION_UNSPECIFIED;
9835 in->zoom = 0;
Carter Hsu2e429db2019-05-14 18:50:52 +08009836 list_init(&in->aec_list);
9837 list_init(&in->ns_list);
Phil Burkd898ba62019-06-20 12:49:01 -07009838 in->mmap_shared_memory_fd = -1; // not open
Haynes Mathew George46740472017-10-27 18:40:12 -07009839
Andy Hung94320602018-10-29 18:31:12 -07009840 ALOGV("%s: source %d, config->channel_mask %#x", __func__, source, config->channel_mask);
Aalique Grahame22e49102018-12-18 14:23:57 -08009841 if (source == AUDIO_SOURCE_VOICE_UPLINK ||
9842 source == AUDIO_SOURCE_VOICE_DOWNLINK) {
9843 /* Force channel config requested to mono if incall
9844 record is being requested for only uplink/downlink */
9845 if (config->channel_mask != AUDIO_CHANNEL_IN_MONO) {
9846 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9847 ret = -EINVAL;
9848 goto err_open;
9849 }
9850 }
9851
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009852 if (is_usb_dev && may_use_hifi_record) {
9853 /* HiFi record selects an appropriate format, channel, rate combo
9854 depending on sink capabilities*/
9855 ret = read_usb_sup_params_and_compare(false /*is_playback*/,
9856 &config->format,
9857 &in->supported_formats[0],
9858 MAX_SUPPORTED_FORMATS,
9859 &config->channel_mask,
9860 &in->supported_channel_masks[0],
9861 MAX_SUPPORTED_CHANNEL_MASKS,
9862 &config->sample_rate,
9863 &in->supported_sample_rates[0],
9864 MAX_SUPPORTED_SAMPLE_RATES);
9865 if (ret != 0) {
9866 ret = -EINVAL;
9867 goto err_open;
9868 }
9869 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009870 } else if (config->format == AUDIO_FORMAT_DEFAULT) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309871 config->format = AUDIO_FORMAT_PCM_16_BIT;
Surendar karkaaca3d082017-11-09 15:18:37 +05309872 } else if (property_get_bool("vendor.audio.capture.pcm.32bit.enable", false)
9873 && config->format == AUDIO_FORMAT_PCM_32_BIT) {
9874 in->config.format = PCM_FORMAT_S32_LE;
9875 in->bit_width = 32;
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309876 } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
9877 (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
9878 (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
9879 (config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
9880 bool ret_error = false;
9881 in->bit_width = 24;
9882 /* 24 bit is restricted to UNPROCESSED source only,also format supported
9883 from HAL is 24_packed and 8_24
9884 *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
9885 24_packed return error indicating supported format is 24_packed
9886 *> In case of any other source requesting 24 bit or float return error
9887 indicating format supported is 16 bit only.
9888
9889 on error flinger will retry with supported format passed
9890 */
9891 if ((source != AUDIO_SOURCE_UNPROCESSED) &&
9892 (source != AUDIO_SOURCE_CAMCORDER)) {
9893 config->format = AUDIO_FORMAT_PCM_16_BIT;
9894 if (config->sample_rate > 48000)
9895 config->sample_rate = 48000;
9896 ret_error = true;
Haynes Mathew George46740472017-10-27 18:40:12 -07009897 } else if (!(config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
9898 config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309899 config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
9900 ret_error = true;
9901 }
9902
9903 if (ret_error) {
9904 ret = -EINVAL;
9905 goto err_open;
9906 }
9907 }
9908
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009909 in->channel_mask = config->channel_mask;
9910 in->format = config->format;
9911
9912 in->usecase = USECASE_AUDIO_RECORD;
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309913
Huicheng Liu1404ba12020-09-11 01:03:25 -04009914 /* validate bus device address */
9915 if (compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUS)) {
9916 /* extract car audio stream index */
9917 in->car_audio_stream =
9918 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
9919 if (in->car_audio_stream < 0) {
9920 ALOGE("%s: invalid car audio stream %x",
9921 __func__, in->car_audio_stream);
9922 ret = -EINVAL;
9923 goto err_open;
9924 }
9925 ALOGV("%s: car_audio_stream 0x%x", __func__, in->car_audio_stream);
Huicheng Liuea4fd422021-01-12 18:34:50 -05009926 ret = audio_extn_auto_hal_open_input_stream(in);
9927 if (ret) {
9928 ALOGE("%s: Failed to open input stream for bus device", __func__);
9929 ret = -EINVAL;
9930 goto err_open;
9931 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04009932 }
9933
Susan Wange3959562021-03-11 11:50:26 -05009934 /* reassign use case for echo reference stream on automotive platforms */
9935 if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) {
9936 ret = audio_extn_auto_hal_open_echo_reference_stream(in);
9937 }
9938
Kogara Naveen Kumar379ff692022-01-31 11:56:51 +05309939 if ((in->source == AUDIO_SOURCE_FM_TUNER) || (devices == AUDIO_DEVICE_IN_FM_TUNER)) {
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309940 if(!get_usecase_from_list(adev, USECASE_AUDIO_RECORD_FM_VIRTUAL))
9941 in->usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
9942 else {
9943 ret = -EINVAL;
9944 goto err_open;
9945 }
9946 }
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +05309947#ifdef PLATFORM_AUTO
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05309948 if ((config->sample_rate == 48000 ||
9949 config->sample_rate == 32000 ||
9950 config->sample_rate == 24000 ||
9951 config->sample_rate == 16000 ||
9952 config->sample_rate == 8000)&&
Deeraj Somanfa377bf2019-02-06 12:57:59 +05309953 (flags & AUDIO_INPUT_FLAG_TIMESTAMP) == 0 &&
9954 (flags & AUDIO_INPUT_FLAG_COMPRESS) == 0 &&
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +05309955 (flags & AUDIO_INPUT_FLAG_FAST) != 0)
9956#else
9957 if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
9958 (flags & AUDIO_INPUT_FLAG_TIMESTAMP) == 0 &&
9959 (flags & AUDIO_INPUT_FLAG_COMPRESS) == 0 &&
9960 (flags & AUDIO_INPUT_FLAG_FAST) != 0)
9961#endif
9962{
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009963 is_low_latency = true;
9964#if LOW_LATENCY_CAPTURE_USE_CASE
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05309965 if ((flags & AUDIO_INPUT_FLAG_VOIP_TX) != 0)
9966 in->usecase = USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY;
9967 else
9968 in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009969#endif
9970 in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
Aalique Grahame22e49102018-12-18 14:23:57 -08009971 if (!in->realtime) {
9972 in->config = pcm_config_audio_capture;
9973 frame_size = audio_stream_in_frame_size(&in->stream);
9974 buffer_size = get_input_buffer_size(config->sample_rate,
9975 config->format,
9976 channel_count,
9977 is_low_latency);
9978 in->config.period_size = buffer_size / frame_size;
9979 in->config.rate = config->sample_rate;
9980 in->af_period_multiplier = 1;
9981 } else {
9982 // period size is left untouched for rt mode playback
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +05309983#ifdef PLATFORM_AUTO
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05309984 switch(config->sample_rate)
9985 {
9986 case 48000:
9987 in->config = pcm_config_audio_capture_rt_48KHz;
9988 break;
9989 case 32000:
9990 in->config = pcm_config_audio_capture_rt_32KHz;
9991 break;
9992 case 24000:
9993 in->config = pcm_config_audio_capture_rt_24KHz;
9994 break;
9995 case 16000:
9996 in->config = pcm_config_audio_capture_rt_16KHz;
9997 break;
9998 case 8000:
9999 in->config = pcm_config_audio_capture_rt_8KHz;
10000 break;
10001 default:
10002 in->config = pcm_config_audio_capture_rt_48KHz;
10003 }
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +053010004#else
10005 in->config = pcm_config_audio_capture_rt_48KHz;
10006#endif
Aalique Grahame22e49102018-12-18 14:23:57 -080010007 in->af_period_multiplier = af_period_multiplier;
10008 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -070010009 }
10010
Susan Wangb803cb52021-10-14 12:03:36 -040010011 /* Additional sample rates added below must also be present
10012 in audio_policy_configuration.xml for mmap_no_irq_in */
10013 bool valid_mmap_record_rate = (config->sample_rate == 8000 ||
10014 config->sample_rate == 16000 ||
Susan Wang89da9042021-10-14 12:03:36 -040010015 config->sample_rate == 24000 ||
Susan Wangb803cb52021-10-14 12:03:36 -040010016 config->sample_rate == 32000 ||
10017 config->sample_rate == 48000);
10018 if (valid_mmap_record_rate &&
10019 ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -070010020 in->realtime = 0;
10021 in->usecase = USECASE_AUDIO_RECORD_MMAP;
10022 in->config = pcm_config_mmap_capture;
Haynes Mathew George46740472017-10-27 18:40:12 -070010023 in->config.format = pcm_format_from_audio_format(config->format);
Haynes Mathew George484e8d22017-07-31 18:55:17 -070010024 in->stream.start = in_start;
10025 in->stream.stop = in_stop;
10026 in->stream.create_mmap_buffer = in_create_mmap_buffer;
10027 in->stream.get_mmap_position = in_get_mmap_position;
Ramjee Singhbcb3b6c2021-11-17 13:19:16 +053010028 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -070010029 ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
Haynes Mathew George46740472017-10-27 18:40:12 -070010030 } else if (is_usb_dev && may_use_hifi_record) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -070010031 in->usecase = USECASE_AUDIO_RECORD_HIFI;
10032 in->config = pcm_config_audio_capture;
10033 frame_size = audio_stream_in_frame_size(&in->stream);
10034 buffer_size = get_input_buffer_size(config->sample_rate,
10035 config->format,
10036 channel_count,
10037 false /*is_low_latency*/);
10038 in->config.period_size = buffer_size / frame_size;
10039 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -070010040 in->config.format = pcm_format_from_audio_format(config->format);
Karthikeyan Mani07faa602018-08-20 11:01:32 -070010041 switch (config->format) {
10042 case AUDIO_FORMAT_PCM_32_BIT:
10043 in->bit_width = 32;
10044 break;
10045 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
10046 case AUDIO_FORMAT_PCM_8_24_BIT:
10047 in->bit_width = 24;
10048 break;
10049 default:
10050 in->bit_width = 16;
10051 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010052 } else if (is_single_device_type_equal(&in->device_list,
10053 AUDIO_DEVICE_IN_TELEPHONY_RX) ||
10054 is_single_device_type_equal(&in->device_list,
10055 AUDIO_DEVICE_IN_PROXY)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010056 if (config->sample_rate == 0)
10057 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
10058 if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
10059 config->sample_rate != 8000) {
10060 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
10061 ret = -EINVAL;
10062 goto err_open;
10063 }
10064 if (config->format == AUDIO_FORMAT_DEFAULT)
10065 config->format = AUDIO_FORMAT_PCM_16_BIT;
10066 if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
10067 config->format = AUDIO_FORMAT_PCM_16_BIT;
10068 ret = -EINVAL;
10069 goto err_open;
10070 }
10071
10072 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
Zhou Song62ea0282020-03-22 19:53:01 +080010073 if (adev->ha_proxy_enable &&
10074 is_single_device_type_equal(&in->device_list,
10075 AUDIO_DEVICE_IN_TELEPHONY_RX))
10076 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY2;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010077 in->config = pcm_config_afe_proxy_record;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010078 in->config.rate = config->sample_rate;
Aalique Grahame22e49102018-12-18 14:23:57 -080010079 in->af_period_multiplier = 1;
10080 } else if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
Shalini Manjunathaac412b32020-01-03 15:00:14 +053010081 (!voice_extn_is_compress_voip_supported()) &&
Aalique Grahame22e49102018-12-18 14:23:57 -080010082 in->flags & AUDIO_INPUT_FLAG_VOIP_TX &&
10083 (config->sample_rate == 8000 ||
10084 config->sample_rate == 16000 ||
10085 config->sample_rate == 32000 ||
10086 config->sample_rate == 48000) &&
10087 channel_count == 1) {
10088 in->usecase = USECASE_AUDIO_RECORD_VOIP;
10089 in->config = pcm_config_audio_capture;
10090 frame_size = audio_stream_in_frame_size(&in->stream);
10091 buffer_size = get_stream_buffer_size(VOIP_CAPTURE_PERIOD_DURATION_MSEC,
10092 config->sample_rate,
10093 config->format,
10094 channel_count, false /*is_low_latency*/);
10095 in->config.period_size = buffer_size / frame_size;
10096 in->config.period_count = VOIP_CAPTURE_PERIOD_COUNT;
10097 in->config.rate = config->sample_rate;
10098 in->af_period_multiplier = 1;
Mingshu Pangc2d65042021-01-14 16:19:10 +080010099 } else if (in->realtime) {
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +053010100#ifdef PLATFORM_AUTO
Kogara Naveen Kumara688a812022-04-27 16:45:59 +053010101 switch(config->sample_rate)
10102 {
10103 case 48000:
10104 in->config = pcm_config_audio_capture_rt_48KHz;
10105 break;
10106 case 32000:
10107 in->config = pcm_config_audio_capture_rt_32KHz;
10108 break;
10109 case 24000:
10110 in->config = pcm_config_audio_capture_rt_24KHz;
10111 break;
10112 case 16000:
10113 in->config = pcm_config_audio_capture_rt_16KHz;
10114 break;
10115 case 8000:
10116 in->config = pcm_config_audio_capture_rt_8KHz;
10117 break;
10118 default:
10119 in->config = pcm_config_audio_capture_rt_48KHz;
10120 }
Mingshu Pangc2d65042021-01-14 16:19:10 +080010121 in->config.format = pcm_format_from_audio_format(config->format);
10122 in->af_period_multiplier = af_period_multiplier;
Krishna Kishor Jhac1542b22022-08-22 13:12:09 +053010123#else
10124 in->config = pcm_config_audio_capture_rt_48KHz;
10125#endif
10126} else {
Revathi Uddarajud2634032017-12-07 14:42:34 +053010127 int ret_val;
10128 pthread_mutex_lock(&adev->lock);
10129 ret_val = audio_extn_check_and_set_multichannel_usecase(adev,
10130 in, config, &channel_mask_updated);
10131 pthread_mutex_unlock(&adev->lock);
10132
10133 if (!ret_val) {
10134 if (channel_mask_updated == true) {
10135 ALOGD("%s: return error to retry with updated channel mask (%#x)",
10136 __func__, config->channel_mask);
10137 ret = -EINVAL;
10138 goto err_open;
10139 }
10140 ALOGD("%s: created multi-channel session succesfully",__func__);
10141 } else if (audio_extn_compr_cap_enabled() &&
10142 audio_extn_compr_cap_format_supported(config->format) &&
10143 (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
10144 audio_extn_compr_cap_init(in);
10145 } else if (audio_extn_cin_applicable_stream(in)) {
Deeraj Soman14230922019-01-30 16:39:30 +053010146 ret = audio_extn_cin_configure_input_stream(in, config);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010147 if (ret)
10148 goto err_open;
10149 } else {
10150 in->config = pcm_config_audio_capture;
10151 in->config.rate = config->sample_rate;
10152 in->config.format = pcm_format_from_audio_format(config->format);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010153 in->format = config->format;
10154 frame_size = audio_stream_in_frame_size(&in->stream);
10155 buffer_size = get_input_buffer_size(config->sample_rate,
Haynes Mathew George46740472017-10-27 18:40:12 -070010156 config->format,
10157 channel_count,
10158 is_low_latency);
Dieter Luecking5d57def2018-09-07 14:23:37 +020010159 /* prevent division-by-zero */
10160 if (frame_size == 0) {
10161 ALOGE("%s: Error frame_size==0", __func__);
10162 ret = -EINVAL;
10163 goto err_open;
10164 }
10165
Revathi Uddarajud2634032017-12-07 14:42:34 +053010166 in->config.period_size = buffer_size / frame_size;
Aalique Grahame22e49102018-12-18 14:23:57 -080010167 in->af_period_multiplier = 1;
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010168
Revathi Uddarajud2634032017-12-07 14:42:34 +053010169 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
10170 /* optionally use VOIP usecase depending on config(s) */
10171 ret = adev_update_voice_comm_input_stream(in, config);
10172 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010173
Revathi Uddarajud2634032017-12-07 14:42:34 +053010174 if (ret) {
10175 ALOGE("%s AUDIO_SOURCE_VOICE_COMMUNICATION invalid args", __func__);
10176 goto err_open;
10177 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010178 }
Jaideep Sharmad305a4a2020-02-27 14:29:04 +053010179
10180 /* assign concurrent capture usecase if record has to caried out from
10181 * actual hardware input source */
10182 if (audio_extn_is_concurrent_capture_enabled() &&
10183 !audio_is_virtual_input_source(in->source)) {
Samyak Jainc37062f2019-04-25 18:41:06 +053010184 /* Acquire lock to avoid two concurrent use cases initialized to
10185 same pcm record use case */
kunleiz28c73e72019-03-27 17:24:04 +080010186
Samyak Jainc37062f2019-04-25 18:41:06 +053010187 if (in->usecase == USECASE_AUDIO_RECORD) {
10188 pthread_mutex_lock(&adev->lock);
10189 if (!(adev->pcm_record_uc_state)) {
10190 ALOGV("%s: using USECASE_AUDIO_RECORD",__func__);
10191 adev->pcm_record_uc_state = 1;
10192 pthread_mutex_unlock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010193 } else if (audio_extn_is_concurrent_pcm_record_enabled()) {
10194 in->usecase = get_record_usecase(adev);
10195 pthread_mutex_unlock(&adev->lock);
Samyak Jainc37062f2019-04-25 18:41:06 +053010196 } else {
10197 pthread_mutex_unlock(&adev->lock);
10198 /* Assign compress record use case for second record */
10199 in->usecase = USECASE_AUDIO_RECORD_COMPRESS2;
10200 in->flags |= AUDIO_INPUT_FLAG_COMPRESS;
10201 ALOGV("%s: overriding usecase with USECASE_AUDIO_RECORD_COMPRESS2 and appending compress flag", __func__);
10202 if (audio_extn_cin_applicable_stream(in)) {
10203 in->sample_rate = config->sample_rate;
Deeraj Soman14230922019-01-30 16:39:30 +053010204 ret = audio_extn_cin_configure_input_stream(in, config);
Samyak Jainc37062f2019-04-25 18:41:06 +053010205 if (ret)
10206 goto err_open;
10207 }
10208 }
10209 }
kunleiz28c73e72019-03-27 17:24:04 +080010210 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010211 }
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +053010212
Ramjee Singh82fd0c12019-08-21 16:31:33 +053010213 if (audio_extn_ssr_get_stream() != in)
10214 in->config.channels = channel_count;
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -070010215
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -070010216 in->sample_rate = in->config.rate;
10217
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010218 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
10219 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010220 &in->device_list, flags, in->format,
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010221 in->sample_rate, in->bit_width,
10222 in->profile, &in->app_type_cfg);
Naresh Tanniru04f71882018-06-26 17:46:22 +053010223 register_format(in->format, in->supported_formats);
10224 register_channel_mask(in->channel_mask, in->supported_channel_masks);
10225 register_sample_rate(in->sample_rate, in->supported_sample_rates);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010226
Dechen Chai22768452021-07-30 09:29:16 +053010227#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -080010228 in->error_log = error_log_create(
10229 ERROR_LOG_ENTRIES,
10230 1000000000 /* aggregate consecutive identical errors within one second */);
Dechen Chai22768452021-07-30 09:29:16 +053010231#endif
Aalique Grahame22e49102018-12-18 14:23:57 -080010232
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010233 /* This stream could be for sound trigger lab,
10234 get sound trigger pcm if present */
10235 audio_extn_sound_trigger_check_and_get_session(in);
10236
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010237 lock_input_stream(in);
10238 audio_extn_snd_mon_register_listener(in, in_snd_mon_cb);
10239 pthread_mutex_lock(&adev->lock);
10240 in->card_status = adev->card_status;
10241 pthread_mutex_unlock(&adev->lock);
10242 pthread_mutex_unlock(&in->lock);
10243
Aalique Grahame22e49102018-12-18 14:23:57 -080010244 stream_app_type_cfg_init(&in->app_type_cfg);
10245
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010246 *stream_in = &in->stream;
Derek Chenf939fb72018-11-13 13:34:41 -080010247
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010248 ret = io_streams_map_insert(adev, &in->stream.common,
10249 handle, AUDIO_PATCH_HANDLE_NONE);
10250 if (ret != 0)
10251 goto err_open;
10252
Susan Wang6dd13092021-01-25 10:27:11 -050010253 in->in_ctxt.input = in;
Derek Chenf939fb72018-11-13 13:34:41 -080010254
10255 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -050010256 list_add_tail(&adev->active_inputs_list, &in->in_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -080010257 pthread_mutex_unlock(&adev->lock);
10258
Eric Laurent994a6932013-07-17 11:51:42 -070010259 ALOGV("%s: exit", __func__);
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -080010260 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010261
10262err_open:
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010263 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
10264 free_record_usecase(adev, in->usecase);
10265 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jainc37062f2019-04-25 18:41:06 +053010266 pthread_mutex_lock(&adev->lock);
10267 adev->pcm_record_uc_state = 0;
10268 pthread_mutex_unlock(&adev->lock);
10269 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010270 free(in);
10271 *stream_in = NULL;
10272 return ret;
10273}
10274
10275static void adev_close_input_stream(struct audio_hw_device *dev,
10276 struct audio_stream_in *stream)
10277{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010278 int ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010279 struct stream_in *in = (struct stream_in *)stream;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010280 struct audio_device *adev = (struct audio_device *)dev;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010281
Sidipotu Ashokf43018c2014-05-02 16:21:50 +053010282 ALOGD("%s: enter:stream_handle(%p)",__func__, in);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080010283
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010284 if (in == NULL) {
10285 ALOGE("%s: audio_stream_in ptr is NULL", __func__);
10286 return;
10287 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010288 io_streams_map_remove(adev, in->capture_handle);
10289
Susan Wang6dd13092021-01-25 10:27:11 -050010290 // remove out_ctxt early to prevent the stream
10291 // being opened in a race condition
10292 pthread_mutex_lock(&adev->lock);
10293 list_remove(&in->in_ctxt.list);
10294 pthread_mutex_unlock(&adev->lock);
10295
kunleiz70e57612018-12-28 17:50:23 +080010296 /* must deregister from sndmonitor first to prevent races
10297 * between the callback and close_stream
10298 */
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010299 audio_extn_snd_mon_unregister_listener(stream);
10300
kunleiz70e57612018-12-28 17:50:23 +080010301 /* Disable echo reference if there are no active input, hfp call
10302 * and sound trigger while closing input stream
10303 */
Eric Laurent637e2d42018-11-15 12:24:31 -080010304 if (adev_get_active_input(adev) == NULL &&
kunleiz70e57612018-12-28 17:50:23 +080010305 !audio_extn_hfp_is_active(adev) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010306 !audio_extn_sound_trigger_check_ec_ref_enable()) {
10307 struct listnode out_devices;
10308 list_init(&out_devices);
10309 platform_set_echo_reference(adev, false, &out_devices);
Zhenlin Lian4f947842022-05-14 15:50:52 +053010310 clear_devices(&out_devices);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010311 } else
kunleiz70e57612018-12-28 17:50:23 +080010312 audio_extn_sound_trigger_update_ec_ref_status(false);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +053010313
Dechen Chai22768452021-07-30 09:29:16 +053010314#ifndef LINUX_ENABLED
Weiyin Jiang2995f662019-04-17 14:25:12 +080010315 error_log_destroy(in->error_log);
10316 in->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +053010317#endif
Pallavid7c7a272018-01-16 11:22:55 +053010318
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010319 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010320 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010321 ret = voice_extn_compress_voip_close_input_stream(&stream->common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010322 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010323 if (ret != 0)
10324 ALOGE("%s: Compress voip input cannot be closed, error:%d",
10325 __func__, ret);
10326 } else
10327 in_standby(&stream->common);
10328
Weiyin Jiang280ea742020-09-08 20:28:22 +080010329 pthread_mutex_destroy(&in->lock);
10330 pthread_mutex_destroy(&in->pre_lock);
10331
Revathi Uddarajud2634032017-12-07 14:42:34 +053010332 pthread_mutex_lock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010333 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
10334 free_record_usecase(adev, in->usecase);
10335 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jain15fda662018-12-18 16:40:52 +053010336 adev->pcm_record_uc_state = 0;
10337 }
10338
Kunlei Zhang5d5d8d92020-02-26 15:00:59 +080010339 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
10340 adev->enable_voicerx = false;
10341 }
10342
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070010343 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010344 audio_extn_ssr_deinit();
10345 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010346
Garmond Leunge2433c32017-09-28 21:51:22 -070010347 if (audio_extn_ffv_get_stream() == in) {
10348 audio_extn_ffv_stream_deinit();
10349 }
10350
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010351 if (audio_extn_compr_cap_enabled() &&
Subhadra Jagadeesan63a1e832023-01-13 11:26:38 +053010352 audio_extn_compr_cap_format_supported(pcm_format_to_audio_format((in->config).format)))
Mingming Yine62d7842013-10-25 16:26:03 -070010353 audio_extn_compr_cap_deinit();
Dhanalakshmi Siddani74cf00b2016-12-02 13:55:57 +053010354
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +053010355 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +053010356 audio_extn_cin_free_input_stream_resources(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010357
Mingming Yinfd7607b2016-01-22 12:48:44 -080010358 if (in->is_st_session) {
10359 ALOGV("%s: sound trigger pcm stop lab", __func__);
10360 audio_extn_sound_trigger_stop_lab(in);
10361 }
Zhenlin Lian4f947842022-05-14 15:50:52 +053010362 clear_devices(&in->device_list);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010363 free(stream);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010364 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010365 return;
10366}
10367
Aalique Grahame22e49102018-12-18 14:23:57 -080010368/* verifies input and output devices and their capabilities.
10369 *
10370 * This verification is required when enabling extended bit-depth or
10371 * sampling rates, as not all qcom products support it.
10372 *
10373 * Suitable for calling only on initialization such as adev_open().
10374 * It fills the audio_device use_case_table[] array.
10375 *
10376 * Has a side-effect that it needs to configure audio routing / devices
10377 * in order to power up the devices and read the device parameters.
10378 * It does not acquire any hw device lock. Should restore the devices
10379 * back to "normal state" upon completion.
10380 */
10381static int adev_verify_devices(struct audio_device *adev)
10382{
10383 /* enumeration is a bit difficult because one really wants to pull
10384 * the use_case, device id, etc from the hidden pcm_device_table[].
10385 * In this case there are the following use cases and device ids.
10386 *
10387 * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
10388 * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
10389 * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
10390 * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
10391 * [USECASE_AUDIO_RECORD] = {0, 0},
10392 * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
10393 * [USECASE_VOICE_CALL] = {2, 2},
10394 *
10395 * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
10396 * USECASE_VOICE_CALL omitted, but possible for either input or output.
10397 */
10398
10399 /* should be the usecases enabled in adev_open_input_stream() */
10400 static const int test_in_usecases[] = {
10401 USECASE_AUDIO_RECORD,
10402 USECASE_AUDIO_RECORD_LOW_LATENCY, /* does not appear to be used */
10403 };
10404 /* should be the usecases enabled in adev_open_output_stream()*/
10405 static const int test_out_usecases[] = {
10406 USECASE_AUDIO_PLAYBACK_DEEP_BUFFER,
10407 USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
10408 };
10409 static const usecase_type_t usecase_type_by_dir[] = {
10410 PCM_PLAYBACK,
10411 PCM_CAPTURE,
10412 };
10413 static const unsigned flags_by_dir[] = {
10414 PCM_OUT,
10415 PCM_IN,
10416 };
10417
10418 size_t i;
10419 unsigned dir;
10420 const unsigned card_id = adev->snd_card;
10421
10422 for (dir = 0; dir < 2; ++dir) {
10423 const usecase_type_t usecase_type = usecase_type_by_dir[dir];
10424 const unsigned flags_dir = flags_by_dir[dir];
10425 const size_t testsize =
10426 dir ? ARRAY_SIZE(test_in_usecases) : ARRAY_SIZE(test_out_usecases);
10427 const int *testcases =
10428 dir ? test_in_usecases : test_out_usecases;
10429 const audio_devices_t audio_device =
10430 dir ? AUDIO_DEVICE_IN_BUILTIN_MIC : AUDIO_DEVICE_OUT_SPEAKER;
10431
10432 for (i = 0; i < testsize; ++i) {
10433 const audio_usecase_t audio_usecase = testcases[i];
10434 int device_id;
10435 struct pcm_params **pparams;
10436 struct stream_out out;
10437 struct stream_in in;
10438 struct audio_usecase uc_info;
10439 int retval;
10440
10441 pparams = &adev->use_case_table[audio_usecase];
10442 pcm_params_free(*pparams); /* can accept null input */
10443 *pparams = NULL;
10444
10445 /* find the device ID for the use case (signed, for error) */
10446 device_id = platform_get_pcm_device_id(audio_usecase, usecase_type);
10447 if (device_id < 0)
10448 continue;
10449
10450 /* prepare structures for device probing */
10451 memset(&uc_info, 0, sizeof(uc_info));
10452 uc_info.id = audio_usecase;
10453 uc_info.type = usecase_type;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010454 list_init(&uc_info.device_list);
Aalique Grahame22e49102018-12-18 14:23:57 -080010455 if (dir) {
Aalique Grahame22e49102018-12-18 14:23:57 -080010456 memset(&in, 0, sizeof(in));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010457 list_init(&in.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010458 update_device_list(&in.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010459 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
10460 uc_info.stream.in = &in;
Aalique Grahame22e49102018-12-18 14:23:57 -080010461 }
10462 memset(&out, 0, sizeof(out));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010463 list_init(&out.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010464 update_device_list(&out.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010465 uc_info.stream.out = &out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010466 update_device_list(&uc_info.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010467 uc_info.in_snd_device = SND_DEVICE_NONE;
10468 uc_info.out_snd_device = SND_DEVICE_NONE;
10469 list_add_tail(&adev->usecase_list, &uc_info.list);
10470
10471 /* select device - similar to start_(in/out)put_stream() */
10472 retval = select_devices(adev, audio_usecase);
10473 if (retval >= 0) {
10474 *pparams = pcm_params_get(card_id, device_id, flags_dir);
10475#if LOG_NDEBUG == 0
Aalique Grahame203bee02019-03-13 17:49:36 -070010476 char info[512]; /* for possible debug info */
Aalique Grahame22e49102018-12-18 14:23:57 -080010477 if (*pparams) {
10478 ALOGV("%s: (%s) card %d device %d", __func__,
10479 dir ? "input" : "output", card_id, device_id);
10480 pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
10481 } else {
10482 ALOGV("%s: cannot locate card %d device %d", __func__, card_id, device_id);
10483 }
10484#endif
10485 }
10486
10487 /* deselect device - similar to stop_(in/out)put_stream() */
10488 /* 1. Get and set stream specific mixer controls */
10489 retval = disable_audio_route(adev, &uc_info);
10490 /* 2. Disable the rx device */
10491 retval = disable_snd_device(adev,
10492 dir ? uc_info.in_snd_device : uc_info.out_snd_device);
10493 list_remove(&uc_info.list);
10494 }
10495 }
Aalique Grahame22e49102018-12-18 14:23:57 -080010496 return 0;
10497}
10498
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010499int update_patch(unsigned int num_sources,
10500 const struct audio_port_config *sources,
10501 unsigned int num_sinks,
10502 const struct audio_port_config *sinks,
10503 audio_patch_handle_t handle,
10504 struct audio_patch_info *p_info,
10505 patch_type_t patch_type, bool new_patch)
10506{
Aniket Kumar Latad13758f2020-08-06 15:11:36 -070010507 ALOGV("%s: enter", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010508
10509 if (p_info == NULL) {
10510 ALOGE("%s: Invalid patch pointer", __func__);
10511 return -EINVAL;
10512 }
10513
10514 if (new_patch) {
10515 p_info->patch = (struct audio_patch *) calloc(1, sizeof(struct audio_patch));
10516 if (p_info->patch == NULL) {
10517 ALOGE("%s: Could not allocate patch", __func__);
10518 return -ENOMEM;
10519 }
10520 }
10521
10522 p_info->patch->id = handle;
10523 p_info->patch->num_sources = num_sources;
10524 p_info->patch->num_sinks = num_sinks;
10525
10526 for (int i = 0; i < num_sources; i++)
10527 p_info->patch->sources[i] = sources[i];
10528 for (int i = 0; i < num_sinks; i++)
10529 p_info->patch->sinks[i] = sinks[i];
10530
10531 p_info->patch_type = patch_type;
10532 return 0;
10533}
10534
10535audio_patch_handle_t generate_patch_handle()
10536{
10537 static audio_patch_handle_t patch_handle = AUDIO_PATCH_HANDLE_NONE;
10538 if (++patch_handle < 0)
10539 patch_handle = AUDIO_PATCH_HANDLE_NONE + 1;
10540 return patch_handle;
10541}
10542
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010543int adev_create_audio_patch(struct audio_hw_device *dev,
10544 unsigned int num_sources,
10545 const struct audio_port_config *sources,
10546 unsigned int num_sinks,
10547 const struct audio_port_config *sinks,
10548 audio_patch_handle_t *handle)
10549{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010550 int ret = 0;
10551 struct audio_device *adev = (struct audio_device *)dev;
10552 struct audio_patch_info *p_info = NULL;
10553 patch_type_t patch_type = PATCH_NONE;
10554 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10555 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
10556 struct audio_stream_info *s_info = NULL;
10557 struct audio_stream *stream = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010558 struct listnode devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010559 audio_devices_t device_type = AUDIO_DEVICE_NONE;
10560 bool new_patch = false;
10561 char addr[AUDIO_DEVICE_MAX_ADDRESS_LEN];
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010562
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010563 ALOGD("%s: enter: num sources %d, num_sinks %d, handle %d", __func__,
10564 num_sources, num_sinks, *handle);
10565
10566 if (num_sources == 0 || num_sources > AUDIO_PATCH_PORTS_MAX ||
10567 num_sinks == 0 || num_sinks > AUDIO_PATCH_PORTS_MAX) {
10568 ALOGE("%s: Invalid patch arguments", __func__);
10569 ret = -EINVAL;
10570 goto done;
10571 }
10572
10573 if (num_sources > 1) {
10574 ALOGE("%s: Multiple sources are not supported", __func__);
10575 ret = -EINVAL;
10576 goto done;
10577 }
10578
10579 if (sources == NULL || sinks == NULL) {
10580 ALOGE("%s: Invalid sources or sinks port config", __func__);
10581 ret = -EINVAL;
10582 goto done;
10583 }
10584
10585 ALOGV("%s: source role %d, source type %d", __func__,
10586 sources[0].type, sources[0].role);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010587 list_init(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010588
10589 // Populate source/sink information and fetch stream info
10590 switch (sources[0].type) {
10591 case AUDIO_PORT_TYPE_DEVICE: // Patch for audio capture or loopback
10592 device_type = sources[0].ext.device.type;
10593 strlcpy(&addr[0], &sources[0].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010594 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010595 if (sinks[0].type == AUDIO_PORT_TYPE_MIX) {
10596 patch_type = PATCH_CAPTURE;
10597 io_handle = sinks[0].ext.mix.handle;
10598 input_source = sinks[0].ext.mix.usecase.source;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010599 ALOGD("%s: Capture patch from device %x to mix %d",
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010600 __func__, device_type, io_handle);
10601 } else {
10602 // Device to device patch is not implemented.
10603 // This space will need changes if audio HAL
10604 // handles device to device patches in the future.
10605 patch_type = PATCH_DEVICE_LOOPBACK;
10606 }
10607 break;
10608 case AUDIO_PORT_TYPE_MIX: // Patch for audio playback
10609 io_handle = sources[0].ext.mix.handle;
10610 for (int i = 0; i < num_sinks; i++) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010611 device_type = sinks[i].ext.device.type;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010612 strlcpy(&addr[0], &sinks[i].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010613 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010614 }
10615 patch_type = PATCH_PLAYBACK;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010616 ALOGD("%s: Playback patch from mix handle %d to device %x",
10617 __func__, io_handle, get_device_types(&devices));
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010618 break;
10619 case AUDIO_PORT_TYPE_SESSION:
10620 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010621 ALOGE("%s: Unsupported source type %d", __func__, sources[0].type);
10622 ret = -EINVAL;
10623 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010624 }
10625
10626 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010627
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010628 // Generate patch info and update patch
10629 if (*handle == AUDIO_PATCH_HANDLE_NONE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010630 *handle = generate_patch_handle();
10631 p_info = (struct audio_patch_info *)
10632 calloc(1, sizeof(struct audio_patch_info));
10633 if (p_info == NULL) {
10634 ALOGE("%s: Failed to allocate memory", __func__);
10635 pthread_mutex_unlock(&adev->lock);
10636 ret = -ENOMEM;
10637 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010638 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010639 new_patch = true;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010640 } else {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010641 p_info = fetch_patch_info_l(adev, *handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010642 if (p_info == NULL) {
10643 ALOGE("%s: Unable to fetch patch for received patch handle %d",
10644 __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010645 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010646 ret = -EINVAL;
10647 goto done;
10648 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010649 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010650 update_patch(num_sources, sources, num_sinks, sinks,
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010651 *handle, p_info, patch_type, new_patch);
10652
10653 // Fetch stream info of associated mix for playback or capture patches
10654 if (p_info->patch_type == PATCH_PLAYBACK ||
10655 p_info->patch_type == PATCH_CAPTURE) {
10656 s_info = hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10657 if (s_info == NULL) {
10658 ALOGE("%s: Failed to obtain stream info", __func__);
10659 if (new_patch)
10660 free(p_info);
10661 pthread_mutex_unlock(&adev->lock);
10662 ret = -EINVAL;
10663 goto done;
10664 }
10665 ALOGV("%s: Fetched stream info with io_handle %d", __func__, io_handle);
10666 s_info->patch_handle = *handle;
10667 stream = s_info->stream;
10668 }
10669 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010670
10671 // Update routing for stream
10672 if (stream != NULL) {
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010673 if (p_info->patch_type == PATCH_PLAYBACK) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010674 ret = route_output_stream((struct stream_out *) stream, &devices);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010675 } else if (p_info->patch_type == PATCH_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010676 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010677 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010678 if (ret < 0) {
10679 pthread_mutex_lock(&adev->lock);
10680 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10681 if (new_patch)
10682 free(p_info);
10683 pthread_mutex_unlock(&adev->lock);
10684 ALOGE("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10685 goto done;
10686 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010687 }
10688
10689 // Add new patch to patch map
10690 if (!ret && new_patch) {
10691 pthread_mutex_lock(&adev->lock);
10692 hashmapPut(adev->patch_map, (void *) (intptr_t) *handle, (void *) p_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010693 ALOGD("%s: Added a new patch with 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 }
10696
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010697done:
Zhenlin Lian4f947842022-05-14 15:50:52 +053010698 clear_devices(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010699 audio_extn_hw_loopback_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010700 num_sources,
10701 sources,
10702 num_sinks,
10703 sinks,
10704 handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010705 audio_extn_auto_hal_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010706 num_sources,
10707 sources,
10708 num_sinks,
10709 sinks,
10710 handle);
10711 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010712}
10713
10714int adev_release_audio_patch(struct audio_hw_device *dev,
10715 audio_patch_handle_t handle)
10716{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010717 struct audio_device *adev = (struct audio_device *) dev;
10718 int ret = 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010719 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010720 struct audio_stream *stream = NULL;
Derek Chenf939fb72018-11-13 13:34:41 -080010721
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010722 if (handle == AUDIO_PATCH_HANDLE_NONE) {
10723 ALOGE("%s: Invalid patch handle %d", __func__, handle);
10724 ret = -EINVAL;
10725 goto done;
10726 }
10727
10728 ALOGD("%s: Remove patch with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010729 pthread_mutex_lock(&adev->lock);
10730 struct audio_patch_info *p_info = fetch_patch_info_l(adev, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010731 if (p_info == NULL) {
10732 ALOGE("%s: Patch info not found with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010733 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010734 ret = -EINVAL;
10735 goto done;
10736 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010737 struct audio_patch *patch = p_info->patch;
10738 if (patch == NULL) {
10739 ALOGE("%s: Patch not found for handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010740 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010741 ret = -EINVAL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010742 goto done;
10743 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010744 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10745 switch (patch->sources[0].type) {
10746 case AUDIO_PORT_TYPE_MIX:
10747 io_handle = patch->sources[0].ext.mix.handle;
10748 break;
10749 case AUDIO_PORT_TYPE_DEVICE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010750 if (p_info->patch_type == PATCH_CAPTURE)
10751 io_handle = patch->sinks[0].ext.mix.handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010752 break;
10753 case AUDIO_PORT_TYPE_SESSION:
10754 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010755 pthread_mutex_unlock(&adev->lock);
10756 ret = -EINVAL;
10757 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010758 }
10759
10760 // Remove patch and reset patch handle in stream info
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010761 patch_type_t patch_type = p_info->patch_type;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010762 patch_map_remove_l(adev, handle);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010763 if (patch_type == PATCH_PLAYBACK ||
10764 patch_type == PATCH_CAPTURE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010765 struct audio_stream_info *s_info =
10766 hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10767 if (s_info == NULL) {
10768 ALOGE("%s: stream for io_handle %d is not available", __func__, io_handle);
10769 pthread_mutex_unlock(&adev->lock);
10770 goto done;
10771 }
10772 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10773 stream = s_info->stream;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010774 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010775 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010776
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010777 if (stream != NULL) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010778 struct listnode devices;
10779 list_init(&devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010780 if (patch_type == PATCH_PLAYBACK)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010781 ret = route_output_stream((struct stream_out *) stream, &devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010782 else if (patch_type == PATCH_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010783 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Zhenlin Lian4f947842022-05-14 15:50:52 +053010784 clear_devices(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010785 }
10786
10787 if (ret < 0)
10788 ALOGW("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10789
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010790done:
10791 audio_extn_hw_loopback_release_audio_patch(dev, handle);
10792 audio_extn_auto_hal_release_audio_patch(dev, handle);
10793
10794 ALOGV("%s: Successfully released patch %d", __func__, handle);
Derek Chenf939fb72018-11-13 13:34:41 -080010795 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010796}
10797
10798int adev_get_audio_port(struct audio_hw_device *dev, struct audio_port *config)
10799{
Derek Chenf13dd492018-11-13 14:53:51 -080010800 int ret = 0;
10801
10802 ret = audio_extn_hw_loopback_get_audio_port(dev, config);
10803 ret |= audio_extn_auto_hal_get_audio_port(dev, config);
10804 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010805}
10806
10807int adev_set_audio_port_config(struct audio_hw_device *dev,
10808 const struct audio_port_config *config)
10809{
Derek Chenf13dd492018-11-13 14:53:51 -080010810 int ret = 0;
10811
10812 ret = audio_extn_hw_loopback_set_audio_port_config(dev, config);
10813 ret |= audio_extn_auto_hal_set_audio_port_config(dev, config);
10814 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010815}
10816
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010817static int adev_dump(const audio_hw_device_t *device __unused,
10818 int fd __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010819{
10820 return 0;
10821}
10822
10823static int adev_close(hw_device_t *device)
10824{
Aalique Grahame22e49102018-12-18 14:23:57 -080010825 size_t i;
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010826 struct audio_device *adev_temp = (struct audio_device *)device;
Kiran Kandi910e1862013-10-29 13:29:42 -070010827
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010828 if (!adev_temp)
Kiran Kandi910e1862013-10-29 13:29:42 -070010829 return 0;
10830
10831 pthread_mutex_lock(&adev_init_lock);
10832
10833 if ((--audio_device_ref_count) == 0) {
Sujin Panicker390724d2019-04-26 10:43:36 +053010834 if (audio_extn_spkr_prot_is_enabled())
10835 audio_extn_spkr_prot_deinit();
Jaideep Sharmaa2b49672019-09-10 20:37:03 +053010836 audio_extn_battery_properties_listener_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010837 audio_extn_snd_mon_unregister_listener(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010838 audio_extn_sound_trigger_deinit(adev);
Kiran Kandide144c82013-11-20 15:58:32 -080010839 audio_extn_listen_deinit(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010840 audio_extn_qdsp_deinit();
Aalique Grahame22e49102018-12-18 14:23:57 -080010841 audio_extn_extspk_deinit(adev->extspk);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010842 audio_extn_utils_release_streams_cfg_lists(
10843 &adev->streams_output_cfg_list,
10844 &adev->streams_input_cfg_list);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010845 if (audio_extn_qap_is_enabled())
10846 audio_extn_qap_deinit();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010847 if (audio_extn_qaf_is_enabled())
10848 audio_extn_qaf_deinit();
Kiran Kandi910e1862013-10-29 13:29:42 -070010849 audio_route_free(adev->audio_route);
Weiyin Jiangfa65d3e2019-03-05 23:39:45 +080010850 audio_extn_gef_deinit(adev);
Kiran Kandi910e1862013-10-29 13:29:42 -070010851 free(adev->snd_dev_ref_cnt);
10852 platform_deinit(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080010853 for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
10854 pcm_params_free(adev->use_case_table[i]);
10855 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010856 if (adev->adm_deinit)
10857 adev->adm_deinit(adev->adm_data);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010858 qahwi_deinit(device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080010859 audio_extn_adsp_hdlr_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010860 audio_extn_snd_mon_deinit();
Siddartha Shaik44dd7702017-06-14 12:13:25 +053010861 audio_extn_hw_loopback_deinit(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070010862 audio_extn_ffv_deinit();
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053010863 if (adev->device_cfg_params) {
10864 free(adev->device_cfg_params);
10865 adev->device_cfg_params = NULL;
10866 }
Derek Chend2530072014-11-24 12:39:14 -080010867 if(adev->ext_hw_plugin)
10868 audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
Derek Chenae7b0342019-02-08 15:17:04 -080010869 audio_extn_auto_hal_deinit();
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010870 free_map(adev->patch_map);
10871 free_map(adev->io_streams_map);
Kiran Kandi910e1862013-10-29 13:29:42 -070010872 free(device);
10873 adev = NULL;
10874 }
10875 pthread_mutex_unlock(&adev_init_lock);
Vatsal Buchac09ae062018-11-14 13:25:08 +053010876 enable_gcov();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010877 return 0;
10878}
10879
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010880/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
10881 * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
10882 * just that it _might_ work.
10883 */
10884static int period_size_is_plausible_for_low_latency(int period_size)
10885{
10886 switch (period_size) {
10887 case 160:
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -070010888 case 192:
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010889 case 240:
10890 case 320:
10891 case 480:
10892 return 1;
10893 default:
10894 return 0;
10895 }
10896}
10897
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010898static void adev_snd_mon_cb(void *cookie, struct str_parms *parms)
10899{
10900 bool is_snd_card_status = false;
10901 bool is_ext_device_status = false;
10902 char value[32];
10903 int card = -1;
10904 card_status_t status;
10905
10906 if (cookie != adev || !parms)
10907 return;
10908
10909 if (!parse_snd_card_status(parms, &card, &status)) {
10910 is_snd_card_status = true;
10911 } else if (0 < str_parms_get_str(parms, "ext_audio_device", value, sizeof(value))) {
10912 is_ext_device_status = true;
10913 } else {
10914 // not a valid event
10915 return;
10916 }
10917
10918 pthread_mutex_lock(&adev->lock);
10919 if (card == adev->snd_card || is_ext_device_status) {
10920 if (is_snd_card_status && adev->card_status != status) {
Jaideep Sharmacb402512020-09-24 17:51:07 +053010921 ALOGD("%s card_status %d", __func__, status);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010922 adev->card_status = status;
10923 platform_snd_card_update(adev->platform, status);
10924 audio_extn_fm_set_parameters(adev, parms);
Derek Chend6f371d2019-03-01 13:45:58 -080010925 audio_extn_auto_hal_set_parameters(adev, parms);
Zhou Song4f43e352019-07-02 00:32:23 +080010926 if (status == CARD_STATUS_OFFLINE)
10927 audio_extn_sco_reset_configuration();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010928 } else if (is_ext_device_status) {
10929 platform_set_parameters(adev->platform, parms);
10930 }
10931 }
10932 pthread_mutex_unlock(&adev->lock);
10933 return;
10934}
10935
Weiyin Jiang280ea742020-09-08 20:28:22 +080010936/* adev lock held */
10937int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010938{
10939 struct audio_usecase *uc_info;
Zhou Song407e5aa2020-12-27 19:13:04 +080010940 struct audio_usecase *usecase;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010941 struct listnode devices;
Zhou Song407e5aa2020-12-27 19:13:04 +080010942 struct listnode *node;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010943
10944 uc_info = get_usecase_from_list(adev, out->usecase);
10945 if (uc_info == NULL) {
10946 ALOGE("%s: Could not find the usecase (%d) in the list",
10947 __func__, out->usecase);
10948 return -EINVAL;
10949 }
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010950 list_init(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010951
Zhou Songbaddf9f2020-11-20 13:57:39 +080010952 ALOGD("%s: enter: usecase(%d: %s), a2dp muted %d", __func__,
10953 out->usecase, use_case_table[out->usecase], out->a2dp_muted);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010954
10955 if (restore) {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010956 pthread_mutex_lock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010957 // restore A2DP device for active usecases and unmute if required
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010958 if (is_a2dp_out_device_type(&out->device_list)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010959 ALOGD("%s: restoring A2dp and unmuting stream", __func__);
Zhou Songe5225132019-09-26 15:33:36 +080010960 if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
10961 select_devices(adev, uc_info->id);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010962
10963 if (is_offload_usecase(out->usecase)) {
10964 if (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)
Weiyin Jiang280ea742020-09-08 20:28:22 +080010965 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010966 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
10967 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
10968 } else {
10969 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010970 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010971 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010972 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010973 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010974 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010975 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010976 // mute stream and switch to speaker if suspended
10977 if (!out->a2dp_muted && !out->standby) {
Zhou Songbaddf9f2020-11-20 13:57:39 +080010978 assign_devices(&devices, &out->device_list);
10979 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Zhou Song407e5aa2020-12-27 19:13:04 +080010980 list_for_each(node, &adev->usecase_list) {
10981 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Songe63b6fe2021-04-15 13:54:46 +080010982 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
10983 !is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songcf77af02021-05-14 18:21:14 +080010984 !is_sco_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songe63b6fe2021-04-15 13:54:46 +080010985 platform_check_backends_match(SND_DEVICE_OUT_SPEAKER,
10986 usecase->out_snd_device)) {
Zhou Song407e5aa2020-12-27 19:13:04 +080010987 assign_devices(&out->device_list, &usecase->stream.out->device_list);
10988 break;
10989 }
10990 }
Zhou Songcf77af02021-05-14 18:21:14 +080010991 if ((is_a2dp_out_device_type(&devices) && list_length(&devices) == 1) ||
10992 (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
Zhou Song8edbbdb2021-01-14 16:48:03 +080010993 out->a2dp_muted = true;
10994 if (is_offload_usecase(out->usecase)) {
10995 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10996 compress_pause(out->compr);
10997 out_set_compr_volume(&out->stream, (float)0, (float)0);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010998 } else {
Weiyin Jiang906db3c2021-03-02 13:17:04 +080010999 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
11000 out_set_voip_volume(&out->stream, (float)0, (float)0);
11001 else
11002 out_set_pcm_volume(&out->stream, (float)0, (float)0);
11003
Zhou Song8edbbdb2021-01-14 16:48:03 +080011004 /* wait for stale pcm drained before switching to speaker */
11005 uint32_t latency =
11006 (out->config.period_count * out->config.period_size * 1000) /
11007 (out->config.rate);
11008 usleep(latency * 1000);
11009 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080011010 }
11011 select_devices(adev, out->usecase);
Zhou Song8edbbdb2021-01-14 16:48:03 +080011012 ALOGD("%s: switched to device:%s and stream muted:%d", __func__,
11013 platform_get_snd_device_name(uc_info->out_snd_device), out->a2dp_muted);
Zhou Songbaddf9f2020-11-20 13:57:39 +080011014 if (is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053011015 if (out->offload_state == OFFLOAD_STATE_PLAYING)
11016 compress_resume(out->compr);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053011017 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080011018 assign_devices(&out->device_list, &devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053011019 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080011020 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053011021 }
Zhenlin Lian4f947842022-05-14 15:50:52 +053011022 clear_devices(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053011023 ALOGV("%s: exit", __func__);
11024 return 0;
11025}
11026
Haynes Mathew George01156f92018-04-13 15:29:54 -070011027void adev_on_battery_status_changed(bool charging)
11028{
11029 pthread_mutex_lock(&adev->lock);
11030 ALOGI("%s: battery status changed to %scharging", __func__, charging ? "" : "not ");
11031 adev->is_charging = charging;
Zhou Songc1088ea2018-06-12 00:17:29 +080011032 audio_extn_sound_trigger_update_battery_status(charging);
Haynes Mathew George01156f92018-04-13 15:29:54 -070011033 pthread_mutex_unlock(&adev->lock);
11034}
11035
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011036static int adev_open(const hw_module_t *module, const char *name,
11037 hw_device_t **device)
11038{
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011039 int ret;
Derek Chenf939fb72018-11-13 13:34:41 -080011040 char value[PROPERTY_VALUE_MAX] = {0};
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011041 char mixer_ctl_name[128] = {0};
11042 struct mixer_ctl *ctl = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011043
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080011044 ALOGD("%s: enter", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011045 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
11046
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011047 pthread_mutex_lock(&adev_init_lock);
Kiran Kandi910e1862013-10-29 13:29:42 -070011048 if (audio_device_ref_count != 0){
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011049 *device = &adev->device.common;
Kiran Kandi910e1862013-10-29 13:29:42 -070011050 audio_device_ref_count++;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011051 ALOGD("%s: returning existing instance of adev", __func__);
11052 ALOGD("%s: exit", __func__);
11053 pthread_mutex_unlock(&adev_init_lock);
11054 return 0;
11055 }
11056
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011057 adev = calloc(1, sizeof(struct audio_device));
11058
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -070011059 if (!adev) {
11060 pthread_mutex_unlock(&adev_init_lock);
11061 return -ENOMEM;
11062 }
11063
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -070011064 pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
11065
Weiyin Jiange6ce6312019-01-28 18:28:22 +080011066 // register audio ext hidl at the earliest
11067 audio_extn_hidl_init();
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053011068#ifdef DYNAMIC_LOG_ENABLED
11069 register_for_dynamic_logging("hal");
11070#endif
11071
Derek Chenf939fb72018-11-13 13:34:41 -080011072 /* default audio HAL major version */
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011073 uint32_t maj_version = 3;
Derek Chenf939fb72018-11-13 13:34:41 -080011074 if(property_get("vendor.audio.hal.maj.version", value, NULL))
11075 maj_version = atoi(value);
11076
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011077 adev->device.common.tag = HARDWARE_DEVICE_TAG;
Derek Chenf939fb72018-11-13 13:34:41 -080011078 adev->device.common.version = HARDWARE_DEVICE_API_VERSION(maj_version, 0);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011079 adev->device.common.module = (struct hw_module_t *)module;
11080 adev->device.common.close = adev_close;
11081
11082 adev->device.init_check = adev_init_check;
11083 adev->device.set_voice_volume = adev_set_voice_volume;
11084 adev->device.set_master_volume = adev_set_master_volume;
11085 adev->device.get_master_volume = adev_get_master_volume;
11086 adev->device.set_master_mute = adev_set_master_mute;
11087 adev->device.get_master_mute = adev_get_master_mute;
11088 adev->device.set_mode = adev_set_mode;
11089 adev->device.set_mic_mute = adev_set_mic_mute;
11090 adev->device.get_mic_mute = adev_get_mic_mute;
11091 adev->device.set_parameters = adev_set_parameters;
11092 adev->device.get_parameters = adev_get_parameters;
11093 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
11094 adev->device.open_output_stream = adev_open_output_stream;
11095 adev->device.close_output_stream = adev_close_output_stream;
11096 adev->device.open_input_stream = adev_open_input_stream;
11097 adev->device.close_input_stream = adev_close_input_stream;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053011098 adev->device.create_audio_patch = adev_create_audio_patch;
11099 adev->device.release_audio_patch = adev_release_audio_patch;
11100 adev->device.get_audio_port = adev_get_audio_port;
11101 adev->device.set_audio_port_config = adev_set_audio_port_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011102 adev->device.dump = adev_dump;
Naresh Tannirudcb47c52018-06-25 16:23:32 +053011103 adev->device.get_microphones = adev_get_microphones;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011104
11105 /* Set the default route before the PCM stream is opened */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011106 adev->mode = AUDIO_MODE_NORMAL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -080011107 adev->primary_output = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011108 adev->out_device = AUDIO_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011109 adev->bluetooth_nrec = true;
Ravi Kumar Alamandaf9967042013-02-14 19:35:14 -080011110 adev->acdb_settings = TTY_MODE_OFF;
vivek mehta344576a2016-04-12 18:56:03 -070011111 adev->allow_afe_proxy_usage = true;
Ashish Jain1b9b30c2017-05-18 20:57:40 +053011112 adev->bt_sco_on = false;
Eric Laurent07eeafd2013-10-06 12:52:49 -070011113 /* adev->cur_hdmi_channels = 0; by calloc() */
Eric Laurentb23d5282013-05-14 15:27:20 -070011114 adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
vivek mehtaae1018c2019-05-09 12:19:57 -070011115 /* Init audio and voice feature */
11116 audio_extn_feature_init();
11117 voice_extn_feature_init();
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070011118 voice_init(adev);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -080011119 list_init(&adev->usecase_list);
Derek Chenf939fb72018-11-13 13:34:41 -080011120 list_init(&adev->active_inputs_list);
11121 list_init(&adev->active_outputs_list);
Rahul Sharma99770982019-03-06 17:05:26 +053011122 list_init(&adev->audio_patch_record_list);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011123 adev->io_streams_map = hashmapCreate(AUDIO_IO_PORTS_MAX, audio_extn_utils_hash_fn,
11124 audio_extn_utils_hash_eq);
11125 if (!adev->io_streams_map) {
11126 ALOGE("%s: Could not create io streams map", __func__);
11127 ret = -ENOMEM;
11128 goto adev_open_err;
11129 }
11130 adev->patch_map = hashmapCreate(AUDIO_PATCH_PORTS_MAX, audio_extn_utils_hash_fn,
11131 audio_extn_utils_hash_eq);
11132 if (!adev->patch_map) {
11133 ALOGE("%s: Could not create audio patch map", __func__);
11134 ret = -ENOMEM;
11135 goto adev_open_err;
11136 }
Krishnankutty Kolathappilly0b2de1c2014-02-14 14:45:49 -080011137 adev->cur_wfd_channels = 2;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -070011138 adev->offload_usecases_state = 0;
Samyak Jain15fda662018-12-18 16:40:52 +053011139 adev->pcm_record_uc_state = 0;
Ashish Jain81eb2a82015-05-13 10:52:34 +053011140 adev->is_channel_status_set = false;
Sudheer Papothifa9d2282015-09-17 01:53:25 +053011141 adev->perf_lock_opts[0] = 0x101;
11142 adev->perf_lock_opts[1] = 0x20E;
11143 adev->perf_lock_opts_size = 2;
Xiaojun Sang785b5da2017-08-03 15:52:29 +080011144 adev->dsp_bit_width_enforce_mode = 0;
Aalique Grahame552b0832019-03-11 10:16:38 -070011145 adev->enable_hfp = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011146 adev->use_old_pspd_mix_ctrl = false;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070011147 adev->adm_routing_changed = false;
Revathi Uddarajub26e3932020-06-10 14:51:02 +053011148 adev->a2dp_started = false;
Zhou Song503196b2021-07-23 17:31:05 +080011149 adev->ha_proxy_enable = false;
Naresh Tanniru4c630392014-05-12 01:05:52 +053011150
Zhou Song68ebc352019-12-05 17:11:15 +080011151 audio_extn_perf_lock_init();
11152
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011153 /* Loads platform specific libraries dynamically */
Eric Laurentb23d5282013-05-14 15:27:20 -070011154 adev->platform = platform_init(adev);
11155 if (!adev->platform) {
Eric Laurentb23d5282013-05-14 15:27:20 -070011156 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011157 ret = -EINVAL;
11158 goto adev_open_err;
Eric Laurentb23d5282013-05-14 15:27:20 -070011159 }
Eric Laurentc4aef752013-09-12 17:45:53 -070011160
Aalique Grahame22e49102018-12-18 14:23:57 -080011161 adev->extspk = audio_extn_extspk_init(adev);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011162 if (audio_extn_qap_is_enabled()) {
11163 ret = audio_extn_qap_init(adev);
11164 if (ret < 0) {
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011165 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011166 goto adev_open_err;
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011167 }
11168 adev->device.open_output_stream = audio_extn_qap_open_output_stream;
11169 adev->device.close_output_stream = audio_extn_qap_close_output_stream;
11170 }
Aalique Grahame22e49102018-12-18 14:23:57 -080011171
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011172 if (audio_extn_qaf_is_enabled()) {
11173 ret = audio_extn_qaf_init(adev);
11174 if (ret < 0) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011175 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011176 goto adev_open_err;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011177 }
11178
11179 adev->device.open_output_stream = audio_extn_qaf_open_output_stream;
11180 adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
11181 }
11182
Derek Chenae7b0342019-02-08 15:17:04 -080011183 audio_extn_auto_hal_init(adev);
Derek Chend2530072014-11-24 12:39:14 -080011184 adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);
11185
Eric Laurentc4aef752013-09-12 17:45:53 -070011186 if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
11187 adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
11188 if (adev->visualizer_lib == NULL) {
11189 ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
11190 } else {
11191 ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
11192 adev->visualizer_start_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011193 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070011194 "visualizer_hal_start_output");
11195 adev->visualizer_stop_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011196 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070011197 "visualizer_hal_stop_output");
11198 }
11199 }
Dhanalakshmi Siddani21be3ac2016-12-29 14:31:08 +053011200 audio_extn_init(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080011201 voice_extn_init(adev);
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -080011202 audio_extn_listen_init(adev, adev->snd_card);
Weiyin Jiangaa80acd2016-09-21 16:42:11 +080011203 audio_extn_gef_init(adev);
Siddartha Shaik44dd7702017-06-14 12:13:25 +053011204 audio_extn_hw_loopback_init(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070011205 audio_extn_ffv_init(adev);
Eric Laurentc4aef752013-09-12 17:45:53 -070011206
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011207 if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
11208 adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
11209 if (adev->offload_effects_lib == NULL) {
11210 ALOGE("%s: DLOPEN failed for %s", __func__,
11211 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
11212 } else {
11213 ALOGV("%s: DLOPEN successful for %s", __func__,
11214 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
11215 adev->offload_effects_start_output =
Ashish Jain5106d362016-05-11 19:23:33 +053011216 (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib,
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011217 "offload_effects_bundle_hal_start_output");
11218 adev->offload_effects_stop_output =
11219 (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
11220 "offload_effects_bundle_hal_stop_output");
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080011221 adev->offload_effects_set_hpx_state =
11222 (int (*)(bool))dlsym(adev->offload_effects_lib,
11223 "offload_effects_bundle_set_hpx_state");
Dhananjay Kumard68883d2015-09-04 13:39:26 +053011224 adev->offload_effects_get_parameters =
11225 (void (*)(struct str_parms *, struct str_parms *))
11226 dlsym(adev->offload_effects_lib,
11227 "offload_effects_bundle_get_parameters");
11228 adev->offload_effects_set_parameters =
11229 (void (*)(struct str_parms *))dlsym(adev->offload_effects_lib,
11230 "offload_effects_bundle_set_parameters");
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011231 }
11232 }
11233
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011234 if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
11235 adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
11236 if (adev->adm_lib == NULL) {
11237 ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
11238 } else {
11239 ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
11240 adev->adm_init = (adm_init_t)
11241 dlsym(adev->adm_lib, "adm_init");
11242 adev->adm_deinit = (adm_deinit_t)
11243 dlsym(adev->adm_lib, "adm_deinit");
11244 adev->adm_register_input_stream = (adm_register_input_stream_t)
11245 dlsym(adev->adm_lib, "adm_register_input_stream");
11246 adev->adm_register_output_stream = (adm_register_output_stream_t)
11247 dlsym(adev->adm_lib, "adm_register_output_stream");
11248 adev->adm_deregister_stream = (adm_deregister_stream_t)
11249 dlsym(adev->adm_lib, "adm_deregister_stream");
11250 adev->adm_request_focus = (adm_request_focus_t)
11251 dlsym(adev->adm_lib, "adm_request_focus");
11252 adev->adm_abandon_focus = (adm_abandon_focus_t)
11253 dlsym(adev->adm_lib, "adm_abandon_focus");
Haynes Mathew George5beddd42016-06-27 18:33:40 -070011254 adev->adm_set_config = (adm_set_config_t)
11255 dlsym(adev->adm_lib, "adm_set_config");
11256 adev->adm_request_focus_v2 = (adm_request_focus_v2_t)
11257 dlsym(adev->adm_lib, "adm_request_focus_v2");
11258 adev->adm_is_noirq_avail = (adm_is_noirq_avail_t)
11259 dlsym(adev->adm_lib, "adm_is_noirq_avail");
11260 adev->adm_on_routing_change = (adm_on_routing_change_t)
11261 dlsym(adev->adm_lib, "adm_on_routing_change");
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070011262 adev->adm_request_focus_v2_1 = (adm_request_focus_v2_1_t)
11263 dlsym(adev->adm_lib, "adm_request_focus_v2_1");
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011264 }
11265 }
11266
Aalique Grahame22e49102018-12-18 14:23:57 -080011267 adev->enable_voicerx = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070011268 adev->bt_wb_speech_enabled = false;
Zhou Song12c29502019-03-16 10:37:18 +080011269 adev->swb_speech_mode = SPEECH_MODE_INVALID;
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +080011270 adev->fluence_nn_usecase_id = USECASE_INVALID;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -080011271 //initialize this to false for now,
11272 //this will be set to true through set param
11273 adev->vr_audio_mode_enabled = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070011274
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -070011275 audio_extn_ds2_enable(adev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011276 *device = &adev->device.common;
Aalique Grahame22e49102018-12-18 14:23:57 -080011277
11278 if (k_enable_extended_precision)
11279 adev_verify_devices(adev);
11280
Xiaojun Sang785b5da2017-08-03 15:52:29 +080011281 adev->dsp_bit_width_enforce_mode =
11282 adev_init_dsp_bit_width_enforce_mode(adev->mixer);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011283
Dhananjay Kumard6d32152016-10-13 16:11:03 +053011284 audio_extn_utils_update_streams_cfg_lists(adev->platform, adev->mixer,
11285 &adev->streams_output_cfg_list,
11286 &adev->streams_input_cfg_list);
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -070011287
Kiran Kandi910e1862013-10-29 13:29:42 -070011288 audio_device_ref_count++;
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011289
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011290 int trial;
Manisha Agarwalc75a0202019-12-06 18:48:25 +053011291 if (property_get("vendor.audio_hal.period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011292 trial = atoi(value);
11293 if (period_size_is_plausible_for_low_latency(trial)) {
11294 pcm_config_low_latency.period_size = trial;
11295 pcm_config_low_latency.start_threshold = trial / 4;
11296 pcm_config_low_latency.avail_min = trial / 4;
11297 configured_low_latency_capture_period_size = trial;
11298 }
11299 }
ronghuiz93177262021-04-21 19:58:13 +080011300 if (property_get("vendor.audio_hal.in_period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011301 trial = atoi(value);
11302 if (period_size_is_plausible_for_low_latency(trial)) {
11303 configured_low_latency_capture_period_size = trial;
11304 }
11305 }
11306
Vignesh Kulothungan7d374312018-02-21 17:12:00 -080011307 adev->mic_break_enabled = property_get_bool("vendor.audio.mic_break", false);
11308
Eric Laurent4b084132018-10-19 17:33:43 -070011309 adev->camera_orientation = CAMERA_DEFAULT;
11310
Manisha Agarwalc75a0202019-12-06 18:48:25 +053011311 if (property_get("vendor.audio_hal.period_multiplier",value,NULL) > 0) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -070011312 af_period_multiplier = atoi(value);
11313 if (af_period_multiplier < 0)
11314 af_period_multiplier = 2;
11315 else if (af_period_multiplier > 4)
11316 af_period_multiplier = 4;
11317
11318 ALOGV("new period_multiplier = %d", af_period_multiplier);
11319 }
11320
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080011321 audio_extn_qdsp_init(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080011322
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -070011323 adev->multi_offload_enable = property_get_bool("vendor.audio.offload.multiple.enabled", false);
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011324 pthread_mutex_unlock(&adev_init_lock);
11325
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011326 if (adev->adm_init)
11327 adev->adm_data = adev->adm_init();
11328
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053011329 qahwi_init(*device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080011330 audio_extn_adsp_hdlr_init(adev->mixer);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011331
11332 audio_extn_snd_mon_init();
11333 pthread_mutex_lock(&adev->lock);
11334 audio_extn_snd_mon_register_listener(adev, adev_snd_mon_cb);
11335 adev->card_status = CARD_STATUS_ONLINE;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -050011336 adev->out_power_policy = POWER_POLICY_STATUS_ONLINE;
11337 adev->in_power_policy = POWER_POLICY_STATUS_ONLINE;
Haynes Mathew George01156f92018-04-13 15:29:54 -070011338 audio_extn_battery_properties_listener_init(adev_on_battery_status_changed);
11339 /*
11340 * if the battery state callback happens before charging can be queried,
11341 * it will be guarded with the adev->lock held in the cb function and so
11342 * the callback value will reflect the latest state
11343 */
11344 adev->is_charging = audio_extn_battery_properties_is_charging();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011345 audio_extn_sound_trigger_init(adev); /* dependent on snd_mon_init() */
Zhou Songc1088ea2018-06-12 00:17:29 +080011346 audio_extn_sound_trigger_update_battery_status(adev->is_charging);
justinweng20fb6d82019-02-21 18:49:00 -070011347 audio_extn_audiozoom_init();
Zhou Songc1088ea2018-06-12 00:17:29 +080011348 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053011349 /* Allocate memory for Device config params */
11350 adev->device_cfg_params = (struct audio_device_config_param*)
11351 calloc(platform_get_max_codec_backend(),
11352 sizeof(struct audio_device_config_param));
11353 if (adev->device_cfg_params == NULL)
11354 ALOGE("%s: Memory allocation failed for Device config params", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011355
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011356 /*
11357 * Check if new PSPD matrix mixer control is supported. If not
11358 * supported, then set flag so that old mixer ctrl is sent while
11359 * sending pspd coefficients on older kernel version. Query mixer
11360 * control for default pcm id and channel value one.
11361 */
11362 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
11363 "AudStr %d ChMixer Weight Ch %d", 0, 1);
11364
11365 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
11366 if (!ctl) {
11367 ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
11368 __func__, mixer_ctl_name);
11369 adev->use_old_pspd_mix_ctrl = true;
11370 }
11371
Jaideep Sharma0fa53812020-09-17 09:00:11 +053011372 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011373 return 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011374
11375adev_open_err:
11376 free_map(adev->patch_map);
11377 free_map(adev->io_streams_map);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080011378 free(adev->snd_dev_ref_cnt);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011379 pthread_mutex_destroy(&adev->lock);
11380 free(adev);
11381 adev = NULL;
11382 *device = NULL;
11383 pthread_mutex_unlock(&adev_init_lock);
11384 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011385}
11386
11387static struct hw_module_methods_t hal_module_methods = {
11388 .open = adev_open,
11389};
11390
11391struct audio_module HAL_MODULE_INFO_SYM = {
11392 .common = {
11393 .tag = HARDWARE_MODULE_TAG,
11394 .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
11395 .hal_api_version = HARDWARE_HAL_API_VERSION,
11396 .id = AUDIO_HARDWARE_MODULE_ID,
11397 .name = "QCOM Audio HAL",
Duy Truongfae19622013-11-24 02:17:54 -080011398 .author = "The Linux Foundation",
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011399 .methods = &hal_module_methods,
11400 },
11401};