blob: fd590a90eeb91e6bb368ccb9d9230b3dfc499166 [file] [log] [blame]
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001/*
vivek mehtaa51fd402016-02-04 19:49:33 -08002 * Copyright (C) 2013-2016 The Android Open Source Project
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "audio_hw_primary"
Haynes Mathew George03c40102016-01-29 17:57:48 -080018#define ATRACE_TAG ATRACE_TAG_AUDIO
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080019/*#define LOG_NDEBUG 0*/
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070020/*#define VERY_VERY_VERBOSE_LOGGING*/
21#ifdef VERY_VERY_VERBOSE_LOGGING
22#define ALOGVV ALOGV
23#else
24#define ALOGVV(a...) do { } while(0)
25#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080026
27#include <errno.h>
28#include <pthread.h>
29#include <stdint.h>
30#include <sys/time.h>
31#include <stdlib.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080032#include <math.h>
Eric Laurentc4aef752013-09-12 17:45:53 -070033#include <dlfcn.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070034#include <sys/resource.h>
35#include <sys/prctl.h>
Kevin Rocardb5c28192017-05-02 15:30:20 -070036#include <limits.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080037
38#include <cutils/log.h>
Haynes Mathew George03c40102016-01-29 17:57:48 -080039#include <cutils/trace.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080040#include <cutils/str_parms.h>
41#include <cutils/properties.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070042#include <cutils/atomic.h>
43#include <cutils/sched_policy.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080044
Eric Laurentb23d5282013-05-14 15:27:20 -070045#include <hardware/audio_effect.h>
Andy Hung31aca912014-03-20 17:14:59 -070046#include <hardware/audio_alsaops.h>
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070047#include <system/thread_defs.h>
Phil Burkbc991042017-02-24 08:06:44 -080048#include <tinyalsa/asoundlib.h>
Eric Laurentb23d5282013-05-14 15:27:20 -070049#include <audio_effects/effect_aec.h>
50#include <audio_effects/effect_ns.h>
Andy Hungfc044e12017-03-20 09:24:22 -070051#include <audio_utils/clock.h>
52#include <audio_utils/power.h>
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080053#include "audio_hw.h"
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -080054#include "audio_extn.h"
Eric Laurentb23d5282013-05-14 15:27:20 -070055#include "platform_api.h"
56#include <platform.h>
Vineeta Srivastava4b89e372014-06-19 14:21:42 -070057#include "voice_extn.h"
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -080058
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070059#include "sound/compress_params.h"
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -080060#include "audio_extn/tfa_98xx.h"
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070061
Eric Laurent397db572016-05-11 11:31:47 -070062/* COMPRESS_OFFLOAD_FRAGMENT_SIZE must be more than 8KB and a multiple of 32KB if more than 32KB.
63 * COMPRESS_OFFLOAD_FRAGMENT_SIZE * COMPRESS_OFFLOAD_NUM_FRAGMENTS must be less than 8MB. */
Marco Nelissen32093f52015-04-08 15:14:02 -070064#define COMPRESS_OFFLOAD_FRAGMENT_SIZE (256 * 1024)
Marco Nelissen94c33a02015-05-12 09:11:34 -070065// 2 buffers causes problems with high bitrate files
66#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 3
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -070067/* ToDo: Check and update a proper value in msec */
68#define COMPRESS_OFFLOAD_PLAYBACK_LATENCY 96
69#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
70
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -070071#define PROXY_OPEN_RETRY_COUNT 100
72#define PROXY_OPEN_WAIT_TIME 20
73
vivek mehtadae44712015-07-27 14:13:18 -070074#define MIN_CHANNEL_COUNT 1
75#define DEFAULT_CHANNEL_COUNT 2
76
Jean-Michel Trivic0750692015-10-12 12:12:32 -070077#ifndef MAX_TARGET_SPECIFIC_CHANNEL_CNT
78#define MAX_CHANNEL_COUNT 1
79#else
vivek mehtadae44712015-07-27 14:13:18 -070080#define MAX_CHANNEL_COUNT atoi(XSTR(MAX_TARGET_SPECIFIC_CHANNEL_CNT))
81#define XSTR(x) STR(x)
82#define STR(x) #x
Jean-Michel Trivic0750692015-10-12 12:12:32 -070083#endif
vivek mehtadae44712015-07-27 14:13:18 -070084
Haynes Mathew George03c40102016-01-29 17:57:48 -080085#define ULL_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
86
Glenn Kasten4f993392014-05-14 07:30:48 -070087static unsigned int configured_low_latency_capture_period_size =
88 LOW_LATENCY_CAPTURE_PERIOD_SIZE;
89
Eric Laurent0e46adf2016-12-16 12:49:24 -080090
91#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
Phil Burkbc991042017-02-24 08:06:44 -080092#define MMAP_PERIOD_COUNT_MIN 32
93#define MMAP_PERIOD_COUNT_MAX 512
94#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
Eric Laurent0e46adf2016-12-16 12:49:24 -080095
96
Andy Hung31aca912014-03-20 17:14:59 -070097/* This constant enables extended precision handling.
98 * TODO The flag is off until more testing is done.
99 */
100static const bool k_enable_extended_precision = false;
101
Eric Laurentb23d5282013-05-14 15:27:20 -0700102struct pcm_config pcm_config_deep_buffer = {
vivek mehtadae44712015-07-27 14:13:18 -0700103 .channels = DEFAULT_CHANNEL_COUNT,
Eric Laurentb23d5282013-05-14 15:27:20 -0700104 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
105 .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
106 .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
107 .format = PCM_FORMAT_S16_LE,
108 .start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
109 .stop_threshold = INT_MAX,
110 .avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
111};
112
113struct pcm_config pcm_config_low_latency = {
vivek mehtadae44712015-07-27 14:13:18 -0700114 .channels = DEFAULT_CHANNEL_COUNT,
Eric Laurentb23d5282013-05-14 15:27:20 -0700115 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
116 .period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
117 .period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
118 .format = PCM_FORMAT_S16_LE,
119 .start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
120 .stop_threshold = INT_MAX,
121 .avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
122};
123
Haynes Mathew George03c40102016-01-29 17:57:48 -0800124static int af_period_multiplier = 4;
125struct pcm_config pcm_config_rt = {
126 .channels = DEFAULT_CHANNEL_COUNT,
127 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
128 .period_size = ULL_PERIOD_SIZE, //1 ms
129 .period_count = 512, //=> buffer size is 512ms
130 .format = PCM_FORMAT_S16_LE,
131 .start_threshold = ULL_PERIOD_SIZE*8, //8ms
132 .stop_threshold = INT_MAX,
133 .silence_threshold = 0,
134 .silence_size = 0,
135 .avail_min = ULL_PERIOD_SIZE, //1 ms
136};
137
Eric Laurentb23d5282013-05-14 15:27:20 -0700138struct pcm_config pcm_config_hdmi_multi = {
139 .channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
140 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
141 .period_size = HDMI_MULTI_PERIOD_SIZE,
142 .period_count = HDMI_MULTI_PERIOD_COUNT,
143 .format = PCM_FORMAT_S16_LE,
144 .start_threshold = 0,
145 .stop_threshold = INT_MAX,
146 .avail_min = 0,
147};
148
Eric Laurent0e46adf2016-12-16 12:49:24 -0800149struct pcm_config pcm_config_mmap_playback = {
150 .channels = DEFAULT_CHANNEL_COUNT,
151 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
152 .period_size = MMAP_PERIOD_SIZE,
Phil Burkbc991042017-02-24 08:06:44 -0800153 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
Eric Laurent0e46adf2016-12-16 12:49:24 -0800154 .format = PCM_FORMAT_S16_LE,
155 .start_threshold = MMAP_PERIOD_SIZE*8,
156 .stop_threshold = INT32_MAX,
157 .silence_threshold = 0,
158 .silence_size = 0,
159 .avail_min = MMAP_PERIOD_SIZE, //1 ms
160};
161
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800162struct pcm_config pcm_config_hifi = {
163 .channels = DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
164 .rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
165 .period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE, /* change #define */
166 .period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
167 .format = PCM_FORMAT_S24_3LE,
168 .start_threshold = 0,
169 .stop_threshold = INT_MAX,
170 .avail_min = 0,
171};
172
Eric Laurentb23d5282013-05-14 15:27:20 -0700173struct pcm_config pcm_config_audio_capture = {
vivek mehtadae44712015-07-27 14:13:18 -0700174 .channels = DEFAULT_CHANNEL_COUNT,
Eric Laurentb23d5282013-05-14 15:27:20 -0700175 .period_count = AUDIO_CAPTURE_PERIOD_COUNT,
176 .format = PCM_FORMAT_S16_LE,
Eric Laurente2d2d1d2015-07-06 17:54:15 -0700177 .stop_threshold = INT_MAX,
178 .avail_min = 0,
Eric Laurentb23d5282013-05-14 15:27:20 -0700179};
180
Haynes Mathew George03c40102016-01-29 17:57:48 -0800181struct pcm_config pcm_config_audio_capture_rt = {
182 .channels = DEFAULT_CHANNEL_COUNT,
183 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
184 .period_size = ULL_PERIOD_SIZE,
185 .period_count = 512,
186 .format = PCM_FORMAT_S16_LE,
187 .start_threshold = 0,
188 .stop_threshold = INT_MAX,
189 .silence_threshold = 0,
190 .silence_size = 0,
191 .avail_min = ULL_PERIOD_SIZE, //1 ms
192};
193
Eric Laurent0e46adf2016-12-16 12:49:24 -0800194struct pcm_config pcm_config_mmap_capture = {
195 .channels = DEFAULT_CHANNEL_COUNT,
196 .rate = DEFAULT_OUTPUT_SAMPLING_RATE,
197 .period_size = MMAP_PERIOD_SIZE,
Phil Burkbc991042017-02-24 08:06:44 -0800198 .period_count = MMAP_PERIOD_COUNT_DEFAULT,
Eric Laurent0e46adf2016-12-16 12:49:24 -0800199 .format = PCM_FORMAT_S16_LE,
200 .start_threshold = 0,
201 .stop_threshold = INT_MAX,
202 .silence_threshold = 0,
203 .silence_size = 0,
204 .avail_min = MMAP_PERIOD_SIZE, //1 ms
205};
206
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -0700207#define AFE_PROXY_CHANNEL_COUNT 2
208#define AFE_PROXY_SAMPLING_RATE 48000
209
210#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768
211#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
212
213struct pcm_config pcm_config_afe_proxy_playback = {
214 .channels = AFE_PROXY_CHANNEL_COUNT,
215 .rate = AFE_PROXY_SAMPLING_RATE,
216 .period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
217 .period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
218 .format = PCM_FORMAT_S16_LE,
219 .start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
220 .stop_threshold = INT_MAX,
221 .avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
222};
223
224#define AFE_PROXY_RECORD_PERIOD_SIZE 768
225#define AFE_PROXY_RECORD_PERIOD_COUNT 4
226
227struct pcm_config pcm_config_afe_proxy_record = {
228 .channels = AFE_PROXY_CHANNEL_COUNT,
229 .rate = AFE_PROXY_SAMPLING_RATE,
230 .period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
231 .period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
232 .format = PCM_FORMAT_S16_LE,
233 .start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
234 .stop_threshold = INT_MAX,
235 .avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
236};
237
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700238const char * const use_case_table[AUDIO_USECASE_MAX] = {
Eric Laurentb23d5282013-05-14 15:27:20 -0700239 [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
240 [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800241 [USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700242 [USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",
Ravi Kumar Alamandaf78a4d92015-04-24 15:18:23 -0700243 [USECASE_AUDIO_PLAYBACK_TTS] = "audio-tts-playback",
Ravi Kumar Alamanda2bc7b022015-06-25 20:08:01 -0700244 [USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
Eric Laurent0e46adf2016-12-16 12:49:24 -0800245 [USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback",
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700246
Eric Laurentb23d5282013-05-14 15:27:20 -0700247 [USECASE_AUDIO_RECORD] = "audio-record",
248 [USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",
Eric Laurent0e46adf2016-12-16 12:49:24 -0800249 [USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700250
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -0800251 [USECASE_AUDIO_HFP_SCO] = "hfp-sco",
252 [USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700253
Eric Laurentb23d5282013-05-14 15:27:20 -0700254 [USECASE_VOICE_CALL] = "voice-call",
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700255 [USECASE_VOICE2_CALL] = "voice2-call",
256 [USECASE_VOLTE_CALL] = "volte-call",
257 [USECASE_QCHAT_CALL] = "qchat-call",
258 [USECASE_VOWLAN_CALL] = "vowlan-call",
vivek mehtaa51fd402016-02-04 19:49:33 -0800259 [USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
260 [USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -0700261
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700262 [USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
263 [USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
264
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -0700265 [USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
266 [USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
vivek mehta781065c2017-04-04 12:55:01 -0700267
268 [USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
269 [USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
270 [USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
271
Eric Laurentb23d5282013-05-14 15:27:20 -0700272};
273
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800274
275#define STRING_TO_ENUM(string) { #string, string }
276
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800277struct string_to_enum {
278 const char *name;
279 uint32_t value;
280};
281
282static const struct string_to_enum out_channels_name_to_enum_table[] = {
283 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
284 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
285 STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
286};
287
Haynes Mathew George5191a852013-09-11 14:19:36 -0700288static int set_voice_volume_l(struct audio_device *adev, float volume);
vivek mehta1a9b7c02015-06-25 11:49:38 -0700289static struct audio_device *adev = NULL;
290static pthread_mutex_t adev_init_lock;
291static unsigned int audio_device_ref_count;
vivek mehtafb4d7bd2016-04-29 03:16:47 -0700292//cache last MBDRC cal step level
293static int last_known_cal_step = -1 ;
vivek mehta1a9b7c02015-06-25 11:49:38 -0700294
Haynes Mathew George03c40102016-01-29 17:57:48 -0800295static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id,
296 int flags __unused)
297{
298 int dir = 0;
299 switch (uc_id) {
300 case USECASE_AUDIO_RECORD_LOW_LATENCY:
301 dir = 1;
302 case USECASE_AUDIO_PLAYBACK_ULL:
303 break;
304 default:
305 return false;
306 }
307
308 int dev_id = platform_get_pcm_device_id(uc_id, dir == 0 ?
309 PCM_PLAYBACK : PCM_CAPTURE);
310 if (adev->adm_is_noirq_avail)
311 return adev->adm_is_noirq_avail(adev->adm_data,
312 adev->snd_card, dev_id, dir);
313 return false;
314}
315
316static void register_out_stream(struct stream_out *out)
317{
318 struct audio_device *adev = out->dev;
319 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
320 return;
321
322 if (!adev->adm_register_output_stream)
323 return;
324
325 adev->adm_register_output_stream(adev->adm_data,
326 out->handle,
327 out->flags);
328
329 if (!adev->adm_set_config)
330 return;
331
332 if (out->realtime) {
333 adev->adm_set_config(adev->adm_data,
334 out->handle,
335 out->pcm, &out->config);
336 }
337}
338
339static void register_in_stream(struct stream_in *in)
340{
341 struct audio_device *adev = in->dev;
342 if (!adev->adm_register_input_stream)
343 return;
344
345 adev->adm_register_input_stream(adev->adm_data,
346 in->capture_handle,
347 in->flags);
348
349 if (!adev->adm_set_config)
350 return;
351
352 if (in->realtime) {
353 adev->adm_set_config(adev->adm_data,
354 in->capture_handle,
355 in->pcm,
356 &in->config);
357 }
358}
359
360static void request_out_focus(struct stream_out *out, long ns)
361{
362 struct audio_device *adev = out->dev;
363
364 if (out->routing_change) {
365 out->routing_change = false;
366 if (adev->adm_on_routing_change)
367 adev->adm_on_routing_change(adev->adm_data, out->handle);
368 }
369
370 if (adev->adm_request_focus_v2) {
371 adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
372 } else if (adev->adm_request_focus) {
373 adev->adm_request_focus(adev->adm_data, out->handle);
374 }
375}
376
377static void request_in_focus(struct stream_in *in, long ns)
378{
379 struct audio_device *adev = in->dev;
380
381 if (in->routing_change) {
382 in->routing_change = false;
383 if (adev->adm_on_routing_change)
384 adev->adm_on_routing_change(adev->adm_data, in->capture_handle);
385 }
386
387 if (adev->adm_request_focus_v2) {
388 adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
389 } else if (adev->adm_request_focus) {
390 adev->adm_request_focus(adev->adm_data, in->capture_handle);
391 }
392}
393
394static void release_out_focus(struct stream_out *out, long ns __unused)
395{
396 struct audio_device *adev = out->dev;
397
398 if (adev->adm_abandon_focus)
399 adev->adm_abandon_focus(adev->adm_data, out->handle);
400}
401
402static void release_in_focus(struct stream_in *in, long ns __unused)
403{
404 struct audio_device *adev = in->dev;
405 if (adev->adm_abandon_focus)
406 adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
407}
408
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -0700409static int parse_snd_card_status(struct str_parms * parms, int * card,
410 card_status_t * status)
411{
412 char value[32]={0};
413 char state[32]={0};
414
415 int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
416
417 if (ret < 0)
418 return -1;
419
420 // sscanf should be okay as value is of max length 32.
421 // same as sizeof state.
422 if (sscanf(value, "%d,%s", card, state) < 2)
423 return -1;
424
425 *status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
426 CARD_STATUS_OFFLINE;
427 return 0;
428}
429
vivek mehta1a9b7c02015-06-25 11:49:38 -0700430__attribute__ ((visibility ("default")))
431bool audio_hw_send_gain_dep_calibration(int level) {
432 bool ret_val = false;
433 ALOGV("%s: enter ... ", __func__);
434
435 pthread_mutex_lock(&adev_init_lock);
436
437 if (adev != NULL && adev->platform != NULL) {
438 pthread_mutex_lock(&adev->lock);
439 ret_val = platform_send_gain_dep_cal(adev->platform, level);
440 pthread_mutex_unlock(&adev->lock);
vivek mehtafb4d7bd2016-04-29 03:16:47 -0700441
442 // if cal set fails, cache level info
443 // if cal set succeds, reset known last cal set
444 if (!ret_val)
445 last_known_cal_step = level;
446 else if (last_known_cal_step != -1)
447 last_known_cal_step = -1;
vivek mehta1a9b7c02015-06-25 11:49:38 -0700448 } else {
449 ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
450 }
451
452 pthread_mutex_unlock(&adev_init_lock);
453
454 ALOGV("%s: exit with ret_val %d ", __func__, ret_val);
455 return ret_val;
456}
Haynes Mathew George5191a852013-09-11 14:19:36 -0700457
vivek mehtaa8d7c922016-05-25 14:40:44 -0700458__attribute__ ((visibility ("default")))
459int audio_hw_get_gain_level_mapping(struct amp_db_and_gain_table *mapping_tbl,
460 int table_size) {
461 int ret_val = 0;
462 ALOGV("%s: enter ... ", __func__);
463
464 pthread_mutex_lock(&adev_init_lock);
465 if (adev == NULL) {
466 ALOGW("%s: adev is NULL .... ", __func__);
467 goto done;
468 }
469
470 pthread_mutex_lock(&adev->lock);
471 ret_val = platform_get_gain_level_mapping(mapping_tbl, table_size);
472 pthread_mutex_unlock(&adev->lock);
473done:
474 pthread_mutex_unlock(&adev_init_lock);
475 ALOGV("%s: exit ... ", __func__);
476 return ret_val;
477}
478
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700479static bool is_supported_format(audio_format_t format)
480{
Eric Laurent8251ac82014-07-23 11:00:25 -0700481 switch (format) {
482 case AUDIO_FORMAT_MP3:
483 case AUDIO_FORMAT_AAC_LC:
484 case AUDIO_FORMAT_AAC_HE_V1:
485 case AUDIO_FORMAT_AAC_HE_V2:
486 return true;
487 default:
488 break;
489 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700490 return false;
491}
492
Haynes Mathew George03c40102016-01-29 17:57:48 -0800493static inline bool is_mmap_usecase(audio_usecase_t uc_id)
494{
495 return (uc_id == USECASE_AUDIO_RECORD_AFE_PROXY) ||
496 (uc_id == USECASE_AUDIO_PLAYBACK_AFE_PROXY);
497}
498
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700499static int get_snd_codec_id(audio_format_t format)
500{
501 int id = 0;
502
Eric Laurent8251ac82014-07-23 11:00:25 -0700503 switch (format & AUDIO_FORMAT_MAIN_MASK) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -0700504 case AUDIO_FORMAT_MP3:
505 id = SND_AUDIOCODEC_MP3;
506 break;
507 case AUDIO_FORMAT_AAC:
508 id = SND_AUDIOCODEC_AAC;
509 break;
510 default:
511 ALOGE("%s: Unsupported audio format", __func__);
512 }
513
514 return id;
515}
Ravi Kumar Alamandaf9967042013-02-14 19:35:14 -0800516
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -0800517static int audio_ssr_status(struct audio_device *adev)
518{
519 int ret = 0;
520 struct mixer_ctl *ctl;
521 const char *mixer_ctl_name = "Audio SSR Status";
522
523 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
524 ret = mixer_ctl_get_value(ctl, 0);
525 ALOGD("%s: value: %d", __func__, ret);
526 return ret;
527}
528
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -0800529int enable_audio_route(struct audio_device *adev,
530 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800531{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700532 snd_device_t snd_device;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800533 char mixer_path[50];
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800534
535 if (usecase == NULL)
536 return -EINVAL;
537
538 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
539
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800540 if (usecase->type == PCM_CAPTURE)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700541 snd_device = usecase->in_snd_device;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800542 else
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700543 snd_device = usecase->out_snd_device;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800544
Yamit Mehtae3b99562016-09-16 22:44:00 +0530545 audio_extn_utils_send_app_type_cfg(adev, usecase);
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800546 audio_extn_utils_send_audio_calibration(adev, usecase);
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800547 strcpy(mixer_path, use_case_table[usecase->id]);
Ravi Kumar Alamanda299760a2013-11-01 17:29:09 -0500548 platform_add_backend_name(adev->platform, mixer_path, snd_device);
Eric Laurent2e140aa2016-06-30 17:14:46 -0700549 ALOGD("%s: usecase(%d) apply and update mixer path: %s", __func__, usecase->id, mixer_path);
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700550 audio_route_apply_and_update_path(adev->audio_route, mixer_path);
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800551
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800552 ALOGV("%s: exit", __func__);
553 return 0;
554}
555
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -0800556int disable_audio_route(struct audio_device *adev,
557 struct audio_usecase *usecase)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800558{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700559 snd_device_t snd_device;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800560 char mixer_path[50];
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800561
562 if (usecase == NULL)
563 return -EINVAL;
564
565 ALOGV("%s: enter: usecase(%d)", __func__, usecase->id);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700566 if (usecase->type == PCM_CAPTURE)
567 snd_device = usecase->in_snd_device;
568 else
569 snd_device = usecase->out_snd_device;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800570 strcpy(mixer_path, use_case_table[usecase->id]);
Ravi Kumar Alamanda299760a2013-11-01 17:29:09 -0500571 platform_add_backend_name(adev->platform, mixer_path, snd_device);
Eric Laurent2e140aa2016-06-30 17:14:46 -0700572 ALOGD("%s: usecase(%d) reset and update mixer path: %s", __func__, usecase->id, mixer_path);
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700573 audio_route_reset_and_update_path(adev->audio_route, mixer_path);
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -0800574
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800575 ALOGV("%s: exit", __func__);
576 return 0;
577}
578
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -0800579int enable_snd_device(struct audio_device *adev,
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700580 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800581{
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700582 int i, num_devices = 0;
583 snd_device_t new_snd_devices[2];
vivek mehtade4849c2016-03-03 17:23:38 -0800584 int ret_val = -EINVAL;
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -0800585 if (snd_device < SND_DEVICE_MIN ||
586 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -0800587 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
vivek mehtade4849c2016-03-03 17:23:38 -0800588 goto on_error;
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -0800589 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700590
Ravi Kumar Alamanda5a95ff62015-08-31 17:42:44 -0700591 platform_send_audio_calibration(adev->platform, snd_device);
592
vivek mehtade4849c2016-03-03 17:23:38 -0800593 if (adev->snd_dev_ref_cnt[snd_device] >= 1) {
Eric Laurent994a6932013-07-17 11:51:42 -0700594 ALOGV("%s: snd_device(%d: %s) is already active",
Eric Laurentb23d5282013-05-14 15:27:20 -0700595 __func__, snd_device, platform_get_snd_device_name(snd_device));
vivek mehtade4849c2016-03-03 17:23:38 -0800596 goto on_success;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700597 }
598
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700599 /* due to the possibility of calibration overwrite between listen
600 and audio, notify sound trigger hal before audio calibration is sent */
601 audio_extn_sound_trigger_update_device_status(snd_device,
602 ST_EVENT_SND_DEVICE_BUSY);
603
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700604 if (audio_extn_spkr_prot_is_enabled())
605 audio_extn_spkr_prot_calib_cancel(adev);
606
zhaoyang yin4211fad2015-06-04 21:13:25 +0800607 audio_extn_dsm_feedback_enable(adev, snd_device, true);
608
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700609 if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
610 snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
611 audio_extn_spkr_prot_is_enabled()) {
612 if (audio_extn_spkr_prot_get_acdb_id(snd_device) < 0) {
vivek mehtade4849c2016-03-03 17:23:38 -0800613 goto on_error;
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700614 }
615 if (audio_extn_spkr_prot_start_processing(snd_device)) {
616 ALOGE("%s: spkr_start_processing failed", __func__);
vivek mehtade4849c2016-03-03 17:23:38 -0800617 goto on_error;
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700618 }
Haynes Mathew George2d809e02016-09-22 17:38:16 -0700619 } else if (platform_can_split_snd_device(snd_device,
620 &num_devices,
621 new_snd_devices) == 0) {
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700622 for (i = 0; i < num_devices; i++) {
623 enable_snd_device(adev, new_snd_devices[i]);
624 }
vivek mehtab6506412015-08-07 16:55:17 -0700625 platform_set_speaker_gain_in_combo(adev, snd_device, true);
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700626 } else {
vivek mehtade4849c2016-03-03 17:23:38 -0800627 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
628 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) {
629 ALOGE(" %s: Invalid sound device returned", __func__);
630 goto on_error;
631 }
Ed Tam70b5c142016-03-21 19:14:29 -0700632
Eric Laurent2e140aa2016-06-30 17:14:46 -0700633 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
vivek mehtade4849c2016-03-03 17:23:38 -0800634 audio_route_apply_and_update_path(adev->audio_route, device_name);
635 }
636on_success:
637 adev->snd_dev_ref_cnt[snd_device]++;
638 ret_val = 0;
639on_error:
640 return ret_val;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800641}
642
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -0800643int disable_snd_device(struct audio_device *adev,
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700644 snd_device_t snd_device)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800645{
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700646 int i, num_devices = 0;
647 snd_device_t new_snd_devices[2];
648
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -0800649 if (snd_device < SND_DEVICE_MIN ||
650 snd_device >= SND_DEVICE_MAX) {
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -0800651 ALOGE("%s: Invalid sound device %d", __func__, snd_device);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -0800652 return -EINVAL;
653 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700654 if (adev->snd_dev_ref_cnt[snd_device] <= 0) {
655 ALOGE("%s: device ref cnt is already 0", __func__);
656 return -EINVAL;
657 }
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -0800658 audio_extn_tfa_98xx_disable_speaker(snd_device);
659
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700660 adev->snd_dev_ref_cnt[snd_device]--;
661 if (adev->snd_dev_ref_cnt[snd_device] == 0) {
zhaoyang yin4211fad2015-06-04 21:13:25 +0800662 audio_extn_dsm_feedback_enable(adev, snd_device, false);
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700663 if ((snd_device == SND_DEVICE_OUT_SPEAKER ||
664 snd_device == SND_DEVICE_OUT_VOICE_SPEAKER) &&
665 audio_extn_spkr_prot_is_enabled()) {
666 audio_extn_spkr_prot_stop_processing(snd_device);
Haynes Mathew George2d809e02016-09-22 17:38:16 -0700667 } else if (platform_can_split_snd_device(snd_device,
668 &num_devices,
669 new_snd_devices) == 0) {
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700670 for (i = 0; i < num_devices; i++) {
671 disable_snd_device(adev, new_snd_devices[i]);
672 }
vivek mehtab6506412015-08-07 16:55:17 -0700673 platform_set_speaker_gain_in_combo(adev, snd_device, false);
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700674 } else {
vivek mehtade4849c2016-03-03 17:23:38 -0800675 char device_name[DEVICE_NAME_MAX_SIZE] = {0};
676 if (platform_get_snd_device_name_extn(adev->platform, snd_device, device_name) < 0 ) {
677 ALOGE(" %s: Invalid sound device returned", __func__);
678 return -EINVAL;
679 }
680
Eric Laurent2e140aa2016-06-30 17:14:46 -0700681 ALOGD("%s: snd_device(%d: %s)", __func__, snd_device, device_name);
vivek mehtade4849c2016-03-03 17:23:38 -0800682 audio_route_reset_and_update_path(adev->audio_route, device_name);
Ravi Kumar Alamanda63863002015-04-22 11:15:25 -0700683 }
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -0700684 audio_extn_sound_trigger_update_device_status(snd_device,
685 ST_EVENT_SND_DEVICE_FREE);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700686 }
vivek mehtab6506412015-08-07 16:55:17 -0700687
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800688 return 0;
689}
690
Haynes Mathew George2d809e02016-09-22 17:38:16 -0700691/*
692 legend:
693 uc - existing usecase
694 new_uc - new usecase
695 d1, d11, d2 - SND_DEVICE enums
696 a1, a2 - corresponding ANDROID device enums
697 B, B1, B2 - backend strings
698
699case 1
700 uc->dev d1 (a1) B1
701 new_uc->dev d1 (a1), d2 (a2) B1, B2
702
703 resolution: disable and enable uc->dev on d1
704
705case 2
706 uc->dev d1 (a1) B1
707 new_uc->dev d11 (a1) B1
708
709 resolution: need to switch uc since d1 and d11 are related
710 (e.g. speaker and voice-speaker)
711 use ANDROID_DEVICE_OUT enums to match devices since SND_DEVICE enums may vary
712
713case 3
714 uc->dev d1 (a1) B1
715 new_uc->dev d2 (a2) B2
716
717 resolution: no need to switch uc
718
719case 4
720 uc->dev d1 (a1) B
721 new_uc->dev d2 (a2) B
722
723 resolution: disable enable uc-dev on d2 since backends match
724 we cannot enable two streams on two different devices if they
725 share the same backend. e.g. if offload is on speaker device using
726 QUAD_MI2S backend and a low-latency stream is started on voice-handset
727 using the same backend, offload must also be switched to voice-handset.
728
729case 5
730 uc->dev d1 (a1) B
731 new_uc->dev d1 (a1), d2 (a2) B
732
733 resolution: disable enable uc-dev on d2 since backends match
734 we cannot enable two streams on two different devices if they
735 share the same backend.
736
737case 6
738 uc->dev d1 a1 B1
739 new_uc->dev d2 a1 B2
740
741 resolution: no need to switch
742
743case 7
744
745 uc->dev d1 (a1), d2 (a2) B1, B2
746 new_uc->dev d1 B1
747
748 resolution: no need to switch
749
750*/
751static snd_device_t derive_playback_snd_device(struct audio_usecase *uc,
752 struct audio_usecase *new_uc,
753 snd_device_t new_snd_device)
754{
755 audio_devices_t a1 = uc->stream.out->devices;
756 audio_devices_t a2 = new_uc->stream.out->devices;
757
758 snd_device_t d1 = uc->out_snd_device;
759 snd_device_t d2 = new_snd_device;
760
761 // Treat as a special case when a1 and a2 are not disjoint
762 if ((a1 != a2) && (a1 & a2)) {
763 snd_device_t d3[2];
764 int num_devices = 0;
765 int ret = platform_can_split_snd_device(popcount(a1) > 1 ? d1 : d2,
766 &num_devices,
767 d3);
768 if (ret < 0) {
769 if (ret != -ENOSYS) {
770 ALOGW("%s failed to split snd_device %d",
771 __func__,
772 popcount(a1) > 1 ? d1 : d2);
773 }
774 goto end;
775 }
776
777 // NB: case 7 is hypothetical and isn't a practical usecase yet.
778 // But if it does happen, we need to give priority to d2 if
779 // the combo devices active on the existing usecase share a backend.
780 // This is because we cannot have a usecase active on a combo device
781 // and a new usecase requests one device in this combo pair.
782 if (platform_check_backends_match(d3[0], d3[1])) {
783 return d2; // case 5
784 } else {
785 return d1; // case 1
786 }
787 } else {
788 if (platform_check_backends_match(d1, d2)) {
789 return d2; // case 2, 4
790 } else {
791 return d1; // case 6, 3
792 }
793 }
794
795end:
796 return d2; // return whatever was calculated before.
797}
798
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700799static void check_and_route_playback_usecases(struct audio_device *adev,
800 struct audio_usecase *uc_info,
801 snd_device_t snd_device)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700802{
803 struct listnode *node;
804 struct audio_usecase *usecase;
805 bool switch_device[AUDIO_USECASE_MAX];
806 int i, num_uc_to_switch = 0;
807
David Linee3fe402017-03-13 10:00:42 -0700808 platform_check_and_set_playback_backend_cfg(adev, uc_info, snd_device);
809
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700810 /*
811 * This function is to make sure that all the usecases that are active on
812 * the hardware codec backend are always routed to any one device that is
813 * handled by the hardware codec.
814 * For example, if low-latency and deep-buffer usecases are currently active
815 * on speaker and out_set_parameters(headset) is received on low-latency
816 * output, then we have to make sure deep-buffer is also switched to headset,
817 * because of the limitation that both the devices cannot be enabled
818 * at the same time as they share the same backend.
819 */
820 /* Disable all the usecases on the shared backend other than the
821 specified usecase */
822 for (i = 0; i < AUDIO_USECASE_MAX; i++)
823 switch_device[i] = false;
824
825 list_for_each(node, &adev->usecase_list) {
826 usecase = node_to_item(node, struct audio_usecase, list);
827 if (usecase->type != PCM_CAPTURE &&
828 usecase != uc_info &&
829 usecase->out_snd_device != snd_device &&
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -0700830 usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND &&
831 platform_check_backends_match(snd_device, usecase->out_snd_device)) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700832 ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
833 __func__, use_case_table[usecase->id],
Eric Laurentb23d5282013-05-14 15:27:20 -0700834 platform_get_snd_device_name(usecase->out_snd_device));
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700835 disable_audio_route(adev, usecase);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700836 switch_device[usecase->id] = true;
837 num_uc_to_switch++;
838 }
839 }
840
841 if (num_uc_to_switch) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700842 list_for_each(node, &adev->usecase_list) {
843 usecase = node_to_item(node, struct audio_usecase, list);
844 if (switch_device[usecase->id]) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700845 disable_snd_device(adev, usecase->out_snd_device);
sangwon.jeon866d5ff2013-10-17 21:42:50 +0900846 }
847 }
848
Haynes Mathew George2d809e02016-09-22 17:38:16 -0700849 snd_device_t d_device;
sangwon.jeon866d5ff2013-10-17 21:42:50 +0900850 list_for_each(node, &adev->usecase_list) {
851 usecase = node_to_item(node, struct audio_usecase, list);
852 if (switch_device[usecase->id]) {
Haynes Mathew George2d809e02016-09-22 17:38:16 -0700853 d_device = derive_playback_snd_device(usecase, uc_info,
854 snd_device);
855 enable_snd_device(adev, d_device);
856 /* Update the out_snd_device before enabling the audio route */
857 usecase->out_snd_device = d_device;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700858 }
859 }
860
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700861 /* Re-route all the usecases on the shared backend other than the
862 specified usecase to new snd devices */
863 list_for_each(node, &adev->usecase_list) {
864 usecase = node_to_item(node, struct audio_usecase, list);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700865 if (switch_device[usecase->id] ) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700866 enable_audio_route(adev, usecase);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700867 }
868 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -0700869 }
870}
871
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700872static void check_and_route_capture_usecases(struct audio_device *adev,
873 struct audio_usecase *uc_info,
874 snd_device_t snd_device)
875{
876 struct listnode *node;
877 struct audio_usecase *usecase;
878 bool switch_device[AUDIO_USECASE_MAX];
879 int i, num_uc_to_switch = 0;
880
vivek mehta4ed66e62016-04-15 23:33:34 -0700881 platform_check_and_set_capture_backend_cfg(adev, uc_info, snd_device);
882
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700883 /*
884 * This function is to make sure that all the active capture usecases
885 * are always routed to the same input sound device.
886 * For example, if audio-record and voice-call usecases are currently
887 * active on speaker(rx) and speaker-mic (tx) and out_set_parameters(earpiece)
888 * is received for voice call then we have to make sure that audio-record
889 * usecase is also switched to earpiece i.e. voice-dmic-ef,
890 * because of the limitation that two devices cannot be enabled
891 * at the same time if they share the same backend.
892 */
893 for (i = 0; i < AUDIO_USECASE_MAX; i++)
894 switch_device[i] = false;
895
896 list_for_each(node, &adev->usecase_list) {
897 usecase = node_to_item(node, struct audio_usecase, list);
898 if (usecase->type != PCM_PLAYBACK &&
899 usecase != uc_info &&
Anish Kumarff864712015-06-03 13:35:11 -0700900 usecase->in_snd_device != snd_device &&
901 (usecase->id != USECASE_AUDIO_SPKR_CALIB_TX)) {
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700902 ALOGV("%s: Usecase (%s) is active on (%s) - disabling ..",
903 __func__, use_case_table[usecase->id],
Devin Kim1e5f3532013-08-09 07:48:29 -0700904 platform_get_snd_device_name(usecase->in_snd_device));
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700905 disable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700906 switch_device[usecase->id] = true;
907 num_uc_to_switch++;
908 }
909 }
910
911 if (num_uc_to_switch) {
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700912 list_for_each(node, &adev->usecase_list) {
913 usecase = node_to_item(node, struct audio_usecase, list);
914 if (switch_device[usecase->id]) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700915 disable_snd_device(adev, usecase->in_snd_device);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -0700916 }
917 }
918
919 list_for_each(node, &adev->usecase_list) {
920 usecase = node_to_item(node, struct audio_usecase, list);
921 if (switch_device[usecase->id]) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700922 enable_snd_device(adev, snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700923 }
924 }
925
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700926 /* Re-route all the usecases on the shared backend other than the
927 specified usecase to new snd devices */
928 list_for_each(node, &adev->usecase_list) {
929 usecase = node_to_item(node, struct audio_usecase, list);
930 /* Update the in_snd_device only before enabling the audio route */
931 if (switch_device[usecase->id] ) {
932 usecase->in_snd_device = snd_device;
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -0700933 enable_audio_route(adev, usecase);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700934 }
935 }
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -0700936 }
937}
938
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800939/* must be called with hw device mutex locked */
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -0700940static int read_hdmi_channel_masks(struct stream_out *out)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800941{
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -0700942 int ret = 0;
Haynes Mathew George47cd4cb2013-07-19 11:58:50 -0700943 int channels = platform_edid_get_max_channels(out->dev->platform);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800944
945 switch (channels) {
946 /*
947 * Do not handle stereo output in Multi-channel cases
948 * Stereo case is handled in normal playback path
949 */
950 case 6:
951 ALOGV("%s: HDMI supports 5.1", __func__);
952 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
953 break;
954 case 8:
955 ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__);
956 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
957 out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
958 break;
959 default:
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -0700960 ALOGE("HDMI does not support multi channel playback");
961 ret = -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800962 break;
963 }
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -0700964 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -0800965}
966
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -0800967static int read_usb_sup_sample_rates(struct stream_out *out)
968{
969 uint32_t *sr = out->supported_sample_rates;
970 size_t count = audio_extn_usb_sup_sample_rates(0 /*playback*/,
971 sr,
972 MAX_SUPPORTED_SAMPLE_RATES);
973#if !LOG_NDEBUG
974
975 for (size_t i=0; i<count; i++) {
976 ALOGV("%s %d", __func__, out->supported_sample_rates[i]);
977 }
978#endif
979 return count > 0 ? 0 : -1;
980}
981
982static int read_usb_sup_channel_masks(struct stream_out *out)
983{
984 int channels = audio_extn_usb_get_max_channels();
985 out->supported_channel_masks[0] =
986 channels < 3 ? audio_channel_out_mask_from_count(channels) :
987 audio_channel_mask_for_index_assignment_from_count(channels);
988 return 0;
989}
990
991static int read_usb_sup_formats(struct stream_out *out)
992{
993 int bitwidth = audio_extn_usb_get_max_bit_width();
994 switch (bitwidth) {
995 case 24:
996 // XXX : usb.c returns 24 for s24 and s24_le?
997 out->supported_formats[0] = AUDIO_FORMAT_PCM_24_BIT_PACKED;
998 break;
999 case 32:
1000 out->supported_formats[0] = AUDIO_FORMAT_PCM_32_BIT;
1001 break;
1002 case 16:
1003 default :
1004 out->supported_formats[0] = AUDIO_FORMAT_PCM_16_BIT;
1005 break;
1006 }
1007
1008 return 0;
1009}
1010
Ravi Kumar Alamandaa237ecc2014-07-24 17:27:05 -07001011static audio_usecase_t get_voice_usecase_id_from_list(struct audio_device *adev)
1012{
1013 struct audio_usecase *usecase;
1014 struct listnode *node;
1015
1016 list_for_each(node, &adev->usecase_list) {
1017 usecase = node_to_item(node, struct audio_usecase, list);
1018 if (usecase->type == VOICE_CALL) {
1019 ALOGV("%s: usecase id %d", __func__, usecase->id);
1020 return usecase->id;
1021 }
1022 }
1023 return USECASE_INVALID;
1024}
1025
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -08001026struct audio_usecase *get_usecase_from_list(struct audio_device *adev,
1027 audio_usecase_t uc_id)
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001028{
1029 struct audio_usecase *usecase;
1030 struct listnode *node;
1031
1032 list_for_each(node, &adev->usecase_list) {
1033 usecase = node_to_item(node, struct audio_usecase, list);
1034 if (usecase->id == uc_id)
1035 return usecase;
1036 }
1037 return NULL;
1038}
1039
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -08001040int select_devices(struct audio_device *adev,
1041 audio_usecase_t uc_id)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001042{
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001043 snd_device_t out_snd_device = SND_DEVICE_NONE;
1044 snd_device_t in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001045 struct audio_usecase *usecase = NULL;
1046 struct audio_usecase *vc_usecase = NULL;
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -08001047 struct audio_usecase *hfp_usecase = NULL;
1048 audio_usecase_t hfp_ucid;
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001049 struct listnode *node;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001050 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001051
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001052 usecase = get_usecase_from_list(adev, uc_id);
1053 if (usecase == NULL) {
1054 ALOGE("%s: Could not find the usecase(%d)", __func__, uc_id);
1055 return -EINVAL;
1056 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001057
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -08001058 if ((usecase->type == VOICE_CALL) ||
1059 (usecase->type == PCM_HFP_CALL)) {
Eric Laurentb23d5282013-05-14 15:27:20 -07001060 out_snd_device = platform_get_output_snd_device(adev->platform,
1061 usecase->stream.out->devices);
1062 in_snd_device = platform_get_input_snd_device(adev->platform, usecase->stream.out->devices);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001063 usecase->devices = usecase->stream.out->devices;
1064 } else {
1065 /*
1066 * If the voice call is active, use the sound devices of voice call usecase
1067 * so that it would not result any device switch. All the usecases will
1068 * be switched to new device when select_devices() is called for voice call
1069 * usecase. This is to avoid switching devices for voice call when
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -07001070 * check_and_route_playback_usecases() is called below.
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001071 */
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07001072 if (voice_is_in_call(adev)) {
Ravi Kumar Alamandaa237ecc2014-07-24 17:27:05 -07001073 vc_usecase = get_usecase_from_list(adev,
1074 get_voice_usecase_id_from_list(adev));
1075 if ((vc_usecase != NULL) &&
1076 ((vc_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
1077 (usecase->devices == AUDIO_DEVICE_IN_VOICE_CALL))) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001078 in_snd_device = vc_usecase->in_snd_device;
1079 out_snd_device = vc_usecase->out_snd_device;
1080 }
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -08001081 } else if (audio_extn_hfp_is_active(adev)) {
1082 hfp_ucid = audio_extn_hfp_get_usecase();
1083 hfp_usecase = get_usecase_from_list(adev, hfp_ucid);
1084 if (hfp_usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) {
1085 in_snd_device = hfp_usecase->in_snd_device;
1086 out_snd_device = hfp_usecase->out_snd_device;
1087 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001088 }
1089 if (usecase->type == PCM_PLAYBACK) {
1090 usecase->devices = usecase->stream.out->devices;
1091 in_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07001092 if (out_snd_device == SND_DEVICE_NONE) {
Eric Laurentb23d5282013-05-14 15:27:20 -07001093 out_snd_device = platform_get_output_snd_device(adev->platform,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001094 usecase->stream.out->devices);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07001095 if (usecase->stream.out == adev->primary_output &&
1096 adev->active_input &&
Eric Laurent50a38ed2015-10-14 18:48:06 -07001097 (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
1098 adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
Ravi Kumar Alamandaf2829012014-11-12 16:16:10 -08001099 out_snd_device != usecase->out_snd_device) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07001100 select_devices(adev, adev->active_input->usecase);
1101 }
1102 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001103 } else if (usecase->type == PCM_CAPTURE) {
1104 usecase->devices = usecase->stream.in->device;
1105 out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07001106 if (in_snd_device == SND_DEVICE_NONE) {
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07001107 audio_devices_t out_device = AUDIO_DEVICE_NONE;
Eric Laurent50a38ed2015-10-14 18:48:06 -07001108 if (adev->active_input &&
1109 (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
1110 adev->mode == AUDIO_MODE_IN_COMMUNICATION)) {
Ravi Kumar Alamandaf2829012014-11-12 16:16:10 -08001111 platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE);
Ravi Kumar Alamanda04643592015-09-24 19:17:26 -07001112 if (usecase->id == USECASE_AUDIO_RECORD_AFE_PROXY) {
1113 out_device = AUDIO_DEVICE_OUT_TELEPHONY_TX;
1114 } else if (adev->primary_output) {
1115 out_device = adev->primary_output->devices;
1116 }
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07001117 }
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07001118 in_snd_device = platform_get_input_snd_device(adev->platform, out_device);
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07001119 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001120 }
1121 }
1122
1123 if (out_snd_device == usecase->out_snd_device &&
1124 in_snd_device == usecase->in_snd_device) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001125 return 0;
1126 }
1127
Eric Laurent2bafff12016-03-17 12:17:23 -07001128 if (out_snd_device != SND_DEVICE_NONE &&
1129 out_snd_device != adev->last_logged_snd_device[uc_id][0]) {
1130 ALOGD("%s: changing use case %s output device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
1131 __func__,
1132 use_case_table[uc_id],
1133 adev->last_logged_snd_device[uc_id][0],
1134 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][0]),
1135 adev->last_logged_snd_device[uc_id][0] != SND_DEVICE_NONE ?
1136 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][0]) :
1137 -1,
1138 out_snd_device,
1139 platform_get_snd_device_name(out_snd_device),
1140 platform_get_snd_device_acdb_id(out_snd_device));
1141 adev->last_logged_snd_device[uc_id][0] = out_snd_device;
1142 }
1143 if (in_snd_device != SND_DEVICE_NONE &&
1144 in_snd_device != adev->last_logged_snd_device[uc_id][1]) {
1145 ALOGD("%s: changing use case %s input device from(%d: %s, acdb %d) to (%d: %s, acdb %d)",
1146 __func__,
1147 use_case_table[uc_id],
1148 adev->last_logged_snd_device[uc_id][1],
1149 platform_get_snd_device_name(adev->last_logged_snd_device[uc_id][1]),
1150 adev->last_logged_snd_device[uc_id][1] != SND_DEVICE_NONE ?
1151 platform_get_snd_device_acdb_id(adev->last_logged_snd_device[uc_id][1]) :
1152 -1,
1153 in_snd_device,
1154 platform_get_snd_device_name(in_snd_device),
1155 platform_get_snd_device_acdb_id(in_snd_device));
1156 adev->last_logged_snd_device[uc_id][1] = in_snd_device;
1157 }
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001158
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001159 /*
1160 * Limitation: While in call, to do a device switch we need to disable
1161 * and enable both RX and TX devices though one of them is same as current
1162 * device.
1163 */
Ravi Kumar Alamanda36886fc2014-09-29 13:41:51 -07001164 if ((usecase->type == VOICE_CALL) &&
1165 (usecase->in_snd_device != SND_DEVICE_NONE) &&
1166 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Eric Laurentb23d5282013-05-14 15:27:20 -07001167 status = platform_switch_voice_call_device_pre(adev->platform);
vivek mehta765eb642015-08-07 19:46:06 -07001168 /* Disable sidetone only if voice call already exists */
1169 if (voice_is_call_state_active(adev))
1170 voice_set_sidetone(adev, usecase->out_snd_device, false);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08001171 }
1172
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001173 /* Disable current sound devices */
1174 if (usecase->out_snd_device != SND_DEVICE_NONE) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001175 disable_audio_route(adev, usecase);
1176 disable_snd_device(adev, usecase->out_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001177 }
1178
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001179 if (usecase->in_snd_device != SND_DEVICE_NONE) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001180 disable_audio_route(adev, usecase);
1181 disable_snd_device(adev, usecase->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001182 }
1183
Ravi Kumar Alamanda83281a92014-05-19 18:14:57 -07001184 /* Applicable only on the targets that has external modem.
1185 * New device information should be sent to modem before enabling
1186 * the devices to reduce in-call device switch time.
1187 */
Ravi Kumar Alamanda36886fc2014-09-29 13:41:51 -07001188 if ((usecase->type == VOICE_CALL) &&
1189 (usecase->in_snd_device != SND_DEVICE_NONE) &&
1190 (usecase->out_snd_device != SND_DEVICE_NONE)) {
Ravi Kumar Alamanda83281a92014-05-19 18:14:57 -07001191 status = platform_switch_voice_call_enable_device_config(adev->platform,
1192 out_snd_device,
1193 in_snd_device);
Ravi Kumar Alamanda36886fc2014-09-29 13:41:51 -07001194 }
Ravi Kumar Alamanda83281a92014-05-19 18:14:57 -07001195
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001196 /* Enable new sound devices */
1197 if (out_snd_device != SND_DEVICE_NONE) {
David Linee3fe402017-03-13 10:00:42 -07001198 if ((usecase->devices & AUDIO_DEVICE_OUT_ALL_CODEC_BACKEND) ||
1199 (usecase->devices & AUDIO_DEVICE_OUT_USB_DEVICE))
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -07001200 check_and_route_playback_usecases(adev, usecase, out_snd_device);
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001201 enable_snd_device(adev, out_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001202 }
1203
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07001204 if (in_snd_device != SND_DEVICE_NONE) {
1205 check_and_route_capture_usecases(adev, usecase, in_snd_device);
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001206 enable_snd_device(adev, in_snd_device);
Ravi Kumar Alamandac4ba7432013-06-05 14:11:39 -07001207 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001208
Eric Laurentb23d5282013-05-14 15:27:20 -07001209 if (usecase->type == VOICE_CALL)
1210 status = platform_switch_voice_call_device_post(adev->platform,
1211 out_snd_device,
1212 in_snd_device);
Ravi Kumar Alamanda610e8cc2013-02-12 01:42:38 -08001213
sangwoo170731f2013-06-08 15:36:36 +09001214 usecase->in_snd_device = in_snd_device;
1215 usecase->out_snd_device = out_snd_device;
1216
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08001217 audio_extn_tfa_98xx_set_mode();
1218
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001219 enable_audio_route(adev, usecase);
sangwoo170731f2013-06-08 15:36:36 +09001220
Ravi Kumar Alamanda83281a92014-05-19 18:14:57 -07001221 /* Applicable only on the targets that has external modem.
1222 * Enable device command should be sent to modem only after
1223 * enabling voice call mixer controls
1224 */
vivek mehta765eb642015-08-07 19:46:06 -07001225 if (usecase->type == VOICE_CALL) {
Ravi Kumar Alamanda83281a92014-05-19 18:14:57 -07001226 status = platform_switch_voice_call_usecase_route_post(adev->platform,
1227 out_snd_device,
1228 in_snd_device);
vivek mehta765eb642015-08-07 19:46:06 -07001229 /* Enable sidetone only if voice call already exists */
1230 if (voice_is_call_state_active(adev))
1231 voice_set_sidetone(adev, out_snd_device, true);
1232 }
Ravi Kumar Alamanda83281a92014-05-19 18:14:57 -07001233
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001234 return status;
1235}
1236
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001237static int stop_input_stream(struct stream_in *in)
1238{
1239 int i, ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001240 struct audio_usecase *uc_info;
1241 struct audio_device *adev = in->dev;
1242
Eric Laurentc8400632013-02-14 19:04:54 -08001243 adev->active_input = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001244
Eric Laurent994a6932013-07-17 11:51:42 -07001245 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001246 in->usecase, use_case_table[in->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001247 uc_info = get_usecase_from_list(adev, in->usecase);
1248 if (uc_info == NULL) {
1249 ALOGE("%s: Could not find the usecase (%d) in the list",
1250 __func__, in->usecase);
1251 return -EINVAL;
1252 }
1253
vivek mehta781065c2017-04-04 12:55:01 -07001254 /* Close in-call recording streams */
1255 voice_check_and_stop_incall_rec_usecase(adev, in);
1256
Eric Laurent150dbfe2013-02-27 14:31:02 -08001257 /* 1. Disable stream specific mixer controls */
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001258 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001259
1260 /* 2. Disable the tx device */
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001261 disable_snd_device(adev, uc_info->in_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001262
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001263 list_remove(&uc_info->list);
1264 free(uc_info);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001265
Eric Laurent994a6932013-07-17 11:51:42 -07001266 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001267 return ret;
1268}
1269
1270int start_input_stream(struct stream_in *in)
1271{
1272 /* 1. Enable output device and stream routing controls */
Eric Laurentc8400632013-02-14 19:04:54 -08001273 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001274 struct audio_usecase *uc_info;
1275 struct audio_device *adev = in->dev;
1276
Eric Laurent994a6932013-07-17 11:51:42 -07001277 ALOGV("%s: enter: usecase(%d)", __func__, in->usecase);
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07001278
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08001279 if (audio_extn_tfa_98xx_is_supported() && !audio_ssr_status(adev))
1280 return -EIO;
1281
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07001282 if (in->card_status == CARD_STATUS_OFFLINE ||
1283 adev->card_status == CARD_STATUS_OFFLINE) {
1284 ALOGW("in->card_status or adev->card_status offline, try again");
1285 ret = -EAGAIN;
1286 goto error_config;
1287 }
1288
vivek mehta781065c2017-04-04 12:55:01 -07001289 /* Check if source matches incall recording usecase criteria */
1290 ret = voice_check_and_set_incall_rec_usecase(adev, in);
1291 if (ret)
1292 goto error_config;
1293 else
1294 ALOGV("%s: usecase(%d)", __func__, in->usecase);
1295
Eric Laurentb23d5282013-05-14 15:27:20 -07001296 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001297 if (in->pcm_device_id < 0) {
1298 ALOGE("%s: Could not find PCM device id for the usecase(%d)",
1299 __func__, in->usecase);
Eric Laurentc8400632013-02-14 19:04:54 -08001300 ret = -EINVAL;
1301 goto error_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001302 }
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001303
1304 adev->active_input = in;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001305 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
1306 uc_info->id = in->usecase;
1307 uc_info->type = PCM_CAPTURE;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001308 uc_info->stream.in = in;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001309 uc_info->devices = in->device;
1310 uc_info->in_snd_device = SND_DEVICE_NONE;
1311 uc_info->out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001312
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001313 list_add_tail(&adev->usecase_list, &uc_info->list);
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07001314
1315 audio_extn_perf_lock_acquire();
1316
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001317 select_devices(adev, in->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001318
Eric Laurent0e46adf2016-12-16 12:49:24 -08001319 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
Phil Burkbc991042017-02-24 08:06:44 -08001320 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
Eric Laurent0e46adf2016-12-16 12:49:24 -08001321 ALOGE("%s: pcm stream not ready", __func__);
1322 goto error_open;
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07001323 }
Haynes Mathew George03c40102016-01-29 17:57:48 -08001324 ret = pcm_start(in->pcm);
Haynes Mathew Georgefbe87312016-08-01 19:29:27 -07001325 if (ret < 0) {
Eric Laurent0e46adf2016-12-16 12:49:24 -08001326 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
1327 goto error_open;
1328 }
1329 } else {
1330 unsigned int flags = PCM_IN | PCM_MONOTONIC;
1331 unsigned int pcm_open_retry_count = 0;
1332
1333 if (in->usecase == USECASE_AUDIO_RECORD_AFE_PROXY) {
1334 flags |= PCM_MMAP | PCM_NOIRQ;
1335 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
1336 } else if (in->realtime) {
1337 flags |= PCM_MMAP | PCM_NOIRQ;
1338 }
1339
1340 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
1341 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
1342
1343 while (1) {
1344 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
1345 flags, &in->config);
1346 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
1347 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
1348 if (in->pcm != NULL) {
1349 pcm_close(in->pcm);
1350 in->pcm = NULL;
1351 }
1352 if (pcm_open_retry_count-- == 0) {
1353 ret = -EIO;
1354 goto error_open;
1355 }
1356 usleep(PROXY_OPEN_WAIT_TIME * 1000);
1357 continue;
1358 }
1359 break;
1360 }
1361
1362 ALOGV("%s: pcm_prepare", __func__);
1363 ret = pcm_prepare(in->pcm);
1364 if (ret < 0) {
1365 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
Haynes Mathew Georgefbe87312016-08-01 19:29:27 -07001366 pcm_close(in->pcm);
1367 in->pcm = NULL;
1368 goto error_open;
1369 }
Eric Laurent0e46adf2016-12-16 12:49:24 -08001370 if (in->realtime) {
1371 ret = pcm_start(in->pcm);
1372 if (ret < 0) {
1373 ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
1374 pcm_close(in->pcm);
1375 in->pcm = NULL;
1376 goto error_open;
1377 }
1378 }
Haynes Mathew George03c40102016-01-29 17:57:48 -08001379 }
Haynes Mathew Georgefbe87312016-08-01 19:29:27 -07001380 register_in_stream(in);
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07001381 audio_extn_perf_lock_release();
Eric Laurent994a6932013-07-17 11:51:42 -07001382 ALOGV("%s: exit", __func__);
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07001383
Eric Laurent0e46adf2016-12-16 12:49:24 -08001384 return 0;
Eric Laurentc8400632013-02-14 19:04:54 -08001385
1386error_open:
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001387 stop_input_stream(in);
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07001388 audio_extn_perf_lock_release();
Eric Laurentc8400632013-02-14 19:04:54 -08001389
1390error_config:
1391 adev->active_input = NULL;
Eric Laurent2bafff12016-03-17 12:17:23 -07001392 ALOGW("%s: exit: status(%d)", __func__, ret);
Eric Laurentc8400632013-02-14 19:04:54 -08001393
1394 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001395}
1396
Eric Laurenta1478072015-09-21 17:21:52 -07001397void lock_input_stream(struct stream_in *in)
1398{
1399 pthread_mutex_lock(&in->pre_lock);
1400 pthread_mutex_lock(&in->lock);
1401 pthread_mutex_unlock(&in->pre_lock);
1402}
1403
1404void lock_output_stream(struct stream_out *out)
1405{
1406 pthread_mutex_lock(&out->pre_lock);
1407 pthread_mutex_lock(&out->lock);
1408 pthread_mutex_unlock(&out->pre_lock);
1409}
1410
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001411/* must be called with out->lock locked */
1412static int send_offload_cmd_l(struct stream_out* out, int command)
1413{
1414 struct offload_cmd *cmd = (struct offload_cmd *)calloc(1, sizeof(struct offload_cmd));
1415
1416 ALOGVV("%s %d", __func__, command);
1417
1418 cmd->cmd = command;
1419 list_add_tail(&out->offload_cmd_list, &cmd->node);
1420 pthread_cond_signal(&out->offload_cond);
1421 return 0;
1422}
1423
1424/* must be called iwth out->lock locked */
1425static void stop_compressed_output_l(struct stream_out *out)
1426{
1427 out->offload_state = OFFLOAD_STATE_IDLE;
1428 out->playback_started = 0;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07001429 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001430 if (out->compr != NULL) {
1431 compress_stop(out->compr);
1432 while (out->offload_thread_blocked) {
1433 pthread_cond_wait(&out->cond, &out->lock);
1434 }
1435 }
1436}
1437
1438static void *offload_thread_loop(void *context)
1439{
1440 struct stream_out *out = (struct stream_out *) context;
1441 struct listnode *item;
1442
1443 out->offload_state = OFFLOAD_STATE_IDLE;
1444 out->playback_started = 0;
1445
1446 setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO);
1447 set_sched_policy(0, SP_FOREGROUND);
1448 prctl(PR_SET_NAME, (unsigned long)"Offload Callback", 0, 0, 0);
1449
1450 ALOGV("%s", __func__);
Eric Laurenta1478072015-09-21 17:21:52 -07001451 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001452 for (;;) {
1453 struct offload_cmd *cmd = NULL;
1454 stream_callback_event_t event;
1455 bool send_callback = false;
1456
1457 ALOGVV("%s offload_cmd_list %d out->offload_state %d",
1458 __func__, list_empty(&out->offload_cmd_list),
1459 out->offload_state);
1460 if (list_empty(&out->offload_cmd_list)) {
1461 ALOGV("%s SLEEPING", __func__);
1462 pthread_cond_wait(&out->offload_cond, &out->lock);
1463 ALOGV("%s RUNNING", __func__);
1464 continue;
1465 }
1466
1467 item = list_head(&out->offload_cmd_list);
1468 cmd = node_to_item(item, struct offload_cmd, node);
1469 list_remove(item);
1470
1471 ALOGVV("%s STATE %d CMD %d out->compr %p",
1472 __func__, out->offload_state, cmd->cmd, out->compr);
1473
1474 if (cmd->cmd == OFFLOAD_CMD_EXIT) {
1475 free(cmd);
1476 break;
1477 }
1478
1479 if (out->compr == NULL) {
1480 ALOGE("%s: Compress handle is NULL", __func__);
Andy Hung68f55fd2016-04-21 11:51:11 -07001481 free(cmd);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001482 pthread_cond_signal(&out->cond);
1483 continue;
1484 }
1485 out->offload_thread_blocked = true;
1486 pthread_mutex_unlock(&out->lock);
1487 send_callback = false;
1488 switch(cmd->cmd) {
1489 case OFFLOAD_CMD_WAIT_FOR_BUFFER:
1490 compress_wait(out->compr, -1);
1491 send_callback = true;
1492 event = STREAM_CBK_EVENT_WRITE_READY;
1493 break;
1494 case OFFLOAD_CMD_PARTIAL_DRAIN:
Haynes Mathew George352f27b2013-07-26 00:00:15 -07001495 compress_next_track(out->compr);
1496 compress_partial_drain(out->compr);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001497 send_callback = true;
1498 event = STREAM_CBK_EVENT_DRAIN_READY;
Ravi Kumar Alamandacc4f6bf2014-12-02 19:21:51 -08001499 /* Resend the metadata for next iteration */
1500 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001501 break;
1502 case OFFLOAD_CMD_DRAIN:
1503 compress_drain(out->compr);
1504 send_callback = true;
1505 event = STREAM_CBK_EVENT_DRAIN_READY;
1506 break;
Haynes Mathew George3ddd3bd2016-07-07 20:01:53 -07001507 case OFFLOAD_CMD_ERROR:
1508 send_callback = true;
1509 event = STREAM_CBK_EVENT_ERROR;
1510 break;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001511 default:
1512 ALOGE("%s unknown command received: %d", __func__, cmd->cmd);
1513 break;
1514 }
Eric Laurenta1478072015-09-21 17:21:52 -07001515 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001516 out->offload_thread_blocked = false;
1517 pthread_cond_signal(&out->cond);
Eric Laurent6e895242013-09-05 16:10:57 -07001518 if (send_callback) {
Ravi Kumar Alamandacc4f6bf2014-12-02 19:21:51 -08001519 ALOGVV("%s: sending offload_callback event %d", __func__, event);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001520 out->offload_callback(event, NULL, out->offload_cookie);
Eric Laurent6e895242013-09-05 16:10:57 -07001521 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001522 free(cmd);
1523 }
1524
1525 pthread_cond_signal(&out->cond);
1526 while (!list_empty(&out->offload_cmd_list)) {
1527 item = list_head(&out->offload_cmd_list);
1528 list_remove(item);
1529 free(node_to_item(item, struct offload_cmd, node));
1530 }
1531 pthread_mutex_unlock(&out->lock);
1532
1533 return NULL;
1534}
1535
1536static int create_offload_callback_thread(struct stream_out *out)
1537{
1538 pthread_cond_init(&out->offload_cond, (const pthread_condattr_t *) NULL);
1539 list_init(&out->offload_cmd_list);
1540 pthread_create(&out->offload_thread, (const pthread_attr_t *) NULL,
1541 offload_thread_loop, out);
1542 return 0;
1543}
1544
1545static int destroy_offload_callback_thread(struct stream_out *out)
1546{
Eric Laurenta1478072015-09-21 17:21:52 -07001547 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001548 stop_compressed_output_l(out);
1549 send_offload_cmd_l(out, OFFLOAD_CMD_EXIT);
1550
1551 pthread_mutex_unlock(&out->lock);
1552 pthread_join(out->offload_thread, (void **) NULL);
1553 pthread_cond_destroy(&out->offload_cond);
1554
1555 return 0;
1556}
1557
Eric Laurent07eeafd2013-10-06 12:52:49 -07001558static bool allow_hdmi_channel_config(struct audio_device *adev)
1559{
1560 struct listnode *node;
1561 struct audio_usecase *usecase;
1562 bool ret = true;
1563
1564 list_for_each(node, &adev->usecase_list) {
1565 usecase = node_to_item(node, struct audio_usecase, list);
1566 if (usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
1567 /*
1568 * If voice call is already existing, do not proceed further to avoid
1569 * disabling/enabling both RX and TX devices, CSD calls, etc.
1570 * Once the voice call done, the HDMI channels can be configured to
1571 * max channels of remaining use cases.
1572 */
1573 if (usecase->id == USECASE_VOICE_CALL) {
Joe Onorato188b6222016-03-01 11:02:27 -08001574 ALOGV("%s: voice call is active, no change in HDMI channels",
Eric Laurent07eeafd2013-10-06 12:52:49 -07001575 __func__);
1576 ret = false;
1577 break;
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08001578 } else if (usecase->id == USECASE_AUDIO_PLAYBACK_HIFI) {
1579 ALOGV("%s: hifi playback is active, "
Eric Laurent07eeafd2013-10-06 12:52:49 -07001580 "no change in HDMI channels", __func__);
1581 ret = false;
1582 break;
1583 }
1584 }
1585 }
1586 return ret;
1587}
1588
1589static int check_and_set_hdmi_channels(struct audio_device *adev,
1590 unsigned int channels)
1591{
1592 struct listnode *node;
1593 struct audio_usecase *usecase;
1594
1595 /* Check if change in HDMI channel config is allowed */
1596 if (!allow_hdmi_channel_config(adev))
1597 return 0;
1598
1599 if (channels == adev->cur_hdmi_channels) {
Joe Onorato188b6222016-03-01 11:02:27 -08001600 ALOGV("%s: Requested channels are same as current", __func__);
Eric Laurent07eeafd2013-10-06 12:52:49 -07001601 return 0;
1602 }
1603
1604 platform_set_hdmi_channels(adev->platform, channels);
1605 adev->cur_hdmi_channels = channels;
1606
1607 /*
1608 * Deroute all the playback streams routed to HDMI so that
1609 * the back end is deactivated. Note that backend will not
1610 * be deactivated if any one stream is connected to it.
1611 */
1612 list_for_each(node, &adev->usecase_list) {
1613 usecase = node_to_item(node, struct audio_usecase, list);
1614 if (usecase->type == PCM_PLAYBACK &&
1615 usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001616 disable_audio_route(adev, usecase);
Eric Laurent07eeafd2013-10-06 12:52:49 -07001617 }
1618 }
1619
1620 /*
1621 * Enable all the streams disabled above. Now the HDMI backend
1622 * will be activated with new channel configuration
1623 */
1624 list_for_each(node, &adev->usecase_list) {
1625 usecase = node_to_item(node, struct audio_usecase, list);
1626 if (usecase->type == PCM_PLAYBACK &&
1627 usecase->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001628 enable_audio_route(adev, usecase);
Eric Laurent07eeafd2013-10-06 12:52:49 -07001629 }
1630 }
1631
1632 return 0;
1633}
1634
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001635static int stop_output_stream(struct stream_out *out)
1636{
1637 int i, ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001638 struct audio_usecase *uc_info;
1639 struct audio_device *adev = out->dev;
1640
Eric Laurent994a6932013-07-17 11:51:42 -07001641 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001642 out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001643 uc_info = get_usecase_from_list(adev, out->usecase);
1644 if (uc_info == NULL) {
1645 ALOGE("%s: Could not find the usecase (%d) in the list",
1646 __func__, out->usecase);
1647 return -EINVAL;
1648 }
1649
Haynes Mathew George41f86652014-06-17 14:22:15 -07001650 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
1651 if (adev->visualizer_stop_output != NULL)
1652 adev->visualizer_stop_output(out->handle, out->pcm_device_id);
1653 if (adev->offload_effects_stop_output != NULL)
1654 adev->offload_effects_stop_output(out->handle, out->pcm_device_id);
1655 }
Eric Laurentc4aef752013-09-12 17:45:53 -07001656
Eric Laurent150dbfe2013-02-27 14:31:02 -08001657 /* 1. Get and set stream specific mixer controls */
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001658 disable_audio_route(adev, uc_info);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001659
1660 /* 2. Disable the rx device */
Ravi Kumar Alamandac38e4522014-04-14 11:46:35 -07001661 disable_snd_device(adev, uc_info->out_snd_device);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001662
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001663 list_remove(&uc_info->list);
1664 free(uc_info);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001665
Eric Laurent0499d4f2014-08-25 22:39:29 -05001666 audio_extn_extspk_update(adev->extspk);
1667
Eric Laurent07eeafd2013-10-06 12:52:49 -07001668 /* Must be called after removing the usecase from list */
1669 if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
1670 check_and_set_hdmi_channels(adev, DEFAULT_HDMI_OUT_CHANNELS);
1671
Eric Laurent994a6932013-07-17 11:51:42 -07001672 ALOGV("%s: exit: status(%d)", __func__, ret);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001673 return ret;
1674}
1675
1676int start_output_stream(struct stream_out *out)
1677{
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001678 int ret = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001679 struct audio_usecase *uc_info;
1680 struct audio_device *adev = out->dev;
1681
Eric Laurent994a6932013-07-17 11:51:42 -07001682 ALOGV("%s: enter: usecase(%d: %s) devices(%#x)",
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001683 __func__, out->usecase, use_case_table[out->usecase], out->devices);
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07001684
1685 if (out->card_status == CARD_STATUS_OFFLINE ||
1686 adev->card_status == CARD_STATUS_OFFLINE) {
1687 ALOGW("out->card_status or adev->card_status offline, try again");
1688 ret = -EAGAIN;
1689 goto error_config;
1690 }
1691
Eric Laurentb23d5282013-05-14 15:27:20 -07001692 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001693 if (out->pcm_device_id < 0) {
1694 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
1695 __func__, out->pcm_device_id, out->usecase);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001696 ret = -EINVAL;
1697 goto error_config;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001698 }
1699
1700 uc_info = (struct audio_usecase *)calloc(1, sizeof(struct audio_usecase));
1701 uc_info->id = out->usecase;
1702 uc_info->type = PCM_PLAYBACK;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08001703 uc_info->stream.out = out;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001704 uc_info->devices = out->devices;
1705 uc_info->in_snd_device = SND_DEVICE_NONE;
1706 uc_info->out_snd_device = SND_DEVICE_NONE;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001707
Eric Laurent07eeafd2013-10-06 12:52:49 -07001708 /* This must be called before adding this usecase to the list */
1709 if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL)
1710 check_and_set_hdmi_channels(adev, out->config.channels);
1711
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08001712 list_add_tail(&adev->usecase_list, &uc_info->list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001713
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07001714 audio_extn_perf_lock_acquire();
1715
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001716 select_devices(adev, out->usecase);
1717
Eric Laurent0499d4f2014-08-25 22:39:29 -05001718 audio_extn_extspk_update(adev->extspk);
1719
Andy Hung31aca912014-03-20 17:14:59 -07001720 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d) format(%#x)",
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07001721 __func__, adev->snd_card, out->pcm_device_id, out->config.format);
Eric Laurent0e46adf2016-12-16 12:49:24 -08001722 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
1723 out->pcm = NULL;
1724 out->compr = compress_open(adev->snd_card, out->pcm_device_id,
1725 COMPRESS_IN, &out->compr_config);
1726 if (out->compr && !is_compress_ready(out->compr)) {
1727 ALOGE("%s: %s", __func__, compress_get_error(out->compr));
1728 compress_close(out->compr);
1729 out->compr = NULL;
1730 ret = -EIO;
1731 goto error_open;
1732 }
1733 if (out->offload_callback)
1734 compress_nonblock(out->compr, out->non_blocking);
1735
1736 if (adev->visualizer_start_output != NULL)
1737 adev->visualizer_start_output(out->handle, out->pcm_device_id);
1738 if (adev->offload_effects_start_output != NULL)
1739 adev->offload_effects_start_output(out->handle, out->pcm_device_id);
1740 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
Phil Burkbc991042017-02-24 08:06:44 -08001741 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
Eric Laurent0e46adf2016-12-16 12:49:24 -08001742 ALOGE("%s: pcm stream not ready", __func__);
1743 goto error_open;
1744 }
Eric Laurent0e46adf2016-12-16 12:49:24 -08001745 ret = pcm_start(out->pcm);
1746 if (ret < 0) {
1747 ALOGE("%s: MMAP pcm_start failed ret %d", __func__, ret);
1748 goto error_open;
1749 }
1750 } else {
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07001751 unsigned int flags = PCM_OUT;
1752 unsigned int pcm_open_retry_count = 0;
Haynes Mathew George03c40102016-01-29 17:57:48 -08001753
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07001754 if (out->usecase == USECASE_AUDIO_PLAYBACK_AFE_PROXY) {
1755 flags |= PCM_MMAP | PCM_NOIRQ;
1756 pcm_open_retry_count = PROXY_OPEN_RETRY_COUNT;
Haynes Mathew George03c40102016-01-29 17:57:48 -08001757 } else if (out->realtime) {
1758 flags |= PCM_MMAP | PCM_NOIRQ;
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07001759 } else
1760 flags |= PCM_MONOTONIC;
1761
1762 while (1) {
1763 out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
1764 flags, &out->config);
1765 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
1766 ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
1767 if (out->pcm != NULL) {
1768 pcm_close(out->pcm);
1769 out->pcm = NULL;
1770 }
1771 if (pcm_open_retry_count-- == 0) {
1772 ret = -EIO;
1773 goto error_open;
1774 }
1775 usleep(PROXY_OPEN_WAIT_TIME * 1000);
1776 continue;
1777 }
1778 break;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001779 }
Ravi Kumar Alamanda50919a72015-10-02 09:37:33 -07001780 ALOGV("%s: pcm_prepare", __func__);
1781 if (pcm_is_ready(out->pcm)) {
1782 ret = pcm_prepare(out->pcm);
1783 if (ret < 0) {
1784 ALOGE("%s: pcm_prepare returned %d", __func__, ret);
1785 pcm_close(out->pcm);
1786 out->pcm = NULL;
1787 goto error_open;
1788 }
1789 }
Eric Laurent0e46adf2016-12-16 12:49:24 -08001790 if (out->realtime) {
1791 ret = pcm_start(out->pcm);
1792 if (ret < 0) {
1793 ALOGE("%s: RT pcm_start failed ret %d", __func__, ret);
1794 pcm_close(out->pcm);
1795 out->pcm = NULL;
1796 goto error_open;
1797 }
Haynes Mathew Georgefbe87312016-08-01 19:29:27 -07001798 }
Haynes Mathew George03c40102016-01-29 17:57:48 -08001799 }
Haynes Mathew Georgefbe87312016-08-01 19:29:27 -07001800 register_out_stream(out);
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07001801 audio_extn_perf_lock_release();
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08001802 audio_extn_tfa_98xx_enable_speaker();
1803
Eric Laurent994a6932013-07-17 11:51:42 -07001804 ALOGV("%s: exit", __func__);
Eric Laurent0e46adf2016-12-16 12:49:24 -08001805 return 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001806error_open:
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07001807 audio_extn_perf_lock_release();
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001808 stop_output_stream(out);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001809error_config:
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08001810 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001811}
1812
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001813static int check_input_parameters(uint32_t sample_rate,
1814 audio_format_t format,
1815 int channel_count)
1816{
vivek mehta4ed66e62016-04-15 23:33:34 -07001817 if ((format != AUDIO_FORMAT_PCM_16_BIT) && (format != AUDIO_FORMAT_PCM_8_24_BIT)) {
vivek mehtadae44712015-07-27 14:13:18 -07001818 ALOGE("%s: unsupported AUDIO FORMAT (%d) ", __func__, format);
1819 return -EINVAL;
1820 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001821
vivek mehtadae44712015-07-27 14:13:18 -07001822 if ((channel_count < MIN_CHANNEL_COUNT) || (channel_count > MAX_CHANNEL_COUNT)) {
Jean-Michel Trivic0750692015-10-12 12:12:32 -07001823 ALOGE("%s: unsupported channel count (%d) passed Min / Max (%d / %d)", __func__,
vivek mehtadae44712015-07-27 14:13:18 -07001824 channel_count, MIN_CHANNEL_COUNT, MAX_CHANNEL_COUNT);
1825 return -EINVAL;
1826 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001827
1828 switch (sample_rate) {
1829 case 8000:
1830 case 11025:
1831 case 12000:
1832 case 16000:
1833 case 22050:
1834 case 24000:
1835 case 32000:
1836 case 44100:
1837 case 48000:
1838 break;
1839 default:
vivek mehtadae44712015-07-27 14:13:18 -07001840 ALOGE("%s: unsupported (%d) samplerate passed ", __func__, sample_rate);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001841 return -EINVAL;
1842 }
1843
1844 return 0;
1845}
1846
1847static size_t get_input_buffer_size(uint32_t sample_rate,
1848 audio_format_t format,
Glenn Kasten68e79ce2014-07-15 10:56:59 -07001849 int channel_count,
1850 bool is_low_latency)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001851{
1852 size_t size = 0;
1853
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07001854 if (check_input_parameters(sample_rate, format, channel_count) != 0)
1855 return 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001856
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07001857 size = (sample_rate * AUDIO_CAPTURE_PERIOD_DURATION_MSEC) / 1000;
Glenn Kasten68e79ce2014-07-15 10:56:59 -07001858 if (is_low_latency)
Glenn Kasten4f993392014-05-14 07:30:48 -07001859 size = configured_low_latency_capture_period_size;
vivek mehta4ed66e62016-04-15 23:33:34 -07001860
1861 size *= channel_count * audio_bytes_per_sample(format);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001862
Glenn Kasten4f993392014-05-14 07:30:48 -07001863 /* make sure the size is multiple of 32 bytes
1864 * At 48 kHz mono 16-bit PCM:
1865 * 5.000 ms = 240 frames = 15*16*1*2 = 480, a whole multiple of 32 (15)
1866 * 3.333 ms = 160 frames = 10*16*1*2 = 320, a whole multiple of 32 (10)
1867 */
1868 size += 0x1f;
1869 size &= ~0x1f;
Ravi Kumar Alamanda33d33062013-06-11 14:40:01 -07001870
1871 return size;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001872}
1873
1874static uint32_t out_get_sample_rate(const struct audio_stream *stream)
1875{
1876 struct stream_out *out = (struct stream_out *)stream;
1877
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001878 return out->sample_rate;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001879}
1880
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07001881static int out_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001882{
1883 return -ENOSYS;
1884}
1885
1886static size_t out_get_buffer_size(const struct audio_stream *stream)
1887{
1888 struct stream_out *out = (struct stream_out *)stream;
1889
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001890 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
1891 return out->compr_config.fragment_size;
1892 }
Haynes Mathew George03c40102016-01-29 17:57:48 -08001893 return out->config.period_size * out->af_period_multiplier *
Eric Laurentfdf296a2014-07-03 16:41:51 -07001894 audio_stream_out_frame_size((const struct audio_stream_out *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001895}
1896
1897static uint32_t out_get_channels(const struct audio_stream *stream)
1898{
1899 struct stream_out *out = (struct stream_out *)stream;
1900
1901 return out->channel_mask;
1902}
1903
1904static audio_format_t out_get_format(const struct audio_stream *stream)
1905{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001906 struct stream_out *out = (struct stream_out *)stream;
1907
1908 return out->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001909}
1910
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07001911static int out_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001912{
1913 return -ENOSYS;
1914}
1915
1916static int out_standby(struct audio_stream *stream)
1917{
1918 struct stream_out *out = (struct stream_out *)stream;
1919 struct audio_device *adev = out->dev;
Phil Burkbc991042017-02-24 08:06:44 -08001920 bool do_stop = true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001921
Eric Laurent994a6932013-07-17 11:51:42 -07001922 ALOGV("%s: enter: usecase(%d: %s)", __func__,
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07001923 out->usecase, use_case_table[out->usecase]);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001924
Eric Laurenta1478072015-09-21 17:21:52 -07001925 lock_output_stream(out);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001926 if (!out->standby) {
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07001927 if (adev->adm_deregister_stream)
1928 adev->adm_deregister_stream(adev->adm_data, out->handle);
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08001929 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001930 out->standby = true;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001931 if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
1932 if (out->pcm) {
1933 pcm_close(out->pcm);
1934 out->pcm = NULL;
1935 }
Eric Laurent0e46adf2016-12-16 12:49:24 -08001936 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
Phil Burkbc991042017-02-24 08:06:44 -08001937 do_stop = out->playback_started;
Eric Laurent0e46adf2016-12-16 12:49:24 -08001938 out->playback_started = false;
1939 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001940 } else {
1941 stop_compressed_output_l(out);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07001942 out->gapless_mdata.encoder_delay = 0;
1943 out->gapless_mdata.encoder_padding = 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07001944 if (out->compr != NULL) {
1945 compress_close(out->compr);
1946 out->compr = NULL;
1947 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08001948 }
Phil Burkbc991042017-02-24 08:06:44 -08001949 if (do_stop) {
1950 stop_output_stream(out);
1951 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08001952 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001953 }
1954 pthread_mutex_unlock(&out->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07001955 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001956 return 0;
1957}
1958
Haynes Mathew George3ddd3bd2016-07-07 20:01:53 -07001959static int out_on_error(struct audio_stream *stream)
1960{
1961 struct stream_out *out = (struct stream_out *)stream;
1962 struct audio_device *adev = out->dev;
1963 bool do_standby = false;
1964
1965 lock_output_stream(out);
1966 if (!out->standby) {
1967 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
1968 stop_compressed_output_l(out);
1969 send_offload_cmd_l(out, OFFLOAD_CMD_ERROR);
1970 } else
1971 do_standby = true;
1972 }
1973 pthread_mutex_unlock(&out->lock);
1974
1975 if (do_standby)
1976 return out_standby(&out->stream.common);
1977
1978 return 0;
1979}
1980
Andy Hung7401c7c2016-09-21 12:41:21 -07001981static int out_dump(const struct audio_stream *stream, int fd)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08001982{
Andy Hung7401c7c2016-09-21 12:41:21 -07001983 struct stream_out *out = (struct stream_out *)stream;
1984
1985 // We try to get the lock for consistency,
1986 // but it isn't necessary for these variables.
1987 // If we're not in standby, we may be blocked on a write.
1988 const bool locked = (pthread_mutex_trylock(&out->lock) == 0);
1989 dprintf(fd, " Standby: %s\n", out->standby ? "yes" : "no");
1990 dprintf(fd, " Frames written: %lld\n", (long long)out->written);
1991
1992 if (locked) {
Andy Hung7401c7c2016-09-21 12:41:21 -07001993 pthread_mutex_unlock(&out->lock);
Andy Hung7401c7c2016-09-21 12:41:21 -07001994 }
Andy Hunga452b0a2017-03-15 14:51:15 -07001995
1996 // dump error info
1997 (void)error_log_dump(
1998 out->error_log, fd, " " /* prefix */, 0 /* lines */, 0 /* limit_ns */);
Andy Hungfc044e12017-03-20 09:24:22 -07001999 // dump power info (out->power_log may be null)
Andy Hung62c9b882017-03-22 16:43:42 -07002000 (void)power_log_dump(
2001 out->power_log, fd, " " /* prefix */, POWER_LOG_LINES, 0 /* limit_ns */);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002002 return 0;
2003}
2004
Haynes Mathew George352f27b2013-07-26 00:00:15 -07002005static int parse_compress_metadata(struct stream_out *out, struct str_parms *parms)
2006{
2007 int ret = 0;
2008 char value[32];
2009 struct compr_gapless_mdata tmp_mdata;
2010
2011 if (!out || !parms) {
2012 return -EINVAL;
2013 }
2014
2015 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_DELAY_SAMPLES, value, sizeof(value));
2016 if (ret >= 0) {
2017 tmp_mdata.encoder_delay = atoi(value); //whats a good limit check?
2018 } else {
2019 return -EINVAL;
2020 }
2021
2022 ret = str_parms_get_str(parms, AUDIO_OFFLOAD_CODEC_PADDING_SAMPLES, value, sizeof(value));
2023 if (ret >= 0) {
2024 tmp_mdata.encoder_padding = atoi(value);
2025 } else {
2026 return -EINVAL;
2027 }
2028
2029 out->gapless_mdata = tmp_mdata;
2030 out->send_new_metadata = 1;
2031 ALOGV("%s new encoder delay %u and padding %u", __func__,
2032 out->gapless_mdata.encoder_delay, out->gapless_mdata.encoder_padding);
2033
2034 return 0;
2035}
2036
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07002037static bool output_drives_call(struct audio_device *adev, struct stream_out *out)
2038{
2039 return out == adev->primary_output || out == adev->voice_tx_output;
2040}
Haynes Mathew George352f27b2013-07-26 00:00:15 -07002041
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002042static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
2043{
2044 struct stream_out *out = (struct stream_out *)stream;
2045 struct audio_device *adev = out->dev;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08002046 struct audio_usecase *usecase;
2047 struct listnode *node;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002048 struct str_parms *parms;
2049 char value[32];
2050 int ret, val = 0;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08002051 bool select_new_device = false;
Eric Laurent03f09432014-03-25 18:09:11 -07002052 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002053
Eric Laurent2e140aa2016-06-30 17:14:46 -07002054 ALOGD("%s: enter: usecase(%d: %s) kvpairs: %s",
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002055 __func__, out->usecase, use_case_table[out->usecase], kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002056 parms = str_parms_create_str(kvpairs);
2057 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
2058 if (ret >= 0) {
2059 val = atoi(value);
Eric Laurenta1478072015-09-21 17:21:52 -07002060 lock_output_stream(out);
Eric Laurent150dbfe2013-02-27 14:31:02 -08002061 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002062
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002063 /*
2064 * When HDMI cable is unplugged the music playback is paused and
2065 * the policy manager sends routing=0. But the audioflinger
2066 * continues to write data until standby time (3sec).
2067 * As the HDMI core is turned off, the write gets blocked.
2068 * Avoid this by routing audio to speaker until standby.
2069 */
2070 if (out->devices == AUDIO_DEVICE_OUT_AUX_DIGITAL &&
2071 val == AUDIO_DEVICE_NONE) {
2072 val = AUDIO_DEVICE_OUT_SPEAKER;
2073 }
2074
2075 /*
2076 * select_devices() call below switches all the usecases on the same
Ravi Kumar Alamandab7ea4f52015-06-08 16:44:05 -07002077 * backend to the new device. Refer to check_and_route_playback_usecases() in
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002078 * the select_devices(). But how do we undo this?
2079 *
2080 * For example, music playback is active on headset (deep-buffer usecase)
2081 * and if we go to ringtones and select a ringtone, low-latency usecase
2082 * will be started on headset+speaker. As we can't enable headset+speaker
2083 * and headset devices at the same time, select_devices() switches the music
2084 * playback to headset+speaker while starting low-lateny usecase for ringtone.
2085 * So when the ringtone playback is completed, how do we undo the same?
2086 *
2087 * We are relying on the out_set_parameters() call on deep-buffer output,
2088 * once the ringtone playback is ended.
2089 * NOTE: We should not check if the current devices are same as new devices.
2090 * Because select_devices() must be called to switch back the music
2091 * playback to headset.
2092 */
Haynes Mathew George03c40102016-01-29 17:57:48 -08002093 audio_devices_t new_dev = val;
2094 if (new_dev != AUDIO_DEVICE_NONE) {
2095 bool same_dev = out->devices == new_dev;
2096 out->devices = new_dev;
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07002097
Eric Laurenta7657192014-10-09 21:09:33 -07002098 if (output_drives_call(adev, out)) {
2099 if (!voice_is_in_call(adev)) {
2100 if (adev->mode == AUDIO_MODE_IN_CALL) {
2101 adev->current_call_output = out;
2102 ret = voice_start_call(adev);
2103 }
2104 } else {
2105 adev->current_call_output = out;
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07002106 voice_update_devices_for_all_voice_usecases(adev);
Eric Laurenta7657192014-10-09 21:09:33 -07002107 }
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08002108 }
vivek mehta0d3637a2016-07-24 09:32:02 -07002109
2110 if (!out->standby) {
2111 if (!same_dev) {
2112 ALOGV("update routing change");
2113 out->routing_change = true;
2114 }
2115 select_devices(adev, out->usecase);
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08002116 audio_extn_tfa_98xx_update();
vivek mehta0d3637a2016-07-24 09:32:02 -07002117 }
2118
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08002119 }
2120
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002121 pthread_mutex_unlock(&adev->lock);
Eric Laurent150dbfe2013-02-27 14:31:02 -08002122 pthread_mutex_unlock(&out->lock);
Eric Laurent0499d4f2014-08-25 22:39:29 -05002123
2124 /*handles device and call state changes*/
2125 audio_extn_extspk_update(adev->extspk);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002126 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07002127
2128 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
2129 parse_compress_metadata(out, parms);
2130 }
2131
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002132 str_parms_destroy(parms);
Eric Laurent03f09432014-03-25 18:09:11 -07002133 ALOGV("%s: exit: code(%d)", __func__, status);
2134 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002135}
2136
2137static char* out_get_parameters(const struct audio_stream *stream, const char *keys)
2138{
2139 struct stream_out *out = (struct stream_out *)stream;
2140 struct str_parms *query = str_parms_create_str(keys);
2141 char *str;
2142 char value[256];
2143 struct str_parms *reply = str_parms_create();
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08002144 bool replied = false;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002145 size_t i, j;
2146 int ret;
2147 bool first = true;
Eric Laurent994a6932013-07-17 11:51:42 -07002148 ALOGV("%s: enter: keys - %s", __func__, keys);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002149 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value, sizeof(value));
2150 if (ret >= 0) {
2151 value[0] = '\0';
2152 i = 0;
2153 while (out->supported_channel_masks[i] != 0) {
2154 for (j = 0; j < ARRAY_SIZE(out_channels_name_to_enum_table); j++) {
2155 if (out_channels_name_to_enum_table[j].value == out->supported_channel_masks[i]) {
2156 if (!first) {
2157 strcat(value, "|");
2158 }
2159 strcat(value, out_channels_name_to_enum_table[j].name);
2160 first = false;
2161 break;
2162 }
2163 }
2164 i++;
2165 }
2166 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_CHANNELS, value);
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08002167 replied = true;
2168 }
2169
2170 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value, sizeof(value));
2171 if (ret >= 0) {
2172 value[0] = '\0';
2173 switch (out->supported_formats[0]) {
2174 case AUDIO_FORMAT_PCM_16_BIT:
2175 strcat(value, "AUDIO_FORMAT_PCM_16_BIT");
2176 break;
2177 case AUDIO_FORMAT_PCM_24_BIT_PACKED:
2178 strcat(value, "AUDIO_FORMAT_PCM_24_BIT_PACKED");
2179 break;
2180 case AUDIO_FORMAT_PCM_32_BIT:
2181 strcat(value, "AUDIO_FORMAT_PCM_32_BIT");
2182 break;
2183 default:
2184 ALOGE("%s: unsupported format %#x", __func__,
2185 out->supported_formats[0]);
2186 break;
2187 }
2188 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_FORMATS, value);
2189 replied = true;
2190 }
2191
2192 ret = str_parms_get_str(query, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
2193 value, sizeof(value));
2194 if (ret >= 0) {
2195 value[0] = '\0';
2196 i=0;
2197 int cursor = 0;
2198 while (out->supported_sample_rates[i]) {
2199 int avail = sizeof(value) - cursor;
2200 ret = snprintf(value + cursor, avail, "%s%d",
2201 cursor > 0 ? "|" : "",
2202 out->supported_sample_rates[i]);
2203 if (ret < 0 || ret >= avail) {
2204 // if cursor is at the last element of the array
2205 // overwrite with \0 is duplicate work as
2206 // snprintf already put a \0 in place.
2207 // else
2208 // we had space to write the '|' at value[cursor]
2209 // (which will be overwritten) or no space to fill
2210 // the first element (=> cursor == 0)
2211 value[cursor] = '\0';
2212 break;
2213 }
2214 cursor += ret;
2215 ++i;
2216 }
2217 str_parms_add_str(reply, AUDIO_PARAMETER_STREAM_SUP_SAMPLING_RATES,
2218 value);
2219 replied = true;
2220 }
2221
2222 if (replied) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002223 str = str_parms_to_str(reply);
2224 } else {
Kevin Rocardedf0b4c2017-05-05 09:08:11 -07002225 str = strdup("");
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002226 }
2227 str_parms_destroy(query);
2228 str_parms_destroy(reply);
Eric Laurent994a6932013-07-17 11:51:42 -07002229 ALOGV("%s: exit: returns - %s", __func__, str);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002230 return str;
2231}
2232
2233static uint32_t out_get_latency(const struct audio_stream_out *stream)
2234{
Haynes Mathew George03c40102016-01-29 17:57:48 -08002235 uint32_t hw_delay, period_ms;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002236 struct stream_out *out = (struct stream_out *)stream;
2237
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002238 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD)
2239 return COMPRESS_OFFLOAD_PLAYBACK_LATENCY;
Eric Laurent0e46adf2016-12-16 12:49:24 -08002240 else if ((out->realtime) ||
2241 (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP)) {
Haynes Mathew George03c40102016-01-29 17:57:48 -08002242 // since the buffer won't be filled up faster than realtime,
2243 // return a smaller number
2244 period_ms = (out->af_period_multiplier * out->config.period_size *
2245 1000) / (out->config.rate);
2246 hw_delay = platform_render_latency(out->usecase)/1000;
2247 return period_ms + hw_delay;
2248 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002249
2250 return (out->config.period_count * out->config.period_size * 1000) /
2251 (out->config.rate);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002252}
2253
2254static int out_set_volume(struct audio_stream_out *stream, float left,
2255 float right)
2256{
Eric Laurenta9024de2013-04-04 09:19:12 -07002257 struct stream_out *out = (struct stream_out *)stream;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002258 int volume[2];
2259
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08002260 if (out->usecase == USECASE_AUDIO_PLAYBACK_HIFI) {
Eric Laurenta9024de2013-04-04 09:19:12 -07002261 /* only take left channel into account: the API is for stereo anyway */
2262 out->muted = (left == 0.0f);
2263 return 0;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002264 } else if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
2265 const char *mixer_ctl_name = "Compress Playback Volume";
2266 struct audio_device *adev = out->dev;
2267 struct mixer_ctl *ctl;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002268 ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
2269 if (!ctl) {
Haynes Mathew George20bcfa82014-06-25 13:37:03 -07002270 /* try with the control based on device id */
2271 int pcm_device_id = platform_get_pcm_device_id(out->usecase,
2272 PCM_PLAYBACK);
2273 char ctl_name[128] = {0};
2274 snprintf(ctl_name, sizeof(ctl_name),
2275 "Compress Playback %d Volume", pcm_device_id);
2276 ctl = mixer_get_ctl_by_name(adev->mixer, ctl_name);
2277 if (!ctl) {
2278 ALOGE("%s: Could not get volume ctl mixer cmd", __func__);
2279 return -EINVAL;
2280 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002281 }
2282 volume[0] = (int)(left * COMPRESS_PLAYBACK_VOLUME_MAX);
2283 volume[1] = (int)(right * COMPRESS_PLAYBACK_VOLUME_MAX);
2284 mixer_ctl_set_array(ctl, volume, sizeof(volume)/sizeof(volume[0]));
2285 return 0;
Eric Laurenta9024de2013-04-04 09:19:12 -07002286 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002287
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002288 return -ENOSYS;
2289}
2290
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07002291// note: this call is safe only if the stream_cb is
2292// removed first in close_output_stream (as is done now).
2293static void out_snd_mon_cb(void * stream, struct str_parms * parms)
2294{
2295 if (!stream || !parms)
2296 return;
2297
2298 struct stream_out *out = (struct stream_out *)stream;
2299 struct audio_device *adev = out->dev;
2300
2301 card_status_t status;
2302 int card;
2303 if (parse_snd_card_status(parms, &card, &status) < 0)
2304 return;
2305
2306 pthread_mutex_lock(&adev->lock);
2307 bool valid_cb = (card == adev->snd_card);
2308 pthread_mutex_unlock(&adev->lock);
2309
2310 if (!valid_cb)
2311 return;
2312
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07002313 lock_output_stream(out);
2314 if (out->card_status != status)
2315 out->card_status = status;
2316 pthread_mutex_unlock(&out->lock);
2317
Haynes Mathew George3ddd3bd2016-07-07 20:01:53 -07002318 ALOGW("out_snd_mon_cb for card %d usecase %s, status %s", card,
2319 use_case_table[out->usecase],
2320 status == CARD_STATUS_OFFLINE ? "offline" : "online");
2321
2322 if (status == CARD_STATUS_OFFLINE)
2323 out_on_error(stream);
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07002324
2325 return;
2326}
2327
Uday Kishore Pasupuleticec8ad82015-04-15 10:34:06 -07002328#ifdef NO_AUDIO_OUT
2329static ssize_t out_write_for_no_output(struct audio_stream_out *stream,
Ariel Gertzensteinc2c11742016-11-14 18:08:28 -05002330 const void *buffer __unused, size_t bytes)
Uday Kishore Pasupuleticec8ad82015-04-15 10:34:06 -07002331{
2332 struct stream_out *out = (struct stream_out *)stream;
2333
2334 /* No Output device supported other than BT for playback.
2335 * Sleep for the amount of buffer duration
2336 */
Eric Laurenta1478072015-09-21 17:21:52 -07002337 lock_output_stream(out);
Ariel Gertzensteinc2c11742016-11-14 18:08:28 -05002338 usleep(bytes * 1000000 / audio_stream_out_frame_size(
2339 (const struct audio_stream_out *)&out->stream) /
Uday Kishore Pasupuleticec8ad82015-04-15 10:34:06 -07002340 out_get_sample_rate(&out->stream.common));
2341 pthread_mutex_unlock(&out->lock);
2342 return bytes;
2343}
2344#endif
2345
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002346static ssize_t out_write(struct audio_stream_out *stream, const void *buffer,
2347 size_t bytes)
2348{
2349 struct stream_out *out = (struct stream_out *)stream;
2350 struct audio_device *adev = out->dev;
Eric Laurent6e895242013-09-05 16:10:57 -07002351 ssize_t ret = 0;
Andy Hung7401c7c2016-09-21 12:41:21 -07002352 int error_code = ERROR_CODE_STANDBY;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002353
Eric Laurenta1478072015-09-21 17:21:52 -07002354 lock_output_stream(out);
vivek mehtae3afca22017-04-11 17:13:50 -07002355 // this is always nonzero
2356 const int frame_size = audio_stream_out_frame_size(stream);
2357
Eric Laurent0e46adf2016-12-16 12:49:24 -08002358 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP) {
2359 error_code = ERROR_CODE_WRITE;
2360 goto exit;
2361 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002362 if (out->standby) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002363 out->standby = false;
Eric Laurent150dbfe2013-02-27 14:31:02 -08002364 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002365 ret = start_output_stream(out);
Eric Laurent150dbfe2013-02-27 14:31:02 -08002366 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002367 /* ToDo: If use case is compress offload should return 0 */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002368 if (ret != 0) {
Ravi Kumar Alamanda59d296d2013-05-02 11:25:27 -07002369 out->standby = true;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002370 goto exit;
2371 }
vivek mehtafb4d7bd2016-04-29 03:16:47 -07002372
2373 if (last_known_cal_step != -1) {
2374 ALOGD("%s: retry previous failed cal level set", __func__);
2375 audio_hw_send_gain_dep_calibration(last_known_cal_step);
2376 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002377 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002378
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002379 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
Eric Laurent0e46adf2016-12-16 12:49:24 -08002380 ALOGVV("%s: writing buffer (%zu bytes) to compress device", __func__, bytes);
Haynes Mathew George352f27b2013-07-26 00:00:15 -07002381 if (out->send_new_metadata) {
2382 ALOGVV("send new gapless metadata");
2383 compress_set_gapless_metadata(out->compr, &out->gapless_mdata);
2384 out->send_new_metadata = 0;
2385 }
Eric Laurentb49b3f62016-02-29 17:59:49 -08002386 unsigned int avail;
2387 struct timespec tstamp;
2388 ret = compress_get_hpointer(out->compr, &avail, &tstamp);
2389 /* Do not limit write size if the available frames count is unknown */
2390 if (ret != 0) {
2391 avail = bytes;
2392 }
2393 if (avail == 0) {
2394 ret = 0;
2395 } else {
2396 if (avail > bytes) {
2397 avail = bytes;
2398 }
2399 ret = compress_write(out->compr, buffer, avail);
2400 ALOGVV("%s: writing buffer (%d bytes) to compress device returned %zd",
2401 __func__, avail, ret);
2402 }
Haynes Mathew George352f27b2013-07-26 00:00:15 -07002403
Eric Laurent6e895242013-09-05 16:10:57 -07002404 if (ret >= 0 && ret < (ssize_t)bytes) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002405 send_offload_cmd_l(out, OFFLOAD_CMD_WAIT_FOR_BUFFER);
2406 }
Eric Laurentb49b3f62016-02-29 17:59:49 -08002407 if (ret > 0 && !out->playback_started) {
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002408 compress_start(out->compr);
2409 out->playback_started = 1;
2410 out->offload_state = OFFLOAD_STATE_PLAYING;
2411 }
Andy Hung7401c7c2016-09-21 12:41:21 -07002412 if (ret < 0) {
Andy Hunga452b0a2017-03-15 14:51:15 -07002413 error_log_log(out->error_log, ERROR_CODE_WRITE, audio_utils_get_real_time_ns());
Andy Hungdacb45c2017-03-31 15:38:14 -07002414 } else {
2415 out->written += ret; // accumulate bytes written for offload.
Andy Hung7401c7c2016-09-21 12:41:21 -07002416 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002417 pthread_mutex_unlock(&out->lock);
Andy Hungfc044e12017-03-20 09:24:22 -07002418 // TODO: consider logging offload pcm
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002419 return ret;
2420 } else {
Andy Hung7401c7c2016-09-21 12:41:21 -07002421 error_code = ERROR_CODE_WRITE;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002422 if (out->pcm) {
2423 if (out->muted)
2424 memset((void *)buffer, 0, bytes);
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07002425
Eric Laurent0e46adf2016-12-16 12:49:24 -08002426 ALOGVV("%s: writing buffer (%zu bytes) to pcm device", __func__, bytes);
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07002427
Haynes Mathew George03c40102016-01-29 17:57:48 -08002428 long ns = pcm_bytes_to_frames(out->pcm, bytes)*1000000000LL/
2429 out->config.rate;
2430 request_out_focus(out, ns);
2431
2432 bool use_mmap = is_mmap_usecase(out->usecase) || out->realtime;
2433 if (use_mmap)
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07002434 ret = pcm_mmap_write(out->pcm, (void *)buffer, bytes);
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07002435 else
2436 ret = pcm_write(out->pcm, (void *)buffer, bytes);
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07002437
Haynes Mathew George03c40102016-01-29 17:57:48 -08002438 release_out_focus(out, ns);
Andy Hung7401c7c2016-09-21 12:41:21 -07002439 } else {
2440 LOG_ALWAYS_FATAL("out->pcm is NULL after starting output stream");
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002441 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002442 }
2443
2444exit:
Andy Hungda9b56b2016-09-16 20:06:35 -07002445 // For PCM we always consume the buffer and return #bytes regardless of ret.
2446 if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
2447 out->written += bytes / (out->config.channels * sizeof(short));
2448 }
Andy Hung7401c7c2016-09-21 12:41:21 -07002449 long long sleeptime_us = 0;
Andy Hungfc044e12017-03-20 09:24:22 -07002450 const int64_t now_ns = audio_utils_get_real_time_ns();
2451
Andy Hung7401c7c2016-09-21 12:41:21 -07002452 if (ret != 0) {
Andy Hunga452b0a2017-03-15 14:51:15 -07002453 error_log_log(out->error_log, error_code, now_ns);
Andy Hung7401c7c2016-09-21 12:41:21 -07002454 if (out->usecase != USECASE_AUDIO_PLAYBACK_OFFLOAD) {
2455 ALOGE_IF(out->pcm != NULL,
2456 "%s: error %zd - %s", __func__, ret, pcm_get_error(out->pcm));
Andy Hungfc044e12017-03-20 09:24:22 -07002457 sleeptime_us = bytes * 1000000LL / frame_size /
Andy Hung7401c7c2016-09-21 12:41:21 -07002458 out_get_sample_rate(&out->stream.common);
2459 // usleep not guaranteed for values over 1 second but we don't limit here.
2460 }
2461 }
Andy Hungda9b56b2016-09-16 20:06:35 -07002462
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002463 pthread_mutex_unlock(&out->lock);
2464
2465 if (ret != 0) {
Haynes Mathew Georgef9c7aae2016-09-20 14:12:41 -07002466 out_on_error(&out->stream.common);
Andy Hung7401c7c2016-09-21 12:41:21 -07002467 if (sleeptime_us != 0)
2468 usleep(sleeptime_us);
Andy Hungfc044e12017-03-20 09:24:22 -07002469 } else {
2470 // only log if the data is properly written (out->power_log may be null)
2471 power_log_log(out->power_log, buffer, bytes / frame_size, now_ns);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002472 }
2473 return bytes;
2474}
2475
2476static int out_get_render_position(const struct audio_stream_out *stream,
2477 uint32_t *dsp_frames)
2478{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002479 struct stream_out *out = (struct stream_out *)stream;
2480 *dsp_frames = 0;
2481 if ((out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) && (dsp_frames != NULL)) {
Eric Laurenta1478072015-09-21 17:21:52 -07002482 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002483 if (out->compr != NULL) {
Andy Hung7171da22016-03-08 16:58:42 -08002484 unsigned long frames = 0;
2485 // TODO: check return value
2486 compress_get_tstamp(out->compr, &frames, &out->sample_rate);
2487 *dsp_frames = (uint32_t)frames;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002488 ALOGVV("%s rendered frames %d sample_rate %d",
2489 __func__, *dsp_frames, out->sample_rate);
2490 }
2491 pthread_mutex_unlock(&out->lock);
2492 return 0;
2493 } else
Kevin Rocard75d41bf2017-05-02 16:38:39 -07002494 return -ENODATA;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002495}
2496
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002497static int out_add_audio_effect(const struct audio_stream *stream __unused,
2498 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002499{
2500 return 0;
2501}
2502
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002503static int out_remove_audio_effect(const struct audio_stream *stream __unused,
2504 effect_handle_t effect __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002505{
2506 return 0;
2507}
2508
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002509static int out_get_next_write_timestamp(const struct audio_stream_out *stream __unused,
2510 int64_t *timestamp __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002511{
Kevin Rocard75d41bf2017-05-02 16:38:39 -07002512 return -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002513}
2514
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07002515static int out_get_presentation_position(const struct audio_stream_out *stream,
2516 uint64_t *frames, struct timespec *timestamp)
2517{
2518 struct stream_out *out = (struct stream_out *)stream;
Kevin Rocard75d41bf2017-05-02 16:38:39 -07002519 int ret = -ENODATA;
Eric Laurent949a0892013-09-20 09:20:13 -07002520 unsigned long dsp_frames;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07002521
Eric Laurenta1478072015-09-21 17:21:52 -07002522 lock_output_stream(out);
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07002523
Eric Laurent949a0892013-09-20 09:20:13 -07002524 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
2525 if (out->compr != NULL) {
Andy Hung7171da22016-03-08 16:58:42 -08002526 // TODO: check return value
Eric Laurent949a0892013-09-20 09:20:13 -07002527 compress_get_tstamp(out->compr, &dsp_frames,
2528 &out->sample_rate);
2529 ALOGVV("%s rendered frames %ld sample_rate %d",
2530 __func__, dsp_frames, out->sample_rate);
2531 *frames = dsp_frames;
2532 ret = 0;
2533 /* this is the best we can do */
2534 clock_gettime(CLOCK_MONOTONIC, timestamp);
2535 }
2536 } else {
2537 if (out->pcm) {
vivek mehta1a9b7c02015-06-25 11:49:38 -07002538 unsigned int avail;
Eric Laurent949a0892013-09-20 09:20:13 -07002539 if (pcm_get_htimestamp(out->pcm, &avail, timestamp) == 0) {
2540 size_t kernel_buffer_size = out->config.period_size * out->config.period_count;
Eric Laurent949a0892013-09-20 09:20:13 -07002541 int64_t signed_frames = out->written - kernel_buffer_size + avail;
Haynes Mathew George7ff216f2013-09-11 19:51:41 -07002542 // This adjustment accounts for buffering after app processor.
2543 // It is based on estimated DSP latency per use case, rather than exact.
2544 signed_frames -=
2545 (platform_render_latency(out->usecase) * out->sample_rate / 1000000LL);
2546
Eric Laurent949a0892013-09-20 09:20:13 -07002547 // It would be unusual for this value to be negative, but check just in case ...
2548 if (signed_frames >= 0) {
2549 *frames = signed_frames;
2550 ret = 0;
2551 }
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07002552 }
2553 }
2554 }
2555
2556 pthread_mutex_unlock(&out->lock);
2557
2558 return ret;
2559}
2560
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002561static int out_set_callback(struct audio_stream_out *stream,
2562 stream_callback_t callback, void *cookie)
2563{
2564 struct stream_out *out = (struct stream_out *)stream;
2565
2566 ALOGV("%s", __func__);
Eric Laurenta1478072015-09-21 17:21:52 -07002567 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002568 out->offload_callback = callback;
2569 out->offload_cookie = cookie;
2570 pthread_mutex_unlock(&out->lock);
2571 return 0;
2572}
2573
2574static int out_pause(struct audio_stream_out* stream)
2575{
2576 struct stream_out *out = (struct stream_out *)stream;
2577 int status = -ENOSYS;
2578 ALOGV("%s", __func__);
2579 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
Eric Laurenta1478072015-09-21 17:21:52 -07002580 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002581 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PLAYING) {
2582 status = compress_pause(out->compr);
2583 out->offload_state = OFFLOAD_STATE_PAUSED;
2584 }
2585 pthread_mutex_unlock(&out->lock);
2586 }
2587 return status;
2588}
2589
2590static int out_resume(struct audio_stream_out* stream)
2591{
2592 struct stream_out *out = (struct stream_out *)stream;
2593 int status = -ENOSYS;
2594 ALOGV("%s", __func__);
2595 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
2596 status = 0;
Eric Laurenta1478072015-09-21 17:21:52 -07002597 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002598 if (out->compr != NULL && out->offload_state == OFFLOAD_STATE_PAUSED) {
2599 status = compress_resume(out->compr);
2600 out->offload_state = OFFLOAD_STATE_PLAYING;
2601 }
2602 pthread_mutex_unlock(&out->lock);
2603 }
2604 return status;
2605}
2606
2607static int out_drain(struct audio_stream_out* stream, audio_drain_type_t type )
2608{
2609 struct stream_out *out = (struct stream_out *)stream;
2610 int status = -ENOSYS;
2611 ALOGV("%s", __func__);
2612 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
Eric Laurenta1478072015-09-21 17:21:52 -07002613 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002614 if (type == AUDIO_DRAIN_EARLY_NOTIFY)
2615 status = send_offload_cmd_l(out, OFFLOAD_CMD_PARTIAL_DRAIN);
2616 else
2617 status = send_offload_cmd_l(out, OFFLOAD_CMD_DRAIN);
2618 pthread_mutex_unlock(&out->lock);
2619 }
2620 return status;
2621}
2622
2623static int out_flush(struct audio_stream_out* stream)
2624{
2625 struct stream_out *out = (struct stream_out *)stream;
2626 ALOGV("%s", __func__);
2627 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
Eric Laurenta1478072015-09-21 17:21:52 -07002628 lock_output_stream(out);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07002629 stop_compressed_output_l(out);
2630 pthread_mutex_unlock(&out->lock);
2631 return 0;
2632 }
2633 return -ENOSYS;
2634}
2635
Eric Laurent0e46adf2016-12-16 12:49:24 -08002636static int out_stop(const struct audio_stream_out* stream)
2637{
2638 struct stream_out *out = (struct stream_out *)stream;
2639 struct audio_device *adev = out->dev;
2640 int ret = -ENOSYS;
2641
2642 ALOGV("%s", __func__);
2643 pthread_mutex_lock(&adev->lock);
2644 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
2645 out->playback_started && out->pcm != NULL) {
2646 pcm_stop(out->pcm);
2647 ret = stop_output_stream(out);
Phil Burkbc991042017-02-24 08:06:44 -08002648 out->playback_started = false;
Eric Laurent0e46adf2016-12-16 12:49:24 -08002649 }
2650 pthread_mutex_unlock(&adev->lock);
2651 return ret;
2652}
2653
2654static int out_start(const struct audio_stream_out* stream)
2655{
2656 struct stream_out *out = (struct stream_out *)stream;
2657 struct audio_device *adev = out->dev;
2658 int ret = -ENOSYS;
2659
2660 ALOGV("%s", __func__);
2661 pthread_mutex_lock(&adev->lock);
2662 if (out->usecase == USECASE_AUDIO_PLAYBACK_MMAP && !out->standby &&
2663 !out->playback_started && out->pcm != NULL) {
2664 ret = start_output_stream(out);
2665 if (ret == 0) {
2666 out->playback_started = true;
2667 }
2668 }
2669 pthread_mutex_unlock(&adev->lock);
2670 return ret;
2671}
2672
Phil Burkbc991042017-02-24 08:06:44 -08002673/*
2674 * Modify config->period_count based on min_size_frames
2675 */
2676static void adjust_mmap_period_count(struct pcm_config *config, int32_t min_size_frames)
2677{
2678 int periodCountRequested = (min_size_frames + config->period_size - 1)
2679 / config->period_size;
2680 int periodCount = MMAP_PERIOD_COUNT_MIN;
2681
2682 ALOGV("%s original config.period_size = %d config.period_count = %d",
2683 __func__, config->period_size, config->period_count);
2684
2685 while (periodCount < periodCountRequested && (periodCount * 2) < MMAP_PERIOD_COUNT_MAX) {
2686 periodCount *= 2;
2687 }
2688 config->period_count = periodCount;
2689
2690 ALOGV("%s requested config.period_count = %d", __func__, config->period_count);
2691}
2692
Eric Laurent0e46adf2016-12-16 12:49:24 -08002693static int out_create_mmap_buffer(const struct audio_stream_out *stream,
2694 int32_t min_size_frames,
2695 struct audio_mmap_buffer_info *info)
2696{
2697 struct stream_out *out = (struct stream_out *)stream;
2698 struct audio_device *adev = out->dev;
2699 int ret = 0;
2700 unsigned int offset1;
2701 unsigned int frames1;
2702 const char *step = "";
2703
2704 ALOGV("%s", __func__);
2705 pthread_mutex_lock(&adev->lock);
2706
2707 if (info == NULL || min_size_frames == 0) {
Phil Burkbc991042017-02-24 08:06:44 -08002708 ALOGE("%s: info = %p, min_size_frames = %d", __func__, info, min_size_frames);
Eric Laurent0e46adf2016-12-16 12:49:24 -08002709 ret = -EINVAL;
2710 goto exit;
2711 }
2712 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP || !out->standby) {
Phil Burkbc991042017-02-24 08:06:44 -08002713 ALOGE("%s: usecase = %d, standby = %d", __func__, out->usecase, out->standby);
Eric Laurent0e46adf2016-12-16 12:49:24 -08002714 ret = -ENOSYS;
2715 goto exit;
2716 }
2717 out->pcm_device_id = platform_get_pcm_device_id(out->usecase, PCM_PLAYBACK);
2718 if (out->pcm_device_id < 0) {
2719 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
2720 __func__, out->pcm_device_id, out->usecase);
2721 ret = -EINVAL;
2722 goto exit;
2723 }
Phil Burkbc991042017-02-24 08:06:44 -08002724
2725 adjust_mmap_period_count(&out->config, min_size_frames);
2726
Eric Laurent0e46adf2016-12-16 12:49:24 -08002727 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
2728 __func__, adev->snd_card, out->pcm_device_id, out->config.channels);
2729 out->pcm = pcm_open(adev->snd_card, out->pcm_device_id,
2730 (PCM_OUT | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &out->config);
2731 if (out->pcm == NULL || !pcm_is_ready(out->pcm)) {
2732 step = "open";
2733 ret = -ENODEV;
2734 goto exit;
2735 }
2736 ret = pcm_mmap_begin(out->pcm, &info->shared_memory_address, &offset1, &frames1);
2737 if (ret < 0) {
2738 step = "begin";
2739 goto exit;
2740 }
2741 info->buffer_size_frames = pcm_get_buffer_size(out->pcm);
2742 info->burst_size_frames = out->config.period_size;
2743 info->shared_memory_fd = pcm_get_poll_fd(out->pcm);
2744
2745 memset(info->shared_memory_address, 0, pcm_frames_to_bytes(out->pcm,
2746 info->buffer_size_frames));
2747
2748 ret = pcm_mmap_commit(out->pcm, 0, MMAP_PERIOD_SIZE);
2749 if (ret < 0) {
2750 step = "commit";
2751 goto exit;
2752 }
Phil Burkbc991042017-02-24 08:06:44 -08002753
2754 out->standby = false;
Eric Laurent0e46adf2016-12-16 12:49:24 -08002755 ret = 0;
2756
2757 ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
2758 __func__, info->shared_memory_address, info->buffer_size_frames);
2759
2760exit:
2761 if (ret != 0) {
Phil Burkbc991042017-02-24 08:06:44 -08002762 if (out->pcm == NULL) {
2763 ALOGE("%s: %s - %d", __func__, step, ret);
2764 } else {
2765 ALOGE("%s: %s %s", __func__, step, pcm_get_error(out->pcm));
Eric Laurent0e46adf2016-12-16 12:49:24 -08002766 pcm_close(out->pcm);
2767 out->pcm = NULL;
2768 }
2769 }
2770 pthread_mutex_unlock(&adev->lock);
2771 return ret;
2772}
2773
2774static int out_get_mmap_position(const struct audio_stream_out *stream,
2775 struct audio_mmap_position *position)
2776{
2777 struct stream_out *out = (struct stream_out *)stream;
2778 ALOGVV("%s", __func__);
2779 if (position == NULL) {
2780 return -EINVAL;
2781 }
2782 if (out->usecase != USECASE_AUDIO_PLAYBACK_MMAP) {
2783 return -ENOSYS;
2784 }
2785 if (out->pcm == NULL) {
2786 return -ENOSYS;
2787 }
2788
2789 struct timespec ts = { 0, 0 };
2790 int ret = pcm_mmap_get_hw_ptr(out->pcm, (unsigned int *)&position->position_frames, &ts);
2791 if (ret < 0) {
2792 ALOGE("%s: %s", __func__, pcm_get_error(out->pcm));
2793 return ret;
2794 }
Andy Hungfc044e12017-03-20 09:24:22 -07002795 position->time_nanoseconds = audio_utils_ns_from_timespec(&ts);
Eric Laurent0e46adf2016-12-16 12:49:24 -08002796 return 0;
2797}
2798
2799
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002800/** audio_stream_in implementation **/
2801static uint32_t in_get_sample_rate(const struct audio_stream *stream)
2802{
2803 struct stream_in *in = (struct stream_in *)stream;
2804
2805 return in->config.rate;
2806}
2807
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002808static int in_set_sample_rate(struct audio_stream *stream __unused, uint32_t rate __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002809{
2810 return -ENOSYS;
2811}
2812
2813static size_t in_get_buffer_size(const struct audio_stream *stream)
2814{
2815 struct stream_in *in = (struct stream_in *)stream;
2816
Haynes Mathew George03c40102016-01-29 17:57:48 -08002817 return in->config.period_size * in->af_period_multiplier *
2818 audio_stream_in_frame_size((const struct audio_stream_in *)stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002819}
2820
2821static uint32_t in_get_channels(const struct audio_stream *stream)
2822{
2823 struct stream_in *in = (struct stream_in *)stream;
2824
2825 return in->channel_mask;
2826}
2827
vivek mehta4ed66e62016-04-15 23:33:34 -07002828static audio_format_t in_get_format(const struct audio_stream *stream)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002829{
vivek mehta4ed66e62016-04-15 23:33:34 -07002830 struct stream_in *in = (struct stream_in *)stream;
2831 return in->format;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002832}
2833
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002834static int in_set_format(struct audio_stream *stream __unused, audio_format_t format __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002835{
2836 return -ENOSYS;
2837}
2838
2839static int in_standby(struct audio_stream *stream)
2840{
2841 struct stream_in *in = (struct stream_in *)stream;
2842 struct audio_device *adev = in->dev;
2843 int status = 0;
Phil Burkbc991042017-02-24 08:06:44 -08002844 bool do_stop = true;
2845
Eric Laurent994a6932013-07-17 11:51:42 -07002846 ALOGV("%s: enter", __func__);
Eric Laurenta1478072015-09-21 17:21:52 -07002847
2848 lock_input_stream(in);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07002849
2850 if (!in->standby && in->is_st_session) {
Joe Onorato188b6222016-03-01 11:02:27 -08002851 ALOGV("%s: sound trigger pcm stop lab", __func__);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07002852 audio_extn_sound_trigger_stop_lab(in);
2853 in->standby = true;
2854 }
2855
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002856 if (!in->standby) {
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07002857 if (adev->adm_deregister_stream)
2858 adev->adm_deregister_stream(adev->adm_data, in->capture_handle);
2859
Ravi Kumar Alamanda8bba9e92013-11-11 21:09:07 -08002860 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002861 in->standby = true;
Eric Laurent0e46adf2016-12-16 12:49:24 -08002862 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
Phil Burkbc991042017-02-24 08:06:44 -08002863 do_stop = in->capture_started;
Eric Laurent0e46adf2016-12-16 12:49:24 -08002864 in->capture_started = false;
2865 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08002866 if (in->pcm) {
2867 pcm_close(in->pcm);
2868 in->pcm = NULL;
2869 }
Eric Laurentcefbbac2014-09-04 13:54:10 -05002870 adev->enable_voicerx = false;
2871 platform_set_echo_reference(adev, false, AUDIO_DEVICE_NONE );
Phil Burkbc991042017-02-24 08:06:44 -08002872 if (do_stop) {
2873 status = stop_input_stream(in);
2874 }
Eric Laurent150dbfe2013-02-27 14:31:02 -08002875 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002876 }
2877 pthread_mutex_unlock(&in->lock);
Eric Laurent994a6932013-07-17 11:51:42 -07002878 ALOGV("%s: exit: status(%d)", __func__, status);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002879 return status;
2880}
2881
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002882static int in_dump(const struct audio_stream *stream __unused, int fd __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002883{
2884 return 0;
2885}
2886
2887static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
2888{
2889 struct stream_in *in = (struct stream_in *)stream;
2890 struct audio_device *adev = in->dev;
2891 struct str_parms *parms;
2892 char *str;
2893 char value[32];
2894 int ret, val = 0;
Eric Laurent03f09432014-03-25 18:09:11 -07002895 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002896
Eric Laurent994a6932013-07-17 11:51:42 -07002897 ALOGV("%s: enter: kvpairs=%s", __func__, kvpairs);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002898 parms = str_parms_create_str(kvpairs);
2899
2900 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
2901
Eric Laurenta1478072015-09-21 17:21:52 -07002902 lock_input_stream(in);
2903
Eric Laurent150dbfe2013-02-27 14:31:02 -08002904 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002905 if (ret >= 0) {
2906 val = atoi(value);
2907 /* no audio source uses val == 0 */
2908 if ((in->source != val) && (val != 0)) {
2909 in->source = val;
2910 }
2911 }
2912
2913 ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
Eric Laurent03f09432014-03-25 18:09:11 -07002914
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002915 if (ret >= 0) {
2916 val = atoi(value);
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07002917 if (((int)in->device != val) && (val != 0)) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002918 in->device = val;
2919 /* If recording is in progress, change the tx device to new device */
Haynes Mathew George03c40102016-01-29 17:57:48 -08002920 if (!in->standby) {
2921 ALOGV("update input routing change");
2922 in->routing_change = true;
2923 select_devices(adev, in->usecase);
2924 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002925 }
2926 }
2927
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002928 pthread_mutex_unlock(&adev->lock);
Eric Laurent150dbfe2013-02-27 14:31:02 -08002929 pthread_mutex_unlock(&in->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002930
2931 str_parms_destroy(parms);
Eric Laurent03f09432014-03-25 18:09:11 -07002932 ALOGV("%s: exit: status(%d)", __func__, status);
2933 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002934}
2935
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002936static char* in_get_parameters(const struct audio_stream *stream __unused,
2937 const char *keys __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002938{
2939 return strdup("");
2940}
2941
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07002942static int in_set_gain(struct audio_stream_in *stream __unused, float gain __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002943{
Kevin Rocard75d41bf2017-05-02 16:38:39 -07002944 return -ENOSYS;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002945}
2946
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07002947static void in_snd_mon_cb(void * stream, struct str_parms * parms)
2948{
2949 if (!stream || !parms)
2950 return;
2951
2952 struct stream_in *in = (struct stream_in *)stream;
2953 struct audio_device *adev = in->dev;
2954
2955 card_status_t status;
2956 int card;
2957 if (parse_snd_card_status(parms, &card, &status) < 0)
2958 return;
2959
2960 pthread_mutex_lock(&adev->lock);
2961 bool valid_cb = (card == adev->snd_card);
2962 pthread_mutex_unlock(&adev->lock);
2963
2964 if (!valid_cb)
2965 return;
2966
2967 lock_input_stream(in);
2968 if (in->card_status != status)
2969 in->card_status = status;
2970 pthread_mutex_unlock(&in->lock);
2971
2972 ALOGW("in_snd_mon_cb for card %d usecase %s, status %s", card,
2973 use_case_table[in->usecase],
2974 status == CARD_STATUS_OFFLINE ? "offline" : "online");
2975
2976 // a better solution would be to report error back to AF and let
2977 // it put the stream to standby
2978 if (status == CARD_STATUS_OFFLINE)
2979 in_standby(&in->stream.common);
2980
2981 return;
2982}
2983
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002984static ssize_t in_read(struct audio_stream_in *stream, void *buffer,
2985 size_t bytes)
2986{
2987 struct stream_in *in = (struct stream_in *)stream;
2988 struct audio_device *adev = in->dev;
2989 int i, ret = -1;
vivek mehta4ed66e62016-04-15 23:33:34 -07002990 int *int_buf_stream = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08002991
Eric Laurenta1478072015-09-21 17:21:52 -07002992 lock_input_stream(in);
2993
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07002994 if (in->is_st_session) {
Eric Laurent0e46adf2016-12-16 12:49:24 -08002995 ALOGVV(" %s: reading on st session bytes=%zu", __func__, bytes);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07002996 /* Read from sound trigger HAL */
2997 audio_extn_sound_trigger_read(in, buffer, bytes);
2998 pthread_mutex_unlock(&in->lock);
2999 return bytes;
3000 }
3001
Eric Laurent0e46adf2016-12-16 12:49:24 -08003002 if (in->usecase == USECASE_AUDIO_RECORD_MMAP) {
3003 ret = -ENOSYS;
3004 goto exit;
3005 }
3006
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003007 if (in->standby) {
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003008 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003009 ret = start_input_stream(in);
Eric Laurent150dbfe2013-02-27 14:31:02 -08003010 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003011 if (ret != 0) {
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003012 goto exit;
3013 }
3014 in->standby = 0;
3015 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003016
Haynes Mathew George03c40102016-01-29 17:57:48 -08003017 //what's the duration requested by the client?
3018 long ns = pcm_bytes_to_frames(in->pcm, bytes)*1000000000LL/
3019 in->config.rate;
3020 request_in_focus(in, ns);
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07003021
Haynes Mathew George03c40102016-01-29 17:57:48 -08003022 bool use_mmap = is_mmap_usecase(in->usecase) || in->realtime;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003023 if (in->pcm) {
Haynes Mathew George03c40102016-01-29 17:57:48 -08003024 if (use_mmap) {
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003025 ret = pcm_mmap_read(in->pcm, buffer, bytes);
vivek mehta4ed66e62016-04-15 23:33:34 -07003026 } else {
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003027 ret = pcm_read(in->pcm, buffer, bytes);
Eric Laurentf8b50aa2016-05-06 11:03:53 -07003028 }
Haynes Mathew George03c40102016-01-29 17:57:48 -08003029 if (ret < 0) {
3030 ALOGE("Failed to read w/err %s", strerror(errno));
3031 ret = -errno;
3032 }
Eric Laurentf8b50aa2016-05-06 11:03:53 -07003033 if (!ret && bytes > 0 && (in->format == AUDIO_FORMAT_PCM_8_24_BIT)) {
3034 if (bytes % 4 == 0) {
3035 /* data from DSP comes in 24_8 format, convert it to 8_24 */
3036 int_buf_stream = buffer;
3037 for (size_t itt=0; itt < bytes/4 ; itt++) {
3038 int_buf_stream[itt] >>= 8;
vivek mehta4ed66e62016-04-15 23:33:34 -07003039 }
Eric Laurentf8b50aa2016-05-06 11:03:53 -07003040 } else {
3041 ALOGE("%s: !!! something wrong !!! ... data not 32 bit aligned ", __func__);
3042 ret = -EINVAL;
3043 goto exit;
vivek mehta4ed66e62016-04-15 23:33:34 -07003044 }
3045 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003046 }
3047
Haynes Mathew George03c40102016-01-29 17:57:48 -08003048 release_in_focus(in, ns);
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07003049
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003050 /*
3051 * Instead of writing zeroes here, we could trust the hardware
3052 * to always provide zeroes when muted.
Eric Laurent7b2b5ab2014-09-14 12:29:59 -07003053 * No need to acquire adev->lock to read mic_muted here as we don't change its state.
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003054 */
Eric Laurent7b2b5ab2014-09-14 12:29:59 -07003055 if (ret == 0 && adev->mic_muted && in->usecase != USECASE_AUDIO_RECORD_AFE_PROXY)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003056 memset(buffer, 0, bytes);
3057
3058exit:
3059 pthread_mutex_unlock(&in->lock);
3060
3061 if (ret != 0) {
3062 in_standby(&in->stream.common);
3063 ALOGV("%s: read failed - sleeping for buffer duration", __func__);
Eric Laurentfdf296a2014-07-03 16:41:51 -07003064 usleep(bytes * 1000000 / audio_stream_in_frame_size(stream) /
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003065 in_get_sample_rate(&in->stream.common));
Andy Hungc8589872016-03-10 16:37:48 -08003066 memset(buffer, 0, bytes); // clear return data
3067 }
3068 if (bytes > 0) {
Andy Hung6ebe5962016-01-15 17:46:57 -08003069 in->frames_read += bytes / audio_stream_in_frame_size(stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003070 }
3071 return bytes;
3072}
3073
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003074static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003075{
3076 return 0;
3077}
3078
Andy Hung6ebe5962016-01-15 17:46:57 -08003079static int in_get_capture_position(const struct audio_stream_in *stream,
3080 int64_t *frames, int64_t *time)
3081{
3082 if (stream == NULL || frames == NULL || time == NULL) {
3083 return -EINVAL;
3084 }
3085 struct stream_in *in = (struct stream_in *)stream;
3086 int ret = -ENOSYS;
3087
3088 lock_input_stream(in);
3089 if (in->pcm) {
3090 struct timespec timestamp;
3091 unsigned int avail;
3092 if (pcm_get_htimestamp(in->pcm, &avail, &timestamp) == 0) {
3093 *frames = in->frames_read + avail;
3094 *time = timestamp.tv_sec * 1000000000LL + timestamp.tv_nsec;
3095 ret = 0;
3096 }
3097 }
3098 pthread_mutex_unlock(&in->lock);
3099 return ret;
3100}
3101
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003102static int add_remove_audio_effect(const struct audio_stream *stream,
3103 effect_handle_t effect,
3104 bool enable)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003105{
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003106 struct stream_in *in = (struct stream_in *)stream;
Eric Laurentcefbbac2014-09-04 13:54:10 -05003107 struct audio_device *adev = in->dev;
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003108 int status = 0;
3109 effect_descriptor_t desc;
3110
3111 status = (*effect)->get_descriptor(effect, &desc);
3112 if (status != 0)
3113 return status;
3114
Eric Laurenta1478072015-09-21 17:21:52 -07003115 lock_input_stream(in);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003116 pthread_mutex_lock(&in->dev->lock);
Eric Laurent50a38ed2015-10-14 18:48:06 -07003117 if ((in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
vivek mehta733c1df2016-04-04 15:09:24 -07003118 in->source == AUDIO_SOURCE_VOICE_RECOGNITION ||
Eric Laurent50a38ed2015-10-14 18:48:06 -07003119 adev->mode == AUDIO_MODE_IN_COMMUNICATION) &&
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003120 in->enable_aec != enable &&
3121 (memcmp(&desc.type, FX_IID_AEC, sizeof(effect_uuid_t)) == 0)) {
3122 in->enable_aec = enable;
Eric Laurentcefbbac2014-09-04 13:54:10 -05003123 if (!enable)
3124 platform_set_echo_reference(in->dev, enable, AUDIO_DEVICE_NONE);
vivek mehta733c1df2016-04-04 15:09:24 -07003125 if (in->source == AUDIO_SOURCE_VOICE_COMMUNICATION ||
3126 adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
3127 adev->enable_voicerx = enable;
3128 struct audio_usecase *usecase;
3129 struct listnode *node;
3130 list_for_each(node, &adev->usecase_list) {
3131 usecase = node_to_item(node, struct audio_usecase, list);
3132 if (usecase->type == PCM_PLAYBACK) {
3133 select_devices(adev, usecase->id);
3134 break;
3135 }
Eric Laurentcefbbac2014-09-04 13:54:10 -05003136 }
3137 }
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003138 if (!in->standby)
3139 select_devices(in->dev, in->usecase);
3140 }
Ravi Kumar Alamanda3ad4e1b2014-06-03 00:08:15 -07003141 if (in->enable_ns != enable &&
3142 (memcmp(&desc.type, FX_IID_NS, sizeof(effect_uuid_t)) == 0)) {
3143 in->enable_ns = enable;
3144 if (!in->standby)
3145 select_devices(in->dev, in->usecase);
3146 }
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003147 pthread_mutex_unlock(&in->dev->lock);
3148 pthread_mutex_unlock(&in->lock);
3149
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003150 return 0;
3151}
3152
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003153static int in_add_audio_effect(const struct audio_stream *stream,
3154 effect_handle_t effect)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003155{
Eric Laurent994a6932013-07-17 11:51:42 -07003156 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003157 return add_remove_audio_effect(stream, effect, true);
3158}
3159
3160static int in_remove_audio_effect(const struct audio_stream *stream,
3161 effect_handle_t effect)
3162{
Eric Laurent994a6932013-07-17 11:51:42 -07003163 ALOGV("%s: effect %p", __func__, effect);
Ravi Kumar Alamandaf70ffb42013-04-16 15:55:53 -07003164 return add_remove_audio_effect(stream, effect, false);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003165}
3166
Eric Laurent0e46adf2016-12-16 12:49:24 -08003167static int in_stop(const struct audio_stream_in* stream)
3168{
3169 struct stream_in *in = (struct stream_in *)stream;
3170 struct audio_device *adev = in->dev;
3171
3172 int ret = -ENOSYS;
3173 ALOGV("%s", __func__);
3174 pthread_mutex_lock(&adev->lock);
3175 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
3176 in->capture_started && in->pcm != NULL) {
3177 pcm_stop(in->pcm);
3178 ret = stop_input_stream(in);
Phil Burkbc991042017-02-24 08:06:44 -08003179 in->capture_started = false;
Eric Laurent0e46adf2016-12-16 12:49:24 -08003180 }
3181 pthread_mutex_unlock(&adev->lock);
3182 return ret;
3183}
3184
3185static int in_start(const struct audio_stream_in* stream)
3186{
3187 struct stream_in *in = (struct stream_in *)stream;
3188 struct audio_device *adev = in->dev;
3189 int ret = -ENOSYS;
3190
3191 ALOGV("%s in %p", __func__, in);
3192 pthread_mutex_lock(&adev->lock);
3193 if (in->usecase == USECASE_AUDIO_RECORD_MMAP && !in->standby &&
3194 !in->capture_started && in->pcm != NULL) {
3195 if (!in->capture_started) {
3196 ret = start_input_stream(in);
3197 if (ret == 0) {
3198 in->capture_started = true;
3199 }
3200 }
3201 }
3202 pthread_mutex_unlock(&adev->lock);
3203 return ret;
3204}
3205
3206static int in_create_mmap_buffer(const struct audio_stream_in *stream,
3207 int32_t min_size_frames,
3208 struct audio_mmap_buffer_info *info)
3209{
3210 struct stream_in *in = (struct stream_in *)stream;
3211 struct audio_device *adev = in->dev;
3212 int ret = 0;
3213 unsigned int offset1;
3214 unsigned int frames1;
3215 const char *step = "";
3216
3217 pthread_mutex_lock(&adev->lock);
3218 ALOGV("%s in %p", __func__, in);
Phil Burkbc991042017-02-24 08:06:44 -08003219
Eric Laurent0e46adf2016-12-16 12:49:24 -08003220 if (info == NULL || min_size_frames == 0) {
Phil Burkbc991042017-02-24 08:06:44 -08003221 ALOGE("%s invalid argument info %p min_size_frames %d", __func__, info, min_size_frames);
Eric Laurent0e46adf2016-12-16 12:49:24 -08003222 ret = -EINVAL;
3223 goto exit;
3224 }
3225 if (in->usecase != USECASE_AUDIO_RECORD_MMAP || !in->standby) {
Phil Burkbc991042017-02-24 08:06:44 -08003226 ALOGE("%s: usecase = %d, standby = %d", __func__, in->usecase, in->standby);
Eric Laurent0e46adf2016-12-16 12:49:24 -08003227 ALOGV("%s in %p", __func__, in);
3228 ret = -ENOSYS;
3229 goto exit;
3230 }
3231 in->pcm_device_id = platform_get_pcm_device_id(in->usecase, PCM_CAPTURE);
3232 if (in->pcm_device_id < 0) {
3233 ALOGE("%s: Invalid PCM device id(%d) for the usecase(%d)",
3234 __func__, in->pcm_device_id, in->usecase);
3235 ret = -EINVAL;
3236 goto exit;
3237 }
Phil Burkbc991042017-02-24 08:06:44 -08003238
3239 adjust_mmap_period_count(&in->config, min_size_frames);
3240
Eric Laurent0e46adf2016-12-16 12:49:24 -08003241 ALOGV("%s: Opening PCM device card_id(%d) device_id(%d), channels %d",
3242 __func__, adev->snd_card, in->pcm_device_id, in->config.channels);
3243 in->pcm = pcm_open(adev->snd_card, in->pcm_device_id,
3244 (PCM_IN | PCM_MMAP | PCM_NOIRQ | PCM_MONOTONIC), &in->config);
3245 if (in->pcm == NULL || !pcm_is_ready(in->pcm)) {
3246 step = "open";
3247 ret = -ENODEV;
3248 goto exit;
3249 }
3250
3251 ret = pcm_mmap_begin(in->pcm, &info->shared_memory_address, &offset1, &frames1);
3252 if (ret < 0) {
3253 step = "begin";
3254 goto exit;
3255 }
3256 info->buffer_size_frames = pcm_get_buffer_size(in->pcm);
3257 info->burst_size_frames = in->config.period_size;
3258 info->shared_memory_fd = pcm_get_poll_fd(in->pcm);
3259
3260 memset(info->shared_memory_address, 0, pcm_frames_to_bytes(in->pcm,
3261 info->buffer_size_frames));
3262
3263 ret = pcm_mmap_commit(in->pcm, 0, MMAP_PERIOD_SIZE);
3264 if (ret < 0) {
3265 step = "commit";
3266 goto exit;
3267 }
3268
Phil Burkbc991042017-02-24 08:06:44 -08003269 in->standby = false;
3270 ret = 0;
3271
Eric Laurent0e46adf2016-12-16 12:49:24 -08003272 ALOGV("%s: got mmap buffer address %p info->buffer_size_frames %d",
3273 __func__, info->shared_memory_address, info->buffer_size_frames);
Eric Laurent0e46adf2016-12-16 12:49:24 -08003274
3275exit:
3276 if (ret != 0) {
Phil Burkbc991042017-02-24 08:06:44 -08003277 if (in->pcm == NULL) {
3278 ALOGE("%s: %s - %d", __func__, step, ret);
3279 } else {
3280 ALOGE("%s: %s %s", __func__, step, pcm_get_error(in->pcm));
Eric Laurent0e46adf2016-12-16 12:49:24 -08003281 pcm_close(in->pcm);
3282 in->pcm = NULL;
3283 }
3284 }
3285 pthread_mutex_unlock(&adev->lock);
3286 return ret;
3287}
3288
3289static int in_get_mmap_position(const struct audio_stream_in *stream,
3290 struct audio_mmap_position *position)
3291{
3292 struct stream_in *in = (struct stream_in *)stream;
3293 ALOGVV("%s", __func__);
3294 if (position == NULL) {
3295 return -EINVAL;
3296 }
3297 if (in->usecase != USECASE_AUDIO_RECORD_MMAP) {
3298 return -ENOSYS;
3299 }
3300 if (in->pcm == NULL) {
3301 return -ENOSYS;
3302 }
3303 struct timespec ts = { 0, 0 };
3304 int ret = pcm_mmap_get_hw_ptr(in->pcm, (unsigned int *)&position->position_frames, &ts);
3305 if (ret < 0) {
3306 ALOGE("%s: %s", __func__, pcm_get_error(in->pcm));
3307 return ret;
3308 }
Andy Hungfc044e12017-03-20 09:24:22 -07003309 position->time_nanoseconds = audio_utils_ns_from_timespec(&ts);
Eric Laurent0e46adf2016-12-16 12:49:24 -08003310 return 0;
3311}
3312
3313
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003314static int adev_open_output_stream(struct audio_hw_device *dev,
3315 audio_io_handle_t handle,
3316 audio_devices_t devices,
3317 audio_output_flags_t flags,
3318 struct audio_config *config,
Eric Laurent91975a62014-07-27 17:15:50 -07003319 struct audio_stream_out **stream_out,
3320 const char *address __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003321{
3322 struct audio_device *adev = (struct audio_device *)dev;
3323 struct stream_out *out;
3324 int i, ret;
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08003325 const uint32_t direct_dev = (AUDIO_DEVICE_OUT_HDMI|AUDIO_DEVICE_OUT_USB_DEVICE);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003326
Eric Laurent994a6932013-07-17 11:51:42 -07003327 ALOGV("%s: enter: sample_rate(%d) channel_mask(%#x) devices(%#x) flags(%#x)",
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003328 __func__, config->sample_rate, config->channel_mask, devices, flags);
3329 *stream_out = NULL;
3330 out = (struct stream_out *)calloc(1, sizeof(struct stream_out));
3331
3332 if (devices == AUDIO_DEVICE_NONE)
3333 devices = AUDIO_DEVICE_OUT_SPEAKER;
3334
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003335 out->flags = flags;
3336 out->devices = devices;
Haynes Mathew George47cd4cb2013-07-19 11:58:50 -07003337 out->dev = adev;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003338 out->format = config->format;
3339 out->sample_rate = config->sample_rate;
3340 out->channel_mask = AUDIO_CHANNEL_OUT_STEREO;
3341 out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_STEREO;
Eric Laurentc4aef752013-09-12 17:45:53 -07003342 out->handle = handle;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003343
3344 /* Init use case and pcm_config */
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08003345 if (audio_is_linear_pcm(out->format) &&
3346 (out->flags == AUDIO_OUTPUT_FLAG_NONE ||
3347 out->flags == AUDIO_OUTPUT_FLAG_DIRECT) &&
3348 (out->devices & direct_dev)) {
3349
3350 bool hdmi = (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL);
3351
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003352 pthread_mutex_lock(&adev->lock);
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08003353 if (out->devices & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
3354 ret = read_hdmi_channel_masks(out);
3355 } else if (out->devices & AUDIO_DEVICE_OUT_USB_DEVICE) {
3356 ret = read_usb_sup_formats(out) ||
3357 read_usb_sup_channel_masks(out) ||
3358 read_usb_sup_sample_rates(out);
3359 ALOGV("plugged dev USB ret %d", ret);
3360 } else {
3361 ret = -1;
3362 }
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003363 pthread_mutex_unlock(&adev->lock);
Eric Laurent07eeafd2013-10-06 12:52:49 -07003364 if (ret != 0)
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003365 goto error_open;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003366
3367 if (config->sample_rate == 0)
3368 config->sample_rate = DEFAULT_OUTPUT_SAMPLING_RATE;
3369 if (config->channel_mask == 0)
3370 config->channel_mask = AUDIO_CHANNEL_OUT_5POINT1;
Eric Laurentad1cec22015-12-16 10:12:27 -08003371 if (config->format == AUDIO_FORMAT_DEFAULT)
3372 config->format = AUDIO_FORMAT_PCM_16_BIT;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003373
3374 out->channel_mask = config->channel_mask;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003375 out->sample_rate = config->sample_rate;
Eric Laurentad1cec22015-12-16 10:12:27 -08003376 out->format = config->format;
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08003377 out->usecase = USECASE_AUDIO_PLAYBACK_HIFI;
3378 // does this change?
3379 out->config = hdmi ? pcm_config_hdmi_multi : pcm_config_hifi;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003380 out->config.rate = config->sample_rate;
Eric Laurent0de8d1f2014-07-01 20:34:45 -07003381 out->config.channels = audio_channel_count_from_out_mask(out->channel_mask);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003382 out->config.period_size = HDMI_MULTI_PERIOD_BYTES / (out->config.channels * 2);
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08003383 out->config.format = pcm_format_from_audio_format(out->format);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003384 } else if (out->flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
Haynes Mathew George35807692016-07-07 20:04:54 -07003385 pthread_mutex_lock(&adev->lock);
3386 bool offline = (adev->card_status == CARD_STATUS_OFFLINE);
3387 pthread_mutex_unlock(&adev->lock);
3388
3389 // reject offload during card offline to allow
3390 // fallback to s/w paths
3391 if (offline) {
3392 ret = -ENODEV;
3393 goto error_open;
3394 }
3395
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003396 if (config->offload_info.version != AUDIO_INFO_INITIALIZER.version ||
3397 config->offload_info.size != AUDIO_INFO_INITIALIZER.size) {
3398 ALOGE("%s: Unsupported Offload information", __func__);
3399 ret = -EINVAL;
3400 goto error_open;
3401 }
3402 if (!is_supported_format(config->offload_info.format)) {
3403 ALOGE("%s: Unsupported audio format", __func__);
3404 ret = -EINVAL;
3405 goto error_open;
3406 }
3407
3408 out->compr_config.codec = (struct snd_codec *)
3409 calloc(1, sizeof(struct snd_codec));
3410
3411 out->usecase = USECASE_AUDIO_PLAYBACK_OFFLOAD;
3412 if (config->offload_info.channel_mask)
3413 out->channel_mask = config->offload_info.channel_mask;
3414 else if (config->channel_mask)
3415 out->channel_mask = config->channel_mask;
3416 out->format = config->offload_info.format;
3417 out->sample_rate = config->offload_info.sample_rate;
3418
3419 out->stream.set_callback = out_set_callback;
3420 out->stream.pause = out_pause;
3421 out->stream.resume = out_resume;
3422 out->stream.drain = out_drain;
3423 out->stream.flush = out_flush;
3424
3425 out->compr_config.codec->id =
3426 get_snd_codec_id(config->offload_info.format);
3427 out->compr_config.fragment_size = COMPRESS_OFFLOAD_FRAGMENT_SIZE;
3428 out->compr_config.fragments = COMPRESS_OFFLOAD_NUM_FRAGMENTS;
Eric Laurent1ccf3972014-10-23 14:42:59 -07003429 out->compr_config.codec->sample_rate = config->offload_info.sample_rate;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003430 out->compr_config.codec->bit_rate =
3431 config->offload_info.bit_rate;
3432 out->compr_config.codec->ch_in =
Eric Laurent0de8d1f2014-07-01 20:34:45 -07003433 audio_channel_count_from_out_mask(config->channel_mask);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003434 out->compr_config.codec->ch_out = out->compr_config.codec->ch_in;
3435
3436 if (flags & AUDIO_OUTPUT_FLAG_NON_BLOCKING)
3437 out->non_blocking = 1;
Haynes Mathew George352f27b2013-07-26 00:00:15 -07003438
3439 out->send_new_metadata = 1;
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003440 create_offload_callback_thread(out);
3441 ALOGV("%s: offloaded output offload_info version %04x bit rate %d",
3442 __func__, config->offload_info.version,
3443 config->offload_info.bit_rate);
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003444 } else if (out->devices == AUDIO_DEVICE_OUT_TELEPHONY_TX) {
3445 if (config->sample_rate == 0)
3446 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
3447 if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
3448 config->sample_rate != 8000) {
3449 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
3450 ret = -EINVAL;
3451 goto error_open;
3452 }
3453 out->sample_rate = config->sample_rate;
3454 out->config.rate = config->sample_rate;
3455 if (config->format == AUDIO_FORMAT_DEFAULT)
3456 config->format = AUDIO_FORMAT_PCM_16_BIT;
3457 if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
3458 config->format = AUDIO_FORMAT_PCM_16_BIT;
3459 ret = -EINVAL;
3460 goto error_open;
3461 }
3462 out->format = config->format;
3463 out->usecase = USECASE_AUDIO_PLAYBACK_AFE_PROXY;
3464 out->config = pcm_config_afe_proxy_playback;
3465 adev->voice_tx_output = out;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003466 } else {
Andy Hung6fcba9c2014-03-18 11:53:32 -07003467 if (out->flags & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
3468 out->usecase = USECASE_AUDIO_PLAYBACK_DEEP_BUFFER;
3469 out->config = pcm_config_deep_buffer;
Ravi Kumar Alamandaf78a4d92015-04-24 15:18:23 -07003470 } else if (out->flags & AUDIO_OUTPUT_FLAG_TTS) {
3471 out->usecase = USECASE_AUDIO_PLAYBACK_TTS;
3472 out->config = pcm_config_deep_buffer;
Ravi Kumar Alamanda2bc7b022015-06-25 20:08:01 -07003473 } else if (out->flags & AUDIO_OUTPUT_FLAG_RAW) {
3474 out->usecase = USECASE_AUDIO_PLAYBACK_ULL;
Haynes Mathew George03c40102016-01-29 17:57:48 -08003475 out->realtime = may_use_noirq_mode(adev, USECASE_AUDIO_PLAYBACK_ULL, out->flags);
Haynes Mathew George03c40102016-01-29 17:57:48 -08003476 out->config = out->realtime ? pcm_config_rt : pcm_config_low_latency;
Eric Laurent0e46adf2016-12-16 12:49:24 -08003477 } else if (out->flags & AUDIO_OUTPUT_FLAG_MMAP_NOIRQ) {
3478 out->usecase = USECASE_AUDIO_PLAYBACK_MMAP;
3479 out->config = pcm_config_mmap_playback;
3480 out->stream.start = out_start;
3481 out->stream.stop = out_stop;
3482 out->stream.create_mmap_buffer = out_create_mmap_buffer;
3483 out->stream.get_mmap_position = out_get_mmap_position;
Andy Hung6fcba9c2014-03-18 11:53:32 -07003484 } else {
3485 out->usecase = USECASE_AUDIO_PLAYBACK_LOW_LATENCY;
3486 out->config = pcm_config_low_latency;
3487 }
3488 if (config->format != audio_format_from_pcm_format(out->config.format)) {
3489 if (k_enable_extended_precision
3490 && pcm_params_format_test(adev->use_case_table[out->usecase],
3491 pcm_format_from_audio_format(config->format))) {
3492 out->config.format = pcm_format_from_audio_format(config->format);
3493 /* out->format already set to config->format */
3494 } else {
3495 /* deny the externally proposed config format
3496 * and use the one specified in audio_hw layer configuration.
3497 * Note: out->format is returned by out->stream.common.get_format()
3498 * and is used to set config->format in the code several lines below.
3499 */
3500 out->format = audio_format_from_pcm_format(out->config.format);
3501 }
3502 }
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003503 out->sample_rate = out->config.rate;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003504 }
Andy Hung6fcba9c2014-03-18 11:53:32 -07003505 ALOGV("%s: Usecase(%s) config->format %#x out->config.format %#x\n",
3506 __func__, use_case_table[out->usecase], config->format, out->config.format);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003507
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003508 if (flags & AUDIO_OUTPUT_FLAG_PRIMARY) {
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003509 if (adev->primary_output == NULL)
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003510 adev->primary_output = out;
3511 else {
3512 ALOGE("%s: Primary output is already opened", __func__);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003513 ret = -EEXIST;
3514 goto error_open;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08003515 }
3516 }
3517
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003518 /* Check if this usecase is already existing */
3519 pthread_mutex_lock(&adev->lock);
3520 if (get_usecase_from_list(adev, out->usecase) != NULL) {
3521 ALOGE("%s: Usecase (%d) is already present", __func__, out->usecase);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003522 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003523 ret = -EEXIST;
3524 goto error_open;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003525 }
3526 pthread_mutex_unlock(&adev->lock);
3527
3528 out->stream.common.get_sample_rate = out_get_sample_rate;
3529 out->stream.common.set_sample_rate = out_set_sample_rate;
3530 out->stream.common.get_buffer_size = out_get_buffer_size;
3531 out->stream.common.get_channels = out_get_channels;
3532 out->stream.common.get_format = out_get_format;
3533 out->stream.common.set_format = out_set_format;
3534 out->stream.common.standby = out_standby;
3535 out->stream.common.dump = out_dump;
3536 out->stream.common.set_parameters = out_set_parameters;
3537 out->stream.common.get_parameters = out_get_parameters;
3538 out->stream.common.add_audio_effect = out_add_audio_effect;
3539 out->stream.common.remove_audio_effect = out_remove_audio_effect;
3540 out->stream.get_latency = out_get_latency;
3541 out->stream.set_volume = out_set_volume;
Uday Kishore Pasupuleticec8ad82015-04-15 10:34:06 -07003542#ifdef NO_AUDIO_OUT
3543 out->stream.write = out_write_for_no_output;
3544#else
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003545 out->stream.write = out_write;
Uday Kishore Pasupuleticec8ad82015-04-15 10:34:06 -07003546#endif
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003547 out->stream.get_render_position = out_get_render_position;
3548 out->stream.get_next_write_timestamp = out_get_next_write_timestamp;
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07003549 out->stream.get_presentation_position = out_get_presentation_position;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003550
Eric Laurent0e46adf2016-12-16 12:49:24 -08003551 if (out->realtime)
3552 out->af_period_multiplier = af_period_multiplier;
3553 else
3554 out->af_period_multiplier = 1;
3555
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003556 out->standby = 1;
Eric Laurenta9024de2013-04-04 09:19:12 -07003557 /* out->muted = false; by calloc() */
Glenn Kasten2ccd7ba2013-09-10 09:04:31 -07003558 /* out->written = 0; by calloc() */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003559
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003560 pthread_mutex_init(&out->lock, (const pthread_mutexattr_t *) NULL);
Eric Laurenta1478072015-09-21 17:21:52 -07003561 pthread_mutex_init(&out->pre_lock, (const pthread_mutexattr_t *) NULL);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003562 pthread_cond_init(&out->cond, (const pthread_condattr_t *) NULL);
3563
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003564 config->format = out->stream.common.get_format(&out->stream.common);
3565 config->channel_mask = out->stream.common.get_channels(&out->stream.common);
3566 config->sample_rate = out->stream.common.get_sample_rate(&out->stream.common);
3567
Andy Hunga452b0a2017-03-15 14:51:15 -07003568 out->error_log = error_log_create(
3569 ERROR_LOG_ENTRIES,
3570 1000000000 /* aggregate consecutive identical errors within one second in ns */);
3571
Andy Hungfc044e12017-03-20 09:24:22 -07003572 const size_t POWER_LOG_FRAMES_PER_ENTRY =
3573 config->sample_rate * POWER_LOG_SAMPLING_INTERVAL_MS / 1000;
3574 // power_log may be null if the format is not supported
3575 out->power_log = power_log_create(
3576 config->sample_rate,
3577 audio_channel_count_from_out_mask(config->channel_mask),
3578 config->format,
3579 POWER_LOG_ENTRIES,
3580 POWER_LOG_FRAMES_PER_ENTRY);
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07003581
3582 /*
3583 By locking output stream before registering, we allow the callback
3584 to update stream's state only after stream's initial state is set to
3585 adev state.
3586 */
3587 lock_output_stream(out);
3588 audio_extn_snd_mon_register_listener(out, out_snd_mon_cb);
3589 pthread_mutex_lock(&adev->lock);
3590 out->card_status = adev->card_status;
3591 pthread_mutex_unlock(&adev->lock);
3592 pthread_mutex_unlock(&out->lock);
3593
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003594 *stream_out = &out->stream;
Eric Laurent0e46adf2016-12-16 12:49:24 -08003595
Eric Laurent994a6932013-07-17 11:51:42 -07003596 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003597 return 0;
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003598
3599error_open:
3600 free(out);
3601 *stream_out = NULL;
Eric Laurent2bafff12016-03-17 12:17:23 -07003602 ALOGW("%s: exit: ret %d", __func__, ret);
Ravi Kumar Alamandab1995062013-03-21 23:18:20 -07003603 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003604}
3605
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003606static void adev_close_output_stream(struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003607 struct audio_stream_out *stream)
3608{
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003609 struct stream_out *out = (struct stream_out *)stream;
3610 struct audio_device *adev = out->dev;
3611
Eric Laurent994a6932013-07-17 11:51:42 -07003612 ALOGV("%s: enter", __func__);
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07003613
3614 // must deregister from sndmonitor first to prevent races
3615 // between the callback and close_stream
3616 audio_extn_snd_mon_unregister_listener(out);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003617 out_standby(&stream->common);
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003618 if (out->usecase == USECASE_AUDIO_PLAYBACK_OFFLOAD) {
3619 destroy_offload_callback_thread(out);
3620
3621 if (out->compr_config.codec != NULL)
3622 free(out->compr_config.codec);
3623 }
Ravi Kumar Alamandaa4fc9022014-10-08 18:57:46 -07003624
3625 if (adev->voice_tx_output == out)
3626 adev->voice_tx_output = NULL;
3627
Andy Hungfc044e12017-03-20 09:24:22 -07003628 power_log_destroy(out->power_log);
3629 out->power_log = NULL;
3630
Andy Hunga452b0a2017-03-15 14:51:15 -07003631 error_log_destroy(out->error_log);
3632 out->error_log = NULL;
3633
Ravi Kumar Alamanda4e02e552013-07-17 15:22:04 -07003634 pthread_cond_destroy(&out->cond);
3635 pthread_mutex_destroy(&out->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003636 free(stream);
Eric Laurent994a6932013-07-17 11:51:42 -07003637 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003638}
3639
3640static int adev_set_parameters(struct audio_hw_device *dev, const char *kvpairs)
3641{
3642 struct audio_device *adev = (struct audio_device *)dev;
3643 struct str_parms *parms;
3644 char *str;
3645 char value[32];
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07003646 int val;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003647 int ret;
Eric Laurent03f09432014-03-25 18:09:11 -07003648 int status = 0;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003649
Joe Onorato188b6222016-03-01 11:02:27 -08003650 ALOGV("%s: enter: %s", __func__, kvpairs);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003651
3652 pthread_mutex_lock(&adev->lock);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003653
3654 parms = str_parms_create_str(kvpairs);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003655 status = voice_set_parameters(adev, parms);
3656 if (status != 0) {
3657 goto done;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003658 }
3659
3660 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_NREC, value, sizeof(value));
3661 if (ret >= 0) {
Ravi Kumar Alamandae258e682015-06-25 13:32:42 -07003662 /* When set to false, HAL should disable EC and NS */
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003663 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
3664 adev->bluetooth_nrec = true;
3665 else
3666 adev->bluetooth_nrec = false;
3667 }
3668
3669 ret = str_parms_get_str(parms, "screen_state", value, sizeof(value));
3670 if (ret >= 0) {
3671 if (strcmp(value, AUDIO_PARAMETER_VALUE_ON) == 0)
3672 adev->screen_off = false;
3673 else
3674 adev->screen_off = true;
3675 }
3676
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07003677 ret = str_parms_get_int(parms, "rotation", &val);
3678 if (ret >= 0) {
3679 bool reverse_speakers = false;
3680 switch(val) {
3681 // FIXME: note that the code below assumes that the speakers are in the correct placement
3682 // relative to the user when the device is rotated 90deg from its default rotation. This
3683 // assumption is device-specific, not platform-specific like this code.
3684 case 270:
3685 reverse_speakers = true;
3686 break;
3687 case 0:
3688 case 90:
3689 case 180:
3690 break;
3691 default:
3692 ALOGE("%s: unexpected rotation of %d", __func__, val);
Eric Laurent03f09432014-03-25 18:09:11 -07003693 status = -EINVAL;
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07003694 }
Eric Laurent03f09432014-03-25 18:09:11 -07003695 if (status == 0) {
Ravi Kumar Alamanda1f60cf82015-04-23 19:45:17 -07003696 platform_swap_lr_channels(adev, reverse_speakers);
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07003697 }
Jean-Michel Trivic56336b2013-05-24 16:55:17 -07003698 }
3699
Ravi Kumar Alamanda9f306542014-04-02 15:11:49 -07003700 ret = str_parms_get_str(parms, AUDIO_PARAMETER_KEY_BT_SCO_WB, value, sizeof(value));
3701 if (ret >= 0) {
Ravi Kumar Alamanda9f306542014-04-02 15:11:49 -07003702 adev->bt_wb_speech_enabled = !strcmp(value, AUDIO_PARAMETER_VALUE_ON);
Ravi Kumar Alamanda9f306542014-04-02 15:11:49 -07003703 }
3704
David Linee3fe402017-03-13 10:00:42 -07003705 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
3706 if (ret >= 0) {
3707 audio_devices_t device = (audio_devices_t)strtoul(value, NULL, 10);
3708 if (device == AUDIO_DEVICE_OUT_USB_DEVICE) {
3709 ret = str_parms_get_str(parms, "card", value, sizeof(value));
3710 if (ret >= 0) {
3711 const int card = atoi(value);
3712 audio_extn_usb_add_device(AUDIO_DEVICE_OUT_USB_DEVICE, card);
3713 }
3714 } else if (device == AUDIO_DEVICE_IN_USB_DEVICE) {
3715 ret = str_parms_get_str(parms, "card", value, sizeof(value));
3716 if (ret >= 0) {
3717 const int card = atoi(value);
3718 audio_extn_usb_add_device(AUDIO_DEVICE_IN_USB_DEVICE, card);
3719 }
3720 }
3721 }
3722
3723 ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
3724 if (ret >= 0) {
3725 audio_devices_t device = (audio_devices_t)strtoul(value, NULL, 10);
3726 if (device == AUDIO_DEVICE_OUT_USB_DEVICE) {
3727 ret = str_parms_get_str(parms, "card", value, sizeof(value));
3728 if (ret >= 0) {
3729 const int card = atoi(value);
3730
3731 audio_extn_usb_remove_device(AUDIO_DEVICE_OUT_USB_DEVICE, card);
3732 }
3733 } else if (device == AUDIO_DEVICE_IN_USB_DEVICE) {
3734 ret = str_parms_get_str(parms, "card", value, sizeof(value));
3735 if (ret >= 0) {
3736 const int card = atoi(value);
3737 audio_extn_usb_remove_device(AUDIO_DEVICE_IN_USB_DEVICE, card);
3738 }
3739 }
3740 }
3741
Ravi Kumar Alamanda8e6e98f2013-11-05 15:57:39 -08003742 audio_extn_hfp_set_parameters(adev, parms);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003743done:
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003744 str_parms_destroy(parms);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003745 pthread_mutex_unlock(&adev->lock);
Eric Laurent03f09432014-03-25 18:09:11 -07003746 ALOGV("%s: exit with code(%d)", __func__, status);
3747 return status;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003748}
3749
3750static char* adev_get_parameters(const struct audio_hw_device *dev,
3751 const char *keys)
3752{
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003753 struct audio_device *adev = (struct audio_device *)dev;
3754 struct str_parms *reply = str_parms_create();
3755 struct str_parms *query = str_parms_create_str(keys);
3756 char *str;
3757
3758 pthread_mutex_lock(&adev->lock);
3759
3760 voice_get_parameters(adev, query, reply);
3761 str = str_parms_to_str(reply);
3762 str_parms_destroy(query);
3763 str_parms_destroy(reply);
3764
3765 pthread_mutex_unlock(&adev->lock);
3766 ALOGV("%s: exit: returns - %s", __func__, str);
3767 return str;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003768}
3769
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003770static int adev_init_check(const struct audio_hw_device *dev __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003771{
3772 return 0;
3773}
3774
Haynes Mathew George5191a852013-09-11 14:19:36 -07003775static int adev_set_voice_volume(struct audio_hw_device *dev, float volume)
3776{
3777 int ret;
3778 struct audio_device *adev = (struct audio_device *)dev;
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003779
Eric Laurent4cc4ce12014-09-10 13:21:01 -05003780 audio_extn_extspk_set_voice_vol(adev->extspk, volume);
3781
Haynes Mathew George5191a852013-09-11 14:19:36 -07003782 pthread_mutex_lock(&adev->lock);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003783 ret = voice_set_volume(adev, volume);
Haynes Mathew George5191a852013-09-11 14:19:36 -07003784 pthread_mutex_unlock(&adev->lock);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003785
Haynes Mathew George5191a852013-09-11 14:19:36 -07003786 return ret;
3787}
3788
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003789static int adev_set_master_volume(struct audio_hw_device *dev __unused, float volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003790{
3791 return -ENOSYS;
3792}
3793
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003794static int adev_get_master_volume(struct audio_hw_device *dev __unused,
3795 float *volume __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003796{
3797 return -ENOSYS;
3798}
3799
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003800static int adev_set_master_mute(struct audio_hw_device *dev __unused, bool muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003801{
3802 return -ENOSYS;
3803}
3804
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003805static int adev_get_master_mute(struct audio_hw_device *dev __unused, bool *muted __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003806{
3807 return -ENOSYS;
3808}
3809
3810static int adev_set_mode(struct audio_hw_device *dev, audio_mode_t mode)
3811{
3812 struct audio_device *adev = (struct audio_device *)dev;
3813
3814 pthread_mutex_lock(&adev->lock);
3815 if (adev->mode != mode) {
Eric Laurent2bafff12016-03-17 12:17:23 -07003816 ALOGD("%s: mode %d", __func__, (int)mode);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003817 adev->mode = mode;
Ravi Kumar Alamanda36886fc2014-09-29 13:41:51 -07003818 if ((mode == AUDIO_MODE_NORMAL || mode == AUDIO_MODE_IN_COMMUNICATION) &&
3819 voice_is_in_call(adev)) {
3820 voice_stop_call(adev);
3821 adev->current_call_output = NULL;
3822 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003823 }
3824 pthread_mutex_unlock(&adev->lock);
Eric Laurent0499d4f2014-08-25 22:39:29 -05003825
3826 audio_extn_extspk_set_mode(adev->extspk, mode);
3827
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003828 return 0;
3829}
3830
3831static int adev_set_mic_mute(struct audio_hw_device *dev, bool state)
3832{
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003833 int ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003834 struct audio_device *adev = (struct audio_device *)dev;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003835
Eric Laurent2bafff12016-03-17 12:17:23 -07003836 ALOGD("%s: state %d", __func__, (int)state);
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07003837 pthread_mutex_lock(&adev->lock);
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08003838 if (audio_extn_tfa_98xx_is_supported() && adev->enable_hfp) {
3839 ret = audio_extn_hfp_set_mic_mute(adev, state);
3840 } else {
3841 ret = voice_set_mic_mute(adev, state);
3842 }
Eric Laurent7b2b5ab2014-09-14 12:29:59 -07003843 adev->mic_muted = state;
Eric Laurenta609e8e2014-06-18 02:15:17 +00003844 pthread_mutex_unlock(&adev->lock);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003845
3846 return ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003847}
3848
3849static int adev_get_mic_mute(const struct audio_hw_device *dev, bool *state)
3850{
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003851 *state = voice_get_mic_mute((struct audio_device *)dev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003852 return 0;
3853}
3854
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07003855static size_t adev_get_input_buffer_size(const struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003856 const struct audio_config *config)
3857{
Eric Laurent0de8d1f2014-07-01 20:34:45 -07003858 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003859
Glenn Kasten68e79ce2014-07-15 10:56:59 -07003860 return get_input_buffer_size(config->sample_rate, config->format, channel_count,
3861 false /* is_low_latency: since we don't know, be conservative */);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003862}
3863
3864static int adev_open_input_stream(struct audio_hw_device *dev,
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07003865 audio_io_handle_t handle,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003866 audio_devices_t devices,
3867 struct audio_config *config,
Glenn Kasten68e79ce2014-07-15 10:56:59 -07003868 struct audio_stream_in **stream_in,
Eric Laurent91975a62014-07-27 17:15:50 -07003869 audio_input_flags_t flags,
3870 const char *address __unused,
Eric Laurentcefbbac2014-09-04 13:54:10 -05003871 audio_source_t source )
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003872{
3873 struct audio_device *adev = (struct audio_device *)dev;
3874 struct stream_in *in;
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003875 int ret = 0, buffer_size, frame_size;
Eric Laurent0de8d1f2014-07-01 20:34:45 -07003876 int channel_count = audio_channel_count_from_in_mask(config->channel_mask);
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003877 bool is_low_latency = false;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003878
Eric Laurent994a6932013-07-17 11:51:42 -07003879 ALOGV("%s: enter", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003880 *stream_in = NULL;
3881 if (check_input_parameters(config->sample_rate, config->format, channel_count) != 0)
3882 return -EINVAL;
3883
Zheng Zhang6185d572016-12-01 20:35:17 +08003884 if (audio_extn_tfa_98xx_is_supported() && (audio_extn_hfp_is_active(adev) || voice_is_in_call(adev)))
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08003885 return -EINVAL;
3886
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003887 in = (struct stream_in *)calloc(1, sizeof(struct stream_in));
3888
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003889 pthread_mutex_init(&in->lock, (const pthread_mutexattr_t *) NULL);
Eric Laurenta1478072015-09-21 17:21:52 -07003890 pthread_mutex_init(&in->pre_lock, (const pthread_mutexattr_t *) NULL);
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07003891
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003892 in->stream.common.get_sample_rate = in_get_sample_rate;
3893 in->stream.common.set_sample_rate = in_set_sample_rate;
3894 in->stream.common.get_buffer_size = in_get_buffer_size;
3895 in->stream.common.get_channels = in_get_channels;
3896 in->stream.common.get_format = in_get_format;
3897 in->stream.common.set_format = in_set_format;
3898 in->stream.common.standby = in_standby;
3899 in->stream.common.dump = in_dump;
3900 in->stream.common.set_parameters = in_set_parameters;
3901 in->stream.common.get_parameters = in_get_parameters;
3902 in->stream.common.add_audio_effect = in_add_audio_effect;
3903 in->stream.common.remove_audio_effect = in_remove_audio_effect;
3904 in->stream.set_gain = in_set_gain;
3905 in->stream.read = in_read;
3906 in->stream.get_input_frames_lost = in_get_input_frames_lost;
Andy Hung6ebe5962016-01-15 17:46:57 -08003907 in->stream.get_capture_position = in_get_capture_position;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003908
3909 in->device = devices;
Eric Laurentcefbbac2014-09-04 13:54:10 -05003910 in->source = source;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003911 in->dev = adev;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003912 in->standby = 1;
3913 in->channel_mask = config->channel_mask;
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07003914 in->capture_handle = handle;
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07003915 in->flags = flags;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003916
vivek mehta57ff9b52016-04-28 14:13:08 -07003917 // restrict 24 bit capture for unprocessed source only
3918 // for other sources if 24 bit requested reject 24 and set 16 bit capture only
3919 if (config->format == AUDIO_FORMAT_DEFAULT) {
vivek mehta4ed66e62016-04-15 23:33:34 -07003920 config->format = AUDIO_FORMAT_PCM_16_BIT;
vivek mehta57ff9b52016-04-28 14:13:08 -07003921 } else if (config->format == AUDIO_FORMAT_PCM_FLOAT ||
3922 config->format == AUDIO_FORMAT_PCM_24_BIT_PACKED ||
3923 config->format == AUDIO_FORMAT_PCM_8_24_BIT) {
3924 bool ret_error = false;
3925 /* 24 bit is restricted to UNPROCESSED source only,also format supported
3926 from HAL is 8_24
3927 *> In case of UNPROCESSED source, for 24 bit, if format requested is other than
3928 8_24 return error indicating supported format is 8_24
3929 *> In case of any other source requesting 24 bit or float return error
3930 indicating format supported is 16 bit only.
vivek mehta4ed66e62016-04-15 23:33:34 -07003931
vivek mehta57ff9b52016-04-28 14:13:08 -07003932 on error flinger will retry with supported format passed
3933 */
3934 if (source != AUDIO_SOURCE_UNPROCESSED) {
3935 config->format = AUDIO_FORMAT_PCM_16_BIT;
3936 ret_error = true;
3937 } else if (config->format != AUDIO_FORMAT_PCM_8_24_BIT) {
3938 config->format = AUDIO_FORMAT_PCM_8_24_BIT;
3939 ret_error = true;
3940 }
3941
3942 if (ret_error) {
3943 ret = -EINVAL;
3944 goto err_open;
3945 }
vivek mehta4ed66e62016-04-15 23:33:34 -07003946 }
3947
vivek mehta57ff9b52016-04-28 14:13:08 -07003948 in->format = config->format;
3949
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08003950 /* Update config params with the requested sample rate and channels */
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003951 if (in->device == AUDIO_DEVICE_IN_TELEPHONY_RX) {
3952 if (config->sample_rate == 0)
3953 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
3954 if (config->sample_rate != 48000 && config->sample_rate != 16000 &&
3955 config->sample_rate != 8000) {
3956 config->sample_rate = AFE_PROXY_SAMPLING_RATE;
3957 ret = -EINVAL;
3958 goto err_open;
3959 }
vivek mehta4ed66e62016-04-15 23:33:34 -07003960
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003961 if (config->format != AUDIO_FORMAT_PCM_16_BIT) {
3962 config->format = AUDIO_FORMAT_PCM_16_BIT;
3963 ret = -EINVAL;
3964 goto err_open;
3965 }
3966
3967 in->usecase = USECASE_AUDIO_RECORD_AFE_PROXY;
3968 in->config = pcm_config_afe_proxy_record;
David Line5b12ac2017-03-29 13:37:33 -07003969 in->af_period_multiplier = 1;
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003970 } else {
3971 in->usecase = USECASE_AUDIO_RECORD;
3972 if (config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE &&
Eric Laurent0e46adf2016-12-16 12:49:24 -08003973 (in->flags & AUDIO_INPUT_FLAG_FAST) != 0) {
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003974 is_low_latency = true;
Glenn Kasten4f993392014-05-14 07:30:48 -07003975#if LOW_LATENCY_CAPTURE_USE_CASE
Ravi Kumar Alamanda99c752d2014-08-20 17:55:26 -07003976 in->usecase = USECASE_AUDIO_RECORD_LOW_LATENCY;
Glenn Kasten4f993392014-05-14 07:30:48 -07003977#endif
Haynes Mathew George03c40102016-01-29 17:57:48 -08003978 in->realtime = may_use_noirq_mode(adev, in->usecase, in->flags);
Eric Laurent0e46adf2016-12-16 12:49:24 -08003979 if (!in->realtime) {
Eric Laurentff1e5e62017-02-21 16:08:55 -08003980 in->config = pcm_config_audio_capture;
Eric Laurent0e46adf2016-12-16 12:49:24 -08003981 frame_size = audio_stream_in_frame_size(&in->stream);
3982 buffer_size = get_input_buffer_size(config->sample_rate,
3983 config->format,
3984 channel_count,
3985 is_low_latency);
3986 in->config.period_size = buffer_size / frame_size;
Eric Laurent0e46adf2016-12-16 12:49:24 -08003987 in->config.rate = config->sample_rate;
3988 in->af_period_multiplier = 1;
3989 } else {
3990 // period size is left untouched for rt mode playback
3991 in->config = pcm_config_audio_capture_rt;
3992 in->af_period_multiplier = af_period_multiplier;
3993 }
3994 } else if ((config->sample_rate == LOW_LATENCY_CAPTURE_SAMPLE_RATE) &&
3995 ((in->flags & AUDIO_INPUT_FLAG_MMAP_NOIRQ) != 0)) {
3996 in->usecase = USECASE_AUDIO_RECORD_MMAP;
3997 in->config = pcm_config_mmap_capture;
3998 in->stream.start = in_start;
3999 in->stream.stop = in_stop;
4000 in->stream.create_mmap_buffer = in_create_mmap_buffer;
4001 in->stream.get_mmap_position = in_get_mmap_position;
4002 in->af_period_multiplier = 1;
4003 ALOGV("%s: USECASE_AUDIO_RECORD_MMAP", __func__);
4004 } else {
4005 in->config = pcm_config_audio_capture;
Haynes Mathew George03c40102016-01-29 17:57:48 -08004006 frame_size = audio_stream_in_frame_size(&in->stream);
4007 buffer_size = get_input_buffer_size(config->sample_rate,
4008 config->format,
4009 channel_count,
Eric Laurentf8b50aa2016-05-06 11:03:53 -07004010 is_low_latency);
Haynes Mathew George03c40102016-01-29 17:57:48 -08004011 in->config.period_size = buffer_size / frame_size;
Eric Laurent0e46adf2016-12-16 12:49:24 -08004012 in->config.rate = config->sample_rate;
4013 in->af_period_multiplier = 1;
4014 }
4015 if (config->format == AUDIO_FORMAT_PCM_8_24_BIT)
4016 in->config.format = PCM_FORMAT_S24_LE;
Glenn Kasten68e79ce2014-07-15 10:56:59 -07004017 }
Haynes Mathew George03c40102016-01-29 17:57:48 -08004018
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004019 in->config.channels = channel_count;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004020
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07004021 /* This stream could be for sound trigger lab,
4022 get sound trigger pcm if present */
4023 audio_extn_sound_trigger_check_and_get_session(in);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004024
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07004025 lock_input_stream(in);
4026 audio_extn_snd_mon_register_listener(in, in_snd_mon_cb);
4027 pthread_mutex_lock(&adev->lock);
4028 in->card_status = adev->card_status;
4029 pthread_mutex_unlock(&adev->lock);
4030 pthread_mutex_unlock(&in->lock);
4031
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004032 *stream_in = &in->stream;
Eric Laurent994a6932013-07-17 11:51:42 -07004033 ALOGV("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004034 return 0;
4035
4036err_open:
4037 free(in);
4038 *stream_in = NULL;
4039 return ret;
4040}
4041
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07004042static void adev_close_input_stream(struct audio_hw_device *dev __unused,
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004043 struct audio_stream_in *stream)
4044{
Eric Laurent994a6932013-07-17 11:51:42 -07004045 ALOGV("%s", __func__);
Ravi Kumar Alamanda75d924d2013-02-20 21:30:08 -08004046
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07004047 // must deregister from sndmonitor first to prevent races
4048 // between the callback and close_stream
4049 audio_extn_snd_mon_unregister_listener(stream);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004050 in_standby(&stream->common);
4051 free(stream);
4052
4053 return;
4054}
4055
Haynes Mathew Georgecc9649b2014-06-10 15:08:39 -07004056static int adev_dump(const audio_hw_device_t *device __unused, int fd __unused)
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004057{
4058 return 0;
4059}
4060
Andy Hung31aca912014-03-20 17:14:59 -07004061/* verifies input and output devices and their capabilities.
4062 *
4063 * This verification is required when enabling extended bit-depth or
4064 * sampling rates, as not all qcom products support it.
4065 *
4066 * Suitable for calling only on initialization such as adev_open().
4067 * It fills the audio_device use_case_table[] array.
4068 *
4069 * Has a side-effect that it needs to configure audio routing / devices
4070 * in order to power up the devices and read the device parameters.
4071 * It does not acquire any hw device lock. Should restore the devices
4072 * back to "normal state" upon completion.
4073 */
4074static int adev_verify_devices(struct audio_device *adev)
4075{
4076 /* enumeration is a bit difficult because one really wants to pull
4077 * the use_case, device id, etc from the hidden pcm_device_table[].
4078 * In this case there are the following use cases and device ids.
4079 *
4080 * [USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = {0, 0},
4081 * [USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = {15, 15},
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08004082 * [USECASE_AUDIO_PLAYBACK_HIFI] = {1, 1},
Andy Hung31aca912014-03-20 17:14:59 -07004083 * [USECASE_AUDIO_PLAYBACK_OFFLOAD] = {9, 9},
4084 * [USECASE_AUDIO_RECORD] = {0, 0},
4085 * [USECASE_AUDIO_RECORD_LOW_LATENCY] = {15, 15},
4086 * [USECASE_VOICE_CALL] = {2, 2},
4087 *
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08004088 * USECASE_AUDIO_PLAYBACK_OFFLOAD, USECASE_AUDIO_PLAYBACK_HIFI omitted.
Andy Hung31aca912014-03-20 17:14:59 -07004089 * USECASE_VOICE_CALL omitted, but possible for either input or output.
4090 */
4091
4092 /* should be the usecases enabled in adev_open_input_stream() */
4093 static const int test_in_usecases[] = {
4094 USECASE_AUDIO_RECORD,
4095 USECASE_AUDIO_RECORD_LOW_LATENCY, /* does not appear to be used */
4096 };
4097 /* should be the usecases enabled in adev_open_output_stream()*/
4098 static const int test_out_usecases[] = {
4099 USECASE_AUDIO_PLAYBACK_DEEP_BUFFER,
4100 USECASE_AUDIO_PLAYBACK_LOW_LATENCY,
4101 };
4102 static const usecase_type_t usecase_type_by_dir[] = {
4103 PCM_PLAYBACK,
4104 PCM_CAPTURE,
4105 };
4106 static const unsigned flags_by_dir[] = {
4107 PCM_OUT,
4108 PCM_IN,
4109 };
4110
4111 size_t i;
4112 unsigned dir;
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07004113 const unsigned card_id = adev->snd_card;
Andy Hung31aca912014-03-20 17:14:59 -07004114 char info[512]; /* for possible debug info */
4115
4116 for (dir = 0; dir < 2; ++dir) {
4117 const usecase_type_t usecase_type = usecase_type_by_dir[dir];
4118 const unsigned flags_dir = flags_by_dir[dir];
4119 const size_t testsize =
4120 dir ? ARRAY_SIZE(test_in_usecases) : ARRAY_SIZE(test_out_usecases);
4121 const int *testcases =
4122 dir ? test_in_usecases : test_out_usecases;
4123 const audio_devices_t audio_device =
4124 dir ? AUDIO_DEVICE_IN_BUILTIN_MIC : AUDIO_DEVICE_OUT_SPEAKER;
4125
4126 for (i = 0; i < testsize; ++i) {
4127 const audio_usecase_t audio_usecase = testcases[i];
4128 int device_id;
4129 snd_device_t snd_device;
4130 struct pcm_params **pparams;
4131 struct stream_out out;
4132 struct stream_in in;
4133 struct audio_usecase uc_info;
4134 int retval;
4135
4136 pparams = &adev->use_case_table[audio_usecase];
4137 pcm_params_free(*pparams); /* can accept null input */
4138 *pparams = NULL;
4139
4140 /* find the device ID for the use case (signed, for error) */
4141 device_id = platform_get_pcm_device_id(audio_usecase, usecase_type);
4142 if (device_id < 0)
4143 continue;
4144
4145 /* prepare structures for device probing */
4146 memset(&uc_info, 0, sizeof(uc_info));
4147 uc_info.id = audio_usecase;
4148 uc_info.type = usecase_type;
4149 if (dir) {
4150 adev->active_input = &in;
4151 memset(&in, 0, sizeof(in));
4152 in.device = audio_device;
4153 in.source = AUDIO_SOURCE_VOICE_COMMUNICATION;
4154 uc_info.stream.in = &in;
4155 } else {
4156 adev->active_input = NULL;
4157 }
4158 memset(&out, 0, sizeof(out));
4159 out.devices = audio_device; /* only field needed in select_devices */
4160 uc_info.stream.out = &out;
4161 uc_info.devices = audio_device;
4162 uc_info.in_snd_device = SND_DEVICE_NONE;
4163 uc_info.out_snd_device = SND_DEVICE_NONE;
4164 list_add_tail(&adev->usecase_list, &uc_info.list);
4165
4166 /* select device - similar to start_(in/out)put_stream() */
4167 retval = select_devices(adev, audio_usecase);
4168 if (retval >= 0) {
4169 *pparams = pcm_params_get(card_id, device_id, flags_dir);
4170#if LOG_NDEBUG == 0
4171 if (*pparams) {
4172 ALOGV("%s: (%s) card %d device %d", __func__,
4173 dir ? "input" : "output", card_id, device_id);
4174 pcm_params_to_string(*pparams, info, ARRAY_SIZE(info));
Andy Hung31aca912014-03-20 17:14:59 -07004175 } else {
4176 ALOGV("%s: cannot locate card %d device %d", __func__, card_id, device_id);
4177 }
4178#endif
4179 }
4180
4181 /* deselect device - similar to stop_(in/out)put_stream() */
4182 /* 1. Get and set stream specific mixer controls */
Glenn Kastene7137302014-04-28 15:12:18 -07004183 retval = disable_audio_route(adev, &uc_info);
Andy Hung31aca912014-03-20 17:14:59 -07004184 /* 2. Disable the rx device */
4185 retval = disable_snd_device(adev,
Glenn Kastene7137302014-04-28 15:12:18 -07004186 dir ? uc_info.in_snd_device : uc_info.out_snd_device);
Andy Hung31aca912014-03-20 17:14:59 -07004187 list_remove(&uc_info.list);
4188 }
4189 }
4190 adev->active_input = NULL; /* restore adev state */
4191 return 0;
4192}
4193
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004194static int adev_close(hw_device_t *device)
4195{
Andy Hung31aca912014-03-20 17:14:59 -07004196 size_t i;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004197 struct audio_device *adev = (struct audio_device *)device;
vivek mehta1a9b7c02015-06-25 11:49:38 -07004198
4199 if (!adev)
4200 return 0;
4201
Kevin Rocarda5453442017-05-02 15:09:20 -07004202 audio_extn_snd_mon_unregister_listener(adev);
Kevin Rocard8342c2c2017-04-07 18:50:00 -07004203 audio_extn_snd_mon_deinit();
Kevin Rocarda5453442017-05-02 15:09:20 -07004204
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08004205 audio_extn_tfa_98xx_deinit();
4206
vivek mehta1a9b7c02015-06-25 11:49:38 -07004207 pthread_mutex_lock(&adev_init_lock);
4208
4209 if ((--audio_device_ref_count) == 0) {
4210 audio_route_free(adev->audio_route);
4211 free(adev->snd_dev_ref_cnt);
4212 platform_deinit(adev->platform);
4213 audio_extn_extspk_deinit(adev->extspk);
4214 audio_extn_sound_trigger_deinit(adev);
4215 for (i = 0; i < ARRAY_SIZE(adev->use_case_table); ++i) {
4216 pcm_params_free(adev->use_case_table[i]);
4217 }
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07004218 if (adev->adm_deinit)
4219 adev->adm_deinit(adev->adm_data);
vivek mehta1a9b7c02015-06-25 11:49:38 -07004220 free(device);
Andy Hung31aca912014-03-20 17:14:59 -07004221 }
vivek mehta1a9b7c02015-06-25 11:49:38 -07004222
4223 pthread_mutex_unlock(&adev_init_lock);
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07004224
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004225 return 0;
4226}
4227
Glenn Kasten4f993392014-05-14 07:30:48 -07004228/* This returns 1 if the input parameter looks at all plausible as a low latency period size,
4229 * or 0 otherwise. A return value of 1 doesn't mean the value is guaranteed to work,
4230 * just that it _might_ work.
4231 */
4232static int period_size_is_plausible_for_low_latency(int period_size)
4233{
4234 switch (period_size) {
Glenn Kasten5b5d04e2015-04-09 09:43:29 -07004235 case 48:
4236 case 96:
4237 case 144:
Glenn Kasten4f993392014-05-14 07:30:48 -07004238 case 160:
Glenn Kasten5b5d04e2015-04-09 09:43:29 -07004239 case 192:
Glenn Kasten4f993392014-05-14 07:30:48 -07004240 case 240:
4241 case 320:
4242 case 480:
4243 return 1;
4244 default:
4245 return 0;
4246 }
4247}
4248
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07004249static void adev_snd_mon_cb(void * stream __unused, struct str_parms * parms)
4250{
4251 int card;
4252 card_status_t status;
4253
4254 if (!parms)
4255 return;
4256
4257 if (parse_snd_card_status(parms, &card, &status) < 0)
4258 return;
4259
4260 pthread_mutex_lock(&adev->lock);
4261 bool valid_cb = (card == adev->snd_card);
4262 if (valid_cb) {
4263 if (adev->card_status != status) {
4264 adev->card_status = status;
4265 platform_snd_card_update(adev->platform, status);
4266 }
4267 }
4268 pthread_mutex_unlock(&adev->lock);
4269 return;
4270}
4271
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004272static int adev_open(const hw_module_t *module, const char *name,
4273 hw_device_t **device)
4274{
Ravi Kumar Alamanda71c84b72013-03-10 23:50:28 -07004275 int i, ret;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004276
Eric Laurent2bafff12016-03-17 12:17:23 -07004277 ALOGD("%s: enter", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004278 if (strcmp(name, AUDIO_HARDWARE_INTERFACE) != 0) return -EINVAL;
vivek mehta1a9b7c02015-06-25 11:49:38 -07004279 pthread_mutex_lock(&adev_init_lock);
4280 if (audio_device_ref_count != 0) {
4281 *device = &adev->device.common;
4282 audio_device_ref_count++;
4283 ALOGV("%s: returning existing instance of adev", __func__);
4284 ALOGV("%s: exit", __func__);
4285 pthread_mutex_unlock(&adev_init_lock);
4286 return 0;
4287 }
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004288 adev = calloc(1, sizeof(struct audio_device));
4289
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07004290 pthread_mutex_init(&adev->lock, (const pthread_mutexattr_t *) NULL);
4291
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004292 adev->device.common.tag = HARDWARE_DEVICE_TAG;
4293 adev->device.common.version = AUDIO_DEVICE_API_VERSION_2_0;
4294 adev->device.common.module = (struct hw_module_t *)module;
4295 adev->device.common.close = adev_close;
4296
4297 adev->device.init_check = adev_init_check;
4298 adev->device.set_voice_volume = adev_set_voice_volume;
4299 adev->device.set_master_volume = adev_set_master_volume;
4300 adev->device.get_master_volume = adev_get_master_volume;
4301 adev->device.set_master_mute = adev_set_master_mute;
4302 adev->device.get_master_mute = adev_get_master_mute;
4303 adev->device.set_mode = adev_set_mode;
4304 adev->device.set_mic_mute = adev_set_mic_mute;
4305 adev->device.get_mic_mute = adev_get_mic_mute;
4306 adev->device.set_parameters = adev_set_parameters;
4307 adev->device.get_parameters = adev_get_parameters;
4308 adev->device.get_input_buffer_size = adev_get_input_buffer_size;
4309 adev->device.open_output_stream = adev_open_output_stream;
4310 adev->device.close_output_stream = adev_close_output_stream;
4311 adev->device.open_input_stream = adev_open_input_stream;
Eric Laurent0e46adf2016-12-16 12:49:24 -08004312
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004313 adev->device.close_input_stream = adev_close_input_stream;
4314 adev->device.dump = adev_dump;
4315
4316 /* Set the default route before the PCM stream is opened */
4317 pthread_mutex_lock(&adev->lock);
4318 adev->mode = AUDIO_MODE_NORMAL;
Eric Laurentc8400632013-02-14 19:04:54 -08004319 adev->active_input = NULL;
Ravi Kumar Alamanda096c87f2013-02-28 20:54:57 -08004320 adev->primary_output = NULL;
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004321 adev->bluetooth_nrec = true;
Ravi Kumar Alamandaf9967042013-02-14 19:35:14 -08004322 adev->acdb_settings = TTY_MODE_OFF;
Eric Laurent07eeafd2013-10-06 12:52:49 -07004323 /* adev->cur_hdmi_channels = 0; by calloc() */
Eric Laurentb23d5282013-05-14 15:27:20 -07004324 adev->snd_dev_ref_cnt = calloc(SND_DEVICE_MAX, sizeof(int));
Vineeta Srivastava4b89e372014-06-19 14:21:42 -07004325 voice_init(adev);
Ravi Kumar Alamanda3b1816c2013-02-27 23:01:21 -08004326 list_init(&adev->usecase_list);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004327 pthread_mutex_unlock(&adev->lock);
4328
4329 /* Loads platform specific libraries dynamically */
Eric Laurentb23d5282013-05-14 15:27:20 -07004330 adev->platform = platform_init(adev);
4331 if (!adev->platform) {
4332 free(adev->snd_dev_ref_cnt);
4333 free(adev);
4334 ALOGE("%s: Failed to init platform data, aborting.", __func__);
4335 *device = NULL;
vivek mehta1a9b7c02015-06-25 11:49:38 -07004336 pthread_mutex_unlock(&adev_init_lock);
Eric Laurentb23d5282013-05-14 15:27:20 -07004337 return -EINVAL;
4338 }
Eric Laurent0499d4f2014-08-25 22:39:29 -05004339 adev->extspk = audio_extn_extspk_init(adev);
Ravi Kumar Alamandaa417cc52015-05-01 16:41:56 -07004340 audio_extn_sound_trigger_init(adev);
Eric Laurent0499d4f2014-08-25 22:39:29 -05004341
Glenn Kasten6d53bfd2016-04-04 16:58:03 -07004342 adev->visualizer_lib = dlopen(VISUALIZER_LIBRARY_PATH, RTLD_NOW);
4343 if (adev->visualizer_lib == NULL) {
4344 ALOGW("%s: DLOPEN failed for %s", __func__, VISUALIZER_LIBRARY_PATH);
4345 } else {
4346 ALOGV("%s: DLOPEN successful for %s", __func__, VISUALIZER_LIBRARY_PATH);
4347 adev->visualizer_start_output =
4348 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
4349 "visualizer_hal_start_output");
4350 adev->visualizer_stop_output =
4351 (int (*)(audio_io_handle_t, int))dlsym(adev->visualizer_lib,
4352 "visualizer_hal_stop_output");
Eric Laurentc4aef752013-09-12 17:45:53 -07004353 }
4354
Glenn Kasten6d53bfd2016-04-04 16:58:03 -07004355 adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW);
4356 if (adev->offload_effects_lib == NULL) {
4357 ALOGW("%s: DLOPEN failed for %s", __func__,
4358 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
4359 } else {
4360 ALOGV("%s: DLOPEN successful for %s", __func__,
4361 OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH);
4362 adev->offload_effects_start_output =
4363 (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
4364 "offload_effects_bundle_hal_start_output");
4365 adev->offload_effects_stop_output =
4366 (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib,
4367 "offload_effects_bundle_hal_stop_output");
Haynes Mathew George41f86652014-06-17 14:22:15 -07004368 }
4369
Glenn Kasten6d53bfd2016-04-04 16:58:03 -07004370 adev->adm_lib = dlopen(ADM_LIBRARY_PATH, RTLD_NOW);
4371 if (adev->adm_lib == NULL) {
4372 ALOGW("%s: DLOPEN failed for %s", __func__, ADM_LIBRARY_PATH);
4373 } else {
4374 ALOGV("%s: DLOPEN successful for %s", __func__, ADM_LIBRARY_PATH);
4375 adev->adm_init = (adm_init_t)
4376 dlsym(adev->adm_lib, "adm_init");
4377 adev->adm_deinit = (adm_deinit_t)
4378 dlsym(adev->adm_lib, "adm_deinit");
4379 adev->adm_register_input_stream = (adm_register_input_stream_t)
4380 dlsym(adev->adm_lib, "adm_register_input_stream");
4381 adev->adm_register_output_stream = (adm_register_output_stream_t)
4382 dlsym(adev->adm_lib, "adm_register_output_stream");
4383 adev->adm_deregister_stream = (adm_deregister_stream_t)
4384 dlsym(adev->adm_lib, "adm_deregister_stream");
4385 adev->adm_request_focus = (adm_request_focus_t)
4386 dlsym(adev->adm_lib, "adm_request_focus");
4387 adev->adm_abandon_focus = (adm_abandon_focus_t)
4388 dlsym(adev->adm_lib, "adm_abandon_focus");
Haynes Mathew George03c40102016-01-29 17:57:48 -08004389 adev->adm_set_config = (adm_set_config_t)
4390 dlsym(adev->adm_lib, "adm_set_config");
4391 adev->adm_request_focus_v2 = (adm_request_focus_v2_t)
4392 dlsym(adev->adm_lib, "adm_request_focus_v2");
4393 adev->adm_is_noirq_avail = (adm_is_noirq_avail_t)
4394 dlsym(adev->adm_lib, "adm_is_noirq_avail");
4395 adev->adm_on_routing_change = (adm_on_routing_change_t)
4396 dlsym(adev->adm_lib, "adm_on_routing_change");
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07004397 }
4398
Ravi Kumar Alamanda9f306542014-04-02 15:11:49 -07004399 adev->bt_wb_speech_enabled = false;
Eric Laurentcefbbac2014-09-04 13:54:10 -05004400 adev->enable_voicerx = false;
Ravi Kumar Alamanda9f306542014-04-02 15:11:49 -07004401
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004402 *device = &adev->device.common;
vivek mehta1a9b7c02015-06-25 11:49:38 -07004403
Andy Hung31aca912014-03-20 17:14:59 -07004404 if (k_enable_extended_precision)
4405 adev_verify_devices(adev);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004406
Glenn Kasten4f993392014-05-14 07:30:48 -07004407 char value[PROPERTY_VALUE_MAX];
4408 int trial;
4409 if (property_get("audio_hal.period_size", value, NULL) > 0) {
4410 trial = atoi(value);
4411 if (period_size_is_plausible_for_low_latency(trial)) {
4412 pcm_config_low_latency.period_size = trial;
4413 pcm_config_low_latency.start_threshold = trial / 4;
4414 pcm_config_low_latency.avail_min = trial / 4;
4415 configured_low_latency_capture_period_size = trial;
4416 }
4417 }
4418 if (property_get("audio_hal.in_period_size", value, NULL) > 0) {
4419 trial = atoi(value);
4420 if (period_size_is_plausible_for_low_latency(trial)) {
4421 configured_low_latency_capture_period_size = trial;
4422 }
4423 }
4424
Haynes Mathew Georgee5ff0fc2017-02-16 20:33:38 -08004425 // commented as full set of app type cfg is sent from platform
4426 // audio_extn_utils_send_default_app_type_cfg(adev->platform, adev->mixer);
vivek mehta1a9b7c02015-06-25 11:49:38 -07004427 audio_device_ref_count++;
Haynes Mathew George03c40102016-01-29 17:57:48 -08004428
4429 if (property_get("audio_hal.period_multiplier", value, NULL) > 0) {
4430 af_period_multiplier = atoi(value);
4431 if (af_period_multiplier < 0) {
4432 af_period_multiplier = 2;
4433 } else if (af_period_multiplier > 4) {
4434 af_period_multiplier = 4;
4435 }
4436 ALOGV("new period_multiplier = %d", af_period_multiplier);
4437 }
4438
Alain Vongsouvanh13f26e82016-11-18 14:39:11 -08004439 audio_extn_tfa_98xx_init(adev);
4440
vivek mehta1a9b7c02015-06-25 11:49:38 -07004441 pthread_mutex_unlock(&adev_init_lock);
4442
Haynes Mathew George88e6fb22015-08-19 11:51:34 -07004443 if (adev->adm_init)
4444 adev->adm_data = adev->adm_init();
4445
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07004446 audio_extn_perf_lock_init();
Haynes Mathew Georgec735fb02016-06-30 18:00:28 -07004447 audio_extn_snd_mon_init();
4448 pthread_mutex_lock(&adev->lock);
4449 audio_extn_snd_mon_register_listener(NULL, adev_snd_mon_cb);
4450 adev->card_status = CARD_STATUS_ONLINE;
4451 pthread_mutex_unlock(&adev->lock);
Ravi Kumar Alamanda533bb722015-09-23 13:47:03 -07004452
Eric Laurent2bafff12016-03-17 12:17:23 -07004453 ALOGD("%s: exit", __func__);
Ravi Kumar Alamanda2dfba2b2013-01-17 16:50:22 -08004454 return 0;
4455}
4456
4457static struct hw_module_methods_t hal_module_methods = {
4458 .open = adev_open,
4459};
4460
4461struct audio_module HAL_MODULE_INFO_SYM = {
4462 .common = {
4463 .tag = HARDWARE_MODULE_TAG,
4464 .module_api_version = AUDIO_MODULE_API_VERSION_0_1,
4465 .hal_api_version = HARDWARE_HAL_API_VERSION,
4466 .id = AUDIO_HARDWARE_MODULE_ID,
4467 .name = "QCOM Audio HAL",
4468 .author = "Code Aurora Forum",
4469 .methods = &hal_module_methods,
4470 },
4471};