blob: 36cbc852ba8414ff61bbcb53bea3b9e189eef770 [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",
Mingming Yine62d7842013-10-25 16:26:03 -0700363 [USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
Dhananjay Kumaree4d2002016-10-25 18:02:58 +0530364 [USECASE_AUDIO_RECORD_COMPRESS2] = "audio-record-compress2",
365 [USECASE_AUDIO_RECORD_COMPRESS3] = "audio-record-compress3",
366 [USECASE_AUDIO_RECORD_COMPRESS4] = "audio-record-compress4",
Dhananjay Kumar376e38b2017-09-28 22:26:23 +0530367 [USECASE_AUDIO_RECORD_COMPRESS5] = "audio-record-compress5",
368 [USECASE_AUDIO_RECORD_COMPRESS6] = "audio-record-compress6",
Eric Laurentb23d5282013-05-14 15:27:20 -0700369 [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
Preetam Singh Ranawatde84f1a2013-11-01 14:58:16 -0700370 [USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700371 [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700372 [USECASE_AUDIO_RECORD_HIFI] = "hifi-record",
Haynes Mathew George16081042017-05-31 17:16:49 -0700373
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -0800374 [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
Vimal Puthanveed47e64852013-12-20 13:23:39 -0800375 [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
Derek Chenf7092792017-05-23 12:23:53 -0400376 [USECASE_AUDIO_HFP_SCO_DOWNLINK] = "hfp-sco-downlink",
377 [USECASE_AUDIO_HFP_SCO_WB_DOWNLINK] = "hfp-sco-wb-downlink",
Mingming Yin3ee55c62014-08-04 14:23:35 -0700378
Derek Chenf7092792017-05-23 12:23:53 -0400379 [USECASE_VOICE_CALL] = "voice-call",
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -0700380 [USECASE_VOICE2_CALL] = "voice2-call",
381 [USECASE_VOLTE_CALL] = "volte-call",
382 [USECASE_QCHAT_CALL] = "qchat-call",
Vicky Sehrawat7e4fc152014-02-12 17:58:59 -0800383 [USECASE_VOWLAN_CALL] = "vowlan-call",
Vidyakumar Athota0e109352015-02-12 17:38:22 -0800384 [USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
385 [USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
Narsinga Rao Chella05573b72013-11-15 15:21:40 -0800386 [USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
Shiv Maliyappanahallida107642013-10-17 11:16:13 -0700387 [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
388 [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
389 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
Helen Zenge56b4852013-12-03 16:54:40 -0800390 [USECASE_INCALL_REC_UPLINK_COMPRESS] = "incall-rec-uplink-compress",
391 [USECASE_INCALL_REC_DOWNLINK_COMPRESS] = "incall-rec-downlink-compress",
392 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = "incall-rec-uplink-and-downlink-compress",
393
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -0700394 [USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
395 [USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -0700396 [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
397 [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -0700398
399 [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
400 [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
Zhou Song62ea0282020-03-22 19:53:01 +0800401 [USECASE_AUDIO_RECORD_AFE_PROXY2] = "afe-proxy-record2",
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +0530402 [USECASE_AUDIO_PLAYBACK_SILENCE] = "silence-playback",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700403
Siddartha Shaik31b530e2017-05-19 15:26:33 +0530404 /* Transcode loopback cases */
Surendar Karka93cd25a2018-08-28 14:21:37 +0530405 [USECASE_AUDIO_TRANSCODE_LOOPBACK_RX] = "audio-transcode-loopback-rx",
406 [USECASE_AUDIO_TRANSCODE_LOOPBACK_TX] = "audio-transcode-loopback-tx",
Vikram Panduranga93f080e2017-06-07 18:16:14 -0700407
408 [USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
409 [USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530410 [USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY] = "audio-record-voip-low-latency",
Varun Balaraje49253e2017-07-06 19:48:56 +0530411 /* For Interactive Audio Streams */
412 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] = "audio-interactive-stream1",
413 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] = "audio-interactive-stream2",
414 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] = "audio-interactive-stream3",
415 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] = "audio-interactive-stream4",
416 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] = "audio-interactive-stream5",
417 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] = "audio-interactive-stream6",
418 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
419 [USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
Garmond Leunge2433c32017-09-28 21:51:22 -0700420
Aniket Kumar Lata7fd86e12018-02-20 19:26:10 -0800421 [USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",
422
Derek Chenf6318be2017-06-12 17:16:24 -0400423 [USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback",
424
425 [USECASE_AUDIO_PLAYBACK_MEDIA] = "media-playback",
426 [USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION] = "sys-notification-playback",
427 [USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE] = "nav-guidance-playback",
428 [USECASE_AUDIO_PLAYBACK_PHONE] = "phone-playback",
Susan Wang117cf6f2022-04-06 20:11:46 -0400429 [USECASE_AUDIO_PLAYBACK_ALERTS] = "alerts-playback",
Derek Chen1bcdc6b2020-02-06 22:44:53 -0800430 [USECASE_AUDIO_PLAYBACK_FRONT_PASSENGER] = "front-passenger-playback",
Derek Chendf05eea2019-08-01 13:57:49 -0700431 [USECASE_AUDIO_PLAYBACK_REAR_SEAT] = "rear-seat-playback",
Rahul Sharma99770982019-03-06 17:05:26 +0530432 [USECASE_AUDIO_FM_TUNER_EXT] = "fm-tuner-ext",
Derek Chena30a5f42019-12-03 11:17:09 -0500433 [USECASE_ICC_CALL] = "icc-call",
Huicheng Liu1404ba12020-09-11 01:03:25 -0400434
435 [USECASE_AUDIO_RECORD_BUS] = "audio-record",
436 [USECASE_AUDIO_RECORD_BUS_FRONT_PASSENGER] = "front-passenger-record",
437 [USECASE_AUDIO_RECORD_BUS_REAR_SEAT] = "rear-seat-record",
Fei Tongaffdf732020-02-20 20:39:05 +0800438 [USECASE_AUDIO_PLAYBACK_SYNTHESIZER] = "synth-loopback",
Susan Wange3959562021-03-11 11:50:26 -0500439 [USECASE_AUDIO_RECORD_ECHO_REF_EXT] = "echo-reference-external",
Eric Laurentb23d5282013-05-14 15:27:20 -0700440};
441
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700442static const audio_usecase_t offload_usecases[] = {
443 USECASE_AUDIO_PLAYBACK_OFFLOAD,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700444 USECASE_AUDIO_PLAYBACK_OFFLOAD2,
445 USECASE_AUDIO_PLAYBACK_OFFLOAD3,
446 USECASE_AUDIO_PLAYBACK_OFFLOAD4,
447 USECASE_AUDIO_PLAYBACK_OFFLOAD5,
448 USECASE_AUDIO_PLAYBACK_OFFLOAD6,
449 USECASE_AUDIO_PLAYBACK_OFFLOAD7,
450 USECASE_AUDIO_PLAYBACK_OFFLOAD8,
451 USECASE_AUDIO_PLAYBACK_OFFLOAD9,
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -0700452};
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800453
Varun Balaraje49253e2017-07-06 19:48:56 +0530454static const audio_usecase_t interactive_usecases[] = {
455 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
456 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
457 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
458 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
459 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
460 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
461 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
462 USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
463};
464
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800465#define STRING_TO_ENUM(string) { #string, string }
466
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800467struct string_to_enum {
468 const char *name;
469 uint32_t value;
470};
471
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700472static const struct string_to_enum channels_name_to_enum_table[] = {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800473 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
Mingming Yin3a941d42016-02-17 18:08:05 -0800474 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
475 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
476 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -0700477 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
Mingming Yin3a941d42016-02-17 18:08:05 -0800478 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
479 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800480 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700481 STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
482 STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
483 STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
484 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
485 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
486 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
487 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
488 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
489 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
490 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
491 STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800492};
493
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700494static const struct string_to_enum formats_name_to_enum_table[] = {
495 STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
496 STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
497 STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700498 STRING_TO_ENUM(AUDIO_FORMAT_AC3),
499 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
500 STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
Ben Romberger1aaaf862017-04-06 17:49:46 -0700501 STRING_TO_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
Mingming Yin3a941d42016-02-17 18:08:05 -0800502 STRING_TO_ENUM(AUDIO_FORMAT_DTS),
503 STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
Naresh Tanniru928f0862017-04-07 16:44:23 -0700504 STRING_TO_ENUM(AUDIO_FORMAT_IEC61937)
Mingming Yin3a941d42016-02-17 18:08:05 -0800505};
506
507//list of all supported sample rates by HDMI specification.
508static const int out_hdmi_sample_rates[] = {
509 32000, 44100, 48000, 88200, 96000, 176400, 192000,
510};
511
Haynes Mathew George484e8d22017-07-31 18:55:17 -0700512static const struct string_to_enum out_sample_rates_name_to_enum_table[] = {
Mingming Yin3a941d42016-02-17 18:08:05 -0800513 STRING_TO_ENUM(32000),
514 STRING_TO_ENUM(44100),
515 STRING_TO_ENUM(48000),
516 STRING_TO_ENUM(88200),
517 STRING_TO_ENUM(96000),
518 STRING_TO_ENUM(176400),
519 STRING_TO_ENUM(192000),
Mingshu pange8aedf12019-10-25 15:38:27 +0800520 STRING_TO_ENUM(352800),
521 STRING_TO_ENUM(384000),
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -0700522};
523
Carter Hsu2e429db2019-05-14 18:50:52 +0800524struct in_effect_list {
525 struct listnode list;
526 effect_handle_t handle;
527};
528
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -0700529static struct audio_device *adev = NULL;
Ben Romberger02ab1192018-05-24 12:10:08 -0700530static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
Kiran Kandi910e1862013-10-29 13:29:42 -0700531static unsigned int audio_device_ref_count;
vivek mehtab72d08d2016-04-29 03:16:47 -0700532//cache last MBDRC cal step level
533static int last_known_cal_step = -1 ;
Kiran Kandi910e1862013-10-29 13:29:42 -0700534
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +0530535static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
Arun Mirpuri5d170872019-03-26 13:21:31 -0700536static int out_set_mmap_volume(struct audio_stream_out *stream, float left, float right);
Zhou Song2b8f28f2017-09-11 10:51:38 +0800537static int out_set_voip_volume(struct audio_stream_out *stream, float left, float right);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +0530538static int out_set_pcm_volume(struct audio_stream_out *stream, float left, float right);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +0530539
Derek Chen6f293672019-04-01 01:40:24 -0700540static void adev_snd_mon_cb(void *cookie, struct str_parms *parms);
541static void in_snd_mon_cb(void * stream, struct str_parms * parms);
542static void out_snd_mon_cb(void * stream, struct str_parms * parms);
543
Zhou Song331c8e52019-08-26 14:16:12 +0800544static int configure_btsco_sample_rate(snd_device_t snd_device);
545
Vatsal Buchac09ae062018-11-14 13:25:08 +0530546#ifdef AUDIO_FEATURE_ENABLED_GCOV
547extern void __gcov_flush();
548static void enable_gcov()
549{
550 __gcov_flush();
551}
552#else
553static void enable_gcov()
554{
555}
556#endif
557
justinweng20fb6d82019-02-21 18:49:00 -0700558static int in_set_microphone_direction(const struct audio_stream_in *stream,
559 audio_microphone_direction_t dir);
560static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom);
561
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700562static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id,
563 int flags __unused)
564{
565 int dir = 0;
566 switch (uc_id) {
567 case USECASE_AUDIO_RECORD_LOW_LATENCY:
Revathi Uddarajud9f23d92020-07-27 10:55:06 +0530568 case USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY:
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700569 dir = 1;
570 case USECASE_AUDIO_PLAYBACK_ULL:
571 break;
572 default:
573 return false;
574 }
575
576 int dev_id = platform_get_pcm_device_id(uc_id, dir == 0 ?
577 PCM_PLAYBACK : PCM_CAPTURE);
578 if (adev->adm_is_noirq_avail)
579 return adev->adm_is_noirq_avail(adev->adm_data,
580 adev->snd_card, dev_id, dir);
581 return false;
582}
583
584static void register_out_stream(struct stream_out *out)
585{
586 struct audio_device *adev = out->dev;
587 if (is_offload_usecase(out->usecase) ||
588 !adev->adm_register_output_stream)
589 return;
590
591 // register stream first for backward compatibility
592 adev->adm_register_output_stream(adev->adm_data,
593 out->handle,
594 out->flags);
595
596 if (!adev->adm_set_config)
597 return;
598
599 if (out->realtime)
600 adev->adm_set_config(adev->adm_data,
601 out->handle,
602 out->pcm, &out->config);
603}
604
605static void register_in_stream(struct stream_in *in)
606{
607 struct audio_device *adev = in->dev;
608 if (!adev->adm_register_input_stream)
609 return;
610
611 adev->adm_register_input_stream(adev->adm_data,
612 in->capture_handle,
613 in->flags);
614
615 if (!adev->adm_set_config)
616 return;
617
618 if (in->realtime)
619 adev->adm_set_config(adev->adm_data,
620 in->capture_handle,
621 in->pcm,
622 &in->config);
623}
624
625static void request_out_focus(struct stream_out *out, long ns)
626{
627 struct audio_device *adev = out->dev;
628
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700629 if (adev->adm_request_focus_v2)
630 adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
631 else if (adev->adm_request_focus)
632 adev->adm_request_focus(adev->adm_data, out->handle);
633}
634
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700635static int request_in_focus(struct stream_in *in, long ns)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700636{
637 struct audio_device *adev = in->dev;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700638 int ret = 0;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700639
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700640 if (adev->adm_request_focus_v2_1)
641 ret = adev->adm_request_focus_v2_1(adev->adm_data, in->capture_handle, ns);
642 else if (adev->adm_request_focus_v2)
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700643 adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
644 else if (adev->adm_request_focus)
645 adev->adm_request_focus(adev->adm_data, in->capture_handle);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -0700646
647 return ret;
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700648}
649
650static void release_out_focus(struct stream_out *out)
651{
652 struct audio_device *adev = out->dev;
653
654 if (adev->adm_abandon_focus)
655 adev->adm_abandon_focus(adev->adm_data, out->handle);
656}
657
658static void release_in_focus(struct stream_in *in)
659{
660 struct audio_device *adev = in->dev;
661 if (adev->adm_abandon_focus)
662 adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
663}
664
Dhananjay Kumare6293dd2017-05-25 17:25:30 +0530665static int parse_snd_card_status(struct str_parms *parms, int *card,
666 card_status_t *status)
667{
668 char value[32]={0};
669 char state[32]={0};
670
671 int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
672 if (ret < 0)
673 return -1;
674
675 // sscanf should be okay as value is of max length 32.
676 // same as sizeof state.
677 if (sscanf(value, "%d,%s", card, state) < 2)
678 return -1;
679
680 *status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
681 CARD_STATUS_OFFLINE;
682 return 0;
683}
684
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700685static inline void adjust_frames_for_device_delay(struct stream_out *out,
686 uint32_t *dsp_frames) {
687 // Adjustment accounts for A2dp encoder latency with offload usecases
688 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -0800689 if (is_a2dp_out_device_type(&out->device_list)) {
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -0700690 unsigned long offset =
691 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
692 *dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
693 }
694}
695
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700696static inline bool free_entry(void *key __unused,
697 void *value, void *context __unused)
698{
699 free(value);
700 return true;
701}
702
703static inline void free_map(Hashmap *map)
704{
705 if (map) {
706 hashmapForEach(map, free_entry, (void *) NULL);
707 hashmapFree(map);
708 }
709}
710
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800711static inline void patch_map_remove_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700712 audio_patch_handle_t patch_handle)
713{
714 if (patch_handle == AUDIO_PATCH_HANDLE_NONE)
715 return;
716
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700717 struct audio_patch_info *p_info =
718 hashmapGet(adev->patch_map, (void *) (intptr_t) patch_handle);
719 if (p_info) {
720 ALOGV("%s: Remove patch %d", __func__, patch_handle);
721 hashmapRemove(adev->patch_map, (void *) (intptr_t) patch_handle);
722 free(p_info->patch);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700723 free(p_info);
724 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700725}
726
727static inline int io_streams_map_insert(struct audio_device *adev,
728 struct audio_stream *stream,
729 audio_io_handle_t handle,
730 audio_patch_handle_t patch_handle)
731{
732 struct audio_stream_info *s_info =
733 (struct audio_stream_info *) calloc(1, sizeof(struct audio_stream_info));
734
735 if (s_info == NULL) {
736 ALOGE("%s: Could not allocate stream info", __func__);
737 return -ENOMEM;
738 }
739 s_info->stream = stream;
740 s_info->patch_handle = patch_handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700741
742 pthread_mutex_lock(&adev->lock);
743 struct audio_stream_info *stream_info =
744 hashmapPut(adev->io_streams_map, (void *) (intptr_t) handle, (void *) s_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700745 if (stream_info != NULL)
746 free(stream_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800747 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700748 ALOGV("%s: Added stream in io_streams_map with handle %d", __func__, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700749 return 0;
750}
751
752static inline void io_streams_map_remove(struct audio_device *adev,
753 audio_io_handle_t handle)
754{
755 pthread_mutex_lock(&adev->lock);
756 struct audio_stream_info *s_info =
757 hashmapRemove(adev->io_streams_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700758 if (s_info == NULL)
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800759 goto done;
Aniket Kumar Latad13758f2020-08-06 15:11:36 -0700760 ALOGV("%s: Removed stream with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800761 patch_map_remove_l(adev, s_info->patch_handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700762 free(s_info);
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800763done:
764 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700765 return;
766}
767
Aniket Kumar Latabc774842020-01-16 21:22:05 -0800768static struct audio_patch_info* fetch_patch_info_l(struct audio_device *adev,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700769 audio_patch_handle_t handle)
770{
771 struct audio_patch_info *p_info = NULL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700772 p_info = (struct audio_patch_info *)
773 hashmapGet(adev->patch_map, (void *) (intptr_t) handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -0700774 return p_info;
775}
776
vivek mehtaa76401a2015-04-24 14:12:15 -0700777__attribute__ ((visibility ("default")))
778bool audio_hw_send_gain_dep_calibration(int level) {
779 bool ret_val = false;
vivek mehtab72d08d2016-04-29 03:16:47 -0700780 ALOGV("%s: called ...", __func__);
vivek mehtaa76401a2015-04-24 14:12:15 -0700781
782 pthread_mutex_lock(&adev_init_lock);
783
784 if (adev != NULL && adev->platform != NULL) {
785 pthread_mutex_lock(&adev->lock);
786 ret_val = platform_send_gain_dep_cal(adev->platform, level);
vivek mehtab72d08d2016-04-29 03:16:47 -0700787
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +0530788 // cache level info for any of the use case which
789 // was not started.
790 last_known_cal_step = level;;
vivek mehtab72d08d2016-04-29 03:16:47 -0700791
vivek mehtaa76401a2015-04-24 14:12:15 -0700792 pthread_mutex_unlock(&adev->lock);
793 } else {
794 ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
795 }
796
797 pthread_mutex_unlock(&adev_init_lock);
798
799 return ret_val;
800}
801
Ashish Jain5106d362016-05-11 19:23:33 +0530802static int check_and_set_gapless_mode(struct audio_device *adev, bool enable_gapless)
803{
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800804 bool gapless_enabled = false;
805 const char *mixer_ctl_name = "Compress Gapless Playback";
806 struct mixer_ctl *ctl;
807
808 ALOGV("%s:", __func__);
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -0700809 gapless_enabled = property_get_bool("vendor.audio.offload.gapless.enabled", false);
Ashish Jain5106d362016-05-11 19:23:33 +0530810
811 /*Disable gapless if its AV playback*/
812 gapless_enabled = gapless_enabled && enable_gapless;
Krishnankutty Kolathappilly6d8788b2014-01-09 12:45:31 -0800813
814 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
815 if (!ctl) {
816 ALOGE("%s: Could not get ctl for mixer cmd - %s",
817 __func__, mixer_ctl_name);
818 return -EINVAL;
819 }
820
821 if (mixer_ctl_set_value(ctl, 0, gapless_enabled) < 0) {
822 ALOGE("%s: Could not set gapless mode %d",
823 __func__, gapless_enabled);
824 return -EINVAL;
825 }
826 return 0;
827}
Haynes Mathew George5191a852013-09-11 14:19:36 -0700828
Aniket Kumar Lataf56b6402016-10-27 12:03:18 -0700829__attribute__ ((visibility ("default")))
830int audio_hw_get_gain_level_mapping(struct amp_db_and_gain_table *mapping_tbl,
831 int table_size) {
832 int ret_val = 0;
833 ALOGV("%s: enter ... ", __func__);
834
835 pthread_mutex_lock(&adev_init_lock);
836 if (adev == NULL) {
837 ALOGW("%s: adev is NULL .... ", __func__);
838 goto done;
839 }
840
841 pthread_mutex_lock(&adev->lock);
842 ret_val = platform_get_gain_level_mapping(mapping_tbl, table_size);
843 pthread_mutex_unlock(&adev->lock);
844done:
845 pthread_mutex_unlock(&adev_init_lock);
846 ALOGV("%s: exit ... ", __func__);
847 return ret_val;
848}
849
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800850bool audio_hw_send_qdsp_parameter(int stream_type, float vol, bool active)
Aalique Grahame22e49102018-12-18 14:23:57 -0800851{
852 bool ret = false;
853 ALOGV("%s: enter ...", __func__);
854
855 pthread_mutex_lock(&adev_init_lock);
856
857 if (adev != NULL && adev->platform != NULL) {
858 pthread_mutex_lock(&adev->lock);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -0800859 ret = audio_extn_qdsp_set_state(adev, stream_type, vol, active);
Aalique Grahame22e49102018-12-18 14:23:57 -0800860 pthread_mutex_unlock(&adev->lock);
861 }
862
863 pthread_mutex_unlock(&adev_init_lock);
864
865 ALOGV("%s: exit with ret %d", __func__, ret);
866 return ret;
867}
Aalique Grahame22e49102018-12-18 14:23:57 -0800868
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700869static bool is_supported_format(audio_format_t format)
870{
Eric Laurent86e17132013-09-12 17:49:30 -0700871 if (format == AUDIO_FORMAT_MP3 ||
Satish Babu Patakokila0c313922016-12-08 12:07:08 +0530872 format == AUDIO_FORMAT_MP2 ||
Ashish Jainf9b78162014-08-25 20:36:25 +0530873 format == AUDIO_FORMAT_AAC_LC ||
874 format == AUDIO_FORMAT_AAC_HE_V1 ||
875 format == AUDIO_FORMAT_AAC_HE_V2 ||
Manish Dewangana6fc5442015-08-24 20:30:31 +0530876 format == AUDIO_FORMAT_AAC_ADTS_LC ||
877 format == AUDIO_FORMAT_AAC_ADTS_HE_V1 ||
878 format == AUDIO_FORMAT_AAC_ADTS_HE_V2 ||
Arun Kumar Dasari3b174182016-12-27 13:01:14 +0530879 format == AUDIO_FORMAT_AAC_LATM_LC ||
880 format == AUDIO_FORMAT_AAC_LATM_HE_V1 ||
881 format == AUDIO_FORMAT_AAC_LATM_HE_V2 ||
Ashish Jain5106d362016-05-11 19:23:33 +0530882 format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
883 format == AUDIO_FORMAT_PCM_8_24_BIT ||
Ashish Jainf1eaa582016-05-23 20:54:24 +0530884 format == AUDIO_FORMAT_PCM_FLOAT ||
885 format == AUDIO_FORMAT_PCM_32_BIT ||
vivek mehta0ea887a2015-08-26 14:01:20 -0700886 format == AUDIO_FORMAT_PCM_16_BIT ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +0530887 format == AUDIO_FORMAT_AC3 ||
888 format == AUDIO_FORMAT_E_AC3 ||
Ben Romberger1aaaf862017-04-06 17:49:46 -0700889 format == AUDIO_FORMAT_DOLBY_TRUEHD ||
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +0530890 format == AUDIO_FORMAT_DTS ||
891 format == AUDIO_FORMAT_DTS_HD ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +0800892 format == AUDIO_FORMAT_FLAC ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +0530893 format == AUDIO_FORMAT_ALAC ||
894 format == AUDIO_FORMAT_APE ||
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +0530895 format == AUDIO_FORMAT_DSD ||
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +0530896 format == AUDIO_FORMAT_VORBIS ||
Weiyin Jiang18ac4e92015-03-15 15:03:40 +0800897 format == AUDIO_FORMAT_WMA ||
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +0530898 format == AUDIO_FORMAT_WMA_PRO ||
Naresh Tanniru928f0862017-04-07 16:44:23 -0700899 format == AUDIO_FORMAT_APTX ||
900 format == AUDIO_FORMAT_IEC61937)
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -0800901 return true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700902
903 return false;
904}
905
Kunlei Zhang67cc7072020-12-18 17:16:49 +0800906static bool is_supported_conc_usecase_for_power_mode_call(struct audio_device *adev)
907{
908 struct listnode *node;
909 struct audio_usecase *usecase;
910
911 list_for_each(node, &adev->usecase_list) {
912 usecase = node_to_item(node, struct audio_usecase, list);
913 if (usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
914 ALOGD("%s: FM usecase is active, not setting power mode", __func__);
915 return false;
916 }
917 }
918
919 return true;
920}
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700921static inline bool is_mmap_usecase(audio_usecase_t uc_id)
922{
923 return (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY) ||
Zhou Song62ea0282020-03-22 19:53:01 +0800924 (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY2) ||
Haynes Mathew George5beddd42016-06-27 18:33:40 -0700925 (uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
926}
927
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -0700928static inline bool is_valid_volume(float left, float right)
929{
930 return ((left >= 0.0f && right >= 0.0f) ? true : false);
931}
932
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +0530933static void enable_asrc_mode(struct audio_device *adev)
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +0530934{
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +0530935 ALOGV("%s", __func__);
936 audio_route_apply_and_update_path(adev->audio_route,
937 "asrc-mode");
938 adev->asrc_mode_enabled = true;
939}
940
941static void disable_asrc_mode(struct audio_device *adev)
942{
943 ALOGV("%s", __func__);
944 audio_route_reset_and_update_path(adev->audio_route,
945 "asrc-mode");
946 adev->asrc_mode_enabled = false;
947}
948
Saurav Kumarc1411662020-10-14 10:50:45 +0530949static void check_and_configure_headphone(struct audio_device *adev,
950 struct audio_usecase *uc_info,
951 snd_device_t snd_device)
952{
953 struct listnode *node;
954 struct audio_usecase *usecase;
955 int new_backend_idx, usecase_backend_idx;
956 bool spkr_hph_single_be_native_concurrency;
957
958 new_backend_idx = platform_get_backend_index(snd_device);
959 spkr_hph_single_be_native_concurrency = platform_get_spkr_hph_single_be_native_concurrency_flag();
Zhou Songd4b18c42021-01-14 15:15:29 +0800960 if ((spkr_hph_single_be_native_concurrency && (new_backend_idx == DEFAULT_CODEC_BACKEND)) ||
961 uc_info->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
Saurav Kumarc1411662020-10-14 10:50:45 +0530962 list_for_each(node, &adev->usecase_list) {
963 usecase = node_to_item(node, struct audio_usecase, list);
964 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info)) {
965 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
966 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
967 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
968 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
969 disable_audio_route(adev, usecase);
970 disable_snd_device(adev, usecase->out_snd_device);
971 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
Saurav Kumar70902382020-10-28 11:16:04 +0530972 platform_check_and_set_codec_backend_cfg(adev, usecase,
973 usecase->out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +0530974 enable_snd_device(adev, usecase->out_snd_device);
Zhou Songd4b18c42021-01-14 15:15:29 +0800975 enable_audio_route(adev, usecase);
Saurav Kumarc1411662020-10-14 10:50:45 +0530976 }
977 }
Revathi Uddaraju2c0eac02021-07-27 02:06:42 -0700978 else if ((usecase->type != PCM_CAPTURE) && (usecase == uc_info)) {
979 usecase_backend_idx = platform_get_backend_index(usecase->out_snd_device);
980 if (((usecase_backend_idx == HEADPHONE_BACKEND) ||
981 (usecase_backend_idx == HEADPHONE_44_1_BACKEND)) &&
982 ((usecase->stream.out->sample_rate % OUTPUT_SAMPLING_RATE_44100) == 0)) {
983 usecase->stream.out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
984 platform_check_and_set_codec_backend_cfg(adev, usecase,
985 usecase->out_snd_device);
986 }
987 }
Saurav Kumarc1411662020-10-14 10:50:45 +0530988 }
989 }
990}
991
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +0530992/*
993 * - Enable ASRC mode for incoming mix path use case(Headphone backend)if Headphone
994 * 44.1 or Native DSD backends are enabled for any of current use case.
995 * e.g. 48-> + (Naitve DSD or Headphone 44.1)
996 * - Disable current mix path use case(Headphone backend) and re-enable it with
997 * ASRC mode for incoming Headphone 44.1 or Native DSD use case.
998 * e.g. Naitve DSD or Headphone 44.1 -> + 48
999 */
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301000static void check_and_set_asrc_mode(struct audio_device *adev,
1001 struct audio_usecase *uc_info,
1002 snd_device_t snd_device)
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301003{
1004 ALOGV("%s snd device %d", __func__, snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301005 int i, num_new_devices = 0;
1006 snd_device_t split_new_snd_devices[SND_DEVICE_OUT_END];
1007 /*
1008 *Split snd device for new combo use case
1009 *e.g. Headphopne 44.1-> + Ringtone (Headphone + Speaker)
1010 */
1011 if (platform_split_snd_device(adev->platform,
1012 snd_device,
1013 &num_new_devices,
1014 split_new_snd_devices) == 0) {
1015 for (i = 0; i < num_new_devices; i++)
1016 check_and_set_asrc_mode(adev, uc_info, split_new_snd_devices[i]);
1017 } else {
1018 int new_backend_idx = platform_get_backend_index(snd_device);
1019 if (((new_backend_idx == HEADPHONE_BACKEND) ||
1020 (new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1021 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1022 !adev->asrc_mode_enabled) {
1023 struct listnode *node = NULL;
1024 struct audio_usecase *uc = NULL;
1025 struct stream_out *curr_out = NULL;
1026 int usecase_backend_idx = DEFAULT_CODEC_BACKEND;
1027 int i, num_devices, ret = 0;
1028 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301029
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301030 list_for_each(node, &adev->usecase_list) {
1031 uc = node_to_item(node, struct audio_usecase, list);
1032 curr_out = (struct stream_out*) uc->stream.out;
1033 if (curr_out && PCM_PLAYBACK == uc->type && uc != uc_info) {
1034 /*
1035 *Split snd device for existing combo use case
1036 *e.g. Ringtone (Headphone + Speaker) + Headphopne 44.1
1037 */
1038 ret = platform_split_snd_device(adev->platform,
1039 uc->out_snd_device,
1040 &num_devices,
1041 split_snd_devices);
1042 if (ret < 0 || num_devices == 0) {
1043 ALOGV("%s: Unable to split uc->out_snd_device: %d",__func__, uc->out_snd_device);
1044 split_snd_devices[0] = uc->out_snd_device;
1045 num_devices = 1;
Garmond Leung50058f62017-02-08 09:49:30 -08001046 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301047 for (i = 0; i < num_devices; i++) {
1048 usecase_backend_idx = platform_get_backend_index(split_snd_devices[i]);
1049 ALOGD("%s:snd_dev %d usecase_backend_idx %d",__func__, split_snd_devices[i],usecase_backend_idx);
1050 if((new_backend_idx == HEADPHONE_BACKEND) &&
1051 ((usecase_backend_idx == HEADPHONE_44_1_BACKEND) ||
1052 (usecase_backend_idx == DSD_NATIVE_BACKEND))) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001053 ALOGV("%s:DSD or native stream detected enabling asrcmode in hardware",
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301054 __func__);
1055 enable_asrc_mode(adev);
1056 break;
1057 } else if(((new_backend_idx == HEADPHONE_44_1_BACKEND) ||
1058 (new_backend_idx == DSD_NATIVE_BACKEND)) &&
1059 (usecase_backend_idx == HEADPHONE_BACKEND)) {
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07001060 ALOGV("%s: 48K stream detected, disabling and enabling it \
1061 with asrcmode in hardware", __func__);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301062 disable_audio_route(adev, uc);
1063 disable_snd_device(adev, uc->out_snd_device);
1064 // Apply true-high-quality-mode if DSD or > 44.1KHz or >=24-bit
1065 if (new_backend_idx == DSD_NATIVE_BACKEND)
1066 audio_route_apply_and_update_path(adev->audio_route,
1067 "hph-true-highquality-mode");
1068 else if ((new_backend_idx == HEADPHONE_44_1_BACKEND) &&
1069 (curr_out->bit_width >= 24))
1070 audio_route_apply_and_update_path(adev->audio_route,
1071 "hph-highquality-mode");
1072 enable_asrc_mode(adev);
1073 enable_snd_device(adev, uc->out_snd_device);
1074 enable_audio_route(adev, uc);
1075 break;
1076 }
1077 }
1078 // reset split devices count
1079 num_devices = 0;
Garmond Leung50058f62017-02-08 09:49:30 -08001080 }
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05301081 if (adev->asrc_mode_enabled)
1082 break;
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301083 }
1084 }
1085 }
1086}
1087
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001088static int send_effect_enable_disable_mixer_ctl(struct audio_device *adev,
1089 struct audio_effect_config effect_config,
1090 unsigned int param_value)
1091{
1092 char mixer_ctl_name[] = "Audio Effect";
1093 struct mixer_ctl *ctl;
1094 long set_values[6];
Eric Laurent637e2d42018-11-15 12:24:31 -08001095 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001096
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001097 if (in == NULL) {
1098 ALOGE("%s: active input stream is NULL", __func__);
1099 return -EINVAL;
1100 }
1101
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001102 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
1103 if (!ctl) {
1104 ALOGE("%s: Could not get mixer ctl - %s",
1105 __func__, mixer_ctl_name);
1106 return -EINVAL;
1107 }
1108
1109 set_values[0] = 1; //0:Rx 1:Tx
1110 set_values[1] = in->app_type_cfg.app_type;
1111 set_values[2] = (long)effect_config.module_id;
1112 set_values[3] = (long)effect_config.instance_id;
1113 set_values[4] = (long)effect_config.param_id;
1114 set_values[5] = param_value;
1115
1116 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
1117
1118 return 0;
1119
1120}
1121
1122static int update_effect_param_ecns(struct audio_device *adev, unsigned int module_id,
1123 int effect_type, unsigned int *param_value)
1124{
1125 int ret = 0;
1126 struct audio_effect_config other_effect_config;
1127 struct audio_usecase *usecase = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08001128 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001129
Aniket Kumar Lata7de63522019-06-13 11:05:18 -07001130 if (in == NULL) {
1131 ALOGE("%s: active input stream is NULL", __func__);
1132 return -EINVAL;
1133 }
1134
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001135 usecase = get_usecase_from_list(adev, in->usecase);
1136 if (!usecase)
1137 return -EINVAL;
1138
1139 ret = platform_get_effect_config_data(usecase->in_snd_device, &other_effect_config,
1140 effect_type == EFFECT_AEC ? EFFECT_NS : EFFECT_AEC);
1141 if (ret < 0) {
1142 ALOGE("%s Failed to get effect params %d", __func__, ret);
1143 return ret;
1144 }
1145
1146 if (module_id == other_effect_config.module_id) {
1147 //Same module id for AEC/NS. Values need to be combined
1148 if (((effect_type == EFFECT_AEC) && (in->enable_ns)) ||
1149 ((effect_type == EFFECT_NS) && (in->enable_aec))) {
1150 *param_value |= other_effect_config.param_value;
1151 }
1152 }
1153
1154 return ret;
1155}
1156
1157static int enable_disable_effect(struct audio_device *adev, int effect_type, bool enable)
Gangadhar Sb0210342019-02-22 17:39:41 +05301158{
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001159 struct audio_effect_config effect_config;
1160 struct audio_usecase *usecase = NULL;
1161 int ret = 0;
1162 unsigned int param_value = 0;
Eric Laurent637e2d42018-11-15 12:24:31 -08001163 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001164
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001165 if(!voice_extn_is_dynamic_ecns_enabled())
1166 return ENOSYS;
1167
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001168 if (!in) {
1169 ALOGE("%s: Invalid input stream", __func__);
1170 return -EINVAL;
1171 }
1172
1173 ALOGD("%s: effect_type:%d enable:%d", __func__, effect_type, enable);
1174
1175 usecase = get_usecase_from_list(adev, in->usecase);
Weiyin Jiang20d3fa62018-08-01 18:06:27 +08001176 if (usecase == NULL) {
1177 ALOGE("%s: Could not find the usecase (%d) in the list",
1178 __func__, in->usecase);
1179 return -EINVAL;
1180 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001181
1182 ret = platform_get_effect_config_data(usecase->in_snd_device, &effect_config, effect_type);
1183 if (ret < 0) {
1184 ALOGE("%s Failed to get module id %d", __func__, ret);
1185 return ret;
1186 }
1187 ALOGV("%s: %d %d usecase->id:%d usecase->in_snd_device:%d", __func__, effect_config.module_id,
1188 in->app_type_cfg.app_type, usecase->id, usecase->in_snd_device);
1189
1190 if(enable)
1191 param_value = effect_config.param_value;
1192
1193 /*Special handling for AEC & NS effects Param values need to be
1194 updated if module ids are same*/
1195
1196 if ((effect_type == EFFECT_AEC) || (effect_type == EFFECT_NS)) {
1197 ret = update_effect_param_ecns(adev, effect_config.module_id, effect_type, &param_value);
1198 if (ret < 0)
1199 return ret;
1200 }
1201
1202 ret = send_effect_enable_disable_mixer_ctl(adev, effect_config, param_value);
1203
1204 return ret;
1205}
1206
1207static void check_and_enable_effect(struct audio_device *adev)
1208{
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08001209 if(!voice_extn_is_dynamic_ecns_enabled())
1210 return;
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001211
Eric Laurent637e2d42018-11-15 12:24:31 -08001212 struct stream_in *in = adev_get_active_input(adev);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001213
Eric Laurent637e2d42018-11-15 12:24:31 -08001214 if (in != NULL && !in->standby) {
1215 if (in->enable_aec)
1216 enable_disable_effect(adev, EFFECT_AEC, true);
1217
1218 if (in->enable_ns &&
1219 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
1220 enable_disable_effect(adev, EFFECT_NS, true);
1221 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001222 }
1223}
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07001224
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07001225int pcm_ioctl(struct pcm *pcm, int request, ...)
1226{
1227 va_list ap;
1228 void * arg;
1229 int pcm_fd = *(int*)pcm;
1230
1231 va_start(ap, request);
1232 arg = va_arg(ap, void *);
1233 va_end(ap);
1234
1235 return ioctl(pcm_fd, request, arg);
1236}
1237
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001238int enable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001239 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001240{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001241 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001242 char mixer_path[MIXER_PATH_MAX_LENGTH];
Manish Dewangan58229382017-02-02 15:48:41 +05301243 struct stream_out *out = NULL;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301244 struct stream_in *in = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001245 struct listnode out_devices;
Soumya Managoli6993b762018-06-28 16:04:57 +05301246 int ret = 0;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001247
1248 if (usecase == NULL)
1249 return -EINVAL;
1250
1251 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
1252
Carter Hsu2e429db2019-05-14 18:50:52 +08001253 if (usecase->type == PCM_CAPTURE) {
1254 struct stream_in *in = usecase->stream.in;
1255 struct audio_usecase *uinfo;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001256 snd_device = usecase->in_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001257
1258 if (in) {
1259 if (in->enable_aec || in->enable_ec_port) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001260 list_init(&out_devices);
1261 update_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "", true);
Carter Hsu2e429db2019-05-14 18:50:52 +08001262 struct listnode *node;
1263 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
1264 USECASE_AUDIO_PLAYBACK_VOIP);
1265 if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001266 assign_devices(&out_devices,
1267 &voip_usecase->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001268 } else if (adev->primary_output &&
1269 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001270 assign_devices(&out_devices,
1271 &adev->primary_output->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001272 } else {
1273 list_for_each(node, &adev->usecase_list) {
1274 uinfo = node_to_item(node, struct audio_usecase, list);
1275 if (uinfo->type != PCM_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001276 assign_devices(&out_devices,
1277 &uinfo->stream.out->device_list);
Carter Hsu2e429db2019-05-14 18:50:52 +08001278 break;
1279 }
1280 }
1281 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001282
1283 platform_set_echo_reference(adev, true, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001284 in->ec_opened = true;
1285 }
1286 }
Guodong Huf5e614d2019-06-24 18:42:03 +08001287 } else if ((usecase->type == TRANSCODE_LOOPBACK_TX) || ((usecase->type == PCM_HFP_CALL) &&
1288 ((usecase->id == USECASE_AUDIO_HFP_SCO) || (usecase->id == USECASE_AUDIO_HFP_SCO_WB)) &&
1289 (usecase->in_snd_device == SND_DEVICE_IN_VOICE_SPEAKER_MIC_HFP_MMSECNS))) {
Carter Hsu2e429db2019-05-14 18:50:52 +08001290 snd_device = usecase->in_snd_device;
1291 } else {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001292 snd_device = usecase->out_snd_device;
Carter Hsu2e429db2019-05-14 18:50:52 +08001293 }
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001294
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001295 if (usecase->type == PCM_CAPTURE) {
1296 if (platform_get_fluence_nn_state(adev->platform) == 0) {
1297 platform_set_fluence_nn_state(adev->platform, true);
1298 ALOGD("%s: set fluence nn capture state", __func__);
1299 }
1300 }
1301
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08001302#ifdef DS1_DOLBY_DAP_ENABLED
1303 audio_extn_dolby_set_dmid(adev);
1304 audio_extn_dolby_set_endpoint(adev);
1305#endif
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -07001306 audio_extn_dolby_ds2_set_endpoint(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001307 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301308 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_BUSY);
Ben Romberger1fafdde2015-09-09 19:43:15 -07001309 audio_extn_utils_send_app_type_cfg(adev, usecase);
Jasmine Cha4dcc1092019-03-04 18:12:47 +08001310 if (audio_extn_is_maxx_audio_enabled())
1311 audio_extn_ma_set_device(usecase);
Dhananjay Kumar14170dd2015-08-28 13:24:16 +05301312 audio_extn_utils_send_audio_calibration(adev, usecase);
Zhou Songbaddf9f2020-11-20 13:57:39 +08001313 if ((usecase->type == PCM_PLAYBACK) && is_offload_usecase(usecase->id)) {
1314 out = usecase->stream.out;
1315 if (out && out->compr)
Manish Dewangan58229382017-02-02 15:48:41 +05301316 audio_extn_utils_compress_set_clk_rec_mode(usecase);
1317 }
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301318
1319 if (usecase->type == PCM_CAPTURE) {
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001320 if (platform_get_fluence_nn_state(adev->platform) == 1 &&
1321 adev->fluence_nn_usecase_id == USECASE_INVALID ) {
1322 adev->fluence_nn_usecase_id = usecase->id;
1323 ALOGD("%s: assign fluence nn usecase %d", __func__, usecase->id);
1324 }
1325 }
1326
1327 if (usecase->type == PCM_CAPTURE) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301328 in = usecase->stream.in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001329 if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301330 ALOGD("%s: set custom mtmx params v1", __func__);
1331 audio_extn_set_custom_mtmx_params_v1(adev, usecase, true);
1332 }
1333 } else {
1334 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
1335 }
Manish Dewangan58229382017-02-02 15:48:41 +05301336
Andy Hung756ecc12018-10-19 17:47:12 -07001337 // we shouldn't truncate mixer_path
1338 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1339 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1340 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001341 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001342 ALOGD("%s: apply mixer and update path: %s", __func__, mixer_path);
Soumya Managoli6993b762018-06-28 16:04:57 +05301343 ret = audio_route_apply_and_update_path(adev->audio_route, mixer_path);
1344 if (!ret && usecase->id == USECASE_AUDIO_PLAYBACK_FM) {
1345 struct str_parms *parms = str_parms_create_str("fm_restore_volume=1");
1346 if (parms) {
1347 audio_extn_fm_set_parameters(adev, parms);
1348 str_parms_destroy(parms);
1349 }
1350 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001351 ALOGV("%s: exit", __func__);
1352 return 0;
1353}
1354
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001355int disable_audio_route(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001356 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001357{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001358 snd_device_t snd_device;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001359 char mixer_path[MIXER_PATH_MAX_LENGTH];
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301360 struct stream_in *in = NULL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001361
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05301362 if (usecase == NULL || usecase->id == USECASE_INVALID)
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001363 return -EINVAL;
1364
1365 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
Surendar Karka93cd25a2018-08-28 14:21:37 +05301366 if (usecase->type == PCM_CAPTURE || usecase->type == TRANSCODE_LOOPBACK_TX)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001367 snd_device = usecase->in_snd_device;
1368 else
1369 snd_device = usecase->out_snd_device;
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001370
1371 /* disable island and power mode on supported device for voice call */
1372 if (usecase->type == VOICE_CALL) {
1373 if (usecase->in_snd_device != SND_DEVICE_NONE) {
1374 if (platform_get_island_cfg_on_device(adev->platform, usecase->in_snd_device) &&
1375 platform_get_power_mode_on_device(adev->platform, usecase->in_snd_device)) {
1376 platform_set_island_cfg_on_device(adev, usecase->in_snd_device, false);
1377 platform_set_power_mode_on_device(adev, usecase->in_snd_device, false);
1378 platform_reset_island_power_status(adev->platform, usecase->in_snd_device);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001379 if (voice_is_lte_call_active(adev))
1380 platform_set_tx_lpi_mode(adev->platform, false);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001381 ALOGD("%s: disable island cfg and power mode in voice tx path",
1382 __func__);
1383 }
1384 }
1385 if (usecase->out_snd_device != SND_DEVICE_NONE) {
1386 if (platform_get_island_cfg_on_device(adev->platform, usecase->out_snd_device) &&
1387 platform_get_power_mode_on_device(adev->platform, usecase->out_snd_device)) {
1388 platform_set_island_cfg_on_device(adev, usecase->out_snd_device, false);
1389 platform_set_power_mode_on_device(adev, usecase->out_snd_device, false);
1390 platform_reset_island_power_status(adev->platform, usecase->out_snd_device);
1391 ALOGD("%s: disable island cfg and power mode in voice rx path",
1392 __func__);
1393 }
1394 }
1395 }
1396
Andy Hung756ecc12018-10-19 17:47:12 -07001397 // we shouldn't truncate mixer_path
1398 ALOGW_IF(strlcpy(mixer_path, use_case_table[usecase->id], sizeof(mixer_path))
1399 >= sizeof(mixer_path), "%s: truncation on mixer path", __func__);
1400 // this also appends to mixer_path
Banajit Goswami20cdd212015-09-11 01:11:30 -07001401 platform_add_backend_name(mixer_path, snd_device, usecase);
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001402 ALOGD("%s: reset and update mixer path: %s", __func__, mixer_path);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001403 audio_route_reset_and_update_path(adev->audio_route, mixer_path);
Carter Hsu2e429db2019-05-14 18:50:52 +08001404 if (usecase->type == PCM_CAPTURE) {
1405 struct stream_in *in = usecase->stream.in;
1406 if (in && in->ec_opened) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001407 struct listnode out_devices;
1408 list_init(&out_devices);
1409 platform_set_echo_reference(in->dev, false, &out_devices);
Carter Hsu2e429db2019-05-14 18:50:52 +08001410 in->ec_opened = false;
1411 }
1412 }
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +08001413 if (usecase->id == adev->fluence_nn_usecase_id) {
1414 platform_set_fluence_nn_state(adev->platform, false);
1415 adev->fluence_nn_usecase_id = USECASE_INVALID;
1416 ALOGD("%s: reset fluence nn capture state", __func__);
1417 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001418 audio_extn_sound_trigger_update_stream_status(usecase, ST_EVENT_STREAM_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301419 audio_extn_listen_update_stream_status(usecase, LISTEN_EVENT_STREAM_FREE);
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301420
1421 if (usecase->type == PCM_CAPTURE) {
1422 in = usecase->stream.in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001423 if (in && is_loopback_input_device(get_device_types(&in->device_list))) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301424 ALOGD("%s: reset custom mtmx params v1", __func__);
1425 audio_extn_set_custom_mtmx_params_v1(adev, usecase, false);
1426 }
1427 } else {
1428 audio_extn_set_custom_mtmx_params_v2(adev, usecase, false);
1429 }
1430
Weiyin Jiang298ffd92019-06-03 14:29:30 +08001431 if ((usecase->type == PCM_PLAYBACK) &&
1432 (usecase->stream.out != NULL))
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05301433 usecase->stream.out->pspd_coeff_sent = false;
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05301434
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001435 ALOGV("%s: exit", __func__);
1436 return 0;
1437}
1438
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001439int enable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001440 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001441{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301442 int i, num_devices = 0;
1443 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001444 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1445
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001446 if (snd_device < SND_DEVICE_MIN ||
1447 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001448 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001449 return -EINVAL;
1450 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001451
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001452 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001453 ALOGE("%s: Invalid sound device returned", __func__);
1454 return -EINVAL;
1455 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001456
1457 adev->snd_dev_ref_cnt[snd_device]++;
1458
1459 if ((adev->snd_dev_ref_cnt[snd_device] > 1) &&
1460 (platform_split_snd_device(adev->platform,
1461 snd_device,
1462 &num_devices,
1463 new_snd_devices) != 0)) {
Eric Laurent994a6932013-07-17 11:51:42 -07001464 ALOGV("%s: snd_device(%d: %s) is already active",
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001465 __func__, snd_device, device_name);
Aniket Kumar Lata990de552019-07-11 14:20:23 -07001466 /* Set backend config for A2DP to ensure slimbus configuration
1467 is correct if A2DP is already active and backend is closed
1468 and re-opened */
1469 if (snd_device == SND_DEVICE_OUT_BT_A2DP)
1470 audio_extn_a2dp_set_source_backend_cfg();
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001471 return 0;
1472 }
1473
Gopikrishnaiah Anandane85d0462014-06-30 21:41:20 -07001474 if (audio_extn_spkr_prot_is_enabled())
1475 audio_extn_spkr_prot_calib_cancel(adev);
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001476
Aalique Grahame22e49102018-12-18 14:23:57 -08001477 audio_extn_dsm_feedback_enable(adev, snd_device, true);
1478
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001479 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1480 audio_extn_spkr_prot_is_enabled()) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001481 if (platform_get_spkr_prot_acdb_id(snd_device) < 0) {
1482 goto err;
1483 }
1484 audio_extn_dev_arbi_acquire(snd_device);
1485 if (audio_extn_spkr_prot_start_processing(snd_device)) {
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001486 ALOGE("%s: spkr_start_processing failed", __func__);
Ravit Dennisaaee49c2015-02-04 21:26:22 +02001487 audio_extn_dev_arbi_release(snd_device);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001488 goto err;
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001489 }
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001490 } else if (platform_split_snd_device(adev->platform,
1491 snd_device,
1492 &num_devices,
1493 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301494 for (i = 0; i < num_devices; i++) {
1495 enable_snd_device(adev, new_snd_devices[i]);
1496 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001497 platform_set_speaker_gain_in_combo(adev, snd_device, true);
Vidyakumar Athota1c6419a2014-01-10 14:47:34 -08001498 } else {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001499 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301500
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001501 /* enable island and power mode on supported device */
1502 if (platform_get_island_cfg_on_device(adev->platform, snd_device) &&
1503 platform_get_power_mode_on_device(adev->platform, snd_device)) {
1504 platform_set_island_cfg_on_device(adev, snd_device, true);
1505 platform_set_power_mode_on_device(adev, snd_device, true);
Kunlei Zhang91c4b332020-07-20 17:53:14 +08001506 if (voice_is_lte_call_active(adev) &&
1507 (snd_device >= SND_DEVICE_IN_BEGIN &&
1508 snd_device < SND_DEVICE_IN_END))
1509 platform_set_tx_lpi_mode(adev->platform, true);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001510 ALOGD("%s: enable island cfg and power mode on: %s",
1511 __func__, device_name);
1512 }
Preetam Singh Ranawatf1d417c2017-01-10 17:00:32 +05301513
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301514 if (SND_DEVICE_OUT_BT_A2DP == snd_device) {
Ramjee Singh2d2944a2021-12-14 14:13:41 +05301515
1516 struct audio_usecase *usecase;
1517 struct listnode *node;
1518 /* Disable SCO Devices and enable handset mic for active input stream */
1519 list_for_each(node, &adev->usecase_list) {
1520 usecase = node_to_item(node, struct audio_usecase, list);
1521 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
1522 is_sco_in_device_type(&usecase->stream.in->device_list)) {
1523 ALOGD("a2dp resumed, switch bt sco mic to handset mic");
1524 reassign_device_list(&usecase->stream.in->device_list,
1525 AUDIO_DEVICE_IN_BUILTIN_MIC, "");
1526 select_devices(adev, usecase->id);
1527 }
1528 }
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301529 if (audio_extn_a2dp_start_playback() < 0) {
1530 ALOGE(" fail to configure A2dp Source control path ");
1531 goto err;
1532 } else {
1533 adev->a2dp_started = true;
1534 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001535 }
Florian Pfister1a84f312018-07-19 14:38:18 +02001536
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001537 if ((SND_DEVICE_IN_BT_A2DP == snd_device) &&
1538 (audio_extn_a2dp_start_capture() < 0)) {
1539 ALOGE(" fail to configure A2dp Sink control path ");
1540 goto err;
1541 }
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301542
Mingshu Pang7be5b1d2020-03-04 15:24:38 +08001543 if ((SND_DEVICE_OUT_BT_SCO_SWB == snd_device) ||
1544 (SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC == snd_device) ||
1545 (SND_DEVICE_IN_BT_SCO_MIC_SWB == snd_device)) {
1546 if (!adev->bt_sco_on || (audio_extn_sco_start_configuration() < 0)) {
1547 ALOGE(" fail to configure sco control path ");
1548 goto err;
1549 }
Zhou Song12c29502019-03-16 10:37:18 +08001550 }
1551
Zhou Song331c8e52019-08-26 14:16:12 +08001552 configure_btsco_sample_rate(snd_device);
Bharath Ramachandramurthy0de16782014-03-28 21:34:33 -07001553 /* due to the possibility of calibration overwrite between listen
1554 and audio, notify listen hal before audio calibration is sent */
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001555 audio_extn_sound_trigger_update_device_status(snd_device,
1556 ST_EVENT_SND_DEVICE_BUSY);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301557 audio_extn_listen_update_device_status(snd_device,
1558 LISTEN_EVENT_SND_DEVICE_BUSY);
Subhash Chandra Bose Naripeddy54274672014-03-10 14:51:02 -07001559 if (platform_get_snd_device_acdb_id(snd_device) < 0) {
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001560 audio_extn_sound_trigger_update_device_status(snd_device,
1561 ST_EVENT_SND_DEVICE_FREE);
Dhananjay Kumar45b71742014-05-29 21:47:27 +05301562 audio_extn_listen_update_device_status(snd_device,
1563 LISTEN_EVENT_SND_DEVICE_FREE);
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001564 goto err;
Gopikrishnaiah Anandanf538cef2013-10-28 14:06:03 -07001565 }
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001566 audio_extn_dev_arbi_acquire(snd_device);
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001567 audio_route_apply_and_update_path(adev->audio_route, device_name);
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301568
1569 if (SND_DEVICE_OUT_HEADPHONES == snd_device &&
1570 !adev->native_playback_enabled &&
1571 audio_is_true_native_stream_active(adev)) {
1572 ALOGD("%s: %d: napb: enabling native mode in hardware",
1573 __func__, __LINE__);
1574 audio_route_apply_and_update_path(adev->audio_route,
1575 "true-native-mode");
1576 adev->native_playback_enabled = true;
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301577 }
Dhanalakshmi Siddani10621622018-04-30 15:07:27 +05301578 if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
1579 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001580 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001581 ALOGD("%s: init ec ref loopback", __func__);
1582 audio_extn_ffv_init_ec_ref_loopback(adev, snd_device);
1583 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001584 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001585 return 0;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001586err:
1587 adev->snd_dev_ref_cnt[snd_device]--;
1588 return -EINVAL;;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001589}
1590
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07001591int disable_snd_device(struct audio_device *adev,
Haynes Mathew George1376ca62014-04-24 11:55:48 -07001592 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001593{
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301594 int i, num_devices = 0;
1595 snd_device_t new_snd_devices[SND_DEVICE_OUT_END];
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001596 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
1597
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001598 if (snd_device < SND_DEVICE_MIN ||
1599 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001600 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001601 return -EINVAL;
1602 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001603
1604 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0) {
1605 ALOGE("%s: Invalid sound device returned", __func__);
1606 return -EINVAL;
1607 }
1608
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001609 if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
1610 ALOGE("%s: device ref cnt is already 0", __func__);
1611 return -EINVAL;
1612 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001613
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001614 adev->snd_dev_ref_cnt[snd_device]--;
Apoorv Raghuvanshi5792d4b2013-10-07 18:40:05 -07001615
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001616
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001617 if (adev->snd_dev_ref_cnt[snd_device] == 0) {
Ravi Kumar Alamandac7d9bef2015-09-30 22:27:26 -07001618 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301619
Aalique Grahame22e49102018-12-18 14:23:57 -08001620 audio_extn_dsm_feedback_enable(adev, snd_device, false);
1621
Xiaojun Sang040cc9f2015-08-03 19:38:28 +08001622 if (platform_can_enable_spkr_prot_on_device(snd_device) &&
1623 audio_extn_spkr_prot_is_enabled()) {
Anish Kumar46c7b872014-09-09 01:49:44 -07001624 audio_extn_spkr_prot_stop_processing(snd_device);
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07001625
1626 // when speaker device is disabled, reset swap.
1627 // will be renabled on usecase start
1628 platform_set_swap_channels(adev, false);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001629 } else if (platform_split_snd_device(adev->platform,
1630 snd_device,
1631 &num_devices,
1632 new_snd_devices) == 0) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301633 for (i = 0; i < num_devices; i++) {
1634 disable_snd_device(adev, new_snd_devices[i]);
1635 }
Aalique Grahame22e49102018-12-18 14:23:57 -08001636 platform_set_speaker_gain_in_combo(adev, snd_device, false);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001637 } else {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001638 audio_route_reset_and_update_path(adev->audio_route, device_name);
Lior Barenboim0b61bc72014-05-13 13:01:37 +03001639 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07001640
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301641 if (snd_device == SND_DEVICE_OUT_BT_A2DP) {
Naresh Tannirucd2353e2016-08-19 00:37:25 +05301642 audio_extn_a2dp_stop_playback();
Revathi Uddarajub26e3932020-06-10 14:51:02 +05301643 adev->a2dp_started = false;
1644 } else if (snd_device == SND_DEVICE_IN_BT_A2DP)
Florian Pfister1a84f312018-07-19 14:38:18 +02001645 audio_extn_a2dp_stop_capture();
Zhou Songd6d71752019-05-21 18:08:51 +08001646 else if ((snd_device == SND_DEVICE_OUT_HDMI) ||
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001647 (snd_device == SND_DEVICE_OUT_DISPLAY_PORT))
Ashish Jain81eb2a82015-05-13 10:52:34 +05301648 adev->is_channel_status_set = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001649 else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301650 adev->native_playback_enabled) {
1651 ALOGD("%s: %d: napb: disabling native mode in hardware",
1652 __func__, __LINE__);
1653 audio_route_reset_and_update_path(adev->audio_route,
1654 "true-native-mode");
1655 adev->native_playback_enabled = false;
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001656 } else if ((snd_device == SND_DEVICE_OUT_HEADPHONES) &&
Preetam Singh Ranawatb0c0dd72016-08-18 00:32:06 +05301657 adev->asrc_mode_enabled) {
1658 ALOGD("%s: %d: disabling asrc mode in hardware", __func__, __LINE__);
Preetam Singh Ranawat6a836662016-09-08 17:04:35 +05301659 disable_asrc_mode(adev);
1660 audio_route_apply_and_update_path(adev->audio_route, "hph-lowpower-mode");
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001661 } else if (((snd_device == SND_DEVICE_IN_HANDSET_6MIC) ||
Dhanalakshmi Siddaniaf4bd622019-02-27 16:28:06 +05301662 (snd_device == SND_DEVICE_IN_HANDSET_QMIC)) &&
Eric Laurent637e2d42018-11-15 12:24:31 -08001663 (audio_extn_ffv_get_stream() == adev_get_active_input(adev))) {
Garmond Leunge2433c32017-09-28 21:51:22 -07001664 ALOGD("%s: deinit ec ref loopback", __func__);
1665 audio_extn_ffv_deinit_ec_ref_loopback(adev, snd_device);
1666 }
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001667
1668 audio_extn_utils_release_snd_device(snd_device);
1669 } else {
1670 if (platform_split_snd_device(adev->platform,
1671 snd_device,
1672 &num_devices,
1673 new_snd_devices) == 0) {
1674 for (i = 0; i < num_devices; i++) {
1675 adev->snd_dev_ref_cnt[new_snd_devices[i]]--;
1676 }
1677 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001678 }
Ravi Kumar Alamanda48c921d2013-10-29 06:07:44 -07001679
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001680 return 0;
1681}
1682
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001683/*
1684 legend:
1685 uc - existing usecase
1686 new_uc - new usecase
1687 d1, d11, d2 - SND_DEVICE enums
1688 a1, a2 - corresponding ANDROID device enums
1689 B1, B2 - backend strings
1690
1691case 1
1692 uc->dev d1 (a1) B1
1693 new_uc->dev d1 (a1), d2 (a2) B1, B2
1694
1695 resolution: disable and enable uc->dev on d1
1696
1697case 2
1698 uc->dev d1 (a1) B1
1699 new_uc->dev d11 (a1) B1
1700
1701 resolution: need to switch uc since d1 and d11 are related
1702 (e.g. speaker and voice-speaker)
1703 use ANDROID_DEVICE_OUT enums to match devices since SND_DEVICE enums may vary
1704
1705case 3
1706 uc->dev d1 (a1) B1
1707 new_uc->dev d2 (a2) B2
1708
1709 resolution: no need to switch uc
1710
1711case 4
1712 uc->dev d1 (a1) B1
1713 new_uc->dev d2 (a2) B1
1714
1715 resolution: disable enable uc-dev on d2 since backends match
1716 we cannot enable two streams on two different devices if they
1717 share the same backend. e.g. if offload is on speaker device using
1718 QUAD_MI2S backend and a low-latency stream is started on voice-handset
1719 using the same backend, offload must also be switched to voice-handset.
1720
1721case 5
1722 uc->dev d1 (a1) B1
1723 new_uc->dev d1 (a1), d2 (a2) B1
1724
1725 resolution: disable enable uc-dev on d2 since backends match
1726 we cannot enable two streams on two different devices if they
1727 share the same backend.
1728
1729case 6
1730 uc->dev d1 (a1) B1
1731 new_uc->dev d2 (a1) B2
1732
1733 resolution: no need to switch
1734
1735case 7
1736 uc->dev d1 (a1), d2 (a2) B1, B2
1737 new_uc->dev d1 (a1) B1
1738
1739 resolution: no need to switch
1740
Zhou Song4ba65882018-07-09 14:48:07 +08001741case 8
1742 uc->dev d1 (a1) B1
1743 new_uc->dev d11 (a1), d2 (a2) B1, B2
1744 resolution: compared to case 1, for this case, d1 and d11 are related
1745 then need to do the same as case 2 to siwtch to new uc
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301746
1747case 9
1748 uc->dev d1 (a1), d2(a2) B1 B2
1749 new_uc->dev d1 (a1), d22 (a2) B1, B2
1750 resolution: disable enable uc-dev on d2 since backends match
1751 we cannot enable two streams on two different devices if they
1752 share the same backend. This is special case for combo use case
1753 with a2dp and sco devices which uses same backend.
1754 e.g. speaker-a2dp and speaker-btsco
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001755*/
1756static snd_device_t derive_playback_snd_device(void * platform,
1757 struct audio_usecase *uc,
1758 struct audio_usecase *new_uc,
1759 snd_device_t new_snd_device)
1760{
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001761 struct listnode a1, a2;
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001762
1763 snd_device_t d1 = uc->out_snd_device;
1764 snd_device_t d2 = new_snd_device;
1765
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001766 list_init(&a1);
1767 list_init(&a2);
1768
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301769 switch (uc->type) {
Surendar Karka93cd25a2018-08-28 14:21:37 +05301770 case TRANSCODE_LOOPBACK_RX :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001771 assign_devices(&a1, &uc->stream.inout->out_config.device_list);
1772 assign_devices(&a2, &new_uc->stream.inout->out_config.device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301773 break;
1774 default :
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001775 assign_devices(&a1, &uc->stream.out->device_list);
1776 assign_devices(&a2, &new_uc->stream.out->device_list);
Siddartha Shaik31b530e2017-05-19 15:26:33 +05301777 break;
1778 }
1779
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001780 // Treat as a special case when a1 and a2 are not disjoint
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001781 if (!compare_devices(&a1, &a2) &&
1782 compare_devices_for_any_match(&a1 ,&a2)) {
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001783 snd_device_t d3[2];
1784 int num_devices = 0;
1785 int ret = platform_split_snd_device(platform,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001786 list_length(&a1) > 1 ? d1 : d2,
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001787 &num_devices,
1788 d3);
1789 if (ret < 0) {
1790 if (ret != -ENOSYS) {
1791 ALOGW("%s failed to split snd_device %d",
1792 __func__,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001793 list_length(&a1) > 1 ? d1 : d2);
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001794 }
1795 goto end;
1796 }
1797
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001798 if (platform_check_backends_match(d3[0], d3[1])) {
1799 return d2; // case 5
1800 } else {
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301801 if ((list_length(&a1) > 1) && (list_length(&a2) > 1) &&
1802 platform_check_backends_match(d1, d2))
1803 return d2; //case 9
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001804 if (list_length(&a1) > 1)
Samyak Jaind826b502019-07-17 16:16:42 +05301805 return d1; //case 7
Garmond Leungb9eeba42018-09-18 11:10:41 -07001806 // check if d1 is related to any of d3's
1807 if (d1 == d3[0] || d1 == d3[1])
Zhou Song4ba65882018-07-09 14:48:07 +08001808 return d1; // case 1
1809 else
1810 return d3[1]; // case 8
Haynes Mathew Georgebfe8ff42016-09-22 17:38:16 -07001811 }
1812 } else {
1813 if (platform_check_backends_match(d1, d2)) {
1814 return d2; // case 2, 4
1815 } else {
1816 return d1; // case 6, 3
1817 }
1818 }
1819
1820end:
1821 return d2; // return whatever was calculated before.
1822}
1823
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001824static void check_usecases_codec_backend(struct audio_device *adev,
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301825 struct audio_usecase *uc_info,
1826 snd_device_t snd_device)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001827{
1828 struct listnode *node;
1829 struct audio_usecase *usecase;
1830 bool switch_device[AUDIO_USECASE_MAX];
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301831 snd_device_t uc_derive_snd_device;
1832 snd_device_t derive_snd_device[AUDIO_USECASE_MAX];
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001833 snd_device_t split_snd_devices[SND_DEVICE_OUT_END];
1834 int i, num_uc_to_switch = 0, num_devices = 0;
kunleiz5cd52b82016-11-07 17:22:52 +08001835 int status = 0;
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301836 bool force_restart_session = false;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001837 /*
1838 * This function is to make sure that all the usecases that are active on
1839 * the hardware codec backend are always routed to any one device that is
1840 * handled by the hardware codec.
1841 * For example, if low-latency and deep-buffer usecases are currently active
1842 * on speaker and out_set_parameters(headset) is received on low-latency
1843 * output, then we have to make sure deep-buffer is also switched to headset,
1844 * because of the limitation that both the devices cannot be enabled
1845 * at the same time as they share the same backend.
1846 */
Mingming Yin3ee55c62014-08-04 14:23:35 -07001847 /*
1848 * This call is to check if we need to force routing for a particular stream
1849 * If there is a backend configuration change for the device when a
1850 * new stream starts, then ADM needs to be closed and re-opened with the new
1851 * configuraion. This call check if we need to re-route all the streams
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001852 * associated with the backend. Touch tone + 24 bit + native playback.
Mingming Yin3ee55c62014-08-04 14:23:35 -07001853 */
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001854 bool force_routing = platform_check_and_set_codec_backend_cfg(adev, uc_info,
1855 snd_device);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301856 /* For a2dp device reconfigure all active sessions
1857 * with new AFE encoder format based on a2dp state
1858 */
1859 if ((SND_DEVICE_OUT_BT_A2DP == snd_device ||
Preetam Singh Ranawatd399e6f2020-06-25 12:20:36 +05301860 SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP == snd_device ||
1861 SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP == snd_device) &&
Naresh Tanniru9d027a62015-03-13 01:32:10 +05301862 audio_extn_a2dp_is_force_device_switch()) {
1863 force_routing = true;
1864 force_restart_session = true;
1865 }
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001866
1867 /*
1868 * Island cfg and power mode config needs to set before AFE port start.
1869 * Set force routing in case of voice device was enable before.
1870 */
1871 if (uc_info->type == VOICE_CALL &&
1872 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08001873 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08001874 platform_check_and_update_island_power_status(adev->platform,
1875 uc_info,
1876 snd_device)) {
1877 force_routing = true;
1878 ALOGD("%s:becf: force routing %d for power mode supported device",
1879 __func__, force_routing);
1880 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301881 ALOGD("%s:becf: force routing %d", __func__, force_routing);
1882
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001883 /* Disable all the usecases on the shared backend other than the
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08001884 * specified usecase.
Apoorv Raghuvanshif59bb222015-02-18 12:23:23 -08001885 */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001886 for (i = 0; i < AUDIO_USECASE_MAX; i++)
1887 switch_device[i] = false;
1888
1889 list_for_each(node, &adev->usecase_list) {
1890 usecase = node_to_item(node, struct audio_usecase, list);
Apoorv Raghuvanshi21492162015-02-19 18:19:36 -08001891
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301892 ALOGD("%s:becf: (%d) check_usecases curr device: %s, usecase device:%s "
1893 "backends match %d",__func__, i,
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301894 platform_get_snd_device_name(snd_device),
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301895 platform_get_snd_device_name(usecase->out_snd_device),
1896 platform_check_backends_match(snd_device, usecase->out_snd_device));
Rahul Sharma99770982019-03-06 17:05:26 +05301897 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
1898 (usecase->type != PCM_PASSTHROUGH)) {
Ashish Jain6a65b352017-03-21 17:24:40 +05301899 uc_derive_snd_device = derive_playback_snd_device(adev->platform,
1900 usecase, uc_info, snd_device);
1901 if (((uc_derive_snd_device != usecase->out_snd_device) || force_routing) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08001902 (is_codec_backend_out_device_type(&usecase->device_list) ||
1903 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) ||
1904 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_DEVICE) ||
1905 compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_USB_HEADSET) ||
1906 is_a2dp_out_device_type(&usecase->device_list) ||
1907 is_sco_out_device_type(&usecase->device_list)) &&
Ashish Jain6a65b352017-03-21 17:24:40 +05301908 ((force_restart_session) ||
1909 (platform_check_backends_match(snd_device, usecase->out_snd_device)))) {
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301910 ALOGD("%s:becf: check_usecases (%s) is active on (%s) - disabling ..",
1911 __func__, use_case_table[usecase->id],
1912 platform_get_snd_device_name(usecase->out_snd_device));
1913 disable_audio_route(adev, usecase);
1914 switch_device[usecase->id] = true;
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301915 /* Enable existing usecase on derived playback device */
1916 derive_snd_device[usecase->id] = uc_derive_snd_device;
Sidipotu Ashok9f0b16e2016-04-28 13:48:28 +05301917 num_uc_to_switch++;
Ashish Jain6a65b352017-03-21 17:24:40 +05301918 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001919 }
1920 }
1921
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05301922 ALOGD("%s:becf: check_usecases num.of Usecases to switch %d", __func__,
1923 num_uc_to_switch);
1924
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001925 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07001926 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001927
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05301928 /* Make sure the previous devices to be disabled first and then enable the
1929 selected devices */
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001930 list_for_each(node, &adev->usecase_list) {
1931 usecase = node_to_item(node, struct audio_usecase, list);
1932 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001933 /* Check if output sound device to be switched can be split and if any
1934 of the split devices match with derived sound device */
1935 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
1936 &num_devices, split_snd_devices) == 0) {
1937 adev->snd_dev_ref_cnt[usecase->out_snd_device]--;
1938 for (i = 0; i < num_devices; i++) {
1939 /* Disable devices that do not match with derived sound device */
1940 if (split_snd_devices[i] != derive_snd_device[usecase->id])
1941 disable_snd_device(adev, split_snd_devices[i]);
1942 }
1943 } else {
1944 disable_snd_device(adev, usecase->out_snd_device);
1945 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001946 }
1947 }
1948
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07001949 list_for_each(node, &adev->usecase_list) {
1950 usecase = node_to_item(node, struct audio_usecase, list);
1951 if (switch_device[usecase->id]) {
Weiyin Jiang0d84c8e2019-04-09 22:59:54 +08001952 if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
1953 &num_devices, split_snd_devices) == 0) {
1954 /* Enable derived sound device only if it does not match with
1955 one of the split sound devices. This is because the matching
1956 sound device was not disabled */
1957 bool should_enable = true;
1958 for (i = 0; i < num_devices; i++) {
1959 if (derive_snd_device[usecase->id] == split_snd_devices[i]) {
1960 should_enable = false;
1961 break;
1962 }
1963 }
1964 if (should_enable)
1965 enable_snd_device(adev, derive_snd_device[usecase->id]);
1966 } else {
1967 enable_snd_device(adev, derive_snd_device[usecase->id]);
1968 }
Krishnankutty Kolathappillydc4f7572013-11-01 20:07:13 -07001969 }
1970 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001971
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001972 /* Re-route all the usecases on the shared backend other than the
1973 specified usecase to new snd devices */
1974 list_for_each(node, &adev->usecase_list) {
1975 usecase = node_to_item(node, struct audio_usecase, list);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05301976 /* Update the out_snd_device only before enabling the audio route */
1977 if (switch_device[usecase->id]) {
Chaithanya Krishna Bacharaju49e7db02017-03-14 11:57:26 +05301978 usecase->out_snd_device = derive_snd_device[usecase->id];
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05301979 ALOGD("%s:becf: enabling usecase (%s) on (%s)", __func__,
1980 use_case_table[usecase->id],
1981 platform_get_snd_device_name(usecase->out_snd_device));
1982 /* Update voc calibration before enabling Voice/VoIP route */
1983 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
1984 status = platform_switch_voice_call_device_post(adev->platform,
1985 usecase->out_snd_device,
1986 platform_get_input_snd_device(
1987 adev->platform, NULL,
1988 &uc_info->device_list,
1989 usecase->type));
1990 enable_audio_route(adev, usecase);
1991 if (usecase->stream.out && usecase->id == USECASE_AUDIO_PLAYBACK_VOIP) {
1992 out_set_voip_volume(&usecase->stream.out->stream,
1993 usecase->stream.out->volume_l,
1994 usecase->stream.out->volume_r);
Karthik Reddy Katta3abfee22016-02-23 10:55:27 +05301995 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001996 }
1997 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001998 }
1999}
2000
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302001static void check_usecases_capture_codec_backend(struct audio_device *adev,
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002002 struct audio_usecase *uc_info,
2003 snd_device_t snd_device)
2004{
2005 struct listnode *node;
2006 struct audio_usecase *usecase;
2007 bool switch_device[AUDIO_USECASE_MAX];
2008 int i, num_uc_to_switch = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002009 int backend_check_cond = is_codec_backend_out_device_type(&uc_info->device_list);
kunleiz5cd52b82016-11-07 17:22:52 +08002010 int status = 0;
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002011
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05302012 bool force_routing = platform_check_and_set_capture_codec_backend_cfg(adev, uc_info,
2013 snd_device);
2014 ALOGD("%s:becf: force routing %d", __func__, force_routing);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302015
2016 /*
2017 * Make sure out devices is checked against out codec backend device and
2018 * also in devices against in codec backend. Checking out device against in
2019 * codec backend or vice versa causes issues.
2020 */
2021 if (uc_info->type == PCM_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002022 backend_check_cond = is_codec_backend_in_device_type(&uc_info->device_list);
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002023
2024 /*
2025 * Island cfg and power mode config needs to set before AFE port start.
2026 * Set force routing in case of voice device was enable before.
2027 */
2028
2029 if (uc_info->type == VOICE_CALL &&
2030 voice_extn_is_voice_power_mode_supported() &&
Kunlei Zhang67cc7072020-12-18 17:16:49 +08002031 is_supported_conc_usecase_for_power_mode_call(adev) &&
Kunlei Zhange7cab1a2020-05-17 20:31:05 +08002032 platform_check_and_update_island_power_status(adev->platform,
2033 uc_info,
2034 snd_device)) {
2035 force_routing = true;
2036 ALOGD("%s:becf: force routing %d for power mode supported device",
2037 __func__, force_routing);
2038 }
2039
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002040 /*
2041 * This function is to make sure that all the active capture usecases
2042 * are always routed to the same input sound device.
2043 * For example, if audio-record and voice-call usecases are currently
2044 * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
2045 * is received for voice call then we have to make sure that audio-record
2046 * usecase is also switched to earpiece i.e. voice-dmic-ef,
2047 * because of the limitation that two devices cannot be enabled
2048 * at the same time if they share the same backend.
2049 */
2050 for (i = 0; i < AUDIO_USECASE_MAX; i++)
2051 switch_device[i] = false;
2052
2053 list_for_each(node, &adev->usecase_list) {
2054 usecase = node_to_item(node, struct audio_usecase, list);
Dhanalakshmi Siddanib678a802016-12-03 11:51:41 +05302055 /*
2056 * TODO: Enhance below condition to handle BT sco/USB multi recording
2057 */
Jaideep Sharma477917f2020-03-13 18:13:33 +05302058
2059 bool capture_uc_needs_routing = usecase->type != PCM_PLAYBACK && (usecase != uc_info &&
2060 (usecase->in_snd_device != snd_device || force_routing));
2061 bool call_proxy_snd_device = platform_is_call_proxy_snd_device(snd_device) ||
2062 platform_is_call_proxy_snd_device(usecase->in_snd_device);
2063 if (capture_uc_needs_routing && !call_proxy_snd_device &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002064 ((backend_check_cond &&
2065 (is_codec_backend_in_device_type(&usecase->device_list) ||
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08002066 (usecase->type == VOIP_CALL))) ||
Carter Hsu1d2a0532018-10-04 09:24:36 +08002067 ((uc_info->type == VOICE_CALL &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002068 is_single_device_type_equal(&usecase->device_list,
2069 AUDIO_DEVICE_IN_VOICE_CALL)) ||
Anver sadhique4fdc6992022-01-21 12:26:28 +05302070 platform_check_all_backends_match(snd_device,\
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002071 usecase->in_snd_device))) &&
Anish Kumara020a7c2014-10-17 11:13:22 -07002072 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05302073 ALOGD("%s: Usecase (%s) is active on (%s) - disabling ..",
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002074 __func__, use_case_table[usecase->id],
Devin Kim1e5f3532013-08-09 07:48:29 -07002075 platform_get_snd_device_name(usecase->in_snd_device));
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002076 disable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002077 switch_device[usecase->id] = true;
2078 num_uc_to_switch++;
2079 }
2080 }
2081
2082 if (num_uc_to_switch) {
Haynes Mathew Georgeef1e3d32014-04-24 11:53:44 -07002083 /* All streams have been de-routed. Disable the device */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002084
Venkata Narendra Kumar Gutta7610e632014-04-14 23:16:38 +05302085 /* Make sure the previous devices to be disabled first and then enable the
2086 selected devices */
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002087 list_for_each(node, &adev->usecase_list) {
2088 usecase = node_to_item(node, struct audio_usecase, list);
2089 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002090 disable_snd_device(adev, usecase->in_snd_device);
Shiv Maliyappanahalli80ac6282013-12-20 18:56:15 -08002091 }
2092 }
2093
2094 list_for_each(node, &adev->usecase_list) {
2095 usecase = node_to_item(node, struct audio_usecase, list);
2096 if (switch_device[usecase->id]) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07002097 enable_snd_device(adev, snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002098 }
2099 }
2100
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002101 /* Re-route all the usecases on the shared backend other than the
2102 specified usecase to new snd devices */
2103 list_for_each(node, &adev->usecase_list) {
2104 usecase = node_to_item(node, struct audio_usecase, list);
2105 /* Update the in_snd_device only before enabling the audio route */
2106 if (switch_device[usecase->id] ) {
2107 usecase->in_snd_device = snd_device;
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302108 /* Update voc calibration before enabling Voice/VoIP route */
2109 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
2110 snd_device_t voip_snd_device;
2111 voip_snd_device = platform_get_output_snd_device(adev->platform,
2112 usecase->stream.out,
2113 usecase->type);
2114 status = platform_switch_voice_call_device_post(adev->platform,
2115 voip_snd_device,
2116 usecase->in_snd_device);
kunleiz5cd52b82016-11-07 17:22:52 +08002117 }
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05302118 enable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002119 }
2120 }
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07002121 }
2122}
2123
Mingming Yin3a941d42016-02-17 18:08:05 -08002124static void reset_hdmi_sink_caps(struct stream_out *out) {
2125 int i = 0;
2126
2127 for (i = 0; i<= MAX_SUPPORTED_CHANNEL_MASKS; i++) {
2128 out->supported_channel_masks[i] = 0;
2129 }
2130 for (i = 0; i<= MAX_SUPPORTED_FORMATS; i++) {
2131 out->supported_formats[i] = 0;
2132 }
2133 for (i = 0; i<= MAX_SUPPORTED_SAMPLE_RATES; i++) {
2134 out->supported_sample_rates[i] = 0;
2135 }
2136}
2137
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002138/* must be called with hw device mutex locked */
Mingming Yin3a941d42016-02-17 18:08:05 -08002139static int read_hdmi_sink_caps(struct stream_out *out)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002140{
Mingming Yin3a941d42016-02-17 18:08:05 -08002141 int ret = 0, i = 0, j = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002142 int channels = platform_edid_get_max_channels_v2(out->dev->platform,
2143 out->extconn.cs.controller,
2144 out->extconn.cs.stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002145
Mingming Yin3a941d42016-02-17 18:08:05 -08002146 reset_hdmi_sink_caps(out);
2147
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002148 /* Cache ext disp type */
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002149 ret = platform_get_ext_disp_type_v2(adev->platform,
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002150 out->extconn.cs.controller,
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08002151 out->extconn.cs.stream);
2152 if(ret < 0) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002153 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Garmond Leung37850ab2016-10-06 11:42:18 -07002154 return -EINVAL;
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07002155 }
2156
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002157 switch (channels) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002158 case 8:
Mingming Yin3a941d42016-02-17 18:08:05 -08002159 ALOGV("%s: HDMI supports 7.1 channels", __func__);
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07002160 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_7POINT1;
Mingming Yin3a941d42016-02-17 18:08:05 -08002161 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_6POINT1;
2162 case 6:
2163 ALOGV("%s: HDMI supports 5.1 channels", __func__);
2164 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
2165 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
2166 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
2167 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_SURROUND;
2168 out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_2POINT1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002169 break;
2170 default:
Mingming Yin3a941d42016-02-17 18:08:05 -08002171 ALOGE("invalid/nonstandard channal count[%d]",channels);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002172 ret = -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002173 break;
2174 }
Mingming Yin3a941d42016-02-17 18:08:05 -08002175
2176 // check channel format caps
2177 i = 0;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002178 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_AC3,
2179 out->extconn.cs.controller,
2180 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002181 ALOGV(":%s HDMI supports AC3/EAC3 formats", __func__);
2182 out->supported_formats[i++] = AUDIO_FORMAT_AC3;
2183 //Adding EAC3/EAC3_JOC formats if AC3 is supported by the sink.
2184 //EAC3/EAC3_JOC will be converted to AC3 for decoding if needed
2185 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3;
2186 out->supported_formats[i++] = AUDIO_FORMAT_E_AC3_JOC;
2187 }
2188
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002189 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DOLBY_TRUEHD,
2190 out->extconn.cs.controller,
2191 out->extconn.cs.stream)) {
Ben Romberger1aaaf862017-04-06 17:49:46 -07002192 ALOGV(":%s HDMI supports TRUE HD format", __func__);
2193 out->supported_formats[i++] = AUDIO_FORMAT_DOLBY_TRUEHD;
2194 }
2195
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002196 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS,
2197 out->extconn.cs.controller,
2198 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002199 ALOGV(":%s HDMI supports DTS format", __func__);
2200 out->supported_formats[i++] = AUDIO_FORMAT_DTS;
2201 }
2202
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002203 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_DTS_HD,
2204 out->extconn.cs.controller,
2205 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002206 ALOGV(":%s HDMI supports DTS HD format", __func__);
2207 out->supported_formats[i++] = AUDIO_FORMAT_DTS_HD;
2208 }
2209
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002210 if (platform_is_edid_supported_format_v2(out->dev->platform, AUDIO_FORMAT_IEC61937,
2211 out->extconn.cs.controller,
2212 out->extconn.cs.stream)) {
Naresh Tanniru928f0862017-04-07 16:44:23 -07002213 ALOGV(":%s HDMI supports IEC61937 format", __func__);
2214 out->supported_formats[i++] = AUDIO_FORMAT_IEC61937;
2215 }
2216
Mingming Yin3a941d42016-02-17 18:08:05 -08002217
2218 // check sample rate caps
2219 i = 0;
2220 for (j = 0; j < MAX_SUPPORTED_SAMPLE_RATES; j++) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07002221 if (platform_is_edid_supported_sample_rate_v2(out->dev->platform, out_hdmi_sample_rates[j],
2222 out->extconn.cs.controller,
2223 out->extconn.cs.stream)) {
Mingming Yin3a941d42016-02-17 18:08:05 -08002224 ALOGV(":%s HDMI supports sample rate:%d", __func__, out_hdmi_sample_rates[j]);
2225 out->supported_sample_rates[i++] = out_hdmi_sample_rates[j];
2226 }
2227 }
2228
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07002229 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002230}
2231
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002232static inline ssize_t read_usb_sup_sample_rates(bool is_playback __unused,
2233 uint32_t *supported_sample_rates __unused,
2234 uint32_t max_rates __unused)
2235{
2236 ssize_t count = audio_extn_usb_get_sup_sample_rates(is_playback,
2237 supported_sample_rates,
2238 max_rates);
Ashish Jain4847e9d2017-08-17 19:16:57 +05302239 ssize_t i = 0;
2240
2241 for (i=0; i<count; i++) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002242 ALOGV("%s %s %d", __func__, is_playback ? "P" : "C",
2243 supported_sample_rates[i]);
2244 }
2245 return count;
2246}
2247
2248static inline int read_usb_sup_channel_masks(bool is_playback,
2249 audio_channel_mask_t *supported_channel_masks,
2250 uint32_t max_masks)
2251{
2252 int channels = audio_extn_usb_get_max_channels(is_playback);
2253 int channel_count;
2254 uint32_t num_masks = 0;
2255 if (channels > MAX_HIFI_CHANNEL_COUNT)
2256 channels = MAX_HIFI_CHANNEL_COUNT;
2257
2258 if (is_playback) {
Eric Laurent68a87112019-05-01 18:07:29 -07002259 // start from 2 channels as framework currently doesn't support mono.
2260 if (channels >= FCC_2) {
2261 supported_channel_masks[num_masks++] = audio_channel_out_mask_from_count(FCC_2);
2262 }
2263 for (channel_count = FCC_2;
2264 channel_count <= channels && num_masks < max_masks;
2265 ++channel_count) {
2266 supported_channel_masks[num_masks++] =
2267 audio_channel_mask_for_index_assignment_from_count(channel_count);
2268 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002269 } else {
vincenttewf51c94e2019-05-07 10:28:53 +08002270 // For capture we report all supported channel masks from 1 channel up.
2271 channel_count = MIN_CHANNEL_COUNT;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002272 // audio_channel_in_mask_from_count() does the right conversion to either positional or
2273 // indexed mask
Eric Laurent68a87112019-05-01 18:07:29 -07002274 for ( ; channel_count <= channels && num_masks < max_masks; channel_count++) {
2275 audio_channel_mask_t mask = AUDIO_CHANNEL_NONE;
2276 if (channel_count <= FCC_2) {
2277 mask = audio_channel_in_mask_from_count(channel_count);
2278 supported_channel_masks[num_masks++] = mask;
2279 }
2280 const audio_channel_mask_t index_mask =
2281 audio_channel_mask_for_index_assignment_from_count(channel_count);
2282 if (mask != index_mask && num_masks < max_masks) { // ensure index mask added.
2283 supported_channel_masks[num_masks++] = index_mask;
2284 }
2285 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002286 }
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302287
vincenttewf51c94e2019-05-07 10:28:53 +08002288 for (size_t i = 0; i < num_masks; ++i) {
2289 ALOGV("%s: %s supported ch %d supported_channel_masks[%zu] %08x num_masks %d", __func__,
2290 is_playback ? "P" : "C", channels, i, supported_channel_masks[i], num_masks);
Lakshman Chaluvarajub79fafd2018-11-21 10:24:37 +05302291 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07002292 return num_masks;
2293}
2294
2295static inline int read_usb_sup_formats(bool is_playback __unused,
2296 audio_format_t *supported_formats,
2297 uint32_t max_formats __unused)
2298{
2299 int bitwidth = audio_extn_usb_get_max_bit_width(is_playback);
2300 switch (bitwidth) {
2301 case 24:
2302 // XXX : usb.c returns 24 for s24 and s24_le?
2303 supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
2304 break;
2305 case 32:
2306 supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
2307 break;
2308 case 16:
2309 default :
2310 supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
2311 break;
2312 }
2313 ALOGV("%s: %s supported format %d", __func__,
2314 is_playback ? "P" : "C", bitwidth);
2315 return 1;
2316}
2317
2318static inline int read_usb_sup_params_and_compare(bool is_playback,
2319 audio_format_t *format,
2320 audio_format_t *supported_formats,
2321 uint32_t max_formats,
2322 audio_channel_mask_t *mask,
2323 audio_channel_mask_t *supported_channel_masks,
2324 uint32_t max_masks,
2325 uint32_t *rate,
2326 uint32_t *supported_sample_rates,
2327 uint32_t max_rates) {
2328 int ret = 0;
2329 int num_formats;
2330 int num_masks;
2331 int num_rates;
2332 int i;
2333
2334 num_formats = read_usb_sup_formats(is_playback, supported_formats,
2335 max_formats);
2336 num_masks = read_usb_sup_channel_masks(is_playback, supported_channel_masks,
2337 max_masks);
2338
2339 num_rates = read_usb_sup_sample_rates(is_playback,
2340 supported_sample_rates, max_rates);
2341
2342#define LUT(table, len, what, dflt) \
2343 for (i=0; i<len && (table[i] != what); i++); \
2344 if (i==len) { ret |= (what == dflt ? 0 : -1); what=table[0]; }
2345
2346 LUT(supported_formats, num_formats, *format, AUDIO_FORMAT_DEFAULT);
2347 LUT(supported_channel_masks, num_masks, *mask, AUDIO_CHANNEL_NONE);
2348 LUT(supported_sample_rates, num_rates, *rate, 0);
2349
2350#undef LUT
2351 return ret < 0 ? -EINVAL : 0; // HACK TBD
2352}
2353
Alexy Josephb1379942016-01-29 15:49:38 -08002354audio_usecase_t get_usecase_id_from_usecase_type(const struct audio_device *adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002355 usecase_type_t type)
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002356{
2357 struct audio_usecase *usecase;
2358 struct listnode *node;
2359
2360 list_for_each(node, &adev->usecase_list) {
2361 usecase = node_to_item(node, struct audio_usecase, list);
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002362 if (usecase->type == type) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002363 ALOGV("%s: usecase id %d", __func__, usecase->id);
2364 return usecase->id;
2365 }
2366 }
2367 return USECASE_INVALID;
2368}
2369
Alexy Josephb1379942016-01-29 15:49:38 -08002370struct audio_usecase *get_usecase_from_list(const struct audio_device *adev,
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002371 audio_usecase_t uc_id)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002372{
2373 struct audio_usecase *usecase;
2374 struct listnode *node;
2375
2376 list_for_each(node, &adev->usecase_list) {
2377 usecase = node_to_item(node, struct audio_usecase, list);
2378 if (usecase->id == uc_id)
2379 return usecase;
2380 }
2381 return NULL;
2382}
2383
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302384/*
2385 * is a true native playback active
2386 */
2387bool audio_is_true_native_stream_active(struct audio_device *adev)
2388{
2389 bool active = false;
2390 int i = 0;
2391 struct listnode *node;
2392
2393 if (NATIVE_AUDIO_MODE_TRUE_44_1 != platform_get_native_support()) {
2394 ALOGV("%s:napb: not in true mode or non hdphones device",
2395 __func__);
2396 active = false;
2397 goto exit;
2398 }
2399
2400 list_for_each(node, &adev->usecase_list) {
2401 struct audio_usecase *uc;
2402 uc = node_to_item(node, struct audio_usecase, list);
2403 struct stream_out *curr_out =
2404 (struct stream_out*) uc->stream.out;
2405
2406 if (curr_out && PCM_PLAYBACK == uc->type) {
2407 ALOGD("%s:napb: (%d) (%s)id (%d) sr %d bw "
2408 "(%d) device %s", __func__, i++, use_case_table[uc->id],
2409 uc->id, curr_out->sample_rate,
2410 curr_out->bit_width,
2411 platform_get_snd_device_name(uc->out_snd_device));
2412
2413 if (is_offload_usecase(uc->id) &&
2414 (curr_out->sample_rate == OUTPUT_SAMPLING_RATE_44100)) {
2415 active = true;
2416 ALOGD("%s:napb:native stream detected", __func__);
2417 }
2418 }
2419 }
2420exit:
2421 return active;
2422}
2423
Xiaojun Sang785b5da2017-08-03 15:52:29 +08002424uint32_t adev_get_dsp_bit_width_enforce_mode()
2425{
2426 if (adev == NULL) {
2427 ALOGE("%s: adev is null. Disable DSP bit width enforce mode.\n", __func__);
2428 return 0;
2429 }
2430 return adev->dsp_bit_width_enforce_mode;
2431}
2432
2433static uint32_t adev_init_dsp_bit_width_enforce_mode(struct mixer *mixer)
2434{
2435 char value[PROPERTY_VALUE_MAX];
2436 int trial;
2437 uint32_t dsp_bit_width_enforce_mode = 0;
2438
2439 if (!mixer) {
2440 ALOGE("%s: adev mixer is null. cannot update DSP bitwidth.\n",
2441 __func__);
2442 return 0;
2443 }
2444
2445 if (property_get("persist.vendor.audio_hal.dsp_bit_width_enforce_mode",
2446 value, NULL) > 0) {
2447 trial = atoi(value);
2448 switch (trial) {
2449 case 16:
2450 dsp_bit_width_enforce_mode = 16;
2451 break;
2452 case 24:
2453 dsp_bit_width_enforce_mode = 24;
2454 break;
2455 case 32:
2456 dsp_bit_width_enforce_mode = 32;
2457 break;
2458 default:
2459 dsp_bit_width_enforce_mode = 0;
2460 ALOGD("%s Dynamic DSP bitwidth config is disabled.", __func__);
2461 break;
2462 }
2463 }
2464
2465 return dsp_bit_width_enforce_mode;
2466}
2467
2468static void audio_enable_asm_bit_width_enforce_mode(struct mixer *mixer,
2469 uint32_t enforce_mode,
2470 bool enable)
2471{
2472 struct mixer_ctl *ctl = NULL;
2473 const char *mixer_ctl_name = "ASM Bit Width";
2474 uint32_t asm_bit_width_mode = 0;
2475
2476 if (enforce_mode == 0) {
2477 ALOGD("%s: DSP bitwidth feature is disabled.", __func__);
2478 return;
2479 }
2480
2481 ctl = mixer_get_ctl_by_name(mixer, mixer_ctl_name);
2482 if (!ctl) {
2483 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2484 __func__, mixer_ctl_name);
2485 return;
2486 }
2487
2488 if (enable)
2489 asm_bit_width_mode = enforce_mode;
2490 else
2491 asm_bit_width_mode = 0;
2492
2493 ALOGV("%s DSP bit width feature status is %d width=%d",
2494 __func__, enable, asm_bit_width_mode);
2495 if (mixer_ctl_set_value(ctl, 0, asm_bit_width_mode) < 0)
2496 ALOGE("%s: Could not set ASM biwidth %d", __func__,
2497 asm_bit_width_mode);
2498
2499 return;
2500}
2501
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302502/*
2503 * if native DSD playback active
2504 */
2505bool audio_is_dsd_native_stream_active(struct audio_device *adev)
2506{
2507 bool active = false;
2508 struct listnode *node = NULL;
2509 struct audio_usecase *uc = NULL;
2510 struct stream_out *curr_out = NULL;
2511
2512 list_for_each(node, &adev->usecase_list) {
2513 uc = node_to_item(node, struct audio_usecase, list);
2514 curr_out = (struct stream_out*) uc->stream.out;
2515
2516 if (curr_out && PCM_PLAYBACK == uc->type &&
2517 (DSD_NATIVE_BACKEND == platform_get_backend_index(uc->out_snd_device))) {
2518 active = true;
2519 ALOGV("%s:DSD playback is active", __func__);
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05302520 break;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05302521 }
2522 }
2523 return active;
2524}
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302525
2526static bool force_device_switch(struct audio_usecase *usecase)
2527{
2528 bool ret = false;
2529 bool is_it_true_mode = false;
2530
Zhou Song30f2c3e2018-02-08 14:02:15 +08002531 if (usecase->type == PCM_CAPTURE ||
Surendar Karka93cd25a2018-08-28 14:21:37 +05302532 usecase->type == TRANSCODE_LOOPBACK_RX ||
2533 usecase->type == TRANSCODE_LOOPBACK_TX) {
Zhou Song30f2c3e2018-02-08 14:02:15 +08002534 return false;
2535 }
2536
Aalique Grahamecbc46a22017-10-05 10:30:23 -07002537 if(usecase->stream.out == NULL) {
2538 ALOGE("%s: stream.out is NULL", __func__);
2539 return false;
2540 }
2541
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302542 if (is_offload_usecase(usecase->id) &&
Xiaojun Sang869f2012016-02-23 16:33:07 +08002543 (usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002544 (compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADSET) ||
2545 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_WIRED_HEADPHONE))) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302546 is_it_true_mode = (NATIVE_AUDIO_MODE_TRUE_44_1 == platform_get_native_support()? true : false);
2547 if ((is_it_true_mode && !adev->native_playback_enabled) ||
2548 (!is_it_true_mode && adev->native_playback_enabled)){
2549 ret = true;
2550 ALOGD("napb: time to toggle native mode");
2551 }
2552 }
2553
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302554 // Force all a2dp output devices to reconfigure for proper AFE encode format
Ashish Jainc597d102016-12-12 10:31:34 +05302555 //Also handle a case where in earlier a2dp start failed as A2DP stream was
2556 //in suspended state, hence try to trigger a retry when we again get a routing request.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002557 if(is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Ashish Jainc597d102016-12-12 10:31:34 +05302558 audio_extn_a2dp_is_force_device_switch()) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302559 ALOGD("Force a2dp device switch to update new encoder config");
2560 ret = true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002561 }
Naresh Tanniru9d027a62015-03-13 01:32:10 +05302562
Florian Pfister1a84f312018-07-19 14:38:18 +02002563 if (usecase->stream.out->stream_config_changed) {
Manish Dewangan671a4202017-08-18 17:30:46 +05302564 ALOGD("Force stream_config_changed to update iec61937 transmission config");
2565 return true;
Florian Pfister1a84f312018-07-19 14:38:18 +02002566 }
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302567 return ret;
2568}
2569
Aalique Grahame22e49102018-12-18 14:23:57 -08002570static void stream_app_type_cfg_init(struct stream_app_type_cfg *cfg)
2571{
2572 cfg->gain[0] = cfg->gain[1] = APP_TYPE_GAIN_DEFAULT;
2573}
2574
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302575bool is_btsco_device(snd_device_t out_snd_device, snd_device_t in_snd_device)
2576{
2577 bool ret=false;
2578 if ((out_snd_device == SND_DEVICE_OUT_BT_SCO ||
Zhou Song5657f492019-08-07 11:30:39 +08002579 out_snd_device == SND_DEVICE_OUT_BT_SCO_WB ||
2580 out_snd_device == SND_DEVICE_OUT_BT_SCO_SWB) ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302581 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB_NREC ||
2582 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_WB ||
Zhou Song5657f492019-08-07 11:30:39 +08002583 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB ||
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302584 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_NREC ||
Mingshu Pang16093502020-04-20 11:21:16 +08002585 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC ||
2586 in_snd_device == SND_DEVICE_IN_BT_SCO_MIC_SWB_NREC)
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302587 ret = true;
2588
2589 return ret;
2590}
2591
2592bool is_a2dp_device(snd_device_t out_snd_device)
2593{
2594 bool ret=false;
2595 if (out_snd_device == SND_DEVICE_OUT_BT_A2DP)
2596 ret = true;
2597
2598 return ret;
2599}
2600
2601bool is_bt_soc_on(struct audio_device *adev)
2602{
2603 struct mixer_ctl *ctl;
2604 char *mixer_ctl_name = "BT SOC status";
2605 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
2606 bool bt_soc_status = true;
2607 if (!ctl) {
2608 ALOGE("%s: Could not get ctl for mixer cmd - %s",
2609 __func__, mixer_ctl_name);
2610 /*This is to ensure we dont break targets which dont have the kernel change*/
2611 return true;
2612 }
2613 bt_soc_status = mixer_ctl_get_value(ctl, 0);
2614 ALOGD("BT SOC status: %d",bt_soc_status);
2615 return bt_soc_status;
2616}
2617
Zhou Song331c8e52019-08-26 14:16:12 +08002618static int configure_btsco_sample_rate(snd_device_t snd_device)
2619{
2620 struct mixer_ctl *ctl = NULL;
2621 struct mixer_ctl *ctl_sr_rx = NULL, *ctl_sr_tx = NULL, *ctl_sr = NULL;
2622 char *rate_str = NULL;
2623 bool is_rx_dev = true;
2624
2625 if (is_btsco_device(snd_device, snd_device)) {
2626 ctl_sr_tx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate TX");
2627 ctl_sr_rx = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate RX");
2628 if (!ctl_sr_tx || !ctl_sr_rx) {
2629 ctl_sr = mixer_get_ctl_by_name(adev->mixer, "BT SampleRate");
2630 if (!ctl_sr)
2631 return -ENOSYS;
2632 }
2633
2634 switch (snd_device) {
2635 case SND_DEVICE_OUT_BT_SCO:
2636 rate_str = "KHZ_8";
2637 break;
2638 case SND_DEVICE_IN_BT_SCO_MIC_NREC:
2639 case SND_DEVICE_IN_BT_SCO_MIC:
2640 rate_str = "KHZ_8";
2641 is_rx_dev = false;
2642 break;
2643 case SND_DEVICE_OUT_BT_SCO_WB:
2644 rate_str = "KHZ_16";
2645 break;
2646 case SND_DEVICE_IN_BT_SCO_MIC_WB_NREC:
2647 case SND_DEVICE_IN_BT_SCO_MIC_WB:
2648 rate_str = "KHZ_16";
2649 is_rx_dev = false;
2650 break;
2651 default:
2652 return 0;
2653 }
2654
2655 ctl = (ctl_sr == NULL) ? (is_rx_dev ? ctl_sr_rx : ctl_sr_tx) : ctl_sr;
2656 if (mixer_ctl_set_enum_by_string(ctl, rate_str) != 0)
2657 return -ENOSYS;
2658 }
2659 return 0;
2660}
2661
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302662int out_standby_l(struct audio_stream *stream);
2663
Eric Laurent637e2d42018-11-15 12:24:31 -08002664struct stream_in *adev_get_active_input(const struct audio_device *adev)
2665{
2666 struct listnode *node;
2667 struct stream_in *last_active_in = NULL;
2668
2669 /* Get last added active input.
2670 * TODO: We may use a priority mechanism to pick highest priority active source */
2671 list_for_each(node, &adev->usecase_list)
2672 {
2673 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2674 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL)
2675 last_active_in = usecase->stream.in;
2676 }
2677
2678 return last_active_in;
2679}
2680
2681struct stream_in *get_voice_communication_input(const struct audio_device *adev)
2682{
2683 struct listnode *node;
2684
2685 /* First check active inputs with voice communication source and then
2686 * any input if audio mode is in communication */
2687 list_for_each(node, &adev->usecase_list)
2688 {
2689 struct audio_usecase *usecase = node_to_item(node, struct audio_usecase, list);
2690 if (usecase->type == PCM_CAPTURE && usecase->stream.in != NULL &&
2691 usecase->stream.in->source == AUDIO_SOURCE_VOICE_COMMUNICATION)
2692 return usecase->stream.in;
2693 }
2694 if (adev->mode == AUDIO_MODE_IN_COMMUNICATION)
2695 return adev_get_active_input(adev);
2696
2697 return NULL;
2698}
2699
Carter Hsu2e429db2019-05-14 18:50:52 +08002700/*
2701 * Aligned with policy.h
2702 */
2703static inline int source_priority(int inputSource)
2704{
2705 switch (inputSource) {
2706 case AUDIO_SOURCE_VOICE_COMMUNICATION:
2707 return 9;
2708 case AUDIO_SOURCE_CAMCORDER:
2709 return 8;
2710 case AUDIO_SOURCE_VOICE_PERFORMANCE:
2711 return 7;
2712 case AUDIO_SOURCE_UNPROCESSED:
2713 return 6;
2714 case AUDIO_SOURCE_MIC:
2715 return 5;
2716 case AUDIO_SOURCE_ECHO_REFERENCE:
2717 return 4;
2718 case AUDIO_SOURCE_FM_TUNER:
2719 return 3;
2720 case AUDIO_SOURCE_VOICE_RECOGNITION:
2721 return 2;
2722 case AUDIO_SOURCE_HOTWORD:
2723 return 1;
2724 default:
2725 break;
2726 }
2727 return 0;
2728}
2729
2730static struct stream_in *get_priority_input(struct audio_device *adev)
2731{
2732 struct listnode *node;
2733 struct audio_usecase *usecase;
2734 int last_priority = 0, priority;
2735 struct stream_in *priority_in = NULL;
2736 struct stream_in *in;
2737
2738 list_for_each(node, &adev->usecase_list) {
2739 usecase = node_to_item(node, struct audio_usecase, list);
2740 if (usecase->type == PCM_CAPTURE) {
2741 in = usecase->stream.in;
2742 if (!in)
2743 continue;
2744 priority = source_priority(in->source);
2745
2746 if (priority > last_priority) {
2747 last_priority = priority;
2748 priority_in = in;
2749 }
2750 }
2751 }
2752 return priority_in;
2753}
2754
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002755int select_devices(struct audio_device *adev, audio_usecase_t uc_id)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002756{
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08002757 snd_device_t out_snd_device = SND_DEVICE_NONE;
2758 snd_device_t in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002759 struct audio_usecase *usecase = NULL;
2760 struct audio_usecase *vc_usecase = NULL;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002761 struct audio_usecase *voip_usecase = NULL;
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002762 struct audio_usecase *hfp_usecase = NULL;
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302763 struct stream_out stream_out;
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08002764 audio_usecase_t hfp_ucid;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002765 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002766
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302767 ALOGD("%s for use case (%s)", __func__, use_case_table[uc_id]);
2768
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002769 usecase = get_usecase_from_list(adev, uc_id);
2770 if (usecase == NULL) {
2771 ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
2772 return -EINVAL;
2773 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002774
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002775 if ((usecase->type == VOICE_CALL) ||
Vimal Puthanveed5b4d3f12013-11-05 15:57:39 -08002776 (usecase->type == VOIP_CALL) ||
Derek Chena30a5f42019-12-03 11:17:09 -05002777 (usecase->type == PCM_HFP_CALL)||
Fei Tongaffdf732020-02-20 20:39:05 +08002778 (usecase->type == ICC_CALL) ||
2779 (usecase->type == SYNTH_LOOPBACK)) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302780 if(usecase->stream.out == NULL) {
2781 ALOGE("%s: stream.out is NULL", __func__);
2782 return -EINVAL;
2783 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002784 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS)) {
Guodong Hu267bdf82019-08-12 19:22:32 +08002785 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev,
2786 uc_id);
2787 in_snd_device = audio_extn_auto_hal_get_input_snd_device(adev,
2788 uc_id);
2789 } else {
2790 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302791 usecase->stream.out, usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002792 in_snd_device = platform_get_input_snd_device(adev->platform,
2793 NULL,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302794 &usecase->stream.out->device_list,
2795 usecase->type);
Guodong Hu267bdf82019-08-12 19:22:32 +08002796 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002797 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302798 } else if (usecase->type == TRANSCODE_LOOPBACK_RX) {
Siddartha Shaik31b530e2017-05-19 15:26:33 +05302799 if (usecase->stream.inout == NULL) {
2800 ALOGE("%s: stream.inout is NULL", __func__);
2801 return -EINVAL;
2802 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002803 assign_devices(&stream_out.device_list, &usecase->stream.inout->out_config.device_list);
Siddartha Shaik44dd7702017-06-14 12:13:25 +05302804 stream_out.sample_rate = usecase->stream.inout->out_config.sample_rate;
2805 stream_out.format = usecase->stream.inout->out_config.format;
2806 stream_out.channel_mask = usecase->stream.inout->out_config.channel_mask;
Jaideep Sharma477917f2020-03-13 18:13:33 +05302807 out_snd_device = platform_get_output_snd_device(adev->platform, &stream_out, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002808 assign_devices(&usecase->device_list,
2809 &usecase->stream.inout->out_config.device_list);
Surendar Karka93cd25a2018-08-28 14:21:37 +05302810 } else if (usecase->type == TRANSCODE_LOOPBACK_TX ) {
2811 if (usecase->stream.inout == NULL) {
2812 ALOGE("%s: stream.inout is NULL", __func__);
2813 return -EINVAL;
2814 }
Manisha Agarwal03297972020-04-17 15:36:55 +05302815 struct listnode out_devices;
2816 list_init(&out_devices);
2817 in_snd_device = platform_get_input_snd_device(adev->platform, NULL,
2818 &out_devices, usecase->type);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002819 assign_devices(&usecase->device_list,
2820 &usecase->stream.inout->in_config.device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002821 } else {
2822 /*
2823 * If the voice call is active, use the sound devices of voice call usecase
2824 * so that it would not result any device switch. All the usecases will
2825 * be switched to new device when select_devices() is called for voice call
2826 * usecase. This is to avoid switching devices for voice call when
2827 * check_usecases_codec_backend() is called below.
Alexy Joseph79dfa3c2016-04-20 18:44:56 -07002828 * choose voice call device only if the use case device is
2829 * also using the codec backend
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002830 */
Shiv Maliyappanahallibb4cf0b2016-01-21 11:30:06 -08002831 if (voice_is_in_call(adev) && adev->mode != AUDIO_MODE_NORMAL) {
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07002832 vc_usecase = get_usecase_from_list(adev,
Narsinga Rao Chellaf928a982015-03-06 14:57:35 -08002833 get_usecase_id_from_usecase_type(adev, VOICE_CALL));
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002834 if ((vc_usecase) && ((is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2835 is_codec_backend_out_device_type(&usecase->device_list)) ||
2836 (is_codec_backend_out_device_type(&vc_usecase->device_list) &&
2837 is_codec_backend_in_device_type(&usecase->device_list)) ||
2838 is_single_device_type_equal(&vc_usecase->device_list,
2839 AUDIO_DEVICE_OUT_HEARING_AID) ||
2840 is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002841 AUDIO_DEVICE_IN_VOICE_CALL) ||
2842 (is_single_device_type_equal(&usecase->device_list,
Gautam Manam8fa06162021-09-24 10:41:29 +05302843 AUDIO_DEVICE_IN_BUILTIN_MIC) &&
2844 is_single_device_type_equal(&vc_usecase->device_list,
2845 AUDIO_DEVICE_OUT_USB_HEADSET)) ||
2846 (is_single_device_type_equal(&usecase->device_list,
Robert Lee8a6aaf32019-09-20 16:40:19 +08002847 AUDIO_DEVICE_IN_USB_HEADSET) &&
2848 is_single_device_type_equal(&vc_usecase->device_list,
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05302849 AUDIO_DEVICE_OUT_USB_HEADSET))||
Gautam Manamf4002142021-09-13 22:05:56 +05302850 (is_single_device_type_equal(&usecase->device_list,
2851 AUDIO_DEVICE_IN_USB_HEADSET) &&
2852 is_codec_backend_out_device_type(&vc_usecase->device_list)) ||
Kamalakar Yalasiri5edba852021-01-28 14:52:38 +05302853 (is_single_device_type_equal(&usecase->device_list,
2854 AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) &&
2855 is_codec_backend_out_device_type(&vc_usecase->device_list)))) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002856 in_snd_device = vc_usecase->in_snd_device;
2857 out_snd_device = vc_usecase->out_snd_device;
2858 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002859 } else if (voice_extn_compress_voip_is_active(adev)) {
yidongh02ef86f2017-04-21 15:36:04 +08002860 bool out_snd_device_backend_match = true;
yidongh47785a82017-05-08 19:29:29 +08002861 voip_usecase = get_usecase_from_list(adev, USECASE_COMPRESS_VOIP_CALL);
yidongh6261d8e2017-05-15 17:04:02 +08002862 if ((voip_usecase != NULL) &&
2863 (usecase->type == PCM_PLAYBACK) &&
2864 (usecase->stream.out != NULL)) {
yidongh02ef86f2017-04-21 15:36:04 +08002865 out_snd_device_backend_match = platform_check_backends_match(
2866 voip_usecase->out_snd_device,
2867 platform_get_output_snd_device(
2868 adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302869 usecase->stream.out, usecase->type));
yidongh02ef86f2017-04-21 15:36:04 +08002870 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002871 if ((voip_usecase) && (is_codec_backend_out_device_type(&voip_usecase->device_list) &&
2872 (is_codec_backend_out_device_type(&usecase->device_list) ||
2873 is_codec_backend_in_device_type(&usecase->device_list)) &&
yidongh02ef86f2017-04-21 15:36:04 +08002874 out_snd_device_backend_match &&
Mingming Yin2d8aa2e2014-08-14 00:00:51 -07002875 (voip_usecase->stream.out != adev->primary_output))) {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08002876 in_snd_device = voip_usecase->in_snd_device;
2877 out_snd_device = voip_usecase->out_snd_device;
2878 }
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002879 } else if (audio_extn_hfp_is_active(adev)) {
Vimal Puthanveed41fcff22014-01-23 15:56:53 -08002880 hfp_ucid = audio_extn_hfp_get_usecase();
2881 hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002882 if ((hfp_usecase) && is_codec_backend_out_device_type(&hfp_usecase->device_list)) {
Vimal Puthanveed37b4a1c2014-01-07 16:47:47 -08002883 in_snd_device = hfp_usecase->in_snd_device;
2884 out_snd_device = hfp_usecase->out_snd_device;
2885 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002886 }
2887 if (usecase->type == PCM_PLAYBACK) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302888 if (usecase->stream.out == NULL) {
2889 ALOGE("%s: stream.out is NULL", __func__);
2890 return -EINVAL;
2891 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002892 assign_devices(&usecase->device_list, &usecase->stream.out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002893 in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002894 if (out_snd_device == SND_DEVICE_NONE) {
Eric Laurent637e2d42018-11-15 12:24:31 -08002895 struct stream_out *voip_out = adev->primary_output;
2896 struct stream_in *voip_in = get_voice_communication_input(adev);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002897 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS))
Guodong Hu267bdf82019-08-12 19:22:32 +08002898 out_snd_device = audio_extn_auto_hal_get_output_snd_device(adev, uc_id);
2899 else
2900 out_snd_device = platform_get_output_snd_device(adev->platform,
Jaideep Sharma477917f2020-03-13 18:13:33 +05302901 usecase->stream.out,
2902 usecase->type);
kunleizdcf967a2018-08-07 17:09:11 +08002903 voip_usecase = get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP);
kunleizdcf967a2018-08-07 17:09:11 +08002904
Eric Laurent637e2d42018-11-15 12:24:31 -08002905 if (voip_usecase)
2906 voip_out = voip_usecase->stream.out;
2907
2908 if (usecase->stream.out == voip_out && voip_in != NULL)
2909 select_devices(adev, voip_in->usecase);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002910 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002911 } else if (usecase->type == PCM_CAPTURE) {
Aditya Bavanaribdda2f22016-10-19 15:02:05 +05302912 if (usecase->stream.in == NULL) {
2913 ALOGE("%s: stream.in is NULL", __func__);
2914 return -EINVAL;
2915 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002916 assign_devices(&usecase->device_list, &usecase->stream.in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002917 out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002918 if (in_snd_device == SND_DEVICE_NONE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002919 struct listnode out_devices;
Eric Laurent637e2d42018-11-15 12:24:31 -08002920 struct stream_in *voip_in = get_voice_communication_input(adev);
Carter Hsu2e429db2019-05-14 18:50:52 +08002921 struct stream_in *priority_in = NULL;
Eric Laurent637e2d42018-11-15 12:24:31 -08002922
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002923 list_init(&out_devices);
Eric Laurent637e2d42018-11-15 12:24:31 -08002924 if (voip_in != NULL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08002925 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
2926 USECASE_AUDIO_PLAYBACK_VOIP);
2927
Carter Hsu2e429db2019-05-14 18:50:52 +08002928 usecase->stream.in->enable_ec_port = false;
2929
Zhou Song503196b2021-07-23 17:31:05 +08002930 if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY ||
2931 usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY2) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002932 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_TELEPHONY_TX, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08002933 } else if (voip_usecase) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002934 assign_devices(&out_devices, &voip_usecase->stream.out->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08002935 } else if (adev->primary_output &&
2936 !adev->primary_output->standby) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002937 assign_devices(&out_devices, &adev->primary_output->device_list);
Eric Laurent637e2d42018-11-15 12:24:31 -08002938 } else {
2939 /* forcing speaker o/p device to get matching i/p pair
2940 in case o/p is not routed from same primary HAL */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002941 reassign_device_list(&out_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Eric Laurent637e2d42018-11-15 12:24:31 -08002942 }
Carter Hsu2e429db2019-05-14 18:50:52 +08002943 priority_in = voip_in;
2944 } else {
2945 /* get the input with the highest priority source*/
2946 priority_in = get_priority_input(adev);
2947
Susan Wang727dd6b2021-03-26 11:28:59 -04002948 if (!priority_in ||
2949 audio_extn_auto_hal_overwrite_priority_for_auto(usecase->stream.in))
Carter Hsu2e429db2019-05-14 18:50:52 +08002950 priority_in = usecase->stream.in;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002951 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04002952 if (compare_device_type(&usecase->device_list, AUDIO_DEVICE_IN_BUS)){
2953 in_snd_device = audio_extn_auto_hal_get_snd_device_for_car_audio_stream(priority_in->car_audio_stream);
2954 }
2955 else
2956 in_snd_device = platform_get_input_snd_device(adev->platform,
2957 priority_in,
2958 &out_devices,
2959 usecase->type);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002960 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002961 }
2962 }
2963
2964 if (out_snd_device == usecase->out_snd_device &&
2965 in_snd_device == usecase->in_snd_device) {
Sidipotu Ashoke6f78cb2015-11-05 14:42:20 +05302966
2967 if (!force_device_switch(usecase))
2968 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002969 }
2970
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002971 if (!compare_device_type(&usecase->device_list, AUDIO_DEVICE_OUT_BUS) &&
Guodong Hu267bdf82019-08-12 19:22:32 +08002972 ((is_btsco_device(out_snd_device,in_snd_device) && !adev->bt_sco_on) ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08002973 (is_a2dp_device(out_snd_device) && !audio_extn_a2dp_source_is_ready()))) {
Guodong Hu267bdf82019-08-12 19:22:32 +08002974 ALOGD("SCO/A2DP is selected but they are not connected/ready hence dont route");
2975 return 0;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05302976 }
2977
Aalique Grahame22e49102018-12-18 14:23:57 -08002978 if (out_snd_device != SND_DEVICE_NONE &&
2979 out_snd_device != adev->last_logged_snd_device[uc_id][0]) {
2980 ALOGD("%s: changing use case %s output device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
2981 __func__,
2982 use_case_table[uc_id],
2983 adev->last_logged_snd_device[uc_id][0],
2984 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][0]),
2985 adev->last_logged_snd_device[uc_id][0] != SND_DEVICE_NONE ?
2986 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][0]) :
2987 -1,
2988 out_snd_device,
2989 platform_get_snd_device_name(out_snd_device),
2990 platform_get_snd_device_acdb_id(out_snd_device));
2991 adev->last_logged_snd_device[uc_id][0] = out_snd_device;
2992 }
2993 if (in_snd_device != SND_DEVICE_NONE &&
2994 in_snd_device != adev->last_logged_snd_device[uc_id][1]) {
2995 ALOGD("%s: changing use case %s input device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
2996 __func__,
2997 use_case_table[uc_id],
2998 adev->last_logged_snd_device[uc_id][1],
2999 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][1]),
3000 adev->last_logged_snd_device[uc_id][1] != SND_DEVICE_NONE ?
3001 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][1]) :
3002 -1,
3003 in_snd_device,
3004 platform_get_snd_device_name(in_snd_device),
3005 platform_get_snd_device_acdb_id(in_snd_device));
3006 adev->last_logged_snd_device[uc_id][1] = in_snd_device;
3007 }
3008
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08003009
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003010 /*
3011 * Limitation: While in call, to do a device switch we need to disable
3012 * and enable both RX and TX devices though one of them is same as current
3013 * device.
3014 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003015 if ((usecase->type == VOICE_CALL) &&
3016 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3017 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Eric Laurentb23d5282013-05-14 15:27:20 -07003018 status = platform_switch_voice_call_device_pre(adev->platform);
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003019 }
3020
3021 if (((usecase->type == VOICE_CALL) ||
3022 (usecase->type == VOIP_CALL)) &&
3023 (usecase->out_snd_device != SND_DEVICE_NONE)) {
3024 /* Disable sidetone only if voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303025 if (voice_is_call_state_active_in_call(adev) ||
Narsinga Rao Chella116142b2015-08-14 18:00:08 -07003026 voice_extn_compress_voip_is_started(adev))
Bhalchandra Gajare45fee282015-06-09 22:23:45 -07003027 voice_set_sidetone(adev, usecase->out_snd_device, false);
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003028
3029 /* Disable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303030 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003031 voice_check_and_update_aanc_path(adev, usecase->out_snd_device, false);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003032 }
3033
Aalique Grahame22e49102018-12-18 14:23:57 -08003034 if ((out_snd_device == SND_DEVICE_OUT_SPEAKER_AND_BT_A2DP ||
3035 out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02003036 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303037 ALOGW("%s: A2DP profile is not ready, routing to speaker only", __func__);
Aalique Grahame22e49102018-12-18 14:23:57 -08003038 if (out_snd_device == SND_DEVICE_OUT_SPEAKER_SAFE_AND_BT_A2DP)
3039 out_snd_device = SND_DEVICE_OUT_SPEAKER_SAFE;
3040 else
3041 out_snd_device = SND_DEVICE_OUT_SPEAKER;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303042 }
3043
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003044 /* Disable current sound devices */
3045 if (usecase->out_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003046 disable_audio_route(adev, usecase);
3047 disable_snd_device(adev, usecase->out_snd_device);
Gautam Manam274f4752021-09-24 10:58:49 +05303048 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3049 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003050 }
3051
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003052 if (usecase->in_snd_device != SND_DEVICE_NONE) {
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003053 disable_audio_route(adev, usecase);
3054 disable_snd_device(adev, usecase->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003055 }
3056
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003057 /* Applicable only on the targets that has external modem.
3058 * New device information should be sent to modem before enabling
3059 * the devices to reduce in-call device switch time.
3060 */
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003061 if ((usecase->type == VOICE_CALL) &&
3062 (usecase->in_snd_device != SND_DEVICE_NONE) &&
3063 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003064 status = platform_switch_voice_call_enable_device_config(adev->platform,
3065 out_snd_device,
3066 in_snd_device);
Vidyakumar Athota21b3bb92014-04-25 11:08:08 -07003067 }
Vidyakumar Athota545dbd32013-11-13 17:30:53 -08003068
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003069 /* Enable new sound devices */
3070 if (out_snd_device != SND_DEVICE_NONE) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08003071 check_usecases_codec_backend(adev, usecase, out_snd_device);
Saurav Kumarc1411662020-10-14 10:50:45 +05303072 check_and_configure_headphone(adev, usecase, out_snd_device);
Preetam Singh Ranawat43eac682017-03-07 18:19:02 +05303073 if (platform_check_codec_asrc_support(adev->platform))
3074 check_and_set_asrc_mode(adev, usecase, out_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003075 enable_snd_device(adev, out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08003076 /* Enable haptics device for haptic usecase */
3077 if (usecase->id == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3078 enable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003079 }
3080
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003081 if (in_snd_device != SND_DEVICE_NONE) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05303082 check_usecases_capture_codec_backend(adev, usecase, in_snd_device);
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003083 enable_snd_device(adev, in_snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07003084 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003085
Lakshman Chaluvarajuab7e5572020-10-28 19:29:23 +05303086 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL)
Eric Laurentb23d5282013-05-14 15:27:20 -07003087 status = platform_switch_voice_call_device_post(adev->platform,
3088 out_snd_device,
3089 in_snd_device);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08003090
sangwoo170731f2013-06-08 15:36:36 +09003091 usecase->in_snd_device = in_snd_device;
3092 usecase->out_snd_device = out_snd_device;
3093
Dhananjay Kumard6d32152016-10-13 16:11:03 +05303094 audio_extn_utils_update_stream_app_type_cfg_for_usecase(adev,
3095 usecase);
Preetam Singh Ranawata4a37d82014-09-25 16:56:38 +05303096 if (usecase->type == PCM_PLAYBACK) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003097 if ((24 == usecase->stream.out->bit_width) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003098 compare_device_type(&usecase->stream.out->device_list, AUDIO_DEVICE_OUT_SPEAKER)) {
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003099 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3100 } else if ((out_snd_device == SND_DEVICE_OUT_HDMI ||
3101 out_snd_device == SND_DEVICE_OUT_USB_HEADSET ||
3102 out_snd_device == SND_DEVICE_OUT_DISPLAY_PORT) &&
3103 (usecase->stream.out->sample_rate >= OUTPUT_SAMPLING_RATE_44100)) {
3104 /*
3105 * To best utlize DSP, check if the stream sample rate is supported/multiple of
3106 * configured device sample rate, if not update the COPP rate to be equal to the
3107 * device sample rate, else open COPP at stream sample rate
3108 */
3109 platform_check_and_update_copp_sample_rate(adev->platform, out_snd_device,
3110 usecase->stream.out->sample_rate,
3111 &usecase->stream.out->app_type_cfg.sample_rate);
Ashish Jain4826f6c2017-02-06 13:33:20 +05303112 } else if (((out_snd_device != SND_DEVICE_OUT_HEADPHONES_44_1 &&
Preetam Singh Ranawat590d0432019-09-30 14:39:47 +05303113 out_snd_device != SND_DEVICE_OUT_HEADPHONES &&
3114 out_snd_device != SND_DEVICE_OUT_HEADPHONES_HIFI_FILTER &&
Ashish Jain4826f6c2017-02-06 13:33:20 +05303115 !audio_is_true_native_stream_active(adev)) &&
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003116 usecase->stream.out->sample_rate == OUTPUT_SAMPLING_RATE_44100) ||
3117 (usecase->stream.out->sample_rate < OUTPUT_SAMPLING_RATE_44100)) {
3118 usecase->stream.out->app_type_cfg.sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3119 }
Weiyin Jiangcdece202019-07-08 16:13:16 +08003120 }
3121 enable_audio_route(adev, usecase);
Weiyin Jiang6f4c8062016-11-23 15:30:29 +08003122
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303123 if (uc_id == USECASE_AUDIO_PLAYBACK_VOIP) {
3124 struct stream_in *voip_in = get_voice_communication_input(adev);
3125 struct audio_usecase *voip_in_usecase = NULL;
3126 voip_in_usecase = get_usecase_from_list(adev, USECASE_AUDIO_RECORD_VOIP);
3127 if (voip_in != NULL &&
3128 voip_in_usecase != NULL &&
3129 !(out_snd_device == AUDIO_DEVICE_OUT_SPEAKER ||
3130 out_snd_device == AUDIO_DEVICE_OUT_SPEAKER_SAFE) &&
3131 (voip_in_usecase->in_snd_device ==
3132 platform_get_input_snd_device(adev->platform, voip_in,
3133 &usecase->stream.out->device_list,usecase->type))) {
3134 /*
3135 * if VOIP TX is enabled before VOIP RX, needs to re-route the TX path
3136 * for enabling echo-reference-voip with correct port
3137 */
3138 ALOGD("%s: VOIP TX is enabled before VOIP RX,needs to re-route the TX path",__func__);
3139 disable_audio_route(adev, voip_in_usecase);
3140 disable_snd_device(adev, voip_in_usecase->in_snd_device);
3141 enable_snd_device(adev, voip_in_usecase->in_snd_device);
3142 enable_audio_route(adev, voip_in_usecase);
3143 }
3144 }
Ramjee Singhcdf67af2021-09-29 14:20:27 +05303145 if (voice_extn_compress_voip_is_active(adev)) {
3146 struct audio_usecase *voip_usecase = get_usecase_from_list(adev,
3147 USECASE_COMPRESS_VOIP_CALL);
3148 /*
3149 * If only compress voip input is opened voip out will be primary out.
3150 * Need to consider re-routing to select correct i/p pair
3151 */
3152 if ((voip_usecase != NULL) &&
3153 (usecase->type == PCM_PLAYBACK) &&
3154 (usecase->stream.out == voip_usecase->stream.out)) {
3155 in_snd_device = platform_get_input_snd_device(adev->platform,
3156 NULL,
3157 &usecase->stream.out->device_list,
3158 usecase->type);
3159 if (voip_usecase->in_snd_device != in_snd_device ) {
3160 ALOGD("%s:Re routing compress voip tx snd device matching voip rx pair",
3161 __func__);
3162 disable_audio_route(adev, voip_usecase);
3163 disable_snd_device(adev, voip_usecase->in_snd_device);
3164 voip_usecase->in_snd_device = in_snd_device;
3165 voip_usecase->out_snd_device = usecase->out_snd_device;
3166 /* Route all TX usecase to Compress voip BE */
3167 check_usecases_capture_codec_backend(adev, voip_usecase, in_snd_device);
3168 enable_snd_device(adev, in_snd_device);
3169 /* Send Voice related calibration for RX /TX pair */
3170 status = platform_switch_voice_call_device_post(adev->platform,
3171 out_snd_device,
3172 in_snd_device);
3173 enable_audio_route(adev, voip_usecase);
3174 }
3175 }
3176 }
Shalini Manjunatha5e610912020-12-29 13:02:25 +05303177
3178
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08003179 audio_extn_qdsp_set_device(usecase);
Aalique Grahame22e49102018-12-18 14:23:57 -08003180
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003181 /* If input stream is already running then effect needs to be
3182 applied on the new input device that's being enabled here. */
Eric Laurent637e2d42018-11-15 12:24:31 -08003183 if (in_snd_device != SND_DEVICE_NONE)
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003184 check_and_enable_effect(adev);
3185
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003186 if (usecase->type == VOICE_CALL || usecase->type == VOIP_CALL) {
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003187 /* Enable aanc only if voice call exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303188 if (voice_is_call_state_active_in_call(adev))
Vidyakumar Athotaea269c62016-10-31 09:05:59 -07003189 voice_check_and_update_aanc_path(adev, out_snd_device, true);
3190
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003191 /* Enable sidetone only if other voice/voip call already exists */
Jaideep Sharma477917f2020-03-13 18:13:33 +05303192 if (voice_is_call_state_active_in_call(adev) ||
Vidyakumar Athota493f2892016-08-14 11:56:55 -07003193 voice_extn_compress_voip_is_started(adev))
3194 voice_set_sidetone(adev, out_snd_device, true);
3195 }
3196
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003197 /* Applicable only on the targets that has external modem.
3198 * Enable device command should be sent to modem only after
3199 * enabling voice call mixer controls
3200 */
Vidyakumar Athota339342f2014-07-01 15:30:57 -07003201 if (usecase->type == VOICE_CALL)
Vidyakumar Athota1fd21792013-11-15 14:50:57 -08003202 status = platform_switch_voice_call_usecase_route_post(adev->platform,
3203 out_snd_device,
3204 in_snd_device);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303205
3206 if (is_btsco_device(out_snd_device, in_snd_device) || is_a2dp_device(out_snd_device)) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003207 struct stream_in *in = adev_get_active_input(adev);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303208 if (usecase->type == VOIP_CALL) {
Eric Laurent637e2d42018-11-15 12:24:31 -08003209 if (in != NULL && !in->standby) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303210 if (is_bt_soc_on(adev) == false){
3211 ALOGD("BT SCO MIC disconnected while in connection");
Eric Laurent637e2d42018-11-15 12:24:31 -08003212 if (in->pcm != NULL)
3213 pcm_stop(in->pcm);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303214 }
3215 }
3216 if ((usecase->stream.out != NULL) && (usecase->stream.out != adev->primary_output)
3217 && usecase->stream.out->started) {
3218 if (is_bt_soc_on(adev) == false) {
3219 ALOGD("BT SCO/A2DP disconnected while in connection");
3220 out_standby_l(&usecase->stream.out->stream.common);
3221 }
3222 }
3223 } else if ((usecase->stream.out != NULL) &&
3224 !(usecase->stream.out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Surendar Karkae1dc8742018-11-19 16:23:14 +05303225 (usecase->type != TRANSCODE_LOOPBACK_TX) &&
3226 (usecase->type != TRANSCODE_LOOPBACK_RX) &&
Weiyin Jiang0d373242019-07-25 13:18:17 +08003227 (usecase->type != PCM_CAPTURE) &&
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303228 usecase->stream.out->started) {
3229 if (is_bt_soc_on(adev) == false) {
3230 ALOGD("BT SCO/A2dp disconnected while in connection");
3231 out_standby_l(&usecase->stream.out->stream.common);
3232 }
3233 }
3234 }
3235
Yung Ti Su70cb8242018-06-22 17:38:47 +08003236 if (usecase->type != PCM_CAPTURE && usecase == voip_usecase) {
Aalique Grahame22e49102018-12-18 14:23:57 -08003237 struct stream_out *voip_out = voip_usecase->stream.out;
3238 audio_extn_utils_send_app_type_gain(adev,
3239 voip_out->app_type_cfg.app_type,
3240 &voip_out->app_type_cfg.gain[0]);
3241 }
3242
Ajender Reddyb940b832021-07-07 11:51:42 +05303243 ALOGD("%s: done",__func__);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303244
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003245 return status;
3246}
3247
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003248static int stop_input_stream(struct stream_in *in)
3249{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303250 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003251 struct audio_usecase *uc_info;
Pallavid7c7a272018-01-16 11:22:55 +05303252
3253 if (in == NULL) {
3254 ALOGE("%s: stream_in ptr is NULL", __func__);
3255 return -EINVAL;
3256 }
3257
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003258 struct audio_device *adev = in->dev;
Carter Hsu2e429db2019-05-14 18:50:52 +08003259 struct stream_in *priority_in = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003260
Eric Laurent994a6932013-07-17 11:51:42 -07003261 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003262 in->usecase, use_case_table[in->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003263 uc_info = get_usecase_from_list(adev, in->usecase);
3264 if (uc_info == NULL) {
3265 ALOGE("%s: Could not find the usecase (%d) in the list",
3266 __func__, in->usecase);
3267 return -EINVAL;
3268 }
3269
Carter Hsu2e429db2019-05-14 18:50:52 +08003270 priority_in = get_priority_input(adev);
3271
Derek Chenea197282019-01-07 17:35:01 -08003272 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3273 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003274
Vidyakumar Athota2850d532013-11-19 16:02:12 -08003275 /* Close in-call recording streams */
3276 voice_check_and_stop_incall_rec_usecase(adev, in);
3277
Eric Laurent150dbfe2013-02-27 14:31:02 -08003278 /* 1. Disable stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003279 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003280
3281 /* 2. Disable the tx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003282 disable_snd_device(adev, uc_info->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003283
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003284 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303285 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_PRIMARY);
3286
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003287 list_remove(&uc_info->list);
3288 free(uc_info);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003289
Carter Hsu2e429db2019-05-14 18:50:52 +08003290 if (priority_in == in) {
3291 priority_in = get_priority_input(adev);
Sujin Panicker110f7942021-08-26 17:01:22 +05303292 if (priority_in) {
3293 if (is_usb_in_device_type(&priority_in->device_list)) {
3294 if (audio_extn_usb_connected(NULL))
3295 select_devices(adev, priority_in->usecase);
3296 } else {
3297 select_devices(adev, priority_in->usecase);
3298 }
3299 }
Carter Hsu2e429db2019-05-14 18:50:52 +08003300 }
3301
Vatsal Buchac09ae062018-11-14 13:25:08 +05303302 enable_gcov();
Eric Laurent994a6932013-07-17 11:51:42 -07003303 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003304 return ret;
3305}
3306
3307int start_input_stream(struct stream_in *in)
3308{
3309 /* 1. Enable output device and stream routing controls */
Eric Laurentc8400632013-02-14 19:04:54 -08003310 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003311 struct audio_usecase *uc_info;
Preetam Singh Ranawata87e9742018-02-13 16:52:53 +05303312
3313 if (in == NULL) {
3314 ALOGE("%s: stream_in ptr is NULL", __func__);
3315 return -EINVAL;
3316 }
3317
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003318 struct audio_device *adev = in->dev;
Garmond Leunge2433c32017-09-28 21:51:22 -07003319 struct pcm_config config = in->config;
Garmond Leung438932f2017-10-04 19:35:18 -07003320 int usecase = platform_update_usecase_from_source(in->source,in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003321
Mingming Yin2664a5b2015-09-03 10:53:11 -07003322 if (get_usecase_from_list(adev, usecase) == NULL)
3323 in->usecase = usecase;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303324 ALOGD("%s: enter: stream(%p)usecase(%d: %s)",
3325 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003326
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303327 if (CARD_STATUS_OFFLINE == in->card_status||
3328 CARD_STATUS_OFFLINE == adev->card_status) {
3329 ALOGW("in->card_status or adev->card_status offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05303330 ret = -EIO;
Naresh Tanniru4c630392014-05-12 01:05:52 +05303331 goto error_config;
3332 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05303333
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003334 if (is_sco_in_device_type(&in->device_list)) {
Lakshman Chaluvaraju87f53aa2021-02-02 15:50:11 +05303335 if (!adev->bt_sco_on || audio_extn_a2dp_source_is_ready()) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303336 ALOGE("%s: SCO profile is not ready, return error", __func__);
3337 ret = -EIO;
3338 goto error_config;
3339 }
3340 }
3341
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003342 /* Check if source matches incall recording usecase criteria */
3343 ret = voice_check_and_set_incall_rec_usecase(adev, in);
3344 if (ret)
3345 goto error_config;
3346 else
Mingming Yin2664a5b2015-09-03 10:53:11 -07003347 ALOGV("%s: usecase(%d)", __func__, in->usecase);
3348
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303349 if (audio_extn_cin_attached_usecase(in))
3350 audio_extn_cin_acquire_usecase(in);
3351
Mingming Yin2664a5b2015-09-03 10:53:11 -07003352 if (get_usecase_from_list(adev, in->usecase) != NULL) {
3353 ALOGE("%s: use case assigned already in use, stream(%p)usecase(%d: %s)",
3354 __func__, &in->stream, in->usecase, use_case_table[in->usecase]);
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003355 ret = -EINVAL;
3356 goto error_config;
Mingming Yin2664a5b2015-09-03 10:53:11 -07003357 }
Shiv Maliyappanahallida107642013-10-17 11:16:13 -07003358
Eric Laurentb23d5282013-05-14 15:27:20 -07003359 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003360 if (in->pcm_device_id < 0) {
3361 ALOGE("%s: Could not find PCM device id for the usecase(%d)",
3362 __func__, in->usecase);
Eric Laurentc8400632013-02-14 19:04:54 -08003363 ret = -EINVAL;
3364 goto error_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003365 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003366
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003367 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003368
3369 if (!uc_info) {
3370 ret = -ENOMEM;
3371 goto error_config;
3372 }
3373
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003374 uc_info->id = in->usecase;
3375 uc_info->type = PCM_CAPTURE;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003376 uc_info->stream.in = in;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003377 list_init(&uc_info->device_list);
3378 assign_devices(&uc_info->device_list, &in->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003379 uc_info->in_snd_device = SND_DEVICE_NONE;
3380 uc_info->out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003381
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003382 list_add_tail(&adev->usecase_list, &uc_info->list);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003383 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303384 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
3385 adev->perf_lock_opts,
3386 adev->perf_lock_opts_size);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003387 select_devices(adev, in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003388
Derek Chenea197282019-01-07 17:35:01 -08003389 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
3390 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003391
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05303392 android_atomic_acquire_cas(true, false, &(in->capture_stopped));
3393
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05303394 if (audio_extn_cin_attached_usecase(in)) {
Manish Dewangan46e07982018-12-13 18:18:59 +05303395 ret = audio_extn_cin_open_input_stream(in);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303396 if (ret)
3397 goto error_open;
3398 else
3399 goto done_open;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003400 }
3401
Haynes Mathew George16081042017-05-31 17:16:49 -07003402 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003403 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003404 ALOGE("%s: pcm stream not ready", __func__);
3405 goto error_open;
3406 }
3407 ret = pcm_start(in->pcm);
3408 if (ret < 0) {
3409 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
3410 goto error_open;
3411 }
3412 } else {
3413 unsigned int flags = PCM_IN | PCM_MONOTONIC;
3414 unsigned int pcm_open_retry_count = 0;
3415
Zhou Song62ea0282020-03-22 19:53:01 +08003416 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) ||
3417 (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003418 flags |= PCM_MMAP | PCM_NOIRQ;
3419 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
3420 } else if (in->realtime) {
3421 flags |= PCM_MMAP | PCM_NOIRQ;
3422 }
3423
Garmond Leunge2433c32017-09-28 21:51:22 -07003424 if (audio_extn_ffv_get_stream() == in) {
3425 ALOGD("%s: ffv stream, update pcm config", __func__);
3426 audio_extn_ffv_update_pcm_config(&config);
3427 }
Haynes Mathew George16081042017-05-31 17:16:49 -07003428 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
3429 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
3430
3431 while (1) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003432 ATRACE_BEGIN("pcm_in_open");
Haynes Mathew George16081042017-05-31 17:16:49 -07003433 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
Garmond Leung438932f2017-10-04 19:35:18 -07003434 flags, &config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003435 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05303436 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05303437 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
3438 adev->card_status = CARD_STATUS_OFFLINE;
3439 in->card_status = CARD_STATUS_OFFLINE;
3440 ret = -EIO;
3441 goto error_open;
3442 }
3443
Haynes Mathew George16081042017-05-31 17:16:49 -07003444 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
3445 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
3446 if (in->pcm != NULL) {
3447 pcm_close(in->pcm);
3448 in->pcm = NULL;
3449 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003450 if (pcm_open_retry_count == 0) {
Haynes Mathew George16081042017-05-31 17:16:49 -07003451 ret = -EIO;
3452 goto error_open;
3453 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003454 pcm_open_retry_count--;
Haynes Mathew George16081042017-05-31 17:16:49 -07003455 usleep(PROXY_OPEN_WAIT_TIME * 1000);
3456 continue;
3457 }
3458 break;
3459 }
3460
3461 ALOGV("%s: pcm_prepare", __func__);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003462 ATRACE_BEGIN("pcm_in_prepare");
Haynes Mathew George16081042017-05-31 17:16:49 -07003463 ret = pcm_prepare(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003464 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003465 if (ret < 0) {
3466 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
3467 pcm_close(in->pcm);
3468 in->pcm = NULL;
3469 goto error_open;
3470 }
3471 register_in_stream(in);
3472 if (in->realtime) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07003473 ATRACE_BEGIN("pcm_in_start");
Haynes Mathew George16081042017-05-31 17:16:49 -07003474 ret = pcm_start(in->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07003475 ATRACE_END();
Haynes Mathew George16081042017-05-31 17:16:49 -07003476 if (ret < 0) {
3477 ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003478 pcm_close(in->pcm);
3479 in->pcm = NULL;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003480 goto error_open;
3481 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07003482 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07003483 }
3484
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003485 check_and_enable_effect(adev);
justinweng20fb6d82019-02-21 18:49:00 -07003486 audio_extn_audiozoom_set_microphone_direction(in, in->zoom);
3487 audio_extn_audiozoom_set_microphone_field_dimension(in, in->direction);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07003488
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003489 if (is_loopback_input_device(get_device_types(&in->device_list)))
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05303490 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_PRIMARY);
3491
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05303492done_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003493 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303494 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Manisha Agarwal4c2402e2020-10-21 12:02:57 +05303495 ALOGD("%s: exit", __func__);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303496 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003497 return ret;
3498
3499error_open:
Wei Wangf7ca6c92017-11-21 14:51:20 -08003500 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05303501 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003502 stop_input_stream(in);
Wei Wangf7ca6c92017-11-21 14:51:20 -08003503
Eric Laurentc8400632013-02-14 19:04:54 -08003504error_config:
Weiyin Jiang38c0e612020-09-10 16:10:51 +08003505 if (audio_extn_cin_attached_usecase(in))
3506 audio_extn_cin_close_input_stream(in);
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05303507 /*
3508 * sleep 50ms to allow sufficient time for kernel
3509 * drivers to recover incases like SSR.
3510 */
3511 usleep(50000);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003512 ALOGD("%s: exit: status(%d)", __func__, ret);
Vatsal Buchac09ae062018-11-14 13:25:08 +05303513 enable_gcov();
Eric Laurentc8400632013-02-14 19:04:54 -08003514 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003515}
3516
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003517void lock_input_stream(struct stream_in *in)
3518{
3519 pthread_mutex_lock(&in->pre_lock);
3520 pthread_mutex_lock(&in->lock);
3521 pthread_mutex_unlock(&in->pre_lock);
3522}
3523
3524void lock_output_stream(struct stream_out *out)
3525{
3526 pthread_mutex_lock(&out->pre_lock);
3527 pthread_mutex_lock(&out->lock);
3528 pthread_mutex_unlock(&out->pre_lock);
3529}
3530
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003531/* must be called with out->lock locked */
3532static int send_offload_cmd_l(struct stream_out* out, int command)
3533{
3534 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
3535
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003536 if (!cmd) {
3537 ALOGE("failed to allocate mem for command 0x%x", command);
3538 return -ENOMEM;
3539 }
3540
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003541 ALOGVV("%s %d", __func__, command);
3542
3543 cmd->cmd = command;
3544 list_add_tail(&out->offload_cmd_list, &cmd->node);
3545 pthread_cond_signal(&out->offload_cond);
3546 return 0;
3547}
3548
Gautam Manam14c198b2020-12-24 14:08:04 +05303549/* must be called with out->lock */
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003550static void stop_compressed_output_l(struct stream_out *out)
3551{
Gautam Manam14c198b2020-12-24 14:08:04 +05303552 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003553 out->offload_state = OFFLOAD_STATE_IDLE;
Gautam Manam14c198b2020-12-24 14:08:04 +05303554 pthread_mutex_unlock(&out->latch_lock);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08003555
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003556 out->playback_started = 0;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07003557 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003558 if (out->compr != NULL) {
3559 compress_stop(out->compr);
3560 while (out->offload_thread_blocked) {
3561 pthread_cond_wait(&out->cond, &out->lock);
3562 }
3563 }
3564}
3565
Varun Balaraje49253e2017-07-06 19:48:56 +05303566bool is_interactive_usecase(audio_usecase_t uc_id)
3567{
3568 unsigned int i;
3569 for (i = 0; i < sizeof(interactive_usecases)/sizeof(interactive_usecases[0]); i++) {
3570 if (uc_id == interactive_usecases[i])
3571 return true;
3572 }
3573 return false;
3574}
3575
3576static audio_usecase_t get_interactive_usecase(struct audio_device *adev)
3577{
3578 audio_usecase_t ret_uc = USECASE_INVALID;
3579 unsigned int intract_uc_index;
3580 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3581
3582 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
3583 for (intract_uc_index = 0; intract_uc_index < num_usecase; intract_uc_index++) {
3584 if (!(adev->interactive_usecase_state & (0x1 << intract_uc_index))) {
3585 adev->interactive_usecase_state |= 0x1 << intract_uc_index;
3586 ret_uc = interactive_usecases[intract_uc_index];
3587 break;
3588 }
3589 }
3590
3591 ALOGV("%s: Interactive usecase is %d", __func__, ret_uc);
3592 return ret_uc;
3593}
3594
3595static void free_interactive_usecase(struct audio_device *adev,
3596 audio_usecase_t uc_id)
3597{
3598 unsigned int interact_uc_index;
3599 unsigned int num_usecase = sizeof(interactive_usecases)/sizeof(interactive_usecases[0]);
3600
3601 for (interact_uc_index = 0; interact_uc_index < num_usecase; interact_uc_index++) {
3602 if (interactive_usecases[interact_uc_index] == uc_id) {
3603 adev->interactive_usecase_state &= ~(0x1 << interact_uc_index);
3604 break;
3605 }
3606 }
3607 ALOGV("%s: free Interactive usecase %d", __func__, uc_id);
3608}
3609
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003610bool is_offload_usecase(audio_usecase_t uc_id)
3611{
3612 unsigned int i;
3613 for (i = 0; i < sizeof(offload_usecases)/sizeof(offload_usecases[0]); i++) {
3614 if (uc_id == offload_usecases[i])
3615 return true;
3616 }
3617 return false;
3618}
3619
Dhananjay Kumarac341582017-02-23 23:42:25 +05303620static audio_usecase_t get_offload_usecase(struct audio_device *adev, bool is_compress)
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003621{
vivek mehta446c3962015-09-14 10:57:35 -07003622 audio_usecase_t ret_uc = USECASE_INVALID;
3623 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003624 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003625 if (!adev->multi_offload_enable) {
Dhananjay Kumarac341582017-02-23 23:42:25 +05303626 if (!is_compress)
vivek mehta446c3962015-09-14 10:57:35 -07003627 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD2;
3628 else
3629 ret_uc = USECASE_AUDIO_PLAYBACK_OFFLOAD;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003630
vivek mehta446c3962015-09-14 10:57:35 -07003631 pthread_mutex_lock(&adev->lock);
3632 if (get_usecase_from_list(adev, ret_uc) != NULL)
3633 ret_uc = USECASE_INVALID;
3634 pthread_mutex_unlock(&adev->lock);
3635
3636 return ret_uc;
3637 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003638
3639 ALOGV("%s: num_usecase: %d", __func__, num_usecase);
vivek mehta446c3962015-09-14 10:57:35 -07003640 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3641 if (!(adev->offload_usecases_state & (0x1 << offload_uc_index))) {
3642 adev->offload_usecases_state |= 0x1 << offload_uc_index;
3643 ret_uc = offload_usecases[offload_uc_index];
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003644 break;
3645 }
3646 }
vivek mehta446c3962015-09-14 10:57:35 -07003647
3648 ALOGV("%s: offload usecase is %d", __func__, ret_uc);
3649 return ret_uc;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003650}
3651
3652static void free_offload_usecase(struct audio_device *adev,
3653 audio_usecase_t uc_id)
3654{
vivek mehta446c3962015-09-14 10:57:35 -07003655 unsigned int offload_uc_index;
Alexy Josephb1379942016-01-29 15:49:38 -08003656 unsigned int num_usecase = sizeof(offload_usecases)/sizeof(offload_usecases[0]);
vivek mehta446c3962015-09-14 10:57:35 -07003657
3658 if (!adev->multi_offload_enable)
3659 return;
3660
3661 for (offload_uc_index = 0; offload_uc_index < num_usecase; offload_uc_index++) {
3662 if (offload_usecases[offload_uc_index] == uc_id) {
3663 adev->offload_usecases_state &= ~(0x1 << offload_uc_index);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07003664 break;
3665 }
3666 }
3667 ALOGV("%s: free offload usecase %d", __func__, uc_id);
3668}
3669
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003670static void *offload_thread_loop(void *context)
3671{
3672 struct stream_out *out = (struct stream_out *) context;
3673 struct listnode *item;
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003674 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003675
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003676 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08003677 set_sched_policy(0, SP_FOREGROUND);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003678 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
3679
3680 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003681 lock_output_stream(out);
juyuchen391b5fa2018-12-12 17:58:09 +08003682 out->offload_state = OFFLOAD_STATE_IDLE;
3683 out->playback_started = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003684 for (;;) {
3685 struct offload_cmd *cmd = NULL;
3686 stream_callback_event_t event;
3687 bool send_callback = false;
3688
3689 ALOGVV("%s offload_cmd_list %d out->offload_state %d",
3690 __func__, list_empty(&out->offload_cmd_list),
3691 out->offload_state);
3692 if (list_empty(&out->offload_cmd_list)) {
3693 ALOGV("%s SLEEPING", __func__);
3694 pthread_cond_wait(&out->offload_cond, &out->lock);
3695 ALOGV("%s RUNNING", __func__);
3696 continue;
3697 }
3698
3699 item = list_head(&out->offload_cmd_list);
3700 cmd = node_to_item(item, struct offload_cmd, node);
3701 list_remove(item);
3702
3703 ALOGVV("%s STATE %d CMD %d out->compr %p",
3704 __func__, out->offload_state, cmd->cmd, out->compr);
3705
3706 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
3707 free(cmd);
3708 break;
3709 }
3710
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08003711 // allow OFFLOAD_CMD_ERROR reporting during standby
3712 // this is needed to handle failures during compress_open
3713 // Note however that on a pause timeout, the stream is closed
3714 // and no offload usecase will be active. Therefore this
3715 // special case is needed for compress_open failures alone
3716 if (cmd->cmd != OFFLOAD_CMD_ERROR &&
3717 out->compr == NULL) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003718 ALOGE("%s: Compress handle is NULL", __func__);
Haynes Mathew Georgea9abb202016-06-02 14:13:20 -07003719 free(cmd);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003720 pthread_cond_signal(&out->cond);
3721 continue;
3722 }
3723 out->offload_thread_blocked = true;
3724 pthread_mutex_unlock(&out->lock);
3725 send_callback = false;
3726 switch(cmd->cmd) {
3727 case OFFLOAD_CMD_WAIT_FOR_BUFFER:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003728 ALOGD("copl(%p):calling compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003729 compress_wait(out->compr, -1);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003730 ALOGD("copl(%p):out of compress_wait", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003731 send_callback = true;
3732 event = STREAM_CBK_EVENT_WRITE_READY;
3733 break;
3734 case OFFLOAD_CMD_PARTIAL_DRAIN:
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003735 ret = compress_next_track(out->compr);
Sidipotu Ashok55820562014-02-10 16:16:38 +05303736 if(ret == 0) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003737 ALOGD("copl(%p):calling compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303738 ret = compress_partial_drain(out->compr);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003739 ALOGD("copl(%p):out of compress_partial_drain", out);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303740 if (ret < 0)
3741 ret = -errno;
Sidipotu Ashok55820562014-02-10 16:16:38 +05303742 }
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303743 else if (ret == -ETIMEDOUT)
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003744 ret = compress_drain(out->compr);
Krishnankutty Kolathappillyd4f1d132014-01-06 18:33:58 -08003745 else
3746 ALOGE("%s: Next track returned error %d",__func__, ret);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003747 if (-ENETRESET != ret && !(-EINTR == ret &&
3748 CARD_STATUS_OFFLINE == out->card_status)) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303749 send_callback = true;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05303750 pthread_mutex_lock(&out->lock);
3751 out->send_new_metadata = 1;
3752 out->send_next_track_params = true;
3753 pthread_mutex_unlock(&out->lock);
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05303754 event = STREAM_CBK_EVENT_DRAIN_READY;
3755 ALOGV("copl(%p):send drain callback, ret %d", out, ret);
3756 } else
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303757 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003758 break;
3759 case OFFLOAD_CMD_DRAIN:
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07003760 ALOGD("copl(%p):calling compress_drain", out);
Aniket Kumar Lata3570fb12017-11-08 15:53:44 -08003761 ret = compress_drain(out->compr);
3762 ALOGD("copl(%p):out of compress_drain", out);
3763 // EINTR check avoids drain interruption due to SSR
3764 if (-ENETRESET != ret && !(-EINTR == ret &&
3765 CARD_STATUS_OFFLINE == out->card_status)) {
3766 send_callback = true;
3767 event = STREAM_CBK_EVENT_DRAIN_READY;
3768 } else
3769 ALOGI("%s: Block drain ready event during SSR", __func__);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003770 break;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05303771 case OFFLOAD_CMD_ERROR:
3772 ALOGD("copl(%p): sending error callback to AF", out);
3773 send_callback = true;
3774 event = STREAM_CBK_EVENT_ERROR;
3775 break;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003776 default:
3777 ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
3778 break;
3779 }
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003780 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003781 out->offload_thread_blocked = false;
3782 pthread_cond_signal(&out->cond);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08003783 if (send_callback && out->client_callback) {
3784 ALOGVV("%s: sending client_callback event %d", __func__, event);
3785 out->client_callback(event, NULL, out->client_cookie);
Eric Laurent6e895242013-09-05 16:10:57 -07003786 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003787 free(cmd);
3788 }
3789
3790 pthread_cond_signal(&out->cond);
3791 while (!list_empty(&out->offload_cmd_list)) {
3792 item = list_head(&out->offload_cmd_list);
3793 list_remove(item);
3794 free(node_to_item(item, struct offload_cmd, node));
3795 }
3796 pthread_mutex_unlock(&out->lock);
3797
3798 return NULL;
3799}
3800
3801static int create_offload_callback_thread(struct stream_out *out)
3802{
3803 pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
3804 list_init(&out->offload_cmd_list);
3805 pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
3806 offload_thread_loop, out);
3807 return 0;
3808}
3809
3810static int destroy_offload_callback_thread(struct stream_out *out)
3811{
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07003812 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003813 stop_compressed_output_l(out);
3814 send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
3815
3816 pthread_mutex_unlock(&out->lock);
3817 pthread_join(out->offload_thread, (void **) NULL);
3818 pthread_cond_destroy(&out->offload_cond);
3819
3820 return 0;
3821}
3822
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003823static int stop_output_stream(struct stream_out *out)
3824{
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05303825 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003826 struct audio_usecase *uc_info;
3827 struct audio_device *adev = out->dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08003828 bool has_voip_usecase =
3829 get_usecase_from_list(adev, USECASE_AUDIO_PLAYBACK_VOIP) != NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003830
Eric Laurent994a6932013-07-17 11:51:42 -07003831 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003832 out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003833 uc_info = get_usecase_from_list(adev, out->usecase);
3834 if (uc_info == NULL) {
3835 ALOGE("%s: Could not find the usecase (%d) in the list",
3836 __func__, out->usecase);
3837 return -EINVAL;
3838 }
3839
Zhou Songbaddf9f2020-11-20 13:57:39 +08003840 out->a2dp_muted = false;
3841
Derek Chenea197282019-01-07 17:35:01 -08003842 if (audio_extn_ext_hw_plugin_usecase_stop(adev->ext_hw_plugin, uc_info))
3843 ALOGE("%s: failed to stop ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08003844
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003845 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05303846 !(audio_extn_passthru_is_passthrough_stream(out))) {
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08003847 if (adev->visualizer_stop_output != NULL)
3848 adev->visualizer_stop_output(out->handle, out->pcm_device_id);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08003849
3850 audio_extn_dts_remove_state_notifier_node(out->usecase);
3851
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08003852 if (adev->offload_effects_stop_output != NULL)
3853 adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
vivek mehtad15d2bf2019-05-17 13:35:10 -07003854 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
3855 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
3856 audio_low_latency_hint_end();
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -08003857 }
Eric Laurentc4aef752013-09-12 17:45:53 -07003858
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07003859 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
3860 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07003861 voice_set_device_mute_flag(adev, false);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07003862 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07003863
Eric Laurent150dbfe2013-02-27 14:31:02 -08003864 /* 1. Get and set stream specific mixer controls */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003865 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003866
3867 /* 2. Disable the rx device */
Haynes Mathew George1376ca62014-04-24 11:55:48 -07003868 disable_snd_device(adev, uc_info->out_snd_device);
Zhou Songd9bd9302020-08-04 16:34:45 +08003869 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
3870 disable_snd_device(adev, SND_DEVICE_OUT_HAPTICS);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003871
Aalique Grahame22e49102018-12-18 14:23:57 -08003872 audio_extn_extspk_update(adev->extspk);
3873
Xiaojun Sang785b5da2017-08-03 15:52:29 +08003874 if (is_offload_usecase(out->usecase)) {
3875 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
3876 adev->dsp_bit_width_enforce_mode,
3877 false);
3878 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003879 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07003880 ret = audio_extn_usb_check_and_set_svc_int(uc_info,
3881 false);
3882
3883 if (ret != 0)
3884 check_usecases_codec_backend(adev, uc_info, uc_info->out_snd_device);
3885 /* default service interval was successfully updated,
3886 reopen USB backend with new service interval */
3887 ret = 0;
3888 }
Xiaojun Sang785b5da2017-08-03 15:52:29 +08003889
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08003890 list_remove(&uc_info->list);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05303891 out->started = 0;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003892 if (is_offload_usecase(out->usecase) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05303893 (audio_extn_passthru_is_passthrough_stream(out))) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003894 ALOGV("Disable passthrough , reset mixer to pcm");
3895 /* NO_PASSTHROUGH */
Meng Wang4c32fb42020-01-16 17:57:11 +08003896#ifdef AUDIO_GKI_ENABLED
3897 /* out->compr_config.codec->reserved[0] is for compr_passthr */
3898 out->compr_config.codec->reserved[0] = 0;
3899#else
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003900 out->compr_config.codec->compr_passthr = 0;
Meng Wang4c32fb42020-01-16 17:57:11 +08003901#endif
Mingming Yin21854652016-04-13 11:54:02 -07003902 audio_extn_passthru_on_stop(out);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07003903 audio_extn_dolby_set_dap_bypass(adev, DAP_STATE_ON);
3904 }
Eric Laurent07eeafd2013-10-06 12:52:49 -07003905
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05303906 /* Must be called after removing the usecase from list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003907 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL))
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05303908 audio_extn_keep_alive_start(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05303909
Manish Dewangan21a850a2017-08-14 12:03:55 +05303910 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07003911 ret = audio_extn_ip_hdlr_intf_close(out->ip_hdlr_handle, true, out);
3912 if (ret < 0)
3913 ALOGE("%s: audio_extn_ip_hdlr_intf_close failed %d",__func__, ret);
3914 }
3915
Zhou Song642ec432020-12-23 16:11:10 +08003916 /* trigger voip input to reroute when voip output changes to hearing aid */
Aalique Grahame22e49102018-12-18 14:23:57 -08003917 if (has_voip_usecase ||
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003918 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08003919 struct listnode *node;
3920 struct audio_usecase *usecase;
3921 list_for_each(node, &adev->usecase_list) {
3922 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Song642ec432020-12-23 16:11:10 +08003923 if (usecase->type == PCM_PLAYBACK || usecase == uc_info ||
3924 (usecase->type == PCM_CAPTURE &&
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05303925 usecase->id != USECASE_AUDIO_RECORD_VOIP &&
Zhou Song642ec432020-12-23 16:11:10 +08003926 usecase->id != USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY))
Aalique Grahame22e49102018-12-18 14:23:57 -08003927 continue;
3928
3929 ALOGD("%s: select_devices at usecase(%d: %s) after removing the usecase(%d: %s)",
3930 __func__, usecase->id, use_case_table[usecase->id],
3931 out->usecase, use_case_table[out->usecase]);
3932 select_devices(adev, usecase->id);
3933 }
3934 }
3935
Garmond Leung5fd0b552018-04-17 11:56:12 -07003936 free(uc_info);
Eric Laurent994a6932013-07-17 11:51:42 -07003937 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003938 return ret;
3939}
3940
Vignesh Kulothungana6927272019-02-20 15:17:07 -08003941struct pcm* pcm_open_prepare_helper(unsigned int snd_card, unsigned int pcm_device_id,
3942 unsigned int flags, unsigned int pcm_open_retry_count,
3943 struct pcm_config *config)
3944{
3945 struct pcm* pcm = NULL;
3946
3947 while (1) {
3948 pcm = pcm_open(snd_card, pcm_device_id, flags, config);
3949 if (pcm == NULL || !pcm_is_ready(pcm)) {
3950 ALOGE("%s: %s", __func__, pcm_get_error(pcm));
3951 if (pcm != NULL) {
3952 pcm_close(pcm);
3953 pcm = NULL;
3954 }
Weiyin Jiang72197252019-10-09 11:49:32 +08003955 if (pcm_open_retry_count == 0)
Vignesh Kulothungana6927272019-02-20 15:17:07 -08003956 return NULL;
3957
Weiyin Jiang72197252019-10-09 11:49:32 +08003958 pcm_open_retry_count--;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08003959 usleep(PROXY_OPEN_WAIT_TIME * 1000);
3960 continue;
3961 }
3962 break;
3963 }
3964
3965 if (pcm_is_ready(pcm)) {
3966 int ret = pcm_prepare(pcm);
3967 if (ret < 0) {
3968 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
3969 pcm_close(pcm);
3970 pcm = NULL;
3971 }
3972 }
3973
3974 return pcm;
3975}
3976
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003977int start_output_stream(struct stream_out *out)
3978{
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003979 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003980 struct audio_usecase *uc_info;
3981 struct audio_device *adev = out->dev;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08003982 char mixer_ctl_name[128];
3983 struct mixer_ctl *ctl = NULL;
3984 char* perf_mode[] = {"ULL", "ULL_PP", "LL"};
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05303985 bool a2dp_combo = false;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08003986 bool is_haptic_usecase = (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) ? true: false;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003987
Haynes Mathew George380745d2017-10-04 15:27:45 -07003988 ATRACE_BEGIN("start_output_stream");
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07003989 if ((out->usecase < 0) || (out->usecase >= AUDIO_USECASE_MAX)) {
3990 ret = -EINVAL;
3991 goto error_config;
3992 }
3993
Vignesh Kulothungana6927272019-02-20 15:17:07 -08003994 ALOGD("%s: enter: stream(%p)usecase(%d: %s) devices(%#x) is_haptic_usecase(%d)",
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05303995 __func__, &out->stream, out->usecase, use_case_table[out->usecase],
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08003996 get_device_types(&out->device_list), is_haptic_usecase);
3997
3998 bool is_speaker_active = compare_device_type(&out->device_list,
3999 AUDIO_DEVICE_OUT_SPEAKER);
4000 bool is_speaker_safe_active = compare_device_type(&out->device_list,
4001 AUDIO_DEVICE_OUT_SPEAKER_SAFE);
Naresh Tanniru4c630392014-05-12 01:05:52 +05304002
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304003 if (CARD_STATUS_OFFLINE == out->card_status ||
4004 CARD_STATUS_OFFLINE == adev->card_status) {
4005 ALOGW("out->card_status or adev->card_status offline, try again");
Dhanalakshmi Siddani4d57e992014-07-17 16:37:51 +05304006 ret = -EIO;
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004007 goto error_fatal;
Naresh Tanniru4c630392014-05-12 01:05:52 +05304008 }
Naresh Tanniru4c630392014-05-12 01:05:52 +05304009
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004010 //Update incall music usecase to reflect correct voice session
4011 if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
4012 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
4013 if (ret != 0) {
4014 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
4015 __func__, ret);
4016 goto error_config;
4017 }
4018 }
4019
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004020 if (is_a2dp_out_device_type(&out->device_list)) {
Florian Pfister1a84f312018-07-19 14:38:18 +02004021 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004022 if (is_speaker_active || is_speaker_safe_active) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304023 a2dp_combo = true;
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304024 } else {
Zhou Songd01e7a22020-09-23 22:49:01 +08004025 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304026 ALOGE("%s: A2DP profile is not ready, return error", __func__);
4027 ret = -EAGAIN;
4028 goto error_config;
4029 }
Preetam Singh Ranawata1849ba2017-02-06 14:10:11 +05304030 }
4031 }
4032 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004033 if (is_sco_out_device_type(&out->device_list)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304034 if (!adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004035 if (is_speaker_active) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304036 //combo usecase just by pass a2dp
4037 ALOGW("%s: SCO is not connected, route it to speaker", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004038 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304039 } else {
4040 ALOGE("%s: SCO profile is not ready, return error", __func__);
4041 ret = -EAGAIN;
4042 goto error_config;
4043 }
4044 }
4045 }
4046
Eric Laurentb23d5282013-05-14 15:27:20 -07004047 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004048 if (out->pcm_device_id < 0) {
4049 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
4050 __func__, out->pcm_device_id, out->usecase);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004051 ret = -EINVAL;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004052 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004053 }
4054
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004055 if (is_haptic_usecase) {
Meng Wang51d8c2a2020-04-27 15:23:21 +08004056 adev->haptic_pcm_device_id = platform_get_pcm_device_id(
4057 USECASE_AUDIO_PLAYBACK_HAPTICS, PCM_PLAYBACK);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004058 if (adev->haptic_pcm_device_id < 0) {
4059 ALOGE("%s: Invalid Haptics pcm device id(%d) for the usecase(%d)",
4060 __func__, adev->haptic_pcm_device_id, out->usecase);
4061 ret = -EINVAL;
4062 goto error_config;
4063 }
4064 }
4065
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004066 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07004067
4068 if (!uc_info) {
4069 ret = -ENOMEM;
4070 goto error_config;
4071 }
4072
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004073 uc_info->id = out->usecase;
4074 uc_info->type = PCM_PLAYBACK;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08004075 uc_info->stream.out = out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004076 list_init(&uc_info->device_list);
4077 assign_devices(&uc_info->device_list, &out->device_list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004078 uc_info->in_snd_device = SND_DEVICE_NONE;
4079 uc_info->out_snd_device = SND_DEVICE_NONE;
Garmond Leung5fd0b552018-04-17 11:56:12 -07004080
4081 /* This must be called before adding this usecase to the list */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004082 if (is_usb_out_device_type(&out->device_list)) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07004083 audio_extn_usb_check_and_set_svc_int(uc_info, true);
4084 /* USB backend is not reopened immediately.
4085 This is eventually done as part of select_devices */
4086 }
4087
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004088 list_add_tail(&adev->usecase_list, &uc_info->list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004089
Wei Wangf7ca6c92017-11-21 14:51:20 -08004090 audio_streaming_hint_start();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304091 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
4092 adev->perf_lock_opts,
4093 adev->perf_lock_opts_size);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304094
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004095 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Md Mansoor Ahmeddb1b4f92018-01-25 18:56:31 +05304096 audio_extn_keep_alive_stop(KEEP_ALIVE_OUT_HDMI);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304097 if (audio_extn_passthru_is_enabled() &&
4098 audio_extn_passthru_is_passthrough_stream(out)) {
4099 audio_extn_passthru_on_start(out);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05304100 }
4101 }
4102
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004103 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02004104 (!audio_extn_a2dp_source_is_ready())) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304105 if (!a2dp_combo) {
4106 check_a2dp_restore_l(adev, out, false);
4107 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004108 struct listnode dev;
4109 list_init(&dev);
4110 assign_devices(&dev, &out->device_list);
4111 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4112 reassign_device_list(&out->device_list,
4113 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aalique Grahame22e49102018-12-18 14:23:57 -08004114 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004115 reassign_device_list(&out->device_list,
4116 AUDIO_DEVICE_OUT_SPEAKER, "");
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304117 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004118 assign_devices(&out->device_list, &dev);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304119 }
4120 } else {
Revathi Uddarajub26e3932020-06-10 14:51:02 +05304121 select_devices(adev, out->usecase);
4122 if (is_a2dp_out_device_type(&out->device_list) &&
4123 !adev->a2dp_started) {
4124 if (is_speaker_active || is_speaker_safe_active) {
4125 struct listnode dev;
4126 list_init(&dev);
4127 assign_devices(&dev, &out->device_list);
4128 if (compare_device_type(&dev, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
4129 reassign_device_list(&out->device_list,
4130 AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
4131 else
4132 reassign_device_list(&out->device_list,
4133 AUDIO_DEVICE_OUT_SPEAKER, "");
4134 select_devices(adev, out->usecase);
4135 assign_devices(&out->device_list, &dev);
4136 } else {
4137 ret = -EINVAL;
4138 goto error_open;
4139 }
4140 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05304141 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004142
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004143 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
4144 out->usecase == USECASE_INCALL_MUSIC_UPLINK2) {
Arun Mirpurief53ce52018-09-11 18:00:09 -07004145 voice_set_device_mute_flag(adev, true);
Arun Mirpuri2ce92a62018-09-12 18:36:10 -07004146 }
Arun Mirpurief53ce52018-09-11 18:00:09 -07004147
Derek Chenea197282019-01-07 17:35:01 -08004148 if (audio_extn_ext_hw_plugin_usecase_start(adev->ext_hw_plugin, uc_info))
4149 ALOGE("%s: failed to start ext hw plugin", __func__);
Derek Chend2530072014-11-24 12:39:14 -08004150
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004151 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
4152 __func__, adev->snd_card, out->pcm_device_id, out->config.format);
Haynes Mathew George16081042017-05-31 17:16:49 -07004153
4154 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07004155 ALOGD("%s: Starting MMAP stream", __func__);
Haynes Mathew George16081042017-05-31 17:16:49 -07004156 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4157 ALOGE("%s: pcm stream not ready", __func__);
4158 goto error_open;
4159 }
4160 ret = pcm_start(out->pcm);
4161 if (ret < 0) {
4162 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
4163 goto error_open;
4164 }
Arun Mirpuri5d170872019-03-26 13:21:31 -07004165 out_set_mmap_volume(&out->stream, out->volume_l, out->volume_r);
Haynes Mathew George16081042017-05-31 17:16:49 -07004166 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004167 unsigned int flags = PCM_OUT;
4168 unsigned int pcm_open_retry_count = 0;
4169 if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
4170 flags |= PCM_MMAP | PCM_NOIRQ;
4171 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004172 } else if (out->realtime) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08004173 flags |= PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004174 } else
4175 flags |= PCM_MONOTONIC;
4176
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08004177 if ((adev->vr_audio_mode_enabled) &&
4178 (out->flags & AUDIO_OUTPUT_FLAG_RAW)) {
4179 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
4180 "PCM_Dev %d Topology", out->pcm_device_id);
4181 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
4182 if (!ctl) {
4183 ALOGI("%s: Could not get ctl for mixer cmd might be ULL - %s",
4184 __func__, mixer_ctl_name);
4185 } else {
4186 //if success use ULLPP
4187 ALOGI("%s: mixer ctrl %s succeeded setting up ULL for %d",
4188 __func__, mixer_ctl_name, out->pcm_device_id);
4189 //There is a still a possibility that some sessions
4190 // that request for FAST|RAW when 3D audio is active
4191 //can go through ULLPP. Ideally we expects apps to
4192 //listen to audio focus and stop concurrent playback
4193 //Also, we will look for mode flag (voice_in_communication)
4194 //before enabling the realtime flag.
4195 mixer_ctl_set_enum_by_string(ctl, perf_mode[1]);
4196 }
4197 }
4198
Vatsal Bucha3f39f222021-06-29 16:16:55 +05304199 platform_set_stream_channel_map(adev->platform, out->channel_mask,
4200 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Surendar Karka91fa3682018-07-02 18:12:12 +05304201
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004202 out->pcm = pcm_open_prepare_helper(adev->snd_card, out->pcm_device_id,
4203 flags, pcm_open_retry_count,
4204 &(out->config));
4205 if (out->pcm == NULL) {
4206 ret = -EIO;
4207 goto error_open;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004208 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004209
4210 if (is_haptic_usecase) {
4211 adev->haptic_pcm = pcm_open_prepare_helper(adev->snd_card,
4212 adev->haptic_pcm_device_id,
4213 flags, pcm_open_retry_count,
4214 &(adev->haptics_config));
4215 // failure to open haptics pcm shouldnt stop audio,
4216 // so do not close audio pcm in case of error
Vignesh Kulothungane4039c12019-05-07 15:51:39 -07004217
4218 if (property_get_bool("vendor.audio.enable_haptic_audio_sync", false)) {
4219 ALOGD("%s: enable haptic audio synchronization", __func__);
4220 platform_set_qtime(adev->platform, out->pcm_device_id, adev->haptic_pcm_device_id);
4221 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004222 }
4223
Zhou Song2b8f28f2017-09-11 10:51:38 +08004224 // apply volume for voip playback after path is set up
4225 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
4226 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
Ramu Gottipati36547092018-12-28 11:32:09 +05304227 else if ((out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY || out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
4228 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) && (out->apply_volume)) {
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304229 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
4230 out->apply_volume = false;
Derek Chenf13dd492018-11-13 14:53:51 -08004231 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
4232 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05304233 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004234 } else {
Zhou Song79929fe2020-01-20 17:57:43 +08004235 /*
4236 * set custom channel map if:
4237 * 1. neither mono nor stereo clips i.e. channels > 2 OR
4238 * 2. custom channel map has been set by client
4239 * else default channel map of FC/FR/FL can always be set to DSP
4240 */
4241 if (popcount(out->channel_mask) > 2 || out->channel_map_param.channel_map[0])
4242 platform_set_stream_channel_map(adev->platform, out->channel_mask,
Weiyin Jiang810a80d2021-01-18 16:04:31 +08004243 out->pcm_device_id, -1, &out->channel_map_param.channel_map[0]);
Xiaojun Sang785b5da2017-08-03 15:52:29 +08004244 audio_enable_asm_bit_width_enforce_mode(adev->mixer,
4245 adev->dsp_bit_width_enforce_mode,
4246 true);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004247 out->pcm = NULL;
Haynes Mathew George380745d2017-10-04 15:27:45 -07004248 ATRACE_BEGIN("compress_open");
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -08004249 out->compr = compress_open(adev->snd_card,
4250 out->pcm_device_id,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004251 COMPRESS_IN, &out->compr_config);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004252 ATRACE_END();
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05304253 if (errno == ENETRESET && !is_compress_ready(out->compr)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05304254 ALOGE("%s: compress_open failed errno:%d\n", __func__, errno);
4255 adev->card_status = CARD_STATUS_OFFLINE;
4256 out->card_status = CARD_STATUS_OFFLINE;
4257 ret = -EIO;
4258 goto error_open;
4259 }
4260
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004261 if (out->compr && !is_compress_ready(out->compr)) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004262 ALOGE("%s: failed /w error %s", __func__, compress_get_error(out->compr));
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004263 compress_close(out->compr);
4264 out->compr = NULL;
4265 ret = -EIO;
4266 goto error_open;
4267 }
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304268 /* compress_open sends params of the track, so reset the flag here */
4269 out->is_compr_metadata_avail = false;
4270
Ben Rombergerd771a7c2017-02-22 18:05:17 -08004271 if (out->client_callback)
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004272 compress_nonblock(out->compr, out->non_blocking);
Eric Laurentc4aef752013-09-12 17:45:53 -07004273
Fred Oh3f43e742015-03-04 18:42:34 -08004274 /* Since small bufs uses blocking writes, a write will be blocked
4275 for the default max poll time (20s) in the event of an SSR.
4276 Reduce the poll time to observe and deal with SSR faster.
4277 */
Ashish Jain5106d362016-05-11 19:23:33 +05304278 if (!out->non_blocking) {
Fred Oh3f43e742015-03-04 18:42:34 -08004279 compress_set_max_poll_wait(out->compr, 1000);
4280 }
4281
Manish Dewangan69426c82017-01-30 17:35:36 +05304282 audio_extn_utils_compress_set_render_mode(out);
Manish Dewangan58229382017-02-02 15:48:41 +05304283 audio_extn_utils_compress_set_clk_rec_mode(uc_info);
Manish Dewangan69426c82017-01-30 17:35:36 +05304284
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004285 audio_extn_dts_create_state_notifier_node(out->usecase);
4286 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
4287 popcount(out->channel_mask),
4288 out->playback_started);
4289
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004290#ifdef DS1_DOLBY_DDP_ENABLED
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05304291 if (audio_extn_utils_is_dolby_format(out->format))
Subhash Chandra Bose Naripeddy7690c562013-12-14 00:34:53 -08004292 audio_extn_dolby_send_ddp_endp_params(adev);
4293#endif
Preetam Singh Ranawatd18d8832017-02-08 17:34:54 +05304294 if (!(audio_extn_passthru_is_passthrough_stream(out)) &&
4295 (out->sample_rate != 176400 && out->sample_rate <= 192000)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004296 if (adev->visualizer_start_output != NULL)
4297 adev->visualizer_start_output(out->handle, out->pcm_device_id);
4298 if (adev->offload_effects_start_output != NULL)
Ashish Jain5106d362016-05-11 19:23:33 +05304299 adev->offload_effects_start_output(out->handle, out->pcm_device_id, adev->mixer);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08004300 audio_extn_check_and_set_dts_hpx_state(adev);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07004301 }
Derek Chenf13dd492018-11-13 14:53:51 -08004302
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004303 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf13dd492018-11-13 14:53:51 -08004304 /* Update cached volume from media to offload/direct stream */
4305 struct listnode *node = NULL;
4306 list_for_each(node, &adev->active_outputs_list) {
4307 streams_output_ctxt_t *out_ctxt = node_to_item(node,
4308 streams_output_ctxt_t,
4309 list);
4310 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
4311 out->volume_l = out_ctxt->output->volume_l;
4312 out->volume_r = out_ctxt->output->volume_r;
4313 }
4314 }
4315 out_set_compr_volume(&out->stream,
4316 out->volume_l, out->volume_r);
4317 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004318 }
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004319
4320 if (ret == 0) {
4321 register_out_stream(out);
4322 if (out->realtime) {
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07004323 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
4324 ALOGE("%s: pcm stream not ready", __func__);
4325 goto error_open;
4326 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07004327 ATRACE_BEGIN("pcm_start");
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004328 ret = pcm_start(out->pcm);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004329 ATRACE_END();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004330 if (ret < 0)
4331 goto error_open;
4332 }
4333 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004334 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304335 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Jaideep Sharma0fa53812020-09-17 09:00:11 +05304336 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004337
vivek mehtad15d2bf2019-05-17 13:35:10 -07004338 if (out->usecase == USECASE_AUDIO_PLAYBACK_ULL ||
4339 out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4340 audio_low_latency_hint_start();
4341 }
4342
Manish Dewangan21a850a2017-08-14 12:03:55 +05304343 if (out->ip_hdlr_handle) {
Vidyakumar Athota6d655882017-05-22 18:26:24 -07004344 ret = audio_extn_ip_hdlr_intf_open(out->ip_hdlr_handle, true, out, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07004345 if (ret < 0)
4346 ALOGE("%s: audio_extn_ip_hdlr_intf_open failed %d",__func__, ret);
4347 }
4348
Vignesh Kulothungan3b5fae52017-09-25 12:16:30 -07004349 // consider a scenario where on pause lower layers are tear down.
4350 // so on resume, swap mixer control need to be sent only when
4351 // backend is active, hence rather than sending from enable device
4352 // sending it from start of streamtream
4353
4354 platform_set_swap_channels(adev, true);
4355
Haynes Mathew George380745d2017-10-04 15:27:45 -07004356 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304357 enable_gcov();
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004358 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004359error_open:
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004360 if (adev->haptic_pcm) {
4361 pcm_close(adev->haptic_pcm);
4362 adev->haptic_pcm = NULL;
4363 }
Wei Wangf7ca6c92017-11-21 14:51:20 -08004364 audio_streaming_hint_end();
Sudheer Papothifa9d2282015-09-17 01:53:25 +05304365 audio_extn_perf_lock_release(&adev->perf_lock_handle);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004366 stop_output_stream(out);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004367error_fatal:
Laxminath Kasam2cb4b752015-09-24 03:59:15 +05304368 /*
4369 * sleep 50ms to allow sufficient time for kernel
4370 * drivers to recover incases like SSR.
4371 */
4372 usleep(50000);
Mingshu Pang5fc696f2020-02-28 12:32:00 +08004373error_config:
Haynes Mathew George380745d2017-10-04 15:27:45 -07004374 ATRACE_END();
Vatsal Buchac09ae062018-11-14 13:25:08 +05304375 enable_gcov();
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004376 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004377}
4378
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004379static int check_input_parameters(uint32_t sample_rate,
4380 audio_format_t format,
Aalique Grahame22e49102018-12-18 14:23:57 -08004381 int channel_count,
4382 bool is_usb_hifi)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004383{
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004384 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004385
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304386 if (((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT) &&
4387 (format != AUDIO_FORMAT_PCM_24_BIT_PACKED) && (format != AUDIO_FORMAT_PCM_32_BIT) &&
4388 (format != AUDIO_FORMAT_PCM_FLOAT)) &&
Mingming Yine62d7842013-10-25 16:26:03 -07004389 !voice_extn_compress_voip_is_format_supported(format) &&
Ralf Herzaec80262018-07-03 07:08:49 +02004390 !audio_extn_compr_cap_format_supported(format) &&
4391 !audio_extn_cin_format_supported(format))
Haynes Mathew George484e8d22017-07-31 18:55:17 -07004392 ret = -EINVAL;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004393
Aalique Grahame22e49102018-12-18 14:23:57 -08004394 int max_channel_count = is_usb_hifi ? MAX_HIFI_CHANNEL_COUNT : MAX_CHANNEL_COUNT;
4395 if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > max_channel_count)) {
4396 ALOGE("%s: unsupported channel count (%d) passed Min / Max (%d / %d)", __func__,
4397 channel_count, MIN_CHANNEL_COUNT, max_channel_count);
4398 return -EINVAL;
4399 }
4400
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004401 switch (channel_count) {
4402 case 1:
4403 case 2:
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05304404 case 3:
4405 case 4:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004406 case 6:
Karthikeyan Mani07faa602018-08-20 11:01:32 -07004407 case 8:
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05304408 case 10:
4409 case 12:
4410 case 14:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004411 break;
4412 default:
4413 ret = -EINVAL;
4414 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004415
4416 switch (sample_rate) {
4417 case 8000:
4418 case 11025:
4419 case 12000:
4420 case 16000:
4421 case 22050:
4422 case 24000:
4423 case 32000:
4424 case 44100:
4425 case 48000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004426 case 88200:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304427 case 96000:
Haynes Mathew Georgec9253d12017-12-13 15:58:28 -08004428 case 176400:
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304429 case 192000:
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004430 break;
4431 default:
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004432 ret = -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004433 }
4434
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08004435 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004436}
4437
Naresh Tanniru04f71882018-06-26 17:46:22 +05304438
4439/** Add a value in a list if not already present.
4440 * @return true if value was successfully inserted or already present,
4441 * false if the list is full and does not contain the value.
4442 */
4443static bool register_uint(uint32_t value, uint32_t* list, size_t list_length) {
4444 for (size_t i = 0; i < list_length; i++) {
4445 if (list[i] == value) return true; // value is already present
4446 if (list[i] == 0) { // no values in this slot
4447 list[i] = value;
4448 return true; // value inserted
4449 }
4450 }
4451 return false; // could not insert value
4452}
4453
4454/** Add channel_mask in supported_channel_masks if not already present.
4455 * @return true if channel_mask was successfully inserted or already present,
4456 * false if supported_channel_masks is full and does not contain channel_mask.
4457 */
4458static void register_channel_mask(audio_channel_mask_t channel_mask,
4459 audio_channel_mask_t supported_channel_masks[static MAX_SUPPORTED_CHANNEL_MASKS]) {
4460 ALOGE_IF(!register_uint(channel_mask, supported_channel_masks, MAX_SUPPORTED_CHANNEL_MASKS),
4461 "%s: stream can not declare supporting its channel_mask %x", __func__, channel_mask);
4462}
4463
4464/** Add format in supported_formats if not already present.
4465 * @return true if format was successfully inserted or already present,
4466 * false if supported_formats is full and does not contain format.
4467 */
4468static void register_format(audio_format_t format,
4469 audio_format_t supported_formats[static MAX_SUPPORTED_FORMATS]) {
4470 ALOGE_IF(!register_uint(format, supported_formats, MAX_SUPPORTED_FORMATS),
4471 "%s: stream can not declare supporting its format %x", __func__, format);
4472}
4473/** Add sample_rate in supported_sample_rates if not already present.
4474 * @return true if sample_rate was successfully inserted or already present,
4475 * false if supported_sample_rates is full and does not contain sample_rate.
4476 */
4477static void register_sample_rate(uint32_t sample_rate,
4478 uint32_t supported_sample_rates[static MAX_SUPPORTED_SAMPLE_RATES]) {
4479 ALOGE_IF(!register_uint(sample_rate, supported_sample_rates, MAX_SUPPORTED_SAMPLE_RATES),
4480 "%s: stream can not declare supporting its sample rate %x", __func__, sample_rate);
4481}
4482
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004483static inline uint32_t lcm(uint32_t num1, uint32_t num2)
4484{
4485 uint32_t high = num1, low = num2, temp = 0;
4486
4487 if (!num1 || !num2)
4488 return 0;
4489
4490 if (num1 < num2) {
4491 high = num2;
4492 low = num1;
4493 }
4494
4495 while (low != 0) {
4496 temp = low;
4497 low = high % low;
4498 high = temp;
4499 }
4500 return (num1 * num2)/high;
4501}
4502
4503static inline uint32_t nearest_multiple(uint32_t num, uint32_t multiplier)
4504{
4505 uint32_t remainder = 0;
4506
4507 if (!multiplier)
4508 return num;
4509
4510 remainder = num % multiplier;
4511 if (remainder)
4512 num += (multiplier - remainder);
4513
4514 return num;
4515}
4516
Aalique Grahame22e49102018-12-18 14:23:57 -08004517static size_t get_stream_buffer_size(size_t duration_ms,
4518 uint32_t sample_rate,
4519 audio_format_t format,
4520 int channel_count,
4521 bool is_low_latency)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004522{
4523 size_t size = 0;
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004524 uint32_t bytes_per_period_sample = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004525
Aalique Grahame22e49102018-12-18 14:23:57 -08004526 size = (sample_rate * duration_ms) / 1000;
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004527 if (is_low_latency)
4528 size = configured_low_latency_capture_period_size;
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05304529
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004530 bytes_per_period_sample = audio_bytes_per_sample(format) * channel_count;
Aalique Grahame22e49102018-12-18 14:23:57 -08004531 size *= audio_bytes_per_sample(format) * channel_count;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004532
Ralf Herzbd08d632018-09-28 15:50:49 +02004533 /* make sure the size is multiple of 32 bytes and additionally multiple of
4534 * the frame_size (required for 24bit samples and non-power-of-2 channel counts)
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004535 * At 48 kHz mono 16-bit PCM:
4536 * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
4537 * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004538 * Also, make sure the size is multiple of bytes per period sample
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07004539 */
Karthikeyan Manib38769c2018-11-07 15:44:13 -08004540 size = nearest_multiple(size, lcm(32, bytes_per_period_sample));
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07004541
4542 return size;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004543}
4544
Aalique Grahame22e49102018-12-18 14:23:57 -08004545static size_t get_input_buffer_size(uint32_t sample_rate,
4546 audio_format_t format,
4547 int channel_count,
4548 bool is_low_latency)
4549{
4550 /* Don't know if USB HIFI in this context so use true to be conservative */
4551 if (check_input_parameters(sample_rate, format, channel_count,
4552 true /*is_usb_hifi */) != 0)
4553 return 0;
4554
4555 return get_stream_buffer_size(AUDIO_CAPTURE_PERIOD_DURATION_MSEC,
4556 sample_rate,
4557 format,
4558 channel_count,
4559 is_low_latency);
4560}
4561
Derek Chenf6318be2017-06-12 17:16:24 -04004562size_t get_output_period_size(uint32_t sample_rate,
4563 audio_format_t format,
4564 int channel_count,
4565 int duration /*in millisecs*/)
Ashish Jain058165c2016-09-28 23:18:48 +05304566{
4567 size_t size = 0;
4568 uint32_t bytes_per_sample = audio_bytes_per_sample(format);
4569
4570 if ((duration == 0) || (sample_rate == 0) ||
4571 (bytes_per_sample == 0) || (channel_count == 0)) {
4572 ALOGW("Invalid config duration %d sr %d bps %d ch %d", duration, sample_rate,
4573 bytes_per_sample, channel_count);
4574 return -EINVAL;
4575 }
4576
4577 size = (sample_rate *
4578 duration *
4579 bytes_per_sample *
4580 channel_count) / 1000;
4581 /*
4582 * To have same PCM samples for all channels, the buffer size requires to
4583 * be multiple of (number of channels * bytes per sample)
4584 * For writes to succeed, the buffer must be written at address which is multiple of 32
4585 */
4586 size = ALIGN(size, (bytes_per_sample * channel_count * 32));
4587
4588 return (size/(channel_count * bytes_per_sample));
4589}
4590
Zhou Song48453a02018-01-10 17:50:59 +08004591static uint64_t get_actual_pcm_frames_rendered(struct stream_out *out, struct timespec *timestamp)
Ashish Jain5106d362016-05-11 19:23:33 +05304592{
4593 uint64_t actual_frames_rendered = 0;
Weiyin Jiang4813da12020-05-28 00:37:28 +08004594 uint64_t written_frames = 0;
4595 uint64_t kernel_frames = 0;
4596 uint64_t dsp_frames = 0;
4597 uint64_t signed_frames = 0;
4598 size_t kernel_buffer_size = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05304599
4600 /* This adjustment accounts for buffering after app processor.
4601 * It is based on estimated DSP latency per use case, rather than exact.
4602 */
George Gao9ba8a142020-07-23 14:30:03 -07004603 dsp_frames = platform_render_latency(out) *
Weiyin Jiang4813da12020-05-28 00:37:28 +08004604 out->sample_rate / 1000000LL;
Ashish Jain5106d362016-05-11 19:23:33 +05304605
Zhou Song48453a02018-01-10 17:50:59 +08004606 pthread_mutex_lock(&out->position_query_lock);
Weiyin Jiang4813da12020-05-28 00:37:28 +08004607 written_frames = out->written /
4608 (audio_bytes_per_sample(out->hal_ip_format) * popcount(out->channel_mask));
4609
Ashish Jain5106d362016-05-11 19:23:33 +05304610 /* not querying actual state of buffering in kernel as it would involve an ioctl call
4611 * which then needs protection, this causes delay in TS query for pcm_offload usecase
4612 * hence only estimate.
4613 */
Weiyin Jiang4813da12020-05-28 00:37:28 +08004614 kernel_buffer_size = out->compr_config.fragment_size * out->compr_config.fragments;
4615 kernel_frames = kernel_buffer_size /
4616 (audio_bytes_per_sample(out->hal_op_format) * popcount(out->channel_mask));
Ashish Jain5106d362016-05-11 19:23:33 +05304617
Weiyin Jiang4813da12020-05-28 00:37:28 +08004618 if (written_frames >= (kernel_frames + dsp_frames))
4619 signed_frames = written_frames - kernel_frames - dsp_frames;
Ashish Jain5106d362016-05-11 19:23:33 +05304620
Zhou Song48453a02018-01-10 17:50:59 +08004621 if (signed_frames > 0) {
Ashish Jain5106d362016-05-11 19:23:33 +05304622 actual_frames_rendered = signed_frames;
Zhou Song48453a02018-01-10 17:50:59 +08004623 if (timestamp != NULL )
4624 *timestamp = out->writeAt;
4625 } else if (timestamp != NULL) {
4626 clock_gettime(CLOCK_MONOTONIC, timestamp);
4627 }
4628 pthread_mutex_unlock(&out->position_query_lock);
Ashish Jain5106d362016-05-11 19:23:33 +05304629
Weiyin Jiang4813da12020-05-28 00:37:28 +08004630 ALOGVV("%s signed frames %lld written frames %lld kernel frames %lld dsp frames %lld",
4631 __func__, signed_frames, written_frames, kernel_frames, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05304632
4633 return actual_frames_rendered;
4634}
4635
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004636static uint32_t out_get_sample_rate(const struct audio_stream *stream)
4637{
4638 struct stream_out *out = (struct stream_out *)stream;
4639
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004640 return out->sample_rate;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004641}
4642
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004643static int out_set_sample_rate(struct audio_stream *stream __unused,
4644 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004645{
4646 return -ENOSYS;
4647}
4648
4649static size_t out_get_buffer_size(const struct audio_stream *stream)
4650{
4651 struct stream_out *out = (struct stream_out *)stream;
4652
Varun Balaraje49253e2017-07-06 19:48:56 +05304653 if (is_interactive_usecase(out->usecase)) {
Sri Karri27279e12017-08-07 16:05:20 +05304654 return out->config.period_size * out->config.period_count;
Varun Balaraje49253e2017-07-06 19:48:56 +05304655 } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Naresh Tanniruee3499a2017-01-05 14:05:35 +05304656 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
4657 return out->compr_config.fragment_size - sizeof(struct snd_codec_metadata);
4658 else
4659 return out->compr_config.fragment_size;
4660 } else if(out->usecase == USECASE_COMPRESS_VOIP_CALL)
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08004661 return voice_extn_compress_voip_out_get_buffer_size(out);
Dhananjay Kumarac341582017-02-23 23:42:25 +05304662 else if (is_offload_usecase(out->usecase) &&
4663 out->flags == AUDIO_OUTPUT_FLAG_DIRECT)
Ashish Jain83a6cc22016-06-28 14:34:17 +05304664 return out->hal_fragment_size;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004665
Haynes Mathew George5beddd42016-06-27 18:33:40 -07004666 return out->config.period_size * out->af_period_multiplier *
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07004667 audio_stream_out_frame_size((const struct audio_stream_out *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004668}
4669
4670static uint32_t out_get_channels(const struct audio_stream *stream)
4671{
4672 struct stream_out *out = (struct stream_out *)stream;
4673
4674 return out->channel_mask;
4675}
4676
4677static audio_format_t out_get_format(const struct audio_stream *stream)
4678{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004679 struct stream_out *out = (struct stream_out *)stream;
4680
4681 return out->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004682}
4683
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07004684static int out_set_format(struct audio_stream *stream __unused,
4685 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004686{
4687 return -ENOSYS;
4688}
4689
4690static int out_standby(struct audio_stream *stream)
4691{
4692 struct stream_out *out = (struct stream_out *)stream;
4693 struct audio_device *adev = out->dev;
Haynes Mathew George16081042017-05-31 17:16:49 -07004694 bool do_stop = true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004695
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05304696 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4697 stream, out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004698
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07004699 lock_output_stream(out);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004700 if (!out->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07004701 if (adev->adm_deregister_stream)
4702 adev->adm_deregister_stream(adev->adm_data, out->handle);
4703
Weiyin Jiang280ea742020-09-08 20:28:22 +08004704 if (is_offload_usecase(out->usecase)) {
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004705 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08004706 }
Haynes Mathew George7fce0a52016-06-23 18:22:27 -07004707
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08004708 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004709 out->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08004710 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
4711 voice_extn_compress_voip_close_output_stream(stream);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304712 out->started = 0;
Zhou Songa8895042016-07-05 17:54:22 +08004713 pthread_mutex_unlock(&adev->lock);
4714 pthread_mutex_unlock(&out->lock);
4715 ALOGD("VOIP output entered standby");
4716 return 0;
4717 } else if (!is_offload_usecase(out->usecase)) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004718 if (out->pcm) {
4719 pcm_close(out->pcm);
4720 out->pcm = NULL;
4721 }
Meng Wanga09da002020-04-20 12:56:04 +08004722 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
4723 if (adev->haptic_pcm) {
4724 pcm_close(adev->haptic_pcm);
4725 adev->haptic_pcm = NULL;
4726 }
4727
4728 if (adev->haptic_buffer != NULL) {
4729 free(adev->haptic_buffer);
4730 adev->haptic_buffer = NULL;
4731 adev->haptic_buffer_size = 0;
4732 }
4733 adev->haptic_pcm_device_id = 0;
4734 }
4735
Haynes Mathew George16081042017-05-31 17:16:49 -07004736 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
4737 do_stop = out->playback_started;
4738 out->playback_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07004739
4740 if (out->mmap_shared_memory_fd >= 0) {
4741 ALOGV("%s: closing mmap_shared_memory_fd = %d",
4742 __func__, out->mmap_shared_memory_fd);
4743 close(out->mmap_shared_memory_fd);
4744 out->mmap_shared_memory_fd = -1;
4745 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004746 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004747 } else {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07004748 ALOGD("copl(%p):standby", out);
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05304749 out->send_next_track_params = false;
4750 out->is_compr_metadata_avail = false;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004751 out->gapless_mdata.encoder_delay = 0;
4752 out->gapless_mdata.encoder_padding = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07004753 if (out->compr != NULL) {
4754 compress_close(out->compr);
4755 out->compr = NULL;
4756 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08004757 }
Haynes Mathew George16081042017-05-31 17:16:49 -07004758 if (do_stop) {
4759 stop_output_stream(out);
4760 }
Lakshman Chaluvaraju06677b42019-06-24 10:04:52 +05304761 // if fm is active route on selected device in UI
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004762 audio_extn_fm_route_on_selected_device(adev, &out->device_list);
Eric Laurent150dbfe2013-02-27 14:31:02 -08004763 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004764 }
4765 pthread_mutex_unlock(&out->lock);
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07004766 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004767 return 0;
4768}
4769
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304770static int out_on_error(struct audio_stream *stream)
4771{
4772 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004773 int status = 0;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304774
4775 lock_output_stream(out);
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004776 // always send CMD_ERROR for offload streams, this
4777 // is needed e.g. when SSR happens within compress_open
4778 // since the stream is active, offload_callback_thread is also active.
4779 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
4780 stop_compressed_output_l(out);
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004781 }
4782 pthread_mutex_unlock(&out->lock);
4783
4784 status = out_standby(&out->stream.common);
4785
4786 lock_output_stream(out);
4787 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Haynes Mathew Georgeee5836f2017-11-21 18:02:10 -08004788 send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304789 }
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05304790
4791 if (is_offload_usecase(out->usecase) && out->card_status == CARD_STATUS_OFFLINE) {
4792 ALOGD("Setting previous card status if offline");
4793 out->prev_card_status_offline = true;
4794 }
4795
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304796 pthread_mutex_unlock(&out->lock);
4797
Ben Rombergerfd02a2f2018-09-17 10:23:23 -07004798 return status;
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304799}
4800
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304801/*
Weiyin Jiang280ea742020-09-08 20:28:22 +08004802 * standby implementation without locks, assumes that the callee already
4803 * has taken adev and out lock.
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304804 */
4805int out_standby_l(struct audio_stream *stream)
4806{
4807 struct stream_out *out = (struct stream_out *)stream;
4808 struct audio_device *adev = out->dev;
4809
4810 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
4811 stream, out->usecase, use_case_table[out->usecase]);
4812
4813 if (!out->standby) {
Haynes Mathew George380745d2017-10-04 15:27:45 -07004814 ATRACE_BEGIN("out_standby_l");
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304815 if (adev->adm_deregister_stream)
4816 adev->adm_deregister_stream(adev->adm_data, out->handle);
4817
Weiyin Jiang280ea742020-09-08 20:28:22 +08004818 if (is_offload_usecase(out->usecase)) {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304819 stop_compressed_output_l(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08004820 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304821
4822 out->standby = true;
4823 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
4824 voice_extn_compress_voip_close_output_stream(stream);
4825 out->started = 0;
4826 ALOGD("VOIP output entered standby");
Haynes Mathew George380745d2017-10-04 15:27:45 -07004827 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304828 return 0;
4829 } else if (!is_offload_usecase(out->usecase)) {
4830 if (out->pcm) {
4831 pcm_close(out->pcm);
4832 out->pcm = NULL;
4833 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08004834 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS) {
4835 if (adev->haptic_pcm) {
4836 pcm_close(adev->haptic_pcm);
4837 adev->haptic_pcm = NULL;
4838 }
4839
4840 if (adev->haptic_buffer != NULL) {
4841 free(adev->haptic_buffer);
4842 adev->haptic_buffer = NULL;
4843 adev->haptic_buffer_size = 0;
4844 }
4845 adev->haptic_pcm_device_id = 0;
4846 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304847 } else {
4848 ALOGD("copl(%p):standby", out);
4849 out->send_next_track_params = false;
4850 out->is_compr_metadata_avail = false;
4851 out->gapless_mdata.encoder_delay = 0;
4852 out->gapless_mdata.encoder_padding = 0;
4853 if (out->compr != NULL) {
4854 compress_close(out->compr);
4855 out->compr = NULL;
4856 }
4857 }
4858 stop_output_stream(out);
Haynes Mathew George380745d2017-10-04 15:27:45 -07004859 ATRACE_END();
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304860 }
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07004861 ALOGV("%s: exit", __func__);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05304862 return 0;
4863}
4864
Aalique Grahame22e49102018-12-18 14:23:57 -08004865static int out_dump(const struct audio_stream *stream, int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004866{
Aalique Grahame22e49102018-12-18 14:23:57 -08004867 struct stream_out *out = (struct stream_out *)stream;
4868
4869 // We try to get the lock for consistency,
4870 // but it isn't necessary for these variables.
4871 // If we're not in standby, we may be blocked on a write.
4872 const bool locked = (pthread_mutex_trylock(&out->lock) == 0);
4873 dprintf(fd, " Standby: %s\n", out->standby ? "yes" : "no");
4874 dprintf(fd, " Frames written: %lld\n", (long long)out->written);
Dechen Chai22768452021-07-30 09:29:16 +05304875#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07004876 char buffer[256]; // for statistics formatting
4877 if (!is_offload_usecase(out->usecase)) {
4878 simple_stats_to_string(&out->fifo_underruns, buffer, sizeof(buffer));
4879 dprintf(fd, " Fifo frame underruns: %s\n", buffer);
4880 }
4881
Andy Hungc6bfd4a2019-07-01 18:26:00 -07004882 if (out->start_latency_ms.n > 0) {
4883 simple_stats_to_string(&out->start_latency_ms, buffer, sizeof(buffer));
4884 dprintf(fd, " Start latency ms: %s\n", buffer);
4885 }
Dechen Chai22768452021-07-30 09:29:16 +05304886#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08004887 if (locked) {
4888 pthread_mutex_unlock(&out->lock);
4889 }
4890
Dechen Chai22768452021-07-30 09:29:16 +05304891#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08004892 // dump error info
4893 (void)error_log_dump(
4894 out->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05304895#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004896 return 0;
4897}
4898
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004899static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
4900{
4901 int ret = 0;
4902 char value[32];
ApurupaPattapu2e084df2013-12-18 15:47:59 -08004903
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004904 if (!out || !parms) {
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08004905 ALOGE("%s: return invalid ",__func__);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004906 return -EINVAL;
4907 }
4908
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05304909 ret = audio_extn_parse_compress_metadata(out, parms);
Weiyin Jiang18ac4e92015-03-15 15:03:40 +08004910
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004911 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
4912 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05304913 out->gapless_mdata.encoder_delay = atoi(value); //whats a good limit check?
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004914 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004915 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
4916 if (ret >= 0) {
Satya Krishna Pindiproli70471602015-04-24 19:12:43 +05304917 out->gapless_mdata.encoder_padding = atoi(value);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004918 }
4919
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004920 ALOGV("%s new encoder delay %u and padding %u", __func__,
4921 out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
4922
4923 return 0;
4924}
4925
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07004926static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
4927{
4928 return out == adev->primary_output || out == adev->voice_tx_output;
4929}
Haynes Mathew George352f27b2013-07-26 00:00:15 -07004930
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304931// note: this call is safe only if the stream_cb is
4932// removed first in close_output_stream (as is done now).
4933static void out_snd_mon_cb(void * stream, struct str_parms * parms)
4934{
4935 if (!stream || !parms)
4936 return;
4937
4938 struct stream_out *out = (struct stream_out *)stream;
4939 struct audio_device *adev = out->dev;
4940
4941 card_status_t status;
4942 int card;
4943 if (parse_snd_card_status(parms, &card, &status) < 0)
4944 return;
4945
4946 pthread_mutex_lock(&adev->lock);
4947 bool valid_cb = (card == adev->snd_card);
4948 pthread_mutex_unlock(&adev->lock);
4949
4950 if (!valid_cb)
4951 return;
4952
4953 lock_output_stream(out);
4954 if (out->card_status != status)
4955 out->card_status = status;
4956 pthread_mutex_unlock(&out->lock);
4957
4958 ALOGI("out_snd_mon_cb for card %d usecase %s, status %s", card,
4959 use_case_table[out->usecase],
4960 status == CARD_STATUS_OFFLINE ? "offline" : "online");
4961
Aditya Bavanari59ebed42019-02-05 17:44:57 +05304962 if (status == CARD_STATUS_OFFLINE) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304963 out_on_error(stream);
Aditya Bavanari59ebed42019-02-05 17:44:57 +05304964 if (voice_is_call_state_active(adev) &&
4965 out == adev->primary_output) {
4966 ALOGD("%s: SSR/PDR occurred, end all calls\n", __func__);
4967 pthread_mutex_lock(&adev->lock);
4968 voice_stop_call(adev);
4969 adev->mode = AUDIO_MODE_NORMAL;
4970 pthread_mutex_unlock(&adev->lock);
4971 }
4972 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05304973 return;
4974}
4975
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07004976int route_output_stream(struct stream_out *out,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004977 struct listnode *devices)
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07004978{
4979 struct audio_device *adev = out->dev;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07004980 int ret = 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004981 struct listnode new_devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07004982 bool bypass_a2dp = false;
4983 bool reconfig = false;
4984 unsigned long service_interval = 0;
4985
4986 ALOGD("%s: enter: usecase(%d: %s) devices %x",
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08004987 __func__, out->usecase, use_case_table[out->usecase], get_device_types(devices));
4988
4989 list_init(&new_devices);
4990 assign_devices(&new_devices, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07004991
4992 lock_output_stream(out);
4993 pthread_mutex_lock(&adev->lock);
4994
4995 /*
4996 * When HDMI cable is unplugged the music playback is paused and
4997 * the policy manager sends routing=0. But the audioflinger continues
4998 * to write data until standby time (3sec). As the HDMI core is
4999 * turned off, the write gets blocked.
5000 * Avoid this by routing audio to speaker until standby.
5001 */
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -08005002 if (is_single_device_type_equal(&out->device_list,
5003 AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005004 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005005 !audio_extn_passthru_is_passthrough_stream(out) &&
5006 (platform_get_edid_info(adev->platform) != 0) /* HDMI disconnected */) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005007 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005008 }
5009 /*
5010 * When A2DP is disconnected the
5011 * music playback is paused and the policy manager sends routing=0
5012 * But the audioflinger continues to write data until standby time
5013 * (3sec). As BT is turned off, the write gets blocked.
5014 * Avoid this by routing audio to speaker until standby.
5015 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005016 if (is_a2dp_out_device_type(&out->device_list) &&
5017 list_empty(&new_devices) &&
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005018 !audio_extn_a2dp_source_is_ready() &&
5019 !adev->bt_sco_on) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005020 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005021 }
5022 /*
Weiyin Jiangabedea32020-12-09 12:49:19 +08005023 * When USB headset is disconnected the music playback paused
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005024 * and the policy manager send routing=0. But if the USB is connected
5025 * back before the standby time, AFE is not closed and opened
5026 * when USB is connected back. So routing to speker will guarantee
5027 * AFE reconfiguration and AFE will be opend once USB is connected again
5028 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005029 if (is_usb_out_device_type(&out->device_list) &&
5030 list_empty(&new_devices) &&
5031 !audio_extn_usb_connected(NULL)) {
Sujin Panicker84d953a2020-11-16 17:39:54 +05305032 if (adev->mode == AUDIO_MODE_IN_CALL || adev->mode == AUDIO_MODE_IN_COMMUNICATION)
5033 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_EARPIECE, "");
5034 else
5035 reassign_device_list(&new_devices, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005036 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005037 /* To avoid a2dp to sco overlapping / BT device improper state
5038 * check with BT lib about a2dp streaming support before routing
5039 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005040 if (is_a2dp_out_device_type(&new_devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005041 if (!audio_extn_a2dp_source_is_ready()) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005042 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER) ||
5043 compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005044 //combo usecase just by pass a2dp
5045 ALOGW("%s: A2DP profile is not ready,routing to speaker only", __func__);
5046 bypass_a2dp = true;
5047 } else {
5048 ALOGE("%s: A2DP profile is not ready,ignoring routing request", __func__);
5049 /* update device to a2dp and don't route as BT returned error
5050 * However it is still possible a2dp routing called because
5051 * of current active device disconnection (like wired headset)
5052 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005053 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005054 pthread_mutex_unlock(&adev->lock);
5055 pthread_mutex_unlock(&out->lock);
5056 goto error;
5057 }
5058 }
5059 }
5060
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005061 // Workaround: If routing to an non existing usb device, fail gracefully
5062 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005063 if (is_usb_out_device_type(&new_devices)) {
5064 struct str_parms *parms =
5065 str_parms_create_str(get_usb_device_address(&new_devices));
5066 if (!parms)
5067 goto error;
Weiyin Jiangabedea32020-12-09 12:49:19 +08005068 if (!audio_extn_usb_connected(NULL)) {
5069 ALOGW("%s: ignoring rerouting to non existing USB card", __func__);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005070 pthread_mutex_unlock(&adev->lock);
5071 pthread_mutex_unlock(&out->lock);
5072 str_parms_destroy(parms);
5073 ret = -ENOSYS;
5074 goto error;
5075 }
5076 str_parms_destroy(parms);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005077 }
5078
Weiyin Jiang80c8f9a2020-01-10 20:42:08 +08005079 // Workaround: If routing to an non existing hdmi device, fail gracefully
5080 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
5081 (platform_get_edid_info_v2(adev->platform,
5082 out->extconn.cs.controller,
5083 out->extconn.cs.stream) != 0)) {
5084 ALOGW("out_set_parameters() ignoring rerouting to non existing HDMI/DP");
5085 pthread_mutex_unlock(&adev->lock);
5086 pthread_mutex_unlock(&out->lock);
5087 ret = -ENOSYS;
5088 goto error;
5089 }
5090
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005091 /*
5092 * select_devices() call below switches all the usecases on the same
5093 * backend to the new device. Refer to check_usecases_codec_backend() in
5094 * the select_devices(). But how do we undo this?
5095 *
5096 * For example, music playback is active on headset (deep-buffer usecase)
5097 * and if we go to ringtones and select a ringtone, low-latency usecase
5098 * will be started on headset+speaker. As we can't enable headset+speaker
5099 * and headset devices at the same time, select_devices() switches the music
5100 * playback to headset+speaker while starting low-lateny usecase for ringtone.
5101 * So when the ringtone playback is completed, how do we undo the same?
5102 *
5103 * We are relying on the out_set_parameters() call on deep-buffer output,
5104 * once the ringtone playback is ended.
5105 * NOTE: We should not check if the current devices are same as new devices.
5106 * Because select_devices() must be called to switch back the music
5107 * playback to headset.
5108 */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005109 if (!list_empty(&new_devices)) {
5110 bool same_dev = compare_devices(&out->device_list, &new_devices);
5111 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005112
5113 if (output_drives_call(adev, out)) {
5114 if (!voice_is_call_state_active(adev)) {
5115 if (adev->mode == AUDIO_MODE_IN_CALL) {
5116 adev->current_call_output = out;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005117 ret = voice_start_call(adev);
5118 }
5119 } else {
Kunlei Zhang253ad102020-10-14 16:21:28 +08005120 platform_is_volume_boost_supported_device(adev->platform, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005121 adev->current_call_output = out;
5122 voice_update_devices_for_all_voice_usecases(adev);
5123 }
5124 }
5125
Mingshu Pang971ff702020-09-09 15:28:22 +08005126 if (is_usb_out_device_type(&out->device_list)) {
5127 service_interval = audio_extn_usb_find_service_interval(false, true /*playback*/);
5128 audio_extn_usb_set_service_interval(true /*playback*/,
5129 service_interval,
5130 &reconfig);
5131 ALOGD("%s, svc_int(%ld),reconfig(%d)",__func__,service_interval, reconfig);
5132 }
5133
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005134 if (!out->standby) {
5135 if (!same_dev) {
5136 ALOGV("update routing change");
5137 audio_extn_perf_lock_acquire(&adev->perf_lock_handle, 0,
5138 adev->perf_lock_opts,
5139 adev->perf_lock_opts_size);
5140 if (adev->adm_on_routing_change)
5141 adev->adm_on_routing_change(adev->adm_data,
5142 out->handle);
5143 }
5144 if (!bypass_a2dp) {
5145 select_devices(adev, out->usecase);
5146 } else {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005147 if (compare_device_type(&new_devices, AUDIO_DEVICE_OUT_SPEAKER_SAFE))
5148 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005149 else
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005150 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005151 select_devices(adev, out->usecase);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005152 assign_devices(&out->device_list, &new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005153 }
5154
5155 if (!same_dev) {
5156 // on device switch force swap, lower functions will make sure
5157 // to check if swap is allowed or not.
5158 platform_set_swap_channels(adev, true);
5159 audio_extn_perf_lock_release(&adev->perf_lock_handle);
5160 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005161 pthread_mutex_lock(&out->latch_lock);
5162 if (!is_a2dp_out_device_type(&out->device_list) || audio_extn_a2dp_source_is_ready()) {
5163 if (out->a2dp_muted) {
5164 out->a2dp_muted = false;
5165 if (is_offload_usecase(out->usecase))
5166 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
5167 else if (out->usecase != USECASE_AUDIO_PLAYBACK_VOIP)
5168 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Weiyin Jiang280ea742020-09-08 20:28:22 +08005169 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005170 }
Zhou Songbaddf9f2020-11-20 13:57:39 +08005171 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP && !out->a2dp_muted)
5172 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
5173 pthread_mutex_unlock(&out->latch_lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005174 }
5175 }
5176
5177 pthread_mutex_unlock(&adev->lock);
5178 pthread_mutex_unlock(&out->lock);
5179
5180 /*handles device and call state changes*/
5181 audio_extn_extspk_update(adev->extspk);
5182
Revathi Uddaraju4255a632021-12-02 05:11:13 -08005183 clear_devices(&new_devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005184error:
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005185 ALOGV("%s: exit: code(%d)", __func__, ret);
5186 return ret;
5187}
5188
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005189static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
5190{
5191 struct stream_out *out = (struct stream_out *)stream;
5192 struct audio_device *adev = out->dev;
5193 struct str_parms *parms;
5194 char value[32];
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07005195 int ret = 0, err;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005196 int ext_controller = -1;
5197 int ext_stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005198
sangwoobc677242013-08-08 16:53:43 +09005199 ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07005200 __func__, out->usecase, use_case_table[out->usecase], kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005201 parms = str_parms_create_str(kvpairs);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305202 if (!parms)
5203 goto error;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005204
5205 err = platform_get_controller_stream_from_params(parms, &ext_controller,
5206 &ext_stream);
Vignesh Kulothungan1b3957e2019-12-02 16:16:51 -08005207 if (err == 0) {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005208 out->extconn.cs.controller = ext_controller;
5209 out->extconn.cs.stream = ext_stream;
5210 ALOGD("%s: usecase(%s) new controller/stream (%d/%d)", __func__,
5211 use_case_table[out->usecase], out->extconn.cs.controller,
5212 out->extconn.cs.stream);
5213 }
5214
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005215 if (out == adev->primary_output) {
5216 pthread_mutex_lock(&adev->lock);
5217 audio_extn_set_parameters(adev, parms);
5218 pthread_mutex_unlock(&adev->lock);
5219 }
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005220 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07005221 lock_output_stream(out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005222 parse_compress_metadata(out, parms);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08005223
5224 audio_extn_dts_create_state_notifier_node(out->usecase);
5225 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
5226 popcount(out->channel_mask),
5227 out->playback_started);
5228
Krishnankutty Kolathappillyeb78be72013-12-15 12:03:07 -08005229 pthread_mutex_unlock(&out->lock);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07005230 }
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -07005231
Surendar Karkaf51b5842018-04-26 11:28:38 +05305232 err = str_parms_get_str(parms, AUDIO_PARAMETER_DUAL_MONO, value,
5233 sizeof(value));
5234 if (err >= 0) {
5235 if (!strncmp("true", value, sizeof("true")) || atoi(value))
5236 audio_extn_send_dual_mono_mixing_coefficients(out);
5237 }
5238
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305239 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
5240 if (err >= 0) {
5241 strlcpy(out->profile, value, sizeof(out->profile));
5242 ALOGV("updating stream profile with value '%s'", out->profile);
5243 lock_output_stream(out);
5244 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
5245 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005246 &out->device_list, out->flags,
5247 out->hal_op_format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05305248 out->sample_rate, out->bit_width,
5249 out->channel_mask, out->profile,
5250 &out->app_type_cfg);
5251 pthread_mutex_unlock(&out->lock);
5252 }
5253
Alexy Joseph98988832017-01-13 14:56:59 -08005254 //suspend, resume handling block
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005255 //remove QOS only if vendor.audio.hal.dynamic.qos.config.supported is set to true
5256 // and vendor.audio.hal.output.suspend.supported is set to true
5257 if (out->hal_output_suspend_supported && out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08005258 //check suspend parameter only for low latency and if the property
5259 //is enabled
5260 if (str_parms_get_str(parms, "suspend_playback", value, sizeof(value)) >= 0) {
5261 ALOGI("%s: got suspend_playback %s", __func__, value);
5262 lock_output_stream(out);
5263 if (!strncmp(value, "false", 5)) {
5264 //suspend_playback=false is supposed to set QOS value back to 75%
5265 //the mixer control sent with value Enable will achieve that
5266 ret = audio_route_apply_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5267 } else if (!strncmp (value, "true", 4)) {
5268 //suspend_playback=true is supposed to remove QOS value
5269 //resetting the mixer control will set the default value
5270 //for the mixer control which is Disable and this removes the QOS vote
5271 ret = audio_route_reset_and_update_path(adev->audio_route, out->pm_qos_mixer_path);
5272 } else {
5273 ALOGE("%s: Wrong value sent for suspend_playback, expected true/false,"
5274 " got %s", __func__, value);
5275 ret = -1;
5276 }
5277
5278 if (ret != 0) {
5279 ALOGE("%s: %s mixer ctl failed with %d, ignore suspend/resume setparams",
5280 __func__, out->pm_qos_mixer_path, ret);
5281 }
5282
5283 pthread_mutex_unlock(&out->lock);
5284 }
5285 }
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07005286
Alexy Joseph98988832017-01-13 14:56:59 -08005287 //end suspend, resume handling block
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005288 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05305289error:
Eric Laurent994a6932013-07-17 11:51:42 -07005290 ALOGV("%s: exit: code(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005291 return ret;
5292}
5293
Paul McLeana50b7332018-12-17 08:24:21 -07005294static int in_set_microphone_direction(const struct audio_stream_in *stream,
5295 audio_microphone_direction_t dir) {
justinweng20fb6d82019-02-21 18:49:00 -07005296 struct stream_in *in = (struct stream_in *)stream;
5297
5298 ALOGVV("%s: standby %d source %d dir %d", __func__, in->standby, in->source, dir);
5299
5300 in->direction = dir;
5301
5302 if (in->standby)
5303 return 0;
5304
5305 return audio_extn_audiozoom_set_microphone_direction(in, dir);
Paul McLeana50b7332018-12-17 08:24:21 -07005306}
5307
5308static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom) {
justinweng20fb6d82019-02-21 18:49:00 -07005309 struct stream_in *in = (struct stream_in *)stream;
5310
5311 ALOGVV("%s: standby %d source %d zoom %f", __func__, in->standby, in->source, zoom);
5312
5313 if (zoom > 1.0 || zoom < -1.0)
5314 return -EINVAL;
5315
5316 in->zoom = zoom;
5317
5318 if (in->standby)
5319 return 0;
5320
5321 return audio_extn_audiozoom_set_microphone_field_dimension(in, zoom);
Paul McLeana50b7332018-12-17 08:24:21 -07005322}
5323
5324
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005325static bool stream_get_parameter_channels(struct str_parms *query,
5326 struct str_parms *reply,
5327 audio_channel_mask_t *supported_channel_masks) {
5328 int ret = -1;
5329 char value[512];
5330 bool first = true;
5331 size_t i, j;
5332
5333 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS)) {
5334 ret = 0;
5335 value[0] = '\0';
5336 i = 0;
5337 while (supported_channel_masks[i] != 0) {
5338 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5339 if (channels_name_to_enum_table[j].value == supported_channel_masks[i]) {
5340 if (!first)
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305341 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005342
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305343 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005344 first = false;
5345 break;
5346 }
5347 }
5348 i++;
5349 }
5350 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5351 }
5352 return ret == 0;
5353}
5354
5355static bool stream_get_parameter_formats(struct str_parms *query,
5356 struct str_parms *reply,
5357 audio_format_t *supported_formats) {
5358 int ret = -1;
5359 char value[256];
5360 size_t i, j;
5361 bool first = true;
5362
5363 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS)) {
5364 ret = 0;
5365 value[0] = '\0';
5366 i = 0;
5367 while (supported_formats[i] != 0) {
5368 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5369 if (formats_name_to_enum_table[j].value == supported_formats[i]) {
5370 if (!first) {
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305371 strlcat(value, "|", sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005372 }
Satya Krishna Pindiprolib22ac722017-10-09 15:44:16 +05305373 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005374 first = false;
5375 break;
5376 }
5377 }
5378 i++;
5379 }
5380 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
5381 }
5382 return ret == 0;
5383}
5384
5385static bool stream_get_parameter_rates(struct str_parms *query,
5386 struct str_parms *reply,
5387 uint32_t *supported_sample_rates) {
5388
5389 int i;
5390 char value[256];
5391 int ret = -1;
5392 if (str_parms_has_key(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES)) {
5393 ret = 0;
5394 value[0] = '\0';
5395 i=0;
5396 int cursor = 0;
5397 while (supported_sample_rates[i]) {
5398 int avail = sizeof(value) - cursor;
5399 ret = snprintf(value + cursor, avail, "%s%d",
5400 cursor > 0 ? "|" : "",
5401 supported_sample_rates[i]);
5402 if (ret < 0 || ret >= avail) {
5403 // if cursor is at the last element of the array
5404 // overwrite with \0 is duplicate work as
5405 // snprintf already put a \0 in place.
5406 // else
5407 // we had space to write the '|' at value[cursor]
5408 // (which will be overwritten) or no space to fill
5409 // the first element (=> cursor == 0)
5410 value[cursor] = '\0';
5411 break;
5412 }
5413 cursor += ret;
5414 ++i;
5415 }
5416 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
5417 value);
5418 }
5419 return ret >= 0;
5420}
5421
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005422static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
5423{
5424 struct stream_out *out = (struct stream_out *)stream;
5425 struct str_parms *query = str_parms_create_str(keys);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005426 char *str = (char*) NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005427 char value[256];
5428 struct str_parms *reply = str_parms_create();
5429 size_t i, j;
5430 int ret;
5431 bool first = true;
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005432
5433 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005434 if (reply) {
5435 str_parms_destroy(reply);
5436 }
5437 if (query) {
5438 str_parms_destroy(query);
5439 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07005440 ALOGE("out_get_parameters: failed to allocate mem for query or reply");
5441 return NULL;
5442 }
5443
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005444 ALOGV("%s: %s enter: keys - %s", __func__, use_case_table[out->usecase], keys);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005445 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
5446 if (ret >= 0) {
5447 value[0] = '\0';
5448 i = 0;
5449 while (out->supported_channel_masks[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005450 for (j = 0; j < ARRAY_SIZE(channels_name_to_enum_table); j++) {
5451 if (channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005452 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005453 strlcat(value, "|", sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005454 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005455 strlcat(value, channels_name_to_enum_table[j].name, sizeof(value));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005456 first = false;
5457 break;
5458 }
5459 }
5460 i++;
5461 }
5462 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
5463 str = str_parms_to_str(reply);
5464 } else {
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08005465 voice_extn_out_get_parameters(out, query, reply);
5466 str = str_parms_to_str(reply);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005467 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005468
Alexy Joseph62142aa2015-11-16 15:10:34 -08005469
5470 ret = str_parms_get_str(query, "is_direct_pcm_track", value, sizeof(value));
5471 if (ret >= 0) {
5472 value[0] = '\0';
Dhananjay Kumarac341582017-02-23 23:42:25 +05305473 if (out->flags & AUDIO_OUTPUT_FLAG_DIRECT &&
5474 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Alexy Joseph62142aa2015-11-16 15:10:34 -08005475 ALOGV("in direct_pcm");
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05305476 strlcat(value, "true", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005477 } else {
5478 ALOGV("not in direct_pcm");
Sharad Sangle3dd5a4a2015-12-10 18:39:17 +05305479 strlcat(value, "false", sizeof(value));
Alexy Joseph62142aa2015-11-16 15:10:34 -08005480 }
5481 str_parms_add_str(reply, "is_direct_pcm_track", value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005482 if (str)
5483 free(str);
Alexy Joseph62142aa2015-11-16 15:10:34 -08005484 str = str_parms_to_str(reply);
5485 }
5486
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005487 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
5488 if (ret >= 0) {
5489 value[0] = '\0';
5490 i = 0;
5491 first = true;
5492 while (out->supported_formats[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005493 for (j = 0; j < ARRAY_SIZE(formats_name_to_enum_table); j++) {
5494 if (formats_name_to_enum_table[j].value == out->supported_formats[i]) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005495 if (!first) {
Apoorv Raghuvanshi8880cac2015-02-06 15:33:49 -08005496 strlcat(value, "|", sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005497 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005498 strlcat(value, formats_name_to_enum_table[j].name, sizeof(value));
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005499 first = false;
5500 break;
5501 }
5502 }
5503 i++;
5504 }
5505 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
Alexy Josephaee4fdd2016-01-29 13:02:07 -08005506 if (str)
5507 free(str);
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005508 str = str_parms_to_str(reply);
5509 }
Mingming Yin3a941d42016-02-17 18:08:05 -08005510
5511 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value, sizeof(value));
5512 if (ret >= 0) {
5513 value[0] = '\0';
5514 i = 0;
5515 first = true;
5516 while (out->supported_sample_rates[i] != 0) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005517 for (j = 0; j < ARRAY_SIZE(out_sample_rates_name_to_enum_table); j++) {
5518 if (out_sample_rates_name_to_enum_table[j].value == out->supported_sample_rates[i]) {
Mingming Yin3a941d42016-02-17 18:08:05 -08005519 if (!first) {
5520 strlcat(value, "|", sizeof(value));
5521 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07005522 strlcat(value, out_sample_rates_name_to_enum_table[j].name, sizeof(value));
Mingming Yin3a941d42016-02-17 18:08:05 -08005523 first = false;
5524 break;
5525 }
5526 }
5527 i++;
5528 }
5529 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES, value);
5530 if (str)
5531 free(str);
5532 str = str_parms_to_str(reply);
5533 }
5534
Alexy Joseph98988832017-01-13 14:56:59 -08005535 if (str_parms_get_str(query, "supports_hw_suspend", value, sizeof(value)) >= 0) {
5536 //only low latency track supports suspend_resume
5537 str_parms_add_int(reply, "supports_hw_suspend",
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08005538 (out->hal_output_suspend_supported));
Alexy Joseph98988832017-01-13 14:56:59 -08005539 if (str)
5540 free(str);
5541 str = str_parms_to_str(reply);
5542 }
5543
5544
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005545 str_parms_destroy(query);
5546 str_parms_destroy(reply);
Eric Laurent994a6932013-07-17 11:51:42 -07005547 ALOGV("%s: exit: returns - %s", __func__, str);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005548 return str;
5549}
5550
5551static uint32_t out_get_latency(const struct audio_stream_out *stream)
5552{
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005553 uint32_t period_ms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005554 struct stream_out *out = (struct stream_out *)stream;
Alexy Josephaa54c872014-12-03 02:46:47 -08005555 uint32_t latency = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005556
Alexy Josephaa54c872014-12-03 02:46:47 -08005557 if (is_offload_usecase(out->usecase)) {
Manish Dewangan07de2142017-02-27 19:27:20 +05305558 lock_output_stream(out);
5559 latency = audio_extn_utils_compress_get_dsp_latency(out);
5560 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07005561 } else if ((out->realtime) ||
5562 (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -07005563 // since the buffer won't be filled up faster than realtime,
5564 // return a smaller number
5565 if (out->config.rate)
5566 period_ms = (out->af_period_multiplier * out->config.period_size *
5567 1000) / (out->config.rate);
5568 else
5569 period_ms = 0;
George Gao9ba8a142020-07-23 14:30:03 -07005570 latency = period_ms + platform_render_latency(out) / 1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005571 } else {
5572 latency = (out->config.period_count * out->config.period_size * 1000) /
Mingshu Pangf69a88d2021-04-30 16:14:39 +08005573 (out->config.rate);
5574 if (out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER)
5575 latency += platform_render_latency(out)/1000;
Alexy Josephaa54c872014-12-03 02:46:47 -08005576 }
5577
Zhou Songd2537a02020-06-11 22:04:46 +08005578 if (!out->standby && is_a2dp_out_device_type(&out->device_list))
Aniket Kumar Latad5972fa2017-02-08 13:53:48 -08005579 latency += audio_extn_a2dp_get_encoder_latency();
5580
Anish Kumar50ebcbf2014-12-09 04:01:39 +05305581 ALOGV("%s: Latency %d", __func__, latency);
Alexy Josephaa54c872014-12-03 02:46:47 -08005582 return latency;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005583}
5584
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305585static float AmpToDb(float amplification)
5586{
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305587 float db = DSD_VOLUME_MIN_DB;
5588 if (amplification > 0) {
5589 db = 20 * log10(amplification);
5590 if(db < DSD_VOLUME_MIN_DB)
5591 return DSD_VOLUME_MIN_DB;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305592 }
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05305593 return db;
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305594}
5595
Arun Mirpuri5d170872019-03-26 13:21:31 -07005596static int out_set_mmap_volume(struct audio_stream_out *stream, float left,
5597 float right)
5598{
5599 struct stream_out *out = (struct stream_out *)stream;
5600 long volume = 0;
5601 char mixer_ctl_name[128] = "";
5602 struct audio_device *adev = out->dev;
5603 struct mixer_ctl *ctl = NULL;
5604 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5605 PCM_PLAYBACK);
5606
5607 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5608 "Playback %d Volume", pcm_device_id);
5609 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5610 if (!ctl) {
5611 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5612 __func__, mixer_ctl_name);
5613 return -EINVAL;
5614 }
5615 if (left != right)
5616 ALOGW("%s: Left and right channel volume mismatch:%f,%f",
5617 __func__, left, right);
5618 volume = (long)(left * (MMAP_PLAYBACK_VOLUME_MAX*1.0));
5619 if (mixer_ctl_set_value(ctl, 0, volume) < 0){
5620 ALOGE("%s:ctl for mixer cmd - %s, volume %ld returned error",
5621 __func__, mixer_ctl_name, volume);
5622 return -EINVAL;
5623 }
5624 return 0;
5625}
5626
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305627static int out_set_compr_volume(struct audio_stream_out *stream, float left,
5628 float right)
5629{
5630 struct stream_out *out = (struct stream_out *)stream;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305631 long volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305632 char mixer_ctl_name[128];
5633 struct audio_device *adev = out->dev;
5634 struct mixer_ctl *ctl;
5635 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
5636 PCM_PLAYBACK);
5637
5638 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
5639 "Compress Playback %d Volume", pcm_device_id);
5640 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5641 if (!ctl) {
5642 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5643 __func__, mixer_ctl_name);
5644 return -EINVAL;
5645 }
5646 ALOGE("%s:ctl for mixer cmd - %s, left %f, right %f",
5647 __func__, mixer_ctl_name, left, right);
5648 volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
5649 volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
5650 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5651
5652 return 0;
5653}
5654
Zhou Song2b8f28f2017-09-11 10:51:38 +08005655static int out_set_voip_volume(struct audio_stream_out *stream, float left,
5656 float right)
5657{
5658 struct stream_out *out = (struct stream_out *)stream;
5659 char mixer_ctl_name[] = "App Type Gain";
5660 struct audio_device *adev = out->dev;
5661 struct mixer_ctl *ctl;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305662 long set_values[4];
Zhou Song2b8f28f2017-09-11 10:51:38 +08005663
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07005664 if (!is_valid_volume(left, right)) {
5665 ALOGE("%s: Invalid stream volume for left=%f, right=%f",
5666 __func__, left, right);
5667 return -EINVAL;
5668 }
5669
Zhou Song2b8f28f2017-09-11 10:51:38 +08005670 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5671 if (!ctl) {
5672 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5673 __func__, mixer_ctl_name);
5674 return -EINVAL;
5675 }
5676
5677 set_values[0] = 0; //0: Rx Session 1:Tx Session
5678 set_values[1] = out->app_type_cfg.app_type;
Manish Dewangan338c50a2017-09-12 15:22:03 +05305679 set_values[2] = (long)(left * VOIP_PLAYBACK_VOLUME_MAX);
5680 set_values[3] = (long)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Song2b8f28f2017-09-11 10:51:38 +08005681
5682 mixer_ctl_set_array(ctl, set_values, ARRAY_SIZE(set_values));
5683 return 0;
5684}
5685
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305686static int out_set_pcm_volume(struct audio_stream_out *stream, float left,
5687 float right)
5688{
5689 struct stream_out *out = (struct stream_out *)stream;
5690 /* Volume control for pcm playback */
5691 if (left != right) {
5692 return -EINVAL;
5693 } else {
5694 char mixer_ctl_name[128];
5695 struct audio_device *adev = out->dev;
5696 struct mixer_ctl *ctl;
5697 int pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
5698 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Playback %d Volume", pcm_device_id);
5699 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5700 if (!ctl) {
5701 ALOGE("%s : Could not get ctl for mixer cmd - %s", __func__, mixer_ctl_name);
5702 return -EINVAL;
5703 }
5704
5705 int volume = (int) (left * PCM_PLAYBACK_VOLUME_MAX);
5706 int ret = mixer_ctl_set_value(ctl, 0, volume);
5707 if (ret < 0) {
5708 ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
5709 return -EINVAL;
5710 }
5711
5712 ALOGV("%s : Pcm set volume value %d left %f", __func__, volume, left);
5713
5714 return 0;
5715 }
5716}
5717
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005718static int out_set_volume(struct audio_stream_out *stream, float left,
5719 float right)
5720{
Eric Laurenta9024de2013-04-04 09:19:12 -07005721 struct stream_out *out = (struct stream_out *)stream;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005722 int volume[2];
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305723 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005724
Arun Mirpuri5d170872019-03-26 13:21:31 -07005725 ALOGD("%s: called with left_vol=%f, right_vol=%f", __func__, left, right);
Eric Laurenta9024de2013-04-04 09:19:12 -07005726 if (out->usecase == USECASE_AUDIO_PLAYBACK_MULTI_CH) {
5727 /* only take left channel into account: the API is for stereo anyway */
5728 out->muted = (left == 0.0f);
5729 return 0;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07005730 } else if (is_offload_usecase(out->usecase)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305731 if (audio_extn_passthru_is_passthrough_stream(out)) {
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005732 /*
5733 * Set mute or umute on HDMI passthrough stream.
5734 * Only take left channel into account.
5735 * Mute is 0 and unmute 1
5736 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305737 audio_extn_passthru_set_volume(out, (left == 0.0f));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305738 } else if (out->format == AUDIO_FORMAT_DSD){
5739 char mixer_ctl_name[128] = "DSD Volume";
5740 struct audio_device *adev = out->dev;
5741 struct mixer_ctl *ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
5742
5743 if (!ctl) {
5744 ALOGE("%s: Could not get ctl for mixer cmd - %s",
5745 __func__, mixer_ctl_name);
5746 return -EINVAL;
5747 }
Manish Dewangan338c50a2017-09-12 15:22:03 +05305748 volume[0] = (long)(AmpToDb(left));
5749 volume[1] = (long)(AmpToDb(right));
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05305750 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
5751 return 0;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005752 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS) &&
Derek Chendf05eea2019-08-01 13:57:49 -07005753 (out->car_audio_stream == CAR_AUDIO_STREAM_MEDIA)) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005754 ALOGD("%s: Overriding offload set volume for media bus stream", __func__);
5755 struct listnode *node = NULL;
5756 list_for_each(node, &adev->active_outputs_list) {
5757 streams_output_ctxt_t *out_ctxt = node_to_item(node,
5758 streams_output_ctxt_t,
5759 list);
5760 if (out_ctxt->output->usecase == USECASE_AUDIO_PLAYBACK_MEDIA) {
5761 out->volume_l = out_ctxt->output->volume_l;
5762 out->volume_r = out_ctxt->output->volume_r;
5763 }
5764 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08005765 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005766 if (!out->a2dp_muted) {
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005767 ret = out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
5768 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08005769 pthread_mutex_unlock(&out->latch_lock);
Philippe Gravel1c9ac352019-05-28 16:08:37 -07005770 return ret;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07005771 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +08005772 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005773 ALOGV("%s: compress mute %d", __func__, out->a2dp_muted);
5774 if (!out->a2dp_muted)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305775 ret = out_set_compr_volume(stream, left, right);
5776 out->volume_l = left;
5777 out->volume_r = right;
Weiyin Jiang280ea742020-09-08 20:28:22 +08005778 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05305779 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005780 }
Vikram Panduranga93f080e2017-06-07 18:16:14 -07005781 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
Aalique Grahame22e49102018-12-18 14:23:57 -08005782 out->app_type_cfg.gain[0] = (int)(left * VOIP_PLAYBACK_VOLUME_MAX);
5783 out->app_type_cfg.gain[1] = (int)(right * VOIP_PLAYBACK_VOLUME_MAX);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005784 pthread_mutex_lock(&out->latch_lock);
Aalique Grahame22e49102018-12-18 14:23:57 -08005785 if (!out->standby) {
5786 audio_extn_utils_send_app_type_gain(out->dev,
5787 out->app_type_cfg.app_type,
5788 &out->app_type_cfg.gain[0]);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005789 if (!out->a2dp_muted)
5790 ret = out_set_voip_volume(stream, left, right);
Aalique Grahame22e49102018-12-18 14:23:57 -08005791 }
Zhou Song2b8f28f2017-09-11 10:51:38 +08005792 out->volume_l = left;
5793 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08005794 pthread_mutex_unlock(&out->latch_lock);
Zhou Song2b8f28f2017-09-11 10:51:38 +08005795 return ret;
Arun Mirpuri5d170872019-03-26 13:21:31 -07005796 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
5797 ALOGV("%s: MMAP set volume called", __func__);
5798 if (!out->standby)
5799 ret = out_set_mmap_volume(stream, left, right);
5800 out->volume_l = left;
5801 out->volume_r = right;
5802 return ret;
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305803 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_LOW_LATENCY ||
Ramu Gottipati36547092018-12-28 11:32:09 +05305804 out->usecase == USECASE_AUDIO_PLAYBACK_DEEP_BUFFER ||
5805 out->usecase == USECASE_AUDIO_PLAYBACK_ULL) {
Zhou Songbaddf9f2020-11-20 13:57:39 +08005806 pthread_mutex_lock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305807 /* Volume control for pcm playback */
Zhou Songbaddf9f2020-11-20 13:57:39 +08005808 if (!out->standby && !out->a2dp_muted)
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305809 ret = out_set_pcm_volume(stream, left, right);
5810 else
5811 out->apply_volume = true;
5812
5813 out->volume_l = left;
5814 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08005815 pthread_mutex_unlock(&out->latch_lock);
Ramu Gottipati97bdcfb2018-04-13 17:58:24 +05305816 return ret;
Derek Chenf13dd492018-11-13 14:53:51 -08005817 } else if (audio_extn_auto_hal_is_bus_device_usecase(out->usecase)) {
5818 ALOGV("%s: bus device set volume called", __func__);
Zhou Songbaddf9f2020-11-20 13:57:39 +08005819 pthread_mutex_lock(&out->latch_lock);
5820 if (!out->standby && !out->a2dp_muted)
Derek Chenf13dd492018-11-13 14:53:51 -08005821 ret = out_set_pcm_volume(stream, left, right);
5822 out->volume_l = left;
5823 out->volume_r = right;
Zhou Songbaddf9f2020-11-20 13:57:39 +08005824 pthread_mutex_unlock(&out->latch_lock);
Derek Chenf13dd492018-11-13 14:53:51 -08005825 return ret;
Eric Laurenta9024de2013-04-04 09:19:12 -07005826 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07005827
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005828 return -ENOSYS;
5829}
5830
Zhou Songc9672822017-08-16 16:01:39 +08005831static void update_frames_written(struct stream_out *out, size_t bytes)
5832{
5833 size_t bpf = 0;
5834
5835 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
5836 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD))
5837 bpf = 1;
5838 else if (!is_offload_usecase(out->usecase))
5839 bpf = audio_bytes_per_sample(out->format) *
5840 audio_channel_count_from_out_mask(out->channel_mask);
Zhou Song48453a02018-01-10 17:50:59 +08005841
5842 pthread_mutex_lock(&out->position_query_lock);
5843 if (bpf != 0) {
Zhou Songc9672822017-08-16 16:01:39 +08005844 out->written += bytes / bpf;
Zhou Song48453a02018-01-10 17:50:59 +08005845 clock_gettime(CLOCK_MONOTONIC, &out->writeAt);
5846 }
5847 pthread_mutex_unlock(&out->position_query_lock);
Zhou Songc9672822017-08-16 16:01:39 +08005848}
5849
Vignesh Kulothungana6927272019-02-20 15:17:07 -08005850int split_and_write_audio_haptic_data(struct stream_out *out,
5851 const void *buffer, size_t bytes_to_write)
5852{
5853 struct audio_device *adev = out->dev;
5854
5855 int ret = 0;
5856 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
5857 size_t bytes_per_sample = audio_bytes_per_sample(out->format);
5858 size_t frame_size = channel_count * bytes_per_sample;
5859 size_t frame_count = bytes_to_write / frame_size;
5860
5861 bool force_haptic_path =
5862 property_get_bool("vendor.audio.test_haptic", false);
5863
5864 // extract Haptics data from Audio buffer
5865 bool alloc_haptic_buffer = false;
5866 int haptic_channel_count = adev->haptics_config.channels;
5867 size_t haptic_frame_size = bytes_per_sample * haptic_channel_count;
5868 size_t audio_frame_size = frame_size - haptic_frame_size;
5869 size_t total_haptic_buffer_size = frame_count * haptic_frame_size;
5870
5871 if (adev->haptic_buffer == NULL) {
5872 alloc_haptic_buffer = true;
5873 } else if (adev->haptic_buffer_size < total_haptic_buffer_size) {
5874 free(adev->haptic_buffer);
5875 adev->haptic_buffer_size = 0;
5876 alloc_haptic_buffer = true;
5877 }
5878
5879 if (alloc_haptic_buffer) {
5880 adev->haptic_buffer = (uint8_t *)calloc(1, total_haptic_buffer_size);
Mingshu Pang1513f972019-05-24 12:43:51 +08005881 if(adev->haptic_buffer == NULL) {
5882 ALOGE("%s: failed to allocate mem for dev->haptic_buffer", __func__);
5883 return -ENOMEM;
5884 }
Vignesh Kulothungana6927272019-02-20 15:17:07 -08005885 adev->haptic_buffer_size = total_haptic_buffer_size;
5886 }
5887
5888 size_t src_index = 0, aud_index = 0, hap_index = 0;
5889 uint8_t *audio_buffer = (uint8_t *)buffer;
5890 uint8_t *haptic_buffer = adev->haptic_buffer;
5891
5892 // This is required for testing only. This works for stereo data only.
5893 // One channel is fed to audio stream and other to haptic stream for testing.
5894 if (force_haptic_path)
5895 audio_frame_size = haptic_frame_size = bytes_per_sample;
5896
5897 for (size_t i = 0; i < frame_count; i++) {
5898 memcpy(audio_buffer + aud_index, audio_buffer + src_index,
5899 audio_frame_size);
5900 aud_index += audio_frame_size;
5901 src_index += audio_frame_size;
5902
5903 if (adev->haptic_pcm)
5904 memcpy(haptic_buffer + hap_index, audio_buffer + src_index,
5905 haptic_frame_size);
5906 hap_index += haptic_frame_size;
5907 src_index += haptic_frame_size;
5908
5909 // This is required for testing only.
5910 // Discard haptic channel data.
5911 if (force_haptic_path)
5912 src_index += haptic_frame_size;
5913 }
5914
5915 // write to audio pipeline
5916 ret = pcm_write(out->pcm, (void *)audio_buffer,
5917 frame_count * audio_frame_size);
5918
5919 // write to haptics pipeline
5920 if (adev->haptic_pcm)
5921 ret = pcm_write(adev->haptic_pcm, (void *)adev->haptic_buffer,
5922 frame_count * haptic_frame_size);
5923
5924 return ret;
5925}
5926
Aalique Grahame22e49102018-12-18 14:23:57 -08005927#ifdef NO_AUDIO_OUT
5928static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
5929 const void *buffer __unused, size_t bytes)
5930{
5931 struct stream_out *out = (struct stream_out *)stream;
5932
5933 /* No Output device supported other than BT for playback.
5934 * Sleep for the amount of buffer duration
5935 */
5936 lock_output_stream(out);
5937 usleep(bytes * 1000000 / audio_stream_out_frame_size(
5938 (const struct audio_stream_out *)&out->stream) /
5939 out_get_sample_rate(&out->stream.common));
5940 pthread_mutex_unlock(&out->lock);
5941 return bytes;
5942}
5943#endif
5944
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005945static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
5946 size_t bytes)
5947{
5948 struct stream_out *out = (struct stream_out *)stream;
5949 struct audio_device *adev = out->dev;
Eric Laurent6e895242013-09-05 16:10:57 -07005950 ssize_t ret = 0;
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05305951 int channels = 0;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07005952 const size_t frame_size = audio_stream_out_frame_size(stream);
5953 const size_t frames = (frame_size != 0) ? bytes / frame_size : bytes;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05305954 struct audio_usecase *usecase = NULL;
Meng Wang4c32fb42020-01-16 17:57:11 +08005955 uint32_t compr_passthr = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08005956
Haynes Mathew George380745d2017-10-04 15:27:45 -07005957 ATRACE_BEGIN("out_write");
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07005958 lock_output_stream(out);
Naresh Tanniru4c630392014-05-12 01:05:52 +05305959
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05305960 if (CARD_STATUS_OFFLINE == out->card_status) {
Zhou Song0b2e5dc2015-03-16 14:41:38 +08005961
Dhananjay Kumarac341582017-02-23 23:42:25 +05305962 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Ashish Jainbbce4322016-02-16 13:25:27 +05305963 /*during SSR for compress usecase we should return error to flinger*/
Naresh Tanniru80659832014-06-04 18:17:56 +05305964 ALOGD(" copl %s: sound card is not active/SSR state", __func__);
5965 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07005966 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05305967 return -ENETRESET;
Ashish Jainbbce4322016-02-16 13:25:27 +05305968 } else {
Ashish Jainbbce4322016-02-16 13:25:27 +05305969 ALOGD(" %s: sound card is not active/SSR state", __func__);
5970 ret= -EIO;
5971 goto exit;
Naresh Tanniru4c630392014-05-12 01:05:52 +05305972 }
5973 }
5974
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305975 if (audio_extn_passthru_should_drop_data(out)) {
Ashish Jaind84fd6a2016-07-27 12:33:25 +05305976 ALOGV(" %s : Drop data as compress passthrough session is going on", __func__);
Ashish Jaind84fd6a2016-07-27 12:33:25 +05305977 ret = -EIO;
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05305978 goto exit;
5979 }
5980
Haynes Mathew George16081042017-05-31 17:16:49 -07005981 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
5982 ret = -EINVAL;
5983 goto exit;
5984 }
5985
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08005986 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05305987 !out->is_iec61937_info_available) {
5988
5989 if (!audio_extn_passthru_is_passthrough_stream(out)) {
5990 out->is_iec61937_info_available = true;
5991 } else if (audio_extn_passthru_is_enabled()) {
5992 audio_extn_passthru_update_stream_configuration(adev, out, buffer, bytes);
Manish Dewangan37864bc2017-06-09 12:28:37 +05305993 out->is_iec61937_info_available = true;
Manish Dewangan671a4202017-08-18 17:30:46 +05305994
5995 if((out->format == AUDIO_FORMAT_DTS) ||
5996 (out->format == AUDIO_FORMAT_DTS_HD)) {
5997 ret = audio_extn_passthru_update_dts_stream_configuration(out,
5998 buffer, bytes);
5999 if (ret) {
6000 if (ret != -ENOSYS) {
6001 out->is_iec61937_info_available = false;
6002 ALOGD("iec61937 transmission info not yet updated retry");
6003 }
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306004 } else if (!out->standby) {
Manish Dewangan671a4202017-08-18 17:30:46 +05306005 /* if stream has started and after that there is
6006 * stream config change (iec transmission config)
6007 * then trigger select_device to update backend configuration.
6008 */
6009 out->stream_config_changed = true;
6010 pthread_mutex_lock(&adev->lock);
6011 select_devices(adev, out->usecase);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306012 if (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out)) {
Weiyin Jiang29c08a42019-04-30 17:11:10 +08006013 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306014 ret = -EINVAL;
6015 goto exit;
6016 }
Manish Dewangan671a4202017-08-18 17:30:46 +05306017 pthread_mutex_unlock(&adev->lock);
6018 out->stream_config_changed = false;
6019 out->is_iec61937_info_available = true;
6020 }
6021 }
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306022
Meng Wang4c32fb42020-01-16 17:57:11 +08006023#ifdef AUDIO_GKI_ENABLED
6024 /* out->compr_config.codec->reserved[0] is for compr_passthr */
6025 compr_passthr = out->compr_config.codec->reserved[0];
6026#else
6027 compr_passthr = out->compr_config.codec->compr_passthr;
6028#endif
6029
Garmond Leung317cbf12017-09-13 16:20:50 -07006030 if ((channels < (int)audio_channel_count_from_out_mask(out->channel_mask)) &&
Meng Wang4c32fb42020-01-16 17:57:11 +08006031 (compr_passthr == PASSTHROUGH) &&
Satish Babu Patakokila715b1422017-08-22 14:33:21 +05306032 (out->is_iec61937_info_available == true)) {
6033 ALOGE("%s: ERROR: Unsupported channel config in passthrough mode", __func__);
6034 ret = -EINVAL;
6035 goto exit;
6036 }
Manish Dewangan37864bc2017-06-09 12:28:37 +05306037 }
6038 }
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306039
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006040 if (is_a2dp_out_device_type(&out->device_list) &&
Florian Pfister1a84f312018-07-19 14:38:18 +02006041 (audio_extn_a2dp_source_is_suspended())) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006042 if (!(compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER) ||
6043 compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER_SAFE))) {
Zhou Songd01e7a22020-09-23 22:49:01 +08006044 if (!is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05306045 ret = -EIO;
6046 goto exit;
6047 }
6048 }
6049 }
6050
Weiyin Jiangabedea32020-12-09 12:49:19 +08006051 if (is_usb_out_device_type(&out->device_list) &&
6052 !audio_extn_usb_connected(NULL)) {
6053 ret = -EIO;
6054 goto exit;
6055 }
6056
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006057 if (out->standby) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006058 out->standby = false;
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006059 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
6060
Eric Laurent150dbfe2013-02-27 14:31:02 -08006061 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006062 if (out->usecase == USECASE_COMPRESS_VOIP_CALL)
6063 ret = voice_extn_compress_voip_start_output_stream(out);
6064 else
6065 ret = start_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006066 /* ToDo: If use case is compress offload should return 0 */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006067 if (ret != 0) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07006068 out->standby = true;
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006069 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006070 goto exit;
6071 }
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306072 out->started = 1;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006073 out->last_fifo_valid = false; // we're coming out of standby, last_fifo isn't valid.
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006074
6075 if ((last_known_cal_step != -1) && (adev->platform != NULL)) {
vivek mehtab72d08d2016-04-29 03:16:47 -07006076 ALOGD("%s: retry previous failed cal level set", __func__);
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006077 platform_send_gain_dep_cal(adev->platform, last_known_cal_step);
Preetam Singh Ranawatf4ae0222017-05-31 17:07:28 +05306078 last_known_cal_step = -1;
vivek mehtab72d08d2016-04-29 03:16:47 -07006079 }
Weiyin Jiangac2bae82020-07-29 17:23:53 +08006080 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05306081
6082 if ((out->is_iec61937_info_available == true) &&
6083 (audio_extn_passthru_is_passthrough_stream(out))&&
6084 (!audio_extn_passthru_is_supported_backend_edid_cfg(adev, out))) {
6085 ret = -EINVAL;
6086 goto exit;
6087 }
Surendar Karkaf51b5842018-04-26 11:28:38 +05306088 if (out->set_dual_mono)
6089 audio_extn_send_dual_mono_mixing_coefficients(out);
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006090
Dechen Chai22768452021-07-30 09:29:16 +05306091#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07006092 // log startup time in ms.
6093 simple_stats_log(
6094 &out->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05306095#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006096 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006097
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006098 if (adev->is_channel_status_set == false &&
6099 compare_device_type(&out->device_list,
6100 AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Alexy Josephb1379942016-01-29 15:49:38 -08006101 audio_utils_set_hdmi_channel_status(out, (void *)buffer, bytes);
Ashish Jain81eb2a82015-05-13 10:52:34 +05306102 adev->is_channel_status_set = true;
6103 }
6104
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306105 if ((adev->use_old_pspd_mix_ctrl == true) &&
6106 (out->pspd_coeff_sent == false)) {
6107 /*
6108 * Need to resend pspd coefficients after stream started for
6109 * older kernel version as it does not save the coefficients
6110 * and also stream has to be started for coeff to apply.
6111 */
6112 usecase = get_usecase_from_list(adev, out->usecase);
6113 if (usecase != NULL) {
Chaithanya Krishna Bacharajuc9f99712019-04-16 15:32:52 +05306114 audio_extn_set_custom_mtmx_params_v2(adev, usecase, true);
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05306115 out->pspd_coeff_sent = true;
6116 }
6117 }
6118
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006119 if (is_offload_usecase(out->usecase)) {
Alexy Joseph01e54e62015-03-03 19:01:03 -08006120 ALOGVV("copl(%p): writing buffer (%zu bytes) to compress device", out, bytes);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006121 if (out->send_new_metadata) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006122 ALOGD("copl(%p):send new gapless metadata", out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006123 compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
6124 out->send_new_metadata = 0;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306125 if (out->send_next_track_params && out->is_compr_metadata_avail) {
6126 ALOGD("copl(%p):send next track params in gapless", out);
Weiyin Jiangd9b5a4e2019-07-18 17:24:21 +08006127 compress_set_next_track_param(out->compr, &(out->compr_config.codec->options));
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05306128 out->send_next_track_params = false;
6129 out->is_compr_metadata_avail = false;
6130 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006131 }
Dhananjay Kumarac341582017-02-23 23:42:25 +05306132 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306133 (out->convert_buffer) != NULL) {
Haynes Mathew George352f27b2013-07-26 00:00:15 -07006134
Ashish Jain83a6cc22016-06-28 14:34:17 +05306135 if ((bytes > out->hal_fragment_size)) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05306136 ALOGW("Error written bytes %zu > %d (fragment_size)",
Ashish Jain83a6cc22016-06-28 14:34:17 +05306137 bytes, out->hal_fragment_size);
Ashish Jainf1eaa582016-05-23 20:54:24 +05306138 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006139 ATRACE_END();
Ashish Jainf1eaa582016-05-23 20:54:24 +05306140 return -EINVAL;
6141 } else {
Ashish Jain83a6cc22016-06-28 14:34:17 +05306142 audio_format_t dst_format = out->hal_op_format;
6143 audio_format_t src_format = out->hal_ip_format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05306144
Dieter Luecking5d57def2018-09-07 14:23:37 +02006145 /* prevent division-by-zero */
6146 uint32_t bitwidth_src = format_to_bitwidth_table[src_format];
6147 uint32_t bitwidth_dst = format_to_bitwidth_table[dst_format];
6148 if ((bitwidth_src == 0) || (bitwidth_dst == 0)) {
6149 ALOGE("%s: Error bitwidth == 0", __func__);
Ramu Gottipati02809682018-12-19 16:46:12 +05306150 pthread_mutex_unlock(&out->lock);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006151 ATRACE_END();
6152 return -EINVAL;
6153 }
6154
Ashish Jainf1eaa582016-05-23 20:54:24 +05306155 uint32_t frames = bytes / format_to_bitwidth_table[src_format];
6156 uint32_t bytes_to_write = frames * format_to_bitwidth_table[dst_format];
6157
Ashish Jain83a6cc22016-06-28 14:34:17 +05306158 memcpy_by_audio_format(out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306159 dst_format,
6160 buffer,
6161 src_format,
6162 frames);
6163
Ashish Jain83a6cc22016-06-28 14:34:17 +05306164 ret = compress_write(out->compr, out->convert_buffer,
Ashish Jainf1eaa582016-05-23 20:54:24 +05306165 bytes_to_write);
6166
6167 /*Convert written bytes in audio flinger format*/
6168 if (ret > 0)
6169 ret = ((ret * format_to_bitwidth_table[out->format]) /
6170 format_to_bitwidth_table[dst_format]);
6171 }
6172 } else
6173 ret = compress_write(out->compr, buffer, bytes);
6174
Zhou Songc9672822017-08-16 16:01:39 +08006175 if ((ret < 0 || ret == (ssize_t)bytes) && !out->non_blocking)
6176 update_frames_written(out, bytes);
6177
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306178 if (ret < 0)
6179 ret = -errno;
Weiyin Jiangcc60dbb2018-08-21 13:12:03 +08006180 ALOGVV("%s: writing buffer (%zu bytes) to compress device returned %d", __func__, bytes, (int)ret);
Ashish Jainb26edfb2016-08-25 00:10:11 +05306181 /*msg to cb thread only if non blocking write is enabled*/
6182 if (ret >= 0 && ret < (ssize_t)bytes && out->non_blocking) {
Sidipotu Ashok55820562014-02-10 16:16:38 +05306183 ALOGD("No space available in compress driver, post msg to cb thread");
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006184 send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
Naresh Tanniru80659832014-06-04 18:17:56 +05306185 } else if (-ENETRESET == ret) {
6186 ALOGE("copl %s: received sound card offline state on compress write", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306187 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru80659832014-06-04 18:17:56 +05306188 pthread_mutex_unlock(&out->lock);
Dhananjay Kumar1248dd82017-07-28 21:22:16 +05306189 out_on_error(&out->stream.common);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006190 ATRACE_END();
Naresh Tanniru80659832014-06-04 18:17:56 +05306191 return ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006192 }
Ashish Jain5106d362016-05-11 19:23:33 +05306193
Dhanalakshmi Siddania6b76c72016-09-09 18:10:31 +05306194 /* Call compr start only when non-zero bytes of data is there to be rendered */
6195 if (!out->playback_started && ret > 0) {
6196 int status = compress_start(out->compr);
6197 if (status < 0) {
6198 ret = status;
6199 ALOGE("%s: compr start failed with err %d", __func__, errno);
6200 goto exit;
6201 }
Alexy Joseph7de344d2015-03-30 10:40:03 -07006202 audio_extn_dts_eagle_fade(adev, true, out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006203 out->playback_started = 1;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006204 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006205 out->offload_state = OFFLOAD_STATE_PLAYING;
Weiyin Jiang280ea742020-09-08 20:28:22 +08006206 pthread_mutex_unlock(&out->latch_lock);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006207
6208 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6209 popcount(out->channel_mask),
6210 out->playback_started);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006211 }
6212 pthread_mutex_unlock(&out->lock);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006213 ATRACE_END();
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006214 return ret;
6215 } else {
6216 if (out->pcm) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006217 size_t bytes_to_write = bytes;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006218 if (out->muted)
6219 memset((void *)buffer, 0, bytes);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006220 ALOGV("%s: frames=%zu, frame_size=%zu, bytes_to_write=%zu",
6221 __func__, frames, frame_size, bytes_to_write);
6222
Aalique Grahame22e49102018-12-18 14:23:57 -08006223 if (out->usecase == USECASE_INCALL_MUSIC_UPLINK ||
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07006224 out->usecase == USECASE_INCALL_MUSIC_UPLINK2 ||
6225 (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP &&
6226 !audio_extn_utils_is_vendor_enhanced_fwk())) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006227 size_t channel_count = audio_channel_count_from_out_mask(out->channel_mask);
6228 int16_t *src = (int16_t *)buffer;
6229 int16_t *dst = (int16_t *)buffer;
6230
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006231 LOG_ALWAYS_FATAL_IF(channel_count > 2 ||
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006232 out->format != AUDIO_FORMAT_PCM_16_BIT,
Aalique Grahame22e49102018-12-18 14:23:57 -08006233 "out_write called for %s use case with wrong properties",
6234 use_case_table[out->usecase]);
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006235
6236 /*
6237 * FIXME: this can be removed once audio flinger mixer supports
6238 * mono output
6239 */
6240
6241 /*
6242 * Code below goes over each frame in the buffer and adds both
6243 * L and R samples and then divides by 2 to convert to mono
6244 */
Yunfei Zhanga6cd66d2019-07-22 16:15:36 +08006245 if (channel_count == 2) {
6246 for (size_t i = 0; i < frames ; i++, dst++, src += 2) {
6247 *dst = (int16_t)(((int32_t)src[0] + (int32_t)src[1]) >> 1);
6248 }
6249 bytes_to_write /= 2;
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006250 }
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006251 }
Andy Hunga1f48fa2019-07-01 18:14:53 -07006252
6253 // Note: since out_get_presentation_position() is called alternating with out_write()
6254 // by AudioFlinger, we can check underruns using the prior timestamp read.
6255 // (Alternately we could check if the buffer is empty using pcm_get_htimestamp().
6256 if (out->last_fifo_valid) {
6257 // compute drain to see if there is an underrun.
6258 const int64_t current_ns = systemTime(SYSTEM_TIME_MONOTONIC); // sys call
Dhananjay Kumara4429632020-07-11 02:53:37 +05306259 int64_t time_diff_ns = current_ns - out->last_fifo_time_ns;
6260 int64_t frames_by_time =
6261 ((time_diff_ns > 0) && (time_diff_ns < (INT64_MAX / out->config.rate))) ?
6262 (time_diff_ns * out->config.rate / NANOS_PER_SECOND) : 0;
Andy Hunga1f48fa2019-07-01 18:14:53 -07006263 const int64_t underrun = frames_by_time - out->last_fifo_frames_remaining;
6264
6265 if (underrun > 0) {
Dechen Chai22768452021-07-30 09:29:16 +05306266#ifndef LINUX_ENABLED
Andy Hunga1f48fa2019-07-01 18:14:53 -07006267 simple_stats_log(&out->fifo_underruns, underrun);
Dechen Chai22768452021-07-30 09:29:16 +05306268#endif
Andy Hunga1f48fa2019-07-01 18:14:53 -07006269
6270 ALOGW("%s: underrun(%lld) "
6271 "frames_by_time(%lld) > out->last_fifo_frames_remaining(%lld)",
6272 __func__,
6273 (long long)out->fifo_underruns.n,
6274 (long long)frames_by_time,
6275 (long long)out->last_fifo_frames_remaining);
6276 }
6277 out->last_fifo_valid = false; // we're writing below, mark fifo info as stale.
6278 }
6279
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05306280 ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006281
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006282 long ns = 0;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006283
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006284 if (out->config.rate)
6285 ns = pcm_bytes_to_frames(out->pcm, bytes)*1000000000LL/
6286 out->config.rate;
6287
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006288 request_out_focus(out, ns);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006289 bool use_mmap = is_mmap_usecase(out->usecase) || out->realtime;
6290
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006291 if (use_mmap)
Arun Mirpuri7da752a2018-09-11 18:01:15 -07006292 ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes_to_write);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006293 else if (out->hal_op_format != out->hal_ip_format &&
Ashish Jain83a6cc22016-06-28 14:34:17 +05306294 out->convert_buffer != NULL) {
6295
6296 memcpy_by_audio_format(out->convert_buffer,
6297 out->hal_op_format,
6298 buffer,
6299 out->hal_ip_format,
6300 out->config.period_size * out->config.channels);
6301
6302 ret = pcm_write(out->pcm, out->convert_buffer,
6303 (out->config.period_size *
6304 out->config.channels *
6305 format_to_bitwidth_table[out->hal_op_format]));
6306 } else {
Aditya Bavanarid4db8ee2017-05-29 21:08:03 +05306307 /*
6308 * To avoid underrun in DSP when the application is not pumping
6309 * data at required rate, check for the no. of bytes and ignore
6310 * pcm_write if it is less than actual buffer size.
6311 * It is a work around to a change in compress VOIP driver.
6312 */
6313 if ((out->flags & AUDIO_OUTPUT_FLAG_VOIP_RX) &&
6314 bytes < (out->config.period_size * out->config.channels *
6315 audio_bytes_per_sample(out->format))) {
6316 size_t voip_buf_size =
6317 out->config.period_size * out->config.channels *
6318 audio_bytes_per_sample(out->format);
6319 ALOGE("%s:VOIP underrun: bytes received %zu, required:%zu\n",
6320 __func__, bytes, voip_buf_size);
6321 usleep(((uint64_t)voip_buf_size - bytes) *
6322 1000000 / audio_stream_out_frame_size(stream) /
6323 out_get_sample_rate(&out->stream.common));
6324 ret = 0;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08006325 } else {
6326 if (out->usecase == USECASE_AUDIO_PLAYBACK_WITH_HAPTICS)
6327 ret = split_and_write_audio_haptic_data(out, buffer, bytes);
6328 else
6329 ret = pcm_write(out->pcm, (void *)buffer, bytes_to_write);
6330 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05306331 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006332
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006333 release_out_focus(out);
6334
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306335 if (ret < 0)
6336 ret = -errno;
Zhou Songc9672822017-08-16 16:01:39 +08006337 else if (ret > 0)
Ashish Jain83a6cc22016-06-28 14:34:17 +05306338 ret = -EINVAL;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006339 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006340 }
6341
6342exit:
Zhou Songc9672822017-08-16 16:01:39 +08006343 update_frames_written(out, bytes);
Naresh Tanniru4c630392014-05-12 01:05:52 +05306344 if (-ENETRESET == ret) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306345 out->card_status = CARD_STATUS_OFFLINE;
Naresh Tanniru4c630392014-05-12 01:05:52 +05306346 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006347 pthread_mutex_unlock(&out->lock);
6348
6349 if (ret != 0) {
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07006350 if (out->pcm)
Alexy Josephb1379942016-01-29 15:49:38 -08006351 ALOGE("%s: error %d, %s", __func__, (int)ret, pcm_get_error(out->pcm));
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306352 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306353 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306354 voice_extn_compress_voip_close_output_stream(&out->stream.common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05306355 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05306356 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05306357 out->standby = true;
6358 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306359 out_on_error(&out->stream.common);
Dieter Luecking5d57def2018-09-07 14:23:37 +02006360 if (!(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
6361 /* prevent division-by-zero */
6362 uint32_t stream_size = audio_stream_out_frame_size(stream);
6363 uint32_t srate = out_get_sample_rate(&out->stream.common);
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006364
Dieter Luecking5d57def2018-09-07 14:23:37 +02006365 if ((stream_size == 0) || (srate == 0)) {
6366 ALOGE("%s: stream_size= %d, srate = %d", __func__, stream_size, srate);
6367 ATRACE_END();
6368 return -EINVAL;
6369 }
6370 usleep((uint64_t)bytes * 1000000 / stream_size / srate);
6371 }
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006372 if (audio_extn_passthru_is_passthrough_stream(out)) {
Rajshekar Eashwarappa88834522018-04-02 17:20:15 +05306373 //ALOGE("%s: write error, ret = %zd", __func__, ret);
Haynes Mathew George380745d2017-10-04 15:27:45 -07006374 ATRACE_END();
Vidyakumar Athotaa9d3a5f2017-08-09 12:13:05 -07006375 return ret;
6376 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006377 }
Haynes Mathew George380745d2017-10-04 15:27:45 -07006378 ATRACE_END();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006379 return bytes;
6380}
6381
6382static int out_get_render_position(const struct audio_stream_out *stream,
6383 uint32_t *dsp_frames)
6384{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006385 struct stream_out *out = (struct stream_out *)stream;
Zhou Song32a556e2015-05-05 10:46:56 +08006386
6387 if (dsp_frames == NULL)
6388 return -EINVAL;
6389
6390 *dsp_frames = 0;
6391 if (is_offload_usecase(out->usecase)) {
Mingming Yin9e348b52014-11-19 16:18:55 -08006392 ssize_t ret = 0;
Ashish Jain5106d362016-05-11 19:23:33 +05306393
6394 /* Below piece of code is not guarded against any lock beacuse audioFliner serializes
6395 * this operation and adev_close_output_stream(where out gets reset).
6396 */
Dhananjay Kumarac341582017-02-23 23:42:25 +05306397 if (!out->non_blocking && !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006398 *dsp_frames = get_actual_pcm_frames_rendered(out, NULL);
Ashish Jain5106d362016-05-11 19:23:33 +05306399 ALOGVV("dsp_frames %d sampleRate %d",(int)*dsp_frames,out->sample_rate);
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006400 adjust_frames_for_device_delay(out, dsp_frames);
Ashish Jain5106d362016-05-11 19:23:33 +05306401 return 0;
6402 }
6403
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006404 lock_output_stream(out);
Ashish Jain5106d362016-05-11 19:23:33 +05306405 if (out->compr != NULL && out->non_blocking) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306406 ret = compress_get_tstamp(out->compr, (unsigned long *)dsp_frames,
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006407 &out->sample_rate);
Dhanalakshmi Siddani37ca1d62014-08-20 12:28:34 +05306408 if (ret < 0)
6409 ret = -errno;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006410 ALOGVV("%s rendered frames %d sample_rate %d",
Ashish Jain5106d362016-05-11 19:23:33 +05306411 __func__, *dsp_frames, out->sample_rate);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006412 }
Naresh Tanniru80659832014-06-04 18:17:56 +05306413 if (-ENETRESET == ret) {
6414 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306415 out->card_status = CARD_STATUS_OFFLINE;
6416 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306417 } else if(ret < 0) {
6418 ALOGE(" ERROR: Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306419 ret = -EINVAL;
6420 } else if (out->card_status == CARD_STATUS_OFFLINE) {
Preetam Singh Ranawat2d0e4632015-02-02 12:40:59 +05306421 /*
6422 * Handle corner case where compress session is closed during SSR
6423 * and timestamp is queried
6424 */
6425 ALOGE(" ERROR: sound card not active, return error");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306426 ret = -EINVAL;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306427 } else if (out->prev_card_status_offline) {
6428 ALOGE("ERROR: previously sound card was offline,return error");
6429 ret = -EINVAL;
Naresh Tanniru80659832014-06-04 18:17:56 +05306430 } else {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306431 ret = 0;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006432 adjust_frames_for_device_delay(out, dsp_frames);
Naresh Tanniru80659832014-06-04 18:17:56 +05306433 }
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306434 pthread_mutex_unlock(&out->lock);
6435 return ret;
Zhou Song32a556e2015-05-05 10:46:56 +08006436 } else if (audio_is_linear_pcm(out->format)) {
6437 *dsp_frames = out->written;
Haynes Mathew Georgeb0f5dc32017-10-06 18:35:12 -07006438 adjust_frames_for_device_delay(out, dsp_frames);
Zhou Song32a556e2015-05-05 10:46:56 +08006439 return 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006440 } else
6441 return -EINVAL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006442}
6443
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006444static int out_add_audio_effect(const struct audio_stream *stream __unused,
6445 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006446{
6447 return 0;
6448}
6449
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006450static int out_remove_audio_effect(const struct audio_stream *stream __unused,
6451 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006452{
6453 return 0;
6454}
6455
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006456static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
6457 int64_t *timestamp __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006458{
Satya Krishna Pindiprolib6655542017-07-03 19:38:19 +05306459 return -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006460}
6461
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006462static int out_get_presentation_position(const struct audio_stream_out *stream,
6463 uint64_t *frames, struct timespec *timestamp)
6464{
6465 struct stream_out *out = (struct stream_out *)stream;
pavance65c2fe2017-10-18 17:52:01 +05306466 int ret = -ENODATA;
Eric Laurent949a0892013-09-20 09:20:13 -07006467 unsigned long dsp_frames;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006468
Ashish Jain5106d362016-05-11 19:23:33 +05306469 /* below piece of code is not guarded against any lock because audioFliner serializes
6470 * this operation and adev_close_output_stream( where out gets reset).
6471 */
6472 if (is_offload_usecase(out->usecase) && !out->non_blocking &&
Dhananjay Kumarac341582017-02-23 23:42:25 +05306473 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Zhou Song48453a02018-01-10 17:50:59 +08006474 *frames = get_actual_pcm_frames_rendered(out, timestamp);
Ashish Jain5106d362016-05-11 19:23:33 +05306475 ALOGVV("frames %lld playedat %lld",(long long int)*frames,
6476 timestamp->tv_sec * 1000000LL + timestamp->tv_nsec / 1000);
6477 return 0;
6478 }
6479
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006480 lock_output_stream(out);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006481
Ashish Jain5106d362016-05-11 19:23:33 +05306482 if (is_offload_usecase(out->usecase) && out->compr != NULL && out->non_blocking) {
6483 ret = compress_get_tstamp(out->compr, &dsp_frames,
6484 &out->sample_rate);
yidongh0515e042017-07-06 15:00:34 +08006485 // Adjustment accounts for A2dp encoder latency with offload usecases
6486 // Note: Encoder latency is returned in ms.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006487 if (is_a2dp_out_device_type(&out->device_list)) {
yidongh0515e042017-07-06 15:00:34 +08006488 unsigned long offset =
6489 (audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
6490 dsp_frames = (dsp_frames > offset) ? (dsp_frames - offset) : 0;
6491 }
Ashish Jain5106d362016-05-11 19:23:33 +05306492 ALOGVV("%s rendered frames %ld sample_rate %d",
6493 __func__, dsp_frames, out->sample_rate);
6494 *frames = dsp_frames;
6495 if (ret < 0)
6496 ret = -errno;
6497 if (-ENETRESET == ret) {
6498 ALOGE(" ERROR: sound card not active Unable to get time stamp from compress driver");
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306499 out->card_status = CARD_STATUS_OFFLINE;
Ashish Jain5106d362016-05-11 19:23:33 +05306500 ret = -EINVAL;
6501 } else
6502 ret = 0;
6503 /* this is the best we can do */
6504 clock_gettime(CLOCK_MONOTONIC, timestamp);
Eric Laurent949a0892013-09-20 09:20:13 -07006505 } else {
6506 if (out->pcm) {
Weiyin Jiangd4633762018-03-16 12:05:03 +08006507 unsigned int avail;
6508 if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
George Gao62ebc722019-07-29 16:29:44 -07006509 uint64_t signed_frames = 0;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006510 uint64_t frames_temp = 0;
George Gao62ebc722019-07-29 16:29:44 -07006511
Andy Hunga1f48fa2019-07-01 18:14:53 -07006512 if (out->kernel_buffer_size > avail) {
6513 frames_temp = out->last_fifo_frames_remaining = out->kernel_buffer_size - avail;
6514 } else {
6515 ALOGW("%s: avail:%u > kernel_buffer_size:%zu clamping!",
6516 __func__, avail, out->kernel_buffer_size);
6517 avail = out->kernel_buffer_size;
6518 frames_temp = out->last_fifo_frames_remaining = 0;
6519 }
6520 out->last_fifo_valid = true;
6521 out->last_fifo_time_ns = audio_utils_ns_from_timespec(timestamp);
6522
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006523 if (out->written >= frames_temp)
6524 signed_frames = out->written - frames_temp;
George Gao62ebc722019-07-29 16:29:44 -07006525
Andy Hunga1f48fa2019-07-01 18:14:53 -07006526 ALOGVV("%s: frames:%lld avail:%u kernel_buffer_size:%zu",
6527 __func__, (long long)signed_frames, avail, out->kernel_buffer_size);
6528
Weiyin Jiangd4633762018-03-16 12:05:03 +08006529 // This adjustment accounts for buffering after app processor.
6530 // It is based on estimated DSP latency per use case, rather than exact.
George Gao9ba8a142020-07-23 14:30:03 -07006531 frames_temp = platform_render_latency(out) *
Robert Lee58215542019-07-15 20:55:12 +08006532 out->sample_rate / 1000000LL;
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006533 if (signed_frames >= frames_temp)
6534 signed_frames -= frames_temp;
Aniket Kumar Lataff613152017-07-18 18:19:21 -07006535
Weiyin Jiangd4633762018-03-16 12:05:03 +08006536 // Adjustment accounts for A2dp encoder latency with non offload usecases
6537 // Note: Encoder latency is returned in ms, while platform_render_latency in us.
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08006538 if (is_a2dp_out_device_type(&out->device_list)) {
Weiyin Jiang0d25bcf2019-08-30 15:27:23 +08006539 frames_temp = audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000;
6540 if (signed_frames >= frames_temp)
6541 signed_frames -= frames_temp;
Weiyin Jiangd4633762018-03-16 12:05:03 +08006542 }
6543
6544 // It would be unusual for this value to be negative, but check just in case ...
George Gao62ebc722019-07-29 16:29:44 -07006545 *frames = signed_frames;
6546 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006547 }
Eric Laurenta7a33042019-07-10 16:20:22 -07006548 } else if (out->card_status == CARD_STATUS_OFFLINE ||
6549 // audioflinger still needs position updates when A2DP is suspended
Jasmine Cha5c2517f2019-09-09 11:07:28 +08006550 (is_a2dp_out_device_type(&out->device_list) && audio_extn_a2dp_source_is_suspended())) {
Ashish Jainbbce4322016-02-16 13:25:27 +05306551 *frames = out->written;
6552 clock_gettime(CLOCK_MONOTONIC, timestamp);
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05306553 if (is_offload_usecase(out->usecase))
6554 ret = -EINVAL;
6555 else
6556 ret = 0;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006557 }
6558 }
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006559 pthread_mutex_unlock(&out->lock);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07006560 return ret;
6561}
6562
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006563static int out_set_callback(struct audio_stream_out *stream,
6564 stream_callback_t callback, void *cookie)
6565{
6566 struct stream_out *out = (struct stream_out *)stream;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006567 int ret;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006568
6569 ALOGV("%s", __func__);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006570 lock_output_stream(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08006571 out->client_callback = callback;
6572 out->client_cookie = cookie;
6573 if (out->adsp_hdlr_stream_handle) {
6574 ret = audio_extn_adsp_hdlr_stream_set_callback(
6575 out->adsp_hdlr_stream_handle,
6576 callback,
6577 cookie);
6578 if (ret)
6579 ALOGW("%s:adsp hdlr callback registration failed %d",
6580 __func__, ret);
6581 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006582 pthread_mutex_unlock(&out->lock);
6583 return 0;
6584}
6585
6586static int out_pause(struct audio_stream_out* stream)
6587{
6588 struct stream_out *out = (struct stream_out *)stream;
6589 int status = -ENOSYS;
6590 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006591 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006592 ALOGD("copl(%p):pause compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306593 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006594 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006595 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006596 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306597 if (out->card_status != CARD_STATUS_OFFLINE)
Naresh Tanniru80659832014-06-04 18:17:56 +05306598 status = compress_pause(out->compr);
6599
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006600 out->offload_state = OFFLOAD_STATE_PAUSED;
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006601
Mingming Yin21854652016-04-13 11:54:02 -07006602 if (audio_extn_passthru_is_active()) {
6603 ALOGV("offload use case, pause passthru");
6604 audio_extn_passthru_on_pause(out);
6605 }
6606
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306607 audio_extn_dts_eagle_fade(adev, false, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006608 audio_extn_dts_notify_playback_state(out->usecase, 0,
6609 out->sample_rate, popcount(out->channel_mask),
6610 0);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006611 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006612 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006613 pthread_mutex_unlock(&out->lock);
6614 }
6615 return status;
6616}
6617
6618static int out_resume(struct audio_stream_out* stream)
6619{
6620 struct stream_out *out = (struct stream_out *)stream;
6621 int status = -ENOSYS;
6622 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006623 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006624 ALOGD("copl(%p):resume compress driver", out);
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306625 status = -ENODATA;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006626 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006627 pthread_mutex_lock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006628 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05306629 if (out->card_status != CARD_STATUS_OFFLINE) {
Naresh Tanniru80659832014-06-04 18:17:56 +05306630 status = compress_resume(out->compr);
Mingming Yin21854652016-04-13 11:54:02 -07006631 }
6632 if (!status) {
6633 out->offload_state = OFFLOAD_STATE_PLAYING;
6634 }
Dhanalakshmi Siddani79415e72015-03-23 11:54:47 +05306635 audio_extn_dts_eagle_fade(adev, true, out);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08006636 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
6637 popcount(out->channel_mask), 1);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006638 }
Weiyin Jiang280ea742020-09-08 20:28:22 +08006639 pthread_mutex_unlock(&out->latch_lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006640 pthread_mutex_unlock(&out->lock);
6641 }
6642 return status;
6643}
6644
6645static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
6646{
6647 struct stream_out *out = (struct stream_out *)stream;
6648 int status = -ENOSYS;
6649 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006650 if (is_offload_usecase(out->usecase)) {
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006651 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006652 if (type == AUDIO_DRAIN_EARLY_NOTIFY)
6653 status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
6654 else
6655 status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
6656 pthread_mutex_unlock(&out->lock);
6657 }
6658 return status;
6659}
6660
6661static int out_flush(struct audio_stream_out* stream)
6662{
6663 struct stream_out *out = (struct stream_out *)stream;
6664 ALOGV("%s", __func__);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07006665 if (is_offload_usecase(out->usecase)) {
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006666 ALOGD("copl(%p):calling compress flush", out);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006667 lock_output_stream(out);
Weiyin Jiang280ea742020-09-08 20:28:22 +08006668 pthread_mutex_lock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006669 if (out->offload_state == OFFLOAD_STATE_PAUSED) {
Gautam Manam14c198b2020-12-24 14:08:04 +05306670 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006671 stop_compressed_output_l(out);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006672 } else {
6673 ALOGW("%s called in invalid state %d", __func__, out->offload_state);
Gautam Manam14c198b2020-12-24 14:08:04 +05306674 pthread_mutex_unlock(&out->latch_lock);
Haynes Mathew Georgeafe54d82016-09-21 14:39:19 -07006675 }
Weiyin Jiang547e4152017-09-14 17:24:18 +08006676 out->written = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006677 pthread_mutex_unlock(&out->lock);
Apoorv Raghuvanshi44bd9172014-05-28 14:50:07 -07006678 ALOGD("copl(%p):out of compress flush", out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07006679 return 0;
6680 }
6681 return -ENOSYS;
6682}
6683
Haynes Mathew George16081042017-05-31 17:16:49 -07006684static int out_stop(const struct audio_stream_out* stream)
6685{
6686 struct stream_out *out = (struct stream_out *)stream;
6687 struct audio_device *adev = out->dev;
6688 int ret = -ENOSYS;
6689
6690 ALOGV("%s", __func__);
6691 pthread_mutex_lock(&adev->lock);
6692 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6693 out->playback_started && out->pcm != NULL) {
6694 pcm_stop(out->pcm);
6695 ret = stop_output_stream(out);
6696 out->playback_started = false;
6697 }
6698 pthread_mutex_unlock(&adev->lock);
6699 return ret;
6700}
6701
6702static int out_start(const struct audio_stream_out* stream)
6703{
6704 struct stream_out *out = (struct stream_out *)stream;
6705 struct audio_device *adev = out->dev;
6706 int ret = -ENOSYS;
6707
6708 ALOGV("%s", __func__);
6709 pthread_mutex_lock(&adev->lock);
6710 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
6711 !out->playback_started && out->pcm != NULL) {
6712 ret = start_output_stream(out);
6713 if (ret == 0) {
6714 out->playback_started = true;
6715 }
6716 }
6717 pthread_mutex_unlock(&adev->lock);
6718 return ret;
6719}
6720
6721/*
6722 * Modify config->period_count based on min_size_frames
6723 */
6724static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
6725{
6726 int periodCountRequested = (min_size_frames + config->period_size - 1)
6727 / config->period_size;
6728 int periodCount = MMAP_PERIOD_COUNT_MIN;
6729
6730 ALOGV("%s original config.period_size = %d config.period_count = %d",
6731 __func__, config->period_size, config->period_count);
6732
6733 while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
6734 periodCount *= 2;
6735 }
6736 config->period_count = periodCount;
6737
6738 ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
6739}
6740
Phil Burkfe17efd2019-03-25 10:23:35 -07006741// Read offset for the positional timestamp from a persistent vendor property.
6742// This is to workaround apparent inaccuracies in the timing information that
6743// is used by the AAudio timing model. The inaccuracies can cause glitches.
6744static int64_t get_mmap_out_time_offset() {
6745 const int32_t kDefaultOffsetMicros = 0;
6746 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08006747 "persist.vendor.audio.out_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burkfe17efd2019-03-25 10:23:35 -07006748 ALOGI("mmap_time_offset_micros = %d for output", mmap_time_offset_micros);
6749 return mmap_time_offset_micros * (int64_t)1000;
6750}
6751
Haynes Mathew George16081042017-05-31 17:16:49 -07006752static int out_create_mmap_buffer(const struct audio_stream_out *stream,
6753 int32_t min_size_frames,
6754 struct audio_mmap_buffer_info *info)
6755{
6756 struct stream_out *out = (struct stream_out *)stream;
6757 struct audio_device *adev = out->dev;
6758 int ret = 0;
Aalique Grahame1f123102017-10-12 10:38:32 -07006759 unsigned int offset1 = 0;
6760 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07006761 const char *step = "";
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006762 uint32_t mmap_size;
Arun Mirpuri5d170872019-03-26 13:21:31 -07006763 uint32_t buffer_size;
Haynes Mathew George16081042017-05-31 17:16:49 -07006764
Arun Mirpuri5d170872019-03-26 13:21:31 -07006765 ALOGD("%s", __func__);
Sharad Sanglec6f32552018-05-04 16:15:38 +05306766 lock_output_stream(out);
Haynes Mathew George16081042017-05-31 17:16:49 -07006767 pthread_mutex_lock(&adev->lock);
6768
Sharad Sanglec6f32552018-05-04 16:15:38 +05306769 if (CARD_STATUS_OFFLINE == out->card_status ||
6770 CARD_STATUS_OFFLINE == adev->card_status) {
6771 ALOGW("out->card_status or adev->card_status offline, try again");
6772 ret = -EIO;
6773 goto exit;
6774 }
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05306775 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07006776 ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
6777 ret = -EINVAL;
6778 goto exit;
6779 }
6780 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
6781 ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
6782 ret = -ENOSYS;
6783 goto exit;
6784 }
6785 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
6786 if (out->pcm_device_id < 0) {
6787 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
6788 __func__, out->pcm_device_id, out->usecase);
6789 ret = -EINVAL;
6790 goto exit;
6791 }
6792
6793 adjust_mmap_period_count(&out->config, min_size_frames);
6794
Arun Mirpuri5d170872019-03-26 13:21:31 -07006795 ALOGD("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07006796 __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
6797 out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
6798 (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05306799 if (errno == ENETRESET && !pcm_is_ready(out->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05306800 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
6801 out->card_status = CARD_STATUS_OFFLINE;
6802 adev->card_status = CARD_STATUS_OFFLINE;
6803 ret = -EIO;
6804 goto exit;
6805 }
6806
Haynes Mathew George16081042017-05-31 17:16:49 -07006807 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
6808 step = "open";
6809 ret = -ENODEV;
6810 goto exit;
6811 }
6812 ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
6813 if (ret < 0) {
6814 step = "begin";
6815 goto exit;
6816 }
juyuchen626833d2019-06-04 16:48:02 +08006817
6818 info->flags = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07006819 info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
Arun Mirpuri5d170872019-03-26 13:21:31 -07006820 buffer_size = pcm_frames_to_bytes(out->pcm, info->buffer_size_frames);
Haynes Mathew George16081042017-05-31 17:16:49 -07006821 info->burst_size_frames = out->config.period_size;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006822 ret = platform_get_mmap_data_fd(adev->platform,
6823 out->pcm_device_id, 0 /*playback*/,
6824 &info->shared_memory_fd,
6825 &mmap_size);
6826 if (ret < 0) {
Arun Mirpuri5d170872019-03-26 13:21:31 -07006827 // Fall back to non exclusive mode
6828 info->shared_memory_fd = pcm_get_poll_fd(out->pcm);
6829 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07006830 out->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
6831 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, out->mmap_shared_memory_fd);
6832
Arun Mirpuri5d170872019-03-26 13:21:31 -07006833 if (mmap_size < buffer_size) {
6834 step = "mmap";
6835 goto exit;
6836 }
juyuchen626833d2019-06-04 16:48:02 +08006837 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006838 }
Haynes Mathew George16081042017-05-31 17:16:49 -07006839 memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
Haynes Mathew Georgeef514882017-05-01 17:46:23 -07006840 info->buffer_size_frames));
Haynes Mathew George16081042017-05-31 17:16:49 -07006841
6842 ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
6843 if (ret < 0) {
6844 step = "commit";
6845 goto exit;
6846 }
6847
Phil Burkfe17efd2019-03-25 10:23:35 -07006848 out->mmap_time_offset_nanos = get_mmap_out_time_offset();
6849
Haynes Mathew George16081042017-05-31 17:16:49 -07006850 out->standby = false;
6851 ret = 0;
6852
Arun Mirpuri5d170872019-03-26 13:21:31 -07006853 ALOGD("%s: got mmap buffer address %p info->buffer_size_frames %d",
Haynes Mathew George16081042017-05-31 17:16:49 -07006854 __func__, info->shared_memory_address, info->buffer_size_frames);
6855
6856exit:
6857 if (ret != 0) {
6858 if (out->pcm == NULL) {
6859 ALOGE("%s: %s - %d", __func__, step, ret);
6860 } else {
6861 ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
6862 pcm_close(out->pcm);
6863 out->pcm = NULL;
6864 }
6865 }
6866 pthread_mutex_unlock(&adev->lock);
Sharad Sanglec6f32552018-05-04 16:15:38 +05306867 pthread_mutex_unlock(&out->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07006868 return ret;
6869}
6870
6871static int out_get_mmap_position(const struct audio_stream_out *stream,
6872 struct audio_mmap_position *position)
6873{
6874 struct stream_out *out = (struct stream_out *)stream;
6875 ALOGVV("%s", __func__);
6876 if (position == NULL) {
6877 return -EINVAL;
6878 }
6879 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
Haynes Mathew George4ab3ba92017-12-11 14:49:43 -08006880 ALOGE("%s: called on %s", __func__, use_case_table[out->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07006881 return -ENOSYS;
6882 }
6883 if (out->pcm == NULL) {
6884 return -ENOSYS;
6885 }
6886
6887 struct timespec ts = { 0, 0 };
6888 int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
6889 if (ret < 0) {
6890 ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
6891 return ret;
6892 }
Phil Burkfe17efd2019-03-25 10:23:35 -07006893 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
6894 + out->mmap_time_offset_nanos;
Haynes Mathew George16081042017-05-31 17:16:49 -07006895 return 0;
6896}
6897
6898
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006899/** audio_stream_in implementation **/
6900static uint32_t in_get_sample_rate(const struct audio_stream *stream)
6901{
6902 struct stream_in *in = (struct stream_in *)stream;
6903
6904 return in->config.rate;
6905}
6906
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006907static int in_set_sample_rate(struct audio_stream *stream __unused,
6908 uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006909{
6910 return -ENOSYS;
6911}
6912
6913static size_t in_get_buffer_size(const struct audio_stream *stream)
6914{
6915 struct stream_in *in = (struct stream_in *)stream;
6916
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006917 if(in->usecase == USECASE_COMPRESS_VOIP_CALL)
6918 return voice_extn_compress_voip_in_get_buffer_size(in);
Mingming Yine62d7842013-10-25 16:26:03 -07006919 else if(audio_extn_compr_cap_usecase_supported(in->usecase))
6920 return audio_extn_compr_cap_get_buffer_size(in->config.format);
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05306921 else if(audio_extn_cin_attached_usecase(in))
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05306922 return audio_extn_cin_get_buffer_size(in);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006923
Haynes Mathew George5beddd42016-06-27 18:33:40 -07006924 return in->config.period_size * in->af_period_multiplier *
6925 audio_stream_in_frame_size((const struct audio_stream_in *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006926}
6927
6928static uint32_t in_get_channels(const struct audio_stream *stream)
6929{
6930 struct stream_in *in = (struct stream_in *)stream;
6931
6932 return in->channel_mask;
6933}
6934
6935static audio_format_t in_get_format(const struct audio_stream *stream)
6936{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08006937 struct stream_in *in = (struct stream_in *)stream;
6938
6939 return in->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006940}
6941
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07006942static int in_set_format(struct audio_stream *stream __unused,
6943 audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006944{
6945 return -ENOSYS;
6946}
6947
6948static int in_standby(struct audio_stream *stream)
6949{
6950 struct stream_in *in = (struct stream_in *)stream;
6951 struct audio_device *adev = in->dev;
6952 int status = 0;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05306953 ALOGD("%s: enter: stream (%p) usecase(%d: %s)", __func__,
6954 stream, in->usecase, use_case_table[in->usecase]);
Haynes Mathew George16081042017-05-31 17:16:49 -07006955 bool do_stop = true;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05306956
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07006957 lock_input_stream(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07006958 if (!in->standby && in->is_st_session) {
6959 ALOGD("%s: sound trigger pcm stop lab", __func__);
6960 audio_extn_sound_trigger_stop_lab(in);
George Gao3018ede2019-10-23 13:23:00 -07006961 if (adev->num_va_sessions > 0)
6962 adev->num_va_sessions--;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07006963 in->standby = 1;
6964 }
6965
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006966 if (!in->standby) {
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07006967 if (adev->adm_deregister_stream)
6968 adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
6969
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08006970 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08006971 in->standby = true;
Zhou Songa8895042016-07-05 17:54:22 +08006972 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
kunleizbecba2d2017-09-07 13:37:16 +08006973 do_stop = false;
Zhou Songa8895042016-07-05 17:54:22 +08006974 voice_extn_compress_voip_close_input_stream(stream);
6975 ALOGD("VOIP input entered standby");
Haynes Mathew George16081042017-05-31 17:16:49 -07006976 } else if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
6977 do_stop = in->capture_started;
6978 in->capture_started = false;
Phil Burkd898ba62019-06-20 12:49:01 -07006979 if (in->mmap_shared_memory_fd >= 0) {
6980 ALOGV("%s: closing mmap_shared_memory_fd = %d",
6981 __func__, in->mmap_shared_memory_fd);
6982 close(in->mmap_shared_memory_fd);
6983 in->mmap_shared_memory_fd = -1;
6984 }
Zhou Songa8895042016-07-05 17:54:22 +08006985 } else {
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05306986 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +05306987 audio_extn_cin_close_input_stream(in);
kunleizbecba2d2017-09-07 13:37:16 +08006988 }
6989
Arun Mirpuri5d170872019-03-26 13:21:31 -07006990 if (in->pcm) {
6991 ATRACE_BEGIN("pcm_in_close");
6992 pcm_close(in->pcm);
6993 ATRACE_END();
6994 in->pcm = NULL;
6995 }
6996
Carter Hsu2e429db2019-05-14 18:50:52 +08006997 if (do_stop)
Zhou Songa8895042016-07-05 17:54:22 +08006998 status = stop_input_stream(in);
Quinn Malef6050362019-01-30 15:55:40 -08006999
George Gao3018ede2019-10-23 13:23:00 -07007000 if (in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7001 if (adev->num_va_sessions > 0)
7002 adev->num_va_sessions--;
7003 }
Quinn Malef6050362019-01-30 15:55:40 -08007004
Eric Laurent150dbfe2013-02-27 14:31:02 -08007005 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007006 }
7007 pthread_mutex_unlock(&in->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07007008 ALOGV("%s: exit: status(%d)", __func__, status);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007009 return status;
7010}
7011
Aalique Grahame22e49102018-12-18 14:23:57 -08007012static int in_dump(const struct audio_stream *stream,
7013 int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007014{
Aalique Grahame22e49102018-12-18 14:23:57 -08007015 struct stream_in *in = (struct stream_in *)stream;
7016
7017 // We try to get the lock for consistency,
7018 // but it isn't necessary for these variables.
7019 // If we're not in standby, we may be blocked on a read.
7020 const bool locked = (pthread_mutex_trylock(&in->lock) == 0);
7021 dprintf(fd, " Standby: %s\n", in->standby ? "yes" : "no");
7022 dprintf(fd, " Frames read: %lld\n", (long long)in->frames_read);
7023 dprintf(fd, " Frames muted: %lld\n", (long long)in->frames_muted);
Dechen Chai22768452021-07-30 09:29:16 +05307024#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007025 char buffer[256]; // for statistics formatting
7026 if (in->start_latency_ms.n > 0) {
7027 simple_stats_to_string(&in->start_latency_ms, buffer, sizeof(buffer));
7028 dprintf(fd, " Start latency ms: %s\n", buffer);
7029 }
Dechen Chai22768452021-07-30 09:29:16 +05307030#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08007031 if (locked) {
7032 pthread_mutex_unlock(&in->lock);
7033 }
Dechen Chai22768452021-07-30 09:29:16 +05307034#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08007035 // dump error info
7036 (void)error_log_dump(
7037 in->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Dechen Chai22768452021-07-30 09:29:16 +05307038#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007039 return 0;
7040}
7041
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307042static void in_snd_mon_cb(void * stream, struct str_parms * parms)
7043{
7044 if (!stream || !parms)
7045 return;
7046
7047 struct stream_in *in = (struct stream_in *)stream;
7048 struct audio_device *adev = in->dev;
7049
7050 card_status_t status;
7051 int card;
7052 if (parse_snd_card_status(parms, &card, &status) < 0)
7053 return;
7054
7055 pthread_mutex_lock(&adev->lock);
7056 bool valid_cb = (card == adev->snd_card);
7057 pthread_mutex_unlock(&adev->lock);
7058
7059 if (!valid_cb)
7060 return;
7061
7062 lock_input_stream(in);
7063 if (in->card_status != status)
7064 in->card_status = status;
7065 pthread_mutex_unlock(&in->lock);
7066
7067 ALOGW("in_snd_mon_cb for card %d usecase %s, status %s", card,
7068 use_case_table[in->usecase],
7069 status == CARD_STATUS_OFFLINE ? "offline" : "online");
7070
7071 // a better solution would be to report error back to AF and let
7072 // it put the stream to standby
7073 if (status == CARD_STATUS_OFFLINE)
7074 in_standby(&in->stream.common);
7075
7076 return;
7077}
7078
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007079int route_input_stream(struct stream_in *in,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007080 struct listnode *devices,
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007081 audio_source_t source)
7082{
7083 struct audio_device *adev = in->dev;
7084 int ret = 0;
7085
7086 lock_input_stream(in);
7087 pthread_mutex_lock(&adev->lock);
7088
7089 /* no audio source uses val == 0 */
7090 if ((in->source != source) && (source != AUDIO_SOURCE_DEFAULT)) {
7091 in->source = source;
7092 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) &&
7093 (in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
7094 (voice_extn_compress_voip_is_format_supported(in->format)) &&
7095 (in->config.rate == 8000 || in->config.rate == 16000 ||
7096 in->config.rate == 32000 || in->config.rate == 48000 ) &&
7097 (audio_channel_count_from_in_mask(in->channel_mask) == 1)) {
7098 ret = voice_extn_compress_voip_open_input_stream(in);
7099 if (ret != 0) {
7100 ALOGE("%s: Compress voip input cannot be opened, error:%d",
7101 __func__, ret);
7102 }
7103 }
7104 }
7105
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007106 if (!compare_devices(&in->device_list, devices) && !list_empty(devices) &&
7107 is_audio_in_device_type(devices)) {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007108 // Workaround: If routing to an non existing usb device, fail gracefully
7109 // The routing request will otherwise block during 10 second
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007110 struct str_parms *usb_addr =
7111 str_parms_create_str(get_usb_device_address(devices));
7112 if (is_usb_in_device_type(devices) && usb_addr &&
Weiyin Jiangabedea32020-12-09 12:49:19 +08007113 !audio_extn_usb_connected(NULL)) {
7114 ALOGW("%s: ignoring rerouting to non existing USB", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007115 ret = -ENOSYS;
7116 } else {
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007117 /* If recording is in progress, change the tx device to new device */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007118 assign_devices(&in->device_list, devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007119 if (!in->standby && !in->is_st_session) {
7120 ALOGV("update input routing change");
7121 // inform adm before actual routing to prevent glitches.
7122 if (adev->adm_on_routing_change) {
7123 adev->adm_on_routing_change(adev->adm_data,
7124 in->capture_handle);
7125 ret = select_devices(adev, in->usecase);
7126 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7127 adev->adm_routing_changed = true;
7128 }
7129 }
7130 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007131 if (usb_addr)
7132 str_parms_destroy(usb_addr);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007133 }
7134 pthread_mutex_unlock(&adev->lock);
7135 pthread_mutex_unlock(&in->lock);
7136
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07007137 ALOGV("%s: exit: status(%d)", __func__, ret);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07007138 return ret;
7139}
7140
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007141static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
7142{
7143 struct stream_in *in = (struct stream_in *)stream;
7144 struct audio_device *adev = in->dev;
7145 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007146 char value[32];
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307147 int err = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007148
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307149 ALOGD("%s: enter: kvpairs=%s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007150 parms = str_parms_create_str(kvpairs);
7151
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307152 if (!parms)
7153 goto error;
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007154 lock_input_stream(in);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007155 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08007156
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307157 err = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_PROFILE, value, sizeof(value));
7158 if (err >= 0) {
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307159 strlcpy(in->profile, value, sizeof(in->profile));
7160 ALOGV("updating stream profile with value '%s'", in->profile);
7161 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
7162 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007163 &in->device_list, in->flags, in->format,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05307164 in->sample_rate, in->bit_width,
7165 in->profile, &in->app_type_cfg);
7166 }
7167
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007168 pthread_mutex_unlock(&adev->lock);
Eric Laurent150dbfe2013-02-27 14:31:02 -08007169 pthread_mutex_unlock(&in->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007170
7171 str_parms_destroy(parms);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05307172error:
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307173 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007174}
7175
7176static char* in_get_parameters(const struct audio_stream *stream,
7177 const char *keys)
7178{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007179 struct stream_in *in = (struct stream_in *)stream;
7180 struct str_parms *query = str_parms_create_str(keys);
7181 char *str;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007182 struct str_parms *reply = str_parms_create();
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007183
7184 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08007185 if (reply) {
7186 str_parms_destroy(reply);
7187 }
7188 if (query) {
7189 str_parms_destroy(query);
7190 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07007191 ALOGE("in_get_parameters: failed to create query or reply");
7192 return NULL;
7193 }
7194
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007195 ALOGV("%s: enter: keys - %s %s ", __func__, use_case_table[in->usecase], keys);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007196
7197 voice_extn_in_get_parameters(in, query, reply);
7198
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007199 stream_get_parameter_channels(query, reply,
7200 &in->supported_channel_masks[0]);
7201 stream_get_parameter_formats(query, reply,
7202 &in->supported_formats[0]);
7203 stream_get_parameter_rates(query, reply,
7204 &in->supported_sample_rates[0]);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08007205 str = str_parms_to_str(reply);
7206 str_parms_destroy(query);
7207 str_parms_destroy(reply);
7208
7209 ALOGV("%s: exit: returns - %s", __func__, str);
7210 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007211}
7212
Aalique Grahame22e49102018-12-18 14:23:57 -08007213static int in_set_gain(struct audio_stream_in *stream,
7214 float gain)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007215{
Aalique Grahame22e49102018-12-18 14:23:57 -08007216 struct stream_in *in = (struct stream_in *)stream;
7217 char mixer_ctl_name[128];
7218 struct mixer_ctl *ctl;
7219 int ctl_value;
7220
7221 ALOGV("%s: gain %f", __func__, gain);
7222
7223 if (stream == NULL)
7224 return -EINVAL;
7225
7226 /* in_set_gain() only used to silence MMAP capture for now */
7227 if (in->usecase != USECASE_AUDIO_RECORD_MMAP)
7228 return -ENOSYS;
7229
7230 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name), "Capture %d Volume", in->pcm_device_id);
7231
7232 ctl = mixer_get_ctl_by_name(in->dev->mixer, mixer_ctl_name);
7233 if (!ctl) {
7234 ALOGW("%s: Could not get ctl for mixer cmd - %s",
7235 __func__, mixer_ctl_name);
7236 return -ENOSYS;
7237 }
7238
7239 if (gain < RECORD_GAIN_MIN)
7240 gain = RECORD_GAIN_MIN;
7241 else if (gain > RECORD_GAIN_MAX)
7242 gain = RECORD_GAIN_MAX;
7243 ctl_value = (int)(RECORD_VOLUME_CTL_MAX * gain);
7244
7245 mixer_ctl_set_value(ctl, 0, ctl_value);
7246
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007247 return 0;
7248}
7249
7250static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
7251 size_t bytes)
7252{
7253 struct stream_in *in = (struct stream_in *)stream;
Pallavid7c7a272018-01-16 11:22:55 +05307254
7255 if (in == NULL) {
7256 ALOGE("%s: stream_in ptr is NULL", __func__);
7257 return -EINVAL;
7258 }
7259
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007260 struct audio_device *adev = in->dev;
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05307261 int ret = -1;
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307262 size_t bytes_read = 0, frame_size = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007263
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007264 lock_input_stream(in);
Naresh Tanniru4c630392014-05-12 01:05:52 +05307265
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007266 if (in->is_st_session) {
7267 ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
7268 /* Read from sound trigger HAL */
7269 audio_extn_sound_trigger_read(in, buffer, bytes);
Quinn Malef6050362019-01-30 15:55:40 -08007270 if (in->standby) {
George Gao3018ede2019-10-23 13:23:00 -07007271 if (adev->num_va_sessions < UINT_MAX)
7272 adev->num_va_sessions++;
Quinn Malef6050362019-01-30 15:55:40 -08007273 in->standby = 0;
7274 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007275 pthread_mutex_unlock(&in->lock);
7276 return bytes;
7277 }
7278
Haynes Mathew George16081042017-05-31 17:16:49 -07007279 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
7280 ret = -ENOSYS;
7281 goto exit;
7282 }
7283
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007284 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY &&
7285 !in->standby && adev->adm_routing_changed) {
7286 ret = -ENOSYS;
7287 goto exit;
7288 }
7289
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007290 if (in->standby) {
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007291 const int64_t startNs = systemTime(SYSTEM_TIME_MONOTONIC);
7292
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007293 pthread_mutex_lock(&adev->lock);
7294 if (in->usecase == USECASE_COMPRESS_VOIP_CALL)
7295 ret = voice_extn_compress_voip_start_input_stream(in);
7296 else
7297 ret = start_input_stream(in);
George Gao3018ede2019-10-23 13:23:00 -07007298 if (!ret && in->source == AUDIO_SOURCE_VOICE_RECOGNITION) {
7299 if (adev->num_va_sessions < UINT_MAX)
7300 adev->num_va_sessions++;
7301 }
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007302 pthread_mutex_unlock(&adev->lock);
7303 if (ret != 0) {
7304 goto exit;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007305 }
7306 in->standby = 0;
Dechen Chai22768452021-07-30 09:29:16 +05307307#ifndef LINUX_ENABLED
Andy Hungc6bfd4a2019-07-01 18:26:00 -07007308 // log startup time in ms.
7309 simple_stats_log(
7310 &in->start_latency_ms, (systemTime(SYSTEM_TIME_MONOTONIC) - startNs) * 1e-6);
Dechen Chai22768452021-07-30 09:29:16 +05307311#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007312 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007313
Deeraj Soman30cc7ae2019-03-18 16:26:55 +05307314 /* Avoid read if capture_stopped is set */
7315 if (android_atomic_acquire_load(&(in->capture_stopped)) > 0) {
7316 ALOGD("%s: force stopped catpure session, ignoring read request", __func__);
7317 ret = -EINVAL;
7318 goto exit;
7319 }
7320
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007321 // what's the duration requested by the client?
7322 long ns = 0;
7323
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307324 if (in->pcm && in->config.rate)
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007325 ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
7326 in->config.rate;
7327
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007328 ret = request_in_focus(in, ns);
7329 if (ret != 0)
7330 goto exit;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007331 bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007332
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307333 if (audio_extn_cin_attached_usecase(in)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307334 ret = audio_extn_cin_read(in, buffer, bytes, &bytes_read);
7335 } else if (in->pcm) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307336 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007337 ret = audio_extn_ssr_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307338 } else if (audio_extn_compr_cap_usecase_supported(in->usecase)) {
Mingming Yine62d7842013-10-25 16:26:03 -07007339 ret = audio_extn_compr_cap_read(in, buffer, bytes);
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007340 } else if (use_mmap) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07007341 ret = pcm_mmap_read(in->pcm, buffer, bytes);
Garmond Leunge2433c32017-09-28 21:51:22 -07007342 } else if (audio_extn_ffv_get_stream() == in) {
7343 ret = audio_extn_ffv_read(stream, buffer, bytes);
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307344 } else {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07007345 ret = pcm_read(in->pcm, buffer, bytes);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307346 /* data from DSP comes in 24_8 format, convert it to 8_24 */
7347 if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
7348 if (audio_extn_utils_convert_format_24_8_to_8_24(buffer, bytes)
7349 != bytes) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307350 ret = -EINVAL;
7351 goto exit;
7352 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307353 } else if (ret < 0) {
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05307354 ret = -errno;
7355 }
7356 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307357 /* bytes read is always set to bytes for non compress usecases */
7358 bytes_read = bytes;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007359 }
7360
Haynes Mathew George5beddd42016-06-27 18:33:40 -07007361 release_in_focus(in);
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07007362
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007363 /*
Quinn Malef6050362019-01-30 15:55:40 -08007364 * Instead of writing zeroes here, we could trust the hardware to always
7365 * provide zeroes when muted. This is also muted with voice recognition
7366 * usecases so that other clients do not have access to voice recognition
7367 * data.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007368 */
Quinn Malef6050362019-01-30 15:55:40 -08007369 if ((ret == 0 && voice_get_mic_mute(adev) &&
7370 !voice_is_in_call_rec_stream(in) &&
Zhou Song62ea0282020-03-22 19:53:01 +08007371 (in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY &&
7372 in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY2)) ||
Quinn Malef6050362019-01-30 15:55:40 -08007373 (adev->num_va_sessions &&
7374 in->source != AUDIO_SOURCE_VOICE_RECOGNITION &&
7375 property_get_bool("persist.vendor.audio.va_concurrency_mute_enabled",
7376 false)))
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007377 memset(buffer, 0, bytes);
7378
7379exit:
Dhananjay Kumar97b81e32019-05-15 21:00:21 +05307380 frame_size = audio_stream_in_frame_size(stream);
7381 if (frame_size > 0)
7382 in->frames_read += bytes_read/frame_size;
7383
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07007384 if (-ENETRESET == ret)
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05307385 in->card_status = CARD_STATUS_OFFLINE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007386 pthread_mutex_unlock(&in->lock);
7387
7388 if (ret != 0) {
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307389 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307390 pthread_mutex_lock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307391 voice_extn_compress_voip_close_input_stream(&in->stream.common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05307392 pthread_mutex_unlock(&adev->lock);
Venkata Narendra Kumar Guttabc9c9ca2014-06-25 20:38:03 +05307393 in->standby = true;
7394 }
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05307395 if (!audio_extn_cin_attached_usecase(in)) {
Sharad Sangled17c9122017-03-20 15:58:52 +05307396 bytes_read = bytes;
7397 memset(buffer, 0, bytes);
7398 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007399 in_standby(&in->stream.common);
Aniket Kumar Lata60586a92019-05-22 22:18:55 -07007400 if (in->usecase == USECASE_AUDIO_RECORD_LOW_LATENCY)
7401 adev->adm_routing_changed = false;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07007402 ALOGV("%s: read failed status %d- sleeping for buffer duration", __func__, ret);
Ashish Jainbbce4322016-02-16 13:25:27 +05307403 usleep((uint64_t)bytes * 1000000 / audio_stream_in_frame_size(stream) /
Naresh Tanniru4c630392014-05-12 01:05:52 +05307404 in_get_sample_rate(&in->stream.common));
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007405 }
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05307406 return bytes_read;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007407}
7408
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07007409static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007410{
7411 return 0;
7412}
7413
Aalique Grahame22e49102018-12-18 14:23:57 -08007414static int in_get_capture_position(const struct audio_stream_in *stream,
7415 int64_t *frames, int64_t *time)
7416{
7417 if (stream == NULL || frames == NULL || time == NULL) {
7418 return -EINVAL;
7419 }
7420 struct stream_in *in = (struct stream_in *)stream;
7421 int ret = -ENOSYS;
7422
7423 lock_input_stream(in);
7424 // note: ST sessions do not close the alsa pcm driver synchronously
7425 // on standby. Therefore, we may return an error even though the
7426 // pcm stream is still opened.
7427 if (in->standby) {
7428 ALOGE_IF(in->pcm != NULL && !in->is_st_session,
7429 "%s stream in standby but pcm not NULL for non ST session", __func__);
7430 goto exit;
7431 }
7432 if (in->pcm) {
7433 struct timespec timestamp;
7434 unsigned int avail;
7435 if (pcm_get_htimestamp(in->pcm, &avail, &timestamp) == 0) {
7436 *frames = in->frames_read + avail;
Robert Lee58215542019-07-15 20:55:12 +08007437 *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec
George Gao9ba8a142020-07-23 14:30:03 -07007438 - platform_capture_latency(in) * 1000LL;
Kakanaboina Ramanjaneyulu8cedb092021-03-15 15:55:29 +05307439 //Adjustment accounts for A2dp decoder latency for recording usecase
7440 // Note: decoder latency is returned in ms, while platform_capture_latency in ns.
7441 if (is_a2dp_in_device_type(&in->device_list))
7442 *time -= audio_extn_a2dp_get_decoder_latency() * 1000000LL;
Aalique Grahame22e49102018-12-18 14:23:57 -08007443 ret = 0;
7444 }
7445 }
7446exit:
7447 pthread_mutex_unlock(&in->lock);
7448 return ret;
7449}
7450
Carter Hsu2e429db2019-05-14 18:50:52 +08007451static int in_update_effect_list(bool add, effect_handle_t effect,
7452 struct listnode *head)
7453{
7454 struct listnode *node;
7455 struct in_effect_list *elist = NULL;
7456 struct in_effect_list *target = NULL;
7457 int ret = 0;
7458
7459 if (!head)
7460 return ret;
7461
7462 list_for_each(node, head) {
7463 elist = node_to_item(node, struct in_effect_list, list);
7464 if (elist->handle == effect) {
7465 target = elist;
7466 break;
7467 }
7468 }
7469
7470 if (add) {
7471 if (target) {
7472 ALOGD("effect %p already exist", effect);
7473 return ret;
7474 }
7475
7476 target = (struct in_effect_list *)
7477 calloc(1, sizeof(struct in_effect_list));
7478
7479 if (!target) {
7480 ALOGE("%s:fail to allocate memory", __func__);
7481 return -ENOMEM;
7482 }
7483
7484 target->handle = effect;
7485 list_add_tail(head, &target->list);
7486 } else {
7487 if (target) {
7488 list_remove(&target->list);
7489 free(target);
7490 }
7491 }
7492
7493 return ret;
7494}
7495
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007496static int add_remove_audio_effect(const struct audio_stream *stream,
7497 effect_handle_t effect,
7498 bool enable)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007499{
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007500 struct stream_in *in = (struct stream_in *)stream;
7501 int status = 0;
7502 effect_descriptor_t desc;
7503
7504 status = (*effect)->get_descriptor(effect, &desc);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007505 ALOGV("%s: status %d in->standby %d enable:%d", __func__, status, in->standby, enable);
7506
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007507 if (status != 0)
7508 return status;
7509
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007510 lock_input_stream(in);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007511 pthread_mutex_lock(&in->dev->lock);
kunleizd96526c2018-04-09 11:12:32 +08007512 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Carter Hsu2e429db2019-05-14 18:50:52 +08007513 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
7514 adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007515 (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
Carter Hsu2e429db2019-05-14 18:50:52 +08007516
7517 in_update_effect_list(enable, effect, &in->aec_list);
7518 enable = !list_empty(&in->aec_list);
7519 if (enable == in->enable_aec)
7520 goto exit;
7521
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007522 in->enable_aec = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007523 ALOGD("AEC enable %d", enable);
7524
Aalique Grahame22e49102018-12-18 14:23:57 -08007525 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
7526 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
7527 in->dev->enable_voicerx = enable;
7528 struct audio_usecase *usecase;
7529 struct listnode *node;
7530 list_for_each(node, &in->dev->usecase_list) {
7531 usecase = node_to_item(node, struct audio_usecase, list);
7532 if (usecase->type == PCM_PLAYBACK)
7533 select_devices(in->dev, usecase->id);
7534 }
7535 }
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007536 if (!in->standby) {
7537 if (enable_disable_effect(in->dev, EFFECT_AEC, enable) == ENOSYS)
7538 select_devices(in->dev, in->usecase);
7539 }
7540
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007541 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007542 if (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0) {
7543
7544 in_update_effect_list(enable, effect, &in->ns_list);
7545 enable = !list_empty(&in->ns_list);
7546 if (enable == in->enable_ns)
7547 goto exit;
7548
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007549 in->enable_ns = enable;
Carter Hsu2e429db2019-05-14 18:50:52 +08007550 ALOGD("NS enable %d", enable);
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007551 if (!in->standby) {
kunleizd96526c2018-04-09 11:12:32 +08007552 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Ramu Gottipatifa5be522021-12-28 19:18:21 +05307553 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
kunleizd96526c2018-04-09 11:12:32 +08007554 in->dev->mode == AUDIO_MODE_IN_COMMUNICATION) {
Vikram Pandurangadf59cae2017-08-03 18:04:55 -07007555 if (enable_disable_effect(in->dev, EFFECT_NS, enable) == ENOSYS)
7556 select_devices(in->dev, in->usecase);
7557 } else
7558 select_devices(in->dev, in->usecase);
7559 }
Ravi Kumar Alamanda198185e2013-11-07 15:42:19 -08007560 }
Carter Hsu2e429db2019-05-14 18:50:52 +08007561exit:
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007562 pthread_mutex_unlock(&in->dev->lock);
7563 pthread_mutex_unlock(&in->lock);
7564
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007565 return 0;
7566}
7567
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007568static int in_add_audio_effect(const struct audio_stream *stream,
7569 effect_handle_t effect)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007570{
Eric Laurent994a6932013-07-17 11:51:42 -07007571 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007572 return add_remove_audio_effect(stream, effect, true);
7573}
7574
7575static int in_remove_audio_effect(const struct audio_stream *stream,
7576 effect_handle_t effect)
7577{
Eric Laurent994a6932013-07-17 11:51:42 -07007578 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07007579 return add_remove_audio_effect(stream, effect, false);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007580}
7581
Haynes Mathew George16081042017-05-31 17:16:49 -07007582static int in_stop(const struct audio_stream_in* stream)
7583{
7584 struct stream_in *in = (struct stream_in *)stream;
7585 struct audio_device *adev = in->dev;
7586
7587 int ret = -ENOSYS;
7588 ALOGV("%s", __func__);
7589 pthread_mutex_lock(&adev->lock);
7590 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7591 in->capture_started && in->pcm != NULL) {
7592 pcm_stop(in->pcm);
7593 ret = stop_input_stream(in);
7594 in->capture_started = false;
7595 }
7596 pthread_mutex_unlock(&adev->lock);
7597 return ret;
7598}
7599
7600static int in_start(const struct audio_stream_in* stream)
7601{
7602 struct stream_in *in = (struct stream_in *)stream;
7603 struct audio_device *adev = in->dev;
7604 int ret = -ENOSYS;
7605
7606 ALOGV("%s in %p", __func__, in);
7607 pthread_mutex_lock(&adev->lock);
7608 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
7609 !in->capture_started && in->pcm != NULL) {
7610 if (!in->capture_started) {
7611 ret = start_input_stream(in);
7612 if (ret == 0) {
7613 in->capture_started = true;
7614 }
7615 }
7616 }
7617 pthread_mutex_unlock(&adev->lock);
7618 return ret;
7619}
7620
Phil Burke0a86d12019-02-16 22:28:11 -08007621// Read offset for the positional timestamp from a persistent vendor property.
7622// This is to workaround apparent inaccuracies in the timing information that
7623// is used by the AAudio timing model. The inaccuracies can cause glitches.
7624static int64_t in_get_mmap_time_offset() {
7625 const int32_t kDefaultOffsetMicros = 0;
7626 int32_t mmap_time_offset_micros = property_get_int32(
Weiyin Jiangbd68b4d2019-05-17 16:29:50 +08007627 "persist.vendor.audio.in_mmap_delay_micros", kDefaultOffsetMicros);
Phil Burke0a86d12019-02-16 22:28:11 -08007628 ALOGI("mmap_time_offset_micros = %d for input", mmap_time_offset_micros);
7629 return mmap_time_offset_micros * (int64_t)1000;
7630}
7631
Haynes Mathew George16081042017-05-31 17:16:49 -07007632static int in_create_mmap_buffer(const struct audio_stream_in *stream,
7633 int32_t min_size_frames,
7634 struct audio_mmap_buffer_info *info)
7635{
7636 struct stream_in *in = (struct stream_in *)stream;
7637 struct audio_device *adev = in->dev;
7638 int ret = 0;
Aniket Kumar Lataf9f246e2017-09-15 15:20:16 -07007639 unsigned int offset1 = 0;
7640 unsigned int frames1 = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007641 const char *step = "";
Arun Mirpuri5d170872019-03-26 13:21:31 -07007642 uint32_t mmap_size = 0;
7643 uint32_t buffer_size = 0;
Haynes Mathew George16081042017-05-31 17:16:49 -07007644
7645 pthread_mutex_lock(&adev->lock);
7646 ALOGV("%s in %p", __func__, in);
7647
Sharad Sanglec6f32552018-05-04 16:15:38 +05307648 if (CARD_STATUS_OFFLINE == in->card_status||
7649 CARD_STATUS_OFFLINE == adev->card_status) {
7650 ALOGW("in->card_status or adev->card_status offline, try again");
7651 ret = -EIO;
7652 goto exit;
7653 }
7654
Sujin Panicker7c7b6f92020-04-03 12:57:55 +05307655 if (info == NULL || !(min_size_frames > 0 && min_size_frames < INT32_MAX)) {
Haynes Mathew George16081042017-05-31 17:16:49 -07007656 ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
7657 ret = -EINVAL;
7658 goto exit;
7659 }
7660 if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
7661 ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
7662 ALOGV("%s in %p", __func__, in);
7663 ret = -ENOSYS;
7664 goto exit;
7665 }
7666 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
7667 if (in->pcm_device_id < 0) {
7668 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
7669 __func__, in->pcm_device_id, in->usecase);
7670 ret = -EINVAL;
7671 goto exit;
7672 }
7673
7674 adjust_mmap_period_count(&in->config, min_size_frames);
7675
7676 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
7677 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
7678 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
7679 (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
Satish Babu Patakokila54ce83d2018-07-06 18:00:37 +05307680 if (errno == ENETRESET && !pcm_is_ready(in->pcm)) {
Sharad Sanglec6f32552018-05-04 16:15:38 +05307681 ALOGE("%s: pcm_open failed errno:%d\n", __func__, errno);
7682 in->card_status = CARD_STATUS_OFFLINE;
7683 adev->card_status = CARD_STATUS_OFFLINE;
7684 ret = -EIO;
7685 goto exit;
7686 }
7687
Haynes Mathew George16081042017-05-31 17:16:49 -07007688 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
7689 step = "open";
7690 ret = -ENODEV;
7691 goto exit;
7692 }
7693
7694 ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
7695 if (ret < 0) {
7696 step = "begin";
7697 goto exit;
7698 }
Haynes Mathew George16081042017-05-31 17:16:49 -07007699
juyuchen626833d2019-06-04 16:48:02 +08007700 info->flags = 0;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007701 info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
7702 buffer_size = pcm_frames_to_bytes(in->pcm, info->buffer_size_frames);
7703 info->burst_size_frames = in->config.period_size;
7704 ret = platform_get_mmap_data_fd(adev->platform,
7705 in->pcm_device_id, 1 /*capture*/,
7706 &info->shared_memory_fd,
7707 &mmap_size);
7708 if (ret < 0) {
7709 // Fall back to non exclusive mode
7710 info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
7711 } else {
Phil Burkd898ba62019-06-20 12:49:01 -07007712 in->mmap_shared_memory_fd = info->shared_memory_fd; // for closing later
7713 ALOGV("%s: opened mmap_shared_memory_fd = %d", __func__, in->mmap_shared_memory_fd);
7714
Arun Mirpuri5d170872019-03-26 13:21:31 -07007715 if (mmap_size < buffer_size) {
7716 step = "mmap";
7717 goto exit;
7718 }
juyuchen626833d2019-06-04 16:48:02 +08007719 info->flags |= AUDIO_MMAP_APPLICATION_SHAREABLE;
Arun Mirpuri5d170872019-03-26 13:21:31 -07007720 }
7721
7722 memset(info->shared_memory_address, 0, buffer_size);
Haynes Mathew George16081042017-05-31 17:16:49 -07007723
7724 ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
7725 if (ret < 0) {
7726 step = "commit";
7727 goto exit;
7728 }
7729
Phil Burke0a86d12019-02-16 22:28:11 -08007730 in->mmap_time_offset_nanos = in_get_mmap_time_offset();
7731
Haynes Mathew George16081042017-05-31 17:16:49 -07007732 in->standby = false;
7733 ret = 0;
7734
7735 ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
7736 __func__, info->shared_memory_address, info->buffer_size_frames);
7737
7738exit:
7739 if (ret != 0) {
7740 if (in->pcm == NULL) {
7741 ALOGE("%s: %s - %d", __func__, step, ret);
7742 } else {
7743 ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
7744 pcm_close(in->pcm);
7745 in->pcm = NULL;
7746 }
7747 }
7748 pthread_mutex_unlock(&adev->lock);
7749 return ret;
7750}
7751
7752static int in_get_mmap_position(const struct audio_stream_in *stream,
7753 struct audio_mmap_position *position)
7754{
7755 struct stream_in *in = (struct stream_in *)stream;
7756 ALOGVV("%s", __func__);
7757 if (position == NULL) {
7758 return -EINVAL;
7759 }
Gautam Manam34d1f542021-01-05 20:24:37 +05307760 lock_input_stream(in);
Haynes Mathew George16081042017-05-31 17:16:49 -07007761 if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
Gautam Manam34d1f542021-01-05 20:24:37 +05307762 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007763 return -ENOSYS;
7764 }
7765 if (in->pcm == NULL) {
Gautam Manam34d1f542021-01-05 20:24:37 +05307766 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007767 return -ENOSYS;
7768 }
7769 struct timespec ts = { 0, 0 };
7770 int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
7771 if (ret < 0) {
7772 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
Gautam Manam34d1f542021-01-05 20:24:37 +05307773 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007774 return ret;
7775 }
Phil Burke0a86d12019-02-16 22:28:11 -08007776 position->time_nanoseconds = ts.tv_sec*1000000000LL + ts.tv_nsec
7777 + in->mmap_time_offset_nanos;
Gautam Manam34d1f542021-01-05 20:24:37 +05307778 pthread_mutex_unlock(&in->lock);
Haynes Mathew George16081042017-05-31 17:16:49 -07007779 return 0;
7780}
7781
Naresh Tannirudcb47c52018-06-25 16:23:32 +05307782static int in_get_active_microphones(const struct audio_stream_in *stream,
7783 struct audio_microphone_characteristic_t *mic_array,
7784 size_t *mic_count) {
7785 struct stream_in *in = (struct stream_in *)stream;
7786 struct audio_device *adev = in->dev;
7787 ALOGVV("%s", __func__);
7788
7789 lock_input_stream(in);
7790 pthread_mutex_lock(&adev->lock);
7791 int ret = platform_get_active_microphones(adev->platform,
7792 audio_channel_count_from_in_mask(in->channel_mask),
7793 in->usecase, mic_array, mic_count);
7794 pthread_mutex_unlock(&adev->lock);
7795 pthread_mutex_unlock(&in->lock);
7796
7797 return ret;
7798}
7799
7800static int adev_get_microphones(const struct audio_hw_device *dev,
7801 struct audio_microphone_characteristic_t *mic_array,
7802 size_t *mic_count) {
7803 struct audio_device *adev = (struct audio_device *)dev;
7804 ALOGVV("%s", __func__);
7805
7806 pthread_mutex_lock(&adev->lock);
7807 int ret = platform_get_microphones(adev->platform, mic_array, mic_count);
7808 pthread_mutex_unlock(&adev->lock);
7809
7810 return ret;
7811}
juyuchendb308c22019-01-21 11:57:17 -07007812
7813static void in_update_sink_metadata(struct audio_stream_in *stream,
7814 const struct sink_metadata *sink_metadata) {
7815
7816 if (stream == NULL
7817 || sink_metadata == NULL
7818 || sink_metadata->tracks == NULL) {
7819 return;
7820 }
7821
7822 int error = 0;
7823 struct stream_in *in = (struct stream_in *)stream;
7824 struct audio_device *adev = in->dev;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007825 struct listnode devices;
7826
7827 list_init(&devices);
juyuchendb308c22019-01-21 11:57:17 -07007828
7829 if (sink_metadata->track_count != 0)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007830 reassign_device_list(&devices, sink_metadata->tracks->dest_device, "");
juyuchendb308c22019-01-21 11:57:17 -07007831
7832 lock_input_stream(in);
7833 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007834 ALOGV("%s: in->usecase: %d, device: %x", __func__, in->usecase, get_device_types(&devices));
juyuchendb308c22019-01-21 11:57:17 -07007835
Zhou Song503196b2021-07-23 17:31:05 +08007836 if ((in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY ||
7837 in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY2) &&
7838 !list_empty(&devices) &&
7839 adev->voice_tx_output != NULL) {
juyuchendb308c22019-01-21 11:57:17 -07007840 /* Use the rx device from afe-proxy record to route voice call because
7841 there is no routing if tx device is on primary hal and rx device
7842 is on other hal during voice call. */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007843 assign_devices(&adev->voice_tx_output->device_list, &devices);
juyuchendb308c22019-01-21 11:57:17 -07007844
7845 if (!voice_is_call_state_active(adev)) {
7846 if (adev->mode == AUDIO_MODE_IN_CALL) {
7847 adev->current_call_output = adev->voice_tx_output;
7848 error = voice_start_call(adev);
7849 if (error != 0)
7850 ALOGE("%s: start voice call failed %d", __func__, error);
7851 }
7852 } else {
7853 adev->current_call_output = adev->voice_tx_output;
7854 voice_update_devices_for_all_voice_usecases(adev);
7855 }
7856 }
7857
7858 pthread_mutex_unlock(&adev->lock);
7859 pthread_mutex_unlock(&in->lock);
7860}
7861
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05307862int adev_open_output_stream(struct audio_hw_device *dev,
Haynes Mathew George16081042017-05-31 17:16:49 -07007863 audio_io_handle_t handle,
7864 audio_devices_t devices,
7865 audio_output_flags_t flags,
7866 struct audio_config *config,
7867 struct audio_stream_out **stream_out,
Derek Chenf6318be2017-06-12 17:16:24 -04007868 const char *address)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007869{
7870 struct audio_device *adev = (struct audio_device *)dev;
7871 struct stream_out *out;
Gangadhar Sb0210342019-02-22 17:39:41 +05307872 int ret = 0, ip_hdlr_stream = 0, ip_hdlr_dev = 0;
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07007873 audio_format_t format;
Ben Rombergerd771a7c2017-02-22 18:05:17 -08007874 struct adsp_hdlr_stream_cfg hdlr_stream_cfg;
Manish Dewangan21a850a2017-08-14 12:03:55 +05307875 bool is_direct_passthough = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007876 bool is_hdmi = devices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
7877 bool is_usb_dev = audio_is_usb_out_device(devices) &&
7878 (devices != AUDIO_DEVICE_OUT_USB_ACCESSORY);
7879 bool direct_dev = is_hdmi || is_usb_dev;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08007880 bool use_db_as_primary =
vivek mehtaae1018c2019-05-09 12:19:57 -07007881 property_get_bool("vendor.audio.feature.deepbuffer_as_primary.enable",
7882 false);
Vignesh Kulothungana6927272019-02-20 15:17:07 -08007883 bool force_haptic_path =
7884 property_get_bool("vendor.audio.test_haptic", false);
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07007885 bool is_voip_rx = flags & AUDIO_OUTPUT_FLAG_VOIP_RX;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08007886#ifdef AUDIO_GKI_ENABLED
7887 __s32 *generic_dec;
7888#endif
Weiyin Jiang906db3c2021-03-02 13:17:04 +08007889 pthread_mutexattr_t latch_attr;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007890
kunleizdff872d2018-08-20 14:40:33 +08007891 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08007892 is_usb_dev = false;
7893 devices = AUDIO_DEVICE_OUT_SPEAKER;
7894 ALOGW("%s: ignore set device to non existing USB card, use output device(%#x)",
7895 __func__, devices);
Mingshu Pangdbd20562019-11-25 18:04:39 +08007896 if (config->format == AUDIO_FORMAT_DEFAULT)
7897 config->format = AUDIO_FORMAT_PCM_16_BIT;
7898 if (config->sample_rate == 0)
7899 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
7900 if (config->channel_mask == AUDIO_CHANNEL_NONE)
7901 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
kunleizd6a9e0c2018-07-30 15:38:52 +08007902 }
7903
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007904 *stream_out = NULL;
Naresh Tanniru80659832014-06-04 18:17:56 +05307905
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007906 out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
7907
Mingming Yin3a941d42016-02-17 18:08:05 -08007908 ALOGD("%s: enter: format(%#x) sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)\
Derek Chenf6318be2017-06-12 17:16:24 -04007909 stream_handle(%p) address(%s)", __func__, config->format, config->sample_rate, config->channel_mask,
7910 devices, flags, &out->stream, address);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05307911
7912
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08007913 if (!out) {
7914 return -ENOMEM;
7915 }
7916
Haynes Mathew George204045b2015-02-25 20:32:03 -08007917 pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07007918 pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
Weiyin Jiang906db3c2021-03-02 13:17:04 +08007919 pthread_mutexattr_init(&latch_attr);
7920 pthread_mutexattr_settype(&latch_attr, PTHREAD_MUTEX_RECURSIVE);
7921 pthread_mutex_init(&out->latch_lock, &latch_attr);
7922 pthread_mutexattr_destroy(&latch_attr);
Zhou Song48453a02018-01-10 17:50:59 +08007923 pthread_mutex_init(&out->position_query_lock, (const pthread_mutexattr_t *) NULL);
Haynes Mathew George204045b2015-02-25 20:32:03 -08007924 pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
7925
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007926 if (devices == AUDIO_DEVICE_NONE)
7927 devices = AUDIO_DEVICE_OUT_SPEAKER;
7928
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007929 out->flags = flags;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08007930 list_init(&out->device_list);
7931 update_device_list(&out->device_list, devices, address, true /* add devices */);
Haynes Mathew George47cd4cb2013-07-19 11:58:50 -07007932 out->dev = adev;
Aalique Grahame65780b52017-09-27 14:59:56 -07007933 out->hal_op_format = out->hal_ip_format = format = out->format = config->format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07007934 out->sample_rate = config->sample_rate;
Sachin Mohan Gadag3d09acd2017-06-19 12:43:44 +05307935 out->channel_mask = config->channel_mask;
Ramjee Singh5857aeb2017-08-03 19:18:50 +05307936 if (out->channel_mask == AUDIO_CHANNEL_NONE)
7937 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
7938 else
7939 out->supported_channel_masks[0] = out->channel_mask;
Eric Laurentc4aef752013-09-12 17:45:53 -07007940 out->handle = handle;
Mingming Yin3ee55c62014-08-04 14:23:35 -07007941 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Alexy Josephaa54c872014-12-03 02:46:47 -08007942 out->non_blocking = 0;
Ashish Jain83a6cc22016-06-28 14:34:17 +05307943 out->convert_buffer = NULL;
Ashish Jain1b9b30c2017-05-18 20:57:40 +05307944 out->started = 0;
Zhou Songbaddf9f2020-11-20 13:57:39 +08007945 out->a2dp_muted = false;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08007946 out->hal_output_suspend_supported = 0;
7947 out->dynamic_pm_qos_config_supported = 0;
Surendar Karkaf51b5842018-04-26 11:28:38 +05307948 out->set_dual_mono = false;
Manisha Agarwal7b3e3772019-02-20 14:33:45 +05307949 out->prev_card_status_offline = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +05307950 out->pspd_coeff_sent = false;
Phil Burkd898ba62019-06-20 12:49:01 -07007951 out->mmap_shared_memory_fd = -1; // not open
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08007952
Nikhil Laturkar26b690b2017-07-25 11:06:14 +05307953 if ((flags & AUDIO_OUTPUT_FLAG_BD) &&
Satish Babu Patakokila37e7c482018-02-02 11:50:06 +05307954 (property_get_bool("vendor.audio.matrix.limiter.enable", false)))
Ben Romberger6c4d3812017-06-13 17:46:45 -07007955 platform_set_device_params(out, DEVICE_PARAM_LIMITER_ID, 1);
7956
Aalique Grahame22e49102018-12-18 14:23:57 -08007957 if (direct_dev &&
7958 (audio_is_linear_pcm(out->format) ||
7959 config->format == AUDIO_FORMAT_DEFAULT) &&
7960 out->flags == AUDIO_OUTPUT_FLAG_NONE) {
7961 audio_format_t req_format = config->format;
7962 audio_channel_mask_t req_channel_mask = config->channel_mask;
7963 uint32_t req_sample_rate = config->sample_rate;
7964
7965 pthread_mutex_lock(&adev->lock);
7966 if (is_hdmi) {
7967 ALOGV("AUDIO_DEVICE_OUT_AUX_DIGITAL and DIRECT|OFFLOAD, check hdmi caps");
7968 ret = read_hdmi_sink_caps(out);
7969 if (config->sample_rate == 0)
7970 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
7971 if (config->channel_mask == AUDIO_CHANNEL_NONE)
7972 config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
7973 if (config->format == AUDIO_FORMAT_DEFAULT)
7974 config->format = AUDIO_FORMAT_PCM_16_BIT;
7975 } else if (is_usb_dev) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007976 ret = read_usb_sup_params_and_compare(true /*is_playback*/,
7977 &config->format,
7978 &out->supported_formats[0],
7979 MAX_SUPPORTED_FORMATS,
7980 &config->channel_mask,
7981 &out->supported_channel_masks[0],
7982 MAX_SUPPORTED_CHANNEL_MASKS,
7983 &config->sample_rate,
7984 &out->supported_sample_rates[0],
7985 MAX_SUPPORTED_SAMPLE_RATES);
7986 ALOGV("plugged dev USB ret %d", ret);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007987 }
Aalique Grahame22e49102018-12-18 14:23:57 -08007988
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007989 pthread_mutex_unlock(&adev->lock);
7990 if (ret != 0) {
Mingming Yin3a941d42016-02-17 18:08:05 -08007991 if (ret == -ENOSYS) {
7992 /* ignore and go with default */
7993 ret = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08007994 }
7995 // For MMAP NO IRQ, allow conversions in ADSP
7996 else if (is_hdmi || (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) == 0)
7997 goto error_open;
7998 else {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07007999 ALOGE("error reading direct dev sink caps");
Mingming Yin3a941d42016-02-17 18:08:05 -08008000 goto error_open;
8001 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008002
8003 if (req_sample_rate != 0 && config->sample_rate != req_sample_rate)
8004 config->sample_rate = req_sample_rate;
8005 if (req_channel_mask != AUDIO_CHANNEL_NONE && config->channel_mask != req_channel_mask)
8006 config->channel_mask = req_channel_mask;
8007 if (req_format != AUDIO_FORMAT_DEFAULT && config->format != req_format)
8008 config->format = req_format;
Mingming Yin3a941d42016-02-17 18:08:05 -08008009 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008010
8011 out->sample_rate = config->sample_rate;
8012 out->channel_mask = config->channel_mask;
8013 out->format = config->format;
8014 if (is_hdmi) {
8015 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8016 out->config = pcm_config_hdmi_multi;
8017 } else if (flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8018 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8019 out->config = pcm_config_mmap_playback;
8020 out->stream.start = out_start;
8021 out->stream.stop = out_stop;
8022 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8023 out->stream.get_mmap_position = out_get_mmap_position;
8024 } else {
8025 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8026 out->config = pcm_config_hifi;
8027 }
8028
8029 out->config.rate = out->sample_rate;
8030 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8031 if (is_hdmi) {
8032 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8033 audio_bytes_per_sample(out->format));
8034 }
8035 out->config.format = pcm_format_from_audio_format(out->format);
Mingming Yin3a941d42016-02-17 18:08:05 -08008036 }
8037
Derek Chenf6318be2017-06-12 17:16:24 -04008038 /* validate bus device address */
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008039 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008040 /* extract car audio stream index */
8041 out->car_audio_stream =
8042 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
8043 if (out->car_audio_stream < 0) {
8044 ALOGE("%s: invalid car audio stream %x",
8045 __func__, out->car_audio_stream);
8046 ret = -EINVAL;
8047 goto error_open;
8048 }
Derek Chen5f67a942020-02-24 23:08:13 -08008049 ALOGV("%s: car_audio_stream %x", __func__, out->car_audio_stream);
Derek Chenf6318be2017-06-12 17:16:24 -04008050 }
8051
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008052 /* Check for VOIP usecase */
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07008053 if (is_voip_rx) {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008054 if (!voice_extn_is_compress_voip_supported()) {
8055 if (out->sample_rate == 8000 || out->sample_rate == 16000 ||
8056 out->sample_rate == 32000 || out->sample_rate == 48000) {
Aniket Kumar Lata4f9a2a52019-05-09 18:44:09 -07008057 out->channel_mask = audio_extn_utils_is_vendor_enhanced_fwk() ?
Lakshman Chaluvarajue7fc9482020-05-30 14:29:29 +05308058 config->channel_mask : AUDIO_CHANNEL_OUT_STEREO;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008059 out->usecase = USECASE_AUDIO_PLAYBACK_VOIP;
8060 out->format = AUDIO_FORMAT_PCM_16_BIT;
Aniket Kumar Lata8426d1f2019-06-10 15:25:53 -07008061 out->volume_l = INVALID_OUT_VOLUME;
8062 out->volume_r = INVALID_OUT_VOLUME;
Vikram Panduranga93f080e2017-06-07 18:16:14 -07008063
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008064 out->config = default_pcm_config_voip_copp;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008065 out->config.rate = out->sample_rate;
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008066 uint32_t channel_count =
8067 audio_channel_count_from_out_mask(out->channel_mask);
Ramjee Singh968858a2020-08-06 16:30:48 +05308068 out->config.channels = channel_count;
8069
Aniket Kumar Lata1e344f22019-06-19 17:09:01 -07008070 uint32_t buffer_size = get_stream_buffer_size(DEFAULT_VOIP_BUF_DURATION_MS,
8071 out->sample_rate, out->format,
8072 channel_count, false);
8073 uint32_t frame_size = audio_bytes_per_sample(out->format) * channel_count;
8074 if (frame_size != 0)
8075 out->config.period_size = buffer_size / frame_size;
8076 else
8077 ALOGW("%s: frame size is 0 for format %#x", __func__, out->format);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008078 }
8079 } else {
8080 if ((out->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
8081 voice_extn_compress_voip_is_active(out->dev)) &&
8082 (voice_extn_compress_voip_is_config_supported(config))) {
8083 ret = voice_extn_compress_voip_open_output_stream(out);
8084 if (ret != 0) {
8085 ALOGE("%s: Compress voip output cannot be opened, error:%d",
8086 __func__, ret);
8087 goto error_open;
8088 }
Sujin Panicker19027262019-09-16 18:28:06 +05308089 } else {
8090 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8091 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008092 }
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008093 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008094 } else if (audio_is_linear_pcm(out->format) &&
8095 out->flags == AUDIO_OUTPUT_FLAG_NONE && is_usb_dev) {
8096 out->channel_mask = config->channel_mask;
8097 out->sample_rate = config->sample_rate;
8098 out->format = config->format;
8099 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
8100 // does this change?
8101 out->config = is_hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
8102 out->config.rate = config->sample_rate;
8103 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
8104 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels *
8105 audio_bytes_per_sample(config->format));
8106 out->config.format = pcm_format_from_audio_format(out->format);
vivek mehta0ea887a2015-08-26 14:01:20 -07008107 } else if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308108 (out->flags == AUDIO_OUTPUT_FLAG_DIRECT)) {
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308109 pthread_mutex_lock(&adev->lock);
8110 bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
8111 pthread_mutex_unlock(&adev->lock);
8112
8113 // reject offload during card offline to allow
8114 // fallback to s/w paths
8115 if (offline) {
8116 ret = -ENODEV;
8117 goto error_open;
8118 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008119
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008120 if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
8121 config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
8122 ALOGE("%s: Unsupported Offload information", __func__);
8123 ret = -EINVAL;
8124 goto error_open;
8125 }
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008126
Atul Khare3fa6e542017-08-09 00:56:17 +05308127 if (config->offload_info.format == 0)
8128 config->offload_info.format = config->format;
8129 if (config->offload_info.sample_rate == 0)
8130 config->offload_info.sample_rate = config->sample_rate;
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008131
Mingming Yin90310102013-11-13 16:57:00 -08008132 if (!is_supported_format(config->offload_info.format) &&
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308133 !audio_extn_passthru_is_supported_format(config->offload_info.format)) {
vivek mehta0ea887a2015-08-26 14:01:20 -07008134 ALOGE("%s: Unsupported audio format %x " , __func__, config->offload_info.format);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008135 ret = -EINVAL;
8136 goto error_open;
8137 }
8138
Ben Romberger0f8c87b2017-05-24 17:41:11 -07008139 /* TrueHD only supported for 48k multiples (48k, 96k, 192k) */
8140 if ((config->offload_info.format == AUDIO_FORMAT_DOLBY_TRUEHD) &&
8141 (audio_extn_passthru_is_passthrough_stream(out)) &&
8142 !((config->sample_rate == 48000) ||
8143 (config->sample_rate == 96000) ||
8144 (config->sample_rate == 192000))) {
8145 ALOGE("%s: Unsupported sample rate %d for audio format %x",
8146 __func__, config->sample_rate, config->offload_info.format);
8147 ret = -EINVAL;
8148 goto error_open;
8149 }
8150
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008151 out->compr_config.codec = (struct snd_codec *)
8152 calloc(1, sizeof(struct snd_codec));
8153
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07008154 if (!out->compr_config.codec) {
8155 ret = -ENOMEM;
8156 goto error_open;
8157 }
8158
Dhananjay Kumarac341582017-02-23 23:42:25 +05308159 out->stream.pause = out_pause;
8160 out->stream.resume = out_resume;
8161 out->stream.flush = out_flush;
Ashish Jain4847e9d2017-08-17 19:16:57 +05308162 out->stream.set_callback = out_set_callback;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308163 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Mingming Yin21d60472015-09-30 13:56:25 -07008164 out->stream.drain = out_drain;
Dhananjay Kumarac341582017-02-23 23:42:25 +05308165 out->usecase = get_offload_usecase(adev, true /* is_compress */);
vivek mehta446c3962015-09-14 10:57:35 -07008166 ALOGV("Compress Offload usecase .. usecase selected %d", out->usecase);
Dhananjay Kumarac341582017-02-23 23:42:25 +05308167 } else {
8168 out->usecase = get_offload_usecase(adev, false /* is_compress */);
8169 ALOGV("non-offload DIRECT_usecase ... usecase selected %d ", out->usecase);
vivek mehta0ea887a2015-08-26 14:01:20 -07008170 }
vivek mehta446c3962015-09-14 10:57:35 -07008171
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308172 if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8173 ALOGD("%s: Setting latency mode to true", __func__);
Meng Wang4c32fb42020-01-16 17:57:11 +08008174#ifdef AUDIO_GKI_ENABLED
8175 /* out->compr_config.codec->reserved[1] is for flags */
8176 out->compr_config.codec->reserved[1] |= audio_extn_utils_get_perf_mode_flag();
8177#else
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308178 out->compr_config.codec->flags |= audio_extn_utils_get_perf_mode_flag();
Meng Wang4c32fb42020-01-16 17:57:11 +08008179#endif
Deeraj Somanfa377bf2019-02-06 12:57:59 +05308180 }
8181
vivek mehta446c3962015-09-14 10:57:35 -07008182 if (out->usecase == USECASE_INVALID) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008183 if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_AUX_DIGITAL) &&
Mingming Yin3a941d42016-02-17 18:08:05 -08008184 config->format == 0 && config->sample_rate == 0 &&
8185 config->channel_mask == 0) {
Mingming Yin21854652016-04-13 11:54:02 -07008186 ALOGI("%s dummy open to query sink capability",__func__);
Mingming Yin3a941d42016-02-17 18:08:05 -08008187 out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
8188 } else {
8189 ALOGE("%s, Max allowed OFFLOAD usecase reached ... ", __func__);
8190 ret = -EEXIST;
8191 goto error_open;
8192 }
vivek mehta446c3962015-09-14 10:57:35 -07008193 }
8194
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008195 if (config->offload_info.channel_mask)
8196 out->channel_mask = config->offload_info.channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008197 else if (config->channel_mask) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008198 out->channel_mask = config->channel_mask;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008199 config->offload_info.channel_mask = config->channel_mask;
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008200 } else {
Dhananjay Kumarac341582017-02-23 23:42:25 +05308201 ALOGE("out->channel_mask not set for OFFLOAD/DIRECT usecase");
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008202 ret = -EINVAL;
8203 goto error_open;
ApurupaPattapuc6a3a9e2014-01-10 14:46:02 -08008204 }
Haynes Mathew Georgea99f7532016-08-24 16:01:21 -07008205
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008206 format = out->format = config->offload_info.format;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008207 out->sample_rate = config->offload_info.sample_rate;
8208
Mingming Yin3ee55c62014-08-04 14:23:35 -07008209 out->bit_width = CODEC_BACKEND_DEFAULT_BIT_WIDTH;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008210
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308211 out->compr_config.codec->id = get_snd_codec_id(config->offload_info.format);
Satish Babu Patakokila5933e972017-08-24 12:22:08 +05308212 if (audio_extn_utils_is_dolby_format(config->offload_info.format)) {
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308213 audio_extn_dolby_send_ddp_endp_params(adev);
8214 audio_extn_dolby_set_dmid(adev);
8215 }
vivek mehta0ea887a2015-08-26 14:01:20 -07008216
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008217 out->compr_config.codec->sample_rate =
Ravi Kumar Alamandab91bff32014-11-14 12:05:54 -08008218 config->offload_info.sample_rate;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008219 out->compr_config.codec->bit_rate =
8220 config->offload_info.bit_rate;
8221 out->compr_config.codec->ch_in =
Dhanalakshmi Siddania15c6792016-08-10 15:33:53 +05308222 audio_channel_count_from_out_mask(out->channel_mask);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008223 out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
Satish Babu Patakokilaa395a9e2016-11-01 12:18:49 +05308224 /* Update bit width only for non passthrough usecases.
8225 * For passthrough usecases, the output will always be opened @16 bit
8226 */
8227 if (!audio_extn_passthru_is_passthrough_stream(out))
8228 out->bit_width = AUDIO_OUTPUT_BIT_WIDTH;
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308229
8230 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP)
Meng Wang4c32fb42020-01-16 17:57:11 +08008231#ifdef AUDIO_GKI_ENABLED
8232 /* out->compr_config.codec->reserved[1] is for flags */
8233 out->compr_config.codec->reserved[1] |= COMPRESSED_TIMESTAMP_FLAG;
8234 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->reserved[1]);
8235#else
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308236 out->compr_config.codec->flags |= COMPRESSED_TIMESTAMP_FLAG;
8237 ALOGVV("%s : out->compr_config.codec->flags -> (%#x) ", __func__, out->compr_config.codec->flags);
Meng Wang4c32fb42020-01-16 17:57:11 +08008238#endif
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308239
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008240 /*TODO: Do we need to change it for passthrough */
8241 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008242
Manish Dewangana6fc5442015-08-24 20:30:31 +05308243 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC)
8244 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_RAW;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308245 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_ADTS)
Manish Dewangana6fc5442015-08-24 20:30:31 +05308246 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4ADTS;
Arun Kumar Dasari3b174182016-12-27 13:01:14 +05308247 else if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) == AUDIO_FORMAT_AAC_LATM)
8248 out->compr_config.codec->format = SND_AUDIOSTREAMFORMAT_MP4LATM;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308249
8250 if ((config->offload_info.format & AUDIO_FORMAT_MAIN_MASK) ==
8251 AUDIO_FORMAT_PCM) {
8252
8253 /*Based on platform support, configure appropriate alsa format for corresponding
8254 *hal input format.
8255 */
8256 out->compr_config.codec->format = hal_format_to_alsa(
8257 config->offload_info.format);
8258
Ashish Jain83a6cc22016-06-28 14:34:17 +05308259 out->hal_op_format = alsa_format_to_hal(
Ashish Jainf1eaa582016-05-23 20:54:24 +05308260 out->compr_config.codec->format);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308261 out->hal_ip_format = out->format;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308262
Dhananjay Kumarac341582017-02-23 23:42:25 +05308263 /*for direct non-compress playback populate bit_width based on selected alsa format as
Ashish Jainf1eaa582016-05-23 20:54:24 +05308264 *hal input format and alsa format might differ based on platform support.
8265 */
8266 out->bit_width = audio_bytes_per_sample(
Ashish Jain83a6cc22016-06-28 14:34:17 +05308267 out->hal_op_format) << 3;
Ashish Jainf1eaa582016-05-23 20:54:24 +05308268
8269 out->compr_config.fragments = DIRECT_PCM_NUM_FRAGMENTS;
8270
Deeraj Soman93155a62019-09-30 19:00:37 +05308271 if (property_get_bool("vendor.audio.offload.buffer.duration.enabled", false)) {
8272 if ((config->offload_info.duration_us >= MIN_OFFLOAD_BUFFER_DURATION_MS * 1000) &&
8273 (config->offload_info.duration_us <= MAX_OFFLOAD_BUFFER_DURATION_MS * 1000))
8274 out->info.duration_us = (int64_t)config->offload_info.duration_us;
8275 }
Deeraj Soman65358ab2019-02-07 15:40:49 +05308276
Ashish Jainf1eaa582016-05-23 20:54:24 +05308277 /* Check if alsa session is configured with the same format as HAL input format,
8278 * if not then derive correct fragment size needed to accomodate the
8279 * conversion of HAL input format to alsa format.
8280 */
8281 audio_extn_utils_update_direct_pcm_fragment_size(out);
8282
8283 /*if hal input and output fragment size is different this indicates HAL input format is
8284 *not same as the alsa format
8285 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308286 if (out->hal_fragment_size != out->compr_config.fragment_size) {
Ashish Jainf1eaa582016-05-23 20:54:24 +05308287 /*Allocate a buffer to convert input data to the alsa configured format.
8288 *size of convert buffer is equal to the size required to hold one fragment size
8289 *worth of pcm data, this is because flinger does not write more than fragment_size
8290 */
Ashish Jain83a6cc22016-06-28 14:34:17 +05308291 out->convert_buffer = calloc(1,out->compr_config.fragment_size);
8292 if (out->convert_buffer == NULL){
Ashish Jainf1eaa582016-05-23 20:54:24 +05308293 ALOGE("Allocation failed for convert buffer for size %d", out->compr_config.fragment_size);
8294 ret = -ENOMEM;
8295 goto error_open;
8296 }
8297 }
8298 } else if (audio_extn_passthru_is_passthrough_stream(out)) {
8299 out->compr_config.fragment_size =
8300 audio_extn_passthru_get_buffer_size(&config->offload_info);
8301 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8302 } else {
8303 out->compr_config.fragment_size =
8304 platform_get_compress_offload_buffer_size(&config->offload_info);
8305 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
8306 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008307
Naresh Tanniruee3499a2017-01-05 14:05:35 +05308308 if (out->flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8309 out->compr_config.fragment_size += sizeof(struct snd_codec_metadata);
8310 }
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008311 if (config->offload_info.format == AUDIO_FORMAT_FLAC) {
8312#ifdef AUDIO_GKI_ENABLED
8313 generic_dec =
8314 &(out->compr_config.codec->options.generic.reserved[1]);
8315 ((struct snd_generic_dec_flac *)generic_dec)->sample_size =
8316 AUDIO_OUTPUT_BIT_WIDTH;
8317#else
Satya Krishna Pindiproli5d82d012015-08-12 18:21:25 +05308318 out->compr_config.codec->options.flac_dec.sample_size = AUDIO_OUTPUT_BIT_WIDTH;
Xiaojun Sang782e5b12020-06-29 21:13:06 +08008319#endif
8320 }
Mingming Yin3ee55c62014-08-04 14:23:35 -07008321
Dhanalakshmi Siddani18737932016-11-29 17:33:17 +05308322 if (config->offload_info.format == AUDIO_FORMAT_APTX) {
8323 audio_extn_send_aptx_dec_bt_addr_to_dsp(out);
8324 }
8325
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008326 if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
8327 out->non_blocking = 1;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008328
Manish Dewangan69426c82017-01-30 17:35:36 +05308329 if ((flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) &&
8330 (flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC)) {
8331 out->render_mode = RENDER_MODE_AUDIO_STC_MASTER;
8332 } else if(flags & AUDIO_OUTPUT_FLAG_TIMESTAMP) {
8333 out->render_mode = RENDER_MODE_AUDIO_MASTER;
8334 } else {
8335 out->render_mode = RENDER_MODE_AUDIO_NO_TIMESTAMP;
8336 }
Alexy Josephaa54c872014-12-03 02:46:47 -08008337
Naresh Tanniru29bce4e2017-04-27 17:54:30 +05308338 memset(&out->channel_map_param, 0,
8339 sizeof(struct audio_out_channel_map_param));
8340
Haynes Mathew George352f27b2013-07-26 00:00:15 -07008341 out->send_new_metadata = 1;
Chaithanya Krishna Bacharajua70cb6a2015-07-24 14:15:05 +05308342 out->send_next_track_params = false;
8343 out->is_compr_metadata_avail = false;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008344 out->offload_state = OFFLOAD_STATE_IDLE;
8345 out->playback_started = 0;
Zhou Song48453a02018-01-10 17:50:59 +08008346 out->writeAt.tv_sec = 0;
8347 out->writeAt.tv_nsec = 0;
Haynes Mathew Georgeb9012ab2013-12-10 13:44:56 -08008348
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008349 audio_extn_dts_create_state_notifier_node(out->usecase);
8350
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008351 ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
8352 __func__, config->offload_info.version,
8353 config->offload_info.bit_rate);
Ashish Jain5106d362016-05-11 19:23:33 +05308354
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308355 /* Check if DSD audio format is supported in codec
8356 * and there is no active native DSD use case
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308357 */
8358
8359 if ((config->format == AUDIO_FORMAT_DSD) &&
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308360 (!platform_check_codec_dsd_support(adev->platform) ||
8361 audio_is_dsd_native_stream_active(adev))) {
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308362 ret = -EINVAL;
8363 goto error_open;
8364 }
8365
Ashish Jain5106d362016-05-11 19:23:33 +05308366 /* Disable gapless if any of the following is true
8367 * passthrough playback
8368 * AV playback
Dhananjay Kumarac341582017-02-23 23:42:25 +05308369 * non compressed Direct playback
Ashish Jain5106d362016-05-11 19:23:33 +05308370 */
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308371 if (audio_extn_passthru_is_passthrough_stream(out) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308372 (config->format == AUDIO_FORMAT_DSD) ||
Naresh Tanniru928f0862017-04-07 16:44:23 -07008373 (config->format == AUDIO_FORMAT_IEC61937) ||
Preetam Singh Ranawatf5fbdd62016-09-29 18:38:31 +05308374 config->offload_info.has_video ||
Dhananjay Kumarac341582017-02-23 23:42:25 +05308375 !(out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
Ashish Jain5106d362016-05-11 19:23:33 +05308376 check_and_set_gapless_mode(adev, false);
8377 } else
8378 check_and_set_gapless_mode(adev, true);
Mingming Yin21854652016-04-13 11:54:02 -07008379
Satish Babu Patakokila1caa1b72016-05-24 13:47:08 +05308380 if (audio_extn_passthru_is_passthrough_stream(out)) {
Mingming Yin21854652016-04-13 11:54:02 -07008381 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
8382 }
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308383 if (config->format == AUDIO_FORMAT_DSD) {
8384 out->flags |= AUDIO_OUTPUT_FLAG_COMPRESS_PASSTHROUGH;
Meng Wang4c32fb42020-01-16 17:57:11 +08008385#ifdef AUDIO_GKI_ENABLED
8386 /* out->compr_config.codec->reserved[0] is for compr_passthr */
8387 out->compr_config.codec->reserved[0] = PASSTHROUGH_DSD;
8388#else
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308389 out->compr_config.codec->compr_passthr = PASSTHROUGH_DSD;
Meng Wang4c32fb42020-01-16 17:57:11 +08008390#endif
Preetam Singh Ranawatcb6212e2016-07-19 18:33:53 +05308391 }
Aalique Grahame0359a1f2016-09-08 16:54:22 -07008392
8393 create_offload_callback_thread(out);
8394
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008395 } else if (out->flags & AUDIO_OUTPUT_FLAG_INCALL_MUSIC) {
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008396 switch (config->sample_rate) {
8397 case 0:
8398 out->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8399 break;
8400 case 8000:
8401 case 16000:
8402 case 48000:
8403 out->sample_rate = config->sample_rate;
8404 break;
8405 default:
8406 ALOGE("%s: Unsupported sampling rate %d for Incall Music", __func__,
8407 config->sample_rate);
8408 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8409 ret = -EINVAL;
8410 goto error_open;
8411 }
8412 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8413 switch (config->channel_mask) {
8414 case AUDIO_CHANNEL_NONE:
8415 case AUDIO_CHANNEL_OUT_STEREO:
8416 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8417 break;
8418 default:
8419 ALOGE("%s: Unsupported channel mask %#x for Incall Music", __func__,
8420 config->channel_mask);
8421 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8422 ret = -EINVAL;
8423 goto error_open;
8424 }
8425 switch (config->format) {
8426 case AUDIO_FORMAT_DEFAULT:
8427 case AUDIO_FORMAT_PCM_16_BIT:
8428 out->format = AUDIO_FORMAT_PCM_16_BIT;
8429 break;
8430 default:
8431 ALOGE("%s: Unsupported format %#x for Incall Music", __func__,
8432 config->format);
8433 config->format = AUDIO_FORMAT_PCM_16_BIT;
8434 ret = -EINVAL;
8435 goto error_open;
8436 }
8437
Satya Krishna Pindiprolif1cd92b2016-04-14 19:05:23 +05308438 ret = voice_extn_check_and_set_incall_music_usecase(adev, out);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008439 if (ret != 0) {
8440 ALOGE("%s: Incall music delivery usecase cannot be set error:%d",
Arun Mirpuri7da752a2018-09-11 18:01:15 -07008441 __func__, ret);
Shiv Maliyappanahallif3b9a422013-10-22 16:38:08 -07008442 goto error_open;
8443 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008444 } else if (is_single_device_type_equal(&out->device_list,
8445 AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
Aalique Grahame22e49102018-12-18 14:23:57 -08008446 switch (config->sample_rate) {
8447 case 0:
8448 out->sample_rate = AFE_PROXY_SAMPLING_RATE;
8449 break;
8450 case 8000:
8451 case 16000:
8452 case 48000:
8453 out->sample_rate = config->sample_rate;
8454 break;
8455 default:
8456 ALOGE("%s: Unsupported sampling rate %d for Telephony TX", __func__,
8457 config->sample_rate);
8458 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
8459 ret = -EINVAL;
8460 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008461 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008462 //FIXME: add support for MONO stream configuration when audioflinger mixer supports it
8463 switch (config->channel_mask) {
8464 case AUDIO_CHANNEL_NONE:
8465 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8466 break;
8467 case AUDIO_CHANNEL_OUT_STEREO:
8468 out->channel_mask = config->channel_mask;
8469 break;
8470 default:
8471 ALOGE("%s: Unsupported channel mask %#x for Telephony TX", __func__,
8472 config->channel_mask);
8473 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8474 ret = -EINVAL;
8475 break;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008476 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008477 switch (config->format) {
8478 case AUDIO_FORMAT_DEFAULT:
8479 out->format = AUDIO_FORMAT_PCM_16_BIT;
8480 break;
8481 case AUDIO_FORMAT_PCM_16_BIT:
8482 out->format = config->format;
8483 break;
8484 default:
8485 ALOGE("%s: Unsupported format %#x for Telephony TX", __func__,
8486 config->format);
8487 config->format = AUDIO_FORMAT_PCM_16_BIT;
8488 ret = -EINVAL;
8489 break;
8490 }
8491 if (ret != 0)
8492 goto error_open;
8493
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008494 out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
8495 out->config = pcm_config_afe_proxy_playback;
Aalique Grahame22e49102018-12-18 14:23:57 -08008496 out->config.rate = out->sample_rate;
8497 out->config.channels =
8498 audio_channel_count_from_out_mask(out->channel_mask);
8499 out->config.format = pcm_format_from_audio_format(out->format);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008500 adev->voice_tx_output = out;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008501 } else {
Ashish Jain058165c2016-09-28 23:18:48 +05308502 unsigned int channels = 0;
8503 /*Update config params to default if not set by the caller*/
8504 if (config->sample_rate == 0)
8505 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
8506 if (config->channel_mask == AUDIO_CHANNEL_NONE)
8507 config->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
8508 if (config->format == AUDIO_FORMAT_DEFAULT)
8509 config->format = AUDIO_FORMAT_PCM_16_BIT;
8510
8511 channels = audio_channel_count_from_out_mask(out->channel_mask);
8512
Varun Balaraje49253e2017-07-06 19:48:56 +05308513 if (out->flags & AUDIO_OUTPUT_FLAG_INTERACTIVE) {
8514 out->usecase = get_interactive_usecase(adev);
8515 out->config = pcm_config_low_latency;
8516 } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
Ashish Jain83a6cc22016-06-28 14:34:17 +05308517 out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
Haynes Mathew George5beddd42016-06-27 18:33:40 -07008518 out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL,
8519 out->flags);
8520 out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
Haynes Mathew George16081042017-05-31 17:16:49 -07008521 } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
8522 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
8523 out->config = pcm_config_mmap_playback;
8524 out->stream.start = out_start;
8525 out->stream.stop = out_stop;
8526 out->stream.create_mmap_buffer = out_create_mmap_buffer;
8527 out->stream.get_mmap_position = out_get_mmap_position;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308528 } else if (out->flags & AUDIO_OUTPUT_FLAG_FAST) {
8529 out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
Aniket Kumar Lata932f4872017-11-06 18:29:44 -08008530 out->hal_output_suspend_supported =
8531 property_get_bool("vendor.audio.hal.output.suspend.supported", false);
8532 out->dynamic_pm_qos_config_supported =
8533 property_get_bool("vendor.audio.hal.dynamic.qos.config.supported", false);
8534 if (!out->dynamic_pm_qos_config_supported) {
Alexy Joseph98988832017-01-13 14:56:59 -08008535 ALOGI("%s: dynamic qos voting not enabled for platform", __func__);
8536 } else {
8537 ALOGI("%s: dynamic qos voting enabled for platform", __func__);
8538 //the mixer path will be a string similar to "low-latency-playback resume"
8539 strlcpy(out->pm_qos_mixer_path, use_case_table[out->usecase], MAX_MIXER_PATH_LEN);
8540 strlcat(out->pm_qos_mixer_path,
8541 " resume", MAX_MIXER_PATH_LEN);
8542 ALOGI("%s: created %s pm_qos_mixer_path" , __func__,
8543 out->pm_qos_mixer_path);
8544 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308545 out->config = pcm_config_low_latency;
8546 } else if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
8547 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
8548 out->config = pcm_config_deep_buffer;
Ashish Jain058165c2016-09-28 23:18:48 +05308549 out->config.period_size = get_output_period_size(config->sample_rate, out->format,
8550 channels, DEEP_BUFFER_OUTPUT_PERIOD_DURATION);
8551 if (out->config.period_size <= 0) {
8552 ALOGE("Invalid configuration period size is not valid");
8553 ret = -EINVAL;
8554 goto error_open;
8555 }
Aalique Grahame22e49102018-12-18 14:23:57 -08008556 } else if (flags & AUDIO_OUTPUT_FLAG_TTS) {
8557 out->usecase = USECASE_AUDIO_PLAYBACK_TTS;
8558 out->config = pcm_config_deep_buffer;
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008559 } else if (config->channel_mask & AUDIO_CHANNEL_HAPTIC_ALL) {
8560 out->usecase = USECASE_AUDIO_PLAYBACK_WITH_HAPTICS;
8561 out->config = pcm_config_haptics_audio;
8562 if (force_haptic_path)
8563 adev->haptics_config = pcm_config_haptics_audio;
8564 else
8565 adev->haptics_config = pcm_config_haptics;
8566
Meng Wangd08ce322020-04-02 08:59:20 +08008567 channels =
Vignesh Kulothungana6927272019-02-20 15:17:07 -08008568 audio_channel_count_from_out_mask(out->channel_mask & ~AUDIO_CHANNEL_HAPTIC_ALL);
8569
8570 if (force_haptic_path) {
8571 out->config.channels = 1;
8572 adev->haptics_config.channels = 1;
8573 } else
8574 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 -08008575 } else if (compare_device_type(&out->device_list, AUDIO_DEVICE_OUT_BUS)) {
Derek Chenf6318be2017-06-12 17:16:24 -04008576 ret = audio_extn_auto_hal_open_output_stream(out);
8577 if (ret) {
8578 ALOGE("%s: Failed to open output stream for bus device", __func__);
8579 ret = -EINVAL;
8580 goto error_open;
8581 }
Ashish Jain83a6cc22016-06-28 14:34:17 +05308582 } else {
8583 /* primary path is the default path selected if no other outputs are available/suitable */
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08008584 out->usecase = GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
8585 out->config = GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308586 }
8587 out->hal_ip_format = format = out->format;
8588 out->config.format = hal_format_to_pcm(out->hal_ip_format);
8589 out->hal_op_format = pcm_format_to_hal(out->config.format);
8590 out->bit_width = format_to_bitwidth_table[out->hal_op_format] << 3;
8591 out->config.rate = config->sample_rate;
Ravi Kumar Alamanda8f715d92013-11-01 20:37:38 -07008592 out->sample_rate = out->config.rate;
Ashish Jain058165c2016-09-28 23:18:48 +05308593 out->config.channels = channels;
Ashish Jain83a6cc22016-06-28 14:34:17 +05308594 if (out->hal_ip_format != out->hal_op_format) {
8595 uint32_t buffer_size = out->config.period_size *
8596 format_to_bitwidth_table[out->hal_op_format] *
8597 out->config.channels;
8598 out->convert_buffer = calloc(1, buffer_size);
8599 if (out->convert_buffer == NULL){
8600 ALOGE("Allocation failed for convert buffer for size %d",
8601 out->compr_config.fragment_size);
8602 ret = -ENOMEM;
8603 goto error_open;
8604 }
8605 ALOGD("Convert buffer allocated of size %d", buffer_size);
8606 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008607 }
8608
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008609 ALOGV("%s devices:%d, format:%x, out->sample_rate:%d,out->bit_width:%d out->format:%d out->flags:%x, flags: %x usecase %d",
8610 __func__, devices, format, out->sample_rate, out->bit_width, out->format, out->flags, flags, out->usecase);
Ashish Jain83a6cc22016-06-28 14:34:17 +05308611
Pradnya Chaphekar80a8cfb2014-10-20 16:17:01 -07008612 /* TODO remove this hardcoding and check why width is zero*/
8613 if (out->bit_width == 0)
8614 out->bit_width = 16;
Dhananjay Kumard6d32152016-10-13 16:11:03 +05308615 audio_extn_utils_update_stream_output_app_type_cfg(adev->platform,
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -07008616 &adev->streams_output_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08008617 &out->device_list, out->flags,
8618 out->hal_op_format, out->sample_rate,
Dhananjay Kumar4d91c1a2016-12-01 23:27:29 +05308619 out->bit_width, out->channel_mask, out->profile,
Manish Dewangan837dc462015-05-27 10:17:41 +05308620 &out->app_type_cfg);
Aalique Grahame6e763712019-01-31 16:18:17 -08008621 if ((out->usecase == (audio_usecase_t)(GET_USECASE_AUDIO_PLAYBACK_PRIMARY(use_db_as_primary))) ||
Haynes Mathew Georgebf143712013-12-03 13:02:53 -08008622 (flags & AUDIO_OUTPUT_FLAG_PRIMARY)) {
8623 /* Ensure the default output is not selected twice */
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008624 if(adev->primary_output == NULL)
8625 adev->primary_output = out;
8626 else {
8627 ALOGE("%s: Primary output is already opened", __func__);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008628 ret = -EEXIST;
8629 goto error_open;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08008630 }
8631 }
8632
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008633 /* Check if this usecase is already existing */
8634 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella7ce05352014-04-17 20:00:41 -07008635 if ((get_usecase_from_list(adev, out->usecase) != NULL) &&
8636 (out->usecase != USECASE_COMPRESS_VOIP_CALL)) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008637 ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008638 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008639 ret = -EEXIST;
8640 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008641 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08008642
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008643 pthread_mutex_unlock(&adev->lock);
8644
8645 out->stream.common.get_sample_rate = out_get_sample_rate;
8646 out->stream.common.set_sample_rate = out_set_sample_rate;
8647 out->stream.common.get_buffer_size = out_get_buffer_size;
8648 out->stream.common.get_channels = out_get_channels;
8649 out->stream.common.get_format = out_get_format;
8650 out->stream.common.set_format = out_set_format;
8651 out->stream.common.standby = out_standby;
8652 out->stream.common.dump = out_dump;
8653 out->stream.common.set_parameters = out_set_parameters;
8654 out->stream.common.get_parameters = out_get_parameters;
8655 out->stream.common.add_audio_effect = out_add_audio_effect;
8656 out->stream.common.remove_audio_effect = out_remove_audio_effect;
8657 out->stream.get_latency = out_get_latency;
8658 out->stream.set_volume = out_set_volume;
Aalique Grahame22e49102018-12-18 14:23:57 -08008659#ifdef NO_AUDIO_OUT
8660 out->stream.write = out_write_for_no_output;
8661#else
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008662 out->stream.write = out_write;
Aalique Grahame22e49102018-12-18 14:23:57 -08008663#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008664 out->stream.get_render_position = out_get_render_position;
8665 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008666 out->stream.get_presentation_position = out_get_presentation_position;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008667
Haynes Mathew George16081042017-05-31 17:16:49 -07008668 if (out->realtime)
8669 out->af_period_multiplier = af_period_multiplier;
8670 else
8671 out->af_period_multiplier = 1;
8672
Andy Hunga1f48fa2019-07-01 18:14:53 -07008673 out->kernel_buffer_size = out->config.period_size * out->config.period_count;
8674
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008675 out->standby = 1;
Zhou Songbaddf9f2020-11-20 13:57:39 +08008676 out->volume_l = PLAYBACK_GAIN_MAX;
8677 out->volume_r = PLAYBACK_GAIN_MAX;
Eric Laurenta9024de2013-04-04 09:19:12 -07008678 /* out->muted = false; by calloc() */
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07008679 /* out->written = 0; by calloc() */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008680
8681 config->format = out->stream.common.get_format(&out->stream.common);
8682 config->channel_mask = out->stream.common.get_channels(&out->stream.common);
8683 config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
Naresh Tanniru04f71882018-06-26 17:46:22 +05308684 register_format(out->format, out->supported_formats);
8685 register_channel_mask(out->channel_mask, out->supported_channel_masks);
8686 register_sample_rate(out->sample_rate, out->supported_sample_rates);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008687
Dechen Chai22768452021-07-30 09:29:16 +05308688#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08008689 out->error_log = error_log_create(
8690 ERROR_LOG_ENTRIES,
8691 1000000000 /* aggregate consecutive identical errors within one second in ns */);
Dechen Chai22768452021-07-30 09:29:16 +05308692#endif
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308693 /*
8694 By locking output stream before registering, we allow the callback
8695 to update stream's state only after stream's initial state is set to
8696 adev state.
8697 */
8698 lock_output_stream(out);
8699 audio_extn_snd_mon_register_listener(out, out_snd_mon_cb);
8700 pthread_mutex_lock(&adev->lock);
8701 out->card_status = adev->card_status;
8702 pthread_mutex_unlock(&adev->lock);
8703 pthread_mutex_unlock(&out->lock);
8704
Aalique Grahame22e49102018-12-18 14:23:57 -08008705 stream_app_type_cfg_init(&out->app_type_cfg);
8706
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008707 *stream_out = &out->stream;
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308708 ALOGD("%s: Stream (%p) picks up usecase (%s)", __func__, &out->stream,
vivek mehta0ea887a2015-08-26 14:01:20 -07008709 use_case_table[out->usecase]);
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008710
8711 if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)
8712 audio_extn_dts_notify_playback_state(out->usecase, 0, out->sample_rate,
8713 popcount(out->channel_mask), out->playback_started);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008714 /* setup a channel for client <--> adsp communication for stream events */
Manish Dewangan21a850a2017-08-14 12:03:55 +05308715 is_direct_passthough = audio_extn_passthru_is_direct_passthrough(out);
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008716 if ((out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) ||
Naresh Tanniru85819452017-05-04 18:55:45 -07008717 (out->flags & AUDIO_OUTPUT_FLAG_DIRECT_PCM) ||
Gangadhar Sb0210342019-02-22 17:39:41 +05308718 audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform) ||
8719 (audio_extn_ip_hdlr_intf_supported(config->format, is_direct_passthough, false))) {
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008720 hdlr_stream_cfg.pcm_device_id = platform_get_pcm_device_id(
8721 out->usecase, PCM_PLAYBACK);
8722 hdlr_stream_cfg.flags = out->flags;
8723 hdlr_stream_cfg.type = PCM_PLAYBACK;
8724 ret = audio_extn_adsp_hdlr_stream_open(&out->adsp_hdlr_stream_handle,
8725 &hdlr_stream_cfg);
8726 if (ret) {
8727 ALOGE("%s: adsp_hdlr_stream_open failed %d",__func__, ret);
8728 out->adsp_hdlr_stream_handle = NULL;
8729 }
8730 }
Gangadhar Sb0210342019-02-22 17:39:41 +05308731 ip_hdlr_stream = audio_extn_ip_hdlr_intf_supported(config->format,
8732 is_direct_passthough, false);
8733 ip_hdlr_dev = audio_extn_ip_hdlr_intf_supported_for_copp(adev->platform);
8734 if (ip_hdlr_stream || ip_hdlr_dev ) {
Vidyakumar Athota2062f912017-06-27 14:46:15 -07008735 ret = audio_extn_ip_hdlr_intf_init(&out->ip_hdlr_handle, NULL, NULL, adev, out->usecase);
Naresh Tanniru85819452017-05-04 18:55:45 -07008736 if (ret < 0) {
8737 ALOGE("%s: audio_extn_ip_hdlr_intf_init failed %d",__func__, ret);
8738 out->ip_hdlr_handle = NULL;
8739 }
8740 }
Derek Chenf939fb72018-11-13 13:34:41 -08008741
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07008742 ret = io_streams_map_insert(adev, &out->stream.common,
8743 out->handle, AUDIO_PATCH_HANDLE_NONE);
8744 if (ret != 0)
8745 goto error_open;
8746
Susan Wang6dd13092021-01-25 10:27:11 -05008747 out->out_ctxt.output = out;
Derek Chenf939fb72018-11-13 13:34:41 -08008748
8749 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -05008750 list_add_tail(&adev->active_outputs_list, &out->out_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -08008751 pthread_mutex_unlock(&adev->lock);
8752
Eric Laurent994a6932013-07-17 11:51:42 -07008753 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008754 return 0;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008755
8756error_open:
Ashish Jain83a6cc22016-06-28 14:34:17 +05308757 if (out->convert_buffer)
8758 free(out->convert_buffer);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07008759 free(out);
8760 *stream_out = NULL;
8761 ALOGD("%s: exit: ret %d", __func__, ret);
8762 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008763}
8764
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +05308765void adev_close_output_stream(struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008766 struct audio_stream_out *stream)
8767{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008768 struct stream_out *out = (struct stream_out *)stream;
8769 struct audio_device *adev = out->dev;
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008770 int ret = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008771
Haynes Mathew George484e8d22017-07-31 18:55:17 -07008772 ALOGD("%s: enter:stream_handle(%s)",__func__, use_case_table[out->usecase]);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05308773
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07008774 io_streams_map_remove(adev, out->handle);
8775
Susan Wang6dd13092021-01-25 10:27:11 -05008776 // remove out_ctxt early to prevent the stream
8777 // being opened in a race condition
8778 pthread_mutex_lock(&adev->lock);
8779 list_remove(&out->out_ctxt.list);
8780 pthread_mutex_unlock(&adev->lock);
8781
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05308782 // must deregister from sndmonitor first to prevent races
8783 // between the callback and close_stream
8784 audio_extn_snd_mon_unregister_listener(out);
8785
Ben Rombergerd771a7c2017-02-22 18:05:17 -08008786 /* close adsp hdrl session before standby */
8787 if (out->adsp_hdlr_stream_handle) {
8788 ret = audio_extn_adsp_hdlr_stream_close(out->adsp_hdlr_stream_handle);
8789 if (ret)
8790 ALOGE("%s: adsp_hdlr_stream_close failed %d",__func__, ret);
8791 out->adsp_hdlr_stream_handle = NULL;
8792 }
8793
Manish Dewangan21a850a2017-08-14 12:03:55 +05308794 if (out->ip_hdlr_handle) {
Naresh Tanniru85819452017-05-04 18:55:45 -07008795 audio_extn_ip_hdlr_intf_deinit(out->ip_hdlr_handle);
8796 out->ip_hdlr_handle = NULL;
8797 }
8798
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008799 if (out->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05308800 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008801 ret = voice_extn_compress_voip_close_output_stream(&stream->common);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308802 out->started = 0;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05308803 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008804 if(ret != 0)
8805 ALOGE("%s: Compress voip output cannot be closed, error:%d",
8806 __func__, ret);
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008807 } else
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08008808 out_standby(&stream->common);
8809
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07008810 if (is_offload_usecase(out->usecase)) {
Jitendra Naruka1b6513f2014-11-22 19:34:13 -08008811 audio_extn_dts_remove_state_notifier_node(out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008812 destroy_offload_callback_thread(out);
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -07008813 free_offload_usecase(adev, out->usecase);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008814 if (out->compr_config.codec != NULL)
8815 free(out->compr_config.codec);
8816 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008817
Zhou Songbaddf9f2020-11-20 13:57:39 +08008818 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +05308819
Varun Balaraje49253e2017-07-06 19:48:56 +05308820 if (is_interactive_usecase(out->usecase))
8821 free_interactive_usecase(adev, out->usecase);
8822
Ashish Jain83a6cc22016-06-28 14:34:17 +05308823 if (out->convert_buffer != NULL) {
8824 free(out->convert_buffer);
8825 out->convert_buffer = NULL;
8826 }
8827
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07008828 if (adev->voice_tx_output == out)
8829 adev->voice_tx_output = NULL;
8830
Dechen Chai22768452021-07-30 09:29:16 +05308831#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08008832 error_log_destroy(out->error_log);
8833 out->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +05308834#endif
Dhanalakshmi Siddani6c3d0992017-01-16 16:52:33 +05308835 if (adev->primary_output == out)
8836 adev->primary_output = NULL;
8837
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07008838 pthread_cond_destroy(&out->cond);
8839 pthread_mutex_destroy(&out->lock);
Weiyin Jiang280ea742020-09-08 20:28:22 +08008840 pthread_mutex_destroy(&out->pre_lock);
8841 pthread_mutex_destroy(&out->latch_lock);
8842 pthread_mutex_destroy(&out->position_query_lock);
Derek Chenf939fb72018-11-13 13:34:41 -08008843
8844 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008845 free(stream);
Derek Chenf939fb72018-11-13 13:34:41 -08008846 pthread_mutex_unlock(&adev->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07008847 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008848}
8849
8850static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
8851{
8852 struct audio_device *adev = (struct audio_device *)dev;
8853 struct str_parms *parms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008854 char value[32];
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07008855 int val;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008856 int ret;
8857 int status = 0;
Aalique Grahame22e49102018-12-18 14:23:57 -08008858 bool a2dp_reconfig = false;
Zhou Songd6d71752019-05-21 18:08:51 +08008859 struct listnode *node;
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07008860 int controller = -1, stream = -1;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008861
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08008862 ALOGD("%s: enter: %s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008863 parms = str_parms_create_str(kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008864
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05308865 if (!parms)
8866 goto error;
Naresh Tanniru4c630392014-05-12 01:05:52 +05308867
Derek Chen6f293672019-04-01 01:40:24 -07008868 /* notify adev and input/output streams on the snd card status */
8869 adev_snd_mon_cb((void *)adev, parms);
8870
Weiyin Jiang24f55292020-12-22 14:35:46 +08008871 ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
8872 if (ret >= 0) {
8873 list_for_each(node, &adev->active_outputs_list) {
8874 streams_output_ctxt_t *out_ctxt = node_to_item(node,
8875 streams_output_ctxt_t,
8876 list);
8877 out_snd_mon_cb((void *)out_ctxt->output, parms);
8878 }
Derek Chen6f293672019-04-01 01:40:24 -07008879
Weiyin Jiang24f55292020-12-22 14:35:46 +08008880 list_for_each(node, &adev->active_inputs_list) {
8881 streams_input_ctxt_t *in_ctxt = node_to_item(node,
8882 streams_input_ctxt_t,
8883 list);
8884 in_snd_mon_cb((void *)in_ctxt->input, parms);
8885 }
Derek Chen6f293672019-04-01 01:40:24 -07008886 }
8887
Zhou Songd6d71752019-05-21 18:08:51 +08008888 pthread_mutex_lock(&adev->lock);
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308889 ret = str_parms_get_str(parms, "BT_SCO", value, sizeof(value));
8890 if (ret >= 0) {
8891 /* When set to false, HAL should disable EC and NS */
Zhou Songd6d71752019-05-21 18:08:51 +08008892 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0){
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308893 adev->bt_sco_on = true;
Shalini Manjunatha3a2e06e2021-02-01 12:23:49 +05308894 /*
8895 * When ever BT_SCO=ON arrives, make sure to route
8896 * all use cases to SCO device, otherwise due to delay in
8897 * BT_SCO=ON and lack of synchronization with create audio patch
8898 * request for SCO device, some times use case not routed properly to
8899 * SCO device
8900 */
8901 struct audio_usecase *usecase;
8902 struct listnode *node;
8903 list_for_each(node, &adev->usecase_list) {
8904 usecase = node_to_item(node, struct audio_usecase, list);
Anver sadhiquef0efca32021-09-03 15:25:44 +05308905 if (usecase->stream.in && (usecase->type == PCM_CAPTURE) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05308906 (!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 +05308907 ALOGD("BT_SCO ON, switch all in use case to it");
8908 select_devices(adev, usecase->id);
8909 }
Mingshu Pangef517202021-04-22 10:35:00 +08008910 if (usecase->stream.out && (usecase->type == PCM_PLAYBACK ||
8911 usecase->type == VOICE_CALL) &&
Anver sadhique93f3c912021-08-11 11:19:45 +05308912 (!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 +05308913 ALOGD("BT_SCO ON, switch all out use case to it");
8914 select_devices(adev, usecase->id);
8915 }
8916 }
8917 }
8918 else {
Ashish Jain1b9b30c2017-05-18 20:57:40 +05308919 adev->bt_sco_on = false;
Zhou Songd6d71752019-05-21 18:08:51 +08008920 audio_extn_sco_reset_configuration();
Kunlei Zhangd96af8f2019-08-27 16:33:29 +08008921 }
8922 }
8923
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008924 status = voice_set_parameters(adev, parms);
8925 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08008926 goto done;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008927
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008928 status = platform_set_parameters(adev->platform, parms);
8929 if (status != 0)
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08008930 goto done;
8931
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008932 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
8933 if (ret >= 0) {
Vicky Sehrawate240e5d2014-08-12 17:17:04 -07008934 /* When set to false, HAL should disable EC and NS */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008935 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
8936 adev->bluetooth_nrec = true;
8937 else
8938 adev->bluetooth_nrec = false;
8939 }
8940
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07008941 ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
8942 if (ret >= 0) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008943 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
8944 adev->screen_off = false;
8945 else
8946 adev->screen_off = true;
Quinn Male70f20f32019-06-26 16:50:26 -07008947 audio_extn_sound_trigger_update_screen_status(adev->screen_off);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08008948 }
8949
Eric Laurent4b084132018-10-19 17:33:43 -07008950 ret = str_parms_get_int(parms, "rotation", &val);
8951 if (ret >= 0) {
8952 bool reverse_speakers = false;
8953 int camera_rotation = CAMERA_ROTATION_LANDSCAPE;
8954 switch (val) {
8955 // FIXME: note that the code below assumes that the speakers are in the correct placement
8956 // relative to the user when the device is rotated 90deg from its default rotation. This
8957 // assumption is device-specific, not platform-specific like this code.
8958 case 270:
8959 reverse_speakers = true;
8960 camera_rotation = CAMERA_ROTATION_INVERT_LANDSCAPE;
8961 break;
8962 case 0:
8963 case 180:
8964 camera_rotation = CAMERA_ROTATION_PORTRAIT;
8965 break;
8966 case 90:
8967 camera_rotation = CAMERA_ROTATION_LANDSCAPE;
8968 break;
8969 default:
8970 ALOGE("%s: unexpected rotation of %d", __func__, val);
8971 status = -EINVAL;
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07008972 }
Eric Laurent4b084132018-10-19 17:33:43 -07008973 if (status == 0) {
8974 // check and set swap
8975 // - check if orientation changed and speaker active
8976 // - set rotation and cache the rotation value
8977 adev->camera_orientation =
8978 (adev->camera_orientation & ~CAMERA_ROTATION_MASK) | camera_rotation;
8979 if (!audio_extn_is_maxx_audio_enabled())
8980 platform_check_and_set_swap_lr_channels(adev, reverse_speakers);
8981 }
8982 }
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07008983
Mingming Yin514a8bc2014-07-29 15:22:21 -07008984 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
8985 if (ret >= 0) {
8986 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
8987 adev->bt_wb_speech_enabled = true;
8988 else
8989 adev->bt_wb_speech_enabled = false;
8990 }
8991
Zhou Song12c29502019-03-16 10:37:18 +08008992 ret = str_parms_get_str(parms, "bt_swb", value, sizeof(value));
8993 if (ret >= 0) {
8994 val = atoi(value);
8995 adev->swb_speech_mode = val;
8996 }
8997
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07008998 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
8999 if (ret >= 0) {
9000 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309001 audio_devices_t device = (audio_devices_t) val;
Zhou Song681350a2017-10-19 16:28:42 +08009002 if (audio_is_output_device(val) &&
9003 (val & AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009004 ALOGV("cache new ext disp type and edid");
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009005 platform_get_controller_stream_from_params(parms, &controller, &stream);
9006 platform_set_ext_display_device_v2(adev->platform, controller, stream);
9007 ret = platform_get_ext_disp_type_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009008 if (ret < 0) {
9009 ALOGE("%s: Failed to query disp type, ret:%d", __func__, ret);
Manisha Agarwal2f5ff882018-08-08 17:09:29 +05309010 } else {
Vignesh Kulothungan39fc6a22019-08-01 00:55:59 -07009011 platform_cache_edid_v2(adev->platform, controller, stream);
Shiv Maliyappanahallic0656402016-09-03 14:13:26 -07009012 }
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309013 } else if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
vivek mehta344576a2016-04-12 18:56:03 -07009014 /*
9015 * Do not allow AFE proxy port usage by WFD source when USB headset is connected.
9016 * Per AudioPolicyManager, USB device is higher priority than WFD.
9017 * For Voice call over USB headset, voice call audio is routed to AFE proxy ports.
9018 * If WFD use case occupies AFE proxy, it may result unintended behavior while
9019 * starting voice call on USB
9020 */
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009021 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309022 if (ret >= 0)
9023 audio_extn_usb_add_device(device, atoi(value));
9024
Zhou Song6f862822017-11-06 17:27:57 +08009025 if (!audio_extn_usb_is_tunnel_supported()) {
9026 ALOGV("detected USB connect .. disable proxy");
9027 adev->allow_afe_proxy_usage = false;
9028 }
Zhou Song503196b2021-07-23 17:31:05 +08009029 } else if (audio_is_hearing_aid_out_device(device) &&
9030 property_get_bool("persist.vendor.audio.ha_proxy.enabled", false)) {
9031 adev->ha_proxy_enable = true;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009032 }
9033 }
9034
9035 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
9036 if (ret >= 0) {
9037 val = atoi(value);
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309038 audio_devices_t device = (audio_devices_t) val;
Garmond Leunge3b6d482016-10-25 16:48:01 -07009039 /*
9040 * The HDMI / Displayport disconnect handling has been moved to
9041 * audio extension to ensure that its parameters are not
9042 * invalidated prior to updating sysfs of the disconnect event
9043 * Invalidate will be handled by audio_extn_ext_disp_set_parameters()
9044 */
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309045 if (audio_is_usb_out_device(device) || audio_is_usb_in_device(device)) {
Kuirong Wanga9f7cee2016-03-07 11:21:52 -08009046 ret = str_parms_get_str(parms, "card", value, sizeof(value));
Satya Krishna Pindiprolice227962017-12-13 16:07:14 +05309047 if (ret >= 0)
9048 audio_extn_usb_remove_device(device, atoi(value));
9049
Zhou Song6f862822017-11-06 17:27:57 +08009050 if (!audio_extn_usb_is_tunnel_supported()) {
9051 ALOGV("detected USB disconnect .. enable proxy");
9052 adev->allow_afe_proxy_usage = true;
9053 }
Zhou Song503196b2021-07-23 17:31:05 +08009054 } else if (audio_is_hearing_aid_out_device(device)) {
9055 adev->ha_proxy_enable = false;
Pradnya Chaphekar4403bd72014-09-09 09:50:01 -07009056 }
9057 }
9058
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009059 audio_extn_qdsp_set_parameters(adev, parms);
Aalique Grahame22e49102018-12-18 14:23:57 -08009060
9061 status = audio_extn_a2dp_set_parameters(parms, &a2dp_reconfig);
Aniket Kumar Lata23300322019-02-20 22:25:30 -08009062 if (status >= 0 && a2dp_reconfig) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309063 struct audio_usecase *usecase;
9064 struct listnode *node;
9065 list_for_each(node, &adev->usecase_list) {
9066 usecase = node_to_item(node, struct audio_usecase, list);
Weiyin Jiangff56ff32020-05-08 14:32:21 +08009067 if ((usecase->stream.out == NULL) || (usecase->type != PCM_PLAYBACK))
9068 continue;
9069
9070 if (is_a2dp_out_device_type(&usecase->device_list)) {
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309071 ALOGD("reconfigure a2dp... forcing device switch");
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309072 audio_extn_a2dp_set_handoff_mode(true);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309073 ALOGD("Switching to speaker and muting the stream before select_devices");
9074 check_a2dp_restore_l(adev, usecase->stream.out, false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309075 //force device switch to re configure encoder
9076 select_devices(adev, usecase->id);
Manisha Agarwalf1c3b6b2019-06-25 13:00:33 +05309077 ALOGD("Unmuting the stream after select_devices");
Zhou Songbaddf9f2020-11-20 13:57:39 +08009078 check_a2dp_restore_l(adev, usecase->stream.out, true);
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309079 audio_extn_a2dp_set_handoff_mode(false);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309080 break;
Zhou Songd01e7a22020-09-23 22:49:01 +08009081 } else if (is_offload_usecase(usecase->stream.out->usecase)) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009082 pthread_mutex_lock(&usecase->stream.out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +08009083 if (usecase->stream.out->a2dp_muted) {
Weiyin Jiang280ea742020-09-08 20:28:22 +08009084 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
9085 reassign_device_list(&usecase->stream.out->device_list,
9086 AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, "");
9087 check_a2dp_restore_l(adev, usecase->stream.out, true);
9088 break;
9089 }
9090 pthread_mutex_unlock(&usecase->stream.out->latch_lock);
Naresh Tanniru9d027a62015-03-13 01:32:10 +05309091 }
9092 }
9093 }
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009094
9095 //handle vr audio setparam
9096 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9097 value, sizeof(value));
9098 if (ret >= 0) {
9099 ALOGI("Setting vr mode to be %s", value);
9100 if (!strncmp(value, "true", 4)) {
9101 adev->vr_audio_mode_enabled = true;
9102 ALOGI("Setting vr mode to true");
9103 } else if (!strncmp(value, "false", 5)) {
9104 adev->vr_audio_mode_enabled = false;
9105 ALOGI("Setting vr mode to false");
9106 } else {
9107 ALOGI("wrong vr mode set");
9108 }
9109 }
9110
Eric Laurent4b084132018-10-19 17:33:43 -07009111 //FIXME: to be replaced by proper video capture properties API
9112 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_CAMERA_FACING, value, sizeof(value));
9113 if (ret >= 0) {
9114 int camera_facing = CAMERA_FACING_BACK;
9115 if (strcmp(value, AUDIO_PARAMETER_VALUE_FRONT) == 0)
9116 camera_facing = CAMERA_FACING_FRONT;
9117 else if (strcmp(value, AUDIO_PARAMETER_VALUE_BACK) == 0)
9118 camera_facing = CAMERA_FACING_BACK;
9119 else {
9120 ALOGW("%s: invalid camera facing value: %s", __func__, value);
9121 goto done;
9122 }
9123 adev->camera_orientation =
9124 (adev->camera_orientation & ~CAMERA_FACING_MASK) | camera_facing;
9125 struct audio_usecase *usecase;
9126 struct listnode *node;
9127 list_for_each(node, &adev->usecase_list) {
9128 usecase = node_to_item(node, struct audio_usecase, list);
9129 struct stream_in *in = usecase->stream.in;
9130 if (usecase->type == PCM_CAPTURE && in != NULL &&
9131 in->source == AUDIO_SOURCE_CAMCORDER && !in->standby) {
9132 select_devices(adev, in->usecase);
9133 }
9134 }
9135 }
9136
Naresh Tannirucd2353e2016-08-19 00:37:25 +05309137 audio_extn_set_parameters(adev, parms);
Shiv Maliyappanahalli3e064fd2013-12-16 15:54:40 -08009138done:
9139 str_parms_destroy(parms);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009140 pthread_mutex_unlock(&adev->lock);
Preetam Singh Ranawata5f32b42014-09-23 12:12:47 +05309141error:
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009142 ALOGV("%s: exit with code(%d)", __func__, status);
9143 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009144}
9145
9146static char* adev_get_parameters(const struct audio_hw_device *dev,
9147 const char *keys)
9148{
Sidipotu Ashokaa4fa6a2018-12-21 09:19:26 +05309149 ALOGD("%s:%s", __func__, keys);
9150
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009151 struct audio_device *adev = (struct audio_device *)dev;
9152 struct str_parms *reply = str_parms_create();
9153 struct str_parms *query = str_parms_create_str(keys);
9154 char *str;
Naresh Tannirud7205b62014-06-20 02:54:48 +05309155 char value[256] = {0};
9156 int ret = 0;
9157
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009158 if (!query || !reply) {
Alexy Josephaee4fdd2016-01-29 13:02:07 -08009159 if (reply) {
9160 str_parms_destroy(reply);
9161 }
9162 if (query) {
9163 str_parms_destroy(query);
9164 }
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009165 ALOGE("adev_get_parameters: failed to create query or reply");
9166 return NULL;
9167 }
9168
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009169 //handle vr audio getparam
9170
9171 ret = str_parms_get_str(query,
9172 AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9173 value, sizeof(value));
9174
9175 if (ret >= 0) {
9176 bool vr_audio_enabled = false;
9177 pthread_mutex_lock(&adev->lock);
9178 vr_audio_enabled = adev->vr_audio_mode_enabled;
9179 pthread_mutex_unlock(&adev->lock);
9180
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009181 ALOGV("getting vr mode to %d", vr_audio_enabled);
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -08009182
9183 if (vr_audio_enabled) {
9184 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9185 "true");
9186 goto exit;
9187 } else {
9188 str_parms_add_str(reply, AUDIO_PARAMETER_KEY_VR_AUDIO_MODE,
9189 "false");
9190 goto exit;
9191 }
9192 }
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009193
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009194 pthread_mutex_lock(&adev->lock);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009195 audio_extn_get_parameters(adev, query, reply);
Shiv Maliyappanahallif9308492013-12-12 12:18:09 -08009196 voice_get_parameters(adev, query, reply);
Aalique Grahame22e49102018-12-18 14:23:57 -08009197 audio_extn_a2dp_get_parameters(query, reply);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009198 platform_get_parameters(adev->platform, query, reply);
justinwengd5395152019-11-04 12:23:09 +08009199 audio_extn_ma_get_parameters(adev, query, reply);
Naresh Tanniru80659832014-06-04 18:17:56 +05309200 pthread_mutex_unlock(&adev->lock);
9201
Naresh Tannirud7205b62014-06-20 02:54:48 +05309202exit:
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009203 str = str_parms_to_str(reply);
9204 str_parms_destroy(query);
9205 str_parms_destroy(reply);
9206
Aniket Kumar Latad13758f2020-08-06 15:11:36 -07009207 ALOGV("%s: exit: returns - %s", __func__, str);
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009208 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009209}
9210
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009211static int adev_init_check(const struct audio_hw_device *dev __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009212{
9213 return 0;
9214}
9215
9216static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
9217{
Haynes Mathew George5191a852013-09-11 14:19:36 -07009218 int ret;
9219 struct audio_device *adev = (struct audio_device *)dev;
Aalique Grahame22e49102018-12-18 14:23:57 -08009220
9221 audio_extn_extspk_set_voice_vol(adev->extspk, volume);
9222
Haynes Mathew George5191a852013-09-11 14:19:36 -07009223 pthread_mutex_lock(&adev->lock);
9224 /* cache volume */
Shruthi Krishnaace10852013-10-25 14:32:12 -07009225 ret = voice_set_volume(adev, volume);
Haynes Mathew George5191a852013-09-11 14:19:36 -07009226 pthread_mutex_unlock(&adev->lock);
9227 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009228}
9229
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009230static int adev_set_master_volume(struct audio_hw_device *dev __unused,
9231 float volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009232{
9233 return -ENOSYS;
9234}
9235
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009236static int adev_get_master_volume(struct audio_hw_device *dev __unused,
9237 float *volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009238{
9239 return -ENOSYS;
9240}
9241
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009242static int adev_set_master_mute(struct audio_hw_device *dev __unused,
9243 bool muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009244{
9245 return -ENOSYS;
9246}
9247
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009248static int adev_get_master_mute(struct audio_hw_device *dev __unused,
9249 bool *muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009250{
9251 return -ENOSYS;
9252}
9253
9254static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
9255{
9256 struct audio_device *adev = (struct audio_device *)dev;
Garmond Leung5fd0b552018-04-17 11:56:12 -07009257 struct listnode *node;
9258 struct audio_usecase *usecase = NULL;
9259 int ret = 0;
kunleizdc4af9d2017-05-04 12:15:35 +08009260
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009261 pthread_mutex_lock(&adev->lock);
9262 if (adev->mode != mode) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309263 ALOGD("%s: mode %d , prev_mode %d \n", __func__, mode , adev->mode);
9264 adev->prev_mode = adev->mode; /* prev_mode is kept to handle voip concurrency*/
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009265 adev->mode = mode;
Weiyin Jiang96b96f72020-09-22 16:48:19 +08009266 if (mode == AUDIO_MODE_CALL_SCREEN) {
Jaideep Sharma477917f2020-03-13 18:13:33 +05309267 adev->current_call_output = adev->primary_output;
9268 voice_start_call(adev);
9269 } else if (voice_is_in_call_or_call_screen(adev) &&
Kunlei Zhang1d5c7f22019-05-21 14:25:57 +08009270 (mode == AUDIO_MODE_NORMAL ||
9271 (mode == AUDIO_MODE_IN_COMMUNICATION && !voice_is_call_state_active(adev)))) {
Garmond Leung5fd0b552018-04-17 11:56:12 -07009272 list_for_each(node, &adev->usecase_list) {
9273 usecase = node_to_item(node, struct audio_usecase, list);
9274 if (usecase->type == VOICE_CALL)
9275 break;
9276 }
9277 if (usecase &&
9278 audio_is_usb_out_device(usecase->out_snd_device & AUDIO_DEVICE_OUT_ALL_USB)) {
9279 ret = audio_extn_usb_check_and_set_svc_int(usecase,
9280 true);
9281 if (ret != 0) {
9282 /* default service interval was successfully updated,
9283 reopen USB backend with new service interval */
9284 check_usecases_codec_backend(adev,
9285 usecase,
9286 usecase->out_snd_device);
9287 }
9288 }
9289
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009290 voice_stop_call(adev);
Banajit Goswami20cdd212015-09-11 01:11:30 -07009291 platform_set_gsm_mode(adev->platform, false);
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009292 adev->current_call_output = NULL;
kunleizdc4af9d2017-05-04 12:15:35 +08009293 // restore device for other active usecases after stop call
9294 list_for_each(node, &adev->usecase_list) {
9295 usecase = node_to_item(node, struct audio_usecase, list);
9296 select_devices(adev, usecase->id);
9297 }
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009298 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009299 }
9300 pthread_mutex_unlock(&adev->lock);
9301 return 0;
9302}
9303
9304static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
9305{
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009306 int ret;
Aalique Grahame22e49102018-12-18 14:23:57 -08009307 struct audio_device *adev = (struct audio_device *)dev;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009308
9309 pthread_mutex_lock(&adev->lock);
Vidyakumar Athota2850d532013-11-19 16:02:12 -08009310 ALOGD("%s state %d\n", __func__, state);
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009311 ret = voice_set_mic_mute((struct audio_device *)dev, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009312
Derek Chend2530072014-11-24 12:39:14 -08009313 if (adev->ext_hw_plugin)
9314 ret = audio_extn_ext_hw_plugin_set_mic_mute(adev->ext_hw_plugin, state);
Aalique Grahame22e49102018-12-18 14:23:57 -08009315
9316 adev->mic_muted = state;
Shiv Maliyappanahalli3bb73582013-11-05 12:49:15 -08009317 pthread_mutex_unlock(&adev->lock);
9318
9319 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009320}
9321
9322static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
9323{
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -07009324 *state = voice_get_mic_mute((struct audio_device *)dev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009325 return 0;
9326}
9327
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009328static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009329 const struct audio_config *config)
9330{
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009331 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009332
Aalique Grahame22e49102018-12-18 14:23:57 -08009333 /* Don't know if USB HIFI in this context so use true to be conservative */
9334 if (check_input_parameters(config->sample_rate, config->format, channel_count,
9335 true /*is_usb_hifi */) != 0)
9336 return 0;
9337
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009338 return get_input_buffer_size(config->sample_rate, config->format, channel_count,
9339 false /* is_low_latency: since we don't know, be conservative */);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009340}
9341
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009342static bool adev_input_allow_hifi_record(struct audio_device *adev,
9343 audio_devices_t devices,
9344 audio_input_flags_t flags,
9345 audio_source_t source) {
9346 const bool allowed = true;
9347
9348 if (!audio_is_usb_in_device(devices))
9349 return !allowed;
9350
9351 switch (flags) {
9352 case AUDIO_INPUT_FLAG_NONE:
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009353 break;
Haynes Mathew George59862182017-10-24 16:23:57 -07009354 case AUDIO_INPUT_FLAG_FAST: // disallow hifi record for FAST as
9355 // it affects RTD numbers over USB
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009356 default:
9357 return !allowed;
9358 }
9359
9360 switch (source) {
9361 case AUDIO_SOURCE_DEFAULT:
9362 case AUDIO_SOURCE_MIC:
9363 case AUDIO_SOURCE_UNPROCESSED:
9364 break;
9365 default:
9366 return !allowed;
9367 }
9368
9369 switch (adev->mode) {
9370 case 0:
9371 break;
9372 default:
9373 return !allowed;
9374 }
9375
9376 return allowed;
9377}
9378
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009379static int adev_update_voice_comm_input_stream(struct stream_in *in,
9380 struct audio_config *config)
9381{
9382 bool valid_rate = (config->sample_rate == 8000 ||
9383 config->sample_rate == 16000 ||
9384 config->sample_rate == 32000 ||
9385 config->sample_rate == 48000);
9386 bool valid_ch = audio_channel_count_from_in_mask(in->channel_mask) == 1;
9387
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009388 if(!voice_extn_is_compress_voip_supported()) {
kunleiz28c73e72019-03-27 17:24:04 +08009389 if (valid_rate && valid_ch) {
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009390 in->usecase = USECASE_AUDIO_RECORD_VOIP;
9391 in->config = default_pcm_config_voip_copp;
9392 in->config.period_size = VOIP_IO_BUF_SIZE(in->sample_rate,
9393 DEFAULT_VOIP_BUF_DURATION_MS,
9394 DEFAULT_VOIP_BIT_DEPTH_BYTE)/2;
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009395 } else {
9396 ALOGW("%s No valid input in voip, use defaults"
9397 "sample rate %u, channel mask 0x%X",
9398 __func__, config->sample_rate, in->channel_mask);
9399 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009400 in->config.rate = config->sample_rate;
9401 in->sample_rate = config->sample_rate;
9402 } else {
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009403 //XXX needed for voice_extn_compress_voip_open_input_stream
9404 in->config.rate = config->sample_rate;
9405 if ((in->dev->mode == AUDIO_MODE_IN_COMMUNICATION ||
Shalini Manjunathaa763cc42019-08-23 15:13:46 +05309406 in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
Arun Mirpurib1bec9c2019-01-29 16:42:45 -08009407 voice_extn_compress_voip_is_active(in->dev)) &&
9408 (voice_extn_compress_voip_is_format_supported(in->format)) &&
9409 valid_rate && valid_ch) {
9410 voice_extn_compress_voip_open_input_stream(in);
9411 // update rate entries to match config from AF
9412 in->config.rate = config->sample_rate;
9413 in->sample_rate = config->sample_rate;
9414 } else {
9415 ALOGW("%s compress voip not active, use defaults", __func__);
9416 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009417 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009418 return 0;
9419}
9420
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009421static int adev_open_input_stream(struct audio_hw_device *dev,
Bharath Ramachandramurthy76d20892015-04-27 15:47:55 -07009422 audio_io_handle_t handle,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009423 audio_devices_t devices,
9424 struct audio_config *config,
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009425 struct audio_stream_in **stream_in,
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309426 audio_input_flags_t flags,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009427 const char *address,
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009428 audio_source_t source)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009429{
9430 struct audio_device *adev = (struct audio_device *)dev;
9431 struct stream_in *in;
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08009432 int ret = 0, buffer_size, frame_size;
Ravi Kumar Alamandac3bc0812014-09-08 15:34:32 -07009433 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -07009434 bool is_low_latency = false;
Divya Narayanan Poojary45f19192016-09-30 18:52:13 +05309435 bool channel_mask_updated = false;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009436 bool is_usb_dev = audio_is_usb_in_device(devices);
9437 bool may_use_hifi_record = adev_input_allow_hifi_record(adev,
9438 devices,
9439 flags,
9440 source);
Andy Hung94320602018-10-29 18:31:12 -07009441 ALOGV("%s: enter: flags %#x, is_usb_dev %d, may_use_hifi_record %d,"
9442 " sample_rate %u, channel_mask %#x, format %#x",
9443 __func__, flags, is_usb_dev, may_use_hifi_record,
9444 config->sample_rate, config->channel_mask, config->format);
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309445
kunleizdff872d2018-08-20 14:40:33 +08009446 if (is_usb_dev && (!audio_extn_usb_connected(NULL))) {
kunleizd6a9e0c2018-07-30 15:38:52 +08009447 is_usb_dev = false;
9448 devices = AUDIO_DEVICE_IN_BUILTIN_MIC;
9449 ALOGW("%s: ignore set device to non existing USB card, use input device(%#x)",
9450 __func__, devices);
9451 }
9452
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009453 *stream_in = NULL;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009454
9455 if (!(is_usb_dev && may_use_hifi_record)) {
9456 if (config->sample_rate == 0)
9457 config->sample_rate = 48000;
9458 if (config->channel_mask == AUDIO_CHANNEL_NONE)
9459 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9460 if (config->format == AUDIO_FORMAT_DEFAULT)
9461 config->format = AUDIO_FORMAT_PCM_16_BIT;
9462
9463 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
9464
Aalique Grahame22e49102018-12-18 14:23:57 -08009465 if (check_input_parameters(config->sample_rate, config->format, channel_count,
9466 false) != 0)
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009467 return -EINVAL;
Chaithanya Krishna Bacharaju9955b162016-05-25 16:25:53 +05309468 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009469
9470 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -07009471
9472 if (!in) {
9473 ALOGE("failed to allocate input stream");
9474 return -ENOMEM;
9475 }
9476
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309477 ALOGD("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x)\
Manish Dewanganba9fcfa2016-03-24 16:20:06 +05309478 stream_handle(%p) io_handle(%d) source(%d) format %x",__func__, config->sample_rate,
9479 config->channel_mask, devices, &in->stream, handle, source, config->format);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009480 pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
Shiv Maliyappanahalli736d4ce2015-09-28 15:23:06 -07009481 pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -07009482
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009483 in->stream.common.get_sample_rate = in_get_sample_rate;
9484 in->stream.common.set_sample_rate = in_set_sample_rate;
9485 in->stream.common.get_buffer_size = in_get_buffer_size;
9486 in->stream.common.get_channels = in_get_channels;
9487 in->stream.common.get_format = in_get_format;
9488 in->stream.common.set_format = in_set_format;
9489 in->stream.common.standby = in_standby;
9490 in->stream.common.dump = in_dump;
9491 in->stream.common.set_parameters = in_set_parameters;
9492 in->stream.common.get_parameters = in_get_parameters;
9493 in->stream.common.add_audio_effect = in_add_audio_effect;
9494 in->stream.common.remove_audio_effect = in_remove_audio_effect;
9495 in->stream.set_gain = in_set_gain;
9496 in->stream.read = in_read;
9497 in->stream.get_input_frames_lost = in_get_input_frames_lost;
Aalique Grahame22e49102018-12-18 14:23:57 -08009498 in->stream.get_capture_position = in_get_capture_position;
Naresh Tannirudcb47c52018-06-25 16:23:32 +05309499 in->stream.get_active_microphones = in_get_active_microphones;
Paul McLeana50b7332018-12-17 08:24:21 -07009500 in->stream.set_microphone_direction = in_set_microphone_direction;
9501 in->stream.set_microphone_field_dimension = in_set_microphone_field_dimension;
juyuchendb308c22019-01-21 11:57:17 -07009502 in->stream.update_sink_metadata = in_update_sink_metadata;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009503
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009504 list_init(&in->device_list);
9505 update_device_list(&in->device_list, devices, address, true);
Vidyakumar Athota5c398212015-03-31 21:53:21 -07009506 in->source = source;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009507 in->dev = adev;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009508 in->standby = 1;
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009509 in->capture_handle = handle;
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -07009510 in->flags = flags;
Haynes Mathew George46740472017-10-27 18:40:12 -07009511 in->bit_width = 16;
9512 in->af_period_multiplier = 1;
justinweng20fb6d82019-02-21 18:49:00 -07009513 in->direction = MIC_DIRECTION_UNSPECIFIED;
9514 in->zoom = 0;
Carter Hsu2e429db2019-05-14 18:50:52 +08009515 list_init(&in->aec_list);
9516 list_init(&in->ns_list);
Phil Burkd898ba62019-06-20 12:49:01 -07009517 in->mmap_shared_memory_fd = -1; // not open
Haynes Mathew George46740472017-10-27 18:40:12 -07009518
Andy Hung94320602018-10-29 18:31:12 -07009519 ALOGV("%s: source %d, config->channel_mask %#x", __func__, source, config->channel_mask);
Aalique Grahame22e49102018-12-18 14:23:57 -08009520 if (source == AUDIO_SOURCE_VOICE_UPLINK ||
9521 source == AUDIO_SOURCE_VOICE_DOWNLINK) {
9522 /* Force channel config requested to mono if incall
9523 record is being requested for only uplink/downlink */
9524 if (config->channel_mask != AUDIO_CHANNEL_IN_MONO) {
9525 config->channel_mask = AUDIO_CHANNEL_IN_MONO;
9526 ret = -EINVAL;
9527 goto err_open;
9528 }
9529 }
9530
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009531 if (is_usb_dev && may_use_hifi_record) {
9532 /* HiFi record selects an appropriate format, channel, rate combo
9533 depending on sink capabilities*/
9534 ret = read_usb_sup_params_and_compare(false /*is_playback*/,
9535 &config->format,
9536 &in->supported_formats[0],
9537 MAX_SUPPORTED_FORMATS,
9538 &config->channel_mask,
9539 &in->supported_channel_masks[0],
9540 MAX_SUPPORTED_CHANNEL_MASKS,
9541 &config->sample_rate,
9542 &in->supported_sample_rates[0],
9543 MAX_SUPPORTED_SAMPLE_RATES);
9544 if (ret != 0) {
9545 ret = -EINVAL;
9546 goto err_open;
9547 }
9548 channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009549 } else if (config->format == AUDIO_FORMAT_DEFAULT) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309550 config->format = AUDIO_FORMAT_PCM_16_BIT;
Surendar karkaaca3d082017-11-09 15:18:37 +05309551 } else if (property_get_bool("vendor.audio.capture.pcm.32bit.enable", false)
9552 && config->format == AUDIO_FORMAT_PCM_32_BIT) {
9553 in->config.format = PCM_FORMAT_S32_LE;
9554 in->bit_width = 32;
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309555 } else if ((config->format == AUDIO_FORMAT_PCM_FLOAT) ||
9556 (config->format == AUDIO_FORMAT_PCM_32_BIT) ||
9557 (config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED) ||
9558 (config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
9559 bool ret_error = false;
9560 in->bit_width = 24;
9561 /* 24 bit is restricted to UNPROCESSED source only,also format supported
9562 from HAL is 24_packed and 8_24
9563 *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
9564 24_packed return error indicating supported format is 24_packed
9565 *> In case of any other source requesting 24 bit or float return error
9566 indicating format supported is 16 bit only.
9567
9568 on error flinger will retry with supported format passed
9569 */
9570 if ((source != AUDIO_SOURCE_UNPROCESSED) &&
9571 (source != AUDIO_SOURCE_CAMCORDER)) {
9572 config->format = AUDIO_FORMAT_PCM_16_BIT;
9573 if (config->sample_rate > 48000)
9574 config->sample_rate = 48000;
9575 ret_error = true;
Haynes Mathew George46740472017-10-27 18:40:12 -07009576 } else if (!(config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
9577 config->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309578 config->format = AUDIO_FORMAT_PCM_24_BIT_PACKED;
9579 ret_error = true;
9580 }
9581
9582 if (ret_error) {
9583 ret = -EINVAL;
9584 goto err_open;
9585 }
9586 }
9587
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009588 in->channel_mask = config->channel_mask;
9589 in->format = config->format;
9590
9591 in->usecase = USECASE_AUDIO_RECORD;
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309592
Huicheng Liu1404ba12020-09-11 01:03:25 -04009593 /* validate bus device address */
9594 if (compare_device_type(&in->device_list, AUDIO_DEVICE_IN_BUS)) {
9595 /* extract car audio stream index */
9596 in->car_audio_stream =
9597 audio_extn_auto_hal_get_car_audio_stream_from_address(address);
9598 if (in->car_audio_stream < 0) {
9599 ALOGE("%s: invalid car audio stream %x",
9600 __func__, in->car_audio_stream);
9601 ret = -EINVAL;
9602 goto err_open;
9603 }
9604 ALOGV("%s: car_audio_stream 0x%x", __func__, in->car_audio_stream);
Huicheng Liuea4fd422021-01-12 18:34:50 -05009605 ret = audio_extn_auto_hal_open_input_stream(in);
9606 if (ret) {
9607 ALOGE("%s: Failed to open input stream for bus device", __func__);
9608 ret = -EINVAL;
9609 goto err_open;
9610 }
Huicheng Liu1404ba12020-09-11 01:03:25 -04009611 }
9612
Susan Wange3959562021-03-11 11:50:26 -05009613 /* reassign use case for echo reference stream on automotive platforms */
9614 if (in->source == AUDIO_SOURCE_ECHO_REFERENCE) {
9615 ret = audio_extn_auto_hal_open_echo_reference_stream(in);
9616 }
9617
Kogara Naveen Kumar379ff692022-01-31 11:56:51 +05309618 if ((in->source == AUDIO_SOURCE_FM_TUNER) || (devices == AUDIO_DEVICE_IN_FM_TUNER)) {
Samyak Jain0aa07ab2019-04-04 14:36:32 +05309619 if(!get_usecase_from_list(adev, USECASE_AUDIO_RECORD_FM_VIRTUAL))
9620 in->usecase = USECASE_AUDIO_RECORD_FM_VIRTUAL;
9621 else {
9622 ret = -EINVAL;
9623 goto err_open;
9624 }
9625 }
9626
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009627 if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
Deeraj Somanfa377bf2019-02-06 12:57:59 +05309628 (flags & AUDIO_INPUT_FLAG_TIMESTAMP) == 0 &&
9629 (flags & AUDIO_INPUT_FLAG_COMPRESS) == 0 &&
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009630 (flags & AUDIO_INPUT_FLAG_FAST) != 0) {
9631 is_low_latency = true;
9632#if LOW_LATENCY_CAPTURE_USE_CASE
Revathi Uddarajud9f23d92020-07-27 10:55:06 +05309633 if ((flags & AUDIO_INPUT_FLAG_VOIP_TX) != 0)
9634 in->usecase = USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY;
9635 else
9636 in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009637#endif
9638 in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
Aalique Grahame22e49102018-12-18 14:23:57 -08009639 if (!in->realtime) {
9640 in->config = pcm_config_audio_capture;
9641 frame_size = audio_stream_in_frame_size(&in->stream);
9642 buffer_size = get_input_buffer_size(config->sample_rate,
9643 config->format,
9644 channel_count,
9645 is_low_latency);
9646 in->config.period_size = buffer_size / frame_size;
9647 in->config.rate = config->sample_rate;
9648 in->af_period_multiplier = 1;
9649 } else {
9650 // period size is left untouched for rt mode playback
9651 in->config = pcm_config_audio_capture_rt;
9652 in->af_period_multiplier = af_period_multiplier;
9653 }
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009654 }
9655
Susan Wangb803cb52021-10-14 12:03:36 -04009656 /* Additional sample rates added below must also be present
9657 in audio_policy_configuration.xml for mmap_no_irq_in */
9658 bool valid_mmap_record_rate = (config->sample_rate == 8000 ||
9659 config->sample_rate == 16000 ||
Susan Wang89da9042021-10-14 12:03:36 -04009660 config->sample_rate == 24000 ||
Susan Wangb803cb52021-10-14 12:03:36 -04009661 config->sample_rate == 32000 ||
9662 config->sample_rate == 48000);
9663 if (valid_mmap_record_rate &&
9664 ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009665 in->realtime = 0;
9666 in->usecase = USECASE_AUDIO_RECORD_MMAP;
9667 in->config = pcm_config_mmap_capture;
Haynes Mathew George46740472017-10-27 18:40:12 -07009668 in->config.format = pcm_format_from_audio_format(config->format);
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009669 in->stream.start = in_start;
9670 in->stream.stop = in_stop;
9671 in->stream.create_mmap_buffer = in_create_mmap_buffer;
9672 in->stream.get_mmap_position = in_get_mmap_position;
Ramjee Singhbcb3b6c2021-11-17 13:19:16 +05309673 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009674 ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
Haynes Mathew George46740472017-10-27 18:40:12 -07009675 } else if (is_usb_dev && may_use_hifi_record) {
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009676 in->usecase = USECASE_AUDIO_RECORD_HIFI;
9677 in->config = pcm_config_audio_capture;
9678 frame_size = audio_stream_in_frame_size(&in->stream);
9679 buffer_size = get_input_buffer_size(config->sample_rate,
9680 config->format,
9681 channel_count,
9682 false /*is_low_latency*/);
9683 in->config.period_size = buffer_size / frame_size;
9684 in->config.rate = config->sample_rate;
Haynes Mathew George484e8d22017-07-31 18:55:17 -07009685 in->config.format = pcm_format_from_audio_format(config->format);
Karthikeyan Mani07faa602018-08-20 11:01:32 -07009686 switch (config->format) {
9687 case AUDIO_FORMAT_PCM_32_BIT:
9688 in->bit_width = 32;
9689 break;
9690 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
9691 case AUDIO_FORMAT_PCM_8_24_BIT:
9692 in->bit_width = 24;
9693 break;
9694 default:
9695 in->bit_width = 16;
9696 }
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009697 } else if (is_single_device_type_equal(&in->device_list,
9698 AUDIO_DEVICE_IN_TELEPHONY_RX) ||
9699 is_single_device_type_equal(&in->device_list,
9700 AUDIO_DEVICE_IN_PROXY)) {
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009701 if (config->sample_rate == 0)
9702 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
9703 if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
9704 config->sample_rate != 8000) {
9705 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
9706 ret = -EINVAL;
9707 goto err_open;
9708 }
9709 if (config->format == AUDIO_FORMAT_DEFAULT)
9710 config->format = AUDIO_FORMAT_PCM_16_BIT;
9711 if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
9712 config->format = AUDIO_FORMAT_PCM_16_BIT;
9713 ret = -EINVAL;
9714 goto err_open;
9715 }
9716
9717 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
Zhou Song62ea0282020-03-22 19:53:01 +08009718 if (adev->ha_proxy_enable &&
9719 is_single_device_type_equal(&in->device_list,
9720 AUDIO_DEVICE_IN_TELEPHONY_RX))
9721 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY2;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009722 in->config = pcm_config_afe_proxy_record;
Ravi Kumar Alamanda060bc5a2014-09-05 13:51:35 -07009723 in->config.rate = config->sample_rate;
Aalique Grahame22e49102018-12-18 14:23:57 -08009724 in->af_period_multiplier = 1;
9725 } else if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION &&
Shalini Manjunathaac412b32020-01-03 15:00:14 +05309726 (!voice_extn_is_compress_voip_supported()) &&
Aalique Grahame22e49102018-12-18 14:23:57 -08009727 in->flags & AUDIO_INPUT_FLAG_VOIP_TX &&
9728 (config->sample_rate == 8000 ||
9729 config->sample_rate == 16000 ||
9730 config->sample_rate == 32000 ||
9731 config->sample_rate == 48000) &&
9732 channel_count == 1) {
9733 in->usecase = USECASE_AUDIO_RECORD_VOIP;
9734 in->config = pcm_config_audio_capture;
9735 frame_size = audio_stream_in_frame_size(&in->stream);
9736 buffer_size = get_stream_buffer_size(VOIP_CAPTURE_PERIOD_DURATION_MSEC,
9737 config->sample_rate,
9738 config->format,
9739 channel_count, false /*is_low_latency*/);
9740 in->config.period_size = buffer_size / frame_size;
9741 in->config.period_count = VOIP_CAPTURE_PERIOD_COUNT;
9742 in->config.rate = config->sample_rate;
9743 in->af_period_multiplier = 1;
Mingshu Pangc2d65042021-01-14 16:19:10 +08009744 } else if (in->realtime) {
9745 in->config = pcm_config_audio_capture_rt;
9746 in->config.format = pcm_format_from_audio_format(config->format);
9747 in->af_period_multiplier = af_period_multiplier;
Haynes Mathew George46740472017-10-27 18:40:12 -07009748 } else {
Revathi Uddarajud2634032017-12-07 14:42:34 +05309749 int ret_val;
9750 pthread_mutex_lock(&adev->lock);
9751 ret_val = audio_extn_check_and_set_multichannel_usecase(adev,
9752 in, config, &channel_mask_updated);
9753 pthread_mutex_unlock(&adev->lock);
9754
9755 if (!ret_val) {
9756 if (channel_mask_updated == true) {
9757 ALOGD("%s: return error to retry with updated channel mask (%#x)",
9758 __func__, config->channel_mask);
9759 ret = -EINVAL;
9760 goto err_open;
9761 }
9762 ALOGD("%s: created multi-channel session succesfully",__func__);
9763 } else if (audio_extn_compr_cap_enabled() &&
9764 audio_extn_compr_cap_format_supported(config->format) &&
9765 (in->dev->mode != AUDIO_MODE_IN_COMMUNICATION)) {
9766 audio_extn_compr_cap_init(in);
9767 } else if (audio_extn_cin_applicable_stream(in)) {
Deeraj Soman14230922019-01-30 16:39:30 +05309768 ret = audio_extn_cin_configure_input_stream(in, config);
Revathi Uddarajud2634032017-12-07 14:42:34 +05309769 if (ret)
9770 goto err_open;
9771 } else {
9772 in->config = pcm_config_audio_capture;
9773 in->config.rate = config->sample_rate;
9774 in->config.format = pcm_format_from_audio_format(config->format);
Revathi Uddarajud2634032017-12-07 14:42:34 +05309775 in->format = config->format;
9776 frame_size = audio_stream_in_frame_size(&in->stream);
9777 buffer_size = get_input_buffer_size(config->sample_rate,
Haynes Mathew George46740472017-10-27 18:40:12 -07009778 config->format,
9779 channel_count,
9780 is_low_latency);
Dieter Luecking5d57def2018-09-07 14:23:37 +02009781 /* prevent division-by-zero */
9782 if (frame_size == 0) {
9783 ALOGE("%s: Error frame_size==0", __func__);
9784 ret = -EINVAL;
9785 goto err_open;
9786 }
9787
Revathi Uddarajud2634032017-12-07 14:42:34 +05309788 in->config.period_size = buffer_size / frame_size;
Aalique Grahame22e49102018-12-18 14:23:57 -08009789 in->af_period_multiplier = 1;
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009790
Revathi Uddarajud2634032017-12-07 14:42:34 +05309791 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
9792 /* optionally use VOIP usecase depending on config(s) */
9793 ret = adev_update_voice_comm_input_stream(in, config);
9794 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009795
Revathi Uddarajud2634032017-12-07 14:42:34 +05309796 if (ret) {
9797 ALOGE("%s AUDIO_SOURCE_VOICE_COMMUNICATION invalid args", __func__);
9798 goto err_open;
9799 }
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009800 }
Jaideep Sharmad305a4a2020-02-27 14:29:04 +05309801
9802 /* assign concurrent capture usecase if record has to caried out from
9803 * actual hardware input source */
9804 if (audio_extn_is_concurrent_capture_enabled() &&
9805 !audio_is_virtual_input_source(in->source)) {
Samyak Jainc37062f2019-04-25 18:41:06 +05309806 /* Acquire lock to avoid two concurrent use cases initialized to
9807 same pcm record use case */
kunleiz28c73e72019-03-27 17:24:04 +08009808
Samyak Jainc37062f2019-04-25 18:41:06 +05309809 if (in->usecase == USECASE_AUDIO_RECORD) {
9810 pthread_mutex_lock(&adev->lock);
9811 if (!(adev->pcm_record_uc_state)) {
9812 ALOGV("%s: using USECASE_AUDIO_RECORD",__func__);
9813 adev->pcm_record_uc_state = 1;
9814 pthread_mutex_unlock(&adev->lock);
9815 } else {
9816 pthread_mutex_unlock(&adev->lock);
9817 /* Assign compress record use case for second record */
9818 in->usecase = USECASE_AUDIO_RECORD_COMPRESS2;
9819 in->flags |= AUDIO_INPUT_FLAG_COMPRESS;
9820 ALOGV("%s: overriding usecase with USECASE_AUDIO_RECORD_COMPRESS2 and appending compress flag", __func__);
9821 if (audio_extn_cin_applicable_stream(in)) {
9822 in->sample_rate = config->sample_rate;
Deeraj Soman14230922019-01-30 16:39:30 +05309823 ret = audio_extn_cin_configure_input_stream(in, config);
Samyak Jainc37062f2019-04-25 18:41:06 +05309824 if (ret)
9825 goto err_open;
9826 }
9827 }
9828 }
kunleiz28c73e72019-03-27 17:24:04 +08009829 }
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07009830 }
Ramjee Singh82fd0c12019-08-21 16:31:33 +05309831 if (audio_extn_ssr_get_stream() != in)
9832 in->config.channels = channel_count;
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07009833
Aniket Kumar Lata23d8cbf2019-04-10 19:54:46 -07009834 in->sample_rate = in->config.rate;
9835
Dhananjay Kumard6d32152016-10-13 16:11:03 +05309836 audio_extn_utils_update_stream_input_app_type_cfg(adev->platform,
9837 &adev->streams_input_cfg_list,
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009838 &in->device_list, flags, in->format,
Haynes Mathew George4ffef292017-11-21 15:08:02 -08009839 in->sample_rate, in->bit_width,
9840 in->profile, &in->app_type_cfg);
Naresh Tanniru04f71882018-06-26 17:46:22 +05309841 register_format(in->format, in->supported_formats);
9842 register_channel_mask(in->channel_mask, in->supported_channel_masks);
9843 register_sample_rate(in->sample_rate, in->supported_sample_rates);
Dhananjay Kumard6d32152016-10-13 16:11:03 +05309844
Dechen Chai22768452021-07-30 09:29:16 +05309845#ifndef LINUX_ENABLED
Aalique Grahame22e49102018-12-18 14:23:57 -08009846 in->error_log = error_log_create(
9847 ERROR_LOG_ENTRIES,
9848 1000000000 /* aggregate consecutive identical errors within one second */);
Dechen Chai22768452021-07-30 09:29:16 +05309849#endif
Aalique Grahame22e49102018-12-18 14:23:57 -08009850
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009851 /* This stream could be for sound trigger lab,
9852 get sound trigger pcm if present */
9853 audio_extn_sound_trigger_check_and_get_session(in);
9854
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05309855 lock_input_stream(in);
9856 audio_extn_snd_mon_register_listener(in, in_snd_mon_cb);
9857 pthread_mutex_lock(&adev->lock);
9858 in->card_status = adev->card_status;
9859 pthread_mutex_unlock(&adev->lock);
9860 pthread_mutex_unlock(&in->lock);
9861
Aalique Grahame22e49102018-12-18 14:23:57 -08009862 stream_app_type_cfg_init(&in->app_type_cfg);
9863
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009864 *stream_in = &in->stream;
Derek Chenf939fb72018-11-13 13:34:41 -08009865
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009866 ret = io_streams_map_insert(adev, &in->stream.common,
9867 handle, AUDIO_PATCH_HANDLE_NONE);
9868 if (ret != 0)
9869 goto err_open;
9870
Susan Wang6dd13092021-01-25 10:27:11 -05009871 in->in_ctxt.input = in;
Derek Chenf939fb72018-11-13 13:34:41 -08009872
9873 pthread_mutex_lock(&adev->lock);
Susan Wang6dd13092021-01-25 10:27:11 -05009874 list_add_tail(&adev->active_inputs_list, &in->in_ctxt.list);
Derek Chenf939fb72018-11-13 13:34:41 -08009875 pthread_mutex_unlock(&adev->lock);
9876
Eric Laurent994a6932013-07-17 11:51:42 -07009877 ALOGV("%s: exit", __func__);
Ravi Kumar Alamandafae42112013-11-07 23:31:54 -08009878 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009879
9880err_open:
Samyak Jainc37062f2019-04-25 18:41:06 +05309881 if (in->usecase == USECASE_AUDIO_RECORD) {
9882 pthread_mutex_lock(&adev->lock);
9883 adev->pcm_record_uc_state = 0;
9884 pthread_mutex_unlock(&adev->lock);
9885 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009886 free(in);
9887 *stream_in = NULL;
9888 return ret;
9889}
9890
9891static void adev_close_input_stream(struct audio_hw_device *dev,
9892 struct audio_stream_in *stream)
9893{
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009894 int ret;
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07009895 struct stream_in *in = (struct stream_in *)stream;
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -07009896 struct audio_device *adev = (struct audio_device *)dev;
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309897
Sidipotu Ashokf43018c2014-05-02 16:21:50 +05309898 ALOGD("%s: enter:stream_handle(%p)",__func__, in);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08009899
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009900 if (in == NULL) {
9901 ALOGE("%s: audio_stream_in ptr is NULL", __func__);
9902 return;
9903 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -07009904 io_streams_map_remove(adev, in->capture_handle);
9905
Susan Wang6dd13092021-01-25 10:27:11 -05009906 // remove out_ctxt early to prevent the stream
9907 // being opened in a race condition
9908 pthread_mutex_lock(&adev->lock);
9909 list_remove(&in->in_ctxt.list);
9910 pthread_mutex_unlock(&adev->lock);
9911
kunleiz70e57612018-12-28 17:50:23 +08009912 /* must deregister from sndmonitor first to prevent races
9913 * between the callback and close_stream
9914 */
Dhananjay Kumare6293dd2017-05-25 17:25:30 +05309915 audio_extn_snd_mon_unregister_listener(stream);
9916
kunleiz70e57612018-12-28 17:50:23 +08009917 /* Disable echo reference if there are no active input, hfp call
9918 * and sound trigger while closing input stream
9919 */
Eric Laurent637e2d42018-11-15 12:24:31 -08009920 if (adev_get_active_input(adev) == NULL &&
kunleiz70e57612018-12-28 17:50:23 +08009921 !audio_extn_hfp_is_active(adev) &&
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -08009922 !audio_extn_sound_trigger_check_ec_ref_enable()) {
9923 struct listnode out_devices;
9924 list_init(&out_devices);
9925 platform_set_echo_reference(adev, false, &out_devices);
9926 } else
kunleiz70e57612018-12-28 17:50:23 +08009927 audio_extn_sound_trigger_update_ec_ref_status(false);
Venkata Narendra Kumar Gutta1bbbf542014-09-04 19:11:25 +05309928
Dechen Chai22768452021-07-30 09:29:16 +05309929#ifndef LINUX_ENABLED
Weiyin Jiang2995f662019-04-17 14:25:12 +08009930 error_log_destroy(in->error_log);
9931 in->error_log = NULL;
Dechen Chai22768452021-07-30 09:29:16 +05309932#endif
Pallavid7c7a272018-01-16 11:22:55 +05309933
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009934 if (in->usecase == USECASE_COMPRESS_VOIP_CALL) {
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309935 pthread_mutex_lock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009936 ret = voice_extn_compress_voip_close_input_stream(&stream->common);
Venkata Narendra Kumar Gutta91812142014-08-11 18:20:49 +05309937 pthread_mutex_unlock(&adev->lock);
Narsinga Rao Chella05573b72013-11-15 15:21:40 -08009938 if (ret != 0)
9939 ALOGE("%s: Compress voip input cannot be closed, error:%d",
9940 __func__, ret);
9941 } else
9942 in_standby(&stream->common);
9943
Weiyin Jiang280ea742020-09-08 20:28:22 +08009944 pthread_mutex_destroy(&in->lock);
9945 pthread_mutex_destroy(&in->pre_lock);
9946
Revathi Uddarajud2634032017-12-07 14:42:34 +05309947 pthread_mutex_lock(&adev->lock);
Samyak Jain15fda662018-12-18 16:40:52 +05309948 if (in->usecase == USECASE_AUDIO_RECORD) {
9949 adev->pcm_record_uc_state = 0;
9950 }
9951
Kunlei Zhang5d5d8d92020-02-26 15:00:59 +08009952 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION) {
9953 adev->enable_voicerx = false;
9954 }
9955
Shiv Maliyappanahalli5a10aea2015-07-02 10:36:23 -07009956 if (audio_extn_ssr_get_stream() == in) {
Apoorv Raghuvanshi6178a3f2013-10-19 12:38:54 -07009957 audio_extn_ssr_deinit();
9958 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009959
Garmond Leunge2433c32017-09-28 21:51:22 -07009960 if (audio_extn_ffv_get_stream() == in) {
9961 audio_extn_ffv_stream_deinit();
9962 }
9963
Dhananjay Kumaree4d2002016-10-25 18:02:58 +05309964 if (audio_extn_compr_cap_enabled() &&
Mingming Yine62d7842013-10-25 16:26:03 -07009965 audio_extn_compr_cap_format_supported(in->config.format))
9966 audio_extn_compr_cap_deinit();
Dhanalakshmi Siddani74cf00b2016-12-02 13:55:57 +05309967
Dhananjay Kumar7dbe3562019-08-30 05:49:33 +05309968 if (audio_extn_cin_attached_usecase(in))
Manish Dewangan46e07982018-12-13 18:18:59 +05309969 audio_extn_cin_free_input_stream_resources(in);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009970
Mingming Yinfd7607b2016-01-22 12:48:44 -08009971 if (in->is_st_session) {
9972 ALOGV("%s: sound trigger pcm stop lab", __func__);
9973 audio_extn_sound_trigger_stop_lab(in);
9974 }
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -07009975 free(stream);
Revathi Uddarajud2634032017-12-07 14:42:34 +05309976 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08009977 return;
9978}
9979
Aalique Grahame22e49102018-12-18 14:23:57 -08009980/* verifies input and output devices and their capabilities.
9981 *
9982 * This verification is required when enabling extended bit-depth or
9983 * sampling rates, as not all qcom products support it.
9984 *
9985 * Suitable for calling only on initialization such as adev_open().
9986 * It fills the audio_device use_case_table[] array.
9987 *
9988 * Has a side-effect that it needs to configure audio routing / devices
9989 * in order to power up the devices and read the device parameters.
9990 * It does not acquire any hw device lock. Should restore the devices
9991 * back to "normal state" upon completion.
9992 */
9993static int adev_verify_devices(struct audio_device *adev)
9994{
9995 /* enumeration is a bit difficult because one really wants to pull
9996 * the use_case, device id, etc from the hidden pcm_device_table[].
9997 * In this case there are the following use cases and device ids.
9998 *
9999 * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
10000 * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
10001 * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
10002 * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
10003 * [USECASE_AUDIO_RECORD] = {0, 0},
10004 * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
10005 * [USECASE_VOICE_CALL] = {2, 2},
10006 *
10007 * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
10008 * USECASE_VOICE_CALL omitted, but possible for either input or output.
10009 */
10010
10011 /* should be the usecases enabled in adev_open_input_stream() */
10012 static const int test_in_usecases[] = {
10013 USECASE_AUDIO_RECORD,
10014 USECASE_AUDIO_RECORD_LOW_LATENCY, /* does not appear to be used */
10015 };
10016 /* should be the usecases enabled in adev_open_output_stream()*/
10017 static const int test_out_usecases[] = {
10018 USECASE_AUDIO_PLAYBACK_DEEP_BUFFER,
10019 USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
10020 };
10021 static const usecase_type_t usecase_type_by_dir[] = {
10022 PCM_PLAYBACK,
10023 PCM_CAPTURE,
10024 };
10025 static const unsigned flags_by_dir[] = {
10026 PCM_OUT,
10027 PCM_IN,
10028 };
10029
10030 size_t i;
10031 unsigned dir;
10032 const unsigned card_id = adev->snd_card;
10033
10034 for (dir = 0; dir < 2; ++dir) {
10035 const usecase_type_t usecase_type = usecase_type_by_dir[dir];
10036 const unsigned flags_dir = flags_by_dir[dir];
10037 const size_t testsize =
10038 dir ? ARRAY_SIZE(test_in_usecases) : ARRAY_SIZE(test_out_usecases);
10039 const int *testcases =
10040 dir ? test_in_usecases : test_out_usecases;
10041 const audio_devices_t audio_device =
10042 dir ? AUDIO_DEVICE_IN_BUILTIN_MIC : AUDIO_DEVICE_OUT_SPEAKER;
10043
10044 for (i = 0; i < testsize; ++i) {
10045 const audio_usecase_t audio_usecase = testcases[i];
10046 int device_id;
10047 struct pcm_params **pparams;
10048 struct stream_out out;
10049 struct stream_in in;
10050 struct audio_usecase uc_info;
10051 int retval;
10052
10053 pparams = &adev->use_case_table[audio_usecase];
10054 pcm_params_free(*pparams); /* can accept null input */
10055 *pparams = NULL;
10056
10057 /* find the device ID for the use case (signed, for error) */
10058 device_id = platform_get_pcm_device_id(audio_usecase, usecase_type);
10059 if (device_id < 0)
10060 continue;
10061
10062 /* prepare structures for device probing */
10063 memset(&uc_info, 0, sizeof(uc_info));
10064 uc_info.id = audio_usecase;
10065 uc_info.type = usecase_type;
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010066 list_init(&uc_info.device_list);
Aalique Grahame22e49102018-12-18 14:23:57 -080010067 if (dir) {
Aalique Grahame22e49102018-12-18 14:23:57 -080010068 memset(&in, 0, sizeof(in));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010069 list_init(&in.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010070 update_device_list(&in.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010071 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
10072 uc_info.stream.in = &in;
Aalique Grahame22e49102018-12-18 14:23:57 -080010073 }
10074 memset(&out, 0, sizeof(out));
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010075 list_init(&out.device_list);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010076 update_device_list(&out.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010077 uc_info.stream.out = &out;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010078 update_device_list(&uc_info.device_list, audio_device, "", true);
Aalique Grahame22e49102018-12-18 14:23:57 -080010079 uc_info.in_snd_device = SND_DEVICE_NONE;
10080 uc_info.out_snd_device = SND_DEVICE_NONE;
10081 list_add_tail(&adev->usecase_list, &uc_info.list);
10082
10083 /* select device - similar to start_(in/out)put_stream() */
10084 retval = select_devices(adev, audio_usecase);
10085 if (retval >= 0) {
10086 *pparams = pcm_params_get(card_id, device_id, flags_dir);
10087#if LOG_NDEBUG == 0
Aalique Grahame203bee02019-03-13 17:49:36 -070010088 char info[512]; /* for possible debug info */
Aalique Grahame22e49102018-12-18 14:23:57 -080010089 if (*pparams) {
10090 ALOGV("%s: (%s) card %d device %d", __func__,
10091 dir ? "input" : "output", card_id, device_id);
10092 pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
10093 } else {
10094 ALOGV("%s: cannot locate card %d device %d", __func__, card_id, device_id);
10095 }
10096#endif
10097 }
10098
10099 /* deselect device - similar to stop_(in/out)put_stream() */
10100 /* 1. Get and set stream specific mixer controls */
10101 retval = disable_audio_route(adev, &uc_info);
10102 /* 2. Disable the rx device */
10103 retval = disable_snd_device(adev,
10104 dir ? uc_info.in_snd_device : uc_info.out_snd_device);
10105 list_remove(&uc_info.list);
10106 }
10107 }
Aalique Grahame22e49102018-12-18 14:23:57 -080010108 return 0;
10109}
10110
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010111int update_patch(unsigned int num_sources,
10112 const struct audio_port_config *sources,
10113 unsigned int num_sinks,
10114 const struct audio_port_config *sinks,
10115 audio_patch_handle_t handle,
10116 struct audio_patch_info *p_info,
10117 patch_type_t patch_type, bool new_patch)
10118{
Aniket Kumar Latad13758f2020-08-06 15:11:36 -070010119 ALOGV("%s: enter", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010120
10121 if (p_info == NULL) {
10122 ALOGE("%s: Invalid patch pointer", __func__);
10123 return -EINVAL;
10124 }
10125
10126 if (new_patch) {
10127 p_info->patch = (struct audio_patch *) calloc(1, sizeof(struct audio_patch));
10128 if (p_info->patch == NULL) {
10129 ALOGE("%s: Could not allocate patch", __func__);
10130 return -ENOMEM;
10131 }
10132 }
10133
10134 p_info->patch->id = handle;
10135 p_info->patch->num_sources = num_sources;
10136 p_info->patch->num_sinks = num_sinks;
10137
10138 for (int i = 0; i < num_sources; i++)
10139 p_info->patch->sources[i] = sources[i];
10140 for (int i = 0; i < num_sinks; i++)
10141 p_info->patch->sinks[i] = sinks[i];
10142
10143 p_info->patch_type = patch_type;
10144 return 0;
10145}
10146
10147audio_patch_handle_t generate_patch_handle()
10148{
10149 static audio_patch_handle_t patch_handle = AUDIO_PATCH_HANDLE_NONE;
10150 if (++patch_handle < 0)
10151 patch_handle = AUDIO_PATCH_HANDLE_NONE + 1;
10152 return patch_handle;
10153}
10154
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010155int adev_create_audio_patch(struct audio_hw_device *dev,
10156 unsigned int num_sources,
10157 const struct audio_port_config *sources,
10158 unsigned int num_sinks,
10159 const struct audio_port_config *sinks,
10160 audio_patch_handle_t *handle)
10161{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010162 int ret = 0;
10163 struct audio_device *adev = (struct audio_device *)dev;
10164 struct audio_patch_info *p_info = NULL;
10165 patch_type_t patch_type = PATCH_NONE;
10166 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10167 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
10168 struct audio_stream_info *s_info = NULL;
10169 struct audio_stream *stream = NULL;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010170 struct listnode devices;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010171 audio_devices_t device_type = AUDIO_DEVICE_NONE;
10172 bool new_patch = false;
10173 char addr[AUDIO_DEVICE_MAX_ADDRESS_LEN];
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010174
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010175 ALOGD("%s: enter: num sources %d, num_sinks %d, handle %d", __func__,
10176 num_sources, num_sinks, *handle);
10177
10178 if (num_sources == 0 || num_sources > AUDIO_PATCH_PORTS_MAX ||
10179 num_sinks == 0 || num_sinks > AUDIO_PATCH_PORTS_MAX) {
10180 ALOGE("%s: Invalid patch arguments", __func__);
10181 ret = -EINVAL;
10182 goto done;
10183 }
10184
10185 if (num_sources > 1) {
10186 ALOGE("%s: Multiple sources are not supported", __func__);
10187 ret = -EINVAL;
10188 goto done;
10189 }
10190
10191 if (sources == NULL || sinks == NULL) {
10192 ALOGE("%s: Invalid sources or sinks port config", __func__);
10193 ret = -EINVAL;
10194 goto done;
10195 }
10196
10197 ALOGV("%s: source role %d, source type %d", __func__,
10198 sources[0].type, sources[0].role);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010199 list_init(&devices);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010200
10201 // Populate source/sink information and fetch stream info
10202 switch (sources[0].type) {
10203 case AUDIO_PORT_TYPE_DEVICE: // Patch for audio capture or loopback
10204 device_type = sources[0].ext.device.type;
10205 strlcpy(&addr[0], &sources[0].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010206 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010207 if (sinks[0].type == AUDIO_PORT_TYPE_MIX) {
10208 patch_type = PATCH_CAPTURE;
10209 io_handle = sinks[0].ext.mix.handle;
10210 input_source = sinks[0].ext.mix.usecase.source;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010211 ALOGD("%s: Capture patch from device %x to mix %d",
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010212 __func__, device_type, io_handle);
10213 } else {
10214 // Device to device patch is not implemented.
10215 // This space will need changes if audio HAL
10216 // handles device to device patches in the future.
10217 patch_type = PATCH_DEVICE_LOOPBACK;
10218 }
10219 break;
10220 case AUDIO_PORT_TYPE_MIX: // Patch for audio playback
10221 io_handle = sources[0].ext.mix.handle;
10222 for (int i = 0; i < num_sinks; i++) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010223 device_type = sinks[i].ext.device.type;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010224 strlcpy(&addr[0], &sinks[i].ext.device.address[0], AUDIO_DEVICE_MAX_ADDRESS_LEN);
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010225 update_device_list(&devices, device_type, &addr[0], true);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010226 }
10227 patch_type = PATCH_PLAYBACK;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010228 ALOGD("%s: Playback patch from mix handle %d to device %x",
10229 __func__, io_handle, get_device_types(&devices));
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010230 break;
10231 case AUDIO_PORT_TYPE_SESSION:
10232 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010233 ALOGE("%s: Unsupported source type %d", __func__, sources[0].type);
10234 ret = -EINVAL;
10235 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010236 }
10237
10238 pthread_mutex_lock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010239
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010240 // Generate patch info and update patch
10241 if (*handle == AUDIO_PATCH_HANDLE_NONE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010242 *handle = generate_patch_handle();
10243 p_info = (struct audio_patch_info *)
10244 calloc(1, sizeof(struct audio_patch_info));
10245 if (p_info == NULL) {
10246 ALOGE("%s: Failed to allocate memory", __func__);
10247 pthread_mutex_unlock(&adev->lock);
10248 ret = -ENOMEM;
10249 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010250 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010251 new_patch = true;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010252 } else {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010253 p_info = fetch_patch_info_l(adev, *handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010254 if (p_info == NULL) {
10255 ALOGE("%s: Unable to fetch patch for received patch handle %d",
10256 __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010257 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010258 ret = -EINVAL;
10259 goto done;
10260 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010261 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010262 update_patch(num_sources, sources, num_sinks, sinks,
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010263 *handle, p_info, patch_type, new_patch);
10264
10265 // Fetch stream info of associated mix for playback or capture patches
10266 if (p_info->patch_type == PATCH_PLAYBACK ||
10267 p_info->patch_type == PATCH_CAPTURE) {
10268 s_info = hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10269 if (s_info == NULL) {
10270 ALOGE("%s: Failed to obtain stream info", __func__);
10271 if (new_patch)
10272 free(p_info);
10273 pthread_mutex_unlock(&adev->lock);
10274 ret = -EINVAL;
10275 goto done;
10276 }
10277 ALOGV("%s: Fetched stream info with io_handle %d", __func__, io_handle);
10278 s_info->patch_handle = *handle;
10279 stream = s_info->stream;
10280 }
10281 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010282
10283 // Update routing for stream
10284 if (stream != NULL) {
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010285 if (p_info->patch_type == PATCH_PLAYBACK) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010286 ret = route_output_stream((struct stream_out *) stream, &devices);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010287 clear_devices(&devices);
10288 } else if (p_info->patch_type == PATCH_CAPTURE) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010289 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Revathi Uddaraju4255a632021-12-02 05:11:13 -080010290 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010291 if (ret < 0) {
10292 pthread_mutex_lock(&adev->lock);
10293 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10294 if (new_patch)
10295 free(p_info);
10296 pthread_mutex_unlock(&adev->lock);
10297 ALOGE("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10298 goto done;
10299 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010300 }
10301
10302 // Add new patch to patch map
10303 if (!ret && new_patch) {
10304 pthread_mutex_lock(&adev->lock);
10305 hashmapPut(adev->patch_map, (void *) (intptr_t) *handle, (void *) p_info);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010306 ALOGD("%s: Added a new patch with handle %d", __func__, *handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010307 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010308 }
10309
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010310done:
10311 audio_extn_hw_loopback_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010312 num_sources,
10313 sources,
10314 num_sinks,
10315 sinks,
10316 handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010317 audio_extn_auto_hal_create_audio_patch(dev,
Derek Chenf939fb72018-11-13 13:34:41 -080010318 num_sources,
10319 sources,
10320 num_sinks,
10321 sinks,
10322 handle);
10323 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010324}
10325
10326int adev_release_audio_patch(struct audio_hw_device *dev,
10327 audio_patch_handle_t handle)
10328{
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010329 struct audio_device *adev = (struct audio_device *) dev;
10330 int ret = 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010331 audio_source_t input_source = AUDIO_SOURCE_DEFAULT;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010332 struct audio_stream *stream = NULL;
Derek Chenf939fb72018-11-13 13:34:41 -080010333
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010334 if (handle == AUDIO_PATCH_HANDLE_NONE) {
10335 ALOGE("%s: Invalid patch handle %d", __func__, handle);
10336 ret = -EINVAL;
10337 goto done;
10338 }
10339
10340 ALOGD("%s: Remove patch with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010341 pthread_mutex_lock(&adev->lock);
10342 struct audio_patch_info *p_info = fetch_patch_info_l(adev, handle);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010343 if (p_info == NULL) {
10344 ALOGE("%s: Patch info not found with handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010345 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010346 ret = -EINVAL;
10347 goto done;
10348 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010349 struct audio_patch *patch = p_info->patch;
10350 if (patch == NULL) {
10351 ALOGE("%s: Patch not found for handle %d", __func__, handle);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010352 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010353 ret = -EINVAL;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010354 goto done;
10355 }
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010356 audio_io_handle_t io_handle = AUDIO_IO_HANDLE_NONE;
10357 switch (patch->sources[0].type) {
10358 case AUDIO_PORT_TYPE_MIX:
10359 io_handle = patch->sources[0].ext.mix.handle;
10360 break;
10361 case AUDIO_PORT_TYPE_DEVICE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010362 if (p_info->patch_type == PATCH_CAPTURE)
10363 io_handle = patch->sinks[0].ext.mix.handle;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010364 break;
10365 case AUDIO_PORT_TYPE_SESSION:
10366 case AUDIO_PORT_TYPE_NONE:
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010367 pthread_mutex_unlock(&adev->lock);
10368 ret = -EINVAL;
10369 goto done;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010370 }
10371
10372 // Remove patch and reset patch handle in stream info
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010373 patch_type_t patch_type = p_info->patch_type;
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010374 patch_map_remove_l(adev, handle);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010375 if (patch_type == PATCH_PLAYBACK ||
10376 patch_type == PATCH_CAPTURE) {
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010377 struct audio_stream_info *s_info =
10378 hashmapGet(adev->io_streams_map, (void *) (intptr_t) io_handle);
10379 if (s_info == NULL) {
10380 ALOGE("%s: stream for io_handle %d is not available", __func__, io_handle);
10381 pthread_mutex_unlock(&adev->lock);
10382 goto done;
10383 }
10384 s_info->patch_handle = AUDIO_PATCH_HANDLE_NONE;
10385 stream = s_info->stream;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010386 }
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010387 pthread_mutex_unlock(&adev->lock);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010388
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010389 if (stream != NULL) {
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010390 struct listnode devices;
10391 list_init(&devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010392 if (patch_type == PATCH_PLAYBACK)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010393 ret = route_output_stream((struct stream_out *) stream, &devices);
Aniket Kumar Latace2b9fa2020-03-10 15:04:15 -070010394 else if (patch_type == PATCH_CAPTURE)
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010395 ret = route_input_stream((struct stream_in *) stream, &devices, input_source);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010396 }
10397
10398 if (ret < 0)
10399 ALOGW("%s: Stream routing failed for io_handle %d", __func__, io_handle);
10400
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010401done:
10402 audio_extn_hw_loopback_release_audio_patch(dev, handle);
10403 audio_extn_auto_hal_release_audio_patch(dev, handle);
10404
10405 ALOGV("%s: Successfully released patch %d", __func__, handle);
Derek Chenf939fb72018-11-13 13:34:41 -080010406 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010407}
10408
10409int adev_get_audio_port(struct audio_hw_device *dev, struct audio_port *config)
10410{
Derek Chenf13dd492018-11-13 14:53:51 -080010411 int ret = 0;
10412
10413 ret = audio_extn_hw_loopback_get_audio_port(dev, config);
10414 ret |= audio_extn_auto_hal_get_audio_port(dev, config);
10415 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010416}
10417
10418int adev_set_audio_port_config(struct audio_hw_device *dev,
10419 const struct audio_port_config *config)
10420{
Derek Chenf13dd492018-11-13 14:53:51 -080010421 int ret = 0;
10422
10423 ret = audio_extn_hw_loopback_set_audio_port_config(dev, config);
10424 ret |= audio_extn_auto_hal_set_audio_port_config(dev, config);
10425 return ret;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010426}
10427
Ravi Kumar Alamandabdf14162014-09-05 16:14:17 -070010428static int adev_dump(const audio_hw_device_t *device __unused,
10429 int fd __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010430{
10431 return 0;
10432}
10433
10434static int adev_close(hw_device_t *device)
10435{
Aalique Grahame22e49102018-12-18 14:23:57 -080010436 size_t i;
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010437 struct audio_device *adev_temp = (struct audio_device *)device;
Kiran Kandi910e1862013-10-29 13:29:42 -070010438
Preetam Singh Ranawatacc64542019-06-24 15:11:28 +053010439 if (!adev_temp)
Kiran Kandi910e1862013-10-29 13:29:42 -070010440 return 0;
10441
10442 pthread_mutex_lock(&adev_init_lock);
10443
10444 if ((--audio_device_ref_count) == 0) {
Sujin Panicker390724d2019-04-26 10:43:36 +053010445 if (audio_extn_spkr_prot_is_enabled())
10446 audio_extn_spkr_prot_deinit();
Jaideep Sharmaa2b49672019-09-10 20:37:03 +053010447 audio_extn_battery_properties_listener_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010448 audio_extn_snd_mon_unregister_listener(adev);
Ravi Kumar Alamanda8fa6b192014-09-09 16:06:42 -070010449 audio_extn_sound_trigger_deinit(adev);
Kiran Kandide144c82013-11-20 15:58:32 -080010450 audio_extn_listen_deinit(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010451 audio_extn_qdsp_deinit();
Aalique Grahame22e49102018-12-18 14:23:57 -080010452 audio_extn_extspk_deinit(adev->extspk);
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010453 audio_extn_utils_release_streams_cfg_lists(
10454 &adev->streams_output_cfg_list,
10455 &adev->streams_input_cfg_list);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010456 if (audio_extn_qap_is_enabled())
10457 audio_extn_qap_deinit();
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010458 if (audio_extn_qaf_is_enabled())
10459 audio_extn_qaf_deinit();
Kiran Kandi910e1862013-10-29 13:29:42 -070010460 audio_route_free(adev->audio_route);
Weiyin Jiangfa65d3e2019-03-05 23:39:45 +080010461 audio_extn_gef_deinit(adev);
Kiran Kandi910e1862013-10-29 13:29:42 -070010462 free(adev->snd_dev_ref_cnt);
10463 platform_deinit(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080010464 for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
10465 pcm_params_free(adev->use_case_table[i]);
10466 }
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010467 if (adev->adm_deinit)
10468 adev->adm_deinit(adev->adm_data);
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010469 qahwi_deinit(device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080010470 audio_extn_adsp_hdlr_deinit();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010471 audio_extn_snd_mon_deinit();
Siddartha Shaik44dd7702017-06-14 12:13:25 +053010472 audio_extn_hw_loopback_deinit(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070010473 audio_extn_ffv_deinit();
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053010474 if (adev->device_cfg_params) {
10475 free(adev->device_cfg_params);
10476 adev->device_cfg_params = NULL;
10477 }
Derek Chend2530072014-11-24 12:39:14 -080010478 if(adev->ext_hw_plugin)
10479 audio_extn_ext_hw_plugin_deinit(adev->ext_hw_plugin);
Derek Chenae7b0342019-02-08 15:17:04 -080010480 audio_extn_auto_hal_deinit();
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010481 free_map(adev->patch_map);
10482 free_map(adev->io_streams_map);
Kiran Kandi910e1862013-10-29 13:29:42 -070010483 free(device);
10484 adev = NULL;
10485 }
10486 pthread_mutex_unlock(&adev_init_lock);
Vatsal Buchac09ae062018-11-14 13:25:08 +053010487 enable_gcov();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010488 return 0;
10489}
10490
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010491/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
10492 * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
10493 * just that it _might_ work.
10494 */
10495static int period_size_is_plausible_for_low_latency(int period_size)
10496{
10497 switch (period_size) {
10498 case 160:
Ravi Kumar Alamanda474de5a2015-06-25 20:08:01 -070010499 case 192:
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010500 case 240:
10501 case 320:
10502 case 480:
10503 return 1;
10504 default:
10505 return 0;
10506 }
10507}
10508
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010509static void adev_snd_mon_cb(void *cookie, struct str_parms *parms)
10510{
10511 bool is_snd_card_status = false;
10512 bool is_ext_device_status = false;
10513 char value[32];
10514 int card = -1;
10515 card_status_t status;
10516
10517 if (cookie != adev || !parms)
10518 return;
10519
10520 if (!parse_snd_card_status(parms, &card, &status)) {
10521 is_snd_card_status = true;
10522 } else if (0 < str_parms_get_str(parms, "ext_audio_device", value, sizeof(value))) {
10523 is_ext_device_status = true;
10524 } else {
10525 // not a valid event
10526 return;
10527 }
10528
10529 pthread_mutex_lock(&adev->lock);
10530 if (card == adev->snd_card || is_ext_device_status) {
10531 if (is_snd_card_status && adev->card_status != status) {
Jaideep Sharmacb402512020-09-24 17:51:07 +053010532 ALOGD("%s card_status %d", __func__, status);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010533 adev->card_status = status;
10534 platform_snd_card_update(adev->platform, status);
10535 audio_extn_fm_set_parameters(adev, parms);
Derek Chend6f371d2019-03-01 13:45:58 -080010536 audio_extn_auto_hal_set_parameters(adev, parms);
Zhou Song4f43e352019-07-02 00:32:23 +080010537 if (status == CARD_STATUS_OFFLINE)
10538 audio_extn_sco_reset_configuration();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010539 } else if (is_ext_device_status) {
10540 platform_set_parameters(adev->platform, parms);
10541 }
10542 }
10543 pthread_mutex_unlock(&adev->lock);
10544 return;
10545}
10546
Weiyin Jiang280ea742020-09-08 20:28:22 +080010547/* adev lock held */
10548int check_a2dp_restore_l(struct audio_device *adev, struct stream_out *out, bool restore)
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010549{
10550 struct audio_usecase *uc_info;
Zhou Song407e5aa2020-12-27 19:13:04 +080010551 struct audio_usecase *usecase;
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010552 struct listnode devices;
Zhou Song407e5aa2020-12-27 19:13:04 +080010553 struct listnode *node;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010554
10555 uc_info = get_usecase_from_list(adev, out->usecase);
10556 if (uc_info == NULL) {
10557 ALOGE("%s: Could not find the usecase (%d) in the list",
10558 __func__, out->usecase);
10559 return -EINVAL;
10560 }
Aniket Kumar Lata9c2fd892020-01-22 22:20:00 -080010561 list_init(&devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010562
Zhou Songbaddf9f2020-11-20 13:57:39 +080010563 ALOGD("%s: enter: usecase(%d: %s), a2dp muted %d", __func__,
10564 out->usecase, use_case_table[out->usecase], out->a2dp_muted);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010565
10566 if (restore) {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010567 pthread_mutex_lock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010568 // restore A2DP device for active usecases and unmute if required
Aniket Kumar Lata0e6e1e52019-11-14 21:43:55 -080010569 if (is_a2dp_out_device_type(&out->device_list)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010570 ALOGD("%s: restoring A2dp and unmuting stream", __func__);
Zhou Songe5225132019-09-26 15:33:36 +080010571 if (uc_info->out_snd_device != SND_DEVICE_OUT_BT_A2DP)
10572 select_devices(adev, uc_info->id);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010573
10574 if (is_offload_usecase(out->usecase)) {
10575 if (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)
Weiyin Jiang280ea742020-09-08 20:28:22 +080010576 out_set_compr_volume(&out->stream, out->volume_l, out->volume_r);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010577 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP) {
10578 out_set_voip_volume(&out->stream, out->volume_l, out->volume_r);
10579 } else {
10580 out_set_pcm_volume(&out->stream, out->volume_l, out->volume_r);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010581 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010582 out->a2dp_muted = false;
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010583 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010584 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010585 } else {
Weiyin Jiang280ea742020-09-08 20:28:22 +080010586 pthread_mutex_lock(&out->latch_lock);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010587 // mute stream and switch to speaker if suspended
10588 if (!out->a2dp_muted && !out->standby) {
Zhou Songbaddf9f2020-11-20 13:57:39 +080010589 assign_devices(&devices, &out->device_list);
10590 reassign_device_list(&out->device_list, AUDIO_DEVICE_OUT_SPEAKER, "");
Zhou Song407e5aa2020-12-27 19:13:04 +080010591 list_for_each(node, &adev->usecase_list) {
10592 usecase = node_to_item(node, struct audio_usecase, list);
Zhou Songe63b6fe2021-04-15 13:54:46 +080010593 if ((usecase->type != PCM_CAPTURE) && (usecase != uc_info) &&
10594 !is_a2dp_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songcf77af02021-05-14 18:21:14 +080010595 !is_sco_out_device_type(&usecase->stream.out->device_list) &&
Zhou Songe63b6fe2021-04-15 13:54:46 +080010596 platform_check_backends_match(SND_DEVICE_OUT_SPEAKER,
10597 usecase->out_snd_device)) {
Zhou Song407e5aa2020-12-27 19:13:04 +080010598 assign_devices(&out->device_list, &usecase->stream.out->device_list);
10599 break;
10600 }
10601 }
Zhou Songcf77af02021-05-14 18:21:14 +080010602 if ((is_a2dp_out_device_type(&devices) && list_length(&devices) == 1) ||
10603 (uc_info->out_snd_device == SND_DEVICE_OUT_BT_A2DP)) {
Zhou Song8edbbdb2021-01-14 16:48:03 +080010604 out->a2dp_muted = true;
10605 if (is_offload_usecase(out->usecase)) {
10606 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10607 compress_pause(out->compr);
10608 out_set_compr_volume(&out->stream, (float)0, (float)0);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010609 } else {
Weiyin Jiang906db3c2021-03-02 13:17:04 +080010610 if (out->usecase == USECASE_AUDIO_PLAYBACK_VOIP)
10611 out_set_voip_volume(&out->stream, (float)0, (float)0);
10612 else
10613 out_set_pcm_volume(&out->stream, (float)0, (float)0);
10614
Zhou Song8edbbdb2021-01-14 16:48:03 +080010615 /* wait for stale pcm drained before switching to speaker */
10616 uint32_t latency =
10617 (out->config.period_count * out->config.period_size * 1000) /
10618 (out->config.rate);
10619 usleep(latency * 1000);
10620 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010621 }
10622 select_devices(adev, out->usecase);
Zhou Song8edbbdb2021-01-14 16:48:03 +080010623 ALOGD("%s: switched to device:%s and stream muted:%d", __func__,
10624 platform_get_snd_device_name(uc_info->out_snd_device), out->a2dp_muted);
Zhou Songbaddf9f2020-11-20 13:57:39 +080010625 if (is_offload_usecase(out->usecase)) {
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010626 if (out->offload_state == OFFLOAD_STATE_PLAYING)
10627 compress_resume(out->compr);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010628 }
Zhou Songbaddf9f2020-11-20 13:57:39 +080010629 assign_devices(&out->device_list, &devices);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010630 }
Weiyin Jiang280ea742020-09-08 20:28:22 +080010631 pthread_mutex_unlock(&out->latch_lock);
Chaithanya Krishna Bacharaju69d2e4c2017-05-26 18:22:46 +053010632 }
10633 ALOGV("%s: exit", __func__);
10634 return 0;
10635}
10636
Haynes Mathew George01156f92018-04-13 15:29:54 -070010637void adev_on_battery_status_changed(bool charging)
10638{
10639 pthread_mutex_lock(&adev->lock);
10640 ALOGI("%s: battery status changed to %scharging", __func__, charging ? "" : "not ");
10641 adev->is_charging = charging;
Zhou Songc1088ea2018-06-12 00:17:29 +080010642 audio_extn_sound_trigger_update_battery_status(charging);
Haynes Mathew George01156f92018-04-13 15:29:54 -070010643 pthread_mutex_unlock(&adev->lock);
10644}
10645
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010646static int adev_open(const hw_module_t *module, const char *name,
10647 hw_device_t **device)
10648{
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010649 int ret;
Derek Chenf939fb72018-11-13 13:34:41 -080010650 char value[PROPERTY_VALUE_MAX] = {0};
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053010651 char mixer_ctl_name[128] = {0};
10652 struct mixer_ctl *ctl = NULL;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010653
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -080010654 ALOGD("%s: enter", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010655 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
10656
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010657 pthread_mutex_lock(&adev_init_lock);
Kiran Kandi910e1862013-10-29 13:29:42 -070010658 if (audio_device_ref_count != 0){
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010659 *device = &adev->device.common;
Kiran Kandi910e1862013-10-29 13:29:42 -070010660 audio_device_ref_count++;
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010661 ALOGD("%s: returning existing instance of adev", __func__);
10662 ALOGD("%s: exit", __func__);
10663 pthread_mutex_unlock(&adev_init_lock);
10664 return 0;
10665 }
10666
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010667 adev = calloc(1, sizeof(struct audio_device));
10668
Haynes Mathew Georgeb51ceb12014-06-30 13:56:18 -070010669 if (!adev) {
10670 pthread_mutex_unlock(&adev_init_lock);
10671 return -ENOMEM;
10672 }
10673
Ravi Kumar Alamanda40703102014-04-24 10:34:41 -070010674 pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
10675
Weiyin Jiange6ce6312019-01-28 18:28:22 +080010676 // register audio ext hidl at the earliest
10677 audio_extn_hidl_init();
Revathi Uddaraju1eac8b02017-05-18 17:13:33 +053010678#ifdef DYNAMIC_LOG_ENABLED
10679 register_for_dynamic_logging("hal");
10680#endif
10681
Derek Chenf939fb72018-11-13 13:34:41 -080010682 /* default audio HAL major version */
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010683 uint32_t maj_version = 3;
Derek Chenf939fb72018-11-13 13:34:41 -080010684 if(property_get("vendor.audio.hal.maj.version", value, NULL))
10685 maj_version = atoi(value);
10686
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010687 adev->device.common.tag = HARDWARE_DEVICE_TAG;
Derek Chenf939fb72018-11-13 13:34:41 -080010688 adev->device.common.version = HARDWARE_DEVICE_API_VERSION(maj_version, 0);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010689 adev->device.common.module = (struct hw_module_t *)module;
10690 adev->device.common.close = adev_close;
10691
10692 adev->device.init_check = adev_init_check;
10693 adev->device.set_voice_volume = adev_set_voice_volume;
10694 adev->device.set_master_volume = adev_set_master_volume;
10695 adev->device.get_master_volume = adev_get_master_volume;
10696 adev->device.set_master_mute = adev_set_master_mute;
10697 adev->device.get_master_mute = adev_get_master_mute;
10698 adev->device.set_mode = adev_set_mode;
10699 adev->device.set_mic_mute = adev_set_mic_mute;
10700 adev->device.get_mic_mute = adev_get_mic_mute;
10701 adev->device.set_parameters = adev_set_parameters;
10702 adev->device.get_parameters = adev_get_parameters;
10703 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
10704 adev->device.open_output_stream = adev_open_output_stream;
10705 adev->device.close_output_stream = adev_close_output_stream;
10706 adev->device.open_input_stream = adev_open_input_stream;
10707 adev->device.close_input_stream = adev_close_input_stream;
Siddartha Shaik31b530e2017-05-19 15:26:33 +053010708 adev->device.create_audio_patch = adev_create_audio_patch;
10709 adev->device.release_audio_patch = adev_release_audio_patch;
10710 adev->device.get_audio_port = adev_get_audio_port;
10711 adev->device.set_audio_port_config = adev_set_audio_port_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010712 adev->device.dump = adev_dump;
Naresh Tannirudcb47c52018-06-25 16:23:32 +053010713 adev->device.get_microphones = adev_get_microphones;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010714
10715 /* Set the default route before the PCM stream is opened */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010716 adev->mode = AUDIO_MODE_NORMAL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -080010717 adev->primary_output = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010718 adev->out_device = AUDIO_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010719 adev->bluetooth_nrec = true;
Ravi Kumar Alamandaf9967042013-02-14 19:35:14 -080010720 adev->acdb_settings = TTY_MODE_OFF;
vivek mehta344576a2016-04-12 18:56:03 -070010721 adev->allow_afe_proxy_usage = true;
Ashish Jain1b9b30c2017-05-18 20:57:40 +053010722 adev->bt_sco_on = false;
Eric Laurent07eeafd2013-10-06 12:52:49 -070010723 /* adev->cur_hdmi_channels = 0; by calloc() */
Eric Laurentb23d5282013-05-14 15:27:20 -070010724 adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
vivek mehtaae1018c2019-05-09 12:19:57 -070010725 /* Init audio and voice feature */
10726 audio_extn_feature_init();
10727 voice_extn_feature_init();
Shiv Maliyappanahalli34b585f2013-10-01 15:49:05 -070010728 voice_init(adev);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -080010729 list_init(&adev->usecase_list);
Derek Chenf939fb72018-11-13 13:34:41 -080010730 list_init(&adev->active_inputs_list);
10731 list_init(&adev->active_outputs_list);
Rahul Sharma99770982019-03-06 17:05:26 +053010732 list_init(&adev->audio_patch_record_list);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010733 adev->io_streams_map = hashmapCreate(AUDIO_IO_PORTS_MAX, audio_extn_utils_hash_fn,
10734 audio_extn_utils_hash_eq);
10735 if (!adev->io_streams_map) {
10736 ALOGE("%s: Could not create io streams map", __func__);
10737 ret = -ENOMEM;
10738 goto adev_open_err;
10739 }
10740 adev->patch_map = hashmapCreate(AUDIO_PATCH_PORTS_MAX, audio_extn_utils_hash_fn,
10741 audio_extn_utils_hash_eq);
10742 if (!adev->patch_map) {
10743 ALOGE("%s: Could not create audio patch map", __func__);
10744 ret = -ENOMEM;
10745 goto adev_open_err;
10746 }
Krishnankutty Kolathappilly0b2de1c2014-02-14 14:45:49 -080010747 adev->cur_wfd_channels = 2;
Subhash Chandra Bose Naripeddy16ff4f82014-04-01 21:03:10 -070010748 adev->offload_usecases_state = 0;
Samyak Jain15fda662018-12-18 16:40:52 +053010749 adev->pcm_record_uc_state = 0;
Ashish Jain81eb2a82015-05-13 10:52:34 +053010750 adev->is_channel_status_set = false;
Sudheer Papothifa9d2282015-09-17 01:53:25 +053010751 adev->perf_lock_opts[0] = 0x101;
10752 adev->perf_lock_opts[1] = 0x20E;
10753 adev->perf_lock_opts_size = 2;
Xiaojun Sang785b5da2017-08-03 15:52:29 +080010754 adev->dsp_bit_width_enforce_mode = 0;
Aalique Grahame552b0832019-03-11 10:16:38 -070010755 adev->enable_hfp = false;
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053010756 adev->use_old_pspd_mix_ctrl = false;
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070010757 adev->adm_routing_changed = false;
Revathi Uddarajub26e3932020-06-10 14:51:02 +053010758 adev->a2dp_started = false;
Zhou Song503196b2021-07-23 17:31:05 +080010759 adev->ha_proxy_enable = false;
Naresh Tanniru4c630392014-05-12 01:05:52 +053010760
Zhou Song68ebc352019-12-05 17:11:15 +080010761 audio_extn_perf_lock_init();
10762
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010763 /* Loads platform specific libraries dynamically */
Eric Laurentb23d5282013-05-14 15:27:20 -070010764 adev->platform = platform_init(adev);
10765 if (!adev->platform) {
Eric Laurentb23d5282013-05-14 15:27:20 -070010766 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010767 ret = -EINVAL;
10768 goto adev_open_err;
Eric Laurentb23d5282013-05-14 15:27:20 -070010769 }
Eric Laurentc4aef752013-09-12 17:45:53 -070010770
Aalique Grahame22e49102018-12-18 14:23:57 -080010771 adev->extspk = audio_extn_extspk_init(adev);
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010772 if (audio_extn_qap_is_enabled()) {
10773 ret = audio_extn_qap_init(adev);
10774 if (ret < 0) {
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010775 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010776 goto adev_open_err;
Sidipotu Ashokd2f10ba2019-05-06 15:41:56 +053010777 }
10778 adev->device.open_output_stream = audio_extn_qap_open_output_stream;
10779 adev->device.close_output_stream = audio_extn_qap_close_output_stream;
10780 }
Aalique Grahame22e49102018-12-18 14:23:57 -080010781
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010782 if (audio_extn_qaf_is_enabled()) {
10783 ret = audio_extn_qaf_init(adev);
10784 if (ret < 0) {
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010785 ALOGE("%s: Failed to init platform data, aborting.", __func__);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010786 goto adev_open_err;
Lakshman Chaluvaraju22ba9f12016-09-12 11:42:10 +053010787 }
10788
10789 adev->device.open_output_stream = audio_extn_qaf_open_output_stream;
10790 adev->device.close_output_stream = audio_extn_qaf_close_output_stream;
10791 }
10792
Derek Chenae7b0342019-02-08 15:17:04 -080010793 audio_extn_auto_hal_init(adev);
Derek Chend2530072014-11-24 12:39:14 -080010794 adev->ext_hw_plugin = audio_extn_ext_hw_plugin_init(adev);
10795
Eric Laurentc4aef752013-09-12 17:45:53 -070010796 if (access(VISUALIZER_LIBRARY_PATH, R_OK) == 0) {
10797 adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
10798 if (adev->visualizer_lib == NULL) {
10799 ALOGE("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
10800 } else {
10801 ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
10802 adev->visualizer_start_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010803 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070010804 "visualizer_hal_start_output");
10805 adev->visualizer_stop_output =
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010806 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
Eric Laurentc4aef752013-09-12 17:45:53 -070010807 "visualizer_hal_stop_output");
10808 }
10809 }
Dhanalakshmi Siddani21be3ac2016-12-29 14:31:08 +053010810 audio_extn_init(adev);
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010811 voice_extn_init(adev);
Apoorv Raghuvanshi84fa2fe2013-12-04 11:57:47 -080010812 audio_extn_listen_init(adev, adev->snd_card);
Weiyin Jiangaa80acd2016-09-21 16:42:11 +080010813 audio_extn_gef_init(adev);
Siddartha Shaik44dd7702017-06-14 12:13:25 +053010814 audio_extn_hw_loopback_init(adev);
Garmond Leunge2433c32017-09-28 21:51:22 -070010815 audio_extn_ffv_init(adev);
Eric Laurentc4aef752013-09-12 17:45:53 -070010816
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010817 if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) {
10818 adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
10819 if (adev->offload_effects_lib == NULL) {
10820 ALOGE("%s: DLOPEN failed for %s", __func__,
10821 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
10822 } else {
10823 ALOGV("%s: DLOPEN successful for %s", __func__,
10824 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
10825 adev->offload_effects_start_output =
Ashish Jain5106d362016-05-11 19:23:33 +053010826 (int (*)(audio_io_handle_t, int, struct mixer *))dlsym(adev->offload_effects_lib,
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010827 "offload_effects_bundle_hal_start_output");
10828 adev->offload_effects_stop_output =
10829 (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
10830 "offload_effects_bundle_hal_stop_output");
Jitendra Naruka1b6513f2014-11-22 19:34:13 -080010831 adev->offload_effects_set_hpx_state =
10832 (int (*)(bool))dlsym(adev->offload_effects_lib,
10833 "offload_effects_bundle_set_hpx_state");
Dhananjay Kumard68883d2015-09-04 13:39:26 +053010834 adev->offload_effects_get_parameters =
10835 (void (*)(struct str_parms *, struct str_parms *))
10836 dlsym(adev->offload_effects_lib,
10837 "offload_effects_bundle_get_parameters");
10838 adev->offload_effects_set_parameters =
10839 (void (*)(struct str_parms *))dlsym(adev->offload_effects_lib,
10840 "offload_effects_bundle_set_parameters");
Subhash Chandra Bose Naripeddy1d089162013-11-13 13:31:50 -080010841 }
10842 }
10843
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010844 if (access(ADM_LIBRARY_PATH, R_OK) == 0) {
10845 adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
10846 if (adev->adm_lib == NULL) {
10847 ALOGE("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
10848 } else {
10849 ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
10850 adev->adm_init = (adm_init_t)
10851 dlsym(adev->adm_lib, "adm_init");
10852 adev->adm_deinit = (adm_deinit_t)
10853 dlsym(adev->adm_lib, "adm_deinit");
10854 adev->adm_register_input_stream = (adm_register_input_stream_t)
10855 dlsym(adev->adm_lib, "adm_register_input_stream");
10856 adev->adm_register_output_stream = (adm_register_output_stream_t)
10857 dlsym(adev->adm_lib, "adm_register_output_stream");
10858 adev->adm_deregister_stream = (adm_deregister_stream_t)
10859 dlsym(adev->adm_lib, "adm_deregister_stream");
10860 adev->adm_request_focus = (adm_request_focus_t)
10861 dlsym(adev->adm_lib, "adm_request_focus");
10862 adev->adm_abandon_focus = (adm_abandon_focus_t)
10863 dlsym(adev->adm_lib, "adm_abandon_focus");
Haynes Mathew George5beddd42016-06-27 18:33:40 -070010864 adev->adm_set_config = (adm_set_config_t)
10865 dlsym(adev->adm_lib, "adm_set_config");
10866 adev->adm_request_focus_v2 = (adm_request_focus_v2_t)
10867 dlsym(adev->adm_lib, "adm_request_focus_v2");
10868 adev->adm_is_noirq_avail = (adm_is_noirq_avail_t)
10869 dlsym(adev->adm_lib, "adm_is_noirq_avail");
10870 adev->adm_on_routing_change = (adm_on_routing_change_t)
10871 dlsym(adev->adm_lib, "adm_on_routing_change");
Aniket Kumar Lata60586a92019-05-22 22:18:55 -070010872 adev->adm_request_focus_v2_1 = (adm_request_focus_v2_1_t)
10873 dlsym(adev->adm_lib, "adm_request_focus_v2_1");
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010874 }
10875 }
10876
Aalique Grahame22e49102018-12-18 14:23:57 -080010877 adev->enable_voicerx = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070010878 adev->bt_wb_speech_enabled = false;
Zhou Song12c29502019-03-16 10:37:18 +080010879 adev->swb_speech_mode = SPEECH_MODE_INVALID;
Kunlei Zhanga3c4cb02021-03-05 16:03:54 +080010880 adev->fluence_nn_usecase_id = USECASE_INVALID;
Alexy Joseph5e4ccbc2017-02-21 14:20:12 -080010881 //initialize this to false for now,
10882 //this will be set to true through set param
10883 adev->vr_audio_mode_enabled = false;
Mingming Yin514a8bc2014-07-29 15:22:21 -070010884
Pradnya Chaphekar8a9dcd82014-09-09 09:49:10 -070010885 audio_extn_ds2_enable(adev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010886 *device = &adev->device.common;
Aalique Grahame22e49102018-12-18 14:23:57 -080010887
10888 if (k_enable_extended_precision)
10889 adev_verify_devices(adev);
10890
Xiaojun Sang785b5da2017-08-03 15:52:29 +080010891 adev->dsp_bit_width_enforce_mode =
10892 adev_init_dsp_bit_width_enforce_mode(adev->mixer);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010893
Dhananjay Kumard6d32152016-10-13 16:11:03 +053010894 audio_extn_utils_update_streams_cfg_lists(adev->platform, adev->mixer,
10895 &adev->streams_output_cfg_list,
10896 &adev->streams_input_cfg_list);
Subhash Chandra Bose Naripeddy19dc03b2014-03-10 14:43:05 -070010897
Kiran Kandi910e1862013-10-29 13:29:42 -070010898 audio_device_ref_count++;
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010899
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010900 int trial;
Manisha Agarwalc75a0202019-12-06 18:48:25 +053010901 if (property_get("vendor.audio_hal.period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010902 trial = atoi(value);
10903 if (period_size_is_plausible_for_low_latency(trial)) {
10904 pcm_config_low_latency.period_size = trial;
10905 pcm_config_low_latency.start_threshold = trial / 4;
10906 pcm_config_low_latency.avail_min = trial / 4;
10907 configured_low_latency_capture_period_size = trial;
10908 }
10909 }
ronghuiz93177262021-04-21 19:58:13 +080010910 if (property_get("vendor.audio_hal.in_period_size", value, NULL) > 0) {
Ravi Kumar Alamandadc9bb152014-09-08 15:59:58 -070010911 trial = atoi(value);
10912 if (period_size_is_plausible_for_low_latency(trial)) {
10913 configured_low_latency_capture_period_size = trial;
10914 }
10915 }
10916
Vignesh Kulothungan7d374312018-02-21 17:12:00 -080010917 adev->mic_break_enabled = property_get_bool("vendor.audio.mic_break", false);
10918
Eric Laurent4b084132018-10-19 17:33:43 -070010919 adev->camera_orientation = CAMERA_DEFAULT;
10920
Manisha Agarwalc75a0202019-12-06 18:48:25 +053010921 if (property_get("vendor.audio_hal.period_multiplier",value,NULL) > 0) {
Haynes Mathew George5beddd42016-06-27 18:33:40 -070010922 af_period_multiplier = atoi(value);
10923 if (af_period_multiplier < 0)
10924 af_period_multiplier = 2;
10925 else if (af_period_multiplier > 4)
10926 af_period_multiplier = 4;
10927
10928 ALOGV("new period_multiplier = %d", af_period_multiplier);
10929 }
10930
Arun Mirpurib1bec9c2019-01-29 16:42:45 -080010931 audio_extn_qdsp_init(adev->platform);
Aalique Grahame22e49102018-12-18 14:23:57 -080010932
Aniket Kumar Lata8fc67e62017-05-02 12:33:46 -070010933 adev->multi_offload_enable = property_get_bool("vendor.audio.offload.multiple.enabled", false);
Apoorv Raghuvanshi6e262842013-10-06 14:39:35 -070010934 pthread_mutex_unlock(&adev_init_lock);
10935
Ravi Kumar Alamanda8a0f9772015-06-15 10:35:19 -070010936 if (adev->adm_init)
10937 adev->adm_data = adev->adm_init();
10938
Dhananjay Kumaree4d2002016-10-25 18:02:58 +053010939 qahwi_init(*device);
Ben Rombergerd771a7c2017-02-22 18:05:17 -080010940 audio_extn_adsp_hdlr_init(adev->mixer);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010941
10942 audio_extn_snd_mon_init();
10943 pthread_mutex_lock(&adev->lock);
10944 audio_extn_snd_mon_register_listener(adev, adev_snd_mon_cb);
10945 adev->card_status = CARD_STATUS_ONLINE;
Haynes Mathew George01156f92018-04-13 15:29:54 -070010946 audio_extn_battery_properties_listener_init(adev_on_battery_status_changed);
10947 /*
10948 * if the battery state callback happens before charging can be queried,
10949 * it will be guarded with the adev->lock held in the cb function and so
10950 * the callback value will reflect the latest state
10951 */
10952 adev->is_charging = audio_extn_battery_properties_is_charging();
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010953 audio_extn_sound_trigger_init(adev); /* dependent on snd_mon_init() */
Zhou Songc1088ea2018-06-12 00:17:29 +080010954 audio_extn_sound_trigger_update_battery_status(adev->is_charging);
justinweng20fb6d82019-02-21 18:49:00 -070010955 audio_extn_audiozoom_init();
Zhou Songc1088ea2018-06-12 00:17:29 +080010956 pthread_mutex_unlock(&adev->lock);
Satish Babu Patakokilac3c5d432017-07-04 22:48:59 +053010957 /* Allocate memory for Device config params */
10958 adev->device_cfg_params = (struct audio_device_config_param*)
10959 calloc(platform_get_max_codec_backend(),
10960 sizeof(struct audio_device_config_param));
10961 if (adev->device_cfg_params == NULL)
10962 ALOGE("%s: Memory allocation failed for Device config params", __func__);
Dhananjay Kumare6293dd2017-05-25 17:25:30 +053010963
Dhanalakshmi Siddani20628c82019-01-27 17:31:09 +053010964 /*
10965 * Check if new PSPD matrix mixer control is supported. If not
10966 * supported, then set flag so that old mixer ctrl is sent while
10967 * sending pspd coefficients on older kernel version. Query mixer
10968 * control for default pcm id and channel value one.
10969 */
10970 snprintf(mixer_ctl_name, sizeof(mixer_ctl_name),
10971 "AudStr %d ChMixer Weight Ch %d", 0, 1);
10972
10973 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
10974 if (!ctl) {
10975 ALOGE("%s: ERROR. Could not get ctl for mixer cmd - %s",
10976 __func__, mixer_ctl_name);
10977 adev->use_old_pspd_mix_ctrl = true;
10978 }
10979
Jaideep Sharma0fa53812020-09-17 09:00:11 +053010980 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010981 return 0;
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010982
10983adev_open_err:
10984 free_map(adev->patch_map);
10985 free_map(adev->io_streams_map);
Aniket Kumar Latabc774842020-01-16 21:22:05 -080010986 free(adev->snd_dev_ref_cnt);
Aniket Kumar Lata1fda9432019-11-01 17:08:33 -070010987 pthread_mutex_destroy(&adev->lock);
10988 free(adev);
10989 adev = NULL;
10990 *device = NULL;
10991 pthread_mutex_unlock(&adev_init_lock);
10992 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080010993}
10994
10995static struct hw_module_methods_t hal_module_methods = {
10996 .open = adev_open,
10997};
10998
10999struct audio_module HAL_MODULE_INFO_SYM = {
11000 .common = {
11001 .tag = HARDWARE_MODULE_TAG,
11002 .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
11003 .hal_api_version = HARDWARE_HAL_API_VERSION,
11004 .id = AUDIO_HARDWARE_MODULE_ID,
11005 .name = "QCOM Audio HAL",
Duy Truongfae19622013-11-24 02:17:54 -080011006 .author = "The Linux Foundation",
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080011007 .methods = &hal_module_methods,
11008 },
11009};