Newer
Older
* Copyright (c) 2013-2022, The Linux Foundation. All rights reserved.
* Not a Contribution.
*
* Copyright (C) 2013 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* This file was modified by DTS, Inc. The portions of the
* code modified by DTS, Inc are copyrighted and
* licensed separately, as follows:
*
* (C) 2014 DTS, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Changes from Qualcomm Innovation Center are provided under the following license:
* Copyright (c) 2023-2024 Qualcomm Innovation Center, Inc. All rights reserved.
* SPDX-License-Identifier: BSD-3-Clause-Clear
*
*/
#define LOG_TAG "audio_hw_primary"
#define ATRACE_TAG (ATRACE_TAG_AUDIO|ATRACE_TAG_HAL)
/*#define VERY_VERY_VERBOSE_LOGGING*/
#ifdef VERY_VERY_VERBOSE_LOGGING
#define ALOGVV ALOGV
#else
#define ALOGVV(a...) do { } while(0)
#endif
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <sys/time.h>
#include <stdlib.h>
#include <math.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <cutils/trace.h>
#include <cutils/str_parms.h>
#include <cutils/properties.h>
#include <cutils/atomic.h>
#include <cutils/sched_policy.h>
#include <hardware/audio_effect.h>
#include <hardware/audio_alsaops.h>
#include <system/thread_defs.h>
#include <tinyalsa/asoundlib.h>
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_ns.h>
#include <audio_utils/format.h>
#include "platform_api.h"
#include <platform.h>
#include "audio_extn.h"
#include "sound/compress_params.h"
#ifdef AUDIO_GKI_ENABLED
#include "sound/audio_compressed_formats.h"
#endif
#include "audio_amplifier.h"
#ifdef DYNAMIC_LOG_ENABLED
#include <log_xml_parser.h>
#define LOG_MASK HAL_MOD_FILE_AUDIO_HW
#include <log_utils.h>
#endif
#define SKIP_INPUT_SOURCE_PRIORITY
#define COMPRESS_OFFLOAD_NUM_FRAGMENTS 4
/*DIRECT PCM has same buffer sizes as DEEP Buffer*/
#define DIRECT_PCM_NUM_FRAGMENTS 2
#define COMPRESS_PLAYBACK_VOLUME_MAX 0x2000
#define VOIP_PLAYBACK_VOLUME_MAX 0x2000
#define PCM_PLAYBACK_VOLUME_MAX 0x2000
#define DSD_VOLUME_MIN_DB (-110)
#define INVALID_OUT_VOLUME -1
#define AUDIO_IO_PORTS_MAX 32
#define PLAYBACK_GAIN_MAX 1.0f
#define RECORD_GAIN_MIN 0.0f
#define RECORD_GAIN_MAX 1.0f
#define RECORD_VOLUME_CTL_MAX 0x2000
/* treat as unsigned Q1.13 */
#define APP_TYPE_GAIN_DEFAULT 0x2000
#define PROXY_OPEN_RETRY_COUNT 100
#define PROXY_OPEN_WAIT_TIME 20
#define GET_USECASE_AUDIO_PLAYBACK_PRIMARY(db) \
(db)? USECASE_AUDIO_PLAYBACK_DEEP_BUFFER : \
USECASE_AUDIO_PLAYBACK_LOW_LATENCY
#define GET_PCM_CONFIG_AUDIO_PLAYBACK_PRIMARY(db) \
(db)? pcm_config_deep_buffer : pcm_config_low_latency
#define ULL_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
#define DEFAULT_VOIP_BUF_DURATION_MS 20
#define DEFAULT_VOIP_BIT_DEPTH_BYTE sizeof(int16_t)
#define DEFAULT_VOIP_SAMP_RATE 48000
#define VOIP_IO_BUF_SIZE(SR, DURATION_MS, BIT_DEPTH) (SR)/1000 * DURATION_MS * BIT_DEPTH
struct pcm_config default_pcm_config_voip_copp = {
.channels = 1,
.rate = DEFAULT_VOIP_SAMP_RATE, /* changed when the stream is opened */
.period_size = VOIP_IO_BUF_SIZE(DEFAULT_VOIP_SAMP_RATE, DEFAULT_VOIP_BUF_DURATION_MS, DEFAULT_VOIP_BIT_DEPTH_BYTE)/2,
.period_count = 2,
.format = PCM_FORMAT_S16_LE,
.avail_min = VOIP_IO_BUF_SIZE(DEFAULT_VOIP_SAMP_RATE, DEFAULT_VOIP_BUF_DURATION_MS, DEFAULT_VOIP_BIT_DEPTH_BYTE)/2,
.stop_threshold = INT_MAX,
#define MIN_CHANNEL_COUNT 1
#define DEFAULT_CHANNEL_COUNT 2
#define MAX_HIFI_CHANNEL_COUNT 8
#ifndef MAX_TARGET_SPECIFIC_CHANNEL_CNT
#define MAX_CHANNEL_COUNT 1
#else
#define MAX_CHANNEL_COUNT atoi(XSTR(MAX_TARGET_SPECIFIC_CHANNEL_CNT))
#define XSTR(x) STR(x)
#define STR(x) #x
#endif
#define IS_USB_HIFI (MAX_HIFI_CHANNEL_COUNT >= MAX_CHANNEL_COUNT) ? \
true : false
#ifdef LINUX_ENABLED
static inline int64_t audio_utils_ns_from_timespec(const struct timespec *ts)
{
return ts->tv_sec * 1000000000LL + ts->tv_nsec;
}
#endif
static unsigned int configured_low_latency_capture_period_size =
LOW_LATENCY_CAPTURE_PERIOD_SIZE;
#define MMAP_PERIOD_SIZE (DEFAULT_OUTPUT_SAMPLING_RATE/1000)
#define MMAP_PERIOD_COUNT_MIN 32
#define MMAP_PERIOD_COUNT_MAX 512
#define MMAP_PERIOD_COUNT_DEFAULT (MMAP_PERIOD_COUNT_MAX)
/* This constant enables extended precision handling.
* TODO The flag is off until more testing is done.
*/
static const bool k_enable_extended_precision = false;
extern int AUDIO_DEVICE_IN_ALL_CODEC_BACKEND;
struct pcm_config pcm_config_deep_buffer = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = DEEP_BUFFER_OUTPUT_PERIOD_SIZE,
.period_count = DEEP_BUFFER_OUTPUT_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
.stop_threshold = INT_MAX,
.avail_min = DEEP_BUFFER_OUTPUT_PERIOD_SIZE / 4,
};
struct pcm_config pcm_config_low_latency = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
.period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
.stop_threshold = INT_MAX,
.avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
};
struct pcm_config pcm_config_haptics_audio = {
.channels = 1,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
.period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
.stop_threshold = INT_MAX,
.avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
};
struct pcm_config pcm_config_haptics = {
.channels = 1,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
.period_count = LOW_LATENCY_OUTPUT_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = LOW_LATENCY_OUTPUT_PERIOD_SIZE,
.stop_threshold = INT_MAX,
.avail_min = LOW_LATENCY_OUTPUT_PERIOD_SIZE / 4,
};
static int af_period_multiplier = 4;
struct pcm_config pcm_config_rt = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = ULL_PERIOD_SIZE, //1 ms
.period_count = 512, //=> buffer size is 512ms
.format = PCM_FORMAT_S16_LE,
.start_threshold = ULL_PERIOD_SIZE*8, //8ms
.stop_threshold = INT_MAX,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = ULL_PERIOD_SIZE, //1 ms
};
struct pcm_config pcm_config_hdmi_multi = {
.channels = HDMI_MULTI_DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
.rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
.period_size = HDMI_MULTI_PERIOD_SIZE,
.period_count = HDMI_MULTI_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = INT_MAX,
.avail_min = 0,
struct pcm_config pcm_config_mmap_playback = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = MMAP_PERIOD_SIZE,
.period_count = MMAP_PERIOD_COUNT_DEFAULT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = MMAP_PERIOD_SIZE*8,
.stop_threshold = INT32_MAX,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = MMAP_PERIOD_SIZE, //1 ms
};
struct pcm_config pcm_config_hifi = {
.channels = DEFAULT_CHANNEL_COUNT, /* changed when the stream is opened */
.rate = DEFAULT_OUTPUT_SAMPLING_RATE, /* changed when the stream is opened */
.period_size = HIFI_BUFFER_OUTPUT_PERIOD_SIZE, /* change #define */
.period_count = HIFI_BUFFER_OUTPUT_PERIOD_COUNT,
.format = PCM_FORMAT_S24_3LE,
.start_threshold = 0,
.stop_threshold = INT_MAX,
.avail_min = 0,
};
struct pcm_config pcm_config_audio_capture = {
.channels = 2,
.period_count = AUDIO_CAPTURE_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
};
struct pcm_config pcm_config_mmap_capture = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = MMAP_PERIOD_SIZE,
.period_count = MMAP_PERIOD_COUNT_DEFAULT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = INT_MAX,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = MMAP_PERIOD_SIZE, //1 ms
};
#define AFE_PROXY_CHANNEL_COUNT 2
#define AFE_PROXY_SAMPLING_RATE 48000
#define AFE_PROXY_PLAYBACK_PERIOD_SIZE 768
#define AFE_PROXY_PLAYBACK_PERIOD_COUNT 4
struct pcm_config pcm_config_afe_proxy_playback = {
.channels = AFE_PROXY_CHANNEL_COUNT,
.rate = AFE_PROXY_SAMPLING_RATE,
.period_size = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
.period_count = AFE_PROXY_PLAYBACK_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
.stop_threshold = INT_MAX,
.avail_min = AFE_PROXY_PLAYBACK_PERIOD_SIZE,
};
#define AFE_PROXY_RECORD_PERIOD_SIZE 768
#define AFE_PROXY_RECORD_PERIOD_COUNT 4
struct pcm_config pcm_config_audio_capture_rt = {
.channels = 2,
.rate = DEFAULT_OUTPUT_SAMPLING_RATE,
.period_size = ULL_PERIOD_SIZE,
.period_count = 512,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = ULL_PERIOD_SIZE, //1 ms
};
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
struct pcm_config pcm_config_audio_capture_rt_48KHz = {
.channels = 2,
.rate = 48000,
.period_size = 48,
.period_count = 512,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = 48, //1 ms
};
struct pcm_config pcm_config_audio_capture_rt_32KHz = {
.channels = 2,
.rate = 32000,
.period_size = 32,
.period_count = 512,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = 32, //1 ms
};
struct pcm_config pcm_config_audio_capture_rt_24KHz = {
.channels = 2,
.rate = 24000,
.period_size = 24,
.period_count = 512,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = 24, //1 ms
};
struct pcm_config pcm_config_audio_capture_rt_16KHz = {
.channels = 2,
.rate = 16000,
.period_size = 16,
.period_count = 512,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = 16, //1 ms
};
struct pcm_config pcm_config_audio_capture_rt_8KHz = {
.channels = 2,
.rate = 8000,
.period_size = 8,
.period_count = 512,
.format = PCM_FORMAT_S16_LE,
.start_threshold = 0,
.stop_threshold = AFE_PROXY_RECORD_PERIOD_SIZE * AFE_PROXY_RECORD_PERIOD_COUNT,
.silence_threshold = 0,
.silence_size = 0,
.avail_min = 8, //1 ms
};
struct pcm_config pcm_config_afe_proxy_record = {
.channels = AFE_PROXY_CHANNEL_COUNT,
.rate = AFE_PROXY_SAMPLING_RATE,
.period_size = AFE_PROXY_RECORD_PERIOD_SIZE,
.period_count = AFE_PROXY_RECORD_PERIOD_COUNT,
.format = PCM_FORMAT_S16_LE,
.start_threshold = AFE_PROXY_RECORD_PERIOD_SIZE,
.stop_threshold = INT_MAX,
.avail_min = AFE_PROXY_RECORD_PERIOD_SIZE,
};
#define AUDIO_MAX_PCM_FORMATS 7
const uint32_t format_to_bitwidth_table[AUDIO_MAX_PCM_FORMATS] = {
[AUDIO_FORMAT_DEFAULT] = 0,
[AUDIO_FORMAT_PCM_16_BIT] = sizeof(uint16_t),
[AUDIO_FORMAT_PCM_8_BIT] = sizeof(uint8_t),
[AUDIO_FORMAT_PCM_32_BIT] = sizeof(uint32_t),
[AUDIO_FORMAT_PCM_8_24_BIT] = sizeof(uint32_t),
[AUDIO_FORMAT_PCM_FLOAT] = sizeof(float),
[AUDIO_FORMAT_PCM_24_BIT_PACKED] = sizeof(uint8_t) * 3,
};
const char * const use_case_table[AUDIO_USECASE_MAX] = {
[USECASE_AUDIO_PLAYBACK_DEEP_BUFFER] = "deep-buffer-playback",
[USECASE_AUDIO_PLAYBACK_LOW_LATENCY] = "low-latency-playback",
[USECASE_AUDIO_PLAYBACK_WITH_HAPTICS] = "audio-with-haptics-playback",
[USECASE_AUDIO_PLAYBACK_HAPTICS] = "haptics-playback",
[USECASE_AUDIO_PLAYBACK_ULL] = "audio-ull-playback",
[USECASE_AUDIO_PLAYBACK_MULTI_CH] = "multi-channel-playback",
[USECASE_AUDIO_PLAYBACK_OFFLOAD] = "compress-offload-playback",

Subhash Chandra Bose Naripeddy
committed
[USECASE_AUDIO_PLAYBACK_OFFLOAD2] = "compress-offload-playback2",
[USECASE_AUDIO_PLAYBACK_OFFLOAD3] = "compress-offload-playback3",
[USECASE_AUDIO_PLAYBACK_OFFLOAD4] = "compress-offload-playback4",
[USECASE_AUDIO_PLAYBACK_OFFLOAD5] = "compress-offload-playback5",
[USECASE_AUDIO_PLAYBACK_OFFLOAD6] = "compress-offload-playback6",
[USECASE_AUDIO_PLAYBACK_OFFLOAD7] = "compress-offload-playback7",
[USECASE_AUDIO_PLAYBACK_OFFLOAD8] = "compress-offload-playback8",
[USECASE_AUDIO_PLAYBACK_OFFLOAD9] = "compress-offload-playback9",
[USECASE_AUDIO_PLAYBACK_FM] = "play-fm",
[USECASE_AUDIO_PLAYBACK_MMAP] = "mmap-playback",
[USECASE_AUDIO_PLAYBACK_HIFI] = "hifi-playback",
[USECASE_AUDIO_RECORD] = "audio-record",
[USECASE_AUDIO_RECORD2] = "audio-record2",
[USECASE_AUDIO_RECORD3] = "audio-record3",
[USECASE_AUDIO_RECORD_COMPRESS] = "audio-record-compress",
[USECASE_AUDIO_RECORD_COMPRESS2] = "audio-record-compress2",
[USECASE_AUDIO_RECORD_COMPRESS3] = "audio-record-compress3",
[USECASE_AUDIO_RECORD_COMPRESS4] = "audio-record-compress4",
[USECASE_AUDIO_RECORD_COMPRESS5] = "audio-record-compress5",
[USECASE_AUDIO_RECORD_COMPRESS6] = "audio-record-compress6",
[USECASE_AUDIO_RECORD_LOW_LATENCY] = "low-latency-record",

Kogara Naveen Kumar
committed
[USECASE_AUDIO_RECORD_LOW_LATENCY2] = "low-latency-record2",
[USECASE_AUDIO_RECORD_FM_VIRTUAL] = "fm-virtual-record",
[USECASE_AUDIO_RECORD_MMAP] = "mmap-record",
[USECASE_AUDIO_RECORD_HIFI] = "hifi-record",
[USECASE_AUDIO_HFP_SCO_WB] = "hfp-sco-wb",
[USECASE_AUDIO_HFP_SCO_DOWNLINK] = "hfp-sco-downlink",
[USECASE_AUDIO_HFP_SCO_WB_DOWNLINK] = "hfp-sco-wb-downlink",
[USECASE_VOICE_CALL] = "voice-call",
[USECASE_VOICE2_CALL] = "voice2-call",
[USECASE_VOLTE_CALL] = "volte-call",
[USECASE_QCHAT_CALL] = "qchat-call",
[USECASE_VOWLAN_CALL] = "vowlan-call",
[USECASE_VOICEMMODE1_CALL] = "voicemmode1-call",
[USECASE_VOICEMMODE2_CALL] = "voicemmode2-call",
[USECASE_COMPRESS_VOIP_CALL] = "compress-voip-call",
[USECASE_INCALL_REC_UPLINK] = "incall-rec-uplink",
[USECASE_INCALL_REC_DOWNLINK] = "incall-rec-downlink",
[USECASE_INCALL_REC_UPLINK_AND_DOWNLINK] = "incall-rec-uplink-and-downlink",
[USECASE_INCALL_REC_UPLINK_COMPRESS] = "incall-rec-uplink-compress",
[USECASE_INCALL_REC_DOWNLINK_COMPRESS] = "incall-rec-downlink-compress",
[USECASE_INCALL_REC_UPLINK_AND_DOWNLINK_COMPRESS] = "incall-rec-uplink-and-downlink-compress",
[USECASE_INCALL_MUSIC_UPLINK] = "incall_music_uplink",
[USECASE_INCALL_MUSIC_UPLINK2] = "incall_music_uplink2",
[USECASE_AUDIO_SPKR_CALIB_RX] = "spkr-rx-calib",
[USECASE_AUDIO_SPKR_CALIB_TX] = "spkr-vi-record",
[USECASE_AUDIO_PLAYBACK_AFE_PROXY] = "afe-proxy-playback",
[USECASE_AUDIO_RECORD_AFE_PROXY] = "afe-proxy-record",
[USECASE_AUDIO_RECORD_AFE_PROXY2] = "afe-proxy-record2",
[USECASE_AUDIO_PLAYBACK_SILENCE] = "silence-playback",
/* Transcode loopback cases */
[USECASE_AUDIO_TRANSCODE_LOOPBACK_RX] = "audio-transcode-loopback-rx",
[USECASE_AUDIO_TRANSCODE_LOOPBACK_TX] = "audio-transcode-loopback-tx",
[USECASE_AUDIO_PLAYBACK_VOIP] = "audio-playback-voip",
[USECASE_AUDIO_RECORD_VOIP] = "audio-record-voip",
[USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY] = "audio-record-voip-low-latency",
/* For Interactive Audio Streams */
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1] = "audio-interactive-stream1",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2] = "audio-interactive-stream2",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3] = "audio-interactive-stream3",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4] = "audio-interactive-stream4",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5] = "audio-interactive-stream5",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6] = "audio-interactive-stream6",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7] = "audio-interactive-stream7",
[USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8] = "audio-interactive-stream8",
[USECASE_AUDIO_EC_REF_LOOPBACK] = "ec-ref-audio-capture",
[USECASE_AUDIO_A2DP_ABR_FEEDBACK] = "a2dp-abr-feedback",
[USECASE_AUDIO_PLAYBACK_MEDIA] = "media-playback",

