blob: 9aaeb81a6ea79b6272e6d83539c417ea00f43d28 [file] [log] [blame]
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001/*
Ramu Gottipatifa5be522021-12-28 19:18:21 +05302 * Copyright (c) 2013-2022, The Linux Foundation. All rights reserved.
Apoorv Raghuvanshi9eaf94e2013-10-04 16:13:44 -07003 * Not a Contribution.
4 *
Shiv Maliyappanahalli8911f282014-01-10 15:56:19 -08005 * Copyright (C) 2013 The Android Open Source Project
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080018 *
19 * This file was modified by DTS, Inc. The portions of the
20 * code modified by DTS, Inc are copyrighted and
21 * licensed separately, as follows:
22 *
23 * (C) 2014 DTS, Inc.
24 *
25 * Licensed under the Apache License, Version 2.0 (the "License");
26 * you may not use this file except in compliance with the License.
27 * You may obtain a copy of the License at
28 *
29 * http://www.apache.org/licenses/LICENSE-2.0
30 *
31 * Unless required by applicable law or agreed to in writing, software
32 * distributed under the License is distributed on an "AS IS" BASIS,
33 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34 * See the License for the specific language governing permissions and
35 * limitations under the License.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080036 */
37
38#define LOG_TAG "audio_hw_primary"
Haynes Mathew George5beddd42016-06-27 18:33:40 -070039#define ATRACE_TAG (ATRACE_TAG_AUDIO|ATRACE_TAG_HAL)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080040/*#define LOG_NDEBUG 0*/
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070041/*#define VERY_VERY_VERBOSE_LOGGING*/
42#ifdef VERY_VERY_VERBOSE_LOGGING
43#define ALOGVV ALOGV
44#else
45#define ALOGVV(a...) do { } while(0)
46#endif
George Gao3018ede2019-10-23 13:23:00 -070047#include <limits.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080048#include <errno.h>
49#include <pthread.h>
50#include <stdint.h>
51#include <sys/time.h>
52#include <stdlib.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080053#include <math.h>
Eric Laurentc4aef752013-09-12 17:45:53 -070054#include <dlfcn.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070055#include <sys/resource.h>
56#include <sys/prctl.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080057
Aalique Grahame22e49102018-12-18 14:23:57 -080058#include <log/log.h>
Haynes Mathew George5beddd42016-06-27 18:33:40 -070059#include <cutils/trace.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080060#include <cutils/str_parms.h>
61#include <cutils/properties.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070062#include <cutils/atomic.h>
63#include <cutils/sched_policy.h>
Eric Laurentb23d5282013-05-14 15:27:20 -070064#include <hardware/audio_effect.h>
Haynes Mathew George484e8d22017-07-31 18:55:17 -070065#include <hardware/audio_alsaops.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070066#include <system/thread_defs.h>
Haynes Mathew George16081042017-05-31 17:16:49 -070067#include <tinyalsa/asoundlib.h>
Andy Hunga1f48fa2019-07-01 18:14:53 -070068#include <utils/Timers.h> // systemTime
Eric Laurentb23d5282013-05-14 15:27:20 -070069#include <audio_effects/effect_aec.h>
70#include <audio_effects/effect_ns.h>
Ashish Jainf1eaa582016-05-23 20:54:24 +053071#include <audio_utils/format.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080072#include "audio_hw.h"
Wei Wangf7ca6c92017-11-21 14:51:20 -080073#include "audio_perf.h"
Eric Laurentb23d5282013-05-14 15:27:20 -070074#include "platform_api.h"
75#include <platform.h>
Apoorv Raghuvanshi9eaf94e2013-10-04 16:13:44 -070076#include "audio_extn.h"
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080077#include "voice_extn.h"
Ashish Jaind5694242017-09-05 20:09:06 +053078#include "ip_hdlr_intf.h"
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080079
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070080#include "sound/compress_params.h"
Xiaojun Sang782e5b12020-06-29 21:13:06 +080081
82#ifdef AUDIO_GKI_ENABLED
83#include "sound/audio_compressed_formats.h"
84#endif
85
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -080086#include "sound/asound.h"
ApurupaPattapu2e084df2013-12-18 15:47:59 -080087
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053088#ifdef DYNAMIC_LOG_ENABLED
89#include <log_xml_parser.h>
90#define LOG_MASK HAL_MOD_FILE_AUDIO_HW
91#include <log_utils.h>
92#endif
93
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070094#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
Ashish Jain5106d362016-05-11 19:23:33 +053095/*DIRECT PCM has same buffer sizes as DEEP Buffer*/
96#define DIRECT_PCM_NUM_FRAGMENTS 2
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070097#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
Vikram Panduranga93f080e2017-06-07 18:16:14 -070098#define VOIP_PLAYBACK_VOLUME_MAX 0x2000
Arun Mirpuri5d170872019-03-26 13:21:31 -070099#define MMAP_PLAYBACK_VOLUME_MAX 0x2000
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +0530100#define PCM_PLAYBACK_VOLUME_MAX 0x2000
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +0530101#define DSD_VOLUME_MIN_DB (-110)
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -0700102#define INVALID_OUT_VOLUME -1
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700103#define AUDIO_IO_PORTS_MAX 32
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700104
Zhou Songbaddf9f2020-11-20 13:57:39 +0800105#define PLAYBACK_GAIN_MAX 1.0f
Aalique Grahame22e49102018-12-18 14:23:57 -0800106#define RECORD_GAIN_MIN 0.0f
107#define RECORD_GAIN_MAX 1.0f
108#define RECORD_VOLUME_CTL_MAX 0x2000
109
110/* treat as unsigned Q1.13 */
111#define APP_TYPE_GAIN_DEFAULT 0x2000
112
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700113#define PROXY_OPEN_RETRY_COUNT 100
114#define PROXY_OPEN_WAIT_TIME 20
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -0800115
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800116#define GET_USECASE_AUDIO_PLAYBACK_PRIMARY(db) \
117 (db)? USECASE_AUDIO_PLAYBACK_DEEP_BUFFER : \
118 USECASE_AUDIO_PLAYBACK_LOW_LATENCY
119#define GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(db) \
120 (db)? pcm_config_deep_buffer : pcm_config_low_latency
Haynes Mathew Georgebf143712013-12-03 13:02:53 -0800121
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700122#define ULL_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700123#define DEFAULT_VOIP_BUF_DURATION_MS 20
124#define DEFAULT_VOIP_BIT_DEPTH_BYTE sizeof(int16_t)
125#define DEFAULT_VOIP_SAMP_RATE 48000
126
127#define VOIP_IO_BUF_SIZE(SR, DURATION_MS, BIT_DEPTH) (SR)/1000 * DURATION_MS * BIT_DEPTH
128
129struct pcm_config default_pcm_config_voip_copp = {
130 .channels = 1,
131 .rate = DEFAULT_VOIP_SAMP_RATE, /* changed when the stream is opened */
132 .period_size = VOIP_IO_BUF_SIZE(DEFAULT_VOIP_SAMP_RATE, DEFAULT_VOIP_BUF_DURATION_MS, DEFAULT_VOIP_BIT_DEPTH_BYTE)/2,
133 .period_count = 2,
134 .format = PCM_FORMAT_S16_LE,
kunleiz95b597a2017-10-23 17:07:33 +0800135 .avail_min = VOIP_IO_BUF_SIZE(DEFAULT_VOIP_SAMP_RATE, DEFAULT_VOIP_BUF_DURATION_MS, DEFAULT_VOIP_BIT_DEPTH_BYTE)/2,
136 .stop_threshold = INT_MAX,
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700137};
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700138
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700139#define MIN_CHANNEL_COUNT 1
140#define DEFAULT_CHANNEL_COUNT 2
141#define MAX_HIFI_CHANNEL_COUNT 8
142
Aalique Grahame22e49102018-12-18 14:23:57 -0800143#ifndef MAX_TARGET_SPECIFIC_CHANNEL_CNT
144#define MAX_CHANNEL_COUNT 1
145#else
146#define MAX_CHANNEL_COUNT atoi(XSTR(MAX_TARGET_SPECIFIC_CHANNEL_CNT))
147#define XSTR(x) STR(x)
148#define STR(x) #x
149#endif
150
Avinash Chandrad7296d42021-08-04 15:07:47 +0530151#define IS_USB_HIFI (MAX_HIFI_CHANNEL_COUNT >= MAX_CHANNEL_COUNT) ? \
152 true : false
153
Dechen Chai22768452021-07-30 09:29:16 +0530154#ifdef LINUX_ENABLED
155static inline int64_t audio_utils_ns_from_timespec(const struct timespec *ts)
156{
157 return ts->tv_sec * 1000000000LL + ts->tv_nsec;
158}
159#endif
160
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -0700161static unsigned int configured_low_latency_capture_period_size =
162 LOW_LATENCY_CAPTURE_PERIOD_SIZE;
163
Haynes Mathew George16081042017-05-31 17:16:49 -0700164#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
165#define MMAP_PERIOD_COUNT_MIN 32
166#define MMAP_PERIOD_COUNT_MAX 512
167#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
168
Aalique Grahame22e49102018-12-18 14:23:57 -0800169/* This constant enables extended precision handling.
170 * TODO The flag is off until more testing is done.
171 */
172static const bool k_enable_extended_precision = false;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700173extern int AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
Aalique Grahame22e49102018-12-18 14:23:57 -0800174
Eric Laurentb23d5282013-05-14 15:27:20 -0700175struct pcm_config pcm_config_deep_buffer = {
176 .channels = 2,
177 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
178 .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
179 .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
180 .format = PCM_FORMAT_S16_LE,
181 .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
182 .stop_threshold = INT_MAX,
183 .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
184};
185
186struct pcm_config pcm_config_low_latency = {
187 .channels = 2,
188 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
189 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
190 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
191 .format = PCM_FORMAT_S16_LE,
192 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
193 .stop_threshold = INT_MAX,
194 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
195};
196
Vignesh Kulothungana6927272019-02-20 15:17:07 -0800197struct pcm_config pcm_config_haptics_audio = {
198 .channels = 1,
199 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
200 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
201 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
202 .format = PCM_FORMAT_S16_LE,
203 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
204 .stop_threshold = INT_MAX,
205 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
206};
207
208struct pcm_config pcm_config_haptics = {
209 .channels = 1,
210 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
211 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
212 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
213 .format = PCM_FORMAT_S16_LE,
214 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
215 .stop_threshold = INT_MAX,
216 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
217};
218
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700219static int af_period_multiplier = 4;
220struct pcm_config pcm_config_rt = {
221 .channels = 2,
222 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
223 .period_size = ULL_PERIOD_SIZE, //1 ms
224 .period_count = 512, //=> buffer size is 512ms
225 .format = PCM_FORMAT_S16_LE,
226 .start_threshold = ULL_PERIOD_SIZE*8, //8ms
227 .stop_threshold = INT_MAX,
228 .silence_threshold = 0,
229 .silence_size = 0,
230 .avail_min = ULL_PERIOD_SIZE, //1 ms
231};
232
Eric Laurentb23d5282013-05-14 15:27:20 -0700233struct pcm_config pcm_config_hdmi_multi = {
234 .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
235 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
236 .period_size = HDMI_MULTI_PERIOD_SIZE,
237 .period_count = HDMI_MULTI_PERIOD_COUNT,
238 .format = PCM_FORMAT_S16_LE,
239 .start_threshold = 0,
240 .stop_threshold = INT_MAX,
241 .avail_min = 0,
242};
243
Haynes Mathew George16081042017-05-31 17:16:49 -0700244struct pcm_config pcm_config_mmap_playback = {
245 .channels = 2,
246 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
247 .period_size = MMAP_PERIOD_SIZE,
248 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
249 .format = PCM_FORMAT_S16_LE,
250 .start_threshold = MMAP_PERIOD_SIZE*8,
251 .stop_threshold = INT32_MAX,
252 .silence_threshold = 0,
253 .silence_size = 0,
254 .avail_min = MMAP_PERIOD_SIZE, //1 ms
255};
256
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700257struct pcm_config pcm_config_hifi = {
258 .channels = DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
259 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
260 .period_size = HIFI_BUFFER_OUTPUT_PERIOD_SIZE, /* change #define */
261 .period_count = HIFI_BUFFER_OUTPUT_PERIOD_COUNT,
262 .format = PCM_FORMAT_S24_3LE,
263 .start_threshold = 0,
264 .stop_threshold = INT_MAX,
265 .avail_min = 0,
266};
267
Eric Laurentb23d5282013-05-14 15:27:20 -0700268struct pcm_config pcm_config_audio_capture = {
269 .channels = 2,
Eric Laurentb23d5282013-05-14 15:27:20 -0700270 .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
271 .format = PCM_FORMAT_S16_LE,
272};
273
Haynes Mathew George16081042017-05-31 17:16:49 -0700274struct pcm_config pcm_config_mmap_capture = {
275 .channels = 2,
276 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
277 .period_size = MMAP_PERIOD_SIZE,
278 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
279 .format = PCM_FORMAT_S16_LE,
280 .start_threshold = 0,
281 .stop_threshold = INT_MAX,
282 .silence_threshold = 0,
283 .silence_size = 0,
284 .avail_min = MMAP_PERIOD_SIZE, //1 ms
285};
286
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700287#define AFE_PROXY_CHANNEL_COUNT 2
288#define AFE_PROXY_SAMPLING_RATE 48000
289
290#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768
291#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
292
293struct pcm_config pcm_config_afe_proxy_playback = {
294 .channels = AFE_PROXY_CHANNEL_COUNT,
295 .rate = AFE_PROXY_SAMPLING_RATE,
296 .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
297 .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
298 .format = PCM_FORMAT_S16_LE,
299 .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
300 .stop_threshold = INT_MAX,
301 .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
302};
303
304#define AFE_PROXY_RECORD_PERIOD_SIZE 768
305#define AFE_PROXY_RECORD_PERIOD_COUNT 4
306
Aalique Grahame22e49102018-12-18 14:23:57 -0800307struct pcm_config pcm_config_audio_capture_rt = {
308 .channels = 2,
309 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
310 .period_size = ULL_PERIOD_SIZE,
311 .period_count = 512,
312 .format = PCM_FORMAT_S16_LE,
313 .start_threshold = 0,
314 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
315 .silence_threshold = 0,
316 .silence_size = 0,
317 .avail_min = ULL_PERIOD_SIZE, //1 ms
318};
319
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +0530320struct pcm_config pcm_config_audio_capture_rt_48KHz = {
321 .channels = 2,
322 .rate = 48000,
323 .period_size = 48,
324 .period_count = 512,
325 .format = PCM_FORMAT_S16_LE,
326 .start_threshold = 0,
327 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
328 .silence_threshold = 0,
329 .silence_size = 0,
330 .avail_min = 48, //1 ms
331};
332struct pcm_config pcm_config_audio_capture_rt_32KHz = {
333 .channels = 2,
334 .rate = 32000,
335 .period_size = 32,
336 .period_count = 512,
337 .format = PCM_FORMAT_S16_LE,
338 .start_threshold = 0,
339 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
340 .silence_threshold = 0,
341 .silence_size = 0,
342 .avail_min = 32, //1 ms
343};
344struct pcm_config pcm_config_audio_capture_rt_24KHz = {
345 .channels = 2,
346 .rate = 24000,
347 .period_size = 24,
348 .period_count = 512,
349 .format = PCM_FORMAT_S16_LE,
350 .start_threshold = 0,
351 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
352 .silence_threshold = 0,
353 .silence_size = 0,
354 .avail_min = 24, //1 ms
355};
356struct pcm_config pcm_config_audio_capture_rt_16KHz = {
357 .channels = 2,
358 .rate = 16000,
359 .period_size = 16,
360 .period_count = 512,
361 .format = PCM_FORMAT_S16_LE,
362 .start_threshold = 0,
363 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
364 .silence_threshold = 0,
365 .silence_size = 0,
366 .avail_min = 16, //1 ms
367};
368struct pcm_config pcm_config_audio_capture_rt_8KHz = {
369 .channels = 2,
370 .rate = 8000,
371 .period_size = 8,
372 .period_count = 512,
373 .format = PCM_FORMAT_S16_LE,
374 .start_threshold = 0,
375 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
376 .silence_threshold = 0,
377 .silence_size = 0,
378 .avail_min = 8, //1 ms
379};
380
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700381struct pcm_config pcm_config_afe_proxy_record = {
382 .channels = AFE_PROXY_CHANNEL_COUNT,
383 .rate = AFE_PROXY_SAMPLING_RATE,
384 .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
385 .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
386 .format = PCM_FORMAT_S16_LE,
387 .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
388 .stop_threshold = INT_MAX,
389 .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
390};
391
Ashish Jainf1eaa582016-05-23 20:54:24 +0530392#define AUDIO_MAX_PCM_FORMATS 7
393
394const uint32_t format_to_bitwidth_table[AUDIO_MAX_PCM_FORMATS] = {
395 [AUDIO_FORMAT_DEFAULT] = 0,
396 [AUDIO_FORMAT_PCM_16_BIT] = sizeof(uint16_t),
397 [AUDIO_FORMAT_PCM_8_BIT] = sizeof(uint8_t),
398 [AUDIO_FORMAT_PCM_32_BIT] = sizeof(uint32_t),
399 [AUDIO_FORMAT_PCM_8_24_BIT] = sizeof(uint32_t),
400 [AUDIO_FORMAT_PCM_FLOAT] = sizeof(float),
401 [AUDIO_FORMAT_PCM_24_BIT_PACKED] = sizeof(uint8_t) * 3,
402};
403
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800404const char * const use_case_table[AUDIO_USECASE_MAX] = {
Eric Laurentb23d5282013-05-14 15:27:20 -0700405 [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
406 [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
Vignesh Kulothungana6927272019-02-20 15:17:07 -0800407 [USECASE_AUDIO_PLAYBACK_WITH_HAPTICS] = "audio-with-haptics-playback",
Meng Wang51d8c2a2020-04-27 15:23:21 +0800408 [USECASE_AUDIO_PLAYBACK_HAPTICS] = "haptics-playback",
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -0700409 [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
410 [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
Shruthi Krishnaace10852013-10-25 14:32:12 -0700411 [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
vivek mehta446c3962015-09-14 10:57:35 -0700412 //Enabled for Direct_PCM
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700413 [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
414 [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
415 [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
416 [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
417 [USECASE_AUDIO_PLAYBACK_OFFLOAD6] = "compress-offload-playback6",
418 [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
419 [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
420 [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
Haynes Mathew George16081042017-05-31 17:16:49 -0700421 [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
422 [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback",
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700423 [USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
Aalique Grahame22e49102018-12-18 14:23:57 -0800424 [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
vivek mehta0ea887a2015-08-26 14:01:20 -0700425
Eric Laurentb23d5282013-05-14 15:27:20 -0700426 [USECASE_AUDIO_RECORD] = "audio-record",
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530427 [USECASE_AUDIO_RECORD2] = "audio-record2",
428 [USECASE_AUDIO_RECORD3] = "audio-record3",
Mingming Yine62d7842013-10-25 16:26:03 -0700429 [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
Dhananjay Kumaree4d2002016-10-25 18:02:58 +0530430 [USECASE_AUDIO_RECORD_COMPRESS2] = "audio-record-compress2",
431 [USECASE_AUDIO_RECORD_COMPRESS3] = "audio-record-compress3",
432 [USECASE_AUDIO_RECORD_COMPRESS4] = "audio-record-compress4",
Dhananjay Kumar376e38b2017-09-28 22:26:23 +0530433 [USECASE_AUDIO_RECORD_COMPRESS5] = "audio-record-compress5",
434 [USECASE_AUDIO_RECORD_COMPRESS6] = "audio-record-compress6",
Eric Laurentb23d5282013-05-14 15:27:20 -0700435 [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
Preetam Singh Ranawatde84f1a2013-11-01 14:58:16 -0700436 [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700437 [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700438 [USECASE_AUDIO_RECORD_HIFI] = "hifi-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700439
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800440 [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800441 [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
Derek Chenf7092792017-05-23 12:23:53 -0400442 [USECASE_AUDIO_HFP_SCO_DOWNLINK] = "hfp-sco-downlink",
443 [USECASE_AUDIO_HFP_SCO_WB_DOWNLINK] = "hfp-sco-wb-downlink",
Mingming Yin3ee55c62014-08-04 14:23:35 -0700444
Derek Chenf7092792017-05-23 12:23:53 -0400445 [USECASE_VOICE_CALL] = "voice-call",
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700446 [USECASE_VOICE2_CALL] = "voice2-call",
447 [USECASE_VOLTE_CALL] = "volte-call",
448 [USECASE_QCHAT_CALL] = "qchat-call",
Vicky Sehrawat7e4fc152014-02-12 17:58:59 -0800449 [USECASE_VOWLAN_CALL] = "vowlan-call",
Vidyakumar Athota0e109352015-02-12 17:38:22 -0800450 [USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
451 [USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
Narsinga Rao Chella05573b72013-11-15 15:21:40 -0800452 [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
Shiv Maliyappanahallida107642013-10-17 11:16:13 -0700453 [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
454 [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
455 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
Helen Zenge56b4852013-12-03 16:54:40 -0800456 [USECASE_INCALL_REC_UPLINK_COMPRESS] = "incall-rec-uplink-compress",
457 [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = "incall-rec-downlink-compress",
458 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = "incall-rec-uplink-and-downlink-compress",
459
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700460 [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
461 [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -0700462 [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
463 [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700464
465 [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
466 [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
Zhou Song62ea0282020-03-22 19:53:01 +0800467 [USECASE_AUDIO_RECORD_AFE_PROXY2] = "afe-proxy-record2",
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +0530468 [USECASE_AUDIO_PLAYBACK_SILENCE] = "silence-playback",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700469
Siddartha Shaik31b530e2017-05-19 15:26:33 +0530470 /* Transcode loopback cases */
Surendar Karka93cd25a2018-08-28 14:21:37 +0530471 [USECASE_AUDIO_TRANSCODE_LOOPBACK_RX] = "audio-transcode-loopback-rx",
472 [USECASE_AUDIO_TRANSCODE_LOOPBACK_TX] = "audio-transcode-loopback-tx",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700473
474 [USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
475 [USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530476 [USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY] = "audio-record-voip-low-latency",
Varun Balaraje49253e2017-07-06 19:48:56 +0530477 /* For Interactive Audio Streams */
478 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] = "audio-interactive-stream1",
479 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] = "audio-interactive-stream2",
480 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] = "audio-interactive-stream3",
481 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] = "audio-interactive-stream4",
482 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] = "audio-interactive-stream5",
483 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] = "audio-interactive-stream6",
484 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
485 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
Garmond Leunge2433c32017-09-28 21:51:22 -0700486
Aniket Kumar Lata7fd86e12018-02-20 19:26:10 -0800487 [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",
488
Derek Chenf6318be2017-06-12 17:16:24 -0400489 [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback",
490
491 [USECASE_AUDIO_PLAYBACK_MEDIA] = "media-playback",
492 [USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION] = "sys-notification-playback",
493 [USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE] = "nav-guidance-playback",
494 [USECASE_AUDIO_PLAYBACK_PHONE] = "phone-playback",
Susan Wang117cf6f2022-04-06 20:11:46 -0400495 [USECASE_AUDIO_PLAYBACK_ALERTS] = "alerts-playback",
Derek Chen1bcdc6b2020-02-06 22:44:53 -0800496 [USECASE_AUDIO_PLAYBACK_FRONT_PASSENGER] = "front-passenger-playback",
Derek Chendf05eea2019-08-01 13:57:49 -0700497 [USECASE_AUDIO_PLAYBACK_REAR_SEAT] = "rear-seat-playback",
Rahul Sharma99770982019-03-06 17:05:26 +0530498 [USECASE_AUDIO_FM_TUNER_EXT] = "fm-tuner-ext",
Derek Chena30a5f42019-12-03 11:17:09 -0500499 [USECASE_ICC_CALL] = "icc-call",
Huicheng Liu1404ba12020-09-11 01:03:25 -0400500
501 [USECASE_AUDIO_RECORD_BUS] = "audio-record",
502 [USECASE_AUDIO_RECORD_BUS_FRONT_PASSENGER] = "front-passenger-record",
503 [USECASE_AUDIO_RECORD_BUS_REAR_SEAT] = "rear-seat-record",
Fei Tongaffdf732020-02-20 20:39:05 +0800504 [USECASE_AUDIO_PLAYBACK_SYNTHESIZER] = "synth-loopback",
Susan Wange3959562021-03-11 11:50:26 -0500505 [USECASE_AUDIO_RECORD_ECHO_REF_EXT] = "echo-reference-external",
Eric Laurentb23d5282013-05-14 15:27:20 -0700506};
507
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700508static const audio_usecase_t offload_usecases[] = {
509 USECASE_AUDIO_PLAYBACK_OFFLOAD,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700510 USECASE_AUDIO_PLAYBACK_OFFLOAD2,
511 USECASE_AUDIO_PLAYBACK_OFFLOAD3,
512 USECASE_AUDIO_PLAYBACK_OFFLOAD4,
513 USECASE_AUDIO_PLAYBACK_OFFLOAD5,
514 USECASE_AUDIO_PLAYBACK_OFFLOAD6,
515 USECASE_AUDIO_PLAYBACK_OFFLOAD7,
516 USECASE_AUDIO_PLAYBACK_OFFLOAD8,
517 USECASE_AUDIO_PLAYBACK_OFFLOAD9,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700518};
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800519
Varun Balaraje49253e2017-07-06 19:48:56 +0530520static const audio_usecase_t interactive_usecases[] = {
521 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
522 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
523 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
524 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
525 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
526 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
527 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
528 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
529};
530
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800531#define STRING_TO_ENUM(string) { #string, string }
532
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800533struct string_to_enum {
534 const char *name;
535 uint32_t value;
536};
537
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700538static const struct string_to_enum channels_name_to_enum_table[] = {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800539 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
Mingming Yin3a941d42016-02-17 18:08:05 -0800540 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
541 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
542 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -0700543 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
Mingming Yin3a941d42016-02-17 18:08:05 -0800544 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
545 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800546 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700547 STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
548 STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
549 STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
550 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
551 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
552 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
553 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
554 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
555 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
556 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
557 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800558};
559
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700560static const struct string_to_enum formats_name_to_enum_table[] = {
561 STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
562 STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
563 STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700564 STRING_TO_ENUM(AUDIO_FORMAT_AC3),
565 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
566 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
Ben Romberger1aaaf862017-04-06 17:49:46 -0700567 STRING_TO_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
Mingming Yin3a941d42016-02-17 18:08:05 -0800568 STRING_TO_ENUM(AUDIO_FORMAT_DTS),
569 STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
Naresh Tanniru928f0862017-04-07 16:44:23 -0700570 STRING_TO_ENUM(AUDIO_FORMAT_IEC61937)
Mingming Yin3a941d42016-02-17 18:08:05 -0800571};
572
573//list of all supported sample rates by HDMI specification.
574static const int out_hdmi_sample_rates[] = {
575 32000, 44100, 48000, 88200, 96000, 176400, 192000,
576};
577
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700578static const struct string_to_enum out_sample_rates_name_to_enum_table[] = {
Mingming Yin3a941d42016-02-17 18:08:05 -0800579 STRING_TO_ENUM(32000),
580 STRING_TO_ENUM(44100),
581 STRING_TO_ENUM(48000),
582 STRING_TO_ENUM(88200),
583 STRING_TO_ENUM(96000),
584 STRING_TO_ENUM(176400),
585 STRING_TO_ENUM(192000),
Mingshu pange8aedf12019-10-25 15:38:27 +0800586 STRING_TO_ENUM(352800),
587 STRING_TO_ENUM(384000),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700588};
589
Carter Hsu2e429db2019-05-14 18:50:52 +0800590struct in_effect_list {
591 struct listnode list;
592 effect_handle_t handle;
593};
594
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530595static const audio_usecase_t record_usecases[] = {
596 USECASE_AUDIO_RECORD,
597 USECASE_AUDIO_RECORD2,
598 USECASE_AUDIO_RECORD3,
599};
600
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -0700601static struct audio_device *adev = NULL;
Ben Romberger02ab1192018-05-24 12:10:08 -0700602static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
Kiran Kandi910e1862013-10-29 13:29:42 -0700603static unsigned int audio_device_ref_count;
vivek mehtab72d08d2016-04-29 03:16:47 -0700604//cache last MBDRC cal step level
605static int last_known_cal_step = -1 ;
Kiran Kandi910e1862013-10-29 13:29:42 -0700606
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +0530607static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
Arun Mirpuri5d170872019-03-26 13:21:31 -0700608static int out_set_mmap_volume(struct audio_stream_out *stream, float left, float right);
Zhou Song2b8f28f2017-09-11 10:51:38 +0800609static int out_set_voip_volume(struct audio_stream_out *stream, float left, float right);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +0530610static int out_set_pcm_volume(struct audio_stream_out *stream, float left, float right);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +0530611#ifdef SOFT_VOLUME
612static int out_set_soft_volume_params(struct audio_stream_out *stream);
613#endif
Derek Chen6f293672019-04-01 01:40:24 -0700614static void adev_snd_mon_cb(void *cookie, struct str_parms *parms);
615static void in_snd_mon_cb(void * stream, struct str_parms * parms);
616static void out_snd_mon_cb(void * stream, struct str_parms * parms);
617
Zhou Song331c8e52019-08-26 14:16:12 +0800618static int configure_btsco_sample_rate(snd_device_t snd_device);
619
Vatsal Buchac09ae062018-11-14 13:25:08 +0530620#ifdef AUDIO_FEATURE_ENABLED_GCOV
621extern void __gcov_flush();
622static void enable_gcov()
623{
624 __gcov_flush();
625}
626#else
627static void enable_gcov()
628{
629}
630#endif
631
justinweng20fb6d82019-02-21 18:49:00 -0700632static int in_set_microphone_direction(const struct audio_stream_in *stream,
633 audio_microphone_direction_t dir);
634static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom);
635
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530636static bool is_pcm_record_usecase(audio_usecase_t uc_id)
637{
638 unsigned int record_uc_index;
639 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
640
641 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
642 if (uc_id == record_usecases[record_uc_index])
643 return true;
644 }
645 return false;
646}
647
648static audio_usecase_t get_record_usecase(struct audio_device *adev)
649{
650 audio_usecase_t ret_uc = USECASE_INVALID;
651 unsigned int record_uc_index;
652 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
653
654 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
655 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
656 if (!(adev->pcm_record_uc_state & (0x1 << record_uc_index))) {
657 adev->pcm_record_uc_state |= 0x1 << record_uc_index;
658 ret_uc = record_usecases[record_uc_index];
659 break;
660 }
661 }
662
663 ALOGV("%s: pcm record usecase is %d", __func__, ret_uc);
664 return ret_uc;
665}
666
667static void free_record_usecase(struct audio_device *adev,
668 audio_usecase_t uc_id)
669{
670 unsigned int record_uc_index;
671 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
672
673 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
674 if (record_usecases[record_uc_index] == uc_id) {
675 adev->pcm_record_uc_state &= ~(0x1 << record_uc_index);
676 break;
677 }
678 }
679 ALOGV("%s: free pcm record usecase %d", __func__, uc_id);
680}
681
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700682static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id,
683 int flags __unused)
684{
685 int dir = 0;
686 switch (uc_id) {
687 case USECASE_AUDIO_RECORD_LOW_LATENCY:
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530688 case USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY:
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700689 dir = 1;
690 case USECASE_AUDIO_PLAYBACK_ULL:
691 break;
692 default:
693 return false;
694 }
695
696 int dev_id = platform_get_pcm_device_id(uc_id, dir == 0 ?
697 PCM_PLAYBACK : PCM_CAPTURE);
698 if (adev->adm_is_noirq_avail)
699 return adev->adm_is_noirq_avail(adev->adm_data,
700 adev->snd_card, dev_id, dir);
701 return false;
702}
703
704static void register_out_stream(struct stream_out *out)
705{
706 struct audio_device *adev = out->dev;
707 if (is_offload_usecase(out->usecase) ||
708 !adev->adm_register_output_stream)
709 return;
710
711 // register stream first for backward compatibility
712 adev->adm_register_output_stream(adev->adm_data,
713 out->handle,
714 out->flags);
715
716 if (!adev->adm_set_config)
717 return;
718
Kogara Naveen Kumar6db5fb02022-05-07 00:22:50 +0530719 if (out->realtime || (out->flags & AUDIO_OUTPUT_FLAG_SYS_NOTIFICATION))
720 adev->adm_set_config(adev->adm_data,
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700721 out->handle,
722 out->pcm, &out->config);
723}
724
725static void register_in_stream(struct stream_in *in)
726{
727 struct audio_device *adev = in->dev;
728 if (!adev->adm_register_input_stream)
729 return;
730
731 adev->adm_register_input_stream(adev->adm_data,
732 in->capture_handle,
733 in->flags);
734
735 if (!adev->adm_set_config)
736 return;
737
738 if (in->realtime)
739 adev->adm_set_config(adev->adm_data,
740 in->capture_handle,
741 in->pcm,
742 &in->config);
743}
744
745static void request_out_focus(struct stream_out *out, long ns)
746{
747 struct audio_device *adev = out->dev;
748
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700749 if (adev->adm_request_focus_v2)
750 adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
751 else if (adev->adm_request_focus)
752 adev->adm_request_focus(adev->adm_data, out->handle);
753}
754
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700755static int request_in_focus(struct stream_in *in, long ns)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700756{
757 struct audio_device *adev = in->dev;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700758 int ret = 0;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700759
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700760 if (adev->adm_request_focus_v2_1)
761 ret = adev->adm_request_focus_v2_1(adev->adm_data, in->capture_handle, ns);
762 else if (adev->adm_request_focus_v2)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700763 adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
764 else if (adev->adm_request_focus)
765 adev->adm_request_focus(adev->adm_data, in->capture_handle);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700766
767 return ret;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700768}
769
770static void release_out_focus(struct stream_out *out)
771{
772 struct audio_device *adev = out->dev;
773
774 if (adev->adm_abandon_focus)
775 adev->adm_abandon_focus(adev->adm_data, out->handle);
776}
777
778static void release_in_focus(struct stream_in *in)
779{
780 struct audio_device *adev = in->dev;
781 if (adev->adm_abandon_focus)
782 adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
783}
784
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530785static int parse_snd_card_status(struct str_parms *parms, int *card,
786 card_status_t *status)
787{
788 char value[32]={0};
789 char state[32]={0};
790
791 int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
792 if (ret < 0)
793 return -1;
794
795 // sscanf should be okay as value is of max length 32.
796 // same as sizeof state.
797 if (sscanf(value, "%d,%s", card, state) < 2)
798 return -1;
799
800 *status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
801 CARD_STATUS_OFFLINE;
802 return 0;
803}
804
Avinash Chandrad7296d42021-08-04 15:07:47 +0530805bool is_combo_audio_input_device(struct listnode *devices){
806
Sandhya Mutha Naga Venkata153d95e2022-07-12 14:54:43 +0530807 if ((devices == NULL) || (!list_empty(devices)))
Avinash Chandrad7296d42021-08-04 15:07:47 +0530808 return false;
809
810 if(compare_device_type(devices, AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_SPEAKER_MIC2))
811 return true;
812 else
813 return false;
814}
815
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700816static inline void adjust_frames_for_device_delay(struct stream_out *out,
817 uint32_t *dsp_frames) {
818 // Adjustment accounts for A2dp encoder latency with offload usecases
819 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800820 if (is_a2dp_out_device_type(&out->device_list)) {
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700821 unsigned long offset =
822 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
823 *dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
824 }
825}
826
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700827static inline bool free_entry(void *key __unused,
828 void *value, void *context __unused)
829{
830 free(value);
831 return true;
832}
833
834static inline void free_map(Hashmap *map)
835{
836 if (map) {
837 hashmapForEach(map, free_entry, (void *) NULL);
838 hashmapFree(map);
839 }
840}
841
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800842static inline void patch_map_remove_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700843 audio_patch_handle_t patch_handle)
844{
845 if (patch_handle == AUDIO_PATCH_HANDLE_NONE)
846 return;
847
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700848 struct audio_patch_info *p_info =
849 hashmapGet(adev->patch_map, (void *) (intptr_t) patch_handle);
850 if (p_info) {
851 ALOGV("%s: Remove patch %d", __func__, patch_handle);
852 hashmapRemove(adev->patch_map, (void *) (intptr_t) patch_handle);
853 free(p_info->patch);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700854 free(p_info);
855 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700856}
857
858static inline int io_streams_map_insert(struct audio_device *adev,
859 struct audio_stream *stream,
860 audio_io_handle_t handle,
861 audio_patch_handle_t patch_handle)
862{
863 struct audio_stream_info *s_info =
864 (struct audio_stream_info *) calloc(1, sizeof(struct audio_stream_info));
865
866 if (s_info == NULL) {
867 ALOGE("%s: Could not allocate stream info", __func__);
868 return -ENOMEM;
869 }
870 s_info->stream = stream;
871 s_info->patch_handle = patch_handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700872
873 pthread_mutex_lock(&adev->lock);
874 struct audio_stream_info *stream_info =
875 hashmapPut(adev->io_streams_map, (void *) (intptr_t) handle, (void *) s_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700876 if (stream_info != NULL)
877 free(stream_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800878 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700879 ALOGV("%s: Added stream in io_streams_map with handle %d", __func__, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700880 return 0;
881}
882
883static inline void io_streams_map_remove(struct audio_device *adev,
884 audio_io_handle_t handle)
885{
886 pthread_mutex_lock(&adev->lock);
887 struct audio_stream_info *s_info =
888 hashmapRemove(adev->io_streams_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700889 if (s_info == NULL)
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800890 goto done;
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700891 ALOGV("%s: Removed stream with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800892 patch_map_remove_l(adev, s_info->patch_handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700893 free(s_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800894done:
895 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700896 return;
897}
898
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800899static struct audio_patch_info* fetch_patch_info_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700900 audio_patch_handle_t handle)
901{
902 struct audio_patch_info *p_info = NULL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700903 p_info = (struct audio_patch_info *)
904 hashmapGet(adev->patch_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700905 return p_info;
906}
907
vivek mehtaa76401a2015-04-24 14:12:15 -0700908__attribute__ ((visibility ("default")))
909bool audio_hw_send_gain_dep_calibration(int level) {
910 bool ret_val = false;
vivek mehtab72d08d2016-04-29 03:16:47 -0700911 ALOGV("%s: called ...", __func__);
vivek mehtaa76401a2015-04-24 14:12:15 -0700912
913 pthread_mutex_lock(&adev_init_lock);
914
915 if (adev != NULL && adev->platform != NULL) {
916 pthread_mutex_lock(&adev->lock);
917 ret_val = platform_send_gain_dep_cal(adev->platform, level);
vivek mehtab72d08d2016-04-29 03:16:47 -0700918
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +0530919 // cache level info for any of the use case which
920 // was not started.
921 last_known_cal_step = level;;
vivek mehtab72d08d2016-04-29 03:16:47 -0700922
vivek mehtaa76401a2015-04-24 14:12:15 -0700923 pthread_mutex_unlock(&adev->lock);
924 } else {
925 ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
926 }
927
928 pthread_mutex_unlock(&adev_init_lock);
929
930 return ret_val;
931}
932
Ashish Jain5106d362016-05-11 19:23:33 +0530933static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless)
934{
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800935 bool gapless_enabled = false;
936 const char *mixer_ctl_name = "Compress Gapless Playback";
937 struct mixer_ctl *ctl;
938
939 ALOGV("%s:", __func__);
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700940 gapless_enabled = property_get_bool("vendor.audio.offload.gapless.enabled", false);
Ashish Jain5106d362016-05-11 19:23:33 +0530941
942 /*Disable gapless if its AV playback*/
943 gapless_enabled = gapless_enabled && enable_gapless;
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800944
945 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
946 if (!ctl) {
947 ALOGE("%s: Could not get ctl for mixer cmd - %s",
948 __func__, mixer_ctl_name);
949 return -EINVAL;
950 }
951
952 if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) {
953 ALOGE("%s: Could not set gapless mode %d",
954 __func__, gapless_enabled);
955 return -EINVAL;
956 }
957 return 0;
958}
Haynes Mathew George5191a852013-09-11 14:19:36 -0700959
Aniket Kumar Lataf56b6402016-10-27 12:03:18 -0700960__attribute__ ((visibility ("default")))
961int audio_hw_get_gain_level_mapping(struct amp_db_and_gain_table *mapping_tbl,
962 int table_size) {
963 int ret_val = 0;
964 ALOGV("%s: enter ... ", __func__);
965
966 pthread_mutex_lock(&adev_init_lock);
967 if (adev == NULL) {
968 ALOGW("%s: adev is NULL .... ", __func__);
969 goto done;
970 }
971
972 pthread_mutex_lock(&adev->lock);
973 ret_val = platform_get_gain_level_mapping(mapping_tbl, table_size);
974 pthread_mutex_unlock(&adev->lock);
975done:
976 pthread_mutex_unlock(&adev_init_lock);
977 ALOGV("%s: exit ... ", __func__);
978 return ret_val;
979}
980
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800981bool audio_hw_send_qdsp_parameter(int stream_type, float vol, bool active)
Aalique Grahame22e49102018-12-18 14:23:57 -0800982{
983 bool ret = false;
984 ALOGV("%s: enter ...", __func__);
985
986 pthread_mutex_lock(&adev_init_lock);
987
988 if (adev != NULL && adev->platform != NULL) {
989 pthread_mutex_lock(&adev->lock);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800990 ret = audio_extn_qdsp_set_state(adev, stream_type, vol, active);
Aalique Grahame22e49102018-12-18 14:23:57 -0800991 pthread_mutex_unlock(&adev->lock);
992 }
993
994 pthread_mutex_unlock(&adev_init_lock);
995
996 ALOGV("%s: exit with ret %d", __func__, ret);
997 return ret;
998}
Aalique Grahame22e49102018-12-18 14:23:57 -0800999
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001000static bool is_supported_format(audio_format_t format)
1001{
Eric Laurent86e17132013-09-12 17:49:30 -07001002 if (format == AUDIO_FORMAT_MP3 ||
Satish Babu Patakokila0c313922016-12-08 12:07:08 +05301003 format == AUDIO_FORMAT_MP2 ||
Ashish Jainf9b78162014-08-25 20:36:25 +05301004 format == AUDIO_FORMAT_AAC_LC ||
1005 format == AUDIO_FORMAT_AAC_HE_V1 ||
1006 format == AUDIO_FORMAT_AAC_HE_V2 ||
Manish Dewangana6fc5442015-08-24 20:30:31 +05301007 format == AUDIO_FORMAT_AAC_ADTS_LC ||
1008 format == AUDIO_FORMAT_AAC_ADTS_HE_V1 ||
1009 format == AUDIO_FORMAT_AAC_ADTS_HE_V2 ||
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05301010 format == AUDIO_FORMAT_AAC_LATM_LC ||
1011 format == AUDIO_FORMAT_AAC_LATM_HE_V1 ||
1012 format == AUDIO_FORMAT_AAC_LATM_HE_V2 ||
Ashish Jain5106d362016-05-11 19:23:33 +05301013 format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
1014 format == AUDIO_FORMAT_PCM_8_24_BIT ||
Ashish Jainf1eaa582016-05-23 20:54:24 +05301015 format == AUDIO_FORMAT_PCM_FLOAT ||
1016 format == AUDIO_FORMAT_PCM_32_BIT ||
vivek mehta0ea887a2015-08-26 14:01:20 -07001017 format == AUDIO_FORMAT_PCM_16_BIT ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05301018 format == AUDIO_FORMAT_AC3 ||
1019 format == AUDIO_FORMAT_E_AC3 ||
Ben Romberger1aaaf862017-04-06 17:49:46 -07001020 format == AUDIO_FORMAT_DOLBY_TRUEHD ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05301021 format == AUDIO_FORMAT_DTS ||
1022 format == AUDIO_FORMAT_DTS_HD ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08001023 format == AUDIO_FORMAT_FLAC ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05301024 format == AUDIO_FORMAT_ALAC ||
1025 format == AUDIO_FORMAT_APE ||
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05301026 format == AUDIO_FORMAT_DSD ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05301027 format == AUDIO_FORMAT_VORBIS ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08001028 format == AUDIO_FORMAT_WMA ||
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05301029 format == AUDIO_FORMAT_WMA_PRO ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07001030 format == AUDIO_FORMAT_APTX ||
1031 format == AUDIO_FORMAT_IEC61937)
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08001032 return true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001033
1034 return false;
1035}
1036
Kunlei Zhang67cc7072020-12-18 17:16:49 +08001037static bool is_supported_conc_usecase_for_power_mode_call(struct audio_device *adev)
1038{
1039 struct listnode *node;
1040 struct audio_usecase *usecase;
1041
1042 list_for_each(node, &adev->usecase_list) {
1043 usecase = node_to_item(node, struct audio_usecase, list);
1044 if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1045 ALOGD("%s: FM usecase is active, not setting power mode", __func__);
1046 return false;
1047 }
1048 }
1049
1050 return true;
1051}
Haynes Mathew George5beddd42016-06-27 18:33:40 -07001052static inline bool is_mmap_usecase(audio_usecase_t uc_id)
1053{
1054 return (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY) ||
Zhou Song62ea0282020-03-22 19:53:01 +08001055 (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY2) ||
Haynes Mathew George5beddd42016-06-27 18:33:40 -07001056 (uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
1057}
1058
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07001059static inline bool is_valid_volume(float left, float right)
1060{
1061 return ((left >= 0.0f && right >= 0.0f) ? true : false);
1062}
1063
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301064static void enable_asrc_mode(struct audio_device *adev)
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301065{
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301066 ALOGV("%s", __func__);
1067 audio_route_apply_and_update_path(adev->audio_route,
1068 "asrc-mode");
1069 adev->asrc_mode_enabled = true;
1070}
1071
1072static void disable_asrc_mode(struct audio_device *adev)
1073{
1074 ALOGV("%s", __func__);
1075 audio_route_reset_and_update_path(adev->audio_route,
1076 "asrc-mode");
1077 adev->asrc_mode_enabled = false;
1078}
1079
Saurav Kumarc1411662020-10-14 10:50:45 +05301080static void check_and_configure_headphone(struct audio_device *adev,
1081 struct audio_usecase *uc_info,
1082 snd_device_t snd_device)
1083{
1084 struct listnode *node;
1085 struct audio_usecase *usecase;
1086 int new_backend_idx, usecase_backend_idx;
1087 bool spkr_hph_single_be_native_concurrency;
1088
1089 new_backend_idx = platform_get_backend_index(snd_device);
1090 spkr_hph_single_be_native_concurrency = platform_get_spkr_hph_single_be_native_concurrency_flag();
Zhou Songd4b18c42021-01-14 15:15:29 +08001091 if ((spkr_hph_single_be_native_concurrency && (new_backend_idx == DEFAULT_CODEC_BACKEND)) ||
1092 uc_info->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
Saurav Kumarc1411662020-10-14 10:50:45 +05301093 list_for_each(node, &adev->usecase_list) {
1094 usecase = node_to_item(node, struct audio_usecase, list);
1095 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info)) {
1096 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1097 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1098 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1099 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1100 disable_audio_route(adev, usecase);
1101 disable_snd_device(adev, usecase->out_snd_device);
1102 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
Saurav Kumar70902382020-10-28 11:16:04 +05301103 platform_check_and_set_codec_backend_cfg(adev, usecase,
1104 usecase->out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05301105 enable_snd_device(adev, usecase->out_snd_device);
Zhou Songd4b18c42021-01-14 15:15:29 +08001106 enable_audio_route(adev, usecase);
Saurav Kumarc1411662020-10-14 10:50:45 +05301107 }
1108 }
Revathi Uddaraju2c0eac02021-07-27 02:06:42 -07001109 else if ((usecase->type != PCM_CAPTURE) && (usecase == uc_info)) {
1110 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1111 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1112 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1113 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1114 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
1115 platform_check_and_set_codec_backend_cfg(adev, usecase,
1116 usecase->out_snd_device);
1117 }
1118 }
Saurav Kumarc1411662020-10-14 10:50:45 +05301119 }
1120 }
1121}
1122
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301123/*
1124 * - Enable ASRC mode for incoming mix path use case(Headphone backend)if Headphone
1125 * 44.1 or Native DSD backends are enabled for any of current use case.
1126 * e.g. 48-> + (Naitve DSD or Headphone 44.1)
1127 * - Disable current mix path use case(Headphone backend) and re-enable it with
1128 * ASRC mode for incoming Headphone 44.1 or Native DSD use case.
1129 * e.g. Naitve DSD or Headphone 44.1 -> + 48
1130 */
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301131static void check_and_set_asrc_mode(struct audio_device *adev,
1132 struct audio_usecase *uc_info,
1133 snd_device_t snd_device)
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301134{
1135 ALOGV("%s snd device %d", __func__, snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301136 int i, num_new_devices = 0;
1137 snd_device_t split_new_snd_devices[SND_DEVICE_OUT_END];
1138 /*
1139 *Split snd device for new combo use case
1140 *e.g. Headphopne 44.1-> + Ringtone (Headphone + Speaker)
1141 */
1142 if (platform_split_snd_device(adev->platform,
1143 snd_device,
1144 &num_new_devices,
1145 split_new_snd_devices) == 0) {
1146 for (i = 0; i < num_new_devices; i++)
1147 check_and_set_asrc_mode(adev, uc_info, split_new_snd_devices[i]);
1148 } else {
1149 int new_backend_idx = platform_get_backend_index(snd_device);
1150 if (((new_backend_idx == HEADPHONE_BACKEND) ||
1151 (new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1152 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1153 !adev->asrc_mode_enabled) {
1154 struct listnode *node = NULL;
1155 struct audio_usecase *uc = NULL;
1156 struct stream_out *curr_out = NULL;
1157 int usecase_backend_idx = DEFAULT_CODEC_BACKEND;
1158 int i, num_devices, ret = 0;
1159 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301160
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301161 list_for_each(node, &adev->usecase_list) {
1162 uc = node_to_item(node, struct audio_usecase, list);
1163 curr_out = (struct stream_out*) uc->stream.out;
1164 if (curr_out && PCM_PLAYBACK == uc->type && uc != uc_info) {
1165 /*
1166 *Split snd device for existing combo use case
1167 *e.g. Ringtone (Headphone + Speaker) + Headphopne 44.1
1168 */
1169 ret = platform_split_snd_device(adev->platform,
1170 uc->out_snd_device,
1171 &num_devices,
1172 split_snd_devices);
1173 if (ret < 0 || num_devices == 0) {
1174 ALOGV("%s: Unable to split uc->out_snd_device: %d",__func__, uc->out_snd_device);
1175 split_snd_devices[0] = uc->out_snd_device;
1176 num_devices = 1;
Garmond Leung50058f62017-02-08 09:49:30 -08001177 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301178 for (i = 0; i < num_devices; i++) {
1179 usecase_backend_idx = platform_get_backend_index(split_snd_devices[i]);
1180 ALOGD("%s:snd_dev %d usecase_backend_idx %d",__func__, split_snd_devices[i],usecase_backend_idx);
1181 if((new_backend_idx == HEADPHONE_BACKEND) &&
1182 ((usecase_backend_idx == HEADPHONE_44_1_BACKEND) ||
1183 (usecase_backend_idx == DSD_NATIVE_BACKEND))) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001184 ALOGV("%s:DSD or native stream detected enabling asrcmode in hardware",
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301185 __func__);
1186 enable_asrc_mode(adev);
1187 break;
1188 } else if(((new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1189 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1190 (usecase_backend_idx == HEADPHONE_BACKEND)) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001191 ALOGV("%s: 48K stream detected, disabling and enabling it \
1192 with asrcmode in hardware", __func__);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301193 disable_audio_route(adev, uc);
1194 disable_snd_device(adev, uc->out_snd_device);
1195 // Apply true-high-quality-mode if DSD or > 44.1KHz or >=24-bit
1196 if (new_backend_idx == DSD_NATIVE_BACKEND)
1197 audio_route_apply_and_update_path(adev->audio_route,
1198 "hph-true-highquality-mode");
1199 else if ((new_backend_idx == HEADPHONE_44_1_BACKEND) &&
1200 (curr_out->bit_width >= 24))
1201 audio_route_apply_and_update_path(adev->audio_route,
1202 "hph-highquality-mode");
1203 enable_asrc_mode(adev);
1204 enable_snd_device(adev, uc->out_snd_device);
1205 enable_audio_route(adev, uc);
1206 break;
1207 }
1208 }
1209 // reset split devices count
1210 num_devices = 0;
Garmond Leung50058f62017-02-08 09:49:30 -08001211 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301212 if (adev->asrc_mode_enabled)
1213 break;
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301214 }
1215 }
1216 }
1217}
1218
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001219static int send_effect_enable_disable_mixer_ctl(struct audio_device *adev,
1220 struct audio_effect_config effect_config,
1221 unsigned int param_value)
1222{
1223 char mixer_ctl_name[] = "Audio Effect";
1224 struct mixer_ctl *ctl;
1225 long set_values[6];
Eric Laurent637e2d42018-11-15 12:24:31 -08001226 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001227
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001228 if (in == NULL) {
1229 ALOGE("%s: active input stream is NULL", __func__);
1230 return -EINVAL;
1231 }
1232
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001233 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
1234 if (!ctl) {
1235 ALOGE("%s: Could not get mixer ctl - %s",
1236 __func__, mixer_ctl_name);
1237 return -EINVAL;
1238 }
1239
1240 set_values[0] = 1; //0:Rx 1:Tx
1241 set_values[1] = in->app_type_cfg.app_type;
1242 set_values[2] = (long)effect_config.module_id;
1243 set_values[3] = (long)effect_config.instance_id;
1244 set_values[4] = (long)effect_config.param_id;
1245 set_values[5] = param_value;
1246
1247 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
1248
1249 return 0;
1250
1251}
1252
1253static int update_effect_param_ecns(struct audio_device *adev, unsigned int module_id,
1254 int effect_type, unsigned int *param_value)
1255{
1256 int ret = 0;
1257 struct audio_effect_config other_effect_config;
1258 struct audio_usecase *usecase = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08001259 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001260
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001261 if (in == NULL) {
1262 ALOGE("%s: active input stream is NULL", __func__);
1263 return -EINVAL;
1264 }
1265
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001266 usecase = get_usecase_from_list(adev, in->usecase);
1267 if (!usecase)
1268 return -EINVAL;
1269
1270 ret = platform_get_effect_config_data(usecase->in_snd_device, &other_effect_config,
1271 effect_type == EFFECT_AEC ? EFFECT_NS : EFFECT_AEC);
1272 if (ret < 0) {
1273 ALOGE("%s Failed to get effect params %d", __func__, ret);
1274 return ret;
1275 }
1276
1277 if (module_id == other_effect_config.module_id) {
1278 //Same module id for AEC/NS. Values need to be combined
1279 if (((effect_type == EFFECT_AEC) && (in->enable_ns)) ||
1280 ((effect_type == EFFECT_NS) && (in->enable_aec))) {
1281 *param_value |= other_effect_config.param_value;
1282 }
1283 }
1284
1285 return ret;
1286}
1287
1288static int enable_disable_effect(struct audio_device *adev, int effect_type, bool enable)
Gangadhar Sb0210342019-02-22 17:39:41 +05301289{
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001290 struct audio_effect_config effect_config;
1291 struct audio_usecase *usecase = NULL;
1292 int ret = 0;
1293 unsigned int param_value = 0;
Eric Laurent637e2d42018-11-15 12:24:31 -08001294 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001295
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001296 if(!voice_extn_is_dynamic_ecns_enabled())
1297 return ENOSYS;
1298
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001299 if (!in) {
1300 ALOGE("%s: Invalid input stream", __func__);
1301 return -EINVAL;
1302 }
1303
1304 ALOGD("%s: effect_type:%d enable:%d", __func__, effect_type, enable);
1305
1306 usecase = get_usecase_from_list(adev, in->usecase);
Weiyin Jiang20d3fa62018-08-01 18:06:27 +08001307 if (usecase == NULL) {
1308 ALOGE("%s: Could not find the usecase (%d) in the list",
1309 __func__, in->usecase);
1310 return -EINVAL;
1311 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001312
1313 ret = platform_get_effect_config_data(usecase->in_snd_device, &effect_config, effect_type);
1314 if (ret < 0) {
1315 ALOGE("%s Failed to get module id %d", __func__, ret);
1316 return ret;
1317 }
1318 ALOGV("%s: %d %d usecase->id:%d usecase->in_snd_device:%d", __func__, effect_config.module_id,
1319 in->app_type_cfg.app_type, usecase->id, usecase->in_snd_device);
1320
1321 if(enable)
1322 param_value = effect_config.param_value;
1323
1324 /*Special handling for AEC & NS effects Param values need to be
1325 updated if module ids are same*/
1326
1327 if ((effect_type == EFFECT_AEC) || (effect_type == EFFECT_NS)) {
1328 ret = update_effect_param_ecns(adev, effect_config.module_id, effect_type, &param_value);
1329 if (ret < 0)
1330 return ret;
1331 }
1332
1333 ret = send_effect_enable_disable_mixer_ctl(adev, effect_config, param_value);
1334
1335 return ret;
1336}
1337
1338static void check_and_enable_effect(struct audio_device *adev)
1339{
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001340 if(!voice_extn_is_dynamic_ecns_enabled())
1341 return;
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001342
Eric Laurent637e2d42018-11-15 12:24:31 -08001343 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001344
Eric Laurent637e2d42018-11-15 12:24:31 -08001345 if (in != NULL && !in->standby) {
1346 if (in->enable_aec)
1347 enable_disable_effect(adev, EFFECT_AEC, true);
1348
1349 if (in->enable_ns &&
1350 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
1351 enable_disable_effect(adev, EFFECT_NS, true);
1352 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001353 }
1354}
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001355
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07001356int pcm_ioctl(struct pcm *pcm, int request, ...)
1357{
1358 va_list ap;
1359 void * arg;
1360 int pcm_fd = *(int*)pcm;
1361
1362 va_start(ap, request);
1363 arg = va_arg(ap, void *);
1364 va_end(ap);
1365
1366 return ioctl(pcm_fd, request, arg);
1367}
1368
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001369int enable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001370 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001371{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001372 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001373 char mixer_path[MIXER_PATH_MAX_LENGTH];
Manish Dewangan58229382017-02-02 15:48:41 +05301374 struct stream_out *out = NULL;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301375 struct stream_in *in = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001376 struct listnode out_devices;
Soumya Managoli6993b762018-06-28 16:04:57 +05301377 int ret = 0;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001378
1379 if (usecase == NULL)
1380 return -EINVAL;
1381
1382 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
1383
Carter Hsu2e429db2019-05-14 18:50:52 +08001384 if (usecase->type == PCM_CAPTURE) {
1385 struct stream_in *in = usecase->stream.in;
1386 struct audio_usecase *uinfo;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001387 snd_device = usecase->in_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001388
1389 if (in) {
1390 if (in->enable_aec || in->enable_ec_port) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001391 list_init(&out_devices);
1392 update_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "", true);
Carter Hsu2e429db2019-05-14 18:50:52 +08001393 struct listnode *node;
1394 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
1395 USECASE_AUDIO_PLAYBACK_VOIP);
1396 if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001397 assign_devices(&out_devices,
1398 &voip_usecase->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001399 } else if (adev->primary_output &&
1400 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001401 assign_devices(&out_devices,
1402 &adev->primary_output->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001403 } else {
1404 list_for_each(node, &adev->usecase_list) {
1405 uinfo = node_to_item(node, struct audio_usecase, list);
1406 if (uinfo->type != PCM_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001407 assign_devices(&out_devices,
1408 &uinfo->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001409 break;
1410 }
1411 }
1412 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001413
1414 platform_set_echo_reference(adev, true, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001415 in->ec_opened = true;
Zhenlin Lian4f947842022-05-14 15:50:52 +05301416 clear_devices(&out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001417 }
1418 }
Guodong Huf5e614d2019-06-24 18:42:03 +08001419 } else if ((usecase->type == TRANSCODE_LOOPBACK_TX) || ((usecase->type == PCM_HFP_CALL) &&
1420 ((usecase->id == USECASE_AUDIO_HFP_SCO) || (usecase->id == USECASE_AUDIO_HFP_SCO_WB)) &&
1421 (usecase->in_snd_device == SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS))) {
Carter Hsu2e429db2019-05-14 18:50:52 +08001422 snd_device = usecase->in_snd_device;
1423 } else {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001424 snd_device = usecase->out_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001425 }
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001426
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001427 if (usecase->type == PCM_CAPTURE) {
1428 if (platform_get_fluence_nn_state(adev->platform) == 0) {
1429 platform_set_fluence_nn_state(adev->platform, true);
1430 ALOGD("%s: set fluence nn capture state", __func__);
1431 }
1432 }
1433
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08001434#ifdef DS1_DOLBY_DAP_ENABLED
1435 audio_extn_dolby_set_dmid(adev);
1436 audio_extn_dolby_set_endpoint(adev);
1437#endif
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -07001438 audio_extn_dolby_ds2_set_endpoint(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001439 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301440 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
Ben Romberger1fafdde2015-09-09 19:43:15 -07001441 audio_extn_utils_send_app_type_cfg(adev, usecase);
Jasmine Cha4dcc1092019-03-04 18:12:47 +08001442 if (audio_extn_is_maxx_audio_enabled())
1443 audio_extn_ma_set_device(usecase);
Dhananjay Kumar14170dd2015-08-28 13:24:16 +05301444 audio_extn_utils_send_audio_calibration(adev, usecase);
Zhou Songbaddf9f2020-11-20 13:57:39 +08001445 if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
1446 out = usecase->stream.out;
1447 if (out && out->compr)
Manish Dewangan58229382017-02-02 15:48:41 +05301448 audio_extn_utils_compress_set_clk_rec_mode(usecase);
1449 }
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301450
1451 if (usecase->type == PCM_CAPTURE) {
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001452 if (platform_get_fluence_nn_state(adev->platform) == 1 &&
1453 adev->fluence_nn_usecase_id == USECASE_INVALID ) {
1454 adev->fluence_nn_usecase_id = usecase->id;
1455 ALOGD("%s: assign fluence nn usecase %d", __func__, usecase->id);
1456 }
1457 }
1458
1459 if (usecase->type == PCM_CAPTURE) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301460 in = usecase->stream.in;
Avinash Chandrad7296d42021-08-04 15:07:47 +05301461 if ((in && is_loopback_input_device(get_device_types(&in->device_list))) ||
1462 (in && is_combo_audio_input_device(&in->device_list)) ||
1463 (in && ((compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
1464 compare_device_type(&in->device_list, AUDIO_DEVICE_IN_LINE)) &&
1465 (snd_device == SND_DEVICE_IN_HANDSET_GENERIC_6MIC)))) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301466 ALOGD("%s: set custom mtmx params v1", __func__);
1467 audio_extn_set_custom_mtmx_params_v1(adev, usecase, true);
1468 }
1469 } else {
1470 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
1471 }
Manish Dewangan58229382017-02-02 15:48:41 +05301472
Andy Hung756ecc12018-10-19 17:47:12 -07001473 // we shouldn't truncate mixer_path
1474 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1475 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1476 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001477 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001478 ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
Soumya Managoli6993b762018-06-28 16:04:57 +05301479 ret = audio_route_apply_and_update_path(adev->audio_route, mixer_path);
1480 if (!ret && usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1481 struct str_parms *parms = str_parms_create_str("fm_restore_volume=1");
1482 if (parms) {
1483 audio_extn_fm_set_parameters(adev, parms);
1484 str_parms_destroy(parms);
1485 }
1486 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001487 ALOGV("%s: exit", __func__);
1488 return 0;
1489}
1490
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001491int disable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001492 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001493{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001494 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001495 char mixer_path[MIXER_PATH_MAX_LENGTH];
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301496 struct stream_in *in = NULL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001497
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05301498 if (usecase == NULL || usecase->id == USECASE_INVALID)
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001499 return -EINVAL;
1500
1501 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
Surendar Karka93cd25a2018-08-28 14:21:37 +05301502 if (usecase->type == PCM_CAPTURE || usecase->type == TRANSCODE_LOOPBACK_TX)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001503 snd_device = usecase->in_snd_device;
1504 else
1505 snd_device = usecase->out_snd_device;
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001506
1507 /* disable island and power mode on supported device for voice call */
1508 if (usecase->type == VOICE_CALL) {
1509 if (usecase->in_snd_device != SND_DEVICE_NONE) {
1510 if (platform_get_island_cfg_on_device(adev->platform, usecase->in_snd_device) &&
1511 platform_get_power_mode_on_device(adev->platform, usecase->in_snd_device)) {
1512 platform_set_island_cfg_on_device(adev, usecase->in_snd_device, false);
1513 platform_set_power_mode_on_device(adev, usecase->in_snd_device, false);
1514 platform_reset_island_power_status(adev->platform, usecase->in_snd_device);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001515 if (voice_is_lte_call_active(adev))
1516 platform_set_tx_lpi_mode(adev->platform, false);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001517 ALOGD("%s: disable island cfg and power mode in voice tx path",
1518 __func__);
1519 }
1520 }
1521 if (usecase->out_snd_device != SND_DEVICE_NONE) {
1522 if (platform_get_island_cfg_on_device(adev->platform, usecase->out_snd_device) &&
1523 platform_get_power_mode_on_device(adev->platform, usecase->out_snd_device)) {
1524 platform_set_island_cfg_on_device(adev, usecase->out_snd_device, false);
1525 platform_set_power_mode_on_device(adev, usecase->out_snd_device, false);
1526 platform_reset_island_power_status(adev->platform, usecase->out_snd_device);
1527 ALOGD("%s: disable island cfg and power mode in voice rx path",
1528 __func__);
1529 }
1530 }
1531 }
1532
Andy Hung756ecc12018-10-19 17:47:12 -07001533 // we shouldn't truncate mixer_path
1534 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1535 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1536 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001537 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001538 ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001539 audio_route_reset_and_update_path(adev->audio_route, mixer_path);
Carter Hsu2e429db2019-05-14 18:50:52 +08001540 if (usecase->type == PCM_CAPTURE) {
1541 struct stream_in *in = usecase->stream.in;
1542 if (in && in->ec_opened) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001543 struct listnode out_devices;
1544 list_init(&out_devices);
1545 platform_set_echo_reference(in->dev, false, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001546 in->ec_opened = false;
Zhenlin Lian4f947842022-05-14 15:50:52 +05301547 clear_devices(&out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001548 }
1549 }
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001550 if (usecase->id == adev->fluence_nn_usecase_id) {
1551 platform_set_fluence_nn_state(adev->platform, false);
1552 adev->fluence_nn_usecase_id = USECASE_INVALID;
1553 ALOGD("%s: reset fluence nn capture state", __func__);
1554 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001555 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301556 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301557
1558 if (usecase->type == PCM_CAPTURE) {
1559 in = usecase->stream.in;
Avinash Chandrad7296d42021-08-04 15:07:47 +05301560 if ((in && is_loopback_input_device(get_device_types(&in->device_list))) ||
1561 (in && is_combo_audio_input_device(&in->device_list)) ||
1562 (in && ((compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUILTIN_MIC) ||
1563 compare_device_type(&in->device_list, AUDIO_DEVICE_IN_LINE)) &&
1564 (snd_device == SND_DEVICE_IN_HANDSET_GENERIC_6MIC)))){
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301565 ALOGD("%s: reset custom mtmx params v1", __func__);
1566 audio_extn_set_custom_mtmx_params_v1(adev, usecase, false);
1567 }
1568 } else {
1569 audio_extn_set_custom_mtmx_params_v2(adev, usecase, false);
1570 }
1571
Weiyin Jiang298ffd92019-06-03 14:29:30 +08001572 if ((usecase->type == PCM_PLAYBACK) &&
1573 (usecase->stream.out != NULL))
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05301574 usecase->stream.out->pspd_coeff_sent = false;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301575
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001576 ALOGV("%s: exit", __func__);
1577 return 0;
1578}
1579
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001580int enable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001581 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001582{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301583 int i, num_devices = 0;
1584 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001585 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1586
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001587 if (snd_device < SND_DEVICE_MIN ||
1588 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001589 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001590 return -EINVAL;
1591 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001592
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001593 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001594 ALOGE("%s: Invalid sound device returned", __func__);
1595 return -EINVAL;
1596 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001597
1598 adev->snd_dev_ref_cnt[snd_device]++;
1599
1600 if ((adev->snd_dev_ref_cnt[snd_device] > 1) &&
1601 (platform_split_snd_device(adev->platform,
1602 snd_device,
1603 &num_devices,
1604 new_snd_devices) != 0)) {
Eric Laurent994a6932013-07-17 11:51:42 -07001605 ALOGV("%s: snd_device(%d: %s) is already active",
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001606 __func__, snd_device, device_name);
Aniket Kumar Lata990de552019-07-11 14:20:23 -07001607 /* Set backend config for A2DP to ensure slimbus configuration
1608 is correct if A2DP is already active and backend is closed
1609 and re-opened */
1610 if (snd_device == SND_DEVICE_OUT_BT_A2DP)
1611 audio_extn_a2dp_set_source_backend_cfg();
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001612 return 0;
1613 }
1614
Gopikrishnaiah Anandane85d0462014-06-30 21:41:20 -07001615 if (audio_extn_spkr_prot_is_enabled())
1616 audio_extn_spkr_prot_calib_cancel(adev);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001617
Aalique Grahame22e49102018-12-18 14:23:57 -08001618 audio_extn_dsm_feedback_enable(adev, snd_device, true);
1619
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001620 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1621 audio_extn_spkr_prot_is_enabled()) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001622 if (platform_get_spkr_prot_acdb_id(snd_device) < 0) {
1623 goto err;
1624 }
1625 audio_extn_dev_arbi_acquire(snd_device);
1626 if (audio_extn_spkr_prot_start_processing(snd_device)) {
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001627 ALOGE("%s: spkr_start_processing failed", __func__);
Ravit Dennisaaee49c2015-02-04 21:26:22 +02001628 audio_extn_dev_arbi_release(snd_device);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001629 goto err;
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001630 }
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001631 } else if (platform_split_snd_device(adev->platform,
1632 snd_device,
1633 &num_devices,
1634 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301635 for (i = 0; i < num_devices; i++) {
1636 enable_snd_device(adev, new_snd_devices[i]);
1637 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001638 platform_set_speaker_gain_in_combo(adev, snd_device, true);
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001639 } else {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001640 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301641
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001642 /* enable island and power mode on supported device */
1643 if (platform_get_island_cfg_on_device(adev->platform, snd_device) &&
1644 platform_get_power_mode_on_device(adev->platform, snd_device)) {
1645 platform_set_island_cfg_on_device(adev, snd_device, true);
1646 platform_set_power_mode_on_device(adev, snd_device, true);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001647 if (voice_is_lte_call_active(adev) &&
1648 (snd_device >= SND_DEVICE_IN_BEGIN &&
1649 snd_device < SND_DEVICE_IN_END))
1650 platform_set_tx_lpi_mode(adev->platform, true);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001651 ALOGD("%s: enable island cfg and power mode on: %s",
1652 __func__, device_name);
1653 }
Preetam Singh Ranawatf1d417c2017-01-10 17:00:32 +05301654
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301655 if (SND_DEVICE_OUT_BT_A2DP == snd_device) {
Ramjee Singh2d2944a2021-12-14 14:13:41 +05301656
1657 struct audio_usecase *usecase;
1658 struct listnode *node;
1659 /* Disable SCO Devices and enable handset mic for active input stream */
1660 list_for_each(node, &adev->usecase_list) {
1661 usecase = node_to_item(node, struct audio_usecase, list);
1662 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
1663 is_sco_in_device_type(&usecase->stream.in->device_list)) {
1664 ALOGD("a2dp resumed, switch bt sco mic to handset mic");
1665 reassign_device_list(&usecase->stream.in->device_list,
1666 AUDIO_DEVICE_IN_BUILTIN_MIC, "");
1667 select_devices(adev, usecase->id);
1668 }
1669 }
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301670 if (audio_extn_a2dp_start_playback() < 0) {
1671 ALOGE(" fail to configure A2dp Source control path ");
1672 goto err;
1673 } else {
1674 adev->a2dp_started = true;
1675 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001676 }
Florian Pfister1a84f312018-07-19 14:38:18 +02001677
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001678 if ((SND_DEVICE_IN_BT_A2DP == snd_device) &&
1679 (audio_extn_a2dp_start_capture() < 0)) {
1680 ALOGE(" fail to configure A2dp Sink control path ");
1681 goto err;
1682 }
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301683
Mingshu Pang7be5b1d2020-03-04 15:24:38 +08001684 if ((SND_DEVICE_OUT_BT_SCO_SWB == snd_device) ||
1685 (SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC == snd_device) ||
1686 (SND_DEVICE_IN_BT_SCO_MIC_SWB == snd_device)) {
1687 if (!adev->bt_sco_on || (audio_extn_sco_start_configuration() < 0)) {
1688 ALOGE(" fail to configure sco control path ");
1689 goto err;
1690 }
Zhou Song12c29502019-03-16 10:37:18 +08001691 }
1692
Zhou Song331c8e52019-08-26 14:16:12 +08001693 configure_btsco_sample_rate(snd_device);
Bharath Ramachandramurthy0de16782014-03-28 21:34:33 -07001694 /* due to the possibility of calibration overwrite between listen
1695 and audio, notify listen hal before audio calibration is sent */
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001696 audio_extn_sound_trigger_update_device_status(snd_device,
1697 ST_EVENT_SND_DEVICE_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301698 audio_extn_listen_update_device_status(snd_device,
1699 LISTEN_EVENT_SND_DEVICE_BUSY);
Subhash Chandra Bose Naripeddy54274672014-03-10 14:51:02 -07001700 if (platform_get_snd_device_acdb_id(snd_device) < 0) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001701 audio_extn_sound_trigger_update_device_status(snd_device,
1702 ST_EVENT_SND_DEVICE_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301703 audio_extn_listen_update_device_status(snd_device,
1704 LISTEN_EVENT_SND_DEVICE_FREE);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001705 goto err;
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001706 }
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001707 audio_extn_dev_arbi_acquire(snd_device);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001708 audio_route_apply_and_update_path(adev->audio_route, device_name);
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301709
1710 if (SND_DEVICE_OUT_HEADPHONES == snd_device &&
1711 !adev->native_playback_enabled &&
1712 audio_is_true_native_stream_active(adev)) {
1713 ALOGD("%s: %d: napb: enabling native mode in hardware",
1714 __func__, __LINE__);
1715 audio_route_apply_and_update_path(adev->audio_route,
1716 "true-native-mode");
1717 adev->native_playback_enabled = true;
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301718 }
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +05301719 if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
1720 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001721 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001722 ALOGD("%s: init ec ref loopback", __func__);
1723 audio_extn_ffv_init_ec_ref_loopback(adev, snd_device);
1724 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001725 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001726 return 0;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001727err:
1728 adev->snd_dev_ref_cnt[snd_device]--;
1729 return -EINVAL;;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001730}
1731
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001732int disable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001733 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001734{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301735 int i, num_devices = 0;
1736 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001737 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1738
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001739 if (snd_device < SND_DEVICE_MIN ||
1740 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001741 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001742 return -EINVAL;
1743 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001744
1745 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
1746 ALOGE("%s: Invalid sound device returned", __func__);
1747 return -EINVAL;
1748 }
1749
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001750 if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
1751 ALOGE("%s: device ref cnt is already 0", __func__);
1752 return -EINVAL;
1753 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001754
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001755 adev->snd_dev_ref_cnt[snd_device]--;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001756
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001757
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001758 if (adev->snd_dev_ref_cnt[snd_device] == 0) {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001759 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301760
Aalique Grahame22e49102018-12-18 14:23:57 -08001761 audio_extn_dsm_feedback_enable(adev, snd_device, false);
1762
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001763 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1764 audio_extn_spkr_prot_is_enabled()) {
Anish Kumar46c7b872014-09-09 01:49:44 -07001765 audio_extn_spkr_prot_stop_processing(snd_device);
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07001766
1767 // when speaker device is disabled, reset swap.
1768 // will be renabled on usecase start
1769 platform_set_swap_channels(adev, false);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001770 } else if (platform_split_snd_device(adev->platform,
1771 snd_device,
1772 &num_devices,
1773 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301774 for (i = 0; i < num_devices; i++) {
1775 disable_snd_device(adev, new_snd_devices[i]);
1776 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001777 platform_set_speaker_gain_in_combo(adev, snd_device, false);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001778 } else {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001779 audio_route_reset_and_update_path(adev->audio_route, device_name);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001780 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001781
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301782 if (snd_device == SND_DEVICE_OUT_BT_A2DP) {
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301783 audio_extn_a2dp_stop_playback();
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301784 adev->a2dp_started = false;
1785 } else if (snd_device == SND_DEVICE_IN_BT_A2DP)
Florian Pfister1a84f312018-07-19 14:38:18 +02001786 audio_extn_a2dp_stop_capture();
Zhou Songd6d71752019-05-21 18:08:51 +08001787 else if ((snd_device == SND_DEVICE_OUT_HDMI) ||
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001788 (snd_device == SND_DEVICE_OUT_DISPLAY_PORT))
Ashish Jain81eb2a82015-05-13 10:52:34 +05301789 adev->is_channel_status_set = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001790 else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301791 adev->native_playback_enabled) {
1792 ALOGD("%s: %d: napb: disabling native mode in hardware",
1793 __func__, __LINE__);
1794 audio_route_reset_and_update_path(adev->audio_route,
1795 "true-native-mode");
1796 adev->native_playback_enabled = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001797 } else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301798 adev->asrc_mode_enabled) {
1799 ALOGD("%s: %d: disabling asrc mode in hardware", __func__, __LINE__);
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301800 disable_asrc_mode(adev);
1801 audio_route_apply_and_update_path(adev->audio_route, "hph-lowpower-mode");
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001802 } else if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
Dhanalakshmi Siddaniaf4bd622019-02-27 16:28:06 +05301803 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001804 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001805 ALOGD("%s: deinit ec ref loopback", __func__);
1806 audio_extn_ffv_deinit_ec_ref_loopback(adev, snd_device);
1807 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001808
1809 audio_extn_utils_release_snd_device(snd_device);
1810 } else {
1811 if (platform_split_snd_device(adev->platform,
1812 snd_device,
1813 &num_devices,
1814 new_snd_devices) == 0) {
1815 for (i = 0; i < num_devices; i++) {
1816 adev->snd_dev_ref_cnt[new_snd_devices[i]]--;
1817 }
1818 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001819 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001820
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001821 return 0;
1822}
1823
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001824/*
1825 legend:
1826 uc - existing usecase
1827 new_uc - new usecase
1828 d1, d11, d2 - SND_DEVICE enums
1829 a1, a2 - corresponding ANDROID device enums
1830 B1, B2 - backend strings
1831
1832case 1
1833 uc->dev d1 (a1) B1
1834 new_uc->dev d1 (a1), d2 (a2) B1, B2
1835
1836 resolution: disable and enable uc->dev on d1
1837
1838case 2
1839 uc->dev d1 (a1) B1
1840 new_uc->dev d11 (a1) B1
1841
1842 resolution: need to switch uc since d1 and d11 are related
1843 (e.g. speaker and voice-speaker)
1844 use ANDROID_DEVICE_OUT enums to match devices since SND_DEVICE enums may vary
1845
1846case 3
1847 uc->dev d1 (a1) B1
1848 new_uc->dev d2 (a2) B2
1849
1850 resolution: no need to switch uc
1851
1852case 4
1853 uc->dev d1 (a1) B1
1854 new_uc->dev d2 (a2) B1
1855
1856 resolution: disable enable uc-dev on d2 since backends match
1857 we cannot enable two streams on two different devices if they
1858 share the same backend. e.g. if offload is on speaker device using
1859 QUAD_MI2S backend and a low-latency stream is started on voice-handset
1860 using the same backend, offload must also be switched to voice-handset.
1861
1862case 5
1863 uc->dev d1 (a1) B1
1864 new_uc->dev d1 (a1), d2 (a2) B1
1865
1866 resolution: disable enable uc-dev on d2 since backends match
1867 we cannot enable two streams on two different devices if they
1868 share the same backend.
1869
1870case 6
1871 uc->dev d1 (a1) B1
1872 new_uc->dev d2 (a1) B2
1873
1874 resolution: no need to switch
1875
1876case 7
1877 uc->dev d1 (a1), d2 (a2) B1, B2
1878 new_uc->dev d1 (a1) B1
1879
1880 resolution: no need to switch
1881
Zhou Song4ba65882018-07-09 14:48:07 +08001882case 8
1883 uc->dev d1 (a1) B1
1884 new_uc->dev d11 (a1), d2 (a2) B1, B2
1885 resolution: compared to case 1, for this case, d1 and d11 are related
1886 then need to do the same as case 2 to siwtch to new uc
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301887
1888case 9
1889 uc->dev d1 (a1), d2(a2) B1 B2
1890 new_uc->dev d1 (a1), d22 (a2) B1, B2
1891 resolution: disable enable uc-dev on d2 since backends match
1892 we cannot enable two streams on two different devices if they
1893 share the same backend. This is special case for combo use case
1894 with a2dp and sco devices which uses same backend.
1895 e.g. speaker-a2dp and speaker-btsco
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001896*/
1897static snd_device_t derive_playback_snd_device(void * platform,
1898 struct audio_usecase *uc,
1899 struct audio_usecase *new_uc,
1900 snd_device_t new_snd_device)
1901{
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001902 struct listnode a1, a2;
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001903
1904 snd_device_t d1 = uc->out_snd_device;
1905 snd_device_t d2 = new_snd_device;
1906
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001907 list_init(&a1);
1908 list_init(&a2);
1909
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301910 switch (uc->type) {
Surendar Karka93cd25a2018-08-28 14:21:37 +05301911 case TRANSCODE_LOOPBACK_RX :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001912 assign_devices(&a1, &uc->stream.inout->out_config.device_list);
1913 assign_devices(&a2, &new_uc->stream.inout->out_config.device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301914 break;
1915 default :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001916 assign_devices(&a1, &uc->stream.out->device_list);
1917 assign_devices(&a2, &new_uc->stream.out->device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301918 break;
1919 }
1920
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001921 // Treat as a special case when a1 and a2 are not disjoint
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001922 if (!compare_devices(&a1, &a2) &&
1923 compare_devices_for_any_match(&a1 ,&a2)) {
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001924 snd_device_t d3[2];
1925 int num_devices = 0;
1926 int ret = platform_split_snd_device(platform,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001927 list_length(&a1) > 1 ? d1 : d2,
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001928 &num_devices,
1929 d3);
1930 if (ret < 0) {
1931 if (ret != -ENOSYS) {
1932 ALOGW("%s failed to split snd_device %d",
1933 __func__,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001934 list_length(&a1) > 1 ? d1 : d2);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001935 }
1936 goto end;
1937 }
1938
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001939 if (platform_check_backends_match(d3[0], d3[1])) {
1940 return d2; // case 5
1941 } else {
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301942 if ((list_length(&a1) > 1) && (list_length(&a2) > 1) &&
1943 platform_check_backends_match(d1, d2))
1944 return d2; //case 9
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001945 if (list_length(&a1) > 1)
Samyak Jaind826b502019-07-17 16:16:42 +05301946 return d1; //case 7
Garmond Leungb9eeba42018-09-18 11:10:41 -07001947 // check if d1 is related to any of d3's
1948 if (d1 == d3[0] || d1 == d3[1])
Zhou Song4ba65882018-07-09 14:48:07 +08001949 return d1; // case 1
1950 else
1951 return d3[1]; // case 8
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001952 }
1953 } else {
1954 if (platform_check_backends_match(d1, d2)) {
1955 return d2; // case 2, 4
1956 } else {
1957 return d1; // case 6, 3
1958 }
1959 }
1960
Zhenlin Lian4f947842022-05-14 15:50:52 +05301961 clear_devices(&a1);
1962 clear_devices(&a2);
1963
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001964end:
1965 return d2; // return whatever was calculated before.
1966}
1967
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001968static void check_usecases_codec_backend(struct audio_device *adev,
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301969 struct audio_usecase *uc_info,
1970 snd_device_t snd_device)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001971{
1972 struct listnode *node;
1973 struct audio_usecase *usecase;
1974 bool switch_device[AUDIO_USECASE_MAX];
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301975 snd_device_t uc_derive_snd_device;
1976 snd_device_t derive_snd_device[AUDIO_USECASE_MAX];
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001977 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
1978 int i, num_uc_to_switch = 0, num_devices = 0;
kunleiz5cd52b82016-11-07 17:22:52 +08001979 int status = 0;
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301980 bool force_restart_session = false;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001981 /*
1982 * This function is to make sure that all the usecases that are active on
1983 * the hardware codec backend are always routed to any one device that is
1984 * handled by the hardware codec.
1985 * For example, if low-latency and deep-buffer usecases are currently active
1986 * on speaker and out_set_parameters(headset) is received on low-latency
1987 * output, then we have to make sure deep-buffer is also switched to headset,
1988 * because of the limitation that both the devices cannot be enabled
1989 * at the same time as they share the same backend.
1990 */
Mingming Yin3ee55c62014-08-04 14:23:35 -07001991 /*
1992 * This call is to check if we need to force routing for a particular stream
1993 * If there is a backend configuration change for the device when a
1994 * new stream starts, then ADM needs to be closed and re-opened with the new
1995 * configuraion. This call check if we need to re-route all the streams
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001996 * associated with the backend. Touch tone + 24 bit + native playback.
Mingming Yin3ee55c62014-08-04 14:23:35 -07001997 */
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001998 bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info,
1999 snd_device);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302000 /* For a2dp device reconfigure all active sessions
2001 * with new AFE encoder format based on a2dp state
2002 */
2003 if ((SND_DEVICE_OUT_BT_A2DP == snd_device ||
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05302004 SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP == snd_device ||
2005 SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP == snd_device) &&
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302006 audio_extn_a2dp_is_force_device_switch()) {
2007 force_routing = true;
2008 force_restart_session = true;
2009 }
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002010
2011 /*
2012 * Island cfg and power mode config needs to set before AFE port start.
2013 * Set force routing in case of voice device was enable before.
2014 */
2015 if (uc_info->type == VOICE_CALL &&
2016 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002017 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002018 platform_check_and_update_island_power_status(adev->platform,
2019 uc_info,
2020 snd_device)) {
2021 force_routing = true;
2022 ALOGD("%s:becf: force routing %d for power mode supported device",
2023 __func__, force_routing);
2024 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302025 ALOGD("%s:becf: force routing %d", __func__, force_routing);
2026
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002027 /* Disable all the usecases on the shared backend other than the
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08002028 * specified usecase.
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08002029 */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002030 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2031 switch_device[i] = false;
2032
2033 list_for_each(node, &adev->usecase_list) {
2034 usecase = node_to_item(node, struct audio_usecase, list);
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08002035
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302036 ALOGD("%s:becf: (%d) check_usecases curr device: %s, usecase device:%s "
2037 "backends match %d",__func__, i,
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302038 platform_get_snd_device_name(snd_device),
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302039 platform_get_snd_device_name(usecase->out_snd_device),
2040 platform_check_backends_match(snd_device, usecase->out_snd_device));
Rahul Sharma99770982019-03-06 17:05:26 +05302041 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
2042 (usecase->type != PCM_PASSTHROUGH)) {
Ashish Jain6a65b352017-03-21 17:24:40 +05302043 uc_derive_snd_device = derive_playback_snd_device(adev->platform,
2044 usecase, uc_info, snd_device);
2045 if (((uc_derive_snd_device != usecase->out_snd_device) || force_routing) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002046 (is_codec_backend_out_device_type(&usecase->device_list) ||
2047 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
2048 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_DEVICE) ||
2049 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_HEADSET) ||
2050 is_a2dp_out_device_type(&usecase->device_list) ||
2051 is_sco_out_device_type(&usecase->device_list)) &&
Ashish Jain6a65b352017-03-21 17:24:40 +05302052 ((force_restart_session) ||
2053 (platform_check_backends_match(snd_device, usecase->out_snd_device)))) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302054 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
2055 __func__, use_case_table[usecase->id],
2056 platform_get_snd_device_name(usecase->out_snd_device));
2057 disable_audio_route(adev, usecase);
2058 switch_device[usecase->id] = true;
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05302059 /* Enable existing usecase on derived playback device */
2060 derive_snd_device[usecase->id] = uc_derive_snd_device;
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05302061 num_uc_to_switch++;
Ashish Jain6a65b352017-03-21 17:24:40 +05302062 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002063 }
2064 }
2065
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302066 ALOGD("%s:becf: check_usecases num.of Usecases to switch %d", __func__,
2067 num_uc_to_switch);
2068
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002069 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002070 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002071
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302072 /* Make sure the previous devices to be disabled first and then enable the
2073 selected devices */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002074 list_for_each(node, &adev->usecase_list) {
2075 usecase = node_to_item(node, struct audio_usecase, list);
2076 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08002077 /* Check if output sound device to be switched can be split and if any
2078 of the split devices match with derived sound device */
2079 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
2080 &num_devices, split_snd_devices) == 0) {
2081 adev->snd_dev_ref_cnt[usecase->out_snd_device]--;
2082 for (i = 0; i < num_devices; i++) {
2083 /* Disable devices that do not match with derived sound device */
2084 if (split_snd_devices[i] != derive_snd_device[usecase->id])
2085 disable_snd_device(adev, split_snd_devices[i]);
2086 }
2087 } else {
2088 disable_snd_device(adev, usecase->out_snd_device);
2089 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002090 }
2091 }
2092
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002093 list_for_each(node, &adev->usecase_list) {
2094 usecase = node_to_item(node, struct audio_usecase, list);
2095 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08002096 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
2097 &num_devices, split_snd_devices) == 0) {
2098 /* Enable derived sound device only if it does not match with
2099 one of the split sound devices. This is because the matching
2100 sound device was not disabled */
2101 bool should_enable = true;
2102 for (i = 0; i < num_devices; i++) {
2103 if (derive_snd_device[usecase->id] == split_snd_devices[i]) {
2104 should_enable = false;
2105 break;
2106 }
2107 }
2108 if (should_enable)
2109 enable_snd_device(adev, derive_snd_device[usecase->id]);
2110 } else {
2111 enable_snd_device(adev, derive_snd_device[usecase->id]);
2112 }
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002113 }
2114 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002115
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002116 /* Re-route all the usecases on the shared backend other than the
2117 specified usecase to new snd devices */
2118 list_for_each(node, &adev->usecase_list) {
2119 usecase = node_to_item(node, struct audio_usecase, list);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302120 /* Update the out_snd_device only before enabling the audio route */
2121 if (switch_device[usecase->id]) {
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05302122 usecase->out_snd_device = derive_snd_device[usecase->id];
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302123 ALOGD("%s:becf: enabling usecase (%s) on (%s)", __func__,
2124 use_case_table[usecase->id],
2125 platform_get_snd_device_name(usecase->out_snd_device));
2126 /* Update voc calibration before enabling Voice/VoIP route */
2127 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
2128 status = platform_switch_voice_call_device_post(adev->platform,
2129 usecase->out_snd_device,
2130 platform_get_input_snd_device(
2131 adev->platform, NULL,
2132 &uc_info->device_list,
2133 usecase->type));
2134 enable_audio_route(adev, usecase);
2135 if (usecase->stream.out && usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
2136 out_set_voip_volume(&usecase->stream.out->stream,
2137 usecase->stream.out->volume_l,
2138 usecase->stream.out->volume_r);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302139 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002140 }
2141 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002142 }
2143}
2144
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302145static void check_usecases_capture_codec_backend(struct audio_device *adev,
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002146 struct audio_usecase *uc_info,
2147 snd_device_t snd_device)
2148{
2149 struct listnode *node;
2150 struct audio_usecase *usecase;
2151 bool switch_device[AUDIO_USECASE_MAX];
2152 int i, num_uc_to_switch = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002153 int backend_check_cond = is_codec_backend_out_device_type(&uc_info->device_list);
kunleiz5cd52b82016-11-07 17:22:52 +08002154 int status = 0;
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002155
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302156 bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
2157 snd_device);
2158 ALOGD("%s:becf: force routing %d", __func__, force_routing);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302159
2160 /*
2161 * Make sure out devices is checked against out codec backend device and
2162 * also in devices against in codec backend. Checking out device against in
2163 * codec backend or vice versa causes issues.
2164 */
2165 if (uc_info->type == PCM_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002166 backend_check_cond = is_codec_backend_in_device_type(&uc_info->device_list);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002167
2168 /*
2169 * Island cfg and power mode config needs to set before AFE port start.
2170 * Set force routing in case of voice device was enable before.
2171 */
2172
2173 if (uc_info->type == VOICE_CALL &&
2174 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002175 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002176 platform_check_and_update_island_power_status(adev->platform,
2177 uc_info,
2178 snd_device)) {
2179 force_routing = true;
2180 ALOGD("%s:becf: force routing %d for power mode supported device",
2181 __func__, force_routing);
2182 }
2183
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002184 /*
2185 * This function is to make sure that all the active capture usecases
2186 * are always routed to the same input sound device.
2187 * For example, if audio-record and voice-call usecases are currently
2188 * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
2189 * is received for voice call then we have to make sure that audio-record
2190 * usecase is also switched to earpiece i.e. voice-dmic-ef,
2191 * because of the limitation that two devices cannot be enabled
2192 * at the same time if they share the same backend.
2193 */
2194 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2195 switch_device[i] = false;
2196
2197 list_for_each(node, &adev->usecase_list) {
2198 usecase = node_to_item(node, struct audio_usecase, list);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302199 /*
2200 * TODO: Enhance below condition to handle BT sco/USB multi recording
2201 */
Jaideep Sharma477917f2020-03-13 18:13:33 +05302202
2203 bool capture_uc_needs_routing = usecase->type != PCM_PLAYBACK && (usecase != uc_info &&
2204 (usecase->in_snd_device != snd_device || force_routing));
2205 bool call_proxy_snd_device = platform_is_call_proxy_snd_device(snd_device) ||
2206 platform_is_call_proxy_snd_device(usecase->in_snd_device);
2207 if (capture_uc_needs_routing && !call_proxy_snd_device &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002208 ((backend_check_cond &&
2209 (is_codec_backend_in_device_type(&usecase->device_list) ||
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08002210 (usecase->type == VOIP_CALL))) ||
Carter Hsu1d2a0532018-10-04 09:24:36 +08002211 ((uc_info->type == VOICE_CALL &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002212 is_single_device_type_equal(&usecase->device_list,
2213 AUDIO_DEVICE_IN_VOICE_CALL)) ||
Anver sadhique4fdc6992022-01-21 12:26:28 +05302214 platform_check_all_backends_match(snd_device,\
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002215 usecase->in_snd_device))) &&
Anish Kumara020a7c2014-10-17 11:13:22 -07002216 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05302217 ALOGD("%s: Usecase (%s) is active on (%s) - disabling ..",
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002218 __func__, use_case_table[usecase->id],
Devin Kim1e5f3532013-08-09 07:48:29 -07002219 platform_get_snd_device_name(usecase->in_snd_device));
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002220 disable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002221 switch_device[usecase->id] = true;
2222 num_uc_to_switch++;
2223 }
2224 }
2225
2226 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002227 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002228
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302229 /* Make sure the previous devices to be disabled first and then enable the
2230 selected devices */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002231 list_for_each(node, &adev->usecase_list) {
2232 usecase = node_to_item(node, struct audio_usecase, list);
2233 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002234 disable_snd_device(adev, usecase->in_snd_device);
Shiv Maliyappanahalli80ac6282013-12-20 18:56:15 -08002235 }
2236 }
2237
2238 list_for_each(node, &adev->usecase_list) {
2239 usecase = node_to_item(node, struct audio_usecase, list);
2240 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002241 enable_snd_device(adev, snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002242 }
2243 }
2244
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002245 /* Re-route all the usecases on the shared backend other than the
2246 specified usecase to new snd devices */
2247 list_for_each(node, &adev->usecase_list) {
2248 usecase = node_to_item(node, struct audio_usecase, list);
2249 /* Update the in_snd_device only before enabling the audio route */
2250 if (switch_device[usecase->id] ) {
2251 usecase->in_snd_device = snd_device;
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302252 /* Update voc calibration before enabling Voice/VoIP route */
2253 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
2254 snd_device_t voip_snd_device;
2255 voip_snd_device = platform_get_output_snd_device(adev->platform,
2256 usecase->stream.out,
2257 usecase->type);
2258 status = platform_switch_voice_call_device_post(adev->platform,
2259 voip_snd_device,
2260 usecase->in_snd_device);
kunleiz5cd52b82016-11-07 17:22:52 +08002261 }
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302262 enable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002263 }
2264 }
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002265 }
2266}
2267
Mingming Yin3a941d42016-02-17 18:08:05 -08002268static void reset_hdmi_sink_caps(struct stream_out *out) {
2269 int i = 0;
2270
2271 for (i = 0; i<= MAX_SUPPORTED_CHANNEL_MASKS; i++) {
2272 out->supported_channel_masks[i] = 0;
2273 }
2274 for (i = 0; i<= MAX_SUPPORTED_FORMATS; i++) {
2275 out->supported_formats[i] = 0;
2276 }
2277 for (i = 0; i<= MAX_SUPPORTED_SAMPLE_RATES; i++) {
2278 out->supported_sample_rates[i] = 0;
2279 }
2280}
2281
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002282/* must be called with hw device mutex locked */
Mingming Yin3a941d42016-02-17 18:08:05 -08002283static int read_hdmi_sink_caps(struct stream_out *out)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002284{
Mingming Yin3a941d42016-02-17 18:08:05 -08002285 int ret = 0, i = 0, j = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002286 int channels = platform_edid_get_max_channels_v2(out->dev->platform,
2287 out->extconn.cs.controller,
2288 out->extconn.cs.stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002289
Mingming Yin3a941d42016-02-17 18:08:05 -08002290 reset_hdmi_sink_caps(out);
2291
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002292 /* Cache ext disp type */
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002293 ret = platform_get_ext_disp_type_v2(adev->platform,
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002294 out->extconn.cs.controller,
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002295 out->extconn.cs.stream);
2296 if(ret < 0) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002297 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Garmond Leung37850ab2016-10-06 11:42:18 -07002298 return -EINVAL;
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002299 }
2300
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002301 switch (channels) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002302 case 8:
Mingming Yin3a941d42016-02-17 18:08:05 -08002303 ALOGV("%s: HDMI supports 7.1 channels", __func__);
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07002304 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_7POINT1;
Mingming Yin3a941d42016-02-17 18:08:05 -08002305 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_6POINT1;
2306 case 6:
2307 ALOGV("%s: HDMI supports 5.1 channels", __func__);
2308 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
2309 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
2310 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
2311 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_SURROUND;
2312 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_2POINT1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002313 break;
2314 default:
Mingming Yin3a941d42016-02-17 18:08:05 -08002315 ALOGE("invalid/nonstandard channal count[%d]",channels);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002316 ret = -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002317 break;
2318 }
Mingming Yin3a941d42016-02-17 18:08:05 -08002319
2320 // check channel format caps
2321 i = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002322 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_AC3,
2323 out->extconn.cs.controller,
2324 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002325 ALOGV(":%s HDMI supports AC3/EAC3 formats", __func__);
2326 out->supported_formats[i++] = AUDIO_FORMAT_AC3;
2327 //Adding EAC3/EAC3_JOC formats if AC3 is supported by the sink.
2328 //EAC3/EAC3_JOC will be converted to AC3 for decoding if needed
2329 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
2330 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
2331 }
2332
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002333 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD,
2334 out->extconn.cs.controller,
2335 out->extconn.cs.stream)) {
Ben Romberger1aaaf862017-04-06 17:49:46 -07002336 ALOGV(":%s HDMI supports TRUE HD format", __func__);
2337 out->supported_formats[i++] = AUDIO_FORMAT_DOLBY_TRUEHD;
2338 }
2339
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002340 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS,
2341 out->extconn.cs.controller,
2342 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002343 ALOGV(":%s HDMI supports DTS format", __func__);
2344 out->supported_formats[i++] = AUDIO_FORMAT_DTS;
2345 }
2346
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002347 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS_HD,
2348 out->extconn.cs.controller,
2349 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002350 ALOGV(":%s HDMI supports DTS HD format", __func__);
2351 out->supported_formats[i++] = AUDIO_FORMAT_DTS_HD;
2352 }
2353
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002354 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_IEC61937,
2355 out->extconn.cs.controller,
2356 out->extconn.cs.stream)) {
Naresh Tanniru928f0862017-04-07 16:44:23 -07002357 ALOGV(":%s HDMI supports IEC61937 format", __func__);
2358 out->supported_formats[i++] = AUDIO_FORMAT_IEC61937;
2359 }
2360
Mingming Yin3a941d42016-02-17 18:08:05 -08002361
2362 // check sample rate caps
2363 i = 0;
2364 for (j = 0; j < MAX_SUPPORTED_SAMPLE_RATES; j++) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002365 if (platform_is_edid_supported_sample_rate_v2(out->dev->platform, out_hdmi_sample_rates[j],
2366 out->extconn.cs.controller,
2367 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002368 ALOGV(":%s HDMI supports sample rate:%d", __func__, out_hdmi_sample_rates[j]);
2369 out->supported_sample_rates[i++] = out_hdmi_sample_rates[j];
2370 }
2371 }
2372
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002373 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002374}
2375
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002376static inline ssize_t read_usb_sup_sample_rates(bool is_playback __unused,
2377 uint32_t *supported_sample_rates __unused,
2378 uint32_t max_rates __unused)
2379{
2380 ssize_t count = audio_extn_usb_get_sup_sample_rates(is_playback,
2381 supported_sample_rates,
2382 max_rates);
Ashish Jain4847e9d2017-08-17 19:16:57 +05302383 ssize_t i = 0;
2384
2385 for (i=0; i<count; i++) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002386 ALOGV("%s %s %d", __func__, is_playback ? "P" : "C",
2387 supported_sample_rates[i]);
2388 }
2389 return count;
2390}
2391
2392static inline int read_usb_sup_channel_masks(bool is_playback,
2393 audio_channel_mask_t *supported_channel_masks,
2394 uint32_t max_masks)
2395{
2396 int channels = audio_extn_usb_get_max_channels(is_playback);
2397 int channel_count;
2398 uint32_t num_masks = 0;
2399 if (channels > MAX_HIFI_CHANNEL_COUNT)
2400 channels = MAX_HIFI_CHANNEL_COUNT;
2401
2402 if (is_playback) {
Eric Laurent68a87112019-05-01 18:07:29 -07002403 // start from 2 channels as framework currently doesn't support mono.
2404 if (channels >= FCC_2) {
2405 supported_channel_masks[num_masks++] = audio_channel_out_mask_from_count(FCC_2);
2406 }
2407 for (channel_count = FCC_2;
2408 channel_count <= channels && num_masks < max_masks;
2409 ++channel_count) {
2410 supported_channel_masks[num_masks++] =
2411 audio_channel_mask_for_index_assignment_from_count(channel_count);
2412 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002413 } else {
vincenttewf51c94e2019-05-07 10:28:53 +08002414 // For capture we report all supported channel masks from 1 channel up.
2415 channel_count = MIN_CHANNEL_COUNT;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002416 // audio_channel_in_mask_from_count() does the right conversion to either positional or
2417 // indexed mask
Eric Laurent68a87112019-05-01 18:07:29 -07002418 for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
2419 audio_channel_mask_t mask = AUDIO_CHANNEL_NONE;
2420 if (channel_count <= FCC_2) {
2421 mask = audio_channel_in_mask_from_count(channel_count);
2422 supported_channel_masks[num_masks++] = mask;
2423 }
2424 const audio_channel_mask_t index_mask =
2425 audio_channel_mask_for_index_assignment_from_count(channel_count);
2426 if (mask != index_mask && num_masks < max_masks) { // ensure index mask added.
2427 supported_channel_masks[num_masks++] = index_mask;
2428 }
2429 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002430 }
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302431
vincenttewf51c94e2019-05-07 10:28:53 +08002432 for (size_t i = 0; i < num_masks; ++i) {
2433 ALOGV("%s: %s supported ch %d supported_channel_masks[%zu] %08x num_masks %d", __func__,
2434 is_playback ? "P" : "C", channels, i, supported_channel_masks[i], num_masks);
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302435 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002436 return num_masks;
2437}
2438
2439static inline int read_usb_sup_formats(bool is_playback __unused,
2440 audio_format_t *supported_formats,
2441 uint32_t max_formats __unused)
2442{
2443 int bitwidth = audio_extn_usb_get_max_bit_width(is_playback);
2444 switch (bitwidth) {
2445 case 24:
2446 // XXX : usb.c returns 24 for s24 and s24_le?
2447 supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
2448 break;
2449 case 32:
2450 supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
2451 break;
2452 case 16:
2453 default :
2454 supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
2455 break;
2456 }
2457 ALOGV("%s: %s supported format %d", __func__,
2458 is_playback ? "P" : "C", bitwidth);
2459 return 1;
2460}
2461
2462static inline int read_usb_sup_params_and_compare(bool is_playback,
2463 audio_format_t *format,
2464 audio_format_t *supported_formats,
2465 uint32_t max_formats,
2466 audio_channel_mask_t *mask,
2467 audio_channel_mask_t *supported_channel_masks,
2468 uint32_t max_masks,
2469 uint32_t *rate,
2470 uint32_t *supported_sample_rates,
2471 uint32_t max_rates) {
2472 int ret = 0;
2473 int num_formats;
2474 int num_masks;
2475 int num_rates;
2476 int i;
2477
2478 num_formats = read_usb_sup_formats(is_playback, supported_formats,
2479 max_formats);
2480 num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
2481 max_masks);
2482
2483 num_rates = read_usb_sup_sample_rates(is_playback,
2484 supported_sample_rates, max_rates);
2485
2486#define LUT(table, len, what, dflt) \
2487 for (i=0; i<len && (table[i] != what); i++); \
2488 if (i==len) { ret |= (what == dflt ? 0 : -1); what=table[0]; }
2489
2490 LUT(supported_formats, num_formats, *format, AUDIO_FORMAT_DEFAULT);
2491 LUT(supported_channel_masks, num_masks, *mask, AUDIO_CHANNEL_NONE);
2492 LUT(supported_sample_rates, num_rates, *rate, 0);
2493
2494#undef LUT
2495 return ret < 0 ? -EINVAL : 0; // HACK TBD
2496}
2497
Alexy Josephb1379942016-01-29 15:49:38 -08002498audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002499 usecase_type_t type)
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002500{
2501 struct audio_usecase *usecase;
2502 struct listnode *node;
2503
2504 list_for_each(node, &adev->usecase_list) {
2505 usecase = node_to_item(node, struct audio_usecase, list);
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002506 if (usecase->type == type) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002507 ALOGV("%s: usecase id %d", __func__, usecase->id);
2508 return usecase->id;
2509 }
2510 }
2511 return USECASE_INVALID;
2512}
2513
Alexy Josephb1379942016-01-29 15:49:38 -08002514struct audio_usecase *get_usecase_from_list(const struct audio_device *adev,
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002515 audio_usecase_t uc_id)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002516{
2517 struct audio_usecase *usecase;
2518 struct listnode *node;
2519
2520 list_for_each(node, &adev->usecase_list) {
2521 usecase = node_to_item(node, struct audio_usecase, list);
2522 if (usecase->id == uc_id)
2523 return usecase;
2524 }
2525 return NULL;
2526}
2527
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302528/*
2529 * is a true native playback active
2530 */
2531bool audio_is_true_native_stream_active(struct audio_device *adev)
2532{
2533 bool active = false;
2534 int i = 0;
2535 struct listnode *node;
2536
2537 if (NATIVE_AUDIO_MODE_TRUE_44_1 != platform_get_native_support()) {
2538 ALOGV("%s:napb: not in true mode or non hdphones device",
2539 __func__);
2540 active = false;
2541 goto exit;
2542 }
2543
2544 list_for_each(node, &adev->usecase_list) {
2545 struct audio_usecase *uc;
2546 uc = node_to_item(node, struct audio_usecase, list);
2547 struct stream_out *curr_out =
2548 (struct stream_out*) uc->stream.out;
2549
2550 if (curr_out && PCM_PLAYBACK == uc->type) {
2551 ALOGD("%s:napb: (%d) (%s)id (%d) sr %d bw "
2552 "(%d) device %s", __func__, i++, use_case_table[uc->id],
2553 uc->id, curr_out->sample_rate,
2554 curr_out->bit_width,
2555 platform_get_snd_device_name(uc->out_snd_device));
2556
2557 if (is_offload_usecase(uc->id) &&
2558 (curr_out->sample_rate == OUTPUT_SAMPLING_RATE_44100)) {
2559 active = true;
2560 ALOGD("%s:napb:native stream detected", __func__);
2561 }
2562 }
2563 }
2564exit:
2565 return active;
2566}
2567
Xiaojun Sang785b5da2017-08-03 15:52:29 +08002568uint32_t adev_get_dsp_bit_width_enforce_mode()
2569{
2570 if (adev == NULL) {
2571 ALOGE("%s: adev is null. Disable DSP bit width enforce mode.\n", __func__);
2572 return 0;
2573 }
2574 return adev->dsp_bit_width_enforce_mode;
2575}
2576
2577static uint32_t adev_init_dsp_bit_width_enforce_mode(struct mixer *mixer)
2578{
2579 char value[PROPERTY_VALUE_MAX];
2580 int trial;
2581 uint32_t dsp_bit_width_enforce_mode = 0;
2582
2583 if (!mixer) {
2584 ALOGE("%s: adev mixer is null. cannot update DSP bitwidth.\n",
2585 __func__);
2586 return 0;
2587 }
2588
2589 if (property_get("persist.vendor.audio_hal.dsp_bit_width_enforce_mode",
2590 value, NULL) > 0) {
2591 trial = atoi(value);
2592 switch (trial) {
2593 case 16:
2594 dsp_bit_width_enforce_mode = 16;
2595 break;
2596 case 24:
2597 dsp_bit_width_enforce_mode = 24;
2598 break;
2599 case 32:
2600 dsp_bit_width_enforce_mode = 32;
2601 break;
2602 default:
2603 dsp_bit_width_enforce_mode = 0;
2604 ALOGD("%s Dynamic DSP bitwidth config is disabled.", __func__);
2605 break;
2606 }
2607 }
2608
2609 return dsp_bit_width_enforce_mode;
2610}
2611
2612static void audio_enable_asm_bit_width_enforce_mode(struct mixer *mixer,
2613 uint32_t enforce_mode,
2614 bool enable)
2615{
2616 struct mixer_ctl *ctl = NULL;
2617 const char *mixer_ctl_name = "ASM Bit Width";
2618 uint32_t asm_bit_width_mode = 0;
2619
2620 if (enforce_mode == 0) {
2621 ALOGD("%s: DSP bitwidth feature is disabled.", __func__);
2622 return;
2623 }
2624
2625 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
2626 if (!ctl) {
2627 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2628 __func__, mixer_ctl_name);
2629 return;
2630 }
2631
2632 if (enable)
2633 asm_bit_width_mode = enforce_mode;
2634 else
2635 asm_bit_width_mode = 0;
2636
2637 ALOGV("%s DSP bit width feature status is %d width=%d",
2638 __func__, enable, asm_bit_width_mode);
2639 if (mixer_ctl_set_value(ctl, 0, asm_bit_width_mode) < 0)
2640 ALOGE("%s: Could not set ASM biwidth %d", __func__,
2641 asm_bit_width_mode);
2642
2643 return;
2644}
2645
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302646/*
2647 * if native DSD playback active
2648 */
2649bool audio_is_dsd_native_stream_active(struct audio_device *adev)
2650{
2651 bool active = false;
2652 struct listnode *node = NULL;
2653 struct audio_usecase *uc = NULL;
2654 struct stream_out *curr_out = NULL;
2655
2656 list_for_each(node, &adev->usecase_list) {
2657 uc = node_to_item(node, struct audio_usecase, list);
2658 curr_out = (struct stream_out*) uc->stream.out;
2659
2660 if (curr_out && PCM_PLAYBACK == uc->type &&
2661 (DSD_NATIVE_BACKEND == platform_get_backend_index(uc->out_snd_device))) {
2662 active = true;
2663 ALOGV("%s:DSD playback is active", __func__);
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05302664 break;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302665 }
2666 }
2667 return active;
2668}
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302669
2670static bool force_device_switch(struct audio_usecase *usecase)
2671{
2672 bool ret = false;
2673 bool is_it_true_mode = false;
2674
Zhou Song30f2c3e2018-02-08 14:02:15 +08002675 if (usecase->type == PCM_CAPTURE ||
Surendar Karka93cd25a2018-08-28 14:21:37 +05302676 usecase->type == TRANSCODE_LOOPBACK_RX ||
2677 usecase->type == TRANSCODE_LOOPBACK_TX) {
Zhou Song30f2c3e2018-02-08 14:02:15 +08002678 return false;
2679 }
2680
Aalique Grahamecbc46a22017-10-05 10:30:23 -07002681 if(usecase->stream.out == NULL) {
2682 ALOGE("%s: stream.out is NULL", __func__);
2683 return false;
2684 }
2685
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302686 if (is_offload_usecase(usecase->id) &&
Xiaojun Sang869f2012016-02-23 16:33:07 +08002687 (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002688 (compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
2689 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302690 is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
2691 if ((is_it_true_mode && !adev->native_playback_enabled) ||
2692 (!is_it_true_mode && adev->native_playback_enabled)){
2693 ret = true;
2694 ALOGD("napb: time to toggle native mode");
2695 }
2696 }
2697
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302698 // Force all a2dp output devices to reconfigure for proper AFE encode format
Ashish Jainc597d102016-12-12 10:31:34 +05302699 //Also handle a case where in earlier a2dp start failed as A2DP stream was
2700 //in suspended state, hence try to trigger a retry when we again get a routing request.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002701 if(is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Ashish Jainc597d102016-12-12 10:31:34 +05302702 audio_extn_a2dp_is_force_device_switch()) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302703 ALOGD("Force a2dp device switch to update new encoder config");
2704 ret = true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002705 }
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302706
Florian Pfister1a84f312018-07-19 14:38:18 +02002707 if (usecase->stream.out->stream_config_changed) {
Manish Dewangan671a4202017-08-18 17:30:46 +05302708 ALOGD("Force stream_config_changed to update iec61937 transmission config");
2709 return true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002710 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302711 return ret;
2712}
2713
Aalique Grahame22e49102018-12-18 14:23:57 -08002714static void stream_app_type_cfg_init(struct stream_app_type_cfg *cfg)
2715{
2716 cfg->gain[0] = cfg->gain[1] = APP_TYPE_GAIN_DEFAULT;
2717}
2718
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302719bool is_btsco_device(snd_device_t out_snd_device, snd_device_t in_snd_device)
2720{
2721 bool ret=false;
2722 if ((out_snd_device == SND_DEVICE_OUT_BT_SCO ||
Zhou Song5657f492019-08-07 11:30:39 +08002723 out_snd_device == SND_DEVICE_OUT_BT_SCO_WB ||
2724 out_snd_device == SND_DEVICE_OUT_BT_SCO_SWB) ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302725 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC ||
2726 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB ||
Zhou Song5657f492019-08-07 11:30:39 +08002727 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302728 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC ||
Mingshu Pang16093502020-04-20 11:21:16 +08002729 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC ||
2730 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC)
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302731 ret = true;
2732
2733 return ret;
2734}
2735
2736bool is_a2dp_device(snd_device_t out_snd_device)
2737{
2738 bool ret=false;
2739 if (out_snd_device == SND_DEVICE_OUT_BT_A2DP)
2740 ret = true;
2741
2742 return ret;
2743}
2744
2745bool is_bt_soc_on(struct audio_device *adev)
2746{
2747 struct mixer_ctl *ctl;
2748 char *mixer_ctl_name = "BT SOC status";
2749 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
2750 bool bt_soc_status = true;
2751 if (!ctl) {
2752 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2753 __func__, mixer_ctl_name);
2754 /*This is to ensure we dont break targets which dont have the kernel change*/
2755 return true;
2756 }
2757 bt_soc_status = mixer_ctl_get_value(ctl, 0);
2758 ALOGD("BT SOC status: %d",bt_soc_status);
2759 return bt_soc_status;
2760}
2761
Zhou Song331c8e52019-08-26 14:16:12 +08002762static int configure_btsco_sample_rate(snd_device_t snd_device)
2763{
2764 struct mixer_ctl *ctl = NULL;
2765 struct mixer_ctl *ctl_sr_rx = NULL, *ctl_sr_tx = NULL, *ctl_sr = NULL;
2766 char *rate_str = NULL;
2767 bool is_rx_dev = true;
2768
2769 if (is_btsco_device(snd_device, snd_device)) {
2770 ctl_sr_tx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate TX");
2771 ctl_sr_rx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate RX");
2772 if (!ctl_sr_tx || !ctl_sr_rx) {
2773 ctl_sr = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate");
2774 if (!ctl_sr)
2775 return -ENOSYS;
2776 }
2777
2778 switch (snd_device) {
2779 case SND_DEVICE_OUT_BT_SCO:
2780 rate_str = "KHZ_8";
2781 break;
2782 case SND_DEVICE_IN_BT_SCO_MIC_NREC:
2783 case SND_DEVICE_IN_BT_SCO_MIC:
2784 rate_str = "KHZ_8";
2785 is_rx_dev = false;
2786 break;
2787 case SND_DEVICE_OUT_BT_SCO_WB:
2788 rate_str = "KHZ_16";
2789 break;
2790 case SND_DEVICE_IN_BT_SCO_MIC_WB_NREC:
2791 case SND_DEVICE_IN_BT_SCO_MIC_WB:
2792 rate_str = "KHZ_16";
2793 is_rx_dev = false;
2794 break;
2795 default:
2796 return 0;
2797 }
2798
2799 ctl = (ctl_sr == NULL) ? (is_rx_dev ? ctl_sr_rx : ctl_sr_tx) : ctl_sr;
2800 if (mixer_ctl_set_enum_by_string(ctl, rate_str) != 0)
2801 return -ENOSYS;
2802 }
2803 return 0;
2804}
2805
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302806int out_standby_l(struct audio_stream *stream);
2807
Eric Laurent637e2d42018-11-15 12:24:31 -08002808struct stream_in *adev_get_active_input(const struct audio_device *adev)
2809{
2810 struct listnode *node;
2811 struct stream_in *last_active_in = NULL;
2812
2813 /* Get last added active input.
2814 * TODO: We may use a priority mechanism to pick highest priority active source */
2815 list_for_each(node, &adev->usecase_list)
2816 {
2817 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2818 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL)
2819 last_active_in = usecase->stream.in;
2820 }
2821
2822 return last_active_in;
2823}
2824
2825struct stream_in *get_voice_communication_input(const struct audio_device *adev)
2826{
2827 struct listnode *node;
2828
2829 /* First check active inputs with voice communication source and then
2830 * any input if audio mode is in communication */
2831 list_for_each(node, &adev->usecase_list)
2832 {
2833 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2834 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL &&
2835 usecase->stream.in->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
2836 return usecase->stream.in;
2837 }
2838 if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
2839 return adev_get_active_input(adev);
2840
2841 return NULL;
2842}
2843
Carter Hsu2e429db2019-05-14 18:50:52 +08002844/*
2845 * Aligned with policy.h
2846 */
2847static inline int source_priority(int inputSource)
2848{
2849 switch (inputSource) {
2850 case AUDIO_SOURCE_VOICE_COMMUNICATION:
2851 return 9;
2852 case AUDIO_SOURCE_CAMCORDER:
2853 return 8;
2854 case AUDIO_SOURCE_VOICE_PERFORMANCE:
2855 return 7;
2856 case AUDIO_SOURCE_UNPROCESSED:
2857 return 6;
2858 case AUDIO_SOURCE_MIC:
2859 return 5;
2860 case AUDIO_SOURCE_ECHO_REFERENCE:
2861 return 4;
2862 case AUDIO_SOURCE_FM_TUNER:
2863 return 3;
2864 case AUDIO_SOURCE_VOICE_RECOGNITION:
2865 return 2;
2866 case AUDIO_SOURCE_HOTWORD:
2867 return 1;
2868 default:
2869 break;
2870 }
2871 return 0;
2872}
2873
2874static struct stream_in *get_priority_input(struct audio_device *adev)
2875{
2876 struct listnode *node;
2877 struct audio_usecase *usecase;
2878 int last_priority = 0, priority;
2879 struct stream_in *priority_in = NULL;
2880 struct stream_in *in;
2881
2882 list_for_each(node, &adev->usecase_list) {
2883 usecase = node_to_item(node, struct audio_usecase, list);
2884 if (usecase->type == PCM_CAPTURE) {
2885 in = usecase->stream.in;
2886 if (!in)
2887 continue;
Krishna Kishor Jha0b7175d2022-07-28 22:33:46 +05302888
2889 if (USECASE_AUDIO_RECORD_FM_VIRTUAL == usecase->id)
2890 continue;
Carter Hsu2e429db2019-05-14 18:50:52 +08002891 priority = source_priority(in->source);
2892
2893 if (priority > last_priority) {
2894 last_priority = priority;
2895 priority_in = in;
2896 }
2897 }
2898 }
2899 return priority_in;
2900}
2901
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002902int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002903{
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08002904 snd_device_t out_snd_device = SND_DEVICE_NONE;
2905 snd_device_t in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002906 struct audio_usecase *usecase = NULL;
2907 struct audio_usecase *vc_usecase = NULL;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002908 struct audio_usecase *voip_usecase = NULL;
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002909 struct audio_usecase *hfp_usecase = NULL;
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302910 struct stream_out stream_out;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08002911 audio_usecase_t hfp_ucid;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002912 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002913
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302914 ALOGD("%s for use case (%s)", __func__, use_case_table[uc_id]);
2915
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002916 usecase = get_usecase_from_list(adev, uc_id);
2917 if (usecase == NULL) {
2918 ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
2919 return -EINVAL;
2920 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002921
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002922 if ((usecase->type == VOICE_CALL) ||
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08002923 (usecase->type == VOIP_CALL) ||
Derek Chena30a5f42019-12-03 11:17:09 -05002924 (usecase->type == PCM_HFP_CALL)||
Fei Tongaffdf732020-02-20 20:39:05 +08002925 (usecase->type == ICC_CALL) ||
2926 (usecase->type == SYNTH_LOOPBACK)) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302927 if(usecase->stream.out == NULL) {
2928 ALOGE("%s: stream.out is NULL", __func__);
2929 return -EINVAL;
2930 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002931 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS)) {
Guodong Hu267bdf82019-08-12 19:22:32 +08002932 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
2933 uc_id);
2934 in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
2935 uc_id);
2936 } else {
2937 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302938 usecase->stream.out, usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002939 in_snd_device = platform_get_input_snd_device(adev->platform,
2940 NULL,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302941 &usecase->stream.out->device_list,
2942 usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002943 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002944 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302945 } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
Siddartha Shaik31b530e2017-05-19 15:26:33 +05302946 if (usecase->stream.inout == NULL) {
2947 ALOGE("%s: stream.inout is NULL", __func__);
2948 return -EINVAL;
2949 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002950 assign_devices(&stream_out.device_list, &usecase->stream.inout->out_config.device_list);
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302951 stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
2952 stream_out.format = usecase->stream.inout->out_config.format;
2953 stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
Jaideep Sharma477917f2020-03-13 18:13:33 +05302954 out_snd_device = platform_get_output_snd_device(adev->platform, &stream_out, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002955 assign_devices(&usecase->device_list,
2956 &usecase->stream.inout->out_config.device_list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05302957 clear_devices(&stream_out.device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302958 } else if (usecase->type == TRANSCODE_LOOPBACK_TX ) {
2959 if (usecase->stream.inout == NULL) {
2960 ALOGE("%s: stream.inout is NULL", __func__);
2961 return -EINVAL;
2962 }
Manisha Agarwal03297972020-04-17 15:36:55 +05302963 struct listnode out_devices;
2964 list_init(&out_devices);
2965 in_snd_device = platform_get_input_snd_device(adev->platform, NULL,
2966 &out_devices, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002967 assign_devices(&usecase->device_list,
2968 &usecase->stream.inout->in_config.device_list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05302969 clear_devices(&out_devices);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002970 } else {
2971 /*
2972 * If the voice call is active, use the sound devices of voice call usecase
2973 * so that it would not result any device switch. All the usecases will
2974 * be switched to new device when select_devices() is called for voice call
2975 * usecase. This is to avoid switching devices for voice call when
2976 * check_usecases_codec_backend() is called below.
Alexy Joseph79dfa3c2016-04-20 18:44:56 -07002977 * choose voice call device only if the use case device is
2978 * also using the codec backend
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002979 */
Shiv Maliyappanahallibb4cf0b2016-01-21 11:30:06 -08002980 if (voice_is_in_call(adev) && adev->mode != AUDIO_MODE_NORMAL) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002981 vc_usecase = get_usecase_from_list(adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002982 get_usecase_id_from_usecase_type(adev, VOICE_CALL));
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002983 if ((vc_usecase) && ((is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2984 is_codec_backend_out_device_type(&usecase->device_list)) ||
2985 (is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2986 is_codec_backend_in_device_type(&usecase->device_list)) ||
2987 is_single_device_type_equal(&vc_usecase->device_list,
2988 AUDIO_DEVICE_OUT_HEARING_AID) ||
2989 is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002990 AUDIO_DEVICE_IN_VOICE_CALL) ||
2991 (is_single_device_type_equal(&usecase->device_list,
Gautam Manam8fa06162021-09-24 10:41:29 +05302992 AUDIO_DEVICE_IN_BUILTIN_MIC) &&
2993 is_single_device_type_equal(&vc_usecase->device_list,
2994 AUDIO_DEVICE_OUT_USB_HEADSET)) ||
2995 (is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002996 AUDIO_DEVICE_IN_USB_HEADSET) &&
2997 is_single_device_type_equal(&vc_usecase->device_list,
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05302998 AUDIO_DEVICE_OUT_USB_HEADSET))||
Gautam Manamf4002142021-09-13 22:05:56 +05302999 (is_single_device_type_equal(&usecase->device_list,
3000 AUDIO_DEVICE_IN_USB_HEADSET) &&
3001 is_codec_backend_out_device_type(&vc_usecase->device_list)) ||
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05303002 (is_single_device_type_equal(&usecase->device_list,
3003 AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) &&
3004 is_codec_backend_out_device_type(&vc_usecase->device_list)))) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003005 in_snd_device = vc_usecase->in_snd_device;
3006 out_snd_device = vc_usecase->out_snd_device;
3007 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08003008 } else if (voice_extn_compress_voip_is_active(adev)) {
yidongh02ef86f2017-04-21 15:36:04 +08003009 bool out_snd_device_backend_match = true;
yidongh47785a82017-05-08 19:29:29 +08003010 voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
yidongh6261d8e2017-05-15 17:04:02 +08003011 if ((voip_usecase != NULL) &&
3012 (usecase->type == PCM_PLAYBACK) &&
3013 (usecase->stream.out != NULL)) {
yidongh02ef86f2017-04-21 15:36:04 +08003014 out_snd_device_backend_match = platform_check_backends_match(
3015 voip_usecase->out_snd_device,
3016 platform_get_output_snd_device(
3017 adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05303018 usecase->stream.out, usecase->type));
yidongh02ef86f2017-04-21 15:36:04 +08003019 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003020 if ((voip_usecase) && (is_codec_backend_out_device_type(&voip_usecase->device_list) &&
3021 (is_codec_backend_out_device_type(&usecase->device_list) ||
3022 is_codec_backend_in_device_type(&usecase->device_list)) &&
yidongh02ef86f2017-04-21 15:36:04 +08003023 out_snd_device_backend_match &&
Mingming Yin2d8aa2e2014-08-14 00:00:51 -07003024 (voip_usecase->stream.out != adev->primary_output))) {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08003025 in_snd_device = voip_usecase->in_snd_device;
3026 out_snd_device = voip_usecase->out_snd_device;
3027 }
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08003028 } else if (audio_extn_hfp_is_active(adev)) {
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08003029 hfp_ucid = audio_extn_hfp_get_usecase();
3030 hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003031 if ((hfp_usecase) && is_codec_backend_out_device_type(&hfp_usecase->device_list)) {
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08003032 in_snd_device = hfp_usecase->in_snd_device;
3033 out_snd_device = hfp_usecase->out_snd_device;
3034 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003035 }
3036 if (usecase->type == PCM_PLAYBACK) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05303037 if (usecase->stream.out == NULL) {
3038 ALOGE("%s: stream.out is NULL", __func__);
3039 return -EINVAL;
3040 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003041 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003042 in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003043 if (out_snd_device == SND_DEVICE_NONE) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003044 struct stream_out *voip_out = adev->primary_output;
3045 struct stream_in *voip_in = get_voice_communication_input(adev);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003046 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
Guodong Hu267bdf82019-08-12 19:22:32 +08003047 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
3048 else
3049 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05303050 usecase->stream.out,
3051 usecase->type);
kunleizdcf967a2018-08-07 17:09:11 +08003052 voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP);
kunleizdcf967a2018-08-07 17:09:11 +08003053
Eric Laurent637e2d42018-11-15 12:24:31 -08003054 if (voip_usecase)
3055 voip_out = voip_usecase->stream.out;
3056
3057 if (usecase->stream.out == voip_out && voip_in != NULL)
3058 select_devices(adev, voip_in->usecase);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003059 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003060 } else if (usecase->type == PCM_CAPTURE) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05303061 if (usecase->stream.in == NULL) {
3062 ALOGE("%s: stream.in is NULL", __func__);
3063 return -EINVAL;
3064 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003065 assign_devices(&usecase->device_list, &usecase->stream.in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003066 out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003067 if (in_snd_device == SND_DEVICE_NONE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003068 struct listnode out_devices;
Eric Laurent637e2d42018-11-15 12:24:31 -08003069 struct stream_in *voip_in = get_voice_communication_input(adev);
Carter Hsu2e429db2019-05-14 18:50:52 +08003070 struct stream_in *priority_in = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08003071
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003072 list_init(&out_devices);
Eric Laurent637e2d42018-11-15 12:24:31 -08003073 if (voip_in != NULL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003074 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3075 USECASE_AUDIO_PLAYBACK_VOIP);
3076
Carter Hsu2e429db2019-05-14 18:50:52 +08003077 usecase->stream.in->enable_ec_port = false;
3078
Zhou Song503196b2021-07-23 17:31:05 +08003079 if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY ||
3080 usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY2) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003081 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08003082 } else if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003083 assign_devices(&out_devices, &voip_usecase->stream.out->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08003084 } else if (adev->primary_output &&
3085 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003086 assign_devices(&out_devices, &adev->primary_output->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08003087 } else {
3088 /* forcing speaker o/p device to get matching i/p pair
3089 in case o/p is not routed from same primary HAL */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003090 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08003091 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003092 priority_in = voip_in;
3093 } else {
3094 /* get the input with the highest priority source*/
3095 priority_in = get_priority_input(adev);
3096
Susan Wang727dd6b2021-03-26 11:28:59 -04003097 if (!priority_in ||
3098 audio_extn_auto_hal_overwrite_priority_for_auto(usecase->stream.in))
Carter Hsu2e429db2019-05-14 18:50:52 +08003099 priority_in = usecase->stream.in;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003100 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04003101 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_IN_BUS)){
3102 in_snd_device = audio_extn_auto_hal_get_snd_device_for_car_audio_stream(priority_in->car_audio_stream);
3103 }
3104 else
3105 in_snd_device = platform_get_input_snd_device(adev->platform,
3106 priority_in,
3107 &out_devices,
3108 usecase->type);
Zhenlin Lian4f947842022-05-14 15:50:52 +05303109 clear_devices(&out_devices);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003110 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003111 }
3112 }
3113
3114 if (out_snd_device == usecase->out_snd_device &&
3115 in_snd_device == usecase->in_snd_device) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05303116
3117 if (!force_device_switch(usecase))
3118 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003119 }
3120
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003121 if (!compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) &&
Guodong Hu267bdf82019-08-12 19:22:32 +08003122 ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003123 (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
Guodong Hu267bdf82019-08-12 19:22:32 +08003124 ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
3125 return 0;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303126 }
3127
Aalique Grahame22e49102018-12-18 14:23:57 -08003128 if (out_snd_device != SND_DEVICE_NONE &&
3129 out_snd_device != adev->last_logged_snd_device[uc_id][0]) {
3130 ALOGD("%s: changing use case %s output device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3131 __func__,
3132 use_case_table[uc_id],
3133 adev->last_logged_snd_device[uc_id][0],
3134 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][0]),
3135 adev->last_logged_snd_device[uc_id][0] != SND_DEVICE_NONE ?
3136 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][0]) :
3137 -1,
3138 out_snd_device,
3139 platform_get_snd_device_name(out_snd_device),
3140 platform_get_snd_device_acdb_id(out_snd_device));
3141 adev->last_logged_snd_device[uc_id][0] = out_snd_device;
3142 }
3143 if (in_snd_device != SND_DEVICE_NONE &&
3144 in_snd_device != adev->last_logged_snd_device[uc_id][1]) {
3145 ALOGD("%s: changing use case %s input device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3146 __func__,
3147 use_case_table[uc_id],
3148 adev->last_logged_snd_device[uc_id][1],
3149 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][1]),
3150 adev->last_logged_snd_device[uc_id][1] != SND_DEVICE_NONE ?
3151 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][1]) :
3152 -1,
3153 in_snd_device,
3154 platform_get_snd_device_name(in_snd_device),
3155 platform_get_snd_device_acdb_id(in_snd_device));
3156 adev->last_logged_snd_device[uc_id][1] = in_snd_device;
3157 }
3158
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08003159
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003160 /*
3161 * Limitation: While in call, to do a device switch we need to disable
3162 * and enable both RX and TX devices though one of them is same as current
3163 * device.
3164 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003165 if ((usecase->type == VOICE_CALL) &&
3166 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3167 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Eric Laurentb23d5282013-05-14 15:27:20 -07003168 status = platform_switch_voice_call_device_pre(adev->platform);
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003169 }
3170
3171 if (((usecase->type == VOICE_CALL) ||
3172 (usecase->type == VOIP_CALL)) &&
3173 (usecase->out_snd_device != SND_DEVICE_NONE)) {
3174 /* Disable sidetone only if voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303175 if (voice_is_call_state_active_in_call(adev) ||
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003176 voice_extn_compress_voip_is_started(adev))
Bhalchandra Gajare45fee282015-06-09 22:23:45 -07003177 voice_set_sidetone(adev, usecase->out_snd_device, false);
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003178
3179 /* Disable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303180 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003181 voice_check_and_update_aanc_path(adev, usecase->out_snd_device, false);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003182 }
3183
Aalique Grahame22e49102018-12-18 14:23:57 -08003184 if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
3185 out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02003186 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303187 ALOGW("%s: A2DP profile is not ready, routing to speaker only", __func__);
Aalique Grahame22e49102018-12-18 14:23:57 -08003188 if (out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)
3189 out_snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
3190 else
3191 out_snd_device = SND_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303192 }
3193
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003194 /* Disable current sound devices */
3195 if (usecase->out_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003196 disable_audio_route(adev, usecase);
3197 disable_snd_device(adev, usecase->out_snd_device);
Gautam Manam274f4752021-09-24 10:58:49 +05303198 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3199 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003200 }
3201
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003202 if (usecase->in_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003203 disable_audio_route(adev, usecase);
3204 disable_snd_device(adev, usecase->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003205 }
3206
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003207 /* Applicable only on the targets that has external modem.
3208 * New device information should be sent to modem before enabling
3209 * the devices to reduce in-call device switch time.
3210 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003211 if ((usecase->type == VOICE_CALL) &&
3212 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3213 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003214 status = platform_switch_voice_call_enable_device_config(adev->platform,
3215 out_snd_device,
3216 in_snd_device);
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003217 }
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003218
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003219 /* Enable new sound devices */
3220 if (out_snd_device != SND_DEVICE_NONE) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08003221 check_usecases_codec_backend(adev, usecase, out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05303222 check_and_configure_headphone(adev, usecase, out_snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05303223 if (platform_check_codec_asrc_support(adev->platform))
3224 check_and_set_asrc_mode(adev, usecase, out_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003225 enable_snd_device(adev, out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08003226 /* Enable haptics device for haptic usecase */
3227 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3228 enable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003229 }
3230
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003231 if (in_snd_device != SND_DEVICE_NONE) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05303232 check_usecases_capture_codec_backend(adev, usecase, in_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003233 enable_snd_device(adev, in_snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003234 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003235
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05303236 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
Eric Laurentb23d5282013-05-14 15:27:20 -07003237 status = platform_switch_voice_call_device_post(adev->platform,
3238 out_snd_device,
3239 in_snd_device);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003240
sangwoo170731f2013-06-08 15:36:36 +09003241 usecase->in_snd_device = in_snd_device;
3242 usecase->out_snd_device = out_snd_device;
3243
Dhananjay Kumard6d32152016-10-13 16:11:03 +05303244 audio_extn_utils_update_stream_app_type_cfg_for_usecase(adev,
3245 usecase);
Preetam Singh Ranawata4a37d82014-09-25 16:56:38 +05303246 if (usecase->type == PCM_PLAYBACK) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003247 if ((24 == usecase->stream.out->bit_width) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003248 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_SPEAKER)) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003249 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3250 } else if ((out_snd_device == SND_DEVICE_OUT_HDMI ||
3251 out_snd_device == SND_DEVICE_OUT_USB_HEADSET ||
3252 out_snd_device == SND_DEVICE_OUT_DISPLAY_PORT) &&
3253 (usecase->stream.out->sample_rate >= OUTPUT_SAMPLING_RATE_44100)) {
3254 /*
3255 * To best utlize DSP, check if the stream sample rate is supported/multiple of
3256 * configured device sample rate, if not update the COPP rate to be equal to the
3257 * device sample rate, else open COPP at stream sample rate
3258 */
3259 platform_check_and_update_copp_sample_rate(adev->platform, out_snd_device,
3260 usecase->stream.out->sample_rate,
3261 &usecase->stream.out->app_type_cfg.sample_rate);
Ashish Jain4826f6c2017-02-06 13:33:20 +05303262 } else if (((out_snd_device != SND_DEVICE_OUT_HEADPHONES_44_1 &&
Preetam Singh Ranawat590d0432019-09-30 14:39:47 +05303263 out_snd_device != SND_DEVICE_OUT_HEADPHONES &&
3264 out_snd_device != SND_DEVICE_OUT_HEADPHONES_HIFI_FILTER &&
Ashish Jain4826f6c2017-02-06 13:33:20 +05303265 !audio_is_true_native_stream_active(adev)) &&
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003266 usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) ||
3267 (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05303268 if (!(compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) && ((usecase->stream.out->flags &
3269 (audio_output_flags_t)AUDIO_OUTPUT_FLAG_SYS_NOTIFICATION) || (usecase->stream.out->flags &
3270 (audio_output_flags_t)AUDIO_OUTPUT_FLAG_PHONE)))) {
3271 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3272 }
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003273 }
Weiyin Jiangcdece202019-07-08 16:13:16 +08003274 }
3275 enable_audio_route(adev, usecase);
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003276
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303277 if (uc_id == USECASE_AUDIO_PLAYBACK_VOIP) {
3278 struct stream_in *voip_in = get_voice_communication_input(adev);
3279 struct audio_usecase *voip_in_usecase = NULL;
3280 voip_in_usecase = get_usecase_from_list(adev, USECASE_AUDIO_RECORD_VOIP);
3281 if (voip_in != NULL &&
3282 voip_in_usecase != NULL &&
3283 !(out_snd_device == AUDIO_DEVICE_OUT_SPEAKER ||
3284 out_snd_device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
3285 (voip_in_usecase->in_snd_device ==
3286 platform_get_input_snd_device(adev->platform, voip_in,
3287 &usecase->stream.out->device_list,usecase->type))) {
3288 /*
3289 * if VOIP TX is enabled before VOIP RX, needs to re-route the TX path
3290 * for enabling echo-reference-voip with correct port
3291 */
3292 ALOGD("%s: VOIP TX is enabled before VOIP RX,needs to re-route the TX path",__func__);
3293 disable_audio_route(adev, voip_in_usecase);
3294 disable_snd_device(adev, voip_in_usecase->in_snd_device);
3295 enable_snd_device(adev, voip_in_usecase->in_snd_device);
3296 enable_audio_route(adev, voip_in_usecase);
3297 }
3298 }
Ramjee Singhcdf67af2021-09-29 14:20:27 +05303299 if (voice_extn_compress_voip_is_active(adev)) {
3300 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3301 USECASE_COMPRESS_VOIP_CALL);
3302 /*
3303 * If only compress voip input is opened voip out will be primary out.
3304 * Need to consider re-routing to select correct i/p pair
3305 */
3306 if ((voip_usecase != NULL) &&
3307 (usecase->type == PCM_PLAYBACK) &&
3308 (usecase->stream.out == voip_usecase->stream.out)) {
3309 in_snd_device = platform_get_input_snd_device(adev->platform,
3310 NULL,
3311 &usecase->stream.out->device_list,
3312 usecase->type);
3313 if (voip_usecase->in_snd_device != in_snd_device ) {
3314 ALOGD("%s:Re routing compress voip tx snd device matching voip rx pair",
3315 __func__);
3316 disable_audio_route(adev, voip_usecase);
3317 disable_snd_device(adev, voip_usecase->in_snd_device);
3318 voip_usecase->in_snd_device = in_snd_device;
3319 voip_usecase->out_snd_device = usecase->out_snd_device;
3320 /* Route all TX usecase to Compress voip BE */
3321 check_usecases_capture_codec_backend(adev, voip_usecase, in_snd_device);
3322 enable_snd_device(adev, in_snd_device);
3323 /* Send Voice related calibration for RX /TX pair */
3324 status = platform_switch_voice_call_device_post(adev->platform,
3325 out_snd_device,
3326 in_snd_device);
3327 enable_audio_route(adev, voip_usecase);
3328 }
3329 }
3330 }
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303331
3332
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08003333 audio_extn_qdsp_set_device(usecase);
Aalique Grahame22e49102018-12-18 14:23:57 -08003334
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003335 /* If input stream is already running then effect needs to be
3336 applied on the new input device that's being enabled here. */
Eric Laurent637e2d42018-11-15 12:24:31 -08003337 if (in_snd_device != SND_DEVICE_NONE)
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003338 check_and_enable_effect(adev);
3339
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003340 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003341 /* Enable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303342 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003343 voice_check_and_update_aanc_path(adev, out_snd_device, true);
3344
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003345 /* Enable sidetone only if other voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303346 if (voice_is_call_state_active_in_call(adev) ||
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003347 voice_extn_compress_voip_is_started(adev))
3348 voice_set_sidetone(adev, out_snd_device, true);
3349 }
3350
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003351 /* Applicable only on the targets that has external modem.
3352 * Enable device command should be sent to modem only after
3353 * enabling voice call mixer controls
3354 */
Vidyakumar Athota339342f2014-07-01 15:30:57 -07003355 if (usecase->type == VOICE_CALL)
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003356 status = platform_switch_voice_call_usecase_route_post(adev->platform,
3357 out_snd_device,
3358 in_snd_device);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303359
3360 if (is_btsco_device(out_snd_device, in_snd_device) || is_a2dp_device(out_snd_device)) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003361 struct stream_in *in = adev_get_active_input(adev);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303362 if (usecase->type == VOIP_CALL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003363 if (in != NULL && !in->standby) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303364 if (is_bt_soc_on(adev) == false){
3365 ALOGD("BT SCO MIC disconnected while in connection");
Eric Laurent637e2d42018-11-15 12:24:31 -08003366 if (in->pcm != NULL)
3367 pcm_stop(in->pcm);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303368 }
3369 }
3370 if ((usecase->stream.out != NULL) && (usecase->stream.out != adev->primary_output)
3371 && usecase->stream.out->started) {
3372 if (is_bt_soc_on(adev) == false) {
3373 ALOGD("BT SCO/A2DP disconnected while in connection");
3374 out_standby_l(&usecase->stream.out->stream.common);
3375 }
3376 }
3377 } else if ((usecase->stream.out != NULL) &&
3378 !(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Surendar Karkae1dc8742018-11-19 16:23:14 +05303379 (usecase->type != TRANSCODE_LOOPBACK_TX) &&
3380 (usecase->type != TRANSCODE_LOOPBACK_RX) &&
Weiyin Jiang0d373242019-07-25 13:18:17 +08003381 (usecase->type != PCM_CAPTURE) &&
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303382 usecase->stream.out->started) {
3383 if (is_bt_soc_on(adev) == false) {
3384 ALOGD("BT SCO/A2dp disconnected while in connection");
3385 out_standby_l(&usecase->stream.out->stream.common);
3386 }
3387 }
3388 }
3389
Yung Ti Su70cb8242018-06-22 17:38:47 +08003390 if (usecase->type != PCM_CAPTURE && usecase == voip_usecase) {
Aalique Grahame22e49102018-12-18 14:23:57 -08003391 struct stream_out *voip_out = voip_usecase->stream.out;
3392 audio_extn_utils_send_app_type_gain(adev,
3393 voip_out->app_type_cfg.app_type,
3394 &voip_out->app_type_cfg.gain[0]);
3395 }
3396
Ajender Reddyb940b832021-07-07 11:51:42 +05303397 ALOGD("%s: done",__func__);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303398
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003399 return status;
3400}
3401
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003402static int stop_input_stream(struct stream_in *in)
3403{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303404 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003405 struct audio_usecase *uc_info;
Pallavid7c7a272018-01-16 11:22:55 +05303406
3407 if (in == NULL) {
3408 ALOGE("%s: stream_in ptr is NULL", __func__);
3409 return -EINVAL;
3410 }
3411
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003412 struct audio_device *adev = in->dev;
Carter Hsu2e429db2019-05-14 18:50:52 +08003413 struct stream_in *priority_in = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003414
Eric Laurent994a6932013-07-17 11:51:42 -07003415 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003416 in->usecase, use_case_table[in->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003417 uc_info = get_usecase_from_list(adev, in->usecase);
3418 if (uc_info == NULL) {
3419 ALOGE("%s: Could not find the usecase (%d) in the list",
3420 __func__, in->usecase);
3421 return -EINVAL;
3422 }
3423
Carter Hsu2e429db2019-05-14 18:50:52 +08003424 priority_in = get_priority_input(adev);
3425
Derek Chenea197282019-01-07 17:35:01 -08003426 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3427 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003428
Vidyakumar Athota2850d532013-11-19 16:02:12 -08003429 /* Close in-call recording streams */
3430 voice_check_and_stop_incall_rec_usecase(adev, in);
3431
Eric Laurent150dbfe2013-02-27 14:31:02 -08003432 /* 1. Disable stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003433 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003434
3435 /* 2. Disable the tx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003436 disable_snd_device(adev, uc_info->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003437
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003438 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303439 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
3440
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003441 list_remove(&uc_info->list);
Zhenlin Lian4f947842022-05-14 15:50:52 +05303442 clear_devices(&uc_info->device_list);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003443 free(uc_info);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003444
Carter Hsu2e429db2019-05-14 18:50:52 +08003445 if (priority_in == in) {
3446 priority_in = get_priority_input(adev);
Sujin Panicker110f7942021-08-26 17:01:22 +05303447 if (priority_in) {
3448 if (is_usb_in_device_type(&priority_in->device_list)) {
3449 if (audio_extn_usb_connected(NULL))
3450 select_devices(adev, priority_in->usecase);
3451 } else {
3452 select_devices(adev, priority_in->usecase);
3453 }
3454 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003455 }
3456
Vatsal Buchac09ae062018-11-14 13:25:08 +05303457 enable_gcov();
Eric Laurent994a6932013-07-17 11:51:42 -07003458 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003459 return ret;
3460}
3461
3462int start_input_stream(struct stream_in *in)
3463{
3464 /* 1. Enable output device and stream routing controls */
Eric Laurentc8400632013-02-14 19:04:54 -08003465 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003466 struct audio_usecase *uc_info;
Preetam Singh Ranawata87e9742018-02-13 16:52:53 +05303467
3468 if (in == NULL) {
3469 ALOGE("%s: stream_in ptr is NULL", __func__);
3470 return -EINVAL;
3471 }
3472
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003473 struct audio_device *adev = in->dev;
Garmond Leunge2433c32017-09-28 21:51:22 -07003474 struct pcm_config config = in->config;
Garmond Leung438932f2017-10-04 19:35:18 -07003475 int usecase = platform_update_usecase_from_source(in->source,in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003476
Mingming Yin2664a5b2015-09-03 10:53:11 -07003477 if (get_usecase_from_list(adev, usecase) == NULL)
3478 in->usecase = usecase;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303479 ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
3480 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003481
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303482 if (CARD_STATUS_OFFLINE == in->card_status||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003483 CARD_STATUS_OFFLINE == adev->card_status ||
3484 POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
3485 ALOGW("in->card_status or adev->card_status or adev->input_power offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05303486 ret = -EIO;
Naresh Tanniru4c630392014-05-12 01:05:52 +05303487 goto error_config;
3488 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05303489
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003490 if (is_sco_in_device_type(&in->device_list)) {
Lakshman Chaluvaraju87f53aa2021-02-02 15:50:11 +05303491 if (!adev->bt_sco_on || audio_extn_a2dp_source_is_ready()) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303492 ALOGE("%s: SCO profile is not ready, return error", __func__);
3493 ret = -EIO;
3494 goto error_config;
3495 }
3496 }
3497
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003498 /* Check if source matches incall recording usecase criteria */
3499 ret = voice_check_and_set_incall_rec_usecase(adev, in);
3500 if (ret)
3501 goto error_config;
3502 else
Mingming Yin2664a5b2015-09-03 10:53:11 -07003503 ALOGV("%s: usecase(%d)", __func__, in->usecase);
3504
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303505 if (audio_extn_cin_attached_usecase(in))
3506 audio_extn_cin_acquire_usecase(in);
3507
Mingming Yin2664a5b2015-09-03 10:53:11 -07003508 if (get_usecase_from_list(adev, in->usecase) != NULL) {
3509 ALOGE("%s: use case assigned already in use, stream(%p)usecase(%d: %s)",
3510 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003511 ret = -EINVAL;
3512 goto error_config;
Mingming Yin2664a5b2015-09-03 10:53:11 -07003513 }
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003514
Eric Laurentb23d5282013-05-14 15:27:20 -07003515 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003516 if (in->pcm_device_id < 0) {
3517 ALOGE("%s: Could not find PCM device id for the usecase(%d)",
3518 __func__, in->usecase);
Eric Laurentc8400632013-02-14 19:04:54 -08003519 ret = -EINVAL;
3520 goto error_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003521 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003522
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003523 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003524
3525 if (!uc_info) {
3526 ret = -ENOMEM;
3527 goto error_config;
3528 }
3529
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003530 uc_info->id = in->usecase;
3531 uc_info->type = PCM_CAPTURE;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003532 uc_info->stream.in = in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003533 list_init(&uc_info->device_list);
3534 assign_devices(&uc_info->device_list, &in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003535 uc_info->in_snd_device = SND_DEVICE_NONE;
3536 uc_info->out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003537
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003538 list_add_tail(&adev->usecase_list, &uc_info->list);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003539 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303540 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
3541 adev->perf_lock_opts,
3542 adev->perf_lock_opts_size);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003543 select_devices(adev, in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003544
Derek Chenea197282019-01-07 17:35:01 -08003545 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
3546 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003547
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05303548 android_atomic_acquire_cas(true, false, &(in->capture_stopped));
3549
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303550 if (audio_extn_cin_attached_usecase(in)) {
Manish Dewangan46e07982018-12-13 18:18:59 +05303551 ret = audio_extn_cin_open_input_stream(in);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303552 if (ret)
3553 goto error_open;
3554 else
3555 goto done_open;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003556 }
3557
Haynes Mathew George16081042017-05-31 17:16:49 -07003558 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003559 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003560 ALOGE("%s: pcm stream not ready", __func__);
3561 goto error_open;
3562 }
3563 ret = pcm_start(in->pcm);
3564 if (ret < 0) {
3565 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
3566 goto error_open;
3567 }
3568 } else {
3569 unsigned int flags = PCM_IN | PCM_MONOTONIC;
3570 unsigned int pcm_open_retry_count = 0;
3571
Zhou Song62ea0282020-03-22 19:53:01 +08003572 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) ||
3573 (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003574 flags |= PCM_MMAP | PCM_NOIRQ;
3575 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
3576 } else if (in->realtime) {
3577 flags |= PCM_MMAP | PCM_NOIRQ;
3578 }
3579
Garmond Leunge2433c32017-09-28 21:51:22 -07003580 if (audio_extn_ffv_get_stream() == in) {
3581 ALOGD("%s: ffv stream, update pcm config", __func__);
3582 audio_extn_ffv_update_pcm_config(&config);
3583 }
Haynes Mathew George16081042017-05-31 17:16:49 -07003584 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
3585 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
3586
3587 while (1) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003588 ATRACE_BEGIN("pcm_in_open");
Haynes Mathew George16081042017-05-31 17:16:49 -07003589 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
Garmond Leung438932f2017-10-04 19:35:18 -07003590 flags, &config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003591 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05303592 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05303593 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
3594 adev->card_status = CARD_STATUS_OFFLINE;
3595 in->card_status = CARD_STATUS_OFFLINE;
3596 ret = -EIO;
3597 goto error_open;
3598 }
3599
Haynes Mathew George16081042017-05-31 17:16:49 -07003600 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
3601 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
3602 if (in->pcm != NULL) {
3603 pcm_close(in->pcm);
3604 in->pcm = NULL;
3605 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003606 if (pcm_open_retry_count == 0) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003607 ret = -EIO;
3608 goto error_open;
3609 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003610 pcm_open_retry_count--;
Haynes Mathew George16081042017-05-31 17:16:49 -07003611 usleep(PROXY_OPEN_WAIT_TIME * 1000);
3612 continue;
3613 }
3614 break;
3615 }
3616
3617 ALOGV("%s: pcm_prepare", __func__);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003618 ATRACE_BEGIN("pcm_in_prepare");
Haynes Mathew George16081042017-05-31 17:16:49 -07003619 ret = pcm_prepare(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003620 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003621 if (ret < 0) {
3622 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
3623 pcm_close(in->pcm);
3624 in->pcm = NULL;
3625 goto error_open;
3626 }
Narsinga Rao Chellaa6e1f702021-10-22 13:57:32 +05303627 if (in->flags == AUDIO_INPUT_FLAG_FAST)
3628 register_in_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07003629 if (in->realtime) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003630 ATRACE_BEGIN("pcm_in_start");
Haynes Mathew George16081042017-05-31 17:16:49 -07003631 ret = pcm_start(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003632 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003633 if (ret < 0) {
3634 ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003635 pcm_close(in->pcm);
3636 in->pcm = NULL;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003637 goto error_open;
3638 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003639 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07003640 }
3641
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003642 check_and_enable_effect(adev);
justinweng20fb6d82019-02-21 18:49:00 -07003643 audio_extn_audiozoom_set_microphone_direction(in, in->zoom);
3644 audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003645
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003646 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303647 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
3648
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303649done_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003650 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303651 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Manisha Agarwal4c2402e2020-10-21 12:02:57 +05303652 ALOGD("%s: exit", __func__);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303653 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003654 return ret;
3655
3656error_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003657 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303658 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003659 stop_input_stream(in);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003660
Eric Laurentc8400632013-02-14 19:04:54 -08003661error_config:
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003662 if (audio_extn_cin_attached_usecase(in))
3663 audio_extn_cin_close_input_stream(in);
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05303664 /*
3665 * sleep 50ms to allow sufficient time for kernel
3666 * drivers to recover incases like SSR.
3667 */
3668 usleep(50000);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003669 ALOGD("%s: exit: status(%d)", __func__, ret);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303670 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003671 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003672}
3673
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003674void lock_input_stream(struct stream_in *in)
3675{
3676 pthread_mutex_lock(&in->pre_lock);
3677 pthread_mutex_lock(&in->lock);
3678 pthread_mutex_unlock(&in->pre_lock);
3679}
3680
3681void lock_output_stream(struct stream_out *out)
3682{
3683 pthread_mutex_lock(&out->pre_lock);
3684 pthread_mutex_lock(&out->lock);
3685 pthread_mutex_unlock(&out->pre_lock);
3686}
3687
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003688/* must be called with out->lock locked */
3689static int send_offload_cmd_l(struct stream_out* out, int command)
3690{
3691 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
3692
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003693 if (!cmd) {
3694 ALOGE("failed to allocate mem for command 0x%x", command);
3695 return -ENOMEM;
3696 }
3697
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003698 ALOGVV("%s %d", __func__, command);
3699
3700 cmd->cmd = command;
3701 list_add_tail(&out->offload_cmd_list, &cmd->node);
3702 pthread_cond_signal(&out->offload_cond);
3703 return 0;
3704}
3705
Gautam Manam14c198b2020-12-24 14:08:04 +05303706/* must be called with out->lock */
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003707static void stop_compressed_output_l(struct stream_out *out)
3708{
Gautam Manam14c198b2020-12-24 14:08:04 +05303709 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003710 out->offload_state = OFFLOAD_STATE_IDLE;
Gautam Manam14c198b2020-12-24 14:08:04 +05303711 pthread_mutex_unlock(&out->latch_lock);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08003712
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003713 out->playback_started = 0;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07003714 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003715 if (out->compr != NULL) {
3716 compress_stop(out->compr);
3717 while (out->offload_thread_blocked) {
3718 pthread_cond_wait(&out->cond, &out->lock);
3719 }
3720 }
3721}
3722
Varun Balaraje49253e2017-07-06 19:48:56 +05303723bool is_interactive_usecase(audio_usecase_t uc_id)
3724{
3725 unsigned int i;
3726 for (i = 0; i < sizeof(interactive_usecases)/sizeof(interactive_usecases[0]); i++) {
3727 if (uc_id == interactive_usecases[i])
3728 return true;
3729 }
3730 return false;
3731}
3732
3733static audio_usecase_t get_interactive_usecase(struct audio_device *adev)
3734{
3735 audio_usecase_t ret_uc = USECASE_INVALID;
3736 unsigned int intract_uc_index;
3737 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3738
3739 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
3740 for (intract_uc_index = 0; intract_uc_index < num_usecase; intract_uc_index++) {
3741 if (!(adev->interactive_usecase_state & (0x1 << intract_uc_index))) {
3742 adev->interactive_usecase_state |= 0x1 << intract_uc_index;
3743 ret_uc = interactive_usecases[intract_uc_index];
3744 break;
3745 }
3746 }
3747
3748 ALOGV("%s: Interactive usecase is %d", __func__, ret_uc);
3749 return ret_uc;
3750}
3751
3752static void free_interactive_usecase(struct audio_device *adev,
3753 audio_usecase_t uc_id)
3754{
3755 unsigned int interact_uc_index;
3756 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3757
3758 for (interact_uc_index = 0; interact_uc_index < num_usecase; interact_uc_index++) {
3759 if (interactive_usecases[interact_uc_index] == uc_id) {
3760 adev->interactive_usecase_state &= ~(0x1 << interact_uc_index);
3761 break;
3762 }
3763 }
3764 ALOGV("%s: free Interactive usecase %d", __func__, uc_id);
3765}
3766
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003767bool is_offload_usecase(audio_usecase_t uc_id)
3768{
3769 unsigned int i;
3770 for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
3771 if (uc_id == offload_usecases[i])
3772 return true;
3773 }
3774 return false;
3775}
3776
Dhananjay Kumarac341582017-02-23 23:42:25 +05303777static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_compress)
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003778{
vivek mehta446c3962015-09-14 10:57:35 -07003779 audio_usecase_t ret_uc = USECASE_INVALID;
3780 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003781 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003782 if (!adev->multi_offload_enable) {
Dhananjay Kumarac341582017-02-23 23:42:25 +05303783 if (!is_compress)
vivek mehta446c3962015-09-14 10:57:35 -07003784 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
3785 else
3786 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003787
vivek mehta446c3962015-09-14 10:57:35 -07003788 pthread_mutex_lock(&adev->lock);
3789 if (get_usecase_from_list(adev, ret_uc) != NULL)
3790 ret_uc = USECASE_INVALID;
3791 pthread_mutex_unlock(&adev->lock);
3792
3793 return ret_uc;
3794 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003795
3796 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
vivek mehta446c3962015-09-14 10:57:35 -07003797 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3798 if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) {
3799 adev->offload_usecases_state |= 0x1 << offload_uc_index;
3800 ret_uc = offload_usecases[offload_uc_index];
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003801 break;
3802 }
3803 }
vivek mehta446c3962015-09-14 10:57:35 -07003804
3805 ALOGV("%s: offload usecase is %d", __func__, ret_uc);
3806 return ret_uc;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003807}
3808
3809static void free_offload_usecase(struct audio_device *adev,
3810 audio_usecase_t uc_id)
3811{
vivek mehta446c3962015-09-14 10:57:35 -07003812 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003813 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003814
3815 if (!adev->multi_offload_enable)
3816 return;
3817
3818 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3819 if (offload_usecases[offload_uc_index] == uc_id) {
3820 adev->offload_usecases_state &= ~(0x1 << offload_uc_index);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003821 break;
3822 }
3823 }
3824 ALOGV("%s: free offload usecase %d", __func__, uc_id);
3825}
3826
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003827static void *offload_thread_loop(void *context)
3828{
3829 struct stream_out *out = (struct stream_out *) context;
3830 struct listnode *item;
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003831 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003832
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003833 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08003834 set_sched_policy(0, SP_FOREGROUND);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003835 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
3836
3837 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003838 lock_output_stream(out);
juyuchen391b5fa2018-12-12 17:58:09 +08003839 out->offload_state = OFFLOAD_STATE_IDLE;
3840 out->playback_started = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003841 for (;;) {
3842 struct offload_cmd *cmd = NULL;
3843 stream_callback_event_t event;
3844 bool send_callback = false;
3845
3846 ALOGVV("%s offload_cmd_list %d out->offload_state %d",
3847 __func__, list_empty(&out->offload_cmd_list),
3848 out->offload_state);
3849 if (list_empty(&out->offload_cmd_list)) {
3850 ALOGV("%s SLEEPING", __func__);
3851 pthread_cond_wait(&out->offload_cond, &out->lock);
3852 ALOGV("%s RUNNING", __func__);
3853 continue;
3854 }
3855
3856 item = list_head(&out->offload_cmd_list);
3857 cmd = node_to_item(item, struct offload_cmd, node);
3858 list_remove(item);
3859
3860 ALOGVV("%s STATE %d CMD %d out->compr %p",
3861 __func__, out->offload_state, cmd->cmd, out->compr);
3862
3863 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
3864 free(cmd);
3865 break;
3866 }
3867
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08003868 // allow OFFLOAD_CMD_ERROR reporting during standby
3869 // this is needed to handle failures during compress_open
3870 // Note however that on a pause timeout, the stream is closed
3871 // and no offload usecase will be active. Therefore this
3872 // special case is needed for compress_open failures alone
3873 if (cmd->cmd != OFFLOAD_CMD_ERROR &&
3874 out->compr == NULL) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003875 ALOGE("%s: Compress handle is NULL", __func__);
Haynes Mathew Georgea9abb202016-06-02 14:13:20 -07003876 free(cmd);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003877 pthread_cond_signal(&out->cond);
3878 continue;
3879 }
3880 out->offload_thread_blocked = true;
3881 pthread_mutex_unlock(&out->lock);
3882 send_callback = false;
3883 switch(cmd->cmd) {
3884 case OFFLOAD_CMD_WAIT_FOR_BUFFER:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003885 ALOGD("copl(%p):calling compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003886 compress_wait(out->compr, -1);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003887 ALOGD("copl(%p):out of compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003888 send_callback = true;
3889 event = STREAM_CBK_EVENT_WRITE_READY;
3890 break;
3891 case OFFLOAD_CMD_PARTIAL_DRAIN:
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003892 ret = compress_next_track(out->compr);
Sidipotu Ashok55820562014-02-10 16:16:38 +05303893 if(ret == 0) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003894 ALOGD("copl(%p):calling compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303895 ret = compress_partial_drain(out->compr);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003896 ALOGD("copl(%p):out of compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303897 if (ret < 0)
3898 ret = -errno;
Sidipotu Ashok55820562014-02-10 16:16:38 +05303899 }
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303900 else if (ret == -ETIMEDOUT)
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003901 ret = compress_drain(out->compr);
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003902 else
3903 ALOGE("%s: Next track returned error %d",__func__, ret);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003904 if (-ENETRESET != ret && !(-EINTR == ret &&
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003905 (CARD_STATUS_OFFLINE == out->card_status ||
3906 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303907 send_callback = true;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05303908 pthread_mutex_lock(&out->lock);
3909 out->send_new_metadata = 1;
3910 out->send_next_track_params = true;
3911 pthread_mutex_unlock(&out->lock);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303912 event = STREAM_CBK_EVENT_DRAIN_READY;
3913 ALOGV("copl(%p):send drain callback, ret %d", out, ret);
3914 } else
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303915 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003916 break;
3917 case OFFLOAD_CMD_DRAIN:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003918 ALOGD("copl(%p):calling compress_drain", out);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003919 ret = compress_drain(out->compr);
3920 ALOGD("copl(%p):out of compress_drain", out);
3921 // EINTR check avoids drain interruption due to SSR
3922 if (-ENETRESET != ret && !(-EINTR == ret &&
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05003923 (CARD_STATUS_OFFLINE == out->card_status ||
3924 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy))) {
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003925 send_callback = true;
3926 event = STREAM_CBK_EVENT_DRAIN_READY;
3927 } else
3928 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003929 break;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303930 case OFFLOAD_CMD_ERROR:
3931 ALOGD("copl(%p): sending error callback to AF", out);
3932 send_callback = true;
3933 event = STREAM_CBK_EVENT_ERROR;
3934 break;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003935 default:
3936 ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
3937 break;
3938 }
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003939 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003940 out->offload_thread_blocked = false;
3941 pthread_cond_signal(&out->cond);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08003942 if (send_callback && out->client_callback) {
3943 ALOGVV("%s: sending client_callback event %d", __func__, event);
3944 out->client_callback(event, NULL, out->client_cookie);
Eric Laurent6e895242013-09-05 16:10:57 -07003945 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003946 free(cmd);
3947 }
3948
3949 pthread_cond_signal(&out->cond);
3950 while (!list_empty(&out->offload_cmd_list)) {
3951 item = list_head(&out->offload_cmd_list);
3952 list_remove(item);
3953 free(node_to_item(item, struct offload_cmd, node));
3954 }
3955 pthread_mutex_unlock(&out->lock);
3956
3957 return NULL;
3958}
3959
3960static int create_offload_callback_thread(struct stream_out *out)
3961{
3962 pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
3963 list_init(&out->offload_cmd_list);
3964 pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
3965 offload_thread_loop, out);
3966 return 0;
3967}
3968
3969static int destroy_offload_callback_thread(struct stream_out *out)
3970{
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003971 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003972 stop_compressed_output_l(out);
3973 send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
3974
3975 pthread_mutex_unlock(&out->lock);
3976 pthread_join(out->offload_thread, (void **) NULL);
3977 pthread_cond_destroy(&out->offload_cond);
3978
3979 return 0;
3980}
3981
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003982static int stop_output_stream(struct stream_out *out)
3983{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303984 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003985 struct audio_usecase *uc_info;
3986 struct audio_device *adev = out->dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08003987 bool has_voip_usecase =
3988 get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP) != NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003989
Eric Laurent994a6932013-07-17 11:51:42 -07003990 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003991 out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003992 uc_info = get_usecase_from_list(adev, out->usecase);
3993 if (uc_info == NULL) {
3994 ALOGE("%s: Could not find the usecase (%d) in the list",
3995 __func__, out->usecase);
3996 return -EINVAL;
3997 }
3998
Zhou Songbaddf9f2020-11-20 13:57:39 +08003999 out->a2dp_muted = false;
4000
Derek Chenea197282019-01-07 17:35:01 -08004001 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
4002 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004003
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004004 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304005 !(audio_extn_passthru_is_passthrough_stream(out))) {
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004006 if (adev->visualizer_stop_output != NULL)
4007 adev->visualizer_stop_output(out->handle, out->pcm_device_id);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004008
4009 audio_extn_dts_remove_state_notifier_node(out->usecase);
4010
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004011 if (adev->offload_effects_stop_output != NULL)
4012 adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
vivek mehtad15d2bf2019-05-17 13:35:10 -07004013 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4014 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4015 audio_low_latency_hint_end();
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08004016 }
Eric Laurentc4aef752013-09-12 17:45:53 -07004017
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004018 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4019 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004020 voice_set_device_mute_flag(adev, false);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004021 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004022
Eric Laurent150dbfe2013-02-27 14:31:02 -08004023 /* 1. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07004024 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004025
4026 /* 2. Disable the rx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07004027 disable_snd_device(adev, uc_info->out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08004028 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
4029 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004030
Aalique Grahame22e49102018-12-18 14:23:57 -08004031 audio_extn_extspk_update(adev->extspk);
4032
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004033 if (is_offload_usecase(out->usecase)) {
4034 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4035 adev->dsp_bit_width_enforce_mode,
4036 false);
4037 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004038 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004039 ret = audio_extn_usb_check_and_set_svc_int(uc_info,
4040 false);
4041
4042 if (ret != 0)
4043 check_usecases_codec_backend(adev, uc_info, uc_info->out_snd_device);
4044 /* default service interval was successfully updated,
4045 reopen USB backend with new service interval */
4046 ret = 0;
4047 }
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004048
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004049 list_remove(&uc_info->list);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304050 out->started = 0;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004051 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304052 (audio_extn_passthru_is_passthrough_stream(out))) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004053 ALOGV("Disable passthrough , reset mixer to pcm");
4054 /* NO_PASSTHROUGH */
Meng Wang4c32fb42020-01-16 17:57:11 +08004055#ifdef AUDIO_GKI_ENABLED
4056 /* out->compr_config.codec->reserved[0] is for compr_passthr */
4057 out->compr_config.codec->reserved[0] = 0;
4058#else
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004059 out->compr_config.codec->compr_passthr = 0;
Meng Wang4c32fb42020-01-16 17:57:11 +08004060#endif
Mingming Yin21854652016-04-13 11:54:02 -07004061 audio_extn_passthru_on_stop(out);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004062 audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
4063 }
Eric Laurent07eeafd2013-10-06 12:52:49 -07004064
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05304065 /* Must be called after removing the usecase from list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004066 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL))
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304067 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304068
Manish Dewangan21a850a2017-08-14 12:03:55 +05304069 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07004070 ret = audio_extn_ip_hdlr_intf_close(out->ip_hdlr_handle, true, out);
4071 if (ret < 0)
4072 ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
4073 }
4074
Zhou Song642ec432020-12-23 16:11:10 +08004075 /* trigger voip input to reroute when voip output changes to hearing aid */
Aalique Grahame22e49102018-12-18 14:23:57 -08004076 if (has_voip_usecase ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004077 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08004078 struct listnode *node;
4079 struct audio_usecase *usecase;
4080 list_for_each(node, &adev->usecase_list) {
4081 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Song642ec432020-12-23 16:11:10 +08004082 if (usecase->type == PCM_PLAYBACK || usecase == uc_info ||
4083 (usecase->type == PCM_CAPTURE &&
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05304084 usecase->id != USECASE_AUDIO_RECORD_VOIP &&
Zhou Song642ec432020-12-23 16:11:10 +08004085 usecase->id != USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY))
Aalique Grahame22e49102018-12-18 14:23:57 -08004086 continue;
4087
4088 ALOGD("%s: select_devices at usecase(%d: %s) after removing the usecase(%d: %s)",
4089 __func__, usecase->id, use_case_table[usecase->id],
4090 out->usecase, use_case_table[out->usecase]);
4091 select_devices(adev, usecase->id);
4092 }
4093 }
4094
Zhenlin Lian4f947842022-05-14 15:50:52 +05304095 clear_devices(&uc_info->device_list);
Garmond Leung5fd0b552018-04-17 11:56:12 -07004096 free(uc_info);
Eric Laurent994a6932013-07-17 11:51:42 -07004097 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004098 return ret;
4099}
4100
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004101struct pcm* pcm_open_prepare_helper(unsigned int snd_card, unsigned int pcm_device_id,
4102 unsigned int flags, unsigned int pcm_open_retry_count,
4103 struct pcm_config *config)
4104{
4105 struct pcm* pcm = NULL;
4106
4107 while (1) {
4108 pcm = pcm_open(snd_card, pcm_device_id, flags, config);
4109 if (pcm == NULL || !pcm_is_ready(pcm)) {
4110 ALOGE("%s: %s", __func__, pcm_get_error(pcm));
4111 if (pcm != NULL) {
4112 pcm_close(pcm);
4113 pcm = NULL;
4114 }
Weiyin Jiang72197252019-10-09 11:49:32 +08004115 if (pcm_open_retry_count == 0)
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004116 return NULL;
4117
Weiyin Jiang72197252019-10-09 11:49:32 +08004118 pcm_open_retry_count--;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004119 usleep(PROXY_OPEN_WAIT_TIME * 1000);
4120 continue;
4121 }
4122 break;
4123 }
4124
4125 if (pcm_is_ready(pcm)) {
4126 int ret = pcm_prepare(pcm);
4127 if (ret < 0) {
4128 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
4129 pcm_close(pcm);
4130 pcm = NULL;
4131 }
4132 }
4133
4134 return pcm;
4135}
4136
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004137int start_output_stream(struct stream_out *out)
4138{
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004139 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004140 struct audio_usecase *uc_info;
4141 struct audio_device *adev = out->dev;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004142 char mixer_ctl_name[128];
4143 struct mixer_ctl *ctl = NULL;
4144 char* perf_mode[] = {"ULL", "ULL_PP", "LL"};
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304145 bool a2dp_combo = false;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004146 bool is_haptic_usecase = (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) ? true: false;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004147
Haynes Mathew George380745d2017-10-04 15:27:45 -07004148 ATRACE_BEGIN("start_output_stream");
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004149 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
4150 ret = -EINVAL;
4151 goto error_config;
4152 }
4153
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004154 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x) is_haptic_usecase(%d)",
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304155 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004156 get_device_types(&out->device_list), is_haptic_usecase);
4157
4158 bool is_speaker_active = compare_device_type(&out->device_list,
4159 AUDIO_DEVICE_OUT_SPEAKER);
4160 bool is_speaker_safe_active = compare_device_type(&out->device_list,
4161 AUDIO_DEVICE_OUT_SPEAKER_SAFE);
Naresh Tanniru4c630392014-05-12 01:05:52 +05304162
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304163 if (CARD_STATUS_OFFLINE == out->card_status ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05004164 CARD_STATUS_OFFLINE == adev->card_status ||
4165 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304166 ALOGW("out->card_status or adev->card_status offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05304167 ret = -EIO;
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004168 goto error_fatal;
Naresh Tanniru4c630392014-05-12 01:05:52 +05304169 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05304170
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004171 //Update incall music usecase to reflect correct voice session
4172 if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
4173 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
4174 if (ret != 0) {
4175 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
4176 __func__, ret);
4177 goto error_config;
4178 }
4179 }
4180
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004181 if (is_a2dp_out_device_type(&out->device_list)) {
Florian Pfister1a84f312018-07-19 14:38:18 +02004182 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004183 if (is_speaker_active || is_speaker_safe_active) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304184 a2dp_combo = true;
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304185 } else {
Zhou Songd01e7a22020-09-23 22:49:01 +08004186 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304187 ALOGE("%s: A2DP profile is not ready, return error", __func__);
4188 ret = -EAGAIN;
4189 goto error_config;
4190 }
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304191 }
4192 }
4193 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004194 if (is_sco_out_device_type(&out->device_list)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304195 if (!adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004196 if (is_speaker_active) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304197 //combo usecase just by pass a2dp
4198 ALOGW("%s: SCO is not connected, route it to speaker", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004199 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304200 } else {
4201 ALOGE("%s: SCO profile is not ready, return error", __func__);
4202 ret = -EAGAIN;
4203 goto error_config;
4204 }
4205 }
4206 }
4207
Eric Laurentb23d5282013-05-14 15:27:20 -07004208 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004209 if (out->pcm_device_id < 0) {
4210 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
4211 __func__, out->pcm_device_id, out->usecase);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004212 ret = -EINVAL;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004213 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004214 }
4215
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004216 if (is_haptic_usecase) {
Meng Wang51d8c2a2020-04-27 15:23:21 +08004217 adev->haptic_pcm_device_id = platform_get_pcm_device_id(
4218 USECASE_AUDIO_PLAYBACK_HAPTICS, PCM_PLAYBACK);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004219 if (adev->haptic_pcm_device_id < 0) {
4220 ALOGE("%s: Invalid Haptics pcm device id(%d) for the usecase(%d)",
4221 __func__, adev->haptic_pcm_device_id, out->usecase);
4222 ret = -EINVAL;
4223 goto error_config;
4224 }
4225 }
4226
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004227 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004228
4229 if (!uc_info) {
4230 ret = -ENOMEM;
4231 goto error_config;
4232 }
4233
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004234 uc_info->id = out->usecase;
4235 uc_info->type = PCM_PLAYBACK;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08004236 uc_info->stream.out = out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004237 list_init(&uc_info->device_list);
4238 assign_devices(&uc_info->device_list, &out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004239 uc_info->in_snd_device = SND_DEVICE_NONE;
4240 uc_info->out_snd_device = SND_DEVICE_NONE;
Garmond Leung5fd0b552018-04-17 11:56:12 -07004241
4242 /* This must be called before adding this usecase to the list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004243 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004244 audio_extn_usb_check_and_set_svc_int(uc_info, true);
4245 /* USB backend is not reopened immediately.
4246 This is eventually done as part of select_devices */
4247 }
4248
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004249 list_add_tail(&adev->usecase_list, &uc_info->list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004250
Wei Wangf7ca6c92017-11-21 14:51:20 -08004251 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304252 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
4253 adev->perf_lock_opts,
4254 adev->perf_lock_opts_size);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304255
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004256 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304257 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304258 if (audio_extn_passthru_is_enabled() &&
4259 audio_extn_passthru_is_passthrough_stream(out)) {
4260 audio_extn_passthru_on_start(out);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304261 }
4262 }
4263
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004264 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02004265 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304266 if (!a2dp_combo) {
4267 check_a2dp_restore_l(adev, out, false);
4268 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004269 struct listnode dev;
4270 list_init(&dev);
4271 assign_devices(&dev, &out->device_list);
4272 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4273 reassign_device_list(&out->device_list,
4274 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aalique Grahame22e49102018-12-18 14:23:57 -08004275 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004276 reassign_device_list(&out->device_list,
4277 AUDIO_DEVICE_OUT_SPEAKER, "");
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304278 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004279 assign_devices(&out->device_list, &dev);
Zhenlin Lian4f947842022-05-14 15:50:52 +05304280 clear_devices(&dev);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304281 }
4282 } else {
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304283 select_devices(adev, out->usecase);
4284 if (is_a2dp_out_device_type(&out->device_list) &&
4285 !adev->a2dp_started) {
4286 if (is_speaker_active || is_speaker_safe_active) {
4287 struct listnode dev;
4288 list_init(&dev);
4289 assign_devices(&dev, &out->device_list);
4290 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4291 reassign_device_list(&out->device_list,
4292 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
4293 else
4294 reassign_device_list(&out->device_list,
4295 AUDIO_DEVICE_OUT_SPEAKER, "");
4296 select_devices(adev, out->usecase);
4297 assign_devices(&out->device_list, &dev);
Zhenlin Lian4f947842022-05-14 15:50:52 +05304298 clear_devices(&dev);
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304299 } else {
4300 ret = -EINVAL;
4301 goto error_open;
4302 }
4303 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304304 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004305
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004306 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4307 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004308 voice_set_device_mute_flag(adev, true);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004309 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004310
Derek Chenea197282019-01-07 17:35:01 -08004311 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
4312 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004313
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004314 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
4315 __func__, adev->snd_card, out->pcm_device_id, out->config.format);
Haynes Mathew George16081042017-05-31 17:16:49 -07004316
4317 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07004318 ALOGD("%s: Starting MMAP stream", __func__);
Haynes Mathew George16081042017-05-31 17:16:49 -07004319 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4320 ALOGE("%s: pcm stream not ready", __func__);
4321 goto error_open;
4322 }
4323 ret = pcm_start(out->pcm);
4324 if (ret < 0) {
4325 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
4326 goto error_open;
4327 }
Arun Mirpuri5d170872019-03-26 13:21:31 -07004328 out_set_mmap_volume(&out->stream, out->volume_l, out->volume_r);
Haynes Mathew George16081042017-05-31 17:16:49 -07004329 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004330 unsigned int flags = PCM_OUT;
4331 unsigned int pcm_open_retry_count = 0;
4332 if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
4333 flags |= PCM_MMAP | PCM_NOIRQ;
4334 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004335 } else if (out->realtime) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08004336 flags |= PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004337 } else
4338 flags |= PCM_MONOTONIC;
4339
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004340 if ((adev->vr_audio_mode_enabled) &&
4341 (out->flags & AUDIO_OUTPUT_FLAG_RAW)) {
4342 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
4343 "PCM_Dev %d Topology", out->pcm_device_id);
4344 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
4345 if (!ctl) {
4346 ALOGI("%s: Could not get ctl for mixer cmd might be ULL - %s",
4347 __func__, mixer_ctl_name);
4348 } else {
4349 //if success use ULLPP
4350 ALOGI("%s: mixer ctrl %s succeeded setting up ULL for %d",
4351 __func__, mixer_ctl_name, out->pcm_device_id);
4352 //There is a still a possibility that some sessions
4353 // that request for FAST|RAW when 3D audio is active
4354 //can go through ULLPP. Ideally we expects apps to
4355 //listen to audio focus and stop concurrent playback
4356 //Also, we will look for mode flag (voice_in_communication)
4357 //before enabling the realtime flag.
4358 mixer_ctl_set_enum_by_string(ctl, perf_mode[1]);
4359 }
4360 }
4361
Vatsal Bucha3f39f222021-06-29 16:16:55 +05304362 platform_set_stream_channel_map(adev->platform, out->channel_mask,
4363 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Surendar Karka91fa3682018-07-02 18:12:12 +05304364
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004365 out->pcm = pcm_open_prepare_helper(adev->snd_card, out->pcm_device_id,
4366 flags, pcm_open_retry_count,
4367 &(out->config));
4368 if (out->pcm == NULL) {
4369 ret = -EIO;
4370 goto error_open;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004371 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004372
4373 if (is_haptic_usecase) {
4374 adev->haptic_pcm = pcm_open_prepare_helper(adev->snd_card,
4375 adev->haptic_pcm_device_id,
4376 flags, pcm_open_retry_count,
4377 &(adev->haptics_config));
4378 // failure to open haptics pcm shouldnt stop audio,
4379 // so do not close audio pcm in case of error
Vignesh Kulothungane4039c12019-05-07 15:51:39 -07004380
4381 if (property_get_bool("vendor.audio.enable_haptic_audio_sync", false)) {
4382 ALOGD("%s: enable haptic audio synchronization", __func__);
4383 platform_set_qtime(adev->platform, out->pcm_device_id, adev->haptic_pcm_device_id);
4384 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004385 }
4386
Zhou Song2b8f28f2017-09-11 10:51:38 +08004387 // apply volume for voip playback after path is set up
4388 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
4389 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
Ramu Gottipati36547092018-12-28 11:32:09 +05304390 else if ((out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY || out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
4391 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) && (out->apply_volume)) {
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304392 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
4393 out->apply_volume = false;
Derek Chenf13dd492018-11-13 14:53:51 -08004394 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
4395 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05304396#ifdef SOFT_VOLUME
4397 out_set_soft_volume_params(&out->stream);
4398#endif
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304399 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004400 } else {
Zhou Song79929fe2020-01-20 17:57:43 +08004401 /*
4402 * set custom channel map if:
4403 * 1. neither mono nor stereo clips i.e. channels > 2 OR
4404 * 2. custom channel map has been set by client
4405 * else default channel map of FC/FR/FL can always be set to DSP
4406 */
4407 if (popcount(out->channel_mask) > 2 || out->channel_map_param.channel_map[0])
4408 platform_set_stream_channel_map(adev->platform, out->channel_mask,
Weiyin Jiang810a80d2021-01-18 16:04:31 +08004409 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004410 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4411 adev->dsp_bit_width_enforce_mode,
4412 true);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004413 out->pcm = NULL;
Haynes Mathew George380745d2017-10-04 15:27:45 -07004414 ATRACE_BEGIN("compress_open");
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -08004415 out->compr = compress_open(adev->snd_card,
4416 out->pcm_device_id,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004417 COMPRESS_IN, &out->compr_config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004418 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05304419 if (errno == ENETRESET && !is_compress_ready(out->compr)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05304420 ALOGE("%s: compress_open failed errno:%d\n", __func__, errno);
4421 adev->card_status = CARD_STATUS_OFFLINE;
4422 out->card_status = CARD_STATUS_OFFLINE;
4423 ret = -EIO;
4424 goto error_open;
4425 }
4426
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004427 if (out->compr && !is_compress_ready(out->compr)) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004428 ALOGE("%s: failed /w error %s", __func__, compress_get_error(out->compr));
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004429 compress_close(out->compr);
4430 out->compr = NULL;
4431 ret = -EIO;
4432 goto error_open;
4433 }
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304434 /* compress_open sends params of the track, so reset the flag here */
4435 out->is_compr_metadata_avail = false;
4436
Ben Rombergerd771a7c2017-02-22 18:05:17 -08004437 if (out->client_callback)
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004438 compress_nonblock(out->compr, out->non_blocking);
Eric Laurentc4aef752013-09-12 17:45:53 -07004439
Fred Oh3f43e742015-03-04 18:42:34 -08004440 /* Since small bufs uses blocking writes, a write will be blocked
4441 for the default max poll time (20s) in the event of an SSR.
4442 Reduce the poll time to observe and deal with SSR faster.
4443 */
Ashish Jain5106d362016-05-11 19:23:33 +05304444 if (!out->non_blocking) {
Fred Oh3f43e742015-03-04 18:42:34 -08004445 compress_set_max_poll_wait(out->compr, 1000);
4446 }
4447
Manish Dewangan69426c82017-01-30 17:35:36 +05304448 audio_extn_utils_compress_set_render_mode(out);
Manish Dewangan58229382017-02-02 15:48:41 +05304449 audio_extn_utils_compress_set_clk_rec_mode(uc_info);
Manish Dewangan69426c82017-01-30 17:35:36 +05304450
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004451 audio_extn_dts_create_state_notifier_node(out->usecase);
4452 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
4453 popcount(out->channel_mask),
4454 out->playback_started);
4455
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004456#ifdef DS1_DOLBY_DDP_ENABLED
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05304457 if (audio_extn_utils_is_dolby_format(out->format))
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004458 audio_extn_dolby_send_ddp_endp_params(adev);
4459#endif
Preetam Singh Ranawatd18d8832017-02-08 17:34:54 +05304460 if (!(audio_extn_passthru_is_passthrough_stream(out)) &&
4461 (out->sample_rate != 176400 && out->sample_rate <= 192000)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004462 if (adev->visualizer_start_output != NULL)
4463 adev->visualizer_start_output(out->handle, out->pcm_device_id);
4464 if (adev->offload_effects_start_output != NULL)
Ashish Jain5106d362016-05-11 19:23:33 +05304465 adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004466 audio_extn_check_and_set_dts_hpx_state(adev);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004467 }
Derek Chenf13dd492018-11-13 14:53:51 -08004468
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004469 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf13dd492018-11-13 14:53:51 -08004470 /* Update cached volume from media to offload/direct stream */
4471 struct listnode *node = NULL;
4472 list_for_each(node, &adev->active_outputs_list) {
4473 streams_output_ctxt_t *out_ctxt = node_to_item(node,
4474 streams_output_ctxt_t,
4475 list);
4476 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
4477 out->volume_l = out_ctxt->output->volume_l;
4478 out->volume_r = out_ctxt->output->volume_r;
4479 }
4480 }
4481 out_set_compr_volume(&out->stream,
4482 out->volume_l, out->volume_r);
4483 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004484 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004485
4486 if (ret == 0) {
Narsinga Rao Chellaa6e1f702021-10-22 13:57:32 +05304487 if (out->flags == AUDIO_OUTPUT_FLAG_FAST)
4488 register_out_stream(out);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004489 if (out->realtime) {
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07004490 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4491 ALOGE("%s: pcm stream not ready", __func__);
4492 goto error_open;
4493 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07004494 ATRACE_BEGIN("pcm_start");
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004495 ret = pcm_start(out->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004496 ATRACE_END();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004497 if (ret < 0)
4498 goto error_open;
4499 }
4500 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004501 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304502 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Jaideep Sharma0fa53812020-09-17 09:00:11 +05304503 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004504
vivek mehtad15d2bf2019-05-17 13:35:10 -07004505 if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4506 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4507 audio_low_latency_hint_start();
4508 }
4509
Manish Dewangan21a850a2017-08-14 12:03:55 +05304510 if (out->ip_hdlr_handle) {
Vidyakumar Athota6d655882017-05-22 18:26:24 -07004511 ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07004512 if (ret < 0)
4513 ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
4514 }
4515
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07004516 // consider a scenario where on pause lower layers are tear down.
4517 // so on resume, swap mixer control need to be sent only when
4518 // backend is active, hence rather than sending from enable device
4519 // sending it from start of streamtream
4520
4521 platform_set_swap_channels(adev, true);
4522
Haynes Mathew George380745d2017-10-04 15:27:45 -07004523 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304524 enable_gcov();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004525 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004526error_open:
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004527 if (adev->haptic_pcm) {
4528 pcm_close(adev->haptic_pcm);
4529 adev->haptic_pcm = NULL;
4530 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004531 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304532 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004533 stop_output_stream(out);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004534error_fatal:
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05304535 /*
4536 * sleep 50ms to allow sufficient time for kernel
4537 * drivers to recover incases like SSR.
4538 */
4539 usleep(50000);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004540error_config:
Haynes Mathew George380745d2017-10-04 15:27:45 -07004541 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304542 enable_gcov();
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004543 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004544}
4545
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004546static int check_input_parameters(uint32_t sample_rate,
4547 audio_format_t format,
Aalique Grahame22e49102018-12-18 14:23:57 -08004548 int channel_count,
4549 bool is_usb_hifi)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004550{
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004551 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004552
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304553 if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
4554 (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) &&
4555 (format != AUDIO_FORMAT_PCM_FLOAT)) &&
Mingming Yine62d7842013-10-25 16:26:03 -07004556 !voice_extn_compress_voip_is_format_supported(format) &&
Ralf Herzaec80262018-07-03 07:08:49 +02004557 !audio_extn_compr_cap_format_supported(format) &&
4558 !audio_extn_cin_format_supported(format))
Haynes Mathew George484e8d22017-07-31 18:55:17 -07004559 ret = -EINVAL;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004560
Aalique Grahame22e49102018-12-18 14:23:57 -08004561 int max_channel_count = is_usb_hifi ? MAX_HIFI_CHANNEL_COUNT : MAX_CHANNEL_COUNT;
4562 if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > max_channel_count)) {
4563 ALOGE("%s: unsupported channel count (%d) passed Min / Max (%d / %d)", __func__,
4564 channel_count, MIN_CHANNEL_COUNT, max_channel_count);
4565 return -EINVAL;
4566 }
4567
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004568 switch (channel_count) {
4569 case 1:
4570 case 2:
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05304571 case 3:
4572 case 4:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004573 case 6:
Karthikeyan Mani07faa602018-08-20 11:01:32 -07004574 case 8:
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05304575 case 10:
4576 case 12:
4577 case 14:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004578 break;
4579 default:
4580 ret = -EINVAL;
4581 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004582
4583 switch (sample_rate) {
4584 case 8000:
4585 case 11025:
4586 case 12000:
4587 case 16000:
4588 case 22050:
4589 case 24000:
4590 case 32000:
4591 case 44100:
4592 case 48000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004593 case 88200:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304594 case 96000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004595 case 176400:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304596 case 192000:
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004597 break;
4598 default:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004599 ret = -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004600 }
4601
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004602 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004603}
4604
Naresh Tanniru04f71882018-06-26 17:46:22 +05304605
4606/** Add a value in a list if not already present.
4607 * @return true if value was successfully inserted or already present,
4608 * false if the list is full and does not contain the value.
4609 */
4610static bool register_uint(uint32_t value, uint32_t* list, size_t list_length) {
4611 for (size_t i = 0; i < list_length; i++) {
4612 if (list[i] == value) return true; // value is already present
4613 if (list[i] == 0) { // no values in this slot
4614 list[i] = value;
4615 return true; // value inserted
4616 }
4617 }
4618 return false; // could not insert value
4619}
4620
4621/** Add channel_mask in supported_channel_masks if not already present.
4622 * @return true if channel_mask was successfully inserted or already present,
4623 * false if supported_channel_masks is full and does not contain channel_mask.
4624 */
4625static void register_channel_mask(audio_channel_mask_t channel_mask,
4626 audio_channel_mask_t supported_channel_masks[static MAX_SUPPORTED_CHANNEL_MASKS]) {
4627 ALOGE_IF(!register_uint(channel_mask, supported_channel_masks, MAX_SUPPORTED_CHANNEL_MASKS),
4628 "%s: stream can not declare supporting its channel_mask %x", __func__, channel_mask);
4629}
4630
4631/** Add format in supported_formats if not already present.
4632 * @return true if format was successfully inserted or already present,
4633 * false if supported_formats is full and does not contain format.
4634 */
4635static void register_format(audio_format_t format,
4636 audio_format_t supported_formats[static MAX_SUPPORTED_FORMATS]) {
4637 ALOGE_IF(!register_uint(format, supported_formats, MAX_SUPPORTED_FORMATS),
4638 "%s: stream can not declare supporting its format %x", __func__, format);
4639}
4640/** Add sample_rate in supported_sample_rates if not already present.
4641 * @return true if sample_rate was successfully inserted or already present,
4642 * false if supported_sample_rates is full and does not contain sample_rate.
4643 */
4644static void register_sample_rate(uint32_t sample_rate,
4645 uint32_t supported_sample_rates[static MAX_SUPPORTED_SAMPLE_RATES]) {
4646 ALOGE_IF(!register_uint(sample_rate, supported_sample_rates, MAX_SUPPORTED_SAMPLE_RATES),
4647 "%s: stream can not declare supporting its sample rate %x", __func__, sample_rate);
4648}
4649
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004650static inline uint32_t lcm(uint32_t num1, uint32_t num2)
4651{
4652 uint32_t high = num1, low = num2, temp = 0;
4653
4654 if (!num1 || !num2)
4655 return 0;
4656
4657 if (num1 < num2) {
4658 high = num2;
4659 low = num1;
4660 }
4661
4662 while (low != 0) {
4663 temp = low;
4664 low = high % low;
4665 high = temp;
4666 }
4667 return (num1 * num2)/high;
4668}
4669
4670static inline uint32_t nearest_multiple(uint32_t num, uint32_t multiplier)
4671{
4672 uint32_t remainder = 0;
4673
4674 if (!multiplier)
4675 return num;
4676
4677 remainder = num % multiplier;
4678 if (remainder)
4679 num += (multiplier - remainder);
4680
4681 return num;
4682}
4683
Aalique Grahame22e49102018-12-18 14:23:57 -08004684static size_t get_stream_buffer_size(size_t duration_ms,
4685 uint32_t sample_rate,
4686 audio_format_t format,
4687 int channel_count,
4688 bool is_low_latency)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004689{
4690 size_t size = 0;
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004691 uint32_t bytes_per_period_sample = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004692
Aalique Grahame22e49102018-12-18 14:23:57 -08004693 size = (sample_rate * duration_ms) / 1000;
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05304694 if (is_low_latency){
4695 switch(sample_rate) {
4696 case 48000:
4697 size = 240;
4698 break;
4699 case 32000:
4700 size = 160;
4701 break;
4702 case 24000:
4703 size = 120;
4704 break;
4705 case 16000:
4706 size = 80;
4707 break;
4708 case 8000:
4709 size = 40;
4710 break;
4711 default:
4712 size = 240;
4713 }
4714 }
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304715
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004716 bytes_per_period_sample = audio_bytes_per_sample(format) * channel_count;
Aalique Grahame22e49102018-12-18 14:23:57 -08004717 size *= audio_bytes_per_sample(format) * channel_count;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004718
Ralf Herzbd08d632018-09-28 15:50:49 +02004719 /* make sure the size is multiple of 32 bytes and additionally multiple of
4720 * the frame_size (required for 24bit samples and non-power-of-2 channel counts)
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004721 * At 48 kHz mono 16-bit PCM:
4722 * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
4723 * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004724 * Also, make sure the size is multiple of bytes per period sample
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004725 */
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004726 size = nearest_multiple(size, lcm(32, bytes_per_period_sample));
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07004727
4728 return size;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004729}
4730
Aalique Grahame22e49102018-12-18 14:23:57 -08004731static size_t get_input_buffer_size(uint32_t sample_rate,
4732 audio_format_t format,
4733 int channel_count,
4734 bool is_low_latency)
4735{
Avinash Chandrad7296d42021-08-04 15:07:47 +05304736 bool is_usb_hifi = IS_USB_HIFI;
Aalique Grahame22e49102018-12-18 14:23:57 -08004737 /* Don't know if USB HIFI in this context so use true to be conservative */
4738 if (check_input_parameters(sample_rate, format, channel_count,
Avinash Chandrad7296d42021-08-04 15:07:47 +05304739 is_usb_hifi) != 0)
Aalique Grahame22e49102018-12-18 14:23:57 -08004740 return 0;
4741
4742 return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
4743 sample_rate,
4744 format,
4745 channel_count,
4746 is_low_latency);
4747}
4748
Derek Chenf6318be2017-06-12 17:16:24 -04004749size_t get_output_period_size(uint32_t sample_rate,
4750 audio_format_t format,
4751 int channel_count,
4752 int duration /*in millisecs*/)
Ashish Jain058165c2016-09-28 23:18:48 +05304753{
4754 size_t size = 0;
4755 uint32_t bytes_per_sample = audio_bytes_per_sample(format);
4756
4757 if ((duration == 0) || (sample_rate == 0) ||
4758 (bytes_per_sample == 0) || (channel_count == 0)) {
4759 ALOGW("Invalid config duration %d sr %d bps %d ch %d", duration, sample_rate,
4760 bytes_per_sample, channel_count);
4761 return -EINVAL;
4762 }
4763
4764 size = (sample_rate *
4765 duration *
4766 bytes_per_sample *
4767 channel_count) / 1000;
4768 /*
4769 * To have same PCM samples for all channels, the buffer size requires to
4770 * be multiple of (number of channels * bytes per sample)
4771 * For writes to succeed, the buffer must be written at address which is multiple of 32
4772 */
4773 size = ALIGN(size, (bytes_per_sample * channel_count * 32));
4774
4775 return (size/(channel_count * bytes_per_sample));
4776}
4777
Zhou Song48453a02018-01-10 17:50:59 +08004778static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out, struct timespec *timestamp)
Ashish Jain5106d362016-05-11 19:23:33 +05304779{
4780 uint64_t actual_frames_rendered = 0;
Weiyin Jiang4813da12020-05-28 00:37:28 +08004781 uint64_t written_frames = 0;
4782 uint64_t kernel_frames = 0;
4783 uint64_t dsp_frames = 0;
4784 uint64_t signed_frames = 0;
4785 size_t kernel_buffer_size = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05304786
4787 /* This adjustment accounts for buffering after app processor.
4788 * It is based on estimated DSP latency per use case, rather than exact.
4789 */
George Gao9ba8a142020-07-23 14:30:03 -07004790 dsp_frames = platform_render_latency(out) *
Weiyin Jiang4813da12020-05-28 00:37:28 +08004791 out->sample_rate / 1000000LL;
Ashish Jain5106d362016-05-11 19:23:33 +05304792
Zhou Song48453a02018-01-10 17:50:59 +08004793 pthread_mutex_lock(&out->position_query_lock);
Weiyin Jiang4813da12020-05-28 00:37:28 +08004794 written_frames = out->written /
4795 (audio_bytes_per_sample(out->hal_ip_format) * popcount(out->channel_mask));
4796
Ashish Jain5106d362016-05-11 19:23:33 +05304797 /* not querying actual state of buffering in kernel as it would involve an ioctl call
4798 * which then needs protection, this causes delay in TS query for pcm_offload usecase
4799 * hence only estimate.
4800 */
Weiyin Jiang4813da12020-05-28 00:37:28 +08004801 kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments;
4802 kernel_frames = kernel_buffer_size /
4803 (audio_bytes_per_sample(out->hal_op_format) * popcount(out->channel_mask));
Ashish Jain5106d362016-05-11 19:23:33 +05304804
Weiyin Jiang4813da12020-05-28 00:37:28 +08004805 if (written_frames >= (kernel_frames + dsp_frames))
4806 signed_frames = written_frames - kernel_frames - dsp_frames;
Ashish Jain5106d362016-05-11 19:23:33 +05304807
Zhou Song48453a02018-01-10 17:50:59 +08004808 if (signed_frames > 0) {
Ashish Jain5106d362016-05-11 19:23:33 +05304809 actual_frames_rendered = signed_frames;
Zhou Song48453a02018-01-10 17:50:59 +08004810 if (timestamp != NULL )
4811 *timestamp = out->writeAt;
4812 } else if (timestamp != NULL) {
4813 clock_gettime(CLOCK_MONOTONIC, timestamp);
4814 }
4815 pthread_mutex_unlock(&out->position_query_lock);
Ashish Jain5106d362016-05-11 19:23:33 +05304816
Weiyin Jiang4813da12020-05-28 00:37:28 +08004817 ALOGVV("%s signed frames %lld written frames %lld kernel frames %lld dsp frames %lld",
4818 __func__, signed_frames, written_frames, kernel_frames, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05304819
4820 return actual_frames_rendered;
4821}
4822
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004823static uint32_t out_get_sample_rate(const struct audio_stream *stream)
4824{
4825 struct stream_out *out = (struct stream_out *)stream;
4826
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004827 return out->sample_rate;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004828}
4829
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004830static int out_set_sample_rate(struct audio_stream *stream __unused,
4831 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004832{
4833 return -ENOSYS;
4834}
4835
4836static size_t out_get_buffer_size(const struct audio_stream *stream)
4837{
4838 struct stream_out *out = (struct stream_out *)stream;
4839
Varun Balaraje49253e2017-07-06 19:48:56 +05304840 if (is_interactive_usecase(out->usecase)) {
Sri Karri27279e12017-08-07 16:05:20 +05304841 return out->config.period_size * out->config.period_count;
Varun Balaraje49253e2017-07-06 19:48:56 +05304842 } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Naresh Tanniruee3499a2017-01-05 14:05:35 +05304843 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
4844 return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
4845 else
4846 return out->compr_config.fragment_size;
4847 } else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08004848 return voice_extn_compress_voip_out_get_buffer_size(out);
Dhananjay Kumarac341582017-02-23 23:42:25 +05304849 else if (is_offload_usecase(out->usecase) &&
4850 out->flags == AUDIO_OUTPUT_FLAG_DIRECT)
Ashish Jain83a6cc22016-06-28 14:34:17 +05304851 return out->hal_fragment_size;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004852
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004853 return out->config.period_size * out->af_period_multiplier *
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07004854 audio_stream_out_frame_size((const struct audio_stream_out *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004855}
4856
4857static uint32_t out_get_channels(const struct audio_stream *stream)
4858{
4859 struct stream_out *out = (struct stream_out *)stream;
4860
4861 return out->channel_mask;
4862}
4863
4864static audio_format_t out_get_format(const struct audio_stream *stream)
4865{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004866 struct stream_out *out = (struct stream_out *)stream;
4867
4868 return out->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004869}
4870
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004871static int out_set_format(struct audio_stream *stream __unused,
4872 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004873{
4874 return -ENOSYS;
4875}
4876
4877static int out_standby(struct audio_stream *stream)
4878{
4879 struct stream_out *out = (struct stream_out *)stream;
4880 struct audio_device *adev = out->dev;
Haynes Mathew George16081042017-05-31 17:16:49 -07004881 bool do_stop = true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004882
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304883 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4884 stream, out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004885
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07004886 lock_output_stream(out);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004887 if (!out->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004888 if (adev->adm_deregister_stream)
4889 adev->adm_deregister_stream(adev->adm_data, out->handle);
4890
Weiyin Jiang280ea742020-09-08 20:28:22 +08004891 if (is_offload_usecase(out->usecase)) {
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004892 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08004893 }
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004894
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08004895 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004896 out->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08004897 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
4898 voice_extn_compress_voip_close_output_stream(stream);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304899 out->started = 0;
Zhou Songa8895042016-07-05 17:54:22 +08004900 pthread_mutex_unlock(&adev->lock);
4901 pthread_mutex_unlock(&out->lock);
4902 ALOGD("VOIP output entered standby");
4903 return 0;
4904 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004905 if (out->pcm) {
4906 pcm_close(out->pcm);
4907 out->pcm = NULL;
4908 }
Meng Wanga09da002020-04-20 12:56:04 +08004909 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
4910 if (adev->haptic_pcm) {
4911 pcm_close(adev->haptic_pcm);
4912 adev->haptic_pcm = NULL;
4913 }
4914
4915 if (adev->haptic_buffer != NULL) {
4916 free(adev->haptic_buffer);
4917 adev->haptic_buffer = NULL;
4918 adev->haptic_buffer_size = 0;
4919 }
4920 adev->haptic_pcm_device_id = 0;
4921 }
4922
Haynes Mathew George16081042017-05-31 17:16:49 -07004923 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4924 do_stop = out->playback_started;
4925 out->playback_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07004926
4927 if (out->mmap_shared_memory_fd >= 0) {
4928 ALOGV("%s: closing mmap_shared_memory_fd = %d",
4929 __func__, out->mmap_shared_memory_fd);
4930 close(out->mmap_shared_memory_fd);
4931 out->mmap_shared_memory_fd = -1;
4932 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004933 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004934 } else {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07004935 ALOGD("copl(%p):standby", out);
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304936 out->send_next_track_params = false;
4937 out->is_compr_metadata_avail = false;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004938 out->gapless_mdata.encoder_delay = 0;
4939 out->gapless_mdata.encoder_padding = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004940 if (out->compr != NULL) {
4941 compress_close(out->compr);
4942 out->compr = NULL;
4943 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08004944 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004945 if (do_stop) {
4946 stop_output_stream(out);
4947 }
Lakshman Chaluvaraju06677b42019-06-24 10:04:52 +05304948 // if fm is active route on selected device in UI
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004949 audio_extn_fm_route_on_selected_device(adev, &out->device_list);
Eric Laurent150dbfe2013-02-27 14:31:02 -08004950 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004951 }
4952 pthread_mutex_unlock(&out->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07004953 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004954 return 0;
4955}
4956
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304957static int out_on_error(struct audio_stream *stream)
4958{
4959 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004960 int status = 0;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304961
4962 lock_output_stream(out);
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004963 // always send CMD_ERROR for offload streams, this
4964 // is needed e.g. when SSR happens within compress_open
4965 // since the stream is active, offload_callback_thread is also active.
4966 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
4967 stop_compressed_output_l(out);
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004968 }
4969 pthread_mutex_unlock(&out->lock);
4970
4971 status = out_standby(&out->stream.common);
4972
4973 lock_output_stream(out);
4974 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004975 send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304976 }
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05304977
4978 if (is_offload_usecase(out->usecase) && out->card_status == CARD_STATUS_OFFLINE) {
4979 ALOGD("Setting previous card status if offline");
4980 out->prev_card_status_offline = true;
4981 }
4982
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304983 pthread_mutex_unlock(&out->lock);
4984
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004985 return status;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304986}
4987
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304988/*
Weiyin Jiang280ea742020-09-08 20:28:22 +08004989 * standby implementation without locks, assumes that the callee already
4990 * has taken adev and out lock.
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304991 */
4992int out_standby_l(struct audio_stream *stream)
4993{
4994 struct stream_out *out = (struct stream_out *)stream;
4995 struct audio_device *adev = out->dev;
4996
4997 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4998 stream, out->usecase, use_case_table[out->usecase]);
4999
5000 if (!out->standby) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07005001 ATRACE_BEGIN("out_standby_l");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305002 if (adev->adm_deregister_stream)
5003 adev->adm_deregister_stream(adev->adm_data, out->handle);
5004
Weiyin Jiang280ea742020-09-08 20:28:22 +08005005 if (is_offload_usecase(out->usecase)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305006 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005007 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305008
5009 out->standby = true;
5010 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
5011 voice_extn_compress_voip_close_output_stream(stream);
5012 out->started = 0;
5013 ALOGD("VOIP output entered standby");
Haynes Mathew George380745d2017-10-04 15:27:45 -07005014 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305015 return 0;
5016 } else if (!is_offload_usecase(out->usecase)) {
5017 if (out->pcm) {
5018 pcm_close(out->pcm);
5019 out->pcm = NULL;
5020 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08005021 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
5022 if (adev->haptic_pcm) {
5023 pcm_close(adev->haptic_pcm);
5024 adev->haptic_pcm = NULL;
5025 }
5026
5027 if (adev->haptic_buffer != NULL) {
5028 free(adev->haptic_buffer);
5029 adev->haptic_buffer = NULL;
5030 adev->haptic_buffer_size = 0;
5031 }
5032 adev->haptic_pcm_device_id = 0;
5033 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305034 } else {
5035 ALOGD("copl(%p):standby", out);
5036 out->send_next_track_params = false;
5037 out->is_compr_metadata_avail = false;
5038 out->gapless_mdata.encoder_delay = 0;
5039 out->gapless_mdata.encoder_padding = 0;
5040 if (out->compr != NULL) {
5041 compress_close(out->compr);
5042 out->compr = NULL;
5043 }
5044 }
5045 stop_output_stream(out);
Haynes Mathew George380745d2017-10-04 15:27:45 -07005046 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305047 }
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07005048 ALOGV("%s: exit", __func__);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05305049 return 0;
5050}
5051
Aalique Grahame22e49102018-12-18 14:23:57 -08005052static int out_dump(const struct audio_stream *stream, int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005053{
Aalique Grahame22e49102018-12-18 14:23:57 -08005054 struct stream_out *out = (struct stream_out *)stream;
5055
5056 // We try to get the lock for consistency,
5057 // but it isn't necessary for these variables.
5058 // If we're not in standby, we may be blocked on a write.
5059 const bool locked = (pthread_mutex_trylock(&out->lock) == 0);
5060 dprintf(fd, " Standby: %s\n", out->standby ? "yes" : "no");
5061 dprintf(fd, " Frames written: %lld\n", (long long)out->written);
Dechen Chai22768452021-07-30 09:29:16 +05305062#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07005063 char buffer[256]; // for statistics formatting
5064 if (!is_offload_usecase(out->usecase)) {
5065 simple_stats_to_string(&out->fifo_underruns, buffer, sizeof(buffer));
5066 dprintf(fd, " Fifo frame underruns: %s\n", buffer);
5067 }
5068
Andy Hungc6bfd4a2019-07-01 18:26:00 -07005069 if (out->start_latency_ms.n > 0) {
5070 simple_stats_to_string(&out->start_latency_ms, buffer, sizeof(buffer));
5071 dprintf(fd, " Start latency ms: %s\n", buffer);
5072 }
Dechen Chai22768452021-07-30 09:29:16 +05305073#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08005074 if (locked) {
5075 pthread_mutex_unlock(&out->lock);
5076 }
5077
Dechen Chai22768452021-07-30 09:29:16 +05305078#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08005079 // dump error info
5080 (void)error_log_dump(
5081 out->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05305082#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005083 return 0;
5084}
5085
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005086static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
5087{
5088 int ret = 0;
5089 char value[32];
ApurupaPattapu2e084df2013-12-18 15:47:59 -08005090
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005091 if (!out || !parms) {
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005092 ALOGE("%s: return invalid ",__func__);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005093 return -EINVAL;
5094 }
5095
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305096 ret = audio_extn_parse_compress_metadata(out, parms);
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08005097
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005098 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
5099 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305100 out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005101 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005102 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
5103 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05305104 out->gapless_mdata.encoder_padding = atoi(value);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005105 }
5106
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005107 ALOGV("%s new encoder delay %u and padding %u", __func__,
5108 out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
5109
5110 return 0;
5111}
5112
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07005113static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
5114{
5115 return out == adev->primary_output || out == adev->voice_tx_output;
5116}
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005117
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305118// note: this call is safe only if the stream_cb is
5119// removed first in close_output_stream (as is done now).
5120static void out_snd_mon_cb(void * stream, struct str_parms * parms)
5121{
5122 if (!stream || !parms)
5123 return;
5124
5125 struct stream_out *out = (struct stream_out *)stream;
5126 struct audio_device *adev = out->dev;
5127
5128 card_status_t status;
5129 int card;
5130 if (parse_snd_card_status(parms, &card, &status) < 0)
5131 return;
5132
5133 pthread_mutex_lock(&adev->lock);
5134 bool valid_cb = (card == adev->snd_card);
5135 pthread_mutex_unlock(&adev->lock);
5136
5137 if (!valid_cb)
5138 return;
5139
5140 lock_output_stream(out);
5141 if (out->card_status != status)
5142 out->card_status = status;
5143 pthread_mutex_unlock(&out->lock);
5144
5145 ALOGI("out_snd_mon_cb for card %d usecase %s, status %s", card,
5146 use_case_table[out->usecase],
5147 status == CARD_STATUS_OFFLINE ? "offline" : "online");
5148
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305149 if (status == CARD_STATUS_OFFLINE) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305150 out_on_error(stream);
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305151 if (voice_is_call_state_active(adev) &&
5152 out == adev->primary_output) {
5153 ALOGD("%s: SSR/PDR occurred, end all calls\n", __func__);
5154 pthread_mutex_lock(&adev->lock);
5155 voice_stop_call(adev);
5156 adev->mode = AUDIO_MODE_NORMAL;
5157 pthread_mutex_unlock(&adev->lock);
5158 }
5159 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305160 return;
5161}
5162
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005163int route_output_stream(struct stream_out *out,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005164 struct listnode *devices)
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005165{
5166 struct audio_device *adev = out->dev;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005167 int ret = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005168 struct listnode new_devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005169 bool bypass_a2dp = false;
5170 bool reconfig = false;
5171 unsigned long service_interval = 0;
5172
5173 ALOGD("%s: enter: usecase(%d: %s) devices %x",
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005174 __func__, out->usecase, use_case_table[out->usecase], get_device_types(devices));
5175
5176 list_init(&new_devices);
5177 assign_devices(&new_devices, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005178
5179 lock_output_stream(out);
5180 pthread_mutex_lock(&adev->lock);
5181
5182 /*
5183 * When HDMI cable is unplugged the music playback is paused and
5184 * the policy manager sends routing=0. But the audioflinger continues
5185 * to write data until standby time (3sec). As the HDMI core is
5186 * turned off, the write gets blocked.
5187 * Avoid this by routing audio to speaker until standby.
5188 */
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08005189 if (is_single_device_type_equal(&out->device_list,
5190 AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005191 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005192 !audio_extn_passthru_is_passthrough_stream(out) &&
5193 (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005194 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005195 }
5196 /*
5197 * When A2DP is disconnected the
5198 * music playback is paused and the policy manager sends routing=0
5199 * But the audioflinger continues to write data until standby time
5200 * (3sec). As BT is turned off, the write gets blocked.
5201 * Avoid this by routing audio to speaker until standby.
5202 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005203 if (is_a2dp_out_device_type(&out->device_list) &&
5204 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005205 !audio_extn_a2dp_source_is_ready() &&
5206 !adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005207 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005208 }
5209 /*
Weiyin Jiangabedea32020-12-09 12:49:19 +08005210 * When USB headset is disconnected the music playback paused
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005211 * and the policy manager send routing=0. But if the USB is connected
5212 * back before the standby time, AFE is not closed and opened
5213 * when USB is connected back. So routing to speker will guarantee
5214 * AFE reconfiguration and AFE will be opend once USB is connected again
5215 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005216 if (is_usb_out_device_type(&out->device_list) &&
5217 list_empty(&new_devices) &&
5218 !audio_extn_usb_connected(NULL)) {
Sujin Panicker84d953a2020-11-16 17:39:54 +05305219 if (adev->mode == AUDIO_MODE_IN_CALL || adev->mode == AUDIO_MODE_IN_COMMUNICATION)
5220 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_EARPIECE, "");
5221 else
5222 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005223 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005224 /* To avoid a2dp to sco overlapping / BT device improper state
5225 * check with BT lib about a2dp streaming support before routing
5226 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005227 if (is_a2dp_out_device_type(&new_devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005228 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005229 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
5230 compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005231 //combo usecase just by pass a2dp
5232 ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
5233 bypass_a2dp = true;
5234 } else {
5235 ALOGE("%s: A2DP profile is not ready,ignoring routing request", __func__);
5236 /* update device to a2dp and don't route as BT returned error
5237 * However it is still possible a2dp routing called because
5238 * of current active device disconnection (like wired headset)
5239 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005240 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005241 pthread_mutex_unlock(&adev->lock);
5242 pthread_mutex_unlock(&out->lock);
5243 goto error;
5244 }
5245 }
5246 }
5247
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005248 // Workaround: If routing to an non existing usb device, fail gracefully
5249 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005250 if (is_usb_out_device_type(&new_devices)) {
5251 struct str_parms *parms =
5252 str_parms_create_str(get_usb_device_address(&new_devices));
5253 if (!parms)
5254 goto error;
Weiyin Jiangabedea32020-12-09 12:49:19 +08005255 if (!audio_extn_usb_connected(NULL)) {
5256 ALOGW("%s: ignoring rerouting to non existing USB card", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005257 pthread_mutex_unlock(&adev->lock);
5258 pthread_mutex_unlock(&out->lock);
5259 str_parms_destroy(parms);
5260 ret = -ENOSYS;
5261 goto error;
5262 }
5263 str_parms_destroy(parms);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005264 }
5265
Weiyin Jiang80c8f9a2020-01-10 20:42:08 +08005266 // Workaround: If routing to an non existing hdmi device, fail gracefully
5267 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
5268 (platform_get_edid_info_v2(adev->platform,
5269 out->extconn.cs.controller,
5270 out->extconn.cs.stream) != 0)) {
5271 ALOGW("out_set_parameters() ignoring rerouting to non existing HDMI/DP");
5272 pthread_mutex_unlock(&adev->lock);
5273 pthread_mutex_unlock(&out->lock);
5274 ret = -ENOSYS;
5275 goto error;
5276 }
5277
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005278 /*
5279 * select_devices() call below switches all the usecases on the same
5280 * backend to the new device. Refer to check_usecases_codec_backend() in
5281 * the select_devices(). But how do we undo this?
5282 *
5283 * For example, music playback is active on headset (deep-buffer usecase)
5284 * and if we go to ringtones and select a ringtone, low-latency usecase
5285 * will be started on headset+speaker. As we can't enable headset+speaker
5286 * and headset devices at the same time, select_devices() switches the music
5287 * playback to headset+speaker while starting low-lateny usecase for ringtone.
5288 * So when the ringtone playback is completed, how do we undo the same?
5289 *
5290 * We are relying on the out_set_parameters() call on deep-buffer output,
5291 * once the ringtone playback is ended.
5292 * NOTE: We should not check if the current devices are same as new devices.
5293 * Because select_devices() must be called to switch back the music
5294 * playback to headset.
5295 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005296 if (!list_empty(&new_devices)) {
5297 bool same_dev = compare_devices(&out->device_list, &new_devices);
5298 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005299
5300 if (output_drives_call(adev, out)) {
5301 if (!voice_is_call_state_active(adev)) {
5302 if (adev->mode == AUDIO_MODE_IN_CALL) {
5303 adev->current_call_output = out;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005304 ret = voice_start_call(adev);
5305 }
5306 } else {
Kunlei Zhang253ad102020-10-14 16:21:28 +08005307 platform_is_volume_boost_supported_device(adev->platform, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005308 adev->current_call_output = out;
5309 voice_update_devices_for_all_voice_usecases(adev);
5310 }
5311 }
5312
Mingshu Pang971ff702020-09-09 15:28:22 +08005313 if (is_usb_out_device_type(&out->device_list)) {
5314 service_interval = audio_extn_usb_find_service_interval(false, true /*playback*/);
5315 audio_extn_usb_set_service_interval(true /*playback*/,
5316 service_interval,
5317 &reconfig);
5318 ALOGD("%s, svc_int(%ld),reconfig(%d)",__func__,service_interval, reconfig);
5319 }
5320
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005321 if (!out->standby) {
5322 if (!same_dev) {
5323 ALOGV("update routing change");
5324 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
5325 adev->perf_lock_opts,
5326 adev->perf_lock_opts_size);
5327 if (adev->adm_on_routing_change)
5328 adev->adm_on_routing_change(adev->adm_data,
5329 out->handle);
5330 }
5331 if (!bypass_a2dp) {
5332 select_devices(adev, out->usecase);
5333 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005334 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
5335 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005336 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005337 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005338 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005339 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005340 }
5341
5342 if (!same_dev) {
5343 // on device switch force swap, lower functions will make sure
5344 // to check if swap is allowed or not.
5345 platform_set_swap_channels(adev, true);
5346 audio_extn_perf_lock_release(&adev->perf_lock_handle);
5347 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005348 pthread_mutex_lock(&out->latch_lock);
5349 if (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready()) {
5350 if (out->a2dp_muted) {
5351 out->a2dp_muted = false;
5352 if (is_offload_usecase(out->usecase))
5353 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
5354 else if (out->usecase != USECASE_AUDIO_PLAYBACK_VOIP)
5355 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005356 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005357 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005358 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP && !out->a2dp_muted)
5359 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
5360 pthread_mutex_unlock(&out->latch_lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005361 }
5362 }
5363
5364 pthread_mutex_unlock(&adev->lock);
5365 pthread_mutex_unlock(&out->lock);
5366
5367 /*handles device and call state changes*/
5368 audio_extn_extspk_update(adev->extspk);
5369
Revathi Uddaraju4255a632021-12-02 05:11:13 -08005370 clear_devices(&new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005371error:
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005372 ALOGV("%s: exit: code(%d)", __func__, ret);
5373 return ret;
5374}
5375
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005376static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
5377{
5378 struct stream_out *out = (struct stream_out *)stream;
5379 struct audio_device *adev = out->dev;
5380 struct str_parms *parms;
5381 char value[32];
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005382 int ret = 0, err;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005383 int ext_controller = -1;
5384 int ext_stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005385
sangwoobc677242013-08-08 16:53:43 +09005386 ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07005387 __func__, out->usecase, use_case_table[out->usecase], kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005388 parms = str_parms_create_str(kvpairs);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305389 if (!parms)
5390 goto error;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005391
5392 err = platform_get_controller_stream_from_params(parms, &ext_controller,
5393 &ext_stream);
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08005394 if (err == 0) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005395 out->extconn.cs.controller = ext_controller;
5396 out->extconn.cs.stream = ext_stream;
5397 ALOGD("%s: usecase(%s) new controller/stream (%d/%d)", __func__,
5398 use_case_table[out->usecase], out->extconn.cs.controller,
5399 out->extconn.cs.stream);
5400 }
5401
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005402 if (out == adev->primary_output) {
5403 pthread_mutex_lock(&adev->lock);
5404 audio_extn_set_parameters(adev, parms);
5405 pthread_mutex_unlock(&adev->lock);
5406 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005407 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07005408 lock_output_stream(out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005409 parse_compress_metadata(out, parms);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08005410
5411 audio_extn_dts_create_state_notifier_node(out->usecase);
5412 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
5413 popcount(out->channel_mask),
5414 out->playback_started);
5415
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005416 pthread_mutex_unlock(&out->lock);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005417 }
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005418
Surendar Karkaf51b5842018-04-26 11:28:38 +05305419 err = str_parms_get_str(parms, AUDIO_PARAMETER_DUAL_MONO, value,
5420 sizeof(value));
5421 if (err >= 0) {
5422 if (!strncmp("true", value, sizeof("true")) || atoi(value))
5423 audio_extn_send_dual_mono_mixing_coefficients(out);
5424 }
5425
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305426 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
5427 if (err >= 0) {
5428 strlcpy(out->profile, value, sizeof(out->profile));
5429 ALOGV("updating stream profile with value '%s'", out->profile);
5430 lock_output_stream(out);
5431 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
5432 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005433 &out->device_list, out->flags,
5434 out->hal_op_format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305435 out->sample_rate, out->bit_width,
5436 out->channel_mask, out->profile,
5437 &out->app_type_cfg);
5438 pthread_mutex_unlock(&out->lock);
5439 }
5440
Alexy Joseph98988832017-01-13 14:56:59 -08005441 //suspend, resume handling block
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005442 //remove QOS only if vendor.audio.hal.dynamic.qos.config.supported is set to true
5443 // and vendor.audio.hal.output.suspend.supported is set to true
5444 if (out->hal_output_suspend_supported && out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08005445 //check suspend parameter only for low latency and if the property
5446 //is enabled
5447 if (str_parms_get_str(parms, "suspend_playback", value, sizeof(value)) >= 0) {
5448 ALOGI("%s: got suspend_playback %s", __func__, value);
5449 lock_output_stream(out);
5450 if (!strncmp(value, "false", 5)) {
5451 //suspend_playback=false is supposed to set QOS value back to 75%
5452 //the mixer control sent with value Enable will achieve that
5453 ret = audio_route_apply_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5454 } else if (!strncmp (value, "true", 4)) {
5455 //suspend_playback=true is supposed to remove QOS value
5456 //resetting the mixer control will set the default value
5457 //for the mixer control which is Disable and this removes the QOS vote
5458 ret = audio_route_reset_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5459 } else {
5460 ALOGE("%s: Wrong value sent for suspend_playback, expected true/false,"
5461 " got %s", __func__, value);
5462 ret = -1;
5463 }
5464
5465 if (ret != 0) {
5466 ALOGE("%s: %s mixer ctl failed with %d, ignore suspend/resume setparams",
5467 __func__, out->pm_qos_mixer_path, ret);
5468 }
5469
5470 pthread_mutex_unlock(&out->lock);
5471 }
5472 }
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005473
Alexy Joseph98988832017-01-13 14:56:59 -08005474 //end suspend, resume handling block
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005475 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305476error:
Eric Laurent994a6932013-07-17 11:51:42 -07005477 ALOGV("%s: exit: code(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005478 return ret;
5479}
5480
Paul McLeana50b7332018-12-17 08:24:21 -07005481static int in_set_microphone_direction(const struct audio_stream_in *stream,
5482 audio_microphone_direction_t dir) {
justinweng20fb6d82019-02-21 18:49:00 -07005483 struct stream_in *in = (struct stream_in *)stream;
5484
5485 ALOGVV("%s: standby %d source %d dir %d", __func__, in->standby, in->source, dir);
5486
5487 in->direction = dir;
5488
5489 if (in->standby)
5490 return 0;
5491
5492 return audio_extn_audiozoom_set_microphone_direction(in, dir);
Paul McLeana50b7332018-12-17 08:24:21 -07005493}
5494
5495static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom) {
justinweng20fb6d82019-02-21 18:49:00 -07005496 struct stream_in *in = (struct stream_in *)stream;
5497
5498 ALOGVV("%s: standby %d source %d zoom %f", __func__, in->standby, in->source, zoom);
5499
5500 if (zoom > 1.0 || zoom < -1.0)
5501 return -EINVAL;
5502
5503 in->zoom = zoom;
5504
5505 if (in->standby)
5506 return 0;
5507
5508 return audio_extn_audiozoom_set_microphone_field_dimension(in, zoom);
Paul McLeana50b7332018-12-17 08:24:21 -07005509}
5510
5511
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005512static bool stream_get_parameter_channels(struct str_parms *query,
5513 struct str_parms *reply,
5514 audio_channel_mask_t *supported_channel_masks) {
5515 int ret = -1;
5516 char value[512];
5517 bool first = true;
5518 size_t i, j;
5519
5520 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
5521 ret = 0;
5522 value[0] = '\0';
5523 i = 0;
5524 while (supported_channel_masks[i] != 0) {
5525 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5526 if (channels_name_to_enum_table[j].value == supported_channel_masks[i]) {
5527 if (!first)
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305528 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005529
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305530 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005531 first = false;
5532 break;
5533 }
5534 }
5535 i++;
5536 }
5537 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5538 }
5539 return ret == 0;
5540}
5541
5542static bool stream_get_parameter_formats(struct str_parms *query,
5543 struct str_parms *reply,
5544 audio_format_t *supported_formats) {
5545 int ret = -1;
5546 char value[256];
5547 size_t i, j;
5548 bool first = true;
5549
5550 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
5551 ret = 0;
5552 value[0] = '\0';
5553 i = 0;
5554 while (supported_formats[i] != 0) {
5555 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5556 if (formats_name_to_enum_table[j].value == supported_formats[i]) {
5557 if (!first) {
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305558 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005559 }
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305560 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005561 first = false;
5562 break;
5563 }
5564 }
5565 i++;
5566 }
5567 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
5568 }
5569 return ret == 0;
5570}
5571
5572static bool stream_get_parameter_rates(struct str_parms *query,
5573 struct str_parms *reply,
5574 uint32_t *supported_sample_rates) {
5575
5576 int i;
5577 char value[256];
5578 int ret = -1;
5579 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
5580 ret = 0;
5581 value[0] = '\0';
5582 i=0;
5583 int cursor = 0;
5584 while (supported_sample_rates[i]) {
5585 int avail = sizeof(value) - cursor;
5586 ret = snprintf(value + cursor, avail, "%s%d",
5587 cursor > 0 ? "|" : "",
5588 supported_sample_rates[i]);
5589 if (ret < 0 || ret >= avail) {
5590 // if cursor is at the last element of the array
5591 // overwrite with \0 is duplicate work as
5592 // snprintf already put a \0 in place.
5593 // else
5594 // we had space to write the '|' at value[cursor]
5595 // (which will be overwritten) or no space to fill
5596 // the first element (=> cursor == 0)
5597 value[cursor] = '\0';
5598 break;
5599 }
5600 cursor += ret;
5601 ++i;
5602 }
5603 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
5604 value);
5605 }
5606 return ret >= 0;
5607}
5608
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005609static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
5610{
5611 struct stream_out *out = (struct stream_out *)stream;
5612 struct str_parms *query = str_parms_create_str(keys);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005613 char *str = (char*) NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005614 char value[256];
5615 struct str_parms *reply = str_parms_create();
5616 size_t i, j;
5617 int ret;
5618 bool first = true;
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005619
5620 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005621 if (reply) {
5622 str_parms_destroy(reply);
5623 }
5624 if (query) {
5625 str_parms_destroy(query);
5626 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005627 ALOGE("out_get_parameters: failed to allocate mem for query or reply");
5628 return NULL;
5629 }
5630
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005631 ALOGV("%s: %s enter: keys - %s", __func__, use_case_table[out->usecase], keys);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005632 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
5633 if (ret >= 0) {
5634 value[0] = '\0';
5635 i = 0;
5636 while (out->supported_channel_masks[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005637 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5638 if (channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005639 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005640 strlcat(value, "|", sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005641 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005642 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005643 first = false;
5644 break;
5645 }
5646 }
5647 i++;
5648 }
5649 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5650 str = str_parms_to_str(reply);
5651 } else {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08005652 voice_extn_out_get_parameters(out, query, reply);
5653 str = str_parms_to_str(reply);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005654 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005655
Alexy Joseph62142aa2015-11-16 15:10:34 -08005656
5657 ret = str_parms_get_str(query, "is_direct_pcm_track", value, sizeof(value));
5658 if (ret >= 0) {
5659 value[0] = '\0';
Dhananjay Kumarac341582017-02-23 23:42:25 +05305660 if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
5661 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Alexy Joseph62142aa2015-11-16 15:10:34 -08005662 ALOGV("in direct_pcm");
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05305663 strlcat(value, "true", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005664 } else {
5665 ALOGV("not in direct_pcm");
Sharad Sangle3dd5a4a2015-12-10 18:39:17 +05305666 strlcat(value, "false", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005667 }
5668 str_parms_add_str(reply, "is_direct_pcm_track", value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005669 if (str)
5670 free(str);
Alexy Joseph62142aa2015-11-16 15:10:34 -08005671 str = str_parms_to_str(reply);
5672 }
5673
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005674 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
5675 if (ret >= 0) {
5676 value[0] = '\0';
5677 i = 0;
5678 first = true;
5679 while (out->supported_formats[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005680 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5681 if (formats_name_to_enum_table[j].value == out->supported_formats[i]) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005682 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005683 strlcat(value, "|", sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005684 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005685 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005686 first = false;
5687 break;
5688 }
5689 }
5690 i++;
5691 }
5692 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005693 if (str)
5694 free(str);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005695 str = str_parms_to_str(reply);
5696 }
Mingming Yin3a941d42016-02-17 18:08:05 -08005697
5698 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value, sizeof(value));
5699 if (ret >= 0) {
5700 value[0] = '\0';
5701 i = 0;
5702 first = true;
5703 while (out->supported_sample_rates[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005704 for (j = 0; j < ARRAY_SIZE(out_sample_rates_name_to_enum_table); j++) {
5705 if (out_sample_rates_name_to_enum_table[j].value == out->supported_sample_rates[i]) {
Mingming Yin3a941d42016-02-17 18:08:05 -08005706 if (!first) {
5707 strlcat(value, "|", sizeof(value));
5708 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005709 strlcat(value, out_sample_rates_name_to_enum_table[j].name, sizeof(value));
Mingming Yin3a941d42016-02-17 18:08:05 -08005710 first = false;
5711 break;
5712 }
5713 }
5714 i++;
5715 }
5716 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value);
5717 if (str)
5718 free(str);
5719 str = str_parms_to_str(reply);
5720 }
5721
Alexy Joseph98988832017-01-13 14:56:59 -08005722 if (str_parms_get_str(query, "supports_hw_suspend", value, sizeof(value)) >= 0) {
5723 //only low latency track supports suspend_resume
5724 str_parms_add_int(reply, "supports_hw_suspend",
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005725 (out->hal_output_suspend_supported));
Alexy Joseph98988832017-01-13 14:56:59 -08005726 if (str)
5727 free(str);
5728 str = str_parms_to_str(reply);
5729 }
5730
5731
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005732 str_parms_destroy(query);
5733 str_parms_destroy(reply);
Eric Laurent994a6932013-07-17 11:51:42 -07005734 ALOGV("%s: exit: returns - %s", __func__, str);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005735 return str;
5736}
5737
5738static uint32_t out_get_latency(const struct audio_stream_out *stream)
5739{
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005740 uint32_t period_ms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005741 struct stream_out *out = (struct stream_out *)stream;
Alexy Josephaa54c872014-12-03 02:46:47 -08005742 uint32_t latency = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005743
Alexy Josephaa54c872014-12-03 02:46:47 -08005744 if (is_offload_usecase(out->usecase)) {
Manish Dewangan07de2142017-02-27 19:27:20 +05305745 lock_output_stream(out);
5746 latency = audio_extn_utils_compress_get_dsp_latency(out);
5747 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07005748 } else if ((out->realtime) ||
5749 (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005750 // since the buffer won't be filled up faster than realtime,
5751 // return a smaller number
5752 if (out->config.rate)
5753 period_ms = (out->af_period_multiplier * out->config.period_size *
5754 1000) / (out->config.rate);
5755 else
5756 period_ms = 0;
George Gao9ba8a142020-07-23 14:30:03 -07005757 latency = period_ms + platform_render_latency(out) / 1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005758 } else {
5759 latency = (out->config.period_count * out->config.period_size * 1000) /
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005760 (out->config.rate);
pavanisra2d95d82022-02-09 18:55:58 +05305761 if (out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
5762 out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY)
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005763 latency += platform_render_latency(out)/1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005764 }
5765
Zhou Songd2537a02020-06-11 22:04:46 +08005766 if (!out->standby && is_a2dp_out_device_type(&out->device_list))
Aniket Kumar Latad5972fa2017-02-08 13:53:48 -08005767 latency += audio_extn_a2dp_get_encoder_latency();
5768
Anish Kumar50ebcbf2014-12-09 04:01:39 +05305769 ALOGV("%s: Latency %d", __func__, latency);
Alexy Josephaa54c872014-12-03 02:46:47 -08005770 return latency;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005771}
5772
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305773static float AmpToDb(float amplification)
5774{
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305775 float db = DSD_VOLUME_MIN_DB;
5776 if (amplification > 0) {
5777 db = 20 * log10(amplification);
5778 if(db < DSD_VOLUME_MIN_DB)
5779 return DSD_VOLUME_MIN_DB;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305780 }
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305781 return db;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305782}
5783
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305784#ifdef SOFT_VOLUME
5785static int out_set_soft_volume_params(struct audio_stream_out *stream)
5786{
5787 struct stream_out *out = (struct stream_out *)stream;
5788 int ret = 0;
5789 char mixer_ctl_name[128];
5790 struct audio_device *adev = out->dev;
5791 struct mixer_ctl *ctl = NULL;
5792 struct soft_step_volume_params *volume_params = NULL;
5793
5794 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5795 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Soft Vol Params", pcm_device_id);
5796 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5797 if (!ctl) {
5798 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5799 return -EINVAL;
5800 }
5801
5802 volume_params =(struct soft_step_volume_params * ) malloc(sizeof(struct soft_step_volume_params));
5803 if (volume_params == NULL){
5804 ALOGE("%s : malloc is failed for volume params", __func__);
5805 return -EINVAL;
5806 } else {
5807 ret = platform_get_soft_step_volume_params(volume_params,out->usecase);
5808 if (ret < 0) {
5809 ALOGE("%s : platform_get_soft_step_volume_params is fialed", __func__);
Karan Naidu28b335a2022-05-18 23:00:08 +05305810 ret = -EINVAL;
5811 goto ERR_EXIT;
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305812 }
5813
5814 }
5815 ret = mixer_ctl_set_array(ctl, volume_params, sizeof(struct soft_step_volume_params)/sizeof(int));
5816 if (ret < 0) {
5817 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
Karan Naidu28b335a2022-05-18 23:00:08 +05305818 ret = -EINVAL;
5819 goto ERR_EXIT;
5820 }
5821
5822 if (volume_params) {
5823 free(volume_params);
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305824 }
5825 return 0;
Karan Naidu28b335a2022-05-18 23:00:08 +05305826
5827ERR_EXIT:
5828 if (volume_params) {
5829 free(volume_params);
5830 }
5831 return ret;
Krishna Kishor Jha10ad39f2022-02-21 17:02:47 +05305832}
5833#endif
5834
Arun Mirpuri5d170872019-03-26 13:21:31 -07005835static int out_set_mmap_volume(struct audio_stream_out *stream, float left,
5836 float right)
5837{
5838 struct stream_out *out = (struct stream_out *)stream;
5839 long volume = 0;
5840 char mixer_ctl_name[128] = "";
5841 struct audio_device *adev = out->dev;
5842 struct mixer_ctl *ctl = NULL;
5843 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5844 PCM_PLAYBACK);
5845
5846 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5847 "Playback %d Volume", pcm_device_id);
5848 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5849 if (!ctl) {
5850 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5851 __func__, mixer_ctl_name);
5852 return -EINVAL;
5853 }
5854 if (left != right)
5855 ALOGW("%s: Left and right channel volume mismatch:%f,%f",
5856 __func__, left, right);
5857 volume = (long)(left * (MMAP_PLAYBACK_VOLUME_MAX*1.0));
5858 if (mixer_ctl_set_value(ctl, 0, volume) < 0){
5859 ALOGE("%s:ctl for mixer cmd - %s, volume %ld returned error",
5860 __func__, mixer_ctl_name, volume);
5861 return -EINVAL;
5862 }
5863 return 0;
5864}
5865
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305866static int out_set_compr_volume(struct audio_stream_out *stream, float left,
5867 float right)
5868{
5869 struct stream_out *out = (struct stream_out *)stream;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305870 long volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305871 char mixer_ctl_name[128];
5872 struct audio_device *adev = out->dev;
5873 struct mixer_ctl *ctl;
5874 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5875 PCM_PLAYBACK);
5876
5877 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5878 "Compress Playback %d Volume", pcm_device_id);
5879 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5880 if (!ctl) {
5881 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5882 __func__, mixer_ctl_name);
5883 return -EINVAL;
5884 }
5885 ALOGE("%s:ctl for mixer cmd - %s, left %f, right %f",
5886 __func__, mixer_ctl_name, left, right);
5887 volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
5888 volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
5889 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5890
5891 return 0;
5892}
5893
Zhou Song2b8f28f2017-09-11 10:51:38 +08005894static int out_set_voip_volume(struct audio_stream_out *stream, float left,
5895 float right)
5896{
5897 struct stream_out *out = (struct stream_out *)stream;
5898 char mixer_ctl_name[] = "App Type Gain";
5899 struct audio_device *adev = out->dev;
5900 struct mixer_ctl *ctl;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305901 long set_values[4];
Zhou Song2b8f28f2017-09-11 10:51:38 +08005902
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07005903 if (!is_valid_volume(left, right)) {
5904 ALOGE("%s: Invalid stream volume for left=%f, right=%f",
5905 __func__, left, right);
5906 return -EINVAL;
5907 }
5908
Zhou Song2b8f28f2017-09-11 10:51:38 +08005909 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5910 if (!ctl) {
5911 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5912 __func__, mixer_ctl_name);
5913 return -EINVAL;
5914 }
5915
5916 set_values[0] = 0; //0: Rx Session 1:Tx Session
5917 set_values[1] = out->app_type_cfg.app_type;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305918 set_values[2] = (long)(left * VOIP_PLAYBACK_VOLUME_MAX);
5919 set_values[3] = (long)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Song2b8f28f2017-09-11 10:51:38 +08005920
5921 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
5922 return 0;
5923}
5924
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305925static int out_set_pcm_volume(struct audio_stream_out *stream, float left,
5926 float right)
5927{
5928 struct stream_out *out = (struct stream_out *)stream;
5929 /* Volume control for pcm playback */
5930 if (left != right) {
5931 return -EINVAL;
5932 } else {
5933 char mixer_ctl_name[128];
5934 struct audio_device *adev = out->dev;
5935 struct mixer_ctl *ctl;
5936 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5937 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Volume", pcm_device_id);
5938 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5939 if (!ctl) {
5940 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5941 return -EINVAL;
5942 }
5943
5944 int volume = (int) (left * PCM_PLAYBACK_VOLUME_MAX);
5945 int ret = mixer_ctl_set_value(ctl, 0, volume);
5946 if (ret < 0) {
5947 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
5948 return -EINVAL;
5949 }
5950
5951 ALOGV("%s : Pcm set volume value %d left %f", __func__, volume, left);
5952
5953 return 0;
5954 }
5955}
5956
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005957static int out_set_volume(struct audio_stream_out *stream, float left,
5958 float right)
5959{
Eric Laurenta9024de2013-04-04 09:19:12 -07005960 struct stream_out *out = (struct stream_out *)stream;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005961 int volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305962 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005963
Arun Mirpuri5d170872019-03-26 13:21:31 -07005964 ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
Eric Laurenta9024de2013-04-04 09:19:12 -07005965 if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
5966 /* only take left channel into account: the API is for stereo anyway */
5967 out->muted = (left == 0.0f);
5968 return 0;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005969 } else if (is_offload_usecase(out->usecase)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305970 if (audio_extn_passthru_is_passthrough_stream(out)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005971 /*
5972 * Set mute or umute on HDMI passthrough stream.
5973 * Only take left channel into account.
5974 * Mute is 0 and unmute 1
5975 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305976 audio_extn_passthru_set_volume(out, (left == 0.0f));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305977 } else if (out->format == AUDIO_FORMAT_DSD){
5978 char mixer_ctl_name[128] = "DSD Volume";
5979 struct audio_device *adev = out->dev;
5980 struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5981
5982 if (!ctl) {
5983 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5984 __func__, mixer_ctl_name);
5985 return -EINVAL;
5986 }
Manish Dewangan338c50a2017-09-12 15:22:03 +05305987 volume[0] = (long)(AmpToDb(left));
5988 volume[1] = (long)(AmpToDb(right));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305989 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5990 return 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005991 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS) &&
Derek Chendf05eea2019-08-01 13:57:49 -07005992 (out->car_audio_stream == CAR_AUDIO_STREAM_MEDIA)) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005993 ALOGD("%s: Overriding offload set volume for media bus stream", __func__);
5994 struct listnode *node = NULL;
5995 list_for_each(node, &adev->active_outputs_list) {
5996 streams_output_ctxt_t *out_ctxt = node_to_item(node,
5997 streams_output_ctxt_t,
5998 list);
5999 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
6000 out->volume_l = out_ctxt->output->volume_l;
6001 out->volume_r = out_ctxt->output->volume_r;
6002 }
6003 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006004 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006005 if (!out->a2dp_muted) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07006006 ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
6007 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006008 pthread_mutex_unlock(&out->latch_lock);
Philippe Gravel1c9ac352019-05-28 16:08:37 -07006009 return ret;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07006010 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +08006011 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006012 ALOGV("%s: compress mute %d", __func__, out->a2dp_muted);
6013 if (!out->a2dp_muted)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306014 ret = out_set_compr_volume(stream, left, right);
6015 out->volume_l = left;
6016 out->volume_r = right;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006017 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306018 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006019 }
Vikram Panduranga93f080e2017-06-07 18:16:14 -07006020 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
Aalique Grahame22e49102018-12-18 14:23:57 -08006021 out->app_type_cfg.gain[0] = (int)(left * VOIP_PLAYBACK_VOLUME_MAX);
6022 out->app_type_cfg.gain[1] = (int)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006023 pthread_mutex_lock(&out->latch_lock);
Aalique Grahame22e49102018-12-18 14:23:57 -08006024 if (!out->standby) {
6025 audio_extn_utils_send_app_type_gain(out->dev,
6026 out->app_type_cfg.app_type,
6027 &out->app_type_cfg.gain[0]);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006028 if (!out->a2dp_muted)
6029 ret = out_set_voip_volume(stream, left, right);
Aalique Grahame22e49102018-12-18 14:23:57 -08006030 }
Zhou Song2b8f28f2017-09-11 10:51:38 +08006031 out->volume_l = left;
6032 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006033 pthread_mutex_unlock(&out->latch_lock);
Zhou Song2b8f28f2017-09-11 10:51:38 +08006034 return ret;
Arun Mirpuri5d170872019-03-26 13:21:31 -07006035 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
6036 ALOGV("%s: MMAP set volume called", __func__);
6037 if (!out->standby)
6038 ret = out_set_mmap_volume(stream, left, right);
6039 out->volume_l = left;
6040 out->volume_r = right;
6041 return ret;
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306042 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
Ramu Gottipati36547092018-12-28 11:32:09 +05306043 out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
6044 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
Zhou Songbaddf9f2020-11-20 13:57:39 +08006045 pthread_mutex_lock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306046 /* Volume control for pcm playback */
Zhou Songbaddf9f2020-11-20 13:57:39 +08006047 if (!out->standby && !out->a2dp_muted)
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306048 ret = out_set_pcm_volume(stream, left, right);
6049 else
6050 out->apply_volume = true;
6051
6052 out->volume_l = left;
6053 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006054 pthread_mutex_unlock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05306055 return ret;
Derek Chenf13dd492018-11-13 14:53:51 -08006056 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
6057 ALOGV("%s: bus device set volume called", __func__);
Zhou Songbaddf9f2020-11-20 13:57:39 +08006058 pthread_mutex_lock(&out->latch_lock);
6059 if (!out->standby && !out->a2dp_muted)
Derek Chenf13dd492018-11-13 14:53:51 -08006060 ret = out_set_pcm_volume(stream, left, right);
6061 out->volume_l = left;
6062 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08006063 pthread_mutex_unlock(&out->latch_lock);
Derek Chenf13dd492018-11-13 14:53:51 -08006064 return ret;
Eric Laurenta9024de2013-04-04 09:19:12 -07006065 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006066
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006067 return -ENOSYS;
6068}
6069
Zhou Songc9672822017-08-16 16:01:39 +08006070static void update_frames_written(struct stream_out *out, size_t bytes)
6071{
6072 size_t bpf = 0;
6073
6074 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
6075 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
6076 bpf = 1;
6077 else if (!is_offload_usecase(out->usecase))
6078 bpf = audio_bytes_per_sample(out->format) *
6079 audio_channel_count_from_out_mask(out->channel_mask);
Zhou Song48453a02018-01-10 17:50:59 +08006080
6081 pthread_mutex_lock(&out->position_query_lock);
6082 if (bpf != 0) {
Zhou Songc9672822017-08-16 16:01:39 +08006083 out->written += bytes / bpf;
Zhou Song48453a02018-01-10 17:50:59 +08006084 clock_gettime(CLOCK_MONOTONIC, &out->writeAt);
6085 }
6086 pthread_mutex_unlock(&out->position_query_lock);
Zhou Songc9672822017-08-16 16:01:39 +08006087}
6088
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006089int split_and_write_audio_haptic_data(struct stream_out *out,
6090 const void *buffer, size_t bytes_to_write)
6091{
6092 struct audio_device *adev = out->dev;
6093
6094 int ret = 0;
6095 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6096 size_t bytes_per_sample = audio_bytes_per_sample(out->format);
6097 size_t frame_size = channel_count * bytes_per_sample;
6098 size_t frame_count = bytes_to_write / frame_size;
6099
6100 bool force_haptic_path =
6101 property_get_bool("vendor.audio.test_haptic", false);
6102
6103 // extract Haptics data from Audio buffer
6104 bool alloc_haptic_buffer = false;
6105 int haptic_channel_count = adev->haptics_config.channels;
6106 size_t haptic_frame_size = bytes_per_sample * haptic_channel_count;
6107 size_t audio_frame_size = frame_size - haptic_frame_size;
6108 size_t total_haptic_buffer_size = frame_count * haptic_frame_size;
6109
6110 if (adev->haptic_buffer == NULL) {
6111 alloc_haptic_buffer = true;
6112 } else if (adev->haptic_buffer_size < total_haptic_buffer_size) {
6113 free(adev->haptic_buffer);
6114 adev->haptic_buffer_size = 0;
6115 alloc_haptic_buffer = true;
6116 }
6117
6118 if (alloc_haptic_buffer) {
6119 adev->haptic_buffer = (uint8_t *)calloc(1, total_haptic_buffer_size);
Mingshu Pang1513f972019-05-24 12:43:51 +08006120 if(adev->haptic_buffer == NULL) {
6121 ALOGE("%s: failed to allocate mem for dev->haptic_buffer", __func__);
6122 return -ENOMEM;
6123 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006124 adev->haptic_buffer_size = total_haptic_buffer_size;
6125 }
6126
6127 size_t src_index = 0, aud_index = 0, hap_index = 0;
6128 uint8_t *audio_buffer = (uint8_t *)buffer;
6129 uint8_t *haptic_buffer = adev->haptic_buffer;
6130
6131 // This is required for testing only. This works for stereo data only.
6132 // One channel is fed to audio stream and other to haptic stream for testing.
6133 if (force_haptic_path)
6134 audio_frame_size = haptic_frame_size = bytes_per_sample;
6135
6136 for (size_t i = 0; i < frame_count; i++) {
6137 memcpy(audio_buffer + aud_index, audio_buffer + src_index,
6138 audio_frame_size);
6139 aud_index += audio_frame_size;
6140 src_index += audio_frame_size;
6141
6142 if (adev->haptic_pcm)
6143 memcpy(haptic_buffer + hap_index, audio_buffer + src_index,
6144 haptic_frame_size);
6145 hap_index += haptic_frame_size;
6146 src_index += haptic_frame_size;
6147
6148 // This is required for testing only.
6149 // Discard haptic channel data.
6150 if (force_haptic_path)
6151 src_index += haptic_frame_size;
6152 }
6153
6154 // write to audio pipeline
6155 ret = pcm_write(out->pcm, (void *)audio_buffer,
6156 frame_count * audio_frame_size);
6157
6158 // write to haptics pipeline
6159 if (adev->haptic_pcm)
6160 ret = pcm_write(adev->haptic_pcm, (void *)adev->haptic_buffer,
6161 frame_count * haptic_frame_size);
6162
6163 return ret;
6164}
6165
Aalique Grahame22e49102018-12-18 14:23:57 -08006166#ifdef NO_AUDIO_OUT
6167static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
6168 const void *buffer __unused, size_t bytes)
6169{
6170 struct stream_out *out = (struct stream_out *)stream;
6171
6172 /* No Output device supported other than BT for playback.
6173 * Sleep for the amount of buffer duration
6174 */
6175 lock_output_stream(out);
6176 usleep(bytes * 1000000 / audio_stream_out_frame_size(
6177 (const struct audio_stream_out *)&out->stream) /
6178 out_get_sample_rate(&out->stream.common));
6179 pthread_mutex_unlock(&out->lock);
6180 return bytes;
6181}
6182#endif
6183
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006184static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
6185 size_t bytes)
6186{
6187 struct stream_out *out = (struct stream_out *)stream;
6188 struct audio_device *adev = out->dev;
Eric Laurent6e895242013-09-05 16:10:57 -07006189 ssize_t ret = 0;
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306190 int channels = 0;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006191 const size_t frame_size = audio_stream_out_frame_size(stream);
6192 const size_t frames = (frame_size != 0) ? bytes / frame_size : bytes;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306193 struct audio_usecase *usecase = NULL;
Meng Wang4c32fb42020-01-16 17:57:11 +08006194 uint32_t compr_passthr = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006195
Haynes Mathew George380745d2017-10-04 15:27:45 -07006196 ATRACE_BEGIN("out_write");
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006197 lock_output_stream(out);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306198
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006199 if (CARD_STATUS_OFFLINE == out->card_status ||
6200 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Zhou Song0b2e5dc2015-03-16 14:41:38 +08006201
Dhananjay Kumarac341582017-02-23 23:42:25 +05306202 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306203 /*during SSR for compress usecase we should return error to flinger*/
Naresh Tanniru80659832014-06-04 18:17:56 +05306204 ALOGD(" copl %s: sound card is not active/SSR state", __func__);
6205 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006206 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306207 return -ENETRESET;
Ashish Jainbbce4322016-02-16 13:25:27 +05306208 } else {
Ashish Jainbbce4322016-02-16 13:25:27 +05306209 ALOGD(" %s: sound card is not active/SSR state", __func__);
6210 ret= -EIO;
6211 goto exit;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306212 }
6213 }
6214
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306215 if (audio_extn_passthru_should_drop_data(out)) {
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306216 ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306217 ret = -EIO;
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306218 goto exit;
6219 }
6220
Haynes Mathew George16081042017-05-31 17:16:49 -07006221 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
6222 ret = -EINVAL;
6223 goto exit;
6224 }
6225
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006226 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306227 !out->is_iec61937_info_available) {
6228
6229 if (!audio_extn_passthru_is_passthrough_stream(out)) {
6230 out->is_iec61937_info_available = true;
6231 } else if (audio_extn_passthru_is_enabled()) {
6232 audio_extn_passthru_update_stream_configuration(adev, out, buffer, bytes);
Manish Dewangan37864bc2017-06-09 12:28:37 +05306233 out->is_iec61937_info_available = true;
Manish Dewangan671a4202017-08-18 17:30:46 +05306234
6235 if((out->format == AUDIO_FORMAT_DTS) ||
6236 (out->format == AUDIO_FORMAT_DTS_HD)) {
6237 ret = audio_extn_passthru_update_dts_stream_configuration(out,
6238 buffer, bytes);
6239 if (ret) {
6240 if (ret != -ENOSYS) {
6241 out->is_iec61937_info_available = false;
6242 ALOGD("iec61937 transmission info not yet updated retry");
6243 }
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306244 } else if (!out->standby) {
Manish Dewangan671a4202017-08-18 17:30:46 +05306245 /* if stream has started and after that there is
6246 * stream config change (iec transmission config)
6247 * then trigger select_device to update backend configuration.
6248 */
6249 out->stream_config_changed = true;
6250 pthread_mutex_lock(&adev->lock);
6251 select_devices(adev, out->usecase);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306252 if (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out)) {
Weiyin Jiang29c08a42019-04-30 17:11:10 +08006253 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306254 ret = -EINVAL;
6255 goto exit;
6256 }
Manish Dewangan671a4202017-08-18 17:30:46 +05306257 pthread_mutex_unlock(&adev->lock);
6258 out->stream_config_changed = false;
6259 out->is_iec61937_info_available = true;
6260 }
6261 }
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306262
Meng Wang4c32fb42020-01-16 17:57:11 +08006263#ifdef AUDIO_GKI_ENABLED
6264 /* out->compr_config.codec->reserved[0] is for compr_passthr */
6265 compr_passthr = out->compr_config.codec->reserved[0];
6266#else
6267 compr_passthr = out->compr_config.codec->compr_passthr;
6268#endif
6269
Garmond Leung317cbf12017-09-13 16:20:50 -07006270 if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
Meng Wang4c32fb42020-01-16 17:57:11 +08006271 (compr_passthr == PASSTHROUGH) &&
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306272 (out->is_iec61937_info_available == true)) {
6273 ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
6274 ret = -EINVAL;
6275 goto exit;
6276 }
Manish Dewangan37864bc2017-06-09 12:28:37 +05306277 }
6278 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306279
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006280 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02006281 (audio_extn_a2dp_source_is_suspended())) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006282 if (!(compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
6283 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
Zhou Songd01e7a22020-09-23 22:49:01 +08006284 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306285 ret = -EIO;
6286 goto exit;
6287 }
6288 }
6289 }
6290
Weiyin Jiangabedea32020-12-09 12:49:19 +08006291 if (is_usb_out_device_type(&out->device_list) &&
6292 !audio_extn_usb_connected(NULL)) {
6293 ret = -EIO;
6294 goto exit;
6295 }
6296
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006297 if (out->standby) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006298 out->standby = false;
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006299 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
6300
Eric Laurent150dbfe2013-02-27 14:31:02 -08006301 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006302 if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
6303 ret = voice_extn_compress_voip_start_output_stream(out);
6304 else
6305 ret = start_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006306 /* ToDo: If use case is compress offload should return 0 */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006307 if (ret != 0) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006308 out->standby = true;
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006309 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006310 goto exit;
6311 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306312 out->started = 1;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006313 out->last_fifo_valid = false; // we're coming out of standby, last_fifo isn't valid.
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006314
6315 if ((last_known_cal_step != -1) && (adev->platform != NULL)) {
vivek mehtab72d08d2016-04-29 03:16:47 -07006316 ALOGD("%s: retry previous failed cal level set", __func__);
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006317 platform_send_gain_dep_cal(adev->platform, last_known_cal_step);
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +05306318 last_known_cal_step = -1;
vivek mehtab72d08d2016-04-29 03:16:47 -07006319 }
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006320 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306321
6322 if ((out->is_iec61937_info_available == true) &&
6323 (audio_extn_passthru_is_passthrough_stream(out))&&
6324 (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out))) {
6325 ret = -EINVAL;
6326 goto exit;
6327 }
Surendar Karkaf51b5842018-04-26 11:28:38 +05306328 if (out->set_dual_mono)
6329 audio_extn_send_dual_mono_mixing_coefficients(out);
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006330
Dechen Chai22768452021-07-30 09:29:16 +05306331#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006332 // log startup time in ms.
6333 simple_stats_log(
6334 &out->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05306335#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006336 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006337
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006338 if (adev->is_channel_status_set == false &&
6339 compare_device_type(&out->device_list,
6340 AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Alexy Josephb1379942016-01-29 15:49:38 -08006341 audio_utils_set_hdmi_channel_status(out, (void *)buffer, bytes);
Ashish Jain81eb2a82015-05-13 10:52:34 +05306342 adev->is_channel_status_set = true;
6343 }
6344
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306345 if ((adev->use_old_pspd_mix_ctrl == true) &&
6346 (out->pspd_coeff_sent == false)) {
6347 /*
6348 * Need to resend pspd coefficients after stream started for
6349 * older kernel version as it does not save the coefficients
6350 * and also stream has to be started for coeff to apply.
6351 */
6352 usecase = get_usecase_from_list(adev, out->usecase);
6353 if (usecase != NULL) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05306354 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306355 out->pspd_coeff_sent = true;
6356 }
6357 }
6358
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006359 if (is_offload_usecase(out->usecase)) {
Alexy Joseph01e54e62015-03-03 19:01:03 -08006360 ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006361 if (out->send_new_metadata) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006362 ALOGD("copl(%p):send new gapless metadata", out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006363 compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
6364 out->send_new_metadata = 0;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306365 if (out->send_next_track_params && out->is_compr_metadata_avail) {
6366 ALOGD("copl(%p):send next track params in gapless", out);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08006367 compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306368 out->send_next_track_params = false;
6369 out->is_compr_metadata_avail = false;
6370 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006371 }
Dhananjay Kumarac341582017-02-23 23:42:25 +05306372 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306373 (out->convert_buffer) != NULL) {
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006374
Ashish Jain83a6cc22016-06-28 14:34:17 +05306375 if ((bytes > out->hal_fragment_size)) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05306376 ALOGW("Error written bytes %zu > %d (fragment_size)",
Ashish Jain83a6cc22016-06-28 14:34:17 +05306377 bytes, out->hal_fragment_size);
Ashish Jainf1eaa582016-05-23 20:54:24 +05306378 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006379 ATRACE_END();
Ashish Jainf1eaa582016-05-23 20:54:24 +05306380 return -EINVAL;
6381 } else {
Ashish Jain83a6cc22016-06-28 14:34:17 +05306382 audio_format_t dst_format = out->hal_op_format;
6383 audio_format_t src_format = out->hal_ip_format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05306384
Dieter Luecking5d57def2018-09-07 14:23:37 +02006385 /* prevent division-by-zero */
6386 uint32_t bitwidth_src = format_to_bitwidth_table[src_format];
6387 uint32_t bitwidth_dst = format_to_bitwidth_table[dst_format];
6388 if ((bitwidth_src == 0) || (bitwidth_dst == 0)) {
6389 ALOGE("%s: Error bitwidth == 0", __func__);
Ramu Gottipati02809682018-12-19 16:46:12 +05306390 pthread_mutex_unlock(&out->lock);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006391 ATRACE_END();
6392 return -EINVAL;
6393 }
6394
Ashish Jainf1eaa582016-05-23 20:54:24 +05306395 uint32_t frames = bytes / format_to_bitwidth_table[src_format];
6396 uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
6397
Ashish Jain83a6cc22016-06-28 14:34:17 +05306398 memcpy_by_audio_format(out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306399 dst_format,
6400 buffer,
6401 src_format,
6402 frames);
6403
Ashish Jain83a6cc22016-06-28 14:34:17 +05306404 ret = compress_write(out->compr, out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306405 bytes_to_write);
6406
6407 /*Convert written bytes in audio flinger format*/
6408 if (ret > 0)
6409 ret = ((ret * format_to_bitwidth_table[out->format]) /
6410 format_to_bitwidth_table[dst_format]);
6411 }
6412 } else
6413 ret = compress_write(out->compr, buffer, bytes);
6414
Zhou Songc9672822017-08-16 16:01:39 +08006415 if ((ret < 0 || ret == (ssize_t)bytes) && !out->non_blocking)
6416 update_frames_written(out, bytes);
6417
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306418 if (ret < 0)
6419 ret = -errno;
Weiyin Jiangcc60dbb2018-08-21 13:12:03 +08006420 ALOGVV("%s: writing buffer (%zu bytes) to compress device returned %d", __func__, bytes, (int)ret);
Ashish Jainb26edfb2016-08-25 00:10:11 +05306421 /*msg to cb thread only if non blocking write is enabled*/
6422 if (ret >= 0 && ret < (ssize_t)bytes && out->non_blocking) {
Sidipotu Ashok55820562014-02-10 16:16:38 +05306423 ALOGD("No space available in compress driver, post msg to cb thread");
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006424 send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
Naresh Tanniru80659832014-06-04 18:17:56 +05306425 } else if (-ENETRESET == ret) {
6426 ALOGE("copl %s: received sound card offline state on compress write", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306427 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru80659832014-06-04 18:17:56 +05306428 pthread_mutex_unlock(&out->lock);
Dhananjay Kumar1248dd82017-07-28 21:22:16 +05306429 out_on_error(&out->stream.common);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006430 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306431 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006432 }
Ashish Jain5106d362016-05-11 19:23:33 +05306433
Dhanalakshmi Siddania6b76c72016-09-09 18:10:31 +05306434 /* Call compr start only when non-zero bytes of data is there to be rendered */
6435 if (!out->playback_started && ret > 0) {
6436 int status = compress_start(out->compr);
6437 if (status < 0) {
6438 ret = status;
6439 ALOGE("%s: compr start failed with err %d", __func__, errno);
6440 goto exit;
6441 }
Alexy Joseph7de344d2015-03-30 10:40:03 -07006442 audio_extn_dts_eagle_fade(adev, true, out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006443 out->playback_started = 1;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006444 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006445 out->offload_state = OFFLOAD_STATE_PLAYING;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006446 pthread_mutex_unlock(&out->latch_lock);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006447
6448 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6449 popcount(out->channel_mask),
6450 out->playback_started);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006451 }
6452 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006453 ATRACE_END();
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006454 return ret;
6455 } else {
6456 if (out->pcm) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006457 size_t bytes_to_write = bytes;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006458 if (out->muted)
6459 memset((void *)buffer, 0, bytes);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006460 ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
6461 __func__, frames, frame_size, bytes_to_write);
6462
Aalique Grahame22e49102018-12-18 14:23:57 -08006463 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07006464 out->usecase == USECASE_INCALL_MUSIC_UPLINK2 ||
6465 (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP &&
6466 !audio_extn_utils_is_vendor_enhanced_fwk())) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006467 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6468 int16_t *src = (int16_t *)buffer;
6469 int16_t *dst = (int16_t *)buffer;
6470
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006471 LOG_ALWAYS_FATAL_IF(channel_count > 2 ||
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006472 out->format != AUDIO_FORMAT_PCM_16_BIT,
Aalique Grahame22e49102018-12-18 14:23:57 -08006473 "out_write called for %s use case with wrong properties",
6474 use_case_table[out->usecase]);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006475
6476 /*
6477 * FIXME: this can be removed once audio flinger mixer supports
6478 * mono output
6479 */
6480
6481 /*
6482 * Code below goes over each frame in the buffer and adds both
6483 * L and R samples and then divides by 2 to convert to mono
6484 */
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006485 if (channel_count == 2) {
6486 for (size_t i = 0; i < frames ; i++, dst++, src += 2) {
6487 *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
6488 }
6489 bytes_to_write /= 2;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006490 }
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006491 }
Andy Hunga1f48fa2019-07-01 18:14:53 -07006492
6493 // Note: since out_get_presentation_position() is called alternating with out_write()
6494 // by AudioFlinger, we can check underruns using the prior timestamp read.
6495 // (Alternately we could check if the buffer is empty using pcm_get_htimestamp().
6496 if (out->last_fifo_valid) {
6497 // compute drain to see if there is an underrun.
6498 const int64_t current_ns = systemTime(SYSTEM_TIME_MONOTONIC); // sys call
Dhananjay Kumara4429632020-07-11 02:53:37 +05306499 int64_t time_diff_ns = current_ns - out->last_fifo_time_ns;
6500 int64_t frames_by_time =
6501 ((time_diff_ns > 0) && (time_diff_ns < (INT64_MAX / out->config.rate))) ?
6502 (time_diff_ns * out->config.rate / NANOS_PER_SECOND) : 0;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006503 const int64_t underrun = frames_by_time - out->last_fifo_frames_remaining;
6504
6505 if (underrun > 0) {
Dechen Chai22768452021-07-30 09:29:16 +05306506#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07006507 simple_stats_log(&out->fifo_underruns, underrun);
Dechen Chai22768452021-07-30 09:29:16 +05306508#endif
Andy Hunga1f48fa2019-07-01 18:14:53 -07006509
6510 ALOGW("%s: underrun(%lld) "
6511 "frames_by_time(%lld) > out->last_fifo_frames_remaining(%lld)",
6512 __func__,
6513 (long long)out->fifo_underruns.n,
6514 (long long)frames_by_time,
6515 (long long)out->last_fifo_frames_remaining);
6516 }
6517 out->last_fifo_valid = false; // we're writing below, mark fifo info as stale.
6518 }
6519
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05306520 ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006521
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006522 long ns = 0;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006523
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006524 if (out->config.rate)
6525 ns = pcm_bytes_to_frames(out->pcm, bytes)*1000000000LL/
6526 out->config.rate;
6527
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006528 request_out_focus(out, ns);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006529 bool use_mmap = is_mmap_usecase(out->usecase) || out->realtime;
6530
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006531 if (use_mmap)
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006532 ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes_to_write);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006533 else if (out->hal_op_format != out->hal_ip_format &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306534 out->convert_buffer != NULL) {
6535
6536 memcpy_by_audio_format(out->convert_buffer,
6537 out->hal_op_format,
6538 buffer,
6539 out->hal_ip_format,
6540 out->config.period_size * out->config.channels);
6541
6542 ret = pcm_write(out->pcm, out->convert_buffer,
6543 (out->config.period_size *
6544 out->config.channels *
6545 format_to_bitwidth_table[out->hal_op_format]));
6546 } else {
Aditya Bavanarid4db8ee2017-05-29 21:08:03 +05306547 /*
6548 * To avoid underrun in DSP when the application is not pumping
6549 * data at required rate, check for the no. of bytes and ignore
6550 * pcm_write if it is less than actual buffer size.
6551 * It is a work around to a change in compress VOIP driver.
6552 */
6553 if ((out->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) &&
6554 bytes < (out->config.period_size * out->config.channels *
6555 audio_bytes_per_sample(out->format))) {
6556 size_t voip_buf_size =
6557 out->config.period_size * out->config.channels *
6558 audio_bytes_per_sample(out->format);
6559 ALOGE("%s:VOIP underrun: bytes received %zu, required:%zu\n",
6560 __func__, bytes, voip_buf_size);
6561 usleep(((uint64_t)voip_buf_size - bytes) *
6562 1000000 / audio_stream_out_frame_size(stream) /
6563 out_get_sample_rate(&out->stream.common));
6564 ret = 0;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006565 } else {
6566 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
6567 ret = split_and_write_audio_haptic_data(out, buffer, bytes);
6568 else
6569 ret = pcm_write(out->pcm, (void *)buffer, bytes_to_write);
6570 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05306571 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006572
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006573 release_out_focus(out);
6574
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306575 if (ret < 0)
6576 ret = -errno;
Zhou Songc9672822017-08-16 16:01:39 +08006577 else if (ret > 0)
Ashish Jain83a6cc22016-06-28 14:34:17 +05306578 ret = -EINVAL;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006579 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006580 }
6581
6582exit:
Zhou Songc9672822017-08-16 16:01:39 +08006583 update_frames_written(out, bytes);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306584 if (-ENETRESET == ret) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306585 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306586 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006587 pthread_mutex_unlock(&out->lock);
6588
6589 if (ret != 0) {
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07006590 if (out->pcm)
Alexy Josephb1379942016-01-29 15:49:38 -08006591 ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306592 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306593 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306594 voice_extn_compress_voip_close_output_stream(&out->stream.common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306595 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306596 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306597 out->standby = true;
6598 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306599 out_on_error(&out->stream.common);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006600 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
6601 /* prevent division-by-zero */
6602 uint32_t stream_size = audio_stream_out_frame_size(stream);
6603 uint32_t srate = out_get_sample_rate(&out->stream.common);
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006604
Dieter Luecking5d57def2018-09-07 14:23:37 +02006605 if ((stream_size == 0) || (srate == 0)) {
6606 ALOGE("%s: stream_size= %d, srate = %d", __func__, stream_size, srate);
6607 ATRACE_END();
6608 return -EINVAL;
6609 }
6610 usleep((uint64_t)bytes * 1000000 / stream_size / srate);
6611 }
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006612 if (audio_extn_passthru_is_passthrough_stream(out)) {
Rajshekar Eashwarappa88834522018-04-02 17:20:15 +05306613 //ALOGE("%s: write error, ret = %zd", __func__, ret);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006614 ATRACE_END();
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006615 return ret;
6616 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006617 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07006618 ATRACE_END();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006619 return bytes;
6620}
6621
6622static int out_get_render_position(const struct audio_stream_out *stream,
6623 uint32_t *dsp_frames)
6624{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006625 struct stream_out *out = (struct stream_out *)stream;
Zhou Song32a556e2015-05-05 10:46:56 +08006626
6627 if (dsp_frames == NULL)
6628 return -EINVAL;
6629
6630 *dsp_frames = 0;
6631 if (is_offload_usecase(out->usecase)) {
Mingming Yin9e348b52014-11-19 16:18:55 -08006632 ssize_t ret = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05306633
6634 /* Below piece of code is not guarded against any lock beacuse audioFliner serializes
6635 * this operation and adev_close_output_stream(where out gets reset).
6636 */
Dhananjay Kumarac341582017-02-23 23:42:25 +05306637 if (!out->non_blocking && !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006638 *dsp_frames = get_actual_pcm_frames_rendered(out, NULL);
Ashish Jain5106d362016-05-11 19:23:33 +05306639 ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate);
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006640 adjust_frames_for_device_delay(out, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05306641 return 0;
6642 }
6643
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006644 lock_output_stream(out);
Ashish Jain5106d362016-05-11 19:23:33 +05306645 if (out->compr != NULL && out->non_blocking) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306646 ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006647 &out->sample_rate);
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306648 if (ret < 0)
6649 ret = -errno;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006650 ALOGVV("%s rendered frames %d sample_rate %d",
Ashish Jain5106d362016-05-11 19:23:33 +05306651 __func__, *dsp_frames, out->sample_rate);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006652 }
Naresh Tanniru80659832014-06-04 18:17:56 +05306653 if (-ENETRESET == ret) {
6654 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306655 out->card_status = CARD_STATUS_OFFLINE;
6656 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306657 } else if(ret < 0) {
6658 ALOGE(" ERROR: Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306659 ret = -EINVAL;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006660 } else if (out->card_status == CARD_STATUS_OFFLINE ||
6661 adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05306662 /*
6663 * Handle corner case where compress session is closed during SSR
6664 * and timestamp is queried
6665 */
6666 ALOGE(" ERROR: sound card not active, return error");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306667 ret = -EINVAL;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306668 } else if (out->prev_card_status_offline) {
6669 ALOGE("ERROR: previously sound card was offline,return error");
6670 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306671 } else {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306672 ret = 0;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006673 adjust_frames_for_device_delay(out, dsp_frames);
Naresh Tanniru80659832014-06-04 18:17:56 +05306674 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306675 pthread_mutex_unlock(&out->lock);
6676 return ret;
Zhou Song32a556e2015-05-05 10:46:56 +08006677 } else if (audio_is_linear_pcm(out->format)) {
6678 *dsp_frames = out->written;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006679 adjust_frames_for_device_delay(out, dsp_frames);
Zhou Song32a556e2015-05-05 10:46:56 +08006680 return 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006681 } else
6682 return -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006683}
6684
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006685static int out_add_audio_effect(const struct audio_stream *stream __unused,
6686 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006687{
6688 return 0;
6689}
6690
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006691static int out_remove_audio_effect(const struct audio_stream *stream __unused,
6692 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006693{
6694 return 0;
6695}
6696
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006697static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
6698 int64_t *timestamp __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006699{
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05306700 return -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006701}
6702
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006703static int out_get_presentation_position(const struct audio_stream_out *stream,
6704 uint64_t *frames, struct timespec *timestamp)
6705{
6706 struct stream_out *out = (struct stream_out *)stream;
pavance65c2fe2017-10-18 17:52:01 +05306707 int ret = -ENODATA;
Eric Laurent949a0892013-09-20 09:20:13 -07006708 unsigned long dsp_frames;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006709
Ashish Jain5106d362016-05-11 19:23:33 +05306710 /* below piece of code is not guarded against any lock because audioFliner serializes
6711 * this operation and adev_close_output_stream( where out gets reset).
6712 */
6713 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
Dhananjay Kumarac341582017-02-23 23:42:25 +05306714 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006715 *frames = get_actual_pcm_frames_rendered(out, timestamp);
Ashish Jain5106d362016-05-11 19:23:33 +05306716 ALOGVV("frames %lld playedat %lld",(long long int)*frames,
6717 timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000);
6718 return 0;
6719 }
6720
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006721 lock_output_stream(out);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006722
Ashish Jain5106d362016-05-11 19:23:33 +05306723 if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) {
6724 ret = compress_get_tstamp(out->compr, &dsp_frames,
6725 &out->sample_rate);
yidongh0515e042017-07-06 15:00:34 +08006726 // Adjustment accounts for A2dp encoder latency with offload usecases
6727 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006728 if (is_a2dp_out_device_type(&out->device_list)) {
yidongh0515e042017-07-06 15:00:34 +08006729 unsigned long offset =
6730 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
6731 dsp_frames = (dsp_frames > offset) ? (dsp_frames - offset) : 0;
6732 }
Ashish Jain5106d362016-05-11 19:23:33 +05306733 ALOGVV("%s rendered frames %ld sample_rate %d",
6734 __func__, dsp_frames, out->sample_rate);
6735 *frames = dsp_frames;
6736 if (ret < 0)
6737 ret = -errno;
6738 if (-ENETRESET == ret) {
6739 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306740 out->card_status = CARD_STATUS_OFFLINE;
Ashish Jain5106d362016-05-11 19:23:33 +05306741 ret = -EINVAL;
6742 } else
6743 ret = 0;
6744 /* this is the best we can do */
6745 clock_gettime(CLOCK_MONOTONIC, timestamp);
Eric Laurent949a0892013-09-20 09:20:13 -07006746 } else {
6747 if (out->pcm) {
Weiyin Jiangd4633762018-03-16 12:05:03 +08006748 unsigned int avail;
6749 if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
George Gao62ebc722019-07-29 16:29:44 -07006750 uint64_t signed_frames = 0;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006751 uint64_t frames_temp = 0;
George Gao62ebc722019-07-29 16:29:44 -07006752
Andy Hunga1f48fa2019-07-01 18:14:53 -07006753 if (out->kernel_buffer_size > avail) {
6754 frames_temp = out->last_fifo_frames_remaining = out->kernel_buffer_size - avail;
6755 } else {
6756 ALOGW("%s: avail:%u > kernel_buffer_size:%zu clamping!",
6757 __func__, avail, out->kernel_buffer_size);
6758 avail = out->kernel_buffer_size;
6759 frames_temp = out->last_fifo_frames_remaining = 0;
6760 }
6761 out->last_fifo_valid = true;
6762 out->last_fifo_time_ns = audio_utils_ns_from_timespec(timestamp);
6763
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006764 if (out->written >= frames_temp)
6765 signed_frames = out->written - frames_temp;
George Gao62ebc722019-07-29 16:29:44 -07006766
Andy Hunga1f48fa2019-07-01 18:14:53 -07006767 ALOGVV("%s: frames:%lld avail:%u kernel_buffer_size:%zu",
6768 __func__, (long long)signed_frames, avail, out->kernel_buffer_size);
6769
Weiyin Jiangd4633762018-03-16 12:05:03 +08006770 // This adjustment accounts for buffering after app processor.
6771 // It is based on estimated DSP latency per use case, rather than exact.
George Gao9ba8a142020-07-23 14:30:03 -07006772 frames_temp = platform_render_latency(out) *
Robert Lee58215542019-07-15 20:55:12 +08006773 out->sample_rate / 1000000LL;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006774 if (signed_frames >= frames_temp)
6775 signed_frames -= frames_temp;
Aniket Kumar Lataff613152017-07-18 18:19:21 -07006776
Weiyin Jiangd4633762018-03-16 12:05:03 +08006777 // Adjustment accounts for A2dp encoder latency with non offload usecases
6778 // Note: Encoder latency is returned in ms, while platform_render_latency in us.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006779 if (is_a2dp_out_device_type(&out->device_list)) {
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006780 frames_temp = audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000;
6781 if (signed_frames >= frames_temp)
6782 signed_frames -= frames_temp;
Weiyin Jiangd4633762018-03-16 12:05:03 +08006783 }
6784
6785 // It would be unusual for this value to be negative, but check just in case ...
George Gao62ebc722019-07-29 16:29:44 -07006786 *frames = signed_frames;
6787 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006788 }
Eric Laurenta7a33042019-07-10 16:20:22 -07006789 } else if (out->card_status == CARD_STATUS_OFFLINE ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05006790 adev->out_power_policy == POWER_POLICY_STATUS_OFFLINE ||
Eric Laurenta7a33042019-07-10 16:20:22 -07006791 // audioflinger still needs position updates when A2DP is suspended
Jasmine Cha5c2517f2019-09-09 11:07:28 +08006792 (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306793 *frames = out->written;
6794 clock_gettime(CLOCK_MONOTONIC, timestamp);
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306795 if (is_offload_usecase(out->usecase))
6796 ret = -EINVAL;
6797 else
6798 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006799 }
6800 }
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006801 pthread_mutex_unlock(&out->lock);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006802 return ret;
6803}
6804
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006805static int out_set_callback(struct audio_stream_out *stream,
6806 stream_callback_t callback, void *cookie)
6807{
6808 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006809 int ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006810
6811 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006812 lock_output_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006813 out->client_callback = callback;
6814 out->client_cookie = cookie;
6815 if (out->adsp_hdlr_stream_handle) {
6816 ret = audio_extn_adsp_hdlr_stream_set_callback(
6817 out->adsp_hdlr_stream_handle,
6818 callback,
6819 cookie);
6820 if (ret)
6821 ALOGW("%s:adsp hdlr callback registration failed %d",
6822 __func__, ret);
6823 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006824 pthread_mutex_unlock(&out->lock);
6825 return 0;
6826}
6827
6828static int out_pause(struct audio_stream_out* stream)
6829{
6830 struct stream_out *out = (struct stream_out *)stream;
6831 int status = -ENOSYS;
6832 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006833 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006834 ALOGD("copl(%p):pause compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306835 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006836 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006837 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006838 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306839 if (out->card_status != CARD_STATUS_OFFLINE)
Naresh Tanniru80659832014-06-04 18:17:56 +05306840 status = compress_pause(out->compr);
6841
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006842 out->offload_state = OFFLOAD_STATE_PAUSED;
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006843
Mingming Yin21854652016-04-13 11:54:02 -07006844 if (audio_extn_passthru_is_active()) {
6845 ALOGV("offload use case, pause passthru");
6846 audio_extn_passthru_on_pause(out);
6847 }
6848
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306849 audio_extn_dts_eagle_fade(adev, false, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006850 audio_extn_dts_notify_playback_state(out->usecase, 0,
6851 out->sample_rate, popcount(out->channel_mask),
6852 0);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006853 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006854 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006855 pthread_mutex_unlock(&out->lock);
6856 }
6857 return status;
6858}
6859
6860static int out_resume(struct audio_stream_out* stream)
6861{
6862 struct stream_out *out = (struct stream_out *)stream;
6863 int status = -ENOSYS;
6864 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006865 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006866 ALOGD("copl(%p):resume compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306867 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006868 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006869 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006870 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306871 if (out->card_status != CARD_STATUS_OFFLINE) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306872 status = compress_resume(out->compr);
Mingming Yin21854652016-04-13 11:54:02 -07006873 }
6874 if (!status) {
6875 out->offload_state = OFFLOAD_STATE_PLAYING;
6876 }
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306877 audio_extn_dts_eagle_fade(adev, true, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006878 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6879 popcount(out->channel_mask), 1);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006880 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006881 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006882 pthread_mutex_unlock(&out->lock);
6883 }
6884 return status;
6885}
6886
6887static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
6888{
6889 struct stream_out *out = (struct stream_out *)stream;
6890 int status = -ENOSYS;
6891 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006892 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006893 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006894 if (type == AUDIO_DRAIN_EARLY_NOTIFY)
6895 status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
6896 else
6897 status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
6898 pthread_mutex_unlock(&out->lock);
6899 }
6900 return status;
6901}
6902
6903static int out_flush(struct audio_stream_out* stream)
6904{
6905 struct stream_out *out = (struct stream_out *)stream;
6906 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006907 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006908 ALOGD("copl(%p):calling compress flush", out);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006909 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006910 pthread_mutex_lock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006911 if (out->offload_state == OFFLOAD_STATE_PAUSED) {
Gautam Manam14c198b2020-12-24 14:08:04 +05306912 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006913 stop_compressed_output_l(out);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006914 } else {
6915 ALOGW("%s called in invalid state %d", __func__, out->offload_state);
Gautam Manam14c198b2020-12-24 14:08:04 +05306916 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006917 }
Weiyin Jiang547e4152017-09-14 17:24:18 +08006918 out->written = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006919 pthread_mutex_unlock(&out->lock);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006920 ALOGD("copl(%p):out of compress flush", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006921 return 0;
6922 }
6923 return -ENOSYS;
6924}
6925
Haynes Mathew George16081042017-05-31 17:16:49 -07006926static int out_stop(const struct audio_stream_out* stream)
6927{
6928 struct stream_out *out = (struct stream_out *)stream;
6929 struct audio_device *adev = out->dev;
6930 int ret = -ENOSYS;
6931
6932 ALOGV("%s", __func__);
6933 pthread_mutex_lock(&adev->lock);
6934 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6935 out->playback_started && out->pcm != NULL) {
6936 pcm_stop(out->pcm);
6937 ret = stop_output_stream(out);
6938 out->playback_started = false;
6939 }
6940 pthread_mutex_unlock(&adev->lock);
6941 return ret;
6942}
6943
6944static int out_start(const struct audio_stream_out* stream)
6945{
6946 struct stream_out *out = (struct stream_out *)stream;
6947 struct audio_device *adev = out->dev;
6948 int ret = -ENOSYS;
6949
6950 ALOGV("%s", __func__);
6951 pthread_mutex_lock(&adev->lock);
6952 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6953 !out->playback_started && out->pcm != NULL) {
6954 ret = start_output_stream(out);
6955 if (ret == 0) {
6956 out->playback_started = true;
6957 }
6958 }
6959 pthread_mutex_unlock(&adev->lock);
6960 return ret;
6961}
6962
6963/*
6964 * Modify config->period_count based on min_size_frames
6965 */
6966static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
6967{
6968 int periodCountRequested = (min_size_frames + config->period_size - 1)
6969 / config->period_size;
6970 int periodCount = MMAP_PERIOD_COUNT_MIN;
6971
6972 ALOGV("%s original config.period_size = %d config.period_count = %d",
6973 __func__, config->period_size, config->period_count);
6974
6975 while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
6976 periodCount *= 2;
6977 }
6978 config->period_count = periodCount;
6979
6980 ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
6981}
6982
Phil Burkfe17efd2019-03-25 10:23:35 -07006983// Read offset for the positional timestamp from a persistent vendor property.
6984// This is to workaround apparent inaccuracies in the timing information that
6985// is used by the AAudio timing model. The inaccuracies can cause glitches.
6986static int64_t get_mmap_out_time_offset() {
6987 const int32_t kDefaultOffsetMicros = 0;
6988 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08006989 "persist.vendor.audio.out_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burkfe17efd2019-03-25 10:23:35 -07006990 ALOGI("mmap_time_offset_micros = %d for output", mmap_time_offset_micros);
6991 return mmap_time_offset_micros * (int64_t)1000;
6992}
6993
Haynes Mathew George16081042017-05-31 17:16:49 -07006994static int out_create_mmap_buffer(const struct audio_stream_out *stream,
6995 int32_t min_size_frames,
6996 struct audio_mmap_buffer_info *info)
6997{
6998 struct stream_out *out = (struct stream_out *)stream;
6999 struct audio_device *adev = out->dev;
7000 int ret = 0;
Aalique Grahame1f123102017-10-12 10:38:32 -07007001 unsigned int offset1 = 0;
7002 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007003 const char *step = "";
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007004 uint32_t mmap_size;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007005 uint32_t buffer_size;
Haynes Mathew George16081042017-05-31 17:16:49 -07007006
Arun Mirpuri5d170872019-03-26 13:21:31 -07007007 ALOGD("%s", __func__);
Sharad Sanglec6f32552018-05-04 16:15:38 +05307008 lock_output_stream(out);
Haynes Mathew George16081042017-05-31 17:16:49 -07007009 pthread_mutex_lock(&adev->lock);
7010
Sharad Sanglec6f32552018-05-04 16:15:38 +05307011 if (CARD_STATUS_OFFLINE == out->card_status ||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05007012 CARD_STATUS_OFFLINE == adev->card_status ||
7013 POWER_POLICY_STATUS_OFFLINE == adev->out_power_policy) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307014 ALOGW("out->card_status or adev->card_status offline, try again");
7015 ret = -EIO;
7016 goto exit;
7017 }
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307018 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007019 ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
7020 ret = -EINVAL;
7021 goto exit;
7022 }
7023 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
7024 ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
7025 ret = -ENOSYS;
7026 goto exit;
7027 }
7028 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
7029 if (out->pcm_device_id < 0) {
7030 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7031 __func__, out->pcm_device_id, out->usecase);
7032 ret = -EINVAL;
7033 goto exit;
7034 }
7035
7036 adjust_mmap_period_count(&out->config, min_size_frames);
7037
Arun Mirpuri5d170872019-03-26 13:21:31 -07007038 ALOGD("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07007039 __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
7040 out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
7041 (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307042 if (errno == ENETRESET && !pcm_is_ready(out->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307043 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7044 out->card_status = CARD_STATUS_OFFLINE;
7045 adev->card_status = CARD_STATUS_OFFLINE;
7046 ret = -EIO;
7047 goto exit;
7048 }
7049
Haynes Mathew George16081042017-05-31 17:16:49 -07007050 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
7051 step = "open";
7052 ret = -ENODEV;
7053 goto exit;
7054 }
7055 ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
7056 if (ret < 0) {
7057 step = "begin";
7058 goto exit;
7059 }
juyuchen626833d2019-06-04 16:48:02 +08007060
7061 info->flags = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007062 info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
Arun Mirpuri5d170872019-03-26 13:21:31 -07007063 buffer_size = pcm_frames_to_bytes(out->pcm, info->buffer_size_frames);
Haynes Mathew George16081042017-05-31 17:16:49 -07007064 info->burst_size_frames = out->config.period_size;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007065 ret = platform_get_mmap_data_fd(adev->platform,
7066 out->pcm_device_id, 0 /*playback*/,
7067 &info->shared_memory_fd,
7068 &mmap_size);
7069 if (ret < 0) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07007070 // Fall back to non exclusive mode
7071 info->shared_memory_fd = pcm_get_poll_fd(out->pcm);
7072 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007073 out->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7074 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, out->mmap_shared_memory_fd);
7075
Arun Mirpuri5d170872019-03-26 13:21:31 -07007076 if (mmap_size < buffer_size) {
7077 step = "mmap";
7078 goto exit;
7079 }
juyuchen626833d2019-06-04 16:48:02 +08007080 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007081 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007082 memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07007083 info->buffer_size_frames));
Haynes Mathew George16081042017-05-31 17:16:49 -07007084
7085 ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
7086 if (ret < 0) {
7087 step = "commit";
7088 goto exit;
7089 }
7090
Phil Burkfe17efd2019-03-25 10:23:35 -07007091 out->mmap_time_offset_nanos = get_mmap_out_time_offset();
7092
Haynes Mathew George16081042017-05-31 17:16:49 -07007093 out->standby = false;
7094 ret = 0;
7095
Arun Mirpuri5d170872019-03-26 13:21:31 -07007096 ALOGD("%s: got mmap buffer address %p info->buffer_size_frames %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07007097 __func__, info->shared_memory_address, info->buffer_size_frames);
7098
7099exit:
7100 if (ret != 0) {
7101 if (out->pcm == NULL) {
7102 ALOGE("%s: %s - %d", __func__, step, ret);
7103 } else {
7104 ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
7105 pcm_close(out->pcm);
7106 out->pcm = NULL;
7107 }
7108 }
7109 pthread_mutex_unlock(&adev->lock);
Sharad Sanglec6f32552018-05-04 16:15:38 +05307110 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007111 return ret;
7112}
7113
7114static int out_get_mmap_position(const struct audio_stream_out *stream,
7115 struct audio_mmap_position *position)
7116{
7117 struct stream_out *out = (struct stream_out *)stream;
7118 ALOGVV("%s", __func__);
7119 if (position == NULL) {
7120 return -EINVAL;
7121 }
7122 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08007123 ALOGE("%s: called on %s", __func__, use_case_table[out->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07007124 return -ENOSYS;
7125 }
7126 if (out->pcm == NULL) {
7127 return -ENOSYS;
7128 }
7129
7130 struct timespec ts = { 0, 0 };
7131 int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
7132 if (ret < 0) {
7133 ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
7134 return ret;
7135 }
Phil Burkfe17efd2019-03-25 10:23:35 -07007136 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
7137 + out->mmap_time_offset_nanos;
Haynes Mathew George16081042017-05-31 17:16:49 -07007138 return 0;
7139}
7140
7141
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007142/** audio_stream_in implementation **/
7143static uint32_t in_get_sample_rate(const struct audio_stream *stream)
7144{
7145 struct stream_in *in = (struct stream_in *)stream;
7146
7147 return in->config.rate;
7148}
7149
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007150static int in_set_sample_rate(struct audio_stream *stream __unused,
7151 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007152{
7153 return -ENOSYS;
7154}
7155
7156static size_t in_get_buffer_size(const struct audio_stream *stream)
7157{
7158 struct stream_in *in = (struct stream_in *)stream;
7159
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007160 if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
7161 return voice_extn_compress_voip_in_get_buffer_size(in);
Mingming Yine62d7842013-10-25 16:26:03 -07007162 else if(audio_extn_compr_cap_usecase_supported(in->usecase))
7163 return audio_extn_compr_cap_get_buffer_size(in->config.format);
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307164 else if(audio_extn_cin_attached_usecase(in))
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307165 return audio_extn_cin_get_buffer_size(in);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007166
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007167 return in->config.period_size * in->af_period_multiplier *
7168 audio_stream_in_frame_size((const struct audio_stream_in *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007169}
7170
7171static uint32_t in_get_channels(const struct audio_stream *stream)
7172{
7173 struct stream_in *in = (struct stream_in *)stream;
7174
7175 return in->channel_mask;
7176}
7177
7178static audio_format_t in_get_format(const struct audio_stream *stream)
7179{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007180 struct stream_in *in = (struct stream_in *)stream;
7181
7182 return in->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007183}
7184
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007185static int in_set_format(struct audio_stream *stream __unused,
7186 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007187{
7188 return -ENOSYS;
7189}
7190
7191static int in_standby(struct audio_stream *stream)
7192{
7193 struct stream_in *in = (struct stream_in *)stream;
7194 struct audio_device *adev = in->dev;
7195 int status = 0;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307196 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
7197 stream, in->usecase, use_case_table[in->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07007198 bool do_stop = true;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307199
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007200 lock_input_stream(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007201 if (!in->standby && in->is_st_session) {
7202 ALOGD("%s: sound trigger pcm stop lab", __func__);
7203 audio_extn_sound_trigger_stop_lab(in);
George Gao3018ede2019-10-23 13:23:00 -07007204 if (adev->num_va_sessions > 0)
7205 adev->num_va_sessions--;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007206 in->standby = 1;
7207 }
7208
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007209 if (!in->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007210 if (adev->adm_deregister_stream)
7211 adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
7212
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08007213 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007214 in->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08007215 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
kunleizbecba2d2017-09-07 13:37:16 +08007216 do_stop = false;
Zhou Songa8895042016-07-05 17:54:22 +08007217 voice_extn_compress_voip_close_input_stream(stream);
7218 ALOGD("VOIP input entered standby");
Haynes Mathew George16081042017-05-31 17:16:49 -07007219 } else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7220 do_stop = in->capture_started;
7221 in->capture_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07007222 if (in->mmap_shared_memory_fd >= 0) {
7223 ALOGV("%s: closing mmap_shared_memory_fd = %d",
7224 __func__, in->mmap_shared_memory_fd);
7225 close(in->mmap_shared_memory_fd);
7226 in->mmap_shared_memory_fd = -1;
7227 }
Zhou Songa8895042016-07-05 17:54:22 +08007228 } else {
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307229 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +05307230 audio_extn_cin_close_input_stream(in);
kunleizbecba2d2017-09-07 13:37:16 +08007231 }
7232
Arun Mirpuri5d170872019-03-26 13:21:31 -07007233 if (in->pcm) {
7234 ATRACE_BEGIN("pcm_in_close");
7235 pcm_close(in->pcm);
7236 ATRACE_END();
7237 in->pcm = NULL;
7238 }
7239
Carter Hsu2e429db2019-05-14 18:50:52 +08007240 if (do_stop)
Zhou Songa8895042016-07-05 17:54:22 +08007241 status = stop_input_stream(in);
Quinn Malef6050362019-01-30 15:55:40 -08007242
George Gao3018ede2019-10-23 13:23:00 -07007243 if (in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7244 if (adev->num_va_sessions > 0)
7245 adev->num_va_sessions--;
7246 }
Quinn Malef6050362019-01-30 15:55:40 -08007247
Eric Laurent150dbfe2013-02-27 14:31:02 -08007248 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007249 }
7250 pthread_mutex_unlock(&in->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07007251 ALOGV("%s: exit: status(%d)", __func__, status);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007252 return status;
7253}
7254
Aalique Grahame22e49102018-12-18 14:23:57 -08007255static int in_dump(const struct audio_stream *stream,
7256 int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007257{
Aalique Grahame22e49102018-12-18 14:23:57 -08007258 struct stream_in *in = (struct stream_in *)stream;
7259
7260 // We try to get the lock for consistency,
7261 // but it isn't necessary for these variables.
7262 // If we're not in standby, we may be blocked on a read.
7263 const bool locked = (pthread_mutex_trylock(&in->lock) == 0);
7264 dprintf(fd, " Standby: %s\n", in->standby ? "yes" : "no");
7265 dprintf(fd, " Frames read: %lld\n", (long long)in->frames_read);
7266 dprintf(fd, " Frames muted: %lld\n", (long long)in->frames_muted);
Dechen Chai22768452021-07-30 09:29:16 +05307267#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007268 char buffer[256]; // for statistics formatting
7269 if (in->start_latency_ms.n > 0) {
7270 simple_stats_to_string(&in->start_latency_ms, buffer, sizeof(buffer));
7271 dprintf(fd, " Start latency ms: %s\n", buffer);
7272 }
Dechen Chai22768452021-07-30 09:29:16 +05307273#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08007274 if (locked) {
7275 pthread_mutex_unlock(&in->lock);
7276 }
Dechen Chai22768452021-07-30 09:29:16 +05307277#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08007278 // dump error info
7279 (void)error_log_dump(
7280 in->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05307281#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007282 return 0;
7283}
7284
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307285static void in_snd_mon_cb(void * stream, struct str_parms * parms)
7286{
7287 if (!stream || !parms)
7288 return;
7289
7290 struct stream_in *in = (struct stream_in *)stream;
7291 struct audio_device *adev = in->dev;
7292
7293 card_status_t status;
7294 int card;
7295 if (parse_snd_card_status(parms, &card, &status) < 0)
7296 return;
7297
7298 pthread_mutex_lock(&adev->lock);
7299 bool valid_cb = (card == adev->snd_card);
7300 pthread_mutex_unlock(&adev->lock);
7301
7302 if (!valid_cb)
7303 return;
7304
7305 lock_input_stream(in);
7306 if (in->card_status != status)
7307 in->card_status = status;
7308 pthread_mutex_unlock(&in->lock);
7309
7310 ALOGW("in_snd_mon_cb for card %d usecase %s, status %s", card,
7311 use_case_table[in->usecase],
7312 status == CARD_STATUS_OFFLINE ? "offline" : "online");
7313
7314 // a better solution would be to report error back to AF and let
7315 // it put the stream to standby
7316 if (status == CARD_STATUS_OFFLINE)
7317 in_standby(&in->stream.common);
7318
7319 return;
7320}
7321
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007322int route_input_stream(struct stream_in *in,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007323 struct listnode *devices,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007324 audio_source_t source)
7325{
7326 struct audio_device *adev = in->dev;
7327 int ret = 0;
7328
7329 lock_input_stream(in);
7330 pthread_mutex_lock(&adev->lock);
7331
7332 /* no audio source uses val == 0 */
7333 if ((in->source != source) && (source != AUDIO_SOURCE_DEFAULT)) {
7334 in->source = source;
7335 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
7336 (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
7337 (voice_extn_compress_voip_is_format_supported(in->format)) &&
7338 (in->config.rate == 8000 || in->config.rate == 16000 ||
7339 in->config.rate == 32000 || in->config.rate == 48000 ) &&
7340 (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
7341 ret = voice_extn_compress_voip_open_input_stream(in);
7342 if (ret != 0) {
7343 ALOGE("%s: Compress voip input cannot be opened, error:%d",
7344 __func__, ret);
7345 }
7346 }
7347 }
7348
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007349 if (!compare_devices(&in->device_list, devices) && !list_empty(devices) &&
7350 is_audio_in_device_type(devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007351 // Workaround: If routing to an non existing usb device, fail gracefully
7352 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007353 struct str_parms *usb_addr =
7354 str_parms_create_str(get_usb_device_address(devices));
7355 if (is_usb_in_device_type(devices) && usb_addr &&
Weiyin Jiangabedea32020-12-09 12:49:19 +08007356 !audio_extn_usb_connected(NULL)) {
7357 ALOGW("%s: ignoring rerouting to non existing USB", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007358 ret = -ENOSYS;
7359 } else {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007360 /* If recording is in progress, change the tx device to new device */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007361 assign_devices(&in->device_list, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007362 if (!in->standby && !in->is_st_session) {
7363 ALOGV("update input routing change");
7364 // inform adm before actual routing to prevent glitches.
7365 if (adev->adm_on_routing_change) {
7366 adev->adm_on_routing_change(adev->adm_data,
7367 in->capture_handle);
7368 ret = select_devices(adev, in->usecase);
7369 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7370 adev->adm_routing_changed = true;
7371 }
7372 }
7373 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007374 if (usb_addr)
7375 str_parms_destroy(usb_addr);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007376 }
7377 pthread_mutex_unlock(&adev->lock);
7378 pthread_mutex_unlock(&in->lock);
7379
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07007380 ALOGV("%s: exit: status(%d)", __func__, ret);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007381 return ret;
7382}
7383
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007384static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
7385{
7386 struct stream_in *in = (struct stream_in *)stream;
7387 struct audio_device *adev = in->dev;
7388 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007389 char value[32];
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307390 int err = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007391
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307392 ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007393 parms = str_parms_create_str(kvpairs);
7394
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307395 if (!parms)
7396 goto error;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007397 lock_input_stream(in);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007398 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08007399
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307400 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
7401 if (err >= 0) {
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307402 strlcpy(in->profile, value, sizeof(in->profile));
7403 ALOGV("updating stream profile with value '%s'", in->profile);
7404 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
7405 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007406 &in->device_list, in->flags, in->format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307407 in->sample_rate, in->bit_width,
7408 in->profile, &in->app_type_cfg);
7409 }
7410
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007411 pthread_mutex_unlock(&adev->lock);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007412 pthread_mutex_unlock(&in->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007413
7414 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307415error:
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307416 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007417}
7418
7419static char* in_get_parameters(const struct audio_stream *stream,
7420 const char *keys)
7421{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007422 struct stream_in *in = (struct stream_in *)stream;
7423 struct str_parms *query = str_parms_create_str(keys);
7424 char *str;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007425 struct str_parms *reply = str_parms_create();
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007426
7427 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08007428 if (reply) {
7429 str_parms_destroy(reply);
7430 }
7431 if (query) {
7432 str_parms_destroy(query);
7433 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007434 ALOGE("in_get_parameters: failed to create query or reply");
7435 return NULL;
7436 }
7437
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007438 ALOGV("%s: enter: keys - %s %s ", __func__, use_case_table[in->usecase], keys);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007439
7440 voice_extn_in_get_parameters(in, query, reply);
7441
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007442 stream_get_parameter_channels(query, reply,
7443 &in->supported_channel_masks[0]);
7444 stream_get_parameter_formats(query, reply,
7445 &in->supported_formats[0]);
7446 stream_get_parameter_rates(query, reply,
7447 &in->supported_sample_rates[0]);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007448 str = str_parms_to_str(reply);
7449 str_parms_destroy(query);
7450 str_parms_destroy(reply);
7451
7452 ALOGV("%s: exit: returns - %s", __func__, str);
7453 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007454}
7455
Aalique Grahame22e49102018-12-18 14:23:57 -08007456static int in_set_gain(struct audio_stream_in *stream,
7457 float gain)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007458{
Aalique Grahame22e49102018-12-18 14:23:57 -08007459 struct stream_in *in = (struct stream_in *)stream;
7460 char mixer_ctl_name[128];
7461 struct mixer_ctl *ctl;
7462 int ctl_value;
7463
7464 ALOGV("%s: gain %f", __func__, gain);
7465
7466 if (stream == NULL)
7467 return -EINVAL;
7468
7469 /* in_set_gain() only used to silence MMAP capture for now */
7470 if (in->usecase != USECASE_AUDIO_RECORD_MMAP)
7471 return -ENOSYS;
7472
7473 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Capture %d Volume", in->pcm_device_id);
7474
7475 ctl = mixer_get_ctl_by_name(in->dev->mixer, mixer_ctl_name);
7476 if (!ctl) {
7477 ALOGW("%s: Could not get ctl for mixer cmd - %s",
7478 __func__, mixer_ctl_name);
7479 return -ENOSYS;
7480 }
7481
7482 if (gain < RECORD_GAIN_MIN)
7483 gain = RECORD_GAIN_MIN;
7484 else if (gain > RECORD_GAIN_MAX)
7485 gain = RECORD_GAIN_MAX;
7486 ctl_value = (int)(RECORD_VOLUME_CTL_MAX * gain);
7487
7488 mixer_ctl_set_value(ctl, 0, ctl_value);
7489
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007490 return 0;
7491}
7492
7493static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
7494 size_t bytes)
7495{
7496 struct stream_in *in = (struct stream_in *)stream;
Pallavid7c7a272018-01-16 11:22:55 +05307497
7498 if (in == NULL) {
7499 ALOGE("%s: stream_in ptr is NULL", __func__);
7500 return -EINVAL;
7501 }
7502
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007503 struct audio_device *adev = in->dev;
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05307504 int ret = -1;
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307505 size_t bytes_read = 0, frame_size = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007506
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007507 lock_input_stream(in);
Naresh Tanniru4c630392014-05-12 01:05:52 +05307508
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007509 if (in->is_st_session) {
7510 ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
7511 /* Read from sound trigger HAL */
7512 audio_extn_sound_trigger_read(in, buffer, bytes);
Quinn Malef6050362019-01-30 15:55:40 -08007513 if (in->standby) {
George Gao3018ede2019-10-23 13:23:00 -07007514 if (adev->num_va_sessions < UINT_MAX)
7515 adev->num_va_sessions++;
Quinn Malef6050362019-01-30 15:55:40 -08007516 in->standby = 0;
7517 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007518 pthread_mutex_unlock(&in->lock);
7519 return bytes;
7520 }
7521
Haynes Mathew George16081042017-05-31 17:16:49 -07007522 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7523 ret = -ENOSYS;
7524 goto exit;
7525 }
7526
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007527 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY &&
7528 !in->standby && adev->adm_routing_changed) {
7529 ret = -ENOSYS;
7530 goto exit;
7531 }
7532
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007533 if (in->standby) {
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007534 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
7535
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007536 pthread_mutex_lock(&adev->lock);
7537 if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
7538 ret = voice_extn_compress_voip_start_input_stream(in);
7539 else
7540 ret = start_input_stream(in);
George Gao3018ede2019-10-23 13:23:00 -07007541 if (!ret && in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7542 if (adev->num_va_sessions < UINT_MAX)
7543 adev->num_va_sessions++;
7544 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007545 pthread_mutex_unlock(&adev->lock);
7546 if (ret != 0) {
7547 goto exit;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007548 }
7549 in->standby = 0;
Dechen Chai22768452021-07-30 09:29:16 +05307550#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007551 // log startup time in ms.
7552 simple_stats_log(
7553 &in->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05307554#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007555 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007556
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05307557 /* Avoid read if capture_stopped is set */
7558 if (android_atomic_acquire_load(&(in->capture_stopped)) > 0) {
7559 ALOGD("%s: force stopped catpure session, ignoring read request", __func__);
7560 ret = -EINVAL;
7561 goto exit;
7562 }
7563
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007564 // what's the duration requested by the client?
7565 long ns = 0;
7566
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307567 if (in->pcm && in->config.rate)
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007568 ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
7569 in->config.rate;
7570
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007571 ret = request_in_focus(in, ns);
7572 if (ret != 0)
7573 goto exit;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007574 bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007575
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307576 if (audio_extn_cin_attached_usecase(in)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307577 ret = audio_extn_cin_read(in, buffer, bytes, &bytes_read);
7578 } else if (in->pcm) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307579 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007580 ret = audio_extn_ssr_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307581 } else if (audio_extn_compr_cap_usecase_supported(in->usecase)) {
Mingming Yine62d7842013-10-25 16:26:03 -07007582 ret = audio_extn_compr_cap_read(in, buffer, bytes);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007583 } else if (use_mmap) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07007584 ret = pcm_mmap_read(in->pcm, buffer, bytes);
Garmond Leunge2433c32017-09-28 21:51:22 -07007585 } else if (audio_extn_ffv_get_stream() == in) {
7586 ret = audio_extn_ffv_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307587 } else {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007588 ret = pcm_read(in->pcm, buffer, bytes);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307589 /* data from DSP comes in 24_8 format, convert it to 8_24 */
7590 if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
7591 if (audio_extn_utils_convert_format_24_8_to_8_24(buffer, bytes)
7592 != bytes) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307593 ret = -EINVAL;
7594 goto exit;
7595 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307596 } else if (ret < 0) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307597 ret = -errno;
7598 }
7599 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307600 /* bytes read is always set to bytes for non compress usecases */
7601 bytes_read = bytes;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007602 }
7603
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007604 release_in_focus(in);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007605
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007606 /*
Quinn Malef6050362019-01-30 15:55:40 -08007607 * Instead of writing zeroes here, we could trust the hardware to always
7608 * provide zeroes when muted. This is also muted with voice recognition
7609 * usecases so that other clients do not have access to voice recognition
7610 * data.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007611 */
Quinn Malef6050362019-01-30 15:55:40 -08007612 if ((ret == 0 && voice_get_mic_mute(adev) &&
7613 !voice_is_in_call_rec_stream(in) &&
Zhou Song62ea0282020-03-22 19:53:01 +08007614 (in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY &&
7615 in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY2)) ||
Quinn Malef6050362019-01-30 15:55:40 -08007616 (adev->num_va_sessions &&
7617 in->source != AUDIO_SOURCE_VOICE_RECOGNITION &&
7618 property_get_bool("persist.vendor.audio.va_concurrency_mute_enabled",
7619 false)))
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007620 memset(buffer, 0, bytes);
7621
7622exit:
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307623 frame_size = audio_stream_in_frame_size(stream);
7624 if (frame_size > 0)
7625 in->frames_read += bytes_read/frame_size;
7626
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007627 if (-ENETRESET == ret)
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307628 in->card_status = CARD_STATUS_OFFLINE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007629 pthread_mutex_unlock(&in->lock);
7630
7631 if (ret != 0) {
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307632 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307633 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307634 voice_extn_compress_voip_close_input_stream(&in->stream.common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307635 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307636 in->standby = true;
7637 }
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307638 if (!audio_extn_cin_attached_usecase(in)) {
Sharad Sangled17c9122017-03-20 15:58:52 +05307639 bytes_read = bytes;
7640 memset(buffer, 0, bytes);
7641 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007642 in_standby(&in->stream.common);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007643 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7644 adev->adm_routing_changed = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007645 ALOGV("%s: read failed status %d- sleeping for buffer duration", __func__, ret);
Ashish Jainbbce4322016-02-16 13:25:27 +05307646 usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
Naresh Tanniru4c630392014-05-12 01:05:52 +05307647 in_get_sample_rate(&in->stream.common));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007648 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307649 return bytes_read;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007650}
7651
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007652static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007653{
7654 return 0;
7655}
7656
Aalique Grahame22e49102018-12-18 14:23:57 -08007657static int in_get_capture_position(const struct audio_stream_in *stream,
7658 int64_t *frames, int64_t *time)
7659{
7660 if (stream == NULL || frames == NULL || time == NULL) {
7661 return -EINVAL;
7662 }
7663 struct stream_in *in = (struct stream_in *)stream;
7664 int ret = -ENOSYS;
7665
7666 lock_input_stream(in);
7667 // note: ST sessions do not close the alsa pcm driver synchronously
7668 // on standby. Therefore, we may return an error even though the
7669 // pcm stream is still opened.
7670 if (in->standby) {
7671 ALOGE_IF(in->pcm != NULL && !in->is_st_session,
7672 "%s stream in standby but pcm not NULL for non ST session", __func__);
7673 goto exit;
7674 }
7675 if (in->pcm) {
7676 struct timespec timestamp;
7677 unsigned int avail;
7678 if (pcm_get_htimestamp(in->pcm, &avail, &timestamp) == 0) {
7679 *frames = in->frames_read + avail;
Robert Lee58215542019-07-15 20:55:12 +08007680 *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec
George Gao9ba8a142020-07-23 14:30:03 -07007681 - platform_capture_latency(in) * 1000LL;
Kakanaboina Ramanjaneyulu8cedb092021-03-15 15:55:29 +05307682 //Adjustment accounts for A2dp decoder latency for recording usecase
7683 // Note: decoder latency is returned in ms, while platform_capture_latency in ns.
7684 if (is_a2dp_in_device_type(&in->device_list))
7685 *time -= audio_extn_a2dp_get_decoder_latency() * 1000000LL;
Aalique Grahame22e49102018-12-18 14:23:57 -08007686 ret = 0;
7687 }
7688 }
7689exit:
7690 pthread_mutex_unlock(&in->lock);
7691 return ret;
7692}
7693
Carter Hsu2e429db2019-05-14 18:50:52 +08007694static int in_update_effect_list(bool add, effect_handle_t effect,
7695 struct listnode *head)
7696{
7697 struct listnode *node;
7698 struct in_effect_list *elist = NULL;
7699 struct in_effect_list *target = NULL;
7700 int ret = 0;
7701
7702 if (!head)
7703 return ret;
7704
7705 list_for_each(node, head) {
7706 elist = node_to_item(node, struct in_effect_list, list);
7707 if (elist->handle == effect) {
7708 target = elist;
7709 break;
7710 }
7711 }
7712
7713 if (add) {
7714 if (target) {
7715 ALOGD("effect %p already exist", effect);
7716 return ret;
7717 }
7718
7719 target = (struct in_effect_list *)
7720 calloc(1, sizeof(struct in_effect_list));
7721
7722 if (!target) {
7723 ALOGE("%s:fail to allocate memory", __func__);
7724 return -ENOMEM;
7725 }
7726
7727 target->handle = effect;
7728 list_add_tail(head, &target->list);
7729 } else {
7730 if (target) {
7731 list_remove(&target->list);
7732 free(target);
7733 }
7734 }
7735
7736 return ret;
7737}
7738
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007739static int add_remove_audio_effect(const struct audio_stream *stream,
7740 effect_handle_t effect,
7741 bool enable)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007742{
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007743 struct stream_in *in = (struct stream_in *)stream;
7744 int status = 0;
7745 effect_descriptor_t desc;
7746
7747 status = (*effect)->get_descriptor(effect, &desc);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007748 ALOGV("%s: status %d in->standby %d enable:%d", __func__, status, in->standby, enable);
7749
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007750 if (status != 0)
7751 return status;
7752
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007753 lock_input_stream(in);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007754 pthread_mutex_lock(&in->dev->lock);
kunleizd96526c2018-04-09 11:12:32 +08007755 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Carter Hsu2e429db2019-05-14 18:50:52 +08007756 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
7757 adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007758 (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
Carter Hsu2e429db2019-05-14 18:50:52 +08007759
7760 in_update_effect_list(enable, effect, &in->aec_list);
7761 enable = !list_empty(&in->aec_list);
7762 if (enable == in->enable_aec)
7763 goto exit;
7764
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007765 in->enable_aec = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007766 ALOGD("AEC enable %d", enable);
7767
Aalique Grahame22e49102018-12-18 14:23:57 -08007768 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
7769 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
7770 in->dev->enable_voicerx = enable;
7771 struct audio_usecase *usecase;
7772 struct listnode *node;
7773 list_for_each(node, &in->dev->usecase_list) {
7774 usecase = node_to_item(node, struct audio_usecase, list);
7775 if (usecase->type == PCM_PLAYBACK)
7776 select_devices(in->dev, usecase->id);
7777 }
7778 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007779 if (!in->standby) {
7780 if (enable_disable_effect(in->dev, EFFECT_AEC, enable) == ENOSYS)
7781 select_devices(in->dev, in->usecase);
7782 }
7783
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007784 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007785 if (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
7786
7787 in_update_effect_list(enable, effect, &in->ns_list);
7788 enable = !list_empty(&in->ns_list);
7789 if (enable == in->enable_ns)
7790 goto exit;
7791
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007792 in->enable_ns = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007793 ALOGD("NS enable %d", enable);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007794 if (!in->standby) {
kunleizd96526c2018-04-09 11:12:32 +08007795 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Ramu Gottipatifa5be522021-12-28 19:18:21 +05307796 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
kunleizd96526c2018-04-09 11:12:32 +08007797 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007798 if (enable_disable_effect(in->dev, EFFECT_NS, enable) == ENOSYS)
7799 select_devices(in->dev, in->usecase);
7800 } else
7801 select_devices(in->dev, in->usecase);
7802 }
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007803 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007804exit:
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007805 pthread_mutex_unlock(&in->dev->lock);
7806 pthread_mutex_unlock(&in->lock);
7807
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007808 return 0;
7809}
7810
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007811static int in_add_audio_effect(const struct audio_stream *stream,
7812 effect_handle_t effect)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007813{
Eric Laurent994a6932013-07-17 11:51:42 -07007814 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007815 return add_remove_audio_effect(stream, effect, true);
7816}
7817
7818static int in_remove_audio_effect(const struct audio_stream *stream,
7819 effect_handle_t effect)
7820{
Eric Laurent994a6932013-07-17 11:51:42 -07007821 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007822 return add_remove_audio_effect(stream, effect, false);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007823}
7824
Haynes Mathew George16081042017-05-31 17:16:49 -07007825static int in_stop(const struct audio_stream_in* stream)
7826{
7827 struct stream_in *in = (struct stream_in *)stream;
7828 struct audio_device *adev = in->dev;
7829
7830 int ret = -ENOSYS;
7831 ALOGV("%s", __func__);
7832 pthread_mutex_lock(&adev->lock);
7833 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7834 in->capture_started && in->pcm != NULL) {
7835 pcm_stop(in->pcm);
7836 ret = stop_input_stream(in);
7837 in->capture_started = false;
7838 }
7839 pthread_mutex_unlock(&adev->lock);
7840 return ret;
7841}
7842
7843static int in_start(const struct audio_stream_in* stream)
7844{
7845 struct stream_in *in = (struct stream_in *)stream;
7846 struct audio_device *adev = in->dev;
7847 int ret = -ENOSYS;
7848
7849 ALOGV("%s in %p", __func__, in);
7850 pthread_mutex_lock(&adev->lock);
7851 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7852 !in->capture_started && in->pcm != NULL) {
7853 if (!in->capture_started) {
7854 ret = start_input_stream(in);
7855 if (ret == 0) {
7856 in->capture_started = true;
7857 }
7858 }
7859 }
7860 pthread_mutex_unlock(&adev->lock);
7861 return ret;
7862}
7863
Phil Burke0a86d12019-02-16 22:28:11 -08007864// Read offset for the positional timestamp from a persistent vendor property.
7865// This is to workaround apparent inaccuracies in the timing information that
7866// is used by the AAudio timing model. The inaccuracies can cause glitches.
7867static int64_t in_get_mmap_time_offset() {
7868 const int32_t kDefaultOffsetMicros = 0;
7869 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08007870 "persist.vendor.audio.in_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burke0a86d12019-02-16 22:28:11 -08007871 ALOGI("mmap_time_offset_micros = %d for input", mmap_time_offset_micros);
7872 return mmap_time_offset_micros * (int64_t)1000;
7873}
7874
Haynes Mathew George16081042017-05-31 17:16:49 -07007875static int in_create_mmap_buffer(const struct audio_stream_in *stream,
7876 int32_t min_size_frames,
7877 struct audio_mmap_buffer_info *info)
7878{
7879 struct stream_in *in = (struct stream_in *)stream;
7880 struct audio_device *adev = in->dev;
7881 int ret = 0;
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07007882 unsigned int offset1 = 0;
7883 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007884 const char *step = "";
Arun Mirpuri5d170872019-03-26 13:21:31 -07007885 uint32_t mmap_size = 0;
7886 uint32_t buffer_size = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007887
7888 pthread_mutex_lock(&adev->lock);
7889 ALOGV("%s in %p", __func__, in);
7890
Sharad Sanglec6f32552018-05-04 16:15:38 +05307891 if (CARD_STATUS_OFFLINE == in->card_status||
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05007892 CARD_STATUS_OFFLINE == adev->card_status ||
7893 POWER_POLICY_STATUS_OFFLINE == adev->in_power_policy) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307894 ALOGW("in->card_status or adev->card_status offline, try again");
7895 ret = -EIO;
7896 goto exit;
7897 }
7898
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307899 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007900 ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
7901 ret = -EINVAL;
7902 goto exit;
7903 }
7904 if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
7905 ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
7906 ALOGV("%s in %p", __func__, in);
7907 ret = -ENOSYS;
7908 goto exit;
7909 }
7910 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
7911 if (in->pcm_device_id < 0) {
7912 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7913 __func__, in->pcm_device_id, in->usecase);
7914 ret = -EINVAL;
7915 goto exit;
7916 }
7917
7918 adjust_mmap_period_count(&in->config, min_size_frames);
7919
7920 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
7921 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
7922 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
7923 (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307924 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307925 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7926 in->card_status = CARD_STATUS_OFFLINE;
7927 adev->card_status = CARD_STATUS_OFFLINE;
7928 ret = -EIO;
7929 goto exit;
7930 }
7931
Haynes Mathew George16081042017-05-31 17:16:49 -07007932 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
7933 step = "open";
7934 ret = -ENODEV;
7935 goto exit;
7936 }
7937
7938 ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
7939 if (ret < 0) {
7940 step = "begin";
7941 goto exit;
7942 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007943
juyuchen626833d2019-06-04 16:48:02 +08007944 info->flags = 0;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007945 info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
7946 buffer_size = pcm_frames_to_bytes(in->pcm, info->buffer_size_frames);
7947 info->burst_size_frames = in->config.period_size;
7948 ret = platform_get_mmap_data_fd(adev->platform,
7949 in->pcm_device_id, 1 /*capture*/,
7950 &info->shared_memory_fd,
7951 &mmap_size);
7952 if (ret < 0) {
7953 // Fall back to non exclusive mode
7954 info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
7955 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007956 in->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7957 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, in->mmap_shared_memory_fd);
7958
Arun Mirpuri5d170872019-03-26 13:21:31 -07007959 if (mmap_size < buffer_size) {
7960 step = "mmap";
7961 goto exit;
7962 }
juyuchen626833d2019-06-04 16:48:02 +08007963 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007964 }
7965
7966 memset(info->shared_memory_address, 0, buffer_size);
Haynes Mathew George16081042017-05-31 17:16:49 -07007967
7968 ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
7969 if (ret < 0) {
7970 step = "commit";
7971 goto exit;
7972 }
7973
Phil Burke0a86d12019-02-16 22:28:11 -08007974 in->mmap_time_offset_nanos = in_get_mmap_time_offset();
7975
Haynes Mathew George16081042017-05-31 17:16:49 -07007976 in->standby = false;
7977 ret = 0;
7978
7979 ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
7980 __func__, info->shared_memory_address, info->buffer_size_frames);
7981
7982exit:
7983 if (ret != 0) {
7984 if (in->pcm == NULL) {
7985 ALOGE("%s: %s - %d", __func__, step, ret);
7986 } else {
7987 ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
7988 pcm_close(in->pcm);
7989 in->pcm = NULL;
7990 }
7991 }
7992 pthread_mutex_unlock(&adev->lock);
7993 return ret;
7994}
7995
7996static int in_get_mmap_position(const struct audio_stream_in *stream,
7997 struct audio_mmap_position *position)
7998{
7999 struct stream_in *in = (struct stream_in *)stream;
8000 ALOGVV("%s", __func__);
8001 if (position == NULL) {
8002 return -EINVAL;
8003 }
Gautam Manam34d1f542021-01-05 20:24:37 +05308004 lock_input_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07008005 if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
Gautam Manam34d1f542021-01-05 20:24:37 +05308006 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008007 return -ENOSYS;
8008 }
8009 if (in->pcm == NULL) {
Gautam Manam34d1f542021-01-05 20:24:37 +05308010 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008011 return -ENOSYS;
8012 }
8013 struct timespec ts = { 0, 0 };
8014 int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
8015 if (ret < 0) {
8016 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
Gautam Manam34d1f542021-01-05 20:24:37 +05308017 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008018 return ret;
8019 }
Phil Burke0a86d12019-02-16 22:28:11 -08008020 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
8021 + in->mmap_time_offset_nanos;
Gautam Manam34d1f542021-01-05 20:24:37 +05308022 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07008023 return 0;
8024}
8025
Naresh Tannirudcb47c52018-06-25 16:23:32 +05308026static int in_get_active_microphones(const struct audio_stream_in *stream,
8027 struct audio_microphone_characteristic_t *mic_array,
8028 size_t *mic_count) {
8029 struct stream_in *in = (struct stream_in *)stream;
8030 struct audio_device *adev = in->dev;
8031 ALOGVV("%s", __func__);
8032
8033 lock_input_stream(in);
8034 pthread_mutex_lock(&adev->lock);
8035 int ret = platform_get_active_microphones(adev->platform,
8036 audio_channel_count_from_in_mask(in->channel_mask),
8037 in->usecase, mic_array, mic_count);
8038 pthread_mutex_unlock(&adev->lock);
8039 pthread_mutex_unlock(&in->lock);
8040
8041 return ret;
8042}
8043
8044static int adev_get_microphones(const struct audio_hw_device *dev,
8045 struct audio_microphone_characteristic_t *mic_array,
8046 size_t *mic_count) {
8047 struct audio_device *adev = (struct audio_device *)dev;
8048 ALOGVV("%s", __func__);
8049
8050 pthread_mutex_lock(&adev->lock);
8051 int ret = platform_get_microphones(adev->platform, mic_array, mic_count);
8052 pthread_mutex_unlock(&adev->lock);
8053
8054 return ret;
8055}
juyuchendb308c22019-01-21 11:57:17 -07008056
8057static void in_update_sink_metadata(struct audio_stream_in *stream,
8058 const struct sink_metadata *sink_metadata) {
8059
8060 if (stream == NULL
8061 || sink_metadata == NULL
8062 || sink_metadata->tracks == NULL) {
8063 return;
8064 }
8065
8066 int error = 0;
8067 struct stream_in *in = (struct stream_in *)stream;
8068 struct audio_device *adev = in->dev;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008069 struct listnode devices;
8070
8071 list_init(&devices);
juyuchendb308c22019-01-21 11:57:17 -07008072
8073 if (sink_metadata->track_count != 0)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008074 reassign_device_list(&devices, sink_metadata->tracks->dest_device, "");
juyuchendb308c22019-01-21 11:57:17 -07008075
8076 lock_input_stream(in);
8077 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008078 ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, get_device_types(&devices));
juyuchendb308c22019-01-21 11:57:17 -07008079
Zhou Song503196b2021-07-23 17:31:05 +08008080 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY ||
8081 in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2) &&
8082 !list_empty(&devices) &&
8083 adev->voice_tx_output != NULL) {
juyuchendb308c22019-01-21 11:57:17 -07008084 /* Use the rx device from afe-proxy record to route voice call because
8085 there is no routing if tx device is on primary hal and rx device
8086 is on other hal during voice call. */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008087 assign_devices(&adev->voice_tx_output->device_list, &devices);
juyuchendb308c22019-01-21 11:57:17 -07008088
8089 if (!voice_is_call_state_active(adev)) {
8090 if (adev->mode == AUDIO_MODE_IN_CALL) {
8091 adev->current_call_output = adev->voice_tx_output;
8092 error = voice_start_call(adev);
8093 if (error != 0)
8094 ALOGE("%s: start voice call failed %d", __func__, error);
8095 }
8096 } else {
8097 adev->current_call_output = adev->voice_tx_output;
8098 voice_update_devices_for_all_voice_usecases(adev);
8099 }
8100 }
8101
Zhenlin Lian4f947842022-05-14 15:50:52 +05308102 clear_devices(&devices);
juyuchendb308c22019-01-21 11:57:17 -07008103 pthread_mutex_unlock(&adev->lock);
8104 pthread_mutex_unlock(&in->lock);
8105}
8106
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05308107int adev_open_output_stream(struct audio_hw_device *dev,
Haynes Mathew George16081042017-05-31 17:16:49 -07008108 audio_io_handle_t handle,
8109 audio_devices_t devices,
8110 audio_output_flags_t flags,
8111 struct audio_config *config,
8112 struct audio_stream_out **stream_out,
Derek Chenf6318be2017-06-12 17:16:24 -04008113 const char *address)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008114{
8115 struct audio_device *adev = (struct audio_device *)dev;
8116 struct stream_out *out;
Gangadhar Sb0210342019-02-22 17:39:41 +05308117 int ret = 0, ip_hdlr_stream = 0, ip_hdlr_dev = 0;
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008118 audio_format_t format;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008119 struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
Manish Dewangan21a850a2017-08-14 12:03:55 +05308120 bool is_direct_passthough = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008121 bool is_hdmi = devices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
8122 bool is_usb_dev = audio_is_usb_out_device(devices) &&
8123 (devices != AUDIO_DEVICE_OUT_USB_ACCESSORY);
8124 bool direct_dev = is_hdmi || is_usb_dev;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008125 bool use_db_as_primary =
vivek mehtaae1018c2019-05-09 12:19:57 -07008126 property_get_bool("vendor.audio.feature.deepbuffer_as_primary.enable",
8127 false);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008128 bool force_haptic_path =
8129 property_get_bool("vendor.audio.test_haptic", false);
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008130 bool is_voip_rx = flags & AUDIO_OUTPUT_FLAG_VOIP_RX;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008131#ifdef AUDIO_GKI_ENABLED
8132 __s32 *generic_dec;
8133#endif
Weiyin Jiang906db3c2021-03-02 13:17:04 +08008134 pthread_mutexattr_t latch_attr;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008135
kunleizdff872d2018-08-20 14:40:33 +08008136 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08008137 is_usb_dev = false;
8138 devices = AUDIO_DEVICE_OUT_SPEAKER;
8139 ALOGW("%s: ignore set device to non existing USB card, use output device(%#x)",
8140 __func__, devices);
Mingshu Pangdbd20562019-11-25 18:04:39 +08008141 if (config->format == AUDIO_FORMAT_DEFAULT)
8142 config->format = AUDIO_FORMAT_PCM_16_BIT;
8143 if (config->sample_rate == 0)
8144 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8145 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8146 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
kunleizd6a9e0c2018-07-30 15:38:52 +08008147 }
8148
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008149 *stream_out = NULL;
Naresh Tanniru80659832014-06-04 18:17:56 +05308150
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008151 out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
8152
Mingming Yin3a941d42016-02-17 18:08:05 -08008153 ALOGD("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
Derek Chenf6318be2017-06-12 17:16:24 -04008154 stream_handle(%p) address(%s)", __func__, config->format, config->sample_rate, config->channel_mask,
8155 devices, flags, &out->stream, address);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308156
8157
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008158 if (!out) {
8159 return -ENOMEM;
8160 }
8161
Haynes Mathew George204045b2015-02-25 20:32:03 -08008162 pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07008163 pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08008164 pthread_mutexattr_init(&latch_attr);
8165 pthread_mutexattr_settype(&latch_attr, PTHREAD_MUTEX_RECURSIVE);
8166 pthread_mutex_init(&out->latch_lock, &latch_attr);
8167 pthread_mutexattr_destroy(&latch_attr);
Zhou Song48453a02018-01-10 17:50:59 +08008168 pthread_mutex_init(&out->position_query_lock, (const pthread_mutexattr_t *) NULL);
Haynes Mathew George204045b2015-02-25 20:32:03 -08008169 pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
8170
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008171 if (devices == AUDIO_DEVICE_NONE)
8172 devices = AUDIO_DEVICE_OUT_SPEAKER;
8173
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008174 out->flags = flags;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008175 list_init(&out->device_list);
8176 update_device_list(&out->device_list, devices, address, true /* add devices */);
Haynes Mathew George47cd4cb2013-07-19 11:58:50 -07008177 out->dev = adev;
Aalique Grahame65780b52017-09-27 14:59:56 -07008178 out->hal_op_format = out->hal_ip_format = format = out->format = config->format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008179 out->sample_rate = config->sample_rate;
Sachin Mohan Gadag3d09acd2017-06-19 12:43:44 +05308180 out->channel_mask = config->channel_mask;
Ramjee Singh5857aeb2017-08-03 19:18:50 +05308181 if (out->channel_mask == AUDIO_CHANNEL_NONE)
8182 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
8183 else
8184 out->supported_channel_masks[0] = out->channel_mask;
Eric Laurentc4aef752013-09-12 17:45:53 -07008185 out->handle = handle;
Mingming Yin3ee55c62014-08-04 14:23:35 -07008186 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Alexy Josephaa54c872014-12-03 02:46:47 -08008187 out->non_blocking = 0;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308188 out->convert_buffer = NULL;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308189 out->started = 0;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008190 out->a2dp_muted = false;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008191 out->hal_output_suspend_supported = 0;
8192 out->dynamic_pm_qos_config_supported = 0;
Surendar Karkaf51b5842018-04-26 11:28:38 +05308193 out->set_dual_mono = false;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05308194 out->prev_card_status_offline = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05308195 out->pspd_coeff_sent = false;
Phil Burkd898ba62019-06-20 12:49:01 -07008196 out->mmap_shared_memory_fd = -1; // not open
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008197
Nikhil Laturkar26b690b2017-07-25 11:06:14 +05308198 if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
Satish Babu Patakokila37e7c482018-02-02 11:50:06 +05308199 (property_get_bool("vendor.audio.matrix.limiter.enable", false)))
Ben Romberger6c4d3812017-06-13 17:46:45 -07008200 platform_set_device_params(out, DEVICE_PARAM_LIMITER_ID, 1);
8201
Aalique Grahame22e49102018-12-18 14:23:57 -08008202 if (direct_dev &&
8203 (audio_is_linear_pcm(out->format) ||
8204 config->format == AUDIO_FORMAT_DEFAULT) &&
8205 out->flags == AUDIO_OUTPUT_FLAG_NONE) {
8206 audio_format_t req_format = config->format;
8207 audio_channel_mask_t req_channel_mask = config->channel_mask;
8208 uint32_t req_sample_rate = config->sample_rate;
8209
8210 pthread_mutex_lock(&adev->lock);
8211 if (is_hdmi) {
8212 ALOGV("AUDIO_DEVICE_OUT_AUX_DIGITAL and DIRECT|OFFLOAD, check hdmi caps");
8213 ret = read_hdmi_sink_caps(out);
8214 if (config->sample_rate == 0)
8215 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8216 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8217 config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
8218 if (config->format == AUDIO_FORMAT_DEFAULT)
8219 config->format = AUDIO_FORMAT_PCM_16_BIT;
8220 } else if (is_usb_dev) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008221 ret = read_usb_sup_params_and_compare(true /*is_playback*/,
8222 &config->format,
8223 &out->supported_formats[0],
8224 MAX_SUPPORTED_FORMATS,
8225 &config->channel_mask,
8226 &out->supported_channel_masks[0],
8227 MAX_SUPPORTED_CHANNEL_MASKS,
8228 &config->sample_rate,
8229 &out->supported_sample_rates[0],
8230 MAX_SUPPORTED_SAMPLE_RATES);
8231 ALOGV("plugged dev USB ret %d", ret);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008232 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008233
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008234 pthread_mutex_unlock(&adev->lock);
8235 if (ret != 0) {
Mingming Yin3a941d42016-02-17 18:08:05 -08008236 if (ret == -ENOSYS) {
8237 /* ignore and go with default */
8238 ret = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08008239 }
8240 // For MMAP NO IRQ, allow conversions in ADSP
8241 else if (is_hdmi || (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0)
8242 goto error_open;
8243 else {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008244 ALOGE("error reading direct dev sink caps");
Mingming Yin3a941d42016-02-17 18:08:05 -08008245 goto error_open;
8246 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008247
8248 if (req_sample_rate != 0 && config->sample_rate != req_sample_rate)
8249 config->sample_rate = req_sample_rate;
8250 if (req_channel_mask != AUDIO_CHANNEL_NONE && config->channel_mask != req_channel_mask)
8251 config->channel_mask = req_channel_mask;
8252 if (req_format != AUDIO_FORMAT_DEFAULT && config->format != req_format)
8253 config->format = req_format;
Mingming Yin3a941d42016-02-17 18:08:05 -08008254 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008255
8256 out->sample_rate = config->sample_rate;
8257 out->channel_mask = config->channel_mask;
8258 out->format = config->format;
8259 if (is_hdmi) {
8260 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8261 out->config = pcm_config_hdmi_multi;
8262 } else if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8263 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8264 out->config = pcm_config_mmap_playback;
8265 out->stream.start = out_start;
8266 out->stream.stop = out_stop;
8267 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8268 out->stream.get_mmap_position = out_get_mmap_position;
8269 } else {
8270 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8271 out->config = pcm_config_hifi;
8272 }
8273
8274 out->config.rate = out->sample_rate;
8275 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8276 if (is_hdmi) {
8277 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8278 audio_bytes_per_sample(out->format));
8279 }
8280 out->config.format = pcm_format_from_audio_format(out->format);
Mingming Yin3a941d42016-02-17 18:08:05 -08008281 }
8282
Derek Chenf6318be2017-06-12 17:16:24 -04008283 /* validate bus device address */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008284 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008285 /* extract car audio stream index */
8286 out->car_audio_stream =
8287 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
8288 if (out->car_audio_stream < 0) {
8289 ALOGE("%s: invalid car audio stream %x",
8290 __func__, out->car_audio_stream);
8291 ret = -EINVAL;
8292 goto error_open;
8293 }
Derek Chen5f67a942020-02-24 23:08:13 -08008294 ALOGV("%s: car_audio_stream %x", __func__, out->car_audio_stream);
Derek Chenf6318be2017-06-12 17:16:24 -04008295 }
8296
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008297 /* Check for VOIP usecase */
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008298 if (is_voip_rx) {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008299 if (!voice_extn_is_compress_voip_supported()) {
8300 if (out->sample_rate == 8000 || out->sample_rate == 16000 ||
8301 out->sample_rate == 32000 || out->sample_rate == 48000) {
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07008302 out->channel_mask = audio_extn_utils_is_vendor_enhanced_fwk() ?
Lakshman Chaluvarajue7fc9482020-05-30 14:29:29 +05308303 config->channel_mask : AUDIO_CHANNEL_OUT_STEREO;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008304 out->usecase = USECASE_AUDIO_PLAYBACK_VOIP;
8305 out->format = AUDIO_FORMAT_PCM_16_BIT;
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07008306 out->volume_l = INVALID_OUT_VOLUME;
8307 out->volume_r = INVALID_OUT_VOLUME;
Vikram Panduranga93f080e2017-06-07 18:16:14 -07008308
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008309 out->config = default_pcm_config_voip_copp;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008310 out->config.rate = out->sample_rate;
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008311 uint32_t channel_count =
8312 audio_channel_count_from_out_mask(out->channel_mask);
Ramjee Singh968858a2020-08-06 16:30:48 +05308313 out->config.channels = channel_count;
8314
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008315 uint32_t buffer_size = get_stream_buffer_size(DEFAULT_VOIP_BUF_DURATION_MS,
8316 out->sample_rate, out->format,
8317 channel_count, false);
8318 uint32_t frame_size = audio_bytes_per_sample(out->format) * channel_count;
8319 if (frame_size != 0)
8320 out->config.period_size = buffer_size / frame_size;
8321 else
8322 ALOGW("%s: frame size is 0 for format %#x", __func__, out->format);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008323 }
8324 } else {
8325 if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
8326 voice_extn_compress_voip_is_active(out->dev)) &&
8327 (voice_extn_compress_voip_is_config_supported(config))) {
8328 ret = voice_extn_compress_voip_open_output_stream(out);
8329 if (ret != 0) {
8330 ALOGE("%s: Compress voip output cannot be opened, error:%d",
8331 __func__, ret);
8332 goto error_open;
8333 }
Sujin Panicker19027262019-09-16 18:28:06 +05308334 } else {
8335 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8336 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008337 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008338 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008339 } else if (audio_is_linear_pcm(out->format) &&
8340 out->flags == AUDIO_OUTPUT_FLAG_NONE && is_usb_dev) {
8341 out->channel_mask = config->channel_mask;
8342 out->sample_rate = config->sample_rate;
8343 out->format = config->format;
8344 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8345 // does this change?
8346 out->config = is_hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
8347 out->config.rate = config->sample_rate;
8348 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8349 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8350 audio_bytes_per_sample(config->format));
8351 out->config.format = pcm_format_from_audio_format(out->format);
vivek mehta0ea887a2015-08-26 14:01:20 -07008352 } else if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308353 (out->flags == AUDIO_OUTPUT_FLAG_DIRECT)) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308354 pthread_mutex_lock(&adev->lock);
8355 bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
8356 pthread_mutex_unlock(&adev->lock);
8357
8358 // reject offload during card offline to allow
8359 // fallback to s/w paths
8360 if (offline) {
8361 ret = -ENODEV;
8362 goto error_open;
8363 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008364
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008365 if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
8366 config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
8367 ALOGE("%s: Unsupported Offload information", __func__);
8368 ret = -EINVAL;
8369 goto error_open;
8370 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008371
Atul Khare3fa6e542017-08-09 00:56:17 +05308372 if (config->offload_info.format == 0)
8373 config->offload_info.format = config->format;
8374 if (config->offload_info.sample_rate == 0)
8375 config->offload_info.sample_rate = config->sample_rate;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008376
Mingming Yin90310102013-11-13 16:57:00 -08008377 if (!is_supported_format(config->offload_info.format) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308378 !audio_extn_passthru_is_supported_format(config->offload_info.format)) {
vivek mehta0ea887a2015-08-26 14:01:20 -07008379 ALOGE("%s: Unsupported audio format %x " , __func__, config->offload_info.format);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008380 ret = -EINVAL;
8381 goto error_open;
8382 }
8383
Ben Romberger0f8c87b2017-05-24 17:41:11 -07008384 /* TrueHD only supported for 48k multiples (48k, 96k, 192k) */
8385 if ((config->offload_info.format == AUDIO_FORMAT_DOLBY_TRUEHD) &&
8386 (audio_extn_passthru_is_passthrough_stream(out)) &&
8387 !((config->sample_rate == 48000) ||
8388 (config->sample_rate == 96000) ||
8389 (config->sample_rate == 192000))) {
8390 ALOGE("%s: Unsupported sample rate %d for audio format %x",
8391 __func__, config->sample_rate, config->offload_info.format);
8392 ret = -EINVAL;
8393 goto error_open;
8394 }
8395
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008396 out->compr_config.codec = (struct snd_codec *)
8397 calloc(1, sizeof(struct snd_codec));
8398
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07008399 if (!out->compr_config.codec) {
8400 ret = -ENOMEM;
8401 goto error_open;
8402 }
8403
Dhananjay Kumarac341582017-02-23 23:42:25 +05308404 out->stream.pause = out_pause;
8405 out->stream.resume = out_resume;
8406 out->stream.flush = out_flush;
Ashish Jain4847e9d2017-08-17 19:16:57 +05308407 out->stream.set_callback = out_set_callback;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308408 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Mingming Yin21d60472015-09-30 13:56:25 -07008409 out->stream.drain = out_drain;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308410 out->usecase = get_offload_usecase(adev, true /* is_compress */);
vivek mehta446c3962015-09-14 10:57:35 -07008411 ALOGV("Compress Offload usecase .. usecase selected %d", out->usecase);
Dhananjay Kumarac341582017-02-23 23:42:25 +05308412 } else {
8413 out->usecase = get_offload_usecase(adev, false /* is_compress */);
8414 ALOGV("non-offload DIRECT_usecase ... usecase selected %d ", out->usecase);
vivek mehta0ea887a2015-08-26 14:01:20 -07008415 }
vivek mehta446c3962015-09-14 10:57:35 -07008416
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308417 if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8418 ALOGD("%s: Setting latency mode to true", __func__);
Meng Wang4c32fb42020-01-16 17:57:11 +08008419#ifdef AUDIO_GKI_ENABLED
8420 /* out->compr_config.codec->reserved[1] is for flags */
8421 out->compr_config.codec->reserved[1] |= audio_extn_utils_get_perf_mode_flag();
8422#else
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308423 out->compr_config.codec->flags |= audio_extn_utils_get_perf_mode_flag();
Meng Wang4c32fb42020-01-16 17:57:11 +08008424#endif
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308425 }
8426
vivek mehta446c3962015-09-14 10:57:35 -07008427 if (out->usecase == USECASE_INVALID) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008428 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Mingming Yin3a941d42016-02-17 18:08:05 -08008429 config->format == 0 && config->sample_rate == 0 &&
8430 config->channel_mask == 0) {
Mingming Yin21854652016-04-13 11:54:02 -07008431 ALOGI("%s dummy open to query sink capability",__func__);
Mingming Yin3a941d42016-02-17 18:08:05 -08008432 out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
8433 } else {
8434 ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__);
8435 ret = -EEXIST;
8436 goto error_open;
8437 }
vivek mehta446c3962015-09-14 10:57:35 -07008438 }
8439
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008440 if (config->offload_info.channel_mask)
8441 out->channel_mask = config->offload_info.channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008442 else if (config->channel_mask) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008443 out->channel_mask = config->channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008444 config->offload_info.channel_mask = config->channel_mask;
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008445 } else {
Dhananjay Kumarac341582017-02-23 23:42:25 +05308446 ALOGE("out->channel_mask not set for OFFLOAD/DIRECT usecase");
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008447 ret = -EINVAL;
8448 goto error_open;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008449 }
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008450
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008451 format = out->format = config->offload_info.format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008452 out->sample_rate = config->offload_info.sample_rate;
8453
Mingming Yin3ee55c62014-08-04 14:23:35 -07008454 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008455
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308456 out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05308457 if (audio_extn_utils_is_dolby_format(config->offload_info.format)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308458 audio_extn_dolby_send_ddp_endp_params(adev);
8459 audio_extn_dolby_set_dmid(adev);
8460 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008461
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008462 out->compr_config.codec->sample_rate =
Ravi Kumar Alamandab91bff32014-11-14 12:05:54 -08008463 config->offload_info.sample_rate;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008464 out->compr_config.codec->bit_rate =
8465 config->offload_info.bit_rate;
8466 out->compr_config.codec->ch_in =
Dhanalakshmi Siddania15c6792016-08-10 15:33:53 +05308467 audio_channel_count_from_out_mask(out->channel_mask);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008468 out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
Satish Babu Patakokilaa395a9e2016-11-01 12:18:49 +05308469 /* Update bit width only for non passthrough usecases.
8470 * For passthrough usecases, the output will always be opened @16 bit
8471 */
8472 if (!audio_extn_passthru_is_passthrough_stream(out))
8473 out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308474
8475 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
Meng Wang4c32fb42020-01-16 17:57:11 +08008476#ifdef AUDIO_GKI_ENABLED
8477 /* out->compr_config.codec->reserved[1] is for flags */
8478 out->compr_config.codec->reserved[1] |= COMPRESSED_TIMESTAMP_FLAG;
8479 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->reserved[1]);
8480#else
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308481 out->compr_config.codec->flags |= COMPRESSED_TIMESTAMP_FLAG;
8482 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->flags);
Meng Wang4c32fb42020-01-16 17:57:11 +08008483#endif
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308484
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008485 /*TODO: Do we need to change it for passthrough */
8486 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008487
Manish Dewangana6fc5442015-08-24 20:30:31 +05308488 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC)
8489 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308490 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
Manish Dewangana6fc5442015-08-24 20:30:31 +05308491 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308492 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_LATM)
8493 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4LATM;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308494
8495 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) ==
8496 AUDIO_FORMAT_PCM) {
8497
8498 /*Based on platform support, configure appropriate alsa format for corresponding
8499 *hal input format.
8500 */
8501 out->compr_config.codec->format = hal_format_to_alsa(
8502 config->offload_info.format);
8503
Ashish Jain83a6cc22016-06-28 14:34:17 +05308504 out->hal_op_format = alsa_format_to_hal(
Ashish Jainf1eaa582016-05-23 20:54:24 +05308505 out->compr_config.codec->format);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308506 out->hal_ip_format = out->format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308507
Dhananjay Kumarac341582017-02-23 23:42:25 +05308508 /*for direct non-compress playback populate bit_width based on selected alsa format as
Ashish Jainf1eaa582016-05-23 20:54:24 +05308509 *hal input format and alsa format might differ based on platform support.
8510 */
8511 out->bit_width = audio_bytes_per_sample(
Ashish Jain83a6cc22016-06-28 14:34:17 +05308512 out->hal_op_format) << 3;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308513
8514 out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
8515
Deeraj Soman93155a62019-09-30 19:00:37 +05308516 if (property_get_bool("vendor.audio.offload.buffer.duration.enabled", false)) {
8517 if ((config->offload_info.duration_us >= MIN_OFFLOAD_BUFFER_DURATION_MS * 1000) &&
8518 (config->offload_info.duration_us <= MAX_OFFLOAD_BUFFER_DURATION_MS * 1000))
8519 out->info.duration_us = (int64_t)config->offload_info.duration_us;
8520 }
Deeraj Soman65358ab2019-02-07 15:40:49 +05308521
Ashish Jainf1eaa582016-05-23 20:54:24 +05308522 /* Check if alsa session is configured with the same format as HAL input format,
8523 * if not then derive correct fragment size needed to accomodate the
8524 * conversion of HAL input format to alsa format.
8525 */
8526 audio_extn_utils_update_direct_pcm_fragment_size(out);
8527
8528 /*if hal input and output fragment size is different this indicates HAL input format is
8529 *not same as the alsa format
8530 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308531 if (out->hal_fragment_size != out->compr_config.fragment_size) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05308532 /*Allocate a buffer to convert input data to the alsa configured format.
8533 *size of convert buffer is equal to the size required to hold one fragment size
8534 *worth of pcm data, this is because flinger does not write more than fragment_size
8535 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308536 out->convert_buffer = calloc(1,out->compr_config.fragment_size);
8537 if (out->convert_buffer == NULL){
Ashish Jainf1eaa582016-05-23 20:54:24 +05308538 ALOGE("Allocation failed for convert buffer for size %d", out->compr_config.fragment_size);
8539 ret = -ENOMEM;
8540 goto error_open;
8541 }
8542 }
8543 } else if (audio_extn_passthru_is_passthrough_stream(out)) {
8544 out->compr_config.fragment_size =
8545 audio_extn_passthru_get_buffer_size(&config->offload_info);
8546 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8547 } else {
8548 out->compr_config.fragment_size =
8549 platform_get_compress_offload_buffer_size(&config->offload_info);
8550 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8551 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008552
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308553 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8554 out->compr_config.fragment_size += sizeof(struct snd_codec_metadata);
8555 }
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008556 if (config->offload_info.format == AUDIO_FORMAT_FLAC) {
8557#ifdef AUDIO_GKI_ENABLED
8558 generic_dec =
8559 &(out->compr_config.codec->options.generic.reserved[1]);
8560 ((struct snd_generic_dec_flac *)generic_dec)->sample_size =
8561 AUDIO_OUTPUT_BIT_WIDTH;
8562#else
Satya Krishna Pindiproli5d82d012015-08-12 18:21:25 +05308563 out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008564#endif
8565 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008566
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05308567 if (config->offload_info.format == AUDIO_FORMAT_APTX) {
8568 audio_extn_send_aptx_dec_bt_addr_to_dsp(out);
8569 }
8570
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008571 if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
8572 out->non_blocking = 1;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008573
Manish Dewangan69426c82017-01-30 17:35:36 +05308574 if ((flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) &&
8575 (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
8576 out->render_mode = RENDER_MODE_AUDIO_STC_MASTER;
8577 } else if(flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8578 out->render_mode = RENDER_MODE_AUDIO_MASTER;
8579 } else {
8580 out->render_mode = RENDER_MODE_AUDIO_NO_TIMESTAMP;
8581 }
Alexy Josephaa54c872014-12-03 02:46:47 -08008582
Naresh Tanniru29bce4e2017-04-27 17:54:30 +05308583 memset(&out->channel_map_param, 0,
8584 sizeof(struct audio_out_channel_map_param));
8585
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008586 out->send_new_metadata = 1;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05308587 out->send_next_track_params = false;
8588 out->is_compr_metadata_avail = false;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008589 out->offload_state = OFFLOAD_STATE_IDLE;
8590 out->playback_started = 0;
Zhou Song48453a02018-01-10 17:50:59 +08008591 out->writeAt.tv_sec = 0;
8592 out->writeAt.tv_nsec = 0;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008593
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008594 audio_extn_dts_create_state_notifier_node(out->usecase);
8595
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008596 ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
8597 __func__, config->offload_info.version,
8598 config->offload_info.bit_rate);
Ashish Jain5106d362016-05-11 19:23:33 +05308599
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308600 /* Check if DSD audio format is supported in codec
8601 * and there is no active native DSD use case
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308602 */
8603
8604 if ((config->format == AUDIO_FORMAT_DSD) &&
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308605 (!platform_check_codec_dsd_support(adev->platform) ||
8606 audio_is_dsd_native_stream_active(adev))) {
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308607 ret = -EINVAL;
8608 goto error_open;
8609 }
8610
Ashish Jain5106d362016-05-11 19:23:33 +05308611 /* Disable gapless if any of the following is true
8612 * passthrough playback
8613 * AV playback
Dhananjay Kumarac341582017-02-23 23:42:25 +05308614 * non compressed Direct playback
Ashish Jain5106d362016-05-11 19:23:33 +05308615 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308616 if (audio_extn_passthru_is_passthrough_stream(out) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308617 (config->format == AUDIO_FORMAT_DSD) ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07008618 (config->format == AUDIO_FORMAT_IEC61937) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308619 config->offload_info.has_video ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308620 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Ashish Jain5106d362016-05-11 19:23:33 +05308621 check_and_set_gapless_mode(adev, false);
8622 } else
8623 check_and_set_gapless_mode(adev, true);
Mingming Yin21854652016-04-13 11:54:02 -07008624
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308625 if (audio_extn_passthru_is_passthrough_stream(out)) {
Mingming Yin21854652016-04-13 11:54:02 -07008626 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
8627 }
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308628 if (config->format == AUDIO_FORMAT_DSD) {
8629 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
Meng Wang4c32fb42020-01-16 17:57:11 +08008630#ifdef AUDIO_GKI_ENABLED
8631 /* out->compr_config.codec->reserved[0] is for compr_passthr */
8632 out->compr_config.codec->reserved[0] = PASSTHROUGH_DSD;
8633#else
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308634 out->compr_config.codec->compr_passthr = PASSTHROUGH_DSD;
Meng Wang4c32fb42020-01-16 17:57:11 +08008635#endif
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308636 }
Aalique Grahame0359a1f2016-09-08 16:54:22 -07008637
8638 create_offload_callback_thread(out);
8639
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008640 } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008641 switch (config->sample_rate) {
8642 case 0:
8643 out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8644 break;
8645 case 8000:
8646 case 16000:
8647 case 48000:
8648 out->sample_rate = config->sample_rate;
8649 break;
8650 default:
8651 ALOGE("%s: Unsupported sampling rate %d for Incall Music", __func__,
8652 config->sample_rate);
8653 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8654 ret = -EINVAL;
8655 goto error_open;
8656 }
8657 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8658 switch (config->channel_mask) {
8659 case AUDIO_CHANNEL_NONE:
8660 case AUDIO_CHANNEL_OUT_STEREO:
8661 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8662 break;
8663 default:
8664 ALOGE("%s: Unsupported channel mask %#x for Incall Music", __func__,
8665 config->channel_mask);
8666 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8667 ret = -EINVAL;
8668 goto error_open;
8669 }
8670 switch (config->format) {
8671 case AUDIO_FORMAT_DEFAULT:
8672 case AUDIO_FORMAT_PCM_16_BIT:
8673 out->format = AUDIO_FORMAT_PCM_16_BIT;
8674 break;
8675 default:
8676 ALOGE("%s: Unsupported format %#x for Incall Music", __func__,
8677 config->format);
8678 config->format = AUDIO_FORMAT_PCM_16_BIT;
8679 ret = -EINVAL;
8680 goto error_open;
8681 }
8682
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05308683 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008684 if (ret != 0) {
8685 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008686 __func__, ret);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008687 goto error_open;
8688 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008689 } else if (is_single_device_type_equal(&out->device_list,
8690 AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08008691 switch (config->sample_rate) {
8692 case 0:
8693 out->sample_rate = AFE_PROXY_SAMPLING_RATE;
8694 break;
8695 case 8000:
8696 case 16000:
8697 case 48000:
8698 out->sample_rate = config->sample_rate;
8699 break;
8700 default:
8701 ALOGE("%s: Unsupported sampling rate %d for Telephony TX", __func__,
8702 config->sample_rate);
8703 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
8704 ret = -EINVAL;
8705 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008706 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008707 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8708 switch (config->channel_mask) {
8709 case AUDIO_CHANNEL_NONE:
8710 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8711 break;
8712 case AUDIO_CHANNEL_OUT_STEREO:
8713 out->channel_mask = config->channel_mask;
8714 break;
8715 default:
8716 ALOGE("%s: Unsupported channel mask %#x for Telephony TX", __func__,
8717 config->channel_mask);
8718 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8719 ret = -EINVAL;
8720 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008721 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008722 switch (config->format) {
8723 case AUDIO_FORMAT_DEFAULT:
8724 out->format = AUDIO_FORMAT_PCM_16_BIT;
8725 break;
8726 case AUDIO_FORMAT_PCM_16_BIT:
8727 out->format = config->format;
8728 break;
8729 default:
8730 ALOGE("%s: Unsupported format %#x for Telephony TX", __func__,
8731 config->format);
8732 config->format = AUDIO_FORMAT_PCM_16_BIT;
8733 ret = -EINVAL;
8734 break;
8735 }
8736 if (ret != 0)
8737 goto error_open;
8738
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008739 out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
8740 out->config = pcm_config_afe_proxy_playback;
Aalique Grahame22e49102018-12-18 14:23:57 -08008741 out->config.rate = out->sample_rate;
8742 out->config.channels =
8743 audio_channel_count_from_out_mask(out->channel_mask);
8744 out->config.format = pcm_format_from_audio_format(out->format);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008745 adev->voice_tx_output = out;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008746 } else {
Ashish Jain058165c2016-09-28 23:18:48 +05308747 unsigned int channels = 0;
8748 /*Update config params to default if not set by the caller*/
8749 if (config->sample_rate == 0)
8750 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8751 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8752 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8753 if (config->format == AUDIO_FORMAT_DEFAULT)
8754 config->format = AUDIO_FORMAT_PCM_16_BIT;
8755
8756 channels = audio_channel_count_from_out_mask(out->channel_mask);
8757
Varun Balaraje49253e2017-07-06 19:48:56 +05308758 if (out->flags & AUDIO_OUTPUT_FLAG_INTERACTIVE) {
8759 out->usecase = get_interactive_usecase(adev);
8760 out->config = pcm_config_low_latency;
8761 } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
Ashish Jain83a6cc22016-06-28 14:34:17 +05308762 out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07008763 out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
8764 out->flags);
8765 out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
Haynes Mathew George16081042017-05-31 17:16:49 -07008766 } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8767 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8768 out->config = pcm_config_mmap_playback;
8769 out->stream.start = out_start;
8770 out->stream.stop = out_stop;
8771 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8772 out->stream.get_mmap_position = out_get_mmap_position;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308773 } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8774 out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008775 out->hal_output_suspend_supported =
8776 property_get_bool("vendor.audio.hal.output.suspend.supported", false);
8777 out->dynamic_pm_qos_config_supported =
8778 property_get_bool("vendor.audio.hal.dynamic.qos.config.supported", false);
8779 if (!out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08008780 ALOGI("%s: dynamic qos voting not enabled for platform", __func__);
8781 } else {
8782 ALOGI("%s: dynamic qos voting enabled for platform", __func__);
8783 //the mixer path will be a string similar to "low-latency-playback resume"
8784 strlcpy(out->pm_qos_mixer_path, use_case_table[out->usecase], MAX_MIXER_PATH_LEN);
8785 strlcat(out->pm_qos_mixer_path,
8786 " resume", MAX_MIXER_PATH_LEN);
8787 ALOGI("%s: created %s pm_qos_mixer_path" , __func__,
8788 out->pm_qos_mixer_path);
8789 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308790 out->config = pcm_config_low_latency;
8791 } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
8792 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
8793 out->config = pcm_config_deep_buffer;
Ashish Jain058165c2016-09-28 23:18:48 +05308794 out->config.period_size = get_output_period_size(config->sample_rate, out->format,
8795 channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
8796 if (out->config.period_size <= 0) {
8797 ALOGE("Invalid configuration period size is not valid");
8798 ret = -EINVAL;
8799 goto error_open;
8800 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008801 } else if (flags & AUDIO_OUTPUT_FLAG_TTS) {
8802 out->usecase = USECASE_AUDIO_PLAYBACK_TTS;
8803 out->config = pcm_config_deep_buffer;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008804 } else if (config->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL) {
8805 out->usecase = USECASE_AUDIO_PLAYBACK_WITH_HAPTICS;
8806 out->config = pcm_config_haptics_audio;
8807 if (force_haptic_path)
8808 adev->haptics_config = pcm_config_haptics_audio;
8809 else
8810 adev->haptics_config = pcm_config_haptics;
8811
Meng Wangd08ce322020-04-02 08:59:20 +08008812 channels =
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008813 audio_channel_count_from_out_mask(out->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL);
8814
8815 if (force_haptic_path) {
8816 out->config.channels = 1;
8817 adev->haptics_config.channels = 1;
8818 } else
8819 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 -08008820 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008821 ret = audio_extn_auto_hal_open_output_stream(out);
8822 if (ret) {
8823 ALOGE("%s: Failed to open output stream for bus device", __func__);
8824 ret = -EINVAL;
8825 goto error_open;
8826 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308827 } else {
8828 /* primary path is the default path selected if no other outputs are available/suitable */
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008829 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8830 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308831 }
8832 out->hal_ip_format = format = out->format;
8833 out->config.format = hal_format_to_pcm(out->hal_ip_format);
8834 out->hal_op_format = pcm_format_to_hal(out->config.format);
8835 out->bit_width = format_to_bitwidth_table[out->hal_op_format] << 3;
8836 out->config.rate = config->sample_rate;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008837 out->sample_rate = out->config.rate;
Ashish Jain058165c2016-09-28 23:18:48 +05308838 out->config.channels = channels;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308839 if (out->hal_ip_format != out->hal_op_format) {
8840 uint32_t buffer_size = out->config.period_size *
8841 format_to_bitwidth_table[out->hal_op_format] *
8842 out->config.channels;
8843 out->convert_buffer = calloc(1, buffer_size);
8844 if (out->convert_buffer == NULL){
8845 ALOGE("Allocation failed for convert buffer for size %d",
8846 out->compr_config.fragment_size);
8847 ret = -ENOMEM;
8848 goto error_open;
8849 }
8850 ALOGD("Convert buffer allocated of size %d", buffer_size);
8851 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008852 }
8853
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008854 ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags: %x usecase %d",
8855 __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags, out->usecase);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308856
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008857 /* TODO remove this hardcoding and check why width is zero*/
8858 if (out->bit_width == 0)
8859 out->bit_width = 16;
Dhananjay Kumard6d32152016-10-13 16:11:03 +05308860 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008861 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008862 &out->device_list, out->flags,
8863 out->hal_op_format, out->sample_rate,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05308864 out->bit_width, out->channel_mask, out->profile,
Manish Dewangan837dc462015-05-27 10:17:41 +05308865 &out->app_type_cfg);
Aalique Grahame6e763712019-01-31 16:18:17 -08008866 if ((out->usecase == (audio_usecase_t)(GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary))) ||
Haynes Mathew Georgebf143712013-12-03 13:02:53 -08008867 (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
8868 /* Ensure the default output is not selected twice */
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008869 if(adev->primary_output == NULL)
8870 adev->primary_output = out;
8871 else {
8872 ALOGE("%s: Primary output is already opened", __func__);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008873 ret = -EEXIST;
8874 goto error_open;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008875 }
8876 }
8877
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008878 /* Check if this usecase is already existing */
8879 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella7ce05352014-04-17 20:00:41 -07008880 if ((get_usecase_from_list(adev, out->usecase) != NULL) &&
8881 (out->usecase != USECASE_COMPRESS_VOIP_CALL)) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008882 ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008883 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008884 ret = -EEXIST;
8885 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008886 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008887
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008888 pthread_mutex_unlock(&adev->lock);
8889
8890 out->stream.common.get_sample_rate = out_get_sample_rate;
8891 out->stream.common.set_sample_rate = out_set_sample_rate;
8892 out->stream.common.get_buffer_size = out_get_buffer_size;
8893 out->stream.common.get_channels = out_get_channels;
8894 out->stream.common.get_format = out_get_format;
8895 out->stream.common.set_format = out_set_format;
8896 out->stream.common.standby = out_standby;
8897 out->stream.common.dump = out_dump;
8898 out->stream.common.set_parameters = out_set_parameters;
8899 out->stream.common.get_parameters = out_get_parameters;
8900 out->stream.common.add_audio_effect = out_add_audio_effect;
8901 out->stream.common.remove_audio_effect = out_remove_audio_effect;
8902 out->stream.get_latency = out_get_latency;
8903 out->stream.set_volume = out_set_volume;
Aalique Grahame22e49102018-12-18 14:23:57 -08008904#ifdef NO_AUDIO_OUT
8905 out->stream.write = out_write_for_no_output;
8906#else
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008907 out->stream.write = out_write;
Aalique Grahame22e49102018-12-18 14:23:57 -08008908#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008909 out->stream.get_render_position = out_get_render_position;
8910 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008911 out->stream.get_presentation_position = out_get_presentation_position;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008912
Haynes Mathew George16081042017-05-31 17:16:49 -07008913 if (out->realtime)
8914 out->af_period_multiplier = af_period_multiplier;
8915 else
8916 out->af_period_multiplier = 1;
8917
Andy Hunga1f48fa2019-07-01 18:14:53 -07008918 out->kernel_buffer_size = out->config.period_size * out->config.period_count;
8919
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008920 out->standby = 1;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008921 out->volume_l = PLAYBACK_GAIN_MAX;
8922 out->volume_r = PLAYBACK_GAIN_MAX;
Eric Laurenta9024de2013-04-04 09:19:12 -07008923 /* out->muted = false; by calloc() */
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008924 /* out->written = 0; by calloc() */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008925
8926 config->format = out->stream.common.get_format(&out->stream.common);
8927 config->channel_mask = out->stream.common.get_channels(&out->stream.common);
8928 config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
Naresh Tanniru04f71882018-06-26 17:46:22 +05308929 register_format(out->format, out->supported_formats);
8930 register_channel_mask(out->channel_mask, out->supported_channel_masks);
8931 register_sample_rate(out->sample_rate, out->supported_sample_rates);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008932
Dechen Chai22768452021-07-30 09:29:16 +05308933#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08008934 out->error_log = error_log_create(
8935 ERROR_LOG_ENTRIES,
8936 1000000000 /* aggregate consecutive identical errors within one second in ns */);
Dechen Chai22768452021-07-30 09:29:16 +05308937#endif
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308938 /*
8939 By locking output stream before registering, we allow the callback
8940 to update stream's state only after stream's initial state is set to
8941 adev state.
8942 */
8943 lock_output_stream(out);
8944 audio_extn_snd_mon_register_listener(out, out_snd_mon_cb);
8945 pthread_mutex_lock(&adev->lock);
8946 out->card_status = adev->card_status;
8947 pthread_mutex_unlock(&adev->lock);
8948 pthread_mutex_unlock(&out->lock);
8949
Aalique Grahame22e49102018-12-18 14:23:57 -08008950 stream_app_type_cfg_init(&out->app_type_cfg);
8951
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008952 *stream_out = &out->stream;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308953 ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
vivek mehta0ea887a2015-08-26 14:01:20 -07008954 use_case_table[out->usecase]);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008955
8956 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
8957 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
8958 popcount(out->channel_mask), out->playback_started);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008959 /* setup a channel for client <--> adsp communication for stream events */
Manish Dewangan21a850a2017-08-14 12:03:55 +05308960 is_direct_passthough = audio_extn_passthru_is_direct_passthrough(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008961 if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Naresh Tanniru85819452017-05-04 18:55:45 -07008962 (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) ||
Gangadhar Sb0210342019-02-22 17:39:41 +05308963 audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform) ||
8964 (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false))) {
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008965 hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
8966 out->usecase, PCM_PLAYBACK);
8967 hdlr_stream_cfg.flags = out->flags;
8968 hdlr_stream_cfg.type = PCM_PLAYBACK;
8969 ret = audio_extn_adsp_hdlr_stream_open(&out->adsp_hdlr_stream_handle,
8970 &hdlr_stream_cfg);
8971 if (ret) {
8972 ALOGE("%s: adsp_hdlr_stream_open failed %d",__func__, ret);
8973 out->adsp_hdlr_stream_handle = NULL;
8974 }
8975 }
Gangadhar Sb0210342019-02-22 17:39:41 +05308976 ip_hdlr_stream = audio_extn_ip_hdlr_intf_supported(config->format,
8977 is_direct_passthough, false);
8978 ip_hdlr_dev = audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform);
8979 if (ip_hdlr_stream || ip_hdlr_dev ) {
Vidyakumar Athota2062f912017-06-27 14:46:15 -07008980 ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL, adev, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07008981 if (ret < 0) {
8982 ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d",__func__, ret);
8983 out->ip_hdlr_handle = NULL;
8984 }
8985 }
Derek Chenf939fb72018-11-13 13:34:41 -08008986
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07008987 ret = io_streams_map_insert(adev, &out->stream.common,
8988 out->handle, AUDIO_PATCH_HANDLE_NONE);
8989 if (ret != 0)
8990 goto error_open;
8991
Susan Wang6dd13092021-01-25 10:27:11 -05008992 out->out_ctxt.output = out;
Derek Chenf939fb72018-11-13 13:34:41 -08008993
8994 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -05008995 list_add_tail(&adev->active_outputs_list, &out->out_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -08008996 pthread_mutex_unlock(&adev->lock);
8997
Eric Laurent994a6932013-07-17 11:51:42 -07008998 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008999 return 0;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07009000
9001error_open:
Ashish Jain83a6cc22016-06-28 14:34:17 +05309002 if (out->convert_buffer)
9003 free(out->convert_buffer);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07009004 free(out);
9005 *stream_out = NULL;
9006 ALOGD("%s: exit: ret %d", __func__, ret);
9007 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009008}
9009
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05309010void adev_close_output_stream(struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009011 struct audio_stream_out *stream)
9012{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009013 struct stream_out *out = (struct stream_out *)stream;
9014 struct audio_device *adev = out->dev;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009015 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009016
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009017 ALOGD("%s: enter:stream_handle(%s)",__func__, use_case_table[out->usecase]);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309018
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009019 io_streams_map_remove(adev, out->handle);
9020
Susan Wang6dd13092021-01-25 10:27:11 -05009021 // remove out_ctxt early to prevent the stream
9022 // being opened in a race condition
9023 pthread_mutex_lock(&adev->lock);
9024 list_remove(&out->out_ctxt.list);
9025 pthread_mutex_unlock(&adev->lock);
9026
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05309027 // must deregister from sndmonitor first to prevent races
9028 // between the callback and close_stream
9029 audio_extn_snd_mon_unregister_listener(out);
9030
Ben Rombergerd771a7c2017-02-22 18:05:17 -08009031 /* close adsp hdrl session before standby */
9032 if (out->adsp_hdlr_stream_handle) {
9033 ret = audio_extn_adsp_hdlr_stream_close(out->adsp_hdlr_stream_handle);
9034 if (ret)
9035 ALOGE("%s: adsp_hdlr_stream_close failed %d",__func__, ret);
9036 out->adsp_hdlr_stream_handle = NULL;
9037 }
9038
Manish Dewangan21a850a2017-08-14 12:03:55 +05309039 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07009040 audio_extn_ip_hdlr_intf_deinit(out->ip_hdlr_handle);
9041 out->ip_hdlr_handle = NULL;
9042 }
9043
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009044 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309045 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009046 ret = voice_extn_compress_voip_close_output_stream(&stream->common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309047 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309048 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009049 if(ret != 0)
9050 ALOGE("%s: Compress voip output cannot be closed, error:%d",
9051 __func__, ret);
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009052 } else
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009053 out_standby(&stream->common);
9054
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07009055 if (is_offload_usecase(out->usecase)) {
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08009056 audio_extn_dts_remove_state_notifier_node(out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009057 destroy_offload_callback_thread(out);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07009058 free_offload_usecase(adev, out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009059 if (out->compr_config.codec != NULL)
9060 free(out->compr_config.codec);
9061 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009062
Zhou Songbaddf9f2020-11-20 13:57:39 +08009063 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05309064
Varun Balaraje49253e2017-07-06 19:48:56 +05309065 if (is_interactive_usecase(out->usecase))
9066 free_interactive_usecase(adev, out->usecase);
9067
Ashish Jain83a6cc22016-06-28 14:34:17 +05309068 if (out->convert_buffer != NULL) {
9069 free(out->convert_buffer);
9070 out->convert_buffer = NULL;
9071 }
9072
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009073 if (adev->voice_tx_output == out)
9074 adev->voice_tx_output = NULL;
9075
Dechen Chai22768452021-07-30 09:29:16 +05309076#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08009077 error_log_destroy(out->error_log);
9078 out->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +05309079#endif
Dhanalakshmi Siddani6c3d0992017-01-16 16:52:33 +05309080 if (adev->primary_output == out)
9081 adev->primary_output = NULL;
9082
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07009083 pthread_cond_destroy(&out->cond);
9084 pthread_mutex_destroy(&out->lock);
Weiyin Jiang280ea742020-09-08 20:28:22 +08009085 pthread_mutex_destroy(&out->pre_lock);
9086 pthread_mutex_destroy(&out->latch_lock);
9087 pthread_mutex_destroy(&out->position_query_lock);
Derek Chenf939fb72018-11-13 13:34:41 -08009088
9089 pthread_mutex_lock(&adev->lock);
Zhenlin Lian4f947842022-05-14 15:50:52 +05309090 clear_devices(&out->device_list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009091 free(stream);
Derek Chenf939fb72018-11-13 13:34:41 -08009092 pthread_mutex_unlock(&adev->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07009093 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009094}
9095
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05009096void in_set_power_policy(uint8_t enable)
9097{
9098 struct listnode *node;
9099
9100 ALOGD("%s: Enter, state %d", __func__, enable);
9101
9102 pthread_mutex_lock(&adev->lock);
9103 adev->in_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_OFFLINE;
9104 pthread_mutex_unlock(&adev->lock);
9105
9106 if (!enable) {
9107 list_for_each(node, &adev->active_inputs_list) {
9108 streams_input_ctxt_t *in_ctxt = node_to_item(node,
9109 streams_input_ctxt_t,
9110 list);
9111 struct stream_in *in = in_ctxt->input;
9112 in_standby(&in->stream.common);
9113 }
9114 }
9115
9116 ALOGD("%s: Exit", __func__);
9117}
9118
9119void out_set_power_policy(uint8_t enable)
9120{
9121 struct listnode *node;
9122
9123 ALOGD("%s: Enter, state %d", __func__, enable);
9124
9125 pthread_mutex_lock(&adev->lock);
E V Ravi317be872022-02-23 19:08:15 +05309126 adev->out_power_policy = enable ? POWER_POLICY_STATUS_ONLINE : POWER_POLICY_STATUS_OFFLINE;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -05009127 pthread_mutex_unlock(&adev->lock);
9128
9129 if (!enable) {
9130 list_for_each(node, &adev->active_outputs_list) {
9131 streams_output_ctxt_t *out_ctxt = node_to_item(node,
9132 streams_output_ctxt_t,
9133 list);
9134 struct stream_out *out = out_ctxt->output;
9135 out_on_error(&out->stream.common);
9136 }
9137 }
9138
9139 ALOGD("%s: Exit", __func__);
9140}
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009141static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
9142{
9143 struct audio_device *adev = (struct audio_device *)dev;
9144 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009145 char value[32];
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009146 int val;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009147 int ret;
9148 int status = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08009149 bool a2dp_reconfig = false;
Zhou Songd6d71752019-05-21 18:08:51 +08009150 struct listnode *node;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009151 int controller = -1, stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009152
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009153 ALOGD("%s: enter: %s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009154 parms = str_parms_create_str(kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009155
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309156 if (!parms)
9157 goto error;
Naresh Tanniru4c630392014-05-12 01:05:52 +05309158
Derek Chen6f293672019-04-01 01:40:24 -07009159 /* notify adev and input/output streams on the snd card status */
9160 adev_snd_mon_cb((void *)adev, parms);
9161
Weiyin Jiang24f55292020-12-22 14:35:46 +08009162 ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
9163 if (ret >= 0) {
9164 list_for_each(node, &adev->active_outputs_list) {
9165 streams_output_ctxt_t *out_ctxt = node_to_item(node,
9166 streams_output_ctxt_t,
9167 list);
9168 out_snd_mon_cb((void *)out_ctxt->output, parms);
9169 }
Derek Chen6f293672019-04-01 01:40:24 -07009170
Weiyin Jiang24f55292020-12-22 14:35:46 +08009171 list_for_each(node, &adev->active_inputs_list) {
9172 streams_input_ctxt_t *in_ctxt = node_to_item(node,
9173 streams_input_ctxt_t,
9174 list);
9175 in_snd_mon_cb((void *)in_ctxt->input, parms);
9176 }
Derek Chen6f293672019-04-01 01:40:24 -07009177 }
9178
Zhou Songd6d71752019-05-21 18:08:51 +08009179 pthread_mutex_lock(&adev->lock);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309180 ret = str_parms_get_str(parms, "BT_SCO", value, sizeof(value));
9181 if (ret >= 0) {
9182 /* When set to false, HAL should disable EC and NS */
Zhou Songd6d71752019-05-21 18:08:51 +08009183 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0){
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309184 adev->bt_sco_on = true;
Shalini Manjunatha3a2e06e2021-02-01 12:23:49 +05309185 /*
9186 * When ever BT_SCO=ON arrives, make sure to route
9187 * all use cases to SCO device, otherwise due to delay in
9188 * BT_SCO=ON and lack of synchronization with create audio patch
9189 * request for SCO device, some times use case not routed properly to
9190 * SCO device
9191 */
9192 struct audio_usecase *usecase;
9193 struct listnode *node;
9194 list_for_each(node, &adev->usecase_list) {
9195 usecase = node_to_item(node, struct audio_usecase, list);
Anver sadhiquef0efca32021-09-03 15:25:44 +05309196 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05309197 (!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 +05309198 ALOGD("BT_SCO ON, switch all in use case to it");
9199 select_devices(adev, usecase->id);
9200 }
Mingshu Pangef517202021-04-22 10:35:00 +08009201 if (usecase->stream.out && (usecase->type == PCM_PLAYBACK ||
9202 usecase->type == VOICE_CALL) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05309203 (!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 +05309204 ALOGD("BT_SCO ON, switch all out use case to it");
9205 select_devices(adev, usecase->id);
9206 }
9207 }
9208 }
9209 else {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05309210 adev->bt_sco_on = false;
Zhou Songd6d71752019-05-21 18:08:51 +08009211 audio_extn_sco_reset_configuration();
Kunlei Zhangd96af8f2019-08-27 16:33:29 +08009212 }
9213 }
9214
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009215 status = voice_set_parameters(adev, parms);
9216 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009217 goto done;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009218
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009219 status = platform_set_parameters(adev->platform, parms);
9220 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009221 goto done;
9222
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009223 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
9224 if (ret >= 0) {
Vicky Sehrawate240e5d2014-08-12 17:17:04 -07009225 /* When set to false, HAL should disable EC and NS */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009226 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9227 adev->bluetooth_nrec = true;
9228 else
9229 adev->bluetooth_nrec = false;
9230 }
9231
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009232 ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
9233 if (ret >= 0) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009234 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9235 adev->screen_off = false;
9236 else
9237 adev->screen_off = true;
Quinn Male70f20f32019-06-26 16:50:26 -07009238 audio_extn_sound_trigger_update_screen_status(adev->screen_off);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009239 }
9240
Eric Laurent4b084132018-10-19 17:33:43 -07009241 ret = str_parms_get_int(parms, "rotation", &val);
9242 if (ret >= 0) {
9243 bool reverse_speakers = false;
9244 int camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9245 switch (val) {
9246 // FIXME: note that the code below assumes that the speakers are in the correct placement
9247 // relative to the user when the device is rotated 90deg from its default rotation. This
9248 // assumption is device-specific, not platform-specific like this code.
9249 case 270:
9250 reverse_speakers = true;
9251 camera_rotation = CAMERA_ROTATION_INVERT_LANDSCAPE;
9252 break;
9253 case 0:
9254 case 180:
9255 camera_rotation = CAMERA_ROTATION_PORTRAIT;
9256 break;
9257 case 90:
9258 camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9259 break;
9260 default:
9261 ALOGE("%s: unexpected rotation of %d", __func__, val);
9262 status = -EINVAL;
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009263 }
Eric Laurent4b084132018-10-19 17:33:43 -07009264 if (status == 0) {
9265 // check and set swap
9266 // - check if orientation changed and speaker active
9267 // - set rotation and cache the rotation value
9268 adev->camera_orientation =
9269 (adev->camera_orientation & ~CAMERA_ROTATION_MASK) | camera_rotation;
9270 if (!audio_extn_is_maxx_audio_enabled())
9271 platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
9272 }
9273 }
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009274
Mingming Yin514a8bc2014-07-29 15:22:21 -07009275 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
9276 if (ret >= 0) {
9277 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9278 adev->bt_wb_speech_enabled = true;
9279 else
9280 adev->bt_wb_speech_enabled = false;
9281 }
9282
Zhou Song12c29502019-03-16 10:37:18 +08009283 ret = str_parms_get_str(parms, "bt_swb", value, sizeof(value));
9284 if (ret >= 0) {
9285 val = atoi(value);
9286 adev->swb_speech_mode = val;
9287 }
9288
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009289 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
9290 if (ret >= 0) {
9291 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309292 audio_devices_t device = (audio_devices_t) val;
Zhou Song681350a2017-10-19 16:28:42 +08009293 if (audio_is_output_device(val) &&
9294 (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009295 ALOGV("cache new ext disp type and edid");
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009296 platform_get_controller_stream_from_params(parms, &controller, &stream);
9297 platform_set_ext_display_device_v2(adev->platform, controller, stream);
9298 ret = platform_get_ext_disp_type_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009299 if (ret < 0) {
9300 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Manisha Agarwal2f5ff882018-08-08 17:09:29 +05309301 } else {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009302 platform_cache_edid_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009303 }
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309304 } else if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
vivek mehta344576a2016-04-12 18:56:03 -07009305 /*
9306 * Do not allow AFE proxy port usage by WFD source when USB headset is connected.
9307 * Per AudioPolicyManager, USB device is higher priority than WFD.
9308 * For Voice call over USB headset, voice call audio is routed to AFE proxy ports.
9309 * If WFD use case occupies AFE proxy, it may result unintended behavior while
9310 * starting voice call on USB
9311 */
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009312 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309313 if (ret >= 0)
9314 audio_extn_usb_add_device(device, atoi(value));
9315
Zhou Song6f862822017-11-06 17:27:57 +08009316 if (!audio_extn_usb_is_tunnel_supported()) {
9317 ALOGV("detected USB connect .. disable proxy");
9318 adev->allow_afe_proxy_usage = false;
9319 }
Zhou Song503196b2021-07-23 17:31:05 +08009320 } else if (audio_is_hearing_aid_out_device(device) &&
9321 property_get_bool("persist.vendor.audio.ha_proxy.enabled", false)) {
9322 adev->ha_proxy_enable = true;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009323 }
9324 }
9325
9326 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
9327 if (ret >= 0) {
9328 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309329 audio_devices_t device = (audio_devices_t) val;
Garmond Leunge3b6d482016-10-25 16:48:01 -07009330 /*
9331 * The HDMI / Displayport disconnect handling has been moved to
9332 * audio extension to ensure that its parameters are not
9333 * invalidated prior to updating sysfs of the disconnect event
9334 * Invalidate will be handled by audio_extn_ext_disp_set_parameters()
9335 */
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309336 if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009337 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309338 if (ret >= 0)
9339 audio_extn_usb_remove_device(device, atoi(value));
9340
Zhou Song6f862822017-11-06 17:27:57 +08009341 if (!audio_extn_usb_is_tunnel_supported()) {
9342 ALOGV("detected USB disconnect .. enable proxy");
9343 adev->allow_afe_proxy_usage = true;
9344 }
Zhou Song503196b2021-07-23 17:31:05 +08009345 } else if (audio_is_hearing_aid_out_device(device)) {
9346 adev->ha_proxy_enable = false;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009347 }
9348 }
9349
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009350 audio_extn_qdsp_set_parameters(adev, parms);
Aalique Grahame22e49102018-12-18 14:23:57 -08009351
9352 status = audio_extn_a2dp_set_parameters(parms, &a2dp_reconfig);
Aniket Kumar Lata23300322019-02-20 22:25:30 -08009353 if (status >= 0 && a2dp_reconfig) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309354 struct audio_usecase *usecase;
9355 struct listnode *node;
9356 list_for_each(node, &adev->usecase_list) {
9357 usecase = node_to_item(node, struct audio_usecase, list);
Weiyin Jiangff56ff32020-05-08 14:32:21 +08009358 if ((usecase->stream.out == NULL) || (usecase->type != PCM_PLAYBACK))
9359 continue;
9360
9361 if (is_a2dp_out_device_type(&usecase->device_list)) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309362 ALOGD("reconfigure a2dp... forcing device switch");
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309363 audio_extn_a2dp_set_handoff_mode(true);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309364 ALOGD("Switching to speaker and muting the stream before select_devices");
9365 check_a2dp_restore_l(adev, usecase->stream.out, false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309366 //force device switch to re configure encoder
9367 select_devices(adev, usecase->id);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309368 ALOGD("Unmuting the stream after select_devices");
Zhou Songbaddf9f2020-11-20 13:57:39 +08009369 check_a2dp_restore_l(adev, usecase->stream.out, true);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309370 audio_extn_a2dp_set_handoff_mode(false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309371 break;
Zhou Songd01e7a22020-09-23 22:49:01 +08009372 } else if (is_offload_usecase(usecase->stream.out->usecase)) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009373 pthread_mutex_lock(&usecase->stream.out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08009374 if (usecase->stream.out->a2dp_muted) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009375 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
9376 reassign_device_list(&usecase->stream.out->device_list,
9377 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
9378 check_a2dp_restore_l(adev, usecase->stream.out, true);
9379 break;
9380 }
9381 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309382 }
9383 }
9384 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009385
9386 //handle vr audio setparam
9387 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9388 value, sizeof(value));
9389 if (ret >= 0) {
9390 ALOGI("Setting vr mode to be %s", value);
9391 if (!strncmp(value, "true", 4)) {
9392 adev->vr_audio_mode_enabled = true;
9393 ALOGI("Setting vr mode to true");
9394 } else if (!strncmp(value, "false", 5)) {
9395 adev->vr_audio_mode_enabled = false;
9396 ALOGI("Setting vr mode to false");
9397 } else {
9398 ALOGI("wrong vr mode set");
9399 }
9400 }
9401
Eric Laurent4b084132018-10-19 17:33:43 -07009402 //FIXME: to be replaced by proper video capture properties API
9403 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_CAMERA_FACING, value, sizeof(value));
9404 if (ret >= 0) {
9405 int camera_facing = CAMERA_FACING_BACK;
9406 if (strcmp(value, AUDIO_PARAMETER_VALUE_FRONT) == 0)
9407 camera_facing = CAMERA_FACING_FRONT;
9408 else if (strcmp(value, AUDIO_PARAMETER_VALUE_BACK) == 0)
9409 camera_facing = CAMERA_FACING_BACK;
9410 else {
9411 ALOGW("%s: invalid camera facing value: %s", __func__, value);
9412 goto done;
9413 }
9414 adev->camera_orientation =
9415 (adev->camera_orientation & ~CAMERA_FACING_MASK) | camera_facing;
9416 struct audio_usecase *usecase;
9417 struct listnode *node;
9418 list_for_each(node, &adev->usecase_list) {
9419 usecase = node_to_item(node, struct audio_usecase, list);
9420 struct stream_in *in = usecase->stream.in;
9421 if (usecase->type == PCM_CAPTURE && in != NULL &&
9422 in->source == AUDIO_SOURCE_CAMCORDER && !in->standby) {
9423 select_devices(adev, in->usecase);
9424 }
9425 }
9426 }
9427
Tahir Dawson7fabad42022-06-21 12:37:55 -04009428 audio_extn_auto_hal_set_parameters(adev, parms);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309429 audio_extn_set_parameters(adev, parms);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009430done:
9431 str_parms_destroy(parms);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009432 pthread_mutex_unlock(&adev->lock);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309433error:
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009434 ALOGV("%s: exit with code(%d)", __func__, status);
9435 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009436}
9437
9438static char* adev_get_parameters(const struct audio_hw_device *dev,
9439 const char *keys)
9440{
Sidipotu Ashokaa4fa6a2018-12-21 09:19:26 +05309441 ALOGD("%s:%s", __func__, keys);
9442
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009443 struct audio_device *adev = (struct audio_device *)dev;
9444 struct str_parms *reply = str_parms_create();
9445 struct str_parms *query = str_parms_create_str(keys);
9446 char *str;
Naresh Tannirud7205b62014-06-20 02:54:48 +05309447 char value[256] = {0};
9448 int ret = 0;
9449
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009450 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08009451 if (reply) {
9452 str_parms_destroy(reply);
9453 }
9454 if (query) {
9455 str_parms_destroy(query);
9456 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009457 ALOGE("adev_get_parameters: failed to create query or reply");
9458 return NULL;
9459 }
9460
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009461 //handle vr audio getparam
9462
9463 ret = str_parms_get_str(query,
9464 AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9465 value, sizeof(value));
9466
9467 if (ret >= 0) {
9468 bool vr_audio_enabled = false;
9469 pthread_mutex_lock(&adev->lock);
9470 vr_audio_enabled = adev->vr_audio_mode_enabled;
9471 pthread_mutex_unlock(&adev->lock);
9472
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009473 ALOGV("getting vr mode to %d", vr_audio_enabled);
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009474
9475 if (vr_audio_enabled) {
9476 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9477 "true");
9478 goto exit;
9479 } else {
9480 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9481 "false");
9482 goto exit;
9483 }
9484 }
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009485
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009486 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009487 audio_extn_get_parameters(adev, query, reply);
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -08009488 voice_get_parameters(adev, query, reply);
Aalique Grahame22e49102018-12-18 14:23:57 -08009489 audio_extn_a2dp_get_parameters(query, reply);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009490 platform_get_parameters(adev->platform, query, reply);
justinwengd5395152019-11-04 12:23:09 +08009491 audio_extn_ma_get_parameters(adev, query, reply);
Naresh Tanniru80659832014-06-04 18:17:56 +05309492 pthread_mutex_unlock(&adev->lock);
9493
Naresh Tannirud7205b62014-06-20 02:54:48 +05309494exit:
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009495 str = str_parms_to_str(reply);
9496 str_parms_destroy(query);
9497 str_parms_destroy(reply);
9498
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009499 ALOGV("%s: exit: returns - %s", __func__, str);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009500 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009501}
9502
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009503static int adev_init_check(const struct audio_hw_device *dev __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009504{
9505 return 0;
9506}
9507
9508static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
9509{
Haynes Mathew George5191a852013-09-11 14:19:36 -07009510 int ret;
9511 struct audio_device *adev = (struct audio_device *)dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08009512
9513 audio_extn_extspk_set_voice_vol(adev->extspk, volume);
9514
Haynes Mathew George5191a852013-09-11 14:19:36 -07009515 pthread_mutex_lock(&adev->lock);
9516 /* cache volume */
Shruthi Krishnaace10852013-10-25 14:32:12 -07009517 ret = voice_set_volume(adev, volume);
Haynes Mathew George5191a852013-09-11 14:19:36 -07009518 pthread_mutex_unlock(&adev->lock);
9519 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009520}
9521
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009522static int adev_set_master_volume(struct audio_hw_device *dev __unused,
9523 float volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009524{
9525 return -ENOSYS;
9526}
9527
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009528static int adev_get_master_volume(struct audio_hw_device *dev __unused,
9529 float *volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009530{
9531 return -ENOSYS;
9532}
9533
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009534static int adev_set_master_mute(struct audio_hw_device *dev __unused,
9535 bool muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009536{
9537 return -ENOSYS;
9538}
9539
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009540static int adev_get_master_mute(struct audio_hw_device *dev __unused,
9541 bool *muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009542{
9543 return -ENOSYS;
9544}
9545
9546static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
9547{
9548 struct audio_device *adev = (struct audio_device *)dev;
Garmond Leung5fd0b552018-04-17 11:56:12 -07009549 struct listnode *node;
9550 struct audio_usecase *usecase = NULL;
9551 int ret = 0;
kunleizdc4af9d2017-05-04 12:15:35 +08009552
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009553 pthread_mutex_lock(&adev->lock);
9554 if (adev->mode != mode) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309555 ALOGD("%s: mode %d , prev_mode %d \n", __func__, mode , adev->mode);
9556 adev->prev_mode = adev->mode; /* prev_mode is kept to handle voip concurrency*/
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009557 adev->mode = mode;
Weiyin Jiang96b96f72020-09-22 16:48:19 +08009558 if (mode == AUDIO_MODE_CALL_SCREEN) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309559 adev->current_call_output = adev->primary_output;
9560 voice_start_call(adev);
9561 } else if (voice_is_in_call_or_call_screen(adev) &&
Kunlei Zhang1d5c7f22019-05-21 14:25:57 +08009562 (mode == AUDIO_MODE_NORMAL ||
9563 (mode == AUDIO_MODE_IN_COMMUNICATION && !voice_is_call_state_active(adev)))) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07009564 list_for_each(node, &adev->usecase_list) {
9565 usecase = node_to_item(node, struct audio_usecase, list);
9566 if (usecase->type == VOICE_CALL)
9567 break;
9568 }
9569 if (usecase &&
9570 audio_is_usb_out_device(usecase->out_snd_device & AUDIO_DEVICE_OUT_ALL_USB)) {
9571 ret = audio_extn_usb_check_and_set_svc_int(usecase,
9572 true);
9573 if (ret != 0) {
9574 /* default service interval was successfully updated,
9575 reopen USB backend with new service interval */
9576 check_usecases_codec_backend(adev,
9577 usecase,
9578 usecase->out_snd_device);
9579 }
9580 }
9581
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009582 voice_stop_call(adev);
Banajit Goswami20cdd212015-09-11 01:11:30 -07009583 platform_set_gsm_mode(adev->platform, false);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009584 adev->current_call_output = NULL;
kunleizdc4af9d2017-05-04 12:15:35 +08009585 // restore device for other active usecases after stop call
9586 list_for_each(node, &adev->usecase_list) {
9587 usecase = node_to_item(node, struct audio_usecase, list);
9588 select_devices(adev, usecase->id);
9589 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009590 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009591 }
9592 pthread_mutex_unlock(&adev->lock);
9593 return 0;
9594}
9595
9596static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
9597{
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009598 int ret;
Aalique Grahame22e49102018-12-18 14:23:57 -08009599 struct audio_device *adev = (struct audio_device *)dev;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009600
9601 pthread_mutex_lock(&adev->lock);
Vidyakumar Athota2850d532013-11-19 16:02:12 -08009602 ALOGD("%s state %d\n", __func__, state);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009603 ret = voice_set_mic_mute((struct audio_device *)dev, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009604
Derek Chend2530072014-11-24 12:39:14 -08009605 if (adev->ext_hw_plugin)
9606 ret = audio_extn_ext_hw_plugin_set_mic_mute(adev->ext_hw_plugin, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009607
9608 adev->mic_muted = state;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009609 pthread_mutex_unlock(&adev->lock);
9610
9611 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009612}
9613
9614static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
9615{
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009616 *state = voice_get_mic_mute((struct audio_device *)dev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009617 return 0;
9618}
9619
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009620static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009621 const struct audio_config *config)
9622{
Avinash Chandrad7296d42021-08-04 15:07:47 +05309623 bool is_usb_hifi = IS_USB_HIFI;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009624 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009625
Aalique Grahame22e49102018-12-18 14:23:57 -08009626 /* Don't know if USB HIFI in this context so use true to be conservative */
9627 if (check_input_parameters(config->sample_rate, config->format, channel_count,
Avinash Chandrad7296d42021-08-04 15:07:47 +05309628 is_usb_hifi) != 0)
Aalique Grahame22e49102018-12-18 14:23:57 -08009629 return 0;
9630
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009631 return get_input_buffer_size(config->sample_rate, config->format, channel_count,
9632 false /* is_low_latency: since we don't know, be conservative */);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009633}
9634
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009635static bool adev_input_allow_hifi_record(struct audio_device *adev,
9636 audio_devices_t devices,
9637 audio_input_flags_t flags,
9638 audio_source_t source) {
9639 const bool allowed = true;
9640
9641 if (!audio_is_usb_in_device(devices))
9642 return !allowed;
9643
9644 switch (flags) {
9645 case AUDIO_INPUT_FLAG_NONE:
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009646 break;
Haynes Mathew George59862182017-10-24 16:23:57 -07009647 case AUDIO_INPUT_FLAG_FAST: // disallow hifi record for FAST as
9648 // it affects RTD numbers over USB
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009649 default:
9650 return !allowed;
9651 }
9652
9653 switch (source) {
9654 case AUDIO_SOURCE_DEFAULT:
9655 case AUDIO_SOURCE_MIC:
9656 case AUDIO_SOURCE_UNPROCESSED:
9657 break;
9658 default:
9659 return !allowed;
9660 }
9661
9662 switch (adev->mode) {
9663 case 0:
9664 break;
9665 default:
9666 return !allowed;
9667 }
9668
9669 return allowed;
9670}
9671
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009672static int adev_update_voice_comm_input_stream(struct stream_in *in,
9673 struct audio_config *config)
9674{
9675 bool valid_rate = (config->sample_rate == 8000 ||
9676 config->sample_rate == 16000 ||
9677 config->sample_rate == 32000 ||
9678 config->sample_rate == 48000);
9679 bool valid_ch = audio_channel_count_from_in_mask(in->channel_mask) == 1;
9680
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009681 if(!voice_extn_is_compress_voip_supported()) {
kunleiz28c73e72019-03-27 17:24:04 +08009682 if (valid_rate && valid_ch) {
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009683 in->usecase = USECASE_AUDIO_RECORD_VOIP;
9684 in->config = default_pcm_config_voip_copp;
9685 in->config.period_size = VOIP_IO_BUF_SIZE(in->sample_rate,
9686 DEFAULT_VOIP_BUF_DURATION_MS,
9687 DEFAULT_VOIP_BIT_DEPTH_BYTE)/2;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009688 } else {
9689 ALOGW("%s No valid input in voip, use defaults"
9690 "sample rate %u, channel mask 0x%X",
9691 __func__, config->sample_rate, in->channel_mask);
9692 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009693 in->config.rate = config->sample_rate;
9694 in->sample_rate = config->sample_rate;
9695 } else {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009696 //XXX needed for voice_extn_compress_voip_open_input_stream
9697 in->config.rate = config->sample_rate;
9698 if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
Shalini Manjunathaa763cc42019-08-23 15:13:46 +05309699 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009700 voice_extn_compress_voip_is_active(in->dev)) &&
9701 (voice_extn_compress_voip_is_format_supported(in->format)) &&
9702 valid_rate && valid_ch) {
9703 voice_extn_compress_voip_open_input_stream(in);
9704 // update rate entries to match config from AF
9705 in->config.rate = config->sample_rate;
9706 in->sample_rate = config->sample_rate;
9707 } else {
9708 ALOGW("%s compress voip not active, use defaults", __func__);
9709 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009710 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009711 return 0;
9712}
9713
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009714static int adev_open_input_stream(struct audio_hw_device *dev,
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07009715 audio_io_handle_t handle,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009716 audio_devices_t devices,
9717 struct audio_config *config,
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009718 struct audio_stream_in **stream_in,
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309719 audio_input_flags_t flags,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009720 const char *address,
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009721 audio_source_t source)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009722{
9723 struct audio_device *adev = (struct audio_device *)dev;
9724 struct stream_in *in;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08009725 int ret = 0, buffer_size, frame_size;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009726 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009727 bool is_low_latency = false;
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +05309728 bool channel_mask_updated = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009729 bool is_usb_dev = audio_is_usb_in_device(devices);
9730 bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
9731 devices,
9732 flags,
9733 source);
Andy Hung94320602018-10-29 18:31:12 -07009734 ALOGV("%s: enter: flags %#x, is_usb_dev %d, may_use_hifi_record %d,"
9735 " sample_rate %u, channel_mask %#x, format %#x",
9736 __func__, flags, is_usb_dev, may_use_hifi_record,
9737 config->sample_rate, config->channel_mask, config->format);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309738
kunleizdff872d2018-08-20 14:40:33 +08009739 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08009740 is_usb_dev = false;
9741 devices = AUDIO_DEVICE_IN_BUILTIN_MIC;
9742 ALOGW("%s: ignore set device to non existing USB card, use input device(%#x)",
9743 __func__, devices);
9744 }
9745
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009746 *stream_in = NULL;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009747
9748 if (!(is_usb_dev && may_use_hifi_record)) {
9749 if (config->sample_rate == 0)
9750 config->sample_rate = 48000;
9751 if (config->channel_mask == AUDIO_CHANNEL_NONE)
9752 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9753 if (config->format == AUDIO_FORMAT_DEFAULT)
9754 config->format = AUDIO_FORMAT_PCM_16_BIT;
9755
9756 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
9757
Aalique Grahame22e49102018-12-18 14:23:57 -08009758 if (check_input_parameters(config->sample_rate, config->format, channel_count,
9759 false) != 0)
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009760 return -EINVAL;
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05309761 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009762
9763 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009764
9765 if (!in) {
9766 ALOGE("failed to allocate input stream");
9767 return -ENOMEM;
9768 }
9769
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309770 ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05309771 stream_handle(%p) io_handle(%d) source(%d) format %x",__func__, config->sample_rate,
9772 config->channel_mask, devices, &in->stream, handle, source, config->format);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009773 pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07009774 pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009775
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009776 in->stream.common.get_sample_rate = in_get_sample_rate;
9777 in->stream.common.set_sample_rate = in_set_sample_rate;
9778 in->stream.common.get_buffer_size = in_get_buffer_size;
9779 in->stream.common.get_channels = in_get_channels;
9780 in->stream.common.get_format = in_get_format;
9781 in->stream.common.set_format = in_set_format;
9782 in->stream.common.standby = in_standby;
9783 in->stream.common.dump = in_dump;
9784 in->stream.common.set_parameters = in_set_parameters;
9785 in->stream.common.get_parameters = in_get_parameters;
9786 in->stream.common.add_audio_effect = in_add_audio_effect;
9787 in->stream.common.remove_audio_effect = in_remove_audio_effect;
9788 in->stream.set_gain = in_set_gain;
9789 in->stream.read = in_read;
9790 in->stream.get_input_frames_lost = in_get_input_frames_lost;
Aalique Grahame22e49102018-12-18 14:23:57 -08009791 in->stream.get_capture_position = in_get_capture_position;
Naresh Tannirudcb47c52018-06-25 16:23:32 +05309792 in->stream.get_active_microphones = in_get_active_microphones;
Paul McLeana50b7332018-12-17 08:24:21 -07009793 in->stream.set_microphone_direction = in_set_microphone_direction;
9794 in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
juyuchendb308c22019-01-21 11:57:17 -07009795 in->stream.update_sink_metadata = in_update_sink_metadata;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009796
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009797 list_init(&in->device_list);
9798 update_device_list(&in->device_list, devices, address, true);
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009799 in->source = source;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009800 in->dev = adev;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009801 in->standby = 1;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009802 in->capture_handle = handle;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07009803 in->flags = flags;
Haynes Mathew George46740472017-10-27 18:40:12 -07009804 in->bit_width = 16;
9805 in->af_period_multiplier = 1;
justinweng20fb6d82019-02-21 18:49:00 -07009806 in->direction = MIC_DIRECTION_UNSPECIFIED;
9807 in->zoom = 0;
Carter Hsu2e429db2019-05-14 18:50:52 +08009808 list_init(&in->aec_list);
9809 list_init(&in->ns_list);
Phil Burkd898ba62019-06-20 12:49:01 -07009810 in->mmap_shared_memory_fd = -1; // not open
Haynes Mathew George46740472017-10-27 18:40:12 -07009811
Andy Hung94320602018-10-29 18:31:12 -07009812 ALOGV("%s: source %d, config->channel_mask %#x", __func__, source, config->channel_mask);
Aalique Grahame22e49102018-12-18 14:23:57 -08009813 if (source == AUDIO_SOURCE_VOICE_UPLINK ||
9814 source == AUDIO_SOURCE_VOICE_DOWNLINK) {
9815 /* Force channel config requested to mono if incall
9816 record is being requested for only uplink/downlink */
9817 if (config->channel_mask != AUDIO_CHANNEL_IN_MONO) {
9818 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9819 ret = -EINVAL;
9820 goto err_open;
9821 }
9822 }
9823
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009824 if (is_usb_dev && may_use_hifi_record) {
9825 /* HiFi record selects an appropriate format, channel, rate combo
9826 depending on sink capabilities*/
9827 ret = read_usb_sup_params_and_compare(false /*is_playback*/,
9828 &config->format,
9829 &in->supported_formats[0],
9830 MAX_SUPPORTED_FORMATS,
9831 &config->channel_mask,
9832 &in->supported_channel_masks[0],
9833 MAX_SUPPORTED_CHANNEL_MASKS,
9834 &config->sample_rate,
9835 &in->supported_sample_rates[0],
9836 MAX_SUPPORTED_SAMPLE_RATES);
9837 if (ret != 0) {
9838 ret = -EINVAL;
9839 goto err_open;
9840 }
9841 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009842 } else if (config->format == AUDIO_FORMAT_DEFAULT) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309843 config->format = AUDIO_FORMAT_PCM_16_BIT;
Surendar karkaaca3d082017-11-09 15:18:37 +05309844 } else if (property_get_bool("vendor.audio.capture.pcm.32bit.enable", false)
9845 && config->format == AUDIO_FORMAT_PCM_32_BIT) {
9846 in->config.format = PCM_FORMAT_S32_LE;
9847 in->bit_width = 32;
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309848 } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
9849 (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
9850 (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
9851 (config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
9852 bool ret_error = false;
9853 in->bit_width = 24;
9854 /* 24 bit is restricted to UNPROCESSED source only,also format supported
9855 from HAL is 24_packed and 8_24
9856 *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
9857 24_packed return error indicating supported format is 24_packed
9858 *> In case of any other source requesting 24 bit or float return error
9859 indicating format supported is 16 bit only.
9860
9861 on error flinger will retry with supported format passed
9862 */
9863 if ((source != AUDIO_SOURCE_UNPROCESSED) &&
9864 (source != AUDIO_SOURCE_CAMCORDER)) {
9865 config->format = AUDIO_FORMAT_PCM_16_BIT;
9866 if (config->sample_rate > 48000)
9867 config->sample_rate = 48000;
9868 ret_error = true;
Haynes Mathew George46740472017-10-27 18:40:12 -07009869 } else if (!(config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
9870 config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309871 config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
9872 ret_error = true;
9873 }
9874
9875 if (ret_error) {
9876 ret = -EINVAL;
9877 goto err_open;
9878 }
9879 }
9880
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009881 in->channel_mask = config->channel_mask;
9882 in->format = config->format;
9883
9884 in->usecase = USECASE_AUDIO_RECORD;
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309885
Huicheng Liu1404ba12020-09-11 01:03:25 -04009886 /* validate bus device address */
9887 if (compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUS)) {
9888 /* extract car audio stream index */
9889 in->car_audio_stream =
9890 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
9891 if (in->car_audio_stream < 0) {
9892 ALOGE("%s: invalid car audio stream %x",
9893 __func__, in->car_audio_stream);
9894 ret = -EINVAL;
9895 goto err_open;
9896 }
9897 ALOGV("%s: car_audio_stream 0x%x", __func__, in->car_audio_stream);
Huicheng Liuea4fd422021-01-12 18:34:50 -05009898 ret = audio_extn_auto_hal_open_input_stream(in);
9899 if (ret) {
9900 ALOGE("%s: Failed to open input stream for bus device", __func__);
9901 ret = -EINVAL;
9902 goto err_open;
9903 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04009904 }
9905
Susan Wange3959562021-03-11 11:50:26 -05009906 /* reassign use case for echo reference stream on automotive platforms */
9907 if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) {
9908 ret = audio_extn_auto_hal_open_echo_reference_stream(in);
9909 }
9910
Kogara Naveen Kumar379ff692022-01-31 11:56:51 +05309911 if ((in->source == AUDIO_SOURCE_FM_TUNER) || (devices == AUDIO_DEVICE_IN_FM_TUNER)) {
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309912 if(!get_usecase_from_list(adev, USECASE_AUDIO_RECORD_FM_VIRTUAL))
9913 in->usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
9914 else {
9915 ret = -EINVAL;
9916 goto err_open;
9917 }
9918 }
9919
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05309920 if ((config->sample_rate == 48000 ||
9921 config->sample_rate == 32000 ||
9922 config->sample_rate == 24000 ||
9923 config->sample_rate == 16000 ||
9924 config->sample_rate == 8000)&&
Deeraj Somanfa377bf2019-02-06 12:57:59 +05309925 (flags & AUDIO_INPUT_FLAG_TIMESTAMP) == 0 &&
9926 (flags & AUDIO_INPUT_FLAG_COMPRESS) == 0 &&
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009927 (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
9928 is_low_latency = true;
9929#if LOW_LATENCY_CAPTURE_USE_CASE
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05309930 if ((flags & AUDIO_INPUT_FLAG_VOIP_TX) != 0)
9931 in->usecase = USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY;
9932 else
9933 in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009934#endif
9935 in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
Aalique Grahame22e49102018-12-18 14:23:57 -08009936 if (!in->realtime) {
9937 in->config = pcm_config_audio_capture;
9938 frame_size = audio_stream_in_frame_size(&in->stream);
9939 buffer_size = get_input_buffer_size(config->sample_rate,
9940 config->format,
9941 channel_count,
9942 is_low_latency);
9943 in->config.period_size = buffer_size / frame_size;
9944 in->config.rate = config->sample_rate;
9945 in->af_period_multiplier = 1;
9946 } else {
9947 // period size is left untouched for rt mode playback
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +05309948 switch(config->sample_rate)
9949 {
9950 case 48000:
9951 in->config = pcm_config_audio_capture_rt_48KHz;
9952 break;
9953 case 32000:
9954 in->config = pcm_config_audio_capture_rt_32KHz;
9955 break;
9956 case 24000:
9957 in->config = pcm_config_audio_capture_rt_24KHz;
9958 break;
9959 case 16000:
9960 in->config = pcm_config_audio_capture_rt_16KHz;
9961 break;
9962 case 8000:
9963 in->config = pcm_config_audio_capture_rt_8KHz;
9964 break;
9965 default:
9966 in->config = pcm_config_audio_capture_rt_48KHz;
9967 }
Aalique Grahame22e49102018-12-18 14:23:57 -08009968 in->af_period_multiplier = af_period_multiplier;
9969 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009970 }
9971
Susan Wangb803cb52021-10-14 12:03:36 -04009972 /* Additional sample rates added below must also be present
9973 in audio_policy_configuration.xml for mmap_no_irq_in */
9974 bool valid_mmap_record_rate = (config->sample_rate == 8000 ||
9975 config->sample_rate == 16000 ||
Susan Wang89da9042021-10-14 12:03:36 -04009976 config->sample_rate == 24000 ||
Susan Wangb803cb52021-10-14 12:03:36 -04009977 config->sample_rate == 32000 ||
9978 config->sample_rate == 48000);
9979 if (valid_mmap_record_rate &&
9980 ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009981 in->realtime = 0;
9982 in->usecase = USECASE_AUDIO_RECORD_MMAP;
9983 in->config = pcm_config_mmap_capture;
Haynes Mathew George46740472017-10-27 18:40:12 -07009984 in->config.format = pcm_format_from_audio_format(config->format);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009985 in->stream.start = in_start;
9986 in->stream.stop = in_stop;
9987 in->stream.create_mmap_buffer = in_create_mmap_buffer;
9988 in->stream.get_mmap_position = in_get_mmap_position;
Ramjee Singhbcb3b6c2021-11-17 13:19:16 +05309989 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009990 ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
Haynes Mathew George46740472017-10-27 18:40:12 -07009991 } else if (is_usb_dev && may_use_hifi_record) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009992 in->usecase = USECASE_AUDIO_RECORD_HIFI;
9993 in->config = pcm_config_audio_capture;
9994 frame_size = audio_stream_in_frame_size(&in->stream);
9995 buffer_size = get_input_buffer_size(config->sample_rate,
9996 config->format,
9997 channel_count,
9998 false /*is_low_latency*/);
9999 in->config.period_size = buffer_size / frame_size;
10000 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -070010001 in->config.format = pcm_format_from_audio_format(config->format);
Karthikeyan Mani07faa602018-08-20 11:01:32 -070010002 switch (config->format) {
10003 case AUDIO_FORMAT_PCM_32_BIT:
10004 in->bit_width = 32;
10005 break;
10006 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
10007 case AUDIO_FORMAT_PCM_8_24_BIT:
10008 in->bit_width = 24;
10009 break;
10010 default:
10011 in->bit_width = 16;
10012 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010013 } else if (is_single_device_type_equal(&in->device_list,
10014 AUDIO_DEVICE_IN_TELEPHONY_RX) ||
10015 is_single_device_type_equal(&in->device_list,
10016 AUDIO_DEVICE_IN_PROXY)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010017 if (config->sample_rate == 0)
10018 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
10019 if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
10020 config->sample_rate != 8000) {
10021 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
10022 ret = -EINVAL;
10023 goto err_open;
10024 }
10025 if (config->format == AUDIO_FORMAT_DEFAULT)
10026 config->format = AUDIO_FORMAT_PCM_16_BIT;
10027 if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
10028 config->format = AUDIO_FORMAT_PCM_16_BIT;
10029 ret = -EINVAL;
10030 goto err_open;
10031 }
10032
10033 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
Zhou Song62ea0282020-03-22 19:53:01 +080010034 if (adev->ha_proxy_enable &&
10035 is_single_device_type_equal(&in->device_list,
10036 AUDIO_DEVICE_IN_TELEPHONY_RX))
10037 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY2;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010038 in->config = pcm_config_afe_proxy_record;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -070010039 in->config.rate = config->sample_rate;
Aalique Grahame22e49102018-12-18 14:23:57 -080010040 in->af_period_multiplier = 1;
10041 } else if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
Shalini Manjunathaac412b32020-01-03 15:00:14 +053010042 (!voice_extn_is_compress_voip_supported()) &&
Aalique Grahame22e49102018-12-18 14:23:57 -080010043 in->flags & AUDIO_INPUT_FLAG_VOIP_TX &&
10044 (config->sample_rate == 8000 ||
10045 config->sample_rate == 16000 ||
10046 config->sample_rate == 32000 ||
10047 config->sample_rate == 48000) &&
10048 channel_count == 1) {
10049 in->usecase = USECASE_AUDIO_RECORD_VOIP;
10050 in->config = pcm_config_audio_capture;
10051 frame_size = audio_stream_in_frame_size(&in->stream);
10052 buffer_size = get_stream_buffer_size(VOIP_CAPTURE_PERIOD_DURATION_MSEC,
10053 config->sample_rate,
10054 config->format,
10055 channel_count, false /*is_low_latency*/);
10056 in->config.period_size = buffer_size / frame_size;
10057 in->config.period_count = VOIP_CAPTURE_PERIOD_COUNT;
10058 in->config.rate = config->sample_rate;
10059 in->af_period_multiplier = 1;
Mingshu Pangc2d65042021-01-14 16:19:10 +080010060 } else if (in->realtime) {
Kogara Naveen Kumara688a812022-04-27 16:45:59 +053010061 switch(config->sample_rate)
10062 {
10063 case 48000:
10064 in->config = pcm_config_audio_capture_rt_48KHz;
10065 break;
10066 case 32000:
10067 in->config = pcm_config_audio_capture_rt_32KHz;
10068 break;
10069 case 24000:
10070 in->config = pcm_config_audio_capture_rt_24KHz;
10071 break;
10072 case 16000:
10073 in->config = pcm_config_audio_capture_rt_16KHz;
10074 break;
10075 case 8000:
10076 in->config = pcm_config_audio_capture_rt_8KHz;
10077 break;
10078 default:
10079 in->config = pcm_config_audio_capture_rt_48KHz;
10080 }
Mingshu Pangc2d65042021-01-14 16:19:10 +080010081 in->config.format = pcm_format_from_audio_format(config->format);
10082 in->af_period_multiplier = af_period_multiplier;
Haynes Mathew George46740472017-10-27 18:40:12 -070010083 } else {
Revathi Uddarajud2634032017-12-07 14:42:34 +053010084 int ret_val;
10085 pthread_mutex_lock(&adev->lock);
10086 ret_val = audio_extn_check_and_set_multichannel_usecase(adev,
10087 in, config, &channel_mask_updated);
10088 pthread_mutex_unlock(&adev->lock);
10089
10090 if (!ret_val) {
10091 if (channel_mask_updated == true) {
10092 ALOGD("%s: return error to retry with updated channel mask (%#x)",
10093 __func__, config->channel_mask);
10094 ret = -EINVAL;
10095 goto err_open;
10096 }
10097 ALOGD("%s: created multi-channel session succesfully",__func__);
10098 } else if (audio_extn_compr_cap_enabled() &&
10099 audio_extn_compr_cap_format_supported(config->format) &&
10100 (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
10101 audio_extn_compr_cap_init(in);
10102 } else if (audio_extn_cin_applicable_stream(in)) {
Deeraj Soman14230922019-01-30 16:39:30 +053010103 ret = audio_extn_cin_configure_input_stream(in, config);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010104 if (ret)
10105 goto err_open;
10106 } else {
10107 in->config = pcm_config_audio_capture;
10108 in->config.rate = config->sample_rate;
10109 in->config.format = pcm_format_from_audio_format(config->format);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010110 in->format = config->format;
10111 frame_size = audio_stream_in_frame_size(&in->stream);
10112 buffer_size = get_input_buffer_size(config->sample_rate,
Haynes Mathew George46740472017-10-27 18:40:12 -070010113 config->format,
10114 channel_count,
10115 is_low_latency);
Dieter Luecking5d57def2018-09-07 14:23:37 +020010116 /* prevent division-by-zero */
10117 if (frame_size == 0) {
10118 ALOGE("%s: Error frame_size==0", __func__);
10119 ret = -EINVAL;
10120 goto err_open;
10121 }
10122
Revathi Uddarajud2634032017-12-07 14:42:34 +053010123 in->config.period_size = buffer_size / frame_size;
Aalique Grahame22e49102018-12-18 14:23:57 -080010124 in->af_period_multiplier = 1;
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010125
Revathi Uddarajud2634032017-12-07 14:42:34 +053010126 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
10127 /* optionally use VOIP usecase depending on config(s) */
10128 ret = adev_update_voice_comm_input_stream(in, config);
10129 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010130
Revathi Uddarajud2634032017-12-07 14:42:34 +053010131 if (ret) {
10132 ALOGE("%s AUDIO_SOURCE_VOICE_COMMUNICATION invalid args", __func__);
10133 goto err_open;
10134 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010135 }
Jaideep Sharmad305a4a2020-02-27 14:29:04 +053010136
10137 /* assign concurrent capture usecase if record has to caried out from
10138 * actual hardware input source */
10139 if (audio_extn_is_concurrent_capture_enabled() &&
10140 !audio_is_virtual_input_source(in->source)) {
Samyak Jainc37062f2019-04-25 18:41:06 +053010141 /* Acquire lock to avoid two concurrent use cases initialized to
10142 same pcm record use case */
kunleiz28c73e72019-03-27 17:24:04 +080010143
Samyak Jainc37062f2019-04-25 18:41:06 +053010144 if (in->usecase == USECASE_AUDIO_RECORD) {
10145 pthread_mutex_lock(&adev->lock);
10146 if (!(adev->pcm_record_uc_state)) {
10147 ALOGV("%s: using USECASE_AUDIO_RECORD",__func__);
10148 adev->pcm_record_uc_state = 1;
10149 pthread_mutex_unlock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010150 } else if (audio_extn_is_concurrent_pcm_record_enabled()) {
10151 in->usecase = get_record_usecase(adev);
10152 pthread_mutex_unlock(&adev->lock);
Samyak Jainc37062f2019-04-25 18:41:06 +053010153 } else {
10154 pthread_mutex_unlock(&adev->lock);
10155 /* Assign compress record use case for second record */
10156 in->usecase = USECASE_AUDIO_RECORD_COMPRESS2;
10157 in->flags |= AUDIO_INPUT_FLAG_COMPRESS;
10158 ALOGV("%s: overriding usecase with USECASE_AUDIO_RECORD_COMPRESS2 and appending compress flag", __func__);
10159 if (audio_extn_cin_applicable_stream(in)) {
10160 in->sample_rate = config->sample_rate;
Deeraj Soman14230922019-01-30 16:39:30 +053010161 ret = audio_extn_cin_configure_input_stream(in, config);
Samyak Jainc37062f2019-04-25 18:41:06 +053010162 if (ret)
10163 goto err_open;
10164 }
10165 }
10166 }
kunleiz28c73e72019-03-27 17:24:04 +080010167 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010168 }
Kogara Naveen Kumar51bb57d2022-02-17 16:40:06 +053010169
Ramjee Singh82fd0c12019-08-21 16:31:33 +053010170 if (audio_extn_ssr_get_stream() != in)
10171 in->config.channels = channel_count;
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -070010172
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -070010173 in->sample_rate = in->config.rate;
10174
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010175 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
10176 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010177 &in->device_list, flags, in->format,
Haynes Mathew George4ffef292017-11-21 15:08:02 -080010178 in->sample_rate, in->bit_width,
10179 in->profile, &in->app_type_cfg);
Naresh Tanniru04f71882018-06-26 17:46:22 +053010180 register_format(in->format, in->supported_formats);
10181 register_channel_mask(in->channel_mask, in->supported_channel_masks);
10182 register_sample_rate(in->sample_rate, in->supported_sample_rates);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010183
Dechen Chai22768452021-07-30 09:29:16 +053010184#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -080010185 in->error_log = error_log_create(
10186 ERROR_LOG_ENTRIES,
10187 1000000000 /* aggregate consecutive identical errors within one second */);
Dechen Chai22768452021-07-30 09:29:16 +053010188#endif
Aalique Grahame22e49102018-12-18 14:23:57 -080010189
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010190 /* This stream could be for sound trigger lab,
10191 get sound trigger pcm if present */
10192 audio_extn_sound_trigger_check_and_get_session(in);
10193
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010194 lock_input_stream(in);
10195 audio_extn_snd_mon_register_listener(in, in_snd_mon_cb);
10196 pthread_mutex_lock(&adev->lock);
10197 in->card_status = adev->card_status;
10198 pthread_mutex_unlock(&adev->lock);
10199 pthread_mutex_unlock(&in->lock);
10200
Aalique Grahame22e49102018-12-18 14:23:57 -080010201 stream_app_type_cfg_init(&in->app_type_cfg);
10202
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010203 *stream_in = &in->stream;
Derek Chenf939fb72018-11-13 13:34:41 -080010204
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010205 ret = io_streams_map_insert(adev, &in->stream.common,
10206 handle, AUDIO_PATCH_HANDLE_NONE);
10207 if (ret != 0)
10208 goto err_open;
10209
Susan Wang6dd13092021-01-25 10:27:11 -050010210 in->in_ctxt.input = in;
Derek Chenf939fb72018-11-13 13:34:41 -080010211
10212 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -050010213 list_add_tail(&adev->active_inputs_list, &in->in_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -080010214 pthread_mutex_unlock(&adev->lock);
10215
Eric Laurent994a6932013-07-17 11:51:42 -070010216 ALOGV("%s: exit", __func__);
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -080010217 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010218
10219err_open:
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010220 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
10221 free_record_usecase(adev, in->usecase);
10222 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jainc37062f2019-04-25 18:41:06 +053010223 pthread_mutex_lock(&adev->lock);
10224 adev->pcm_record_uc_state = 0;
10225 pthread_mutex_unlock(&adev->lock);
10226 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010227 free(in);
10228 *stream_in = NULL;
10229 return ret;
10230}
10231
10232static void adev_close_input_stream(struct audio_hw_device *dev,
10233 struct audio_stream_in *stream)
10234{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010235 int ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010236 struct stream_in *in = (struct stream_in *)stream;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010237 struct audio_device *adev = (struct audio_device *)dev;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010238
Sidipotu Ashokf43018c2014-05-02 16:21:50 +053010239 ALOGD("%s: enter:stream_handle(%p)",__func__, in);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080010240
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010241 if (in == NULL) {
10242 ALOGE("%s: audio_stream_in ptr is NULL", __func__);
10243 return;
10244 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010245 io_streams_map_remove(adev, in->capture_handle);
10246
Susan Wang6dd13092021-01-25 10:27:11 -050010247 // remove out_ctxt early to prevent the stream
10248 // being opened in a race condition
10249 pthread_mutex_lock(&adev->lock);
10250 list_remove(&in->in_ctxt.list);
10251 pthread_mutex_unlock(&adev->lock);
10252
kunleiz70e57612018-12-28 17:50:23 +080010253 /* must deregister from sndmonitor first to prevent races
10254 * between the callback and close_stream
10255 */
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010256 audio_extn_snd_mon_unregister_listener(stream);
10257
kunleiz70e57612018-12-28 17:50:23 +080010258 /* Disable echo reference if there are no active input, hfp call
10259 * and sound trigger while closing input stream
10260 */
Eric Laurent637e2d42018-11-15 12:24:31 -080010261 if (adev_get_active_input(adev) == NULL &&
kunleiz70e57612018-12-28 17:50:23 +080010262 !audio_extn_hfp_is_active(adev) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010263 !audio_extn_sound_trigger_check_ec_ref_enable()) {
10264 struct listnode out_devices;
10265 list_init(&out_devices);
10266 platform_set_echo_reference(adev, false, &out_devices);
Zhenlin Lian4f947842022-05-14 15:50:52 +053010267 clear_devices(&out_devices);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010268 } else
kunleiz70e57612018-12-28 17:50:23 +080010269 audio_extn_sound_trigger_update_ec_ref_status(false);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +053010270
Dechen Chai22768452021-07-30 09:29:16 +053010271#ifndef LINUX_ENABLED
Weiyin Jiang2995f662019-04-17 14:25:12 +080010272 error_log_destroy(in->error_log);
10273 in->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +053010274#endif
Pallavid7c7a272018-01-16 11:22:55 +053010275
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010276 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010277 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010278 ret = voice_extn_compress_voip_close_input_stream(&stream->common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +053010279 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -080010280 if (ret != 0)
10281 ALOGE("%s: Compress voip input cannot be closed, error:%d",
10282 __func__, ret);
10283 } else
10284 in_standby(&stream->common);
10285
Weiyin Jiang280ea742020-09-08 20:28:22 +080010286 pthread_mutex_destroy(&in->lock);
10287 pthread_mutex_destroy(&in->pre_lock);
10288
Revathi Uddarajud2634032017-12-07 14:42:34 +053010289 pthread_mutex_lock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010290 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
10291 free_record_usecase(adev, in->usecase);
10292 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jain15fda662018-12-18 16:40:52 +053010293 adev->pcm_record_uc_state = 0;
10294 }
10295
Kunlei Zhang5d5d8d92020-02-26 15:00:59 +080010296 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
10297 adev->enable_voicerx = false;
10298 }
10299
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070010300 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010301 audio_extn_ssr_deinit();
10302 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010303
Garmond Leunge2433c32017-09-28 21:51:22 -070010304 if (audio_extn_ffv_get_stream() == in) {
10305 audio_extn_ffv_stream_deinit();
10306 }
10307
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010308 if (audio_extn_compr_cap_enabled() &&
Mingming Yine62d7842013-10-25 16:26:03 -070010309 audio_extn_compr_cap_format_supported(in->config.format))
10310 audio_extn_compr_cap_deinit();
Dhanalakshmi Siddani74cf00b2016-12-02 13:55:57 +053010311
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +053010312 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +053010313 audio_extn_cin_free_input_stream_resources(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010314
Mingming Yinfd7607b2016-01-22 12:48:44 -080010315 if (in->is_st_session) {
10316 ALOGV("%s: sound trigger pcm stop lab", __func__);
10317 audio_extn_sound_trigger_stop_lab(in);
10318 }
Zhenlin Lian4f947842022-05-14 15:50:52 +053010319 clear_devices(&in->device_list);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010320 free(stream);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010321 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010322 return;
10323}
10324
Aalique Grahame22e49102018-12-18 14:23:57 -080010325/* verifies input and output devices and their capabilities.
10326 *
10327 * This verification is required when enabling extended bit-depth or
10328 * sampling rates, as not all qcom products support it.
10329 *
10330 * Suitable for calling only on initialization such as adev_open().
10331 * It fills the audio_device use_case_table[] array.
10332 *
10333 * Has a side-effect that it needs to configure audio routing / devices
10334 * in order to power up the devices and read the device parameters.
10335 * It does not acquire any hw device lock. Should restore the devices
10336 * back to "normal state" upon completion.
10337 */
10338static int adev_verify_devices(struct audio_device *adev)
10339{
10340 /* enumeration is a bit difficult because one really wants to pull
10341 * the use_case, device id, etc from the hidden pcm_device_table[].
10342 * In this case there are the following use cases and device ids.
10343 *
10344 * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
10345 * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
10346 * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
10347 * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
10348 * [USECASE_AUDIO_RECORD] = {0, 0},
10349 * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
10350 * [USECASE_VOICE_CALL] = {2, 2},
10351 *
10352 * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
10353 * USECASE_VOICE_CALL omitted, but possible for either input or output.
10354 */
10355
10356 /* should be the usecases enabled in adev_open_input_stream() */
10357 static const int test_in_usecases[] = {
10358 USECASE_AUDIO_RECORD,
10359 USECASE_AUDIO_RECORD_LOW_LATENCY, /* does not appear to be used */
10360 };
10361 /* should be the usecases enabled in adev_open_output_stream()*/
10362 static const int test_out_usecases[] = {
10363 USECASE_AUDIO_PLAYBACK_DEEP_BUFFER,
10364 USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
10365 };
10366 static const usecase_type_t usecase_type_by_dir[] = {
10367 PCM_PLAYBACK,
10368 PCM_CAPTURE,
10369 };
10370 static const unsigned flags_by_dir[] = {
10371 PCM_OUT,
10372 PCM_IN,
10373 };
10374
10375 size_t i;
10376 unsigned dir;
10377 const unsigned card_id = adev->snd_card;
10378
10379 for (dir = 0; dir < 2; ++dir) {
10380 const usecase_type_t usecase_type = usecase_type_by_dir[dir];
10381 const unsigned flags_dir = flags_by_dir[dir];
10382 const size_t testsize =
10383 dir ? ARRAY_SIZE(test_in_usecases) : ARRAY_SIZE(test_out_usecases);
10384 const int *testcases =
10385 dir ? test_in_usecases : test_out_usecases;
10386 const audio_devices_t audio_device =
10387 dir ? AUDIO_DEVICE_IN_BUILTIN_MIC : AUDIO_DEVICE_OUT_SPEAKER;
10388
10389 for (i = 0; i < testsize; ++i) {
10390 const audio_usecase_t audio_usecase = testcases[i];
10391 int device_id;
10392 struct pcm_params **pparams;
10393 struct stream_out out;
10394 struct stream_in in;
10395 struct audio_usecase uc_info;
10396 int retval;
10397
10398 pparams = &adev->use_case_table[audio_usecase];
10399 pcm_params_free(*pparams); /* can accept null input */
10400 *pparams = NULL;
10401
10402 /* find the device ID for the use case (signed, for error) */
10403 device_id = platform_get_pcm_device_id(audio_usecase, usecase_type);
10404 if (device_id < 0)
10405 continue;
10406
10407 /* prepare structures for device probing */
10408 memset(&uc_info, 0, sizeof(uc_info));
10409 uc_info.id = audio_usecase;
10410 uc_info.type = usecase_type;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010411 list_init(&uc_info.device_list);
Aalique Grahame22e49102018-12-18 14:23:57 -080010412 if (dir) {
Aalique Grahame22e49102018-12-18 14:23:57 -080010413 memset(&in, 0, sizeof(in));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010414 list_init(&in.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010415 update_device_list(&in.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010416 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
10417 uc_info.stream.in = &in;
Aalique Grahame22e49102018-12-18 14:23:57 -080010418 }
10419 memset(&out, 0, sizeof(out));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010420 list_init(&out.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010421 update_device_list(&out.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010422 uc_info.stream.out = &out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010423 update_device_list(&uc_info.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010424 uc_info.in_snd_device = SND_DEVICE_NONE;
10425 uc_info.out_snd_device = SND_DEVICE_NONE;
10426 list_add_tail(&adev->usecase_list, &uc_info.list);
10427
10428 /* select device - similar to start_(in/out)put_stream() */
10429 retval = select_devices(adev, audio_usecase);
10430 if (retval >= 0) {
10431 *pparams = pcm_params_get(card_id, device_id, flags_dir);
10432#if LOG_NDEBUG == 0
Aalique Grahame203bee02019-03-13 17:49:36 -070010433 char info[512]; /* for possible debug info */
Aalique Grahame22e49102018-12-18 14:23:57 -080010434 if (*pparams) {
10435 ALOGV("%s: (%s) card %d device %d", __func__,
10436 dir ? "input" : "output", card_id, device_id);
10437 pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
10438 } else {
10439 ALOGV("%s: cannot locate card %d device %d", __func__, card_id, device_id);
10440 }
10441#endif
10442 }
10443
10444 /* deselect device - similar to stop_(in/out)put_stream() */
10445 /* 1. Get and set stream specific mixer controls */
10446 retval = disable_audio_route(adev, &uc_info);
10447 /* 2. Disable the rx device */
10448 retval = disable_snd_device(adev,
10449 dir ? uc_info.in_snd_device : uc_info.out_snd_device);
10450 list_remove(&uc_info.list);
10451 }
10452 }
Aalique Grahame22e49102018-12-18 14:23:57 -080010453 return 0;
10454}
10455
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010456int update_patch(unsigned int num_sources,
10457 const struct audio_port_config *sources,
10458 unsigned int num_sinks,
10459 const struct audio_port_config *sinks,
10460 audio_patch_handle_t handle,
10461 struct audio_patch_info *p_info,
10462 patch_type_t patch_type, bool new_patch)
10463{
Aniket Kumar Latad13758f2020-08-06 15:11:36 -070010464 ALOGV("%s: enter", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010465
10466 if (p_info == NULL) {
10467 ALOGE("%s: Invalid patch pointer", __func__);
10468 return -EINVAL;
10469 }
10470
10471 if (new_patch) {
10472 p_info->patch = (struct audio_patch *) calloc(1, sizeof(struct audio_patch));
10473 if (p_info->patch == NULL) {
10474 ALOGE("%s: Could not allocate patch", __func__);
10475 return -ENOMEM;
10476 }
10477 }
10478
10479 p_info->patch->id = handle;
10480 p_info->patch->num_sources = num_sources;
10481 p_info->patch->num_sinks = num_sinks;
10482
10483 for (int i = 0; i < num_sources; i++)
10484 p_info->patch->sources[i] = sources[i];
10485 for (int i = 0; i < num_sinks; i++)
10486 p_info->patch->sinks[i] = sinks[i];
10487
10488 p_info->patch_type = patch_type;
10489 return 0;
10490}
10491
10492audio_patch_handle_t generate_patch_handle()
10493{
10494 static audio_patch_handle_t patch_handle = AUDIO_PATCH_HANDLE_NONE;
10495 if (++patch_handle < 0)
10496 patch_handle = AUDIO_PATCH_HANDLE_NONE + 1;
10497 return patch_handle;
10498}
10499
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010500int adev_create_audio_patch(struct audio_hw_device *dev,
10501 unsigned int num_sources,
10502 const struct audio_port_config *sources,
10503 unsigned int num_sinks,
10504 const struct audio_port_config *sinks,
10505 audio_patch_handle_t *handle)
10506{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010507 int ret = 0;
10508 struct audio_device *adev = (struct audio_device *)dev;
10509 struct audio_patch_info *p_info = NULL;
10510 patch_type_t patch_type = PATCH_NONE;
10511 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10512 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
10513 struct audio_stream_info *s_info = NULL;
10514 struct audio_stream *stream = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010515 struct listnode devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010516 audio_devices_t device_type = AUDIO_DEVICE_NONE;
10517 bool new_patch = false;
10518 char addr[AUDIO_DEVICE_MAX_ADDRESS_LEN];
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010519
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010520 ALOGD("%s: enter: num sources %d, num_sinks %d, handle %d", __func__,
10521 num_sources, num_sinks, *handle);
10522
10523 if (num_sources == 0 || num_sources > AUDIO_PATCH_PORTS_MAX ||
10524 num_sinks == 0 || num_sinks > AUDIO_PATCH_PORTS_MAX) {
10525 ALOGE("%s: Invalid patch arguments", __func__);
10526 ret = -EINVAL;
10527 goto done;
10528 }
10529
10530 if (num_sources > 1) {
10531 ALOGE("%s: Multiple sources are not supported", __func__);
10532 ret = -EINVAL;
10533 goto done;
10534 }
10535
10536 if (sources == NULL || sinks == NULL) {
10537 ALOGE("%s: Invalid sources or sinks port config", __func__);
10538 ret = -EINVAL;
10539 goto done;
10540 }
10541
10542 ALOGV("%s: source role %d, source type %d", __func__,
10543 sources[0].type, sources[0].role);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010544 list_init(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010545
10546 // Populate source/sink information and fetch stream info
10547 switch (sources[0].type) {
10548 case AUDIO_PORT_TYPE_DEVICE: // Patch for audio capture or loopback
10549 device_type = sources[0].ext.device.type;
10550 strlcpy(&addr[0], &sources[0].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010551 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010552 if (sinks[0].type == AUDIO_PORT_TYPE_MIX) {
10553 patch_type = PATCH_CAPTURE;
10554 io_handle = sinks[0].ext.mix.handle;
10555 input_source = sinks[0].ext.mix.usecase.source;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010556 ALOGD("%s: Capture patch from device %x to mix %d",
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010557 __func__, device_type, io_handle);
10558 } else {
10559 // Device to device patch is not implemented.
10560 // This space will need changes if audio HAL
10561 // handles device to device patches in the future.
10562 patch_type = PATCH_DEVICE_LOOPBACK;
10563 }
10564 break;
10565 case AUDIO_PORT_TYPE_MIX: // Patch for audio playback
10566 io_handle = sources[0].ext.mix.handle;
10567 for (int i = 0; i < num_sinks; i++) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010568 device_type = sinks[i].ext.device.type;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010569 strlcpy(&addr[0], &sinks[i].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010570 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010571 }
10572 patch_type = PATCH_PLAYBACK;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010573 ALOGD("%s: Playback patch from mix handle %d to device %x",
10574 __func__, io_handle, get_device_types(&devices));
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010575 break;
10576 case AUDIO_PORT_TYPE_SESSION:
10577 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010578 ALOGE("%s: Unsupported source type %d", __func__, sources[0].type);
10579 ret = -EINVAL;
10580 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010581 }
10582
10583 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010584
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010585 // Generate patch info and update patch
10586 if (*handle == AUDIO_PATCH_HANDLE_NONE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010587 *handle = generate_patch_handle();
10588 p_info = (struct audio_patch_info *)
10589 calloc(1, sizeof(struct audio_patch_info));
10590 if (p_info == NULL) {
10591 ALOGE("%s: Failed to allocate memory", __func__);
10592 pthread_mutex_unlock(&adev->lock);
10593 ret = -ENOMEM;
10594 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010595 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010596 new_patch = true;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010597 } else {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010598 p_info = fetch_patch_info_l(adev, *handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010599 if (p_info == NULL) {
10600 ALOGE("%s: Unable to fetch patch for received patch handle %d",
10601 __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010602 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010603 ret = -EINVAL;
10604 goto done;
10605 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010606 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010607 update_patch(num_sources, sources, num_sinks, sinks,
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010608 *handle, p_info, patch_type, new_patch);
10609
10610 // Fetch stream info of associated mix for playback or capture patches
10611 if (p_info->patch_type == PATCH_PLAYBACK ||
10612 p_info->patch_type == PATCH_CAPTURE) {
10613 s_info = hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10614 if (s_info == NULL) {
10615 ALOGE("%s: Failed to obtain stream info", __func__);
10616 if (new_patch)
10617 free(p_info);
10618 pthread_mutex_unlock(&adev->lock);
10619 ret = -EINVAL;
10620 goto done;
10621 }
10622 ALOGV("%s: Fetched stream info with io_handle %d", __func__, io_handle);
10623 s_info->patch_handle = *handle;
10624 stream = s_info->stream;
10625 }
10626 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010627
10628 // Update routing for stream
10629 if (stream != NULL) {
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010630 if (p_info->patch_type == PATCH_PLAYBACK) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010631 ret = route_output_stream((struct stream_out *) stream, &devices);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010632 } else if (p_info->patch_type == PATCH_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010633 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010634 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010635 if (ret < 0) {
10636 pthread_mutex_lock(&adev->lock);
10637 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10638 if (new_patch)
10639 free(p_info);
10640 pthread_mutex_unlock(&adev->lock);
10641 ALOGE("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10642 goto done;
10643 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010644 }
10645
10646 // Add new patch to patch map
10647 if (!ret && new_patch) {
10648 pthread_mutex_lock(&adev->lock);
10649 hashmapPut(adev->patch_map, (void *) (intptr_t) *handle, (void *) p_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010650 ALOGD("%s: Added a new patch with handle %d", __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010651 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010652 }
10653
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010654done:
Zhenlin Lian4f947842022-05-14 15:50:52 +053010655 clear_devices(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010656 audio_extn_hw_loopback_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010657 num_sources,
10658 sources,
10659 num_sinks,
10660 sinks,
10661 handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010662 audio_extn_auto_hal_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010663 num_sources,
10664 sources,
10665 num_sinks,
10666 sinks,
10667 handle);
10668 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010669}
10670
10671int adev_release_audio_patch(struct audio_hw_device *dev,
10672 audio_patch_handle_t handle)
10673{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010674 struct audio_device *adev = (struct audio_device *) dev;
10675 int ret = 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010676 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010677 struct audio_stream *stream = NULL;
Derek Chenf939fb72018-11-13 13:34:41 -080010678
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010679 if (handle == AUDIO_PATCH_HANDLE_NONE) {
10680 ALOGE("%s: Invalid patch handle %d", __func__, handle);
10681 ret = -EINVAL;
10682 goto done;
10683 }
10684
10685 ALOGD("%s: Remove patch with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010686 pthread_mutex_lock(&adev->lock);
10687 struct audio_patch_info *p_info = fetch_patch_info_l(adev, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010688 if (p_info == NULL) {
10689 ALOGE("%s: Patch info not found with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010690 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010691 ret = -EINVAL;
10692 goto done;
10693 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010694 struct audio_patch *patch = p_info->patch;
10695 if (patch == NULL) {
10696 ALOGE("%s: Patch not found for handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010697 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010698 ret = -EINVAL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010699 goto done;
10700 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010701 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10702 switch (patch->sources[0].type) {
10703 case AUDIO_PORT_TYPE_MIX:
10704 io_handle = patch->sources[0].ext.mix.handle;
10705 break;
10706 case AUDIO_PORT_TYPE_DEVICE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010707 if (p_info->patch_type == PATCH_CAPTURE)
10708 io_handle = patch->sinks[0].ext.mix.handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010709 break;
10710 case AUDIO_PORT_TYPE_SESSION:
10711 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010712 pthread_mutex_unlock(&adev->lock);
10713 ret = -EINVAL;
10714 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010715 }
10716
10717 // Remove patch and reset patch handle in stream info
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010718 patch_type_t patch_type = p_info->patch_type;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010719 patch_map_remove_l(adev, handle);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010720 if (patch_type == PATCH_PLAYBACK ||
10721 patch_type == PATCH_CAPTURE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010722 struct audio_stream_info *s_info =
10723 hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10724 if (s_info == NULL) {
10725 ALOGE("%s: stream for io_handle %d is not available", __func__, io_handle);
10726 pthread_mutex_unlock(&adev->lock);
10727 goto done;
10728 }
10729 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10730 stream = s_info->stream;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010731 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010732 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010733
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010734 if (stream != NULL) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010735 struct listnode devices;
10736 list_init(&devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010737 if (patch_type == PATCH_PLAYBACK)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010738 ret = route_output_stream((struct stream_out *) stream, &devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010739 else if (patch_type == PATCH_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010740 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Zhenlin Lian4f947842022-05-14 15:50:52 +053010741 clear_devices(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010742 }
10743
10744 if (ret < 0)
10745 ALOGW("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10746
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010747done:
10748 audio_extn_hw_loopback_release_audio_patch(dev, handle);
10749 audio_extn_auto_hal_release_audio_patch(dev, handle);
10750
10751 ALOGV("%s: Successfully released patch %d", __func__, handle);
Derek Chenf939fb72018-11-13 13:34:41 -080010752 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010753}
10754
10755int adev_get_audio_port(struct audio_hw_device *dev, struct audio_port *config)
10756{
Derek Chenf13dd492018-11-13 14:53:51 -080010757 int ret = 0;
10758
10759 ret = audio_extn_hw_loopback_get_audio_port(dev, config);
10760 ret |= audio_extn_auto_hal_get_audio_port(dev, config);
10761 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010762}
10763
10764int adev_set_audio_port_config(struct audio_hw_device *dev,
10765 const struct audio_port_config *config)
10766{
Derek Chenf13dd492018-11-13 14:53:51 -080010767 int ret = 0;
10768
10769 ret = audio_extn_hw_loopback_set_audio_port_config(dev, config);
10770 ret |= audio_extn_auto_hal_set_audio_port_config(dev, config);
10771 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010772}
10773
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010774static int adev_dump(const audio_hw_device_t *device __unused,
10775 int fd __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010776{
10777 return 0;
10778}
10779
10780static int adev_close(hw_device_t *device)
10781{
Aalique Grahame22e49102018-12-18 14:23:57 -080010782 size_t i;
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010783 struct audio_device *adev_temp = (struct audio_device *)device;
Kiran Kandi910e1862013-10-29 13:29:42 -070010784
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010785 if (!adev_temp)
Kiran Kandi910e1862013-10-29 13:29:42 -070010786 return 0;
10787
10788 pthread_mutex_lock(&adev_init_lock);
10789
10790 if ((--audio_device_ref_count) == 0) {
Sujin Panicker390724d2019-04-26 10:43:36 +053010791 if (audio_extn_spkr_prot_is_enabled())
10792 audio_extn_spkr_prot_deinit();
Jaideep Sharmaa2b49672019-09-10 20:37:03 +053010793 audio_extn_battery_properties_listener_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010794 audio_extn_snd_mon_unregister_listener(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010795 audio_extn_sound_trigger_deinit(adev);
Kiran Kandide144c82013-11-20 15:58:32 -080010796 audio_extn_listen_deinit(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010797 audio_extn_qdsp_deinit();
Aalique Grahame22e49102018-12-18 14:23:57 -080010798 audio_extn_extspk_deinit(adev->extspk);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010799 audio_extn_utils_release_streams_cfg_lists(
10800 &adev->streams_output_cfg_list,
10801 &adev->streams_input_cfg_list);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010802 if (audio_extn_qap_is_enabled())
10803 audio_extn_qap_deinit();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010804 if (audio_extn_qaf_is_enabled())
10805 audio_extn_qaf_deinit();
Kiran Kandi910e1862013-10-29 13:29:42 -070010806 audio_route_free(adev->audio_route);
Weiyin Jiangfa65d3e2019-03-05 23:39:45 +080010807 audio_extn_gef_deinit(adev);
Kiran Kandi910e1862013-10-29 13:29:42 -070010808 free(adev->snd_dev_ref_cnt);
10809 platform_deinit(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080010810 for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
10811 pcm_params_free(adev->use_case_table[i]);
10812 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010813 if (adev->adm_deinit)
10814 adev->adm_deinit(adev->adm_data);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010815 qahwi_deinit(device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080010816 audio_extn_adsp_hdlr_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010817 audio_extn_snd_mon_deinit();
Siddartha Shaik44dd7702017-06-14 12:13:25 +053010818 audio_extn_hw_loopback_deinit(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070010819 audio_extn_ffv_deinit();
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053010820 if (adev->device_cfg_params) {
10821 free(adev->device_cfg_params);
10822 adev->device_cfg_params = NULL;
10823 }
Derek Chend2530072014-11-24 12:39:14 -080010824 if(adev->ext_hw_plugin)
10825 audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
Derek Chenae7b0342019-02-08 15:17:04 -080010826 audio_extn_auto_hal_deinit();
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010827 free_map(adev->patch_map);
10828 free_map(adev->io_streams_map);
Kiran Kandi910e1862013-10-29 13:29:42 -070010829 free(device);
10830 adev = NULL;
10831 }
10832 pthread_mutex_unlock(&adev_init_lock);
Vatsal Buchac09ae062018-11-14 13:25:08 +053010833 enable_gcov();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010834 return 0;
10835}
10836
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010837/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
10838 * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
10839 * just that it _might_ work.
10840 */
10841static int period_size_is_plausible_for_low_latency(int period_size)
10842{
10843 switch (period_size) {
10844 case 160:
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -070010845 case 192:
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010846 case 240:
10847 case 320:
10848 case 480:
10849 return 1;
10850 default:
10851 return 0;
10852 }
10853}
10854
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010855static void adev_snd_mon_cb(void *cookie, struct str_parms *parms)
10856{
10857 bool is_snd_card_status = false;
10858 bool is_ext_device_status = false;
10859 char value[32];
10860 int card = -1;
10861 card_status_t status;
10862
10863 if (cookie != adev || !parms)
10864 return;
10865
10866 if (!parse_snd_card_status(parms, &card, &status)) {
10867 is_snd_card_status = true;
10868 } else if (0 < str_parms_get_str(parms, "ext_audio_device", value, sizeof(value))) {
10869 is_ext_device_status = true;
10870 } else {
10871 // not a valid event
10872 return;
10873 }
10874
10875 pthread_mutex_lock(&adev->lock);
10876 if (card == adev->snd_card || is_ext_device_status) {
10877 if (is_snd_card_status && adev->card_status != status) {
Jaideep Sharmacb402512020-09-24 17:51:07 +053010878 ALOGD("%s card_status %d", __func__, status);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010879 adev->card_status = status;
10880 platform_snd_card_update(adev->platform, status);
10881 audio_extn_fm_set_parameters(adev, parms);
Derek Chend6f371d2019-03-01 13:45:58 -080010882 audio_extn_auto_hal_set_parameters(adev, parms);
Zhou Song4f43e352019-07-02 00:32:23 +080010883 if (status == CARD_STATUS_OFFLINE)
10884 audio_extn_sco_reset_configuration();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010885 } else if (is_ext_device_status) {
10886 platform_set_parameters(adev->platform, parms);
10887 }
10888 }
10889 pthread_mutex_unlock(&adev->lock);
10890 return;
10891}
10892
Weiyin Jiang280ea742020-09-08 20:28:22 +080010893/* adev lock held */
10894int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010895{
10896 struct audio_usecase *uc_info;
Zhou Song407e5aa2020-12-27 19:13:04 +080010897 struct audio_usecase *usecase;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010898 struct listnode devices;
Zhou Song407e5aa2020-12-27 19:13:04 +080010899 struct listnode *node;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010900
10901 uc_info = get_usecase_from_list(adev, out->usecase);
10902 if (uc_info == NULL) {
10903 ALOGE("%s: Could not find the usecase (%d) in the list",
10904 __func__, out->usecase);
10905 return -EINVAL;
10906 }
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010907 list_init(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010908
Zhou Songbaddf9f2020-11-20 13:57:39 +080010909 ALOGD("%s: enter: usecase(%d: %s), a2dp muted %d", __func__,
10910 out->usecase, use_case_table[out->usecase], out->a2dp_muted);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010911
10912 if (restore) {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010913 pthread_mutex_lock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010914 // restore A2DP device for active usecases and unmute if required
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010915 if (is_a2dp_out_device_type(&out->device_list)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010916 ALOGD("%s: restoring A2dp and unmuting stream", __func__);
Zhou Songe5225132019-09-26 15:33:36 +080010917 if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
10918 select_devices(adev, uc_info->id);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010919
10920 if (is_offload_usecase(out->usecase)) {
10921 if (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)
Weiyin Jiang280ea742020-09-08 20:28:22 +080010922 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010923 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
10924 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
10925 } else {
10926 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010927 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010928 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010929 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010930 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010931 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010932 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010933 // mute stream and switch to speaker if suspended
10934 if (!out->a2dp_muted && !out->standby) {
Zhou Songbaddf9f2020-11-20 13:57:39 +080010935 assign_devices(&devices, &out->device_list);
10936 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Zhou Song407e5aa2020-12-27 19:13:04 +080010937 list_for_each(node, &adev->usecase_list) {
10938 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Songe63b6fe2021-04-15 13:54:46 +080010939 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
10940 !is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songcf77af02021-05-14 18:21:14 +080010941 !is_sco_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songe63b6fe2021-04-15 13:54:46 +080010942 platform_check_backends_match(SND_DEVICE_OUT_SPEAKER,
10943 usecase->out_snd_device)) {
Zhou Song407e5aa2020-12-27 19:13:04 +080010944 assign_devices(&out->device_list, &usecase->stream.out->device_list);
10945 break;
10946 }
10947 }
Zhou Songcf77af02021-05-14 18:21:14 +080010948 if ((is_a2dp_out_device_type(&devices) && list_length(&devices) == 1) ||
10949 (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
Zhou Song8edbbdb2021-01-14 16:48:03 +080010950 out->a2dp_muted = true;
10951 if (is_offload_usecase(out->usecase)) {
10952 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10953 compress_pause(out->compr);
10954 out_set_compr_volume(&out->stream, (float)0, (float)0);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010955 } else {
Weiyin Jiang906db3c2021-03-02 13:17:04 +080010956 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
10957 out_set_voip_volume(&out->stream, (float)0, (float)0);
10958 else
10959 out_set_pcm_volume(&out->stream, (float)0, (float)0);
10960
Zhou Song8edbbdb2021-01-14 16:48:03 +080010961 /* wait for stale pcm drained before switching to speaker */
10962 uint32_t latency =
10963 (out->config.period_count * out->config.period_size * 1000) /
10964 (out->config.rate);
10965 usleep(latency * 1000);
10966 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010967 }
10968 select_devices(adev, out->usecase);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010969 ALOGD("%s: switched to device:%s and stream muted:%d", __func__,
10970 platform_get_snd_device_name(uc_info->out_snd_device), out->a2dp_muted);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010971 if (is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010972 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10973 compress_resume(out->compr);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010974 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010975 assign_devices(&out->device_list, &devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010976 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010977 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010978 }
Zhenlin Lian4f947842022-05-14 15:50:52 +053010979 clear_devices(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010980 ALOGV("%s: exit", __func__);
10981 return 0;
10982}
10983
Haynes Mathew George01156f92018-04-13 15:29:54 -070010984void adev_on_battery_status_changed(bool charging)
10985{
10986 pthread_mutex_lock(&adev->lock);
10987 ALOGI("%s: battery status changed to %scharging", __func__, charging ? "" : "not ");
10988 adev->is_charging = charging;
Zhou Songc1088ea2018-06-12 00:17:29 +080010989 audio_extn_sound_trigger_update_battery_status(charging);
Haynes Mathew George01156f92018-04-13 15:29:54 -070010990 pthread_mutex_unlock(&adev->lock);
10991}
10992
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010993static int adev_open(const hw_module_t *module, const char *name,
10994 hw_device_t **device)
10995{
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010996 int ret;
Derek Chenf939fb72018-11-13 13:34:41 -080010997 char value[PROPERTY_VALUE_MAX] = {0};
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053010998 char mixer_ctl_name[128] = {0};
10999 struct mixer_ctl *ctl = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011000
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080011001 ALOGD("%s: enter", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011002 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
11003
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011004 pthread_mutex_lock(&adev_init_lock);
Kiran Kandi910e1862013-10-29 13:29:42 -070011005 if (audio_device_ref_count != 0){
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011006 *device = &adev->device.common;
Kiran Kandi910e1862013-10-29 13:29:42 -070011007 audio_device_ref_count++;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011008 ALOGD("%s: returning existing instance of adev", __func__);
11009 ALOGD("%s: exit", __func__);
11010 pthread_mutex_unlock(&adev_init_lock);
11011 return 0;
11012 }
11013
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011014 adev = calloc(1, sizeof(struct audio_device));
11015
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -070011016 if (!adev) {
11017 pthread_mutex_unlock(&adev_init_lock);
11018 return -ENOMEM;
11019 }
11020
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -070011021 pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
11022
Weiyin Jiange6ce6312019-01-28 18:28:22 +080011023 // register audio ext hidl at the earliest
11024 audio_extn_hidl_init();
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053011025#ifdef DYNAMIC_LOG_ENABLED
11026 register_for_dynamic_logging("hal");
11027#endif
11028
Derek Chenf939fb72018-11-13 13:34:41 -080011029 /* default audio HAL major version */
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011030 uint32_t maj_version = 3;
Derek Chenf939fb72018-11-13 13:34:41 -080011031 if(property_get("vendor.audio.hal.maj.version", value, NULL))
11032 maj_version = atoi(value);
11033
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011034 adev->device.common.tag = HARDWARE_DEVICE_TAG;
Derek Chenf939fb72018-11-13 13:34:41 -080011035 adev->device.common.version = HARDWARE_DEVICE_API_VERSION(maj_version, 0);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011036 adev->device.common.module = (struct hw_module_t *)module;
11037 adev->device.common.close = adev_close;
11038
11039 adev->device.init_check = adev_init_check;
11040 adev->device.set_voice_volume = adev_set_voice_volume;
11041 adev->device.set_master_volume = adev_set_master_volume;
11042 adev->device.get_master_volume = adev_get_master_volume;
11043 adev->device.set_master_mute = adev_set_master_mute;
11044 adev->device.get_master_mute = adev_get_master_mute;
11045 adev->device.set_mode = adev_set_mode;
11046 adev->device.set_mic_mute = adev_set_mic_mute;
11047 adev->device.get_mic_mute = adev_get_mic_mute;
11048 adev->device.set_parameters = adev_set_parameters;
11049 adev->device.get_parameters = adev_get_parameters;
11050 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
11051 adev->device.open_output_stream = adev_open_output_stream;
11052 adev->device.close_output_stream = adev_close_output_stream;
11053 adev->device.open_input_stream = adev_open_input_stream;
11054 adev->device.close_input_stream = adev_close_input_stream;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053011055 adev->device.create_audio_patch = adev_create_audio_patch;
11056 adev->device.release_audio_patch = adev_release_audio_patch;
11057 adev->device.get_audio_port = adev_get_audio_port;
11058 adev->device.set_audio_port_config = adev_set_audio_port_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011059 adev->device.dump = adev_dump;
Naresh Tannirudcb47c52018-06-25 16:23:32 +053011060 adev->device.get_microphones = adev_get_microphones;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011061
11062 /* Set the default route before the PCM stream is opened */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011063 adev->mode = AUDIO_MODE_NORMAL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -080011064 adev->primary_output = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011065 adev->out_device = AUDIO_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011066 adev->bluetooth_nrec = true;
Ravi Kumar Alamandaf9967042013-02-14 19:35:14 -080011067 adev->acdb_settings = TTY_MODE_OFF;
vivek mehta344576a2016-04-12 18:56:03 -070011068 adev->allow_afe_proxy_usage = true;
Ashish Jain1b9b30c2017-05-18 20:57:40 +053011069 adev->bt_sco_on = false;
Eric Laurent07eeafd2013-10-06 12:52:49 -070011070 /* adev->cur_hdmi_channels = 0; by calloc() */
Eric Laurentb23d5282013-05-14 15:27:20 -070011071 adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
vivek mehtaae1018c2019-05-09 12:19:57 -070011072 /* Init audio and voice feature */
11073 audio_extn_feature_init();
11074 voice_extn_feature_init();
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070011075 voice_init(adev);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -080011076 list_init(&adev->usecase_list);
Derek Chenf939fb72018-11-13 13:34:41 -080011077 list_init(&adev->active_inputs_list);
11078 list_init(&adev->active_outputs_list);
Rahul Sharma99770982019-03-06 17:05:26 +053011079 list_init(&adev->audio_patch_record_list);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011080 adev->io_streams_map = hashmapCreate(AUDIO_IO_PORTS_MAX, audio_extn_utils_hash_fn,
11081 audio_extn_utils_hash_eq);
11082 if (!adev->io_streams_map) {
11083 ALOGE("%s: Could not create io streams map", __func__);
11084 ret = -ENOMEM;
11085 goto adev_open_err;
11086 }
11087 adev->patch_map = hashmapCreate(AUDIO_PATCH_PORTS_MAX, audio_extn_utils_hash_fn,
11088 audio_extn_utils_hash_eq);
11089 if (!adev->patch_map) {
11090 ALOGE("%s: Could not create audio patch map", __func__);
11091 ret = -ENOMEM;
11092 goto adev_open_err;
11093 }
Krishnankutty Kolathappilly0b2de1c2014-02-14 14:45:49 -080011094 adev->cur_wfd_channels = 2;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -070011095 adev->offload_usecases_state = 0;
Samyak Jain15fda662018-12-18 16:40:52 +053011096 adev->pcm_record_uc_state = 0;
Ashish Jain81eb2a82015-05-13 10:52:34 +053011097 adev->is_channel_status_set = false;
Sudheer Papothifa9d2282015-09-17 01:53:25 +053011098 adev->perf_lock_opts[0] = 0x101;
11099 adev->perf_lock_opts[1] = 0x20E;
11100 adev->perf_lock_opts_size = 2;
Xiaojun Sang785b5da2017-08-03 15:52:29 +080011101 adev->dsp_bit_width_enforce_mode = 0;
Aalique Grahame552b0832019-03-11 10:16:38 -070011102 adev->enable_hfp = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011103 adev->use_old_pspd_mix_ctrl = false;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070011104 adev->adm_routing_changed = false;
Revathi Uddarajub26e3932020-06-10 14:51:02 +053011105 adev->a2dp_started = false;
Zhou Song503196b2021-07-23 17:31:05 +080011106 adev->ha_proxy_enable = false;
Naresh Tanniru4c630392014-05-12 01:05:52 +053011107
Zhou Song68ebc352019-12-05 17:11:15 +080011108 audio_extn_perf_lock_init();
11109
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011110 /* Loads platform specific libraries dynamically */
Eric Laurentb23d5282013-05-14 15:27:20 -070011111 adev->platform = platform_init(adev);
11112 if (!adev->platform) {
Eric Laurentb23d5282013-05-14 15:27:20 -070011113 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011114 ret = -EINVAL;
11115 goto adev_open_err;
Eric Laurentb23d5282013-05-14 15:27:20 -070011116 }
Eric Laurentc4aef752013-09-12 17:45:53 -070011117
Aalique Grahame22e49102018-12-18 14:23:57 -080011118 adev->extspk = audio_extn_extspk_init(adev);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011119 if (audio_extn_qap_is_enabled()) {
11120 ret = audio_extn_qap_init(adev);
11121 if (ret < 0) {
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011122 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011123 goto adev_open_err;
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053011124 }
11125 adev->device.open_output_stream = audio_extn_qap_open_output_stream;
11126 adev->device.close_output_stream = audio_extn_qap_close_output_stream;
11127 }
Aalique Grahame22e49102018-12-18 14:23:57 -080011128
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011129 if (audio_extn_qaf_is_enabled()) {
11130 ret = audio_extn_qaf_init(adev);
11131 if (ret < 0) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011132 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011133 goto adev_open_err;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053011134 }
11135
11136 adev->device.open_output_stream = audio_extn_qaf_open_output_stream;
11137 adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
11138 }
11139
Derek Chenae7b0342019-02-08 15:17:04 -080011140 audio_extn_auto_hal_init(adev);
Derek Chend2530072014-11-24 12:39:14 -080011141 adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);
11142
Eric Laurentc4aef752013-09-12 17:45:53 -070011143 if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
11144 adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
11145 if (adev->visualizer_lib == NULL) {
11146 ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
11147 } else {
11148 ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
11149 adev->visualizer_start_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011150 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070011151 "visualizer_hal_start_output");
11152 adev->visualizer_stop_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011153 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070011154 "visualizer_hal_stop_output");
11155 }
11156 }
Dhanalakshmi Siddani21be3ac2016-12-29 14:31:08 +053011157 audio_extn_init(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080011158 voice_extn_init(adev);
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -080011159 audio_extn_listen_init(adev, adev->snd_card);
Weiyin Jiangaa80acd2016-09-21 16:42:11 +080011160 audio_extn_gef_init(adev);
Siddartha Shaik44dd7702017-06-14 12:13:25 +053011161 audio_extn_hw_loopback_init(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070011162 audio_extn_ffv_init(adev);
Eric Laurentc4aef752013-09-12 17:45:53 -070011163
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011164 if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
11165 adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
11166 if (adev->offload_effects_lib == NULL) {
11167 ALOGE("%s: DLOPEN failed for %s", __func__,
11168 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
11169 } else {
11170 ALOGV("%s: DLOPEN successful for %s", __func__,
11171 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
11172 adev->offload_effects_start_output =
Ashish Jain5106d362016-05-11 19:23:33 +053011173 (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib,
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011174 "offload_effects_bundle_hal_start_output");
11175 adev->offload_effects_stop_output =
11176 (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
11177 "offload_effects_bundle_hal_stop_output");
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080011178 adev->offload_effects_set_hpx_state =
11179 (int (*)(bool))dlsym(adev->offload_effects_lib,
11180 "offload_effects_bundle_set_hpx_state");
Dhananjay Kumard68883d2015-09-04 13:39:26 +053011181 adev->offload_effects_get_parameters =
11182 (void (*)(struct str_parms *, struct str_parms *))
11183 dlsym(adev->offload_effects_lib,
11184 "offload_effects_bundle_get_parameters");
11185 adev->offload_effects_set_parameters =
11186 (void (*)(struct str_parms *))dlsym(adev->offload_effects_lib,
11187 "offload_effects_bundle_set_parameters");
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080011188 }
11189 }
11190
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011191 if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
11192 adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
11193 if (adev->adm_lib == NULL) {
11194 ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
11195 } else {
11196 ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
11197 adev->adm_init = (adm_init_t)
11198 dlsym(adev->adm_lib, "adm_init");
11199 adev->adm_deinit = (adm_deinit_t)
11200 dlsym(adev->adm_lib, "adm_deinit");
11201 adev->adm_register_input_stream = (adm_register_input_stream_t)
11202 dlsym(adev->adm_lib, "adm_register_input_stream");
11203 adev->adm_register_output_stream = (adm_register_output_stream_t)
11204 dlsym(adev->adm_lib, "adm_register_output_stream");
11205 adev->adm_deregister_stream = (adm_deregister_stream_t)
11206 dlsym(adev->adm_lib, "adm_deregister_stream");
11207 adev->adm_request_focus = (adm_request_focus_t)
11208 dlsym(adev->adm_lib, "adm_request_focus");
11209 adev->adm_abandon_focus = (adm_abandon_focus_t)
11210 dlsym(adev->adm_lib, "adm_abandon_focus");
Haynes Mathew George5beddd42016-06-27 18:33:40 -070011211 adev->adm_set_config = (adm_set_config_t)
11212 dlsym(adev->adm_lib, "adm_set_config");
11213 adev->adm_request_focus_v2 = (adm_request_focus_v2_t)
11214 dlsym(adev->adm_lib, "adm_request_focus_v2");
11215 adev->adm_is_noirq_avail = (adm_is_noirq_avail_t)
11216 dlsym(adev->adm_lib, "adm_is_noirq_avail");
11217 adev->adm_on_routing_change = (adm_on_routing_change_t)
11218 dlsym(adev->adm_lib, "adm_on_routing_change");
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070011219 adev->adm_request_focus_v2_1 = (adm_request_focus_v2_1_t)
11220 dlsym(adev->adm_lib, "adm_request_focus_v2_1");
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011221 }
11222 }
11223
Aalique Grahame22e49102018-12-18 14:23:57 -080011224 adev->enable_voicerx = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070011225 adev->bt_wb_speech_enabled = false;
Zhou Song12c29502019-03-16 10:37:18 +080011226 adev->swb_speech_mode = SPEECH_MODE_INVALID;
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +080011227 adev->fluence_nn_usecase_id = USECASE_INVALID;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -080011228 //initialize this to false for now,
11229 //this will be set to true through set param
11230 adev->vr_audio_mode_enabled = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070011231
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -070011232 audio_extn_ds2_enable(adev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011233 *device = &adev->device.common;
Aalique Grahame22e49102018-12-18 14:23:57 -080011234
11235 if (k_enable_extended_precision)
11236 adev_verify_devices(adev);
11237
Xiaojun Sang785b5da2017-08-03 15:52:29 +080011238 adev->dsp_bit_width_enforce_mode =
11239 adev_init_dsp_bit_width_enforce_mode(adev->mixer);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011240
Dhananjay Kumard6d32152016-10-13 16:11:03 +053011241 audio_extn_utils_update_streams_cfg_lists(adev->platform, adev->mixer,
11242 &adev->streams_output_cfg_list,
11243 &adev->streams_input_cfg_list);
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -070011244
Kiran Kandi910e1862013-10-29 13:29:42 -070011245 audio_device_ref_count++;
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011246
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011247 int trial;
Manisha Agarwalc75a0202019-12-06 18:48:25 +053011248 if (property_get("vendor.audio_hal.period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011249 trial = atoi(value);
11250 if (period_size_is_plausible_for_low_latency(trial)) {
11251 pcm_config_low_latency.period_size = trial;
11252 pcm_config_low_latency.start_threshold = trial / 4;
11253 pcm_config_low_latency.avail_min = trial / 4;
11254 configured_low_latency_capture_period_size = trial;
11255 }
11256 }
ronghuiz93177262021-04-21 19:58:13 +080011257 if (property_get("vendor.audio_hal.in_period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070011258 trial = atoi(value);
11259 if (period_size_is_plausible_for_low_latency(trial)) {
11260 configured_low_latency_capture_period_size = trial;
11261 }
11262 }
11263
Vignesh Kulothungan7d374312018-02-21 17:12:00 -080011264 adev->mic_break_enabled = property_get_bool("vendor.audio.mic_break", false);
11265
Eric Laurent4b084132018-10-19 17:33:43 -070011266 adev->camera_orientation = CAMERA_DEFAULT;
11267
Manisha Agarwalc75a0202019-12-06 18:48:25 +053011268 if (property_get("vendor.audio_hal.period_multiplier",value,NULL) > 0) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -070011269 af_period_multiplier = atoi(value);
11270 if (af_period_multiplier < 0)
11271 af_period_multiplier = 2;
11272 else if (af_period_multiplier > 4)
11273 af_period_multiplier = 4;
11274
11275 ALOGV("new period_multiplier = %d", af_period_multiplier);
11276 }
11277
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080011278 audio_extn_qdsp_init(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080011279
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -070011280 adev->multi_offload_enable = property_get_bool("vendor.audio.offload.multiple.enabled", false);
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070011281 pthread_mutex_unlock(&adev_init_lock);
11282
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070011283 if (adev->adm_init)
11284 adev->adm_data = adev->adm_init();
11285
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053011286 qahwi_init(*device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080011287 audio_extn_adsp_hdlr_init(adev->mixer);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011288
11289 audio_extn_snd_mon_init();
11290 pthread_mutex_lock(&adev->lock);
11291 audio_extn_snd_mon_register_listener(adev, adev_snd_mon_cb);
11292 adev->card_status = CARD_STATUS_ONLINE;
Shubhasini Sugumaran3fde6582022-01-19 15:54:50 -050011293 adev->out_power_policy = POWER_POLICY_STATUS_ONLINE;
11294 adev->in_power_policy = POWER_POLICY_STATUS_ONLINE;
Haynes Mathew George01156f92018-04-13 15:29:54 -070011295 audio_extn_battery_properties_listener_init(adev_on_battery_status_changed);
11296 /*
11297 * if the battery state callback happens before charging can be queried,
11298 * it will be guarded with the adev->lock held in the cb function and so
11299 * the callback value will reflect the latest state
11300 */
11301 adev->is_charging = audio_extn_battery_properties_is_charging();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011302 audio_extn_sound_trigger_init(adev); /* dependent on snd_mon_init() */
Zhou Songc1088ea2018-06-12 00:17:29 +080011303 audio_extn_sound_trigger_update_battery_status(adev->is_charging);
justinweng20fb6d82019-02-21 18:49:00 -070011304 audio_extn_audiozoom_init();
Zhou Songc1088ea2018-06-12 00:17:29 +080011305 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053011306 /* Allocate memory for Device config params */
11307 adev->device_cfg_params = (struct audio_device_config_param*)
11308 calloc(platform_get_max_codec_backend(),
11309 sizeof(struct audio_device_config_param));
11310 if (adev->device_cfg_params == NULL)
11311 ALOGE("%s: Memory allocation failed for Device config params", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011312
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011313 /*
11314 * Check if new PSPD matrix mixer control is supported. If not
11315 * supported, then set flag so that old mixer ctrl is sent while
11316 * sending pspd coefficients on older kernel version. Query mixer
11317 * control for default pcm id and channel value one.
11318 */
11319 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
11320 "AudStr %d ChMixer Weight Ch %d", 0, 1);
11321
11322 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
11323 if (!ctl) {
11324 ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
11325 __func__, mixer_ctl_name);
11326 adev->use_old_pspd_mix_ctrl = true;
11327 }
11328
Jaideep Sharma0fa53812020-09-17 09:00:11 +053011329 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011330 return 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011331
11332adev_open_err:
11333 free_map(adev->patch_map);
11334 free_map(adev->io_streams_map);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080011335 free(adev->snd_dev_ref_cnt);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011336 pthread_mutex_destroy(&adev->lock);
11337 free(adev);
11338 adev = NULL;
11339 *device = NULL;
11340 pthread_mutex_unlock(&adev_init_lock);
11341 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011342}
11343
11344static struct hw_module_methods_t hal_module_methods = {
11345 .open = adev_open,
11346};
11347
11348struct audio_module HAL_MODULE_INFO_SYM = {
11349 .common = {
11350 .tag = HARDWARE_MODULE_TAG,
11351 .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
11352 .hal_api_version = HARDWARE_HAL_API_VERSION,
11353 .id = AUDIO_HARDWARE_MODULE_ID,
11354 .name = "QCOM Audio HAL",
Duy Truongfae19622013-11-24 02:17:54 -080011355 .author = "The Linux Foundation",
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011356 .methods = &hal_module_methods,
11357 },
11358};