blob: 24176782df89add0ff7cc6f16b0a3df0f52142ad [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
Dechen Chai22768452021-07-30 09:29:16 +0530151#ifdef LINUX_ENABLED
152static inline int64_t audio_utils_ns_from_timespec(const struct timespec *ts)
153{
154 return ts->tv_sec * 1000000000LL + ts->tv_nsec;
155}
156#endif
157
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -0700158static unsigned int configured_low_latency_capture_period_size =
159 LOW_LATENCY_CAPTURE_PERIOD_SIZE;
160
Haynes Mathew George16081042017-05-31 17:16:49 -0700161#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
162#define MMAP_PERIOD_COUNT_MIN 32
163#define MMAP_PERIOD_COUNT_MAX 512
164#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
165
Aalique Grahame22e49102018-12-18 14:23:57 -0800166/* This constant enables extended precision handling.
167 * TODO The flag is off until more testing is done.
168 */
169static const bool k_enable_extended_precision = false;
Arun Mirpurie008ed22019-03-21 11:21:04 -0700170extern int AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
Aalique Grahame22e49102018-12-18 14:23:57 -0800171
Eric Laurentb23d5282013-05-14 15:27:20 -0700172struct pcm_config pcm_config_deep_buffer = {
173 .channels = 2,
174 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
175 .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
176 .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
177 .format = PCM_FORMAT_S16_LE,
178 .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
179 .stop_threshold = INT_MAX,
180 .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
181};
182
183struct pcm_config pcm_config_low_latency = {
184 .channels = 2,
185 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
186 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
187 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
188 .format = PCM_FORMAT_S16_LE,
189 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
190 .stop_threshold = INT_MAX,
191 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
192};
193
Vignesh Kulothungana6927272019-02-20 15:17:07 -0800194struct pcm_config pcm_config_haptics_audio = {
195 .channels = 1,
196 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
197 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
198 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
199 .format = PCM_FORMAT_S16_LE,
200 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
201 .stop_threshold = INT_MAX,
202 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
203};
204
205struct pcm_config pcm_config_haptics = {
206 .channels = 1,
207 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
208 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
209 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
210 .format = PCM_FORMAT_S16_LE,
211 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
212 .stop_threshold = INT_MAX,
213 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
214};
215
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700216static int af_period_multiplier = 4;
217struct pcm_config pcm_config_rt = {
218 .channels = 2,
219 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
220 .period_size = ULL_PERIOD_SIZE, //1 ms
221 .period_count = 512, //=> buffer size is 512ms
222 .format = PCM_FORMAT_S16_LE,
223 .start_threshold = ULL_PERIOD_SIZE*8, //8ms
224 .stop_threshold = INT_MAX,
225 .silence_threshold = 0,
226 .silence_size = 0,
227 .avail_min = ULL_PERIOD_SIZE, //1 ms
228};
229
Eric Laurentb23d5282013-05-14 15:27:20 -0700230struct pcm_config pcm_config_hdmi_multi = {
231 .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
232 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
233 .period_size = HDMI_MULTI_PERIOD_SIZE,
234 .period_count = HDMI_MULTI_PERIOD_COUNT,
235 .format = PCM_FORMAT_S16_LE,
236 .start_threshold = 0,
237 .stop_threshold = INT_MAX,
238 .avail_min = 0,
239};
240
Haynes Mathew George16081042017-05-31 17:16:49 -0700241struct pcm_config pcm_config_mmap_playback = {
242 .channels = 2,
243 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
244 .period_size = MMAP_PERIOD_SIZE,
245 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
246 .format = PCM_FORMAT_S16_LE,
247 .start_threshold = MMAP_PERIOD_SIZE*8,
248 .stop_threshold = INT32_MAX,
249 .silence_threshold = 0,
250 .silence_size = 0,
251 .avail_min = MMAP_PERIOD_SIZE, //1 ms
252};
253
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700254struct pcm_config pcm_config_hifi = {
255 .channels = DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
256 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
257 .period_size = HIFI_BUFFER_OUTPUT_PERIOD_SIZE, /* change #define */
258 .period_count = HIFI_BUFFER_OUTPUT_PERIOD_COUNT,
259 .format = PCM_FORMAT_S24_3LE,
260 .start_threshold = 0,
261 .stop_threshold = INT_MAX,
262 .avail_min = 0,
263};
264
Eric Laurentb23d5282013-05-14 15:27:20 -0700265struct pcm_config pcm_config_audio_capture = {
266 .channels = 2,
Eric Laurentb23d5282013-05-14 15:27:20 -0700267 .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
268 .format = PCM_FORMAT_S16_LE,
269};
270
Haynes Mathew George16081042017-05-31 17:16:49 -0700271struct pcm_config pcm_config_mmap_capture = {
272 .channels = 2,
273 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
274 .period_size = MMAP_PERIOD_SIZE,
275 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
276 .format = PCM_FORMAT_S16_LE,
277 .start_threshold = 0,
278 .stop_threshold = INT_MAX,
279 .silence_threshold = 0,
280 .silence_size = 0,
281 .avail_min = MMAP_PERIOD_SIZE, //1 ms
282};
283
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700284#define AFE_PROXY_CHANNEL_COUNT 2
285#define AFE_PROXY_SAMPLING_RATE 48000
286
287#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768
288#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
289
290struct pcm_config pcm_config_afe_proxy_playback = {
291 .channels = AFE_PROXY_CHANNEL_COUNT,
292 .rate = AFE_PROXY_SAMPLING_RATE,
293 .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
294 .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
295 .format = PCM_FORMAT_S16_LE,
296 .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
297 .stop_threshold = INT_MAX,
298 .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
299};
300
301#define AFE_PROXY_RECORD_PERIOD_SIZE 768
302#define AFE_PROXY_RECORD_PERIOD_COUNT 4
303
Aalique Grahame22e49102018-12-18 14:23:57 -0800304struct pcm_config pcm_config_audio_capture_rt = {
305 .channels = 2,
306 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
307 .period_size = ULL_PERIOD_SIZE,
308 .period_count = 512,
309 .format = PCM_FORMAT_S16_LE,
310 .start_threshold = 0,
311 .stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
312 .silence_threshold = 0,
313 .silence_size = 0,
314 .avail_min = ULL_PERIOD_SIZE, //1 ms
315};
316
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700317struct pcm_config pcm_config_afe_proxy_record = {
318 .channels = AFE_PROXY_CHANNEL_COUNT,
319 .rate = AFE_PROXY_SAMPLING_RATE,
320 .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
321 .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
322 .format = PCM_FORMAT_S16_LE,
323 .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
324 .stop_threshold = INT_MAX,
325 .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
326};
327
Ashish Jainf1eaa582016-05-23 20:54:24 +0530328#define AUDIO_MAX_PCM_FORMATS 7
329
330const uint32_t format_to_bitwidth_table[AUDIO_MAX_PCM_FORMATS] = {
331 [AUDIO_FORMAT_DEFAULT] = 0,
332 [AUDIO_FORMAT_PCM_16_BIT] = sizeof(uint16_t),
333 [AUDIO_FORMAT_PCM_8_BIT] = sizeof(uint8_t),
334 [AUDIO_FORMAT_PCM_32_BIT] = sizeof(uint32_t),
335 [AUDIO_FORMAT_PCM_8_24_BIT] = sizeof(uint32_t),
336 [AUDIO_FORMAT_PCM_FLOAT] = sizeof(float),
337 [AUDIO_FORMAT_PCM_24_BIT_PACKED] = sizeof(uint8_t) * 3,
338};
339
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -0800340const char * const use_case_table[AUDIO_USECASE_MAX] = {
Eric Laurentb23d5282013-05-14 15:27:20 -0700341 [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
342 [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
Vignesh Kulothungana6927272019-02-20 15:17:07 -0800343 [USECASE_AUDIO_PLAYBACK_WITH_HAPTICS] = "audio-with-haptics-playback",
Meng Wang51d8c2a2020-04-27 15:23:21 +0800344 [USECASE_AUDIO_PLAYBACK_HAPTICS] = "haptics-playback",
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -0700345 [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
346 [USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
Shruthi Krishnaace10852013-10-25 14:32:12 -0700347 [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
vivek mehta446c3962015-09-14 10:57:35 -0700348 //Enabled for Direct_PCM
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700349 [USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
350 [USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
351 [USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
352 [USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
353 [USECASE_AUDIO_PLAYBACK_OFFLOAD6] = "compress-offload-playback6",
354 [USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
355 [USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
356 [USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
Haynes Mathew George16081042017-05-31 17:16:49 -0700357 [USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
358 [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback",
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700359 [USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
Aalique Grahame22e49102018-12-18 14:23:57 -0800360 [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
vivek mehta0ea887a2015-08-26 14:01:20 -0700361
Eric Laurentb23d5282013-05-14 15:27:20 -0700362 [USECASE_AUDIO_RECORD] = "audio-record",
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530363 [USECASE_AUDIO_RECORD2] = "audio-record2",
364 [USECASE_AUDIO_RECORD3] = "audio-record3",
Mingming Yine62d7842013-10-25 16:26:03 -0700365 [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
Dhananjay Kumaree4d2002016-10-25 18:02:58 +0530366 [USECASE_AUDIO_RECORD_COMPRESS2] = "audio-record-compress2",
367 [USECASE_AUDIO_RECORD_COMPRESS3] = "audio-record-compress3",
368 [USECASE_AUDIO_RECORD_COMPRESS4] = "audio-record-compress4",
Dhananjay Kumar376e38b2017-09-28 22:26:23 +0530369 [USECASE_AUDIO_RECORD_COMPRESS5] = "audio-record-compress5",
370 [USECASE_AUDIO_RECORD_COMPRESS6] = "audio-record-compress6",
Eric Laurentb23d5282013-05-14 15:27:20 -0700371 [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
Preetam Singh Ranawatde84f1a2013-11-01 14:58:16 -0700372 [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700373 [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700374 [USECASE_AUDIO_RECORD_HIFI] = "hifi-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700375
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800376 [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800377 [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
Derek Chenf7092792017-05-23 12:23:53 -0400378 [USECASE_AUDIO_HFP_SCO_DOWNLINK] = "hfp-sco-downlink",
379 [USECASE_AUDIO_HFP_SCO_WB_DOWNLINK] = "hfp-sco-wb-downlink",
Mingming Yin3ee55c62014-08-04 14:23:35 -0700380
Derek Chenf7092792017-05-23 12:23:53 -0400381 [USECASE_VOICE_CALL] = "voice-call",
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700382 [USECASE_VOICE2_CALL] = "voice2-call",
383 [USECASE_VOLTE_CALL] = "volte-call",
384 [USECASE_QCHAT_CALL] = "qchat-call",
Vicky Sehrawat7e4fc152014-02-12 17:58:59 -0800385 [USECASE_VOWLAN_CALL] = "vowlan-call",
Vidyakumar Athota0e109352015-02-12 17:38:22 -0800386 [USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
387 [USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
Narsinga Rao Chella05573b72013-11-15 15:21:40 -0800388 [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
Shiv Maliyappanahallida107642013-10-17 11:16:13 -0700389 [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
390 [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
391 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
Helen Zenge56b4852013-12-03 16:54:40 -0800392 [USECASE_INCALL_REC_UPLINK_COMPRESS] = "incall-rec-uplink-compress",
393 [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = "incall-rec-downlink-compress",
394 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = "incall-rec-uplink-and-downlink-compress",
395
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700396 [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
397 [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -0700398 [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
399 [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700400
401 [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
402 [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
Zhou Song62ea0282020-03-22 19:53:01 +0800403 [USECASE_AUDIO_RECORD_AFE_PROXY2] = "afe-proxy-record2",
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +0530404 [USECASE_AUDIO_PLAYBACK_SILENCE] = "silence-playback",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700405
Siddartha Shaik31b530e2017-05-19 15:26:33 +0530406 /* Transcode loopback cases */
Surendar Karka93cd25a2018-08-28 14:21:37 +0530407 [USECASE_AUDIO_TRANSCODE_LOOPBACK_RX] = "audio-transcode-loopback-rx",
408 [USECASE_AUDIO_TRANSCODE_LOOPBACK_TX] = "audio-transcode-loopback-tx",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700409
410 [USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
411 [USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530412 [USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY] = "audio-record-voip-low-latency",
Varun Balaraje49253e2017-07-06 19:48:56 +0530413 /* For Interactive Audio Streams */
414 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] = "audio-interactive-stream1",
415 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] = "audio-interactive-stream2",
416 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] = "audio-interactive-stream3",
417 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] = "audio-interactive-stream4",
418 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] = "audio-interactive-stream5",
419 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] = "audio-interactive-stream6",
420 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
421 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
Garmond Leunge2433c32017-09-28 21:51:22 -0700422
Aniket Kumar Lata7fd86e12018-02-20 19:26:10 -0800423 [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",
424
Derek Chenf6318be2017-06-12 17:16:24 -0400425 [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback",
426
427 [USECASE_AUDIO_PLAYBACK_MEDIA] = "media-playback",
428 [USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION] = "sys-notification-playback",
429 [USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE] = "nav-guidance-playback",
430 [USECASE_AUDIO_PLAYBACK_PHONE] = "phone-playback",
Derek Chen1bcdc6b2020-02-06 22:44:53 -0800431 [USECASE_AUDIO_PLAYBACK_FRONT_PASSENGER] = "front-passenger-playback",
Derek Chendf05eea2019-08-01 13:57:49 -0700432 [USECASE_AUDIO_PLAYBACK_REAR_SEAT] = "rear-seat-playback",
Rahul Sharma99770982019-03-06 17:05:26 +0530433 [USECASE_AUDIO_FM_TUNER_EXT] = "fm-tuner-ext",
Derek Chena30a5f42019-12-03 11:17:09 -0500434 [USECASE_ICC_CALL] = "icc-call",
Huicheng Liu1404ba12020-09-11 01:03:25 -0400435
436 [USECASE_AUDIO_RECORD_BUS] = "audio-record",
437 [USECASE_AUDIO_RECORD_BUS_FRONT_PASSENGER] = "front-passenger-record",
438 [USECASE_AUDIO_RECORD_BUS_REAR_SEAT] = "rear-seat-record",
Fei Tongaffdf732020-02-20 20:39:05 +0800439 [USECASE_AUDIO_PLAYBACK_SYNTHESIZER] = "synth-loopback",
Susan Wange3959562021-03-11 11:50:26 -0500440 [USECASE_AUDIO_RECORD_ECHO_REF_EXT] = "echo-reference-external",
Eric Laurentb23d5282013-05-14 15:27:20 -0700441};
442
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700443static const audio_usecase_t offload_usecases[] = {
444 USECASE_AUDIO_PLAYBACK_OFFLOAD,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700445 USECASE_AUDIO_PLAYBACK_OFFLOAD2,
446 USECASE_AUDIO_PLAYBACK_OFFLOAD3,
447 USECASE_AUDIO_PLAYBACK_OFFLOAD4,
448 USECASE_AUDIO_PLAYBACK_OFFLOAD5,
449 USECASE_AUDIO_PLAYBACK_OFFLOAD6,
450 USECASE_AUDIO_PLAYBACK_OFFLOAD7,
451 USECASE_AUDIO_PLAYBACK_OFFLOAD8,
452 USECASE_AUDIO_PLAYBACK_OFFLOAD9,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700453};
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800454
Varun Balaraje49253e2017-07-06 19:48:56 +0530455static const audio_usecase_t interactive_usecases[] = {
456 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
457 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
458 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
459 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
460 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
461 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
462 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
463 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
464};
465
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800466#define STRING_TO_ENUM(string) { #string, string }
467
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800468struct string_to_enum {
469 const char *name;
470 uint32_t value;
471};
472
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700473static const struct string_to_enum channels_name_to_enum_table[] = {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800474 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
Mingming Yin3a941d42016-02-17 18:08:05 -0800475 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
476 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
477 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -0700478 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
Mingming Yin3a941d42016-02-17 18:08:05 -0800479 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
480 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800481 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700482 STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
483 STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
484 STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
485 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
486 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
487 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
488 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
489 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
490 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
491 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
492 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800493};
494
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700495static const struct string_to_enum formats_name_to_enum_table[] = {
496 STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
497 STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
498 STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700499 STRING_TO_ENUM(AUDIO_FORMAT_AC3),
500 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
501 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
Ben Romberger1aaaf862017-04-06 17:49:46 -0700502 STRING_TO_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
Mingming Yin3a941d42016-02-17 18:08:05 -0800503 STRING_TO_ENUM(AUDIO_FORMAT_DTS),
504 STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
Naresh Tanniru928f0862017-04-07 16:44:23 -0700505 STRING_TO_ENUM(AUDIO_FORMAT_IEC61937)
Mingming Yin3a941d42016-02-17 18:08:05 -0800506};
507
508//list of all supported sample rates by HDMI specification.
509static const int out_hdmi_sample_rates[] = {
510 32000, 44100, 48000, 88200, 96000, 176400, 192000,
511};
512
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700513static const struct string_to_enum out_sample_rates_name_to_enum_table[] = {
Mingming Yin3a941d42016-02-17 18:08:05 -0800514 STRING_TO_ENUM(32000),
515 STRING_TO_ENUM(44100),
516 STRING_TO_ENUM(48000),
517 STRING_TO_ENUM(88200),
518 STRING_TO_ENUM(96000),
519 STRING_TO_ENUM(176400),
520 STRING_TO_ENUM(192000),
Mingshu pange8aedf12019-10-25 15:38:27 +0800521 STRING_TO_ENUM(352800),
522 STRING_TO_ENUM(384000),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700523};
524
Carter Hsu2e429db2019-05-14 18:50:52 +0800525struct in_effect_list {
526 struct listnode list;
527 effect_handle_t handle;
528};
529
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530530static const audio_usecase_t record_usecases[] = {
531 USECASE_AUDIO_RECORD,
532 USECASE_AUDIO_RECORD2,
533 USECASE_AUDIO_RECORD3,
534};
535
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -0700536static struct audio_device *adev = NULL;
Ben Romberger02ab1192018-05-24 12:10:08 -0700537static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
Kiran Kandi910e1862013-10-29 13:29:42 -0700538static unsigned int audio_device_ref_count;
vivek mehtab72d08d2016-04-29 03:16:47 -0700539//cache last MBDRC cal step level
540static int last_known_cal_step = -1 ;
Kiran Kandi910e1862013-10-29 13:29:42 -0700541
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +0530542static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
Arun Mirpuri5d170872019-03-26 13:21:31 -0700543static int out_set_mmap_volume(struct audio_stream_out *stream, float left, float right);
Zhou Song2b8f28f2017-09-11 10:51:38 +0800544static int out_set_voip_volume(struct audio_stream_out *stream, float left, float right);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +0530545static int out_set_pcm_volume(struct audio_stream_out *stream, float left, float right);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +0530546
Derek Chen6f293672019-04-01 01:40:24 -0700547static void adev_snd_mon_cb(void *cookie, struct str_parms *parms);
548static void in_snd_mon_cb(void * stream, struct str_parms * parms);
549static void out_snd_mon_cb(void * stream, struct str_parms * parms);
550
Zhou Song331c8e52019-08-26 14:16:12 +0800551static int configure_btsco_sample_rate(snd_device_t snd_device);
552
Vatsal Buchac09ae062018-11-14 13:25:08 +0530553#ifdef AUDIO_FEATURE_ENABLED_GCOV
554extern void __gcov_flush();
555static void enable_gcov()
556{
557 __gcov_flush();
558}
559#else
560static void enable_gcov()
561{
562}
563#endif
564
justinweng20fb6d82019-02-21 18:49:00 -0700565static int in_set_microphone_direction(const struct audio_stream_in *stream,
566 audio_microphone_direction_t dir);
567static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom);
568
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +0530569static bool is_pcm_record_usecase(audio_usecase_t uc_id)
570{
571 unsigned int record_uc_index;
572 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
573
574 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
575 if (uc_id == record_usecases[record_uc_index])
576 return true;
577 }
578 return false;
579}
580
581static audio_usecase_t get_record_usecase(struct audio_device *adev)
582{
583 audio_usecase_t ret_uc = USECASE_INVALID;
584 unsigned int record_uc_index;
585 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
586
587 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
588 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
589 if (!(adev->pcm_record_uc_state & (0x1 << record_uc_index))) {
590 adev->pcm_record_uc_state |= 0x1 << record_uc_index;
591 ret_uc = record_usecases[record_uc_index];
592 break;
593 }
594 }
595
596 ALOGV("%s: pcm record usecase is %d", __func__, ret_uc);
597 return ret_uc;
598}
599
600static void free_record_usecase(struct audio_device *adev,
601 audio_usecase_t uc_id)
602{
603 unsigned int record_uc_index;
604 unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
605
606 for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
607 if (record_usecases[record_uc_index] == uc_id) {
608 adev->pcm_record_uc_state &= ~(0x1 << record_uc_index);
609 break;
610 }
611 }
612 ALOGV("%s: free pcm record usecase %d", __func__, uc_id);
613}
614
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700615static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id,
616 int flags __unused)
617{
618 int dir = 0;
619 switch (uc_id) {
620 case USECASE_AUDIO_RECORD_LOW_LATENCY:
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530621 case USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY:
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700622 dir = 1;
623 case USECASE_AUDIO_PLAYBACK_ULL:
624 break;
625 default:
626 return false;
627 }
628
629 int dev_id = platform_get_pcm_device_id(uc_id, dir == 0 ?
630 PCM_PLAYBACK : PCM_CAPTURE);
631 if (adev->adm_is_noirq_avail)
632 return adev->adm_is_noirq_avail(adev->adm_data,
633 adev->snd_card, dev_id, dir);
634 return false;
635}
636
637static void register_out_stream(struct stream_out *out)
638{
639 struct audio_device *adev = out->dev;
640 if (is_offload_usecase(out->usecase) ||
641 !adev->adm_register_output_stream)
642 return;
643
644 // register stream first for backward compatibility
645 adev->adm_register_output_stream(adev->adm_data,
646 out->handle,
647 out->flags);
648
649 if (!adev->adm_set_config)
650 return;
651
652 if (out->realtime)
653 adev->adm_set_config(adev->adm_data,
654 out->handle,
655 out->pcm, &out->config);
656}
657
658static void register_in_stream(struct stream_in *in)
659{
660 struct audio_device *adev = in->dev;
661 if (!adev->adm_register_input_stream)
662 return;
663
664 adev->adm_register_input_stream(adev->adm_data,
665 in->capture_handle,
666 in->flags);
667
668 if (!adev->adm_set_config)
669 return;
670
671 if (in->realtime)
672 adev->adm_set_config(adev->adm_data,
673 in->capture_handle,
674 in->pcm,
675 &in->config);
676}
677
678static void request_out_focus(struct stream_out *out, long ns)
679{
680 struct audio_device *adev = out->dev;
681
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700682 if (adev->adm_request_focus_v2)
683 adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
684 else if (adev->adm_request_focus)
685 adev->adm_request_focus(adev->adm_data, out->handle);
686}
687
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700688static int request_in_focus(struct stream_in *in, long ns)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700689{
690 struct audio_device *adev = in->dev;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700691 int ret = 0;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700692
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700693 if (adev->adm_request_focus_v2_1)
694 ret = adev->adm_request_focus_v2_1(adev->adm_data, in->capture_handle, ns);
695 else if (adev->adm_request_focus_v2)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700696 adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
697 else if (adev->adm_request_focus)
698 adev->adm_request_focus(adev->adm_data, in->capture_handle);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700699
700 return ret;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700701}
702
703static void release_out_focus(struct stream_out *out)
704{
705 struct audio_device *adev = out->dev;
706
707 if (adev->adm_abandon_focus)
708 adev->adm_abandon_focus(adev->adm_data, out->handle);
709}
710
711static void release_in_focus(struct stream_in *in)
712{
713 struct audio_device *adev = in->dev;
714 if (adev->adm_abandon_focus)
715 adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
716}
717
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530718static int parse_snd_card_status(struct str_parms *parms, int *card,
719 card_status_t *status)
720{
721 char value[32]={0};
722 char state[32]={0};
723
724 int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
725 if (ret < 0)
726 return -1;
727
728 // sscanf should be okay as value is of max length 32.
729 // same as sizeof state.
730 if (sscanf(value, "%d,%s", card, state) < 2)
731 return -1;
732
733 *status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
734 CARD_STATUS_OFFLINE;
735 return 0;
736}
737
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700738static inline void adjust_frames_for_device_delay(struct stream_out *out,
739 uint32_t *dsp_frames) {
740 // Adjustment accounts for A2dp encoder latency with offload usecases
741 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800742 if (is_a2dp_out_device_type(&out->device_list)) {
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700743 unsigned long offset =
744 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
745 *dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
746 }
747}
748
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700749static inline bool free_entry(void *key __unused,
750 void *value, void *context __unused)
751{
752 free(value);
753 return true;
754}
755
756static inline void free_map(Hashmap *map)
757{
758 if (map) {
759 hashmapForEach(map, free_entry, (void *) NULL);
760 hashmapFree(map);
761 }
762}
763
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800764static inline void patch_map_remove_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700765 audio_patch_handle_t patch_handle)
766{
767 if (patch_handle == AUDIO_PATCH_HANDLE_NONE)
768 return;
769
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700770 struct audio_patch_info *p_info =
771 hashmapGet(adev->patch_map, (void *) (intptr_t) patch_handle);
772 if (p_info) {
773 ALOGV("%s: Remove patch %d", __func__, patch_handle);
774 hashmapRemove(adev->patch_map, (void *) (intptr_t) patch_handle);
775 free(p_info->patch);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700776 free(p_info);
777 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700778}
779
780static inline int io_streams_map_insert(struct audio_device *adev,
781 struct audio_stream *stream,
782 audio_io_handle_t handle,
783 audio_patch_handle_t patch_handle)
784{
785 struct audio_stream_info *s_info =
786 (struct audio_stream_info *) calloc(1, sizeof(struct audio_stream_info));
787
788 if (s_info == NULL) {
789 ALOGE("%s: Could not allocate stream info", __func__);
790 return -ENOMEM;
791 }
792 s_info->stream = stream;
793 s_info->patch_handle = patch_handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700794
795 pthread_mutex_lock(&adev->lock);
796 struct audio_stream_info *stream_info =
797 hashmapPut(adev->io_streams_map, (void *) (intptr_t) handle, (void *) s_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700798 if (stream_info != NULL)
799 free(stream_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800800 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700801 ALOGV("%s: Added stream in io_streams_map with handle %d", __func__, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700802 return 0;
803}
804
805static inline void io_streams_map_remove(struct audio_device *adev,
806 audio_io_handle_t handle)
807{
808 pthread_mutex_lock(&adev->lock);
809 struct audio_stream_info *s_info =
810 hashmapRemove(adev->io_streams_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700811 if (s_info == NULL)
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800812 goto done;
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700813 ALOGV("%s: Removed stream with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800814 patch_map_remove_l(adev, s_info->patch_handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700815 free(s_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800816done:
817 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700818 return;
819}
820
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800821static struct audio_patch_info* fetch_patch_info_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700822 audio_patch_handle_t handle)
823{
824 struct audio_patch_info *p_info = NULL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700825 p_info = (struct audio_patch_info *)
826 hashmapGet(adev->patch_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700827 return p_info;
828}
829
vivek mehtaa76401a2015-04-24 14:12:15 -0700830__attribute__ ((visibility ("default")))
831bool audio_hw_send_gain_dep_calibration(int level) {
832 bool ret_val = false;
vivek mehtab72d08d2016-04-29 03:16:47 -0700833 ALOGV("%s: called ...", __func__);
vivek mehtaa76401a2015-04-24 14:12:15 -0700834
835 pthread_mutex_lock(&adev_init_lock);
836
837 if (adev != NULL && adev->platform != NULL) {
838 pthread_mutex_lock(&adev->lock);
839 ret_val = platform_send_gain_dep_cal(adev->platform, level);
vivek mehtab72d08d2016-04-29 03:16:47 -0700840
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +0530841 // cache level info for any of the use case which
842 // was not started.
843 last_known_cal_step = level;;
vivek mehtab72d08d2016-04-29 03:16:47 -0700844
vivek mehtaa76401a2015-04-24 14:12:15 -0700845 pthread_mutex_unlock(&adev->lock);
846 } else {
847 ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
848 }
849
850 pthread_mutex_unlock(&adev_init_lock);
851
852 return ret_val;
853}
854
Ashish Jain5106d362016-05-11 19:23:33 +0530855static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless)
856{
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800857 bool gapless_enabled = false;
858 const char *mixer_ctl_name = "Compress Gapless Playback";
859 struct mixer_ctl *ctl;
860
861 ALOGV("%s:", __func__);
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700862 gapless_enabled = property_get_bool("vendor.audio.offload.gapless.enabled", false);
Ashish Jain5106d362016-05-11 19:23:33 +0530863
864 /*Disable gapless if its AV playback*/
865 gapless_enabled = gapless_enabled && enable_gapless;
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800866
867 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
868 if (!ctl) {
869 ALOGE("%s: Could not get ctl for mixer cmd - %s",
870 __func__, mixer_ctl_name);
871 return -EINVAL;
872 }
873
874 if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) {
875 ALOGE("%s: Could not set gapless mode %d",
876 __func__, gapless_enabled);
877 return -EINVAL;
878 }
879 return 0;
880}
Haynes Mathew George5191a852013-09-11 14:19:36 -0700881
Aniket Kumar Lataf56b6402016-10-27 12:03:18 -0700882__attribute__ ((visibility ("default")))
883int audio_hw_get_gain_level_mapping(struct amp_db_and_gain_table *mapping_tbl,
884 int table_size) {
885 int ret_val = 0;
886 ALOGV("%s: enter ... ", __func__);
887
888 pthread_mutex_lock(&adev_init_lock);
889 if (adev == NULL) {
890 ALOGW("%s: adev is NULL .... ", __func__);
891 goto done;
892 }
893
894 pthread_mutex_lock(&adev->lock);
895 ret_val = platform_get_gain_level_mapping(mapping_tbl, table_size);
896 pthread_mutex_unlock(&adev->lock);
897done:
898 pthread_mutex_unlock(&adev_init_lock);
899 ALOGV("%s: exit ... ", __func__);
900 return ret_val;
901}
902
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800903bool audio_hw_send_qdsp_parameter(int stream_type, float vol, bool active)
Aalique Grahame22e49102018-12-18 14:23:57 -0800904{
905 bool ret = false;
906 ALOGV("%s: enter ...", __func__);
907
908 pthread_mutex_lock(&adev_init_lock);
909
910 if (adev != NULL && adev->platform != NULL) {
911 pthread_mutex_lock(&adev->lock);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800912 ret = audio_extn_qdsp_set_state(adev, stream_type, vol, active);
Aalique Grahame22e49102018-12-18 14:23:57 -0800913 pthread_mutex_unlock(&adev->lock);
914 }
915
916 pthread_mutex_unlock(&adev_init_lock);
917
918 ALOGV("%s: exit with ret %d", __func__, ret);
919 return ret;
920}
Aalique Grahame22e49102018-12-18 14:23:57 -0800921
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700922static bool is_supported_format(audio_format_t format)
923{
Eric Laurent86e17132013-09-12 17:49:30 -0700924 if (format == AUDIO_FORMAT_MP3 ||
Satish Babu Patakokila0c313922016-12-08 12:07:08 +0530925 format == AUDIO_FORMAT_MP2 ||
Ashish Jainf9b78162014-08-25 20:36:25 +0530926 format == AUDIO_FORMAT_AAC_LC ||
927 format == AUDIO_FORMAT_AAC_HE_V1 ||
928 format == AUDIO_FORMAT_AAC_HE_V2 ||
Manish Dewangana6fc5442015-08-24 20:30:31 +0530929 format == AUDIO_FORMAT_AAC_ADTS_LC ||
930 format == AUDIO_FORMAT_AAC_ADTS_HE_V1 ||
931 format == AUDIO_FORMAT_AAC_ADTS_HE_V2 ||
Arun Kumar Dasari3b174182016-12-27 13:01:14 +0530932 format == AUDIO_FORMAT_AAC_LATM_LC ||
933 format == AUDIO_FORMAT_AAC_LATM_HE_V1 ||
934 format == AUDIO_FORMAT_AAC_LATM_HE_V2 ||
Ashish Jain5106d362016-05-11 19:23:33 +0530935 format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
936 format == AUDIO_FORMAT_PCM_8_24_BIT ||
Ashish Jainf1eaa582016-05-23 20:54:24 +0530937 format == AUDIO_FORMAT_PCM_FLOAT ||
938 format == AUDIO_FORMAT_PCM_32_BIT ||
vivek mehta0ea887a2015-08-26 14:01:20 -0700939 format == AUDIO_FORMAT_PCM_16_BIT ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +0530940 format == AUDIO_FORMAT_AC3 ||
941 format == AUDIO_FORMAT_E_AC3 ||
Ben Romberger1aaaf862017-04-06 17:49:46 -0700942 format == AUDIO_FORMAT_DOLBY_TRUEHD ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +0530943 format == AUDIO_FORMAT_DTS ||
944 format == AUDIO_FORMAT_DTS_HD ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +0800945 format == AUDIO_FORMAT_FLAC ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +0530946 format == AUDIO_FORMAT_ALAC ||
947 format == AUDIO_FORMAT_APE ||
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +0530948 format == AUDIO_FORMAT_DSD ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +0530949 format == AUDIO_FORMAT_VORBIS ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +0800950 format == AUDIO_FORMAT_WMA ||
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +0530951 format == AUDIO_FORMAT_WMA_PRO ||
Naresh Tanniru928f0862017-04-07 16:44:23 -0700952 format == AUDIO_FORMAT_APTX ||
953 format == AUDIO_FORMAT_IEC61937)
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -0800954 return true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700955
956 return false;
957}
958
Kunlei Zhang67cc7072020-12-18 17:16:49 +0800959static bool is_supported_conc_usecase_for_power_mode_call(struct audio_device *adev)
960{
961 struct listnode *node;
962 struct audio_usecase *usecase;
963
964 list_for_each(node, &adev->usecase_list) {
965 usecase = node_to_item(node, struct audio_usecase, list);
966 if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
967 ALOGD("%s: FM usecase is active, not setting power mode", __func__);
968 return false;
969 }
970 }
971
972 return true;
973}
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700974static inline bool is_mmap_usecase(audio_usecase_t uc_id)
975{
976 return (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY) ||
Zhou Song62ea0282020-03-22 19:53:01 +0800977 (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY2) ||
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700978 (uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
979}
980
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -0700981static inline bool is_valid_volume(float left, float right)
982{
983 return ((left >= 0.0f && right >= 0.0f) ? true : false);
984}
985
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +0530986static void enable_asrc_mode(struct audio_device *adev)
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +0530987{
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +0530988 ALOGV("%s", __func__);
989 audio_route_apply_and_update_path(adev->audio_route,
990 "asrc-mode");
991 adev->asrc_mode_enabled = true;
992}
993
994static void disable_asrc_mode(struct audio_device *adev)
995{
996 ALOGV("%s", __func__);
997 audio_route_reset_and_update_path(adev->audio_route,
998 "asrc-mode");
999 adev->asrc_mode_enabled = false;
1000}
1001
Saurav Kumarc1411662020-10-14 10:50:45 +05301002static void check_and_configure_headphone(struct audio_device *adev,
1003 struct audio_usecase *uc_info,
1004 snd_device_t snd_device)
1005{
1006 struct listnode *node;
1007 struct audio_usecase *usecase;
1008 int new_backend_idx, usecase_backend_idx;
1009 bool spkr_hph_single_be_native_concurrency;
1010
1011 new_backend_idx = platform_get_backend_index(snd_device);
1012 spkr_hph_single_be_native_concurrency = platform_get_spkr_hph_single_be_native_concurrency_flag();
Zhou Songd4b18c42021-01-14 15:15:29 +08001013 if ((spkr_hph_single_be_native_concurrency && (new_backend_idx == DEFAULT_CODEC_BACKEND)) ||
1014 uc_info->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
Saurav Kumarc1411662020-10-14 10:50:45 +05301015 list_for_each(node, &adev->usecase_list) {
1016 usecase = node_to_item(node, struct audio_usecase, list);
1017 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info)) {
1018 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1019 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1020 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1021 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1022 disable_audio_route(adev, usecase);
1023 disable_snd_device(adev, usecase->out_snd_device);
1024 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
Saurav Kumar70902382020-10-28 11:16:04 +05301025 platform_check_and_set_codec_backend_cfg(adev, usecase,
1026 usecase->out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05301027 enable_snd_device(adev, usecase->out_snd_device);
Zhou Songd4b18c42021-01-14 15:15:29 +08001028 enable_audio_route(adev, usecase);
Saurav Kumarc1411662020-10-14 10:50:45 +05301029 }
1030 }
Revathi Uddaraju2c0eac02021-07-27 02:06:42 -07001031 else if ((usecase->type != PCM_CAPTURE) && (usecase == uc_info)) {
1032 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
1033 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
1034 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
1035 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
1036 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
1037 platform_check_and_set_codec_backend_cfg(adev, usecase,
1038 usecase->out_snd_device);
1039 }
1040 }
Saurav Kumarc1411662020-10-14 10:50:45 +05301041 }
1042 }
1043}
1044
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301045/*
1046 * - Enable ASRC mode for incoming mix path use case(Headphone backend)if Headphone
1047 * 44.1 or Native DSD backends are enabled for any of current use case.
1048 * e.g. 48-> + (Naitve DSD or Headphone 44.1)
1049 * - Disable current mix path use case(Headphone backend) and re-enable it with
1050 * ASRC mode for incoming Headphone 44.1 or Native DSD use case.
1051 * e.g. Naitve DSD or Headphone 44.1 -> + 48
1052 */
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301053static void check_and_set_asrc_mode(struct audio_device *adev,
1054 struct audio_usecase *uc_info,
1055 snd_device_t snd_device)
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301056{
1057 ALOGV("%s snd device %d", __func__, snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301058 int i, num_new_devices = 0;
1059 snd_device_t split_new_snd_devices[SND_DEVICE_OUT_END];
1060 /*
1061 *Split snd device for new combo use case
1062 *e.g. Headphopne 44.1-> + Ringtone (Headphone + Speaker)
1063 */
1064 if (platform_split_snd_device(adev->platform,
1065 snd_device,
1066 &num_new_devices,
1067 split_new_snd_devices) == 0) {
1068 for (i = 0; i < num_new_devices; i++)
1069 check_and_set_asrc_mode(adev, uc_info, split_new_snd_devices[i]);
1070 } else {
1071 int new_backend_idx = platform_get_backend_index(snd_device);
1072 if (((new_backend_idx == HEADPHONE_BACKEND) ||
1073 (new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1074 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1075 !adev->asrc_mode_enabled) {
1076 struct listnode *node = NULL;
1077 struct audio_usecase *uc = NULL;
1078 struct stream_out *curr_out = NULL;
1079 int usecase_backend_idx = DEFAULT_CODEC_BACKEND;
1080 int i, num_devices, ret = 0;
1081 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301082
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301083 list_for_each(node, &adev->usecase_list) {
1084 uc = node_to_item(node, struct audio_usecase, list);
1085 curr_out = (struct stream_out*) uc->stream.out;
1086 if (curr_out && PCM_PLAYBACK == uc->type && uc != uc_info) {
1087 /*
1088 *Split snd device for existing combo use case
1089 *e.g. Ringtone (Headphone + Speaker) + Headphopne 44.1
1090 */
1091 ret = platform_split_snd_device(adev->platform,
1092 uc->out_snd_device,
1093 &num_devices,
1094 split_snd_devices);
1095 if (ret < 0 || num_devices == 0) {
1096 ALOGV("%s: Unable to split uc->out_snd_device: %d",__func__, uc->out_snd_device);
1097 split_snd_devices[0] = uc->out_snd_device;
1098 num_devices = 1;
Garmond Leung50058f62017-02-08 09:49:30 -08001099 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301100 for (i = 0; i < num_devices; i++) {
1101 usecase_backend_idx = platform_get_backend_index(split_snd_devices[i]);
1102 ALOGD("%s:snd_dev %d usecase_backend_idx %d",__func__, split_snd_devices[i],usecase_backend_idx);
1103 if((new_backend_idx == HEADPHONE_BACKEND) &&
1104 ((usecase_backend_idx == HEADPHONE_44_1_BACKEND) ||
1105 (usecase_backend_idx == DSD_NATIVE_BACKEND))) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001106 ALOGV("%s:DSD or native stream detected enabling asrcmode in hardware",
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301107 __func__);
1108 enable_asrc_mode(adev);
1109 break;
1110 } else if(((new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1111 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1112 (usecase_backend_idx == HEADPHONE_BACKEND)) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001113 ALOGV("%s: 48K stream detected, disabling and enabling it \
1114 with asrcmode in hardware", __func__);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301115 disable_audio_route(adev, uc);
1116 disable_snd_device(adev, uc->out_snd_device);
1117 // Apply true-high-quality-mode if DSD or > 44.1KHz or >=24-bit
1118 if (new_backend_idx == DSD_NATIVE_BACKEND)
1119 audio_route_apply_and_update_path(adev->audio_route,
1120 "hph-true-highquality-mode");
1121 else if ((new_backend_idx == HEADPHONE_44_1_BACKEND) &&
1122 (curr_out->bit_width >= 24))
1123 audio_route_apply_and_update_path(adev->audio_route,
1124 "hph-highquality-mode");
1125 enable_asrc_mode(adev);
1126 enable_snd_device(adev, uc->out_snd_device);
1127 enable_audio_route(adev, uc);
1128 break;
1129 }
1130 }
1131 // reset split devices count
1132 num_devices = 0;
Garmond Leung50058f62017-02-08 09:49:30 -08001133 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301134 if (adev->asrc_mode_enabled)
1135 break;
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301136 }
1137 }
1138 }
1139}
1140
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001141static int send_effect_enable_disable_mixer_ctl(struct audio_device *adev,
1142 struct audio_effect_config effect_config,
1143 unsigned int param_value)
1144{
1145 char mixer_ctl_name[] = "Audio Effect";
1146 struct mixer_ctl *ctl;
1147 long set_values[6];
Eric Laurent637e2d42018-11-15 12:24:31 -08001148 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001149
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001150 if (in == NULL) {
1151 ALOGE("%s: active input stream is NULL", __func__);
1152 return -EINVAL;
1153 }
1154
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001155 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
1156 if (!ctl) {
1157 ALOGE("%s: Could not get mixer ctl - %s",
1158 __func__, mixer_ctl_name);
1159 return -EINVAL;
1160 }
1161
1162 set_values[0] = 1; //0:Rx 1:Tx
1163 set_values[1] = in->app_type_cfg.app_type;
1164 set_values[2] = (long)effect_config.module_id;
1165 set_values[3] = (long)effect_config.instance_id;
1166 set_values[4] = (long)effect_config.param_id;
1167 set_values[5] = param_value;
1168
1169 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
1170
1171 return 0;
1172
1173}
1174
1175static int update_effect_param_ecns(struct audio_device *adev, unsigned int module_id,
1176 int effect_type, unsigned int *param_value)
1177{
1178 int ret = 0;
1179 struct audio_effect_config other_effect_config;
1180 struct audio_usecase *usecase = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08001181 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001182
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001183 if (in == NULL) {
1184 ALOGE("%s: active input stream is NULL", __func__);
1185 return -EINVAL;
1186 }
1187
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001188 usecase = get_usecase_from_list(adev, in->usecase);
1189 if (!usecase)
1190 return -EINVAL;
1191
1192 ret = platform_get_effect_config_data(usecase->in_snd_device, &other_effect_config,
1193 effect_type == EFFECT_AEC ? EFFECT_NS : EFFECT_AEC);
1194 if (ret < 0) {
1195 ALOGE("%s Failed to get effect params %d", __func__, ret);
1196 return ret;
1197 }
1198
1199 if (module_id == other_effect_config.module_id) {
1200 //Same module id for AEC/NS. Values need to be combined
1201 if (((effect_type == EFFECT_AEC) && (in->enable_ns)) ||
1202 ((effect_type == EFFECT_NS) && (in->enable_aec))) {
1203 *param_value |= other_effect_config.param_value;
1204 }
1205 }
1206
1207 return ret;
1208}
1209
1210static int enable_disable_effect(struct audio_device *adev, int effect_type, bool enable)
Gangadhar Sb0210342019-02-22 17:39:41 +05301211{
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001212 struct audio_effect_config effect_config;
1213 struct audio_usecase *usecase = NULL;
1214 int ret = 0;
1215 unsigned int param_value = 0;
Eric Laurent637e2d42018-11-15 12:24:31 -08001216 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001217
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001218 if(!voice_extn_is_dynamic_ecns_enabled())
1219 return ENOSYS;
1220
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001221 if (!in) {
1222 ALOGE("%s: Invalid input stream", __func__);
1223 return -EINVAL;
1224 }
1225
1226 ALOGD("%s: effect_type:%d enable:%d", __func__, effect_type, enable);
1227
1228 usecase = get_usecase_from_list(adev, in->usecase);
Weiyin Jiang20d3fa62018-08-01 18:06:27 +08001229 if (usecase == NULL) {
1230 ALOGE("%s: Could not find the usecase (%d) in the list",
1231 __func__, in->usecase);
1232 return -EINVAL;
1233 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001234
1235 ret = platform_get_effect_config_data(usecase->in_snd_device, &effect_config, effect_type);
1236 if (ret < 0) {
1237 ALOGE("%s Failed to get module id %d", __func__, ret);
1238 return ret;
1239 }
1240 ALOGV("%s: %d %d usecase->id:%d usecase->in_snd_device:%d", __func__, effect_config.module_id,
1241 in->app_type_cfg.app_type, usecase->id, usecase->in_snd_device);
1242
1243 if(enable)
1244 param_value = effect_config.param_value;
1245
1246 /*Special handling for AEC & NS effects Param values need to be
1247 updated if module ids are same*/
1248
1249 if ((effect_type == EFFECT_AEC) || (effect_type == EFFECT_NS)) {
1250 ret = update_effect_param_ecns(adev, effect_config.module_id, effect_type, &param_value);
1251 if (ret < 0)
1252 return ret;
1253 }
1254
1255 ret = send_effect_enable_disable_mixer_ctl(adev, effect_config, param_value);
1256
1257 return ret;
1258}
1259
1260static void check_and_enable_effect(struct audio_device *adev)
1261{
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001262 if(!voice_extn_is_dynamic_ecns_enabled())
1263 return;
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001264
Eric Laurent637e2d42018-11-15 12:24:31 -08001265 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001266
Eric Laurent637e2d42018-11-15 12:24:31 -08001267 if (in != NULL && !in->standby) {
1268 if (in->enable_aec)
1269 enable_disable_effect(adev, EFFECT_AEC, true);
1270
1271 if (in->enable_ns &&
1272 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
1273 enable_disable_effect(adev, EFFECT_NS, true);
1274 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001275 }
1276}
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001277
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07001278int pcm_ioctl(struct pcm *pcm, int request, ...)
1279{
1280 va_list ap;
1281 void * arg;
1282 int pcm_fd = *(int*)pcm;
1283
1284 va_start(ap, request);
1285 arg = va_arg(ap, void *);
1286 va_end(ap);
1287
1288 return ioctl(pcm_fd, request, arg);
1289}
1290
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001291int enable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001292 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001293{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001294 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001295 char mixer_path[MIXER_PATH_MAX_LENGTH];
Manish Dewangan58229382017-02-02 15:48:41 +05301296 struct stream_out *out = NULL;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301297 struct stream_in *in = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001298 struct listnode out_devices;
Soumya Managoli6993b762018-06-28 16:04:57 +05301299 int ret = 0;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001300
1301 if (usecase == NULL)
1302 return -EINVAL;
1303
1304 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
1305
Carter Hsu2e429db2019-05-14 18:50:52 +08001306 if (usecase->type == PCM_CAPTURE) {
1307 struct stream_in *in = usecase->stream.in;
1308 struct audio_usecase *uinfo;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001309 snd_device = usecase->in_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001310
1311 if (in) {
1312 if (in->enable_aec || in->enable_ec_port) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001313 list_init(&out_devices);
1314 update_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "", true);
Carter Hsu2e429db2019-05-14 18:50:52 +08001315 struct listnode *node;
1316 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
1317 USECASE_AUDIO_PLAYBACK_VOIP);
1318 if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001319 assign_devices(&out_devices,
1320 &voip_usecase->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001321 } else if (adev->primary_output &&
1322 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001323 assign_devices(&out_devices,
1324 &adev->primary_output->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001325 } else {
1326 list_for_each(node, &adev->usecase_list) {
1327 uinfo = node_to_item(node, struct audio_usecase, list);
1328 if (uinfo->type != PCM_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001329 assign_devices(&out_devices,
1330 &uinfo->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001331 break;
1332 }
1333 }
1334 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001335
1336 platform_set_echo_reference(adev, true, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001337 in->ec_opened = true;
1338 }
1339 }
Guodong Huf5e614d2019-06-24 18:42:03 +08001340 } else if ((usecase->type == TRANSCODE_LOOPBACK_TX) || ((usecase->type == PCM_HFP_CALL) &&
1341 ((usecase->id == USECASE_AUDIO_HFP_SCO) || (usecase->id == USECASE_AUDIO_HFP_SCO_WB)) &&
1342 (usecase->in_snd_device == SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS))) {
Carter Hsu2e429db2019-05-14 18:50:52 +08001343 snd_device = usecase->in_snd_device;
1344 } else {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001345 snd_device = usecase->out_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001346 }
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001347
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001348 if (usecase->type == PCM_CAPTURE) {
1349 if (platform_get_fluence_nn_state(adev->platform) == 0) {
1350 platform_set_fluence_nn_state(adev->platform, true);
1351 ALOGD("%s: set fluence nn capture state", __func__);
1352 }
1353 }
1354
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08001355#ifdef DS1_DOLBY_DAP_ENABLED
1356 audio_extn_dolby_set_dmid(adev);
1357 audio_extn_dolby_set_endpoint(adev);
1358#endif
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -07001359 audio_extn_dolby_ds2_set_endpoint(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001360 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301361 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
Ben Romberger1fafdde2015-09-09 19:43:15 -07001362 audio_extn_utils_send_app_type_cfg(adev, usecase);
Jasmine Cha4dcc1092019-03-04 18:12:47 +08001363 if (audio_extn_is_maxx_audio_enabled())
1364 audio_extn_ma_set_device(usecase);
Dhananjay Kumar14170dd2015-08-28 13:24:16 +05301365 audio_extn_utils_send_audio_calibration(adev, usecase);
Zhou Songbaddf9f2020-11-20 13:57:39 +08001366 if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
1367 out = usecase->stream.out;
1368 if (out && out->compr)
Manish Dewangan58229382017-02-02 15:48:41 +05301369 audio_extn_utils_compress_set_clk_rec_mode(usecase);
1370 }
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301371
1372 if (usecase->type == PCM_CAPTURE) {
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001373 if (platform_get_fluence_nn_state(adev->platform) == 1 &&
1374 adev->fluence_nn_usecase_id == USECASE_INVALID ) {
1375 adev->fluence_nn_usecase_id = usecase->id;
1376 ALOGD("%s: assign fluence nn usecase %d", __func__, usecase->id);
1377 }
1378 }
1379
1380 if (usecase->type == PCM_CAPTURE) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301381 in = usecase->stream.in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001382 if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301383 ALOGD("%s: set custom mtmx params v1", __func__);
1384 audio_extn_set_custom_mtmx_params_v1(adev, usecase, true);
1385 }
1386 } else {
1387 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
1388 }
Manish Dewangan58229382017-02-02 15:48:41 +05301389
Andy Hung756ecc12018-10-19 17:47:12 -07001390 // we shouldn't truncate mixer_path
1391 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1392 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1393 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001394 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001395 ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
Soumya Managoli6993b762018-06-28 16:04:57 +05301396 ret = audio_route_apply_and_update_path(adev->audio_route, mixer_path);
1397 if (!ret && usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1398 struct str_parms *parms = str_parms_create_str("fm_restore_volume=1");
1399 if (parms) {
1400 audio_extn_fm_set_parameters(adev, parms);
1401 str_parms_destroy(parms);
1402 }
1403 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001404 ALOGV("%s: exit", __func__);
1405 return 0;
1406}
1407
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001408int disable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001409 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001410{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001411 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001412 char mixer_path[MIXER_PATH_MAX_LENGTH];
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301413 struct stream_in *in = NULL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001414
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05301415 if (usecase == NULL || usecase->id == USECASE_INVALID)
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001416 return -EINVAL;
1417
1418 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
Surendar Karka93cd25a2018-08-28 14:21:37 +05301419 if (usecase->type == PCM_CAPTURE || usecase->type == TRANSCODE_LOOPBACK_TX)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001420 snd_device = usecase->in_snd_device;
1421 else
1422 snd_device = usecase->out_snd_device;
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001423
1424 /* disable island and power mode on supported device for voice call */
1425 if (usecase->type == VOICE_CALL) {
1426 if (usecase->in_snd_device != SND_DEVICE_NONE) {
1427 if (platform_get_island_cfg_on_device(adev->platform, usecase->in_snd_device) &&
1428 platform_get_power_mode_on_device(adev->platform, usecase->in_snd_device)) {
1429 platform_set_island_cfg_on_device(adev, usecase->in_snd_device, false);
1430 platform_set_power_mode_on_device(adev, usecase->in_snd_device, false);
1431 platform_reset_island_power_status(adev->platform, usecase->in_snd_device);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001432 if (voice_is_lte_call_active(adev))
1433 platform_set_tx_lpi_mode(adev->platform, false);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001434 ALOGD("%s: disable island cfg and power mode in voice tx path",
1435 __func__);
1436 }
1437 }
1438 if (usecase->out_snd_device != SND_DEVICE_NONE) {
1439 if (platform_get_island_cfg_on_device(adev->platform, usecase->out_snd_device) &&
1440 platform_get_power_mode_on_device(adev->platform, usecase->out_snd_device)) {
1441 platform_set_island_cfg_on_device(adev, usecase->out_snd_device, false);
1442 platform_set_power_mode_on_device(adev, usecase->out_snd_device, false);
1443 platform_reset_island_power_status(adev->platform, usecase->out_snd_device);
1444 ALOGD("%s: disable island cfg and power mode in voice rx path",
1445 __func__);
1446 }
1447 }
1448 }
1449
Andy Hung756ecc12018-10-19 17:47:12 -07001450 // we shouldn't truncate mixer_path
1451 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1452 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1453 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001454 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001455 ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001456 audio_route_reset_and_update_path(adev->audio_route, mixer_path);
Carter Hsu2e429db2019-05-14 18:50:52 +08001457 if (usecase->type == PCM_CAPTURE) {
1458 struct stream_in *in = usecase->stream.in;
1459 if (in && in->ec_opened) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001460 struct listnode out_devices;
1461 list_init(&out_devices);
1462 platform_set_echo_reference(in->dev, false, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001463 in->ec_opened = false;
1464 }
1465 }
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001466 if (usecase->id == adev->fluence_nn_usecase_id) {
1467 platform_set_fluence_nn_state(adev->platform, false);
1468 adev->fluence_nn_usecase_id = USECASE_INVALID;
1469 ALOGD("%s: reset fluence nn capture state", __func__);
1470 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001471 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301472 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301473
1474 if (usecase->type == PCM_CAPTURE) {
1475 in = usecase->stream.in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001476 if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301477 ALOGD("%s: reset custom mtmx params v1", __func__);
1478 audio_extn_set_custom_mtmx_params_v1(adev, usecase, false);
1479 }
1480 } else {
1481 audio_extn_set_custom_mtmx_params_v2(adev, usecase, false);
1482 }
1483
Weiyin Jiang298ffd92019-06-03 14:29:30 +08001484 if ((usecase->type == PCM_PLAYBACK) &&
1485 (usecase->stream.out != NULL))
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05301486 usecase->stream.out->pspd_coeff_sent = false;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301487
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001488 ALOGV("%s: exit", __func__);
1489 return 0;
1490}
1491
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001492int enable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001493 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001494{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301495 int i, num_devices = 0;
1496 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001497 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1498
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001499 if (snd_device < SND_DEVICE_MIN ||
1500 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001501 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001502 return -EINVAL;
1503 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001504
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001505 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001506 ALOGE("%s: Invalid sound device returned", __func__);
1507 return -EINVAL;
1508 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001509
1510 adev->snd_dev_ref_cnt[snd_device]++;
1511
1512 if ((adev->snd_dev_ref_cnt[snd_device] > 1) &&
1513 (platform_split_snd_device(adev->platform,
1514 snd_device,
1515 &num_devices,
1516 new_snd_devices) != 0)) {
Eric Laurent994a6932013-07-17 11:51:42 -07001517 ALOGV("%s: snd_device(%d: %s) is already active",
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001518 __func__, snd_device, device_name);
Aniket Kumar Lata990de552019-07-11 14:20:23 -07001519 /* Set backend config for A2DP to ensure slimbus configuration
1520 is correct if A2DP is already active and backend is closed
1521 and re-opened */
1522 if (snd_device == SND_DEVICE_OUT_BT_A2DP)
1523 audio_extn_a2dp_set_source_backend_cfg();
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001524 return 0;
1525 }
1526
Gopikrishnaiah Anandane85d0462014-06-30 21:41:20 -07001527 if (audio_extn_spkr_prot_is_enabled())
1528 audio_extn_spkr_prot_calib_cancel(adev);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001529
Aalique Grahame22e49102018-12-18 14:23:57 -08001530 audio_extn_dsm_feedback_enable(adev, snd_device, true);
1531
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001532 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1533 audio_extn_spkr_prot_is_enabled()) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001534 if (platform_get_spkr_prot_acdb_id(snd_device) < 0) {
1535 goto err;
1536 }
1537 audio_extn_dev_arbi_acquire(snd_device);
1538 if (audio_extn_spkr_prot_start_processing(snd_device)) {
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001539 ALOGE("%s: spkr_start_processing failed", __func__);
Ravit Dennisaaee49c2015-02-04 21:26:22 +02001540 audio_extn_dev_arbi_release(snd_device);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001541 goto err;
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001542 }
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001543 } else if (platform_split_snd_device(adev->platform,
1544 snd_device,
1545 &num_devices,
1546 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301547 for (i = 0; i < num_devices; i++) {
1548 enable_snd_device(adev, new_snd_devices[i]);
1549 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001550 platform_set_speaker_gain_in_combo(adev, snd_device, true);
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001551 } else {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001552 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301553
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001554 /* enable island and power mode on supported device */
1555 if (platform_get_island_cfg_on_device(adev->platform, snd_device) &&
1556 platform_get_power_mode_on_device(adev->platform, snd_device)) {
1557 platform_set_island_cfg_on_device(adev, snd_device, true);
1558 platform_set_power_mode_on_device(adev, snd_device, true);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001559 if (voice_is_lte_call_active(adev) &&
1560 (snd_device >= SND_DEVICE_IN_BEGIN &&
1561 snd_device < SND_DEVICE_IN_END))
1562 platform_set_tx_lpi_mode(adev->platform, true);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001563 ALOGD("%s: enable island cfg and power mode on: %s",
1564 __func__, device_name);
1565 }
Preetam Singh Ranawatf1d417c2017-01-10 17:00:32 +05301566
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301567 if (SND_DEVICE_OUT_BT_A2DP == snd_device) {
Ramjee Singh2d2944a2021-12-14 14:13:41 +05301568
1569 struct audio_usecase *usecase;
1570 struct listnode *node;
1571 /* Disable SCO Devices and enable handset mic for active input stream */
1572 list_for_each(node, &adev->usecase_list) {
1573 usecase = node_to_item(node, struct audio_usecase, list);
1574 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
1575 is_sco_in_device_type(&usecase->stream.in->device_list)) {
1576 ALOGD("a2dp resumed, switch bt sco mic to handset mic");
1577 reassign_device_list(&usecase->stream.in->device_list,
1578 AUDIO_DEVICE_IN_BUILTIN_MIC, "");
1579 select_devices(adev, usecase->id);
1580 }
1581 }
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301582 if (audio_extn_a2dp_start_playback() < 0) {
1583 ALOGE(" fail to configure A2dp Source control path ");
1584 goto err;
1585 } else {
1586 adev->a2dp_started = true;
1587 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001588 }
Florian Pfister1a84f312018-07-19 14:38:18 +02001589
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001590 if ((SND_DEVICE_IN_BT_A2DP == snd_device) &&
1591 (audio_extn_a2dp_start_capture() < 0)) {
1592 ALOGE(" fail to configure A2dp Sink control path ");
1593 goto err;
1594 }
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301595
Mingshu Pang7be5b1d2020-03-04 15:24:38 +08001596 if ((SND_DEVICE_OUT_BT_SCO_SWB == snd_device) ||
1597 (SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC == snd_device) ||
1598 (SND_DEVICE_IN_BT_SCO_MIC_SWB == snd_device)) {
1599 if (!adev->bt_sco_on || (audio_extn_sco_start_configuration() < 0)) {
1600 ALOGE(" fail to configure sco control path ");
1601 goto err;
1602 }
Zhou Song12c29502019-03-16 10:37:18 +08001603 }
1604
Zhou Song331c8e52019-08-26 14:16:12 +08001605 configure_btsco_sample_rate(snd_device);
Bharath Ramachandramurthy0de16782014-03-28 21:34:33 -07001606 /* due to the possibility of calibration overwrite between listen
1607 and audio, notify listen hal before audio calibration is sent */
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001608 audio_extn_sound_trigger_update_device_status(snd_device,
1609 ST_EVENT_SND_DEVICE_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301610 audio_extn_listen_update_device_status(snd_device,
1611 LISTEN_EVENT_SND_DEVICE_BUSY);
Subhash Chandra Bose Naripeddy54274672014-03-10 14:51:02 -07001612 if (platform_get_snd_device_acdb_id(snd_device) < 0) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001613 audio_extn_sound_trigger_update_device_status(snd_device,
1614 ST_EVENT_SND_DEVICE_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301615 audio_extn_listen_update_device_status(snd_device,
1616 LISTEN_EVENT_SND_DEVICE_FREE);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001617 goto err;
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001618 }
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001619 audio_extn_dev_arbi_acquire(snd_device);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001620 audio_route_apply_and_update_path(adev->audio_route, device_name);
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301621
1622 if (SND_DEVICE_OUT_HEADPHONES == snd_device &&
1623 !adev->native_playback_enabled &&
1624 audio_is_true_native_stream_active(adev)) {
1625 ALOGD("%s: %d: napb: enabling native mode in hardware",
1626 __func__, __LINE__);
1627 audio_route_apply_and_update_path(adev->audio_route,
1628 "true-native-mode");
1629 adev->native_playback_enabled = true;
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301630 }
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +05301631 if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
1632 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001633 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001634 ALOGD("%s: init ec ref loopback", __func__);
1635 audio_extn_ffv_init_ec_ref_loopback(adev, snd_device);
1636 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001637 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001638 return 0;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001639err:
1640 adev->snd_dev_ref_cnt[snd_device]--;
1641 return -EINVAL;;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001642}
1643
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001644int disable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001645 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001646{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301647 int i, num_devices = 0;
1648 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001649 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1650
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001651 if (snd_device < SND_DEVICE_MIN ||
1652 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001653 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001654 return -EINVAL;
1655 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001656
1657 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
1658 ALOGE("%s: Invalid sound device returned", __func__);
1659 return -EINVAL;
1660 }
1661
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001662 if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
1663 ALOGE("%s: device ref cnt is already 0", __func__);
1664 return -EINVAL;
1665 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001666
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001667 adev->snd_dev_ref_cnt[snd_device]--;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001668
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001669
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001670 if (adev->snd_dev_ref_cnt[snd_device] == 0) {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001671 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301672
Aalique Grahame22e49102018-12-18 14:23:57 -08001673 audio_extn_dsm_feedback_enable(adev, snd_device, false);
1674
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001675 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1676 audio_extn_spkr_prot_is_enabled()) {
Anish Kumar46c7b872014-09-09 01:49:44 -07001677 audio_extn_spkr_prot_stop_processing(snd_device);
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07001678
1679 // when speaker device is disabled, reset swap.
1680 // will be renabled on usecase start
1681 platform_set_swap_channels(adev, false);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001682 } else if (platform_split_snd_device(adev->platform,
1683 snd_device,
1684 &num_devices,
1685 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301686 for (i = 0; i < num_devices; i++) {
1687 disable_snd_device(adev, new_snd_devices[i]);
1688 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001689 platform_set_speaker_gain_in_combo(adev, snd_device, false);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001690 } else {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001691 audio_route_reset_and_update_path(adev->audio_route, device_name);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001692 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001693
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301694 if (snd_device == SND_DEVICE_OUT_BT_A2DP) {
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301695 audio_extn_a2dp_stop_playback();
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301696 adev->a2dp_started = false;
1697 } else if (snd_device == SND_DEVICE_IN_BT_A2DP)
Florian Pfister1a84f312018-07-19 14:38:18 +02001698 audio_extn_a2dp_stop_capture();
Zhou Songd6d71752019-05-21 18:08:51 +08001699 else if ((snd_device == SND_DEVICE_OUT_HDMI) ||
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001700 (snd_device == SND_DEVICE_OUT_DISPLAY_PORT))
Ashish Jain81eb2a82015-05-13 10:52:34 +05301701 adev->is_channel_status_set = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001702 else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301703 adev->native_playback_enabled) {
1704 ALOGD("%s: %d: napb: disabling native mode in hardware",
1705 __func__, __LINE__);
1706 audio_route_reset_and_update_path(adev->audio_route,
1707 "true-native-mode");
1708 adev->native_playback_enabled = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001709 } else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301710 adev->asrc_mode_enabled) {
1711 ALOGD("%s: %d: disabling asrc mode in hardware", __func__, __LINE__);
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301712 disable_asrc_mode(adev);
1713 audio_route_apply_and_update_path(adev->audio_route, "hph-lowpower-mode");
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001714 } else if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
Dhanalakshmi Siddaniaf4bd622019-02-27 16:28:06 +05301715 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001716 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001717 ALOGD("%s: deinit ec ref loopback", __func__);
1718 audio_extn_ffv_deinit_ec_ref_loopback(adev, snd_device);
1719 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001720
1721 audio_extn_utils_release_snd_device(snd_device);
1722 } else {
1723 if (platform_split_snd_device(adev->platform,
1724 snd_device,
1725 &num_devices,
1726 new_snd_devices) == 0) {
1727 for (i = 0; i < num_devices; i++) {
1728 adev->snd_dev_ref_cnt[new_snd_devices[i]]--;
1729 }
1730 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001731 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001732
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001733 return 0;
1734}
1735
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001736/*
1737 legend:
1738 uc - existing usecase
1739 new_uc - new usecase
1740 d1, d11, d2 - SND_DEVICE enums
1741 a1, a2 - corresponding ANDROID device enums
1742 B1, B2 - backend strings
1743
1744case 1
1745 uc->dev d1 (a1) B1
1746 new_uc->dev d1 (a1), d2 (a2) B1, B2
1747
1748 resolution: disable and enable uc->dev on d1
1749
1750case 2
1751 uc->dev d1 (a1) B1
1752 new_uc->dev d11 (a1) B1
1753
1754 resolution: need to switch uc since d1 and d11 are related
1755 (e.g. speaker and voice-speaker)
1756 use ANDROID_DEVICE_OUT enums to match devices since SND_DEVICE enums may vary
1757
1758case 3
1759 uc->dev d1 (a1) B1
1760 new_uc->dev d2 (a2) B2
1761
1762 resolution: no need to switch uc
1763
1764case 4
1765 uc->dev d1 (a1) B1
1766 new_uc->dev d2 (a2) B1
1767
1768 resolution: disable enable uc-dev on d2 since backends match
1769 we cannot enable two streams on two different devices if they
1770 share the same backend. e.g. if offload is on speaker device using
1771 QUAD_MI2S backend and a low-latency stream is started on voice-handset
1772 using the same backend, offload must also be switched to voice-handset.
1773
1774case 5
1775 uc->dev d1 (a1) B1
1776 new_uc->dev d1 (a1), d2 (a2) B1
1777
1778 resolution: disable enable uc-dev on d2 since backends match
1779 we cannot enable two streams on two different devices if they
1780 share the same backend.
1781
1782case 6
1783 uc->dev d1 (a1) B1
1784 new_uc->dev d2 (a1) B2
1785
1786 resolution: no need to switch
1787
1788case 7
1789 uc->dev d1 (a1), d2 (a2) B1, B2
1790 new_uc->dev d1 (a1) B1
1791
1792 resolution: no need to switch
1793
Zhou Song4ba65882018-07-09 14:48:07 +08001794case 8
1795 uc->dev d1 (a1) B1
1796 new_uc->dev d11 (a1), d2 (a2) B1, B2
1797 resolution: compared to case 1, for this case, d1 and d11 are related
1798 then need to do the same as case 2 to siwtch to new uc
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301799
1800case 9
1801 uc->dev d1 (a1), d2(a2) B1 B2
1802 new_uc->dev d1 (a1), d22 (a2) B1, B2
1803 resolution: disable enable uc-dev on d2 since backends match
1804 we cannot enable two streams on two different devices if they
1805 share the same backend. This is special case for combo use case
1806 with a2dp and sco devices which uses same backend.
1807 e.g. speaker-a2dp and speaker-btsco
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001808*/
1809static snd_device_t derive_playback_snd_device(void * platform,
1810 struct audio_usecase *uc,
1811 struct audio_usecase *new_uc,
1812 snd_device_t new_snd_device)
1813{
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001814 struct listnode a1, a2;
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001815
1816 snd_device_t d1 = uc->out_snd_device;
1817 snd_device_t d2 = new_snd_device;
1818
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001819 list_init(&a1);
1820 list_init(&a2);
1821
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301822 switch (uc->type) {
Surendar Karka93cd25a2018-08-28 14:21:37 +05301823 case TRANSCODE_LOOPBACK_RX :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001824 assign_devices(&a1, &uc->stream.inout->out_config.device_list);
1825 assign_devices(&a2, &new_uc->stream.inout->out_config.device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301826 break;
1827 default :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001828 assign_devices(&a1, &uc->stream.out->device_list);
1829 assign_devices(&a2, &new_uc->stream.out->device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301830 break;
1831 }
1832
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001833 // Treat as a special case when a1 and a2 are not disjoint
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001834 if (!compare_devices(&a1, &a2) &&
1835 compare_devices_for_any_match(&a1 ,&a2)) {
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001836 snd_device_t d3[2];
1837 int num_devices = 0;
1838 int ret = platform_split_snd_device(platform,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001839 list_length(&a1) > 1 ? d1 : d2,
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001840 &num_devices,
1841 d3);
1842 if (ret < 0) {
1843 if (ret != -ENOSYS) {
1844 ALOGW("%s failed to split snd_device %d",
1845 __func__,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001846 list_length(&a1) > 1 ? d1 : d2);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001847 }
1848 goto end;
1849 }
1850
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001851 if (platform_check_backends_match(d3[0], d3[1])) {
1852 return d2; // case 5
1853 } else {
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301854 if ((list_length(&a1) > 1) && (list_length(&a2) > 1) &&
1855 platform_check_backends_match(d1, d2))
1856 return d2; //case 9
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001857 if (list_length(&a1) > 1)
Samyak Jaind826b502019-07-17 16:16:42 +05301858 return d1; //case 7
Garmond Leungb9eeba42018-09-18 11:10:41 -07001859 // check if d1 is related to any of d3's
1860 if (d1 == d3[0] || d1 == d3[1])
Zhou Song4ba65882018-07-09 14:48:07 +08001861 return d1; // case 1
1862 else
1863 return d3[1]; // case 8
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001864 }
1865 } else {
1866 if (platform_check_backends_match(d1, d2)) {
1867 return d2; // case 2, 4
1868 } else {
1869 return d1; // case 6, 3
1870 }
1871 }
1872
1873end:
1874 return d2; // return whatever was calculated before.
1875}
1876
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001877static void check_usecases_codec_backend(struct audio_device *adev,
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301878 struct audio_usecase *uc_info,
1879 snd_device_t snd_device)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001880{
1881 struct listnode *node;
1882 struct audio_usecase *usecase;
1883 bool switch_device[AUDIO_USECASE_MAX];
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301884 snd_device_t uc_derive_snd_device;
1885 snd_device_t derive_snd_device[AUDIO_USECASE_MAX];
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001886 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
1887 int i, num_uc_to_switch = 0, num_devices = 0;
kunleiz5cd52b82016-11-07 17:22:52 +08001888 int status = 0;
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301889 bool force_restart_session = false;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001890 /*
1891 * This function is to make sure that all the usecases that are active on
1892 * the hardware codec backend are always routed to any one device that is
1893 * handled by the hardware codec.
1894 * For example, if low-latency and deep-buffer usecases are currently active
1895 * on speaker and out_set_parameters(headset) is received on low-latency
1896 * output, then we have to make sure deep-buffer is also switched to headset,
1897 * because of the limitation that both the devices cannot be enabled
1898 * at the same time as they share the same backend.
1899 */
Mingming Yin3ee55c62014-08-04 14:23:35 -07001900 /*
1901 * This call is to check if we need to force routing for a particular stream
1902 * If there is a backend configuration change for the device when a
1903 * new stream starts, then ADM needs to be closed and re-opened with the new
1904 * configuraion. This call check if we need to re-route all the streams
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001905 * associated with the backend. Touch tone + 24 bit + native playback.
Mingming Yin3ee55c62014-08-04 14:23:35 -07001906 */
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001907 bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info,
1908 snd_device);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301909 /* For a2dp device reconfigure all active sessions
1910 * with new AFE encoder format based on a2dp state
1911 */
1912 if ((SND_DEVICE_OUT_BT_A2DP == snd_device ||
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301913 SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP == snd_device ||
1914 SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP == snd_device) &&
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301915 audio_extn_a2dp_is_force_device_switch()) {
1916 force_routing = true;
1917 force_restart_session = true;
1918 }
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001919
1920 /*
1921 * Island cfg and power mode config needs to set before AFE port start.
1922 * Set force routing in case of voice device was enable before.
1923 */
1924 if (uc_info->type == VOICE_CALL &&
1925 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08001926 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001927 platform_check_and_update_island_power_status(adev->platform,
1928 uc_info,
1929 snd_device)) {
1930 force_routing = true;
1931 ALOGD("%s:becf: force routing %d for power mode supported device",
1932 __func__, force_routing);
1933 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301934 ALOGD("%s:becf: force routing %d", __func__, force_routing);
1935
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001936 /* Disable all the usecases on the shared backend other than the
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08001937 * specified usecase.
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08001938 */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001939 for (i = 0; i < AUDIO_USECASE_MAX; i++)
1940 switch_device[i] = false;
1941
1942 list_for_each(node, &adev->usecase_list) {
1943 usecase = node_to_item(node, struct audio_usecase, list);
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001944
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301945 ALOGD("%s:becf: (%d) check_usecases curr device: %s, usecase device:%s "
1946 "backends match %d",__func__, i,
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301947 platform_get_snd_device_name(snd_device),
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301948 platform_get_snd_device_name(usecase->out_snd_device),
1949 platform_check_backends_match(snd_device, usecase->out_snd_device));
Rahul Sharma99770982019-03-06 17:05:26 +05301950 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
1951 (usecase->type != PCM_PASSTHROUGH)) {
Ashish Jain6a65b352017-03-21 17:24:40 +05301952 uc_derive_snd_device = derive_playback_snd_device(adev->platform,
1953 usecase, uc_info, snd_device);
1954 if (((uc_derive_snd_device != usecase->out_snd_device) || force_routing) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001955 (is_codec_backend_out_device_type(&usecase->device_list) ||
1956 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
1957 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_DEVICE) ||
1958 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_HEADSET) ||
1959 is_a2dp_out_device_type(&usecase->device_list) ||
1960 is_sco_out_device_type(&usecase->device_list)) &&
Ashish Jain6a65b352017-03-21 17:24:40 +05301961 ((force_restart_session) ||
1962 (platform_check_backends_match(snd_device, usecase->out_snd_device)))) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301963 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
1964 __func__, use_case_table[usecase->id],
1965 platform_get_snd_device_name(usecase->out_snd_device));
1966 disable_audio_route(adev, usecase);
1967 switch_device[usecase->id] = true;
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301968 /* Enable existing usecase on derived playback device */
1969 derive_snd_device[usecase->id] = uc_derive_snd_device;
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301970 num_uc_to_switch++;
Ashish Jain6a65b352017-03-21 17:24:40 +05301971 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001972 }
1973 }
1974
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301975 ALOGD("%s:becf: check_usecases num.of Usecases to switch %d", __func__,
1976 num_uc_to_switch);
1977
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001978 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001979 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001980
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05301981 /* Make sure the previous devices to be disabled first and then enable the
1982 selected devices */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001983 list_for_each(node, &adev->usecase_list) {
1984 usecase = node_to_item(node, struct audio_usecase, list);
1985 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001986 /* Check if output sound device to be switched can be split and if any
1987 of the split devices match with derived sound device */
1988 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
1989 &num_devices, split_snd_devices) == 0) {
1990 adev->snd_dev_ref_cnt[usecase->out_snd_device]--;
1991 for (i = 0; i < num_devices; i++) {
1992 /* Disable devices that do not match with derived sound device */
1993 if (split_snd_devices[i] != derive_snd_device[usecase->id])
1994 disable_snd_device(adev, split_snd_devices[i]);
1995 }
1996 } else {
1997 disable_snd_device(adev, usecase->out_snd_device);
1998 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001999 }
2000 }
2001
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002002 list_for_each(node, &adev->usecase_list) {
2003 usecase = node_to_item(node, struct audio_usecase, list);
2004 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08002005 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
2006 &num_devices, split_snd_devices) == 0) {
2007 /* Enable derived sound device only if it does not match with
2008 one of the split sound devices. This is because the matching
2009 sound device was not disabled */
2010 bool should_enable = true;
2011 for (i = 0; i < num_devices; i++) {
2012 if (derive_snd_device[usecase->id] == split_snd_devices[i]) {
2013 should_enable = false;
2014 break;
2015 }
2016 }
2017 if (should_enable)
2018 enable_snd_device(adev, derive_snd_device[usecase->id]);
2019 } else {
2020 enable_snd_device(adev, derive_snd_device[usecase->id]);
2021 }
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07002022 }
2023 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002024
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002025 /* Re-route all the usecases on the shared backend other than the
2026 specified usecase to new snd devices */
2027 list_for_each(node, &adev->usecase_list) {
2028 usecase = node_to_item(node, struct audio_usecase, list);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302029 /* Update the out_snd_device only before enabling the audio route */
2030 if (switch_device[usecase->id]) {
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05302031 usecase->out_snd_device = derive_snd_device[usecase->id];
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302032 ALOGD("%s:becf: enabling usecase (%s) on (%s)", __func__,
2033 use_case_table[usecase->id],
2034 platform_get_snd_device_name(usecase->out_snd_device));
2035 /* Update voc calibration before enabling Voice/VoIP route */
2036 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
2037 status = platform_switch_voice_call_device_post(adev->platform,
2038 usecase->out_snd_device,
2039 platform_get_input_snd_device(
2040 adev->platform, NULL,
2041 &uc_info->device_list,
2042 usecase->type));
2043 enable_audio_route(adev, usecase);
2044 if (usecase->stream.out && usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
2045 out_set_voip_volume(&usecase->stream.out->stream,
2046 usecase->stream.out->volume_l,
2047 usecase->stream.out->volume_r);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05302048 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002049 }
2050 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002051 }
2052}
2053
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302054static void check_usecases_capture_codec_backend(struct audio_device *adev,
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002055 struct audio_usecase *uc_info,
2056 snd_device_t snd_device)
2057{
2058 struct listnode *node;
2059 struct audio_usecase *usecase;
2060 bool switch_device[AUDIO_USECASE_MAX];
2061 int i, num_uc_to_switch = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002062 int backend_check_cond = is_codec_backend_out_device_type(&uc_info->device_list);
kunleiz5cd52b82016-11-07 17:22:52 +08002063 int status = 0;
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002064
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302065 bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
2066 snd_device);
2067 ALOGD("%s:becf: force routing %d", __func__, force_routing);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302068
2069 /*
2070 * Make sure out devices is checked against out codec backend device and
2071 * also in devices against in codec backend. Checking out device against in
2072 * codec backend or vice versa causes issues.
2073 */
2074 if (uc_info->type == PCM_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002075 backend_check_cond = is_codec_backend_in_device_type(&uc_info->device_list);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002076
2077 /*
2078 * Island cfg and power mode config needs to set before AFE port start.
2079 * Set force routing in case of voice device was enable before.
2080 */
2081
2082 if (uc_info->type == VOICE_CALL &&
2083 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002084 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002085 platform_check_and_update_island_power_status(adev->platform,
2086 uc_info,
2087 snd_device)) {
2088 force_routing = true;
2089 ALOGD("%s:becf: force routing %d for power mode supported device",
2090 __func__, force_routing);
2091 }
2092
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002093 /*
2094 * This function is to make sure that all the active capture usecases
2095 * are always routed to the same input sound device.
2096 * For example, if audio-record and voice-call usecases are currently
2097 * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
2098 * is received for voice call then we have to make sure that audio-record
2099 * usecase is also switched to earpiece i.e. voice-dmic-ef,
2100 * because of the limitation that two devices cannot be enabled
2101 * at the same time if they share the same backend.
2102 */
2103 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2104 switch_device[i] = false;
2105
2106 list_for_each(node, &adev->usecase_list) {
2107 usecase = node_to_item(node, struct audio_usecase, list);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302108 /*
2109 * TODO: Enhance below condition to handle BT sco/USB multi recording
2110 */
Jaideep Sharma477917f2020-03-13 18:13:33 +05302111
2112 bool capture_uc_needs_routing = usecase->type != PCM_PLAYBACK && (usecase != uc_info &&
2113 (usecase->in_snd_device != snd_device || force_routing));
2114 bool call_proxy_snd_device = platform_is_call_proxy_snd_device(snd_device) ||
2115 platform_is_call_proxy_snd_device(usecase->in_snd_device);
2116 if (capture_uc_needs_routing && !call_proxy_snd_device &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002117 ((backend_check_cond &&
2118 (is_codec_backend_in_device_type(&usecase->device_list) ||
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08002119 (usecase->type == VOIP_CALL))) ||
Carter Hsu1d2a0532018-10-04 09:24:36 +08002120 ((uc_info->type == VOICE_CALL &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002121 is_single_device_type_equal(&usecase->device_list,
2122 AUDIO_DEVICE_IN_VOICE_CALL)) ||
Anver sadhique4fdc6992022-01-21 12:26:28 +05302123 platform_check_all_backends_match(snd_device,\
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002124 usecase->in_snd_device))) &&
Anish Kumara020a7c2014-10-17 11:13:22 -07002125 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05302126 ALOGD("%s: Usecase (%s) is active on (%s) - disabling ..",
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002127 __func__, use_case_table[usecase->id],
Devin Kim1e5f3532013-08-09 07:48:29 -07002128 platform_get_snd_device_name(usecase->in_snd_device));
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002129 disable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002130 switch_device[usecase->id] = true;
2131 num_uc_to_switch++;
2132 }
2133 }
2134
2135 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002136 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002137
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302138 /* Make sure the previous devices to be disabled first and then enable the
2139 selected devices */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002140 list_for_each(node, &adev->usecase_list) {
2141 usecase = node_to_item(node, struct audio_usecase, list);
2142 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002143 disable_snd_device(adev, usecase->in_snd_device);
Shiv Maliyappanahalli80ac6282013-12-20 18:56:15 -08002144 }
2145 }
2146
2147 list_for_each(node, &adev->usecase_list) {
2148 usecase = node_to_item(node, struct audio_usecase, list);
2149 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002150 enable_snd_device(adev, snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002151 }
2152 }
2153
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002154 /* Re-route all the usecases on the shared backend other than the
2155 specified usecase to new snd devices */
2156 list_for_each(node, &adev->usecase_list) {
2157 usecase = node_to_item(node, struct audio_usecase, list);
2158 /* Update the in_snd_device only before enabling the audio route */
2159 if (switch_device[usecase->id] ) {
2160 usecase->in_snd_device = snd_device;
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302161 /* Update voc calibration before enabling Voice/VoIP route */
2162 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
2163 snd_device_t voip_snd_device;
2164 voip_snd_device = platform_get_output_snd_device(adev->platform,
2165 usecase->stream.out,
2166 usecase->type);
2167 status = platform_switch_voice_call_device_post(adev->platform,
2168 voip_snd_device,
2169 usecase->in_snd_device);
kunleiz5cd52b82016-11-07 17:22:52 +08002170 }
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302171 enable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002172 }
2173 }
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002174 }
2175}
2176
Mingming Yin3a941d42016-02-17 18:08:05 -08002177static void reset_hdmi_sink_caps(struct stream_out *out) {
2178 int i = 0;
2179
2180 for (i = 0; i<= MAX_SUPPORTED_CHANNEL_MASKS; i++) {
2181 out->supported_channel_masks[i] = 0;
2182 }
2183 for (i = 0; i<= MAX_SUPPORTED_FORMATS; i++) {
2184 out->supported_formats[i] = 0;
2185 }
2186 for (i = 0; i<= MAX_SUPPORTED_SAMPLE_RATES; i++) {
2187 out->supported_sample_rates[i] = 0;
2188 }
2189}
2190
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002191/* must be called with hw device mutex locked */
Mingming Yin3a941d42016-02-17 18:08:05 -08002192static int read_hdmi_sink_caps(struct stream_out *out)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002193{
Mingming Yin3a941d42016-02-17 18:08:05 -08002194 int ret = 0, i = 0, j = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002195 int channels = platform_edid_get_max_channels_v2(out->dev->platform,
2196 out->extconn.cs.controller,
2197 out->extconn.cs.stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002198
Mingming Yin3a941d42016-02-17 18:08:05 -08002199 reset_hdmi_sink_caps(out);
2200
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002201 /* Cache ext disp type */
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002202 ret = platform_get_ext_disp_type_v2(adev->platform,
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002203 out->extconn.cs.controller,
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002204 out->extconn.cs.stream);
2205 if(ret < 0) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002206 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Garmond Leung37850ab2016-10-06 11:42:18 -07002207 return -EINVAL;
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002208 }
2209
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002210 switch (channels) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002211 case 8:
Mingming Yin3a941d42016-02-17 18:08:05 -08002212 ALOGV("%s: HDMI supports 7.1 channels", __func__);
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07002213 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_7POINT1;
Mingming Yin3a941d42016-02-17 18:08:05 -08002214 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_6POINT1;
2215 case 6:
2216 ALOGV("%s: HDMI supports 5.1 channels", __func__);
2217 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
2218 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
2219 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
2220 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_SURROUND;
2221 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_2POINT1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002222 break;
2223 default:
Mingming Yin3a941d42016-02-17 18:08:05 -08002224 ALOGE("invalid/nonstandard channal count[%d]",channels);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002225 ret = -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002226 break;
2227 }
Mingming Yin3a941d42016-02-17 18:08:05 -08002228
2229 // check channel format caps
2230 i = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002231 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_AC3,
2232 out->extconn.cs.controller,
2233 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002234 ALOGV(":%s HDMI supports AC3/EAC3 formats", __func__);
2235 out->supported_formats[i++] = AUDIO_FORMAT_AC3;
2236 //Adding EAC3/EAC3_JOC formats if AC3 is supported by the sink.
2237 //EAC3/EAC3_JOC will be converted to AC3 for decoding if needed
2238 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
2239 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
2240 }
2241
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002242 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD,
2243 out->extconn.cs.controller,
2244 out->extconn.cs.stream)) {
Ben Romberger1aaaf862017-04-06 17:49:46 -07002245 ALOGV(":%s HDMI supports TRUE HD format", __func__);
2246 out->supported_formats[i++] = AUDIO_FORMAT_DOLBY_TRUEHD;
2247 }
2248
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002249 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS,
2250 out->extconn.cs.controller,
2251 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002252 ALOGV(":%s HDMI supports DTS format", __func__);
2253 out->supported_formats[i++] = AUDIO_FORMAT_DTS;
2254 }
2255
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002256 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS_HD,
2257 out->extconn.cs.controller,
2258 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002259 ALOGV(":%s HDMI supports DTS HD format", __func__);
2260 out->supported_formats[i++] = AUDIO_FORMAT_DTS_HD;
2261 }
2262
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002263 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_IEC61937,
2264 out->extconn.cs.controller,
2265 out->extconn.cs.stream)) {
Naresh Tanniru928f0862017-04-07 16:44:23 -07002266 ALOGV(":%s HDMI supports IEC61937 format", __func__);
2267 out->supported_formats[i++] = AUDIO_FORMAT_IEC61937;
2268 }
2269
Mingming Yin3a941d42016-02-17 18:08:05 -08002270
2271 // check sample rate caps
2272 i = 0;
2273 for (j = 0; j < MAX_SUPPORTED_SAMPLE_RATES; j++) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002274 if (platform_is_edid_supported_sample_rate_v2(out->dev->platform, out_hdmi_sample_rates[j],
2275 out->extconn.cs.controller,
2276 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002277 ALOGV(":%s HDMI supports sample rate:%d", __func__, out_hdmi_sample_rates[j]);
2278 out->supported_sample_rates[i++] = out_hdmi_sample_rates[j];
2279 }
2280 }
2281
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002282 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002283}
2284
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002285static inline ssize_t read_usb_sup_sample_rates(bool is_playback __unused,
2286 uint32_t *supported_sample_rates __unused,
2287 uint32_t max_rates __unused)
2288{
2289 ssize_t count = audio_extn_usb_get_sup_sample_rates(is_playback,
2290 supported_sample_rates,
2291 max_rates);
Ashish Jain4847e9d2017-08-17 19:16:57 +05302292 ssize_t i = 0;
2293
2294 for (i=0; i<count; i++) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002295 ALOGV("%s %s %d", __func__, is_playback ? "P" : "C",
2296 supported_sample_rates[i]);
2297 }
2298 return count;
2299}
2300
2301static inline int read_usb_sup_channel_masks(bool is_playback,
2302 audio_channel_mask_t *supported_channel_masks,
2303 uint32_t max_masks)
2304{
2305 int channels = audio_extn_usb_get_max_channels(is_playback);
2306 int channel_count;
2307 uint32_t num_masks = 0;
2308 if (channels > MAX_HIFI_CHANNEL_COUNT)
2309 channels = MAX_HIFI_CHANNEL_COUNT;
2310
2311 if (is_playback) {
Eric Laurent68a87112019-05-01 18:07:29 -07002312 // start from 2 channels as framework currently doesn't support mono.
2313 if (channels >= FCC_2) {
2314 supported_channel_masks[num_masks++] = audio_channel_out_mask_from_count(FCC_2);
2315 }
2316 for (channel_count = FCC_2;
2317 channel_count <= channels && num_masks < max_masks;
2318 ++channel_count) {
2319 supported_channel_masks[num_masks++] =
2320 audio_channel_mask_for_index_assignment_from_count(channel_count);
2321 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002322 } else {
vincenttewf51c94e2019-05-07 10:28:53 +08002323 // For capture we report all supported channel masks from 1 channel up.
2324 channel_count = MIN_CHANNEL_COUNT;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002325 // audio_channel_in_mask_from_count() does the right conversion to either positional or
2326 // indexed mask
Eric Laurent68a87112019-05-01 18:07:29 -07002327 for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
2328 audio_channel_mask_t mask = AUDIO_CHANNEL_NONE;
2329 if (channel_count <= FCC_2) {
2330 mask = audio_channel_in_mask_from_count(channel_count);
2331 supported_channel_masks[num_masks++] = mask;
2332 }
2333 const audio_channel_mask_t index_mask =
2334 audio_channel_mask_for_index_assignment_from_count(channel_count);
2335 if (mask != index_mask && num_masks < max_masks) { // ensure index mask added.
2336 supported_channel_masks[num_masks++] = index_mask;
2337 }
2338 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002339 }
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302340
vincenttewf51c94e2019-05-07 10:28:53 +08002341 for (size_t i = 0; i < num_masks; ++i) {
2342 ALOGV("%s: %s supported ch %d supported_channel_masks[%zu] %08x num_masks %d", __func__,
2343 is_playback ? "P" : "C", channels, i, supported_channel_masks[i], num_masks);
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302344 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002345 return num_masks;
2346}
2347
2348static inline int read_usb_sup_formats(bool is_playback __unused,
2349 audio_format_t *supported_formats,
2350 uint32_t max_formats __unused)
2351{
2352 int bitwidth = audio_extn_usb_get_max_bit_width(is_playback);
2353 switch (bitwidth) {
2354 case 24:
2355 // XXX : usb.c returns 24 for s24 and s24_le?
2356 supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
2357 break;
2358 case 32:
2359 supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
2360 break;
2361 case 16:
2362 default :
2363 supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
2364 break;
2365 }
2366 ALOGV("%s: %s supported format %d", __func__,
2367 is_playback ? "P" : "C", bitwidth);
2368 return 1;
2369}
2370
2371static inline int read_usb_sup_params_and_compare(bool is_playback,
2372 audio_format_t *format,
2373 audio_format_t *supported_formats,
2374 uint32_t max_formats,
2375 audio_channel_mask_t *mask,
2376 audio_channel_mask_t *supported_channel_masks,
2377 uint32_t max_masks,
2378 uint32_t *rate,
2379 uint32_t *supported_sample_rates,
2380 uint32_t max_rates) {
2381 int ret = 0;
2382 int num_formats;
2383 int num_masks;
2384 int num_rates;
2385 int i;
2386
2387 num_formats = read_usb_sup_formats(is_playback, supported_formats,
2388 max_formats);
2389 num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
2390 max_masks);
2391
2392 num_rates = read_usb_sup_sample_rates(is_playback,
2393 supported_sample_rates, max_rates);
2394
2395#define LUT(table, len, what, dflt) \
2396 for (i=0; i<len && (table[i] != what); i++); \
2397 if (i==len) { ret |= (what == dflt ? 0 : -1); what=table[0]; }
2398
2399 LUT(supported_formats, num_formats, *format, AUDIO_FORMAT_DEFAULT);
2400 LUT(supported_channel_masks, num_masks, *mask, AUDIO_CHANNEL_NONE);
2401 LUT(supported_sample_rates, num_rates, *rate, 0);
2402
2403#undef LUT
2404 return ret < 0 ? -EINVAL : 0; // HACK TBD
2405}
2406
Alexy Josephb1379942016-01-29 15:49:38 -08002407audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002408 usecase_type_t type)
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002409{
2410 struct audio_usecase *usecase;
2411 struct listnode *node;
2412
2413 list_for_each(node, &adev->usecase_list) {
2414 usecase = node_to_item(node, struct audio_usecase, list);
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002415 if (usecase->type == type) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002416 ALOGV("%s: usecase id %d", __func__, usecase->id);
2417 return usecase->id;
2418 }
2419 }
2420 return USECASE_INVALID;
2421}
2422
Alexy Josephb1379942016-01-29 15:49:38 -08002423struct audio_usecase *get_usecase_from_list(const struct audio_device *adev,
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002424 audio_usecase_t uc_id)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002425{
2426 struct audio_usecase *usecase;
2427 struct listnode *node;
2428
2429 list_for_each(node, &adev->usecase_list) {
2430 usecase = node_to_item(node, struct audio_usecase, list);
2431 if (usecase->id == uc_id)
2432 return usecase;
2433 }
2434 return NULL;
2435}
2436
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302437/*
2438 * is a true native playback active
2439 */
2440bool audio_is_true_native_stream_active(struct audio_device *adev)
2441{
2442 bool active = false;
2443 int i = 0;
2444 struct listnode *node;
2445
2446 if (NATIVE_AUDIO_MODE_TRUE_44_1 != platform_get_native_support()) {
2447 ALOGV("%s:napb: not in true mode or non hdphones device",
2448 __func__);
2449 active = false;
2450 goto exit;
2451 }
2452
2453 list_for_each(node, &adev->usecase_list) {
2454 struct audio_usecase *uc;
2455 uc = node_to_item(node, struct audio_usecase, list);
2456 struct stream_out *curr_out =
2457 (struct stream_out*) uc->stream.out;
2458
2459 if (curr_out && PCM_PLAYBACK == uc->type) {
2460 ALOGD("%s:napb: (%d) (%s)id (%d) sr %d bw "
2461 "(%d) device %s", __func__, i++, use_case_table[uc->id],
2462 uc->id, curr_out->sample_rate,
2463 curr_out->bit_width,
2464 platform_get_snd_device_name(uc->out_snd_device));
2465
2466 if (is_offload_usecase(uc->id) &&
2467 (curr_out->sample_rate == OUTPUT_SAMPLING_RATE_44100)) {
2468 active = true;
2469 ALOGD("%s:napb:native stream detected", __func__);
2470 }
2471 }
2472 }
2473exit:
2474 return active;
2475}
2476
Xiaojun Sang785b5da2017-08-03 15:52:29 +08002477uint32_t adev_get_dsp_bit_width_enforce_mode()
2478{
2479 if (adev == NULL) {
2480 ALOGE("%s: adev is null. Disable DSP bit width enforce mode.\n", __func__);
2481 return 0;
2482 }
2483 return adev->dsp_bit_width_enforce_mode;
2484}
2485
2486static uint32_t adev_init_dsp_bit_width_enforce_mode(struct mixer *mixer)
2487{
2488 char value[PROPERTY_VALUE_MAX];
2489 int trial;
2490 uint32_t dsp_bit_width_enforce_mode = 0;
2491
2492 if (!mixer) {
2493 ALOGE("%s: adev mixer is null. cannot update DSP bitwidth.\n",
2494 __func__);
2495 return 0;
2496 }
2497
2498 if (property_get("persist.vendor.audio_hal.dsp_bit_width_enforce_mode",
2499 value, NULL) > 0) {
2500 trial = atoi(value);
2501 switch (trial) {
2502 case 16:
2503 dsp_bit_width_enforce_mode = 16;
2504 break;
2505 case 24:
2506 dsp_bit_width_enforce_mode = 24;
2507 break;
2508 case 32:
2509 dsp_bit_width_enforce_mode = 32;
2510 break;
2511 default:
2512 dsp_bit_width_enforce_mode = 0;
2513 ALOGD("%s Dynamic DSP bitwidth config is disabled.", __func__);
2514 break;
2515 }
2516 }
2517
2518 return dsp_bit_width_enforce_mode;
2519}
2520
2521static void audio_enable_asm_bit_width_enforce_mode(struct mixer *mixer,
2522 uint32_t enforce_mode,
2523 bool enable)
2524{
2525 struct mixer_ctl *ctl = NULL;
2526 const char *mixer_ctl_name = "ASM Bit Width";
2527 uint32_t asm_bit_width_mode = 0;
2528
2529 if (enforce_mode == 0) {
2530 ALOGD("%s: DSP bitwidth feature is disabled.", __func__);
2531 return;
2532 }
2533
2534 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
2535 if (!ctl) {
2536 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2537 __func__, mixer_ctl_name);
2538 return;
2539 }
2540
2541 if (enable)
2542 asm_bit_width_mode = enforce_mode;
2543 else
2544 asm_bit_width_mode = 0;
2545
2546 ALOGV("%s DSP bit width feature status is %d width=%d",
2547 __func__, enable, asm_bit_width_mode);
2548 if (mixer_ctl_set_value(ctl, 0, asm_bit_width_mode) < 0)
2549 ALOGE("%s: Could not set ASM biwidth %d", __func__,
2550 asm_bit_width_mode);
2551
2552 return;
2553}
2554
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302555/*
2556 * if native DSD playback active
2557 */
2558bool audio_is_dsd_native_stream_active(struct audio_device *adev)
2559{
2560 bool active = false;
2561 struct listnode *node = NULL;
2562 struct audio_usecase *uc = NULL;
2563 struct stream_out *curr_out = NULL;
2564
2565 list_for_each(node, &adev->usecase_list) {
2566 uc = node_to_item(node, struct audio_usecase, list);
2567 curr_out = (struct stream_out*) uc->stream.out;
2568
2569 if (curr_out && PCM_PLAYBACK == uc->type &&
2570 (DSD_NATIVE_BACKEND == platform_get_backend_index(uc->out_snd_device))) {
2571 active = true;
2572 ALOGV("%s:DSD playback is active", __func__);
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05302573 break;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302574 }
2575 }
2576 return active;
2577}
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302578
2579static bool force_device_switch(struct audio_usecase *usecase)
2580{
2581 bool ret = false;
2582 bool is_it_true_mode = false;
2583
Zhou Song30f2c3e2018-02-08 14:02:15 +08002584 if (usecase->type == PCM_CAPTURE ||
Surendar Karka93cd25a2018-08-28 14:21:37 +05302585 usecase->type == TRANSCODE_LOOPBACK_RX ||
2586 usecase->type == TRANSCODE_LOOPBACK_TX) {
Zhou Song30f2c3e2018-02-08 14:02:15 +08002587 return false;
2588 }
2589
Aalique Grahamecbc46a22017-10-05 10:30:23 -07002590 if(usecase->stream.out == NULL) {
2591 ALOGE("%s: stream.out is NULL", __func__);
2592 return false;
2593 }
2594
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302595 if (is_offload_usecase(usecase->id) &&
Xiaojun Sang869f2012016-02-23 16:33:07 +08002596 (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002597 (compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
2598 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302599 is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
2600 if ((is_it_true_mode && !adev->native_playback_enabled) ||
2601 (!is_it_true_mode && adev->native_playback_enabled)){
2602 ret = true;
2603 ALOGD("napb: time to toggle native mode");
2604 }
2605 }
2606
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302607 // Force all a2dp output devices to reconfigure for proper AFE encode format
Ashish Jainc597d102016-12-12 10:31:34 +05302608 //Also handle a case where in earlier a2dp start failed as A2DP stream was
2609 //in suspended state, hence try to trigger a retry when we again get a routing request.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002610 if(is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Ashish Jainc597d102016-12-12 10:31:34 +05302611 audio_extn_a2dp_is_force_device_switch()) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302612 ALOGD("Force a2dp device switch to update new encoder config");
2613 ret = true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002614 }
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302615
Florian Pfister1a84f312018-07-19 14:38:18 +02002616 if (usecase->stream.out->stream_config_changed) {
Manish Dewangan671a4202017-08-18 17:30:46 +05302617 ALOGD("Force stream_config_changed to update iec61937 transmission config");
2618 return true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002619 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302620 return ret;
2621}
2622
Aalique Grahame22e49102018-12-18 14:23:57 -08002623static void stream_app_type_cfg_init(struct stream_app_type_cfg *cfg)
2624{
2625 cfg->gain[0] = cfg->gain[1] = APP_TYPE_GAIN_DEFAULT;
2626}
2627
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302628bool is_btsco_device(snd_device_t out_snd_device, snd_device_t in_snd_device)
2629{
2630 bool ret=false;
2631 if ((out_snd_device == SND_DEVICE_OUT_BT_SCO ||
Zhou Song5657f492019-08-07 11:30:39 +08002632 out_snd_device == SND_DEVICE_OUT_BT_SCO_WB ||
2633 out_snd_device == SND_DEVICE_OUT_BT_SCO_SWB) ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302634 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC ||
2635 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB ||
Zhou Song5657f492019-08-07 11:30:39 +08002636 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302637 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC ||
Mingshu Pang16093502020-04-20 11:21:16 +08002638 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC ||
2639 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC)
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302640 ret = true;
2641
2642 return ret;
2643}
2644
2645bool is_a2dp_device(snd_device_t out_snd_device)
2646{
2647 bool ret=false;
2648 if (out_snd_device == SND_DEVICE_OUT_BT_A2DP)
2649 ret = true;
2650
2651 return ret;
2652}
2653
2654bool is_bt_soc_on(struct audio_device *adev)
2655{
2656 struct mixer_ctl *ctl;
2657 char *mixer_ctl_name = "BT SOC status";
2658 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
2659 bool bt_soc_status = true;
2660 if (!ctl) {
2661 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2662 __func__, mixer_ctl_name);
2663 /*This is to ensure we dont break targets which dont have the kernel change*/
2664 return true;
2665 }
2666 bt_soc_status = mixer_ctl_get_value(ctl, 0);
2667 ALOGD("BT SOC status: %d",bt_soc_status);
2668 return bt_soc_status;
2669}
2670
Zhou Song331c8e52019-08-26 14:16:12 +08002671static int configure_btsco_sample_rate(snd_device_t snd_device)
2672{
2673 struct mixer_ctl *ctl = NULL;
2674 struct mixer_ctl *ctl_sr_rx = NULL, *ctl_sr_tx = NULL, *ctl_sr = NULL;
2675 char *rate_str = NULL;
2676 bool is_rx_dev = true;
2677
2678 if (is_btsco_device(snd_device, snd_device)) {
2679 ctl_sr_tx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate TX");
2680 ctl_sr_rx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate RX");
2681 if (!ctl_sr_tx || !ctl_sr_rx) {
2682 ctl_sr = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate");
2683 if (!ctl_sr)
2684 return -ENOSYS;
2685 }
2686
2687 switch (snd_device) {
2688 case SND_DEVICE_OUT_BT_SCO:
2689 rate_str = "KHZ_8";
2690 break;
2691 case SND_DEVICE_IN_BT_SCO_MIC_NREC:
2692 case SND_DEVICE_IN_BT_SCO_MIC:
2693 rate_str = "KHZ_8";
2694 is_rx_dev = false;
2695 break;
2696 case SND_DEVICE_OUT_BT_SCO_WB:
2697 rate_str = "KHZ_16";
2698 break;
2699 case SND_DEVICE_IN_BT_SCO_MIC_WB_NREC:
2700 case SND_DEVICE_IN_BT_SCO_MIC_WB:
2701 rate_str = "KHZ_16";
2702 is_rx_dev = false;
2703 break;
2704 default:
2705 return 0;
2706 }
2707
2708 ctl = (ctl_sr == NULL) ? (is_rx_dev ? ctl_sr_rx : ctl_sr_tx) : ctl_sr;
2709 if (mixer_ctl_set_enum_by_string(ctl, rate_str) != 0)
2710 return -ENOSYS;
2711 }
2712 return 0;
2713}
2714
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302715int out_standby_l(struct audio_stream *stream);
2716
Eric Laurent637e2d42018-11-15 12:24:31 -08002717struct stream_in *adev_get_active_input(const struct audio_device *adev)
2718{
2719 struct listnode *node;
2720 struct stream_in *last_active_in = NULL;
2721
2722 /* Get last added active input.
2723 * TODO: We may use a priority mechanism to pick highest priority active source */
2724 list_for_each(node, &adev->usecase_list)
2725 {
2726 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2727 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL)
2728 last_active_in = usecase->stream.in;
2729 }
2730
2731 return last_active_in;
2732}
2733
2734struct stream_in *get_voice_communication_input(const struct audio_device *adev)
2735{
2736 struct listnode *node;
2737
2738 /* First check active inputs with voice communication source and then
2739 * any input if audio mode is in communication */
2740 list_for_each(node, &adev->usecase_list)
2741 {
2742 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2743 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL &&
2744 usecase->stream.in->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
2745 return usecase->stream.in;
2746 }
2747 if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
2748 return adev_get_active_input(adev);
2749
2750 return NULL;
2751}
2752
Carter Hsu2e429db2019-05-14 18:50:52 +08002753/*
2754 * Aligned with policy.h
2755 */
2756static inline int source_priority(int inputSource)
2757{
2758 switch (inputSource) {
2759 case AUDIO_SOURCE_VOICE_COMMUNICATION:
2760 return 9;
2761 case AUDIO_SOURCE_CAMCORDER:
2762 return 8;
2763 case AUDIO_SOURCE_VOICE_PERFORMANCE:
2764 return 7;
2765 case AUDIO_SOURCE_UNPROCESSED:
2766 return 6;
2767 case AUDIO_SOURCE_MIC:
2768 return 5;
2769 case AUDIO_SOURCE_ECHO_REFERENCE:
2770 return 4;
2771 case AUDIO_SOURCE_FM_TUNER:
2772 return 3;
2773 case AUDIO_SOURCE_VOICE_RECOGNITION:
2774 return 2;
2775 case AUDIO_SOURCE_HOTWORD:
2776 return 1;
2777 default:
2778 break;
2779 }
2780 return 0;
2781}
2782
2783static struct stream_in *get_priority_input(struct audio_device *adev)
2784{
2785 struct listnode *node;
2786 struct audio_usecase *usecase;
2787 int last_priority = 0, priority;
2788 struct stream_in *priority_in = NULL;
2789 struct stream_in *in;
2790
2791 list_for_each(node, &adev->usecase_list) {
2792 usecase = node_to_item(node, struct audio_usecase, list);
2793 if (usecase->type == PCM_CAPTURE) {
2794 in = usecase->stream.in;
2795 if (!in)
2796 continue;
2797 priority = source_priority(in->source);
2798
2799 if (priority > last_priority) {
2800 last_priority = priority;
2801 priority_in = in;
2802 }
2803 }
2804 }
2805 return priority_in;
2806}
2807
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002808int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002809{
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08002810 snd_device_t out_snd_device = SND_DEVICE_NONE;
2811 snd_device_t in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002812 struct audio_usecase *usecase = NULL;
2813 struct audio_usecase *vc_usecase = NULL;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002814 struct audio_usecase *voip_usecase = NULL;
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002815 struct audio_usecase *hfp_usecase = NULL;
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302816 struct stream_out stream_out;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08002817 audio_usecase_t hfp_ucid;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002818 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002819
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302820 ALOGD("%s for use case (%s)", __func__, use_case_table[uc_id]);
2821
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002822 usecase = get_usecase_from_list(adev, uc_id);
2823 if (usecase == NULL) {
2824 ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
2825 return -EINVAL;
2826 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002827
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002828 if ((usecase->type == VOICE_CALL) ||
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08002829 (usecase->type == VOIP_CALL) ||
Derek Chena30a5f42019-12-03 11:17:09 -05002830 (usecase->type == PCM_HFP_CALL)||
Fei Tongaffdf732020-02-20 20:39:05 +08002831 (usecase->type == ICC_CALL) ||
2832 (usecase->type == SYNTH_LOOPBACK)) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302833 if(usecase->stream.out == NULL) {
2834 ALOGE("%s: stream.out is NULL", __func__);
2835 return -EINVAL;
2836 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002837 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS)) {
Guodong Hu267bdf82019-08-12 19:22:32 +08002838 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
2839 uc_id);
2840 in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
2841 uc_id);
2842 } else {
2843 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302844 usecase->stream.out, usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002845 in_snd_device = platform_get_input_snd_device(adev->platform,
2846 NULL,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302847 &usecase->stream.out->device_list,
2848 usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002849 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002850 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302851 } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
Siddartha Shaik31b530e2017-05-19 15:26:33 +05302852 if (usecase->stream.inout == NULL) {
2853 ALOGE("%s: stream.inout is NULL", __func__);
2854 return -EINVAL;
2855 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002856 assign_devices(&stream_out.device_list, &usecase->stream.inout->out_config.device_list);
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302857 stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
2858 stream_out.format = usecase->stream.inout->out_config.format;
2859 stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
Jaideep Sharma477917f2020-03-13 18:13:33 +05302860 out_snd_device = platform_get_output_snd_device(adev->platform, &stream_out, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002861 assign_devices(&usecase->device_list,
2862 &usecase->stream.inout->out_config.device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302863 } else if (usecase->type == TRANSCODE_LOOPBACK_TX ) {
2864 if (usecase->stream.inout == NULL) {
2865 ALOGE("%s: stream.inout is NULL", __func__);
2866 return -EINVAL;
2867 }
Manisha Agarwal03297972020-04-17 15:36:55 +05302868 struct listnode out_devices;
2869 list_init(&out_devices);
2870 in_snd_device = platform_get_input_snd_device(adev->platform, NULL,
2871 &out_devices, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002872 assign_devices(&usecase->device_list,
2873 &usecase->stream.inout->in_config.device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002874 } else {
2875 /*
2876 * If the voice call is active, use the sound devices of voice call usecase
2877 * so that it would not result any device switch. All the usecases will
2878 * be switched to new device when select_devices() is called for voice call
2879 * usecase. This is to avoid switching devices for voice call when
2880 * check_usecases_codec_backend() is called below.
Alexy Joseph79dfa3c2016-04-20 18:44:56 -07002881 * choose voice call device only if the use case device is
2882 * also using the codec backend
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002883 */
Shiv Maliyappanahallibb4cf0b2016-01-21 11:30:06 -08002884 if (voice_is_in_call(adev) && adev->mode != AUDIO_MODE_NORMAL) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002885 vc_usecase = get_usecase_from_list(adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002886 get_usecase_id_from_usecase_type(adev, VOICE_CALL));
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002887 if ((vc_usecase) && ((is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2888 is_codec_backend_out_device_type(&usecase->device_list)) ||
2889 (is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2890 is_codec_backend_in_device_type(&usecase->device_list)) ||
2891 is_single_device_type_equal(&vc_usecase->device_list,
2892 AUDIO_DEVICE_OUT_HEARING_AID) ||
2893 is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002894 AUDIO_DEVICE_IN_VOICE_CALL) ||
2895 (is_single_device_type_equal(&usecase->device_list,
Gautam Manam8fa06162021-09-24 10:41:29 +05302896 AUDIO_DEVICE_IN_BUILTIN_MIC) &&
2897 is_single_device_type_equal(&vc_usecase->device_list,
2898 AUDIO_DEVICE_OUT_USB_HEADSET)) ||
2899 (is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002900 AUDIO_DEVICE_IN_USB_HEADSET) &&
2901 is_single_device_type_equal(&vc_usecase->device_list,
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05302902 AUDIO_DEVICE_OUT_USB_HEADSET))||
Gautam Manamf4002142021-09-13 22:05:56 +05302903 (is_single_device_type_equal(&usecase->device_list,
2904 AUDIO_DEVICE_IN_USB_HEADSET) &&
2905 is_codec_backend_out_device_type(&vc_usecase->device_list)) ||
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05302906 (is_single_device_type_equal(&usecase->device_list,
2907 AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) &&
2908 is_codec_backend_out_device_type(&vc_usecase->device_list)))) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002909 in_snd_device = vc_usecase->in_snd_device;
2910 out_snd_device = vc_usecase->out_snd_device;
2911 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002912 } else if (voice_extn_compress_voip_is_active(adev)) {
yidongh02ef86f2017-04-21 15:36:04 +08002913 bool out_snd_device_backend_match = true;
yidongh47785a82017-05-08 19:29:29 +08002914 voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
yidongh6261d8e2017-05-15 17:04:02 +08002915 if ((voip_usecase != NULL) &&
2916 (usecase->type == PCM_PLAYBACK) &&
2917 (usecase->stream.out != NULL)) {
yidongh02ef86f2017-04-21 15:36:04 +08002918 out_snd_device_backend_match = platform_check_backends_match(
2919 voip_usecase->out_snd_device,
2920 platform_get_output_snd_device(
2921 adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302922 usecase->stream.out, usecase->type));
yidongh02ef86f2017-04-21 15:36:04 +08002923 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002924 if ((voip_usecase) && (is_codec_backend_out_device_type(&voip_usecase->device_list) &&
2925 (is_codec_backend_out_device_type(&usecase->device_list) ||
2926 is_codec_backend_in_device_type(&usecase->device_list)) &&
yidongh02ef86f2017-04-21 15:36:04 +08002927 out_snd_device_backend_match &&
Mingming Yin2d8aa2e2014-08-14 00:00:51 -07002928 (voip_usecase->stream.out != adev->primary_output))) {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002929 in_snd_device = voip_usecase->in_snd_device;
2930 out_snd_device = voip_usecase->out_snd_device;
2931 }
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002932 } else if (audio_extn_hfp_is_active(adev)) {
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08002933 hfp_ucid = audio_extn_hfp_get_usecase();
2934 hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002935 if ((hfp_usecase) && is_codec_backend_out_device_type(&hfp_usecase->device_list)) {
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002936 in_snd_device = hfp_usecase->in_snd_device;
2937 out_snd_device = hfp_usecase->out_snd_device;
2938 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002939 }
2940 if (usecase->type == PCM_PLAYBACK) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302941 if (usecase->stream.out == NULL) {
2942 ALOGE("%s: stream.out is NULL", __func__);
2943 return -EINVAL;
2944 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002945 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002946 in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002947 if (out_snd_device == SND_DEVICE_NONE) {
Eric Laurent637e2d42018-11-15 12:24:31 -08002948 struct stream_out *voip_out = adev->primary_output;
2949 struct stream_in *voip_in = get_voice_communication_input(adev);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002950 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
Guodong Hu267bdf82019-08-12 19:22:32 +08002951 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
2952 else
2953 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302954 usecase->stream.out,
2955 usecase->type);
kunleizdcf967a2018-08-07 17:09:11 +08002956 voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP);
kunleizdcf967a2018-08-07 17:09:11 +08002957
Eric Laurent637e2d42018-11-15 12:24:31 -08002958 if (voip_usecase)
2959 voip_out = voip_usecase->stream.out;
2960
2961 if (usecase->stream.out == voip_out && voip_in != NULL)
2962 select_devices(adev, voip_in->usecase);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002963 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002964 } else if (usecase->type == PCM_CAPTURE) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302965 if (usecase->stream.in == NULL) {
2966 ALOGE("%s: stream.in is NULL", __func__);
2967 return -EINVAL;
2968 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002969 assign_devices(&usecase->device_list, &usecase->stream.in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002970 out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002971 if (in_snd_device == SND_DEVICE_NONE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002972 struct listnode out_devices;
Eric Laurent637e2d42018-11-15 12:24:31 -08002973 struct stream_in *voip_in = get_voice_communication_input(adev);
Carter Hsu2e429db2019-05-14 18:50:52 +08002974 struct stream_in *priority_in = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08002975
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002976 list_init(&out_devices);
Eric Laurent637e2d42018-11-15 12:24:31 -08002977 if (voip_in != NULL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08002978 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
2979 USECASE_AUDIO_PLAYBACK_VOIP);
2980
Carter Hsu2e429db2019-05-14 18:50:52 +08002981 usecase->stream.in->enable_ec_port = false;
2982
Zhou Song503196b2021-07-23 17:31:05 +08002983 if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY ||
2984 usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY2) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002985 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08002986 } else if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002987 assign_devices(&out_devices, &voip_usecase->stream.out->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08002988 } else if (adev->primary_output &&
2989 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002990 assign_devices(&out_devices, &adev->primary_output->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08002991 } else {
2992 /* forcing speaker o/p device to get matching i/p pair
2993 in case o/p is not routed from same primary HAL */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002994 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08002995 }
Carter Hsu2e429db2019-05-14 18:50:52 +08002996 priority_in = voip_in;
2997 } else {
2998 /* get the input with the highest priority source*/
2999 priority_in = get_priority_input(adev);
3000
Susan Wang727dd6b2021-03-26 11:28:59 -04003001 if (!priority_in ||
3002 audio_extn_auto_hal_overwrite_priority_for_auto(usecase->stream.in))
Carter Hsu2e429db2019-05-14 18:50:52 +08003003 priority_in = usecase->stream.in;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003004 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04003005 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_IN_BUS)){
3006 in_snd_device = audio_extn_auto_hal_get_snd_device_for_car_audio_stream(priority_in->car_audio_stream);
3007 }
3008 else
3009 in_snd_device = platform_get_input_snd_device(adev->platform,
3010 priority_in,
3011 &out_devices,
3012 usecase->type);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07003013 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003014 }
3015 }
3016
3017 if (out_snd_device == usecase->out_snd_device &&
3018 in_snd_device == usecase->in_snd_device) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05303019
3020 if (!force_device_switch(usecase))
3021 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003022 }
3023
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003024 if (!compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) &&
Guodong Hu267bdf82019-08-12 19:22:32 +08003025 ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003026 (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
Guodong Hu267bdf82019-08-12 19:22:32 +08003027 ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
3028 return 0;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303029 }
3030
Aalique Grahame22e49102018-12-18 14:23:57 -08003031 if (out_snd_device != SND_DEVICE_NONE &&
3032 out_snd_device != adev->last_logged_snd_device[uc_id][0]) {
3033 ALOGD("%s: changing use case %s output device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3034 __func__,
3035 use_case_table[uc_id],
3036 adev->last_logged_snd_device[uc_id][0],
3037 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][0]),
3038 adev->last_logged_snd_device[uc_id][0] != SND_DEVICE_NONE ?
3039 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][0]) :
3040 -1,
3041 out_snd_device,
3042 platform_get_snd_device_name(out_snd_device),
3043 platform_get_snd_device_acdb_id(out_snd_device));
3044 adev->last_logged_snd_device[uc_id][0] = out_snd_device;
3045 }
3046 if (in_snd_device != SND_DEVICE_NONE &&
3047 in_snd_device != adev->last_logged_snd_device[uc_id][1]) {
3048 ALOGD("%s: changing use case %s input device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
3049 __func__,
3050 use_case_table[uc_id],
3051 adev->last_logged_snd_device[uc_id][1],
3052 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][1]),
3053 adev->last_logged_snd_device[uc_id][1] != SND_DEVICE_NONE ?
3054 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][1]) :
3055 -1,
3056 in_snd_device,
3057 platform_get_snd_device_name(in_snd_device),
3058 platform_get_snd_device_acdb_id(in_snd_device));
3059 adev->last_logged_snd_device[uc_id][1] = in_snd_device;
3060 }
3061
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08003062
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003063 /*
3064 * Limitation: While in call, to do a device switch we need to disable
3065 * and enable both RX and TX devices though one of them is same as current
3066 * device.
3067 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003068 if ((usecase->type == VOICE_CALL) &&
3069 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3070 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Eric Laurentb23d5282013-05-14 15:27:20 -07003071 status = platform_switch_voice_call_device_pre(adev->platform);
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003072 }
3073
3074 if (((usecase->type == VOICE_CALL) ||
3075 (usecase->type == VOIP_CALL)) &&
3076 (usecase->out_snd_device != SND_DEVICE_NONE)) {
3077 /* Disable sidetone only if voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303078 if (voice_is_call_state_active_in_call(adev) ||
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003079 voice_extn_compress_voip_is_started(adev))
Bhalchandra Gajare45fee282015-06-09 22:23:45 -07003080 voice_set_sidetone(adev, usecase->out_snd_device, false);
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003081
3082 /* Disable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303083 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003084 voice_check_and_update_aanc_path(adev, usecase->out_snd_device, false);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003085 }
3086
Aalique Grahame22e49102018-12-18 14:23:57 -08003087 if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
3088 out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02003089 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303090 ALOGW("%s: A2DP profile is not ready, routing to speaker only", __func__);
Aalique Grahame22e49102018-12-18 14:23:57 -08003091 if (out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)
3092 out_snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
3093 else
3094 out_snd_device = SND_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303095 }
3096
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003097 /* Disable current sound devices */
3098 if (usecase->out_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003099 disable_audio_route(adev, usecase);
3100 disable_snd_device(adev, usecase->out_snd_device);
Gautam Manam274f4752021-09-24 10:58:49 +05303101 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3102 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003103 }
3104
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003105 if (usecase->in_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003106 disable_audio_route(adev, usecase);
3107 disable_snd_device(adev, usecase->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003108 }
3109
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003110 /* Applicable only on the targets that has external modem.
3111 * New device information should be sent to modem before enabling
3112 * the devices to reduce in-call device switch time.
3113 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003114 if ((usecase->type == VOICE_CALL) &&
3115 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3116 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003117 status = platform_switch_voice_call_enable_device_config(adev->platform,
3118 out_snd_device,
3119 in_snd_device);
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003120 }
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003121
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003122 /* Enable new sound devices */
3123 if (out_snd_device != SND_DEVICE_NONE) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08003124 check_usecases_codec_backend(adev, usecase, out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05303125 check_and_configure_headphone(adev, usecase, out_snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05303126 if (platform_check_codec_asrc_support(adev->platform))
3127 check_and_set_asrc_mode(adev, usecase, out_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003128 enable_snd_device(adev, out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08003129 /* Enable haptics device for haptic usecase */
3130 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3131 enable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003132 }
3133
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003134 if (in_snd_device != SND_DEVICE_NONE) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05303135 check_usecases_capture_codec_backend(adev, usecase, in_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003136 enable_snd_device(adev, in_snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003137 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003138
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05303139 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
Eric Laurentb23d5282013-05-14 15:27:20 -07003140 status = platform_switch_voice_call_device_post(adev->platform,
3141 out_snd_device,
3142 in_snd_device);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003143
sangwoo170731f2013-06-08 15:36:36 +09003144 usecase->in_snd_device = in_snd_device;
3145 usecase->out_snd_device = out_snd_device;
3146
Dhananjay Kumard6d32152016-10-13 16:11:03 +05303147 audio_extn_utils_update_stream_app_type_cfg_for_usecase(adev,
3148 usecase);
Preetam Singh Ranawata4a37d82014-09-25 16:56:38 +05303149 if (usecase->type == PCM_PLAYBACK) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003150 if ((24 == usecase->stream.out->bit_width) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003151 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_SPEAKER)) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003152 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3153 } else if ((out_snd_device == SND_DEVICE_OUT_HDMI ||
3154 out_snd_device == SND_DEVICE_OUT_USB_HEADSET ||
3155 out_snd_device == SND_DEVICE_OUT_DISPLAY_PORT) &&
3156 (usecase->stream.out->sample_rate >= OUTPUT_SAMPLING_RATE_44100)) {
3157 /*
3158 * To best utlize DSP, check if the stream sample rate is supported/multiple of
3159 * configured device sample rate, if not update the COPP rate to be equal to the
3160 * device sample rate, else open COPP at stream sample rate
3161 */
3162 platform_check_and_update_copp_sample_rate(adev->platform, out_snd_device,
3163 usecase->stream.out->sample_rate,
3164 &usecase->stream.out->app_type_cfg.sample_rate);
Ashish Jain4826f6c2017-02-06 13:33:20 +05303165 } else if (((out_snd_device != SND_DEVICE_OUT_HEADPHONES_44_1 &&
Preetam Singh Ranawat590d0432019-09-30 14:39:47 +05303166 out_snd_device != SND_DEVICE_OUT_HEADPHONES &&
3167 out_snd_device != SND_DEVICE_OUT_HEADPHONES_HIFI_FILTER &&
Ashish Jain4826f6c2017-02-06 13:33:20 +05303168 !audio_is_true_native_stream_active(adev)) &&
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003169 usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) ||
3170 (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
3171 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3172 }
Weiyin Jiangcdece202019-07-08 16:13:16 +08003173 }
3174 enable_audio_route(adev, usecase);
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003175
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303176 if (uc_id == USECASE_AUDIO_PLAYBACK_VOIP) {
3177 struct stream_in *voip_in = get_voice_communication_input(adev);
3178 struct audio_usecase *voip_in_usecase = NULL;
3179 voip_in_usecase = get_usecase_from_list(adev, USECASE_AUDIO_RECORD_VOIP);
3180 if (voip_in != NULL &&
3181 voip_in_usecase != NULL &&
3182 !(out_snd_device == AUDIO_DEVICE_OUT_SPEAKER ||
3183 out_snd_device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
3184 (voip_in_usecase->in_snd_device ==
3185 platform_get_input_snd_device(adev->platform, voip_in,
3186 &usecase->stream.out->device_list,usecase->type))) {
3187 /*
3188 * if VOIP TX is enabled before VOIP RX, needs to re-route the TX path
3189 * for enabling echo-reference-voip with correct port
3190 */
3191 ALOGD("%s: VOIP TX is enabled before VOIP RX,needs to re-route the TX path",__func__);
3192 disable_audio_route(adev, voip_in_usecase);
3193 disable_snd_device(adev, voip_in_usecase->in_snd_device);
3194 enable_snd_device(adev, voip_in_usecase->in_snd_device);
3195 enable_audio_route(adev, voip_in_usecase);
3196 }
3197 }
Ramjee Singhcdf67af2021-09-29 14:20:27 +05303198 if (voice_extn_compress_voip_is_active(adev)) {
3199 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3200 USECASE_COMPRESS_VOIP_CALL);
3201 /*
3202 * If only compress voip input is opened voip out will be primary out.
3203 * Need to consider re-routing to select correct i/p pair
3204 */
3205 if ((voip_usecase != NULL) &&
3206 (usecase->type == PCM_PLAYBACK) &&
3207 (usecase->stream.out == voip_usecase->stream.out)) {
3208 in_snd_device = platform_get_input_snd_device(adev->platform,
3209 NULL,
3210 &usecase->stream.out->device_list,
3211 usecase->type);
3212 if (voip_usecase->in_snd_device != in_snd_device ) {
3213 ALOGD("%s:Re routing compress voip tx snd device matching voip rx pair",
3214 __func__);
3215 disable_audio_route(adev, voip_usecase);
3216 disable_snd_device(adev, voip_usecase->in_snd_device);
3217 voip_usecase->in_snd_device = in_snd_device;
3218 voip_usecase->out_snd_device = usecase->out_snd_device;
3219 /* Route all TX usecase to Compress voip BE */
3220 check_usecases_capture_codec_backend(adev, voip_usecase, in_snd_device);
3221 enable_snd_device(adev, in_snd_device);
3222 /* Send Voice related calibration for RX /TX pair */
3223 status = platform_switch_voice_call_device_post(adev->platform,
3224 out_snd_device,
3225 in_snd_device);
3226 enable_audio_route(adev, voip_usecase);
3227 }
3228 }
3229 }
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303230
3231
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08003232 audio_extn_qdsp_set_device(usecase);
Aalique Grahame22e49102018-12-18 14:23:57 -08003233
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003234 /* If input stream is already running then effect needs to be
3235 applied on the new input device that's being enabled here. */
Eric Laurent637e2d42018-11-15 12:24:31 -08003236 if (in_snd_device != SND_DEVICE_NONE)
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003237 check_and_enable_effect(adev);
3238
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003239 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003240 /* Enable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303241 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003242 voice_check_and_update_aanc_path(adev, out_snd_device, true);
3243
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003244 /* Enable sidetone only if other voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303245 if (voice_is_call_state_active_in_call(adev) ||
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003246 voice_extn_compress_voip_is_started(adev))
3247 voice_set_sidetone(adev, out_snd_device, true);
3248 }
3249
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003250 /* Applicable only on the targets that has external modem.
3251 * Enable device command should be sent to modem only after
3252 * enabling voice call mixer controls
3253 */
Vidyakumar Athota339342f2014-07-01 15:30:57 -07003254 if (usecase->type == VOICE_CALL)
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003255 status = platform_switch_voice_call_usecase_route_post(adev->platform,
3256 out_snd_device,
3257 in_snd_device);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303258
3259 if (is_btsco_device(out_snd_device, in_snd_device) || is_a2dp_device(out_snd_device)) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003260 struct stream_in *in = adev_get_active_input(adev);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303261 if (usecase->type == VOIP_CALL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003262 if (in != NULL && !in->standby) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303263 if (is_bt_soc_on(adev) == false){
3264 ALOGD("BT SCO MIC disconnected while in connection");
Eric Laurent637e2d42018-11-15 12:24:31 -08003265 if (in->pcm != NULL)
3266 pcm_stop(in->pcm);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303267 }
3268 }
3269 if ((usecase->stream.out != NULL) && (usecase->stream.out != adev->primary_output)
3270 && usecase->stream.out->started) {
3271 if (is_bt_soc_on(adev) == false) {
3272 ALOGD("BT SCO/A2DP disconnected while in connection");
3273 out_standby_l(&usecase->stream.out->stream.common);
3274 }
3275 }
3276 } else if ((usecase->stream.out != NULL) &&
3277 !(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Surendar Karkae1dc8742018-11-19 16:23:14 +05303278 (usecase->type != TRANSCODE_LOOPBACK_TX) &&
3279 (usecase->type != TRANSCODE_LOOPBACK_RX) &&
Weiyin Jiang0d373242019-07-25 13:18:17 +08003280 (usecase->type != PCM_CAPTURE) &&
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303281 usecase->stream.out->started) {
3282 if (is_bt_soc_on(adev) == false) {
3283 ALOGD("BT SCO/A2dp disconnected while in connection");
3284 out_standby_l(&usecase->stream.out->stream.common);
3285 }
3286 }
3287 }
3288
Yung Ti Su70cb8242018-06-22 17:38:47 +08003289 if (usecase->type != PCM_CAPTURE && usecase == voip_usecase) {
Aalique Grahame22e49102018-12-18 14:23:57 -08003290 struct stream_out *voip_out = voip_usecase->stream.out;
3291 audio_extn_utils_send_app_type_gain(adev,
3292 voip_out->app_type_cfg.app_type,
3293 &voip_out->app_type_cfg.gain[0]);
3294 }
3295
Ajender Reddyb940b832021-07-07 11:51:42 +05303296 ALOGD("%s: done",__func__);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303297
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003298 return status;
3299}
3300
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003301static int stop_input_stream(struct stream_in *in)
3302{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303303 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003304 struct audio_usecase *uc_info;
Pallavid7c7a272018-01-16 11:22:55 +05303305
3306 if (in == NULL) {
3307 ALOGE("%s: stream_in ptr is NULL", __func__);
3308 return -EINVAL;
3309 }
3310
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003311 struct audio_device *adev = in->dev;
Carter Hsu2e429db2019-05-14 18:50:52 +08003312 struct stream_in *priority_in = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003313
Eric Laurent994a6932013-07-17 11:51:42 -07003314 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003315 in->usecase, use_case_table[in->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003316 uc_info = get_usecase_from_list(adev, in->usecase);
3317 if (uc_info == NULL) {
3318 ALOGE("%s: Could not find the usecase (%d) in the list",
3319 __func__, in->usecase);
3320 return -EINVAL;
3321 }
3322
Carter Hsu2e429db2019-05-14 18:50:52 +08003323 priority_in = get_priority_input(adev);
3324
Derek Chenea197282019-01-07 17:35:01 -08003325 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3326 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003327
Vidyakumar Athota2850d532013-11-19 16:02:12 -08003328 /* Close in-call recording streams */
3329 voice_check_and_stop_incall_rec_usecase(adev, in);
3330
Eric Laurent150dbfe2013-02-27 14:31:02 -08003331 /* 1. Disable stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003332 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003333
3334 /* 2. Disable the tx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003335 disable_snd_device(adev, uc_info->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003336
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003337 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303338 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
3339
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003340 list_remove(&uc_info->list);
3341 free(uc_info);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003342
Carter Hsu2e429db2019-05-14 18:50:52 +08003343 if (priority_in == in) {
3344 priority_in = get_priority_input(adev);
Sujin Panicker110f7942021-08-26 17:01:22 +05303345 if (priority_in) {
3346 if (is_usb_in_device_type(&priority_in->device_list)) {
3347 if (audio_extn_usb_connected(NULL))
3348 select_devices(adev, priority_in->usecase);
3349 } else {
3350 select_devices(adev, priority_in->usecase);
3351 }
3352 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003353 }
3354
Vatsal Buchac09ae062018-11-14 13:25:08 +05303355 enable_gcov();
Eric Laurent994a6932013-07-17 11:51:42 -07003356 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003357 return ret;
3358}
3359
3360int start_input_stream(struct stream_in *in)
3361{
3362 /* 1. Enable output device and stream routing controls */
Eric Laurentc8400632013-02-14 19:04:54 -08003363 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003364 struct audio_usecase *uc_info;
Preetam Singh Ranawata87e9742018-02-13 16:52:53 +05303365
3366 if (in == NULL) {
3367 ALOGE("%s: stream_in ptr is NULL", __func__);
3368 return -EINVAL;
3369 }
3370
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003371 struct audio_device *adev = in->dev;
Garmond Leunge2433c32017-09-28 21:51:22 -07003372 struct pcm_config config = in->config;
Garmond Leung438932f2017-10-04 19:35:18 -07003373 int usecase = platform_update_usecase_from_source(in->source,in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003374
Mingming Yin2664a5b2015-09-03 10:53:11 -07003375 if (get_usecase_from_list(adev, usecase) == NULL)
3376 in->usecase = usecase;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303377 ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
3378 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003379
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303380 if (CARD_STATUS_OFFLINE == in->card_status||
3381 CARD_STATUS_OFFLINE == adev->card_status) {
3382 ALOGW("in->card_status or adev->card_status offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05303383 ret = -EIO;
Naresh Tanniru4c630392014-05-12 01:05:52 +05303384 goto error_config;
3385 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05303386
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003387 if (is_sco_in_device_type(&in->device_list)) {
Lakshman Chaluvaraju87f53aa2021-02-02 15:50:11 +05303388 if (!adev->bt_sco_on || audio_extn_a2dp_source_is_ready()) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303389 ALOGE("%s: SCO profile is not ready, return error", __func__);
3390 ret = -EIO;
3391 goto error_config;
3392 }
3393 }
3394
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003395 /* Check if source matches incall recording usecase criteria */
3396 ret = voice_check_and_set_incall_rec_usecase(adev, in);
3397 if (ret)
3398 goto error_config;
3399 else
Mingming Yin2664a5b2015-09-03 10:53:11 -07003400 ALOGV("%s: usecase(%d)", __func__, in->usecase);
3401
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303402 if (audio_extn_cin_attached_usecase(in))
3403 audio_extn_cin_acquire_usecase(in);
3404
Mingming Yin2664a5b2015-09-03 10:53:11 -07003405 if (get_usecase_from_list(adev, in->usecase) != NULL) {
3406 ALOGE("%s: use case assigned already in use, stream(%p)usecase(%d: %s)",
3407 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003408 ret = -EINVAL;
3409 goto error_config;
Mingming Yin2664a5b2015-09-03 10:53:11 -07003410 }
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003411
Eric Laurentb23d5282013-05-14 15:27:20 -07003412 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003413 if (in->pcm_device_id < 0) {
3414 ALOGE("%s: Could not find PCM device id for the usecase(%d)",
3415 __func__, in->usecase);
Eric Laurentc8400632013-02-14 19:04:54 -08003416 ret = -EINVAL;
3417 goto error_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003418 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003419
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003420 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003421
3422 if (!uc_info) {
3423 ret = -ENOMEM;
3424 goto error_config;
3425 }
3426
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003427 uc_info->id = in->usecase;
3428 uc_info->type = PCM_CAPTURE;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003429 uc_info->stream.in = in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003430 list_init(&uc_info->device_list);
3431 assign_devices(&uc_info->device_list, &in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003432 uc_info->in_snd_device = SND_DEVICE_NONE;
3433 uc_info->out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003434
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003435 list_add_tail(&adev->usecase_list, &uc_info->list);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003436 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303437 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
3438 adev->perf_lock_opts,
3439 adev->perf_lock_opts_size);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003440 select_devices(adev, in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003441
Derek Chenea197282019-01-07 17:35:01 -08003442 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
3443 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003444
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05303445 android_atomic_acquire_cas(true, false, &(in->capture_stopped));
3446
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303447 if (audio_extn_cin_attached_usecase(in)) {
Manish Dewangan46e07982018-12-13 18:18:59 +05303448 ret = audio_extn_cin_open_input_stream(in);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303449 if (ret)
3450 goto error_open;
3451 else
3452 goto done_open;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003453 }
3454
Haynes Mathew George16081042017-05-31 17:16:49 -07003455 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003456 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003457 ALOGE("%s: pcm stream not ready", __func__);
3458 goto error_open;
3459 }
3460 ret = pcm_start(in->pcm);
3461 if (ret < 0) {
3462 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
3463 goto error_open;
3464 }
3465 } else {
3466 unsigned int flags = PCM_IN | PCM_MONOTONIC;
3467 unsigned int pcm_open_retry_count = 0;
3468
Zhou Song62ea0282020-03-22 19:53:01 +08003469 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) ||
3470 (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003471 flags |= PCM_MMAP | PCM_NOIRQ;
3472 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
3473 } else if (in->realtime) {
3474 flags |= PCM_MMAP | PCM_NOIRQ;
3475 }
3476
Garmond Leunge2433c32017-09-28 21:51:22 -07003477 if (audio_extn_ffv_get_stream() == in) {
3478 ALOGD("%s: ffv stream, update pcm config", __func__);
3479 audio_extn_ffv_update_pcm_config(&config);
3480 }
Haynes Mathew George16081042017-05-31 17:16:49 -07003481 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
3482 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
3483
3484 while (1) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003485 ATRACE_BEGIN("pcm_in_open");
Haynes Mathew George16081042017-05-31 17:16:49 -07003486 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
Garmond Leung438932f2017-10-04 19:35:18 -07003487 flags, &config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003488 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05303489 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05303490 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
3491 adev->card_status = CARD_STATUS_OFFLINE;
3492 in->card_status = CARD_STATUS_OFFLINE;
3493 ret = -EIO;
3494 goto error_open;
3495 }
3496
Haynes Mathew George16081042017-05-31 17:16:49 -07003497 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
3498 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
3499 if (in->pcm != NULL) {
3500 pcm_close(in->pcm);
3501 in->pcm = NULL;
3502 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003503 if (pcm_open_retry_count == 0) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003504 ret = -EIO;
3505 goto error_open;
3506 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003507 pcm_open_retry_count--;
Haynes Mathew George16081042017-05-31 17:16:49 -07003508 usleep(PROXY_OPEN_WAIT_TIME * 1000);
3509 continue;
3510 }
3511 break;
3512 }
3513
3514 ALOGV("%s: pcm_prepare", __func__);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003515 ATRACE_BEGIN("pcm_in_prepare");
Haynes Mathew George16081042017-05-31 17:16:49 -07003516 ret = pcm_prepare(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003517 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003518 if (ret < 0) {
3519 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
3520 pcm_close(in->pcm);
3521 in->pcm = NULL;
3522 goto error_open;
3523 }
3524 register_in_stream(in);
3525 if (in->realtime) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003526 ATRACE_BEGIN("pcm_in_start");
Haynes Mathew George16081042017-05-31 17:16:49 -07003527 ret = pcm_start(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003528 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003529 if (ret < 0) {
3530 ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003531 pcm_close(in->pcm);
3532 in->pcm = NULL;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003533 goto error_open;
3534 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003535 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07003536 }
3537
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003538 check_and_enable_effect(adev);
justinweng20fb6d82019-02-21 18:49:00 -07003539 audio_extn_audiozoom_set_microphone_direction(in, in->zoom);
3540 audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003541
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003542 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303543 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
3544
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303545done_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003546 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303547 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Manisha Agarwal4c2402e2020-10-21 12:02:57 +05303548 ALOGD("%s: exit", __func__);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303549 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003550 return ret;
3551
3552error_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003553 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303554 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003555 stop_input_stream(in);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003556
Eric Laurentc8400632013-02-14 19:04:54 -08003557error_config:
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003558 if (audio_extn_cin_attached_usecase(in))
3559 audio_extn_cin_close_input_stream(in);
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05303560 /*
3561 * sleep 50ms to allow sufficient time for kernel
3562 * drivers to recover incases like SSR.
3563 */
3564 usleep(50000);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003565 ALOGD("%s: exit: status(%d)", __func__, ret);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303566 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003567 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003568}
3569
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003570void lock_input_stream(struct stream_in *in)
3571{
3572 pthread_mutex_lock(&in->pre_lock);
3573 pthread_mutex_lock(&in->lock);
3574 pthread_mutex_unlock(&in->pre_lock);
3575}
3576
3577void lock_output_stream(struct stream_out *out)
3578{
3579 pthread_mutex_lock(&out->pre_lock);
3580 pthread_mutex_lock(&out->lock);
3581 pthread_mutex_unlock(&out->pre_lock);
3582}
3583
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003584/* must be called with out->lock locked */
3585static int send_offload_cmd_l(struct stream_out* out, int command)
3586{
3587 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
3588
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003589 if (!cmd) {
3590 ALOGE("failed to allocate mem for command 0x%x", command);
3591 return -ENOMEM;
3592 }
3593
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003594 ALOGVV("%s %d", __func__, command);
3595
3596 cmd->cmd = command;
3597 list_add_tail(&out->offload_cmd_list, &cmd->node);
3598 pthread_cond_signal(&out->offload_cond);
3599 return 0;
3600}
3601
Gautam Manam14c198b2020-12-24 14:08:04 +05303602/* must be called with out->lock */
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003603static void stop_compressed_output_l(struct stream_out *out)
3604{
Gautam Manam14c198b2020-12-24 14:08:04 +05303605 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003606 out->offload_state = OFFLOAD_STATE_IDLE;
Gautam Manam14c198b2020-12-24 14:08:04 +05303607 pthread_mutex_unlock(&out->latch_lock);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08003608
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003609 out->playback_started = 0;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07003610 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003611 if (out->compr != NULL) {
3612 compress_stop(out->compr);
3613 while (out->offload_thread_blocked) {
3614 pthread_cond_wait(&out->cond, &out->lock);
3615 }
3616 }
3617}
3618
Varun Balaraje49253e2017-07-06 19:48:56 +05303619bool is_interactive_usecase(audio_usecase_t uc_id)
3620{
3621 unsigned int i;
3622 for (i = 0; i < sizeof(interactive_usecases)/sizeof(interactive_usecases[0]); i++) {
3623 if (uc_id == interactive_usecases[i])
3624 return true;
3625 }
3626 return false;
3627}
3628
3629static audio_usecase_t get_interactive_usecase(struct audio_device *adev)
3630{
3631 audio_usecase_t ret_uc = USECASE_INVALID;
3632 unsigned int intract_uc_index;
3633 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3634
3635 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
3636 for (intract_uc_index = 0; intract_uc_index < num_usecase; intract_uc_index++) {
3637 if (!(adev->interactive_usecase_state & (0x1 << intract_uc_index))) {
3638 adev->interactive_usecase_state |= 0x1 << intract_uc_index;
3639 ret_uc = interactive_usecases[intract_uc_index];
3640 break;
3641 }
3642 }
3643
3644 ALOGV("%s: Interactive usecase is %d", __func__, ret_uc);
3645 return ret_uc;
3646}
3647
3648static void free_interactive_usecase(struct audio_device *adev,
3649 audio_usecase_t uc_id)
3650{
3651 unsigned int interact_uc_index;
3652 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3653
3654 for (interact_uc_index = 0; interact_uc_index < num_usecase; interact_uc_index++) {
3655 if (interactive_usecases[interact_uc_index] == uc_id) {
3656 adev->interactive_usecase_state &= ~(0x1 << interact_uc_index);
3657 break;
3658 }
3659 }
3660 ALOGV("%s: free Interactive usecase %d", __func__, uc_id);
3661}
3662
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003663bool is_offload_usecase(audio_usecase_t uc_id)
3664{
3665 unsigned int i;
3666 for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
3667 if (uc_id == offload_usecases[i])
3668 return true;
3669 }
3670 return false;
3671}
3672
Dhananjay Kumarac341582017-02-23 23:42:25 +05303673static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_compress)
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003674{
vivek mehta446c3962015-09-14 10:57:35 -07003675 audio_usecase_t ret_uc = USECASE_INVALID;
3676 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003677 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003678 if (!adev->multi_offload_enable) {
Dhananjay Kumarac341582017-02-23 23:42:25 +05303679 if (!is_compress)
vivek mehta446c3962015-09-14 10:57:35 -07003680 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
3681 else
3682 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003683
vivek mehta446c3962015-09-14 10:57:35 -07003684 pthread_mutex_lock(&adev->lock);
3685 if (get_usecase_from_list(adev, ret_uc) != NULL)
3686 ret_uc = USECASE_INVALID;
3687 pthread_mutex_unlock(&adev->lock);
3688
3689 return ret_uc;
3690 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003691
3692 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
vivek mehta446c3962015-09-14 10:57:35 -07003693 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3694 if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) {
3695 adev->offload_usecases_state |= 0x1 << offload_uc_index;
3696 ret_uc = offload_usecases[offload_uc_index];
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003697 break;
3698 }
3699 }
vivek mehta446c3962015-09-14 10:57:35 -07003700
3701 ALOGV("%s: offload usecase is %d", __func__, ret_uc);
3702 return ret_uc;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003703}
3704
3705static void free_offload_usecase(struct audio_device *adev,
3706 audio_usecase_t uc_id)
3707{
vivek mehta446c3962015-09-14 10:57:35 -07003708 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003709 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003710
3711 if (!adev->multi_offload_enable)
3712 return;
3713
3714 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3715 if (offload_usecases[offload_uc_index] == uc_id) {
3716 adev->offload_usecases_state &= ~(0x1 << offload_uc_index);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003717 break;
3718 }
3719 }
3720 ALOGV("%s: free offload usecase %d", __func__, uc_id);
3721}
3722
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003723static void *offload_thread_loop(void *context)
3724{
3725 struct stream_out *out = (struct stream_out *) context;
3726 struct listnode *item;
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003727 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003728
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003729 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08003730 set_sched_policy(0, SP_FOREGROUND);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003731 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
3732
3733 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003734 lock_output_stream(out);
juyuchen391b5fa2018-12-12 17:58:09 +08003735 out->offload_state = OFFLOAD_STATE_IDLE;
3736 out->playback_started = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003737 for (;;) {
3738 struct offload_cmd *cmd = NULL;
3739 stream_callback_event_t event;
3740 bool send_callback = false;
3741
3742 ALOGVV("%s offload_cmd_list %d out->offload_state %d",
3743 __func__, list_empty(&out->offload_cmd_list),
3744 out->offload_state);
3745 if (list_empty(&out->offload_cmd_list)) {
3746 ALOGV("%s SLEEPING", __func__);
3747 pthread_cond_wait(&out->offload_cond, &out->lock);
3748 ALOGV("%s RUNNING", __func__);
3749 continue;
3750 }
3751
3752 item = list_head(&out->offload_cmd_list);
3753 cmd = node_to_item(item, struct offload_cmd, node);
3754 list_remove(item);
3755
3756 ALOGVV("%s STATE %d CMD %d out->compr %p",
3757 __func__, out->offload_state, cmd->cmd, out->compr);
3758
3759 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
3760 free(cmd);
3761 break;
3762 }
3763
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08003764 // allow OFFLOAD_CMD_ERROR reporting during standby
3765 // this is needed to handle failures during compress_open
3766 // Note however that on a pause timeout, the stream is closed
3767 // and no offload usecase will be active. Therefore this
3768 // special case is needed for compress_open failures alone
3769 if (cmd->cmd != OFFLOAD_CMD_ERROR &&
3770 out->compr == NULL) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003771 ALOGE("%s: Compress handle is NULL", __func__);
Haynes Mathew Georgea9abb202016-06-02 14:13:20 -07003772 free(cmd);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003773 pthread_cond_signal(&out->cond);
3774 continue;
3775 }
3776 out->offload_thread_blocked = true;
3777 pthread_mutex_unlock(&out->lock);
3778 send_callback = false;
3779 switch(cmd->cmd) {
3780 case OFFLOAD_CMD_WAIT_FOR_BUFFER:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003781 ALOGD("copl(%p):calling compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003782 compress_wait(out->compr, -1);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003783 ALOGD("copl(%p):out of compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003784 send_callback = true;
3785 event = STREAM_CBK_EVENT_WRITE_READY;
3786 break;
3787 case OFFLOAD_CMD_PARTIAL_DRAIN:
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003788 ret = compress_next_track(out->compr);
Sidipotu Ashok55820562014-02-10 16:16:38 +05303789 if(ret == 0) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003790 ALOGD("copl(%p):calling compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303791 ret = compress_partial_drain(out->compr);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003792 ALOGD("copl(%p):out of compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303793 if (ret < 0)
3794 ret = -errno;
Sidipotu Ashok55820562014-02-10 16:16:38 +05303795 }
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303796 else if (ret == -ETIMEDOUT)
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003797 ret = compress_drain(out->compr);
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003798 else
3799 ALOGE("%s: Next track returned error %d",__func__, ret);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003800 if (-ENETRESET != ret && !(-EINTR == ret &&
3801 CARD_STATUS_OFFLINE == out->card_status)) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303802 send_callback = true;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05303803 pthread_mutex_lock(&out->lock);
3804 out->send_new_metadata = 1;
3805 out->send_next_track_params = true;
3806 pthread_mutex_unlock(&out->lock);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303807 event = STREAM_CBK_EVENT_DRAIN_READY;
3808 ALOGV("copl(%p):send drain callback, ret %d", out, ret);
3809 } else
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303810 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003811 break;
3812 case OFFLOAD_CMD_DRAIN:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003813 ALOGD("copl(%p):calling compress_drain", out);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003814 ret = compress_drain(out->compr);
3815 ALOGD("copl(%p):out of compress_drain", out);
3816 // EINTR check avoids drain interruption due to SSR
3817 if (-ENETRESET != ret && !(-EINTR == ret &&
3818 CARD_STATUS_OFFLINE == out->card_status)) {
3819 send_callback = true;
3820 event = STREAM_CBK_EVENT_DRAIN_READY;
3821 } else
3822 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003823 break;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303824 case OFFLOAD_CMD_ERROR:
3825 ALOGD("copl(%p): sending error callback to AF", out);
3826 send_callback = true;
3827 event = STREAM_CBK_EVENT_ERROR;
3828 break;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003829 default:
3830 ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
3831 break;
3832 }
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003833 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003834 out->offload_thread_blocked = false;
3835 pthread_cond_signal(&out->cond);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08003836 if (send_callback && out->client_callback) {
3837 ALOGVV("%s: sending client_callback event %d", __func__, event);
3838 out->client_callback(event, NULL, out->client_cookie);
Eric Laurent6e895242013-09-05 16:10:57 -07003839 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003840 free(cmd);
3841 }
3842
3843 pthread_cond_signal(&out->cond);
3844 while (!list_empty(&out->offload_cmd_list)) {
3845 item = list_head(&out->offload_cmd_list);
3846 list_remove(item);
3847 free(node_to_item(item, struct offload_cmd, node));
3848 }
3849 pthread_mutex_unlock(&out->lock);
3850
3851 return NULL;
3852}
3853
3854static int create_offload_callback_thread(struct stream_out *out)
3855{
3856 pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
3857 list_init(&out->offload_cmd_list);
3858 pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
3859 offload_thread_loop, out);
3860 return 0;
3861}
3862
3863static int destroy_offload_callback_thread(struct stream_out *out)
3864{
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003865 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003866 stop_compressed_output_l(out);
3867 send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
3868
3869 pthread_mutex_unlock(&out->lock);
3870 pthread_join(out->offload_thread, (void **) NULL);
3871 pthread_cond_destroy(&out->offload_cond);
3872
3873 return 0;
3874}
3875
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003876static int stop_output_stream(struct stream_out *out)
3877{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303878 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003879 struct audio_usecase *uc_info;
3880 struct audio_device *adev = out->dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08003881 bool has_voip_usecase =
3882 get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP) != NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003883
Eric Laurent994a6932013-07-17 11:51:42 -07003884 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003885 out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003886 uc_info = get_usecase_from_list(adev, out->usecase);
3887 if (uc_info == NULL) {
3888 ALOGE("%s: Could not find the usecase (%d) in the list",
3889 __func__, out->usecase);
3890 return -EINVAL;
3891 }
3892
Zhou Songbaddf9f2020-11-20 13:57:39 +08003893 out->a2dp_muted = false;
3894
Derek Chenea197282019-01-07 17:35:01 -08003895 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3896 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003897
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003898 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05303899 !(audio_extn_passthru_is_passthrough_stream(out))) {
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08003900 if (adev->visualizer_stop_output != NULL)
3901 adev->visualizer_stop_output(out->handle, out->pcm_device_id);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08003902
3903 audio_extn_dts_remove_state_notifier_node(out->usecase);
3904
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08003905 if (adev->offload_effects_stop_output != NULL)
3906 adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
vivek mehtad15d2bf2019-05-17 13:35:10 -07003907 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
3908 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
3909 audio_low_latency_hint_end();
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08003910 }
Eric Laurentc4aef752013-09-12 17:45:53 -07003911
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07003912 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
3913 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07003914 voice_set_device_mute_flag(adev, false);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07003915 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07003916
Eric Laurent150dbfe2013-02-27 14:31:02 -08003917 /* 1. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003918 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003919
3920 /* 2. Disable the rx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003921 disable_snd_device(adev, uc_info->out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08003922 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3923 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003924
Aalique Grahame22e49102018-12-18 14:23:57 -08003925 audio_extn_extspk_update(adev->extspk);
3926
Xiaojun Sang785b5da2017-08-03 15:52:29 +08003927 if (is_offload_usecase(out->usecase)) {
3928 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
3929 adev->dsp_bit_width_enforce_mode,
3930 false);
3931 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003932 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07003933 ret = audio_extn_usb_check_and_set_svc_int(uc_info,
3934 false);
3935
3936 if (ret != 0)
3937 check_usecases_codec_backend(adev, uc_info, uc_info->out_snd_device);
3938 /* default service interval was successfully updated,
3939 reopen USB backend with new service interval */
3940 ret = 0;
3941 }
Xiaojun Sang785b5da2017-08-03 15:52:29 +08003942
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003943 list_remove(&uc_info->list);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303944 out->started = 0;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003945 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05303946 (audio_extn_passthru_is_passthrough_stream(out))) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003947 ALOGV("Disable passthrough , reset mixer to pcm");
3948 /* NO_PASSTHROUGH */
Meng Wang4c32fb42020-01-16 17:57:11 +08003949#ifdef AUDIO_GKI_ENABLED
3950 /* out->compr_config.codec->reserved[0] is for compr_passthr */
3951 out->compr_config.codec->reserved[0] = 0;
3952#else
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003953 out->compr_config.codec->compr_passthr = 0;
Meng Wang4c32fb42020-01-16 17:57:11 +08003954#endif
Mingming Yin21854652016-04-13 11:54:02 -07003955 audio_extn_passthru_on_stop(out);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003956 audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
3957 }
Eric Laurent07eeafd2013-10-06 12:52:49 -07003958
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05303959 /* Must be called after removing the usecase from list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003960 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL))
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05303961 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05303962
Manish Dewangan21a850a2017-08-14 12:03:55 +05303963 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07003964 ret = audio_extn_ip_hdlr_intf_close(out->ip_hdlr_handle, true, out);
3965 if (ret < 0)
3966 ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
3967 }
3968
Zhou Song642ec432020-12-23 16:11:10 +08003969 /* trigger voip input to reroute when voip output changes to hearing aid */
Aalique Grahame22e49102018-12-18 14:23:57 -08003970 if (has_voip_usecase ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003971 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08003972 struct listnode *node;
3973 struct audio_usecase *usecase;
3974 list_for_each(node, &adev->usecase_list) {
3975 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Song642ec432020-12-23 16:11:10 +08003976 if (usecase->type == PCM_PLAYBACK || usecase == uc_info ||
3977 (usecase->type == PCM_CAPTURE &&
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05303978 usecase->id != USECASE_AUDIO_RECORD_VOIP &&
Zhou Song642ec432020-12-23 16:11:10 +08003979 usecase->id != USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY))
Aalique Grahame22e49102018-12-18 14:23:57 -08003980 continue;
3981
3982 ALOGD("%s: select_devices at usecase(%d: %s) after removing the usecase(%d: %s)",
3983 __func__, usecase->id, use_case_table[usecase->id],
3984 out->usecase, use_case_table[out->usecase]);
3985 select_devices(adev, usecase->id);
3986 }
3987 }
3988
Garmond Leung5fd0b552018-04-17 11:56:12 -07003989 free(uc_info);
Eric Laurent994a6932013-07-17 11:51:42 -07003990 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003991 return ret;
3992}
3993
Vignesh Kulothungana6927272019-02-20 15:17:07 -08003994struct pcm* pcm_open_prepare_helper(unsigned int snd_card, unsigned int pcm_device_id,
3995 unsigned int flags, unsigned int pcm_open_retry_count,
3996 struct pcm_config *config)
3997{
3998 struct pcm* pcm = NULL;
3999
4000 while (1) {
4001 pcm = pcm_open(snd_card, pcm_device_id, flags, config);
4002 if (pcm == NULL || !pcm_is_ready(pcm)) {
4003 ALOGE("%s: %s", __func__, pcm_get_error(pcm));
4004 if (pcm != NULL) {
4005 pcm_close(pcm);
4006 pcm = NULL;
4007 }
Weiyin Jiang72197252019-10-09 11:49:32 +08004008 if (pcm_open_retry_count == 0)
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004009 return NULL;
4010
Weiyin Jiang72197252019-10-09 11:49:32 +08004011 pcm_open_retry_count--;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004012 usleep(PROXY_OPEN_WAIT_TIME * 1000);
4013 continue;
4014 }
4015 break;
4016 }
4017
4018 if (pcm_is_ready(pcm)) {
4019 int ret = pcm_prepare(pcm);
4020 if (ret < 0) {
4021 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
4022 pcm_close(pcm);
4023 pcm = NULL;
4024 }
4025 }
4026
4027 return pcm;
4028}
4029
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004030int start_output_stream(struct stream_out *out)
4031{
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004032 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004033 struct audio_usecase *uc_info;
4034 struct audio_device *adev = out->dev;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004035 char mixer_ctl_name[128];
4036 struct mixer_ctl *ctl = NULL;
4037 char* perf_mode[] = {"ULL", "ULL_PP", "LL"};
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304038 bool a2dp_combo = false;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004039 bool is_haptic_usecase = (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) ? true: false;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004040
Haynes Mathew George380745d2017-10-04 15:27:45 -07004041 ATRACE_BEGIN("start_output_stream");
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004042 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
4043 ret = -EINVAL;
4044 goto error_config;
4045 }
4046
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004047 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x) is_haptic_usecase(%d)",
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304048 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004049 get_device_types(&out->device_list), is_haptic_usecase);
4050
4051 bool is_speaker_active = compare_device_type(&out->device_list,
4052 AUDIO_DEVICE_OUT_SPEAKER);
4053 bool is_speaker_safe_active = compare_device_type(&out->device_list,
4054 AUDIO_DEVICE_OUT_SPEAKER_SAFE);
Naresh Tanniru4c630392014-05-12 01:05:52 +05304055
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304056 if (CARD_STATUS_OFFLINE == out->card_status ||
4057 CARD_STATUS_OFFLINE == adev->card_status) {
4058 ALOGW("out->card_status or adev->card_status offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05304059 ret = -EIO;
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004060 goto error_fatal;
Naresh Tanniru4c630392014-05-12 01:05:52 +05304061 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05304062
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004063 //Update incall music usecase to reflect correct voice session
4064 if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
4065 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
4066 if (ret != 0) {
4067 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
4068 __func__, ret);
4069 goto error_config;
4070 }
4071 }
4072
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004073 if (is_a2dp_out_device_type(&out->device_list)) {
Florian Pfister1a84f312018-07-19 14:38:18 +02004074 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004075 if (is_speaker_active || is_speaker_safe_active) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304076 a2dp_combo = true;
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304077 } else {
Zhou Songd01e7a22020-09-23 22:49:01 +08004078 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304079 ALOGE("%s: A2DP profile is not ready, return error", __func__);
4080 ret = -EAGAIN;
4081 goto error_config;
4082 }
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304083 }
4084 }
4085 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004086 if (is_sco_out_device_type(&out->device_list)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304087 if (!adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004088 if (is_speaker_active) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304089 //combo usecase just by pass a2dp
4090 ALOGW("%s: SCO is not connected, route it to speaker", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004091 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304092 } else {
4093 ALOGE("%s: SCO profile is not ready, return error", __func__);
4094 ret = -EAGAIN;
4095 goto error_config;
4096 }
4097 }
4098 }
4099
Eric Laurentb23d5282013-05-14 15:27:20 -07004100 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004101 if (out->pcm_device_id < 0) {
4102 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
4103 __func__, out->pcm_device_id, out->usecase);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004104 ret = -EINVAL;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004105 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004106 }
4107
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004108 if (is_haptic_usecase) {
Meng Wang51d8c2a2020-04-27 15:23:21 +08004109 adev->haptic_pcm_device_id = platform_get_pcm_device_id(
4110 USECASE_AUDIO_PLAYBACK_HAPTICS, PCM_PLAYBACK);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004111 if (adev->haptic_pcm_device_id < 0) {
4112 ALOGE("%s: Invalid Haptics pcm device id(%d) for the usecase(%d)",
4113 __func__, adev->haptic_pcm_device_id, out->usecase);
4114 ret = -EINVAL;
4115 goto error_config;
4116 }
4117 }
4118
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004119 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004120
4121 if (!uc_info) {
4122 ret = -ENOMEM;
4123 goto error_config;
4124 }
4125
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004126 uc_info->id = out->usecase;
4127 uc_info->type = PCM_PLAYBACK;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08004128 uc_info->stream.out = out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004129 list_init(&uc_info->device_list);
4130 assign_devices(&uc_info->device_list, &out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004131 uc_info->in_snd_device = SND_DEVICE_NONE;
4132 uc_info->out_snd_device = SND_DEVICE_NONE;
Garmond Leung5fd0b552018-04-17 11:56:12 -07004133
4134 /* This must be called before adding this usecase to the list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004135 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004136 audio_extn_usb_check_and_set_svc_int(uc_info, true);
4137 /* USB backend is not reopened immediately.
4138 This is eventually done as part of select_devices */
4139 }
4140
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004141 list_add_tail(&adev->usecase_list, &uc_info->list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004142
Wei Wangf7ca6c92017-11-21 14:51:20 -08004143 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304144 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
4145 adev->perf_lock_opts,
4146 adev->perf_lock_opts_size);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304147
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004148 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304149 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304150 if (audio_extn_passthru_is_enabled() &&
4151 audio_extn_passthru_is_passthrough_stream(out)) {
4152 audio_extn_passthru_on_start(out);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304153 }
4154 }
4155
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004156 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02004157 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304158 if (!a2dp_combo) {
4159 check_a2dp_restore_l(adev, out, false);
4160 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004161 struct listnode dev;
4162 list_init(&dev);
4163 assign_devices(&dev, &out->device_list);
4164 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4165 reassign_device_list(&out->device_list,
4166 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aalique Grahame22e49102018-12-18 14:23:57 -08004167 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004168 reassign_device_list(&out->device_list,
4169 AUDIO_DEVICE_OUT_SPEAKER, "");
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304170 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004171 assign_devices(&out->device_list, &dev);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304172 }
4173 } else {
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304174 select_devices(adev, out->usecase);
4175 if (is_a2dp_out_device_type(&out->device_list) &&
4176 !adev->a2dp_started) {
4177 if (is_speaker_active || is_speaker_safe_active) {
4178 struct listnode dev;
4179 list_init(&dev);
4180 assign_devices(&dev, &out->device_list);
4181 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4182 reassign_device_list(&out->device_list,
4183 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
4184 else
4185 reassign_device_list(&out->device_list,
4186 AUDIO_DEVICE_OUT_SPEAKER, "");
4187 select_devices(adev, out->usecase);
4188 assign_devices(&out->device_list, &dev);
4189 } else {
4190 ret = -EINVAL;
4191 goto error_open;
4192 }
4193 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304194 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004195
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004196 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4197 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004198 voice_set_device_mute_flag(adev, true);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004199 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004200
Derek Chenea197282019-01-07 17:35:01 -08004201 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
4202 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004203
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004204 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
4205 __func__, adev->snd_card, out->pcm_device_id, out->config.format);
Haynes Mathew George16081042017-05-31 17:16:49 -07004206
4207 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07004208 ALOGD("%s: Starting MMAP stream", __func__);
Haynes Mathew George16081042017-05-31 17:16:49 -07004209 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4210 ALOGE("%s: pcm stream not ready", __func__);
4211 goto error_open;
4212 }
4213 ret = pcm_start(out->pcm);
4214 if (ret < 0) {
4215 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
4216 goto error_open;
4217 }
Arun Mirpuri5d170872019-03-26 13:21:31 -07004218 out_set_mmap_volume(&out->stream, out->volume_l, out->volume_r);
Haynes Mathew George16081042017-05-31 17:16:49 -07004219 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004220 unsigned int flags = PCM_OUT;
4221 unsigned int pcm_open_retry_count = 0;
4222 if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
4223 flags |= PCM_MMAP | PCM_NOIRQ;
4224 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004225 } else if (out->realtime) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08004226 flags |= PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004227 } else
4228 flags |= PCM_MONOTONIC;
4229
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004230 if ((adev->vr_audio_mode_enabled) &&
4231 (out->flags & AUDIO_OUTPUT_FLAG_RAW)) {
4232 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
4233 "PCM_Dev %d Topology", out->pcm_device_id);
4234 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
4235 if (!ctl) {
4236 ALOGI("%s: Could not get ctl for mixer cmd might be ULL - %s",
4237 __func__, mixer_ctl_name);
4238 } else {
4239 //if success use ULLPP
4240 ALOGI("%s: mixer ctrl %s succeeded setting up ULL for %d",
4241 __func__, mixer_ctl_name, out->pcm_device_id);
4242 //There is a still a possibility that some sessions
4243 // that request for FAST|RAW when 3D audio is active
4244 //can go through ULLPP. Ideally we expects apps to
4245 //listen to audio focus and stop concurrent playback
4246 //Also, we will look for mode flag (voice_in_communication)
4247 //before enabling the realtime flag.
4248 mixer_ctl_set_enum_by_string(ctl, perf_mode[1]);
4249 }
4250 }
4251
Vatsal Bucha3f39f222021-06-29 16:16:55 +05304252 platform_set_stream_channel_map(adev->platform, out->channel_mask,
4253 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Surendar Karka91fa3682018-07-02 18:12:12 +05304254
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004255 out->pcm = pcm_open_prepare_helper(adev->snd_card, out->pcm_device_id,
4256 flags, pcm_open_retry_count,
4257 &(out->config));
4258 if (out->pcm == NULL) {
4259 ret = -EIO;
4260 goto error_open;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004261 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004262
4263 if (is_haptic_usecase) {
4264 adev->haptic_pcm = pcm_open_prepare_helper(adev->snd_card,
4265 adev->haptic_pcm_device_id,
4266 flags, pcm_open_retry_count,
4267 &(adev->haptics_config));
4268 // failure to open haptics pcm shouldnt stop audio,
4269 // so do not close audio pcm in case of error
Vignesh Kulothungane4039c12019-05-07 15:51:39 -07004270
4271 if (property_get_bool("vendor.audio.enable_haptic_audio_sync", false)) {
4272 ALOGD("%s: enable haptic audio synchronization", __func__);
4273 platform_set_qtime(adev->platform, out->pcm_device_id, adev->haptic_pcm_device_id);
4274 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004275 }
4276
Zhou Song2b8f28f2017-09-11 10:51:38 +08004277 // apply volume for voip playback after path is set up
4278 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
4279 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
Ramu Gottipati36547092018-12-28 11:32:09 +05304280 else if ((out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY || out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
4281 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) && (out->apply_volume)) {
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304282 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
4283 out->apply_volume = false;
Derek Chenf13dd492018-11-13 14:53:51 -08004284 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
4285 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304286 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004287 } else {
Zhou Song79929fe2020-01-20 17:57:43 +08004288 /*
4289 * set custom channel map if:
4290 * 1. neither mono nor stereo clips i.e. channels > 2 OR
4291 * 2. custom channel map has been set by client
4292 * else default channel map of FC/FR/FL can always be set to DSP
4293 */
4294 if (popcount(out->channel_mask) > 2 || out->channel_map_param.channel_map[0])
4295 platform_set_stream_channel_map(adev->platform, out->channel_mask,
Weiyin Jiang810a80d2021-01-18 16:04:31 +08004296 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004297 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4298 adev->dsp_bit_width_enforce_mode,
4299 true);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004300 out->pcm = NULL;
Haynes Mathew George380745d2017-10-04 15:27:45 -07004301 ATRACE_BEGIN("compress_open");
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -08004302 out->compr = compress_open(adev->snd_card,
4303 out->pcm_device_id,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004304 COMPRESS_IN, &out->compr_config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004305 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05304306 if (errno == ENETRESET && !is_compress_ready(out->compr)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05304307 ALOGE("%s: compress_open failed errno:%d\n", __func__, errno);
4308 adev->card_status = CARD_STATUS_OFFLINE;
4309 out->card_status = CARD_STATUS_OFFLINE;
4310 ret = -EIO;
4311 goto error_open;
4312 }
4313
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004314 if (out->compr && !is_compress_ready(out->compr)) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004315 ALOGE("%s: failed /w error %s", __func__, compress_get_error(out->compr));
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004316 compress_close(out->compr);
4317 out->compr = NULL;
4318 ret = -EIO;
4319 goto error_open;
4320 }
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304321 /* compress_open sends params of the track, so reset the flag here */
4322 out->is_compr_metadata_avail = false;
4323
Ben Rombergerd771a7c2017-02-22 18:05:17 -08004324 if (out->client_callback)
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004325 compress_nonblock(out->compr, out->non_blocking);
Eric Laurentc4aef752013-09-12 17:45:53 -07004326
Fred Oh3f43e742015-03-04 18:42:34 -08004327 /* Since small bufs uses blocking writes, a write will be blocked
4328 for the default max poll time (20s) in the event of an SSR.
4329 Reduce the poll time to observe and deal with SSR faster.
4330 */
Ashish Jain5106d362016-05-11 19:23:33 +05304331 if (!out->non_blocking) {
Fred Oh3f43e742015-03-04 18:42:34 -08004332 compress_set_max_poll_wait(out->compr, 1000);
4333 }
4334
Manish Dewangan69426c82017-01-30 17:35:36 +05304335 audio_extn_utils_compress_set_render_mode(out);
Manish Dewangan58229382017-02-02 15:48:41 +05304336 audio_extn_utils_compress_set_clk_rec_mode(uc_info);
Manish Dewangan69426c82017-01-30 17:35:36 +05304337
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004338 audio_extn_dts_create_state_notifier_node(out->usecase);
4339 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
4340 popcount(out->channel_mask),
4341 out->playback_started);
4342
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004343#ifdef DS1_DOLBY_DDP_ENABLED
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05304344 if (audio_extn_utils_is_dolby_format(out->format))
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004345 audio_extn_dolby_send_ddp_endp_params(adev);
4346#endif
Preetam Singh Ranawatd18d8832017-02-08 17:34:54 +05304347 if (!(audio_extn_passthru_is_passthrough_stream(out)) &&
4348 (out->sample_rate != 176400 && out->sample_rate <= 192000)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004349 if (adev->visualizer_start_output != NULL)
4350 adev->visualizer_start_output(out->handle, out->pcm_device_id);
4351 if (adev->offload_effects_start_output != NULL)
Ashish Jain5106d362016-05-11 19:23:33 +05304352 adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004353 audio_extn_check_and_set_dts_hpx_state(adev);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004354 }
Derek Chenf13dd492018-11-13 14:53:51 -08004355
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004356 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf13dd492018-11-13 14:53:51 -08004357 /* Update cached volume from media to offload/direct stream */
4358 struct listnode *node = NULL;
4359 list_for_each(node, &adev->active_outputs_list) {
4360 streams_output_ctxt_t *out_ctxt = node_to_item(node,
4361 streams_output_ctxt_t,
4362 list);
4363 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
4364 out->volume_l = out_ctxt->output->volume_l;
4365 out->volume_r = out_ctxt->output->volume_r;
4366 }
4367 }
4368 out_set_compr_volume(&out->stream,
4369 out->volume_l, out->volume_r);
4370 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004371 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004372
4373 if (ret == 0) {
4374 register_out_stream(out);
4375 if (out->realtime) {
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07004376 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4377 ALOGE("%s: pcm stream not ready", __func__);
4378 goto error_open;
4379 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07004380 ATRACE_BEGIN("pcm_start");
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004381 ret = pcm_start(out->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004382 ATRACE_END();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004383 if (ret < 0)
4384 goto error_open;
4385 }
4386 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004387 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304388 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Jaideep Sharma0fa53812020-09-17 09:00:11 +05304389 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004390
vivek mehtad15d2bf2019-05-17 13:35:10 -07004391 if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4392 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4393 audio_low_latency_hint_start();
4394 }
4395
Manish Dewangan21a850a2017-08-14 12:03:55 +05304396 if (out->ip_hdlr_handle) {
Vidyakumar Athota6d655882017-05-22 18:26:24 -07004397 ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07004398 if (ret < 0)
4399 ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
4400 }
4401
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07004402 // consider a scenario where on pause lower layers are tear down.
4403 // so on resume, swap mixer control need to be sent only when
4404 // backend is active, hence rather than sending from enable device
4405 // sending it from start of streamtream
4406
4407 platform_set_swap_channels(adev, true);
4408
Haynes Mathew George380745d2017-10-04 15:27:45 -07004409 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304410 enable_gcov();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004411 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004412error_open:
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004413 if (adev->haptic_pcm) {
4414 pcm_close(adev->haptic_pcm);
4415 adev->haptic_pcm = NULL;
4416 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004417 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304418 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004419 stop_output_stream(out);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004420error_fatal:
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05304421 /*
4422 * sleep 50ms to allow sufficient time for kernel
4423 * drivers to recover incases like SSR.
4424 */
4425 usleep(50000);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004426error_config:
Haynes Mathew George380745d2017-10-04 15:27:45 -07004427 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304428 enable_gcov();
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004429 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004430}
4431
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004432static int check_input_parameters(uint32_t sample_rate,
4433 audio_format_t format,
Aalique Grahame22e49102018-12-18 14:23:57 -08004434 int channel_count,
4435 bool is_usb_hifi)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004436{
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004437 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004438
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304439 if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
4440 (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) &&
4441 (format != AUDIO_FORMAT_PCM_FLOAT)) &&
Mingming Yine62d7842013-10-25 16:26:03 -07004442 !voice_extn_compress_voip_is_format_supported(format) &&
Ralf Herzaec80262018-07-03 07:08:49 +02004443 !audio_extn_compr_cap_format_supported(format) &&
4444 !audio_extn_cin_format_supported(format))
Haynes Mathew George484e8d22017-07-31 18:55:17 -07004445 ret = -EINVAL;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004446
Aalique Grahame22e49102018-12-18 14:23:57 -08004447 int max_channel_count = is_usb_hifi ? MAX_HIFI_CHANNEL_COUNT : MAX_CHANNEL_COUNT;
4448 if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > max_channel_count)) {
4449 ALOGE("%s: unsupported channel count (%d) passed Min / Max (%d / %d)", __func__,
4450 channel_count, MIN_CHANNEL_COUNT, max_channel_count);
4451 return -EINVAL;
4452 }
4453
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004454 switch (channel_count) {
4455 case 1:
4456 case 2:
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05304457 case 3:
4458 case 4:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004459 case 6:
Karthikeyan Mani07faa602018-08-20 11:01:32 -07004460 case 8:
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05304461 case 10:
4462 case 12:
4463 case 14:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004464 break;
4465 default:
4466 ret = -EINVAL;
4467 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004468
4469 switch (sample_rate) {
4470 case 8000:
4471 case 11025:
4472 case 12000:
4473 case 16000:
4474 case 22050:
4475 case 24000:
4476 case 32000:
4477 case 44100:
4478 case 48000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004479 case 88200:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304480 case 96000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004481 case 176400:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304482 case 192000:
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004483 break;
4484 default:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004485 ret = -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004486 }
4487
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004488 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004489}
4490
Naresh Tanniru04f71882018-06-26 17:46:22 +05304491
4492/** Add a value in a list if not already present.
4493 * @return true if value was successfully inserted or already present,
4494 * false if the list is full and does not contain the value.
4495 */
4496static bool register_uint(uint32_t value, uint32_t* list, size_t list_length) {
4497 for (size_t i = 0; i < list_length; i++) {
4498 if (list[i] == value) return true; // value is already present
4499 if (list[i] == 0) { // no values in this slot
4500 list[i] = value;
4501 return true; // value inserted
4502 }
4503 }
4504 return false; // could not insert value
4505}
4506
4507/** Add channel_mask in supported_channel_masks if not already present.
4508 * @return true if channel_mask was successfully inserted or already present,
4509 * false if supported_channel_masks is full and does not contain channel_mask.
4510 */
4511static void register_channel_mask(audio_channel_mask_t channel_mask,
4512 audio_channel_mask_t supported_channel_masks[static MAX_SUPPORTED_CHANNEL_MASKS]) {
4513 ALOGE_IF(!register_uint(channel_mask, supported_channel_masks, MAX_SUPPORTED_CHANNEL_MASKS),
4514 "%s: stream can not declare supporting its channel_mask %x", __func__, channel_mask);
4515}
4516
4517/** Add format in supported_formats if not already present.
4518 * @return true if format was successfully inserted or already present,
4519 * false if supported_formats is full and does not contain format.
4520 */
4521static void register_format(audio_format_t format,
4522 audio_format_t supported_formats[static MAX_SUPPORTED_FORMATS]) {
4523 ALOGE_IF(!register_uint(format, supported_formats, MAX_SUPPORTED_FORMATS),
4524 "%s: stream can not declare supporting its format %x", __func__, format);
4525}
4526/** Add sample_rate in supported_sample_rates if not already present.
4527 * @return true if sample_rate was successfully inserted or already present,
4528 * false if supported_sample_rates is full and does not contain sample_rate.
4529 */
4530static void register_sample_rate(uint32_t sample_rate,
4531 uint32_t supported_sample_rates[static MAX_SUPPORTED_SAMPLE_RATES]) {
4532 ALOGE_IF(!register_uint(sample_rate, supported_sample_rates, MAX_SUPPORTED_SAMPLE_RATES),
4533 "%s: stream can not declare supporting its sample rate %x", __func__, sample_rate);
4534}
4535
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004536static inline uint32_t lcm(uint32_t num1, uint32_t num2)
4537{
4538 uint32_t high = num1, low = num2, temp = 0;
4539
4540 if (!num1 || !num2)
4541 return 0;
4542
4543 if (num1 < num2) {
4544 high = num2;
4545 low = num1;
4546 }
4547
4548 while (low != 0) {
4549 temp = low;
4550 low = high % low;
4551 high = temp;
4552 }
4553 return (num1 * num2)/high;
4554}
4555
4556static inline uint32_t nearest_multiple(uint32_t num, uint32_t multiplier)
4557{
4558 uint32_t remainder = 0;
4559
4560 if (!multiplier)
4561 return num;
4562
4563 remainder = num % multiplier;
4564 if (remainder)
4565 num += (multiplier - remainder);
4566
4567 return num;
4568}
4569
Aalique Grahame22e49102018-12-18 14:23:57 -08004570static size_t get_stream_buffer_size(size_t duration_ms,
4571 uint32_t sample_rate,
4572 audio_format_t format,
4573 int channel_count,
4574 bool is_low_latency)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004575{
4576 size_t size = 0;
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004577 uint32_t bytes_per_period_sample = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004578
Aalique Grahame22e49102018-12-18 14:23:57 -08004579 size = (sample_rate * duration_ms) / 1000;
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004580 if (is_low_latency)
4581 size = configured_low_latency_capture_period_size;
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304582
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004583 bytes_per_period_sample = audio_bytes_per_sample(format) * channel_count;
Aalique Grahame22e49102018-12-18 14:23:57 -08004584 size *= audio_bytes_per_sample(format) * channel_count;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004585
Ralf Herzbd08d632018-09-28 15:50:49 +02004586 /* make sure the size is multiple of 32 bytes and additionally multiple of
4587 * the frame_size (required for 24bit samples and non-power-of-2 channel counts)
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004588 * At 48 kHz mono 16-bit PCM:
4589 * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
4590 * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004591 * Also, make sure the size is multiple of bytes per period sample
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004592 */
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004593 size = nearest_multiple(size, lcm(32, bytes_per_period_sample));
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07004594
4595 return size;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004596}
4597
Aalique Grahame22e49102018-12-18 14:23:57 -08004598static size_t get_input_buffer_size(uint32_t sample_rate,
4599 audio_format_t format,
4600 int channel_count,
4601 bool is_low_latency)
4602{
4603 /* Don't know if USB HIFI in this context so use true to be conservative */
4604 if (check_input_parameters(sample_rate, format, channel_count,
4605 true /*is_usb_hifi */) != 0)
4606 return 0;
4607
4608 return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
4609 sample_rate,
4610 format,
4611 channel_count,
4612 is_low_latency);
4613}
4614
Derek Chenf6318be2017-06-12 17:16:24 -04004615size_t get_output_period_size(uint32_t sample_rate,
4616 audio_format_t format,
4617 int channel_count,
4618 int duration /*in millisecs*/)
Ashish Jain058165c2016-09-28 23:18:48 +05304619{
4620 size_t size = 0;
4621 uint32_t bytes_per_sample = audio_bytes_per_sample(format);
4622
4623 if ((duration == 0) || (sample_rate == 0) ||
4624 (bytes_per_sample == 0) || (channel_count == 0)) {
4625 ALOGW("Invalid config duration %d sr %d bps %d ch %d", duration, sample_rate,
4626 bytes_per_sample, channel_count);
4627 return -EINVAL;
4628 }
4629
4630 size = (sample_rate *
4631 duration *
4632 bytes_per_sample *
4633 channel_count) / 1000;
4634 /*
4635 * To have same PCM samples for all channels, the buffer size requires to
4636 * be multiple of (number of channels * bytes per sample)
4637 * For writes to succeed, the buffer must be written at address which is multiple of 32
4638 */
4639 size = ALIGN(size, (bytes_per_sample * channel_count * 32));
4640
4641 return (size/(channel_count * bytes_per_sample));
4642}
4643
Zhou Song48453a02018-01-10 17:50:59 +08004644static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out, struct timespec *timestamp)
Ashish Jain5106d362016-05-11 19:23:33 +05304645{
4646 uint64_t actual_frames_rendered = 0;
Weiyin Jiang4813da12020-05-28 00:37:28 +08004647 uint64_t written_frames = 0;
4648 uint64_t kernel_frames = 0;
4649 uint64_t dsp_frames = 0;
4650 uint64_t signed_frames = 0;
4651 size_t kernel_buffer_size = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05304652
4653 /* This adjustment accounts for buffering after app processor.
4654 * It is based on estimated DSP latency per use case, rather than exact.
4655 */
George Gao9ba8a142020-07-23 14:30:03 -07004656 dsp_frames = platform_render_latency(out) *
Weiyin Jiang4813da12020-05-28 00:37:28 +08004657 out->sample_rate / 1000000LL;
Ashish Jain5106d362016-05-11 19:23:33 +05304658
Zhou Song48453a02018-01-10 17:50:59 +08004659 pthread_mutex_lock(&out->position_query_lock);
Weiyin Jiang4813da12020-05-28 00:37:28 +08004660 written_frames = out->written /
4661 (audio_bytes_per_sample(out->hal_ip_format) * popcount(out->channel_mask));
4662
Ashish Jain5106d362016-05-11 19:23:33 +05304663 /* not querying actual state of buffering in kernel as it would involve an ioctl call
4664 * which then needs protection, this causes delay in TS query for pcm_offload usecase
4665 * hence only estimate.
4666 */
Weiyin Jiang4813da12020-05-28 00:37:28 +08004667 kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments;
4668 kernel_frames = kernel_buffer_size /
4669 (audio_bytes_per_sample(out->hal_op_format) * popcount(out->channel_mask));
Ashish Jain5106d362016-05-11 19:23:33 +05304670
Weiyin Jiang4813da12020-05-28 00:37:28 +08004671 if (written_frames >= (kernel_frames + dsp_frames))
4672 signed_frames = written_frames - kernel_frames - dsp_frames;
Ashish Jain5106d362016-05-11 19:23:33 +05304673
Zhou Song48453a02018-01-10 17:50:59 +08004674 if (signed_frames > 0) {
Ashish Jain5106d362016-05-11 19:23:33 +05304675 actual_frames_rendered = signed_frames;
Zhou Song48453a02018-01-10 17:50:59 +08004676 if (timestamp != NULL )
4677 *timestamp = out->writeAt;
4678 } else if (timestamp != NULL) {
4679 clock_gettime(CLOCK_MONOTONIC, timestamp);
4680 }
4681 pthread_mutex_unlock(&out->position_query_lock);
Ashish Jain5106d362016-05-11 19:23:33 +05304682
Weiyin Jiang4813da12020-05-28 00:37:28 +08004683 ALOGVV("%s signed frames %lld written frames %lld kernel frames %lld dsp frames %lld",
4684 __func__, signed_frames, written_frames, kernel_frames, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05304685
4686 return actual_frames_rendered;
4687}
4688
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004689static uint32_t out_get_sample_rate(const struct audio_stream *stream)
4690{
4691 struct stream_out *out = (struct stream_out *)stream;
4692
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004693 return out->sample_rate;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004694}
4695
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004696static int out_set_sample_rate(struct audio_stream *stream __unused,
4697 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004698{
4699 return -ENOSYS;
4700}
4701
4702static size_t out_get_buffer_size(const struct audio_stream *stream)
4703{
4704 struct stream_out *out = (struct stream_out *)stream;
4705
Varun Balaraje49253e2017-07-06 19:48:56 +05304706 if (is_interactive_usecase(out->usecase)) {
Sri Karri27279e12017-08-07 16:05:20 +05304707 return out->config.period_size * out->config.period_count;
Varun Balaraje49253e2017-07-06 19:48:56 +05304708 } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Naresh Tanniruee3499a2017-01-05 14:05:35 +05304709 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
4710 return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
4711 else
4712 return out->compr_config.fragment_size;
4713 } else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08004714 return voice_extn_compress_voip_out_get_buffer_size(out);
Dhananjay Kumarac341582017-02-23 23:42:25 +05304715 else if (is_offload_usecase(out->usecase) &&
4716 out->flags == AUDIO_OUTPUT_FLAG_DIRECT)
Ashish Jain83a6cc22016-06-28 14:34:17 +05304717 return out->hal_fragment_size;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004718
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004719 return out->config.period_size * out->af_period_multiplier *
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07004720 audio_stream_out_frame_size((const struct audio_stream_out *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004721}
4722
4723static uint32_t out_get_channels(const struct audio_stream *stream)
4724{
4725 struct stream_out *out = (struct stream_out *)stream;
4726
4727 return out->channel_mask;
4728}
4729
4730static audio_format_t out_get_format(const struct audio_stream *stream)
4731{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004732 struct stream_out *out = (struct stream_out *)stream;
4733
4734 return out->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004735}
4736
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004737static int out_set_format(struct audio_stream *stream __unused,
4738 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004739{
4740 return -ENOSYS;
4741}
4742
4743static int out_standby(struct audio_stream *stream)
4744{
4745 struct stream_out *out = (struct stream_out *)stream;
4746 struct audio_device *adev = out->dev;
Haynes Mathew George16081042017-05-31 17:16:49 -07004747 bool do_stop = true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004748
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304749 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4750 stream, out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004751
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07004752 lock_output_stream(out);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004753 if (!out->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004754 if (adev->adm_deregister_stream)
4755 adev->adm_deregister_stream(adev->adm_data, out->handle);
4756
Weiyin Jiang280ea742020-09-08 20:28:22 +08004757 if (is_offload_usecase(out->usecase)) {
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004758 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08004759 }
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004760
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08004761 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004762 out->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08004763 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
4764 voice_extn_compress_voip_close_output_stream(stream);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304765 out->started = 0;
Zhou Songa8895042016-07-05 17:54:22 +08004766 pthread_mutex_unlock(&adev->lock);
4767 pthread_mutex_unlock(&out->lock);
4768 ALOGD("VOIP output entered standby");
4769 return 0;
4770 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004771 if (out->pcm) {
4772 pcm_close(out->pcm);
4773 out->pcm = NULL;
4774 }
Meng Wanga09da002020-04-20 12:56:04 +08004775 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
4776 if (adev->haptic_pcm) {
4777 pcm_close(adev->haptic_pcm);
4778 adev->haptic_pcm = NULL;
4779 }
4780
4781 if (adev->haptic_buffer != NULL) {
4782 free(adev->haptic_buffer);
4783 adev->haptic_buffer = NULL;
4784 adev->haptic_buffer_size = 0;
4785 }
4786 adev->haptic_pcm_device_id = 0;
4787 }
4788
Haynes Mathew George16081042017-05-31 17:16:49 -07004789 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4790 do_stop = out->playback_started;
4791 out->playback_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07004792
4793 if (out->mmap_shared_memory_fd >= 0) {
4794 ALOGV("%s: closing mmap_shared_memory_fd = %d",
4795 __func__, out->mmap_shared_memory_fd);
4796 close(out->mmap_shared_memory_fd);
4797 out->mmap_shared_memory_fd = -1;
4798 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004799 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004800 } else {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07004801 ALOGD("copl(%p):standby", out);
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304802 out->send_next_track_params = false;
4803 out->is_compr_metadata_avail = false;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004804 out->gapless_mdata.encoder_delay = 0;
4805 out->gapless_mdata.encoder_padding = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004806 if (out->compr != NULL) {
4807 compress_close(out->compr);
4808 out->compr = NULL;
4809 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08004810 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004811 if (do_stop) {
4812 stop_output_stream(out);
4813 }
Lakshman Chaluvaraju06677b42019-06-24 10:04:52 +05304814 // if fm is active route on selected device in UI
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004815 audio_extn_fm_route_on_selected_device(adev, &out->device_list);
Eric Laurent150dbfe2013-02-27 14:31:02 -08004816 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004817 }
4818 pthread_mutex_unlock(&out->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07004819 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004820 return 0;
4821}
4822
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304823static int out_on_error(struct audio_stream *stream)
4824{
4825 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004826 int status = 0;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304827
4828 lock_output_stream(out);
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004829 // always send CMD_ERROR for offload streams, this
4830 // is needed e.g. when SSR happens within compress_open
4831 // since the stream is active, offload_callback_thread is also active.
4832 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
4833 stop_compressed_output_l(out);
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004834 }
4835 pthread_mutex_unlock(&out->lock);
4836
4837 status = out_standby(&out->stream.common);
4838
4839 lock_output_stream(out);
4840 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004841 send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304842 }
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05304843
4844 if (is_offload_usecase(out->usecase) && out->card_status == CARD_STATUS_OFFLINE) {
4845 ALOGD("Setting previous card status if offline");
4846 out->prev_card_status_offline = true;
4847 }
4848
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304849 pthread_mutex_unlock(&out->lock);
4850
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004851 return status;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304852}
4853
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304854/*
Weiyin Jiang280ea742020-09-08 20:28:22 +08004855 * standby implementation without locks, assumes that the callee already
4856 * has taken adev and out lock.
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304857 */
4858int out_standby_l(struct audio_stream *stream)
4859{
4860 struct stream_out *out = (struct stream_out *)stream;
4861 struct audio_device *adev = out->dev;
4862
4863 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4864 stream, out->usecase, use_case_table[out->usecase]);
4865
4866 if (!out->standby) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07004867 ATRACE_BEGIN("out_standby_l");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304868 if (adev->adm_deregister_stream)
4869 adev->adm_deregister_stream(adev->adm_data, out->handle);
4870
Weiyin Jiang280ea742020-09-08 20:28:22 +08004871 if (is_offload_usecase(out->usecase)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304872 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08004873 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304874
4875 out->standby = true;
4876 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
4877 voice_extn_compress_voip_close_output_stream(stream);
4878 out->started = 0;
4879 ALOGD("VOIP output entered standby");
Haynes Mathew George380745d2017-10-04 15:27:45 -07004880 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304881 return 0;
4882 } else if (!is_offload_usecase(out->usecase)) {
4883 if (out->pcm) {
4884 pcm_close(out->pcm);
4885 out->pcm = NULL;
4886 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004887 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
4888 if (adev->haptic_pcm) {
4889 pcm_close(adev->haptic_pcm);
4890 adev->haptic_pcm = NULL;
4891 }
4892
4893 if (adev->haptic_buffer != NULL) {
4894 free(adev->haptic_buffer);
4895 adev->haptic_buffer = NULL;
4896 adev->haptic_buffer_size = 0;
4897 }
4898 adev->haptic_pcm_device_id = 0;
4899 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304900 } else {
4901 ALOGD("copl(%p):standby", out);
4902 out->send_next_track_params = false;
4903 out->is_compr_metadata_avail = false;
4904 out->gapless_mdata.encoder_delay = 0;
4905 out->gapless_mdata.encoder_padding = 0;
4906 if (out->compr != NULL) {
4907 compress_close(out->compr);
4908 out->compr = NULL;
4909 }
4910 }
4911 stop_output_stream(out);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004912 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304913 }
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07004914 ALOGV("%s: exit", __func__);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304915 return 0;
4916}
4917
Aalique Grahame22e49102018-12-18 14:23:57 -08004918static int out_dump(const struct audio_stream *stream, int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004919{
Aalique Grahame22e49102018-12-18 14:23:57 -08004920 struct stream_out *out = (struct stream_out *)stream;
4921
4922 // We try to get the lock for consistency,
4923 // but it isn't necessary for these variables.
4924 // If we're not in standby, we may be blocked on a write.
4925 const bool locked = (pthread_mutex_trylock(&out->lock) == 0);
4926 dprintf(fd, " Standby: %s\n", out->standby ? "yes" : "no");
4927 dprintf(fd, " Frames written: %lld\n", (long long)out->written);
Dechen Chai22768452021-07-30 09:29:16 +05304928#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07004929 char buffer[256]; // for statistics formatting
4930 if (!is_offload_usecase(out->usecase)) {
4931 simple_stats_to_string(&out->fifo_underruns, buffer, sizeof(buffer));
4932 dprintf(fd, " Fifo frame underruns: %s\n", buffer);
4933 }
4934
Andy Hungc6bfd4a2019-07-01 18:26:00 -07004935 if (out->start_latency_ms.n > 0) {
4936 simple_stats_to_string(&out->start_latency_ms, buffer, sizeof(buffer));
4937 dprintf(fd, " Start latency ms: %s\n", buffer);
4938 }
Dechen Chai22768452021-07-30 09:29:16 +05304939#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08004940 if (locked) {
4941 pthread_mutex_unlock(&out->lock);
4942 }
4943
Dechen Chai22768452021-07-30 09:29:16 +05304944#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08004945 // dump error info
4946 (void)error_log_dump(
4947 out->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05304948#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004949 return 0;
4950}
4951
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004952static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
4953{
4954 int ret = 0;
4955 char value[32];
ApurupaPattapu2e084df2013-12-18 15:47:59 -08004956
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004957 if (!out || !parms) {
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08004958 ALOGE("%s: return invalid ",__func__);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004959 return -EINVAL;
4960 }
4961
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05304962 ret = audio_extn_parse_compress_metadata(out, parms);
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08004963
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004964 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
4965 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05304966 out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004967 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004968 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
4969 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05304970 out->gapless_mdata.encoder_padding = atoi(value);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004971 }
4972
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004973 ALOGV("%s new encoder delay %u and padding %u", __func__,
4974 out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
4975
4976 return 0;
4977}
4978
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004979static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
4980{
4981 return out == adev->primary_output || out == adev->voice_tx_output;
4982}
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004983
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304984// note: this call is safe only if the stream_cb is
4985// removed first in close_output_stream (as is done now).
4986static void out_snd_mon_cb(void * stream, struct str_parms * parms)
4987{
4988 if (!stream || !parms)
4989 return;
4990
4991 struct stream_out *out = (struct stream_out *)stream;
4992 struct audio_device *adev = out->dev;
4993
4994 card_status_t status;
4995 int card;
4996 if (parse_snd_card_status(parms, &card, &status) < 0)
4997 return;
4998
4999 pthread_mutex_lock(&adev->lock);
5000 bool valid_cb = (card == adev->snd_card);
5001 pthread_mutex_unlock(&adev->lock);
5002
5003 if (!valid_cb)
5004 return;
5005
5006 lock_output_stream(out);
5007 if (out->card_status != status)
5008 out->card_status = status;
5009 pthread_mutex_unlock(&out->lock);
5010
5011 ALOGI("out_snd_mon_cb for card %d usecase %s, status %s", card,
5012 use_case_table[out->usecase],
5013 status == CARD_STATUS_OFFLINE ? "offline" : "online");
5014
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305015 if (status == CARD_STATUS_OFFLINE) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305016 out_on_error(stream);
Aditya Bavanari59ebed42019-02-05 17:44:57 +05305017 if (voice_is_call_state_active(adev) &&
5018 out == adev->primary_output) {
5019 ALOGD("%s: SSR/PDR occurred, end all calls\n", __func__);
5020 pthread_mutex_lock(&adev->lock);
5021 voice_stop_call(adev);
5022 adev->mode = AUDIO_MODE_NORMAL;
5023 pthread_mutex_unlock(&adev->lock);
5024 }
5025 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305026 return;
5027}
5028
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005029int route_output_stream(struct stream_out *out,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005030 struct listnode *devices)
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005031{
5032 struct audio_device *adev = out->dev;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005033 int ret = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005034 struct listnode new_devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005035 bool bypass_a2dp = false;
5036 bool reconfig = false;
5037 unsigned long service_interval = 0;
5038
5039 ALOGD("%s: enter: usecase(%d: %s) devices %x",
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005040 __func__, out->usecase, use_case_table[out->usecase], get_device_types(devices));
5041
5042 list_init(&new_devices);
5043 assign_devices(&new_devices, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005044
5045 lock_output_stream(out);
5046 pthread_mutex_lock(&adev->lock);
5047
5048 /*
5049 * When HDMI cable is unplugged the music playback is paused and
5050 * the policy manager sends routing=0. But the audioflinger continues
5051 * to write data until standby time (3sec). As the HDMI core is
5052 * turned off, the write gets blocked.
5053 * Avoid this by routing audio to speaker until standby.
5054 */
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08005055 if (is_single_device_type_equal(&out->device_list,
5056 AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005057 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005058 !audio_extn_passthru_is_passthrough_stream(out) &&
5059 (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005060 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005061 }
5062 /*
5063 * When A2DP is disconnected the
5064 * music playback is paused and the policy manager sends routing=0
5065 * But the audioflinger continues to write data until standby time
5066 * (3sec). As BT is turned off, the write gets blocked.
5067 * Avoid this by routing audio to speaker until standby.
5068 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005069 if (is_a2dp_out_device_type(&out->device_list) &&
5070 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005071 !audio_extn_a2dp_source_is_ready() &&
5072 !adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005073 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005074 }
5075 /*
Weiyin Jiangabedea32020-12-09 12:49:19 +08005076 * When USB headset is disconnected the music playback paused
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005077 * and the policy manager send routing=0. But if the USB is connected
5078 * back before the standby time, AFE is not closed and opened
5079 * when USB is connected back. So routing to speker will guarantee
5080 * AFE reconfiguration and AFE will be opend once USB is connected again
5081 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005082 if (is_usb_out_device_type(&out->device_list) &&
5083 list_empty(&new_devices) &&
5084 !audio_extn_usb_connected(NULL)) {
Sujin Panicker84d953a2020-11-16 17:39:54 +05305085 if (adev->mode == AUDIO_MODE_IN_CALL || adev->mode == AUDIO_MODE_IN_COMMUNICATION)
5086 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_EARPIECE, "");
5087 else
5088 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005089 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005090 /* To avoid a2dp to sco overlapping / BT device improper state
5091 * check with BT lib about a2dp streaming support before routing
5092 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005093 if (is_a2dp_out_device_type(&new_devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005094 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005095 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
5096 compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005097 //combo usecase just by pass a2dp
5098 ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
5099 bypass_a2dp = true;
5100 } else {
5101 ALOGE("%s: A2DP profile is not ready,ignoring routing request", __func__);
5102 /* update device to a2dp and don't route as BT returned error
5103 * However it is still possible a2dp routing called because
5104 * of current active device disconnection (like wired headset)
5105 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005106 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005107 pthread_mutex_unlock(&adev->lock);
5108 pthread_mutex_unlock(&out->lock);
5109 goto error;
5110 }
5111 }
5112 }
5113
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005114 // Workaround: If routing to an non existing usb device, fail gracefully
5115 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005116 if (is_usb_out_device_type(&new_devices)) {
5117 struct str_parms *parms =
5118 str_parms_create_str(get_usb_device_address(&new_devices));
5119 if (!parms)
5120 goto error;
Weiyin Jiangabedea32020-12-09 12:49:19 +08005121 if (!audio_extn_usb_connected(NULL)) {
5122 ALOGW("%s: ignoring rerouting to non existing USB card", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005123 pthread_mutex_unlock(&adev->lock);
5124 pthread_mutex_unlock(&out->lock);
5125 str_parms_destroy(parms);
5126 ret = -ENOSYS;
5127 goto error;
5128 }
5129 str_parms_destroy(parms);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005130 }
5131
Weiyin Jiang80c8f9a2020-01-10 20:42:08 +08005132 // Workaround: If routing to an non existing hdmi device, fail gracefully
5133 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
5134 (platform_get_edid_info_v2(adev->platform,
5135 out->extconn.cs.controller,
5136 out->extconn.cs.stream) != 0)) {
5137 ALOGW("out_set_parameters() ignoring rerouting to non existing HDMI/DP");
5138 pthread_mutex_unlock(&adev->lock);
5139 pthread_mutex_unlock(&out->lock);
5140 ret = -ENOSYS;
5141 goto error;
5142 }
5143
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005144 /*
5145 * select_devices() call below switches all the usecases on the same
5146 * backend to the new device. Refer to check_usecases_codec_backend() in
5147 * the select_devices(). But how do we undo this?
5148 *
5149 * For example, music playback is active on headset (deep-buffer usecase)
5150 * and if we go to ringtones and select a ringtone, low-latency usecase
5151 * will be started on headset+speaker. As we can't enable headset+speaker
5152 * and headset devices at the same time, select_devices() switches the music
5153 * playback to headset+speaker while starting low-lateny usecase for ringtone.
5154 * So when the ringtone playback is completed, how do we undo the same?
5155 *
5156 * We are relying on the out_set_parameters() call on deep-buffer output,
5157 * once the ringtone playback is ended.
5158 * NOTE: We should not check if the current devices are same as new devices.
5159 * Because select_devices() must be called to switch back the music
5160 * playback to headset.
5161 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005162 if (!list_empty(&new_devices)) {
5163 bool same_dev = compare_devices(&out->device_list, &new_devices);
5164 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005165
5166 if (output_drives_call(adev, out)) {
5167 if (!voice_is_call_state_active(adev)) {
5168 if (adev->mode == AUDIO_MODE_IN_CALL) {
5169 adev->current_call_output = out;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005170 ret = voice_start_call(adev);
5171 }
5172 } else {
Kunlei Zhang253ad102020-10-14 16:21:28 +08005173 platform_is_volume_boost_supported_device(adev->platform, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005174 adev->current_call_output = out;
5175 voice_update_devices_for_all_voice_usecases(adev);
5176 }
5177 }
5178
Mingshu Pang971ff702020-09-09 15:28:22 +08005179 if (is_usb_out_device_type(&out->device_list)) {
5180 service_interval = audio_extn_usb_find_service_interval(false, true /*playback*/);
5181 audio_extn_usb_set_service_interval(true /*playback*/,
5182 service_interval,
5183 &reconfig);
5184 ALOGD("%s, svc_int(%ld),reconfig(%d)",__func__,service_interval, reconfig);
5185 }
5186
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005187 if (!out->standby) {
5188 if (!same_dev) {
5189 ALOGV("update routing change");
5190 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
5191 adev->perf_lock_opts,
5192 adev->perf_lock_opts_size);
5193 if (adev->adm_on_routing_change)
5194 adev->adm_on_routing_change(adev->adm_data,
5195 out->handle);
5196 }
5197 if (!bypass_a2dp) {
5198 select_devices(adev, out->usecase);
5199 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005200 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
5201 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005202 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005203 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005204 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005205 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005206 }
5207
5208 if (!same_dev) {
5209 // on device switch force swap, lower functions will make sure
5210 // to check if swap is allowed or not.
5211 platform_set_swap_channels(adev, true);
5212 audio_extn_perf_lock_release(&adev->perf_lock_handle);
5213 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005214 pthread_mutex_lock(&out->latch_lock);
5215 if (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready()) {
5216 if (out->a2dp_muted) {
5217 out->a2dp_muted = false;
5218 if (is_offload_usecase(out->usecase))
5219 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
5220 else if (out->usecase != USECASE_AUDIO_PLAYBACK_VOIP)
5221 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005222 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005223 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005224 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP && !out->a2dp_muted)
5225 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
5226 pthread_mutex_unlock(&out->latch_lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005227 }
5228 }
5229
5230 pthread_mutex_unlock(&adev->lock);
5231 pthread_mutex_unlock(&out->lock);
5232
5233 /*handles device and call state changes*/
5234 audio_extn_extspk_update(adev->extspk);
5235
Revathi Uddaraju4255a632021-12-02 05:11:13 -08005236 clear_devices(&new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005237error:
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005238 ALOGV("%s: exit: code(%d)", __func__, ret);
5239 return ret;
5240}
5241
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005242static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
5243{
5244 struct stream_out *out = (struct stream_out *)stream;
5245 struct audio_device *adev = out->dev;
5246 struct str_parms *parms;
5247 char value[32];
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005248 int ret = 0, err;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005249 int ext_controller = -1;
5250 int ext_stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005251
sangwoobc677242013-08-08 16:53:43 +09005252 ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07005253 __func__, out->usecase, use_case_table[out->usecase], kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005254 parms = str_parms_create_str(kvpairs);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305255 if (!parms)
5256 goto error;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005257
5258 err = platform_get_controller_stream_from_params(parms, &ext_controller,
5259 &ext_stream);
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08005260 if (err == 0) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005261 out->extconn.cs.controller = ext_controller;
5262 out->extconn.cs.stream = ext_stream;
5263 ALOGD("%s: usecase(%s) new controller/stream (%d/%d)", __func__,
5264 use_case_table[out->usecase], out->extconn.cs.controller,
5265 out->extconn.cs.stream);
5266 }
5267
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005268 if (out == adev->primary_output) {
5269 pthread_mutex_lock(&adev->lock);
5270 audio_extn_set_parameters(adev, parms);
5271 pthread_mutex_unlock(&adev->lock);
5272 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005273 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07005274 lock_output_stream(out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005275 parse_compress_metadata(out, parms);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08005276
5277 audio_extn_dts_create_state_notifier_node(out->usecase);
5278 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
5279 popcount(out->channel_mask),
5280 out->playback_started);
5281
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005282 pthread_mutex_unlock(&out->lock);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005283 }
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005284
Surendar Karkaf51b5842018-04-26 11:28:38 +05305285 err = str_parms_get_str(parms, AUDIO_PARAMETER_DUAL_MONO, value,
5286 sizeof(value));
5287 if (err >= 0) {
5288 if (!strncmp("true", value, sizeof("true")) || atoi(value))
5289 audio_extn_send_dual_mono_mixing_coefficients(out);
5290 }
5291
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305292 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
5293 if (err >= 0) {
5294 strlcpy(out->profile, value, sizeof(out->profile));
5295 ALOGV("updating stream profile with value '%s'", out->profile);
5296 lock_output_stream(out);
5297 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
5298 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005299 &out->device_list, out->flags,
5300 out->hal_op_format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305301 out->sample_rate, out->bit_width,
5302 out->channel_mask, out->profile,
5303 &out->app_type_cfg);
5304 pthread_mutex_unlock(&out->lock);
5305 }
5306
Alexy Joseph98988832017-01-13 14:56:59 -08005307 //suspend, resume handling block
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005308 //remove QOS only if vendor.audio.hal.dynamic.qos.config.supported is set to true
5309 // and vendor.audio.hal.output.suspend.supported is set to true
5310 if (out->hal_output_suspend_supported && out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08005311 //check suspend parameter only for low latency and if the property
5312 //is enabled
5313 if (str_parms_get_str(parms, "suspend_playback", value, sizeof(value)) >= 0) {
5314 ALOGI("%s: got suspend_playback %s", __func__, value);
5315 lock_output_stream(out);
5316 if (!strncmp(value, "false", 5)) {
5317 //suspend_playback=false is supposed to set QOS value back to 75%
5318 //the mixer control sent with value Enable will achieve that
5319 ret = audio_route_apply_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5320 } else if (!strncmp (value, "true", 4)) {
5321 //suspend_playback=true is supposed to remove QOS value
5322 //resetting the mixer control will set the default value
5323 //for the mixer control which is Disable and this removes the QOS vote
5324 ret = audio_route_reset_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5325 } else {
5326 ALOGE("%s: Wrong value sent for suspend_playback, expected true/false,"
5327 " got %s", __func__, value);
5328 ret = -1;
5329 }
5330
5331 if (ret != 0) {
5332 ALOGE("%s: %s mixer ctl failed with %d, ignore suspend/resume setparams",
5333 __func__, out->pm_qos_mixer_path, ret);
5334 }
5335
5336 pthread_mutex_unlock(&out->lock);
5337 }
5338 }
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005339
Alexy Joseph98988832017-01-13 14:56:59 -08005340 //end suspend, resume handling block
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005341 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305342error:
Eric Laurent994a6932013-07-17 11:51:42 -07005343 ALOGV("%s: exit: code(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005344 return ret;
5345}
5346
Paul McLeana50b7332018-12-17 08:24:21 -07005347static int in_set_microphone_direction(const struct audio_stream_in *stream,
5348 audio_microphone_direction_t dir) {
justinweng20fb6d82019-02-21 18:49:00 -07005349 struct stream_in *in = (struct stream_in *)stream;
5350
5351 ALOGVV("%s: standby %d source %d dir %d", __func__, in->standby, in->source, dir);
5352
5353 in->direction = dir;
5354
5355 if (in->standby)
5356 return 0;
5357
5358 return audio_extn_audiozoom_set_microphone_direction(in, dir);
Paul McLeana50b7332018-12-17 08:24:21 -07005359}
5360
5361static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom) {
justinweng20fb6d82019-02-21 18:49:00 -07005362 struct stream_in *in = (struct stream_in *)stream;
5363
5364 ALOGVV("%s: standby %d source %d zoom %f", __func__, in->standby, in->source, zoom);
5365
5366 if (zoom > 1.0 || zoom < -1.0)
5367 return -EINVAL;
5368
5369 in->zoom = zoom;
5370
5371 if (in->standby)
5372 return 0;
5373
5374 return audio_extn_audiozoom_set_microphone_field_dimension(in, zoom);
Paul McLeana50b7332018-12-17 08:24:21 -07005375}
5376
5377
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005378static bool stream_get_parameter_channels(struct str_parms *query,
5379 struct str_parms *reply,
5380 audio_channel_mask_t *supported_channel_masks) {
5381 int ret = -1;
5382 char value[512];
5383 bool first = true;
5384 size_t i, j;
5385
5386 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
5387 ret = 0;
5388 value[0] = '\0';
5389 i = 0;
5390 while (supported_channel_masks[i] != 0) {
5391 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5392 if (channels_name_to_enum_table[j].value == supported_channel_masks[i]) {
5393 if (!first)
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305394 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005395
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305396 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005397 first = false;
5398 break;
5399 }
5400 }
5401 i++;
5402 }
5403 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5404 }
5405 return ret == 0;
5406}
5407
5408static bool stream_get_parameter_formats(struct str_parms *query,
5409 struct str_parms *reply,
5410 audio_format_t *supported_formats) {
5411 int ret = -1;
5412 char value[256];
5413 size_t i, j;
5414 bool first = true;
5415
5416 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
5417 ret = 0;
5418 value[0] = '\0';
5419 i = 0;
5420 while (supported_formats[i] != 0) {
5421 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5422 if (formats_name_to_enum_table[j].value == supported_formats[i]) {
5423 if (!first) {
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305424 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005425 }
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305426 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005427 first = false;
5428 break;
5429 }
5430 }
5431 i++;
5432 }
5433 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
5434 }
5435 return ret == 0;
5436}
5437
5438static bool stream_get_parameter_rates(struct str_parms *query,
5439 struct str_parms *reply,
5440 uint32_t *supported_sample_rates) {
5441
5442 int i;
5443 char value[256];
5444 int ret = -1;
5445 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
5446 ret = 0;
5447 value[0] = '\0';
5448 i=0;
5449 int cursor = 0;
5450 while (supported_sample_rates[i]) {
5451 int avail = sizeof(value) - cursor;
5452 ret = snprintf(value + cursor, avail, "%s%d",
5453 cursor > 0 ? "|" : "",
5454 supported_sample_rates[i]);
5455 if (ret < 0 || ret >= avail) {
5456 // if cursor is at the last element of the array
5457 // overwrite with \0 is duplicate work as
5458 // snprintf already put a \0 in place.
5459 // else
5460 // we had space to write the '|' at value[cursor]
5461 // (which will be overwritten) or no space to fill
5462 // the first element (=> cursor == 0)
5463 value[cursor] = '\0';
5464 break;
5465 }
5466 cursor += ret;
5467 ++i;
5468 }
5469 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
5470 value);
5471 }
5472 return ret >= 0;
5473}
5474
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005475static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
5476{
5477 struct stream_out *out = (struct stream_out *)stream;
5478 struct str_parms *query = str_parms_create_str(keys);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005479 char *str = (char*) NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005480 char value[256];
5481 struct str_parms *reply = str_parms_create();
5482 size_t i, j;
5483 int ret;
5484 bool first = true;
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005485
5486 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005487 if (reply) {
5488 str_parms_destroy(reply);
5489 }
5490 if (query) {
5491 str_parms_destroy(query);
5492 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005493 ALOGE("out_get_parameters: failed to allocate mem for query or reply");
5494 return NULL;
5495 }
5496
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005497 ALOGV("%s: %s enter: keys - %s", __func__, use_case_table[out->usecase], keys);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005498 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
5499 if (ret >= 0) {
5500 value[0] = '\0';
5501 i = 0;
5502 while (out->supported_channel_masks[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005503 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5504 if (channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005505 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005506 strlcat(value, "|", sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005507 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005508 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005509 first = false;
5510 break;
5511 }
5512 }
5513 i++;
5514 }
5515 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5516 str = str_parms_to_str(reply);
5517 } else {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08005518 voice_extn_out_get_parameters(out, query, reply);
5519 str = str_parms_to_str(reply);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005520 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005521
Alexy Joseph62142aa2015-11-16 15:10:34 -08005522
5523 ret = str_parms_get_str(query, "is_direct_pcm_track", value, sizeof(value));
5524 if (ret >= 0) {
5525 value[0] = '\0';
Dhananjay Kumarac341582017-02-23 23:42:25 +05305526 if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
5527 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Alexy Joseph62142aa2015-11-16 15:10:34 -08005528 ALOGV("in direct_pcm");
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05305529 strlcat(value, "true", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005530 } else {
5531 ALOGV("not in direct_pcm");
Sharad Sangle3dd5a4a2015-12-10 18:39:17 +05305532 strlcat(value, "false", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005533 }
5534 str_parms_add_str(reply, "is_direct_pcm_track", value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005535 if (str)
5536 free(str);
Alexy Joseph62142aa2015-11-16 15:10:34 -08005537 str = str_parms_to_str(reply);
5538 }
5539
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005540 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
5541 if (ret >= 0) {
5542 value[0] = '\0';
5543 i = 0;
5544 first = true;
5545 while (out->supported_formats[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005546 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5547 if (formats_name_to_enum_table[j].value == out->supported_formats[i]) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005548 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005549 strlcat(value, "|", sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005550 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005551 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005552 first = false;
5553 break;
5554 }
5555 }
5556 i++;
5557 }
5558 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005559 if (str)
5560 free(str);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005561 str = str_parms_to_str(reply);
5562 }
Mingming Yin3a941d42016-02-17 18:08:05 -08005563
5564 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value, sizeof(value));
5565 if (ret >= 0) {
5566 value[0] = '\0';
5567 i = 0;
5568 first = true;
5569 while (out->supported_sample_rates[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005570 for (j = 0; j < ARRAY_SIZE(out_sample_rates_name_to_enum_table); j++) {
5571 if (out_sample_rates_name_to_enum_table[j].value == out->supported_sample_rates[i]) {
Mingming Yin3a941d42016-02-17 18:08:05 -08005572 if (!first) {
5573 strlcat(value, "|", sizeof(value));
5574 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005575 strlcat(value, out_sample_rates_name_to_enum_table[j].name, sizeof(value));
Mingming Yin3a941d42016-02-17 18:08:05 -08005576 first = false;
5577 break;
5578 }
5579 }
5580 i++;
5581 }
5582 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value);
5583 if (str)
5584 free(str);
5585 str = str_parms_to_str(reply);
5586 }
5587
Alexy Joseph98988832017-01-13 14:56:59 -08005588 if (str_parms_get_str(query, "supports_hw_suspend", value, sizeof(value)) >= 0) {
5589 //only low latency track supports suspend_resume
5590 str_parms_add_int(reply, "supports_hw_suspend",
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005591 (out->hal_output_suspend_supported));
Alexy Joseph98988832017-01-13 14:56:59 -08005592 if (str)
5593 free(str);
5594 str = str_parms_to_str(reply);
5595 }
5596
5597
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005598 str_parms_destroy(query);
5599 str_parms_destroy(reply);
Eric Laurent994a6932013-07-17 11:51:42 -07005600 ALOGV("%s: exit: returns - %s", __func__, str);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005601 return str;
5602}
5603
5604static uint32_t out_get_latency(const struct audio_stream_out *stream)
5605{
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005606 uint32_t period_ms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005607 struct stream_out *out = (struct stream_out *)stream;
Alexy Josephaa54c872014-12-03 02:46:47 -08005608 uint32_t latency = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005609
Alexy Josephaa54c872014-12-03 02:46:47 -08005610 if (is_offload_usecase(out->usecase)) {
Manish Dewangan07de2142017-02-27 19:27:20 +05305611 lock_output_stream(out);
5612 latency = audio_extn_utils_compress_get_dsp_latency(out);
5613 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07005614 } else if ((out->realtime) ||
5615 (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005616 // since the buffer won't be filled up faster than realtime,
5617 // return a smaller number
5618 if (out->config.rate)
5619 period_ms = (out->af_period_multiplier * out->config.period_size *
5620 1000) / (out->config.rate);
5621 else
5622 period_ms = 0;
George Gao9ba8a142020-07-23 14:30:03 -07005623 latency = period_ms + platform_render_latency(out) / 1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005624 } else {
5625 latency = (out->config.period_count * out->config.period_size * 1000) /
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005626 (out->config.rate);
pavanisra2d95d82022-02-09 18:55:58 +05305627 if (out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
5628 out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY)
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005629 latency += platform_render_latency(out)/1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005630 }
5631
Zhou Songd2537a02020-06-11 22:04:46 +08005632 if (!out->standby && is_a2dp_out_device_type(&out->device_list))
Aniket Kumar Latad5972fa2017-02-08 13:53:48 -08005633 latency += audio_extn_a2dp_get_encoder_latency();
5634
Anish Kumar50ebcbf2014-12-09 04:01:39 +05305635 ALOGV("%s: Latency %d", __func__, latency);
Alexy Josephaa54c872014-12-03 02:46:47 -08005636 return latency;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005637}
5638
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305639static float AmpToDb(float amplification)
5640{
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305641 float db = DSD_VOLUME_MIN_DB;
5642 if (amplification > 0) {
5643 db = 20 * log10(amplification);
5644 if(db < DSD_VOLUME_MIN_DB)
5645 return DSD_VOLUME_MIN_DB;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305646 }
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305647 return db;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305648}
5649
Arun Mirpuri5d170872019-03-26 13:21:31 -07005650static int out_set_mmap_volume(struct audio_stream_out *stream, float left,
5651 float right)
5652{
5653 struct stream_out *out = (struct stream_out *)stream;
5654 long volume = 0;
5655 char mixer_ctl_name[128] = "";
5656 struct audio_device *adev = out->dev;
5657 struct mixer_ctl *ctl = NULL;
5658 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5659 PCM_PLAYBACK);
5660
5661 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5662 "Playback %d Volume", pcm_device_id);
5663 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5664 if (!ctl) {
5665 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5666 __func__, mixer_ctl_name);
5667 return -EINVAL;
5668 }
5669 if (left != right)
5670 ALOGW("%s: Left and right channel volume mismatch:%f,%f",
5671 __func__, left, right);
5672 volume = (long)(left * (MMAP_PLAYBACK_VOLUME_MAX*1.0));
5673 if (mixer_ctl_set_value(ctl, 0, volume) < 0){
5674 ALOGE("%s:ctl for mixer cmd - %s, volume %ld returned error",
5675 __func__, mixer_ctl_name, volume);
5676 return -EINVAL;
5677 }
5678 return 0;
5679}
5680
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305681static int out_set_compr_volume(struct audio_stream_out *stream, float left,
5682 float right)
5683{
5684 struct stream_out *out = (struct stream_out *)stream;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305685 long volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305686 char mixer_ctl_name[128];
5687 struct audio_device *adev = out->dev;
5688 struct mixer_ctl *ctl;
5689 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5690 PCM_PLAYBACK);
5691
5692 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5693 "Compress Playback %d Volume", pcm_device_id);
5694 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5695 if (!ctl) {
5696 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5697 __func__, mixer_ctl_name);
5698 return -EINVAL;
5699 }
5700 ALOGE("%s:ctl for mixer cmd - %s, left %f, right %f",
5701 __func__, mixer_ctl_name, left, right);
5702 volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
5703 volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
5704 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5705
5706 return 0;
5707}
5708
Zhou Song2b8f28f2017-09-11 10:51:38 +08005709static int out_set_voip_volume(struct audio_stream_out *stream, float left,
5710 float right)
5711{
5712 struct stream_out *out = (struct stream_out *)stream;
5713 char mixer_ctl_name[] = "App Type Gain";
5714 struct audio_device *adev = out->dev;
5715 struct mixer_ctl *ctl;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305716 long set_values[4];
Zhou Song2b8f28f2017-09-11 10:51:38 +08005717
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07005718 if (!is_valid_volume(left, right)) {
5719 ALOGE("%s: Invalid stream volume for left=%f, right=%f",
5720 __func__, left, right);
5721 return -EINVAL;
5722 }
5723
Zhou Song2b8f28f2017-09-11 10:51:38 +08005724 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5725 if (!ctl) {
5726 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5727 __func__, mixer_ctl_name);
5728 return -EINVAL;
5729 }
5730
5731 set_values[0] = 0; //0: Rx Session 1:Tx Session
5732 set_values[1] = out->app_type_cfg.app_type;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305733 set_values[2] = (long)(left * VOIP_PLAYBACK_VOLUME_MAX);
5734 set_values[3] = (long)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Song2b8f28f2017-09-11 10:51:38 +08005735
5736 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
5737 return 0;
5738}
5739
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305740static int out_set_pcm_volume(struct audio_stream_out *stream, float left,
5741 float right)
5742{
5743 struct stream_out *out = (struct stream_out *)stream;
5744 /* Volume control for pcm playback */
5745 if (left != right) {
5746 return -EINVAL;
5747 } else {
5748 char mixer_ctl_name[128];
5749 struct audio_device *adev = out->dev;
5750 struct mixer_ctl *ctl;
5751 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5752 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Volume", pcm_device_id);
5753 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5754 if (!ctl) {
5755 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5756 return -EINVAL;
5757 }
5758
5759 int volume = (int) (left * PCM_PLAYBACK_VOLUME_MAX);
5760 int ret = mixer_ctl_set_value(ctl, 0, volume);
5761 if (ret < 0) {
5762 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
5763 return -EINVAL;
5764 }
5765
5766 ALOGV("%s : Pcm set volume value %d left %f", __func__, volume, left);
5767
5768 return 0;
5769 }
5770}
5771
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005772static int out_set_volume(struct audio_stream_out *stream, float left,
5773 float right)
5774{
Eric Laurenta9024de2013-04-04 09:19:12 -07005775 struct stream_out *out = (struct stream_out *)stream;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005776 int volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305777 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005778
Arun Mirpuri5d170872019-03-26 13:21:31 -07005779 ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
Eric Laurenta9024de2013-04-04 09:19:12 -07005780 if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
5781 /* only take left channel into account: the API is for stereo anyway */
5782 out->muted = (left == 0.0f);
5783 return 0;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005784 } else if (is_offload_usecase(out->usecase)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305785 if (audio_extn_passthru_is_passthrough_stream(out)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005786 /*
5787 * Set mute or umute on HDMI passthrough stream.
5788 * Only take left channel into account.
5789 * Mute is 0 and unmute 1
5790 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305791 audio_extn_passthru_set_volume(out, (left == 0.0f));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305792 } else if (out->format == AUDIO_FORMAT_DSD){
5793 char mixer_ctl_name[128] = "DSD Volume";
5794 struct audio_device *adev = out->dev;
5795 struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5796
5797 if (!ctl) {
5798 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5799 __func__, mixer_ctl_name);
5800 return -EINVAL;
5801 }
Manish Dewangan338c50a2017-09-12 15:22:03 +05305802 volume[0] = (long)(AmpToDb(left));
5803 volume[1] = (long)(AmpToDb(right));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305804 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5805 return 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005806 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS) &&
Derek Chendf05eea2019-08-01 13:57:49 -07005807 (out->car_audio_stream == CAR_AUDIO_STREAM_MEDIA)) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005808 ALOGD("%s: Overriding offload set volume for media bus stream", __func__);
5809 struct listnode *node = NULL;
5810 list_for_each(node, &adev->active_outputs_list) {
5811 streams_output_ctxt_t *out_ctxt = node_to_item(node,
5812 streams_output_ctxt_t,
5813 list);
5814 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
5815 out->volume_l = out_ctxt->output->volume_l;
5816 out->volume_r = out_ctxt->output->volume_r;
5817 }
5818 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08005819 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005820 if (!out->a2dp_muted) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005821 ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
5822 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08005823 pthread_mutex_unlock(&out->latch_lock);
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005824 return ret;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005825 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +08005826 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005827 ALOGV("%s: compress mute %d", __func__, out->a2dp_muted);
5828 if (!out->a2dp_muted)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305829 ret = out_set_compr_volume(stream, left, right);
5830 out->volume_l = left;
5831 out->volume_r = right;
Weiyin Jiang280ea742020-09-08 20:28:22 +08005832 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305833 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005834 }
Vikram Panduranga93f080e2017-06-07 18:16:14 -07005835 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
Aalique Grahame22e49102018-12-18 14:23:57 -08005836 out->app_type_cfg.gain[0] = (int)(left * VOIP_PLAYBACK_VOLUME_MAX);
5837 out->app_type_cfg.gain[1] = (int)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005838 pthread_mutex_lock(&out->latch_lock);
Aalique Grahame22e49102018-12-18 14:23:57 -08005839 if (!out->standby) {
5840 audio_extn_utils_send_app_type_gain(out->dev,
5841 out->app_type_cfg.app_type,
5842 &out->app_type_cfg.gain[0]);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005843 if (!out->a2dp_muted)
5844 ret = out_set_voip_volume(stream, left, right);
Aalique Grahame22e49102018-12-18 14:23:57 -08005845 }
Zhou Song2b8f28f2017-09-11 10:51:38 +08005846 out->volume_l = left;
5847 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08005848 pthread_mutex_unlock(&out->latch_lock);
Zhou Song2b8f28f2017-09-11 10:51:38 +08005849 return ret;
Arun Mirpuri5d170872019-03-26 13:21:31 -07005850 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
5851 ALOGV("%s: MMAP set volume called", __func__);
5852 if (!out->standby)
5853 ret = out_set_mmap_volume(stream, left, right);
5854 out->volume_l = left;
5855 out->volume_r = right;
5856 return ret;
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305857 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
Ramu Gottipati36547092018-12-28 11:32:09 +05305858 out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
5859 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
Zhou Songbaddf9f2020-11-20 13:57:39 +08005860 pthread_mutex_lock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305861 /* Volume control for pcm playback */
Zhou Songbaddf9f2020-11-20 13:57:39 +08005862 if (!out->standby && !out->a2dp_muted)
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305863 ret = out_set_pcm_volume(stream, left, right);
5864 else
5865 out->apply_volume = true;
5866
5867 out->volume_l = left;
5868 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08005869 pthread_mutex_unlock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305870 return ret;
Derek Chenf13dd492018-11-13 14:53:51 -08005871 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
5872 ALOGV("%s: bus device set volume called", __func__);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005873 pthread_mutex_lock(&out->latch_lock);
5874 if (!out->standby && !out->a2dp_muted)
Derek Chenf13dd492018-11-13 14:53:51 -08005875 ret = out_set_pcm_volume(stream, left, right);
5876 out->volume_l = left;
5877 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08005878 pthread_mutex_unlock(&out->latch_lock);
Derek Chenf13dd492018-11-13 14:53:51 -08005879 return ret;
Eric Laurenta9024de2013-04-04 09:19:12 -07005880 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005881
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005882 return -ENOSYS;
5883}
5884
Zhou Songc9672822017-08-16 16:01:39 +08005885static void update_frames_written(struct stream_out *out, size_t bytes)
5886{
5887 size_t bpf = 0;
5888
5889 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
5890 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
5891 bpf = 1;
5892 else if (!is_offload_usecase(out->usecase))
5893 bpf = audio_bytes_per_sample(out->format) *
5894 audio_channel_count_from_out_mask(out->channel_mask);
Zhou Song48453a02018-01-10 17:50:59 +08005895
5896 pthread_mutex_lock(&out->position_query_lock);
5897 if (bpf != 0) {
Zhou Songc9672822017-08-16 16:01:39 +08005898 out->written += bytes / bpf;
Zhou Song48453a02018-01-10 17:50:59 +08005899 clock_gettime(CLOCK_MONOTONIC, &out->writeAt);
5900 }
5901 pthread_mutex_unlock(&out->position_query_lock);
Zhou Songc9672822017-08-16 16:01:39 +08005902}
5903
Vignesh Kulothungana6927272019-02-20 15:17:07 -08005904int split_and_write_audio_haptic_data(struct stream_out *out,
5905 const void *buffer, size_t bytes_to_write)
5906{
5907 struct audio_device *adev = out->dev;
5908
5909 int ret = 0;
5910 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
5911 size_t bytes_per_sample = audio_bytes_per_sample(out->format);
5912 size_t frame_size = channel_count * bytes_per_sample;
5913 size_t frame_count = bytes_to_write / frame_size;
5914
5915 bool force_haptic_path =
5916 property_get_bool("vendor.audio.test_haptic", false);
5917
5918 // extract Haptics data from Audio buffer
5919 bool alloc_haptic_buffer = false;
5920 int haptic_channel_count = adev->haptics_config.channels;
5921 size_t haptic_frame_size = bytes_per_sample * haptic_channel_count;
5922 size_t audio_frame_size = frame_size - haptic_frame_size;
5923 size_t total_haptic_buffer_size = frame_count * haptic_frame_size;
5924
5925 if (adev->haptic_buffer == NULL) {
5926 alloc_haptic_buffer = true;
5927 } else if (adev->haptic_buffer_size < total_haptic_buffer_size) {
5928 free(adev->haptic_buffer);
5929 adev->haptic_buffer_size = 0;
5930 alloc_haptic_buffer = true;
5931 }
5932
5933 if (alloc_haptic_buffer) {
5934 adev->haptic_buffer = (uint8_t *)calloc(1, total_haptic_buffer_size);
Mingshu Pang1513f972019-05-24 12:43:51 +08005935 if(adev->haptic_buffer == NULL) {
5936 ALOGE("%s: failed to allocate mem for dev->haptic_buffer", __func__);
5937 return -ENOMEM;
5938 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08005939 adev->haptic_buffer_size = total_haptic_buffer_size;
5940 }
5941
5942 size_t src_index = 0, aud_index = 0, hap_index = 0;
5943 uint8_t *audio_buffer = (uint8_t *)buffer;
5944 uint8_t *haptic_buffer = adev->haptic_buffer;
5945
5946 // This is required for testing only. This works for stereo data only.
5947 // One channel is fed to audio stream and other to haptic stream for testing.
5948 if (force_haptic_path)
5949 audio_frame_size = haptic_frame_size = bytes_per_sample;
5950
5951 for (size_t i = 0; i < frame_count; i++) {
5952 memcpy(audio_buffer + aud_index, audio_buffer + src_index,
5953 audio_frame_size);
5954 aud_index += audio_frame_size;
5955 src_index += audio_frame_size;
5956
5957 if (adev->haptic_pcm)
5958 memcpy(haptic_buffer + hap_index, audio_buffer + src_index,
5959 haptic_frame_size);
5960 hap_index += haptic_frame_size;
5961 src_index += haptic_frame_size;
5962
5963 // This is required for testing only.
5964 // Discard haptic channel data.
5965 if (force_haptic_path)
5966 src_index += haptic_frame_size;
5967 }
5968
5969 // write to audio pipeline
5970 ret = pcm_write(out->pcm, (void *)audio_buffer,
5971 frame_count * audio_frame_size);
5972
5973 // write to haptics pipeline
5974 if (adev->haptic_pcm)
5975 ret = pcm_write(adev->haptic_pcm, (void *)adev->haptic_buffer,
5976 frame_count * haptic_frame_size);
5977
5978 return ret;
5979}
5980
Aalique Grahame22e49102018-12-18 14:23:57 -08005981#ifdef NO_AUDIO_OUT
5982static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
5983 const void *buffer __unused, size_t bytes)
5984{
5985 struct stream_out *out = (struct stream_out *)stream;
5986
5987 /* No Output device supported other than BT for playback.
5988 * Sleep for the amount of buffer duration
5989 */
5990 lock_output_stream(out);
5991 usleep(bytes * 1000000 / audio_stream_out_frame_size(
5992 (const struct audio_stream_out *)&out->stream) /
5993 out_get_sample_rate(&out->stream.common));
5994 pthread_mutex_unlock(&out->lock);
5995 return bytes;
5996}
5997#endif
5998
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005999static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
6000 size_t bytes)
6001{
6002 struct stream_out *out = (struct stream_out *)stream;
6003 struct audio_device *adev = out->dev;
Eric Laurent6e895242013-09-05 16:10:57 -07006004 ssize_t ret = 0;
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306005 int channels = 0;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006006 const size_t frame_size = audio_stream_out_frame_size(stream);
6007 const size_t frames = (frame_size != 0) ? bytes / frame_size : bytes;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306008 struct audio_usecase *usecase = NULL;
Meng Wang4c32fb42020-01-16 17:57:11 +08006009 uint32_t compr_passthr = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006010
Haynes Mathew George380745d2017-10-04 15:27:45 -07006011 ATRACE_BEGIN("out_write");
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006012 lock_output_stream(out);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306013
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306014 if (CARD_STATUS_OFFLINE == out->card_status) {
Zhou Song0b2e5dc2015-03-16 14:41:38 +08006015
Dhananjay Kumarac341582017-02-23 23:42:25 +05306016 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306017 /*during SSR for compress usecase we should return error to flinger*/
Naresh Tanniru80659832014-06-04 18:17:56 +05306018 ALOGD(" copl %s: sound card is not active/SSR state", __func__);
6019 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006020 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306021 return -ENETRESET;
Ashish Jainbbce4322016-02-16 13:25:27 +05306022 } else {
Ashish Jainbbce4322016-02-16 13:25:27 +05306023 ALOGD(" %s: sound card is not active/SSR state", __func__);
6024 ret= -EIO;
6025 goto exit;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306026 }
6027 }
6028
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306029 if (audio_extn_passthru_should_drop_data(out)) {
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306030 ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05306031 ret = -EIO;
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05306032 goto exit;
6033 }
6034
Haynes Mathew George16081042017-05-31 17:16:49 -07006035 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
6036 ret = -EINVAL;
6037 goto exit;
6038 }
6039
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006040 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306041 !out->is_iec61937_info_available) {
6042
6043 if (!audio_extn_passthru_is_passthrough_stream(out)) {
6044 out->is_iec61937_info_available = true;
6045 } else if (audio_extn_passthru_is_enabled()) {
6046 audio_extn_passthru_update_stream_configuration(adev, out, buffer, bytes);
Manish Dewangan37864bc2017-06-09 12:28:37 +05306047 out->is_iec61937_info_available = true;
Manish Dewangan671a4202017-08-18 17:30:46 +05306048
6049 if((out->format == AUDIO_FORMAT_DTS) ||
6050 (out->format == AUDIO_FORMAT_DTS_HD)) {
6051 ret = audio_extn_passthru_update_dts_stream_configuration(out,
6052 buffer, bytes);
6053 if (ret) {
6054 if (ret != -ENOSYS) {
6055 out->is_iec61937_info_available = false;
6056 ALOGD("iec61937 transmission info not yet updated retry");
6057 }
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306058 } else if (!out->standby) {
Manish Dewangan671a4202017-08-18 17:30:46 +05306059 /* if stream has started and after that there is
6060 * stream config change (iec transmission config)
6061 * then trigger select_device to update backend configuration.
6062 */
6063 out->stream_config_changed = true;
6064 pthread_mutex_lock(&adev->lock);
6065 select_devices(adev, out->usecase);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306066 if (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out)) {
Weiyin Jiang29c08a42019-04-30 17:11:10 +08006067 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306068 ret = -EINVAL;
6069 goto exit;
6070 }
Manish Dewangan671a4202017-08-18 17:30:46 +05306071 pthread_mutex_unlock(&adev->lock);
6072 out->stream_config_changed = false;
6073 out->is_iec61937_info_available = true;
6074 }
6075 }
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306076
Meng Wang4c32fb42020-01-16 17:57:11 +08006077#ifdef AUDIO_GKI_ENABLED
6078 /* out->compr_config.codec->reserved[0] is for compr_passthr */
6079 compr_passthr = out->compr_config.codec->reserved[0];
6080#else
6081 compr_passthr = out->compr_config.codec->compr_passthr;
6082#endif
6083
Garmond Leung317cbf12017-09-13 16:20:50 -07006084 if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
Meng Wang4c32fb42020-01-16 17:57:11 +08006085 (compr_passthr == PASSTHROUGH) &&
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306086 (out->is_iec61937_info_available == true)) {
6087 ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
6088 ret = -EINVAL;
6089 goto exit;
6090 }
Manish Dewangan37864bc2017-06-09 12:28:37 +05306091 }
6092 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306093
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006094 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02006095 (audio_extn_a2dp_source_is_suspended())) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006096 if (!(compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
6097 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
Zhou Songd01e7a22020-09-23 22:49:01 +08006098 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306099 ret = -EIO;
6100 goto exit;
6101 }
6102 }
6103 }
6104
Weiyin Jiangabedea32020-12-09 12:49:19 +08006105 if (is_usb_out_device_type(&out->device_list) &&
6106 !audio_extn_usb_connected(NULL)) {
6107 ret = -EIO;
6108 goto exit;
6109 }
6110
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006111 if (out->standby) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006112 out->standby = false;
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006113 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
6114
Eric Laurent150dbfe2013-02-27 14:31:02 -08006115 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006116 if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
6117 ret = voice_extn_compress_voip_start_output_stream(out);
6118 else
6119 ret = start_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006120 /* ToDo: If use case is compress offload should return 0 */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006121 if (ret != 0) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006122 out->standby = true;
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006123 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006124 goto exit;
6125 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306126 out->started = 1;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006127 out->last_fifo_valid = false; // we're coming out of standby, last_fifo isn't valid.
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006128
6129 if ((last_known_cal_step != -1) && (adev->platform != NULL)) {
vivek mehtab72d08d2016-04-29 03:16:47 -07006130 ALOGD("%s: retry previous failed cal level set", __func__);
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006131 platform_send_gain_dep_cal(adev->platform, last_known_cal_step);
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +05306132 last_known_cal_step = -1;
vivek mehtab72d08d2016-04-29 03:16:47 -07006133 }
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006134 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306135
6136 if ((out->is_iec61937_info_available == true) &&
6137 (audio_extn_passthru_is_passthrough_stream(out))&&
6138 (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out))) {
6139 ret = -EINVAL;
6140 goto exit;
6141 }
Surendar Karkaf51b5842018-04-26 11:28:38 +05306142 if (out->set_dual_mono)
6143 audio_extn_send_dual_mono_mixing_coefficients(out);
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006144
Dechen Chai22768452021-07-30 09:29:16 +05306145#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006146 // log startup time in ms.
6147 simple_stats_log(
6148 &out->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05306149#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006150 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006151
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006152 if (adev->is_channel_status_set == false &&
6153 compare_device_type(&out->device_list,
6154 AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Alexy Josephb1379942016-01-29 15:49:38 -08006155 audio_utils_set_hdmi_channel_status(out, (void *)buffer, bytes);
Ashish Jain81eb2a82015-05-13 10:52:34 +05306156 adev->is_channel_status_set = true;
6157 }
6158
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306159 if ((adev->use_old_pspd_mix_ctrl == true) &&
6160 (out->pspd_coeff_sent == false)) {
6161 /*
6162 * Need to resend pspd coefficients after stream started for
6163 * older kernel version as it does not save the coefficients
6164 * and also stream has to be started for coeff to apply.
6165 */
6166 usecase = get_usecase_from_list(adev, out->usecase);
6167 if (usecase != NULL) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05306168 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306169 out->pspd_coeff_sent = true;
6170 }
6171 }
6172
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006173 if (is_offload_usecase(out->usecase)) {
Alexy Joseph01e54e62015-03-03 19:01:03 -08006174 ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006175 if (out->send_new_metadata) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006176 ALOGD("copl(%p):send new gapless metadata", out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006177 compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
6178 out->send_new_metadata = 0;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306179 if (out->send_next_track_params && out->is_compr_metadata_avail) {
6180 ALOGD("copl(%p):send next track params in gapless", out);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08006181 compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306182 out->send_next_track_params = false;
6183 out->is_compr_metadata_avail = false;
6184 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006185 }
Dhananjay Kumarac341582017-02-23 23:42:25 +05306186 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306187 (out->convert_buffer) != NULL) {
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006188
Ashish Jain83a6cc22016-06-28 14:34:17 +05306189 if ((bytes > out->hal_fragment_size)) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05306190 ALOGW("Error written bytes %zu > %d (fragment_size)",
Ashish Jain83a6cc22016-06-28 14:34:17 +05306191 bytes, out->hal_fragment_size);
Ashish Jainf1eaa582016-05-23 20:54:24 +05306192 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006193 ATRACE_END();
Ashish Jainf1eaa582016-05-23 20:54:24 +05306194 return -EINVAL;
6195 } else {
Ashish Jain83a6cc22016-06-28 14:34:17 +05306196 audio_format_t dst_format = out->hal_op_format;
6197 audio_format_t src_format = out->hal_ip_format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05306198
Dieter Luecking5d57def2018-09-07 14:23:37 +02006199 /* prevent division-by-zero */
6200 uint32_t bitwidth_src = format_to_bitwidth_table[src_format];
6201 uint32_t bitwidth_dst = format_to_bitwidth_table[dst_format];
6202 if ((bitwidth_src == 0) || (bitwidth_dst == 0)) {
6203 ALOGE("%s: Error bitwidth == 0", __func__);
Ramu Gottipati02809682018-12-19 16:46:12 +05306204 pthread_mutex_unlock(&out->lock);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006205 ATRACE_END();
6206 return -EINVAL;
6207 }
6208
Ashish Jainf1eaa582016-05-23 20:54:24 +05306209 uint32_t frames = bytes / format_to_bitwidth_table[src_format];
6210 uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
6211
Ashish Jain83a6cc22016-06-28 14:34:17 +05306212 memcpy_by_audio_format(out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306213 dst_format,
6214 buffer,
6215 src_format,
6216 frames);
6217
Ashish Jain83a6cc22016-06-28 14:34:17 +05306218 ret = compress_write(out->compr, out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306219 bytes_to_write);
6220
6221 /*Convert written bytes in audio flinger format*/
6222 if (ret > 0)
6223 ret = ((ret * format_to_bitwidth_table[out->format]) /
6224 format_to_bitwidth_table[dst_format]);
6225 }
6226 } else
6227 ret = compress_write(out->compr, buffer, bytes);
6228
Zhou Songc9672822017-08-16 16:01:39 +08006229 if ((ret < 0 || ret == (ssize_t)bytes) && !out->non_blocking)
6230 update_frames_written(out, bytes);
6231
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306232 if (ret < 0)
6233 ret = -errno;
Weiyin Jiangcc60dbb2018-08-21 13:12:03 +08006234 ALOGVV("%s: writing buffer (%zu bytes) to compress device returned %d", __func__, bytes, (int)ret);
Ashish Jainb26edfb2016-08-25 00:10:11 +05306235 /*msg to cb thread only if non blocking write is enabled*/
6236 if (ret >= 0 && ret < (ssize_t)bytes && out->non_blocking) {
Sidipotu Ashok55820562014-02-10 16:16:38 +05306237 ALOGD("No space available in compress driver, post msg to cb thread");
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006238 send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
Naresh Tanniru80659832014-06-04 18:17:56 +05306239 } else if (-ENETRESET == ret) {
6240 ALOGE("copl %s: received sound card offline state on compress write", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306241 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru80659832014-06-04 18:17:56 +05306242 pthread_mutex_unlock(&out->lock);
Dhananjay Kumar1248dd82017-07-28 21:22:16 +05306243 out_on_error(&out->stream.common);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006244 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306245 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006246 }
Ashish Jain5106d362016-05-11 19:23:33 +05306247
Dhanalakshmi Siddania6b76c72016-09-09 18:10:31 +05306248 /* Call compr start only when non-zero bytes of data is there to be rendered */
6249 if (!out->playback_started && ret > 0) {
6250 int status = compress_start(out->compr);
6251 if (status < 0) {
6252 ret = status;
6253 ALOGE("%s: compr start failed with err %d", __func__, errno);
6254 goto exit;
6255 }
Alexy Joseph7de344d2015-03-30 10:40:03 -07006256 audio_extn_dts_eagle_fade(adev, true, out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006257 out->playback_started = 1;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006258 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006259 out->offload_state = OFFLOAD_STATE_PLAYING;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006260 pthread_mutex_unlock(&out->latch_lock);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006261
6262 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6263 popcount(out->channel_mask),
6264 out->playback_started);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006265 }
6266 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006267 ATRACE_END();
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006268 return ret;
6269 } else {
6270 if (out->pcm) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006271 size_t bytes_to_write = bytes;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006272 if (out->muted)
6273 memset((void *)buffer, 0, bytes);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006274 ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
6275 __func__, frames, frame_size, bytes_to_write);
6276
Aalique Grahame22e49102018-12-18 14:23:57 -08006277 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07006278 out->usecase == USECASE_INCALL_MUSIC_UPLINK2 ||
6279 (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP &&
6280 !audio_extn_utils_is_vendor_enhanced_fwk())) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006281 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6282 int16_t *src = (int16_t *)buffer;
6283 int16_t *dst = (int16_t *)buffer;
6284
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006285 LOG_ALWAYS_FATAL_IF(channel_count > 2 ||
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006286 out->format != AUDIO_FORMAT_PCM_16_BIT,
Aalique Grahame22e49102018-12-18 14:23:57 -08006287 "out_write called for %s use case with wrong properties",
6288 use_case_table[out->usecase]);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006289
6290 /*
6291 * FIXME: this can be removed once audio flinger mixer supports
6292 * mono output
6293 */
6294
6295 /*
6296 * Code below goes over each frame in the buffer and adds both
6297 * L and R samples and then divides by 2 to convert to mono
6298 */
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006299 if (channel_count == 2) {
6300 for (size_t i = 0; i < frames ; i++, dst++, src += 2) {
6301 *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
6302 }
6303 bytes_to_write /= 2;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006304 }
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006305 }
Andy Hunga1f48fa2019-07-01 18:14:53 -07006306
6307 // Note: since out_get_presentation_position() is called alternating with out_write()
6308 // by AudioFlinger, we can check underruns using the prior timestamp read.
6309 // (Alternately we could check if the buffer is empty using pcm_get_htimestamp().
6310 if (out->last_fifo_valid) {
6311 // compute drain to see if there is an underrun.
6312 const int64_t current_ns = systemTime(SYSTEM_TIME_MONOTONIC); // sys call
Dhananjay Kumara4429632020-07-11 02:53:37 +05306313 int64_t time_diff_ns = current_ns - out->last_fifo_time_ns;
6314 int64_t frames_by_time =
6315 ((time_diff_ns > 0) && (time_diff_ns < (INT64_MAX / out->config.rate))) ?
6316 (time_diff_ns * out->config.rate / NANOS_PER_SECOND) : 0;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006317 const int64_t underrun = frames_by_time - out->last_fifo_frames_remaining;
6318
6319 if (underrun > 0) {
Dechen Chai22768452021-07-30 09:29:16 +05306320#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07006321 simple_stats_log(&out->fifo_underruns, underrun);
Dechen Chai22768452021-07-30 09:29:16 +05306322#endif
Andy Hunga1f48fa2019-07-01 18:14:53 -07006323
6324 ALOGW("%s: underrun(%lld) "
6325 "frames_by_time(%lld) > out->last_fifo_frames_remaining(%lld)",
6326 __func__,
6327 (long long)out->fifo_underruns.n,
6328 (long long)frames_by_time,
6329 (long long)out->last_fifo_frames_remaining);
6330 }
6331 out->last_fifo_valid = false; // we're writing below, mark fifo info as stale.
6332 }
6333
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05306334 ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006335
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006336 long ns = 0;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006337
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006338 if (out->config.rate)
6339 ns = pcm_bytes_to_frames(out->pcm, bytes)*1000000000LL/
6340 out->config.rate;
6341
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006342 request_out_focus(out, ns);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006343 bool use_mmap = is_mmap_usecase(out->usecase) || out->realtime;
6344
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006345 if (use_mmap)
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006346 ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes_to_write);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006347 else if (out->hal_op_format != out->hal_ip_format &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306348 out->convert_buffer != NULL) {
6349
6350 memcpy_by_audio_format(out->convert_buffer,
6351 out->hal_op_format,
6352 buffer,
6353 out->hal_ip_format,
6354 out->config.period_size * out->config.channels);
6355
6356 ret = pcm_write(out->pcm, out->convert_buffer,
6357 (out->config.period_size *
6358 out->config.channels *
6359 format_to_bitwidth_table[out->hal_op_format]));
6360 } else {
Aditya Bavanarid4db8ee2017-05-29 21:08:03 +05306361 /*
6362 * To avoid underrun in DSP when the application is not pumping
6363 * data at required rate, check for the no. of bytes and ignore
6364 * pcm_write if it is less than actual buffer size.
6365 * It is a work around to a change in compress VOIP driver.
6366 */
6367 if ((out->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) &&
6368 bytes < (out->config.period_size * out->config.channels *
6369 audio_bytes_per_sample(out->format))) {
6370 size_t voip_buf_size =
6371 out->config.period_size * out->config.channels *
6372 audio_bytes_per_sample(out->format);
6373 ALOGE("%s:VOIP underrun: bytes received %zu, required:%zu\n",
6374 __func__, bytes, voip_buf_size);
6375 usleep(((uint64_t)voip_buf_size - bytes) *
6376 1000000 / audio_stream_out_frame_size(stream) /
6377 out_get_sample_rate(&out->stream.common));
6378 ret = 0;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006379 } else {
6380 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
6381 ret = split_and_write_audio_haptic_data(out, buffer, bytes);
6382 else
6383 ret = pcm_write(out->pcm, (void *)buffer, bytes_to_write);
6384 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05306385 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006386
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006387 release_out_focus(out);
6388
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306389 if (ret < 0)
6390 ret = -errno;
Zhou Songc9672822017-08-16 16:01:39 +08006391 else if (ret > 0)
Ashish Jain83a6cc22016-06-28 14:34:17 +05306392 ret = -EINVAL;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006393 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006394 }
6395
6396exit:
Zhou Songc9672822017-08-16 16:01:39 +08006397 update_frames_written(out, bytes);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306398 if (-ENETRESET == ret) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306399 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306400 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006401 pthread_mutex_unlock(&out->lock);
6402
6403 if (ret != 0) {
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07006404 if (out->pcm)
Alexy Josephb1379942016-01-29 15:49:38 -08006405 ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306406 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306407 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306408 voice_extn_compress_voip_close_output_stream(&out->stream.common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306409 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306410 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306411 out->standby = true;
6412 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306413 out_on_error(&out->stream.common);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006414 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
6415 /* prevent division-by-zero */
6416 uint32_t stream_size = audio_stream_out_frame_size(stream);
6417 uint32_t srate = out_get_sample_rate(&out->stream.common);
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006418
Dieter Luecking5d57def2018-09-07 14:23:37 +02006419 if ((stream_size == 0) || (srate == 0)) {
6420 ALOGE("%s: stream_size= %d, srate = %d", __func__, stream_size, srate);
6421 ATRACE_END();
6422 return -EINVAL;
6423 }
6424 usleep((uint64_t)bytes * 1000000 / stream_size / srate);
6425 }
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006426 if (audio_extn_passthru_is_passthrough_stream(out)) {
Rajshekar Eashwarappa88834522018-04-02 17:20:15 +05306427 //ALOGE("%s: write error, ret = %zd", __func__, ret);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006428 ATRACE_END();
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006429 return ret;
6430 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006431 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07006432 ATRACE_END();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006433 return bytes;
6434}
6435
6436static int out_get_render_position(const struct audio_stream_out *stream,
6437 uint32_t *dsp_frames)
6438{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006439 struct stream_out *out = (struct stream_out *)stream;
Zhou Song32a556e2015-05-05 10:46:56 +08006440
6441 if (dsp_frames == NULL)
6442 return -EINVAL;
6443
6444 *dsp_frames = 0;
6445 if (is_offload_usecase(out->usecase)) {
Mingming Yin9e348b52014-11-19 16:18:55 -08006446 ssize_t ret = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05306447
6448 /* Below piece of code is not guarded against any lock beacuse audioFliner serializes
6449 * this operation and adev_close_output_stream(where out gets reset).
6450 */
Dhananjay Kumarac341582017-02-23 23:42:25 +05306451 if (!out->non_blocking && !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006452 *dsp_frames = get_actual_pcm_frames_rendered(out, NULL);
Ashish Jain5106d362016-05-11 19:23:33 +05306453 ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate);
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006454 adjust_frames_for_device_delay(out, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05306455 return 0;
6456 }
6457
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006458 lock_output_stream(out);
Ashish Jain5106d362016-05-11 19:23:33 +05306459 if (out->compr != NULL && out->non_blocking) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306460 ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006461 &out->sample_rate);
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306462 if (ret < 0)
6463 ret = -errno;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006464 ALOGVV("%s rendered frames %d sample_rate %d",
Ashish Jain5106d362016-05-11 19:23:33 +05306465 __func__, *dsp_frames, out->sample_rate);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006466 }
Naresh Tanniru80659832014-06-04 18:17:56 +05306467 if (-ENETRESET == ret) {
6468 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306469 out->card_status = CARD_STATUS_OFFLINE;
6470 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306471 } else if(ret < 0) {
6472 ALOGE(" ERROR: Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306473 ret = -EINVAL;
6474 } else if (out->card_status == CARD_STATUS_OFFLINE) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05306475 /*
6476 * Handle corner case where compress session is closed during SSR
6477 * and timestamp is queried
6478 */
6479 ALOGE(" ERROR: sound card not active, return error");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306480 ret = -EINVAL;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306481 } else if (out->prev_card_status_offline) {
6482 ALOGE("ERROR: previously sound card was offline,return error");
6483 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306484 } else {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306485 ret = 0;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006486 adjust_frames_for_device_delay(out, dsp_frames);
Naresh Tanniru80659832014-06-04 18:17:56 +05306487 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306488 pthread_mutex_unlock(&out->lock);
6489 return ret;
Zhou Song32a556e2015-05-05 10:46:56 +08006490 } else if (audio_is_linear_pcm(out->format)) {
6491 *dsp_frames = out->written;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006492 adjust_frames_for_device_delay(out, dsp_frames);
Zhou Song32a556e2015-05-05 10:46:56 +08006493 return 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006494 } else
6495 return -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006496}
6497
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006498static int out_add_audio_effect(const struct audio_stream *stream __unused,
6499 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006500{
6501 return 0;
6502}
6503
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006504static int out_remove_audio_effect(const struct audio_stream *stream __unused,
6505 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006506{
6507 return 0;
6508}
6509
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006510static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
6511 int64_t *timestamp __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006512{
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05306513 return -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006514}
6515
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006516static int out_get_presentation_position(const struct audio_stream_out *stream,
6517 uint64_t *frames, struct timespec *timestamp)
6518{
6519 struct stream_out *out = (struct stream_out *)stream;
pavance65c2fe2017-10-18 17:52:01 +05306520 int ret = -ENODATA;
Eric Laurent949a0892013-09-20 09:20:13 -07006521 unsigned long dsp_frames;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006522
Ashish Jain5106d362016-05-11 19:23:33 +05306523 /* below piece of code is not guarded against any lock because audioFliner serializes
6524 * this operation and adev_close_output_stream( where out gets reset).
6525 */
6526 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
Dhananjay Kumarac341582017-02-23 23:42:25 +05306527 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006528 *frames = get_actual_pcm_frames_rendered(out, timestamp);
Ashish Jain5106d362016-05-11 19:23:33 +05306529 ALOGVV("frames %lld playedat %lld",(long long int)*frames,
6530 timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000);
6531 return 0;
6532 }
6533
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006534 lock_output_stream(out);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006535
Ashish Jain5106d362016-05-11 19:23:33 +05306536 if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) {
6537 ret = compress_get_tstamp(out->compr, &dsp_frames,
6538 &out->sample_rate);
yidongh0515e042017-07-06 15:00:34 +08006539 // Adjustment accounts for A2dp encoder latency with offload usecases
6540 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006541 if (is_a2dp_out_device_type(&out->device_list)) {
yidongh0515e042017-07-06 15:00:34 +08006542 unsigned long offset =
6543 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
6544 dsp_frames = (dsp_frames > offset) ? (dsp_frames - offset) : 0;
6545 }
Ashish Jain5106d362016-05-11 19:23:33 +05306546 ALOGVV("%s rendered frames %ld sample_rate %d",
6547 __func__, dsp_frames, out->sample_rate);
6548 *frames = dsp_frames;
6549 if (ret < 0)
6550 ret = -errno;
6551 if (-ENETRESET == ret) {
6552 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306553 out->card_status = CARD_STATUS_OFFLINE;
Ashish Jain5106d362016-05-11 19:23:33 +05306554 ret = -EINVAL;
6555 } else
6556 ret = 0;
6557 /* this is the best we can do */
6558 clock_gettime(CLOCK_MONOTONIC, timestamp);
Eric Laurent949a0892013-09-20 09:20:13 -07006559 } else {
6560 if (out->pcm) {
Weiyin Jiangd4633762018-03-16 12:05:03 +08006561 unsigned int avail;
6562 if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
George Gao62ebc722019-07-29 16:29:44 -07006563 uint64_t signed_frames = 0;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006564 uint64_t frames_temp = 0;
George Gao62ebc722019-07-29 16:29:44 -07006565
Andy Hunga1f48fa2019-07-01 18:14:53 -07006566 if (out->kernel_buffer_size > avail) {
6567 frames_temp = out->last_fifo_frames_remaining = out->kernel_buffer_size - avail;
6568 } else {
6569 ALOGW("%s: avail:%u > kernel_buffer_size:%zu clamping!",
6570 __func__, avail, out->kernel_buffer_size);
6571 avail = out->kernel_buffer_size;
6572 frames_temp = out->last_fifo_frames_remaining = 0;
6573 }
6574 out->last_fifo_valid = true;
6575 out->last_fifo_time_ns = audio_utils_ns_from_timespec(timestamp);
6576
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006577 if (out->written >= frames_temp)
6578 signed_frames = out->written - frames_temp;
George Gao62ebc722019-07-29 16:29:44 -07006579
Andy Hunga1f48fa2019-07-01 18:14:53 -07006580 ALOGVV("%s: frames:%lld avail:%u kernel_buffer_size:%zu",
6581 __func__, (long long)signed_frames, avail, out->kernel_buffer_size);
6582
Weiyin Jiangd4633762018-03-16 12:05:03 +08006583 // This adjustment accounts for buffering after app processor.
6584 // It is based on estimated DSP latency per use case, rather than exact.
George Gao9ba8a142020-07-23 14:30:03 -07006585 frames_temp = platform_render_latency(out) *
Robert Lee58215542019-07-15 20:55:12 +08006586 out->sample_rate / 1000000LL;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006587 if (signed_frames >= frames_temp)
6588 signed_frames -= frames_temp;
Aniket Kumar Lataff613152017-07-18 18:19:21 -07006589
Weiyin Jiangd4633762018-03-16 12:05:03 +08006590 // Adjustment accounts for A2dp encoder latency with non offload usecases
6591 // Note: Encoder latency is returned in ms, while platform_render_latency in us.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006592 if (is_a2dp_out_device_type(&out->device_list)) {
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006593 frames_temp = audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000;
6594 if (signed_frames >= frames_temp)
6595 signed_frames -= frames_temp;
Weiyin Jiangd4633762018-03-16 12:05:03 +08006596 }
6597
6598 // It would be unusual for this value to be negative, but check just in case ...
George Gao62ebc722019-07-29 16:29:44 -07006599 *frames = signed_frames;
6600 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006601 }
Eric Laurenta7a33042019-07-10 16:20:22 -07006602 } else if (out->card_status == CARD_STATUS_OFFLINE ||
6603 // audioflinger still needs position updates when A2DP is suspended
Jasmine Cha5c2517f2019-09-09 11:07:28 +08006604 (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306605 *frames = out->written;
6606 clock_gettime(CLOCK_MONOTONIC, timestamp);
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306607 if (is_offload_usecase(out->usecase))
6608 ret = -EINVAL;
6609 else
6610 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006611 }
6612 }
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006613 pthread_mutex_unlock(&out->lock);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006614 return ret;
6615}
6616
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006617static int out_set_callback(struct audio_stream_out *stream,
6618 stream_callback_t callback, void *cookie)
6619{
6620 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006621 int ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006622
6623 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006624 lock_output_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006625 out->client_callback = callback;
6626 out->client_cookie = cookie;
6627 if (out->adsp_hdlr_stream_handle) {
6628 ret = audio_extn_adsp_hdlr_stream_set_callback(
6629 out->adsp_hdlr_stream_handle,
6630 callback,
6631 cookie);
6632 if (ret)
6633 ALOGW("%s:adsp hdlr callback registration failed %d",
6634 __func__, ret);
6635 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006636 pthread_mutex_unlock(&out->lock);
6637 return 0;
6638}
6639
6640static int out_pause(struct audio_stream_out* stream)
6641{
6642 struct stream_out *out = (struct stream_out *)stream;
6643 int status = -ENOSYS;
6644 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006645 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006646 ALOGD("copl(%p):pause compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306647 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006648 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006649 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006650 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306651 if (out->card_status != CARD_STATUS_OFFLINE)
Naresh Tanniru80659832014-06-04 18:17:56 +05306652 status = compress_pause(out->compr);
6653
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006654 out->offload_state = OFFLOAD_STATE_PAUSED;
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006655
Mingming Yin21854652016-04-13 11:54:02 -07006656 if (audio_extn_passthru_is_active()) {
6657 ALOGV("offload use case, pause passthru");
6658 audio_extn_passthru_on_pause(out);
6659 }
6660
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306661 audio_extn_dts_eagle_fade(adev, false, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006662 audio_extn_dts_notify_playback_state(out->usecase, 0,
6663 out->sample_rate, popcount(out->channel_mask),
6664 0);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006665 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006666 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006667 pthread_mutex_unlock(&out->lock);
6668 }
6669 return status;
6670}
6671
6672static int out_resume(struct audio_stream_out* stream)
6673{
6674 struct stream_out *out = (struct stream_out *)stream;
6675 int status = -ENOSYS;
6676 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006677 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006678 ALOGD("copl(%p):resume compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306679 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006680 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006681 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006682 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306683 if (out->card_status != CARD_STATUS_OFFLINE) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306684 status = compress_resume(out->compr);
Mingming Yin21854652016-04-13 11:54:02 -07006685 }
6686 if (!status) {
6687 out->offload_state = OFFLOAD_STATE_PLAYING;
6688 }
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306689 audio_extn_dts_eagle_fade(adev, true, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006690 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6691 popcount(out->channel_mask), 1);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006692 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006693 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006694 pthread_mutex_unlock(&out->lock);
6695 }
6696 return status;
6697}
6698
6699static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
6700{
6701 struct stream_out *out = (struct stream_out *)stream;
6702 int status = -ENOSYS;
6703 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006704 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006705 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006706 if (type == AUDIO_DRAIN_EARLY_NOTIFY)
6707 status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
6708 else
6709 status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
6710 pthread_mutex_unlock(&out->lock);
6711 }
6712 return status;
6713}
6714
6715static int out_flush(struct audio_stream_out* stream)
6716{
6717 struct stream_out *out = (struct stream_out *)stream;
6718 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006719 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006720 ALOGD("copl(%p):calling compress flush", out);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006721 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006722 pthread_mutex_lock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006723 if (out->offload_state == OFFLOAD_STATE_PAUSED) {
Gautam Manam14c198b2020-12-24 14:08:04 +05306724 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006725 stop_compressed_output_l(out);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006726 } else {
6727 ALOGW("%s called in invalid state %d", __func__, out->offload_state);
Gautam Manam14c198b2020-12-24 14:08:04 +05306728 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006729 }
Weiyin Jiang547e4152017-09-14 17:24:18 +08006730 out->written = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006731 pthread_mutex_unlock(&out->lock);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006732 ALOGD("copl(%p):out of compress flush", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006733 return 0;
6734 }
6735 return -ENOSYS;
6736}
6737
Haynes Mathew George16081042017-05-31 17:16:49 -07006738static int out_stop(const struct audio_stream_out* stream)
6739{
6740 struct stream_out *out = (struct stream_out *)stream;
6741 struct audio_device *adev = out->dev;
6742 int ret = -ENOSYS;
6743
6744 ALOGV("%s", __func__);
6745 pthread_mutex_lock(&adev->lock);
6746 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6747 out->playback_started && out->pcm != NULL) {
6748 pcm_stop(out->pcm);
6749 ret = stop_output_stream(out);
6750 out->playback_started = false;
6751 }
6752 pthread_mutex_unlock(&adev->lock);
6753 return ret;
6754}
6755
6756static int out_start(const struct audio_stream_out* stream)
6757{
6758 struct stream_out *out = (struct stream_out *)stream;
6759 struct audio_device *adev = out->dev;
6760 int ret = -ENOSYS;
6761
6762 ALOGV("%s", __func__);
6763 pthread_mutex_lock(&adev->lock);
6764 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6765 !out->playback_started && out->pcm != NULL) {
6766 ret = start_output_stream(out);
6767 if (ret == 0) {
6768 out->playback_started = true;
6769 }
6770 }
6771 pthread_mutex_unlock(&adev->lock);
6772 return ret;
6773}
6774
6775/*
6776 * Modify config->period_count based on min_size_frames
6777 */
6778static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
6779{
6780 int periodCountRequested = (min_size_frames + config->period_size - 1)
6781 / config->period_size;
6782 int periodCount = MMAP_PERIOD_COUNT_MIN;
6783
6784 ALOGV("%s original config.period_size = %d config.period_count = %d",
6785 __func__, config->period_size, config->period_count);
6786
6787 while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
6788 periodCount *= 2;
6789 }
6790 config->period_count = periodCount;
6791
6792 ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
6793}
6794
Phil Burkfe17efd2019-03-25 10:23:35 -07006795// Read offset for the positional timestamp from a persistent vendor property.
6796// This is to workaround apparent inaccuracies in the timing information that
6797// is used by the AAudio timing model. The inaccuracies can cause glitches.
6798static int64_t get_mmap_out_time_offset() {
6799 const int32_t kDefaultOffsetMicros = 0;
6800 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08006801 "persist.vendor.audio.out_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burkfe17efd2019-03-25 10:23:35 -07006802 ALOGI("mmap_time_offset_micros = %d for output", mmap_time_offset_micros);
6803 return mmap_time_offset_micros * (int64_t)1000;
6804}
6805
Haynes Mathew George16081042017-05-31 17:16:49 -07006806static int out_create_mmap_buffer(const struct audio_stream_out *stream,
6807 int32_t min_size_frames,
6808 struct audio_mmap_buffer_info *info)
6809{
6810 struct stream_out *out = (struct stream_out *)stream;
6811 struct audio_device *adev = out->dev;
6812 int ret = 0;
Aalique Grahame1f123102017-10-12 10:38:32 -07006813 unsigned int offset1 = 0;
6814 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07006815 const char *step = "";
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006816 uint32_t mmap_size;
Arun Mirpuri5d170872019-03-26 13:21:31 -07006817 uint32_t buffer_size;
Haynes Mathew George16081042017-05-31 17:16:49 -07006818
Arun Mirpuri5d170872019-03-26 13:21:31 -07006819 ALOGD("%s", __func__);
Sharad Sanglec6f32552018-05-04 16:15:38 +05306820 lock_output_stream(out);
Haynes Mathew George16081042017-05-31 17:16:49 -07006821 pthread_mutex_lock(&adev->lock);
6822
Sharad Sanglec6f32552018-05-04 16:15:38 +05306823 if (CARD_STATUS_OFFLINE == out->card_status ||
6824 CARD_STATUS_OFFLINE == adev->card_status) {
6825 ALOGW("out->card_status or adev->card_status offline, try again");
6826 ret = -EIO;
6827 goto exit;
6828 }
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306829 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07006830 ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
6831 ret = -EINVAL;
6832 goto exit;
6833 }
6834 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
6835 ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
6836 ret = -ENOSYS;
6837 goto exit;
6838 }
6839 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
6840 if (out->pcm_device_id < 0) {
6841 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
6842 __func__, out->pcm_device_id, out->usecase);
6843 ret = -EINVAL;
6844 goto exit;
6845 }
6846
6847 adjust_mmap_period_count(&out->config, min_size_frames);
6848
Arun Mirpuri5d170872019-03-26 13:21:31 -07006849 ALOGD("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07006850 __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
6851 out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
6852 (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05306853 if (errno == ENETRESET && !pcm_is_ready(out->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05306854 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
6855 out->card_status = CARD_STATUS_OFFLINE;
6856 adev->card_status = CARD_STATUS_OFFLINE;
6857 ret = -EIO;
6858 goto exit;
6859 }
6860
Haynes Mathew George16081042017-05-31 17:16:49 -07006861 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
6862 step = "open";
6863 ret = -ENODEV;
6864 goto exit;
6865 }
6866 ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
6867 if (ret < 0) {
6868 step = "begin";
6869 goto exit;
6870 }
juyuchen626833d2019-06-04 16:48:02 +08006871
6872 info->flags = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07006873 info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
Arun Mirpuri5d170872019-03-26 13:21:31 -07006874 buffer_size = pcm_frames_to_bytes(out->pcm, info->buffer_size_frames);
Haynes Mathew George16081042017-05-31 17:16:49 -07006875 info->burst_size_frames = out->config.period_size;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006876 ret = platform_get_mmap_data_fd(adev->platform,
6877 out->pcm_device_id, 0 /*playback*/,
6878 &info->shared_memory_fd,
6879 &mmap_size);
6880 if (ret < 0) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07006881 // Fall back to non exclusive mode
6882 info->shared_memory_fd = pcm_get_poll_fd(out->pcm);
6883 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07006884 out->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
6885 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, out->mmap_shared_memory_fd);
6886
Arun Mirpuri5d170872019-03-26 13:21:31 -07006887 if (mmap_size < buffer_size) {
6888 step = "mmap";
6889 goto exit;
6890 }
juyuchen626833d2019-06-04 16:48:02 +08006891 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006892 }
Haynes Mathew George16081042017-05-31 17:16:49 -07006893 memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006894 info->buffer_size_frames));
Haynes Mathew George16081042017-05-31 17:16:49 -07006895
6896 ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
6897 if (ret < 0) {
6898 step = "commit";
6899 goto exit;
6900 }
6901
Phil Burkfe17efd2019-03-25 10:23:35 -07006902 out->mmap_time_offset_nanos = get_mmap_out_time_offset();
6903
Haynes Mathew George16081042017-05-31 17:16:49 -07006904 out->standby = false;
6905 ret = 0;
6906
Arun Mirpuri5d170872019-03-26 13:21:31 -07006907 ALOGD("%s: got mmap buffer address %p info->buffer_size_frames %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07006908 __func__, info->shared_memory_address, info->buffer_size_frames);
6909
6910exit:
6911 if (ret != 0) {
6912 if (out->pcm == NULL) {
6913 ALOGE("%s: %s - %d", __func__, step, ret);
6914 } else {
6915 ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
6916 pcm_close(out->pcm);
6917 out->pcm = NULL;
6918 }
6919 }
6920 pthread_mutex_unlock(&adev->lock);
Sharad Sanglec6f32552018-05-04 16:15:38 +05306921 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07006922 return ret;
6923}
6924
6925static int out_get_mmap_position(const struct audio_stream_out *stream,
6926 struct audio_mmap_position *position)
6927{
6928 struct stream_out *out = (struct stream_out *)stream;
6929 ALOGVV("%s", __func__);
6930 if (position == NULL) {
6931 return -EINVAL;
6932 }
6933 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08006934 ALOGE("%s: called on %s", __func__, use_case_table[out->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07006935 return -ENOSYS;
6936 }
6937 if (out->pcm == NULL) {
6938 return -ENOSYS;
6939 }
6940
6941 struct timespec ts = { 0, 0 };
6942 int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
6943 if (ret < 0) {
6944 ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
6945 return ret;
6946 }
Phil Burkfe17efd2019-03-25 10:23:35 -07006947 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
6948 + out->mmap_time_offset_nanos;
Haynes Mathew George16081042017-05-31 17:16:49 -07006949 return 0;
6950}
6951
6952
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006953/** audio_stream_in implementation **/
6954static uint32_t in_get_sample_rate(const struct audio_stream *stream)
6955{
6956 struct stream_in *in = (struct stream_in *)stream;
6957
6958 return in->config.rate;
6959}
6960
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006961static int in_set_sample_rate(struct audio_stream *stream __unused,
6962 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006963{
6964 return -ENOSYS;
6965}
6966
6967static size_t in_get_buffer_size(const struct audio_stream *stream)
6968{
6969 struct stream_in *in = (struct stream_in *)stream;
6970
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006971 if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
6972 return voice_extn_compress_voip_in_get_buffer_size(in);
Mingming Yine62d7842013-10-25 16:26:03 -07006973 else if(audio_extn_compr_cap_usecase_supported(in->usecase))
6974 return audio_extn_compr_cap_get_buffer_size(in->config.format);
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05306975 else if(audio_extn_cin_attached_usecase(in))
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05306976 return audio_extn_cin_get_buffer_size(in);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006977
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006978 return in->config.period_size * in->af_period_multiplier *
6979 audio_stream_in_frame_size((const struct audio_stream_in *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006980}
6981
6982static uint32_t in_get_channels(const struct audio_stream *stream)
6983{
6984 struct stream_in *in = (struct stream_in *)stream;
6985
6986 return in->channel_mask;
6987}
6988
6989static audio_format_t in_get_format(const struct audio_stream *stream)
6990{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006991 struct stream_in *in = (struct stream_in *)stream;
6992
6993 return in->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006994}
6995
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006996static int in_set_format(struct audio_stream *stream __unused,
6997 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006998{
6999 return -ENOSYS;
7000}
7001
7002static int in_standby(struct audio_stream *stream)
7003{
7004 struct stream_in *in = (struct stream_in *)stream;
7005 struct audio_device *adev = in->dev;
7006 int status = 0;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307007 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
7008 stream, in->usecase, use_case_table[in->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07007009 bool do_stop = true;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307010
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007011 lock_input_stream(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007012 if (!in->standby && in->is_st_session) {
7013 ALOGD("%s: sound trigger pcm stop lab", __func__);
7014 audio_extn_sound_trigger_stop_lab(in);
George Gao3018ede2019-10-23 13:23:00 -07007015 if (adev->num_va_sessions > 0)
7016 adev->num_va_sessions--;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007017 in->standby = 1;
7018 }
7019
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007020 if (!in->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007021 if (adev->adm_deregister_stream)
7022 adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
7023
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08007024 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007025 in->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08007026 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
kunleizbecba2d2017-09-07 13:37:16 +08007027 do_stop = false;
Zhou Songa8895042016-07-05 17:54:22 +08007028 voice_extn_compress_voip_close_input_stream(stream);
7029 ALOGD("VOIP input entered standby");
Haynes Mathew George16081042017-05-31 17:16:49 -07007030 } else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7031 do_stop = in->capture_started;
7032 in->capture_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07007033 if (in->mmap_shared_memory_fd >= 0) {
7034 ALOGV("%s: closing mmap_shared_memory_fd = %d",
7035 __func__, in->mmap_shared_memory_fd);
7036 close(in->mmap_shared_memory_fd);
7037 in->mmap_shared_memory_fd = -1;
7038 }
Zhou Songa8895042016-07-05 17:54:22 +08007039 } else {
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307040 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +05307041 audio_extn_cin_close_input_stream(in);
kunleizbecba2d2017-09-07 13:37:16 +08007042 }
7043
Arun Mirpuri5d170872019-03-26 13:21:31 -07007044 if (in->pcm) {
7045 ATRACE_BEGIN("pcm_in_close");
7046 pcm_close(in->pcm);
7047 ATRACE_END();
7048 in->pcm = NULL;
7049 }
7050
Carter Hsu2e429db2019-05-14 18:50:52 +08007051 if (do_stop)
Zhou Songa8895042016-07-05 17:54:22 +08007052 status = stop_input_stream(in);
Quinn Malef6050362019-01-30 15:55:40 -08007053
George Gao3018ede2019-10-23 13:23:00 -07007054 if (in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7055 if (adev->num_va_sessions > 0)
7056 adev->num_va_sessions--;
7057 }
Quinn Malef6050362019-01-30 15:55:40 -08007058
Eric Laurent150dbfe2013-02-27 14:31:02 -08007059 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007060 }
7061 pthread_mutex_unlock(&in->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07007062 ALOGV("%s: exit: status(%d)", __func__, status);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007063 return status;
7064}
7065
Aalique Grahame22e49102018-12-18 14:23:57 -08007066static int in_dump(const struct audio_stream *stream,
7067 int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007068{
Aalique Grahame22e49102018-12-18 14:23:57 -08007069 struct stream_in *in = (struct stream_in *)stream;
7070
7071 // We try to get the lock for consistency,
7072 // but it isn't necessary for these variables.
7073 // If we're not in standby, we may be blocked on a read.
7074 const bool locked = (pthread_mutex_trylock(&in->lock) == 0);
7075 dprintf(fd, " Standby: %s\n", in->standby ? "yes" : "no");
7076 dprintf(fd, " Frames read: %lld\n", (long long)in->frames_read);
7077 dprintf(fd, " Frames muted: %lld\n", (long long)in->frames_muted);
Dechen Chai22768452021-07-30 09:29:16 +05307078#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007079 char buffer[256]; // for statistics formatting
7080 if (in->start_latency_ms.n > 0) {
7081 simple_stats_to_string(&in->start_latency_ms, buffer, sizeof(buffer));
7082 dprintf(fd, " Start latency ms: %s\n", buffer);
7083 }
Dechen Chai22768452021-07-30 09:29:16 +05307084#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08007085 if (locked) {
7086 pthread_mutex_unlock(&in->lock);
7087 }
Dechen Chai22768452021-07-30 09:29:16 +05307088#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08007089 // dump error info
7090 (void)error_log_dump(
7091 in->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05307092#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007093 return 0;
7094}
7095
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307096static void in_snd_mon_cb(void * stream, struct str_parms * parms)
7097{
7098 if (!stream || !parms)
7099 return;
7100
7101 struct stream_in *in = (struct stream_in *)stream;
7102 struct audio_device *adev = in->dev;
7103
7104 card_status_t status;
7105 int card;
7106 if (parse_snd_card_status(parms, &card, &status) < 0)
7107 return;
7108
7109 pthread_mutex_lock(&adev->lock);
7110 bool valid_cb = (card == adev->snd_card);
7111 pthread_mutex_unlock(&adev->lock);
7112
7113 if (!valid_cb)
7114 return;
7115
7116 lock_input_stream(in);
7117 if (in->card_status != status)
7118 in->card_status = status;
7119 pthread_mutex_unlock(&in->lock);
7120
7121 ALOGW("in_snd_mon_cb for card %d usecase %s, status %s", card,
7122 use_case_table[in->usecase],
7123 status == CARD_STATUS_OFFLINE ? "offline" : "online");
7124
7125 // a better solution would be to report error back to AF and let
7126 // it put the stream to standby
7127 if (status == CARD_STATUS_OFFLINE)
7128 in_standby(&in->stream.common);
7129
7130 return;
7131}
7132
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007133int route_input_stream(struct stream_in *in,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007134 struct listnode *devices,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007135 audio_source_t source)
7136{
7137 struct audio_device *adev = in->dev;
7138 int ret = 0;
7139
7140 lock_input_stream(in);
7141 pthread_mutex_lock(&adev->lock);
7142
7143 /* no audio source uses val == 0 */
7144 if ((in->source != source) && (source != AUDIO_SOURCE_DEFAULT)) {
7145 in->source = source;
7146 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
7147 (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
7148 (voice_extn_compress_voip_is_format_supported(in->format)) &&
7149 (in->config.rate == 8000 || in->config.rate == 16000 ||
7150 in->config.rate == 32000 || in->config.rate == 48000 ) &&
7151 (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
7152 ret = voice_extn_compress_voip_open_input_stream(in);
7153 if (ret != 0) {
7154 ALOGE("%s: Compress voip input cannot be opened, error:%d",
7155 __func__, ret);
7156 }
7157 }
7158 }
7159
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007160 if (!compare_devices(&in->device_list, devices) && !list_empty(devices) &&
7161 is_audio_in_device_type(devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007162 // Workaround: If routing to an non existing usb device, fail gracefully
7163 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007164 struct str_parms *usb_addr =
7165 str_parms_create_str(get_usb_device_address(devices));
7166 if (is_usb_in_device_type(devices) && usb_addr &&
Weiyin Jiangabedea32020-12-09 12:49:19 +08007167 !audio_extn_usb_connected(NULL)) {
7168 ALOGW("%s: ignoring rerouting to non existing USB", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007169 ret = -ENOSYS;
7170 } else {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007171 /* If recording is in progress, change the tx device to new device */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007172 assign_devices(&in->device_list, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007173 if (!in->standby && !in->is_st_session) {
7174 ALOGV("update input routing change");
7175 // inform adm before actual routing to prevent glitches.
7176 if (adev->adm_on_routing_change) {
7177 adev->adm_on_routing_change(adev->adm_data,
7178 in->capture_handle);
7179 ret = select_devices(adev, in->usecase);
7180 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7181 adev->adm_routing_changed = true;
7182 }
7183 }
7184 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007185 if (usb_addr)
7186 str_parms_destroy(usb_addr);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007187 }
7188 pthread_mutex_unlock(&adev->lock);
7189 pthread_mutex_unlock(&in->lock);
7190
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07007191 ALOGV("%s: exit: status(%d)", __func__, ret);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007192 return ret;
7193}
7194
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007195static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
7196{
7197 struct stream_in *in = (struct stream_in *)stream;
7198 struct audio_device *adev = in->dev;
7199 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007200 char value[32];
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307201 int err = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007202
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307203 ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007204 parms = str_parms_create_str(kvpairs);
7205
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307206 if (!parms)
7207 goto error;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007208 lock_input_stream(in);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007209 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08007210
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307211 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
7212 if (err >= 0) {
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307213 strlcpy(in->profile, value, sizeof(in->profile));
7214 ALOGV("updating stream profile with value '%s'", in->profile);
7215 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
7216 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007217 &in->device_list, in->flags, in->format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307218 in->sample_rate, in->bit_width,
7219 in->profile, &in->app_type_cfg);
7220 }
7221
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007222 pthread_mutex_unlock(&adev->lock);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007223 pthread_mutex_unlock(&in->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007224
7225 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307226error:
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307227 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007228}
7229
7230static char* in_get_parameters(const struct audio_stream *stream,
7231 const char *keys)
7232{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007233 struct stream_in *in = (struct stream_in *)stream;
7234 struct str_parms *query = str_parms_create_str(keys);
7235 char *str;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007236 struct str_parms *reply = str_parms_create();
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007237
7238 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08007239 if (reply) {
7240 str_parms_destroy(reply);
7241 }
7242 if (query) {
7243 str_parms_destroy(query);
7244 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007245 ALOGE("in_get_parameters: failed to create query or reply");
7246 return NULL;
7247 }
7248
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007249 ALOGV("%s: enter: keys - %s %s ", __func__, use_case_table[in->usecase], keys);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007250
7251 voice_extn_in_get_parameters(in, query, reply);
7252
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007253 stream_get_parameter_channels(query, reply,
7254 &in->supported_channel_masks[0]);
7255 stream_get_parameter_formats(query, reply,
7256 &in->supported_formats[0]);
7257 stream_get_parameter_rates(query, reply,
7258 &in->supported_sample_rates[0]);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007259 str = str_parms_to_str(reply);
7260 str_parms_destroy(query);
7261 str_parms_destroy(reply);
7262
7263 ALOGV("%s: exit: returns - %s", __func__, str);
7264 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007265}
7266
Aalique Grahame22e49102018-12-18 14:23:57 -08007267static int in_set_gain(struct audio_stream_in *stream,
7268 float gain)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007269{
Aalique Grahame22e49102018-12-18 14:23:57 -08007270 struct stream_in *in = (struct stream_in *)stream;
7271 char mixer_ctl_name[128];
7272 struct mixer_ctl *ctl;
7273 int ctl_value;
7274
7275 ALOGV("%s: gain %f", __func__, gain);
7276
7277 if (stream == NULL)
7278 return -EINVAL;
7279
7280 /* in_set_gain() only used to silence MMAP capture for now */
7281 if (in->usecase != USECASE_AUDIO_RECORD_MMAP)
7282 return -ENOSYS;
7283
7284 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Capture %d Volume", in->pcm_device_id);
7285
7286 ctl = mixer_get_ctl_by_name(in->dev->mixer, mixer_ctl_name);
7287 if (!ctl) {
7288 ALOGW("%s: Could not get ctl for mixer cmd - %s",
7289 __func__, mixer_ctl_name);
7290 return -ENOSYS;
7291 }
7292
7293 if (gain < RECORD_GAIN_MIN)
7294 gain = RECORD_GAIN_MIN;
7295 else if (gain > RECORD_GAIN_MAX)
7296 gain = RECORD_GAIN_MAX;
7297 ctl_value = (int)(RECORD_VOLUME_CTL_MAX * gain);
7298
7299 mixer_ctl_set_value(ctl, 0, ctl_value);
7300
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007301 return 0;
7302}
7303
7304static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
7305 size_t bytes)
7306{
7307 struct stream_in *in = (struct stream_in *)stream;
Pallavid7c7a272018-01-16 11:22:55 +05307308
7309 if (in == NULL) {
7310 ALOGE("%s: stream_in ptr is NULL", __func__);
7311 return -EINVAL;
7312 }
7313
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007314 struct audio_device *adev = in->dev;
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05307315 int ret = -1;
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307316 size_t bytes_read = 0, frame_size = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007317
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007318 lock_input_stream(in);
Naresh Tanniru4c630392014-05-12 01:05:52 +05307319
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007320 if (in->is_st_session) {
7321 ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
7322 /* Read from sound trigger HAL */
7323 audio_extn_sound_trigger_read(in, buffer, bytes);
Quinn Malef6050362019-01-30 15:55:40 -08007324 if (in->standby) {
George Gao3018ede2019-10-23 13:23:00 -07007325 if (adev->num_va_sessions < UINT_MAX)
7326 adev->num_va_sessions++;
Quinn Malef6050362019-01-30 15:55:40 -08007327 in->standby = 0;
7328 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007329 pthread_mutex_unlock(&in->lock);
7330 return bytes;
7331 }
7332
Haynes Mathew George16081042017-05-31 17:16:49 -07007333 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7334 ret = -ENOSYS;
7335 goto exit;
7336 }
7337
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007338 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY &&
7339 !in->standby && adev->adm_routing_changed) {
7340 ret = -ENOSYS;
7341 goto exit;
7342 }
7343
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007344 if (in->standby) {
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007345 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
7346
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007347 pthread_mutex_lock(&adev->lock);
7348 if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
7349 ret = voice_extn_compress_voip_start_input_stream(in);
7350 else
7351 ret = start_input_stream(in);
George Gao3018ede2019-10-23 13:23:00 -07007352 if (!ret && in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7353 if (adev->num_va_sessions < UINT_MAX)
7354 adev->num_va_sessions++;
7355 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007356 pthread_mutex_unlock(&adev->lock);
7357 if (ret != 0) {
7358 goto exit;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007359 }
7360 in->standby = 0;
Dechen Chai22768452021-07-30 09:29:16 +05307361#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007362 // log startup time in ms.
7363 simple_stats_log(
7364 &in->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05307365#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007366 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007367
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05307368 /* Avoid read if capture_stopped is set */
7369 if (android_atomic_acquire_load(&(in->capture_stopped)) > 0) {
7370 ALOGD("%s: force stopped catpure session, ignoring read request", __func__);
7371 ret = -EINVAL;
7372 goto exit;
7373 }
7374
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007375 // what's the duration requested by the client?
7376 long ns = 0;
7377
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307378 if (in->pcm && in->config.rate)
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007379 ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
7380 in->config.rate;
7381
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007382 ret = request_in_focus(in, ns);
7383 if (ret != 0)
7384 goto exit;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007385 bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007386
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307387 if (audio_extn_cin_attached_usecase(in)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307388 ret = audio_extn_cin_read(in, buffer, bytes, &bytes_read);
7389 } else if (in->pcm) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307390 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007391 ret = audio_extn_ssr_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307392 } else if (audio_extn_compr_cap_usecase_supported(in->usecase)) {
Mingming Yine62d7842013-10-25 16:26:03 -07007393 ret = audio_extn_compr_cap_read(in, buffer, bytes);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007394 } else if (use_mmap) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07007395 ret = pcm_mmap_read(in->pcm, buffer, bytes);
Garmond Leunge2433c32017-09-28 21:51:22 -07007396 } else if (audio_extn_ffv_get_stream() == in) {
7397 ret = audio_extn_ffv_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307398 } else {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007399 ret = pcm_read(in->pcm, buffer, bytes);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307400 /* data from DSP comes in 24_8 format, convert it to 8_24 */
7401 if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
7402 if (audio_extn_utils_convert_format_24_8_to_8_24(buffer, bytes)
7403 != bytes) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307404 ret = -EINVAL;
7405 goto exit;
7406 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307407 } else if (ret < 0) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307408 ret = -errno;
7409 }
7410 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307411 /* bytes read is always set to bytes for non compress usecases */
7412 bytes_read = bytes;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007413 }
7414
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007415 release_in_focus(in);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007416
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007417 /*
Quinn Malef6050362019-01-30 15:55:40 -08007418 * Instead of writing zeroes here, we could trust the hardware to always
7419 * provide zeroes when muted. This is also muted with voice recognition
7420 * usecases so that other clients do not have access to voice recognition
7421 * data.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007422 */
Quinn Malef6050362019-01-30 15:55:40 -08007423 if ((ret == 0 && voice_get_mic_mute(adev) &&
7424 !voice_is_in_call_rec_stream(in) &&
Zhou Song62ea0282020-03-22 19:53:01 +08007425 (in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY &&
7426 in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY2)) ||
Quinn Malef6050362019-01-30 15:55:40 -08007427 (adev->num_va_sessions &&
7428 in->source != AUDIO_SOURCE_VOICE_RECOGNITION &&
7429 property_get_bool("persist.vendor.audio.va_concurrency_mute_enabled",
7430 false)))
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007431 memset(buffer, 0, bytes);
7432
7433exit:
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307434 frame_size = audio_stream_in_frame_size(stream);
7435 if (frame_size > 0)
7436 in->frames_read += bytes_read/frame_size;
7437
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007438 if (-ENETRESET == ret)
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307439 in->card_status = CARD_STATUS_OFFLINE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007440 pthread_mutex_unlock(&in->lock);
7441
7442 if (ret != 0) {
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307443 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307444 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307445 voice_extn_compress_voip_close_input_stream(&in->stream.common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307446 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307447 in->standby = true;
7448 }
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307449 if (!audio_extn_cin_attached_usecase(in)) {
Sharad Sangled17c9122017-03-20 15:58:52 +05307450 bytes_read = bytes;
7451 memset(buffer, 0, bytes);
7452 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007453 in_standby(&in->stream.common);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007454 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7455 adev->adm_routing_changed = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007456 ALOGV("%s: read failed status %d- sleeping for buffer duration", __func__, ret);
Ashish Jainbbce4322016-02-16 13:25:27 +05307457 usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
Naresh Tanniru4c630392014-05-12 01:05:52 +05307458 in_get_sample_rate(&in->stream.common));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007459 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307460 return bytes_read;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007461}
7462
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007463static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007464{
7465 return 0;
7466}
7467
Aalique Grahame22e49102018-12-18 14:23:57 -08007468static int in_get_capture_position(const struct audio_stream_in *stream,
7469 int64_t *frames, int64_t *time)
7470{
7471 if (stream == NULL || frames == NULL || time == NULL) {
7472 return -EINVAL;
7473 }
7474 struct stream_in *in = (struct stream_in *)stream;
7475 int ret = -ENOSYS;
7476
7477 lock_input_stream(in);
7478 // note: ST sessions do not close the alsa pcm driver synchronously
7479 // on standby. Therefore, we may return an error even though the
7480 // pcm stream is still opened.
7481 if (in->standby) {
7482 ALOGE_IF(in->pcm != NULL && !in->is_st_session,
7483 "%s stream in standby but pcm not NULL for non ST session", __func__);
7484 goto exit;
7485 }
7486 if (in->pcm) {
7487 struct timespec timestamp;
7488 unsigned int avail;
7489 if (pcm_get_htimestamp(in->pcm, &avail, &timestamp) == 0) {
7490 *frames = in->frames_read + avail;
Robert Lee58215542019-07-15 20:55:12 +08007491 *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec
George Gao9ba8a142020-07-23 14:30:03 -07007492 - platform_capture_latency(in) * 1000LL;
Kakanaboina Ramanjaneyulu8cedb092021-03-15 15:55:29 +05307493 //Adjustment accounts for A2dp decoder latency for recording usecase
7494 // Note: decoder latency is returned in ms, while platform_capture_latency in ns.
7495 if (is_a2dp_in_device_type(&in->device_list))
7496 *time -= audio_extn_a2dp_get_decoder_latency() * 1000000LL;
Aalique Grahame22e49102018-12-18 14:23:57 -08007497 ret = 0;
7498 }
7499 }
7500exit:
7501 pthread_mutex_unlock(&in->lock);
7502 return ret;
7503}
7504
Carter Hsu2e429db2019-05-14 18:50:52 +08007505static int in_update_effect_list(bool add, effect_handle_t effect,
7506 struct listnode *head)
7507{
7508 struct listnode *node;
7509 struct in_effect_list *elist = NULL;
7510 struct in_effect_list *target = NULL;
7511 int ret = 0;
7512
7513 if (!head)
7514 return ret;
7515
7516 list_for_each(node, head) {
7517 elist = node_to_item(node, struct in_effect_list, list);
7518 if (elist->handle == effect) {
7519 target = elist;
7520 break;
7521 }
7522 }
7523
7524 if (add) {
7525 if (target) {
7526 ALOGD("effect %p already exist", effect);
7527 return ret;
7528 }
7529
7530 target = (struct in_effect_list *)
7531 calloc(1, sizeof(struct in_effect_list));
7532
7533 if (!target) {
7534 ALOGE("%s:fail to allocate memory", __func__);
7535 return -ENOMEM;
7536 }
7537
7538 target->handle = effect;
7539 list_add_tail(head, &target->list);
7540 } else {
7541 if (target) {
7542 list_remove(&target->list);
7543 free(target);
7544 }
7545 }
7546
7547 return ret;
7548}
7549
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007550static int add_remove_audio_effect(const struct audio_stream *stream,
7551 effect_handle_t effect,
7552 bool enable)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007553{
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007554 struct stream_in *in = (struct stream_in *)stream;
7555 int status = 0;
7556 effect_descriptor_t desc;
7557
7558 status = (*effect)->get_descriptor(effect, &desc);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007559 ALOGV("%s: status %d in->standby %d enable:%d", __func__, status, in->standby, enable);
7560
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007561 if (status != 0)
7562 return status;
7563
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007564 lock_input_stream(in);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007565 pthread_mutex_lock(&in->dev->lock);
kunleizd96526c2018-04-09 11:12:32 +08007566 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Carter Hsu2e429db2019-05-14 18:50:52 +08007567 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
7568 adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007569 (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
Carter Hsu2e429db2019-05-14 18:50:52 +08007570
7571 in_update_effect_list(enable, effect, &in->aec_list);
7572 enable = !list_empty(&in->aec_list);
7573 if (enable == in->enable_aec)
7574 goto exit;
7575
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007576 in->enable_aec = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007577 ALOGD("AEC enable %d", enable);
7578
Aalique Grahame22e49102018-12-18 14:23:57 -08007579 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
7580 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
7581 in->dev->enable_voicerx = enable;
7582 struct audio_usecase *usecase;
7583 struct listnode *node;
7584 list_for_each(node, &in->dev->usecase_list) {
7585 usecase = node_to_item(node, struct audio_usecase, list);
7586 if (usecase->type == PCM_PLAYBACK)
7587 select_devices(in->dev, usecase->id);
7588 }
7589 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007590 if (!in->standby) {
7591 if (enable_disable_effect(in->dev, EFFECT_AEC, enable) == ENOSYS)
7592 select_devices(in->dev, in->usecase);
7593 }
7594
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007595 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007596 if (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
7597
7598 in_update_effect_list(enable, effect, &in->ns_list);
7599 enable = !list_empty(&in->ns_list);
7600 if (enable == in->enable_ns)
7601 goto exit;
7602
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007603 in->enable_ns = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007604 ALOGD("NS enable %d", enable);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007605 if (!in->standby) {
kunleizd96526c2018-04-09 11:12:32 +08007606 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Ramu Gottipatifa5be522021-12-28 19:18:21 +05307607 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
kunleizd96526c2018-04-09 11:12:32 +08007608 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007609 if (enable_disable_effect(in->dev, EFFECT_NS, enable) == ENOSYS)
7610 select_devices(in->dev, in->usecase);
7611 } else
7612 select_devices(in->dev, in->usecase);
7613 }
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007614 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007615exit:
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007616 pthread_mutex_unlock(&in->dev->lock);
7617 pthread_mutex_unlock(&in->lock);
7618
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007619 return 0;
7620}
7621
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007622static int in_add_audio_effect(const struct audio_stream *stream,
7623 effect_handle_t effect)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007624{
Eric Laurent994a6932013-07-17 11:51:42 -07007625 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007626 return add_remove_audio_effect(stream, effect, true);
7627}
7628
7629static int in_remove_audio_effect(const struct audio_stream *stream,
7630 effect_handle_t effect)
7631{
Eric Laurent994a6932013-07-17 11:51:42 -07007632 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007633 return add_remove_audio_effect(stream, effect, false);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007634}
7635
Haynes Mathew George16081042017-05-31 17:16:49 -07007636static int in_stop(const struct audio_stream_in* stream)
7637{
7638 struct stream_in *in = (struct stream_in *)stream;
7639 struct audio_device *adev = in->dev;
7640
7641 int ret = -ENOSYS;
7642 ALOGV("%s", __func__);
7643 pthread_mutex_lock(&adev->lock);
7644 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7645 in->capture_started && in->pcm != NULL) {
7646 pcm_stop(in->pcm);
7647 ret = stop_input_stream(in);
7648 in->capture_started = false;
7649 }
7650 pthread_mutex_unlock(&adev->lock);
7651 return ret;
7652}
7653
7654static int in_start(const struct audio_stream_in* stream)
7655{
7656 struct stream_in *in = (struct stream_in *)stream;
7657 struct audio_device *adev = in->dev;
7658 int ret = -ENOSYS;
7659
7660 ALOGV("%s in %p", __func__, in);
7661 pthread_mutex_lock(&adev->lock);
7662 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7663 !in->capture_started && in->pcm != NULL) {
7664 if (!in->capture_started) {
7665 ret = start_input_stream(in);
7666 if (ret == 0) {
7667 in->capture_started = true;
7668 }
7669 }
7670 }
7671 pthread_mutex_unlock(&adev->lock);
7672 return ret;
7673}
7674
Phil Burke0a86d12019-02-16 22:28:11 -08007675// Read offset for the positional timestamp from a persistent vendor property.
7676// This is to workaround apparent inaccuracies in the timing information that
7677// is used by the AAudio timing model. The inaccuracies can cause glitches.
7678static int64_t in_get_mmap_time_offset() {
7679 const int32_t kDefaultOffsetMicros = 0;
7680 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08007681 "persist.vendor.audio.in_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burke0a86d12019-02-16 22:28:11 -08007682 ALOGI("mmap_time_offset_micros = %d for input", mmap_time_offset_micros);
7683 return mmap_time_offset_micros * (int64_t)1000;
7684}
7685
Haynes Mathew George16081042017-05-31 17:16:49 -07007686static int in_create_mmap_buffer(const struct audio_stream_in *stream,
7687 int32_t min_size_frames,
7688 struct audio_mmap_buffer_info *info)
7689{
7690 struct stream_in *in = (struct stream_in *)stream;
7691 struct audio_device *adev = in->dev;
7692 int ret = 0;
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07007693 unsigned int offset1 = 0;
7694 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007695 const char *step = "";
Arun Mirpuri5d170872019-03-26 13:21:31 -07007696 uint32_t mmap_size = 0;
7697 uint32_t buffer_size = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007698
7699 pthread_mutex_lock(&adev->lock);
7700 ALOGV("%s in %p", __func__, in);
7701
Sharad Sanglec6f32552018-05-04 16:15:38 +05307702 if (CARD_STATUS_OFFLINE == in->card_status||
7703 CARD_STATUS_OFFLINE == adev->card_status) {
7704 ALOGW("in->card_status or adev->card_status offline, try again");
7705 ret = -EIO;
7706 goto exit;
7707 }
7708
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307709 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007710 ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
7711 ret = -EINVAL;
7712 goto exit;
7713 }
7714 if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
7715 ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
7716 ALOGV("%s in %p", __func__, in);
7717 ret = -ENOSYS;
7718 goto exit;
7719 }
7720 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
7721 if (in->pcm_device_id < 0) {
7722 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7723 __func__, in->pcm_device_id, in->usecase);
7724 ret = -EINVAL;
7725 goto exit;
7726 }
7727
7728 adjust_mmap_period_count(&in->config, min_size_frames);
7729
7730 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
7731 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
7732 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
7733 (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307734 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307735 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7736 in->card_status = CARD_STATUS_OFFLINE;
7737 adev->card_status = CARD_STATUS_OFFLINE;
7738 ret = -EIO;
7739 goto exit;
7740 }
7741
Haynes Mathew George16081042017-05-31 17:16:49 -07007742 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
7743 step = "open";
7744 ret = -ENODEV;
7745 goto exit;
7746 }
7747
7748 ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
7749 if (ret < 0) {
7750 step = "begin";
7751 goto exit;
7752 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007753
juyuchen626833d2019-06-04 16:48:02 +08007754 info->flags = 0;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007755 info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
7756 buffer_size = pcm_frames_to_bytes(in->pcm, info->buffer_size_frames);
7757 info->burst_size_frames = in->config.period_size;
7758 ret = platform_get_mmap_data_fd(adev->platform,
7759 in->pcm_device_id, 1 /*capture*/,
7760 &info->shared_memory_fd,
7761 &mmap_size);
7762 if (ret < 0) {
7763 // Fall back to non exclusive mode
7764 info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
7765 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007766 in->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7767 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, in->mmap_shared_memory_fd);
7768
Arun Mirpuri5d170872019-03-26 13:21:31 -07007769 if (mmap_size < buffer_size) {
7770 step = "mmap";
7771 goto exit;
7772 }
juyuchen626833d2019-06-04 16:48:02 +08007773 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007774 }
7775
7776 memset(info->shared_memory_address, 0, buffer_size);
Haynes Mathew George16081042017-05-31 17:16:49 -07007777
7778 ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
7779 if (ret < 0) {
7780 step = "commit";
7781 goto exit;
7782 }
7783
Phil Burke0a86d12019-02-16 22:28:11 -08007784 in->mmap_time_offset_nanos = in_get_mmap_time_offset();
7785
Haynes Mathew George16081042017-05-31 17:16:49 -07007786 in->standby = false;
7787 ret = 0;
7788
7789 ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
7790 __func__, info->shared_memory_address, info->buffer_size_frames);
7791
7792exit:
7793 if (ret != 0) {
7794 if (in->pcm == NULL) {
7795 ALOGE("%s: %s - %d", __func__, step, ret);
7796 } else {
7797 ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
7798 pcm_close(in->pcm);
7799 in->pcm = NULL;
7800 }
7801 }
7802 pthread_mutex_unlock(&adev->lock);
7803 return ret;
7804}
7805
7806static int in_get_mmap_position(const struct audio_stream_in *stream,
7807 struct audio_mmap_position *position)
7808{
7809 struct stream_in *in = (struct stream_in *)stream;
7810 ALOGVV("%s", __func__);
7811 if (position == NULL) {
7812 return -EINVAL;
7813 }
Gautam Manam34d1f542021-01-05 20:24:37 +05307814 lock_input_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07007815 if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
Gautam Manam34d1f542021-01-05 20:24:37 +05307816 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007817 return -ENOSYS;
7818 }
7819 if (in->pcm == NULL) {
Gautam Manam34d1f542021-01-05 20:24:37 +05307820 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007821 return -ENOSYS;
7822 }
7823 struct timespec ts = { 0, 0 };
7824 int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
7825 if (ret < 0) {
7826 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
Gautam Manam34d1f542021-01-05 20:24:37 +05307827 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007828 return ret;
7829 }
Phil Burke0a86d12019-02-16 22:28:11 -08007830 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
7831 + in->mmap_time_offset_nanos;
Gautam Manam34d1f542021-01-05 20:24:37 +05307832 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007833 return 0;
7834}
7835
Naresh Tannirudcb47c52018-06-25 16:23:32 +05307836static int in_get_active_microphones(const struct audio_stream_in *stream,
7837 struct audio_microphone_characteristic_t *mic_array,
7838 size_t *mic_count) {
7839 struct stream_in *in = (struct stream_in *)stream;
7840 struct audio_device *adev = in->dev;
7841 ALOGVV("%s", __func__);
7842
7843 lock_input_stream(in);
7844 pthread_mutex_lock(&adev->lock);
7845 int ret = platform_get_active_microphones(adev->platform,
7846 audio_channel_count_from_in_mask(in->channel_mask),
7847 in->usecase, mic_array, mic_count);
7848 pthread_mutex_unlock(&adev->lock);
7849 pthread_mutex_unlock(&in->lock);
7850
7851 return ret;
7852}
7853
7854static int adev_get_microphones(const struct audio_hw_device *dev,
7855 struct audio_microphone_characteristic_t *mic_array,
7856 size_t *mic_count) {
7857 struct audio_device *adev = (struct audio_device *)dev;
7858 ALOGVV("%s", __func__);
7859
7860 pthread_mutex_lock(&adev->lock);
7861 int ret = platform_get_microphones(adev->platform, mic_array, mic_count);
7862 pthread_mutex_unlock(&adev->lock);
7863
7864 return ret;
7865}
juyuchendb308c22019-01-21 11:57:17 -07007866
7867static void in_update_sink_metadata(struct audio_stream_in *stream,
7868 const struct sink_metadata *sink_metadata) {
7869
7870 if (stream == NULL
7871 || sink_metadata == NULL
7872 || sink_metadata->tracks == NULL) {
7873 return;
7874 }
7875
7876 int error = 0;
7877 struct stream_in *in = (struct stream_in *)stream;
7878 struct audio_device *adev = in->dev;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007879 struct listnode devices;
7880
7881 list_init(&devices);
juyuchendb308c22019-01-21 11:57:17 -07007882
7883 if (sink_metadata->track_count != 0)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007884 reassign_device_list(&devices, sink_metadata->tracks->dest_device, "");
juyuchendb308c22019-01-21 11:57:17 -07007885
7886 lock_input_stream(in);
7887 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007888 ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, get_device_types(&devices));
juyuchendb308c22019-01-21 11:57:17 -07007889
Zhou Song503196b2021-07-23 17:31:05 +08007890 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY ||
7891 in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2) &&
7892 !list_empty(&devices) &&
7893 adev->voice_tx_output != NULL) {
juyuchendb308c22019-01-21 11:57:17 -07007894 /* Use the rx device from afe-proxy record to route voice call because
7895 there is no routing if tx device is on primary hal and rx device
7896 is on other hal during voice call. */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007897 assign_devices(&adev->voice_tx_output->device_list, &devices);
juyuchendb308c22019-01-21 11:57:17 -07007898
7899 if (!voice_is_call_state_active(adev)) {
7900 if (adev->mode == AUDIO_MODE_IN_CALL) {
7901 adev->current_call_output = adev->voice_tx_output;
7902 error = voice_start_call(adev);
7903 if (error != 0)
7904 ALOGE("%s: start voice call failed %d", __func__, error);
7905 }
7906 } else {
7907 adev->current_call_output = adev->voice_tx_output;
7908 voice_update_devices_for_all_voice_usecases(adev);
7909 }
7910 }
7911
7912 pthread_mutex_unlock(&adev->lock);
7913 pthread_mutex_unlock(&in->lock);
7914}
7915
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05307916int adev_open_output_stream(struct audio_hw_device *dev,
Haynes Mathew George16081042017-05-31 17:16:49 -07007917 audio_io_handle_t handle,
7918 audio_devices_t devices,
7919 audio_output_flags_t flags,
7920 struct audio_config *config,
7921 struct audio_stream_out **stream_out,
Derek Chenf6318be2017-06-12 17:16:24 -04007922 const char *address)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007923{
7924 struct audio_device *adev = (struct audio_device *)dev;
7925 struct stream_out *out;
Gangadhar Sb0210342019-02-22 17:39:41 +05307926 int ret = 0, ip_hdlr_stream = 0, ip_hdlr_dev = 0;
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07007927 audio_format_t format;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08007928 struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
Manish Dewangan21a850a2017-08-14 12:03:55 +05307929 bool is_direct_passthough = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007930 bool is_hdmi = devices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
7931 bool is_usb_dev = audio_is_usb_out_device(devices) &&
7932 (devices != AUDIO_DEVICE_OUT_USB_ACCESSORY);
7933 bool direct_dev = is_hdmi || is_usb_dev;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08007934 bool use_db_as_primary =
vivek mehtaae1018c2019-05-09 12:19:57 -07007935 property_get_bool("vendor.audio.feature.deepbuffer_as_primary.enable",
7936 false);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08007937 bool force_haptic_path =
7938 property_get_bool("vendor.audio.test_haptic", false);
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07007939 bool is_voip_rx = flags & AUDIO_OUTPUT_FLAG_VOIP_RX;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08007940#ifdef AUDIO_GKI_ENABLED
7941 __s32 *generic_dec;
7942#endif
Weiyin Jiang906db3c2021-03-02 13:17:04 +08007943 pthread_mutexattr_t latch_attr;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007944
kunleizdff872d2018-08-20 14:40:33 +08007945 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08007946 is_usb_dev = false;
7947 devices = AUDIO_DEVICE_OUT_SPEAKER;
7948 ALOGW("%s: ignore set device to non existing USB card, use output device(%#x)",
7949 __func__, devices);
Mingshu Pangdbd20562019-11-25 18:04:39 +08007950 if (config->format == AUDIO_FORMAT_DEFAULT)
7951 config->format = AUDIO_FORMAT_PCM_16_BIT;
7952 if (config->sample_rate == 0)
7953 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
7954 if (config->channel_mask == AUDIO_CHANNEL_NONE)
7955 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
kunleizd6a9e0c2018-07-30 15:38:52 +08007956 }
7957
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007958 *stream_out = NULL;
Naresh Tanniru80659832014-06-04 18:17:56 +05307959
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007960 out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
7961
Mingming Yin3a941d42016-02-17 18:08:05 -08007962 ALOGD("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
Derek Chenf6318be2017-06-12 17:16:24 -04007963 stream_handle(%p) address(%s)", __func__, config->format, config->sample_rate, config->channel_mask,
7964 devices, flags, &out->stream, address);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307965
7966
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08007967 if (!out) {
7968 return -ENOMEM;
7969 }
7970
Haynes Mathew George204045b2015-02-25 20:32:03 -08007971 pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007972 pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08007973 pthread_mutexattr_init(&latch_attr);
7974 pthread_mutexattr_settype(&latch_attr, PTHREAD_MUTEX_RECURSIVE);
7975 pthread_mutex_init(&out->latch_lock, &latch_attr);
7976 pthread_mutexattr_destroy(&latch_attr);
Zhou Song48453a02018-01-10 17:50:59 +08007977 pthread_mutex_init(&out->position_query_lock, (const pthread_mutexattr_t *) NULL);
Haynes Mathew George204045b2015-02-25 20:32:03 -08007978 pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
7979
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007980 if (devices == AUDIO_DEVICE_NONE)
7981 devices = AUDIO_DEVICE_OUT_SPEAKER;
7982
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007983 out->flags = flags;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007984 list_init(&out->device_list);
7985 update_device_list(&out->device_list, devices, address, true /* add devices */);
Haynes Mathew George47cd4cb2013-07-19 11:58:50 -07007986 out->dev = adev;
Aalique Grahame65780b52017-09-27 14:59:56 -07007987 out->hal_op_format = out->hal_ip_format = format = out->format = config->format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07007988 out->sample_rate = config->sample_rate;
Sachin Mohan Gadag3d09acd2017-06-19 12:43:44 +05307989 out->channel_mask = config->channel_mask;
Ramjee Singh5857aeb2017-08-03 19:18:50 +05307990 if (out->channel_mask == AUDIO_CHANNEL_NONE)
7991 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
7992 else
7993 out->supported_channel_masks[0] = out->channel_mask;
Eric Laurentc4aef752013-09-12 17:45:53 -07007994 out->handle = handle;
Mingming Yin3ee55c62014-08-04 14:23:35 -07007995 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Alexy Josephaa54c872014-12-03 02:46:47 -08007996 out->non_blocking = 0;
Ashish Jain83a6cc22016-06-28 14:34:17 +05307997 out->convert_buffer = NULL;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05307998 out->started = 0;
Zhou Songbaddf9f2020-11-20 13:57:39 +08007999 out->a2dp_muted = false;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008000 out->hal_output_suspend_supported = 0;
8001 out->dynamic_pm_qos_config_supported = 0;
Surendar Karkaf51b5842018-04-26 11:28:38 +05308002 out->set_dual_mono = false;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05308003 out->prev_card_status_offline = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05308004 out->pspd_coeff_sent = false;
Phil Burkd898ba62019-06-20 12:49:01 -07008005 out->mmap_shared_memory_fd = -1; // not open
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008006
Nikhil Laturkar26b690b2017-07-25 11:06:14 +05308007 if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
Satish Babu Patakokila37e7c482018-02-02 11:50:06 +05308008 (property_get_bool("vendor.audio.matrix.limiter.enable", false)))
Ben Romberger6c4d3812017-06-13 17:46:45 -07008009 platform_set_device_params(out, DEVICE_PARAM_LIMITER_ID, 1);
8010
Aalique Grahame22e49102018-12-18 14:23:57 -08008011 if (direct_dev &&
8012 (audio_is_linear_pcm(out->format) ||
8013 config->format == AUDIO_FORMAT_DEFAULT) &&
8014 out->flags == AUDIO_OUTPUT_FLAG_NONE) {
8015 audio_format_t req_format = config->format;
8016 audio_channel_mask_t req_channel_mask = config->channel_mask;
8017 uint32_t req_sample_rate = config->sample_rate;
8018
8019 pthread_mutex_lock(&adev->lock);
8020 if (is_hdmi) {
8021 ALOGV("AUDIO_DEVICE_OUT_AUX_DIGITAL and DIRECT|OFFLOAD, check hdmi caps");
8022 ret = read_hdmi_sink_caps(out);
8023 if (config->sample_rate == 0)
8024 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8025 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8026 config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
8027 if (config->format == AUDIO_FORMAT_DEFAULT)
8028 config->format = AUDIO_FORMAT_PCM_16_BIT;
8029 } else if (is_usb_dev) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008030 ret = read_usb_sup_params_and_compare(true /*is_playback*/,
8031 &config->format,
8032 &out->supported_formats[0],
8033 MAX_SUPPORTED_FORMATS,
8034 &config->channel_mask,
8035 &out->supported_channel_masks[0],
8036 MAX_SUPPORTED_CHANNEL_MASKS,
8037 &config->sample_rate,
8038 &out->supported_sample_rates[0],
8039 MAX_SUPPORTED_SAMPLE_RATES);
8040 ALOGV("plugged dev USB ret %d", ret);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008041 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008042
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008043 pthread_mutex_unlock(&adev->lock);
8044 if (ret != 0) {
Mingming Yin3a941d42016-02-17 18:08:05 -08008045 if (ret == -ENOSYS) {
8046 /* ignore and go with default */
8047 ret = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08008048 }
8049 // For MMAP NO IRQ, allow conversions in ADSP
8050 else if (is_hdmi || (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0)
8051 goto error_open;
8052 else {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008053 ALOGE("error reading direct dev sink caps");
Mingming Yin3a941d42016-02-17 18:08:05 -08008054 goto error_open;
8055 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008056
8057 if (req_sample_rate != 0 && config->sample_rate != req_sample_rate)
8058 config->sample_rate = req_sample_rate;
8059 if (req_channel_mask != AUDIO_CHANNEL_NONE && config->channel_mask != req_channel_mask)
8060 config->channel_mask = req_channel_mask;
8061 if (req_format != AUDIO_FORMAT_DEFAULT && config->format != req_format)
8062 config->format = req_format;
Mingming Yin3a941d42016-02-17 18:08:05 -08008063 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008064
8065 out->sample_rate = config->sample_rate;
8066 out->channel_mask = config->channel_mask;
8067 out->format = config->format;
8068 if (is_hdmi) {
8069 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8070 out->config = pcm_config_hdmi_multi;
8071 } else if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8072 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8073 out->config = pcm_config_mmap_playback;
8074 out->stream.start = out_start;
8075 out->stream.stop = out_stop;
8076 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8077 out->stream.get_mmap_position = out_get_mmap_position;
8078 } else {
8079 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8080 out->config = pcm_config_hifi;
8081 }
8082
8083 out->config.rate = out->sample_rate;
8084 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8085 if (is_hdmi) {
8086 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8087 audio_bytes_per_sample(out->format));
8088 }
8089 out->config.format = pcm_format_from_audio_format(out->format);
Mingming Yin3a941d42016-02-17 18:08:05 -08008090 }
8091
Derek Chenf6318be2017-06-12 17:16:24 -04008092 /* validate bus device address */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008093 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008094 /* extract car audio stream index */
8095 out->car_audio_stream =
8096 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
8097 if (out->car_audio_stream < 0) {
8098 ALOGE("%s: invalid car audio stream %x",
8099 __func__, out->car_audio_stream);
8100 ret = -EINVAL;
8101 goto error_open;
8102 }
Derek Chen5f67a942020-02-24 23:08:13 -08008103 ALOGV("%s: car_audio_stream %x", __func__, out->car_audio_stream);
Derek Chenf6318be2017-06-12 17:16:24 -04008104 }
8105
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008106 /* Check for VOIP usecase */
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008107 if (is_voip_rx) {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008108 if (!voice_extn_is_compress_voip_supported()) {
8109 if (out->sample_rate == 8000 || out->sample_rate == 16000 ||
8110 out->sample_rate == 32000 || out->sample_rate == 48000) {
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07008111 out->channel_mask = audio_extn_utils_is_vendor_enhanced_fwk() ?
Lakshman Chaluvarajue7fc9482020-05-30 14:29:29 +05308112 config->channel_mask : AUDIO_CHANNEL_OUT_STEREO;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008113 out->usecase = USECASE_AUDIO_PLAYBACK_VOIP;
8114 out->format = AUDIO_FORMAT_PCM_16_BIT;
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07008115 out->volume_l = INVALID_OUT_VOLUME;
8116 out->volume_r = INVALID_OUT_VOLUME;
Vikram Panduranga93f080e2017-06-07 18:16:14 -07008117
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008118 out->config = default_pcm_config_voip_copp;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008119 out->config.rate = out->sample_rate;
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008120 uint32_t channel_count =
8121 audio_channel_count_from_out_mask(out->channel_mask);
Ramjee Singh968858a2020-08-06 16:30:48 +05308122 out->config.channels = channel_count;
8123
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008124 uint32_t buffer_size = get_stream_buffer_size(DEFAULT_VOIP_BUF_DURATION_MS,
8125 out->sample_rate, out->format,
8126 channel_count, false);
8127 uint32_t frame_size = audio_bytes_per_sample(out->format) * channel_count;
8128 if (frame_size != 0)
8129 out->config.period_size = buffer_size / frame_size;
8130 else
8131 ALOGW("%s: frame size is 0 for format %#x", __func__, out->format);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008132 }
8133 } else {
8134 if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
8135 voice_extn_compress_voip_is_active(out->dev)) &&
8136 (voice_extn_compress_voip_is_config_supported(config))) {
8137 ret = voice_extn_compress_voip_open_output_stream(out);
8138 if (ret != 0) {
8139 ALOGE("%s: Compress voip output cannot be opened, error:%d",
8140 __func__, ret);
8141 goto error_open;
8142 }
Sujin Panicker19027262019-09-16 18:28:06 +05308143 } else {
8144 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8145 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008146 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008147 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008148 } else if (audio_is_linear_pcm(out->format) &&
8149 out->flags == AUDIO_OUTPUT_FLAG_NONE && is_usb_dev) {
8150 out->channel_mask = config->channel_mask;
8151 out->sample_rate = config->sample_rate;
8152 out->format = config->format;
8153 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8154 // does this change?
8155 out->config = is_hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
8156 out->config.rate = config->sample_rate;
8157 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8158 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8159 audio_bytes_per_sample(config->format));
8160 out->config.format = pcm_format_from_audio_format(out->format);
vivek mehta0ea887a2015-08-26 14:01:20 -07008161 } else if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308162 (out->flags == AUDIO_OUTPUT_FLAG_DIRECT)) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308163 pthread_mutex_lock(&adev->lock);
8164 bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
8165 pthread_mutex_unlock(&adev->lock);
8166
8167 // reject offload during card offline to allow
8168 // fallback to s/w paths
8169 if (offline) {
8170 ret = -ENODEV;
8171 goto error_open;
8172 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008173
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008174 if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
8175 config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
8176 ALOGE("%s: Unsupported Offload information", __func__);
8177 ret = -EINVAL;
8178 goto error_open;
8179 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008180
Atul Khare3fa6e542017-08-09 00:56:17 +05308181 if (config->offload_info.format == 0)
8182 config->offload_info.format = config->format;
8183 if (config->offload_info.sample_rate == 0)
8184 config->offload_info.sample_rate = config->sample_rate;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008185
Mingming Yin90310102013-11-13 16:57:00 -08008186 if (!is_supported_format(config->offload_info.format) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308187 !audio_extn_passthru_is_supported_format(config->offload_info.format)) {
vivek mehta0ea887a2015-08-26 14:01:20 -07008188 ALOGE("%s: Unsupported audio format %x " , __func__, config->offload_info.format);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008189 ret = -EINVAL;
8190 goto error_open;
8191 }
8192
Ben Romberger0f8c87b2017-05-24 17:41:11 -07008193 /* TrueHD only supported for 48k multiples (48k, 96k, 192k) */
8194 if ((config->offload_info.format == AUDIO_FORMAT_DOLBY_TRUEHD) &&
8195 (audio_extn_passthru_is_passthrough_stream(out)) &&
8196 !((config->sample_rate == 48000) ||
8197 (config->sample_rate == 96000) ||
8198 (config->sample_rate == 192000))) {
8199 ALOGE("%s: Unsupported sample rate %d for audio format %x",
8200 __func__, config->sample_rate, config->offload_info.format);
8201 ret = -EINVAL;
8202 goto error_open;
8203 }
8204
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008205 out->compr_config.codec = (struct snd_codec *)
8206 calloc(1, sizeof(struct snd_codec));
8207
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07008208 if (!out->compr_config.codec) {
8209 ret = -ENOMEM;
8210 goto error_open;
8211 }
8212
Dhananjay Kumarac341582017-02-23 23:42:25 +05308213 out->stream.pause = out_pause;
8214 out->stream.resume = out_resume;
8215 out->stream.flush = out_flush;
Ashish Jain4847e9d2017-08-17 19:16:57 +05308216 out->stream.set_callback = out_set_callback;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308217 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Mingming Yin21d60472015-09-30 13:56:25 -07008218 out->stream.drain = out_drain;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308219 out->usecase = get_offload_usecase(adev, true /* is_compress */);
vivek mehta446c3962015-09-14 10:57:35 -07008220 ALOGV("Compress Offload usecase .. usecase selected %d", out->usecase);
Dhananjay Kumarac341582017-02-23 23:42:25 +05308221 } else {
8222 out->usecase = get_offload_usecase(adev, false /* is_compress */);
8223 ALOGV("non-offload DIRECT_usecase ... usecase selected %d ", out->usecase);
vivek mehta0ea887a2015-08-26 14:01:20 -07008224 }
vivek mehta446c3962015-09-14 10:57:35 -07008225
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308226 if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8227 ALOGD("%s: Setting latency mode to true", __func__);
Meng Wang4c32fb42020-01-16 17:57:11 +08008228#ifdef AUDIO_GKI_ENABLED
8229 /* out->compr_config.codec->reserved[1] is for flags */
8230 out->compr_config.codec->reserved[1] |= audio_extn_utils_get_perf_mode_flag();
8231#else
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308232 out->compr_config.codec->flags |= audio_extn_utils_get_perf_mode_flag();
Meng Wang4c32fb42020-01-16 17:57:11 +08008233#endif
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308234 }
8235
vivek mehta446c3962015-09-14 10:57:35 -07008236 if (out->usecase == USECASE_INVALID) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008237 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Mingming Yin3a941d42016-02-17 18:08:05 -08008238 config->format == 0 && config->sample_rate == 0 &&
8239 config->channel_mask == 0) {
Mingming Yin21854652016-04-13 11:54:02 -07008240 ALOGI("%s dummy open to query sink capability",__func__);
Mingming Yin3a941d42016-02-17 18:08:05 -08008241 out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
8242 } else {
8243 ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__);
8244 ret = -EEXIST;
8245 goto error_open;
8246 }
vivek mehta446c3962015-09-14 10:57:35 -07008247 }
8248
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008249 if (config->offload_info.channel_mask)
8250 out->channel_mask = config->offload_info.channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008251 else if (config->channel_mask) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008252 out->channel_mask = config->channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008253 config->offload_info.channel_mask = config->channel_mask;
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008254 } else {
Dhananjay Kumarac341582017-02-23 23:42:25 +05308255 ALOGE("out->channel_mask not set for OFFLOAD/DIRECT usecase");
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008256 ret = -EINVAL;
8257 goto error_open;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008258 }
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008259
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008260 format = out->format = config->offload_info.format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008261 out->sample_rate = config->offload_info.sample_rate;
8262
Mingming Yin3ee55c62014-08-04 14:23:35 -07008263 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008264
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308265 out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05308266 if (audio_extn_utils_is_dolby_format(config->offload_info.format)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308267 audio_extn_dolby_send_ddp_endp_params(adev);
8268 audio_extn_dolby_set_dmid(adev);
8269 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008270
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008271 out->compr_config.codec->sample_rate =
Ravi Kumar Alamandab91bff32014-11-14 12:05:54 -08008272 config->offload_info.sample_rate;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008273 out->compr_config.codec->bit_rate =
8274 config->offload_info.bit_rate;
8275 out->compr_config.codec->ch_in =
Dhanalakshmi Siddania15c6792016-08-10 15:33:53 +05308276 audio_channel_count_from_out_mask(out->channel_mask);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008277 out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
Satish Babu Patakokilaa395a9e2016-11-01 12:18:49 +05308278 /* Update bit width only for non passthrough usecases.
8279 * For passthrough usecases, the output will always be opened @16 bit
8280 */
8281 if (!audio_extn_passthru_is_passthrough_stream(out))
8282 out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308283
8284 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
Meng Wang4c32fb42020-01-16 17:57:11 +08008285#ifdef AUDIO_GKI_ENABLED
8286 /* out->compr_config.codec->reserved[1] is for flags */
8287 out->compr_config.codec->reserved[1] |= COMPRESSED_TIMESTAMP_FLAG;
8288 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->reserved[1]);
8289#else
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308290 out->compr_config.codec->flags |= COMPRESSED_TIMESTAMP_FLAG;
8291 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->flags);
Meng Wang4c32fb42020-01-16 17:57:11 +08008292#endif
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308293
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008294 /*TODO: Do we need to change it for passthrough */
8295 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008296
Manish Dewangana6fc5442015-08-24 20:30:31 +05308297 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC)
8298 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308299 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
Manish Dewangana6fc5442015-08-24 20:30:31 +05308300 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308301 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_LATM)
8302 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4LATM;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308303
8304 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) ==
8305 AUDIO_FORMAT_PCM) {
8306
8307 /*Based on platform support, configure appropriate alsa format for corresponding
8308 *hal input format.
8309 */
8310 out->compr_config.codec->format = hal_format_to_alsa(
8311 config->offload_info.format);
8312
Ashish Jain83a6cc22016-06-28 14:34:17 +05308313 out->hal_op_format = alsa_format_to_hal(
Ashish Jainf1eaa582016-05-23 20:54:24 +05308314 out->compr_config.codec->format);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308315 out->hal_ip_format = out->format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308316
Dhananjay Kumarac341582017-02-23 23:42:25 +05308317 /*for direct non-compress playback populate bit_width based on selected alsa format as
Ashish Jainf1eaa582016-05-23 20:54:24 +05308318 *hal input format and alsa format might differ based on platform support.
8319 */
8320 out->bit_width = audio_bytes_per_sample(
Ashish Jain83a6cc22016-06-28 14:34:17 +05308321 out->hal_op_format) << 3;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308322
8323 out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
8324
Deeraj Soman93155a62019-09-30 19:00:37 +05308325 if (property_get_bool("vendor.audio.offload.buffer.duration.enabled", false)) {
8326 if ((config->offload_info.duration_us >= MIN_OFFLOAD_BUFFER_DURATION_MS * 1000) &&
8327 (config->offload_info.duration_us <= MAX_OFFLOAD_BUFFER_DURATION_MS * 1000))
8328 out->info.duration_us = (int64_t)config->offload_info.duration_us;
8329 }
Deeraj Soman65358ab2019-02-07 15:40:49 +05308330
Ashish Jainf1eaa582016-05-23 20:54:24 +05308331 /* Check if alsa session is configured with the same format as HAL input format,
8332 * if not then derive correct fragment size needed to accomodate the
8333 * conversion of HAL input format to alsa format.
8334 */
8335 audio_extn_utils_update_direct_pcm_fragment_size(out);
8336
8337 /*if hal input and output fragment size is different this indicates HAL input format is
8338 *not same as the alsa format
8339 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308340 if (out->hal_fragment_size != out->compr_config.fragment_size) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05308341 /*Allocate a buffer to convert input data to the alsa configured format.
8342 *size of convert buffer is equal to the size required to hold one fragment size
8343 *worth of pcm data, this is because flinger does not write more than fragment_size
8344 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308345 out->convert_buffer = calloc(1,out->compr_config.fragment_size);
8346 if (out->convert_buffer == NULL){
Ashish Jainf1eaa582016-05-23 20:54:24 +05308347 ALOGE("Allocation failed for convert buffer for size %d", out->compr_config.fragment_size);
8348 ret = -ENOMEM;
8349 goto error_open;
8350 }
8351 }
8352 } else if (audio_extn_passthru_is_passthrough_stream(out)) {
8353 out->compr_config.fragment_size =
8354 audio_extn_passthru_get_buffer_size(&config->offload_info);
8355 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8356 } else {
8357 out->compr_config.fragment_size =
8358 platform_get_compress_offload_buffer_size(&config->offload_info);
8359 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8360 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008361
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308362 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8363 out->compr_config.fragment_size += sizeof(struct snd_codec_metadata);
8364 }
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008365 if (config->offload_info.format == AUDIO_FORMAT_FLAC) {
8366#ifdef AUDIO_GKI_ENABLED
8367 generic_dec =
8368 &(out->compr_config.codec->options.generic.reserved[1]);
8369 ((struct snd_generic_dec_flac *)generic_dec)->sample_size =
8370 AUDIO_OUTPUT_BIT_WIDTH;
8371#else
Satya Krishna Pindiproli5d82d012015-08-12 18:21:25 +05308372 out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008373#endif
8374 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008375
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05308376 if (config->offload_info.format == AUDIO_FORMAT_APTX) {
8377 audio_extn_send_aptx_dec_bt_addr_to_dsp(out);
8378 }
8379
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008380 if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
8381 out->non_blocking = 1;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008382
Manish Dewangan69426c82017-01-30 17:35:36 +05308383 if ((flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) &&
8384 (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
8385 out->render_mode = RENDER_MODE_AUDIO_STC_MASTER;
8386 } else if(flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8387 out->render_mode = RENDER_MODE_AUDIO_MASTER;
8388 } else {
8389 out->render_mode = RENDER_MODE_AUDIO_NO_TIMESTAMP;
8390 }
Alexy Josephaa54c872014-12-03 02:46:47 -08008391
Naresh Tanniru29bce4e2017-04-27 17:54:30 +05308392 memset(&out->channel_map_param, 0,
8393 sizeof(struct audio_out_channel_map_param));
8394
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008395 out->send_new_metadata = 1;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05308396 out->send_next_track_params = false;
8397 out->is_compr_metadata_avail = false;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008398 out->offload_state = OFFLOAD_STATE_IDLE;
8399 out->playback_started = 0;
Zhou Song48453a02018-01-10 17:50:59 +08008400 out->writeAt.tv_sec = 0;
8401 out->writeAt.tv_nsec = 0;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008402
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008403 audio_extn_dts_create_state_notifier_node(out->usecase);
8404
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008405 ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
8406 __func__, config->offload_info.version,
8407 config->offload_info.bit_rate);
Ashish Jain5106d362016-05-11 19:23:33 +05308408
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308409 /* Check if DSD audio format is supported in codec
8410 * and there is no active native DSD use case
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308411 */
8412
8413 if ((config->format == AUDIO_FORMAT_DSD) &&
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308414 (!platform_check_codec_dsd_support(adev->platform) ||
8415 audio_is_dsd_native_stream_active(adev))) {
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308416 ret = -EINVAL;
8417 goto error_open;
8418 }
8419
Ashish Jain5106d362016-05-11 19:23:33 +05308420 /* Disable gapless if any of the following is true
8421 * passthrough playback
8422 * AV playback
Dhananjay Kumarac341582017-02-23 23:42:25 +05308423 * non compressed Direct playback
Ashish Jain5106d362016-05-11 19:23:33 +05308424 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308425 if (audio_extn_passthru_is_passthrough_stream(out) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308426 (config->format == AUDIO_FORMAT_DSD) ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07008427 (config->format == AUDIO_FORMAT_IEC61937) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308428 config->offload_info.has_video ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308429 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Ashish Jain5106d362016-05-11 19:23:33 +05308430 check_and_set_gapless_mode(adev, false);
8431 } else
8432 check_and_set_gapless_mode(adev, true);
Mingming Yin21854652016-04-13 11:54:02 -07008433
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308434 if (audio_extn_passthru_is_passthrough_stream(out)) {
Mingming Yin21854652016-04-13 11:54:02 -07008435 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
8436 }
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308437 if (config->format == AUDIO_FORMAT_DSD) {
8438 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
Meng Wang4c32fb42020-01-16 17:57:11 +08008439#ifdef AUDIO_GKI_ENABLED
8440 /* out->compr_config.codec->reserved[0] is for compr_passthr */
8441 out->compr_config.codec->reserved[0] = PASSTHROUGH_DSD;
8442#else
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308443 out->compr_config.codec->compr_passthr = PASSTHROUGH_DSD;
Meng Wang4c32fb42020-01-16 17:57:11 +08008444#endif
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308445 }
Aalique Grahame0359a1f2016-09-08 16:54:22 -07008446
8447 create_offload_callback_thread(out);
8448
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008449 } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008450 switch (config->sample_rate) {
8451 case 0:
8452 out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8453 break;
8454 case 8000:
8455 case 16000:
8456 case 48000:
8457 out->sample_rate = config->sample_rate;
8458 break;
8459 default:
8460 ALOGE("%s: Unsupported sampling rate %d for Incall Music", __func__,
8461 config->sample_rate);
8462 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8463 ret = -EINVAL;
8464 goto error_open;
8465 }
8466 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8467 switch (config->channel_mask) {
8468 case AUDIO_CHANNEL_NONE:
8469 case AUDIO_CHANNEL_OUT_STEREO:
8470 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8471 break;
8472 default:
8473 ALOGE("%s: Unsupported channel mask %#x for Incall Music", __func__,
8474 config->channel_mask);
8475 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8476 ret = -EINVAL;
8477 goto error_open;
8478 }
8479 switch (config->format) {
8480 case AUDIO_FORMAT_DEFAULT:
8481 case AUDIO_FORMAT_PCM_16_BIT:
8482 out->format = AUDIO_FORMAT_PCM_16_BIT;
8483 break;
8484 default:
8485 ALOGE("%s: Unsupported format %#x for Incall Music", __func__,
8486 config->format);
8487 config->format = AUDIO_FORMAT_PCM_16_BIT;
8488 ret = -EINVAL;
8489 goto error_open;
8490 }
8491
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05308492 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008493 if (ret != 0) {
8494 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008495 __func__, ret);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008496 goto error_open;
8497 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008498 } else if (is_single_device_type_equal(&out->device_list,
8499 AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08008500 switch (config->sample_rate) {
8501 case 0:
8502 out->sample_rate = AFE_PROXY_SAMPLING_RATE;
8503 break;
8504 case 8000:
8505 case 16000:
8506 case 48000:
8507 out->sample_rate = config->sample_rate;
8508 break;
8509 default:
8510 ALOGE("%s: Unsupported sampling rate %d for Telephony TX", __func__,
8511 config->sample_rate);
8512 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
8513 ret = -EINVAL;
8514 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008515 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008516 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8517 switch (config->channel_mask) {
8518 case AUDIO_CHANNEL_NONE:
8519 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8520 break;
8521 case AUDIO_CHANNEL_OUT_STEREO:
8522 out->channel_mask = config->channel_mask;
8523 break;
8524 default:
8525 ALOGE("%s: Unsupported channel mask %#x for Telephony TX", __func__,
8526 config->channel_mask);
8527 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8528 ret = -EINVAL;
8529 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008530 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008531 switch (config->format) {
8532 case AUDIO_FORMAT_DEFAULT:
8533 out->format = AUDIO_FORMAT_PCM_16_BIT;
8534 break;
8535 case AUDIO_FORMAT_PCM_16_BIT:
8536 out->format = config->format;
8537 break;
8538 default:
8539 ALOGE("%s: Unsupported format %#x for Telephony TX", __func__,
8540 config->format);
8541 config->format = AUDIO_FORMAT_PCM_16_BIT;
8542 ret = -EINVAL;
8543 break;
8544 }
8545 if (ret != 0)
8546 goto error_open;
8547
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008548 out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
8549 out->config = pcm_config_afe_proxy_playback;
Aalique Grahame22e49102018-12-18 14:23:57 -08008550 out->config.rate = out->sample_rate;
8551 out->config.channels =
8552 audio_channel_count_from_out_mask(out->channel_mask);
8553 out->config.format = pcm_format_from_audio_format(out->format);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008554 adev->voice_tx_output = out;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008555 } else {
Ashish Jain058165c2016-09-28 23:18:48 +05308556 unsigned int channels = 0;
8557 /*Update config params to default if not set by the caller*/
8558 if (config->sample_rate == 0)
8559 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8560 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8561 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8562 if (config->format == AUDIO_FORMAT_DEFAULT)
8563 config->format = AUDIO_FORMAT_PCM_16_BIT;
8564
8565 channels = audio_channel_count_from_out_mask(out->channel_mask);
8566
Varun Balaraje49253e2017-07-06 19:48:56 +05308567 if (out->flags & AUDIO_OUTPUT_FLAG_INTERACTIVE) {
8568 out->usecase = get_interactive_usecase(adev);
8569 out->config = pcm_config_low_latency;
8570 } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
Ashish Jain83a6cc22016-06-28 14:34:17 +05308571 out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07008572 out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
8573 out->flags);
8574 out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
Haynes Mathew George16081042017-05-31 17:16:49 -07008575 } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8576 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8577 out->config = pcm_config_mmap_playback;
8578 out->stream.start = out_start;
8579 out->stream.stop = out_stop;
8580 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8581 out->stream.get_mmap_position = out_get_mmap_position;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308582 } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8583 out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008584 out->hal_output_suspend_supported =
8585 property_get_bool("vendor.audio.hal.output.suspend.supported", false);
8586 out->dynamic_pm_qos_config_supported =
8587 property_get_bool("vendor.audio.hal.dynamic.qos.config.supported", false);
8588 if (!out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08008589 ALOGI("%s: dynamic qos voting not enabled for platform", __func__);
8590 } else {
8591 ALOGI("%s: dynamic qos voting enabled for platform", __func__);
8592 //the mixer path will be a string similar to "low-latency-playback resume"
8593 strlcpy(out->pm_qos_mixer_path, use_case_table[out->usecase], MAX_MIXER_PATH_LEN);
8594 strlcat(out->pm_qos_mixer_path,
8595 " resume", MAX_MIXER_PATH_LEN);
8596 ALOGI("%s: created %s pm_qos_mixer_path" , __func__,
8597 out->pm_qos_mixer_path);
8598 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308599 out->config = pcm_config_low_latency;
8600 } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
8601 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
8602 out->config = pcm_config_deep_buffer;
Ashish Jain058165c2016-09-28 23:18:48 +05308603 out->config.period_size = get_output_period_size(config->sample_rate, out->format,
8604 channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
8605 if (out->config.period_size <= 0) {
8606 ALOGE("Invalid configuration period size is not valid");
8607 ret = -EINVAL;
8608 goto error_open;
8609 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008610 } else if (flags & AUDIO_OUTPUT_FLAG_TTS) {
8611 out->usecase = USECASE_AUDIO_PLAYBACK_TTS;
8612 out->config = pcm_config_deep_buffer;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008613 } else if (config->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL) {
8614 out->usecase = USECASE_AUDIO_PLAYBACK_WITH_HAPTICS;
8615 out->config = pcm_config_haptics_audio;
8616 if (force_haptic_path)
8617 adev->haptics_config = pcm_config_haptics_audio;
8618 else
8619 adev->haptics_config = pcm_config_haptics;
8620
Meng Wangd08ce322020-04-02 08:59:20 +08008621 channels =
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008622 audio_channel_count_from_out_mask(out->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL);
8623
8624 if (force_haptic_path) {
8625 out->config.channels = 1;
8626 adev->haptics_config.channels = 1;
8627 } else
8628 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 -08008629 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008630 ret = audio_extn_auto_hal_open_output_stream(out);
8631 if (ret) {
8632 ALOGE("%s: Failed to open output stream for bus device", __func__);
8633 ret = -EINVAL;
8634 goto error_open;
8635 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308636 } else {
8637 /* primary path is the default path selected if no other outputs are available/suitable */
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008638 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8639 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308640 }
8641 out->hal_ip_format = format = out->format;
8642 out->config.format = hal_format_to_pcm(out->hal_ip_format);
8643 out->hal_op_format = pcm_format_to_hal(out->config.format);
8644 out->bit_width = format_to_bitwidth_table[out->hal_op_format] << 3;
8645 out->config.rate = config->sample_rate;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008646 out->sample_rate = out->config.rate;
Ashish Jain058165c2016-09-28 23:18:48 +05308647 out->config.channels = channels;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308648 if (out->hal_ip_format != out->hal_op_format) {
8649 uint32_t buffer_size = out->config.period_size *
8650 format_to_bitwidth_table[out->hal_op_format] *
8651 out->config.channels;
8652 out->convert_buffer = calloc(1, buffer_size);
8653 if (out->convert_buffer == NULL){
8654 ALOGE("Allocation failed for convert buffer for size %d",
8655 out->compr_config.fragment_size);
8656 ret = -ENOMEM;
8657 goto error_open;
8658 }
8659 ALOGD("Convert buffer allocated of size %d", buffer_size);
8660 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008661 }
8662
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008663 ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags: %x usecase %d",
8664 __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags, out->usecase);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308665
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008666 /* TODO remove this hardcoding and check why width is zero*/
8667 if (out->bit_width == 0)
8668 out->bit_width = 16;
Dhananjay Kumard6d32152016-10-13 16:11:03 +05308669 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008670 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008671 &out->device_list, out->flags,
8672 out->hal_op_format, out->sample_rate,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05308673 out->bit_width, out->channel_mask, out->profile,
Manish Dewangan837dc462015-05-27 10:17:41 +05308674 &out->app_type_cfg);
Aalique Grahame6e763712019-01-31 16:18:17 -08008675 if ((out->usecase == (audio_usecase_t)(GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary))) ||
Haynes Mathew Georgebf143712013-12-03 13:02:53 -08008676 (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
8677 /* Ensure the default output is not selected twice */
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008678 if(adev->primary_output == NULL)
8679 adev->primary_output = out;
8680 else {
8681 ALOGE("%s: Primary output is already opened", __func__);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008682 ret = -EEXIST;
8683 goto error_open;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008684 }
8685 }
8686
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008687 /* Check if this usecase is already existing */
8688 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella7ce05352014-04-17 20:00:41 -07008689 if ((get_usecase_from_list(adev, out->usecase) != NULL) &&
8690 (out->usecase != USECASE_COMPRESS_VOIP_CALL)) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008691 ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008692 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008693 ret = -EEXIST;
8694 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008695 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008696
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008697 pthread_mutex_unlock(&adev->lock);
8698
8699 out->stream.common.get_sample_rate = out_get_sample_rate;
8700 out->stream.common.set_sample_rate = out_set_sample_rate;
8701 out->stream.common.get_buffer_size = out_get_buffer_size;
8702 out->stream.common.get_channels = out_get_channels;
8703 out->stream.common.get_format = out_get_format;
8704 out->stream.common.set_format = out_set_format;
8705 out->stream.common.standby = out_standby;
8706 out->stream.common.dump = out_dump;
8707 out->stream.common.set_parameters = out_set_parameters;
8708 out->stream.common.get_parameters = out_get_parameters;
8709 out->stream.common.add_audio_effect = out_add_audio_effect;
8710 out->stream.common.remove_audio_effect = out_remove_audio_effect;
8711 out->stream.get_latency = out_get_latency;
8712 out->stream.set_volume = out_set_volume;
Aalique Grahame22e49102018-12-18 14:23:57 -08008713#ifdef NO_AUDIO_OUT
8714 out->stream.write = out_write_for_no_output;
8715#else
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008716 out->stream.write = out_write;
Aalique Grahame22e49102018-12-18 14:23:57 -08008717#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008718 out->stream.get_render_position = out_get_render_position;
8719 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008720 out->stream.get_presentation_position = out_get_presentation_position;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008721
Haynes Mathew George16081042017-05-31 17:16:49 -07008722 if (out->realtime)
8723 out->af_period_multiplier = af_period_multiplier;
8724 else
8725 out->af_period_multiplier = 1;
8726
Andy Hunga1f48fa2019-07-01 18:14:53 -07008727 out->kernel_buffer_size = out->config.period_size * out->config.period_count;
8728
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008729 out->standby = 1;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008730 out->volume_l = PLAYBACK_GAIN_MAX;
8731 out->volume_r = PLAYBACK_GAIN_MAX;
Eric Laurenta9024de2013-04-04 09:19:12 -07008732 /* out->muted = false; by calloc() */
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008733 /* out->written = 0; by calloc() */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008734
8735 config->format = out->stream.common.get_format(&out->stream.common);
8736 config->channel_mask = out->stream.common.get_channels(&out->stream.common);
8737 config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
Naresh Tanniru04f71882018-06-26 17:46:22 +05308738 register_format(out->format, out->supported_formats);
8739 register_channel_mask(out->channel_mask, out->supported_channel_masks);
8740 register_sample_rate(out->sample_rate, out->supported_sample_rates);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008741
Dechen Chai22768452021-07-30 09:29:16 +05308742#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08008743 out->error_log = error_log_create(
8744 ERROR_LOG_ENTRIES,
8745 1000000000 /* aggregate consecutive identical errors within one second in ns */);
Dechen Chai22768452021-07-30 09:29:16 +05308746#endif
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308747 /*
8748 By locking output stream before registering, we allow the callback
8749 to update stream's state only after stream's initial state is set to
8750 adev state.
8751 */
8752 lock_output_stream(out);
8753 audio_extn_snd_mon_register_listener(out, out_snd_mon_cb);
8754 pthread_mutex_lock(&adev->lock);
8755 out->card_status = adev->card_status;
8756 pthread_mutex_unlock(&adev->lock);
8757 pthread_mutex_unlock(&out->lock);
8758
Aalique Grahame22e49102018-12-18 14:23:57 -08008759 stream_app_type_cfg_init(&out->app_type_cfg);
8760
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008761 *stream_out = &out->stream;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308762 ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
vivek mehta0ea887a2015-08-26 14:01:20 -07008763 use_case_table[out->usecase]);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008764
8765 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
8766 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
8767 popcount(out->channel_mask), out->playback_started);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008768 /* setup a channel for client <--> adsp communication for stream events */
Manish Dewangan21a850a2017-08-14 12:03:55 +05308769 is_direct_passthough = audio_extn_passthru_is_direct_passthrough(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008770 if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Naresh Tanniru85819452017-05-04 18:55:45 -07008771 (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) ||
Gangadhar Sb0210342019-02-22 17:39:41 +05308772 audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform) ||
8773 (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false))) {
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008774 hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
8775 out->usecase, PCM_PLAYBACK);
8776 hdlr_stream_cfg.flags = out->flags;
8777 hdlr_stream_cfg.type = PCM_PLAYBACK;
8778 ret = audio_extn_adsp_hdlr_stream_open(&out->adsp_hdlr_stream_handle,
8779 &hdlr_stream_cfg);
8780 if (ret) {
8781 ALOGE("%s: adsp_hdlr_stream_open failed %d",__func__, ret);
8782 out->adsp_hdlr_stream_handle = NULL;
8783 }
8784 }
Gangadhar Sb0210342019-02-22 17:39:41 +05308785 ip_hdlr_stream = audio_extn_ip_hdlr_intf_supported(config->format,
8786 is_direct_passthough, false);
8787 ip_hdlr_dev = audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform);
8788 if (ip_hdlr_stream || ip_hdlr_dev ) {
Vidyakumar Athota2062f912017-06-27 14:46:15 -07008789 ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL, adev, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07008790 if (ret < 0) {
8791 ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d",__func__, ret);
8792 out->ip_hdlr_handle = NULL;
8793 }
8794 }
Derek Chenf939fb72018-11-13 13:34:41 -08008795
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07008796 ret = io_streams_map_insert(adev, &out->stream.common,
8797 out->handle, AUDIO_PATCH_HANDLE_NONE);
8798 if (ret != 0)
8799 goto error_open;
8800
Susan Wang6dd13092021-01-25 10:27:11 -05008801 out->out_ctxt.output = out;
Derek Chenf939fb72018-11-13 13:34:41 -08008802
8803 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -05008804 list_add_tail(&adev->active_outputs_list, &out->out_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -08008805 pthread_mutex_unlock(&adev->lock);
8806
Eric Laurent994a6932013-07-17 11:51:42 -07008807 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008808 return 0;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008809
8810error_open:
Ashish Jain83a6cc22016-06-28 14:34:17 +05308811 if (out->convert_buffer)
8812 free(out->convert_buffer);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008813 free(out);
8814 *stream_out = NULL;
8815 ALOGD("%s: exit: ret %d", __func__, ret);
8816 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008817}
8818
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05308819void adev_close_output_stream(struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008820 struct audio_stream_out *stream)
8821{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008822 struct stream_out *out = (struct stream_out *)stream;
8823 struct audio_device *adev = out->dev;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008824 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008825
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008826 ALOGD("%s: enter:stream_handle(%s)",__func__, use_case_table[out->usecase]);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308827
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07008828 io_streams_map_remove(adev, out->handle);
8829
Susan Wang6dd13092021-01-25 10:27:11 -05008830 // remove out_ctxt early to prevent the stream
8831 // being opened in a race condition
8832 pthread_mutex_lock(&adev->lock);
8833 list_remove(&out->out_ctxt.list);
8834 pthread_mutex_unlock(&adev->lock);
8835
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308836 // must deregister from sndmonitor first to prevent races
8837 // between the callback and close_stream
8838 audio_extn_snd_mon_unregister_listener(out);
8839
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008840 /* close adsp hdrl session before standby */
8841 if (out->adsp_hdlr_stream_handle) {
8842 ret = audio_extn_adsp_hdlr_stream_close(out->adsp_hdlr_stream_handle);
8843 if (ret)
8844 ALOGE("%s: adsp_hdlr_stream_close failed %d",__func__, ret);
8845 out->adsp_hdlr_stream_handle = NULL;
8846 }
8847
Manish Dewangan21a850a2017-08-14 12:03:55 +05308848 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07008849 audio_extn_ip_hdlr_intf_deinit(out->ip_hdlr_handle);
8850 out->ip_hdlr_handle = NULL;
8851 }
8852
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008853 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05308854 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008855 ret = voice_extn_compress_voip_close_output_stream(&stream->common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308856 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05308857 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008858 if(ret != 0)
8859 ALOGE("%s: Compress voip output cannot be closed, error:%d",
8860 __func__, ret);
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008861 } else
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008862 out_standby(&stream->common);
8863
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07008864 if (is_offload_usecase(out->usecase)) {
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008865 audio_extn_dts_remove_state_notifier_node(out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008866 destroy_offload_callback_thread(out);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07008867 free_offload_usecase(adev, out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008868 if (out->compr_config.codec != NULL)
8869 free(out->compr_config.codec);
8870 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008871
Zhou Songbaddf9f2020-11-20 13:57:39 +08008872 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05308873
Varun Balaraje49253e2017-07-06 19:48:56 +05308874 if (is_interactive_usecase(out->usecase))
8875 free_interactive_usecase(adev, out->usecase);
8876
Ashish Jain83a6cc22016-06-28 14:34:17 +05308877 if (out->convert_buffer != NULL) {
8878 free(out->convert_buffer);
8879 out->convert_buffer = NULL;
8880 }
8881
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008882 if (adev->voice_tx_output == out)
8883 adev->voice_tx_output = NULL;
8884
Dechen Chai22768452021-07-30 09:29:16 +05308885#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08008886 error_log_destroy(out->error_log);
8887 out->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +05308888#endif
Dhanalakshmi Siddani6c3d0992017-01-16 16:52:33 +05308889 if (adev->primary_output == out)
8890 adev->primary_output = NULL;
8891
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008892 pthread_cond_destroy(&out->cond);
8893 pthread_mutex_destroy(&out->lock);
Weiyin Jiang280ea742020-09-08 20:28:22 +08008894 pthread_mutex_destroy(&out->pre_lock);
8895 pthread_mutex_destroy(&out->latch_lock);
8896 pthread_mutex_destroy(&out->position_query_lock);
Derek Chenf939fb72018-11-13 13:34:41 -08008897
8898 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008899 free(stream);
Derek Chenf939fb72018-11-13 13:34:41 -08008900 pthread_mutex_unlock(&adev->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07008901 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008902}
8903
8904static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
8905{
8906 struct audio_device *adev = (struct audio_device *)dev;
8907 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008908 char value[32];
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07008909 int val;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008910 int ret;
8911 int status = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08008912 bool a2dp_reconfig = false;
Zhou Songd6d71752019-05-21 18:08:51 +08008913 struct listnode *node;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07008914 int controller = -1, stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008915
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08008916 ALOGD("%s: enter: %s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008917 parms = str_parms_create_str(kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008918
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05308919 if (!parms)
8920 goto error;
Naresh Tanniru4c630392014-05-12 01:05:52 +05308921
Derek Chen6f293672019-04-01 01:40:24 -07008922 /* notify adev and input/output streams on the snd card status */
8923 adev_snd_mon_cb((void *)adev, parms);
8924
Weiyin Jiang24f55292020-12-22 14:35:46 +08008925 ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
8926 if (ret >= 0) {
8927 list_for_each(node, &adev->active_outputs_list) {
8928 streams_output_ctxt_t *out_ctxt = node_to_item(node,
8929 streams_output_ctxt_t,
8930 list);
8931 out_snd_mon_cb((void *)out_ctxt->output, parms);
8932 }
Derek Chen6f293672019-04-01 01:40:24 -07008933
Weiyin Jiang24f55292020-12-22 14:35:46 +08008934 list_for_each(node, &adev->active_inputs_list) {
8935 streams_input_ctxt_t *in_ctxt = node_to_item(node,
8936 streams_input_ctxt_t,
8937 list);
8938 in_snd_mon_cb((void *)in_ctxt->input, parms);
8939 }
Derek Chen6f293672019-04-01 01:40:24 -07008940 }
8941
Zhou Songd6d71752019-05-21 18:08:51 +08008942 pthread_mutex_lock(&adev->lock);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308943 ret = str_parms_get_str(parms, "BT_SCO", value, sizeof(value));
8944 if (ret >= 0) {
8945 /* When set to false, HAL should disable EC and NS */
Zhou Songd6d71752019-05-21 18:08:51 +08008946 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0){
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308947 adev->bt_sco_on = true;
Shalini Manjunatha3a2e06e2021-02-01 12:23:49 +05308948 /*
8949 * When ever BT_SCO=ON arrives, make sure to route
8950 * all use cases to SCO device, otherwise due to delay in
8951 * BT_SCO=ON and lack of synchronization with create audio patch
8952 * request for SCO device, some times use case not routed properly to
8953 * SCO device
8954 */
8955 struct audio_usecase *usecase;
8956 struct listnode *node;
8957 list_for_each(node, &adev->usecase_list) {
8958 usecase = node_to_item(node, struct audio_usecase, list);
Anver sadhiquef0efca32021-09-03 15:25:44 +05308959 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05308960 (!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 +05308961 ALOGD("BT_SCO ON, switch all in use case to it");
8962 select_devices(adev, usecase->id);
8963 }
Mingshu Pangef517202021-04-22 10:35:00 +08008964 if (usecase->stream.out && (usecase->type == PCM_PLAYBACK ||
8965 usecase->type == VOICE_CALL) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05308966 (!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 +05308967 ALOGD("BT_SCO ON, switch all out use case to it");
8968 select_devices(adev, usecase->id);
8969 }
8970 }
8971 }
8972 else {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308973 adev->bt_sco_on = false;
Zhou Songd6d71752019-05-21 18:08:51 +08008974 audio_extn_sco_reset_configuration();
Kunlei Zhangd96af8f2019-08-27 16:33:29 +08008975 }
8976 }
8977
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008978 status = voice_set_parameters(adev, parms);
8979 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08008980 goto done;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008981
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008982 status = platform_set_parameters(adev->platform, parms);
8983 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08008984 goto done;
8985
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008986 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
8987 if (ret >= 0) {
Vicky Sehrawate240e5d2014-08-12 17:17:04 -07008988 /* When set to false, HAL should disable EC and NS */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008989 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
8990 adev->bluetooth_nrec = true;
8991 else
8992 adev->bluetooth_nrec = false;
8993 }
8994
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008995 ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
8996 if (ret >= 0) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008997 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
8998 adev->screen_off = false;
8999 else
9000 adev->screen_off = true;
Quinn Male70f20f32019-06-26 16:50:26 -07009001 audio_extn_sound_trigger_update_screen_status(adev->screen_off);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009002 }
9003
Eric Laurent4b084132018-10-19 17:33:43 -07009004 ret = str_parms_get_int(parms, "rotation", &val);
9005 if (ret >= 0) {
9006 bool reverse_speakers = false;
9007 int camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9008 switch (val) {
9009 // FIXME: note that the code below assumes that the speakers are in the correct placement
9010 // relative to the user when the device is rotated 90deg from its default rotation. This
9011 // assumption is device-specific, not platform-specific like this code.
9012 case 270:
9013 reverse_speakers = true;
9014 camera_rotation = CAMERA_ROTATION_INVERT_LANDSCAPE;
9015 break;
9016 case 0:
9017 case 180:
9018 camera_rotation = CAMERA_ROTATION_PORTRAIT;
9019 break;
9020 case 90:
9021 camera_rotation = CAMERA_ROTATION_LANDSCAPE;
9022 break;
9023 default:
9024 ALOGE("%s: unexpected rotation of %d", __func__, val);
9025 status = -EINVAL;
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009026 }
Eric Laurent4b084132018-10-19 17:33:43 -07009027 if (status == 0) {
9028 // check and set swap
9029 // - check if orientation changed and speaker active
9030 // - set rotation and cache the rotation value
9031 adev->camera_orientation =
9032 (adev->camera_orientation & ~CAMERA_ROTATION_MASK) | camera_rotation;
9033 if (!audio_extn_is_maxx_audio_enabled())
9034 platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
9035 }
9036 }
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07009037
Mingming Yin514a8bc2014-07-29 15:22:21 -07009038 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
9039 if (ret >= 0) {
9040 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
9041 adev->bt_wb_speech_enabled = true;
9042 else
9043 adev->bt_wb_speech_enabled = false;
9044 }
9045
Zhou Song12c29502019-03-16 10:37:18 +08009046 ret = str_parms_get_str(parms, "bt_swb", value, sizeof(value));
9047 if (ret >= 0) {
9048 val = atoi(value);
9049 adev->swb_speech_mode = val;
9050 }
9051
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009052 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
9053 if (ret >= 0) {
9054 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309055 audio_devices_t device = (audio_devices_t) val;
Zhou Song681350a2017-10-19 16:28:42 +08009056 if (audio_is_output_device(val) &&
9057 (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009058 ALOGV("cache new ext disp type and edid");
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009059 platform_get_controller_stream_from_params(parms, &controller, &stream);
9060 platform_set_ext_display_device_v2(adev->platform, controller, stream);
9061 ret = platform_get_ext_disp_type_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009062 if (ret < 0) {
9063 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Manisha Agarwal2f5ff882018-08-08 17:09:29 +05309064 } else {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009065 platform_cache_edid_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009066 }
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309067 } else if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
vivek mehta344576a2016-04-12 18:56:03 -07009068 /*
9069 * Do not allow AFE proxy port usage by WFD source when USB headset is connected.
9070 * Per AudioPolicyManager, USB device is higher priority than WFD.
9071 * For Voice call over USB headset, voice call audio is routed to AFE proxy ports.
9072 * If WFD use case occupies AFE proxy, it may result unintended behavior while
9073 * starting voice call on USB
9074 */
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009075 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309076 if (ret >= 0)
9077 audio_extn_usb_add_device(device, atoi(value));
9078
Zhou Song6f862822017-11-06 17:27:57 +08009079 if (!audio_extn_usb_is_tunnel_supported()) {
9080 ALOGV("detected USB connect .. disable proxy");
9081 adev->allow_afe_proxy_usage = false;
9082 }
Zhou Song503196b2021-07-23 17:31:05 +08009083 } else if (audio_is_hearing_aid_out_device(device) &&
9084 property_get_bool("persist.vendor.audio.ha_proxy.enabled", false)) {
9085 adev->ha_proxy_enable = true;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009086 }
9087 }
9088
9089 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
9090 if (ret >= 0) {
9091 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309092 audio_devices_t device = (audio_devices_t) val;
Garmond Leunge3b6d482016-10-25 16:48:01 -07009093 /*
9094 * The HDMI / Displayport disconnect handling has been moved to
9095 * audio extension to ensure that its parameters are not
9096 * invalidated prior to updating sysfs of the disconnect event
9097 * Invalidate will be handled by audio_extn_ext_disp_set_parameters()
9098 */
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309099 if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009100 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309101 if (ret >= 0)
9102 audio_extn_usb_remove_device(device, atoi(value));
9103
Zhou Song6f862822017-11-06 17:27:57 +08009104 if (!audio_extn_usb_is_tunnel_supported()) {
9105 ALOGV("detected USB disconnect .. enable proxy");
9106 adev->allow_afe_proxy_usage = true;
9107 }
Zhou Song503196b2021-07-23 17:31:05 +08009108 } else if (audio_is_hearing_aid_out_device(device)) {
9109 adev->ha_proxy_enable = false;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009110 }
9111 }
9112
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009113 audio_extn_qdsp_set_parameters(adev, parms);
Aalique Grahame22e49102018-12-18 14:23:57 -08009114
9115 status = audio_extn_a2dp_set_parameters(parms, &a2dp_reconfig);
Aniket Kumar Lata23300322019-02-20 22:25:30 -08009116 if (status >= 0 && a2dp_reconfig) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309117 struct audio_usecase *usecase;
9118 struct listnode *node;
9119 list_for_each(node, &adev->usecase_list) {
9120 usecase = node_to_item(node, struct audio_usecase, list);
Weiyin Jiangff56ff32020-05-08 14:32:21 +08009121 if ((usecase->stream.out == NULL) || (usecase->type != PCM_PLAYBACK))
9122 continue;
9123
9124 if (is_a2dp_out_device_type(&usecase->device_list)) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309125 ALOGD("reconfigure a2dp... forcing device switch");
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309126 audio_extn_a2dp_set_handoff_mode(true);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309127 ALOGD("Switching to speaker and muting the stream before select_devices");
9128 check_a2dp_restore_l(adev, usecase->stream.out, false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309129 //force device switch to re configure encoder
9130 select_devices(adev, usecase->id);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309131 ALOGD("Unmuting the stream after select_devices");
Zhou Songbaddf9f2020-11-20 13:57:39 +08009132 check_a2dp_restore_l(adev, usecase->stream.out, true);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309133 audio_extn_a2dp_set_handoff_mode(false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309134 break;
Zhou Songd01e7a22020-09-23 22:49:01 +08009135 } else if (is_offload_usecase(usecase->stream.out->usecase)) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009136 pthread_mutex_lock(&usecase->stream.out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08009137 if (usecase->stream.out->a2dp_muted) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009138 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
9139 reassign_device_list(&usecase->stream.out->device_list,
9140 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
9141 check_a2dp_restore_l(adev, usecase->stream.out, true);
9142 break;
9143 }
9144 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309145 }
9146 }
9147 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009148
9149 //handle vr audio setparam
9150 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9151 value, sizeof(value));
9152 if (ret >= 0) {
9153 ALOGI("Setting vr mode to be %s", value);
9154 if (!strncmp(value, "true", 4)) {
9155 adev->vr_audio_mode_enabled = true;
9156 ALOGI("Setting vr mode to true");
9157 } else if (!strncmp(value, "false", 5)) {
9158 adev->vr_audio_mode_enabled = false;
9159 ALOGI("Setting vr mode to false");
9160 } else {
9161 ALOGI("wrong vr mode set");
9162 }
9163 }
9164
Eric Laurent4b084132018-10-19 17:33:43 -07009165 //FIXME: to be replaced by proper video capture properties API
9166 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_CAMERA_FACING, value, sizeof(value));
9167 if (ret >= 0) {
9168 int camera_facing = CAMERA_FACING_BACK;
9169 if (strcmp(value, AUDIO_PARAMETER_VALUE_FRONT) == 0)
9170 camera_facing = CAMERA_FACING_FRONT;
9171 else if (strcmp(value, AUDIO_PARAMETER_VALUE_BACK) == 0)
9172 camera_facing = CAMERA_FACING_BACK;
9173 else {
9174 ALOGW("%s: invalid camera facing value: %s", __func__, value);
9175 goto done;
9176 }
9177 adev->camera_orientation =
9178 (adev->camera_orientation & ~CAMERA_FACING_MASK) | camera_facing;
9179 struct audio_usecase *usecase;
9180 struct listnode *node;
9181 list_for_each(node, &adev->usecase_list) {
9182 usecase = node_to_item(node, struct audio_usecase, list);
9183 struct stream_in *in = usecase->stream.in;
9184 if (usecase->type == PCM_CAPTURE && in != NULL &&
9185 in->source == AUDIO_SOURCE_CAMCORDER && !in->standby) {
9186 select_devices(adev, in->usecase);
9187 }
9188 }
9189 }
9190
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309191 audio_extn_set_parameters(adev, parms);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009192done:
9193 str_parms_destroy(parms);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009194 pthread_mutex_unlock(&adev->lock);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309195error:
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009196 ALOGV("%s: exit with code(%d)", __func__, status);
9197 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009198}
9199
9200static char* adev_get_parameters(const struct audio_hw_device *dev,
9201 const char *keys)
9202{
Sidipotu Ashokaa4fa6a2018-12-21 09:19:26 +05309203 ALOGD("%s:%s", __func__, keys);
9204
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009205 struct audio_device *adev = (struct audio_device *)dev;
9206 struct str_parms *reply = str_parms_create();
9207 struct str_parms *query = str_parms_create_str(keys);
9208 char *str;
Naresh Tannirud7205b62014-06-20 02:54:48 +05309209 char value[256] = {0};
9210 int ret = 0;
9211
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009212 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08009213 if (reply) {
9214 str_parms_destroy(reply);
9215 }
9216 if (query) {
9217 str_parms_destroy(query);
9218 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009219 ALOGE("adev_get_parameters: failed to create query or reply");
9220 return NULL;
9221 }
9222
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009223 //handle vr audio getparam
9224
9225 ret = str_parms_get_str(query,
9226 AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9227 value, sizeof(value));
9228
9229 if (ret >= 0) {
9230 bool vr_audio_enabled = false;
9231 pthread_mutex_lock(&adev->lock);
9232 vr_audio_enabled = adev->vr_audio_mode_enabled;
9233 pthread_mutex_unlock(&adev->lock);
9234
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009235 ALOGV("getting vr mode to %d", vr_audio_enabled);
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009236
9237 if (vr_audio_enabled) {
9238 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9239 "true");
9240 goto exit;
9241 } else {
9242 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9243 "false");
9244 goto exit;
9245 }
9246 }
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009247
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009248 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009249 audio_extn_get_parameters(adev, query, reply);
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -08009250 voice_get_parameters(adev, query, reply);
Aalique Grahame22e49102018-12-18 14:23:57 -08009251 audio_extn_a2dp_get_parameters(query, reply);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009252 platform_get_parameters(adev->platform, query, reply);
justinwengd5395152019-11-04 12:23:09 +08009253 audio_extn_ma_get_parameters(adev, query, reply);
Naresh Tanniru80659832014-06-04 18:17:56 +05309254 pthread_mutex_unlock(&adev->lock);
9255
Naresh Tannirud7205b62014-06-20 02:54:48 +05309256exit:
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009257 str = str_parms_to_str(reply);
9258 str_parms_destroy(query);
9259 str_parms_destroy(reply);
9260
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009261 ALOGV("%s: exit: returns - %s", __func__, str);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009262 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009263}
9264
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009265static int adev_init_check(const struct audio_hw_device *dev __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009266{
9267 return 0;
9268}
9269
9270static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
9271{
Haynes Mathew George5191a852013-09-11 14:19:36 -07009272 int ret;
9273 struct audio_device *adev = (struct audio_device *)dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08009274
9275 audio_extn_extspk_set_voice_vol(adev->extspk, volume);
9276
Haynes Mathew George5191a852013-09-11 14:19:36 -07009277 pthread_mutex_lock(&adev->lock);
9278 /* cache volume */
Shruthi Krishnaace10852013-10-25 14:32:12 -07009279 ret = voice_set_volume(adev, volume);
Haynes Mathew George5191a852013-09-11 14:19:36 -07009280 pthread_mutex_unlock(&adev->lock);
9281 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009282}
9283
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009284static int adev_set_master_volume(struct audio_hw_device *dev __unused,
9285 float volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009286{
9287 return -ENOSYS;
9288}
9289
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009290static int adev_get_master_volume(struct audio_hw_device *dev __unused,
9291 float *volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009292{
9293 return -ENOSYS;
9294}
9295
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009296static int adev_set_master_mute(struct audio_hw_device *dev __unused,
9297 bool muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009298{
9299 return -ENOSYS;
9300}
9301
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009302static int adev_get_master_mute(struct audio_hw_device *dev __unused,
9303 bool *muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009304{
9305 return -ENOSYS;
9306}
9307
9308static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
9309{
9310 struct audio_device *adev = (struct audio_device *)dev;
Garmond Leung5fd0b552018-04-17 11:56:12 -07009311 struct listnode *node;
9312 struct audio_usecase *usecase = NULL;
9313 int ret = 0;
kunleizdc4af9d2017-05-04 12:15:35 +08009314
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009315 pthread_mutex_lock(&adev->lock);
9316 if (adev->mode != mode) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309317 ALOGD("%s: mode %d , prev_mode %d \n", __func__, mode , adev->mode);
9318 adev->prev_mode = adev->mode; /* prev_mode is kept to handle voip concurrency*/
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009319 adev->mode = mode;
Weiyin Jiang96b96f72020-09-22 16:48:19 +08009320 if (mode == AUDIO_MODE_CALL_SCREEN) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309321 adev->current_call_output = adev->primary_output;
9322 voice_start_call(adev);
9323 } else if (voice_is_in_call_or_call_screen(adev) &&
Kunlei Zhang1d5c7f22019-05-21 14:25:57 +08009324 (mode == AUDIO_MODE_NORMAL ||
9325 (mode == AUDIO_MODE_IN_COMMUNICATION && !voice_is_call_state_active(adev)))) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07009326 list_for_each(node, &adev->usecase_list) {
9327 usecase = node_to_item(node, struct audio_usecase, list);
9328 if (usecase->type == VOICE_CALL)
9329 break;
9330 }
9331 if (usecase &&
9332 audio_is_usb_out_device(usecase->out_snd_device & AUDIO_DEVICE_OUT_ALL_USB)) {
9333 ret = audio_extn_usb_check_and_set_svc_int(usecase,
9334 true);
9335 if (ret != 0) {
9336 /* default service interval was successfully updated,
9337 reopen USB backend with new service interval */
9338 check_usecases_codec_backend(adev,
9339 usecase,
9340 usecase->out_snd_device);
9341 }
9342 }
9343
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009344 voice_stop_call(adev);
Banajit Goswami20cdd212015-09-11 01:11:30 -07009345 platform_set_gsm_mode(adev->platform, false);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009346 adev->current_call_output = NULL;
kunleizdc4af9d2017-05-04 12:15:35 +08009347 // restore device for other active usecases after stop call
9348 list_for_each(node, &adev->usecase_list) {
9349 usecase = node_to_item(node, struct audio_usecase, list);
9350 select_devices(adev, usecase->id);
9351 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009352 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009353 }
9354 pthread_mutex_unlock(&adev->lock);
9355 return 0;
9356}
9357
9358static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
9359{
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009360 int ret;
Aalique Grahame22e49102018-12-18 14:23:57 -08009361 struct audio_device *adev = (struct audio_device *)dev;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009362
9363 pthread_mutex_lock(&adev->lock);
Vidyakumar Athota2850d532013-11-19 16:02:12 -08009364 ALOGD("%s state %d\n", __func__, state);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009365 ret = voice_set_mic_mute((struct audio_device *)dev, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009366
Derek Chend2530072014-11-24 12:39:14 -08009367 if (adev->ext_hw_plugin)
9368 ret = audio_extn_ext_hw_plugin_set_mic_mute(adev->ext_hw_plugin, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009369
9370 adev->mic_muted = state;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009371 pthread_mutex_unlock(&adev->lock);
9372
9373 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009374}
9375
9376static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
9377{
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009378 *state = voice_get_mic_mute((struct audio_device *)dev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009379 return 0;
9380}
9381
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009382static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009383 const struct audio_config *config)
9384{
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009385 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009386
Aalique Grahame22e49102018-12-18 14:23:57 -08009387 /* Don't know if USB HIFI in this context so use true to be conservative */
9388 if (check_input_parameters(config->sample_rate, config->format, channel_count,
9389 true /*is_usb_hifi */) != 0)
9390 return 0;
9391
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009392 return get_input_buffer_size(config->sample_rate, config->format, channel_count,
9393 false /* is_low_latency: since we don't know, be conservative */);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009394}
9395
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009396static bool adev_input_allow_hifi_record(struct audio_device *adev,
9397 audio_devices_t devices,
9398 audio_input_flags_t flags,
9399 audio_source_t source) {
9400 const bool allowed = true;
9401
9402 if (!audio_is_usb_in_device(devices))
9403 return !allowed;
9404
9405 switch (flags) {
9406 case AUDIO_INPUT_FLAG_NONE:
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009407 break;
Haynes Mathew George59862182017-10-24 16:23:57 -07009408 case AUDIO_INPUT_FLAG_FAST: // disallow hifi record for FAST as
9409 // it affects RTD numbers over USB
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009410 default:
9411 return !allowed;
9412 }
9413
9414 switch (source) {
9415 case AUDIO_SOURCE_DEFAULT:
9416 case AUDIO_SOURCE_MIC:
9417 case AUDIO_SOURCE_UNPROCESSED:
9418 break;
9419 default:
9420 return !allowed;
9421 }
9422
9423 switch (adev->mode) {
9424 case 0:
9425 break;
9426 default:
9427 return !allowed;
9428 }
9429
9430 return allowed;
9431}
9432
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009433static int adev_update_voice_comm_input_stream(struct stream_in *in,
9434 struct audio_config *config)
9435{
9436 bool valid_rate = (config->sample_rate == 8000 ||
9437 config->sample_rate == 16000 ||
9438 config->sample_rate == 32000 ||
9439 config->sample_rate == 48000);
9440 bool valid_ch = audio_channel_count_from_in_mask(in->channel_mask) == 1;
9441
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009442 if(!voice_extn_is_compress_voip_supported()) {
kunleiz28c73e72019-03-27 17:24:04 +08009443 if (valid_rate && valid_ch) {
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009444 in->usecase = USECASE_AUDIO_RECORD_VOIP;
9445 in->config = default_pcm_config_voip_copp;
9446 in->config.period_size = VOIP_IO_BUF_SIZE(in->sample_rate,
9447 DEFAULT_VOIP_BUF_DURATION_MS,
9448 DEFAULT_VOIP_BIT_DEPTH_BYTE)/2;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009449 } else {
9450 ALOGW("%s No valid input in voip, use defaults"
9451 "sample rate %u, channel mask 0x%X",
9452 __func__, config->sample_rate, in->channel_mask);
9453 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009454 in->config.rate = config->sample_rate;
9455 in->sample_rate = config->sample_rate;
9456 } else {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009457 //XXX needed for voice_extn_compress_voip_open_input_stream
9458 in->config.rate = config->sample_rate;
9459 if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
Shalini Manjunathaa763cc42019-08-23 15:13:46 +05309460 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009461 voice_extn_compress_voip_is_active(in->dev)) &&
9462 (voice_extn_compress_voip_is_format_supported(in->format)) &&
9463 valid_rate && valid_ch) {
9464 voice_extn_compress_voip_open_input_stream(in);
9465 // update rate entries to match config from AF
9466 in->config.rate = config->sample_rate;
9467 in->sample_rate = config->sample_rate;
9468 } else {
9469 ALOGW("%s compress voip not active, use defaults", __func__);
9470 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009471 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009472 return 0;
9473}
9474
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009475static int adev_open_input_stream(struct audio_hw_device *dev,
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07009476 audio_io_handle_t handle,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009477 audio_devices_t devices,
9478 struct audio_config *config,
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009479 struct audio_stream_in **stream_in,
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309480 audio_input_flags_t flags,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009481 const char *address,
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009482 audio_source_t source)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009483{
9484 struct audio_device *adev = (struct audio_device *)dev;
9485 struct stream_in *in;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08009486 int ret = 0, buffer_size, frame_size;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009487 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009488 bool is_low_latency = false;
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +05309489 bool channel_mask_updated = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009490 bool is_usb_dev = audio_is_usb_in_device(devices);
9491 bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
9492 devices,
9493 flags,
9494 source);
Andy Hung94320602018-10-29 18:31:12 -07009495 ALOGV("%s: enter: flags %#x, is_usb_dev %d, may_use_hifi_record %d,"
9496 " sample_rate %u, channel_mask %#x, format %#x",
9497 __func__, flags, is_usb_dev, may_use_hifi_record,
9498 config->sample_rate, config->channel_mask, config->format);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309499
kunleizdff872d2018-08-20 14:40:33 +08009500 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08009501 is_usb_dev = false;
9502 devices = AUDIO_DEVICE_IN_BUILTIN_MIC;
9503 ALOGW("%s: ignore set device to non existing USB card, use input device(%#x)",
9504 __func__, devices);
9505 }
9506
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009507 *stream_in = NULL;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009508
9509 if (!(is_usb_dev && may_use_hifi_record)) {
9510 if (config->sample_rate == 0)
9511 config->sample_rate = 48000;
9512 if (config->channel_mask == AUDIO_CHANNEL_NONE)
9513 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9514 if (config->format == AUDIO_FORMAT_DEFAULT)
9515 config->format = AUDIO_FORMAT_PCM_16_BIT;
9516
9517 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
9518
Aalique Grahame22e49102018-12-18 14:23:57 -08009519 if (check_input_parameters(config->sample_rate, config->format, channel_count,
9520 false) != 0)
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009521 return -EINVAL;
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05309522 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009523
9524 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009525
9526 if (!in) {
9527 ALOGE("failed to allocate input stream");
9528 return -ENOMEM;
9529 }
9530
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309531 ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05309532 stream_handle(%p) io_handle(%d) source(%d) format %x",__func__, config->sample_rate,
9533 config->channel_mask, devices, &in->stream, handle, source, config->format);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009534 pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07009535 pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009536
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009537 in->stream.common.get_sample_rate = in_get_sample_rate;
9538 in->stream.common.set_sample_rate = in_set_sample_rate;
9539 in->stream.common.get_buffer_size = in_get_buffer_size;
9540 in->stream.common.get_channels = in_get_channels;
9541 in->stream.common.get_format = in_get_format;
9542 in->stream.common.set_format = in_set_format;
9543 in->stream.common.standby = in_standby;
9544 in->stream.common.dump = in_dump;
9545 in->stream.common.set_parameters = in_set_parameters;
9546 in->stream.common.get_parameters = in_get_parameters;
9547 in->stream.common.add_audio_effect = in_add_audio_effect;
9548 in->stream.common.remove_audio_effect = in_remove_audio_effect;
9549 in->stream.set_gain = in_set_gain;
9550 in->stream.read = in_read;
9551 in->stream.get_input_frames_lost = in_get_input_frames_lost;
Aalique Grahame22e49102018-12-18 14:23:57 -08009552 in->stream.get_capture_position = in_get_capture_position;
Naresh Tannirudcb47c52018-06-25 16:23:32 +05309553 in->stream.get_active_microphones = in_get_active_microphones;
Paul McLeana50b7332018-12-17 08:24:21 -07009554 in->stream.set_microphone_direction = in_set_microphone_direction;
9555 in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
juyuchendb308c22019-01-21 11:57:17 -07009556 in->stream.update_sink_metadata = in_update_sink_metadata;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009557
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009558 list_init(&in->device_list);
9559 update_device_list(&in->device_list, devices, address, true);
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009560 in->source = source;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009561 in->dev = adev;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009562 in->standby = 1;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009563 in->capture_handle = handle;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07009564 in->flags = flags;
Haynes Mathew George46740472017-10-27 18:40:12 -07009565 in->bit_width = 16;
9566 in->af_period_multiplier = 1;
justinweng20fb6d82019-02-21 18:49:00 -07009567 in->direction = MIC_DIRECTION_UNSPECIFIED;
9568 in->zoom = 0;
Carter Hsu2e429db2019-05-14 18:50:52 +08009569 list_init(&in->aec_list);
9570 list_init(&in->ns_list);
Phil Burkd898ba62019-06-20 12:49:01 -07009571 in->mmap_shared_memory_fd = -1; // not open
Haynes Mathew George46740472017-10-27 18:40:12 -07009572
Andy Hung94320602018-10-29 18:31:12 -07009573 ALOGV("%s: source %d, config->channel_mask %#x", __func__, source, config->channel_mask);
Aalique Grahame22e49102018-12-18 14:23:57 -08009574 if (source == AUDIO_SOURCE_VOICE_UPLINK ||
9575 source == AUDIO_SOURCE_VOICE_DOWNLINK) {
9576 /* Force channel config requested to mono if incall
9577 record is being requested for only uplink/downlink */
9578 if (config->channel_mask != AUDIO_CHANNEL_IN_MONO) {
9579 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9580 ret = -EINVAL;
9581 goto err_open;
9582 }
9583 }
9584
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009585 if (is_usb_dev && may_use_hifi_record) {
9586 /* HiFi record selects an appropriate format, channel, rate combo
9587 depending on sink capabilities*/
9588 ret = read_usb_sup_params_and_compare(false /*is_playback*/,
9589 &config->format,
9590 &in->supported_formats[0],
9591 MAX_SUPPORTED_FORMATS,
9592 &config->channel_mask,
9593 &in->supported_channel_masks[0],
9594 MAX_SUPPORTED_CHANNEL_MASKS,
9595 &config->sample_rate,
9596 &in->supported_sample_rates[0],
9597 MAX_SUPPORTED_SAMPLE_RATES);
9598 if (ret != 0) {
9599 ret = -EINVAL;
9600 goto err_open;
9601 }
9602 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009603 } else if (config->format == AUDIO_FORMAT_DEFAULT) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309604 config->format = AUDIO_FORMAT_PCM_16_BIT;
Surendar karkaaca3d082017-11-09 15:18:37 +05309605 } else if (property_get_bool("vendor.audio.capture.pcm.32bit.enable", false)
9606 && config->format == AUDIO_FORMAT_PCM_32_BIT) {
9607 in->config.format = PCM_FORMAT_S32_LE;
9608 in->bit_width = 32;
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309609 } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
9610 (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
9611 (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
9612 (config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
9613 bool ret_error = false;
9614 in->bit_width = 24;
9615 /* 24 bit is restricted to UNPROCESSED source only,also format supported
9616 from HAL is 24_packed and 8_24
9617 *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
9618 24_packed return error indicating supported format is 24_packed
9619 *> In case of any other source requesting 24 bit or float return error
9620 indicating format supported is 16 bit only.
9621
9622 on error flinger will retry with supported format passed
9623 */
9624 if ((source != AUDIO_SOURCE_UNPROCESSED) &&
9625 (source != AUDIO_SOURCE_CAMCORDER)) {
9626 config->format = AUDIO_FORMAT_PCM_16_BIT;
9627 if (config->sample_rate > 48000)
9628 config->sample_rate = 48000;
9629 ret_error = true;
Haynes Mathew George46740472017-10-27 18:40:12 -07009630 } else if (!(config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
9631 config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309632 config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
9633 ret_error = true;
9634 }
9635
9636 if (ret_error) {
9637 ret = -EINVAL;
9638 goto err_open;
9639 }
9640 }
9641
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009642 in->channel_mask = config->channel_mask;
9643 in->format = config->format;
9644
9645 in->usecase = USECASE_AUDIO_RECORD;
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309646
Huicheng Liu1404ba12020-09-11 01:03:25 -04009647 /* validate bus device address */
9648 if (compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUS)) {
9649 /* extract car audio stream index */
9650 in->car_audio_stream =
9651 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
9652 if (in->car_audio_stream < 0) {
9653 ALOGE("%s: invalid car audio stream %x",
9654 __func__, in->car_audio_stream);
9655 ret = -EINVAL;
9656 goto err_open;
9657 }
9658 ALOGV("%s: car_audio_stream 0x%x", __func__, in->car_audio_stream);
Huicheng Liuea4fd422021-01-12 18:34:50 -05009659 ret = audio_extn_auto_hal_open_input_stream(in);
9660 if (ret) {
9661 ALOGE("%s: Failed to open input stream for bus device", __func__);
9662 ret = -EINVAL;
9663 goto err_open;
9664 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04009665 }
9666
Susan Wange3959562021-03-11 11:50:26 -05009667 /* reassign use case for echo reference stream on automotive platforms */
9668 if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) {
9669 ret = audio_extn_auto_hal_open_echo_reference_stream(in);
9670 }
9671
Kogara Naveen Kumar379ff692022-01-31 11:56:51 +05309672 if ((in->source == AUDIO_SOURCE_FM_TUNER) || (devices == AUDIO_DEVICE_IN_FM_TUNER)) {
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309673 if(!get_usecase_from_list(adev, USECASE_AUDIO_RECORD_FM_VIRTUAL))
9674 in->usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
9675 else {
9676 ret = -EINVAL;
9677 goto err_open;
9678 }
9679 }
9680
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009681 if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
Deeraj Somanfa377bf2019-02-06 12:57:59 +05309682 (flags & AUDIO_INPUT_FLAG_TIMESTAMP) == 0 &&
9683 (flags & AUDIO_INPUT_FLAG_COMPRESS) == 0 &&
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009684 (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
9685 is_low_latency = true;
9686#if LOW_LATENCY_CAPTURE_USE_CASE
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05309687 if ((flags & AUDIO_INPUT_FLAG_VOIP_TX) != 0)
9688 in->usecase = USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY;
9689 else
9690 in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009691#endif
9692 in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
Aalique Grahame22e49102018-12-18 14:23:57 -08009693 if (!in->realtime) {
9694 in->config = pcm_config_audio_capture;
9695 frame_size = audio_stream_in_frame_size(&in->stream);
9696 buffer_size = get_input_buffer_size(config->sample_rate,
9697 config->format,
9698 channel_count,
9699 is_low_latency);
9700 in->config.period_size = buffer_size / frame_size;
9701 in->config.rate = config->sample_rate;
9702 in->af_period_multiplier = 1;
9703 } else {
9704 // period size is left untouched for rt mode playback
9705 in->config = pcm_config_audio_capture_rt;
9706 in->af_period_multiplier = af_period_multiplier;
9707 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009708 }
9709
Susan Wangb803cb52021-10-14 12:03:36 -04009710 /* Additional sample rates added below must also be present
9711 in audio_policy_configuration.xml for mmap_no_irq_in */
9712 bool valid_mmap_record_rate = (config->sample_rate == 8000 ||
9713 config->sample_rate == 16000 ||
Susan Wang89da9042021-10-14 12:03:36 -04009714 config->sample_rate == 24000 ||
Susan Wangb803cb52021-10-14 12:03:36 -04009715 config->sample_rate == 32000 ||
9716 config->sample_rate == 48000);
9717 if (valid_mmap_record_rate &&
9718 ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009719 in->realtime = 0;
9720 in->usecase = USECASE_AUDIO_RECORD_MMAP;
9721 in->config = pcm_config_mmap_capture;
Haynes Mathew George46740472017-10-27 18:40:12 -07009722 in->config.format = pcm_format_from_audio_format(config->format);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009723 in->stream.start = in_start;
9724 in->stream.stop = in_stop;
9725 in->stream.create_mmap_buffer = in_create_mmap_buffer;
9726 in->stream.get_mmap_position = in_get_mmap_position;
Ramjee Singhbcb3b6c2021-11-17 13:19:16 +05309727 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009728 ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
Haynes Mathew George46740472017-10-27 18:40:12 -07009729 } else if (is_usb_dev && may_use_hifi_record) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009730 in->usecase = USECASE_AUDIO_RECORD_HIFI;
9731 in->config = pcm_config_audio_capture;
9732 frame_size = audio_stream_in_frame_size(&in->stream);
9733 buffer_size = get_input_buffer_size(config->sample_rate,
9734 config->format,
9735 channel_count,
9736 false /*is_low_latency*/);
9737 in->config.period_size = buffer_size / frame_size;
9738 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009739 in->config.format = pcm_format_from_audio_format(config->format);
Karthikeyan Mani07faa602018-08-20 11:01:32 -07009740 switch (config->format) {
9741 case AUDIO_FORMAT_PCM_32_BIT:
9742 in->bit_width = 32;
9743 break;
9744 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
9745 case AUDIO_FORMAT_PCM_8_24_BIT:
9746 in->bit_width = 24;
9747 break;
9748 default:
9749 in->bit_width = 16;
9750 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009751 } else if (is_single_device_type_equal(&in->device_list,
9752 AUDIO_DEVICE_IN_TELEPHONY_RX) ||
9753 is_single_device_type_equal(&in->device_list,
9754 AUDIO_DEVICE_IN_PROXY)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009755 if (config->sample_rate == 0)
9756 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
9757 if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
9758 config->sample_rate != 8000) {
9759 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
9760 ret = -EINVAL;
9761 goto err_open;
9762 }
9763 if (config->format == AUDIO_FORMAT_DEFAULT)
9764 config->format = AUDIO_FORMAT_PCM_16_BIT;
9765 if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
9766 config->format = AUDIO_FORMAT_PCM_16_BIT;
9767 ret = -EINVAL;
9768 goto err_open;
9769 }
9770
9771 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
Zhou Song62ea0282020-03-22 19:53:01 +08009772 if (adev->ha_proxy_enable &&
9773 is_single_device_type_equal(&in->device_list,
9774 AUDIO_DEVICE_IN_TELEPHONY_RX))
9775 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY2;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009776 in->config = pcm_config_afe_proxy_record;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009777 in->config.rate = config->sample_rate;
Aalique Grahame22e49102018-12-18 14:23:57 -08009778 in->af_period_multiplier = 1;
9779 } else if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
Shalini Manjunathaac412b32020-01-03 15:00:14 +05309780 (!voice_extn_is_compress_voip_supported()) &&
Aalique Grahame22e49102018-12-18 14:23:57 -08009781 in->flags & AUDIO_INPUT_FLAG_VOIP_TX &&
9782 (config->sample_rate == 8000 ||
9783 config->sample_rate == 16000 ||
9784 config->sample_rate == 32000 ||
9785 config->sample_rate == 48000) &&
9786 channel_count == 1) {
9787 in->usecase = USECASE_AUDIO_RECORD_VOIP;
9788 in->config = pcm_config_audio_capture;
9789 frame_size = audio_stream_in_frame_size(&in->stream);
9790 buffer_size = get_stream_buffer_size(VOIP_CAPTURE_PERIOD_DURATION_MSEC,
9791 config->sample_rate,
9792 config->format,
9793 channel_count, false /*is_low_latency*/);
9794 in->config.period_size = buffer_size / frame_size;
9795 in->config.period_count = VOIP_CAPTURE_PERIOD_COUNT;
9796 in->config.rate = config->sample_rate;
9797 in->af_period_multiplier = 1;
Mingshu Pangc2d65042021-01-14 16:19:10 +08009798 } else if (in->realtime) {
9799 in->config = pcm_config_audio_capture_rt;
9800 in->config.format = pcm_format_from_audio_format(config->format);
9801 in->af_period_multiplier = af_period_multiplier;
Haynes Mathew George46740472017-10-27 18:40:12 -07009802 } else {
Revathi Uddarajud2634032017-12-07 14:42:34 +05309803 int ret_val;
9804 pthread_mutex_lock(&adev->lock);
9805 ret_val = audio_extn_check_and_set_multichannel_usecase(adev,
9806 in, config, &channel_mask_updated);
9807 pthread_mutex_unlock(&adev->lock);
9808
9809 if (!ret_val) {
9810 if (channel_mask_updated == true) {
9811 ALOGD("%s: return error to retry with updated channel mask (%#x)",
9812 __func__, config->channel_mask);
9813 ret = -EINVAL;
9814 goto err_open;
9815 }
9816 ALOGD("%s: created multi-channel session succesfully",__func__);
9817 } else if (audio_extn_compr_cap_enabled() &&
9818 audio_extn_compr_cap_format_supported(config->format) &&
9819 (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
9820 audio_extn_compr_cap_init(in);
9821 } else if (audio_extn_cin_applicable_stream(in)) {
Deeraj Soman14230922019-01-30 16:39:30 +05309822 ret = audio_extn_cin_configure_input_stream(in, config);
Revathi Uddarajud2634032017-12-07 14:42:34 +05309823 if (ret)
9824 goto err_open;
9825 } else {
9826 in->config = pcm_config_audio_capture;
9827 in->config.rate = config->sample_rate;
9828 in->config.format = pcm_format_from_audio_format(config->format);
Revathi Uddarajud2634032017-12-07 14:42:34 +05309829 in->format = config->format;
9830 frame_size = audio_stream_in_frame_size(&in->stream);
9831 buffer_size = get_input_buffer_size(config->sample_rate,
Haynes Mathew George46740472017-10-27 18:40:12 -07009832 config->format,
9833 channel_count,
9834 is_low_latency);
Dieter Luecking5d57def2018-09-07 14:23:37 +02009835 /* prevent division-by-zero */
9836 if (frame_size == 0) {
9837 ALOGE("%s: Error frame_size==0", __func__);
9838 ret = -EINVAL;
9839 goto err_open;
9840 }
9841
Revathi Uddarajud2634032017-12-07 14:42:34 +05309842 in->config.period_size = buffer_size / frame_size;
Aalique Grahame22e49102018-12-18 14:23:57 -08009843 in->af_period_multiplier = 1;
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009844
Revathi Uddarajud2634032017-12-07 14:42:34 +05309845 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
9846 /* optionally use VOIP usecase depending on config(s) */
9847 ret = adev_update_voice_comm_input_stream(in, config);
9848 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009849
Revathi Uddarajud2634032017-12-07 14:42:34 +05309850 if (ret) {
9851 ALOGE("%s AUDIO_SOURCE_VOICE_COMMUNICATION invalid args", __func__);
9852 goto err_open;
9853 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009854 }
Jaideep Sharmad305a4a2020-02-27 14:29:04 +05309855
9856 /* assign concurrent capture usecase if record has to caried out from
9857 * actual hardware input source */
9858 if (audio_extn_is_concurrent_capture_enabled() &&
9859 !audio_is_virtual_input_source(in->source)) {
Samyak Jainc37062f2019-04-25 18:41:06 +05309860 /* Acquire lock to avoid two concurrent use cases initialized to
9861 same pcm record use case */
kunleiz28c73e72019-03-27 17:24:04 +08009862
Samyak Jainc37062f2019-04-25 18:41:06 +05309863 if (in->usecase == USECASE_AUDIO_RECORD) {
9864 pthread_mutex_lock(&adev->lock);
9865 if (!(adev->pcm_record_uc_state)) {
9866 ALOGV("%s: using USECASE_AUDIO_RECORD",__func__);
9867 adev->pcm_record_uc_state = 1;
9868 pthread_mutex_unlock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +05309869 } else if (audio_extn_is_concurrent_pcm_record_enabled()) {
9870 in->usecase = get_record_usecase(adev);
9871 pthread_mutex_unlock(&adev->lock);
Samyak Jainc37062f2019-04-25 18:41:06 +05309872 } else {
9873 pthread_mutex_unlock(&adev->lock);
9874 /* Assign compress record use case for second record */
9875 in->usecase = USECASE_AUDIO_RECORD_COMPRESS2;
9876 in->flags |= AUDIO_INPUT_FLAG_COMPRESS;
9877 ALOGV("%s: overriding usecase with USECASE_AUDIO_RECORD_COMPRESS2 and appending compress flag", __func__);
9878 if (audio_extn_cin_applicable_stream(in)) {
9879 in->sample_rate = config->sample_rate;
Deeraj Soman14230922019-01-30 16:39:30 +05309880 ret = audio_extn_cin_configure_input_stream(in, config);
Samyak Jainc37062f2019-04-25 18:41:06 +05309881 if (ret)
9882 goto err_open;
9883 }
9884 }
9885 }
kunleiz28c73e72019-03-27 17:24:04 +08009886 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07009887 }
Ramjee Singh82fd0c12019-08-21 16:31:33 +05309888 if (audio_extn_ssr_get_stream() != in)
9889 in->config.channels = channel_count;
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07009890
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07009891 in->sample_rate = in->config.rate;
9892
Dhananjay Kumard6d32152016-10-13 16:11:03 +05309893 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
9894 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009895 &in->device_list, flags, in->format,
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009896 in->sample_rate, in->bit_width,
9897 in->profile, &in->app_type_cfg);
Naresh Tanniru04f71882018-06-26 17:46:22 +05309898 register_format(in->format, in->supported_formats);
9899 register_channel_mask(in->channel_mask, in->supported_channel_masks);
9900 register_sample_rate(in->sample_rate, in->supported_sample_rates);
Dhananjay Kumard6d32152016-10-13 16:11:03 +05309901
Dechen Chai22768452021-07-30 09:29:16 +05309902#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08009903 in->error_log = error_log_create(
9904 ERROR_LOG_ENTRIES,
9905 1000000000 /* aggregate consecutive identical errors within one second */);
Dechen Chai22768452021-07-30 09:29:16 +05309906#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08009907
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009908 /* This stream could be for sound trigger lab,
9909 get sound trigger pcm if present */
9910 audio_extn_sound_trigger_check_and_get_session(in);
9911
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05309912 lock_input_stream(in);
9913 audio_extn_snd_mon_register_listener(in, in_snd_mon_cb);
9914 pthread_mutex_lock(&adev->lock);
9915 in->card_status = adev->card_status;
9916 pthread_mutex_unlock(&adev->lock);
9917 pthread_mutex_unlock(&in->lock);
9918
Aalique Grahame22e49102018-12-18 14:23:57 -08009919 stream_app_type_cfg_init(&in->app_type_cfg);
9920
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009921 *stream_in = &in->stream;
Derek Chenf939fb72018-11-13 13:34:41 -08009922
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009923 ret = io_streams_map_insert(adev, &in->stream.common,
9924 handle, AUDIO_PATCH_HANDLE_NONE);
9925 if (ret != 0)
9926 goto err_open;
9927
Susan Wang6dd13092021-01-25 10:27:11 -05009928 in->in_ctxt.input = in;
Derek Chenf939fb72018-11-13 13:34:41 -08009929
9930 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -05009931 list_add_tail(&adev->active_inputs_list, &in->in_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -08009932 pthread_mutex_unlock(&adev->lock);
9933
Eric Laurent994a6932013-07-17 11:51:42 -07009934 ALOGV("%s: exit", __func__);
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08009935 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009936
9937err_open:
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +05309938 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
9939 free_record_usecase(adev, in->usecase);
9940 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jainc37062f2019-04-25 18:41:06 +05309941 pthread_mutex_lock(&adev->lock);
9942 adev->pcm_record_uc_state = 0;
9943 pthread_mutex_unlock(&adev->lock);
9944 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009945 free(in);
9946 *stream_in = NULL;
9947 return ret;
9948}
9949
9950static void adev_close_input_stream(struct audio_hw_device *dev,
9951 struct audio_stream_in *stream)
9952{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009953 int ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07009954 struct stream_in *in = (struct stream_in *)stream;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009955 struct audio_device *adev = (struct audio_device *)dev;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309956
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309957 ALOGD("%s: enter:stream_handle(%p)",__func__, in);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08009958
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009959 if (in == NULL) {
9960 ALOGE("%s: audio_stream_in ptr is NULL", __func__);
9961 return;
9962 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009963 io_streams_map_remove(adev, in->capture_handle);
9964
Susan Wang6dd13092021-01-25 10:27:11 -05009965 // remove out_ctxt early to prevent the stream
9966 // being opened in a race condition
9967 pthread_mutex_lock(&adev->lock);
9968 list_remove(&in->in_ctxt.list);
9969 pthread_mutex_unlock(&adev->lock);
9970
kunleiz70e57612018-12-28 17:50:23 +08009971 /* must deregister from sndmonitor first to prevent races
9972 * between the callback and close_stream
9973 */
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05309974 audio_extn_snd_mon_unregister_listener(stream);
9975
kunleiz70e57612018-12-28 17:50:23 +08009976 /* Disable echo reference if there are no active input, hfp call
9977 * and sound trigger while closing input stream
9978 */
Eric Laurent637e2d42018-11-15 12:24:31 -08009979 if (adev_get_active_input(adev) == NULL &&
kunleiz70e57612018-12-28 17:50:23 +08009980 !audio_extn_hfp_is_active(adev) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009981 !audio_extn_sound_trigger_check_ec_ref_enable()) {
9982 struct listnode out_devices;
9983 list_init(&out_devices);
9984 platform_set_echo_reference(adev, false, &out_devices);
9985 } else
kunleiz70e57612018-12-28 17:50:23 +08009986 audio_extn_sound_trigger_update_ec_ref_status(false);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +05309987
Dechen Chai22768452021-07-30 09:29:16 +05309988#ifndef LINUX_ENABLED
Weiyin Jiang2995f662019-04-17 14:25:12 +08009989 error_log_destroy(in->error_log);
9990 in->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +05309991#endif
Pallavid7c7a272018-01-16 11:22:55 +05309992
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009993 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309994 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009995 ret = voice_extn_compress_voip_close_input_stream(&stream->common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309996 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009997 if (ret != 0)
9998 ALOGE("%s: Compress voip input cannot be closed, error:%d",
9999 __func__, ret);
10000 } else
10001 in_standby(&stream->common);
10002
Weiyin Jiang280ea742020-09-08 20:28:22 +080010003 pthread_mutex_destroy(&in->lock);
10004 pthread_mutex_destroy(&in->pre_lock);
10005
Revathi Uddarajud2634032017-12-07 14:42:34 +053010006 pthread_mutex_lock(&adev->lock);
Krishna Kishor Jha0f4d8482022-02-18 10:56:05 +053010007 if (audio_extn_is_concurrent_pcm_record_enabled() && is_pcm_record_usecase(in->usecase)) {
10008 free_record_usecase(adev, in->usecase);
10009 } else if (in->usecase == USECASE_AUDIO_RECORD) {
Samyak Jain15fda662018-12-18 16:40:52 +053010010 adev->pcm_record_uc_state = 0;
10011 }
10012
Kunlei Zhang5d5d8d92020-02-26 15:00:59 +080010013 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
10014 adev->enable_voicerx = false;
10015 }
10016
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -070010017 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -070010018 audio_extn_ssr_deinit();
10019 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010020
Garmond Leunge2433c32017-09-28 21:51:22 -070010021 if (audio_extn_ffv_get_stream() == in) {
10022 audio_extn_ffv_stream_deinit();
10023 }
10024
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010025 if (audio_extn_compr_cap_enabled() &&
Mingming Yine62d7842013-10-25 16:26:03 -070010026 audio_extn_compr_cap_format_supported(in->config.format))
10027 audio_extn_compr_cap_deinit();
Dhanalakshmi Siddani74cf00b2016-12-02 13:55:57 +053010028
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +053010029 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +053010030 audio_extn_cin_free_input_stream_resources(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010031
Mingming Yinfd7607b2016-01-22 12:48:44 -080010032 if (in->is_st_session) {
10033 ALOGV("%s: sound trigger pcm stop lab", __func__);
10034 audio_extn_sound_trigger_stop_lab(in);
10035 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010036 free(stream);
Revathi Uddarajud2634032017-12-07 14:42:34 +053010037 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010038 return;
10039}
10040
Aalique Grahame22e49102018-12-18 14:23:57 -080010041/* verifies input and output devices and their capabilities.
10042 *
10043 * This verification is required when enabling extended bit-depth or
10044 * sampling rates, as not all qcom products support it.
10045 *
10046 * Suitable for calling only on initialization such as adev_open().
10047 * It fills the audio_device use_case_table[] array.
10048 *
10049 * Has a side-effect that it needs to configure audio routing / devices
10050 * in order to power up the devices and read the device parameters.
10051 * It does not acquire any hw device lock. Should restore the devices
10052 * back to "normal state" upon completion.
10053 */
10054static int adev_verify_devices(struct audio_device *adev)
10055{
10056 /* enumeration is a bit difficult because one really wants to pull
10057 * the use_case, device id, etc from the hidden pcm_device_table[].
10058 * In this case there are the following use cases and device ids.
10059 *
10060 * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
10061 * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
10062 * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
10063 * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
10064 * [USECASE_AUDIO_RECORD] = {0, 0},
10065 * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
10066 * [USECASE_VOICE_CALL] = {2, 2},
10067 *
10068 * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
10069 * USECASE_VOICE_CALL omitted, but possible for either input or output.
10070 */
10071
10072 /* should be the usecases enabled in adev_open_input_stream() */
10073 static const int test_in_usecases[] = {
10074 USECASE_AUDIO_RECORD,
10075 USECASE_AUDIO_RECORD_LOW_LATENCY, /* does not appear to be used */
10076 };
10077 /* should be the usecases enabled in adev_open_output_stream()*/
10078 static const int test_out_usecases[] = {
10079 USECASE_AUDIO_PLAYBACK_DEEP_BUFFER,
10080 USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
10081 };
10082 static const usecase_type_t usecase_type_by_dir[] = {
10083 PCM_PLAYBACK,
10084 PCM_CAPTURE,
10085 };
10086 static const unsigned flags_by_dir[] = {
10087 PCM_OUT,
10088 PCM_IN,
10089 };
10090
10091 size_t i;
10092 unsigned dir;
10093 const unsigned card_id = adev->snd_card;
10094
10095 for (dir = 0; dir < 2; ++dir) {
10096 const usecase_type_t usecase_type = usecase_type_by_dir[dir];
10097 const unsigned flags_dir = flags_by_dir[dir];
10098 const size_t testsize =
10099 dir ? ARRAY_SIZE(test_in_usecases) : ARRAY_SIZE(test_out_usecases);
10100 const int *testcases =
10101 dir ? test_in_usecases : test_out_usecases;
10102 const audio_devices_t audio_device =
10103 dir ? AUDIO_DEVICE_IN_BUILTIN_MIC : AUDIO_DEVICE_OUT_SPEAKER;
10104
10105 for (i = 0; i < testsize; ++i) {
10106 const audio_usecase_t audio_usecase = testcases[i];
10107 int device_id;
10108 struct pcm_params **pparams;
10109 struct stream_out out;
10110 struct stream_in in;
10111 struct audio_usecase uc_info;
10112 int retval;
10113
10114 pparams = &adev->use_case_table[audio_usecase];
10115 pcm_params_free(*pparams); /* can accept null input */
10116 *pparams = NULL;
10117
10118 /* find the device ID for the use case (signed, for error) */
10119 device_id = platform_get_pcm_device_id(audio_usecase, usecase_type);
10120 if (device_id < 0)
10121 continue;
10122
10123 /* prepare structures for device probing */
10124 memset(&uc_info, 0, sizeof(uc_info));
10125 uc_info.id = audio_usecase;
10126 uc_info.type = usecase_type;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010127 list_init(&uc_info.device_list);
Aalique Grahame22e49102018-12-18 14:23:57 -080010128 if (dir) {
Aalique Grahame22e49102018-12-18 14:23:57 -080010129 memset(&in, 0, sizeof(in));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010130 list_init(&in.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010131 update_device_list(&in.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010132 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
10133 uc_info.stream.in = &in;
Aalique Grahame22e49102018-12-18 14:23:57 -080010134 }
10135 memset(&out, 0, sizeof(out));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010136 list_init(&out.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010137 update_device_list(&out.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010138 uc_info.stream.out = &out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010139 update_device_list(&uc_info.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010140 uc_info.in_snd_device = SND_DEVICE_NONE;
10141 uc_info.out_snd_device = SND_DEVICE_NONE;
10142 list_add_tail(&adev->usecase_list, &uc_info.list);
10143
10144 /* select device - similar to start_(in/out)put_stream() */
10145 retval = select_devices(adev, audio_usecase);
10146 if (retval >= 0) {
10147 *pparams = pcm_params_get(card_id, device_id, flags_dir);
10148#if LOG_NDEBUG == 0
Aalique Grahame203bee02019-03-13 17:49:36 -070010149 char info[512]; /* for possible debug info */
Aalique Grahame22e49102018-12-18 14:23:57 -080010150 if (*pparams) {
10151 ALOGV("%s: (%s) card %d device %d", __func__,
10152 dir ? "input" : "output", card_id, device_id);
10153 pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
10154 } else {
10155 ALOGV("%s: cannot locate card %d device %d", __func__, card_id, device_id);
10156 }
10157#endif
10158 }
10159
10160 /* deselect device - similar to stop_(in/out)put_stream() */
10161 /* 1. Get and set stream specific mixer controls */
10162 retval = disable_audio_route(adev, &uc_info);
10163 /* 2. Disable the rx device */
10164 retval = disable_snd_device(adev,
10165 dir ? uc_info.in_snd_device : uc_info.out_snd_device);
10166 list_remove(&uc_info.list);
10167 }
10168 }
Aalique Grahame22e49102018-12-18 14:23:57 -080010169 return 0;
10170}
10171
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010172int update_patch(unsigned int num_sources,
10173 const struct audio_port_config *sources,
10174 unsigned int num_sinks,
10175 const struct audio_port_config *sinks,
10176 audio_patch_handle_t handle,
10177 struct audio_patch_info *p_info,
10178 patch_type_t patch_type, bool new_patch)
10179{
Aniket Kumar Latad13758f2020-08-06 15:11:36 -070010180 ALOGV("%s: enter", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010181
10182 if (p_info == NULL) {
10183 ALOGE("%s: Invalid patch pointer", __func__);
10184 return -EINVAL;
10185 }
10186
10187 if (new_patch) {
10188 p_info->patch = (struct audio_patch *) calloc(1, sizeof(struct audio_patch));
10189 if (p_info->patch == NULL) {
10190 ALOGE("%s: Could not allocate patch", __func__);
10191 return -ENOMEM;
10192 }
10193 }
10194
10195 p_info->patch->id = handle;
10196 p_info->patch->num_sources = num_sources;
10197 p_info->patch->num_sinks = num_sinks;
10198
10199 for (int i = 0; i < num_sources; i++)
10200 p_info->patch->sources[i] = sources[i];
10201 for (int i = 0; i < num_sinks; i++)
10202 p_info->patch->sinks[i] = sinks[i];
10203
10204 p_info->patch_type = patch_type;
10205 return 0;
10206}
10207
10208audio_patch_handle_t generate_patch_handle()
10209{
10210 static audio_patch_handle_t patch_handle = AUDIO_PATCH_HANDLE_NONE;
10211 if (++patch_handle < 0)
10212 patch_handle = AUDIO_PATCH_HANDLE_NONE + 1;
10213 return patch_handle;
10214}
10215
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010216int adev_create_audio_patch(struct audio_hw_device *dev,
10217 unsigned int num_sources,
10218 const struct audio_port_config *sources,
10219 unsigned int num_sinks,
10220 const struct audio_port_config *sinks,
10221 audio_patch_handle_t *handle)
10222{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010223 int ret = 0;
10224 struct audio_device *adev = (struct audio_device *)dev;
10225 struct audio_patch_info *p_info = NULL;
10226 patch_type_t patch_type = PATCH_NONE;
10227 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10228 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
10229 struct audio_stream_info *s_info = NULL;
10230 struct audio_stream *stream = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010231 struct listnode devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010232 audio_devices_t device_type = AUDIO_DEVICE_NONE;
10233 bool new_patch = false;
10234 char addr[AUDIO_DEVICE_MAX_ADDRESS_LEN];
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010235
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010236 ALOGD("%s: enter: num sources %d, num_sinks %d, handle %d", __func__,
10237 num_sources, num_sinks, *handle);
10238
10239 if (num_sources == 0 || num_sources > AUDIO_PATCH_PORTS_MAX ||
10240 num_sinks == 0 || num_sinks > AUDIO_PATCH_PORTS_MAX) {
10241 ALOGE("%s: Invalid patch arguments", __func__);
10242 ret = -EINVAL;
10243 goto done;
10244 }
10245
10246 if (num_sources > 1) {
10247 ALOGE("%s: Multiple sources are not supported", __func__);
10248 ret = -EINVAL;
10249 goto done;
10250 }
10251
10252 if (sources == NULL || sinks == NULL) {
10253 ALOGE("%s: Invalid sources or sinks port config", __func__);
10254 ret = -EINVAL;
10255 goto done;
10256 }
10257
10258 ALOGV("%s: source role %d, source type %d", __func__,
10259 sources[0].type, sources[0].role);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010260 list_init(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010261
10262 // Populate source/sink information and fetch stream info
10263 switch (sources[0].type) {
10264 case AUDIO_PORT_TYPE_DEVICE: // Patch for audio capture or loopback
10265 device_type = sources[0].ext.device.type;
10266 strlcpy(&addr[0], &sources[0].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010267 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010268 if (sinks[0].type == AUDIO_PORT_TYPE_MIX) {
10269 patch_type = PATCH_CAPTURE;
10270 io_handle = sinks[0].ext.mix.handle;
10271 input_source = sinks[0].ext.mix.usecase.source;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010272 ALOGD("%s: Capture patch from device %x to mix %d",
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010273 __func__, device_type, io_handle);
10274 } else {
10275 // Device to device patch is not implemented.
10276 // This space will need changes if audio HAL
10277 // handles device to device patches in the future.
10278 patch_type = PATCH_DEVICE_LOOPBACK;
10279 }
10280 break;
10281 case AUDIO_PORT_TYPE_MIX: // Patch for audio playback
10282 io_handle = sources[0].ext.mix.handle;
10283 for (int i = 0; i < num_sinks; i++) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010284 device_type = sinks[i].ext.device.type;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010285 strlcpy(&addr[0], &sinks[i].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010286 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010287 }
10288 patch_type = PATCH_PLAYBACK;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010289 ALOGD("%s: Playback patch from mix handle %d to device %x",
10290 __func__, io_handle, get_device_types(&devices));
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010291 break;
10292 case AUDIO_PORT_TYPE_SESSION:
10293 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010294 ALOGE("%s: Unsupported source type %d", __func__, sources[0].type);
10295 ret = -EINVAL;
10296 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010297 }
10298
10299 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010300
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010301 // Generate patch info and update patch
10302 if (*handle == AUDIO_PATCH_HANDLE_NONE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010303 *handle = generate_patch_handle();
10304 p_info = (struct audio_patch_info *)
10305 calloc(1, sizeof(struct audio_patch_info));
10306 if (p_info == NULL) {
10307 ALOGE("%s: Failed to allocate memory", __func__);
10308 pthread_mutex_unlock(&adev->lock);
10309 ret = -ENOMEM;
10310 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010311 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010312 new_patch = true;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010313 } else {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010314 p_info = fetch_patch_info_l(adev, *handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010315 if (p_info == NULL) {
10316 ALOGE("%s: Unable to fetch patch for received patch handle %d",
10317 __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010318 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010319 ret = -EINVAL;
10320 goto done;
10321 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010322 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010323 update_patch(num_sources, sources, num_sinks, sinks,
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010324 *handle, p_info, patch_type, new_patch);
10325
10326 // Fetch stream info of associated mix for playback or capture patches
10327 if (p_info->patch_type == PATCH_PLAYBACK ||
10328 p_info->patch_type == PATCH_CAPTURE) {
10329 s_info = hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10330 if (s_info == NULL) {
10331 ALOGE("%s: Failed to obtain stream info", __func__);
10332 if (new_patch)
10333 free(p_info);
10334 pthread_mutex_unlock(&adev->lock);
10335 ret = -EINVAL;
10336 goto done;
10337 }
10338 ALOGV("%s: Fetched stream info with io_handle %d", __func__, io_handle);
10339 s_info->patch_handle = *handle;
10340 stream = s_info->stream;
10341 }
10342 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010343
10344 // Update routing for stream
10345 if (stream != NULL) {
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010346 if (p_info->patch_type == PATCH_PLAYBACK) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010347 ret = route_output_stream((struct stream_out *) stream, &devices);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010348 clear_devices(&devices);
10349 } else if (p_info->patch_type == PATCH_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010350 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010351 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010352 if (ret < 0) {
10353 pthread_mutex_lock(&adev->lock);
10354 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10355 if (new_patch)
10356 free(p_info);
10357 pthread_mutex_unlock(&adev->lock);
10358 ALOGE("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10359 goto done;
10360 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010361 }
10362
10363 // Add new patch to patch map
10364 if (!ret && new_patch) {
10365 pthread_mutex_lock(&adev->lock);
10366 hashmapPut(adev->patch_map, (void *) (intptr_t) *handle, (void *) p_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010367 ALOGD("%s: Added a new patch with handle %d", __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010368 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010369 }
10370
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010371done:
10372 audio_extn_hw_loopback_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010373 num_sources,
10374 sources,
10375 num_sinks,
10376 sinks,
10377 handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010378 audio_extn_auto_hal_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010379 num_sources,
10380 sources,
10381 num_sinks,
10382 sinks,
10383 handle);
10384 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010385}
10386
10387int adev_release_audio_patch(struct audio_hw_device *dev,
10388 audio_patch_handle_t handle)
10389{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010390 struct audio_device *adev = (struct audio_device *) dev;
10391 int ret = 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010392 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010393 struct audio_stream *stream = NULL;
Derek Chenf939fb72018-11-13 13:34:41 -080010394
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010395 if (handle == AUDIO_PATCH_HANDLE_NONE) {
10396 ALOGE("%s: Invalid patch handle %d", __func__, handle);
10397 ret = -EINVAL;
10398 goto done;
10399 }
10400
10401 ALOGD("%s: Remove patch with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010402 pthread_mutex_lock(&adev->lock);
10403 struct audio_patch_info *p_info = fetch_patch_info_l(adev, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010404 if (p_info == NULL) {
10405 ALOGE("%s: Patch info not found with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010406 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010407 ret = -EINVAL;
10408 goto done;
10409 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010410 struct audio_patch *patch = p_info->patch;
10411 if (patch == NULL) {
10412 ALOGE("%s: Patch not found for handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010413 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010414 ret = -EINVAL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010415 goto done;
10416 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010417 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10418 switch (patch->sources[0].type) {
10419 case AUDIO_PORT_TYPE_MIX:
10420 io_handle = patch->sources[0].ext.mix.handle;
10421 break;
10422 case AUDIO_PORT_TYPE_DEVICE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010423 if (p_info->patch_type == PATCH_CAPTURE)
10424 io_handle = patch->sinks[0].ext.mix.handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010425 break;
10426 case AUDIO_PORT_TYPE_SESSION:
10427 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010428 pthread_mutex_unlock(&adev->lock);
10429 ret = -EINVAL;
10430 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010431 }
10432
10433 // Remove patch and reset patch handle in stream info
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010434 patch_type_t patch_type = p_info->patch_type;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010435 patch_map_remove_l(adev, handle);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010436 if (patch_type == PATCH_PLAYBACK ||
10437 patch_type == PATCH_CAPTURE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010438 struct audio_stream_info *s_info =
10439 hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10440 if (s_info == NULL) {
10441 ALOGE("%s: stream for io_handle %d is not available", __func__, io_handle);
10442 pthread_mutex_unlock(&adev->lock);
10443 goto done;
10444 }
10445 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10446 stream = s_info->stream;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010447 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010448 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010449
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010450 if (stream != NULL) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010451 struct listnode devices;
10452 list_init(&devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010453 if (patch_type == PATCH_PLAYBACK)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010454 ret = route_output_stream((struct stream_out *) stream, &devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010455 else if (patch_type == PATCH_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010456 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010457 }
10458
10459 if (ret < 0)
10460 ALOGW("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10461
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010462done:
10463 audio_extn_hw_loopback_release_audio_patch(dev, handle);
10464 audio_extn_auto_hal_release_audio_patch(dev, handle);
10465
10466 ALOGV("%s: Successfully released patch %d", __func__, handle);
Derek Chenf939fb72018-11-13 13:34:41 -080010467 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010468}
10469
10470int adev_get_audio_port(struct audio_hw_device *dev, struct audio_port *config)
10471{
Derek Chenf13dd492018-11-13 14:53:51 -080010472 int ret = 0;
10473
10474 ret = audio_extn_hw_loopback_get_audio_port(dev, config);
10475 ret |= audio_extn_auto_hal_get_audio_port(dev, config);
10476 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010477}
10478
10479int adev_set_audio_port_config(struct audio_hw_device *dev,
10480 const struct audio_port_config *config)
10481{
Derek Chenf13dd492018-11-13 14:53:51 -080010482 int ret = 0;
10483
10484 ret = audio_extn_hw_loopback_set_audio_port_config(dev, config);
10485 ret |= audio_extn_auto_hal_set_audio_port_config(dev, config);
10486 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010487}
10488
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010489static int adev_dump(const audio_hw_device_t *device __unused,
10490 int fd __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010491{
10492 return 0;
10493}
10494
10495static int adev_close(hw_device_t *device)
10496{
Aalique Grahame22e49102018-12-18 14:23:57 -080010497 size_t i;
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010498 struct audio_device *adev_temp = (struct audio_device *)device;
Kiran Kandi910e1862013-10-29 13:29:42 -070010499
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010500 if (!adev_temp)
Kiran Kandi910e1862013-10-29 13:29:42 -070010501 return 0;
10502
10503 pthread_mutex_lock(&adev_init_lock);
10504
10505 if ((--audio_device_ref_count) == 0) {
Sujin Panicker390724d2019-04-26 10:43:36 +053010506 if (audio_extn_spkr_prot_is_enabled())
10507 audio_extn_spkr_prot_deinit();
Jaideep Sharmaa2b49672019-09-10 20:37:03 +053010508 audio_extn_battery_properties_listener_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010509 audio_extn_snd_mon_unregister_listener(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010510 audio_extn_sound_trigger_deinit(adev);
Kiran Kandide144c82013-11-20 15:58:32 -080010511 audio_extn_listen_deinit(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010512 audio_extn_qdsp_deinit();
Aalique Grahame22e49102018-12-18 14:23:57 -080010513 audio_extn_extspk_deinit(adev->extspk);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010514 audio_extn_utils_release_streams_cfg_lists(
10515 &adev->streams_output_cfg_list,
10516 &adev->streams_input_cfg_list);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010517 if (audio_extn_qap_is_enabled())
10518 audio_extn_qap_deinit();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010519 if (audio_extn_qaf_is_enabled())
10520 audio_extn_qaf_deinit();
Kiran Kandi910e1862013-10-29 13:29:42 -070010521 audio_route_free(adev->audio_route);
Weiyin Jiangfa65d3e2019-03-05 23:39:45 +080010522 audio_extn_gef_deinit(adev);
Kiran Kandi910e1862013-10-29 13:29:42 -070010523 free(adev->snd_dev_ref_cnt);
10524 platform_deinit(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080010525 for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
10526 pcm_params_free(adev->use_case_table[i]);
10527 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010528 if (adev->adm_deinit)
10529 adev->adm_deinit(adev->adm_data);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010530 qahwi_deinit(device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080010531 audio_extn_adsp_hdlr_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010532 audio_extn_snd_mon_deinit();
Siddartha Shaik44dd7702017-06-14 12:13:25 +053010533 audio_extn_hw_loopback_deinit(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070010534 audio_extn_ffv_deinit();
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053010535 if (adev->device_cfg_params) {
10536 free(adev->device_cfg_params);
10537 adev->device_cfg_params = NULL;
10538 }
Derek Chend2530072014-11-24 12:39:14 -080010539 if(adev->ext_hw_plugin)
10540 audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
Derek Chenae7b0342019-02-08 15:17:04 -080010541 audio_extn_auto_hal_deinit();
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010542 free_map(adev->patch_map);
10543 free_map(adev->io_streams_map);
Kiran Kandi910e1862013-10-29 13:29:42 -070010544 free(device);
10545 adev = NULL;
10546 }
10547 pthread_mutex_unlock(&adev_init_lock);
Vatsal Buchac09ae062018-11-14 13:25:08 +053010548 enable_gcov();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010549 return 0;
10550}
10551
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010552/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
10553 * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
10554 * just that it _might_ work.
10555 */
10556static int period_size_is_plausible_for_low_latency(int period_size)
10557{
10558 switch (period_size) {
10559 case 160:
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -070010560 case 192:
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010561 case 240:
10562 case 320:
10563 case 480:
10564 return 1;
10565 default:
10566 return 0;
10567 }
10568}
10569
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010570static void adev_snd_mon_cb(void *cookie, struct str_parms *parms)
10571{
10572 bool is_snd_card_status = false;
10573 bool is_ext_device_status = false;
10574 char value[32];
10575 int card = -1;
10576 card_status_t status;
10577
10578 if (cookie != adev || !parms)
10579 return;
10580
10581 if (!parse_snd_card_status(parms, &card, &status)) {
10582 is_snd_card_status = true;
10583 } else if (0 < str_parms_get_str(parms, "ext_audio_device", value, sizeof(value))) {
10584 is_ext_device_status = true;
10585 } else {
10586 // not a valid event
10587 return;
10588 }
10589
10590 pthread_mutex_lock(&adev->lock);
10591 if (card == adev->snd_card || is_ext_device_status) {
10592 if (is_snd_card_status && adev->card_status != status) {
Jaideep Sharmacb402512020-09-24 17:51:07 +053010593 ALOGD("%s card_status %d", __func__, status);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010594 adev->card_status = status;
10595 platform_snd_card_update(adev->platform, status);
10596 audio_extn_fm_set_parameters(adev, parms);
Derek Chend6f371d2019-03-01 13:45:58 -080010597 audio_extn_auto_hal_set_parameters(adev, parms);
Zhou Song4f43e352019-07-02 00:32:23 +080010598 if (status == CARD_STATUS_OFFLINE)
10599 audio_extn_sco_reset_configuration();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010600 } else if (is_ext_device_status) {
10601 platform_set_parameters(adev->platform, parms);
10602 }
10603 }
10604 pthread_mutex_unlock(&adev->lock);
10605 return;
10606}
10607
Weiyin Jiang280ea742020-09-08 20:28:22 +080010608/* adev lock held */
10609int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010610{
10611 struct audio_usecase *uc_info;
Zhou Song407e5aa2020-12-27 19:13:04 +080010612 struct audio_usecase *usecase;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010613 struct listnode devices;
Zhou Song407e5aa2020-12-27 19:13:04 +080010614 struct listnode *node;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010615
10616 uc_info = get_usecase_from_list(adev, out->usecase);
10617 if (uc_info == NULL) {
10618 ALOGE("%s: Could not find the usecase (%d) in the list",
10619 __func__, out->usecase);
10620 return -EINVAL;
10621 }
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010622 list_init(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010623
Zhou Songbaddf9f2020-11-20 13:57:39 +080010624 ALOGD("%s: enter: usecase(%d: %s), a2dp muted %d", __func__,
10625 out->usecase, use_case_table[out->usecase], out->a2dp_muted);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010626
10627 if (restore) {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010628 pthread_mutex_lock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010629 // restore A2DP device for active usecases and unmute if required
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010630 if (is_a2dp_out_device_type(&out->device_list)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010631 ALOGD("%s: restoring A2dp and unmuting stream", __func__);
Zhou Songe5225132019-09-26 15:33:36 +080010632 if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
10633 select_devices(adev, uc_info->id);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010634
10635 if (is_offload_usecase(out->usecase)) {
10636 if (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)
Weiyin Jiang280ea742020-09-08 20:28:22 +080010637 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010638 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
10639 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
10640 } else {
10641 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010642 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010643 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010644 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010645 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010646 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010647 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010648 // mute stream and switch to speaker if suspended
10649 if (!out->a2dp_muted && !out->standby) {
Zhou Songbaddf9f2020-11-20 13:57:39 +080010650 assign_devices(&devices, &out->device_list);
10651 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Zhou Song407e5aa2020-12-27 19:13:04 +080010652 list_for_each(node, &adev->usecase_list) {
10653 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Songe63b6fe2021-04-15 13:54:46 +080010654 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
10655 !is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songcf77af02021-05-14 18:21:14 +080010656 !is_sco_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songe63b6fe2021-04-15 13:54:46 +080010657 platform_check_backends_match(SND_DEVICE_OUT_SPEAKER,
10658 usecase->out_snd_device)) {
Zhou Song407e5aa2020-12-27 19:13:04 +080010659 assign_devices(&out->device_list, &usecase->stream.out->device_list);
10660 break;
10661 }
10662 }
Zhou Songcf77af02021-05-14 18:21:14 +080010663 if ((is_a2dp_out_device_type(&devices) && list_length(&devices) == 1) ||
10664 (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
Zhou Song8edbbdb2021-01-14 16:48:03 +080010665 out->a2dp_muted = true;
10666 if (is_offload_usecase(out->usecase)) {
10667 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10668 compress_pause(out->compr);
10669 out_set_compr_volume(&out->stream, (float)0, (float)0);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010670 } else {
Weiyin Jiang906db3c2021-03-02 13:17:04 +080010671 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
10672 out_set_voip_volume(&out->stream, (float)0, (float)0);
10673 else
10674 out_set_pcm_volume(&out->stream, (float)0, (float)0);
10675
Zhou Song8edbbdb2021-01-14 16:48:03 +080010676 /* wait for stale pcm drained before switching to speaker */
10677 uint32_t latency =
10678 (out->config.period_count * out->config.period_size * 1000) /
10679 (out->config.rate);
10680 usleep(latency * 1000);
10681 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010682 }
10683 select_devices(adev, out->usecase);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010684 ALOGD("%s: switched to device:%s and stream muted:%d", __func__,
10685 platform_get_snd_device_name(uc_info->out_snd_device), out->a2dp_muted);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010686 if (is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010687 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10688 compress_resume(out->compr);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010689 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010690 assign_devices(&out->device_list, &devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010691 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010692 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010693 }
10694 ALOGV("%s: exit", __func__);
10695 return 0;
10696}
10697
Haynes Mathew George01156f92018-04-13 15:29:54 -070010698void adev_on_battery_status_changed(bool charging)
10699{
10700 pthread_mutex_lock(&adev->lock);
10701 ALOGI("%s: battery status changed to %scharging", __func__, charging ? "" : "not ");
10702 adev->is_charging = charging;
Zhou Songc1088ea2018-06-12 00:17:29 +080010703 audio_extn_sound_trigger_update_battery_status(charging);
Haynes Mathew George01156f92018-04-13 15:29:54 -070010704 pthread_mutex_unlock(&adev->lock);
10705}
10706
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010707static int adev_open(const hw_module_t *module, const char *name,
10708 hw_device_t **device)
10709{
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010710 int ret;
Derek Chenf939fb72018-11-13 13:34:41 -080010711 char value[PROPERTY_VALUE_MAX] = {0};
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053010712 char mixer_ctl_name[128] = {0};
10713 struct mixer_ctl *ctl = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010714
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080010715 ALOGD("%s: enter", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010716 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
10717
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010718 pthread_mutex_lock(&adev_init_lock);
Kiran Kandi910e1862013-10-29 13:29:42 -070010719 if (audio_device_ref_count != 0){
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010720 *device = &adev->device.common;
Kiran Kandi910e1862013-10-29 13:29:42 -070010721 audio_device_ref_count++;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010722 ALOGD("%s: returning existing instance of adev", __func__);
10723 ALOGD("%s: exit", __func__);
10724 pthread_mutex_unlock(&adev_init_lock);
10725 return 0;
10726 }
10727
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010728 adev = calloc(1, sizeof(struct audio_device));
10729
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -070010730 if (!adev) {
10731 pthread_mutex_unlock(&adev_init_lock);
10732 return -ENOMEM;
10733 }
10734
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -070010735 pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
10736
Weiyin Jiange6ce6312019-01-28 18:28:22 +080010737 // register audio ext hidl at the earliest
10738 audio_extn_hidl_init();
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053010739#ifdef DYNAMIC_LOG_ENABLED
10740 register_for_dynamic_logging("hal");
10741#endif
10742
Derek Chenf939fb72018-11-13 13:34:41 -080010743 /* default audio HAL major version */
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010744 uint32_t maj_version = 3;
Derek Chenf939fb72018-11-13 13:34:41 -080010745 if(property_get("vendor.audio.hal.maj.version", value, NULL))
10746 maj_version = atoi(value);
10747
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010748 adev->device.common.tag = HARDWARE_DEVICE_TAG;
Derek Chenf939fb72018-11-13 13:34:41 -080010749 adev->device.common.version = HARDWARE_DEVICE_API_VERSION(maj_version, 0);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010750 adev->device.common.module = (struct hw_module_t *)module;
10751 adev->device.common.close = adev_close;
10752
10753 adev->device.init_check = adev_init_check;
10754 adev->device.set_voice_volume = adev_set_voice_volume;
10755 adev->device.set_master_volume = adev_set_master_volume;
10756 adev->device.get_master_volume = adev_get_master_volume;
10757 adev->device.set_master_mute = adev_set_master_mute;
10758 adev->device.get_master_mute = adev_get_master_mute;
10759 adev->device.set_mode = adev_set_mode;
10760 adev->device.set_mic_mute = adev_set_mic_mute;
10761 adev->device.get_mic_mute = adev_get_mic_mute;
10762 adev->device.set_parameters = adev_set_parameters;
10763 adev->device.get_parameters = adev_get_parameters;
10764 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
10765 adev->device.open_output_stream = adev_open_output_stream;
10766 adev->device.close_output_stream = adev_close_output_stream;
10767 adev->device.open_input_stream = adev_open_input_stream;
10768 adev->device.close_input_stream = adev_close_input_stream;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010769 adev->device.create_audio_patch = adev_create_audio_patch;
10770 adev->device.release_audio_patch = adev_release_audio_patch;
10771 adev->device.get_audio_port = adev_get_audio_port;
10772 adev->device.set_audio_port_config = adev_set_audio_port_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010773 adev->device.dump = adev_dump;
Naresh Tannirudcb47c52018-06-25 16:23:32 +053010774 adev->device.get_microphones = adev_get_microphones;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010775
10776 /* Set the default route before the PCM stream is opened */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010777 adev->mode = AUDIO_MODE_NORMAL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -080010778 adev->primary_output = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010779 adev->out_device = AUDIO_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010780 adev->bluetooth_nrec = true;
Ravi Kumar Alamandaf9967042013-02-14 19:35:14 -080010781 adev->acdb_settings = TTY_MODE_OFF;
vivek mehta344576a2016-04-12 18:56:03 -070010782 adev->allow_afe_proxy_usage = true;
Ashish Jain1b9b30c2017-05-18 20:57:40 +053010783 adev->bt_sco_on = false;
Eric Laurent07eeafd2013-10-06 12:52:49 -070010784 /* adev->cur_hdmi_channels = 0; by calloc() */
Eric Laurentb23d5282013-05-14 15:27:20 -070010785 adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
vivek mehtaae1018c2019-05-09 12:19:57 -070010786 /* Init audio and voice feature */
10787 audio_extn_feature_init();
10788 voice_extn_feature_init();
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070010789 voice_init(adev);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -080010790 list_init(&adev->usecase_list);
Derek Chenf939fb72018-11-13 13:34:41 -080010791 list_init(&adev->active_inputs_list);
10792 list_init(&adev->active_outputs_list);
Rahul Sharma99770982019-03-06 17:05:26 +053010793 list_init(&adev->audio_patch_record_list);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010794 adev->io_streams_map = hashmapCreate(AUDIO_IO_PORTS_MAX, audio_extn_utils_hash_fn,
10795 audio_extn_utils_hash_eq);
10796 if (!adev->io_streams_map) {
10797 ALOGE("%s: Could not create io streams map", __func__);
10798 ret = -ENOMEM;
10799 goto adev_open_err;
10800 }
10801 adev->patch_map = hashmapCreate(AUDIO_PATCH_PORTS_MAX, audio_extn_utils_hash_fn,
10802 audio_extn_utils_hash_eq);
10803 if (!adev->patch_map) {
10804 ALOGE("%s: Could not create audio patch map", __func__);
10805 ret = -ENOMEM;
10806 goto adev_open_err;
10807 }
Krishnankutty Kolathappilly0b2de1c2014-02-14 14:45:49 -080010808 adev->cur_wfd_channels = 2;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -070010809 adev->offload_usecases_state = 0;
Samyak Jain15fda662018-12-18 16:40:52 +053010810 adev->pcm_record_uc_state = 0;
Ashish Jain81eb2a82015-05-13 10:52:34 +053010811 adev->is_channel_status_set = false;
Sudheer Papothifa9d2282015-09-17 01:53:25 +053010812 adev->perf_lock_opts[0] = 0x101;
10813 adev->perf_lock_opts[1] = 0x20E;
10814 adev->perf_lock_opts_size = 2;
Xiaojun Sang785b5da2017-08-03 15:52:29 +080010815 adev->dsp_bit_width_enforce_mode = 0;
Aalique Grahame552b0832019-03-11 10:16:38 -070010816 adev->enable_hfp = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053010817 adev->use_old_pspd_mix_ctrl = false;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070010818 adev->adm_routing_changed = false;
Revathi Uddarajub26e3932020-06-10 14:51:02 +053010819 adev->a2dp_started = false;
Zhou Song503196b2021-07-23 17:31:05 +080010820 adev->ha_proxy_enable = false;
Naresh Tanniru4c630392014-05-12 01:05:52 +053010821
Zhou Song68ebc352019-12-05 17:11:15 +080010822 audio_extn_perf_lock_init();
10823
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010824 /* Loads platform specific libraries dynamically */
Eric Laurentb23d5282013-05-14 15:27:20 -070010825 adev->platform = platform_init(adev);
10826 if (!adev->platform) {
Eric Laurentb23d5282013-05-14 15:27:20 -070010827 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010828 ret = -EINVAL;
10829 goto adev_open_err;
Eric Laurentb23d5282013-05-14 15:27:20 -070010830 }
Eric Laurentc4aef752013-09-12 17:45:53 -070010831
Aalique Grahame22e49102018-12-18 14:23:57 -080010832 adev->extspk = audio_extn_extspk_init(adev);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010833 if (audio_extn_qap_is_enabled()) {
10834 ret = audio_extn_qap_init(adev);
10835 if (ret < 0) {
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010836 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010837 goto adev_open_err;
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010838 }
10839 adev->device.open_output_stream = audio_extn_qap_open_output_stream;
10840 adev->device.close_output_stream = audio_extn_qap_close_output_stream;
10841 }
Aalique Grahame22e49102018-12-18 14:23:57 -080010842
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010843 if (audio_extn_qaf_is_enabled()) {
10844 ret = audio_extn_qaf_init(adev);
10845 if (ret < 0) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010846 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010847 goto adev_open_err;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010848 }
10849
10850 adev->device.open_output_stream = audio_extn_qaf_open_output_stream;
10851 adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
10852 }
10853
Derek Chenae7b0342019-02-08 15:17:04 -080010854 audio_extn_auto_hal_init(adev);
Derek Chend2530072014-11-24 12:39:14 -080010855 adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);
10856
Eric Laurentc4aef752013-09-12 17:45:53 -070010857 if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
10858 adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
10859 if (adev->visualizer_lib == NULL) {
10860 ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
10861 } else {
10862 ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
10863 adev->visualizer_start_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010864 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070010865 "visualizer_hal_start_output");
10866 adev->visualizer_stop_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010867 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070010868 "visualizer_hal_stop_output");
10869 }
10870 }
Dhanalakshmi Siddani21be3ac2016-12-29 14:31:08 +053010871 audio_extn_init(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010872 voice_extn_init(adev);
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -080010873 audio_extn_listen_init(adev, adev->snd_card);
Weiyin Jiangaa80acd2016-09-21 16:42:11 +080010874 audio_extn_gef_init(adev);
Siddartha Shaik44dd7702017-06-14 12:13:25 +053010875 audio_extn_hw_loopback_init(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070010876 audio_extn_ffv_init(adev);
Eric Laurentc4aef752013-09-12 17:45:53 -070010877
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010878 if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
10879 adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
10880 if (adev->offload_effects_lib == NULL) {
10881 ALOGE("%s: DLOPEN failed for %s", __func__,
10882 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
10883 } else {
10884 ALOGV("%s: DLOPEN successful for %s", __func__,
10885 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
10886 adev->offload_effects_start_output =
Ashish Jain5106d362016-05-11 19:23:33 +053010887 (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib,
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010888 "offload_effects_bundle_hal_start_output");
10889 adev->offload_effects_stop_output =
10890 (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
10891 "offload_effects_bundle_hal_stop_output");
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080010892 adev->offload_effects_set_hpx_state =
10893 (int (*)(bool))dlsym(adev->offload_effects_lib,
10894 "offload_effects_bundle_set_hpx_state");
Dhananjay Kumard68883d2015-09-04 13:39:26 +053010895 adev->offload_effects_get_parameters =
10896 (void (*)(struct str_parms *, struct str_parms *))
10897 dlsym(adev->offload_effects_lib,
10898 "offload_effects_bundle_get_parameters");
10899 adev->offload_effects_set_parameters =
10900 (void (*)(struct str_parms *))dlsym(adev->offload_effects_lib,
10901 "offload_effects_bundle_set_parameters");
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010902 }
10903 }
10904
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010905 if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
10906 adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
10907 if (adev->adm_lib == NULL) {
10908 ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
10909 } else {
10910 ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
10911 adev->adm_init = (adm_init_t)
10912 dlsym(adev->adm_lib, "adm_init");
10913 adev->adm_deinit = (adm_deinit_t)
10914 dlsym(adev->adm_lib, "adm_deinit");
10915 adev->adm_register_input_stream = (adm_register_input_stream_t)
10916 dlsym(adev->adm_lib, "adm_register_input_stream");
10917 adev->adm_register_output_stream = (adm_register_output_stream_t)
10918 dlsym(adev->adm_lib, "adm_register_output_stream");
10919 adev->adm_deregister_stream = (adm_deregister_stream_t)
10920 dlsym(adev->adm_lib, "adm_deregister_stream");
10921 adev->adm_request_focus = (adm_request_focus_t)
10922 dlsym(adev->adm_lib, "adm_request_focus");
10923 adev->adm_abandon_focus = (adm_abandon_focus_t)
10924 dlsym(adev->adm_lib, "adm_abandon_focus");
Haynes Mathew George5beddd42016-06-27 18:33:40 -070010925 adev->adm_set_config = (adm_set_config_t)
10926 dlsym(adev->adm_lib, "adm_set_config");
10927 adev->adm_request_focus_v2 = (adm_request_focus_v2_t)
10928 dlsym(adev->adm_lib, "adm_request_focus_v2");
10929 adev->adm_is_noirq_avail = (adm_is_noirq_avail_t)
10930 dlsym(adev->adm_lib, "adm_is_noirq_avail");
10931 adev->adm_on_routing_change = (adm_on_routing_change_t)
10932 dlsym(adev->adm_lib, "adm_on_routing_change");
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070010933 adev->adm_request_focus_v2_1 = (adm_request_focus_v2_1_t)
10934 dlsym(adev->adm_lib, "adm_request_focus_v2_1");
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010935 }
10936 }
10937
Aalique Grahame22e49102018-12-18 14:23:57 -080010938 adev->enable_voicerx = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070010939 adev->bt_wb_speech_enabled = false;
Zhou Song12c29502019-03-16 10:37:18 +080010940 adev->swb_speech_mode = SPEECH_MODE_INVALID;
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +080010941 adev->fluence_nn_usecase_id = USECASE_INVALID;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -080010942 //initialize this to false for now,
10943 //this will be set to true through set param
10944 adev->vr_audio_mode_enabled = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070010945
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -070010946 audio_extn_ds2_enable(adev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010947 *device = &adev->device.common;
Aalique Grahame22e49102018-12-18 14:23:57 -080010948
10949 if (k_enable_extended_precision)
10950 adev_verify_devices(adev);
10951
Xiaojun Sang785b5da2017-08-03 15:52:29 +080010952 adev->dsp_bit_width_enforce_mode =
10953 adev_init_dsp_bit_width_enforce_mode(adev->mixer);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010954
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010955 audio_extn_utils_update_streams_cfg_lists(adev->platform, adev->mixer,
10956 &adev->streams_output_cfg_list,
10957 &adev->streams_input_cfg_list);
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -070010958
Kiran Kandi910e1862013-10-29 13:29:42 -070010959 audio_device_ref_count++;
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010960
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010961 int trial;
Manisha Agarwalc75a0202019-12-06 18:48:25 +053010962 if (property_get("vendor.audio_hal.period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010963 trial = atoi(value);
10964 if (period_size_is_plausible_for_low_latency(trial)) {
10965 pcm_config_low_latency.period_size = trial;
10966 pcm_config_low_latency.start_threshold = trial / 4;
10967 pcm_config_low_latency.avail_min = trial / 4;
10968 configured_low_latency_capture_period_size = trial;
10969 }
10970 }
ronghuiz93177262021-04-21 19:58:13 +080010971 if (property_get("vendor.audio_hal.in_period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010972 trial = atoi(value);
10973 if (period_size_is_plausible_for_low_latency(trial)) {
10974 configured_low_latency_capture_period_size = trial;
10975 }
10976 }
10977
Vignesh Kulothungan7d374312018-02-21 17:12:00 -080010978 adev->mic_break_enabled = property_get_bool("vendor.audio.mic_break", false);
10979
Eric Laurent4b084132018-10-19 17:33:43 -070010980 adev->camera_orientation = CAMERA_DEFAULT;
10981
Manisha Agarwalc75a0202019-12-06 18:48:25 +053010982 if (property_get("vendor.audio_hal.period_multiplier",value,NULL) > 0) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -070010983 af_period_multiplier = atoi(value);
10984 if (af_period_multiplier < 0)
10985 af_period_multiplier = 2;
10986 else if (af_period_multiplier > 4)
10987 af_period_multiplier = 4;
10988
10989 ALOGV("new period_multiplier = %d", af_period_multiplier);
10990 }
10991
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010992 audio_extn_qdsp_init(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080010993
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -070010994 adev->multi_offload_enable = property_get_bool("vendor.audio.offload.multiple.enabled", false);
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010995 pthread_mutex_unlock(&adev_init_lock);
10996
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010997 if (adev->adm_init)
10998 adev->adm_data = adev->adm_init();
10999
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053011000 qahwi_init(*device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080011001 audio_extn_adsp_hdlr_init(adev->mixer);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011002
11003 audio_extn_snd_mon_init();
11004 pthread_mutex_lock(&adev->lock);
11005 audio_extn_snd_mon_register_listener(adev, adev_snd_mon_cb);
11006 adev->card_status = CARD_STATUS_ONLINE;
Haynes Mathew George01156f92018-04-13 15:29:54 -070011007 audio_extn_battery_properties_listener_init(adev_on_battery_status_changed);
11008 /*
11009 * if the battery state callback happens before charging can be queried,
11010 * it will be guarded with the adev->lock held in the cb function and so
11011 * the callback value will reflect the latest state
11012 */
11013 adev->is_charging = audio_extn_battery_properties_is_charging();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011014 audio_extn_sound_trigger_init(adev); /* dependent on snd_mon_init() */
Zhou Songc1088ea2018-06-12 00:17:29 +080011015 audio_extn_sound_trigger_update_battery_status(adev->is_charging);
justinweng20fb6d82019-02-21 18:49:00 -070011016 audio_extn_audiozoom_init();
Zhou Songc1088ea2018-06-12 00:17:29 +080011017 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053011018 /* Allocate memory for Device config params */
11019 adev->device_cfg_params = (struct audio_device_config_param*)
11020 calloc(platform_get_max_codec_backend(),
11021 sizeof(struct audio_device_config_param));
11022 if (adev->device_cfg_params == NULL)
11023 ALOGE("%s: Memory allocation failed for Device config params", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053011024
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053011025 /*
11026 * Check if new PSPD matrix mixer control is supported. If not
11027 * supported, then set flag so that old mixer ctrl is sent while
11028 * sending pspd coefficients on older kernel version. Query mixer
11029 * control for default pcm id and channel value one.
11030 */
11031 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
11032 "AudStr %d ChMixer Weight Ch %d", 0, 1);
11033
11034 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
11035 if (!ctl) {
11036 ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
11037 __func__, mixer_ctl_name);
11038 adev->use_old_pspd_mix_ctrl = true;
11039 }
11040
Jaideep Sharma0fa53812020-09-17 09:00:11 +053011041 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011042 return 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011043
11044adev_open_err:
11045 free_map(adev->patch_map);
11046 free_map(adev->io_streams_map);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080011047 free(adev->snd_dev_ref_cnt);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070011048 pthread_mutex_destroy(&adev->lock);
11049 free(adev);
11050 adev = NULL;
11051 *device = NULL;
11052 pthread_mutex_unlock(&adev_init_lock);
11053 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011054}
11055
11056static struct hw_module_methods_t hal_module_methods = {
11057 .open = adev_open,
11058};
11059
11060struct audio_module HAL_MODULE_INFO_SYM = {
11061 .common = {
11062 .tag = HARDWARE_MODULE_TAG,
11063 .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
11064 .hal_api_version = HARDWARE_HAL_API_VERSION,
11065 .id = AUDIO_HARDWARE_MODULE_ID,
11066 .name = "QCOM Audio HAL",
Duy Truongfae19622013-11-24 02:17:54 -080011067 .author = "The Linux Foundation",
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011068 .methods = &hal_module_methods,
11069 },
11070};