Kogara Naveen Kumar
committed
[USECASE_AUDIO_PLAYBACK_MEDIA_LL] = "media-playback-ll",
[USECASE_AUDIO_PLAYBACK_SYS_NOTIFICATION] = "sys-notification-playback",
[USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE] = "nav-guidance-playback",

Kogara Naveen Kumar
committed
[USECASE_AUDIO_PLAYBACK_NAV_GUIDANCE_LL] = "nav-guidance-playback-ll",
[USECASE_AUDIO_PLAYBACK_PHONE] = "phone-playback",

Kogara Naveen Kumar
committed
[USECASE_AUDIO_PLAYBACK_PHONE_LL] = "phone-playback-ll",
[USECASE_AUDIO_PLAYBACK_ALERTS] = "alerts-playback",

Kogara Naveen Kumar
committed
[USECASE_AUDIO_PLAYBACK_ALERTS_LL] = "alerts-playback-ll",
[USECASE_AUDIO_PLAYBACK_FRONT_PASSENGER] = "front-passenger-playback",
[USECASE_AUDIO_PLAYBACK_REAR_SEAT] = "rear-seat-playback",
[USECASE_AUDIO_FM_TUNER_EXT] = "fm-tuner-ext",
[USECASE_ICC_CALL] = "icc-call",
[USECASE_AUDIO_RECORD_BUS] = "audio-record",
[USECASE_AUDIO_RECORD_BUS_FRONT_PASSENGER] = "front-passenger-record",
[USECASE_AUDIO_RECORD_BUS_REAR_SEAT] = "rear-seat-record",
[USECASE_AUDIO_PLAYBACK_SYNTHESIZER] = "synth-loopback",
[USECASE_AUDIO_RECORD_ECHO_REF_EXT] = "echo-reference-external",

Subhash Chandra Bose Naripeddy
committed
static const audio_usecase_t offload_usecases[] = {
USECASE_AUDIO_PLAYBACK_OFFLOAD,
USECASE_AUDIO_PLAYBACK_OFFLOAD2,
USECASE_AUDIO_PLAYBACK_OFFLOAD3,
USECASE_AUDIO_PLAYBACK_OFFLOAD4,
USECASE_AUDIO_PLAYBACK_OFFLOAD5,
USECASE_AUDIO_PLAYBACK_OFFLOAD6,
USECASE_AUDIO_PLAYBACK_OFFLOAD7,
USECASE_AUDIO_PLAYBACK_OFFLOAD8,
USECASE_AUDIO_PLAYBACK_OFFLOAD9,
};
static const audio_usecase_t interactive_usecases[] = {
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM1,
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM2,
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM3,
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM4,
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM5,
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM6,
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM7,
USECASE_AUDIO_PLAYBACK_INTERACTIVE_STREAM8,
};
#define STRING_TO_ENUM(string) { #string, string }
struct string_to_enum {
const char *name;
uint32_t value;
static const struct string_to_enum channels_name_to_enum_table[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_2POINT1),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_SURROUND),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_6POINT1),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
STRING_TO_ENUM(AUDIO_CHANNEL_IN_MONO),
STRING_TO_ENUM(AUDIO_CHANNEL_IN_STEREO),
STRING_TO_ENUM(AUDIO_CHANNEL_IN_FRONT_BACK),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_1),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_2),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_3),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_4),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_5),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_6),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_7),
STRING_TO_ENUM(AUDIO_CHANNEL_INDEX_MASK_8),
static const struct string_to_enum formats_name_to_enum_table[] = {
STRING_TO_ENUM(AUDIO_FORMAT_PCM_16_BIT),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_24_BIT_PACKED),
STRING_TO_ENUM(AUDIO_FORMAT_PCM_32_BIT),
STRING_TO_ENUM(AUDIO_FORMAT_AC3),
STRING_TO_ENUM(AUDIO_FORMAT_E_AC3),
STRING_TO_ENUM(AUDIO_FORMAT_E_AC3_JOC),
STRING_TO_ENUM(AUDIO_FORMAT_DOLBY_TRUEHD),
STRING_TO_ENUM(AUDIO_FORMAT_DTS),
STRING_TO_ENUM(AUDIO_FORMAT_DTS_HD),
STRING_TO_ENUM(AUDIO_FORMAT_IEC61937)
};
//list of all supported sample rates by HDMI specification.
static const int out_hdmi_sample_rates[] = {
32000, 44100, 48000, 88200, 96000, 176400, 192000,
};
static const struct string_to_enum out_sample_rates_name_to_enum_table[] = {
STRING_TO_ENUM(32000),
STRING_TO_ENUM(44100),
STRING_TO_ENUM(48000),
STRING_TO_ENUM(88200),
STRING_TO_ENUM(96000),
STRING_TO_ENUM(176400),
STRING_TO_ENUM(192000),
STRING_TO_ENUM(352800),
STRING_TO_ENUM(384000),
struct in_effect_list {
struct listnode list;
effect_handle_t handle;
};
static const audio_usecase_t record_usecases[] = {
USECASE_AUDIO_RECORD,
USECASE_AUDIO_RECORD2,
USECASE_AUDIO_RECORD3,
};

Kogara Naveen Kumar
committed
static const audio_usecase_t low_latency_record_usecases[] = {
USECASE_AUDIO_RECORD_LOW_LATENCY,
USECASE_AUDIO_RECORD_LOW_LATENCY2,
};
static struct audio_device *adev = NULL;
static pthread_mutex_t adev_init_lock = PTHREAD_MUTEX_INITIALIZER;
static unsigned int audio_device_ref_count;
//cache last MBDRC cal step level
static int last_known_cal_step = -1 ;
static int out_set_compr_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_mmap_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_voip_volume(struct audio_stream_out *stream, float left, float right);
static int out_set_pcm_volume(struct audio_stream_out *stream, float left, float right);
#ifdef SOFT_VOLUME
static int out_set_soft_volume_params(struct audio_stream_out *stream);
#endif
static void adev_snd_mon_cb(void *cookie, struct str_parms *parms);
static void in_snd_mon_cb(void * stream, struct str_parms * parms);
static void out_snd_mon_cb(void * stream, struct str_parms * parms);
static int configure_btsco_sample_rate(snd_device_t snd_device);
#ifdef AUDIO_FEATURE_ENABLED_GCOV
extern void __gcov_flush();
static void enable_gcov()
{
__gcov_flush();
}
#else
static void enable_gcov()
{
}
#endif
static int in_set_microphone_direction(const struct audio_stream_in *stream,
audio_microphone_direction_t dir);
static int in_set_microphone_field_dimension(const struct audio_stream_in *stream, float zoom);
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
static bool is_pcm_record_usecase(audio_usecase_t uc_id)
{
unsigned int record_uc_index;
unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
if (uc_id == record_usecases[record_uc_index])
return true;
}
return false;
}
static audio_usecase_t get_record_usecase(struct audio_device *adev)
{
audio_usecase_t ret_uc = USECASE_INVALID;
unsigned int record_uc_index;
unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
ALOGV("%s: num_usecase: %d", __func__, num_usecase);
for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
if (!(adev->pcm_record_uc_state & (0x1 << record_uc_index))) {
adev->pcm_record_uc_state |= 0x1 << record_uc_index;
ret_uc = record_usecases[record_uc_index];
break;
}
}
ALOGV("%s: pcm record usecase is %d", __func__, ret_uc);
return ret_uc;
}
static void free_record_usecase(struct audio_device *adev,
audio_usecase_t uc_id)
{
unsigned int record_uc_index;
unsigned int num_usecase = sizeof(record_usecases)/sizeof(record_usecases[0]);
for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
if (record_usecases[record_uc_index] == uc_id) {
adev->pcm_record_uc_state &= ~(0x1 << record_uc_index);
break;
}
}
ALOGV("%s: free pcm record usecase %d", __func__, uc_id);
}

Kogara Naveen Kumar
committed
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
static bool is_pcm_low_latency_record_usecase(audio_usecase_t uc_id)
{
unsigned int record_uc_index;
unsigned int num_usecase = sizeof(low_latency_record_usecases)/sizeof(low_latency_record_usecases[0]);
ALOGD("%s: Check low latency pcm record usecase", __func__);
for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
if (uc_id == low_latency_record_usecases[record_uc_index])
return true;
}
return false;
}
static audio_usecase_t get_low_latency_record_usecase(struct audio_device *adev)
{
audio_usecase_t ret_uc = USECASE_INVALID;
unsigned int record_uc_index;
unsigned int num_usecase = sizeof(low_latency_record_usecases)/sizeof(low_latency_record_usecases[0]);
ALOGD("%s: get_low_latency_record_usecase: %d", __func__, num_usecase);
for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
if (!(adev->pcm_low_latency_record_uc_state & (0x1 << record_uc_index))) {
adev->pcm_low_latency_record_uc_state |= 0x1 << record_uc_index;
ALOGD("%s: get_low_latency_record_usecase: %d", __func__, record_uc_index);
ret_uc = low_latency_record_usecases[record_uc_index];
break;
}
}
ALOGD("%s: low latency pcm record usecase is %d", __func__, ret_uc);
return ret_uc;
}
static void free_low_latency_record_usecase(struct audio_device *adev,
audio_usecase_t uc_id)
{
unsigned int record_uc_index;
unsigned int num_usecase = sizeof(low_latency_record_usecases)/sizeof(low_latency_record_usecases[0]);
for (record_uc_index = 0; record_uc_index < num_usecase; record_uc_index++) {
if (low_latency_record_usecases[record_uc_index] == uc_id) {
adev->pcm_low_latency_record_uc_state &= ~(0x1 << record_uc_index);
break;
}
}
ALOGD("%s: free low latency pcm record usecase %d", __func__, uc_id);
}
static bool may_use_noirq_mode(struct audio_device *adev, audio_usecase_t uc_id,
int flags __unused)
{
int dir = 0;
switch (uc_id) {
case USECASE_AUDIO_RECORD_LOW_LATENCY:
case USECASE_AUDIO_RECORD_VOIP_LOW_LATENCY:
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
dir = 1;
case USECASE_AUDIO_PLAYBACK_ULL:
break;
default:
return false;
}
int dev_id = platform_get_pcm_device_id(uc_id, dir == 0 ?
PCM_PLAYBACK : PCM_CAPTURE);
if (adev->adm_is_noirq_avail)
return adev->adm_is_noirq_avail(adev->adm_data,
adev->snd_card, dev_id, dir);
return false;
}
static void register_out_stream(struct stream_out *out)
{
struct audio_device *adev = out->dev;
if (is_offload_usecase(out->usecase) ||
!adev->adm_register_output_stream)
return;
// register stream first for backward compatibility
adev->adm_register_output_stream(adev->adm_data,
out->handle,
out->flags);
if (!adev->adm_set_config)
return;
#ifdef PLATFORM_AUTO
if (out->realtime || (out->flags & AUDIO_OUTPUT_FLAG_SYS_NOTIFICATION))
adev->adm_set_config(adev->adm_data,
out->handle,
out->pcm, &out->config);
#else
if (out->realtime)
adev->adm_set_config(adev->adm_data,
out->handle,
out->pcm, &out->config);
#endif
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
}
static void register_in_stream(struct stream_in *in)
{
struct audio_device *adev = in->dev;
if (!adev->adm_register_input_stream)
return;
adev->adm_register_input_stream(adev->adm_data,
in->capture_handle,
in->flags);
if (!adev->adm_set_config)
return;
if (in->realtime)
adev->adm_set_config(adev->adm_data,
in->capture_handle,
in->pcm,
&in->config);
}
static void request_out_focus(struct stream_out *out, long ns)
{
struct audio_device *adev = out->dev;
if (adev->adm_request_focus_v2)
adev->adm_request_focus_v2(adev->adm_data, out->handle, ns);
else if (adev->adm_request_focus)
adev->adm_request_focus(adev->adm_data, out->handle);
}
static int request_in_focus(struct stream_in *in, long ns)
{
struct audio_device *adev = in->dev;
int ret = 0;
if (adev->adm_request_focus_v2_1)
ret = adev->adm_request_focus_v2_1(adev->adm_data, in->capture_handle, ns);
else if (adev->adm_request_focus_v2)
adev->adm_request_focus_v2(adev->adm_data, in->capture_handle, ns);
else if (adev->adm_request_focus)
adev->adm_request_focus(adev->adm_data, in->capture_handle);
return ret;
}
static void release_out_focus(struct stream_out *out)
{
struct audio_device *adev = out->dev;
if (adev->adm_abandon_focus)
adev->adm_abandon_focus(adev->adm_data, out->handle);
}
static void release_in_focus(struct stream_in *in)
{
struct audio_device *adev = in->dev;
if (adev->adm_abandon_focus)
adev->adm_abandon_focus(adev->adm_data, in->capture_handle);
}
static int parse_snd_card_status(struct str_parms *parms, int *card,
card_status_t *status)
{
char value[32]={0};
char state[32]={0};
int ret = str_parms_get_str(parms, "SND_CARD_STATUS", value, sizeof(value));
if (ret < 0)
return -1;
// sscanf should be okay as value is of max length 32.
// same as sizeof state.
if (sscanf(value, "%d,%s", card, state) < 2)
return -1;
*status = !strcmp(state, "ONLINE") ? CARD_STATUS_ONLINE :
CARD_STATUS_OFFLINE;
return 0;
}
bool is_combo_audio_input_device(struct listnode *devices){
if ((devices == NULL) || (!list_empty(devices)))
return false;
if(compare_device_type(devices, AUDIO_DEVICE_IN_BUILTIN_MIC|AUDIO_DEVICE_IN_SPEAKER_MIC2))
return true;
else
return false;
}
static inline void adjust_frames_for_device_delay(struct stream_out *out,
uint32_t *dsp_frames) {
// Adjustment accounts for A2dp encoder latency with offload usecases
// Note: Encoder latency is returned in ms.
if (is_a2dp_out_device_type(&out->device_list)) {
unsigned long offset =
(audio_extn_a2dp_get_encoder_latency() * out->sample_rate / 1000);
*dsp_frames = (*dsp_frames > offset) ? (*dsp_frames - offset) : 0;
}
}
static inline bool free_entry(void *key __unused,
void *value, void *context __unused)
{
free(value);
return true;
}
static inline void free_map(Hashmap *map)
{
if (map) {
hashmapForEach(map, free_entry, (void *) NULL);
hashmapFree(map);
}
}
static inline void patch_map_remove_l(struct audio_device *adev,
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
audio_patch_handle_t patch_handle)
{
if (patch_handle == AUDIO_PATCH_HANDLE_NONE)
return;
struct audio_patch_info *p_info =
hashmapGet(adev->patch_map, (void *) (intptr_t) patch_handle);
if (p_info) {
ALOGV("%s: Remove patch %d", __func__, patch_handle);
hashmapRemove(adev->patch_map, (void *) (intptr_t) patch_handle);
free(p_info->patch);
free(p_info);
}
}
static inline int io_streams_map_insert(struct audio_device *adev,
struct audio_stream *stream,
audio_io_handle_t handle,
audio_patch_handle_t patch_handle)
{
struct audio_stream_info *s_info =
(struct audio_stream_info *) calloc(1, sizeof(struct audio_stream_info));
if (s_info == NULL) {
ALOGE("%s: Could not allocate stream info", __func__);
return -ENOMEM;
}
s_info->stream = stream;
s_info->patch_handle = patch_handle;
pthread_mutex_lock(&adev->lock);
struct audio_stream_info *stream_info =
hashmapPut(adev->io_streams_map, (void *) (intptr_t) handle, (void *) s_info);
if (stream_info != NULL)
free(stream_info);
pthread_mutex_unlock(&adev->lock);
ALOGV("%s: Added stream in io_streams_map with handle %d", __func__, handle);
return 0;
}
static inline void io_streams_map_remove(struct audio_device *adev,
audio_io_handle_t handle)
{
pthread_mutex_lock(&adev->lock);
struct audio_stream_info *s_info =
hashmapRemove(adev->io_streams_map, (void *) (intptr_t) handle);
if (s_info == NULL)
goto done;
ALOGV("%s: Removed stream with handle %d", __func__, handle);
patch_map_remove_l(adev, s_info->patch_handle);
done:
pthread_mutex_unlock(&adev->lock);
static struct audio_patch_info* fetch_patch_info_l(struct audio_device *adev,
audio_patch_handle_t handle)
{
struct audio_patch_info *p_info = NULL;
p_info = (struct audio_patch_info *)
hashmapGet(adev->patch_map, (void *) (intptr_t) handle);
return p_info;
}
__attribute__ ((visibility ("default")))
bool audio_hw_send_gain_dep_calibration(int level) {
bool ret_val = false;
pthread_mutex_lock(&adev_init_lock);
if (adev != NULL && adev->platform != NULL) {
pthread_mutex_lock(&adev->lock);
ret_val = platform_send_gain_dep_cal(adev->platform, level);
// cache level info for any of the use case which
// was not started.
last_known_cal_step = level;;
pthread_mutex_unlock(&adev->lock);
} else {
ALOGE("%s: %s is NULL", __func__, adev == NULL ? "adev" : "adev->platform");
}
pthread_mutex_unlock(&adev_init_lock);