audio: Initial bring up of QCOM added audio feature(jb_cho).
- Update alsa_sound and libalsa-intf to JB mainline
- Use audio channel, format, and mode definitions
from system/core instead of libhardware_legacy
- Enable AudioPolicyManagerALSA as QCOM's customized
audio policy manager
- Enable QCOM audio features including: proxy, USB
audio, and ANC.
- Disable compress audio because it's not supported
by jb_cho kernel
Change-Id: Ia9f0a8024a3f3e1d28210687aecfc72e6b784941
diff --git a/alsa_sound/ALSAControl.cpp b/alsa_sound/ALSAControl.cpp
deleted file mode 100644
index 2d610a1..0000000
--- a/alsa_sound/ALSAControl.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/* ALSAControl.cpp
- **
- ** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- **
- ** 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.
- */
-
-#include <errno.h>
-#include <stdarg.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dlfcn.h>
-
-#define LOG_TAG "ALSAControl"
-//#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
-#include <utils/Log.h>
-#include <utils/String8.h>
-
-#include <cutils/properties.h>
-#include <media/AudioRecord.h>
-#include <hardware_legacy/power.h>
-
-#include "AudioHardwareALSA.h"
-
-namespace android_audio_legacy
-{
-
-ALSAControl::ALSAControl(const char *device)
-{
- ALOGD("ALSAControl: ctor device %s", device);
- mHandle = mixer_open(device);
- ALOGV("ALSAControl: ctor mixer %p", mHandle);
-}
-
-ALSAControl::~ALSAControl()
-{
- if (mHandle) mixer_close(mHandle);
-}
-
-status_t ALSAControl::get(const char *name, unsigned int &value, int index)
-{
- struct mixer_ctl *ctl;
-
- if (!mHandle) {
- ALOGE("Control not initialized");
- return NO_INIT;
- }
-
- ctl = mixer_get_control(mHandle, name, index);
- if (!ctl)
- return BAD_VALUE;
-
- mixer_ctl_get(ctl, &value);
- return NO_ERROR;
-}
-
-status_t ALSAControl::set(const char *name, unsigned int value, int index)
-{
- struct mixer_ctl *ctl;
- int ret = 0;
- ALOGD("set:: name %s value %d index %d", name, value, index);
- if (!mHandle) {
- ALOGE("Control not initialized");
- return NO_INIT;
- }
-
- // ToDo: Do we need to send index here? Right now it works with 0
- ctl = mixer_get_control(mHandle, name, 0);
- if(ctl == NULL) {
- ALOGE("Could not get the mixer control");
- return BAD_VALUE;
- }
- ret = mixer_ctl_set(ctl, value);
- return (ret < 0) ? BAD_VALUE : NO_ERROR;
-}
-
-status_t ALSAControl::set(const char *name, const char *value)
-{
- struct mixer_ctl *ctl;
- int ret = 0;
- ALOGD("set:: name %s value %s", name, value);
-
- if (!mHandle) {
- ALOGE("Control not initialized");
- return NO_INIT;
- }
-
- ctl = mixer_get_control(mHandle, name, 0);
- if(ctl == NULL) {
- ALOGE("Could not get the mixer control");
- return BAD_VALUE;
- }
- ret = mixer_ctl_select(ctl, value);
- return (ret < 0) ? BAD_VALUE : NO_ERROR;
-}
-
-status_t ALSAControl::setext(const char *name, int count, char **setValues)
-{
- struct mixer_ctl *ctl;
- int ret = 0;
- ALOGD("setext:: name %s count %d", name, count);
- if (!mHandle) {
- ALOGE("Control not initialized");
- return NO_INIT;
- }
-
- // ToDo: Do we need to send index here? Right now it works with 0
- ctl = mixer_get_control(mHandle, name, 0);
- if(ctl == NULL) {
- ALOGE("Could not get the mixer control");
- return BAD_VALUE;
- }
- ret = mixer_ctl_set_value(ctl, count, setValues);
- return (ret < 0) ? BAD_VALUE : NO_ERROR;
-}
-
-}; // namespace android
diff --git a/alsa_sound/ALSADevice.cpp b/alsa_sound/ALSADevice.cpp
new file mode 100644
index 0000000..cd5b92d
--- /dev/null
+++ b/alsa_sound/ALSADevice.cpp
@@ -0,0 +1,2408 @@
+/* ALSADevice.cpp
+ **
+ ** Copyright 2009 Wind River Systems
+ ** Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
+ **
+ ** 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.
+ */
+
+#define LOG_TAG "ALSADevice"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#include <utils/Log.h>
+#include <cutils/properties.h>
+#include <linux/ioctl.h>
+#include "AudioUtil.h"
+#include "AudioHardwareALSA.h"
+#include <media/AudioRecord.h>
+#include <dlfcn.h>
+#ifdef QCOM_CSDCLIENT_ENABLED
+extern "C" {
+static int (*csd_disable_device)();
+static int (*csd_enable_device)(int, int, uint32_t);
+static int (*csd_volume)(int);
+static int (*csd_mic_mute)(int);
+static int (*csd_wide_voice)(uint8_t);
+static int (*csd_slow_talk)(uint8_t);
+static int (*csd_fens)(uint8_t);
+static int (*csd_start_voice)();
+static int (*csd_stop_voice)();
+static int (*csd_client_volume)(int);
+static int (*csd_client_mic_mute)(int);
+}
+#endif
+
+#define SAMPLE_RATE_8KHZ 8000
+
+
+#define BTSCO_RATE_16KHZ 16000
+#define USECASE_TYPE_RX 1
+#define USECASE_TYPE_TX 2
+#define MAX_HDMI_CHANNEL_CNT 6
+
+#define AFE_PROXY_PERIOD_SIZE 3072
+#define KILL_A2DP_THREAD 1
+#define SIGNAL_A2DP_THREAD 2
+#define PROXY_CAPTURE_DEVICE_NAME (const char *)("hw:0,8")
+namespace sys_close {
+ ssize_t lib_close(int fd) {
+ return close(fd);
+ }
+};
+
+namespace android_audio_legacy
+{
+
+ALSADevice::ALSADevice() {
+#ifdef USES_FLUENCE_INCALL
+ mDevSettingsFlag = TTY_OFF | DMIC_FLAG;
+#else
+ mDevSettingsFlag = TTY_OFF;
+#endif
+ mBtscoSamplerate = 8000;
+ mCallMode = AUDIO_MODE_NORMAL;
+ mInChannels = 0;
+ char value[128], platform[128], baseband[128];
+
+ property_get("persist.audio.handset.mic",value,"0");
+ strlcpy(mMicType, value, sizeof(mMicType));
+ property_get("persist.audio.fluence.mode",value,"0");
+ if (!strcmp("broadside", value)) {
+ mFluenceMode = FLUENCE_MODE_BROADSIDE;
+ } else {
+ mFluenceMode = FLUENCE_MODE_ENDFIRE;
+ }
+ property_get("ro.board.platform", platform, "");
+ property_get("ro.baseband", baseband, "");
+ if (!strcmp("msm8960", platform) && !strcmp("sglte", baseband)) {
+ mIsSglte = true;
+ }
+ else {
+ mIsSglte = false;
+ }
+ strlcpy(mCurRxUCMDevice, "None", sizeof(mCurRxUCMDevice));
+ strlcpy(mCurTxUCMDevice, "None", sizeof(mCurTxUCMDevice));
+
+ mMixer = mixer_open("/dev/snd/controlC0");
+
+ mProxyParams.mExitRead = false;
+ resetProxyVariables();
+ mProxyParams.mCaptureBufferSize = AFE_PROXY_PERIOD_SIZE;
+ mProxyParams.mCaptureBuffer = NULL;
+ mProxyParams.mProxyState = proxy_params::EProxyClosed;
+ mProxyParams.mProxyPcmHandle = NULL;
+
+ ALOGD("ALSA module opened");
+}
+
+//static int s_device_close(hw_device_t* device)
+ALSADevice::~ALSADevice()
+{
+ if (mMixer) mixer_close(mMixer);
+ if(mProxyParams.mCaptureBuffer != NULL) {
+ free(mProxyParams.mCaptureBuffer);
+ mProxyParams.mCaptureBuffer = NULL;
+ }
+ mProxyParams.mProxyState = proxy_params::EProxyClosed;
+
+}
+
+bool ALSADevice::platform_is_Fusion3()
+{
+ char platform[128], baseband[128];
+ property_get("ro.board.platform", platform, "");
+ property_get("ro.baseband", baseband, "");
+ if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband))
+ return true;
+ else
+ return false;
+}
+
+int ALSADevice::deviceName(alsa_handle_t *handle, unsigned flags, char **value)
+{
+ int ret = 0;
+ char ident[70];
+
+ if (flags & PCM_IN) {
+ strlcpy(ident, "CapturePCM/", sizeof(ident));
+ } else {
+ strlcpy(ident, "PlaybackPCM/", sizeof(ident));
+ }
+ strlcat(ident, handle->useCase, sizeof(ident));
+ ret = snd_use_case_get(handle->ucMgr, ident, (const char **)value);
+ ALOGD("Device value returned is %s", (*value));
+ return ret;
+}
+
+status_t ALSADevice::setHDMIChannelCount()
+{
+ status_t err = NO_ERROR;
+ int channel_count = 0;
+ const char *channel_cnt_str = NULL;
+ EDID_AUDIO_INFO info = { 0 };
+
+ if (AudioUtil::getHDMIAudioSinkCaps(&info)) {
+ for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) {
+ if (info.AudioBlocksArray[i].nChannels > channel_count &&
+ info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) {
+ channel_count = info.AudioBlocksArray[i].nChannels;
+ }
+ }
+ }
+
+ switch (channel_count) {
+ case 6: channel_cnt_str = "Six"; break;
+ case 5: channel_cnt_str = "Five"; break;
+ case 4: channel_cnt_str = "Four"; break;
+ case 3: channel_cnt_str = "Three"; break;
+ default: channel_cnt_str = "Two"; break;
+ }
+ ALOGD("HDMI channel count: %s", channel_cnt_str);
+ setMixerControl("HDMI_RX Channels", channel_cnt_str);
+
+ return err;
+}
+
+status_t ALSADevice::setHardwareParams(alsa_handle_t *handle)
+{
+ struct snd_pcm_hw_params *params;
+ unsigned long bufferSize, reqBuffSize;
+ unsigned int periodTime, bufferTime;
+ unsigned int requestedRate = handle->sampleRate;
+ int status = 0;
+ int channels = handle->channels;
+ status_t err;
+ snd_pcm_format_t format = SNDRV_PCM_FORMAT_S16_LE;
+ struct snd_compr_caps compr_cap;
+ struct snd_compr_params compr_params;
+ uint32_t codec_id = 0;
+
+ ALOGD("handle->format: 0x%x", handle->format);
+ if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL))) {
+ ALOGV("Tunnel mode detected...");
+ //get the list of codec supported by hardware
+ if (ioctl(handle->handle->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
+ ALOGE("SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
+ err = -errno;
+ return err;
+ }
+ if( handle->format == AUDIO_FORMAT_AAC ) {
+ codec_id = get_compressed_format("AAC");
+ ALOGV("### AAC CODEC codec_id %d",codec_id);
+ }
+ else if (handle->format == AUDIO_FORMAT_AMR_WB) {
+ codec_id = get_compressed_format("AMR_WB");
+ if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL))) {
+ compr_params.codec.options.generic.reserved[0] = 8; /*band mode - 23.85 kbps*/
+ compr_params.codec.options.generic.reserved[1] = 0; /*dtx mode - disable*/
+ }
+ ALOGV("### AMR WB CODEC codec_id %d",codec_id);
+ }
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+ else if (handle->format == AUDIO_FORMAT_AMR_WB_PLUS) {
+ codec_id = get_compressed_format("AMR_WB_PLUS");
+ ALOGV("### AMR WB+ CODEC codec_id %d",codec_id);
+ }
+#endif
+ else if (handle->format == AUDIO_FORMAT_MP3) {
+ codec_id = get_compressed_format("MP3");
+ ALOGV("### MP3 CODEC codec_id %d",codec_id);
+ }
+ else {
+ return UNKNOWN_ERROR;
+ }
+ //find if codec_id matches with any of h/w supported codecs.
+ for (int i = 0; i < compr_cap.num_codecs; i++) {
+ if (compr_cap.codecs[i] == codec_id) {
+ ALOGV("### MatchedFcodec_id %u", codec_id);
+ compr_params.codec.id = codec_id;
+ break;
+ }
+ }
+ if (!compr_params.codec.id) {
+ ALOGE("### Codec %u not supported",codec_id);
+ return UNKNOWN_ERROR;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
+ ALOGE("SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
+ err = -errno;
+ return err;
+ }
+ }
+
+ params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
+ if (!params) {
+ ALOGE("Failed to allocate ALSA hardware parameters!");
+ return NO_INIT;
+ }
+
+ reqBuffSize = handle->bufferSize;
+ ALOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d",
+ (int) reqBuffSize, handle->channels, handle->sampleRate);
+
+#ifdef QCOM_SSR_ENABLED
+ if (channels == 6) {
+ if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+ || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+ ALOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
+ channels = 4;
+ }
+ }
+#endif
+
+ param_init(params);
+ if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
+ SNDRV_PCM_ACCESS_MMAP_INTERLEAVED);
+ }
+ else {
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
+ SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ }
+
+ if (handle->format != SNDRV_PCM_FORMAT_S16_LE) {
+ if (handle->format == AUDIO_FORMAT_AMR_NB
+ || handle->format == AUDIO_FORMAT_AMR_WB
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+ || handle->format == AUDIO_FORMAT_EVRC
+ || handle->format == AUDIO_FORMAT_EVRCB
+ || handle->format == AUDIO_FORMAT_EVRCWB
+#endif
+ ) {
+ if ((strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) &&
+ (strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) &&
+ (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) &&
+ (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) &&
+ (strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) &&
+ (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) &&
+ (strcmp(handle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) &&
+ (strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+ format = SNDRV_PCM_FORMAT_SPECIAL;
+ ALOGW("setting format to SNDRV_PCM_FORMAT_SPECIAL");
+ }
+ }
+ }
+ //TODO: Add format setting for tunnel mode using the usecase.
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ format);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_SUBFORMAT_STD);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ channels * 16);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ channels);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, handle->sampleRate);
+ param_set_hw_refine(handle->handle, params);
+
+ if (param_set_hw_params(handle->handle, params)) {
+ ALOGE("cannot set hw params");
+ return NO_INIT;
+ }
+ param_dump(params);
+
+ handle->handle->buffer_size = pcm_buffer_size(params);
+ handle->handle->period_size = pcm_period_size(params);
+ handle->handle->period_cnt = handle->handle->buffer_size/handle->handle->period_size;
+ ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d",
+ handle->handle->buffer_size, handle->handle->period_size,
+ handle->handle->period_cnt);
+ handle->handle->rate = handle->sampleRate;
+ handle->handle->channels = handle->channels;
+ handle->periodSize = handle->handle->period_size;
+ if (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC) &&
+ strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) &&
+ strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC) &&
+ strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED) &&
+ (6 != handle->channels)) {
+ //Do not update buffersize for 5.1 recording
+ if (handle->format == AUDIO_FORMAT_AMR_WB &&
+ format != SNDRV_PCM_FORMAT_SPECIAL) {
+ ALOGV("### format AMWB, set bufsize to 61");
+ handle->bufferSize = 61;
+ } else {
+ handle->bufferSize = handle->handle->period_size;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t ALSADevice::setSoftwareParams(alsa_handle_t *handle)
+{
+ struct snd_pcm_sw_params* params;
+ struct pcm* pcm = handle->handle;
+
+ unsigned long periodSize = pcm->period_size;
+ int channels = handle->channels;
+
+ params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
+ if (!params) {
+ LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!");
+ return NO_INIT;
+ }
+
+#ifdef QCOM_SSR_ENABLED
+ if (channels == 6) {
+ if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+ || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+ ALOGV("SWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
+ channels = 4;
+ }
+ }
+#endif
+
+ // Get the current software parameters
+ params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+ params->period_step = 1;
+ if(((!strcmp(handle->useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
+ (!strcmp(handle->useCase,SND_USE_CASE_VERB_IP_VOICECALL)))){
+ ALOGV("setparam: start & stop threshold for Voip ");
+ params->avail_min = handle->channels - 1 ? periodSize/4 : periodSize/2;
+ params->start_threshold = periodSize/2;
+ params->stop_threshold = INT_MAX;
+ } else {
+ params->avail_min = periodSize/(channels * 2);
+ params->start_threshold = periodSize/(channels * 2);
+ params->stop_threshold = INT_MAX;
+ }
+ params->silence_threshold = 0;
+ params->silence_size = 0;
+
+ if (param_set_sw_params(handle->handle, params)) {
+ ALOGE("cannot set sw params");
+ return NO_INIT;
+ }
+ return NO_ERROR;
+}
+
+void ALSADevice::switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode)
+{
+ const char **mods_list;
+ use_case_t useCaseNode;
+ unsigned usecase_type = 0;
+ bool inCallDevSwitch = false;
+ char *rxDevice, *txDevice, ident[70], *use_case = NULL;
+ int err = 0, index, mods_size;
+ int rx_dev_id, tx_dev_id;
+ ALOGV("%s: device %#x mode:%d", __FUNCTION__, devices, mode);
+
+ if ((mode == AUDIO_MODE_IN_CALL) || (mode == AUDIO_MODE_IN_COMMUNICATION)) {
+ if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) {
+ devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADSET |
+ AudioSystem::DEVICE_IN_WIRED_HEADSET);
+ } else if (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
+ devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
+ AudioSystem::DEVICE_IN_BUILTIN_MIC);
+ } else if ((devices & AudioSystem::DEVICE_OUT_EARPIECE) ||
+ (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC)) {
+ devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
+ AudioSystem::DEVICE_OUT_EARPIECE);
+ } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+ devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
+ AudioSystem::DEVICE_OUT_SPEAKER);
+ } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
+ (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
+ (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
+ devices = devices | (AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+ AudioSystem::DEVICE_OUT_BLUETOOTH_SCO);
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
+ (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)) {
+ devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADSET |
+ AudioSystem::DEVICE_IN_ANC_HEADSET);
+ } else if (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
+ devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADPHONE |
+ AudioSystem::DEVICE_IN_BUILTIN_MIC);
+#endif
+#ifdef QCOM_USBAUDIO_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ) ||
+ (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET )) {
+ devices = devices | (AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET);
+#endif
+ } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+ devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL |
+ AudioSystem::DEVICE_IN_AUX_DIGITAL);
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) ||
+ (devices & AudioSystem::DEVICE_IN_PROXY)) {
+ devices = devices | (AudioSystem::DEVICE_OUT_PROXY |
+ AudioSystem::DEVICE_IN_PROXY);
+ } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ devices = devices | (AudioSystem::DEVICE_IN_PROXY);
+#endif
+ }
+ }
+#ifdef QCOM_SSR_ENABLED
+ if ((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) && ( 6 == handle->channels)) {
+ if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+ || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+ ALOGV(" switchDevice , use ssr devices for channels:%d usecase:%s",handle->channels,handle->useCase);
+ setFlags(SSRQMIC_FLAG);
+ }
+ }
+#endif
+
+ rxDevice = getUCMDevice(devices & AudioSystem::DEVICE_OUT_ALL, 0, NULL);
+ ALOGV("%s: rxDevice %s devices:0x%x", __FUNCTION__, rxDevice,devices);
+ txDevice = getUCMDevice(devices & AudioSystem::DEVICE_IN_ALL, 1, rxDevice);
+ ALOGV("%s: txDevice:%s devices:0x%x", __FUNCTION__, txDevice,devices);
+
+ if ((rxDevice != NULL) && (txDevice != NULL)) {
+ if (((strncmp(rxDevice, mCurRxUCMDevice, MAX_STR_LEN)) ||
+ (strncmp(txDevice, mCurTxUCMDevice, MAX_STR_LEN))) &&
+ ((mode == AUDIO_MODE_IN_CALL) ||
+ (mode == AUDIO_MODE_IN_COMMUNICATION)))
+ inCallDevSwitch = true;
+ }
+
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
+ if (csd_disable_device == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
+ } else {
+ err = csd_disable_device();
+ if (err < 0)
+ {
+ ALOGE("csd_client_disable_device, failed, error %d", err);
+ }
+ }
+ }
+#endif
+
+ snd_use_case_get(handle->ucMgr, "_verb", (const char **)&use_case);
+ mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
+ if (rxDevice != NULL) {
+ if ((strncmp(mCurRxUCMDevice, "None", 4)) &&
+ ((strncmp(rxDevice, mCurRxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
+ if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+ strlen(SND_USE_CASE_VERB_INACTIVE)))) {
+ usecase_type = getUseCaseType(use_case);
+ if (usecase_type & USECASE_TYPE_RX) {
+ ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
+ strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
+ snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
+ mUseCaseList.push_front(useCaseNode);
+ }
+ }
+ if (mods_size) {
+ for(index = 0; index < mods_size; index++) {
+ usecase_type = getUseCaseType(mods_list[index]);
+ if (usecase_type & USECASE_TYPE_RX) {
+ ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
+ strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
+ snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
+ mUseCaseList.push_back(useCaseNode);
+ }
+ }
+ }
+ snd_use_case_set(handle->ucMgr, "_disdev", mCurRxUCMDevice);
+ }
+ }
+ if (txDevice != NULL) {
+ if ((strncmp(mCurTxUCMDevice, "None", 4)) &&
+ ((strncmp(txDevice, mCurTxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
+ if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+ strlen(SND_USE_CASE_VERB_INACTIVE)))) {
+ usecase_type = getUseCaseType(use_case);
+ if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
+ ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
+ strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
+ snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
+ mUseCaseList.push_front(useCaseNode);
+ }
+ }
+ if (mods_size) {
+ for(index = 0; index < mods_size; index++) {
+ usecase_type = getUseCaseType(mods_list[index]);
+ if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
+ ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
+ strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
+ snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
+ mUseCaseList.push_back(useCaseNode);
+ }
+ }
+ }
+ snd_use_case_set(handle->ucMgr, "_disdev", mCurTxUCMDevice);
+ }
+ }
+
+ ALOGV("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, mCurRxUCMDevice, mCurTxUCMDevice);
+
+ if (rxDevice != NULL) {
+ snd_use_case_set(handle->ucMgr, "_enadev", rxDevice);
+ strlcpy(mCurRxUCMDevice, rxDevice, sizeof(mCurRxUCMDevice));
+ }
+ if (txDevice != NULL) {
+ snd_use_case_set(handle->ucMgr, "_enadev", txDevice);
+ strlcpy(mCurTxUCMDevice, txDevice, sizeof(mCurTxUCMDevice));
+ }
+ for(ALSAUseCaseList::iterator it = mUseCaseList.begin(); it != mUseCaseList.end(); ++it) {
+ ALOGD("Route use case %s\n", it->useCase);
+ if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+ strlen(SND_USE_CASE_VERB_INACTIVE))) && (!strncmp(use_case, it->useCase, MAX_UC_LEN))) {
+ snd_use_case_set(handle->ucMgr, "_verb", it->useCase);
+ } else {
+ snd_use_case_set(handle->ucMgr, "_enamod", it->useCase);
+ }
+ }
+ if (!mUseCaseList.empty())
+ mUseCaseList.clear();
+ if (use_case != NULL) {
+ free(use_case);
+ use_case = NULL;
+ }
+#ifdef QCOM_FM_ENABLED
+ if (rxDevice != NULL) {
+ if (devices & AudioSystem::DEVICE_OUT_FM)
+ setFmVolume(mFmVolume);
+ }
+#endif
+ ALOGD("switchDevice: mCurTxUCMDevivce %s mCurRxDevDevice %s", mCurTxUCMDevice, mCurRxUCMDevice);
+ if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
+
+ /* get tx acdb id */
+ memset(&ident,0,sizeof(ident));
+ strlcpy(ident, "ACDBID/", sizeof(ident));
+ strlcat(ident, mCurTxUCMDevice, sizeof(ident));
+ tx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
+
+ /* get rx acdb id */
+ memset(&ident,0,sizeof(ident));
+ strlcpy(ident, "ACDBID/", sizeof(ident));
+ strlcat(ident, mCurRxUCMDevice, sizeof(ident));
+ rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
+
+ if (rx_dev_id == DEVICE_SPEAKER_RX_ACDB_ID && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
+ tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID;
+ }
+
+#ifdef QCOM_CSDCLIENT_ENABLED
+ ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id);
+ if (csd_enable_device == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_client_enable_device", dlerror());
+ } else {
+ err = csd_enable_device(rx_dev_id, tx_dev_id, mDevSettingsFlag);
+ if (err < 0)
+ {
+ ALOGE("csd_client_disable_device failed, error %d", err);
+ }
+ }
+#endif
+ }
+
+ if (rxDevice != NULL) {
+ free(rxDevice);
+ rxDevice = NULL;
+ }
+ if (txDevice != NULL) {
+ free(txDevice);
+ txDevice = NULL;
+ }
+}
+
+// ----------------------------------------------------------------------------
+/*
+status_t ALSADevice::init(alsa_device_t *module, ALSAHandleList &list)
+{
+ ALOGD("s_init: Initializing devices for ALSA module");
+
+ list.clear();
+
+ return NO_ERROR;
+}
+*/
+status_t ALSADevice::open(alsa_handle_t *handle)
+{
+ char *devName = NULL;
+ unsigned flags = 0;
+ int err = NO_ERROR;
+
+ if(handle->devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+ err = setHDMIChannelCount();
+ if(err != OK) {
+ ALOGE("setHDMIChannelCount err = %d", err);
+ return err;
+ }
+ }
+ close(handle);
+
+ ALOGD("open: handle %p, format 0x%x", handle, handle->format);
+
+ // ASoC multicomponent requires a valid path (frontend/backend) for
+ // the device to be opened
+
+ // The PCM stream is opened in blocking mode, per ALSA defaults. The
+ // AudioFlinger seems to assume blocking mode too, so asynchronous mode
+ // should not be used.
+ if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+ ALOGV("LPA/tunnel use case");
+ flags |= PCM_MMAP;
+ flags |= DEBUG_ON;
+ } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) {
+ ALOGV("Music case");
+ flags = PCM_OUT;
+ } else {
+ flags = PCM_IN;
+ }
+
+ if (handle->channels == 1) {
+ flags |= PCM_MONO;
+ }
+#ifdef QCOM_SSR_ENABLED
+ else if (handle->channels == 4 ) {
+ flags |= PCM_QUAD;
+ } else if (handle->channels == 6 ) {
+ if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
+ || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+ flags |= PCM_QUAD;
+ } else {
+ flags |= PCM_5POINT1;
+ }
+ }
+#endif
+ else {
+ flags |= PCM_STEREO;
+ }
+
+ if (deviceName(handle, flags, &devName) < 0) {
+ ALOGE("Failed to get pcm device node: %s", devName);
+ return NO_INIT;
+ }
+ if (devName != NULL) {
+ ALOGV("flags %x, devName %s",flags,devName);
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ ALOGV("pcm_open returned fd %d", handle->handle->fd);
+
+ if (!handle->handle || (handle->handle->fd < 0)) {
+ ALOGE("open: Failed to initialize ALSA device '%s'", devName);
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ return NO_INIT;
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+
+ if (err == NO_ERROR) {
+ err = setSoftwareParams(handle);
+ }
+
+ if(err != NO_ERROR) {
+ ALOGE("Set HW/SW params failed: Closing the pcm stream");
+ standby(handle);
+ free(devName);
+ devName = NULL;
+ return err;
+ }
+
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ return NO_ERROR;
+}
+
+status_t ALSADevice::startVoipCall(alsa_handle_t *handle)
+{
+
+ char* devName = NULL;
+ unsigned flags = 0;
+ int err = NO_ERROR;
+ uint8_t voc_pkt[VOIP_BUFFER_MAX_SIZE];
+
+ close(handle);
+ flags = PCM_OUT;
+ flags |= PCM_MONO;
+ ALOGV("startVoipCall handle %p", handle);
+
+ if (deviceName(handle, flags, &devName) < 0) {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (!handle->handle || (handle->handle->fd < 0)) {
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
+ return NO_INIT;
+ }
+
+ if (!pcm_ready(handle->handle)) {
+ ALOGE(" pcm ready failed");
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+
+ if (err == NO_ERROR) {
+ err = setSoftwareParams(handle);
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ ALOGE("startVoipCall: pcm_prepare failed");
+ }
+
+ /* first write required start dsp */
+ memset(&voc_pkt,0,sizeof(voc_pkt));
+ pcm_write(handle->handle,&voc_pkt,handle->handle->period_size);
+ handle->rxHandle = handle->handle;
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ ALOGV("s_open: DEVICE_IN_COMMUNICATION ");
+ flags = PCM_IN;
+ flags |= PCM_MONO;
+ handle->handle = 0;
+
+ if (deviceName(handle, flags, &devName) < 0) {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (!handle->handle) {
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
+ return NO_INIT;
+ }
+
+ if (!pcm_ready(handle->handle)) {
+ ALOGE(" pcm ready in failed");
+ }
+
+ handle->handle->flags = flags;
+
+ err = setHardwareParams(handle);
+
+ if (err == NO_ERROR) {
+ err = setSoftwareParams(handle);
+ }
+
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ ALOGE("DEVICE_IN_COMMUNICATION: pcm_prepare failed");
+ }
+
+ /* first read required start dsp */
+ memset(&voc_pkt,0,sizeof(voc_pkt));
+ pcm_read(handle->handle,&voc_pkt,handle->handle->period_size);
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ return NO_ERROR;
+}
+
+status_t ALSADevice::startVoiceCall(alsa_handle_t *handle)
+{
+ char* devName = NULL;
+ unsigned flags = 0;
+ int err = NO_ERROR;
+
+ ALOGD("startVoiceCall: handle %p", handle);
+ // ASoC multicomponent requires a valid path (frontend/backend) for
+ // the device to be opened
+
+ flags = PCM_OUT | PCM_MONO;
+ if (deviceName(handle, flags, &devName) < 0) {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (!handle->handle || (handle->handle->fd < 0)) {
+ ALOGE("startVoiceCall: could not open PCM device");
+ goto Error;
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startVoiceCall: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startVoiceCall: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ ALOGE("startVoiceCall: pcm_prepare failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ ALOGE("startVoiceCall:SNDRV_PCM_IOCTL_START failed\n");
+ goto Error;
+ }
+
+ // Store the PCM playback device pointer in rxHandle
+ handle->rxHandle = handle->handle;
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+
+ // Open PCM capture device
+ flags = PCM_IN | PCM_MONO;
+ if (deviceName(handle, flags, &devName) < 0) {
+ ALOGE("Failed to get pcm device node");
+ goto Error;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (!handle->handle || (handle->handle->fd < 0)) {
+ free(devName);
+ goto Error;
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startVoiceCall: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startVoiceCall: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ ALOGE("startVoiceCall: pcm_prepare failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ ALOGE("startVoiceCall:SNDRV_PCM_IOCTL_START failed\n");
+ goto Error;
+ }
+
+ if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (csd_start_voice == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_client_start_voice", dlerror());
+ } else {
+ err = csd_start_voice();
+ if (err < 0){
+ ALOGE("s_start_voice_call: csd_client error %d\n", err);
+ goto Error;
+ }
+ }
+#endif
+ }
+
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ return NO_ERROR;
+
+Error:
+ ALOGE("startVoiceCall: Failed to initialize ALSA device '%s'", devName);
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ close(handle);
+ return NO_INIT;
+}
+
+status_t ALSADevice::startFm(alsa_handle_t *handle)
+{
+ char *devName = NULL;
+ unsigned flags = 0;
+ int err = NO_ERROR;
+
+ ALOGV("startFm: handle %p", handle);
+
+ // ASoC multicomponent requires a valid path (frontend/backend) for
+ // the device to be opened
+
+ flags = PCM_OUT | PCM_STEREO;
+ if (deviceName(handle, flags, &devName) < 0) {
+ ALOGE("Failed to get pcm device node");
+ goto Error;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (!handle->handle || (handle->handle->fd < 0)) {
+ ALOGE("startFm: could not open PCM device");
+ goto Error;
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startFm: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startFm: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ ALOGE("startFm: setSoftwareParams failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ ALOGE("startFm: SNDRV_PCM_IOCTL_START failed\n");
+ goto Error;
+ }
+
+ // Store the PCM playback device pointer in rxHandle
+ handle->rxHandle = handle->handle;
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+
+ // Open PCM capture device
+ flags = PCM_IN | PCM_STEREO;
+ if (deviceName(handle, flags, &devName) < 0) {
+ ALOGE("Failed to get pcm device node");
+ goto Error;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ ALOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (!handle->handle) {
+ goto Error;
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startFm: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ ALOGE("startFm: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ ALOGE("startFm: pcm_prepare failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ ALOGE("startFm: SNDRV_PCM_IOCTL_START failed\n");
+ goto Error;
+ }
+
+
+ setFmVolume(mFmVolume);
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ return NO_ERROR;
+
+Error:
+ if (devName) {
+ free(devName);
+ devName = NULL;
+ }
+ close(handle);
+ return NO_INIT;
+}
+
+status_t ALSADevice::setFmVolume(int value)
+{
+ status_t err = NO_ERROR;
+
+ setMixerControl("Internal FM RX Volume",value,0);
+ mFmVolume = value;
+
+ return err;
+}
+
+status_t ALSADevice::setLpaVolume(int value)
+{
+ status_t err = NO_ERROR;
+
+ setMixerControl("LPA RX Volume",value,0);
+
+ return err;
+}
+
+status_t ALSADevice::start(alsa_handle_t *handle)
+{
+ status_t err = NO_ERROR;
+
+ if(!handle->handle) {
+ ALOGE("No active PCM driver to start");
+ return err;
+ }
+
+ err = pcm_prepare(handle->handle);
+
+ return err;
+}
+
+status_t ALSADevice::close(alsa_handle_t *handle)
+{
+ int ret;
+ status_t err = NO_ERROR;
+ struct pcm *h = handle->rxHandle;
+
+ handle->rxHandle = 0;
+ ALOGD("close: handle %p h %p", handle, h);
+ if (h) {
+ if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) ||
+ !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) &&
+ platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (csd_stop_voice == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
+ } else {
+ err = csd_stop_voice();
+ if (err < 0) {
+ ALOGE("s_close: csd_client error %d\n", err);
+ }
+ }
+#endif
+ }
+ ALOGV("close rxHandle\n");
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ ALOGE("close: pcm_close failed for rxHandle with err %d", err);
+ }
+ }
+
+ h = handle->handle;
+ handle->handle = 0;
+
+ if (h) {
+ ALOGV("close handle h %p\n", h);
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ ALOGE("close: pcm_close failed for handle with err %d", err);
+ }
+ disableDevice(handle);
+ }
+
+ return err;
+}
+
+/*
+ this is same as s_close, but don't discard
+ the device/mode info. This way we can still
+ close the device, hit idle and power-save, reopen the pcm
+ for the same device/mode after resuming
+*/
+status_t ALSADevice::standby(alsa_handle_t *handle)
+{
+ int ret;
+ status_t err = NO_ERROR;
+ struct pcm *h = handle->rxHandle;
+ handle->rxHandle = 0;
+ ALOGD("standby: handle %p h %p", handle, h);
+ if (h) {
+ ALOGV("standby rxHandle\n");
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ ALOGE("standby: pcm_close failed for rxHandle with err %d", err);
+ }
+ }
+
+ h = handle->handle;
+ handle->handle = 0;
+
+ if (h) {
+ ALOGV("standby handle h %p\n", h);
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ ALOGE("standby: pcm_close failed for handle with err %d", err);
+ }
+ disableDevice(handle);
+ }
+
+ return err;
+}
+
+status_t ALSADevice::route(alsa_handle_t *handle, uint32_t devices, int mode)
+{
+ status_t status = NO_ERROR;
+
+ ALOGD("route: devices 0x%x in mode %d", devices, mode);
+ mCallMode = mode;
+ switchDevice(handle, devices, mode);
+ return status;
+}
+
+int ALSADevice::getUseCaseType(const char *useCase)
+{
+ ALOGV("use case is %s\n", useCase);
+ if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
+ MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
+ MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
+ return USECASE_TYPE_RX;
+ } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED,
+ MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
+ MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED,
+ MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
+ return USECASE_TYPE_TX;
+ } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
+ MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_SGLTECALL,
+ MAX_LEN(useCase, SND_USE_CASE_VERB_SGLTECALL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+ MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_SGLTE)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
+ MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
+ return (USECASE_TYPE_RX | USECASE_TYPE_TX);
+ } else {
+ ALOGV("unknown use case %s\n", useCase);
+ return 0;
+ }
+}
+
+void ALSADevice::disableDevice(alsa_handle_t *handle)
+{
+ unsigned usecase_type = 0;
+ int i, mods_size;
+ char *useCase;
+ const char **mods_list;
+
+ snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
+ if (useCase != NULL) {
+ if (!strncmp(useCase, handle->useCase, MAX_UC_LEN)) {
+ snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
+ } else {
+ snd_use_case_set(handle->ucMgr, "_dismod", handle->useCase);
+ }
+ free(useCase);
+ snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
+ if (strncmp(useCase, SND_USE_CASE_VERB_INACTIVE,
+ strlen(SND_USE_CASE_VERB_INACTIVE)))
+ usecase_type |= getUseCaseType(useCase);
+ mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
+ ALOGV("Number of modifiers %d\n", mods_size);
+ if (mods_size) {
+ for(i = 0; i < mods_size; i++) {
+ ALOGV("index %d modifier %s\n", i, mods_list[i]);
+ usecase_type |= getUseCaseType(mods_list[i]);
+ }
+ }
+ ALOGV("usecase_type is %d\n", usecase_type);
+ if (!(usecase_type & USECASE_TYPE_TX) && (strncmp(mCurTxUCMDevice, "None", 4)))
+ snd_use_case_set(handle->ucMgr, "_disdev", mCurTxUCMDevice);
+ if (!(usecase_type & USECASE_TYPE_RX) && (strncmp(mCurRxUCMDevice, "None", 4)))
+ snd_use_case_set(handle->ucMgr, "_disdev", mCurRxUCMDevice);
+ } else {
+ ALOGE("Invalid state, no valid use case found to disable");
+ }
+ free(useCase);
+}
+
+char *ALSADevice::getUCMDeviceFromAcdbId(int acdb_id)
+{
+ switch(acdb_id) {
+ case DEVICE_HANDSET_RX_ACDB_ID:
+ return strdup(SND_USE_CASE_DEV_HANDSET);
+ case DEVICE_SPEAKER_RX_ACDB_ID:
+ return strdup(SND_USE_CASE_DEV_SPEAKER);
+ case DEVICE_HEADSET_RX_ACDB_ID:
+ return strdup(SND_USE_CASE_DEV_HEADPHONES);
+ case DEVICE_TTY_HEADSET_MONO_RX_ACDB_ID:
+ return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX);
+ case DEVICE_ANC_HEADSET_STEREO_RX_ACDB_ID:
+ return strdup(SND_USE_CASE_DEV_ANC_HEADSET);
+ default:
+ return NULL;
+ }
+}
+
+char* ALSADevice::getUCMDevice(uint32_t devices, int input, char *rxDevice)
+{
+ if (!input) {
+ ALOGV("getUCMDevice for output device: devices:%x is input device:%d",devices,input);
+ if (!(mDevSettingsFlag & TTY_OFF) &&
+ (mCallMode == AUDIO_MODE_IN_CALL) &&
+ ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET)
+ || (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ || (devices & AudioSystem::DEVICE_OUT_ANC_HEADSET)
+ || (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)
+#endif
+ )) {
+ if (mDevSettingsFlag & TTY_VCO) {
+ return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX);
+ } else if (mDevSettingsFlag & TTY_FULL) {
+ return strdup(SND_USE_CASE_DEV_TTY_FULL_RX);
+ } else if (mDevSettingsFlag & TTY_HCO) {
+ return strdup(SND_USE_CASE_DEV_TTY_HANDSET_RX); /* HANDSET RX */
+ }
+ } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP &&
+ devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER);
+ } else if (devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX);
+ } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
+ devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER); /* PROXY RX */
+ } else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) {
+ return strdup(SND_USE_CASE_DEV_USB_PROXY_RX); /* PROXY RX */
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ } else if( (devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ (devices & AudioSystem::DEVICE_OUT_PROXY) &&
+ ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) ) ) {
+ if (mDevSettingsFlag & ANC_FLAG) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER_ANC_HEADSET);
+ } else {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER_HEADSET);
+ }
+#endif
+ } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
+ if (mDevSettingsFlag & ANC_FLAG) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_HEADSET); /* COMBO SPEAKER+HEADSET RX */
+ }
+ } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL))) {
+ return strdup(SND_USE_CASE_DEV_HDMI_SPEAKER);
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) &&
+ ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET)||
+ (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) ) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_ANC_HEADSET);
+ } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
+#endif
+#ifdef QCOM_FM_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ (devices & AudioSystem::DEVICE_OUT_FM_TX)) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_FM_TX); /* COMBO SPEAKER+FM_TX RX */
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ (devices & AudioSystem::DEVICE_OUT_PROXY)) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_SPEAKER); /* COMBO SPEAKER + PROXY RX */
+ } else if ((devices & AudioSystem::DEVICE_OUT_EARPIECE) &&
+ (devices & AudioSystem::DEVICE_OUT_PROXY)) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_HANDSET); /* COMBO EARPIECE + PROXY RX */
+#endif
+ } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
+ if (mCallMode == AUDIO_MODE_IN_CALL ||
+ mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+ return strdup(SND_USE_CASE_DEV_VOC_EARPIECE); /* Voice HANDSET RX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_EARPIECE); /* HANDSET RX */
+ }
+ } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
+ } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) {
+ if (mDevSettingsFlag & ANC_FLAG) {
+ if (mCallMode == AUDIO_MODE_IN_CALL ||
+ mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+ return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
+ }
+ } else {
+ if (mCallMode == AUDIO_MODE_IN_CALL ||
+ mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+ return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */
+ }
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) &&
+ ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
+ if (mDevSettingsFlag & ANC_FLAG) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_ANC_HEADSET);
+ } else {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX_HEADSET);
+ }
+ } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) {
+ if (mCallMode == AUDIO_MODE_IN_CALL ||
+ mCallMode == AUDIO_MODE_IN_COMMUNICATION) {
+ return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
+ }
+#endif
+ } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
+ (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
+ if (mBtscoSamplerate == BTSCO_RATE_16KHZ)
+ return strdup(SND_USE_CASE_DEV_BTSCO_WB_RX); /* BTSCO RX*/
+ else
+ return strdup(SND_USE_CASE_DEV_BTSCO_NB_RX); /* BTSCO RX*/
+ } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+ return strdup(SND_USE_CASE_DEV_HDMI); /* HDMI RX */
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ } else if (devices & AudioSystem::DEVICE_OUT_PROXY) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
+#endif
+#ifdef QCOM_FM_TX_ENABLED
+ } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) {
+ return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */
+#endif
+ } else if (devices & AudioSystem::DEVICE_OUT_DEFAULT) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
+ } else {
+ ALOGD("No valid output device: %u", devices);
+ }
+ } else {
+ ALOGV("getUCMDevice for input device: devices:%x is input device:%d",devices,input);
+ if (!(mDevSettingsFlag & TTY_OFF) &&
+ (mCallMode == AUDIO_MODE_IN_CALL) &&
+ ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ || (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)
+#endif
+ )) {
+ if (mDevSettingsFlag & TTY_HCO) {
+ return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX);
+ } else if (mDevSettingsFlag & TTY_FULL) {
+ return strdup(SND_USE_CASE_DEV_TTY_FULL_TX);
+ } else if (mDevSettingsFlag & TTY_VCO) {
+ if (!strncmp(mMicType, "analog", 6)) {
+ return strdup(SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX);
+ } else {
+ return strdup(SND_USE_CASE_DEV_TTY_HANDSET_TX);
+ }
+ }
+ } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+ if (!strncmp(mMicType, "analog", 6)) {
+ return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
+ } else {
+ if ((mDevSettingsFlag & DMIC_FLAG) && (mInChannels == 1)) {
+#ifdef USES_FLUENCE_INCALL
+ if(callMode == AUDIO_MODE_IN_CALL) {
+ if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
+ return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
+ } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
+ return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
+ }
+ }
+#else
+ if (((rxDevice != NULL) &&
+ !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
+ (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
+ ((rxDevice == NULL) &&
+ !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
+ (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) {
+ if (mFluenceMode == FLUENCE_MODE_ENDFIRE) {
+ if (mIsSglte == false) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
+ }
+ else {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE_SGLTE); /* DUALMIC EF TX */
+ }
+ } else if (mFluenceMode == FLUENCE_MODE_BROADSIDE) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
+ }
+ } else {
+ if (mFluenceMode == FLUENCE_MODE_ENDFIRE) {
+ if (mIsSglte == false) {
+ return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
+ }
+ else {
+ return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_SGLTE); /* DUALMIC EF TX */
+ }
+ } else if (mFluenceMode == FLUENCE_MODE_BROADSIDE) {
+ return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
+ }
+ }
+#endif
+ } else if ((mDevSettingsFlag & DMIC_FLAG) && (mInChannels > 1)) {
+ if (((rxDevice != NULL) &&
+ !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
+ (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
+ ((rxDevice == NULL) &&
+ !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
+ (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) {
+ if (mIsSglte == false) {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO); /* DUALMIC EF TX */
+ }
+ else {
+ return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO_SGLTE); /* DUALMIC EF TX */
+ }
+ } else {
+ if (mIsSglte == false) {
+ return strdup(SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO); /* DUALMIC EF TX */
+ }
+ else {
+ return strdup(SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO_SGLTE); /* DUALMIC EF TX */
+ }
+ }
+ } else if ((mDevSettingsFlag & QMIC_FLAG) && (mInChannels == 1)) {
+ if (((rxDevice != NULL) &&
+ !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
+ (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
+ ((rxDevice == NULL) &&
+ !strncmp(mCurRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
+ (strlen(SND_USE_CASE_DEV_SPEAKER)+1)))) {
+ return strdup(SND_USE_CASE_DEV_QUAD_MIC); /* QUADMIC TX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_LINE);
+ }
+ }
+#ifdef QCOM_SSR_ENABLED
+ else if ((mDevSettingsFlag & QMIC_FLAG) && (mInChannels > 1)) {
+ return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC);
+ } else if ((mDevSettingsFlag & SSRQMIC_FLAG) && (mInChannels > 1)){
+ ALOGV("return SSRQMIC_FLAG: 0x%x devices:0x%x",mDevSettingsFlag,devices);
+ // Mapping for quad mic input device.
+ return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); /* SSR Quad MIC */
+ }
+#endif
+#ifdef SEPERATED_AUDIO_INPUT
+ if(mInput_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
+ return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */
+ }
+#endif
+ else {
+ return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
+ }
+ }
+ } else if (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL) {
+ return strdup(SND_USE_CASE_DEV_HDMI_TX); /* HDMI TX */
+ } else if ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) {
+ return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
+ return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
+#endif
+ } else if (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ if (mBtscoSamplerate == BTSCO_RATE_16KHZ)
+ return strdup(SND_USE_CASE_DEV_BTSCO_WB_TX); /* BTSCO TX*/
+ else
+ return strdup(SND_USE_CASE_DEV_BTSCO_NB_TX); /* BTSCO TX*/
+#ifdef QCOM_USBAUDIO_ENABLED
+ } else if (devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) {
+ if ((mCallMode == AUDIO_MODE_IN_CALL) ||
+ (mCallMode == AUDIO_MODE_IN_COMMUNICATION)) {
+ if ((rxDevice != NULL) &&
+ (!strncmp(rxDevice, SND_USE_CASE_DEV_USB_PROXY_RX,
+ (strlen(SND_USE_CASE_DEV_USB_PROXY_RX)+1)))) {
+ return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */
+ } else if ((rxDevice != NULL) &&
+ (!strncmp(rxDevice, SND_USE_CASE_DEV_PROXY_RX,
+ (strlen(SND_USE_CASE_DEV_PROXY_RX)+1)))) {
+ return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */
+ }
+ } else {
+ return strdup(SND_USE_CASE_DEV_USB_PROXY_TX); /* USB PROXY TX */
+ }
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ } else if (devices & AudioSystem::DEVICE_IN_PROXY) {
+ return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */
+#endif
+ } else if ((devices & AudioSystem::DEVICE_IN_COMMUNICATION) ||
+ (devices & AudioSystem::DEVICE_IN_VOICE_CALL)) {
+ /* Nothing to be done, use current active device */
+ if (strncmp(mCurTxUCMDevice, "None", 4)) {
+ return strdup(mCurTxUCMDevice);
+ }
+#ifdef QCOM_FM_ENABLED
+ } else if ((devices & AudioSystem::DEVICE_IN_FM_RX) ||
+ (devices & AudioSystem::DEVICE_IN_FM_RX_A2DP)) {
+ /* Nothing to be done, use current tx device or set dummy device */
+ if (strncmp(mCurTxUCMDevice, "None", 4)) {
+ return strdup(mCurTxUCMDevice);
+ } else {
+ return strdup(SND_USE_CASE_DEV_DUMMY_TX);
+ }
+#endif
+ } else if ((devices & AudioSystem::DEVICE_IN_AMBIENT) ||
+ (devices & AudioSystem::DEVICE_IN_BACK_MIC)) {
+ ALOGI("No proper mapping found with UCM device list, setting default");
+ if (!strncmp(mMicType, "analog", 6)) {
+ return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
+ } else {
+#ifdef SEPERATED_AUDIO_INPUT
+ if (callMode == AUDIO_MODE_IN_CALL) {
+ return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */
+ } else if(mInput_source == AUDIO_SOURCE_CAMCORDER) {
+ return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */
+ } else
+#endif
+ return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
+ }
+ } else {
+ ALOGD("No valid input device: %u", devices);
+ }
+ }
+ return NULL;
+}
+
+void ALSADevice::setVoiceVolume(int vol)
+{
+ int err = 0;
+ ALOGD("setVoiceVolume: volume %d", vol);
+ setMixerControl("Voice Rx Volume", vol, 0);
+
+ if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (csd_volume == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_client_volume", dlerror());
+ } else {
+ err = csd_volume(vol);
+ if (err < 0) {
+ ALOGE("s_set_voice_volume: csd_client error %d", err);
+ }
+ }
+#endif
+ }
+}
+
+void ALSADevice::setSGLTEVolume(int vol)
+{
+ int err = 0;
+ ALOGD("setSGLTEVolume: volume %d", vol);
+ setMixerControl("SGLTE Rx Volume", vol, 0);
+
+ if (platform_is_Fusion3()) {
+ err = csd_client_volume(vol);
+ if (err < 0) {
+ ALOGE("setSGLTEVolume: csd_client error %d", err);
+ }
+ }
+}
+
+void ALSADevice::setVoLTEVolume(int vol)
+{
+ ALOGD("setVoLTEVolume: volume %d", vol);
+ setMixerControl("VoLTE Rx Volume", vol, 0);
+}
+
+
+void ALSADevice::setVoipVolume(int vol)
+{
+ ALOGD("setVoipVolume: volume %d", vol);
+ setMixerControl("Voip Rx Volume", vol, 0);
+}
+
+void ALSADevice::setMicMute(int state)
+{
+ int err = 0;
+ ALOGD("setMicMute: state %d", state);
+ setMixerControl("Voice Tx Mute", state, 0);
+
+ if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (csd_mic_mute == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_mic_mute", dlerror());
+ } else {
+ err=csd_mic_mute(state);
+ if (err < 0) {
+ ALOGE("s_set_mic_mute: csd_client error %d", err);
+ }
+ }
+#endif
+ }
+}
+
+void ALSADevice::setSGLTEMicMute(int state)
+{
+ int err = 0;
+ ALOGD("setSGLTEMicMute: state %d", state);
+ setMixerControl("SGLTE Tx Mute", state, 0);
+
+ if (platform_is_Fusion3()) {
+ err = csd_client_mic_mute(state);
+ if (err < 0) {
+ ALOGE("setSGLTEMicMute: csd_client error %d", err);
+ }
+ }
+}
+
+void ALSADevice::setVoLTEMicMute(int state)
+{
+ ALOGD("setVolteMicMute: state %d", state);
+ setMixerControl("VoLTE Tx Mute", state, 0);
+}
+
+void ALSADevice::setVoipMicMute(int state)
+{
+ ALOGD("setVoipMicMute: state %d", state);
+ setMixerControl("Voip Tx Mute", state, 0);
+}
+
+void ALSADevice::setVoipConfig(int mode, int rate)
+{
+ ALOGD("setVoipConfig: mode %d,rate %d", mode, rate);
+ char** setValues;
+ setValues = (char**)malloc(2*sizeof(char*));
+ if (setValues == NULL) {
+ return;
+ }
+ setValues[0] = (char*)malloc(4*sizeof(char));
+ if (setValues[0] == NULL) {
+ free(setValues);
+ return;
+ }
+
+ setValues[1] = (char*)malloc(8*sizeof(char));
+ if (setValues[1] == NULL) {
+ free(setValues);
+ free(setValues[0]);
+ return;
+ }
+
+ sprintf(setValues[0], "%d",mode);
+ sprintf(setValues[1], "%d",rate);
+
+ setMixerControlExt("Voip Mode Rate Config", 2, setValues);
+ free(setValues[1]);
+ free(setValues[0]);
+ free(setValues);
+ return;
+}
+
+void ALSADevice::setBtscoRate(int rate)
+{
+ mBtscoSamplerate = rate;
+}
+
+void ALSADevice::enableWideVoice(bool flag)
+{
+ int err = 0;
+
+ ALOGD("enableWideVoice: flag %d", flag);
+ if(flag == true) {
+ setMixerControl("Widevoice Enable", 1, 0);
+ } else {
+ setMixerControl("Widevoice Enable", 0, 0);
+ }
+
+ if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (csd_wide_voice == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_wide_voice", dlerror());
+ } else {
+ err = csd_wide_voice(flag);
+ if (err < 0) {
+ ALOGE("enableWideVoice: csd_client_wide_voice error %d", err);
+ }
+ }
+#endif
+ }
+}
+
+void ALSADevice::setVocRecMode(uint8_t mode)
+{
+ ALOGD("setVocRecMode: mode %d", mode);
+ setMixerControl("Incall Rec Mode", mode, 0);
+}
+
+void ALSADevice::enableFENS(bool flag)
+{
+ int err = 0;
+
+ ALOGD("enableFENS: flag %d", flag);
+ if(flag == true) {
+ setMixerControl("FENS Enable", 1, 0);
+ } else {
+ setMixerControl("FENS Enable", 0, 0);
+ }
+
+ if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (csd_fens == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_fens", dlerror());
+ } else {
+ err = csd_fens(flag);
+ if (err < 0) {
+ ALOGE("s_enable_fens: csd_client error %d", err);
+ }
+ }
+#endif
+ }
+}
+
+void ALSADevice::enableSlowTalk(bool flag)
+{
+ int err = 0;
+
+ ALOGD("enableSlowTalk: flag %d", flag);
+ if(flag == true) {
+ setMixerControl("Slowtalk Enable", 1, 0);
+ } else {
+ setMixerControl("Slowtalk Enable", 0, 0);
+ }
+
+ if (platform_is_Fusion3()) {
+#ifdef QCOM_CSDCLIENT_ENABLED
+ if (csd_slow_talk == NULL) {
+ ALOGE("dlsym:Error:%s Loading csd_slow_talk", dlerror());
+ } else {
+ err = csd_slow_talk(flag);
+ if (err < 0) {
+ ALOGE("s_enable_slow_talk: csd_client error %d", err);
+ }
+ }
+#endif
+ }
+}
+
+void ALSADevice::setFlags(uint32_t flags)
+{
+ ALOGV("setFlags: flags %d", flags);
+ mDevSettingsFlag = flags;
+}
+
+status_t ALSADevice::setCompressedVolume(int value)
+{
+ status_t err = NO_ERROR;
+
+ setMixerControl("COMPRESSED RX Volume",value,0);
+
+ return err;
+}
+
+status_t ALSADevice::getMixerControl(const char *name, unsigned int &value, int index)
+{
+ struct mixer_ctl *ctl;
+
+ if (!mMixer) {
+ ALOGE("Control not initialized");
+ return NO_INIT;
+ }
+
+ ctl = mixer_get_control(mMixer, name, index);
+ if (!ctl)
+ return BAD_VALUE;
+
+ mixer_ctl_get(ctl, &value);
+ return NO_ERROR;
+}
+
+status_t ALSADevice::setMixerControl(const char *name, unsigned int value, int index)
+{
+ struct mixer_ctl *ctl;
+ int ret = 0;
+ ALOGD("setMixerControl:: name %s value %d index %d", name, value, index);
+ if (!mMixer) {
+ ALOGE("Control not initialized");
+ return NO_INIT;
+ }
+
+ // ToDo: Do we need to send index here? Right now it works with 0
+ ctl = mixer_get_control(mMixer, name, 0);
+ if(ctl == NULL) {
+ ALOGE("Could not get the mixer control");
+ return BAD_VALUE;
+ }
+ ret = mixer_ctl_set(ctl, value);
+ return (ret < 0) ? BAD_VALUE : NO_ERROR;
+}
+
+status_t ALSADevice::setMixerControl(const char *name, const char *value)
+{
+ struct mixer_ctl *ctl;
+ int ret = 0;
+ ALOGD("setMixerControl:: name %s value %s", name, value);
+
+ if (!mMixer) {
+ ALOGE("Control not initialized");
+ return NO_INIT;
+ }
+
+ ctl = mixer_get_control(mMixer, name, 0);
+ if(ctl == NULL) {
+ ALOGE("Could not get the mixer control");
+ return BAD_VALUE;
+ }
+ ret = mixer_ctl_select(ctl, value);
+ return (ret < 0) ? BAD_VALUE : NO_ERROR;
+}
+
+status_t ALSADevice::setMixerControlExt(const char *name, int count, char **setValues)
+{
+ struct mixer_ctl *ctl;
+ int ret = 0;
+ ALOGD("setMixerControl:: name %s count %d", name, count);
+ if (!mMixer) {
+ ALOGE("Control not initialized");
+ return NO_INIT;
+ }
+
+ // ToDo: Do we need to send index here? Right now it works with 0
+ ctl = mixer_get_control(mMixer, name, 0);
+ if(ctl == NULL) {
+ ALOGE("Could not get the mixer control");
+ return BAD_VALUE;
+ }
+ ret = mixer_ctl_set_value(ctl, count, setValues);
+ return (ret < 0) ? BAD_VALUE : NO_ERROR;
+}
+
+status_t ALSADevice::setEcrxDevice(char *device)
+{
+ status_t err = NO_ERROR;
+ setMixerControl("EC_REF_RX", device);
+ return err;
+}
+
+void ALSADevice::setInChannels(int channels)
+{
+ mInChannels = channels;
+ ALOGV("mInChannels:%d", mInChannels);
+}
+
+status_t ALSADevice::exitReadFromProxy()
+{
+ ALOGV("exitReadFromProxy");
+ mProxyParams.mExitRead = true;
+ if(mProxyParams.mPfdProxy[1].fd != -1) {
+ uint64_t writeValue = KILL_A2DP_THREAD;
+ ALOGD("Writing to mPfdProxy[1].fd %d",mProxyParams.mPfdProxy[1].fd);
+ write(mProxyParams.mPfdProxy[1].fd, &writeValue, sizeof(uint64_t));
+ }
+ return NO_ERROR;
+}
+
+void ALSADevice::resetProxyVariables() {
+
+ mProxyParams.mAvail = 0;
+ mProxyParams.mFrames = 0;
+ mProxyParams.mX.frames = 0;
+ if(mProxyParams.mPfdProxy[1].fd != -1) {
+ sys_close::lib_close(mProxyParams.mPfdProxy[1].fd);
+ mProxyParams.mPfdProxy[1].fd = -1;
+ }
+}
+
+ssize_t ALSADevice::readFromProxy(void **captureBuffer , ssize_t *bufferSize) {
+
+ status_t err = NO_ERROR;
+ int err_poll = 0;
+ initProxyParams();
+ err = startProxy();
+ if(err) {
+ ALOGE("ReadFromProxy-startProxy returned err = %d", err);
+ *captureBuffer = NULL;
+ *bufferSize = 0;
+ return err;
+ }
+ struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle;
+
+ while(!mProxyParams.mExitRead) {
+ ALOGV("Calling sync_ptr(proxy");
+ err = sync_ptr(capture_handle);
+ if(err == EPIPE) {
+ ALOGE("Failed in sync_ptr \n");
+ /* we failed to make our window -- try to restart */
+ capture_handle->underruns++;
+ capture_handle->running = 0;
+ capture_handle->start = 0;
+ continue;
+ } else if (err != NO_ERROR) {
+ ALOGE("Error: Sync ptr returned %d", err);
+ break;
+ }
+
+ mProxyParams.mAvail = pcm_avail(capture_handle);
+ ALOGV("avail is = %d frames = %ld, avai_min = %d\n",\
+ mProxyParams.mAvail, mProxyParams.mFrames,(int)capture_handle->sw_p->avail_min);
+ if (mProxyParams.mAvail < capture_handle->sw_p->avail_min) {
+ err_poll = poll(mProxyParams.mPfdProxy, NUM_FDS, TIMEOUT_INFINITE);
+ if (mProxyParams.mPfdProxy[1].revents & POLLIN) {
+ ALOGV("Event on userspace fd");
+ }
+ if ((mProxyParams.mPfdProxy[1].revents & POLLERR) ||
+ (mProxyParams.mPfdProxy[1].revents & POLLNVAL)) {
+ ALOGV("POLLERR or INVALID POLL");
+ err = BAD_VALUE;
+ break;
+ }
+ if((mProxyParams.mPfdProxy[0].revents & POLLERR) ||
+ (mProxyParams.mPfdProxy[0].revents & POLLNVAL)) {
+ ALOGV("POLLERR or INVALID POLL on zero");
+ err = BAD_VALUE;
+ break;
+ }
+ if (mProxyParams.mPfdProxy[0].revents & POLLIN) {
+ ALOGV("POLLIN on zero");
+ }
+ ALOGV("err_poll = %d",err_poll);
+ continue;
+ }
+ break;
+ }
+ if(err != NO_ERROR) {
+ ALOGE("Reading from proxy failed = err = %d", err);
+ *captureBuffer = NULL;
+ *bufferSize = 0;
+ return err;
+ }
+ if (mProxyParams.mX.frames > mProxyParams.mAvail)
+ mProxyParams.mFrames = mProxyParams.mAvail;
+ void *data = dst_address(capture_handle);
+ //TODO: Return a pointer to AudioHardware
+ if(mProxyParams.mCaptureBuffer == NULL)
+ mProxyParams.mCaptureBuffer = malloc(mProxyParams.mCaptureBufferSize);
+ memcpy(mProxyParams.mCaptureBuffer, (char *)data,
+ mProxyParams.mCaptureBufferSize);
+ mProxyParams.mX.frames -= mProxyParams.mFrames;
+ capture_handle->sync_ptr->c.control.appl_ptr += mProxyParams.mFrames;
+ capture_handle->sync_ptr->flags = 0;
+ ALOGV("Calling sync_ptr for proxy after sync");
+ err = sync_ptr(capture_handle);
+ if(err == EPIPE) {
+ ALOGV("Failed in sync_ptr \n");
+ capture_handle->running = 0;
+ err = sync_ptr(capture_handle);
+ }
+ if(err != NO_ERROR ) {
+ ALOGE("Error: Sync ptr end returned %d", err);
+ *captureBuffer = NULL;
+ *bufferSize = 0;
+ return err;
+ }
+ *captureBuffer = mProxyParams.mCaptureBuffer;
+ *bufferSize = mProxyParams.mCaptureBufferSize;
+ return err;
+}
+
+void ALSADevice::initProxyParams() {
+ if(mProxyParams.mPfdProxy[1].fd == -1) {
+ ALOGV("Allocating A2Dp poll fd");
+ mProxyParams.mPfdProxy[0].fd = mProxyParams.mProxyPcmHandle->fd;
+ mProxyParams.mPfdProxy[0].events = (POLLIN | POLLERR | POLLNVAL);
+ ALOGV("Allocated A2DP poll fd");
+ mProxyParams.mPfdProxy[1].fd = eventfd(0,0);
+ mProxyParams.mPfdProxy[1].events = (POLLIN | POLLERR | POLLNVAL);
+ mProxyParams.mFrames = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+ (mProxyParams.mProxyPcmHandle->period_size / 2) :
+ (mProxyParams.mProxyPcmHandle->period_size / 4);
+ mProxyParams.mX.frames = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+ (mProxyParams.mProxyPcmHandle->period_size / 2) :
+ (mProxyParams.mProxyPcmHandle->period_size / 4);
+ }
+}
+
+status_t ALSADevice::startProxy() {
+
+ status_t err = NO_ERROR;
+ struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle;
+ while(1) {
+ if (!capture_handle->start) {
+ if(ioctl(capture_handle->fd, SNDRV_PCM_IOCTL_START)) {
+ err = -errno;
+ if (errno == EPIPE) {
+ ALOGV("Failed in SNDRV_PCM_IOCTL_START\n");
+ /* we failed to make our window -- try to restart */
+ capture_handle->underruns++;
+ capture_handle->running = 0;
+ capture_handle->start = 0;
+ continue;
+ } else {
+ ALOGE("IGNORE - IOCTL_START failed for proxy err: %d \n", errno);
+ err = NO_ERROR;
+ break;
+ }
+ } else {
+ ALOGD(" Proxy Driver started(IOCTL_START Success)\n");
+ break;
+ }
+ }
+ else {
+ ALOGV("Proxy Already started break out of condition");
+ break;
+ }
+ }
+ ALOGV("startProxy - Proxy started");
+ capture_handle->start = 1;
+ capture_handle->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL |
+ SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
+ return err;
+}
+
+status_t ALSADevice::openProxyDevice()
+{
+ struct snd_pcm_hw_params *params = NULL;
+ struct snd_pcm_sw_params *sparams = NULL;
+ int flags = (DEBUG_ON | PCM_MMAP| PCM_STEREO | PCM_IN);
+
+ ALOGV("openProxyDevice");
+ mProxyParams.mProxyPcmHandle = pcm_open(flags, PROXY_CAPTURE_DEVICE_NAME);
+ if (!pcm_ready(mProxyParams.mProxyPcmHandle)) {
+ ALOGE("Opening proxy device failed");
+ goto bail;
+ }
+ ALOGV("Proxy device opened successfully: mProxyPcmHandle %p", mProxyParams.mProxyPcmHandle);
+ mProxyParams.mProxyPcmHandle->channels = AFE_PROXY_CHANNEL_COUNT;
+ mProxyParams.mProxyPcmHandle->rate = AFE_PROXY_SAMPLE_RATE;
+ mProxyParams.mProxyPcmHandle->flags = flags;
+ mProxyParams.mProxyPcmHandle->period_size = AFE_PROXY_PERIOD_SIZE;
+
+ params = (struct snd_pcm_hw_params*) calloc(1,sizeof(struct snd_pcm_hw_params));
+ if (!params) {
+ goto bail;
+ }
+
+ param_init(params);
+
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
+ (mProxyParams.mProxyPcmHandle->flags & PCM_MMAP)?
+ SNDRV_PCM_ACCESS_MMAP_INTERLEAVED
+ : SNDRV_PCM_ACCESS_RW_INTERLEAVED);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
+ SNDRV_PCM_FORMAT_S16_LE);
+ param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
+ SNDRV_PCM_SUBFORMAT_STD);
+ param_set_min(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+ mProxyParams.mProxyPcmHandle->period_size);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
+ mProxyParams.mProxyPcmHandle->channels - 1 ? 32 : 16);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
+ mProxyParams.mProxyPcmHandle->channels);
+ param_set_int(params, SNDRV_PCM_HW_PARAM_RATE,
+ mProxyParams.mProxyPcmHandle->rate);
+
+ param_set_hw_refine(mProxyParams.mProxyPcmHandle, params);
+
+ if (param_set_hw_params(mProxyParams.mProxyPcmHandle, params)) {
+ ALOGE("Failed to set hardware params on Proxy device");
+ goto bail;
+ }
+
+ mProxyParams.mProxyPcmHandle->buffer_size = pcm_buffer_size(params);
+ mProxyParams.mProxyPcmHandle->period_size = pcm_period_size(params);
+ mProxyParams.mProxyPcmHandle->period_cnt =
+ mProxyParams.mProxyPcmHandle->buffer_size /
+ mProxyParams.mProxyPcmHandle->period_size;
+ ALOGV("Capture - period_size (%d)",\
+ mProxyParams.mProxyPcmHandle->period_size);
+ ALOGV("Capture - buffer_size (%d)",\
+ mProxyParams.mProxyPcmHandle->buffer_size);
+ ALOGV("Capture - period_cnt (%d)\n",\
+ mProxyParams.mProxyPcmHandle->period_cnt);
+ sparams = (struct snd_pcm_sw_params*) calloc(1,sizeof(struct snd_pcm_sw_params));
+ if (!sparams) {
+ ALOGE("Failed to allocated software params for Proxy device");
+ goto bail;
+ }
+
+ sparams->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
+ sparams->period_step = 1;
+ sparams->avail_min = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+ mProxyParams.mProxyPcmHandle->period_size/2
+ : mProxyParams.mProxyPcmHandle->period_size/4;
+ sparams->start_threshold = 1;
+ sparams->stop_threshold = mProxyParams.mProxyPcmHandle->buffer_size;
+ sparams->xfer_align = (mProxyParams.mProxyPcmHandle->flags & PCM_MONO) ?
+ mProxyParams.mProxyPcmHandle->period_size/2
+ : mProxyParams.mProxyPcmHandle->period_size/4; /* needed for old kernels */
+ sparams->silence_size = 0;
+ sparams->silence_threshold = 0;
+
+ if (param_set_sw_params(mProxyParams.mProxyPcmHandle, sparams)) {
+ ALOGE("Failed to set software params on Proxy device");
+ goto bail;
+ }
+ mmap_buffer(mProxyParams.mProxyPcmHandle);
+
+ if (pcm_prepare(mProxyParams.mProxyPcmHandle)) {
+ ALOGE("Failed to pcm_prepare on Proxy device");
+ goto bail;
+ }
+ mProxyParams.mProxyState = proxy_params::EProxySuspended;
+ return NO_ERROR;
+
+bail:
+ if(mProxyParams.mProxyPcmHandle) {
+ pcm_close(mProxyParams.mProxyPcmHandle);
+ mProxyParams.mProxyPcmHandle = NULL;
+ }
+ mProxyParams.mProxyState = proxy_params::EProxyClosed;
+ return NO_INIT;
+}
+
+status_t ALSADevice::closeProxyDevice() {
+ status_t err = NO_ERROR;
+ if(mProxyParams.mProxyPcmHandle) {
+ pcm_close(mProxyParams.mProxyPcmHandle);
+ mProxyParams.mProxyPcmHandle = NULL;
+ }
+ resetProxyVariables();
+ mProxyParams.mProxyState = proxy_params::EProxyClosed;
+ mProxyParams.mExitRead = false;
+ return err;
+}
+
+bool ALSADevice::isProxyDeviceOpened() {
+
+ //TODO : Add some intelligence to return appropriate value
+ if(mProxyParams.mProxyState == proxy_params::EProxyOpened ||
+ mProxyParams.mProxyState == proxy_params::EProxyCapture ||
+ mProxyParams.mProxyState == proxy_params::EProxySuspended)
+ return true;
+ return false;
+}
+
+bool ALSADevice::isProxyDeviceSuspended() {
+
+ if(mProxyParams.mProxyState == proxy_params::EProxySuspended)
+ return true;
+ return false;
+}
+
+bool ALSADevice::suspendProxy() {
+
+ status_t err = NO_ERROR;
+ if(mProxyParams.mProxyState == proxy_params::EProxyOpened ||
+ mProxyParams.mProxyState == proxy_params::EProxyCapture) {
+ mProxyParams.mProxyState = proxy_params::EProxySuspended;
+ }
+ else {
+ ALOGE("Proxy already suspend or closed, in state = %d",\
+ mProxyParams.mProxyState);
+ }
+ return err;
+}
+
+bool ALSADevice::resumeProxy() {
+
+ status_t err = NO_ERROR;
+ struct pcm *capture_handle= mProxyParams.mProxyPcmHandle;
+ ALOGD("resumeProxy mProxyParams.mProxyState = %d, capture_handle =%p",\
+ mProxyParams.mProxyState, capture_handle);
+ if((mProxyParams.mProxyState == proxy_params::EProxyOpened ||
+ mProxyParams.mProxyState == proxy_params::EProxySuspended) &&
+ capture_handle != NULL) {
+ ALOGV("pcm_prepare from Resume");
+ capture_handle->start = 0;
+ err = pcm_prepare(capture_handle);
+ if(err != OK) {
+ ALOGE("IGNORE: PCM Prepare - capture failed err = %d", err);
+ }
+ err = startProxy();
+ if(err) {
+ ALOGE("IGNORE:startProxy returned error = %d", err);
+ }
+ mProxyParams.mProxyState = proxy_params::EProxyCapture;
+ err = sync_ptr(capture_handle);
+ if (err) {
+ ALOGE("IGNORE: sync ptr from resumeProxy returned error = %d", err);
+ }
+ ALOGV("appl_ptr= %d", (int)capture_handle->sync_ptr->c.control.appl_ptr);
+ }
+ else {
+ ALOGV("resume Proxy ignored in invalid state - ignore");
+ if(mProxyParams.mProxyState == proxy_params::EProxyClosed ||
+ capture_handle == NULL) {
+ ALOGE("resumeProxy = BAD_VALUE");
+ err = BAD_VALUE;
+ return err;
+ }
+ }
+ return NO_ERROR;
+}
+
+#ifdef SEPERATED_AUDIO_INPUT
+void s_setInput(int input)
+{
+ mInput_source = input;
+ ALOGD("s_setInput() : input_source = %d",input_source);
+}
+#endif
+
+#ifdef QCOM_CSDCLIENT_ENABLED
+void ALSADevice::setCsdHandle(void* handle)
+{
+ mcsd_handle = static_cast<void*>(handle);
+ ALOGI("%s csd_handle: %p", __func__, mcsd_handle);
+
+ csd_disable_device = (int (*)())::dlsym(mcsd_handle,"csd_client_disable_device");
+ csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(mcsd_handle,"csd_client_enable_device");
+ csd_start_voice = (int (*)())::dlsym(mcsd_handle,"csd_client_start_voice");
+ csd_stop_voice = (int (*)())::dlsym(mcsd_handle,"csd_client_stop_voice");
+ csd_volume = (int (*)(int))::dlsym(mcsd_handle,"csd_client_volume");
+ csd_mic_mute = (int (*)(int))::dlsym(mcsd_handle,"csd_client_mic_mute");
+ csd_wide_voice = (int (*)(uint8_t))::dlsym(mcsd_handle,"csd_client_wide_voice");
+ csd_fens = (int (*)(uint8_t))::dlsym(mcsd_handle,"csd_client_fens");
+ csd_slow_talk = (int (*)(uint8_t))::dlsym(mcsd_handle,"csd_client_slow_talk");
+ csd_client_volume = (int (*)(int))::dlsym(mcsd_handle,"csd_client_volume");
+ csd_client_mic_mute = (int (*)(int))::dlsym(mcsd_handle,"csd_client_mic_mute");
+}
+#endif
+
+}
diff --git a/alsa_sound/ALSAMixer.cpp b/alsa_sound/ALSAMixer.cpp
index d1383cf..0875a57 100644
--- a/alsa_sound/ALSAMixer.cpp
+++ b/alsa_sound/ALSAMixer.cpp
@@ -1,6 +1,7 @@
/* ALSAMixer.cpp
**
** Copyright 2008-2010 Wind River Systems
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
diff --git a/alsa_sound/ALSAStreamOps.cpp b/alsa_sound/ALSAStreamOps.cpp
index 4e534fd..a8c5bad 100644
--- a/alsa_sound/ALSAStreamOps.cpp
+++ b/alsa_sound/ALSAStreamOps.cpp
@@ -1,7 +1,7 @@
/* ALSAStreamOps.cpp
**
** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -65,6 +65,7 @@
}
}
mParent->mVoipStreamCount = 0;
+ mParent->mVoipMicMute = 0;
mParent->mVoipBitRate = 0;
}
close();
@@ -110,15 +111,15 @@
break;
// Do not fall through
case 4:
- *channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;
- *channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;
+ *channels |= AUDIO_CHANNEL_OUT_BACK_LEFT;
+ *channels |= AUDIO_CHANNEL_OUT_BACK_RIGHT;
// Fall through...
default:
case 2:
- *channels |= AudioSystem::CHANNEL_OUT_FRONT_RIGHT;
+ *channels |= AUDIO_CHANNEL_OUT_FRONT_RIGHT;
// Fall through...
case 1:
- *channels |= AudioSystem::CHANNEL_OUT_FRONT_LEFT;
+ *channels |= AUDIO_CHANNEL_OUT_FRONT_LEFT;
break;
}
} else {
@@ -126,16 +127,16 @@
#ifdef QCOM_SSR_ENABLED
// For 5.1 recording
case 6 :
- *channels |= AudioSystem::CHANNEL_IN_5POINT1;
+ *channels |= AUDIO_CHANNEL_IN_5POINT1;
break;
#endif
// Do not fall through...
default:
case 2:
- *channels |= AudioSystem::CHANNEL_IN_RIGHT;
+ *channels |= AUDIO_CHANNEL_IN_RIGHT;
// Fall through...
case 1:
- *channels |= AudioSystem::CHANNEL_IN_LEFT;
+ *channels |= AUDIO_CHANNEL_IN_LEFT;
break;
}
}
@@ -152,23 +153,23 @@
if (format) {
switch(*format) {
- case AudioSystem::FORMAT_DEFAULT:
+ case AUDIO_FORMAT_DEFAULT:
break;
- case AudioSystem::PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_16_BIT:
iformat = SNDRV_PCM_FORMAT_S16_LE;
break;
- case AudioSystem::AMR_NB:
- case AudioSystem::AMR_WB:
-#ifdef QCOM_QCHAT_ENABLED
- case AudioSystem::EVRC:
- case AudioSystem::EVRCB:
- case AudioSystem::EVRCWB:
+ case AUDIO_FORMAT_AMR_NB:
+ case AUDIO_FORMAT_AMR_WB:
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+ case AUDIO_FORMAT_EVRC:
+ case AUDIO_FORMAT_EVRCB:
+ case AUDIO_FORMAT_EVRCWB:
#endif
iformat = *format;
break;
- case AudioSystem::PCM_8_BIT:
+ case AUDIO_FORMAT_PCM_8_BIT:
iformat = SNDRV_PCM_FORMAT_S8;
break;
@@ -182,10 +183,10 @@
switch(iformat) {
case SNDRV_PCM_FORMAT_S16_LE:
- *format = AudioSystem::PCM_16_BIT;
+ *format = AUDIO_FORMAT_PCM_16_BIT;
break;
case SNDRV_PCM_FORMAT_S8:
- *format = AudioSystem::PCM_8_BIT;
+ *format = AUDIO_FORMAT_PCM_8_BIT;
break;
default:
break;
@@ -198,8 +199,9 @@
status_t ALSAStreamOps::setParameters(const String8& keyValuePairs)
{
AudioParameter param = AudioParameter(keyValuePairs);
- String8 key = String8(AudioParameter::keyRouting);
+ String8 key = String8(AudioParameter::keyRouting),value;
int device;
+ status_t err = NO_ERROR;
#ifdef SEPERATED_AUDIO_INPUT
String8 key_input = String8(AudioParameter::keyInputSource);
@@ -219,13 +221,21 @@
if ((device == 0) && (mDevices == AudioSystem::DEVICE_OUT_AUX_DIGITAL)) {
device = AudioSystem::DEVICE_OUT_SPEAKER;
}
- if (device)
- mDevices = device;
- else
- ALOGV("must not change mDevices to 0");
-
if(device) {
- mParent->doRouting(device);
+ ALOGD("setParameters(): keyRouting with device %#x", device);
+ if(device & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ mParent->mRouteAudioToA2dp = true;
+ ALOGD("setParameters(): A2DP device %#x", device);
+ }
+ err = mParent->doRouting(device);
+ if(err) {
+ ALOGE("doRouting failed = %d",err);
+ }
+ else {
+ mDevices = device;
+ }
+ } else {
+ ALOGE("must not change mDevices to 0");
}
param.remove(key);
}
@@ -233,9 +243,9 @@
else {
key = String8(AudioParameter::keyHandleFm);
if (param.getInt(key, device) == NO_ERROR) {
- ALOGD("setParameters(): handleFm with device %d", device);
- mDevices = device;
+ ALOGD("setParameters(): handleFm with device %d", device);
if(device) {
+ mDevices = device;
mParent->handleFm(device);
}
param.remove(key);
@@ -243,7 +253,7 @@
}
#endif
- return NO_ERROR;
+ return err;
}
String8 ALSAStreamOps::getParameters(const String8& keys)
@@ -257,7 +267,7 @@
}
else {
#ifdef QCOM_VOIP_ENABLED
- key = String8(AudioParameter::keyVoipCheck);
+ key = String8(VOIPCHECK_KEY);
if (param.get(key, value) == NO_ERROR) {
if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
(!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP))))
@@ -324,25 +334,25 @@
switch(ALSAFormat) {
case SNDRV_PCM_FORMAT_S8:
- audioSystemFormat = AudioSystem::PCM_8_BIT;
+ audioSystemFormat = AUDIO_FORMAT_PCM_8_BIT;
break;
- case AudioSystem::AMR_NB:
- case AudioSystem::AMR_WB:
-#ifdef QCOM_QCHAT_ENABLED
- case AudioSystem::EVRC:
- case AudioSystem::EVRCB:
- case AudioSystem::EVRCWB:
+ case AUDIO_FORMAT_AMR_NB:
+ case AUDIO_FORMAT_AMR_WB:
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+ case AUDIO_FORMAT_EVRC:
+ case AUDIO_FORMAT_EVRCB:
+ case AUDIO_FORMAT_EVRCWB:
#endif
audioSystemFormat = mHandle->format;
break;
case SNDRV_PCM_FORMAT_S16_LE:
- audioSystemFormat = AudioSystem::PCM_16_BIT;
+ audioSystemFormat = AUDIO_FORMAT_PCM_16_BIT;
break;
default:
LOG_FATAL("Unknown AudioSystem bit width %d!", audioSystemFormat);
- audioSystemFormat = AudioSystem::PCM_16_BIT;
+ audioSystemFormat = AUDIO_FORMAT_PCM_16_BIT;
break;
}
@@ -363,15 +373,15 @@
break;
// Do not fall through
case 4:
- channels |= AudioSystem::CHANNEL_OUT_BACK_LEFT;
- channels |= AudioSystem::CHANNEL_OUT_BACK_RIGHT;
+ channels |= AUDIO_CHANNEL_OUT_BACK_LEFT;
+ channels |= AUDIO_CHANNEL_OUT_BACK_RIGHT;
// Fall through...
default:
case 2:
- channels |= AudioSystem::CHANNEL_OUT_FRONT_RIGHT;
+ channels |= AUDIO_CHANNEL_OUT_FRONT_RIGHT;
// Fall through...
case 1:
- channels |= AudioSystem::CHANNEL_OUT_FRONT_LEFT;
+ channels |= AUDIO_CHANNEL_OUT_FRONT_LEFT;
break;
}
else
@@ -379,16 +389,16 @@
#ifdef QCOM_SSR_ENABLED
// For 5.1 recording
case 6 :
- channels |= AudioSystem::CHANNEL_IN_5POINT1;
+ channels |= AUDIO_CHANNEL_IN_5POINT1;
break;
// Do not fall through...
#endif
default:
case 2:
- channels |= AudioSystem::CHANNEL_IN_RIGHT;
+ channels |= AUDIO_CHANNEL_IN_RIGHT;
// Fall through...
case 1:
- channels |= AudioSystem::CHANNEL_IN_LEFT;
+ channels |= AUDIO_CHANNEL_IN_LEFT;
break;
}
@@ -400,6 +410,7 @@
ALOGD("close");
if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
(!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
+ mParent->mVoipMicMute = false;
mParent->mVoipBitRate = 0;
mParent->mVoipStreamCount = 0;
}
diff --git a/alsa_sound/Android.mk b/alsa_sound/Android.mk
index 738b969..9139af9 100644
--- a/alsa_sound/Android.mk
+++ b/alsa_sound/Android.mk
@@ -11,25 +11,53 @@
LOCAL_ARM_MODE := arm
LOCAL_CFLAGS := -D_POSIX_SOURCE
-LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED
LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
+LOCAL_CFLAGS += -DQCOM_ANC_HEADSET_ENABLED
+LOCAL_CFLAGS += -DQCOM_AUDIO_FORMAT_ENABLED
+LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED
+#LOCAL_CFLAGS += -DQCOM_FM_ENABLED
+#LOCAL_CFLAGS += -DQCOM_FM_TX_ENABLED
+#LOCAL_CFLAGS += -DQCOM_OUTPUT_FLAGS_ENABLED
+LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED
+#LOCAL_CFLAGS += -DQCOM_SSR_ENABLED
+LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED
+LOCAL_CFLAGS += -DQCOM_VOIP_ENABLED
-ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true)
-LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL
+ifeq ($(call is-board-platform,msm8974),true)
+ LOCAL_CFLAGS += -DTARGET_8974
endif
-ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true)
-LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT
+ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),)
+ LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE)
endif
+#Do not use Dual MIC scenario in call feature
+#Dual MIC solution(Fluence) feature in Built-in MIC used scenarioes.
+# 1. Handset
+# 2. 3-Pole Headphones
+#ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true)
+#LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL
+#endif
+
+#Do not use separate audio Input path feature
+#Separate audio input path can be set using input source of audio parameter
+# 1. Voice Recognition
+# 2. Camcording
+# 3. etc.
+#ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true)
+#LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT
+#endif
+
LOCAL_SRC_FILES := \
- AudioHardwareALSA.cpp \
- AudioStreamOutALSA.cpp \
- AudioStreamInALSA.cpp \
- ALSAStreamOps.cpp \
- audio_hw_hal.cpp \
- AudioUsbALSA.cpp \
- AudioUtil.cpp
+ AudioHardwareALSA.cpp \
+ AudioStreamOutALSA.cpp \
+ AudioStreamInALSA.cpp \
+ ALSAStreamOps.cpp \
+ audio_hw_hal.cpp \
+ AudioUsbALSA.cpp \
+ AudioUtil.cpp \
+ AudioSessionOut.cpp \
+ ALSADevice.cpp
LOCAL_STATIC_LIBRARIES := \
libmedia_helper \
@@ -59,20 +87,37 @@
LOCAL_C_INCLUDES += frameworks/base/include
LOCAL_C_INCLUDES += system/core/include
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
-LOCAL_MODULE := audio.primary.msm8960
+ifeq ($(call is-board-platform,msm8974),true)
+ LOCAL_MODULE := audio.primary.msm8974
+endif
+
+ifeq ($(call is-board-platform,msm8960),true)
+ LOCAL_MODULE := audio.primary.msm8960
+endif
+
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_MODULE_TAGS := optional
include $(BUILD_SHARED_LIBRARY)
-ifeq (1,0) # use default audio policy manager
-# This is the ALSA audio policy manager
-
include $(CLEAR_VARS)
LOCAL_CFLAGS := -D_POSIX_SOURCE
LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
+LOCAL_CFLAGS += -DQCOM_ANC_HEADSET_ENABLED
+LOCAL_CFLAGS += -DQCOM_AUDIO_FORMAT_ENABLED
+LOCAL_CFLAGS += -DQCOM_CSDCLIENT_ENABLED
+#LOCAL_CFLAGS += -DQCOM_FM_ENABLED
+#LOCAL_CFLAGS += -DQCOM_FM_TX_ENABLED
+#LOCAL_CFLAGS += -DQCOM_OUTPUT_FLAGS_ENABLED
+LOCAL_CFLAGS += -DQCOM_PROXY_DEVICE_ENABLED
+#LOCAL_CFLAGS += -DQCOM_SSR_ENABLED
+LOCAL_CFLAGS += -DQCOM_USBAUDIO_ENABLED
+LOCAL_CFLAGS += -DQCOM_VOIP_ENABLED
+
ifeq ($(BOARD_HAVE_BLUETOOTH),true)
LOCAL_CFLAGS += -DWITH_A2DP
@@ -82,7 +127,15 @@
audio_policy_hal.cpp \
AudioPolicyManagerALSA.cpp
-LOCAL_MODULE := audio_policy.msm8960
+
+ifeq ($(call is-board-platform,msm8974),true)
+ LOCAL_MODULE := audio_policy.msm8974
+endif
+
+ifeq ($(call is-board-platform,msm8960),true)
+ LOCAL_MODULE := audio_policy.msm8960
+endif
+
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
LOCAL_MODULE_TAGS := optional
@@ -99,51 +152,5 @@
LOCAL_C_INCLUDES += hardware/libhardware_legacy/audio
include $(BUILD_SHARED_LIBRARY)
-endif
-# This is the ALSA module which behaves closely like the original
-
-include $(CLEAR_VARS)
-
-LOCAL_PRELINK_MODULE := false
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
-
-LOCAL_CFLAGS := -D_POSIX_SOURCE -Wno-multichar
-LOCAL_CFLAGS += -DQCOM_ACDB_ENABLED
-
-ifeq ($(strip $(BOARD_USES_FLUENCE_INCALL)),true)
-LOCAL_CFLAGS += -DUSES_FLUENCE_INCALL
-endif
-
-ifeq ($(strip $(BOARD_USES_SEPERATED_AUDIO_INPUT)),true)
-LOCAL_CFLAGS += -DSEPERATED_AUDIO_INPUT
-endif
-
-ifneq ($(ALSA_DEFAULT_SAMPLE_RATE),)
- LOCAL_CFLAGS += -DALSA_DEFAULT_SAMPLE_RATE=$(ALSA_DEFAULT_SAMPLE_RATE)
-endif
-
-LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/libalsa-intf
-
-LOCAL_SRC_FILES:= \
- alsa_default.cpp \
- ALSAControl.cpp \
- AudioUtil.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libalsa-intf
-
-ifeq ($(TARGET_SIMULATOR),true)
- LOCAL_LDLIBS += -ldl
-else
- LOCAL_SHARED_LIBRARIES += libdl
-endif
-
-LOCAL_MODULE:= alsa.msm8960
-LOCAL_MODULE_TAGS := optional
-
- include $(BUILD_SHARED_LIBRARY)
endif
diff --git a/alsa_sound/AudioHardwareALSA.cpp b/alsa_sound/AudioHardwareALSA.cpp
index a53f161..6cf142f 100644
--- a/alsa_sound/AudioHardwareALSA.cpp
+++ b/alsa_sound/AudioHardwareALSA.cpp
@@ -1,7 +1,7 @@
/* AudioHardwareALSA.cpp
**
** Copyright 2008-2010 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -26,7 +26,7 @@
#include <math.h>
#define LOG_TAG "AudioHardwareALSA"
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0
#define LOG_NDDEBUG 0
#include <utils/Log.h>
#include <utils/String8.h>
@@ -37,6 +37,7 @@
#include <cutils/properties.h>
#include <media/AudioRecord.h>
#include <hardware_legacy/power.h>
+#include <pthread.h>
#include "AudioHardwareALSA.h"
#ifdef QCOM_USBAUDIO_ENABLED
@@ -44,6 +45,13 @@
#endif
#include "AudioUtil.h"
+//#define OUTPUT_BUFFER_LOG
+#ifdef OUTPUT_BUFFER_LOG
+ FILE *outputBufferFile1;
+ char outputfilename [50] = "/data/output_proxy";
+ static int number = 0;
+#endif
+
extern "C"
{
//
@@ -72,39 +80,35 @@
}
AudioHardwareALSA::AudioHardwareALSA() :
- mALSADevice(0),mVoipStreamCount(0),mVoipBitRate(0)
+ mALSADevice(0),mVoipStreamCount(0),mVoipMicMute(false),mVoipBitRate(0)
,mCallState(0),mAcdbHandle(NULL),mCsdHandle(NULL),mMicMute(0)
{
FILE *fp;
char soundCardInfo[200];
- hw_module_t *module;
- char platform[128], baseband[128];
- int err = hw_get_module(ALSA_HARDWARE_MODULE_ID,
- (hw_module_t const**)&module);
- int codec_rev = 2;
- ALOGD("hw_get_module(ALSA_HARDWARE_MODULE_ID) returned err %d", err);
- if (err == 0) {
- hw_device_t* device;
- err = module->methods->open(module, ALSA_HARDWARE_NAME, &device);
- if (err == 0) {
- mALSADevice = (alsa_device_t *)device;
- mALSADevice->init(mALSADevice, mDeviceList);
- mCSCallActive = 0;
- mVolteCallActive = 0;
- mIsFmActive = 0;
- mDevSettingsFlag = 0;
+ char platform[128], baseband[128], audio_init[128], platformVer[128];
+ int codec_rev = 2, verNum = 0;
+ mALSADevice = new ALSADevice();
+ mDeviceList.clear();
+ mCSCallActive = 0;
+ mVolteCallActive = 0;
+ mSGLTECallActive = 0;
+ mIsFmActive = 0;
+ mDevSettingsFlag = 0;
+ bool audio_init_done = false;
+ int sleep_retry = 0;
#ifdef QCOM_USBAUDIO_ENABLED
- mAudioUsbALSA = new AudioUsbALSA();
- musbPlaybackState = 0;
- musbRecordingState = 0;
+ mAudioUsbALSA = new AudioUsbALSA();
+ musbPlaybackState = 0;
+ musbRecordingState = 0;
#endif
#ifdef USES_FLUENCE_INCALL
- mDevSettingsFlag |= TTY_OFF | DMIC_FLAG;
+ mDevSettingsFlag |= TTY_OFF | DMIC_FLAG;
#else
- mDevSettingsFlag |= TTY_OFF;
+ mDevSettingsFlag |= TTY_OFF;
#endif
- mBluetoothVGS = false;
- mFusion3Platform = false;
+ mBluetoothVGS = false;
+ mFusion3Platform = false;
+ mIsVoicePathActive = false;
#ifdef QCOM_ACDB_ENABLED
mAcdbHandle = ::dlopen("/system/lib/libacdbloader.so", RTLD_NOW);
@@ -133,61 +137,141 @@
}
mALSADevice->setCsdHandle(mCsdHandle);
#endif
- if((fp = fopen("/proc/asound/cards","r")) == NULL) {
- ALOGE("Cannot open /proc/asound/cards file to get sound card info");
- } else {
- while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
- ALOGV("SoundCardInfo %s", soundCardInfo);
- if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) {
- codec_rev = 1;
- break;
- } else if (strstr(soundCardInfo, "msm-snd-card")) {
- codec_rev = 2;
- break;
- } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) {
- codec_rev = 3;
- break;
- }
- }
- fclose(fp);
- }
-
- if (codec_rev == 1) {
- ALOGV("Detected tabla 1.x sound card");
- snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
- } else if (codec_rev == 3) {
- ALOGV("Detected sitar 1.x sound card");
- snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar");
- } else {
- property_get("ro.board.platform", platform, "");
- property_get("ro.baseband", baseband, "");
- if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
- ALOGV("Detected Fusion tabla 2.x");
- mFusion3Platform = true;
- snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
- } else {
- ALOGV("Detected tabla 2.x sound card");
- snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
- }
- }
-
- if (mUcMgr < 0) {
- ALOGE("Failed to open ucm instance: %d", errno);
- } else {
- ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
- mUcMgr->acdb_handle = NULL;
-#ifdef QCOM_ACDB_ENABLED
- if (mAcdbHandle) {
- mUcMgr->acdb_handle = static_cast<void*> (mAcdbHandle);
- }
-#endif
- }
- } else {
- ALOGE("ALSA Module could not be opened!!!");
- }
+ if((fp = fopen("/proc/asound/cards","r")) == NULL) {
+ ALOGE("Cannot open /proc/asound/cards file to get sound card info");
} else {
- ALOGE("ALSA Module not found!!!");
+ while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
+ ALOGV("SoundCardInfo %s", soundCardInfo);
+ if (strstr(soundCardInfo, "msm8960-tabla1x-snd-card")) {
+ codec_rev = 1;
+ break;
+ } else if (strstr(soundCardInfo, "msm-snd-card")) {
+ codec_rev = 2;
+ break;
+ } else if (strstr(soundCardInfo, "msm8930-sitar-snd-card")) {
+ codec_rev = 3;
+ break;
+ } else if (strstr(soundCardInfo, "msm8974-taiko-mtp-snd-card")) {
+ codec_rev = 40;
+ break;
+ } else if (strstr(soundCardInfo, "msm8974-taiko-cdp-snd-card")) {
+ codec_rev = 41;
+ break;
+ } else if (strstr(soundCardInfo, "msm8974-taiko-fluid-snd-card")) {
+ codec_rev = 42;
+ break;
+ } else if (strstr(soundCardInfo, "msm8974-taiko-liquid-snd-card")) {
+ codec_rev = 43;
+ break;
+ }
+ }
+ fclose(fp);
}
+
+ while (audio_init_done == false && sleep_retry < MAX_SLEEP_RETRY) {
+ property_get("qcom.audio.init", audio_init, NULL);
+ ALOGD("qcom.audio.init is set to %s\n",audio_init);
+ if(!strncmp(audio_init, "complete", sizeof("complete"))) {
+ audio_init_done = true;
+ } else {
+ ALOGD("Sleeping for 50 ms");
+ usleep(AUDIO_INIT_SLEEP_WAIT*1000);
+ sleep_retry++;
+ }
+ }
+
+ if (codec_rev == 1) {
+ ALOGV("Detected tabla 1.x sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
+ } else if (codec_rev == 3) {
+ ALOGV("Detected sitar 1.x sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Sitar");
+ } else if (codec_rev == 40) {
+ ALOGV("Detected taiko sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko");
+ } else if (codec_rev == 41) {
+ ALOGV("Detected taiko sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_CDP");
+ } else if (codec_rev == 42) {
+ ALOGV("Detected taiko sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_Fluid");
+ } else if (codec_rev == 43) {
+ ALOGV("Detected taiko liquid sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_Taiko_liquid");
+ } else {
+ property_get("ro.board.platform", platform, "");
+ property_get("ro.baseband", baseband, "");
+ if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband)) {
+ ALOGV("Detected Fusion tabla 2.x");
+ mFusion3Platform = true;
+ if((fp = fopen("/sys/devices/system/soc/soc0/platform_version","r")) == NULL) {
+ ALOGE("Cannot open /sys/devices/system/soc/soc0/platform_version file");
+
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
+ } else {
+ while((fgets(platformVer, sizeof(platformVer), fp) != NULL)) {
+ ALOGV("platformVer %s", platformVer);
+
+ verNum = atoi(platformVer);
+ if (verNum == 0x10001) {
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_I2SFusion");
+ break;
+ } else {
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ } else {
+ ALOGV("Detected tabla 2.x sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
+ }
+ }
+
+ if (mUcMgr < 0) {
+ ALOGE("Failed to open ucm instance: %d", errno);
+ } else {
+ ALOGI("ucm instance opened: %u", (unsigned)mUcMgr);
+ }
+
+ //set default AudioParameters
+ AudioParameter param;
+ String8 key;
+ String8 value;
+
+ //Set default AudioParameter for fluencetype
+ key = String8(FLUENCE_KEY);
+ char fluence_key[20] = "none";
+ property_get("ro.qc.sdk.audio.fluencetype",fluence_key,"0");
+ if (0 == strncmp("fluencepro", fluence_key, sizeof("fluencepro"))) {
+ mDevSettingsFlag |= QMIC_FLAG;
+ mDevSettingsFlag &= (~DMIC_FLAG);
+ value = String8("fluencepro");
+ ALOGD("FluencePro quadMic feature Enabled");
+ } else if (0 == strncmp("fluence", fluence_key, sizeof("fluence"))) {
+ mDevSettingsFlag |= DMIC_FLAG;
+ mDevSettingsFlag &= (~QMIC_FLAG);
+ value = String8("fluence");
+ ALOGD("Fluence dualmic feature Enabled");
+ } else if (0 == strncmp("none", fluence_key, sizeof("none"))) {
+ mDevSettingsFlag &= (~DMIC_FLAG);
+ mDevSettingsFlag &= (~QMIC_FLAG);
+ value = String8("none");
+ ALOGD("Fluence feature Disabled");
+ }
+ param.add(key, value);
+ mALSADevice->setFlags(mDevSettingsFlag);
+
+ //mALSADevice->setDeviceList(&mDeviceList);
+ mRouteAudioToA2dp = false;
+ mA2dpDevice = NULL;
+ mA2dpStream = NULL;
+ mA2DPActiveUseCases = USECASE_NONE;
+ mIsA2DPEnabled = false;
+ mKillA2DPThread = false;
+ mA2dpThreadAlive = false;
+ mA2dpThread = NULL;
}
AudioHardwareALSA::~AudioHardwareALSA()
@@ -197,7 +281,7 @@
snd_use_case_mgr_close(mUcMgr);
}
if (mALSADevice) {
- mALSADevice->common.close(&mALSADevice->common);
+ delete mALSADevice;
}
for(ALSAHandleList::iterator it = mDeviceList.begin();
it != mDeviceList.end(); ++it) {
@@ -256,11 +340,13 @@
vol = 100 - vol;
if (mALSADevice) {
- if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
+ if(newMode == AUDIO_MODE_IN_COMMUNICATION) {
mALSADevice->setVoipVolume(vol);
- } else if (newMode == AudioSystem::MODE_IN_CALL){
+ } else if (newMode == AUDIO_MODE_IN_CALL){
if (mCSCallActive == CS_ACTIVE)
mALSADevice->setVoiceVolume(vol);
+ else if (mSGLTECallActive == CS_ACTIVE_SESSION2)
+ mALSADevice->setSGLTEVolume(vol);
if (mVolteCallActive == IMS_ACTIVE)
mALSADevice->setVoLTEVolume(vol);
}
@@ -272,6 +358,7 @@
#ifdef QCOM_FM_ENABLED
status_t AudioHardwareALSA::setFmVolume(float value)
{
+ Mutex::Autolock autoLock(mLock);
status_t status = NO_ERROR;
int vol;
@@ -306,10 +393,10 @@
if (mode != mMode) {
status = AudioHardwareBase::setMode(mode);
}
-
- if (mode == AudioSystem::MODE_IN_CALL) {
- mCallState = CS_ACTIVE;
- }else if (mode == AudioSystem::MODE_NORMAL) {
+ if (mode == AUDIO_MODE_IN_CALL) {
+ if (mCallState == CS_INACTIVE)
+ mCallState = CS_ACTIVE;
+ }else if (mode == AUDIO_MODE_NORMAL) {
mCallState = 0;
}
@@ -330,18 +417,18 @@
key = String8(TTY_MODE_KEY);
if (param.get(key, value) == NO_ERROR) {
mDevSettingsFlag &= TTY_CLEAR;
- if (value == "tty_full") {
+ if (value == "full") {
mDevSettingsFlag |= TTY_FULL;
- } else if (value == "tty_hco") {
+ } else if (value == "hco") {
mDevSettingsFlag |= TTY_HCO;
- } else if (value == "tty_vco") {
+ } else if (value == "vco") {
mDevSettingsFlag |= TTY_VCO;
} else {
mDevSettingsFlag |= TTY_OFF;
}
ALOGI("Changed TTY Mode=%s", value.string());
mALSADevice->setFlags(mDevSettingsFlag);
- if(mMode != AudioSystem::MODE_IN_CALL){
+ if(mMode != AUDIO_MODE_IN_CALL){
return NO_ERROR;
}
doRouting(0);
@@ -438,6 +525,43 @@
param.remove(key);
}
+ key = String8("a2dp_connected");
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "true") {
+ status_t err = openA2dpOutput();
+ if(err) {
+ ALOGE("openA2DPOutput failed = %d",err);
+ return err;
+ }
+ } else {
+ uint32_t activeUsecase = getA2DPActiveUseCases_l();
+ stopA2dpPlayback(activeUsecase);
+ status_t err = closeA2dpOutput();
+ if(err) {
+ ALOGE("closeA2dpOutput = %d" ,err);
+ }
+ }
+ param.remove(key);
+ }
+
+ key = String8("A2dpSuspended");
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "true") {
+ if (mA2dpDevice != NULL) {
+ mA2dpDevice->set_parameters(mA2dpDevice,keyValuePairs);
+ }
+ }
+ param.remove(key);
+ }
+
+ key = String8("a2dp_sink_address");
+ if (param.get(key, value) == NO_ERROR) {
+ if (mA2dpStream != NULL) {
+ mA2dpStream->common.set_parameters(&mA2dpStream->common,keyValuePairs);
+ }
+ param.remove(key);
+ }
+
key = String8(VOIPRATE_KEY);
if (param.get(key, value) == NO_ERROR) {
mVoipBitRate = atoi(value);
@@ -496,6 +620,7 @@
{
AudioParameter param = AudioParameter(keys);
String8 value;
+ int device;
String8 key = String8(DUALMIC_KEY);
if (param.get(key, value) == NO_ERROR) {
@@ -518,6 +643,12 @@
}
#ifdef QCOM_FM_ENABLED
+
+ key = String8(AudioParameter::keyHandleA2dpDevice);
+ if ( param.get(key,value) == NO_ERROR ) {
+ param.add(key, String8("true"));
+ }
+
key = String8("Fm-radio");
if ( param.get(key,value) == NO_ERROR ) {
if ( mIsFmActive ) {
@@ -531,6 +662,57 @@
if(mBluetoothVGS)
param.addInt(String8("isVGS"), true);
}
+#ifdef QCOM_SSR_ENABLED
+ key = String8(AudioParameter::keySSR);
+ if (param.get(key, value) == NO_ERROR) {
+ char ssr_enabled[6] = "false";
+ property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
+ if (!strncmp("true", ssr_enabled, 4)) {
+ value = String8("true");
+ }
+ param.add(key, value);
+ }
+#endif
+
+ key = String8("A2dpSuspended");
+ if (param.get(key, value) == NO_ERROR) {
+ if (mA2dpDevice != NULL) {
+ value = mA2dpDevice->get_parameters(mA2dpDevice,key);
+ }
+ param.add(key, value);
+ }
+
+ key = String8("a2dp_sink_address");
+ if (param.get(key, value) == NO_ERROR) {
+ if (mA2dpStream != NULL) {
+ value = mA2dpStream->common.get_parameters(&mA2dpStream->common,key);
+ }
+ param.add(key, value);
+ }
+
+ key = String8(VOICE_PATH_ACTIVE);
+ if (param.get(key, value) == NO_ERROR) {
+ if (mIsVoicePathActive) {
+ value = String8("true");
+ } else {
+ value = String8("false");
+ }
+ param.add(key, value);
+
+ ALOGV("AudioHardwareALSA::getParameters() mIsVoicePathActive %d",
+ mIsVoicePathActive);
+ }
+
+ key = String8("tunneled-input-formats");
+ if ( param.get(key,value) == NO_ERROR ) {
+ ALOGD("Add tunnel AWB to audio parameter");
+ param.addInt(String8("AWB"), true );
+ }
+
+ key = String8(AudioParameter::keyRouting);
+ if (param.getInt(key, device) == NO_ERROR) {
+ param.addInt(key, mCurDevice);
+ }
ALOGV("AudioHardwareALSA::getParameters() %s", param.toString().string());
return param.toString();
@@ -583,7 +765,7 @@
}
#endif
-void AudioHardwareALSA::doRouting(int device)
+status_t AudioHardwareALSA::doRouting(int device)
{
Mutex::Autolock autoLock(mLock);
int newMode = mode();
@@ -592,38 +774,34 @@
if ((device == AudioSystem::DEVICE_IN_VOICE_CALL)
#ifdef QCOM_FM_ENABLED
|| (device == AudioSystem::DEVICE_IN_FM_RX)
- || (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT)
|| (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)
#endif
|| (device == AudioSystem::DEVICE_IN_COMMUNICATION)
) {
ALOGV("Ignoring routing for FM/INCALL/VOIP recording");
- return;
+ return NO_ERROR;
}
+ ALOGV("device = 0x%x,mCurDevice 0x%x", device, mCurDevice);
if (device == 0)
device = mCurDevice;
- ALOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d"
- "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive,
- mIsFmActive);
-
+ ALOGV("doRouting: device %#x newMode %d mCSCallActive %d mVolteCallActive %d"
+ "mSGLTECallActive %d mIsFmActive %d", device, newMode, mCSCallActive,
+ mVolteCallActive, mSGLTECallActive, mIsFmActive);
isRouted = routeVoLTECall(device, newMode);
isRouted |= routeVoiceCall(device, newMode);
+ isRouted |= routeSGLTECall(device, newMode);
if(!isRouted) {
#ifdef QCOM_USBAUDIO_ENABLED
if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) &&
!(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
!(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) &&
- (musbPlaybackState)){
+ (musbPlaybackState || musbRecordingState)){
//USB unplugged
- device &= ~ AudioSystem::DEVICE_OUT_PROXY;
- device &= ~ AudioSystem::DEVICE_IN_PROXY;
ALSAHandleList::iterator it = mDeviceList.end();
it--;
mALSADevice->route(&(*it), (uint32_t)device, newMode);
ALOGD("USB UNPLUGGED, setting musbPlaybackState to 0");
- musbPlaybackState = 0;
- musbRecordingState = 0;
closeUSBRecording();
closeUSBPlayback();
} else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
@@ -631,8 +809,11 @@
ALOGD("Routing everything to prox now");
ALSAHandleList::iterator it = mDeviceList.end();
it--;
- mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY,
- newMode);
+ if (device != mCurDevice) {
+ if(musbPlaybackState)
+ closeUSBPlayback();
+ }
+ mALSADevice->route(&(*it), device, newMode);
for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
(!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
@@ -640,6 +821,12 @@
startUsbPlaybackIfNotStarted();
musbPlaybackState |= USBPLAYBACKBIT_LPA;
break;
+ } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+ ALOGD("doRouting: Tunnel Player device switch to proxy");
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_TUNNEL;
+ break;
} else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) ||
(!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) {
ALOGV("doRouting: VOICE device switch to proxy");
@@ -658,41 +845,134 @@
}
} else
#endif
- {
+ if (device & AudioSystem::DEVICE_OUT_ALL_A2DP &&
+ mRouteAudioToA2dp == true ) {
+ ALOGV(" A2DP Enabled - Routing everything to proxy now");
+ if (device != mCurDevice) {
+ pauseIfUseCaseTunnelOrLPA();
+ }
+ ALSAHandleList::iterator it = mDeviceList.end();
+ it--;
+ status_t err = NO_ERROR;
+ uint32_t activeUsecase = useCaseStringToEnum(it->useCase);
+ ALOGD("doRouting-startA2dpPlayback_l-A2DPHardwareOutput-enable");
+ if ((activeUsecase == USECASE_HIFI_LOW_POWER) ||
+ (activeUsecase == USECASE_HIFI_TUNNEL)) {
+ if (device != mCurDevice) {
+ if((mCurDevice & AudioSystem::DEVICE_OUT_ALL_A2DP) &&
+ (device & AudioSystem::DEVICE_OUT_ALL_A2DP)) {
+ activeUsecase = getA2DPActiveUseCases_l();
+ stopA2dpPlayback_l(activeUsecase);
+ mRouteAudioToA2dp = true;
+ }
+ mALSADevice->route(&(*it),(uint32_t)device, newMode);
+ }
+ err = startA2dpPlayback_l(activeUsecase);
+ if(err) {
+ ALOGW("startA2dpPlayback_l for hardware output failed err = %d", err);
+ stopA2dpPlayback_l(activeUsecase);
+ }
+ } else {
+ //WHY NO check for prev device here?
+ if (device != mCurDevice) {
+ if((mCurDevice & AudioSystem::DEVICE_OUT_ALL_A2DP) &&
+ (device & AudioSystem::DEVICE_OUT_ALL_A2DP)) {
+ activeUsecase = getA2DPActiveUseCases_l();
+ stopA2dpPlayback_l(activeUsecase);
+ mALSADevice->route(&(*it),(uint32_t)device, newMode);
+ mRouteAudioToA2dp = true;
+ startA2dpPlayback_l(activeUsecase);
+ } else {
+ mALSADevice->route(&(*it),(uint32_t)device, newMode);
+ }
+ }
+ if (activeUsecase == USECASE_FM){
+ err = startA2dpPlayback_l(activeUsecase);
+ if(err) {
+ ALOGW("startA2dpPlayback_l for hardware output failed err = %d", err);
+ stopA2dpPlayback_l(activeUsecase);
+ }
+ }
+ }
+ if (device != mCurDevice) {
+ resumeIfUseCaseTunnelOrLPA();
+ }
+ if(err) {
+ mRouteAudioToA2dp = false;
+ mALSADevice->route(&(*it),(uint32_t)mCurDevice, newMode);
+ return err;
+ }
+ } else if(device & AudioSystem::DEVICE_OUT_ALL &&
+ !(device & AudioSystem::DEVICE_OUT_ALL_A2DP) &&
+ mRouteAudioToA2dp == true ) {
+ ALOGV(" A2DP Disable on hardware output");
+ ALSAHandleList::iterator it = mDeviceList.end();
+ it--;
+ status_t err;
+ uint32_t activeUsecase = getA2DPActiveUseCases_l();
+ err = stopA2dpPlayback_l(activeUsecase);
+ if(err) {
+ ALOGW("stop A2dp playback for hardware output failed = %d", err);
+ return err;
+ }
+ if (device != mCurDevice) {
+ mALSADevice->route(&(*it),(uint32_t)device, newMode);
+ }
+ } else {
+ setInChannels(device);
ALSAHandleList::iterator it = mDeviceList.end();
it--;
mALSADevice->route(&(*it), (uint32_t)device, newMode);
}
}
mCurDevice = device;
+ return NO_ERROR;
+}
+
+void AudioHardwareALSA::setInChannels(int device)
+{
+ ALSAHandleList::iterator it;
+
+ if (device & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
+ for(it = mDeviceList.begin(); it != mDeviceList.end(); ++it) {
+ if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC,
+ strlen(SND_USE_CASE_VERB_HIFI_REC)) ||
+ !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
+ strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
+ mALSADevice->setInChannels(it->channels);
+ return;
+ }
+ }
+ }
+
+ mALSADevice->setInChannels(1);
}
uint32_t AudioHardwareALSA::getVoipMode(int format)
{
switch(format) {
- case AudioSystem::PCM_16_BIT:
+ case AUDIO_FORMAT_PCM_16_BIT:
return MODE_PCM;
break;
- case AudioSystem::AMR_NB:
+ case AUDIO_FORMAT_AMR_NB:
return MODE_AMR;
break;
- case AudioSystem::AMR_WB:
+ case AUDIO_FORMAT_AMR_WB:
return MODE_AMR_WB;
break;
-#ifdef QCOM_QCHAT_ENABLED
- case AudioSystem::EVRC:
+#ifdef QCOM_AUDIO_FORMAT_ENABLED
+ case AUDIO_FORMAT_EVRC:
return MODE_IS127;
break;
- case AudioSystem::EVRCB:
+ case AUDIO_FORMAT_EVRCB:
return MODE_4GV_NB;
break;
- case AudioSystem::EVRCWB:
+ case AUDIO_FORMAT_EVRCWB:
return MODE_4GV_WB;
break;
#endif
-
default:
return MODE_PCM;
}
@@ -700,6 +980,9 @@
AudioStreamOut *
AudioHardwareALSA::openOutputStream(uint32_t devices,
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+ audio_output_flags_t flags,
+#endif
int *format,
uint32_t *channels,
uint32_t *sampleRate,
@@ -712,7 +995,30 @@
audio_output_flags_t flag = static_cast<audio_output_flags_t> (*status);
status_t err = BAD_VALUE;
- *status = NO_ERROR;
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+ if (flags & AUDIO_OUTPUT_FLAG_LPA) {
+ AudioSessionOutALSA *out = new AudioSessionOutALSA(this, devices, *format, *channels,
+ *sampleRate, 0, &err);
+ if(err != NO_ERROR) {
+ delete out;
+ out = NULL;
+ }
+ if (status) *status = err;
+ return out;
+ }
+
+ if (flags & AUDIO_OUTPUT_FLAG_TUNNEL) {
+ AudioSessionOutALSA *out = new AudioSessionOutALSA(this, devices, *format, *channels,
+ *sampleRate, 1, &err);
+ if(err != NO_ERROR) {
+ delete out;
+ out = NULL;
+ }
+ if (status) *status = err;
+ return out;
+ }
+#endif
+
AudioStreamOutALSA *out = 0;
ALSAHandleList::iterator it;
@@ -722,9 +1028,14 @@
return out;
}
+ if(devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ ALOGV("Set Capture from proxy true");
+ mRouteAudioToA2dp = true;
-# if 0
- if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) &&
+ }
+
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+ if((flags & AUDIO_OUTPUT_FLAG_DIRECT) && (flags & AUDIO_OUTPUT_FLAG_VOIP_RX)&&
((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
bool voipstream_active = false;
for(it = mDeviceList.begin();
@@ -738,6 +1049,7 @@
}
if(voipstream_active == false) {
mVoipStreamCount = 0;
+ mVoipMicMute = false;
alsa_handle_t alsa_handle;
unsigned long bufferSize;
if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
@@ -755,7 +1067,7 @@
alsa_handle.bufferSize = bufferSize;
alsa_handle.devices = devices;
alsa_handle.handle = 0;
- if(*format == AudioSystem::PCM_16_BIT)
+ if(*format == AUDIO_FORMAT_PCM_16_BIT)
alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
else
alsa_handle.format = *format;
@@ -781,17 +1093,17 @@
(mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
(mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){
ALOGD("Routing to proxy for normal voip call in openOutputStream");
- mCurDevice |= AudioSystem::DEVICE_OUT_PROXY;
- alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
- mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
- ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
+ mALSADevice->route(&(*it), mCurDevice, AUDIO_MODE_IN_COMMUNICATION);
+#ifdef QCOM_USBAUDIO_ENABLED
+ ALOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
startUsbPlaybackIfNotStarted();
musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
ALOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
startUsbRecordingIfNotStarted();
musbRecordingState |= USBRECBIT_VOIPCALL;
- } else{
- mALSADevice->route(&(*it), mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
+#endif
+ } else{
+ mALSADevice->route(&(*it), mCurDevice, AUDIO_MODE_IN_COMMUNICATION);
}
if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
@@ -884,7 +1196,6 @@
if (status) *status = err;
return out;
} else {
-
alsa_handle_t alsa_handle;
unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
@@ -901,54 +1212,52 @@
alsa_handle.latency = PLAYBACK_LATENCY;
alsa_handle.rxHandle = 0;
alsa_handle.ucMgr = mUcMgr;
- alsa_handle.isDeepbufferOutput = false;
+ alsa_handle.session = NULL;
+ alsa_handle.isFastOutput = false;
char *use_case;
snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
- if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
- ALOGD("openOutputStream: DeepBuffer Output");
- alsa_handle.isDeepbufferOutput = true;
- if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
- } else {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
- }
- } else {
- ALOGD("openOutputStream: Lowlatency Output");
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+ if (flags & AUDIO_OUTPUT_FLAG_FAST) {
alsa_handle.bufferSize = PLAYBACK_LOW_LATENCY_BUFFER_SIZE;
- alsa_handle.latency = PLAYBACK_LOW_LATENCY_MEASURED;
+ alsa_handle.latency = PLAYBACK_LOW_LATENCY;
+ alsa_handle.isFastOutput = true;
if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
} else {
strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
}
+ } else
+#endif
+ {
+ if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI, sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(alsa_handle.useCase));
+ }
}
free(use_case);
mDeviceList.push_back(alsa_handle);
ALSAHandleList::iterator it = mDeviceList.end();
it--;
- ALOGV("useCase %s", it->useCase);
-#ifdef QCOM_USBAUDIO_ENABLED
- if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
- (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
- ALOGD("Routing to proxy for normal playback in openOutputStream");
- devices |= AudioSystem::DEVICE_OUT_PROXY;
- }
-#endif
+ ALOGD("useCase %s", it->useCase);
mALSADevice->route(&(*it), devices, mode());
- if (flag & AUDIO_OUTPUT_FLAG_DEEP_BUFFER) {
- if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
- snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
- } else {
- snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
- }
- } else {
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+ if (flags & AUDIO_OUTPUT_FLAG_FAST) {
if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) {
snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC);
} else {
snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC);
}
+ } else
+#endif
+ {
+ if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI)) {
+ snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI);
+ } else {
+ snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_MUSIC);
+ }
}
err = mALSADevice->open(&(*it));
if (err) {
@@ -969,100 +1278,6 @@
delete out;
}
-#ifdef QCOM_TUNNEL_LPA_ENABLED
-AudioStreamOut *
-AudioHardwareALSA::openOutputSession(uint32_t devices,
- int *format,
- status_t *status,
- int sessionId,
- uint32_t samplingRate,
- uint32_t channels)
-{
- Mutex::Autolock autoLock(mLock);
- ALOGD("openOutputSession = %d" ,sessionId);
- AudioStreamOutALSA *out = 0;
- status_t err = BAD_VALUE;
-
- alsa_handle_t alsa_handle;
- unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
-
- for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
- bufferSize &= ~b;
-
- alsa_handle.module = mALSADevice;
- alsa_handle.bufferSize = bufferSize;
- alsa_handle.devices = devices;
- alsa_handle.handle = 0;
- alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
- alsa_handle.channels = DEFAULT_CHANNEL_MODE;
- alsa_handle.sampleRate = DEFAULT_SAMPLING_RATE;
- alsa_handle.latency = VOICE_LATENCY;
- alsa_handle.rxHandle = 0;
- alsa_handle.ucMgr = mUcMgr;
-
- char *use_case;
- if(sessionId == TUNNEL_SESSION_ID) {
- snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
- if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_TUNNEL, sizeof(alsa_handle.useCase));
- } else {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_TUNNEL, sizeof(alsa_handle.useCase));
- }
- } else {
- snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
- if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER, sizeof(alsa_handle.useCase));
- } else {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_LPA, sizeof(alsa_handle.useCase));
- }
- }
- free(use_case);
- mDeviceList.push_back(alsa_handle);
- ALSAHandleList::iterator it = mDeviceList.end();
- it--;
- ALOGD("useCase %s", it->useCase);
-#ifdef QCOM_USBAUDIO_ENABLED
- if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
- (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
- ALOGD("Routing to proxy for LPA in openOutputSession");
- devices |= AudioSystem::DEVICE_OUT_PROXY;
- mALSADevice->route(&(*it), devices, mode());
- devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
- ALOGD("Starting USBPlayback for LPA");
- startUsbPlaybackIfNotStarted();
- musbPlaybackState |= USBPLAYBACKBIT_LPA;
- } else
-#endif
- {
- mALSADevice->route(&(*it), devices, mode());
- }
- if(sessionId == TUNNEL_SESSION_ID) {
- if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) {
- snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_TUNNEL);
- } else {
- snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_TUNNEL);
- }
- }
- else {
- if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) {
- snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_HIFI_LOW_POWER);
- } else {
- snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_LPA);
- }
- }
- err = mALSADevice->open(&(*it));
- out = new AudioStreamOutALSA(this, &(*it));
-
- if (status) *status = err;
- return out;
-}
-
-void
-AudioHardwareALSA::closeOutputSession(AudioStreamOut* out)
-{
- delete out;
-}
-#endif
AudioStreamIn *
AudioHardwareALSA::openInputStream(uint32_t devices,
@@ -1081,9 +1296,10 @@
AudioStreamInALSA *in = 0;
ALSAHandleList::iterator it;
- ALOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate);
+ ALOGD("openInputStream: devices 0x%x format 0x%x channels %d sampleRate %d", devices, *format, *channels, *sampleRate);
if (devices & (devices - 1)) {
if (status) *status = err;
+ ALOGE("openInputStream failed error:0x%x devices:%x",err,devices);
return in;
}
@@ -1101,6 +1317,7 @@
}
if(voipstream_active == false) {
mVoipStreamCount = 0;
+ mVoipMicMute = false;
alsa_handle_t alsa_handle;
unsigned long bufferSize;
if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
@@ -1118,7 +1335,7 @@
alsa_handle.bufferSize = bufferSize;
alsa_handle.devices = devices;
alsa_handle.handle = 0;
- if(*format == AudioSystem::PCM_16_BIT)
+ if(*format == AUDIO_FORMAT_PCM_16_BIT)
alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
else
alsa_handle.format = *format;
@@ -1143,7 +1360,7 @@
if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
(mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
ALOGD("Routing everything from proxy for voipcall");
- mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION);
+ mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AUDIO_MODE_IN_COMMUNICATION);
ALOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState);
startUsbPlaybackIfNotStarted();
musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
@@ -1153,7 +1370,7 @@
} else
#endif
{
- mALSADevice->route(&(*it),mCurDevice, AudioSystem::MODE_IN_COMMUNICATION);
+ mALSADevice->route(&(*it),mCurDevice, AUDIO_MODE_IN_COMMUNICATION);
}
if(!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_IP_VOICECALL);
@@ -1163,8 +1380,10 @@
if(sampleRate) {
it->sampleRate = *sampleRate;
}
- if(channels)
+ if(channels) {
it->channels = AudioSystem::popCount(*channels);
+ setInChannels(devices);
+ }
err = mALSADevice->startVoipCall(&(*it));
if (err) {
ALOGE("Error opening pcm input device");
@@ -1188,7 +1407,10 @@
alsa_handle.bufferSize = bufferSize;
alsa_handle.devices = devices;
alsa_handle.handle = 0;
- alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+ if(*format == AUDIO_FORMAT_PCM_16_BIT)
+ alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+ else
+ alsa_handle.format = *format;
alsa_handle.channels = VOICE_CHANNEL_MODE;
alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
alsa_handle.latency = RECORD_LATENCY;
@@ -1197,27 +1419,37 @@
snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
- (newMode == AudioSystem::MODE_IN_CALL)) {
+ (newMode == AUDIO_MODE_IN_CALL)) {
ALOGD("openInputStream: into incall recording, channels %d", *channels);
mIncallMode = *channels;
- if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
- (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+ if ((*channels & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+ (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
if (mFusion3Platform) {
mALSADevice->setVocRecMode(INCALL_REC_STEREO);
strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
sizeof(alsa_handle.useCase));
} else {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
- sizeof(alsa_handle.useCase));
+ if (*format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL,
+ sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
+ sizeof(alsa_handle.useCase));
+ }
}
- } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+ } else if (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
if (mFusion3Platform) {
mALSADevice->setVocRecMode(INCALL_REC_MONO);
strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
sizeof(alsa_handle.useCase));
} else {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
- sizeof(alsa_handle.useCase));
+ if (*format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL,
+ sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+ sizeof(alsa_handle.useCase));
+ }
}
}
#ifdef QCOM_FM_ENABLED
@@ -1227,37 +1459,50 @@
strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase));
#endif
} else {
- char value[128];
- property_get("persist.audio.lowlatency.rec",value,"0");
+ char value[128];
+ property_get("persist.audio.lowlatency.rec",value,"0");
if (!strcmp("true", value)) {
strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(alsa_handle.useCase));
+ } else if (*format == AUDIO_FORMAT_AMR_WB) {
+ ALOGV("Format AMR_WB, open compressed capture");
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, sizeof(alsa_handle.useCase));
} else {
strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(alsa_handle.useCase));
}
}
} else {
if ((devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
- (newMode == AudioSystem::MODE_IN_CALL)) {
+ (newMode == AUDIO_MODE_IN_CALL)) {
ALOGD("openInputStream: incall recording, channels %d", *channels);
mIncallMode = *channels;
- if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
- (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+ if ((*channels & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+ (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
if (mFusion3Platform) {
mALSADevice->setVocRecMode(INCALL_REC_STEREO);
strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
sizeof(alsa_handle.useCase));
} else {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
- sizeof(alsa_handle.useCase));
+ if (*format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL,
+ sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
+ sizeof(alsa_handle.useCase));
+ }
}
- } else if (*channels & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+ } else if (*channels & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
if (mFusion3Platform) {
mALSADevice->setVocRecMode(INCALL_REC_MONO);
strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_INCALL_REC,
sizeof(alsa_handle.useCase));
} else {
- strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
- sizeof(alsa_handle.useCase));
+ if (*format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL,
+ sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
+ sizeof(alsa_handle.useCase));
+ }
}
}
#ifdef QCOM_FM_ENABLED
@@ -1271,6 +1516,8 @@
property_get("persist.audio.lowlatency.rec",value,"0");
if (!strcmp("true", value)) {
strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(alsa_handle.useCase));
+ } else if (*format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, sizeof(alsa_handle.useCase));
} else {
strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase));
}
@@ -1283,13 +1530,14 @@
//update channel info before do routing
if(channels) {
it->channels = AudioSystem::popCount((*channels) &
- (AudioSystem::CHANNEL_IN_STEREO
- | AudioSystem::CHANNEL_IN_MONO
+ (AUDIO_CHANNEL_IN_STEREO
+ | AUDIO_CHANNEL_IN_MONO
#ifdef QCOM_SSR_ENABLED
- | AudioSystem::CHANNEL_IN_5POINT1
+ | AUDIO_CHANNEL_IN_5POINT1
#endif
));
ALOGV("updated channel info: channels=%d", it->channels);
+ setInChannels(devices);
}
if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
/* Add current devices info to devices to do route */
@@ -1320,12 +1568,15 @@
if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) ||
+ !strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) ||
#ifdef QCOM_FM_ENABLED
!strcmp(it->useCase, SND_USE_CASE_VERB_FM_REC) ||
!strcmp(it->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
#endif
!strcmp(it->useCase, SND_USE_CASE_VERB_DL_REC) ||
!strcmp(it->useCase, SND_USE_CASE_VERB_UL_DL_REC) ||
+ !strcmp(it->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL) ||
+ !strcmp(it->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL) ||
!strcmp(it->useCase, SND_USE_CASE_VERB_INCALL_REC)) {
snd_use_case_set(mUcMgr, "_verb", it->useCase);
} else {
@@ -1336,10 +1587,25 @@
}
if (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
|| !strncmp(it->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
- ALOGV("OpenInoutStream: Use larger buffer size for 5.1(%s) recording ", it->useCase);
+ ALOGV("OpenInoutStream: getInputBufferSize sampleRate:%d format:%d, channels:%d", it->sampleRate,*format,it->channels);
it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
}
+
+#ifdef QCOM_SSR_ENABLED
+ //Check if SSR is supported by reading system property
+ char ssr_enabled[6] = "false";
+ property_get("ro.qc.sdk.audio.ssr",ssr_enabled,"0");
+ if (strncmp("true", ssr_enabled, 4)) {
+ if (status) *status = err;
+ ALOGE("openInputStream: FAILED:%d. Surround sound recording is not supported",*status);
+ return in;
+ }
+#endif
err = mALSADevice->open(&(*it));
+ if (*format == AUDIO_FORMAT_AMR_WB) {
+ ALOGV("### Setting bufsize to 61");
+ it->bufferSize = 61;
+ }
if (err) {
ALOGE("Error opening pcm input device");
} else {
@@ -1359,11 +1625,28 @@
status_t AudioHardwareALSA::setMicMute(bool state)
{
- if (mMicMute != state) {
- mMicMute = state;
- ALOGD("setMicMute: mMicMute %d", mMicMute);
- if(mALSADevice) {
- mALSADevice->setMicMute(state);
+ int newMode = mode();
+ ALOGD("setMicMute newMode %d state:%d",newMode,state);
+ if(newMode == AUDIO_MODE_IN_COMMUNICATION) {
+ if (mVoipMicMute != state) {
+ mVoipMicMute = state;
+ ALOGD("setMicMute: mVoipMicMute %d", mVoipMicMute);
+ if(mALSADevice) {
+ mALSADevice->setVoipMicMute(state);
+ }
+ }
+ } else {
+ if (mMicMute != state) {
+ mMicMute = state;
+ ALOGD("setMicMute: mMicMute %d", mMicMute);
+ if(mALSADevice) {
+ if(mCSCallActive == CS_ACTIVE)
+ mALSADevice->setMicMute(state);
+ else if(mSGLTECallActive == CS_ACTIVE_SESSION2)
+ mALSADevice->setSGLTEMicMute(state);
+ if(mVolteCallActive == IMS_ACTIVE)
+ mALSADevice->setVoLTEMicMute(state);
+ }
}
}
return NO_ERROR;
@@ -1371,7 +1654,12 @@
status_t AudioHardwareALSA::getMicMute(bool *state)
{
- *state = mMicMute;
+ int newMode = mode();
+ if(newMode == AUDIO_MODE_IN_COMMUNICATION) {
+ *state = mVoipMicMute;
+ } else {
+ *state = mMicMute;
+ }
return NO_ERROR;
}
@@ -1383,7 +1671,7 @@
size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
{
size_t bufferSize = 0;
- if (format == AudioSystem::PCM_16_BIT) {
+ if (format == AUDIO_FORMAT_PCM_16_BIT) {
if(sampleRate == 8000 || sampleRate == 16000 || sampleRate == 32000) {
bufferSize = (sampleRate * channelCount * 20 * sizeof(int16_t)) / 1000;
} else if (sampleRate == 11025 || sampleRate == 12000) {
@@ -1402,7 +1690,9 @@
#ifdef QCOM_FM_ENABLED
void AudioHardwareALSA::handleFm(int device)
{
-int newMode = mode();
+ int newMode = mode();
+ uint32_t activeUsecase = USECASE_NONE;
+
if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) {
// Start FM Radio on current active device
unsigned long bufferSize = FM_BUFFER_SIZE;
@@ -1433,12 +1723,6 @@
mDeviceList.push_back(alsa_handle);
ALSAHandleList::iterator it = mDeviceList.end();
it--;
- if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
- (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
- device |= AudioSystem::DEVICE_OUT_PROXY;
- alsa_handle.devices = AudioSystem::DEVICE_OUT_PROXY;
- ALOGD("Routing to proxy for FM case");
- }
mALSADevice->route(&(*it), (uint32_t)device, newMode);
if(!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) {
snd_use_case_set(mUcMgr, "_verb", SND_USE_CASE_VERB_DIGITAL_RADIO);
@@ -1446,12 +1730,25 @@
snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM);
}
mALSADevice->startFm(&(*it));
+ activeUsecase = useCaseStringToEnum(it->useCase);
+#ifdef QCOM_USBAUDIO_ENABLED
if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
ALOGD("Starting FM, musbPlaybackState %d", musbPlaybackState);
startUsbPlaybackIfNotStarted();
musbPlaybackState |= USBPLAYBACKBIT_FM;
}
+#endif
+ if(device & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ status_t err = NO_ERROR;
+ mRouteAudioToA2dp = true;
+ err = startA2dpPlayback_l(activeUsecase);
+ if(err) {
+ ALOGE("startA2dpPlayback_l for hardware output failed err = %d", err);
+ stopA2dpPlayback_l(activeUsecase);
+ }
+ }
+
} else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) {
//i Stop FM Radio
ALOGV("Stop FM");
@@ -1460,17 +1757,27 @@
if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
(!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
mALSADevice->close(&(*it));
+ activeUsecase = useCaseStringToEnum(it->useCase);
//mALSADevice->route(&(*it), (uint32_t)device, newMode);
mDeviceList.erase(it);
break;
}
}
mIsFmActive = 0;
+#ifdef QCOM_USBAUDIO_ENABLED
musbPlaybackState &= ~USBPLAYBACKBIT_FM;
if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
closeUsbPlaybackIfNothingActive();
}
+#endif
+ if(mRouteAudioToA2dp == true) {
+ status_t err = NO_ERROR;
+ err = stopA2dpPlayback_l(activeUsecase);
+ if(err)
+ ALOGE("stopA2dpPlayback_l for hardware output failed err = %d", err);
+ }
+
}
}
#endif
@@ -1488,6 +1795,8 @@
break;
}
}
+ mIsVoicePathActive = false;
+
#ifdef QCOM_USBAUDIO_ENABLED
if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) {
ALOGD("Voice call ended on USB");
@@ -1527,13 +1836,7 @@
mDeviceList.push_back(alsa_handle);
ALSAHandleList::iterator it = mDeviceList.end();
it--;
-#ifdef QCOM_USBAUDIO_ENABLED
- if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
- (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
- device |= AudioSystem::DEVICE_OUT_PROXY;
- alsa_handle.devices = device;
- }
-#endif
+ setInChannels(device);
mALSADevice->route(&(*it), (uint32_t)device, mode);
if (!strcmp(it->useCase, verb)) {
snd_use_case_set(mUcMgr, "_verb", verb);
@@ -1541,6 +1844,8 @@
snd_use_case_set(mUcMgr, "_enamod", modifier);
}
mALSADevice->startVoiceCall(&(*it));
+ mIsVoicePathActive = true;
+
#ifdef QCOM_USBAUDIO_ENABLED
if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
@@ -1613,6 +1918,70 @@
}
return isRouted;
}
+
+bool AudioHardwareALSA::routeSGLTECall(int device, int newMode)
+{
+int SGLTECallState = mCallState&0xF00;
+ bool isRouted = false;
+ switch (SGLTECallState) {
+ case CS_INACTIVE_SESSION2:
+ if (mSGLTECallActive != CS_INACTIVE_SESSION2) {
+ ALOGV("doRouting: Disabling voice call session2");
+ disableVoiceCall((char *)SND_USE_CASE_VERB_SGLTECALL,
+ (char *)SND_USE_CASE_MOD_PLAY_SGLTE, newMode, device);
+ isRouted = true;
+ mSGLTECallActive = CS_INACTIVE_SESSION2;
+ }
+ break;
+ case CS_ACTIVE_SESSION2:
+ if (mSGLTECallActive == CS_INACTIVE_SESSION2) {
+ ALOGV("doRouting: Enabling CS voice call session2 ");
+ enableVoiceCall((char *)SND_USE_CASE_VERB_SGLTECALL,
+ (char *)SND_USE_CASE_MOD_PLAY_SGLTE, newMode, device);
+ isRouted = true;
+ mSGLTECallActive = CS_ACTIVE_SESSION2;
+ } else if (mSGLTECallActive == CS_HOLD_SESSION2) {
+ ALOGV("doRouting: Resume voice call session2 from hold state");
+ ALSAHandleList::iterator vt_it;
+ for(vt_it = mDeviceList.begin();
+ vt_it != mDeviceList.end(); ++vt_it) {
+ if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_SGLTECALL,
+ strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+ (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_SGLTE)))) {
+ alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+ mSGLTECallActive = CS_ACTIVE_SESSION2;
+ if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
+ ALOGE("SGLTE resume failed");
+ break;
+ }
+ }
+ }
+ break;
+ case CS_HOLD_SESSION2:
+ if (mSGLTECallActive == CS_ACTIVE_SESSION2) {
+ ALOGV("doRouting: Voice call session2 going to Hold");
+ ALSAHandleList::iterator vt_it;
+ for(vt_it = mDeviceList.begin();
+ vt_it != mDeviceList.end(); ++vt_it) {
+ if((!strncmp(vt_it->useCase, SND_USE_CASE_VERB_SGLTECALL,
+ strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+ (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_SGLTE)))) {
+ mSGLTECallActive = CS_HOLD_SESSION2;
+ alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+ if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
+ ALOGE("Voice session2 pause failed");
+ break;
+ }
+ }
+ }
+ break;
+ }
+ return isRouted;
+}
+
+
bool AudioHardwareALSA::routeVoLTECall(int device, int newMode)
{
int volteCallState = mCallState&0xF0;
@@ -1675,4 +2044,378 @@
return isRouted;
}
+void AudioHardwareALSA::pauseIfUseCaseTunnelOrLPA() {
+ for (ALSAHandleList::iterator it = mDeviceList.begin();
+ it != mDeviceList.end(); it++) {
+ if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+ strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA,
+ strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+ it->session->pause_l();
+ }
+ }
+}
+
+void AudioHardwareALSA::resumeIfUseCaseTunnelOrLPA() {
+ for (ALSAHandleList::iterator it = mDeviceList.begin();
+ it != mDeviceList.end(); it++) {
+ if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+ strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA,
+ strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+ it->session->resume_l();
+ }
+ }
+}
+
+status_t AudioHardwareALSA::startA2dpPlayback(uint32_t activeUsecase) {
+
+ Mutex::Autolock autoLock(mLock);
+ status_t err = startA2dpPlayback_l(activeUsecase);
+ if(err) {
+ ALOGE("startA2dpPlayback_l = %d", err);
+ }
+ return err;
+}
+status_t AudioHardwareALSA::startA2dpPlayback_l(uint32_t activeUsecase) {
+
+ ALOGV("startA2dpPlayback_l::usecase = %d ", activeUsecase);
+ status_t err = NO_ERROR;
+
+ if (activeUsecase != USECASE_NONE && !mIsA2DPEnabled) {
+ //setA2DPActiveUseCases_l(activeUsecase);
+ Mutex::Autolock autolock1(mA2dpMutex);
+ err = mALSADevice->openProxyDevice();
+ if(err) {
+ ALOGE("openProxyDevice failed = %d", err);
+ }
+
+ err = openA2dpOutput();
+ if(err) {
+ ALOGE("openA2DPOutput failed = %d",err);
+ return err;
+ }
+
+ mKillA2DPThread = false;
+ err = pthread_create(&mA2dpThread, (const pthread_attr_t *) NULL,
+ a2dpThreadWrapper,
+ this);
+ if(err) {
+ ALOGE("thread create failed = %d", err);
+ return err;
+ }
+ mA2dpThreadAlive = true;
+ mIsA2DPEnabled = true;
+
+#ifdef OUTPUT_BUFFER_LOG
+ sprintf(outputfilename, "%s%d%s", outputfilename, number,".pcm");
+ outputBufferFile1 = fopen (outputfilename, "ab");
+ number++;
+#endif
+ }
+
+ setA2DPActiveUseCases_l(activeUsecase);
+ mALSADevice->resumeProxy();
+
+ ALOGV("A2DP signal");
+ mA2dpCv.signal();
+ return err;
+}
+
+status_t AudioHardwareALSA::stopA2dpPlayback(uint32_t activeUsecase) {
+ Mutex::Autolock autoLock(mLock);
+ status_t err = stopA2dpPlayback_l(activeUsecase);
+ if(err) {
+ ALOGE("stopA2dpPlayback = %d", err);
+ }
+ return err;
+}
+
+status_t AudioHardwareALSA::stopA2dpPlayback_l(uint32_t activeUsecase) {
+
+ ALOGV("stopA2dpPlayback = %d", activeUsecase);
+ status_t err = NO_ERROR;
+ suspendA2dpPlayback_l(activeUsecase);
+ {
+ Mutex::Autolock autolock1(mA2dpMutex);
+ ALOGV("stopA2dpPlayback getA2DPActiveUseCases_l = %d",
+ getA2DPActiveUseCases_l());
+
+ if(!getA2DPActiveUseCases_l()) {
+ mIsA2DPEnabled = false;
+
+ mA2dpMutex.unlock();
+ err = stopA2dpThread();
+ mA2dpMutex.lock();
+
+ if(err) {
+ ALOGE("stopA2dpOutput = %d" ,err);
+ }
+
+ err = closeA2dpOutput();
+ if(err) {
+ ALOGE("closeA2dpOutput = %d" ,err);
+ }
+
+ err = mALSADevice->closeProxyDevice();
+ if(err) {
+ ALOGE("closeProxyDevice failed = %d", err);
+ }
+
+ mA2DPActiveUseCases = 0x0;
+ mRouteAudioToA2dp = false;
+
+#ifdef OUTPUT_BUFFER_LOG
+ ALOGV("close file output");
+ fclose (outputBufferFile1);
+#endif
+ }
+ }
+ return err;
+}
+
+status_t AudioHardwareALSA::openA2dpOutput()
+{
+ hw_module_t *mod;
+ int format = AUDIO_FORMAT_PCM_16_BIT;
+ uint32_t channels = AUDIO_CHANNEL_OUT_STEREO;
+ uint32_t sampleRate = AFE_PROXY_SAMPLE_RATE;
+ status_t status;
+ ALOGV("openA2dpOutput");
+ struct audio_config config;
+ config.sample_rate = AFE_PROXY_SAMPLE_RATE;
+ config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
+ config.format = AUDIO_FORMAT_PCM_16_BIT;
+
+ //TODO : Confirm AUDIO_HARDWARE_MODULE_ID_A2DP ???
+ int rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID/*_A2DP*/, (const char*)"a2dp",
+ (const hw_module_t**)&mod);
+ if (rc) {
+ ALOGE("Could not get a2dp hardware module");
+ return NO_INIT;
+ }
+
+ rc = audio_hw_device_open(mod, &mA2dpDevice);
+ if(rc) {
+ ALOGE("couldn't open a2dp audio hw device");
+ return NO_INIT;
+ }
+ //TODO: unique id 0?
+ status = mA2dpDevice->open_output_stream(mA2dpDevice, 0,((audio_devices_t)(AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP)),
+ (audio_output_flags_t)AUDIO_OUTPUT_FLAG_NONE, &config, &mA2dpStream);
+ if(status != NO_ERROR) {
+ ALOGE("Failed to open output stream for a2dp: status %d", status);
+ }
+ return status;
+}
+
+status_t AudioHardwareALSA::closeA2dpOutput()
+{
+ ALOGV("closeA2dpOutput");
+ if(!mA2dpDevice){
+ ALOGE("No Aactive A2dp output found");
+ return NO_ERROR;
+ }
+
+ mA2dpDevice->close_output_stream(mA2dpDevice, mA2dpStream);
+ mA2dpStream = NULL;
+
+ audio_hw_device_close(mA2dpDevice);
+ mA2dpDevice = NULL;
+ return NO_ERROR;
+}
+
+status_t AudioHardwareALSA::stopA2dpThread()
+{
+ ALOGV("stopA2dpThread");
+ status_t err = NO_ERROR;
+ if (!mA2dpThreadAlive) {
+ ALOGD("Return - thread not live");
+ return NO_ERROR;
+ }
+ mKillA2DPThread = true;
+ err = mALSADevice->exitReadFromProxy();
+ if(err) {
+ ALOGE("exitReadFromProxy failed = %d", err);
+ }
+ mA2dpCv.signal();
+ int ret = pthread_join(mA2dpThread,NULL);
+ ALOGD("a2dp thread killed = %d", ret);
+ return err;
+}
+
+void *AudioHardwareALSA::a2dpThreadWrapper(void *me) {
+ static_cast<AudioHardwareALSA *>(me)->a2dpThreadFunc();
+ return NULL;
+}
+
+void AudioHardwareALSA::a2dpThreadFunc() {
+ if(!mA2dpStream) {
+ ALOGE("No valid a2dp output stream found");
+ return;
+ }
+ if(!mALSADevice->isProxyDeviceOpened()) {
+ ALOGE("No valid mProxyPcmHandle found");
+ return;
+ }
+
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"A2DPThread", 0, 0, 0);
+
+ int ionBufCount = 0;
+ uint32_t bytesWritten = 0;
+ uint32_t numBytesRemaining = 0;
+ uint32_t bytesAvailInBuffer = 0;
+ void *data;
+ int err = NO_ERROR;
+ ssize_t size = 0;
+
+ mALSADevice->resetProxyVariables();
+
+ ALOGV("mKillA2DPThread = %d", mKillA2DPThread);
+ while(!mKillA2DPThread) {
+
+ {
+ Mutex::Autolock autolock1(mA2dpMutex);
+ if (!mA2dpStream || !mIsA2DPEnabled ||
+ !mALSADevice->isProxyDeviceOpened() ||
+ (mALSADevice->isProxyDeviceSuspended()) ||
+ (err != NO_ERROR)) {
+ ALOGD("A2DPThreadEntry:: proxy opened = %d,\
+ proxy suspended = %d,err =%d,\
+ mA2dpStream = %p",\
+ mALSADevice->isProxyDeviceOpened(),\
+ mALSADevice->isProxyDeviceSuspended(),err,mA2dpStream);
+ ALOGD("A2DPThreadEntry:: Waiting on mA2DPCv");
+ mA2dpCv.wait(mA2dpMutex);
+ ALOGD("A2DPThreadEntry:: received signal to wake up");
+ mA2dpMutex.unlock();
+ continue;
+ }
+ }
+ err = mALSADevice->readFromProxy(&data, &size);
+ if(err < 0) {
+ ALOGE("ALSADevice readFromProxy returned err = %d,data = %p,\
+ size = %ld", err, data, size);
+ continue;
+ }
+
+#ifdef OUTPUT_BUFFER_LOG
+ if (outputBufferFile1)
+ {
+ fwrite (data,1,size,outputBufferFile1);
+ }
+#endif
+ void *copyBuffer = data;
+ numBytesRemaining = size;
+ while (err == OK && (numBytesRemaining > 0) && !mKillA2DPThread
+ && mIsA2DPEnabled ) {
+ {
+ Mutex::Autolock autolock1(mA2dpMutex);
+ bytesAvailInBuffer = mA2dpStream->common.get_buffer_size(&mA2dpStream->common);
+ }
+ uint32_t writeLen = bytesAvailInBuffer > numBytesRemaining ?
+ numBytesRemaining : bytesAvailInBuffer;
+ ALOGV("Writing %d bytes to A2DP ", writeLen);
+ {
+ Mutex::Autolock autolock1(mA2dpMutex);
+ bytesWritten = mA2dpStream->write(mA2dpStream,copyBuffer, writeLen);
+ }
+ ALOGV("bytesWritten = %d",bytesWritten);
+ //Need to check warning here - void used in arithmetic
+ copyBuffer = (char *)copyBuffer + bytesWritten;
+ numBytesRemaining -= bytesWritten;
+ ALOGV("@_@bytes To write2:%d",numBytesRemaining);
+ }
+ }
+
+ mALSADevice->resetProxyVariables();
+ mA2dpThreadAlive = false;
+ ALOGD("A2DP Thread is dying");
+}
+
+void AudioHardwareALSA::setA2DPActiveUseCases_l(uint32_t activeUsecase)
+{
+ mA2DPActiveUseCases |= activeUsecase;
+ ALOGD("mA2DPActiveUseCases = %u, activeUsecase = %u", mA2DPActiveUseCases, activeUsecase);
+}
+
+uint32_t AudioHardwareALSA::getA2DPActiveUseCases_l()
+{
+ ALOGD("getA2DPActiveUseCases_l: mA2DPActiveUseCases = %u", mA2DPActiveUseCases);
+ return mA2DPActiveUseCases;
+}
+
+void AudioHardwareALSA::clearA2DPActiveUseCases_l(uint32_t activeUsecase) {
+
+ mA2DPActiveUseCases &= ~activeUsecase;
+ ALOGD("clear - mA2DPActiveUseCases = %u, activeUsecase = %u", mA2DPActiveUseCases, activeUsecase);
+
+}
+
+uint32_t AudioHardwareALSA::useCaseStringToEnum(const char *usecase)
+{
+ ALOGV("useCaseStringToEnum usecase:%s",usecase);
+ uint32_t activeUsecase = USECASE_NONE;
+
+ if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+ strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+ (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_LPA,
+ strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+ activeUsecase = USECASE_HIFI_LOW_POWER;
+ } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+ (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) {
+ activeUsecase = USECASE_HIFI_TUNNEL;
+ } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
+ strlen(SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC )))||
+ (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
+ strlen(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)))) {
+ activeUsecase = USECASE_HIFI_LOWLATENCY;
+ } else if ((!strncmp(usecase, SND_USE_CASE_VERB_DIGITAL_RADIO,
+ strlen(SND_USE_CASE_VERB_DIGITAL_RADIO))) ||
+ (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_FM,
+ strlen(SND_USE_CASE_MOD_PLAY_FM)))||
+ (!strncmp(usecase, SND_USE_CASE_VERB_FM_REC,
+ strlen(SND_USE_CASE_VERB_FM_REC)))||
+ (!strncmp(usecase, SND_USE_CASE_MOD_CAPTURE_FM,
+ strlen(SND_USE_CASE_MOD_CAPTURE_FM)))){
+ activeUsecase = USECASE_FM;
+ } else if ((!strncmp(usecase, SND_USE_CASE_VERB_HIFI,
+ strlen(SND_USE_CASE_VERB_HIFI)))||
+ (!strncmp(usecase, SND_USE_CASE_MOD_PLAY_MUSIC,
+ strlen(SND_USE_CASE_MOD_PLAY_MUSIC)))) {
+ activeUsecase = USECASE_HIFI;
+ }
+ return activeUsecase;
+}
+
+bool AudioHardwareALSA::suspendA2dpPlayback(uint32_t activeUsecase) {
+
+ Mutex::Autolock autoLock(mLock);
+ suspendA2dpPlayback_l(activeUsecase);
+ return NO_ERROR;
+}
+
+bool AudioHardwareALSA::suspendA2dpPlayback_l(uint32_t activeUsecase) {
+
+ Mutex::Autolock autolock1(mA2dpMutex);
+ ALOGD("suspendA2dpPlayback_l activeUsecase = %d, mRouteAudioToA2dp = %d",\
+ activeUsecase, mRouteAudioToA2dp);
+ clearA2DPActiveUseCases_l(activeUsecase);
+ if((!getA2DPActiveUseCases_l()) && mIsA2DPEnabled )
+ return mALSADevice->suspendProxy();
+ return NO_ERROR;
+}
+
} // namespace android_audio_legacy
diff --git a/alsa_sound/AudioHardwareALSA.h b/alsa_sound/AudioHardwareALSA.h
index 932b18f..201e8ce 100644
--- a/alsa_sound/AudioHardwareALSA.h
+++ b/alsa_sound/AudioHardwareALSA.h
@@ -1,7 +1,7 @@
/* AudioHardwareALSA.h
**
** Copyright 2008-2010, Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -19,8 +19,6 @@
#ifndef ANDROID_AUDIO_HARDWARE_ALSA_H
#define ANDROID_AUDIO_HARDWARE_ALSA_H
-#define QCOM_CSDCLIENT_ENABLED 1
-
#include <utils/List.h>
#include <hardware_legacy/AudioHardwareBase.h>
@@ -30,15 +28,20 @@
#include <hardware/audio.h>
#include <utils/threads.h>
#include <dlfcn.h>
-
#ifdef QCOM_USBAUDIO_ENABLED
#include <AudioUsbALSA.h>
#endif
+#include <sys/poll.h>
+#include <sys/eventfd.h>
extern "C" {
- #include <sound/asound.h>
- #include "alsa_audio.h"
- #include "msm8960_use_cases.h"
+ #include <sound/asound.h>
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
+ #include <sound/compress_params.h>
+ #include <sound/compress_offload.h>
+#endif
+ #include "alsa_audio.h"
+ #include "msm8960_use_cases.h"
}
#include <hardware/hardware.h>
@@ -47,6 +50,7 @@
{
using android::List;
using android::Mutex;
+using android::Condition;
class AudioHardwareALSA;
/**
@@ -69,7 +73,11 @@
#define PLAYBACK_LOW_LATENCY_BUFFER_SIZE 1024
#define PLAYBACK_LOW_LATENCY 22000
#define PLAYBACK_LOW_LATENCY_MEASURED 42000
+#ifdef TARGET_8974
+#define DEFAULT_IN_BUFFER_SIZE 512
+#else
#define DEFAULT_IN_BUFFER_SIZE 320
+#endif
#define MIN_CAPTURE_BUFFER_SIZE_PER_CH 320
#define MAX_CAPTURE_BUFFER_SIZE_PER_CH 2048
#define FM_BUFFER_SIZE 1024
@@ -92,6 +100,7 @@
#define DUALMIC_KEY "dualmic_enabled"
#define FLUENCE_KEY "fluence"
+#define VOIPCHECK_KEY "voip_flag"
#define ANC_KEY "anc_enabled"
#define TTY_MODE_KEY "tty_mode"
#define BT_SAMPLERATE_KEY "bt_samplerate"
@@ -101,6 +110,7 @@
#define FENS_KEY "fens_enable"
#define ST_KEY "st_enable"
#define INCALLMUSIC_KEY "incall_music_enabled"
+#define VOICE_PATH_ACTIVE "voice_path_active"
#define ANC_FLAG 0x00000001
#define DMIC_FLAG 0x00000002
@@ -123,6 +133,7 @@
static int USBPLAYBACKBIT_VOIPCALL = (1 << 2);
static int USBPLAYBACKBIT_FM = (1 << 3);
static int USBPLAYBACKBIT_LPA = (1 << 4);
+static int USBPLAYBACKBIT_TUNNEL = (1 << 5);
static int USBRECBIT_REC = (1 << 0);
static int USBRECBIT_VOICECALL = (1 << 1);
@@ -143,10 +154,20 @@
#endif
#define MODE_CALL_KEY "CALL_KEY"
+#ifndef ALSA_DEFAULT_SAMPLE_RATE
+#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz
+#endif
-struct alsa_device_t;
+#define NUM_FDS 2
+#define AFE_PROXY_SAMPLE_RATE 48000
+#define AFE_PROXY_CHANNEL_COUNT 2
+
+#define MAX_SLEEP_RETRY 100 /* Will check 100 times before continuing */
+#define AUDIO_INIT_SLEEP_WAIT 50 /* 50 ms */
+
static uint32_t FLUENCE_MODE_ENDFIRE = 0;
static uint32_t FLUENCE_MODE_BROADSIDE = 1;
+class ALSADevice;
enum {
INCALL_REC_MONO,
@@ -157,28 +178,60 @@
CS_INACTIVE = 0x0,
CS_ACTIVE = 0x1,
CS_HOLD = 0x2,
+ CS_INACTIVE_SESSION2 = 0x0,
+ CS_ACTIVE_SESSION2 = 0x100,
+ CS_HOLD_SESSION2 = 0x200,
IMS_INACTIVE = 0x0,
IMS_ACTIVE = 0x10,
IMS_HOLD = 0x20
};
-
+class AudioSessionOutALSA;
struct alsa_handle_t {
- alsa_device_t * module;
+ ALSADevice* module;
uint32_t devices;
char useCase[MAX_STR_LEN];
struct pcm * handle;
snd_pcm_format_t format;
uint32_t channels;
uint32_t sampleRate;
+ int mode;
unsigned int latency; // Delay in usec
unsigned int bufferSize; // Size of sample buffer
unsigned int periodSize;
- bool isDeepbufferOutput;
+ bool isFastOutput;
struct pcm * rxHandle;
snd_use_case_mgr_t *ucMgr;
+ AudioSessionOutALSA *session;
};
+struct output_metadata_handle_t {
+ uint32_t metadataLength;
+ uint32_t bufferLength;
+ uint64_t timestamp;
+ uint32_t reserved[12];
+};
+typedef struct buf_info;
+
+/** Structure to save buffer information for applying effects for
+ * LPA buffers */
+struct buf_info {
+ int bufsize;
+ int nBufs;
+ int **buffers;
+};
+
+#ifdef __cplusplus
+/**
+ *Observer class to post the Events from HAL to Flinger
+*/
+class AudioEventObserver {
+public:
+ virtual ~AudioEventObserver() {}
+ virtual void postEOS(int64_t delayUs) = 0;
+};
+#endif
+
typedef List < alsa_handle_t > ALSAHandleList;
struct use_case_t {
@@ -187,39 +240,119 @@
typedef List < use_case_t > ALSAUseCaseList;
-struct alsa_device_t {
- hw_device_t common;
+class ALSADevice
+{
- status_t (*init)(alsa_device_t *, ALSAHandleList &);
- status_t (*open)(alsa_handle_t *);
- status_t (*close)(alsa_handle_t *);
- status_t (*standby)(alsa_handle_t *);
- status_t (*route)(alsa_handle_t *, uint32_t, int);
- status_t (*startVoiceCall)(alsa_handle_t *);
- status_t (*startVoipCall)(alsa_handle_t *);
- status_t (*startFm)(alsa_handle_t *);
- void (*setVoiceVolume)(int);
- void (*setVoipVolume)(int);
- void (*setMicMute)(int);
- void (*setVoipMicMute)(int);
- void (*setVoipConfig)(int, int);
- status_t (*setFmVolume)(int);
- void (*setBtscoRate)(int);
- status_t (*setLpaVolume)(int);
- void (*enableWideVoice)(bool);
- void (*enableFENS)(bool);
- void (*setFlags)(uint32_t);
- status_t (*setCompressedVolume)(int);
- void (*enableSlowTalk)(bool);
- void (*setVocRecMode)(uint8_t);
- void (*setVoLTEMicMute)(int);
- void (*setVoLTEVolume)(int);
+public:
+
+ ALSADevice();
+ virtual ~ALSADevice();
+// status_t init(alsa_device_t *module, ALSAHandleList &list);
+ status_t open(alsa_handle_t *handle);
+ status_t close(alsa_handle_t *handle);
+ status_t standby(alsa_handle_t *handle);
+ status_t route(alsa_handle_t *handle, uint32_t devices, int mode);
+ status_t startVoiceCall(alsa_handle_t *handle);
+ status_t startVoipCall(alsa_handle_t *handle);
+ status_t startFm(alsa_handle_t *handle);
+ void setVoiceVolume(int volume);
+ void setVoipVolume(int volume);
+ void setMicMute(int state);
+ void setVoipMicMute(int state);
+ void setVoipConfig(int mode, int rate);
+ status_t setFmVolume(int vol);
+ void setBtscoRate(int rate);
+ status_t setLpaVolume(int vol);
+ void enableWideVoice(bool flag);
+ void enableFENS(bool flag);
+ void setFlags(uint32_t flag);
+ status_t setCompressedVolume(int vol);
+ void enableSlowTalk(bool flag);
+ void setVocRecMode(uint8_t mode);
+ void setVoLTEMicMute(int state);
+ void setVoLTEVolume(int vol);
+ void setSGLTEMicMute(int state);
+ void setSGLTEVolume(int vol);
+ status_t setEcrxDevice(char *device);
+ void setInChannels(int);
+ //TODO:check if this needs to be public
+ void disableDevice(alsa_handle_t *handle);
+ char *getUCMDeviceFromAcdbId(int acdb_id);
#ifdef SEPERATED_AUDIO_INPUT
- void (*setInput)(int);
+ void setInput(int);
#endif
#ifdef QCOM_CSDCLIENT_ENABLED
- void (*setCsdHandle)(void*);
+ void setCsdHandle(void*);
#endif
+
+protected:
+ friend class AudioHardwareALSA;
+private:
+ void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode);
+ int getUseCaseType(const char *useCase);
+ status_t setHDMIChannelCount();
+ status_t setHardwareParams(alsa_handle_t *handle);
+ int deviceName(alsa_handle_t *handle, unsigned flags, char **value);
+ status_t setSoftwareParams(alsa_handle_t *handle);
+ bool platform_is_Fusion3();
+ status_t getMixerControl(const char *name, unsigned int &value, int index = 0);
+ status_t setMixerControl(const char *name, unsigned int value, int index = -1);
+ status_t setMixerControl(const char *name, const char *);
+ status_t setMixerControlExt(const char *name, int count, char **setValues);
+ char * getUCMDevice(uint32_t devices, int input, char *rxDevice);
+ status_t start(alsa_handle_t *handle);
+
+ status_t openProxyDevice();
+ status_t closeProxyDevice();
+ bool isProxyDeviceOpened();
+ bool isProxyDeviceSuspended();
+ bool suspendProxy();
+ bool resumeProxy();
+ void resetProxyVariables();
+ ssize_t readFromProxy(void **captureBuffer , ssize_t *bufferSize);
+ status_t exitReadFromProxy();
+ void initProxyParams();
+ status_t startProxy();
+
+private:
+ char mMicType[25];
+ char mCurRxUCMDevice[50];
+ char mCurTxUCMDevice[50];
+ uint32_t mFluenceMode;
+ int mFmVolume;
+ uint32_t mDevSettingsFlag;
+ int mBtscoSamplerate;
+ ALSAUseCaseList mUseCaseList;
+ void *mcsd_handle;
+ int mCallMode;
+ struct mixer* mMixer;
+ int mInChannels;
+ bool mIsSglte;
+#ifdef SEPERATED_AUDIO_INPUT
+ int mInput_source
+#endif
+// ALSAHandleList *mDeviceList;
+
+ struct proxy_params {
+ bool mExitRead;
+ struct pcm *mProxyPcmHandle;
+ uint32_t mCaptureBufferSize;
+ void *mCaptureBuffer;
+ enum {
+ EProxyClosed = 0,
+ EProxyOpened = 1,
+ EProxySuspended = 2,
+ EProxyCapture = 3,
+ };
+
+ uint32_t mProxyState;
+ struct snd_xferi mX;
+ unsigned mAvail;
+ struct pollfd mPfdProxy[NUM_FDS];
+ long mFrames;
+ };
+ struct proxy_params mProxyParams;
+
};
// ----------------------------------------------------------------------------
@@ -244,21 +377,6 @@
};
-class ALSAControl
-{
-public:
- ALSAControl(const char *device = "/dev/snd/controlC0");
- virtual ~ALSAControl();
-
- status_t get(const char *name, unsigned int &value, int index = 0);
- status_t set(const char *name, unsigned int value, int index = -1);
- status_t set(const char *name, const char *);
- status_t setext(const char *name, int count, char **setValues);
-
-private:
- struct mixer* mHandle;
-};
-
class ALSAStreamOps
{
public:
@@ -337,11 +455,155 @@
private:
uint32_t mFrameCount;
+ uint32_t mUseCase;
protected:
AudioHardwareALSA * mParent;
};
+// ----------------------------------------------------------------------------
+
+class AudioSessionOutALSA : public AudioStreamOut
+{
+public:
+ AudioSessionOutALSA(AudioHardwareALSA *parent,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t samplingRate,
+ int type,
+ status_t *status);
+ virtual ~AudioSessionOutALSA();
+
+ virtual uint32_t sampleRate() const
+ {
+ return mSampleRate;
+ }
+
+ virtual size_t bufferSize() const
+ {
+ return mBufferSize;
+ }
+
+ virtual uint32_t channels() const
+ {
+ return mChannels;
+ }
+
+ virtual int format() const
+ {
+ return mFormat;
+ }
+
+ virtual uint32_t latency() const;
+
+ virtual ssize_t write(const void *buffer, size_t bytes);
+
+ virtual status_t start();
+ virtual status_t pause();
+ virtual status_t flush();
+ virtual status_t stop();
+
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+ status_t setVolume(float left, float right);
+
+ virtual status_t standby();
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+
+ virtual String8 getParameters(const String8& keys);
+
+
+ // return the number of audio frames written by the audio dsp to DAC since
+ // the output has exited standby
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ virtual status_t getNextWriteTimestamp(int64_t *timestamp);
+
+ virtual status_t setObserver(void *observer);
+
+ virtual status_t getBufferInfo(buf_info **buf);
+ virtual status_t isBufferAvailable(int *isAvail);
+ status_t pause_l();
+ status_t resume_l();
+
+ void updateMetaData(size_t bytes);
+
+private:
+ Mutex mLock;
+ uint32_t mFrameCount;
+ uint32_t mSampleRate;
+ uint32_t mChannels;
+ size_t mBufferSize;
+ int mFormat;
+ uint32_t mStreamVol;
+
+ bool mPaused;
+ bool mSeeking;
+ bool mReachedEOS;
+ bool mSkipWrite;
+ bool mEosEventReceived;
+ AudioHardwareALSA *mParent;
+ alsa_handle_t * mAlsaHandle;
+ ALSADevice * mAlsaDevice;
+ snd_use_case_mgr_t *mUcMgr;
+ AudioEventObserver *mObserver;
+ output_metadata_handle_t mOutputMetadataTunnel;
+ uint32_t mOutputMetadataLength;
+ uint32_t mUseCase;
+ status_t openDevice(char *pUseCase, bool bIsUseCase, int devices);
+
+ status_t closeDevice(alsa_handle_t *pDevice);
+ void createEventThread();
+ void bufferAlloc(alsa_handle_t *handle);
+ void bufferDeAlloc();
+ bool isReadyToPostEOS(int errPoll, void *fd);
+ status_t drain();
+ status_t openAudioSessionDevice(int type, int devices);
+ // make sure the event thread also exited
+ void requestAndWaitForEventThreadExit();
+ int32_t writeToDriver(char *buffer, int bytes);
+ static void * eventThreadWrapper(void *me);
+ void eventThreadEntry();
+ void reset();
+
+ //Structure to hold mem buffer information
+ class BuffersAllocated {
+ public:
+ BuffersAllocated(void *buf1, int32_t nSize) :
+ memBuf(buf1), memBufsize(nSize), bytesToWrite(0)
+ {}
+ void* memBuf;
+ int32_t memBufsize;
+ uint32_t bytesToWrite;
+ };
+ List<BuffersAllocated> mEmptyQueue;
+ List<BuffersAllocated> mFilledQueue;
+ List<BuffersAllocated> mBufPool;
+
+ //Declare all the threads
+ pthread_t mEventThread;
+
+ //Declare the condition Variables and Mutex
+ Mutex mEmptyQueueMutex;
+ Mutex mFilledQueueMutex;
+
+ Condition mWriteCv;
+ Condition mEventCv;
+ bool mKillEventThread;
+ bool mEventThreadAlive;
+ int mInputBufferSize;
+ int mInputBufferCount;
+
+ //event fd to signal the EOS and Kill from the userspace
+ int mEfd;
+
+public:
+ bool mRouteAudioToA2dp;
+};
+
+
class AudioStreamInALSA : public AudioStreamIn, public ALSAStreamOps
{
public:
@@ -414,14 +676,14 @@
private:
void resetFramesLost();
-#ifdef QCOM_CSDCLIENT_ENABLED
- int start_csd_record(int);
- int stop_csd_record(void);
-#endif
-
unsigned int mFramesLost;
AudioSystem::audio_in_acoustics mAcoustics;
+#ifdef QCOM_CSDCLIENT_ENABLED
+ int start_csd_record(int param);
+ int stop_csd_record();
+#endif
+
#ifdef QCOM_SSR_ENABLED
// Function to read coefficients from files.
status_t readCoeffsFromFile();
@@ -485,22 +747,12 @@
// parameters is not supported
virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channels);
-#ifdef QCOM_TUNNEL_LPA_ENABLED
- /** This method creates and opens the audio hardware output
- * session for LPA */
- virtual AudioStreamOut* openOutputSession(
- uint32_t devices,
- int *format,
- status_t *status,
- int sessionId,
- uint32_t samplingRate=0,
- uint32_t channels=0);
- virtual void closeOutputSession(AudioStreamOut* out);
-#endif
-
/** This method creates and opens the audio hardware output stream */
virtual AudioStreamOut* openOutputStream(
uint32_t devices,
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+ audio_output_flags_t flags,
+#endif
int *format=0,
uint32_t *channels=0,
uint32_t *sampleRate=0,
@@ -517,6 +769,14 @@
AudioSystem::audio_in_acoustics acoustics);
virtual void closeInputStream(AudioStreamIn* in);
+ status_t startA2dpPlayback(uint32_t activeUsecase);
+ status_t stopA2dpPlayback(uint32_t activeUsecase);
+ bool suspendA2dpPlayback(uint32_t activeUsecase);
+
+ status_t startA2dpPlayback_l(uint32_t activeUsecase);
+ status_t stopA2dpPlayback_l(uint32_t activeUsecase);
+ bool suspendA2dpPlayback_l(uint32_t activeUsecase);
+
/**This method dumps the state of the audio hardware */
//virtual status_t dumpState(int fd, const Vector<String16>& args);
@@ -527,10 +787,24 @@
return mMode;
}
+ void pauseIfUseCaseTunnelOrLPA();
+ void resumeIfUseCaseTunnelOrLPA();
+
+private:
+ status_t openA2dpOutput();
+ status_t closeA2dpOutput();
+ status_t stopA2dpThread();
+ void a2dpThreadFunc();
+ static void* a2dpThreadWrapper(void *context);
+ void setA2DPActiveUseCases_l(uint32_t activeUsecase);
+ uint32_t getA2DPActiveUseCases_l();
+ void clearA2DPActiveUseCases_l(uint32_t activeUsecase);
+ uint32_t useCaseStringToEnum(const char *usecase);
+
protected:
virtual status_t dump(int fd, const Vector<String16>& args);
virtual uint32_t getVoipMode(int format);
- void doRouting(int device);
+ status_t doRouting(int device);
#ifdef QCOM_FM_ENABLED
void handleFm(int device);
#endif
@@ -542,16 +816,19 @@
void startUsbPlaybackIfNotStarted();
void startUsbRecordingIfNotStarted();
#endif
+ void setInChannels(int device);
void disableVoiceCall(char* verb, char* modifier, int mode, int device);
void enableVoiceCall(char* verb, char* modifier, int mode, int device);
bool routeVoiceCall(int device, int newMode);
bool routeVoLTECall(int device, int newMode);
+ bool routeSGLTECall(int device, int newMode);
+ friend class AudioSessionOutALSA;
friend class AudioStreamOutALSA;
friend class AudioStreamInALSA;
friend class ALSAStreamOps;
- alsa_device_t * mALSADevice;
+ ALSADevice* mALSADevice;
ALSAHandleList mDeviceList;
@@ -563,17 +840,19 @@
snd_use_case_mgr_t *mUcMgr;
- uint32_t mCurDevice;
+ int32_t mCurDevice;
/* The flag holds all the audio related device settings from
* Settings and Qualcomm Settings applications */
uint32_t mDevSettingsFlag;
uint32_t mVoipStreamCount;
+ bool mVoipMicMute;
uint32_t mVoipBitRate;
uint32_t mIncallMode;
bool mMicMute;
int mCSCallActive;
int mVolteCallActive;
+ int mSGLTECallActive;
int mCallState;
int mIsFmActive;
bool mBluetoothVGS;
@@ -582,8 +861,33 @@
int musbPlaybackState;
int musbRecordingState;
#endif
+ bool mIsVoicePathActive;
+
void *mAcdbHandle;
void *mCsdHandle;
+ //A2DP variables
+ audio_stream_out *mA2dpStream;
+ audio_hw_device_t *mA2dpDevice;
+
+ bool mKillA2DPThread;
+ bool mA2dpThreadAlive;
+ pthread_t mA2dpThread;
+ Mutex mA2dpMutex;
+ Condition mA2dpCv;
+ volatile bool mIsA2DPEnabled;
+
+ enum {
+ USECASE_NONE = 0x0,
+ USECASE_HIFI = 0x1,
+ USECASE_HIFI_LOWLATENCY = 0x2,
+ USECASE_HIFI_LOW_POWER = 0x4,
+ USECASE_HIFI_TUNNEL = 0x8,
+ USECASE_FM = 0x10,
+ };
+ uint32_t mA2DPActiveUseCases;
+
+public:
+ bool mRouteAudioToA2dp;
};
// ----------------------------------------------------------------------------
diff --git a/alsa_sound/AudioPolicyManagerALSA.cpp b/alsa_sound/AudioPolicyManagerALSA.cpp
old mode 100644
new mode 100755
index 98f8203..3345cb9
--- a/alsa_sound/AudioPolicyManagerALSA.cpp
+++ b/alsa_sound/AudioPolicyManagerALSA.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,11 +17,29 @@
#define LOG_TAG "AudioPolicyManagerALSA"
//#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
-#include <utils/Log.h>
+//#define LOG_NDDEBUG 0
+//#define VERY_VERBOSE_LOGGING
+#ifdef VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
+
+// A device mask for all audio input devices that are considered "virtual" when evaluating
+// active inputs in getActiveInput()
+#define APM_AUDIO_IN_DEVICE_VIRTUAL_ALL AUDIO_DEVICE_IN_REMOTE_SUBMIX
+
+#include <utils/Log.h>
#include "AudioPolicyManagerALSA.h"
+#include <hardware/audio_effect.h>
+#include <hardware/audio.h>
+#include <hardware_legacy/audio_policy_conf.h>
+#include <math.h>
#include <media/mediarecorder.h>
+#include <stdio.h>
+
+#define MAX_POLL_VOICE_SETUP 20
namespace android_audio_legacy {
@@ -29,11 +47,1201 @@
// AudioPolicyManagerALSA
// ----------------------------------------------------------------------------
-//Compiling error seen (only) on mako-pdk project if AudioParamer doesn't exist in this file
-//No issue is seen on QCOM jb-mailine if remvong this line
-//AudioParameter param;
+AudioParameter param;
-// --- class factory
+status_t AudioPolicyManager::setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+ SortedVector <audio_io_handle_t> outputs;
+
+ ALOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (!audio_is_output_device(device) && !audio_is_input_device(device)) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ ALOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (audio_is_output_device(device)) {
+
+ //Use QCOM's a2dp solution, no need to check here
+ /*if (!mHasA2dp && audio_is_a2dp_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid A2DP device: %x", device);
+ return BAD_VALUE;
+ }*/
+ if (!mHasUsb && audio_is_usb_device(device)) {
+ ALOGE("setDeviceConnectionState() invalid USB audio device: %x", device);
+ return BAD_VALUE;
+ }
+ if (!mHasRemoteSubmix && audio_is_remote_submix_device((audio_devices_t)device)) {
+ ALOGE("setDeviceConnectionState() invalid remote submix audio device: %x", device);
+ return BAD_VALUE;
+ }
+
+ // save a copy of the opened output descriptors before any output is opened or closed
+ // by checkOutputsForDevice(). This will be needed by checkOutputForAllStrategies()
+ mPreviousOutputs = mOutputs;
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+ if (mAvailableOutputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() connecting device %x", device);
+
+ if (checkOutputsForDevice(device, state, outputs) != NO_ERROR) {
+ return INVALID_OPERATION;
+ }
+ ALOGV("setDeviceConnectionState() checkOutputsForDevice() returned %d outputs",
+ outputs.size());
+ // register new device as available
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices | device);
+
+ if (audio_is_a2dp_device(device)) {
+ AudioParameter param;
+ param.add(String8("a2dp_connected"), String8("true"));
+ mpClientInterface->setParameters(0, param.toString());
+ }
+ if (!outputs.isEmpty()) {
+ String8 paramStr;
+ if (audio_is_a2dp_device(device)) {
+ // handle A2DP device connection
+ AudioParameter param;
+ param.add(String8(AUDIO_PARAMETER_A2DP_SINK_ADDRESS), String8(device_address));
+ paramStr = param.toString();
+ mA2dpDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ mA2dpSuspended = false;
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device connection
+ mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ } else if (mHasUsb && audio_is_usb_device(device)) {
+ // handle USB device connection
+ mUsbCardAndDevice = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+ paramStr = mUsbCardAndDevice;
+ }
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
+ if (!paramStr.isEmpty()) {
+ for (size_t i = 0; i < outputs.size(); i++) {
+ mpClientInterface->setParameters(outputs[i], paramStr);
+ }
+ }
+ }
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableOutputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+
+ ALOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices = (audio_devices_t)(mAvailableOutputDevices & ~device);
+
+ checkOutputsForDevice(device, state, outputs);
+ if (audio_is_a2dp_device(device)) {
+ // handle A2DP device disconnection
+ mA2dpDeviceAddress = "";
+ mA2dpSuspended = false;
+
+ AudioParameter param;
+ param.add(String8("a2dp_connected"), String8("false"));
+ mpClientInterface->setParameters(0, param.toString());
+
+ } else if (audio_is_bluetooth_sco_device(device)) {
+ // handle SCO device disconnection
+ mScoDeviceAddress = "";
+ } else if (mHasUsb && audio_is_usb_device(device)) {
+ // handle USB device disconnection
+ mUsbCardAndDevice = "";
+ }
+ // not currently handling multiple simultaneous submixes: ignoring remote submix
+ // case and address
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ // outputs must be closed after checkOutputForAllStrategies() is executed
+ if (!outputs.isEmpty()) {
+ for (size_t i = 0; i < outputs.size(); i++) {
+ // close unused outputs after device disconnection or direct outputs that have been
+ // opened by checkOutputsForDevice() to query dynamic parameters
+ if ((state == AudioSystem::DEVICE_STATE_UNAVAILABLE) ||
+ (mOutputs.valueFor(outputs[i])->mFlags & AUDIO_OUTPUT_FLAG_DIRECT)) {
+ closeOutput(outputs[i]);
+ }
+ }
+ }
+
+ updateDevicesAndOutputs();
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE &&
+ (mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY) &&
+ audio_is_a2dp_device(device) ) {
+ ALOGV("Delay the proxy device open");
+ return NO_ERROR;
+ }
+#endif
+
+#ifdef QCOM_FM_ENABLED
+ audio_devices_t newDevice = AudioPolicyManagerBase::getNewDevice(mPrimaryOutput, false /*fromCache*/);
+ if(device == AUDIO_DEVICE_OUT_FM) {
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ ALOGV("setDeviceConnectionState() changeRefCount Inc");
+ mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, 1);
+ }
+ else {
+ ALOGV("setDeviceConnectionState() changeRefCount Dec");
+ mOutputs.valueFor(mPrimaryOutput)->changeRefCount(AudioSystem::FM, -1);
+ }
+ if(newDevice == 0){
+ newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ }
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyHandleFm), (int)newDevice);
+ ALOGV("setDeviceConnectionState() setParameters handle_fm");
+ mpClientInterface->setParameters(mPrimaryOutput, param.toString());
+ }
+#endif
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ audio_devices_t newDevice = getNewDevice(mOutputs.keyAt(i), true /*fromCache*/);
+ if(device == AUDIO_DEVICE_OUT_ANC_HEADPHONE ||
+ device == AUDIO_DEVICE_OUT_ANC_HEADSET) {
+ if(newDevice == 0){
+ newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ }
+ }
+#endif
+ setOutputDevice(mOutputs.keyAt(i),
+ getNewDevice(mOutputs.keyAt(i), true /*fromCache*/),
+ true,
+ 0);
+ }
+
+ if (device == AUDIO_DEVICE_OUT_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+ } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+ device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if(device == AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET){
+ device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if(device == AUDIO_DEVICE_OUT_ANC_HEADSET){
+ device = AUDIO_DEVICE_IN_ANC_HEADSET; //wait for actual ANC device
+#endif
+ } else {
+ return NO_ERROR;
+ }
+ }
+ // handle input devices
+ if (audio_is_input_device(device)) {
+
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE: {
+ if (mAvailableInputDevices & device) {
+ ALOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = mAvailableInputDevices | (device & ~AUDIO_DEVICE_BIT_IN);
+ }
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableInputDevices & device)) {
+ ALOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices = (audio_devices_t) (mAvailableInputDevices & ~device);
+ } break;
+
+ default:
+ ALOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+ return NO_ERROR;
+ }
+
+ ALOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+
+AudioSystem::device_connection_state AudioPolicyManager::getDeviceConnectionState(audio_devices_t device,
+ const char *device_address)
+{
+ AudioSystem::device_connection_state state = AudioSystem::DEVICE_STATE_UNAVAILABLE;
+ String8 address = String8(device_address);
+ if (audio_is_output_device(device)) {
+ if (device & mAvailableOutputDevices) {
+ if (audio_is_a2dp_device(device) &&
+ ( (address != "" && mA2dpDeviceAddress != address))) {
+ return state;
+ }
+ if (audio_is_bluetooth_sco_device(device) &&
+ address != "" && mScoDeviceAddress != address) {
+ return state;
+ }
+ if (audio_is_usb_device(device) &&
+ (!mHasUsb || (address != "" && mUsbCardAndDevice != address))) {
+ ALOGE("getDeviceConnectionState() invalid device: %x", device);
+ return state;
+ }
+ if (audio_is_remote_submix_device((audio_devices_t)device) && !mHasRemoteSubmix) {
+ return state;
+ }
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ } else if (audio_is_input_device(device)) {
+ if (device & mAvailableInputDevices) {
+ state = AudioSystem::DEVICE_STATE_AVAILABLE;
+ }
+ }
+
+ return state;
+}
+
+
+void AudioPolicyManager::setPhoneState(int state)
+{
+ ALOGV("setPhoneState() state %d", state);
+ audio_devices_t newDevice = AUDIO_DEVICE_NONE;
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ ALOGW("setPhoneState() invalid state %d", state);
+ return;
+ }
+
+ if (state == mPhoneState ) {
+ ALOGW("setPhoneState() setting same state %d", state);
+ return;
+ }
+
+ // if leaving call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isInCall()) {
+ ALOGV("setPhoneState() in call state management: new state is %d", state);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ handleIncallSonification(stream, false, true);
+ }
+ }
+
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+ bool force = false;
+
+ // are we entering or starting a call
+ if (!isStateInCall(oldState) && isStateInCall(state)) {
+ ALOGV(" Entering call in setPhoneState()");
+ // force routing command to audio hardware when starting a call
+ // even if no device change is needed
+ force = true;
+ } else if (isStateInCall(oldState) && !isStateInCall(state)) {
+ ALOGV(" Exiting call in setPhoneState()");
+ // force routing command to audio hardware when exiting a call
+ // even if no device change is needed
+ force = true;
+ } else if (isStateInCall(state) && (state != oldState)) {
+ ALOGV(" Switching between telephony and VoIP in setPhoneState()");
+ // force routing command to audio hardware when switching between telephony and VoIP
+ // even if no device change is needed
+ force = true;
+ }
+
+ // check for device and output changes triggered by new phone state
+ // Need to update A2DP suspend first then getNewDevice(from cache)
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ updateDevicesAndOutputs();
+ newDevice = getNewDevice(mPrimaryOutput, false /*fromCache*/);
+
+ AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput);
+
+ // force routing command to audio hardware when ending call
+ // even if no device change is needed
+ if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) {
+ newDevice = hwOutputDesc->device();
+ }
+
+ // when changing from ring tone to in call mode, mute the ringing tone
+ // immediately and delay the route change to avoid sending the ring tone
+ // tail into the earpiece or headset.
+ int delayMs = 0;
+ if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) {
+ // delay the device change command by twice the output latency to have some margin
+ // and be sure that audio buffers not yet affected by the mute are out when
+ // we actually apply the route change
+ delayMs = hwOutputDesc->mLatency*2;
+ setStreamMute(AudioSystem::RING, true, mPrimaryOutput);
+ }
+
+ if (isStateInCall(state)) {
+
+ if(!isStateInCall(oldState)) {
+ audio_io_handle_t activeInput = getActiveInput();
+
+ /* Block the policy manager until voice path is setup. This is
+ * done to prevent telephony from signaling call connect before the
+ * entire voice path is established.
+ */
+ for (int i = 0; i < MAX_POLL_VOICE_SETUP; i++) {
+ usleep(100000);
+ String8 voiceActive = mpClientInterface->getParameters(activeInput,
+ String8("voice_path_active"));
+
+ if (!voiceActive.compare(String8("voice_path_active=true"))) {
+ ALOGV("setPhoneState: Voice path is active");
+ break;
+ } else {
+ ALOGV("setPhoneState: voice path is not active");
+ }
+ }
+ }
+
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ //take the biggest latency for all outputs
+ if (delayMs < desc->mLatency*2) {
+ delayMs = desc->mLatency*2;
+ }
+ //mute STRATEGY_MEDIA on all outputs
+ if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) {
+ setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i));
+ setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS,
+ getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/));
+ }
+ }
+ }
+
+ // change routing is necessary
+ setOutputDevice(mPrimaryOutput, newDevice, force, delayMs);
+
+ // if entering in call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isStateInCall(state)) {
+ ALOGV("setPhoneState() in call state management: new state is %d", state);
+ // unmute the ringing tone after a sufficient delay if it was muted before
+ // setting output device above
+ if (oldState == AudioSystem::MODE_RINGTONE) {
+ setStreamMute(AudioSystem::RING, false, mPrimaryOutput, MUTE_TIME_MS);
+ }
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ handleIncallSonification(stream, true, true);
+ }
+ }
+
+ // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
+ if (state == AudioSystem::MODE_RINGTONE &&
+ isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) {
+ mLimitRingtoneVolume = true;
+ } else {
+ mLimitRingtoneVolume = false;
+ }
+}
+
+
+void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ ALOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+ bool forceVolumeReeval = false;
+ switch(usage) {
+ case AudioSystem::FOR_COMMUNICATION:
+ if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+ return;
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_MEDIA:
+ if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK && config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_NO_BT_A2DP && config != AudioSystem::FORCE_SPEAKER) {
+ ALOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_RECORD:
+ if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_NONE) {
+ ALOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_DOCK:
+ if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+ config != AudioSystem::FORCE_BT_DESK_DOCK &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_ANALOG_DOCK &&
+ config != AudioSystem::FORCE_DIGITAL_DOCK) {
+ ALOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_SYSTEM:
+ if (config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_SYSTEM_ENFORCED) {
+ ALOGW("setForceUse() invalid config %d for FOR_SYSTEM", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ default:
+ ALOGW("setForceUse() invalid usage %d", usage);
+ break;
+ }
+
+ // check for device and output changes triggered by new force usage
+ checkA2dpSuspend();
+ checkOutputForAllStrategies();
+ updateDevicesAndOutputs();
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t output = mOutputs.keyAt(i);
+ audio_devices_t newDevice = getNewDevice(output, true /*fromCache*/);
+ setOutputDevice(output, newDevice, (newDevice != AUDIO_DEVICE_NONE));
+ if (forceVolumeReeval && (newDevice != AUDIO_DEVICE_NONE)) {
+ applyStreamVolumes(output, newDevice, 0, true);
+ }
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ audio_devices_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if ((newDevice != AUDIO_DEVICE_NONE) && (newDevice != inputDesc->mDevice)) {
+ ALOGV("setForceUse() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+}
+
+
+status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ ALOGV("startOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("startOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // increment usage count for this stream on the requested output:
+ // NOTE that the usage count is the same for duplicated output and hardware output which is
+ // necessary for a correct control of hardware output routing by startOutput() and stopOutput()
+ outputDesc->changeRefCount(stream, 1);
+
+ if (outputDesc->mRefCount[stream] == 1) {
+ audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ routing_strategy strategy = getStrategy(stream);
+ bool shouldWait = (strategy == STRATEGY_SONIFICATION) ||
+ (strategy == STRATEGY_SONIFICATION_RESPECTFUL);
+ uint32_t waitMs = 0;
+ uint32_t muteWaitMs = 0;
+ bool force = false;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (desc != outputDesc) {
+ // force a device change if any other output is managed by the same hw
+ // module and has a current device selection that differs from selected device.
+ // In this case, the audio HAL must receive the new device selection so that it can
+ // change the device currently selected by the other active output.
+ if (outputDesc->sharesHwModuleWith(desc) &&
+ desc->device() != newDevice) {
+ force = true;
+ }
+ // wait for audio on other active outputs to be presented when starting
+ // a notification so that audio focus effect can propagate.
+ if (shouldWait && (desc->refCount() != 0) && (waitMs < desc->latency())) {
+ waitMs = desc->latency();
+ }
+ }
+ }
+
+#ifdef QCOM_FM_ENABLED
+ if(stream == AudioSystem::FM && output == getA2dpOutput()) {
+ muteWaitMs = setOutputDevice(output, newDevice, true);
+ } else
+#endif
+ {
+ muteWaitMs = setOutputDevice(output, newDevice, force);
+ }
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ handleIncallSonification(stream, true, false);
+ }
+
+ // apply volume rules for current stream and device if necessary
+ checkAndSetVolume(stream,
+ mStreams[stream].getVolumeIndex(newDevice),
+ output,
+ newDevice);
+
+ // update the outputs if starting an output with a stream that can affect notification
+ // routing
+ handleNotificationRoutingForStream(stream);
+ if (waitMs > muteWaitMs) {
+ usleep((waitMs - muteWaitMs) * 2 * 1000);
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ ALOGW("stopOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ handleIncallSonification(stream, false, false);
+ }
+
+ if (outputDesc->mRefCount[stream] > 0) {
+ // decrement usage count of this stream on the output
+ outputDesc->changeRefCount(stream, -1);
+ // store time at which the stream was stopped - see isStreamActive()
+ if (outputDesc->mRefCount[stream] == 0) {
+ outputDesc->mStopTime[stream] = systemTime();
+ audio_devices_t newDevice = getNewDevice(output, false /*fromCache*/);
+ // delay the device switch by twice the latency because stopOutput() is executed when
+ // the track stop() command is received and at that time the audio track buffer can
+ // still contain data that needs to be drained. The latency only covers the audio HAL
+ // and kernel buffers. Also the latency does not always include additional delay in the
+ // audio path (audio DSP, CODEC ...)
+ setOutputDevice(output, newDevice, false, outputDesc->mLatency*2);
+
+ // force restoring the device selection on other active outputs if it differs from the
+ // one being selected for this output
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ audio_io_handle_t curOutput = mOutputs.keyAt(i);
+ AudioOutputDescriptor *desc = mOutputs.valueAt(i);
+ if (curOutput != output &&
+ desc->refCount() != 0 &&
+ outputDesc->sharesHwModuleWith(desc) &&
+ newDevice != desc->device()) {
+ setOutputDevice(curOutput,
+ getNewDevice(curOutput, false /*fromCache*/),
+ true,
+ outputDesc->mLatency*2);
+ }
+ }
+ // update the outputs if stopping one with a stream that can affect notification routing
+ handleNotificationRoutingForStream(stream);
+ }
+ return NO_ERROR;
+ } else {
+ ALOGW("stopOutput() refcount is already 0 for output %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+status_t AudioPolicyManager::startInput(audio_io_handle_t input)
+{
+ ALOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ ALOGW("startInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+#ifdef AUDIO_POLICY_TEST
+ if (mTestInput == 0)
+#endif //AUDIO_POLICY_TEST
+ {
+ // refuse 2 active AudioRecord clients at the same time
+ if (getActiveInput() != 0) {
+ ALOGW("startInput() input %d failed: other input already started", input);
+ return INVALID_OPERATION;
+ }
+ }
+
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+
+ param.addInt(String8(AudioParameter::keyInputSource), (int)inputDesc->mInputSource);
+
+ // use Voice Recognition mode or not for this input based on input source
+ int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0;
+ param.addInt(String8("vr_mode"), vr_enabled);
+ ALOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled);
+
+ mpClientInterface->setParameters(input, param.toString());
+
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ if (fromCache) {
+ ALOGVV("getDeviceForStrategy() from cache strategy %d, device %x",
+ strategy, mDeviceForStrategy[strategy]);
+ return mDeviceForStrategy[strategy];
+ }
+
+ switch (strategy) {
+
+ case STRATEGY_SONIFICATION_RESPECTFUL:
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ } else if (isStreamActive(AudioSystem::MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) {
+ // while media is playing (or has recently played), use the same device
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ } else {
+ // when media is not playing anymore, fall back on the sonification behavior
+ device = getDeviceForStrategy(STRATEGY_SONIFICATION, false /*fromCache*/);
+ }
+
+ break;
+
+ case STRATEGY_DTMF:
+ if (!isInCall()) {
+ // when off call, DTMF strategy follows the same rules as MEDIA strategy
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ break;
+ }
+ // when in call, DTMF and PHONE strategies follow the same rules
+ // FALL THROUGH
+
+ case STRATEGY_PHONE:
+ // for phone strategy, we first consider the forced use and then the available devices by order
+ // of priority
+ switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+ case AudioSystem::FORCE_BT_SCO:
+ if (!isInCall() || strategy != STRATEGY_DTMF) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
+ if (device) break;
+ // if SCO device is requested but no SCO device is available, fall back to default case
+ // FALL THROUGH
+
+ default: // FORCE_NONE
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (!isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADSET;
+ if (device) break;
+#endif
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_EARPIECE;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE");
+ }
+ break;
+
+ case AudioSystem::FORCE_SPEAKER:
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+ // A2DP speaker when forcing to speaker output
+ if (!isInCall() &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ !mA2dpSuspended) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER");
+ }
+ break;
+ }
+#ifdef QCOM_FM_ENABLED
+ if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) {
+ device |= AUDIO_DEVICE_OUT_FM;
+ if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) {
+ device &= ~(AUDIO_DEVICE_OUT_WIRED_HEADSET);
+ device &= ~(AUDIO_DEVICE_OUT_WIRED_HEADPHONE);
+ device &= ~(AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET);
+ device |= AUDIO_DEVICE_OUT_SPEAKER;
+ }
+ }
+#endif
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, false /*fromCache*/);
+ break;
+ }
+ // FALL THROUGH
+
+ case STRATEGY_ENFORCED_AUDIBLE:
+ // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+ // except:
+ // - when in call where it doesn't default to STRATEGY_PHONE behavior
+ // - in countries where not enforced in which case it follows STRATEGY_MEDIA
+
+ if ((strategy == STRATEGY_SONIFICATION) ||
+ (mForceUse[AudioSystem::FOR_SYSTEM] == AudioSystem::FORCE_SYSTEM_ENFORCED)) {
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION");
+ }
+ }
+ // The second device used for sonification is the same as the device used by media strategy
+ // FALL THROUGH
+
+ case STRATEGY_MEDIA: {
+ uint32_t device2 = AUDIO_DEVICE_NONE;
+ if (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_SPEAKER) {
+ if (strategy != STRATEGY_SONIFICATION) {
+ // no sonification on remote submix (e.g. WFD)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_REMOTE_SUBMIX;
+ }
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ //handle proxy device begin
+ if ((device2 == AUDIO_DEVICE_NONE) ||
+ (device2 == AUDIO_DEVICE_OUT_REMOTE_SUBMIX)) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_PROXY;
+ if(device2 != 0) {
+ ALOGV("getDeviceForStrategy() STRATEGY_MEDIA use DEVICE_OUT_PROXY:%x",device2);
+ // No combo device allowed with proxy device
+ device = 0;
+ }
+ }
+#endif
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AudioSystem::FOR_MEDIA] != AudioSystem::FORCE_NO_BT_A2DP) &&
+ !mA2dpSuspended) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ }
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_WIRED_HEADSET;
+ }
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADPHONE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANC_HEADSET;
+ }
+#endif
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_ACCESSORY;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_USB_DEVICE;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) {
+ // no sonification on aux digital (e.g. HDMI)
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_AUX_DIGITAL;
+ }
+ if ((device2 == AUDIO_DEVICE_NONE) &&
+ (mForceUse[AudioSystem::FOR_DOCK] == AudioSystem::FORCE_ANALOG_DOCK)) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ }
+#ifdef QCOM_FM_ENABLED
+ if (device2 == AUDIO_DEVICE_NONE) {
+ device2 = mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM_TX;
+ }
+#endif
+
+ // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+ // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise
+ device |= device2;
+ if (device) break;
+ device = mDefaultOutputDevice;
+ if (device == AUDIO_DEVICE_NONE) {
+ ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA");
+ }
+
+ } else {
+ //AudioSystem::FORCE_SPEAKER for STRATEGY_MEDIA
+ device = mAvailableOutputDevices & AUDIO_DEVICE_OUT_SPEAKER;
+ }
+
+#ifdef QCOM_FM_ENABLED
+ if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM) {
+ device |= AUDIO_DEVICE_OUT_FM;
+ }
+#endif
+
+ } break;
+
+ default:
+ ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ break;
+ }
+
+ ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+ return device;
+}
+
+uint32_t AudioPolicyManager::setOutputDevice(audio_io_handle_t output,
+ audio_devices_t device,
+ bool force,
+ int delayMs)
+
+{
+ ALOGV("setOutputDevice() output %d device %04x delayMs %d", output, device, delayMs);
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+ AudioParameter param;
+ uint32_t muteWaitMs = 0;
+
+ if (outputDesc->isDuplicated()) {
+ muteWaitMs = setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+ muteWaitMs += setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+ return muteWaitMs;
+ }
+ // filter devices according to output selected
+ device = (audio_devices_t)(device & outputDesc->mProfile->mSupportedDevices);
+
+ audio_devices_t prevDevice = outputDesc->mDevice;
+
+ ALOGV("setOutputDevice() prevDevice %04x", prevDevice);
+
+ if (device != AUDIO_DEVICE_NONE) {
+ outputDesc->mDevice = device;
+ }
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // Do not change the routing if:
+ // - the requested device is AUDIO_DEVICE_NONE
+ // - the requested device is the same as current device and force is not specified.
+ // Doing this check here allows the caller to call setOutputDevice() without conditions
+ if ((device == AUDIO_DEVICE_NONE || device == prevDevice) && !force) {
+ ALOGV("setOutputDevice() setting same device %04x or null device for output %d", device, output);
+ return muteWaitMs;
+ }
+
+ ALOGV("setOutputDevice() changing device:%x",device);
+ // do the routing
+ param.addInt(String8(AudioParameter::keyRouting), (int)device);
+ mpClientInterface->setParameters(output, param.toString(), delayMs);
+
+ // update stream volumes according to new device
+ applyStreamVolumes(output, device, delayMs);
+
+#ifdef QCOM_FM_ENABLED
+ //if changing from a combined headset + speaker + FM route, unmute media streams
+ if (mAvailableOutputDevices & AUDIO_DEVICE_OUT_FM)
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+#endif
+
+ return muteWaitMs;
+}
+
+audio_devices_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
+{
+ uint32_t device = AUDIO_DEVICE_NONE;
+
+ switch(inputSource) {
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+ mAvailableInputDevices & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_WIRED_HEADSET) {
+ device = AUDIO_DEVICE_IN_WIRED_HEADSET;
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANC_HEADSET) {
+ device = AUDIO_DEVICE_IN_ANC_HEADSET;
+#endif
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET) {
+ device = AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_BACK_MIC) {
+ device = AUDIO_DEVICE_IN_BACK_MIC;
+ } else if (mAvailableInputDevices & AUDIO_DEVICE_IN_BUILTIN_MIC) {
+ device = AUDIO_DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_VOICE_CALL) {
+ device = AUDIO_DEVICE_IN_VOICE_CALL;
+ }
+ break;
+ case AUDIO_SOURCE_REMOTE_SUBMIX:
+ if (mAvailableInputDevices & AUDIO_DEVICE_IN_REMOTE_SUBMIX) {
+ device = AUDIO_DEVICE_IN_REMOTE_SUBMIX;
+ }
+ break;
+#ifdef QCOM_FM_ENABLED
+ case AUDIO_SOURCE_FM_RX:
+ device = AUDIO_DEVICE_IN_FM_RX;
+ break;
+ case AUDIO_SOURCE_FM_RX_A2DP:
+ device = AUDIO_DEVICE_IN_FM_RX_A2DP;
+ break;
+#endif
+ default:
+ ALOGW("getDeviceForInputSource() invalid input source %d", inputSource);
+ break;
+ }
+ ALOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ return device;
+}
+
+
+status_t AudioPolicyManager::checkAndSetVolume(int stream,
+ int index,
+ audio_io_handle_t output,
+ audio_devices_t device,
+ int delayMs,
+ bool force)
+{
+ // do not change actual stream volume if the stream is muted
+ if (mOutputs.valueFor(output)->mMuteCount[stream] != 0) {
+ ALOGVV("checkAndSetVolume() stream %d muted count %d",
+ stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+ return NO_ERROR;
+ }
+
+ // do not change in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ ALOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ float volume = computeVolume(stream, index, output, device);
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+#ifdef QCOM_FM_ENABLED
+ (stream == AudioSystem::FM) ||
+#endif
+ force) {
+ mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+ ALOGVV("checkAndSetVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+ // Force VOICE_CALL to track BLUETOOTH_SCO stream volume when bluetooth audio is
+ // enabled
+ if (stream == AudioSystem::BLUETOOTH_SCO) {
+ mpClientInterface->setStreamVolume(AudioSystem::VOICE_CALL, volume, output, delayMs);
+#ifdef QCOM_FM_ENABLED
+ } else if (stream == AudioSystem::FM) {
+ float fmVolume = -1.0;
+ fmVolume = computeVolume(stream, index, output, device);
+ if (fmVolume >= 0) {
+ if(output == mPrimaryOutput)
+ mpClientInterface->setFmVolume(fmVolume, delayMs);
+ else if(mHasA2dp && output == getA2dpOutput())
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+ return NO_ERROR;
+#endif
+ }
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume;
+ // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else {
+ voiceVolume = 1.0;
+ }
+
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+
+ // Force voice volume to max when Vgs is set for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::BLUETOOTH_SCO) {
+ String8 key ("bt_headset_vgs");
+ mpClientInterface->getParameters(output,key);
+ AudioParameter result(mpClientInterface->getParameters(0,key));
+ int value;
+ if (result.getInt(String8("isVGS"),value) == NO_ERROR) {
+ ALOGV("Use BT-SCO Voice Volume");
+ voiceVolume = 1.0;
+ }
+ }
+
+ if (voiceVolume != mLastVoiceVolume && output == mPrimaryOutput) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+
+void AudioPolicyManager::checkA2dpSuspend()
+{
+
+ // suspend A2DP output if:
+ // (NOT already suspended) &&
+ // ((SCO device is connected &&
+ // (forced usage for communication || for record is SCO))) ||
+ // (phone state is ringing || in call)
+ //
+ // restore A2DP output if:
+ // (Already suspended) &&
+ // ((SCO device is NOT connected ||
+ // (forced usage NOT for communication && NOT for record is SCO))) &&
+ // (phone state is NOT ringing && NOT in call)
+ //
+ if (mA2dpSuspended) {
+ if (((mScoDeviceAddress == "") ||
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO) &&
+ (mForceUse[AudioSystem::FOR_RECORD] != AudioSystem::FORCE_BT_SCO))) &&
+ ((mPhoneState != AudioSystem::MODE_IN_CALL) &&
+ (mPhoneState != AudioSystem::MODE_RINGTONE))) {
+
+ mA2dpSuspended = false;
+ }
+ } else {
+ if (((mScoDeviceAddress != "") &&
+ ((mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO))) ||
+ ((mPhoneState == AudioSystem::MODE_IN_CALL) ||
+ (mPhoneState == AudioSystem::MODE_RINGTONE))) {
+
+ mA2dpSuspended = true;
+ }
+ }
+}
+
+audio_io_handle_t AudioPolicyManager::getA2dpOutput()
+{
+ return 0;
+}
+
+//private function, no changes from AudioPolicyManagerBase
+void AudioPolicyManager::handleNotificationRoutingForStream(AudioSystem::stream_type stream) {
+ switch(stream) {
+ case AudioSystem::MUSIC:
+ checkOutputForStrategy(STRATEGY_SONIFICATION_RESPECTFUL);
+ updateDevicesAndOutputs();
+ break;
+ default:
+ break;
+ }
+}
+
extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
@@ -46,4 +1254,5 @@
delete interface;
}
-}; // namespace androidi_audio_legacy
+
+}; // namespace android
diff --git a/alsa_sound/AudioPolicyManagerALSA.h b/alsa_sound/AudioPolicyManagerALSA.h
index 2a7dfdb..af3cef6 100644
--- a/alsa_sound/AudioPolicyManagerALSA.h
+++ b/alsa_sound/AudioPolicyManagerALSA.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2009 The Android Open Source Project
- * Copyright (C) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -37,5 +37,65 @@
virtual ~AudioPolicyManager() {}
+ // AudioPolicyInterface
+ virtual status_t setDeviceConnectionState(audio_devices_t device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+ virtual AudioSystem::device_connection_state getDeviceConnectionState(audio_devices_t device,
+ const char *device_address);
+ virtual void setPhoneState(int state);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+ virtual status_t startOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session = 0);
+ virtual status_t stopOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session = 0);
+
+ // indicates to the audio policy manager that the input starts being used.
+ virtual status_t startInput(audio_io_handle_t input);
+ // return appropriate device for streams handled by the specified strategy according to current
+ // phone state, connected devices...
+ // if fromCache is true, the device is returned from mDeviceForStrategy[],
+ // otherwise it is determine by current state
+ // (device connected,phone state, force use, a2dp output...)
+ // This allows to:
+ // 1 speed up process when the state is stable (when starting or stopping an output)
+ // 2 access to either current device selection (fromCache == true) or
+ // "future" device selection (fromCache == false) when called from a context
+ // where conditions are changing (setDeviceConnectionState(), setPhoneState()...) AND
+ // before updateDevicesAndOutputs() is called.
+ virtual audio_devices_t getDeviceForStrategy(routing_strategy strategy,
+ bool fromCache = true);
+
+ // change the route of the specified output. Returns the number of ms we have slept to
+ // allow new routing to take effect in certain cases.
+ uint32_t setOutputDevice(audio_io_handle_t output,
+ audio_devices_t device,
+ bool force = false,
+ int delayMs = 0);
+
+ // select input device corresponding to requested audio source
+ virtual audio_devices_t getDeviceForInputSource(int inputSource);
+
+ // check that volume change is permitted, compute and send new volume to audio hardware
+ status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, audio_devices_t device, int delayMs = 0, bool force = false);
+
+ // manages A2DP output suspend/restore according to phone state and BT SCO usage
+ void checkA2dpSuspend();
+
+ // returns the A2DP output handle if it is open or 0 otherwise
+ audio_io_handle_t getA2dpOutput();
+
+protected:
+
+ // true is current platform implements a back microphone
+ virtual bool hasBackMicrophone() const { return false; }
+ // true is current platform supports suplication of notifications and ringtones over A2DP output
+ virtual bool a2dpUsedForSonification() const { return true; }
+
+private:
+
+ void handleNotificationRoutingForStream(AudioSystem::stream_type stream);
};
};
diff --git a/alsa_sound/AudioSessionOut.cpp b/alsa_sound/AudioSessionOut.cpp
new file mode 100644
index 0000000..b37f7a0
--- /dev/null
+++ b/alsa_sound/AudioSessionOut.cpp
@@ -0,0 +1,895 @@
+/* AudioSessionOutALSA.cpp
+ **
+ ** Copyright 2008-2009 Wind River Systems
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
+ **
+ ** Not a Contribution, Apache license notifications and license are
+ ** retained for attribution purposes only.
+ **
+ ** 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.
+ */
+
+#include <errno.h>
+#include <stdarg.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <dlfcn.h>
+#include <math.h>
+
+#define LOG_TAG "AudioSessionOutALSA"
+#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <cutils/properties.h>
+#include <media/AudioRecord.h>
+#include <hardware_legacy/power.h>
+
+#include <linux/ioctl.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <pthread.h>
+#include <sys/poll.h>
+#include <sys/eventfd.h>
+#include <linux/unistd.h>
+
+#include "AudioHardwareALSA.h"
+
+namespace sys_write {
+ ssize_t lib_write(int fd, const void *buf, size_t count) {
+ return write(fd, buf, count);
+ }
+};
+namespace android_audio_legacy
+{
+#define LPA_MODE 0
+#define TUNNEL_MODE 1
+#define NUM_FDS 2
+#define KILL_EVENT_THREAD 1
+#define BUFFER_COUNT 4
+#define LPA_BUFFER_SIZE 256*1024
+#define TUNNEL_BUFFER_SIZE 600*1024
+#define MONO_CHANNEL_MODE 1
+// ----------------------------------------------------------------------------
+
+AudioSessionOutALSA::AudioSessionOutALSA(AudioHardwareALSA *parent,
+ uint32_t devices,
+ int format,
+ uint32_t channels,
+ uint32_t samplingRate,
+ int type,
+ status_t *status)
+{
+
+ alsa_handle_t alsa_handle;
+ char *use_case;
+ bool bIsUseCaseSet = false;
+
+ Mutex::Autolock autoLock(mLock);
+ // Default initilization
+ mParent = parent;
+ mAlsaDevice = mParent->mALSADevice;
+ mUcMgr = mParent->mUcMgr;
+ mFormat = format;
+ mSampleRate = samplingRate;
+ mChannels = channels;
+
+
+ mBufferSize = 0;
+ *status = BAD_VALUE;
+
+ mPaused = false;
+ mSeeking = false;
+ mReachedEOS = false;
+ mSkipWrite = false;
+
+ mAlsaHandle = NULL;
+ mUseCase = AudioHardwareALSA::USECASE_NONE;
+
+ mInputBufferSize = type ? TUNNEL_BUFFER_SIZE : LPA_BUFFER_SIZE;
+ mInputBufferCount = BUFFER_COUNT;
+ mEfd = -1;
+ mEosEventReceived = false;
+ mEventThread = NULL;
+ mEventThreadAlive = false;
+ mKillEventThread = false;
+ mObserver = NULL;
+ mOutputMetadataLength = 0;
+
+ if(devices == 0) {
+ ALOGE("No output device specified");
+ return;
+ }
+ if((format == AUDIO_FORMAT_PCM_16_BIT) && (channels == 0 || channels > 6)) {
+ ALOGE("Invalid number of channels %d", channels);
+ return;
+ }
+
+ if(devices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ ALOGV("Set Capture from proxy true");
+ mParent->mRouteAudioToA2dp = true;
+ }
+
+ //open device based on the type (LPA or Tunnel) and devices
+ //TODO: Check format type for linear vs non-linear to determine LPA/Tunnel
+ openAudioSessionDevice(type, devices);
+
+ //Creates the event thread to poll events from LPA/Compress Driver
+ createEventThread();
+
+ ALOGV("mParent->mRouteAudioToA2dp = %d", mParent->mRouteAudioToA2dp);
+ if (mParent->mRouteAudioToA2dp) {
+ status_t err = NO_ERROR;
+ mUseCase = mParent->useCaseStringToEnum(mAlsaHandle->useCase);
+ err = mParent->startA2dpPlayback_l(mUseCase);
+ *status = err;
+ }
+
+ *status = NO_ERROR;
+}
+
+AudioSessionOutALSA::~AudioSessionOutALSA()
+{
+ ALOGD("~AudioSessionOutALSA");
+
+ mSkipWrite = true;
+ mWriteCv.signal();
+ if (mParent->mRouteAudioToA2dp) {
+ status_t err = mParent->stopA2dpPlayback(mUseCase);
+ if(err){
+ ALOGE("stopA2dpPlayback return err %d", err);
+ }
+ }
+ //TODO: This might need to be Locked using Parent lock
+ reset();
+}
+
+status_t AudioSessionOutALSA::setVolume(float left, float right)
+{
+ Mutex::Autolock autoLock(mLock);
+ float volume;
+ status_t status = NO_ERROR;
+
+ volume = (left + right) / 2;
+ if (volume < 0.0) {
+ ALOGW("AudioSessionOutALSA::setVolume(%f) under 0.0, assuming 0.0\n", volume);
+ volume = 0.0;
+ } else if (volume > 1.0) {
+ ALOGW("AudioSessionOutALSA::setVolume(%f) over 1.0, assuming 1.0\n", volume);
+ volume = 1.0;
+ }
+ mStreamVol = lrint((volume * 0x2000)+0.5);
+
+ ALOGV("Setting stream volume to %d (available range is 0 to 0x2000)\n", mStreamVol);
+ if(mAlsaHandle) {
+ if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) ||
+ !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) {
+ ALOGD("setLpaVolume(%u)\n", mStreamVol);
+ ALOGD("Setting LPA volume to %d (available range is 0 to 100)\n", mStreamVol);
+ mAlsaHandle->module->setLpaVolume(mStreamVol);
+ return status;
+ }
+ else if(!strcmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) ||
+ !strcmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) {
+ ALOGD("setCompressedVolume(%u)\n", mStreamVol);
+ ALOGD("Setting Compressed volume to %d (available range is 0 to 100)\n", mStreamVol);
+ mAlsaHandle->module->setCompressedVolume(mStreamVol);
+ return status;
+ }
+ }
+ return INVALID_OPERATION;
+}
+
+
+status_t AudioSessionOutALSA::openAudioSessionDevice(int type, int devices)
+{
+ char* use_case;
+ status_t status = NO_ERROR;
+ //1.) Based on the current device and session type (LPA/Tunnel), open a device
+ // with verb or modifier
+ snd_use_case_get(mUcMgr, "_verb", (const char **)&use_case);
+ if (type == LPA_MODE) {
+ if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+ strlen(SND_USE_CASE_VERB_INACTIVE)))) {
+ status = openDevice(SND_USE_CASE_VERB_HIFI_LOW_POWER, true, devices);
+ } else {
+ status = openDevice(SND_USE_CASE_MOD_PLAY_LPA, false, devices);
+ }
+ } else if (type == TUNNEL_MODE) {
+ if ((use_case == NULL) || (!strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
+ strlen(SND_USE_CASE_VERB_INACTIVE)))) {
+ status = openDevice(SND_USE_CASE_VERB_HIFI_TUNNEL, true, devices);
+ } else {
+ status = openDevice(SND_USE_CASE_MOD_PLAY_TUNNEL, false, devices);
+ }
+ mOutputMetadataLength = sizeof(output_metadata_handle_t);
+ ALOGD("openAudioSessionDevice - mOutputMetadataLength = %d", mOutputMetadataLength);
+ }
+ if(use_case) {
+ free(use_case);
+ use_case = NULL;
+ }
+ if(status != NO_ERROR) {
+ return status;
+ }
+
+ //2.) Get the device handle
+ ALSAHandleList::iterator it = mParent->mDeviceList.end();
+ it--;
+
+ mAlsaHandle = &(*it);
+ ALOGV("mAlsaHandle %p, mAlsaHandle->useCase %s",mAlsaHandle, mAlsaHandle->useCase);
+
+ //3.) mmap the buffers for playback
+ status_t err = mmap_buffer(mAlsaHandle->handle);
+ if(err) {
+ ALOGE("MMAP buffer failed - playback err = %d", err);
+ return err;
+ }
+ ALOGV("buffer pointer %p ", mAlsaHandle->handle->addr);
+
+ //4.) prepare the driver for playback and allocate the buffers
+ status = pcm_prepare(mAlsaHandle->handle);
+ if (status) {
+ ALOGE("PCM Prepare failed - playback err = %d", err);
+ return status;
+ }
+ bufferAlloc(mAlsaHandle);
+ mBufferSize = mAlsaHandle->periodSize;
+ return NO_ERROR;
+}
+
+ssize_t AudioSessionOutALSA::write(const void *buffer, size_t bytes)
+{
+ Mutex::Autolock autoLock(mLock);
+ int err;
+ ALOGV("write Empty Queue size() = %d, Filled Queue size() = %d ",
+ mEmptyQueue.size(),mFilledQueue.size());
+
+ if(mFilledQueue.empty() && !bytes) {
+ mReachedEOS = true;
+ mEosEventReceived = true;
+ ALOGV("mObserver: posting EOS");
+ mObserver->postEOS(0);
+ }
+
+ //1.) Dequeue the buffer from empty buffer queue. Copy the data to be
+ // written into the buffer. Then Enqueue the buffer to the filled
+ // buffer queue
+ mEmptyQueueMutex.lock();
+ List<BuffersAllocated>::iterator it = mEmptyQueue.begin();
+ BuffersAllocated buf = *it;
+ if(bytes)
+ mEmptyQueue.erase(it);
+ mEmptyQueueMutex.unlock();
+
+ memset(buf.memBuf, 0, mAlsaHandle->handle->period_size);
+ if((!strncmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+ (!strncmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) {
+ updateMetaData(bytes);
+
+ memcpy(buf.memBuf, &mOutputMetadataTunnel, mOutputMetadataLength);
+ ALOGD("Copy Metadata = %d, bytes = %d", mOutputMetadataLength, bytes);
+
+ if(bytes == 0) {
+ err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size);
+ buf.bytesToWrite = bytes;
+ return err;
+ }
+ }
+ memcpy((buf.memBuf + mOutputMetadataLength), buffer, bytes);
+ buf.bytesToWrite = bytes;
+
+ //2.) Write the buffer to the Driver
+ ALOGV("PCM write start");
+ err = pcm_write(mAlsaHandle->handle, buf.memBuf, mAlsaHandle->handle->period_size);
+ ALOGV("PCM write complete");
+ if (bytes < (mAlsaHandle->handle->period_size - mOutputMetadataLength)) {
+ ALOGV("Last buffer case");
+ if ( ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START) < 0 ) {
+ ALOGE("Audio Start failed");
+ } else {
+ mAlsaHandle->handle->start = 1;
+ }
+ mReachedEOS = true;
+ }
+
+ mFilledQueueMutex.lock();
+ mFilledQueue.push_back(buf);
+ mFilledQueueMutex.unlock();
+ return err;
+}
+
+void AudioSessionOutALSA::bufferAlloc(alsa_handle_t *handle) {
+ void *mem_buf = NULL;
+ int i = 0;
+
+ int32_t nSize = mAlsaHandle->handle->period_size;
+ ALOGV("number of input buffers = %d", mInputBufferCount);
+ ALOGV("memBufferAlloc calling with required size %d", nSize);
+ for (i = 0; i < mInputBufferCount; i++) {
+ mem_buf = (int32_t *)mAlsaHandle->handle->addr + (nSize * i/sizeof(int));
+ ALOGV("Buffer pointer %p ", mem_buf);
+ BuffersAllocated buf(mem_buf, nSize);
+ memset(buf.memBuf, 0x0, nSize);
+ mEmptyQueue.push_back(buf);
+ mBufPool.push_back(buf);
+ ALOGV("The MEM that is allocated - buffer is %x",\
+ (unsigned int)mem_buf);
+ }
+}
+
+void AudioSessionOutALSA::bufferDeAlloc() {
+ while (!mBufPool.empty()) {
+ List<BuffersAllocated>::iterator it = mBufPool.begin();
+ ALOGV("Removing input buffer from Buffer Pool ");
+ mBufPool.erase(it);
+ }
+}
+
+void AudioSessionOutALSA::requestAndWaitForEventThreadExit() {
+ if (!mEventThreadAlive)
+ return;
+ mKillEventThread = true;
+ if(mEfd != -1) {
+ ALOGE("Writing to mEfd %d",mEfd);
+ uint64_t writeValue = KILL_EVENT_THREAD;
+ sys_write::lib_write(mEfd, &writeValue, sizeof(uint64_t));
+ }
+ pthread_join(mEventThread,NULL);
+ ALOGV("event thread killed");
+}
+
+void * AudioSessionOutALSA::eventThreadWrapper(void *me) {
+ static_cast<AudioSessionOutALSA *>(me)->eventThreadEntry();
+ return NULL;
+}
+
+void AudioSessionOutALSA::eventThreadEntry() {
+ //1.) Initialize the variables required for polling events
+ int rc = 0;
+ int err_poll = 0;
+ int avail = 0;
+ int i = 0;
+ struct pollfd pfd[NUM_FDS];
+ int timeout = -1;
+
+ //2.) Set the priority for the event thread
+ pid_t tid = gettid();
+ androidSetThreadPriority(tid, ANDROID_PRIORITY_AUDIO);
+ prctl(PR_SET_NAME, (unsigned long)"HAL Audio EventThread", 0, 0, 0);
+
+ //3.) Allocate two FDs for polling.
+ // 1st FD: Polling on the Driver's timer_fd. This is used for getting write done
+ // events from the driver
+ // 2nd FD: Polling on a local fd so we can interrup the event thread locally
+ // when playback is stopped from Apps
+ // The event thread will when a write is performed on one of these FDs
+ ALOGV("Allocating poll fd");
+ if(!mKillEventThread) {
+ pfd[0].fd = mAlsaHandle->handle->timer_fd;
+ pfd[0].events = (POLLIN | POLLERR | POLLNVAL);
+ mEfd = eventfd(0,0);
+ pfd[1].fd = mEfd;
+ pfd[1].events = (POLLIN | POLLERR | POLLNVAL);
+ }
+
+ //4.) Start a poll for write done events from driver.
+ while(!mKillEventThread && ((err_poll = poll(pfd, NUM_FDS, timeout)) >=0)) {
+ ALOGV("pfd[0].revents =%d ", pfd[0].revents);
+ ALOGV("pfd[1].revents =%d ", pfd[1].revents);
+ // Handle Poll errors
+ if (err_poll == EINTR)
+ ALOGE("Timer is intrrupted");
+ if ((pfd[1].revents & POLLERR) || (pfd[1].revents & POLLNVAL)) {
+ pfd[1].revents = 0;
+ ALOGE("POLLERR or INVALID POLL");
+ }
+
+ //POLLIN event on 2nd FD. Kill from event thread
+ if (pfd[1].revents & POLLIN) {
+ uint64_t u;
+ read(mEfd, &u, sizeof(uint64_t));
+ ALOGV("POLLIN event occured on the event fd, value written to %llu",
+ (unsigned long long)u);
+ pfd[1].revents = 0;
+ if (u == KILL_EVENT_THREAD) {
+ continue;
+ }
+ }
+
+ //Poll error on Driver's timer fd
+ if((pfd[0].revents & POLLERR) || (pfd[0].revents & POLLNVAL)) {
+ pfd[0].revents = 0;
+ continue;
+ }
+
+ //Pollin event on Driver's timer fd
+ if (pfd[0].revents & POLLIN && !mKillEventThread) {
+ struct snd_timer_tread rbuf[4];
+ read(mAlsaHandle->handle->timer_fd, rbuf, sizeof(struct snd_timer_tread) * 4 );
+ pfd[0].revents = 0;
+ if (mPaused)
+ continue;
+ ALOGV("After an event occurs");
+
+ mFilledQueueMutex.lock();
+ if (mFilledQueue.empty()) {
+ ALOGV("Filled queue is empty");
+ mFilledQueueMutex.unlock();
+ continue;
+ }
+ // Transfer a buffer that was consumed by the driver from filled queue
+ // to empty queue
+
+ BuffersAllocated buf = *(mFilledQueue.begin());
+ mFilledQueue.erase(mFilledQueue.begin());
+ ALOGV("mFilledQueue %d", mFilledQueue.size());
+
+ //Post EOS in case the filled queue is empty and EOS is reached.
+ if (mFilledQueue.empty() && mReachedEOS) {
+ mFilledQueueMutex.unlock();
+ if (mObserver != NULL) {
+ if((!strncmp(mAlsaHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+ (!strncmp(mAlsaHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)))) {
+ ALOGD("Audio Drain DONE ++");
+ if ( ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_DRAIN) < 0 ) {
+ ALOGE("Audio Drain failed");
+ }
+ ALOGD("Audio Drain DONE --");
+ }
+ ALOGV("Posting the EOS to the observer player %p", mObserver);
+ mEosEventReceived = true;
+ if(mReachedEOS) {
+ ALOGV("mObserver: posting EOS");
+ mObserver->postEOS(0);
+ }
+ }
+ }
+ mFilledQueueMutex.unlock();
+
+ mEmptyQueueMutex.lock();
+ mEmptyQueue.push_back(buf);
+ mEmptyQueueMutex.unlock();
+ mWriteCv.signal();
+ }
+ }
+
+ //5.) Close mEfd that was created
+ mEventThreadAlive = false;
+ if (mEfd != -1) {
+ close(mEfd);
+ mEfd = -1;
+ }
+ ALOGV("Event Thread is dying.");
+ return;
+
+}
+
+void AudioSessionOutALSA::createEventThread() {
+ ALOGV("Creating Event Thread");
+ mKillEventThread = false;
+ mEventThreadAlive = true;
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+ pthread_create(&mEventThread, &attr, eventThreadWrapper, this);
+ ALOGV("Event Thread created");
+}
+
+status_t AudioSessionOutALSA::start()
+{
+ Mutex::Autolock autoLock(mLock);
+ if (mPaused) {
+ status_t err = NO_ERROR;
+ if (mSeeking) {
+ drain();
+ mSeeking = false;
+ } else if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,0) < 0) {
+ ALOGE("Resume failed on use case %s", mAlsaHandle->useCase);
+ return UNKNOWN_ERROR;
+ }
+ mPaused = false;
+ if (mParent->mRouteAudioToA2dp) {
+ err = mParent->startA2dpPlayback_l(mUseCase);
+ if(err != NO_ERROR) {
+ ALOGE("start Proxy from start returned error = %d",err);
+ return err;
+ }
+ }
+ }
+ else {
+ //Signal the driver to start rendering data
+ if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ ALOGE("start:SNDRV_PCM_IOCTL_START failed\n");
+ return UNKNOWN_ERROR;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::pause()
+{
+ Mutex::Autolock autoLock(mLock);
+ status_t err = NO_ERROR;
+ ALOGD("Pausing the driver");
+ //Signal the driver to pause rendering data
+ if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1) < 0) {
+ ALOGE("PAUSE failed on use case %s", mAlsaHandle->useCase);
+ return UNKNOWN_ERROR;
+ }
+ mPaused = true;
+
+ if(err) {
+ ALOGE("pause returned error");
+ return err;
+ }
+ if (mParent->mRouteAudioToA2dp) {
+ err = mParent->suspendA2dpPlayback(mUseCase);
+ if(err != NO_ERROR) {
+ ALOGE("Suspend Proxy from Pause returned error = %d",err);
+ return err;
+ }
+ }
+ return err;
+
+}
+
+status_t AudioSessionOutALSA::pause_l()
+{
+ if (!mPaused) {
+ if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1) < 0) {
+ ALOGE("PAUSE failed on use case %s", mAlsaHandle->useCase);
+ return UNKNOWN_ERROR;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::resume_l()
+{
+ status_t err = NO_ERROR;
+ if (!mPaused) {
+ if (ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,0) < 0) {
+ ALOGE("Resume failed on use case %s", mAlsaHandle->useCase);
+ return UNKNOWN_ERROR;
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::drain()
+{
+ mAlsaHandle->handle->start = 0;
+ int err = pcm_prepare(mAlsaHandle->handle);
+ if(err != OK) {
+ ALOGE("pcm_prepare -seek = %d",err);
+ //Posting EOS
+ if (mObserver)
+ mObserver->postEOS(0);
+ return UNKNOWN_ERROR;
+ }
+
+ ALOGV("drain Empty Queue size() = %d, Filled Queue size() = %d ",
+ mEmptyQueue.size(), mFilledQueue.size());
+
+ mAlsaHandle->handle->sync_ptr->flags =
+ SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
+ sync_ptr(mAlsaHandle->handle);
+ ALOGV("appl_ptr=%d",(int)mAlsaHandle->handle->sync_ptr->c.control.appl_ptr);
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::flush()
+{
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("AudioSessionOutALSA flush");
+ int err;
+ {
+ Mutex::Autolock autoLockEmptyQueue(mEmptyQueueMutex);
+ Mutex::Autolock autoLockFilledQueue(mFilledQueueMutex);
+ // 1.) Clear the Empty and Filled buffer queue
+ mEmptyQueue.clear();
+ mFilledQueue.clear();
+
+ // 2.) Add all the available buffers to Request Queue (Maintain order)
+ List<BuffersAllocated>::iterator it = mBufPool.begin();
+ for (; it!=mBufPool.end(); ++it) {
+ memset(it->memBuf, 0x0, (*it).memBufsize);
+ mEmptyQueue.push_back(*it);
+ }
+ }
+
+ ALOGV("Transferred all the buffers from Filled queue to "
+ "Empty queue to handle seek");
+ mReachedEOS = false;
+ // 3.) If its in start state,
+ // Pause and flush the driver and Resume it again
+ // If its in paused state,
+ // Set the seek flag, Resume will take care of flushing the
+ // driver
+ if (!mPaused && !mEosEventReceived) {
+ if ((err = ioctl(mAlsaHandle->handle->fd, SNDRV_PCM_IOCTL_PAUSE,1)) < 0) {
+ ALOGE("Audio Pause failed");
+ return UNKNOWN_ERROR;
+ }
+ //mReachedEOS = false;
+ if ((err = drain()) != OK)
+ return err;
+ } else {
+ mSeeking = true;
+ }
+
+ //4.) Skip the current write from the decoder and signal to the Write get
+ // the next set of data from the decoder
+ mSkipWrite = true;
+ mWriteCv.signal();
+
+ ALOGV("AudioSessionOutALSA::flush completed");
+ return NO_ERROR;
+}
+
+
+
+status_t AudioSessionOutALSA::stop()
+{
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("AudioSessionOutALSA- stop");
+ // close all the existing PCM devices
+ mSkipWrite = true;
+ mWriteCv.signal();
+
+ if (mParent->mRouteAudioToA2dp) {
+ status_t err = mParent->suspendA2dpPlayback(mUseCase);
+ if(err) {
+ ALOGE("stop-suspendA2dpPlayback- return err = %d", err);
+ return err;
+ }
+ }
+
+ ALOGV("stop -");
+
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::standby()
+{
+ Mutex::Autolock autoLock(mParent->mLock);
+ status_t err = NO_ERROR;
+ if (mParent->mRouteAudioToA2dp) {
+ ALOGD("Standby - stopA2dpPlayback_l - mUseCase = %d",mUseCase);
+ err = mParent->stopA2dpPlayback_l(mUseCase);
+ if(err){
+ ALOGE("stopA2dpPlayback return err %d", err);
+ }
+ }
+ return err;
+}
+
+#define USEC_TO_MSEC(x) ((x + 999) / 1000)
+
+uint32_t AudioSessionOutALSA::latency() const
+{
+ // Android wants latency in milliseconds.
+ return USEC_TO_MSEC (mAlsaHandle->latency);
+}
+
+status_t AudioSessionOutALSA::setObserver(void *observer)
+{
+ ALOGV("Registering the callback \n");
+ mObserver = reinterpret_cast<AudioEventObserver *>(observer);
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::getNextWriteTimestamp(int64_t *timestamp)
+{
+ struct snd_compr_tstamp tstamp;
+ tstamp.timestamp = -1;
+ if (ioctl(mAlsaHandle->handle->fd, SNDRV_COMPRESS_TSTAMP, &tstamp)){
+ ALOGE("Failed SNDRV_COMPRESS_TSTAMP\n");
+ return UNKNOWN_ERROR;
+ } else {
+ ALOGV("Timestamp returned = %lld\n", tstamp.timestamp);
+ *timestamp = tstamp.timestamp;
+ return NO_ERROR;
+ }
+ return NO_ERROR;
+}
+
+// return the number of audio frames written by the audio dsp to DAC since
+// the output has exited standby
+status_t AudioSessionOutALSA::getRenderPosition(uint32_t *dspFrames)
+{
+ Mutex::Autolock autoLock(mLock);
+ *dspFrames = mFrameCount;
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::getBufferInfo(buf_info **buf) {
+ if (!mAlsaHandle) {
+ return NO_ERROR;
+ }
+ buf_info *tempbuf = (buf_info *)malloc(sizeof(buf_info) + mInputBufferCount*sizeof(int *));
+ ALOGV("Get buffer info");
+ tempbuf->bufsize = mAlsaHandle->handle->period_size;
+ tempbuf->nBufs = mInputBufferCount;
+ tempbuf->buffers = (int **)((char*)tempbuf + sizeof(buf_info));
+ List<BuffersAllocated>::iterator it = mBufPool.begin();
+ for (int i = 0; i < mInputBufferCount; i++) {
+ tempbuf->buffers[i] = (int *)it->memBuf;
+ it++;
+ }
+ *buf = tempbuf;
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::isBufferAvailable(int *isAvail) {
+
+ Mutex::Autolock autoLock(mLock);
+ ALOGV("isBufferAvailable Empty Queue size() = %d, Filled Queue size() = %d ",
+ mEmptyQueue.size(),mFilledQueue.size());
+ *isAvail = false;
+ // 1.) Wait till a empty buffer is available in the Empty buffer queue
+ mEmptyQueueMutex.lock();
+ if (mEmptyQueue.empty()) {
+ ALOGV("Write: waiting on mWriteCv");
+ mLock.unlock();
+ mWriteCv.wait(mEmptyQueueMutex);
+ mLock.lock();
+ if (mSkipWrite) {
+ ALOGV("Write: Flushing the previous write buffer");
+ mSkipWrite = false;
+ mEmptyQueueMutex.unlock();
+ return NO_ERROR;
+ }
+ ALOGV("isBufferAvailable: received a signal to wake up");
+ }
+ mEmptyQueueMutex.unlock();
+
+ *isAvail = true;
+ return NO_ERROR;
+}
+
+status_t AudioSessionOutALSA::openDevice(char *useCase, bool bIsUseCase, int devices)
+{
+ alsa_handle_t alsa_handle;
+ status_t status = NO_ERROR;
+ ALOGV("openDevice: E usecase %s", useCase);
+ alsa_handle.module = mAlsaDevice;
+ alsa_handle.bufferSize = mInputBufferSize;
+ alsa_handle.devices = devices;
+ alsa_handle.handle = 0;
+ alsa_handle.format = (mFormat == AUDIO_FORMAT_PCM_16_BIT ? SNDRV_PCM_FORMAT_S16_LE : mFormat);
+ //ToDo: Add conversion from channel Mask to channel count.
+ if (mChannels == AUDIO_CHANNEL_OUT_MONO)
+ alsa_handle.channels = MONO_CHANNEL_MODE;
+ else
+ alsa_handle.channels = DEFAULT_CHANNEL_MODE;
+ alsa_handle.sampleRate = mSampleRate;
+ alsa_handle.latency = PLAYBACK_LATENCY;
+ alsa_handle.rxHandle = 0;
+ alsa_handle.ucMgr = mUcMgr;
+ alsa_handle.session = this;
+ strlcpy(alsa_handle.useCase, useCase, sizeof(alsa_handle.useCase));
+
+ mAlsaDevice->route(&alsa_handle, devices, mParent->mode());
+ if (bIsUseCase) {
+ snd_use_case_set(mUcMgr, "_verb", useCase);
+ } else {
+ snd_use_case_set(mUcMgr, "_enamod", useCase);
+ }
+
+ status = mAlsaDevice->open(&alsa_handle);
+ if(status != NO_ERROR) {
+ ALOGE("Could not open the ALSA device for use case %s", alsa_handle.useCase);
+ mAlsaDevice->close(&alsa_handle);
+ } else{
+ mParent->mDeviceList.push_back(alsa_handle);
+ }
+ return status;
+}
+
+status_t AudioSessionOutALSA::closeDevice(alsa_handle_t *pHandle)
+{
+ status_t status = NO_ERROR;
+ ALOGV("closeDevice: useCase %s", pHandle->useCase);
+ //TODO: remove from mDeviceList
+ if(pHandle) {
+ status = mAlsaDevice->close(pHandle);
+ }
+ return status;
+}
+
+status_t AudioSessionOutALSA::setParameters(const String8& keyValuePairs)
+{
+ Mutex::Autolock autoLock(mLock);
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key = String8(AudioParameter::keyRouting);
+ int device;
+ if (param.getInt(key, device) == NO_ERROR) {
+ // Ignore routing if device is 0.
+ if(device) {
+ ALOGV("setParameters(): keyRouting with device %#x", device);
+ if(device & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ mParent->mRouteAudioToA2dp = true;
+ ALOGD("setParameters(): A2DP device %#x", device);
+ }
+ mParent->doRouting(device);
+ }
+ param.remove(key);
+ }
+ return NO_ERROR;
+}
+
+String8 AudioSessionOutALSA::getParameters(const String8& keys)
+{
+ Mutex::Autolock autoLock(mLock);
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+ String8 key = String8(AudioParameter::keyRouting);
+
+ if (param.get(key, value) == NO_ERROR) {
+ param.addInt(key, (int)mAlsaHandle->devices);
+ }
+
+ ALOGV("getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+void AudioSessionOutALSA::reset() {
+ mParent->mLock.lock();
+ requestAndWaitForEventThreadExit();
+
+ if(mAlsaHandle) {
+ ALOGV("closeDevice mAlsaHandle");
+ closeDevice(mAlsaHandle);
+ mAlsaHandle = NULL;
+ }
+ ALOGV("Erase device list");
+ for(ALSAHandleList::iterator it = mParent->mDeviceList.begin();
+ it != mParent->mDeviceList.end(); ++it) {
+ if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ strlen(SND_USE_CASE_VERB_HIFI_TUNNEL))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ strlen(SND_USE_CASE_MOD_PLAY_TUNNEL))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+ strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_LPA,
+ strlen(SND_USE_CASE_MOD_PLAY_LPA)))) {
+ mParent->mDeviceList.erase(it);
+ break;
+ }
+ }
+ mParent->mLock.unlock();
+}
+void AudioSessionOutALSA::updateMetaData(size_t bytes) {
+ mOutputMetadataTunnel.metadataLength = sizeof(mOutputMetadataTunnel);
+ mOutputMetadataTunnel.timestamp = 0;
+ mOutputMetadataTunnel.bufferLength = bytes;
+ ALOGD("bytes = %d , mAlsaHandle->handle->period_size = %d ",
+ bytes, mAlsaHandle->handle->period_size);
+}
+
+} // namespace android_audio_legacy
diff --git a/alsa_sound/AudioStreamInALSA.cpp b/alsa_sound/AudioStreamInALSA.cpp
index 3b66c24..86fb532 100644
--- a/alsa_sound/AudioStreamInALSA.cpp
+++ b/alsa_sound/AudioStreamInALSA.cpp
@@ -1,7 +1,7 @@
/* AudioStreamInALSA.cpp
**
** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -41,7 +41,6 @@
static int (*csd_start_record)(int);
static int (*csd_stop_record)(void);
#endif
-
#ifdef QCOM_SSR_ENABLED
#include "surround_filters_interface.h"
#endif
@@ -69,8 +68,8 @@
AudioSystem::audio_in_acoustics audio_acoustics) :
ALSAStreamOps(parent, handle),
mFramesLost(0),
- mAcoustics(audio_acoustics),
- mParent(parent)
+ mParent(parent),
+ mAcoustics(audio_acoustics)
#ifdef QCOM_SSR_ENABLED
, mFp_4ch(NULL),
mFp_6ch(NULL),
@@ -90,7 +89,9 @@
// Call surround sound library init if device is Surround Sound
if ( handle->channels == 6) {
if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
- || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
+ || !strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, strlen(SND_USE_CASE_VERB_HIFI_REC_COMPRESSED))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))
+ || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED))) {
err = initSurroundSoundLibrary(handle->bufferSize);
if ( NO_ERROR != err) {
@@ -125,13 +126,13 @@
ssize_t AudioStreamInALSA::read(void *buffer, ssize_t bytes)
{
- int period_size;
+ unsigned int period_size;
ALOGV("read:: buffer %p, bytes %d", buffer, bytes);
int n;
status_t err;
- ssize_t read = 0;
+ size_t read = 0;
char *use_case;
int newMode = mParent->mode();
@@ -142,10 +143,10 @@
snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
if ((use_case != NULL) && (strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
- (newMode == AudioSystem::MODE_IN_CALL)) {
+ (newMode == AUDIO_MODE_IN_CALL)) {
ALOGD("read:: mParent->mIncallMode=%d", mParent->mIncallMode);
- if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
- (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+ if ((mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+ (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
#ifdef QCOM_CSDCLIENT_ENABLED
if (mParent->mFusion3Platform) {
mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO);
@@ -155,10 +156,15 @@
} else
#endif
{
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
- sizeof(mHandle->useCase));
+ if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL,
+ sizeof(mHandle->useCase));
+ } else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
+ sizeof(mHandle->useCase));
+ }
}
- } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+ } else if (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
#ifdef QCOM_CSDCLIENT_ENABLED
if (mParent->mFusion3Platform) {
mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO);
@@ -168,8 +174,13 @@
} else
#endif
{
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
- sizeof(mHandle->useCase));
+ if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL,
+ sizeof(mHandle->useCase));
+ } else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+ sizeof(mHandle->useCase));
+ }
}
}
#ifdef QCOM_FM_ENABLED
@@ -181,20 +192,22 @@
} else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase));
} else {
- char value[128];
- property_get("persist.audio.lowlatency.rec",value,"0");
- if (!strcmp("true", value)) {
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
- } else {
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase));
- }
+ char value[128];
+ property_get("persist.audio.lowlatency.rec",value,"0");
+ if (!strcmp("true", value)) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+ } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED, sizeof(mHandle->useCase));
+ } else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, sizeof(mHandle->useCase));
+ }
}
} else {
if ((mHandle->devices == AudioSystem::DEVICE_IN_VOICE_CALL) &&
- (newMode == AudioSystem::MODE_IN_CALL)) {
+ (newMode == AUDIO_MODE_IN_CALL)) {
ALOGD("read:: ---- mParent->mIncallMode=%d", mParent->mIncallMode);
- if ((mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
- (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK)) {
+ if ((mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_UPLINK) &&
+ (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK)) {
#ifdef QCOM_CSDCLIENT_ENABLED
if (mParent->mFusion3Platform) {
mParent->mALSADevice->setVocRecMode(INCALL_REC_STEREO);
@@ -204,10 +217,15 @@
} else
#endif
{
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC,
- sizeof(mHandle->useCase));
+ if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL,
+ sizeof(mHandle->useCase));
+ } else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_UL_DL_REC,
+ sizeof(mHandle->useCase));
+ }
}
- } else if (mParent->mIncallMode & AudioSystem::CHANNEL_IN_VOICE_DNLINK) {
+ } else if (mParent->mIncallMode & AUDIO_CHANNEL_IN_VOICE_DNLINK) {
#ifdef QCOM_CSDCLIENT_ENABLED
if (mParent->mFusion3Platform) {
mParent->mALSADevice->setVocRecMode(INCALL_REC_MONO);
@@ -217,8 +235,14 @@
} else
#endif
{
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC,
- sizeof(mHandle->useCase));
+ if (mHandle->format == AUDIO_FORMAT_AMR_WB) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL,
+ sizeof(mHandle->useCase));
+ }
+ else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_DL_REC,
+ sizeof(mHandle->useCase));
+ }
}
}
#ifdef QCOM_FM_ENABLED
@@ -229,14 +253,16 @@
#endif
} else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(mHandle->useCase));
+ } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)){
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED, sizeof(mHandle->useCase));
} else {
- char value[128];
- property_get("persist.audio.lowlatency.rec",value,"0");
- if (!strcmp("true", value)) {
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(mHandle->useCase));
- } else {
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase));
- }
+ char value[128];
+ property_get("persist.audio.lowlatency.rec",value,"0");
+ if (!strcmp("true", value)) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC, sizeof(mHandle->useCase));
+ } else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(mHandle->useCase));
+ }
}
}
free(use_case);
@@ -245,11 +271,11 @@
#ifdef QCOM_USBAUDIO_ENABLED
if((mDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) ||
(mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)) {
- mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AudioSystem::MODE_IN_COMMUNICATION);
+ mHandle->module->route(mHandle, (mDevices | AudioSystem::DEVICE_IN_PROXY) , AUDIO_MODE_IN_COMMUNICATION);
}else
#endif
{
- mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION);
+ mHandle->module->route(mHandle, mDevices , AUDIO_MODE_IN_COMMUNICATION);
}
} else {
#ifdef QCOM_USBAUDIO_ENABLED
@@ -265,6 +291,7 @@
}
if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC) ||
+ !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED) ||
!strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_REC) ||
!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) ||
!strcmp(mHandle->useCase, SND_USE_CASE_VERB_FM_A2DP_REC) ||
@@ -412,6 +439,39 @@
buffer = buffer_start;
} else
#endif
+ if (mHandle->format == AUDIO_FORMAT_AMR_WB &&
+ (strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) &&
+ (strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
+ ALOGV("AUDIO_FORMAT_AMR_WB");
+ do {
+ if (read_pending < 61) {
+ read_pending = 61;
+ }
+ //We should pcm_read period_size to get complete data from driver
+ n = pcm_read(mHandle->handle, buffer, period_size);
+ if (n < 0) {
+ ALOGE("pcm_read() returned failure: %d", n);
+ return 0;
+ } else {
+ struct snd_compr_audio_info *header = (struct snd_compr_audio_info *) buffer;
+ if (header->frame_size > 0) {
+ if (sizeof(*header) + header->reserved[0] + header->frame_size > period_size) {
+ ALOGE("AMR WB read buffer overflow. Assign bigger buffer size");
+ header->frame_size = period_size - sizeof(*header) - header->reserved[0];
+ }
+ read += header->frame_size;
+ read_pending -= header->frame_size;
+ ALOGV("buffer: %p, data offset: %p, header size: %u, reserved[0]: %u",
+ buffer, ((uint8_t*)buffer) + sizeof(*header) + header->reserved[0],
+ sizeof(*header), header->reserved[0]);
+ memmove(buffer, ((uint8_t*)buffer) + sizeof(*header) + header->reserved[0], header->frame_size);
+ buffer += header->frame_size;
+ } else {
+ ALOGW("pcm_read() with zero frame size");
+ }
+ }
+ } while (mHandle->handle && read < bytes);
+ } else
{
do {
@@ -424,24 +484,24 @@
ALOGV("pcm_read() returned n = %d", n);
if (n && (n == -EIO || n == -EAGAIN || n == -EPIPE || n == -EBADFD)) {
mParent->mLock.lock();
- ALOGW("pcm_read() returned error n %d, Recovering from error\n", n);
- pcm_close(mHandle->handle);
- mHandle->handle = NULL;
- if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
- (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
- pcm_close(mHandle->rxHandle);
- mHandle->rxHandle = NULL;
- mHandle->module->startVoipCall(mHandle);
+ if (mHandle->handle != NULL) {
+ ALOGW("pcm_read() returned error n %d, Recovering from error\n", n);
+ pcm_close(mHandle->handle);
+ mHandle->handle = NULL;
+ if((!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL, strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
+ (!strncmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP, strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
+ pcm_close(mHandle->rxHandle);
+ mHandle->rxHandle = NULL;
+ mHandle->module->startVoipCall(mHandle);
+ }
+ else
+ mHandle->module->open(mHandle);
+ if(mHandle->handle == NULL) {
+ ALOGE("read:: PCM device re-open failed");
+ mParent->mLock.unlock();
+ return 0;
+ }
}
- else
- mHandle->module->open(mHandle);
-
- if(mHandle->handle == NULL) {
- ALOGE("read:: PCM device re-open failed");
- mParent->mLock.unlock();
- return 0;
- }
-
mParent->mLock.unlock();
continue;
}
@@ -452,11 +512,7 @@
else {
read += static_cast<ssize_t>((period_size));
read_pending -= period_size;
- //Set mute by cleanning buffers read
- if (mParent->mMicMute) {
- memset(buffer, 0, period_size);
- }
- buffer = ((uint8_t *)buffer) + period_size;
+ buffer += period_size;
}
} while (mHandle->handle && read < bytes);
@@ -488,10 +544,10 @@
(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
if((mParent->mVoipStreamCount)) {
#ifdef QCOM_USBAUDIO_ENABLED
- ALOGD("musbRecordingState: %d, mVoipStreamCount:%d",mParent->musbRecordingState,
+ ALOGV("musbRecordingState: %d, mVoipStreamCount:%d",mParent->musbRecordingState,
mParent->mVoipStreamCount );
if(mParent->mVoipStreamCount == 1) {
- ALOGD("Deregistering VOIP Call bit, musbPlaybackState:%d,"
+ ALOGV("Deregistering VOIP Call bit, musbPlaybackState:%d,"
"musbRecordingState:%d", mParent->musbPlaybackState, mParent->musbRecordingState);
mParent->musbPlaybackState &= ~USBPLAYBACKBIT_VOIPCALL;
mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL;
@@ -502,6 +558,7 @@
return NO_ERROR;
}
mParent->mVoipStreamCount = 0;
+ mParent->mVoipMicMute = 0;
#ifdef QCOM_USBAUDIO_ENABLED
} else {
ALOGD("Deregistering REC bit, musbRecordingState:%d", mParent->musbRecordingState);
diff --git a/alsa_sound/AudioStreamOutALSA.cpp b/alsa_sound/AudioStreamOutALSA.cpp
index 2adb5d8..05c71ae 100644
--- a/alsa_sound/AudioStreamOutALSA.cpp
+++ b/alsa_sound/AudioStreamOutALSA.cpp
@@ -1,7 +1,7 @@
/* AudioStreamOutALSA.cpp
**
** Copyright 2008-2009 Wind River Systems
- ** Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ ** Copyright (c) 2012, The Linux Foundation. All rights reserved.
**
** Licensed under the Apache License, Version 2.0 (the "License");
** you may not use this file except in compliance with the License.
@@ -53,12 +53,19 @@
AudioStreamOutALSA::AudioStreamOutALSA(AudioHardwareALSA *parent, alsa_handle_t *handle) :
ALSAStreamOps(parent, handle),
mParent(parent),
- mFrameCount(0)
+ mFrameCount(0),
+ mUseCase(AudioHardwareALSA::USECASE_NONE)
{
}
AudioStreamOutALSA::~AudioStreamOutALSA()
{
+ if (mParent->mRouteAudioToA2dp) {
+ status_t err = mParent->stopA2dpPlayback(mUseCase);
+ if (err) {
+ ALOGE("stopA2dpPlayback return err %d", err);
+ }
+ }
close();
}
@@ -84,21 +91,7 @@
}
vol = lrint((volume * 0x2000)+0.5);
- if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER) ||
- !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) {
- ALOGV("setLpaVolume(%f)\n", volume);
- ALOGV("Setting LPA volume to %d (available range is 0 to 100)\n", vol);
- mHandle->module->setLpaVolume(vol);
- return status;
- }
- else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL) ||
- !strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL)) {
- ALOGV("setCompressedVolume(%f)\n", volume);
- ALOGV("Setting Compressed volume to %d (available range is 0 to 100)\n", vol);
- mHandle->module->setCompressedVolume(vol);
- return status;
- }
- else if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
+ if(!strncmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
sizeof(mHandle->useCase)) || !strncmp(mHandle->useCase,
SND_USE_CASE_MOD_PLAY_VOIP, sizeof(mHandle->useCase))) {
ALOGV("Avoid Software volume by returning success\n");
@@ -120,98 +113,103 @@
int write_pending = bytes;
- if((mHandle->handle == NULL) && (mHandle->rxHandle == NULL) &&
- (strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) &&
- (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+ if((strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) &&
+ (strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
mParent->mLock.lock();
-
- ALOGD("mHandle->useCase: %s", mHandle->useCase);
- snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
- if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
- if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)){
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,
- sizeof(SND_USE_CASE_VERB_IP_VOICECALL));
- } else if(!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) {
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI2,
- sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
- } else if (!strcmp(mHandle->useCase,SND_USE_CASE_MOD_PLAY_MUSIC)){
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI,
- sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
- } else if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) {
- strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
- sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
+ /* PCM handle might be closed and reopened immediately to flush
+ * the buffers, recheck and break if PCM handle is valid */
+ if (mHandle->handle == NULL && mHandle->rxHandle == NULL) {
+ ALOGV("mDevices =0x%x", mDevices);
+ if(mDevices & AudioSystem::DEVICE_OUT_ALL_A2DP) {
+ ALOGV("StreamOut write - mRouteAudioToA2dp = %d ", mParent->mRouteAudioToA2dp);
+ mParent->mRouteAudioToA2dp = true;
}
- } else {
- if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP,
- sizeof(SND_USE_CASE_MOD_PLAY_VOIP));
- } else if(!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI2)) {
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
- sizeof(SND_USE_CASE_MOD_PLAY_MUSIC2));
- } else if (!strcmp(mHandle->useCase,SND_USE_CASE_VERB_HIFI)){
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
- sizeof(SND_USE_CASE_MOD_PLAY_MUSIC));
- } else if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) {
- strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
- sizeof(SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC));
+ ALOGV("write: mHandle->useCase: %s", mHandle->useCase);
+ snd_use_case_get(mHandle->ucMgr, "_verb", (const char **)&use_case);
+ if ((use_case == NULL) || (!strcmp(use_case, SND_USE_CASE_VERB_INACTIVE))) {
+ if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)){
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL,sizeof(mHandle->useCase));
+ } else if (mHandle->isFastOutput){
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+ } else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_VERB_HIFI, sizeof(mHandle->useCase));
+ }
+ } else {
+ if(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP,sizeof(mHandle->useCase));
+ } else if (mHandle->isFastOutput){
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC, sizeof(mHandle->useCase));
+ } else {
+ strlcpy(mHandle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, sizeof(mHandle->useCase));
+ }
}
- }
- free(use_case);
- if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
- (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
-#ifdef QCOM_USBAUDIO_ENABLED
- if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
- (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
- (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
- mDevices |= AudioSystem::DEVICE_OUT_PROXY;
- mHandle->module->route(mHandle, mDevices , mParent->mode());
- }else
-#endif
- {
- mHandle->module->route(mHandle, mDevices , AudioSystem::MODE_IN_COMMUNICATION);
- }
-#ifdef QCOM_USBAUDIO_ENABLED
- } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
- (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
- (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
- mDevices |= AudioSystem::DEVICE_OUT_PROXY;
- mHandle->module->route(mHandle, mDevices , mParent->mode());
-#endif
- } else {
- mHandle->module->route(mHandle, mDevices , mParent->mode());
- }
- if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) ||
- !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) ||
- !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) ||
- !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
- snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase);
- } else {
- snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase);
- }
- if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
- (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
- err = mHandle->module->startVoipCall(mHandle);
- }
- else
- mHandle->module->open(mHandle);
- if(mHandle->handle == NULL) {
- ALOGE("write:: device open failed");
- mParent->mLock.unlock();
- return bytes;
- }
-#ifdef QCOM_USBAUDIO_ENABLED
- if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)||
- (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){
+ free(use_case);
if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
- mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
+#ifdef QCOM_USBAUDIO_ENABLED
+ if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
+ (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
+ mHandle->module->route(mHandle, mDevices , mParent->mode());
+ }else
+#endif
+ {
+ mHandle->module->route(mHandle, mDevices , AUDIO_MODE_IN_COMMUNICATION);
+ }
+#ifdef QCOM_USBAUDIO_ENABLED
+ } else if((mDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (mDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
+ (mDevices & AudioSystem::DEVICE_OUT_PROXY)) {
+ mHandle->module->route(mHandle, mDevices , mParent->mode());
+#endif
} else {
- mParent->startUsbPlaybackIfNotStarted();
- mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC;
+ mHandle->module->route(mHandle, mDevices , mParent->mode());
+ }
+ if (!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI) ||
+ !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI2) ||
+ !strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC) ||
+ !strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) {
+ snd_use_case_set(mHandle->ucMgr, "_verb", mHandle->useCase);
+ } else {
+ snd_use_case_set(mHandle->ucMgr, "_enamod", mHandle->useCase);
+ }
+ if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
+ (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+ err = mHandle->module->startVoipCall(mHandle);
+ }
+ else
+ mHandle->module->open(mHandle);
+ if(mHandle->handle == NULL) {
+ ALOGE("write:: device open failed");
+ mParent->mLock.unlock();
+ return bytes;
+ }
+#ifdef QCOM_USBAUDIO_ENABLED
+ if((mHandle->devices == AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET)||
+ (mHandle->devices == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)){
+ if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
+ (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+ mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
+ } else {
+ mParent->startUsbPlaybackIfNotStarted();
+ mParent->musbPlaybackState |= USBPLAYBACKBIT_MUSIC;
+ }
+ }
+#endif
+ }
+ if (mParent->mRouteAudioToA2dp) {
+ mUseCase = mParent->useCaseStringToEnum(mHandle->useCase);
+ if (! (mParent->getA2DPActiveUseCases_l() & mUseCase )){
+ ALOGD("startA2dpPlayback_l from write :: useCase = %s", mHandle->useCase);
+ status_t err = NO_ERROR;
+ err = mParent->startA2dpPlayback_l(mUseCase);
+ if(err) {
+ ALOGE("startA2dpPlayback_l from write return err = %d", err);
+ mParent->mLock.unlock();
+ return err;
+ }
}
}
-#endif
-
mParent->mLock.unlock();
}
@@ -224,7 +222,7 @@
ALOGV("Starting playback on USB");
if(!strcmp(mHandle->useCase, SND_USE_CASE_VERB_IP_VOICECALL) ||
!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_VOIP)) {
- ALOGD("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState);
+ ALOGV("Setting VOIPCALL bit here, musbPlaybackState %d", mParent->musbPlaybackState);
mParent->musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
}else{
ALOGV("enabling music, musbPlaybackState: %d ", mParent->musbPlaybackState);
@@ -310,16 +308,24 @@
mParent->musbRecordingState &= ~USBRECBIT_VOIPCALL;
mParent->closeUsbPlaybackIfNothingActive();
mParent->closeUsbRecordingIfNothingActive();
+
+ if (mParent->mRouteAudioToA2dp) {
+ //TODO: HANDLE VOIP A2DP
+ }
}
#endif
return NO_ERROR;
}
mParent->mVoipStreamCount = 0;
+ mParent->mVoipMicMute = 0;
}
#ifdef QCOM_USBAUDIO_ENABLED
else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA;
+ } else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+ mParent->musbPlaybackState &= ~USBPLAYBACKBIT_TUNNEL;
} else {
mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC;
}
@@ -327,6 +333,14 @@
mParent->closeUsbPlaybackIfNothingActive();
#endif
+ if (mParent->mRouteAudioToA2dp) {
+ ALOGD("close-suspendA2dpPlayback_l::mUseCase = %d",mUseCase);
+ status_t err = mParent->suspendA2dpPlayback_l(mUseCase);
+ if(err) {
+ ALOGE("suspendA2dpPlayback from hardware output close return err = %d", err);
+ return err;
+ }
+ }
ALSAStreamOps::close();
return NO_ERROR;
@@ -348,6 +362,10 @@
(!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_LPA))) {
ALOGV("Deregistering LPA bit");
mParent->musbPlaybackState &= ~USBPLAYBACKBIT_LPA;
+ } else if((!strcmp(mHandle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ (!strcmp(mHandle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
+ ALOGD("Deregistering Tunnel Player bit");
+ mParent->musbPlaybackState &= ~USBPLAYBACKBIT_TUNNEL;
} else {
ALOGV("Deregistering MUSIC bit, musbPlaybackState: %d", mParent->musbPlaybackState);
mParent->musbPlaybackState &= ~USBPLAYBACKBIT_MUSIC;
@@ -355,6 +373,12 @@
#endif
mHandle->module->standby(mHandle);
+ if (mParent->mRouteAudioToA2dp) {
+ status_t err = mParent->stopA2dpPlayback_l(mUseCase);
+ if(err) {
+ ALOGE("stopA2dpPlayback return err %d", err);
+ }
+ }
#ifdef QCOM_USBAUDIO_ENABLED
mParent->closeUsbPlaybackIfNothingActive();
diff --git a/alsa_sound/AudioUsbALSA.cpp b/alsa_sound/AudioUsbALSA.cpp
index 3316e3e..02847dc 100644
--- a/alsa_sound/AudioUsbALSA.cpp
+++ b/alsa_sound/AudioUsbALSA.cpp
@@ -1,5 +1,6 @@
/* AudioUsbALSA.cpp
-Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+
+Copyright (c) 2012, The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -54,6 +55,9 @@
#define USB_PERIOD_SIZE 2048
#define PROXY_PERIOD_SIZE 3072
+#define PROXY_SUPPORTED_RATE_8000 8000
+#define PROXY_SUPPORTED_RATE_16000 16000
+#define PROXY_SUPPORTED_RATE_48000 48000
namespace android_audio_legacy
{
@@ -63,6 +67,10 @@
musbpfdPlayback = -1;
mkillPlayBackThread = false;
mkillRecordingThread = false;
+ musbRecordingHandle = NULL;
+ mproxyRecordingHandle = NULL;
+ musbPlaybackHandle = NULL;
+ mproxyPlaybackHandle = NULL;
}
AudioUsbALSA::~AudioUsbALSA()
@@ -117,7 +125,11 @@
fileSize = st.st_size;
- read_buf = (char *)malloc(BUFFSIZE);
+ if ((read_buf = (char *)malloc(BUFFSIZE)) == NULL) {
+ ALOGE("ERROR: Unable to allocate memory to hold stream caps");
+ close(fd);
+ return NO_MEMORY;
+ }
memset(read_buf, 0x0, BUFFSIZE);
err = read(fd, read_buf, BUFFSIZE);
str_start = strstr(read_buf, type);
@@ -175,8 +187,19 @@
return UNKNOWN_ERROR;
}
size = target - ratesStrStart;
- ratesStr = (char *)malloc(size + 1) ;
- ratesStrForVal = (char *)malloc(size + 1) ;
+ if ((ratesStr = (char *)malloc(size + 1)) == NULL) {
+ ALOGE("ERROR: Unable to allocate memory to hold sample rate strings");
+ close(fd);
+ free(read_buf);
+ return NO_MEMORY;
+ }
+ if ((ratesStrForVal = (char *)malloc(size + 1)) == NULL) {
+ ALOGE("ERROR: Unable to allocate memory to hold sample rate string");
+ close(fd);
+ free(ratesStr);
+ free(read_buf);
+ return NO_MEMORY;
+ }
memcpy(ratesStr, ratesStrStart, size);
memcpy(ratesStrForVal, ratesStrStart, size);
ratesStr[size] = '\0';
@@ -205,16 +228,22 @@
}
ratesSupported[0] = atoi(nextSRString);
+ ALOGV("ratesSupported[0] for playback: %d", ratesSupported[0]);
for (i = 1; i<size; i++) {
nextSRString = strtok_r(NULL, " ,.-", &temp_ptr);
ratesSupported[i] = atoi(nextSRString);
ALOGV("ratesSupported[%d] for playback: %d",i, ratesSupported[i]);
}
- for (i = 0; i<=size; i++) {
- if (ratesSupported[i] <= 48000) {
- sampleRate = ratesSupported[i];
- break;
+ for (i = 0; i<size; i++) {
+ if ((ratesSupported[i] > sampleRate) && (ratesSupported[i] <= 48000)) {
+ // Sample Rate should be one of the proxy supported rates only
+ // This is because proxy port is used to read from/write to DSP .
+ if ((ratesSupported[i] == PROXY_SUPPORTED_RATE_8000) ||
+ (ratesSupported[i] == PROXY_SUPPORTED_RATE_16000) ||
+ (ratesSupported[i] == PROXY_SUPPORTED_RATE_48000)) {
+ sampleRate = ratesSupported[i];
+ }
}
}
ALOGD("sampleRate: %d", sampleRate);
@@ -232,42 +261,60 @@
void AudioUsbALSA::exitPlaybackThread(uint64_t writeVal)
{
ALOGD("exitPlaybackThread, mproxypfdPlayback: %d", mproxypfdPlayback);
- if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
- int err;
-
- err = closeDevice(mproxyPlaybackHandle);
- if (err) {
- ALOGE("Info: Could not close proxy %p", mproxyPlaybackHandle);
- }
- err = closeDevice(musbPlaybackHandle);
- if (err) {
- ALOGE("Info: Could not close USB device %p", musbPlaybackHandle);
- }
- }
+ mkillPlayBackThread = true;
if ((mproxypfdPlayback != -1) && (musbpfdPlayback != -1)) {
write(mproxypfdPlayback, &writeVal, sizeof(uint64_t));
write(musbpfdPlayback, &writeVal, sizeof(uint64_t));
- mkillPlayBackThread = true;
pthread_join(mPlaybackUsb,NULL);
+ mPlaybackUsb = NULL;
+ }
+ if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
+ int err;
+ {
+ Mutex::Autolock autoLock(mLock);
+ err = closeDevice(mproxyPlaybackHandle);
+ if (err) {
+ ALOGE("Info: Could not close proxy %p", mproxyPlaybackHandle);
+ }
+ err = closeDevice(musbPlaybackHandle);
+ if (err) {
+ ALOGE("Info: Could not close USB device %p", musbPlaybackHandle);
+ }
+ }
}
}
void AudioUsbALSA::exitRecordingThread(uint64_t writeVal)
{
+ //TODO: Need to use userspace fd to kill the thread.
+ // Not a valid assumption to blindly close the thread.
ALOGD("exitRecordingThread");
- if (writeVal == SIGNAL_EVENT_KILLTHREAD) {
- int err;
+ mkillRecordingThread = true;
- err = closeDevice(mproxyRecordingHandle);
- if (err) {
- ALOGE("Info: Could not close proxy for recording %p", mproxyRecordingHandle);
- }
- err = closeDevice(musbRecordingHandle);
- if (err) {
- ALOGE("Info: Could not close USB recording device %p", musbRecordingHandle);
+ if ((pfdProxyRecording[0].fd != -1) && (pfdUsbRecording[0].fd != -1)) {
+ write(pfdProxyRecording[0].fd, &writeVal, sizeof(uint64_t));
+ write(pfdUsbRecording[0].fd, &writeVal, sizeof(uint64_t));
+ pthread_join(mRecordingUsb,NULL);
+ mRecordingUsb = NULL;
+ }
+ if (writeVal == SIGNAL_EVENT_KILLTHREAD ) {
+ int err;
+ {
+ Mutex::Autolock autoLock(mLock);
+ err = closeDevice(mproxyRecordingHandle);
+ if (err) {
+ ALOGE("Info: Could not close proxy for recording %p", mproxyRecordingHandle);
+ } else {
+ mproxyRecordingHandle = NULL;
+ }
+ err = closeDevice(musbRecordingHandle);
+ if (err) {
+ ALOGE("Info: Could not close USB recording device %p", musbRecordingHandle);
+ } else {
+ musbRecordingHandle = NULL;
+ }
}
}
- mkillRecordingThread = true;
}
void AudioUsbALSA::setkillUsbRecordingThread(bool val){
@@ -308,6 +355,7 @@
if (param_set_hw_params(txHandle, params)) {
ALOGE("ERROR: cannot set hw params");
+ free(params);
return NO_INIT;
}
@@ -321,6 +369,7 @@
txHandle->buffer_size, txHandle->period_size,
txHandle->period_cnt);
+ free(params);
return NO_ERROR;
}
@@ -347,7 +396,8 @@
params->start_threshold = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
}
- params->stop_threshold = pcm->buffer_size;
+ //Setting stop threshold to a huge value to avoid trigger stop being called internally
+ params->stop_threshold = 0x0FFFFFFF;
params->xfer_align = (pcm->flags & PCM_MONO) ? pcm->period_size/2 : pcm->period_size/4;
params->silence_size = 0;
@@ -355,9 +405,10 @@
if (param_set_sw_params(pcm, params)) {
ALOGE("ERROR: cannot set sw params");
+ free(params);
return NO_INIT;
}
-
+ free(params);
return NO_ERROR;
}
@@ -383,7 +434,6 @@
long frames;
static int start = 0;
struct snd_xferi x;
- int filed;
unsigned avail, bufsize;
int bytes_written;
uint32_t sampleRate;
@@ -391,8 +441,8 @@
u_int8_t *srcUsb_addr = NULL;
u_int8_t *dstProxy_addr = NULL;
int err;
- const char *fn = "/data/RecordPcm.pcm";
- filed = open(fn, O_WRONLY | O_CREAT | O_TRUNC | O_APPEND, 0664);
+ pfdProxyRecording[0].fd = -1;
+ pfdUsbRecording[0].fd = -1 ;
err = getCap((char *)"Capture:", mchannelsCapture, msampleRateCapture);
if (err) {
@@ -420,7 +470,13 @@
msampleRateCapture, mchannelsCapture,768,false);
if (!mproxyRecordingHandle) {
ALOGE("ERROR: Could not configure Proxy for recording");
- closeDevice(musbRecordingHandle);
+ {
+ Mutex::Autolock autoLock(mLock);
+ err = closeDevice(musbRecordingHandle);
+ if(err == OK) {
+ musbRecordingHandle = NULL;
+ }
+ }
return;
} else {
ALOGD("Proxy Configured for recording");
@@ -558,7 +614,7 @@
bytes_written = mproxyRecordingHandle->sync_ptr->c.control.appl_ptr - mproxyRecordingHandle->sync_ptr->s.status.hw_ptr;
if ((bytes_written >= mproxyRecordingHandle->sw_p->start_threshold) && (!mproxyRecordingHandle->start)) {
- if (!mkillPlayBackThread) {
+ if (!mkillRecordingThread) {
err = startDevice(mproxyRecordingHandle, &mkillRecordingThread);
if (err == EPIPE) {
continue;
@@ -571,9 +627,19 @@
}
/*************** End sync up after write -- Proxy *********************/
if (mkillRecordingThread) {
- closeDevice(mproxyRecordingHandle);
- closeDevice(musbRecordingHandle);
+ {
+ Mutex::Autolock autoLock(mLock);
+ err = closeDevice(mproxyRecordingHandle);
+ if(err == OK) {
+ mproxyRecordingHandle = NULL;
+ }
+ err = closeDevice(musbRecordingHandle);
+ if(err == OK) {
+ musbRecordingHandle = NULL;
+ }
+ }
}
+ mRecordingUsb = NULL;
ALOGD("Exiting USB Recording thread");
}
@@ -606,29 +672,41 @@
err = setHardwareParams(handle, sampleRate, channelCount,periodSize);
if (err != NO_ERROR) {
ALOGE("ERROR: setHardwareParams failed");
- closeDevice(handle);
- return NULL;
+ {
+ Mutex::Autolock autoLock(mLock);
+ closeDevice(handle);
+ return NULL;
+ }
}
err = setSoftwareParams(handle, playback);
if (err != NO_ERROR) {
ALOGE("ERROR: setSoftwareParams failed");
- closeDevice(handle);
- return NULL;
+ {
+ Mutex::Autolock autoLock(mLock);
+ closeDevice(handle);
+ return NULL;
+ }
}
err = mmap_buffer(handle);
if (err) {
ALOGE("ERROR: mmap_buffer failed");
- closeDevice(handle);
- return NULL;
+ {
+ Mutex::Autolock autoLock(mLock);
+ closeDevice(handle);
+ return NULL;
+ }
}
err = pcm_prepare(handle);
if (err) {
ALOGE("ERROR: pcm_prepare failed");
- closeDevice(handle);
- return NULL;
+ {
+ Mutex::Autolock autoLock(mLock);
+ closeDevice(handle);
+ return NULL;
+ }
}
return handle;
@@ -756,7 +834,7 @@
return;
}
- if (pfdUsbPlayback[0].revents & POLLERR || pfdProxyPlayback[0].revents & POLLHUP ||
+ if (pfdUsbPlayback[0].revents & POLLERR || pfdUsbPlayback[0].revents & POLLHUP ||
pfdUsbPlayback[0].revents & POLLNVAL) {
ALOGE("Info: usb throwing error");
mkillPlayBackThread = true;
@@ -780,8 +858,6 @@
unsigned int tmp;
int numOfBytesWritten;
int err;
- int filed;
- const char *fn = "/data/test.pcm";
mdstUsb_addr = NULL;
msrcProxy_addr = NULL;
@@ -801,7 +877,13 @@
msampleRatePlayback, mchannelsPlayback, USB_PERIOD_SIZE, true);
if (!musbPlaybackHandle) {
ALOGE("ERROR: configureUsbDevice failed, returning");
- closeDevice(musbPlaybackHandle);
+ {
+ Mutex::Autolock autoLock(mLock);
+ err = closeDevice(musbPlaybackHandle);
+ if(err == OK) {
+ musbPlaybackHandle = NULL;
+ }
+ }
return;
} else {
ALOGD("USB Configured for playback");
@@ -819,7 +901,13 @@
msampleRatePlayback, mchannelsPlayback, PROXY_PERIOD_SIZE, false);
if (!mproxyPlaybackHandle) {
ALOGE("ERROR: Could not configure Proxy, returning");
- closeDevice(musbPlaybackHandle);
+ {
+ Mutex::Autolock autoLock(mLock);
+ err = closeDevice(musbPlaybackHandle);
+ if(err == OK) {
+ musbPlaybackHandle = NULL;
+ }
+ }
return;
} else {
ALOGD("Proxy Configured for playback");
@@ -833,7 +921,7 @@
pfdProxyPlayback[0].events = (POLLIN); // | POLLERR | POLLNVAL);
mproxypfdPlayback = eventfd(0,0);
pfdProxyPlayback[1].fd = mproxypfdPlayback;
- pfdProxyPlayback[1].events = (POLLIN | POLLOUT| POLLERR | POLLNVAL);
+ pfdProxyPlayback[1].events = (POLLIN | POLLERR | POLLNVAL);
}
frames = (mproxyPlaybackHandle->flags & PCM_MONO) ? (proxyPeriod / 2) : (proxyPeriod / 4);
@@ -842,9 +930,17 @@
u_int8_t *proxybuf = ( u_int8_t *) malloc(PROXY_PERIOD_SIZE);
u_int8_t *usbbuf = ( u_int8_t *) malloc(USB_PERIOD_SIZE);
- memset(proxybuf, 0x0, PROXY_PERIOD_SIZE);
- memset(usbbuf, 0x0, USB_PERIOD_SIZE);
+ if (proxybuf == NULL || usbbuf == NULL) {
+ ALOGE("ERROR: Unable to allocate USB audio buffer(s): proxybuf=%p, usbbuf=%p",
+ proxybuf, usbbuf);
+ /* Don't run the playback loop if we failed to allocate either of these buffers.
+ If either pointer is non-NULL they'll be freed after the end of the loop. */
+ mkillPlayBackThread = true;
+ } else {
+ memset(proxybuf, 0x0, PROXY_PERIOD_SIZE);
+ memset(usbbuf, 0x0, USB_PERIOD_SIZE);
+ }
/***********************keep reading from proxy and writing to USB******************************************/
while (mkillPlayBackThread != true) {
@@ -928,12 +1024,12 @@
err = syncPtr(mproxyPlaybackHandle, &mkillPlayBackThread);
if (err == EPIPE) {
continue;
- } else if (err != NO_ERROR) {
+ } else if (err != NO_ERROR && err != ENODEV) {
break;
}
}
}
- //ALOGE("usbSizeFilled %d, proxySizeRemaining %d ",usbSizeFilled,proxySizeRemaining);
+ //ALOGV("usbSizeFilled %d, proxySizeRemaining %d ",usbSizeFilled,proxySizeRemaining);
if (usbPeriod - usbSizeFilled <= proxySizeRemaining) {
memcpy(usbbuf + usbSizeFilled, proxybuf + proxyPeriod - proxySizeRemaining, usbPeriod - usbSizeFilled);
proxySizeRemaining -= (usbPeriod - usbSizeFilled);
@@ -1000,20 +1096,20 @@
err = syncPtr(musbPlaybackHandle, &mkillPlayBackThread);
if (err == EPIPE) {
continue;
- } else if (err != NO_ERROR) {
+ } else if (err != NO_ERROR && err != ENODEV ) {
break;
}
}
bytes_written = musbPlaybackHandle->sync_ptr->c.control.appl_ptr - musbPlaybackHandle->sync_ptr->s.status.hw_ptr;
- ALOGE("Appl ptr %d , hw_ptr %d, difference %d",musbPlaybackHandle->sync_ptr->c.control.appl_ptr, musbPlaybackHandle->sync_ptr->s.status.hw_ptr, bytes_written);
+ ALOGV("Appl ptr %lu , hw_ptr %lu, difference %d",musbPlaybackHandle->sync_ptr->c.control.appl_ptr, musbPlaybackHandle->sync_ptr->s.status.hw_ptr, bytes_written);
/*
Following is the check to prevent USB from going to bad state.
This happens in case of an underrun where there is not enough
data from the proxy
*/
- if (bytes_written <= usbPeriod && musbPlaybackHandle->start) {
+ if (bytes_written <= usbPeriod && musbPlaybackHandle->start) {
ioctl(musbPlaybackHandle->fd, SNDRV_PCM_IOCTL_PAUSE,1);
pcm_prepare(musbPlaybackHandle);
musbPlaybackHandle->start = false;
@@ -1033,16 +1129,36 @@
/*************** End sync up after write -- USB *********************/
}
}
- if (mkillPlayBackThread) {
- if (proxybuf)
- free(proxybuf);
- if (usbbuf)
- free(usbbuf);
+ if (proxybuf)
+ free(proxybuf);
+ if (usbbuf)
+ free(usbbuf);
+ if(mproxypfdPlayback != -1) {
+ close(mproxypfdPlayback);
mproxypfdPlayback = -1;
- musbpfdPlayback = -1;
- closeDevice(mproxyPlaybackHandle);
- closeDevice(musbPlaybackHandle);
}
+ if(musbpfdPlayback != -1) {
+ close(musbpfdPlayback);
+ musbpfdPlayback = -1;
+ }
+ if(mkillPlayBackThread) {
+ {
+ Mutex::Autolock autoLock(mLock);
+ err = closeDevice(mproxyPlaybackHandle);
+ if(err == OK) {
+ mproxyPlaybackHandle = NULL;
+ } else {
+ ALOGE("mproxyPlaybackHandle - err = %d", err);
+ }
+ err = closeDevice(musbPlaybackHandle);
+ if(err == OK) {
+ musbPlaybackHandle = NULL;
+ } else {
+ ALOGE("musbPlaybackHandle - err = %d", err);
+ }
+ }
+ }
+ mPlaybackUsb = NULL;
ALOGD("Exiting USB Playback Thread");
}
diff --git a/alsa_sound/AudioUsbALSA.h b/alsa_sound/AudioUsbALSA.h
index 4204eb0..d408d1e 100644
--- a/alsa_sound/AudioUsbALSA.h
+++ b/alsa_sound/AudioUsbALSA.h
@@ -1,6 +1,6 @@
/* AudioUsbALSA.h
-Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ Copyright (c) 2012, The Linux Foundation. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -85,6 +85,7 @@
pthread_t mPlaybackUsb;
pthread_t mRecordingUsb;
snd_use_case_mgr_t *mUcMgr;
+ Mutex mLock;
//Helper functions
struct pcm * configureDevice(unsigned flags, char* hw, int sampleRate, int channelCount, int periodSize, bool playback);
diff --git a/alsa_sound/AudioUtil.cpp b/alsa_sound/AudioUtil.cpp
index 3549f24..98131e9 100644
--- a/alsa_sound/AudioUtil.cpp
+++ b/alsa_sound/AudioUtil.cpp
@@ -1,6 +1,6 @@
/* AudioUtil.cpp
*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/alsa_sound/AudioUtil.h b/alsa_sound/AudioUtil.h
index 6575315..70e5194 100644
--- a/alsa_sound/AudioUtil.h
+++ b/alsa_sound/AudioUtil.h
@@ -1,6 +1,6 @@
/* AudioUtil.h
*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
diff --git a/alsa_sound/alsa_default.cpp b/alsa_sound/alsa_default.cpp
deleted file mode 100644
index 7f477b5..0000000
--- a/alsa_sound/alsa_default.cpp
+++ /dev/null
@@ -1,1798 +0,0 @@
-/* alsa_default.cpp
- **
- ** Copyright 2009 Wind River Systems
- ** Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
- **
- ** 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.
- */
-
-#define LOG_TAG "ALSAModule"
-//#define LOG_NDEBUG 0
-#define LOG_NDDEBUG 0
-#include <utils/Log.h>
-#include <cutils/properties.h>
-#include <linux/ioctl.h>
-#include "AudioUtil.h"
-#include "AudioHardwareALSA.h"
-#include <media/AudioRecord.h>
-#include <dlfcn.h>
-#ifdef QCOM_CSDCLIENT_ENABLED
-extern "C" {
-static int (*csd_disable_device)();
-static int (*csd_enable_device)(int, int, uint32_t);
-static int (*csd_volume)(int);
-static int (*csd_mic_mute)(int);
-static int (*csd_wide_voice)(uint8_t);
-static int (*csd_slow_talk)(uint8_t);
-static int (*csd_fens)(uint8_t);
-static int (*csd_start_voice)();
-static int (*csd_stop_voice)();
-}
-#endif
-
-#ifndef ALSA_DEFAULT_SAMPLE_RATE
-#define ALSA_DEFAULT_SAMPLE_RATE 44100 // in Hz
-#endif
-
-#define BTSCO_RATE_16KHZ 16000
-#define USECASE_TYPE_RX 1
-#define USECASE_TYPE_TX 2
-#define MAX_HDMI_CHANNEL_CNT 6
-
-namespace android_audio_legacy
-{
-
-static int s_device_open(const hw_module_t*, const char*, hw_device_t**);
-static int s_device_close(hw_device_t*);
-static status_t s_init(alsa_device_t *, ALSAHandleList &);
-static status_t s_open(alsa_handle_t *);
-static status_t s_close(alsa_handle_t *);
-static status_t s_standby(alsa_handle_t *);
-static status_t s_route(alsa_handle_t *, uint32_t, int);
-static status_t s_start_voice_call(alsa_handle_t *);
-static status_t s_start_voip_call(alsa_handle_t *);
-static status_t s_start_fm(alsa_handle_t *);
-static void s_set_voice_volume(int);
-static void s_set_voip_volume(int);
-static void s_set_mic_mute(int);
-static void s_set_voip_mic_mute(int);
-static void s_set_voip_config(int, int);
-static status_t s_set_fm_vol(int);
-static void s_set_btsco_rate(int);
-static status_t s_set_lpa_vol(int);
-static void s_enable_wide_voice(bool flag);
-static void s_enable_fens(bool flag);
-static void s_set_flags(uint32_t flags);
-static status_t s_set_compressed_vol(int);
-static void s_enable_slow_talk(bool flag);
-static void s_set_voc_rec_mode(uint8_t mode);
-static void s_set_volte_mic_mute(int state);
-static void s_set_volte_volume(int vol);
-#ifdef SEPERATED_AUDIO_INPUT
-static void s_setInput(int);
-
-static int input_source;
-#endif
-#ifdef QCOM_CSDCLIENT_ENABLED
-static void s_set_csd_handle(void*);
-#endif
-
-static char mic_type[25];
-static char curRxUCMDevice[50];
-static char curTxUCMDevice[50];
-static int fluence_mode;
-static int fmVolume;
-#ifdef USES_FLUENCE_INCALL
-static uint32_t mDevSettingsFlag = TTY_OFF | DMIC_FLAG;
-#else
-static uint32_t mDevSettingsFlag = TTY_OFF;
-#endif
-static int btsco_samplerate = 8000;
-static ALSAUseCaseList mUseCaseList;
-static void *csd_handle;
-
-static hw_module_methods_t s_module_methods = {
- open : s_device_open
-};
-
-extern "C" {
-hw_module_t HAL_MODULE_INFO_SYM = {
- tag : HARDWARE_MODULE_TAG,
- version_major : 1,
- version_minor : 0,
- id : ALSA_HARDWARE_MODULE_ID,
- name : "QCOM ALSA module",
- author : "QuIC Inc",
- methods : &s_module_methods,
- dso : 0,
- reserved : {0,},
-};
-}
-
-static int s_device_open(const hw_module_t* module, const char* name,
- hw_device_t** device)
-{
- char value[128];
- alsa_device_t *dev;
- dev = (alsa_device_t *) malloc(sizeof(*dev));
- if (!dev) return -ENOMEM;
-
- memset(dev, 0, sizeof(*dev));
-
- /* initialize the procs */
- dev->common.tag = HARDWARE_DEVICE_TAG;
- dev->common.version = 0;
- dev->common.module = (hw_module_t *) module;
- dev->common.close = s_device_close;
- dev->init = s_init;
- dev->open = s_open;
- dev->close = s_close;
- dev->route = s_route;
- dev->standby = s_standby;
- dev->startVoiceCall = s_start_voice_call;
- dev->startVoipCall = s_start_voip_call;
- dev->startFm = s_start_fm;
- dev->setVoiceVolume = s_set_voice_volume;
- dev->setVoipVolume = s_set_voip_volume;
- dev->setMicMute = s_set_mic_mute;
- dev->setVoipMicMute = s_set_voip_mic_mute;
- dev->setVoipConfig = s_set_voip_config;
- dev->setFmVolume = s_set_fm_vol;
- dev->setBtscoRate = s_set_btsco_rate;
- dev->setLpaVolume = s_set_lpa_vol;
- dev->enableWideVoice = s_enable_wide_voice;
- dev->enableFENS = s_enable_fens;
- dev->setFlags = s_set_flags;
- dev->setCompressedVolume = s_set_compressed_vol;
- dev->enableSlowTalk = s_enable_slow_talk;
- dev->setVocRecMode = s_set_voc_rec_mode;
- dev->setVoLTEMicMute = s_set_volte_mic_mute;
- dev->setVoLTEVolume = s_set_volte_volume;
-#ifdef SEPERATED_AUDIO_INPUT
- dev->setInput = s_setInput;
-#endif
-#ifdef QCOM_CSDCLIENT_ENABLED
- dev->setCsdHandle = s_set_csd_handle;
-#endif
- *device = &dev->common;
-
- property_get("persist.audio.handset.mic",value,"0");
- strlcpy(mic_type, value, sizeof(mic_type));
- property_get("persist.audio.fluence.mode",value,"0");
- if (!strcmp("broadside", value)) {
- fluence_mode = FLUENCE_MODE_BROADSIDE;
- } else {
- fluence_mode = FLUENCE_MODE_ENDFIRE;
- }
- strlcpy(curRxUCMDevice, "None", sizeof(curRxUCMDevice));
- strlcpy(curTxUCMDevice, "None", sizeof(curTxUCMDevice));
- ALOGV("ALSA module opened");
-
- return 0;
-}
-
-static int s_device_close(hw_device_t* device)
-{
- free(device);
- device = NULL;
- return 0;
-}
-
-// ----------------------------------------------------------------------------
-
-static const int DEFAULT_SAMPLE_RATE = ALSA_DEFAULT_SAMPLE_RATE;
-
-static void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode);
-static char *getUCMDevice(uint32_t devices, int input, char *rxDevice);
-static void disableDevice(alsa_handle_t *handle);
-int getUseCaseType(const char *useCase);
-
-static int callMode = AudioSystem::MODE_NORMAL;
-// ----------------------------------------------------------------------------
-
-bool platform_is_Fusion3()
-{
- char platform[128], baseband[128];
- property_get("ro.board.platform", platform, "");
- property_get("ro.baseband", baseband, "");
- if (!strcmp("msm8960", platform) && !strcmp("mdm", baseband))
- return true;
- else
- return false;
-}
-
-int deviceName(alsa_handle_t *handle, unsigned flags, char **value)
-{
- int ret = 0;
- char ident[70];
-
- if (flags & PCM_IN) {
- strlcpy(ident, "CapturePCM/", sizeof(ident));
- } else {
- strlcpy(ident, "PlaybackPCM/", sizeof(ident));
- }
- strlcat(ident, handle->useCase, sizeof(ident));
- ret = snd_use_case_get(handle->ucMgr, ident, (const char **)value);
- ALOGD("Device value returned is %s", (*value));
- return ret;
-}
-
-status_t setHDMIChannelCount()
-{
- status_t err = NO_ERROR;
- int channel_count = 0;
- const char *channel_cnt_str = NULL;
- EDID_AUDIO_INFO info = { 0 };
-
- ALSAControl control("/dev/snd/controlC0");
- if (AudioUtil::getHDMIAudioSinkCaps(&info)) {
- for (int i = 0; i < info.nAudioBlocks && i < MAX_EDID_BLOCKS; i++) {
- if (info.AudioBlocksArray[i].nChannels > channel_count &&
- info.AudioBlocksArray[i].nChannels <= MAX_HDMI_CHANNEL_CNT) {
- channel_count = info.AudioBlocksArray[i].nChannels;
- }
- }
- }
-
- switch (channel_count) {
- case 6: channel_cnt_str = "Six"; break;
- case 5: channel_cnt_str = "Five"; break;
- case 4: channel_cnt_str = "Four"; break;
- case 3: channel_cnt_str = "Three"; break;
- default: channel_cnt_str = "Two"; break;
- }
- ALOGD("HDMI channel count: %s", channel_cnt_str);
- control.set("HDMI_RX Channels", channel_cnt_str);
-
- return err;
-}
-
-status_t setHardwareParams(alsa_handle_t *handle)
-{
- struct snd_pcm_hw_params *params;
- unsigned long bufferSize, reqBuffSize;
- unsigned int periodTime, bufferTime;
- unsigned int requestedRate = handle->sampleRate;
- int status = 0;
- int channels = handle->channels;
- snd_pcm_format_t format = SNDRV_PCM_FORMAT_S16_LE;
-
- params = (snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
- if (!params) {
- ALOGE("Failed to allocate ALSA hardware parameters!");
- return NO_INIT;
- }
-
- reqBuffSize = handle->bufferSize;
- ALOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d",
- (int) reqBuffSize, handle->channels, handle->sampleRate);
-
-#ifdef QCOM_SSR_ENABLED
- if (channels == 6) {
- if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
- || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
- ALOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
- channels = 4;
- }
- }
-#endif
-
- param_init(params);
- param_set_mask(params, SNDRV_PCM_HW_PARAM_ACCESS,
- SNDRV_PCM_ACCESS_RW_INTERLEAVED);
- if (handle->format != SNDRV_PCM_FORMAT_S16_LE) {
- if (handle->format == AudioSystem::AMR_NB
- || handle->format == AudioSystem::AMR_WB
-#ifdef QCOM_QCHAT_ENABLED
- || handle->format == AudioSystem::EVRC
- || handle->format == AudioSystem::EVRCB
- || handle->format == AudioSystem::EVRCWB
-#endif
- )
- format = SNDRV_PCM_FORMAT_SPECIAL;
- }
- param_set_mask(params, SNDRV_PCM_HW_PARAM_FORMAT,
- format);
- param_set_mask(params, SNDRV_PCM_HW_PARAM_SUBFORMAT,
- SNDRV_PCM_SUBFORMAT_STD);
- param_set_int(params, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, reqBuffSize);
- param_set_int(params, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 16);
- param_set_int(params, SNDRV_PCM_HW_PARAM_FRAME_BITS,
- channels * 16);
- param_set_int(params, SNDRV_PCM_HW_PARAM_CHANNELS,
- channels);
- param_set_int(params, SNDRV_PCM_HW_PARAM_RATE, handle->sampleRate);
- param_set_hw_refine(handle->handle, params);
-
- if (param_set_hw_params(handle->handle, params)) {
- ALOGE("cannot set hw params");
- return NO_INIT;
- }
- param_dump(params);
-
- handle->handle->buffer_size = pcm_buffer_size(params);
- handle->handle->period_size = pcm_period_size(params);
- handle->handle->period_cnt = handle->handle->buffer_size/handle->handle->period_size;
- ALOGD("setHardwareParams: buffer_size %d, period_size %d, period_cnt %d",
- handle->handle->buffer_size, handle->handle->period_size,
- handle->handle->period_cnt);
- handle->handle->rate = handle->sampleRate;
- handle->handle->channels = handle->channels;
- handle->periodSize = handle->handle->period_size;
- if (strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC) &&
- strcmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC) &&
- (6 != handle->channels)) {
- //Do not update buffersize for 5.1 recording
- handle->bufferSize = handle->handle->period_size;
- }
-
- return NO_ERROR;
-}
-
-status_t setSoftwareParams(alsa_handle_t *handle)
-{
- struct snd_pcm_sw_params* params;
- struct pcm* pcm = handle->handle;
-
- unsigned long periodSize = pcm->period_size;
- int channels = handle->channels;
-
- params = (snd_pcm_sw_params*) calloc(1, sizeof(struct snd_pcm_sw_params));
- if (!params) {
- LOG_ALWAYS_FATAL("Failed to allocate ALSA software parameters!");
- return NO_INIT;
- }
-
-#ifdef QCOM_SSR_ENABLED
- if (channels == 6) {
- if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
- || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
- ALOGV("SWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
- channels = 4;
- }
- }
-#endif
-
- // Get the current software parameters
- params->tstamp_mode = SNDRV_PCM_TSTAMP_NONE;
- params->period_step = 1;
- if(((!strcmp(handle->useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
- (!strcmp(handle->useCase,SND_USE_CASE_VERB_IP_VOICECALL)))){
- ALOGV("setparam: start & stop threshold for Voip ");
- params->avail_min = handle->channels - 1 ? periodSize/4 : periodSize/2;
- params->start_threshold = periodSize/2;
- params->stop_threshold = INT_MAX;
- } else {
- params->avail_min = periodSize/(channels * 2);
- params->start_threshold = periodSize/(channels * 2);
- params->stop_threshold = INT_MAX;
- }
- params->silence_threshold = 0;
- params->silence_size = 0;
-
- if (param_set_sw_params(handle->handle, params)) {
- ALOGE("cannot set sw params");
- return NO_INIT;
- }
- return NO_ERROR;
-}
-
-void switchDevice(alsa_handle_t *handle, uint32_t devices, uint32_t mode)
-{
- const char **mods_list;
- use_case_t useCaseNode;
- unsigned usecase_type = 0;
- bool inCallDevSwitch = false;
- char *rxDevice, *txDevice, ident[70], *use_case = NULL;
- int err = 0, index, mods_size;
- int rx_dev_id, tx_dev_id;
- ALOGD("%s: device %d mode:%d", __FUNCTION__, devices, mode);
-
- if ((mode == AudioSystem::MODE_IN_CALL) || (mode == AudioSystem::MODE_IN_COMMUNICATION)) {
- if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
- (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET)) {
- devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADSET |
- AudioSystem::DEVICE_IN_WIRED_HEADSET);
- } else if (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) {
- devices = devices | (AudioSystem::DEVICE_OUT_WIRED_HEADPHONE |
- AudioSystem::DEVICE_IN_BUILTIN_MIC);
- } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
- if (mode == AudioSystem::MODE_IN_CALL) {
- devices |= AudioSystem::DEVICE_OUT_EARPIECE;
-//use QCOM_BACK_MIC_ENABLED only when BACK_MIC is supported by HW
-#ifdef QCOM_BACK_MIC_ENABLED
- } else if (mode == AudioSystem::MODE_IN_COMMUNICATION) {
- if (!strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER, MAX_LEN(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER))) {
- devices &= ~AudioSystem::DEVICE_IN_BUILTIN_MIC;
- devices |= AudioSystem::DEVICE_IN_BACK_MIC;
- }
-#endif
- }
- } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
- devices = devices | AudioSystem::DEVICE_IN_BUILTIN_MIC;
- } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
-#ifdef QCOM_BACK_MIC_ENABLED
- devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC |
-#else
- devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
-#endif
- AudioSystem::DEVICE_OUT_SPEAKER);
- } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
- (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
- (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET)) {
- devices = devices | (AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET |
- AudioSystem::DEVICE_OUT_BLUETOOTH_SCO);
-#ifdef QCOM_ANC_HEADSET_ENABLED
- } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
- (devices & AudioSystem::DEVICE_IN_ANC_HEADSET)) {
- devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADSET |
- AudioSystem::DEVICE_IN_ANC_HEADSET);
- } else if (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
- devices = devices | (AudioSystem::DEVICE_OUT_ANC_HEADPHONE |
- AudioSystem::DEVICE_IN_BUILTIN_MIC);
-#endif
- } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
- if (mode == AudioSystem::MODE_IN_CALL)
-#ifdef QCOM_BACK_MIC_ENABLED
- devices = devices | (AudioSystem::DEVICE_IN_BACK_MIC |
-#else
- devices = devices | (AudioSystem::DEVICE_IN_BUILTIN_MIC |
-#endif
- AudioSystem::DEVICE_OUT_SPEAKER);
- else
- devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL |
-#ifdef QCOM_BACK_MIC_ENABLED
- AudioSystem::DEVICE_IN_BACK_MIC);
-#else
- AudioSystem::DEVICE_IN_BUILTIN_MIC);
-#endif
-#ifdef QCOM_PROXY_DEVICE_ENABLED
- } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) ||
- (devices & AudioSystem::DEVICE_IN_PROXY)) {
- devices = devices | (AudioSystem::DEVICE_OUT_PROXY |
- AudioSystem::DEVICE_IN_PROXY);
-#endif
- }
- }
-#ifdef QCOM_SSR_ENABLED
- if ((devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) && ( 6 == handle->channels)) {
- if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
- || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
- ALOGV(" switchDevice , use ssr devices for channels:%d usecase:%s",handle->channels,handle->useCase);
- s_set_flags(SSRQMIC_FLAG);
- }
- }
-#endif
-
- rxDevice = getUCMDevice(devices & AudioSystem::DEVICE_OUT_ALL, 0, NULL);
- txDevice = getUCMDevice(devices & AudioSystem::DEVICE_IN_ALL, 1, rxDevice);
-
- if ((rxDevice != NULL) && (txDevice != NULL)) {
- if (((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) ||
- (strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN))) &&
- ((mode == AudioSystem::MODE_IN_CALL) ||
- (mode == AudioSystem::MODE_IN_COMMUNICATION)))
- inCallDevSwitch = true;
- }
-
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
- if (csd_disable_device == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
- } else {
- err = csd_disable_device();
- if (err < 0)
- {
- ALOGE("csd_client_disable_device, failed, error %d", err);
- }
- }
- }
-#endif
-
- snd_use_case_get(handle->ucMgr, "_verb", (const char **)&use_case);
- mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
- if (rxDevice != NULL) {
- if ((strncmp(curRxUCMDevice, "None", 4)) &&
- ((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
- if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
- strlen(SND_USE_CASE_VERB_INACTIVE)))) {
- usecase_type = getUseCaseType(use_case);
- if (usecase_type & USECASE_TYPE_RX) {
- ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
- strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
- snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
- mUseCaseList.push_front(useCaseNode);
- }
- }
- if (mods_size) {
- for(index = 0; index < mods_size; index++) {
- usecase_type = getUseCaseType(mods_list[index]);
- if (usecase_type & USECASE_TYPE_RX) {
- ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
- strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
- snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
- mUseCaseList.push_back(useCaseNode);
- }
- }
- }
- snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice);
- }
- }
- if (txDevice != NULL) {
- if ((strncmp(curTxUCMDevice, "None", 4)) &&
- ((strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN)) || (inCallDevSwitch == true))) {
- if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
- strlen(SND_USE_CASE_VERB_INACTIVE)))) {
- usecase_type = getUseCaseType(use_case);
- if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
- ALOGD("Deroute use case %s type is %d\n", use_case, usecase_type);
- strlcpy(useCaseNode.useCase, use_case, MAX_STR_LEN);
- snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
- mUseCaseList.push_front(useCaseNode);
- }
- }
- if (mods_size) {
- for(index = 0; index < mods_size; index++) {
- usecase_type = getUseCaseType(mods_list[index]);
- if ((usecase_type & USECASE_TYPE_TX) && (!(usecase_type & USECASE_TYPE_RX))) {
- ALOGD("Deroute use case %s type is %d\n", mods_list[index], usecase_type);
- strlcpy(useCaseNode.useCase, mods_list[index], MAX_STR_LEN);
- snd_use_case_set(handle->ucMgr, "_dismod", mods_list[index]);
- mUseCaseList.push_back(useCaseNode);
- }
- }
- }
- snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice);
- }
- }
- ALOGD("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, curRxUCMDevice, curTxUCMDevice);
-
- if (rxDevice != NULL) {
- snd_use_case_set(handle->ucMgr, "_enadev", rxDevice);
- strlcpy(curRxUCMDevice, rxDevice, sizeof(curRxUCMDevice));
-#ifdef QCOM_FM_ENABLED
- if (devices & AudioSystem::DEVICE_OUT_FM)
- s_set_fm_vol(fmVolume);
-#endif
- }
- if (txDevice != NULL) {
- snd_use_case_set(handle->ucMgr, "_enadev", txDevice);
- strlcpy(curTxUCMDevice, txDevice, sizeof(curTxUCMDevice));
- }
- for(ALSAUseCaseList::iterator it = mUseCaseList.begin(); it != mUseCaseList.end(); ++it) {
- ALOGD("Route use case %s\n", it->useCase);
- if ((use_case != NULL) && (strncmp(use_case, SND_USE_CASE_VERB_INACTIVE,
- strlen(SND_USE_CASE_VERB_INACTIVE))) && (!strncmp(use_case, it->useCase, MAX_UC_LEN))) {
- snd_use_case_set(handle->ucMgr, "_verb", it->useCase);
- } else {
- snd_use_case_set(handle->ucMgr, "_enamod", it->useCase);
- }
- }
- if (!mUseCaseList.empty())
- mUseCaseList.clear();
- if (use_case != NULL) {
- free(use_case);
- use_case = NULL;
- }
- ALOGD("switchDevice: curTxUCMDevivce %s curRxDevDevice %s", curTxUCMDevice, curRxUCMDevice);
-
- if (platform_is_Fusion3() && (inCallDevSwitch == true)) {
- /* get tx acdb id */
- memset(&ident,0,sizeof(ident));
- strlcpy(ident, "ACDBID/", sizeof(ident));
- strlcat(ident, curTxUCMDevice, sizeof(ident));
- tx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
-
- /* get rx acdb id */
- memset(&ident,0,sizeof(ident));
- strlcpy(ident, "ACDBID/", sizeof(ident));
- strlcat(ident, curRxUCMDevice, sizeof(ident));
- rx_dev_id = snd_use_case_get(handle->ucMgr, ident, NULL);
-
- if (((rx_dev_id == DEVICE_SPEAKER_MONO_RX_ACDB_ID ) || (rx_dev_id == DEVICE_SPEAKER_STEREO_RX_ACDB_ID ))
- && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
- tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID;
- }
-
-#ifdef QCOM_CSDCLIENT_ENABLED
- ALOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id);
- if (csd_enable_device == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_client_enable_device", dlerror());
- } else {
- err = csd_enable_device(rx_dev_id, tx_dev_id, mDevSettingsFlag);
- if (err < 0)
- {
- ALOGE("csd_client_disable_device failed, error %d", err);
- }
- }
-#endif
- }
-
- if (rxDevice != NULL) {
- free(rxDevice);
- rxDevice = NULL;
- }
- if (txDevice != NULL) {
- free(txDevice);
- txDevice = NULL;
- }
-}
-
-// ----------------------------------------------------------------------------
-
-static status_t s_init(alsa_device_t *module, ALSAHandleList &list)
-{
- ALOGV("s_init: Initializing devices for ALSA module");
-
- list.clear();
-
- return NO_ERROR;
-}
-
-static status_t s_open(alsa_handle_t *handle)
-{
- char *devName;
- unsigned flags = 0;
- int err = NO_ERROR;
-
- if(handle->devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
- err = setHDMIChannelCount();
- if(err != OK) {
- ALOGE("setHDMIChannelCount err = %d", err);
- return err;
- }
- }
- /* No need to call s_close for LPA as pcm device open and close is handled by LPAPlayer in stagefright */
- if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA))
- ||(!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) || (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
- ALOGV("s_open: Opening LPA /Tunnel playback");
- return NO_ERROR;
- }
-
- s_close(handle);
-
- ALOGV("s_open: handle %p", handle);
-
- // ASoC multicomponent requires a valid path (frontend/backend) for
- // the device to be opened
-
- // The PCM stream is opened in blocking mode, per ALSA defaults. The
- // AudioFlinger seems to assume blocking mode too, so asynchronous mode
- // should not be used.
- if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
- ALOGV("LPA/tunnel use case");
- flags |= PCM_MMAP;
- flags |= DEBUG_ON;
- } else if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI2)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) {
- ALOGV("Music case");
- flags = PCM_OUT;
- } else {
- flags = PCM_IN;
- }
- if (handle->channels == 1) {
- flags |= PCM_MONO;
- }
- else if (handle->channels == 4 ) {
- flags |= PCM_QUAD;
- } else if (handle->channels == 6 ) {
-#ifdef QCOM_SSR_ENABLED
- if (!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI_REC, strlen(SND_USE_CASE_VERB_HIFI_REC))
- || !strncmp(handle->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
- flags |= PCM_QUAD;
- } else {
- flags |= PCM_5POINT1;
- }
-#else
- flags |= PCM_5POINT1;
-#endif
- }
- else {
- flags |= PCM_STEREO;
- }
- if (deviceName(handle, flags, &devName) < 0) {
- ALOGE("Failed to get pcm device node: %s", devName);
- return NO_INIT;
- }
- if (devName != NULL) {
- handle->handle = pcm_open(flags, (char*)devName);
- } else {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
-
- if (!handle->handle) {
- ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
- free(devName);
- return NO_INIT;
- }
-
- handle->handle->flags = flags;
- err = setHardwareParams(handle);
-
- if (err == NO_ERROR) {
- err = setSoftwareParams(handle);
- }
-
- if(err != NO_ERROR) {
- ALOGE("Set HW/SW params failed: Closing the pcm stream");
- s_standby(handle);
- }
-
- free(devName);
- return NO_ERROR;
-}
-
-static status_t s_start_voip_call(alsa_handle_t *handle)
-{
-
- char* devName;
- char* devName1;
- unsigned flags = 0;
- int err = NO_ERROR;
- uint8_t voc_pkt[VOIP_BUFFER_MAX_SIZE];
-
- s_close(handle);
- flags = PCM_OUT;
- flags |= PCM_MONO;
- ALOGV("s_open:s_start_voip_call handle %p", handle);
-
- if (deviceName(handle, flags, &devName) < 0) {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
-
- if (devName != NULL) {
- handle->handle = pcm_open(flags, (char*)devName);
- } else {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
-
- if (!handle->handle) {
- free(devName);
- ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
- return NO_INIT;
- }
-
- if (!pcm_ready(handle->handle)) {
- ALOGE(" pcm ready failed");
- }
-
- handle->handle->flags = flags;
- err = setHardwareParams(handle);
-
- if (err == NO_ERROR) {
- err = setSoftwareParams(handle);
- }
-
- err = pcm_prepare(handle->handle);
- if(err != NO_ERROR) {
- ALOGE("DEVICE_OUT_DIRECTOUTPUT: pcm_prepare failed");
- }
-
- /* first write required start dsp */
- memset(&voc_pkt,0,sizeof(voc_pkt));
- pcm_write(handle->handle,&voc_pkt,handle->handle->period_size);
- handle->rxHandle = handle->handle;
- free(devName);
- ALOGV("s_open: DEVICE_IN_COMMUNICATION ");
- flags = PCM_IN;
- flags |= PCM_MONO;
- handle->handle = 0;
-
- if (deviceName(handle, flags, &devName1) < 0) {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
- if (devName != NULL) {
- handle->handle = pcm_open(flags, (char*)devName1);
- } else {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
-
- if (!handle->handle) {
- free(devName);
- ALOGE("s_open: Failed to initialize ALSA device '%s'", devName);
- return NO_INIT;
- }
-
- if (!pcm_ready(handle->handle)) {
- ALOGE(" pcm ready in failed");
- }
-
- handle->handle->flags = flags;
-
- err = setHardwareParams(handle);
-
- if (err == NO_ERROR) {
- err = setSoftwareParams(handle);
- }
-
-
- err = pcm_prepare(handle->handle);
- if(err != NO_ERROR) {
- ALOGE("DEVICE_IN_COMMUNICATION: pcm_prepare failed");
- }
-
- /* first read required start dsp */
- memset(&voc_pkt,0,sizeof(voc_pkt));
- pcm_read(handle->handle,&voc_pkt,handle->handle->period_size);
- return NO_ERROR;
-}
-
-static status_t s_start_voice_call(alsa_handle_t *handle)
-{
- char* devName;
- unsigned flags = 0;
- int err = NO_ERROR;
-
- ALOGV("s_start_voice_call: handle %p", handle);
-
- // ASoC multicomponent requires a valid path (frontend/backend) for
- // the device to be opened
-
- flags = PCM_OUT | PCM_MONO;
- if (deviceName(handle, flags, &devName) < 0) {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
- if (devName != NULL) {
- handle->handle = pcm_open(flags, (char*)devName);
- } else {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
- if (!handle->handle) {
- ALOGE("s_start_voicecall: could not open PCM device");
- goto Error;
- }
-
- handle->handle->flags = flags;
- err = setHardwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_voice_call: setHardwareParams failed");
- goto Error;
- }
-
- err = setSoftwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_voice_call: setSoftwareParams failed");
- goto Error;
- }
-
- err = pcm_prepare(handle->handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_voice_call: pcm_prepare failed");
- goto Error;
- }
-
- if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
- ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n");
- goto Error;
- }
-
- // Store the PCM playback device pointer in rxHandle
- handle->rxHandle = handle->handle;
- free(devName);
-
- // Open PCM capture device
- flags = PCM_IN | PCM_MONO;
- if (deviceName(handle, flags, &devName) < 0) {
- ALOGE("Failed to get pcm device node");
- goto Error;
- }
- if (devName != NULL) {
- handle->handle = pcm_open(flags, (char*)devName);
- } else {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
- if (!handle->handle) {
- free(devName);
- goto Error;
- }
-
- handle->handle->flags = flags;
- err = setHardwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_voice_call: setHardwareParams failed");
- goto Error;
- }
-
- err = setSoftwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_voice_call: setSoftwareParams failed");
- goto Error;
- }
-
- err = pcm_prepare(handle->handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_voice_call: pcm_prepare failed");
- goto Error;
- }
-
- if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
- ALOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n");
- goto Error;
- }
-
- if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (csd_start_voice == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_client_start_voice", dlerror());
- } else {
- err = csd_start_voice();
- if (err < 0){
- ALOGE("s_start_voice_call: csd_client error %d\n", err);
- goto Error;
- }
- }
-#endif
- }
-
- free(devName);
- return NO_ERROR;
-
-Error:
- ALOGE("s_start_voice_call: Failed to initialize ALSA device '%s'", devName);
- free(devName);
- s_close(handle);
- return NO_INIT;
-}
-
-static status_t s_start_fm(alsa_handle_t *handle)
-{
- char *devName;
- unsigned flags = 0;
- int err = NO_ERROR;
-
- ALOGV("s_start_fm: handle %p", handle);
-
- // ASoC multicomponent requires a valid path (frontend/backend) for
- // the device to be opened
-
- flags = PCM_OUT | PCM_STEREO;
- if (deviceName(handle, flags, &devName) < 0) {
- ALOGE("Failed to get pcm device node");
- goto Error;
- }
- if (devName != NULL) {
- handle->handle = pcm_open(flags, (char*)devName);
- } else {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
- if (!handle->handle) {
- ALOGE("s_start_fm: could not open PCM device");
- goto Error;
- }
-
- handle->handle->flags = flags;
- err = setHardwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_fm: setHardwareParams failed");
- goto Error;
- }
-
- err = setSoftwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_fm: setSoftwareParams failed");
- goto Error;
- }
-
- err = pcm_prepare(handle->handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_fm: setSoftwareParams failed");
- goto Error;
- }
-
- if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
- ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n");
- goto Error;
- }
-
- // Store the PCM playback device pointer in rxHandle
- handle->rxHandle = handle->handle;
- free(devName);
-
- // Open PCM capture device
- flags = PCM_IN | PCM_STEREO;
- if (deviceName(handle, flags, &devName) < 0) {
- ALOGE("Failed to get pcm device node");
- goto Error;
- }
- if (devName != NULL) {
- handle->handle = pcm_open(flags, (char*)devName);
- } else {
- ALOGE("Failed to get pcm device node");
- return NO_INIT;
- }
- if (!handle->handle) {
- goto Error;
- }
-
- handle->handle->flags = flags;
- err = setHardwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_fm: setHardwareParams failed");
- goto Error;
- }
-
- err = setSoftwareParams(handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_fm: setSoftwareParams failed");
- goto Error;
- }
-
- err = pcm_prepare(handle->handle);
- if(err != NO_ERROR) {
- ALOGE("s_start_fm: pcm_prepare failed");
- goto Error;
- }
-
- if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
- ALOGE("s_start_fm: SNDRV_PCM_IOCTL_START failed\n");
- goto Error;
- }
-
- s_set_fm_vol(fmVolume);
- free(devName);
- return NO_ERROR;
-
-Error:
- free(devName);
- s_close(handle);
- return NO_INIT;
-}
-
-static status_t s_set_fm_vol(int value)
-{
- status_t err = NO_ERROR;
-
- ALSAControl control("/dev/snd/controlC0");
- control.set("Internal FM RX Volume",value,0);
- fmVolume = value;
-
- return err;
-}
-
-static status_t s_set_lpa_vol(int value)
-{
- status_t err = NO_ERROR;
-
- ALSAControl control("/dev/snd/controlC0");
- control.set("LPA RX Volume",value,0);
-
- return err;
-}
-
-static status_t s_start(alsa_handle_t *handle)
-{
- status_t err = NO_ERROR;
-
- if(!handle->handle) {
- ALOGE("No active PCM driver to start");
- return err;
- }
-
- err = pcm_prepare(handle->handle);
-
- return err;
-}
-
-static status_t s_close(alsa_handle_t *handle)
-{
- int ret;
- status_t err = NO_ERROR;
- struct pcm *h = handle->rxHandle;
-
- handle->rxHandle = 0;
- ALOGV("s_close: handle %p h %p", handle, h);
- if (h) {
- if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) ||
- !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) &&
- platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (csd_stop_voice == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_client_disable_device", dlerror());
- } else {
- err = csd_stop_voice();
- if (err < 0) {
- ALOGE("s_close: csd_client error %d\n", err);
- }
- }
-#endif
- }
-
- ALOGV("s_close rxHandle\n");
- err = pcm_close(h);
- if(err != NO_ERROR) {
- ALOGE("s_close: pcm_close failed for rxHandle with err %d", err);
- }
- }
-
- h = handle->handle;
- handle->handle = 0;
-
- if (h) {
- ALOGV("s_close handle h %p\n", h);
- err = pcm_close(h);
- if(err != NO_ERROR) {
- ALOGE("s_close: pcm_close failed for handle with err %d", err);
- }
-
- disableDevice(handle);
- } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))){
- disableDevice(handle);
- }
-
- return err;
-}
-
-/*
- this is same as s_close, but don't discard
- the device/mode info. This way we can still
- close the device, hit idle and power-save, reopen the pcm
- for the same device/mode after resuming
-*/
-static status_t s_standby(alsa_handle_t *handle)
-{
- int ret;
- status_t err = NO_ERROR;
- struct pcm *h = handle->rxHandle;
- handle->rxHandle = 0;
- ALOGV("s_standby: handle %p h %p", handle, h);
- if (h) {
- ALOGD("s_standby rxHandle\n");
- err = pcm_close(h);
- if(err != NO_ERROR) {
- ALOGE("s_standby: pcm_close failed for rxHandle with err %d", err);
- }
- }
-
- h = handle->handle;
- handle->handle = 0;
-
- if (h) {
- ALOGV("s_standby handle h %p\n", h);
- err = pcm_close(h);
- if(err != NO_ERROR) {
- ALOGE("s_standby: pcm_close failed for handle with err %d", err);
- }
- disableDevice(handle);
- } else if((!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_LPA)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
- (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_TUNNEL))) {
- disableDevice(handle);
- }
-
- return err;
-}
-
-static status_t s_route(alsa_handle_t *handle, uint32_t devices, int mode)
-{
- status_t status = NO_ERROR;
-
- ALOGD("s_route: devices 0x%x in mode %d", devices, mode);
- callMode = mode;
- switchDevice(handle, devices, mode);
- return status;
-}
-
-int getUseCaseType(const char *useCase)
-{
- ALOGD("use case is %s\n", useCase);
- if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
- MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
- MAX_LEN(useCase, SND_USE_CASE_VERB_HIFI2)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
- MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
- MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
- MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
- MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
- MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
- return USECASE_TYPE_RX;
- } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
- MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
- MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
- MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
- MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
- return USECASE_TYPE_TX;
- } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
- MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
- MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
- MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
- MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
- MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
- MAX_LEN(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
- !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
- MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
- !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
- MAX_LEN(useCase, SND_USE_CASE_MOD_PLAY_VOLTE))) {
- return (USECASE_TYPE_RX | USECASE_TYPE_TX);
- } else {
- ALOGE("unknown use case %s\n", useCase);
- return 0;
- }
-}
-
-static void disableDevice(alsa_handle_t *handle)
-{
- unsigned usecase_type = 0;
- int i, mods_size;
- char *useCase;
- const char **mods_list;
-
- snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
- if (useCase != NULL) {
- if (!strncmp(useCase, handle->useCase, MAX_UC_LEN)) {
- snd_use_case_set(handle->ucMgr, "_verb", SND_USE_CASE_VERB_INACTIVE);
- } else {
- snd_use_case_set(handle->ucMgr, "_dismod", handle->useCase);
- }
- free(useCase);
- snd_use_case_get(handle->ucMgr, "_verb", (const char **)&useCase);
- if (strncmp(useCase, SND_USE_CASE_VERB_INACTIVE,
- strlen(SND_USE_CASE_VERB_INACTIVE)))
- usecase_type |= getUseCaseType(useCase);
- mods_size = snd_use_case_get_list(handle->ucMgr, "_enamods", &mods_list);
- ALOGV("Number of modifiers %d\n", mods_size);
- if (mods_size) {
- for(i = 0; i < mods_size; i++) {
- ALOGV("index %d modifier %s\n", i, mods_list[i]);
- usecase_type |= getUseCaseType(mods_list[i]);
- }
- }
- ALOGV("usecase_type is %d\n", usecase_type);
- if (!(usecase_type & USECASE_TYPE_TX) && (strncmp(curTxUCMDevice, "None", 4)))
- snd_use_case_set(handle->ucMgr, "_disdev", curTxUCMDevice);
- if (!(usecase_type & USECASE_TYPE_RX) && (strncmp(curRxUCMDevice, "None", 4)))
- snd_use_case_set(handle->ucMgr, "_disdev", curRxUCMDevice);
- } else {
- ALOGE("Invalid state, no valid use case found to disable");
- }
- free(useCase);
-}
-
-char *getUCMDevice(uint32_t devices, int input, char *rxDevice)
-{
- if (!input) {
- if (!(mDevSettingsFlag & TTY_OFF) &&
- (callMode == AudioSystem::MODE_IN_CALL) &&
- ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
-#ifdef QCOM_ANC_HEADSET_ENABLED
- ||
- (devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
-#endif
- if (mDevSettingsFlag & TTY_VCO) {
- return strdup(SND_USE_CASE_DEV_TTY_HEADSET_RX);
- } else if (mDevSettingsFlag & TTY_FULL) {
- return strdup(SND_USE_CASE_DEV_TTY_FULL_RX);
- } else if (mDevSettingsFlag & TTY_HCO) {
- return strdup(SND_USE_CASE_DEV_TTY_HANDSET_RX); /* HANDSET RX */
- }
- }else if ((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)) {
- return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
- } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
- ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) {
- if (mDevSettingsFlag & ANC_FLAG) {
- return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
- } else {
- return strdup(SND_USE_CASE_DEV_SPEAKER_HEADSET); /* COMBO SPEAKER+HEADSET RX */
- }
- } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
- ((devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL))) {
- return strdup(SND_USE_CASE_DEV_HDMI_SPEAKER);
-#ifdef QCOM_ANC_HEADSET_ENABLED
- } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
- ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE))) {
- return strdup(SND_USE_CASE_DEV_SPEAKER_ANC_HEADSET); /* COMBO SPEAKER+ANC HEADSET RX */
- } else if ((devices & AudioSystem::DEVICE_OUT_SPEAKER) &&
- (devices & AudioSystem::DEVICE_OUT_FM_TX)) {
- return strdup(SND_USE_CASE_DEV_SPEAKER_FM_TX); /* COMBO SPEAKER+FM_TX RX */
-#endif
- } else if (devices & AudioSystem::DEVICE_OUT_EARPIECE) {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_EARPIECE); /* Voice HANDSET RX */
- } else
- return strdup(SND_USE_CASE_DEV_EARPIECE); /* HANDSET RX */
- } else if (devices & AudioSystem::DEVICE_OUT_SPEAKER) {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */
- } else
- return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
- } else if ((devices & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) {
- if (mDevSettingsFlag & ANC_FLAG) {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
- } else
- return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
- } else {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_HEADPHONE); /* Voice HEADSET RX */
- } else
- return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */
- }
-#ifdef QCOM_ANC_HEADSET_ENABLED
- } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_ANC_HEADSET); /* Voice ANC HEADSET RX */
- } else
- return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
-#endif
- } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) ||
- (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ||
- (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT)) {
- if (btsco_samplerate == BTSCO_RATE_16KHZ)
- return strdup(SND_USE_CASE_DEV_BTSCO_WB_RX); /* BTSCO RX*/
- else
- return strdup(SND_USE_CASE_DEV_BTSCO_NB_RX); /* BTSCO RX*/
- } else if ((devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP) ||
- (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES) ||
-#ifdef QCOM_VOIP_ENABLED
- (devices & AudioSystem::DEVICE_OUT_DIRECTOUTPUT) ||
-#endif
- (devices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER)) {
- /* Nothing to be done, use current active device */
- if (strncmp(curRxUCMDevice, "None", 4)) {
- return strdup(curRxUCMDevice);
- }
- } else if (devices & AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
- return strdup(SND_USE_CASE_DEV_HDMI); /* HDMI RX */
-#ifdef QCOM_PROXY_DEVICE_ENABLED
- } else if (devices & AudioSystem::DEVICE_OUT_PROXY) {
- return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
-#endif
-#ifdef QCOM_FM_TX_ENABLED
- } else if (devices & AudioSystem::DEVICE_OUT_FM_TX) {
- return strdup(SND_USE_CASE_DEV_FM_TX); /* FM Tx */
-#endif
- } else if (devices & AudioSystem::DEVICE_OUT_DEFAULT) {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_SPEAKER); /* Voice SPEAKER RX */
- } else
- return strdup(SND_USE_CASE_DEV_SPEAKER); /* SPEAKER RX */
- } else {
- ALOGD("No valid output device: %u", devices);
- }
- } else {
- if (!(mDevSettingsFlag & TTY_OFF) &&
- (callMode == AudioSystem::MODE_IN_CALL) &&
- ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET))) {
-#ifdef QCOM_ANC_HEADSET_ENABLED
- ||(devices & AudioSystem::DEVICE_IN_ANC_HEADSET))) {
-#endif
- if (mDevSettingsFlag & TTY_HCO) {
- return strdup(SND_USE_CASE_DEV_TTY_HEADSET_TX);
- } else if (mDevSettingsFlag & TTY_FULL) {
- return strdup(SND_USE_CASE_DEV_TTY_FULL_TX);
- } else if (mDevSettingsFlag & TTY_VCO) {
- if (!strncmp(mic_type, "analog", 6)) {
- return strdup(SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX);
- } else {
- return strdup(SND_USE_CASE_DEV_TTY_HANDSET_TX);
- }
- }
- } else if (devices & AudioSystem::DEVICE_IN_BUILTIN_MIC) {
- if (!strncmp(mic_type, "analog", 6)) {
- return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
- } else {
- if (mDevSettingsFlag & DMIC_FLAG) {
-#ifdef USES_FLUENCE_INCALL
- if(callMode == AudioSystem::MODE_IN_CALL) {
- if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
- return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
- } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
- return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
- } else {
- return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
- }
- }
-#else
- if (((rxDevice != NULL) &&
- !strncmp(rxDevice, SND_USE_CASE_DEV_SPEAKER,
- (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) ||
- !strncmp(curRxUCMDevice, SND_USE_CASE_DEV_SPEAKER,
- (strlen(SND_USE_CASE_DEV_SPEAKER)+1))) {
- if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
- return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
- } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
- return strdup(SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
- }
- } else {
- if (fluence_mode == FLUENCE_MODE_ENDFIRE) {
- return strdup(SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE); /* DUALMIC EF TX */
- } else if (fluence_mode == FLUENCE_MODE_BROADSIDE) {
- return strdup(SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE); /* DUALMIC BS TX */
- }
- }
-#endif
- } else if (mDevSettingsFlag & QMIC_FLAG){
- return strdup(SND_USE_CASE_DEV_QUAD_MIC);
- }
-#ifdef QCOM_SSR_ENABLED
- else if (mDevSettingsFlag & SSRQMIC_FLAG){
- ALOGV("return SSRQMIC_FLAG: 0x%x devices:0x%x",mDevSettingsFlag,devices);
- // Mapping for quad mic input device.
- return strdup(SND_USE_CASE_DEV_SSR_QUAD_MIC); /* SSR Quad MIC */
- }
-#endif
-#ifdef SEPERATED_AUDIO_INPUT
- if(input_source == AUDIO_SOURCE_VOICE_RECOGNITION) {
- return strdup(SND_USE_CASE_DEV_VOICE_RECOGNITION ); /* VOICE RECOGNITION TX */
- }
-#endif
- else {
-#ifdef QCOM_BACK_MIC_ENABLED
- return strdup(SND_USE_CASE_DEV_HANDSET); /* BUILTIN-MIC TX */
-#else
- return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
-#endif
- }
- }
- } else if (devices & AudioSystem::DEVICE_IN_AUX_DIGITAL) {
- return strdup(SND_USE_CASE_DEV_HDMI_TX); /* HDMI TX */
-#ifdef QCOM_ANC_HEADSET_ENABLED
- } else if (devices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
- return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
-#endif
- } else if (devices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_HEADSET); /* Voice HEADSET TX */
- } else
- return strdup(SND_USE_CASE_DEV_HEADSET); /* HEADSET TX */
- } else if (devices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
- if (btsco_samplerate == BTSCO_RATE_16KHZ)
- return strdup(SND_USE_CASE_DEV_BTSCO_WB_TX); /* BTSCO TX*/
- else
- return strdup(SND_USE_CASE_DEV_BTSCO_NB_TX); /* BTSCO TX*/
-#ifdef QCOM_USBAUDIO_ENABLED
- } else if ((devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) ||
- (devices & AudioSystem::DEVICE_IN_PROXY)) {
- return strdup(SND_USE_CASE_DEV_PROXY_TX); /* PROXY TX */
-#endif
- } else if ((devices & AudioSystem::DEVICE_IN_COMMUNICATION) ||
- (devices & AudioSystem::DEVICE_IN_VOICE_CALL)) {
- /* Nothing to be done, use current active device */
- if (strncmp(curTxUCMDevice, "None", 4)) {
- return strdup(curTxUCMDevice);
- }
-#ifdef QCOM_FM_ENABLED
- } else if ((devices & AudioSystem::DEVICE_IN_FM_RX) ||
- (devices & AudioSystem::DEVICE_IN_FM_RX_A2DP)) {
- /* Nothing to be done, use current tx device or set dummy device */
- if (strncmp(curTxUCMDevice, "None", 4)) {
- return strdup(curTxUCMDevice);
- } else {
- return strdup(SND_USE_CASE_DEV_DUMMY_TX);
- }
-#endif
- } else if ((devices & AudioSystem::DEVICE_IN_AMBIENT) ||
- (devices & AudioSystem::DEVICE_IN_BACK_MIC)) {
- ALOGI("No proper mapping found with UCM device list, setting default");
- if (!strncmp(mic_type, "analog", 6)) {
- return strdup(SND_USE_CASE_DEV_HANDSET); /* HANDSET TX */
- } else {
- if (callMode == AudioSystem::MODE_IN_CALL) {
- return strdup(SND_USE_CASE_DEV_VOC_LINE); /* Voice BUILTIN-MIC TX */
-#ifdef SEPERATED_AUDIO_INPUT
- } else if(input_source == AUDIO_SOURCE_CAMCORDER) {
- return strdup(SND_USE_CASE_DEV_CAMCORDER_TX ); /* CAMCORDER TX */
-#endif
- } else
- return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
- }
- } else {
- ALOGD("No valid input device: %u", devices);
- }
- }
- return NULL;
-}
-
-void s_set_voice_volume(int vol)
-{
- int err = 0;
- ALOGV("s_set_voice_volume: volume %d", vol);
- ALSAControl control("/dev/snd/controlC0");
- control.set("Voice Rx Volume", vol, 0);
-
- if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (csd_volume == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_client_volume", dlerror());
- } else {
- err = csd_volume(vol);
- if (err < 0) {
- ALOGE("s_set_voice_volume: csd_client error %d", err);
- }
- }
-#endif
- }
-}
-
-void s_set_volte_volume(int vol)
-{
- ALOGV("s_set_volte_volume: volume %d", vol);
- ALSAControl control("/dev/snd/controlC0");
- control.set("VoLTE Rx Volume", vol, 0);
-}
-
-
-void s_set_voip_volume(int vol)
-{
- ALOGV("s_set_voip_volume: volume %d", vol);
- ALSAControl control("/dev/snd/controlC0");
- control.set("Voip Rx Volume", vol, 0);
-}
-void s_set_mic_mute(int state)
-{
- int err = 0;
- ALOGV("s_set_mic_mute: state %d", state);
- ALSAControl control("/dev/snd/controlC0");
- control.set("Voice Tx Mute", state, 0);
-
- if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (csd_mic_mute == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_mic_mute", dlerror());
- } else {
- err=csd_mic_mute(state);
- if (err < 0) {
- ALOGE("s_set_mic_mute: csd_client error %d", err);
- }
- }
-#endif
- }
-}
-void s_set_volte_mic_mute(int state)
-{
- ALOGV("s_set_volte_mic_mute: state %d", state);
- ALSAControl control("/dev/snd/controlC0");
- control.set("VoLTE Tx Mute", state, 0);
-}
-
-void s_set_voip_mic_mute(int state)
-{
- ALOGV("s_set_voip_mic_mute: state %d", state);
- ALSAControl control("/dev/snd/controlC0");
- control.set("Voip Tx Mute", state, 0);
-}
-
-void s_set_voip_config(int mode, int rate)
-{
- ALOGV("s_set_voip_config: mode %d,rate %d", mode, rate);
- ALSAControl control("/dev/snd/controlC0");
- char** setValues;
- setValues = (char**)malloc(2*sizeof(char*));
- if (setValues == NULL) {
- return;
- }
- setValues[0] = (char*)malloc(4*sizeof(char));
- if (setValues[0] == NULL) {
- free(setValues);
- return;
- }
-
- setValues[1] = (char*)malloc(8*sizeof(char));
- if (setValues[1] == NULL) {
- free(setValues);
- free(setValues[0]);
- return;
- }
-
- sprintf(setValues[0], "%d",mode);
- sprintf(setValues[1], "%d",rate);
-
- control.setext("Voip Mode Rate Config", 2, setValues);
- free(setValues[1]);
- free(setValues[0]);
- free(setValues);
- return;
-}
-
-void s_set_btsco_rate(int rate)
-{
- btsco_samplerate = rate;
-}
-
-void s_enable_wide_voice(bool flag)
-{
- int err = 0;
-
- ALOGV("s_enable_wide_voice: flag %d", flag);
- ALSAControl control("/dev/snd/controlC0");
- if(flag == true) {
- control.set("Widevoice Enable", 1, 0);
- } else {
- control.set("Widevoice Enable", 0, 0);
- }
-
- if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (csd_wide_voice == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_wide_voice", dlerror());
- } else {
- err = csd_wide_voice(flag);
- if (err < 0) {
- ALOGE("enableWideVoice: csd_client_wide_voice error %d", err);
- }
- }
-#endif
- }
-}
-
-void s_set_voc_rec_mode(uint8_t mode)
-{
- ALOGV("s_set_voc_rec_mode: mode %d", mode);
- ALSAControl control("/dev/snd/controlC0");
- control.set("Incall Rec Mode", mode, 0);
-}
-
-void s_enable_fens(bool flag)
-{
- int err = 0;
-
- ALOGV("s_enable_fens: flag %d", flag);
- ALSAControl control("/dev/snd/controlC0");
- if(flag == true) {
- control.set("FENS Enable", 1, 0);
- } else {
- control.set("FENS Enable", 0, 0);
- }
-
- if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (csd_fens == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_fens", dlerror());
- } else {
- err = csd_fens(flag);
- if (err < 0) {
- ALOGE("s_enable_fens: csd_client error %d", err);
- }
- }
-#endif
- }
-}
-
-void s_enable_slow_talk(bool flag)
-{
- int err = 0;
-
- ALOGV("s_enable_slow_talk: flag %d", flag);
- ALSAControl control("/dev/snd/controlC0");
- if(flag == true) {
- control.set("Slowtalk Enable", 1, 0);
- } else {
- control.set("Slowtalk Enable", 0, 0);
- }
-
- if (platform_is_Fusion3()) {
-#ifdef QCOM_CSDCLIENT_ENABLED
- if (csd_slow_talk == NULL) {
- ALOGE("dlsym:Error:%s Loading csd_slow_talk", dlerror());
- } else {
- err = csd_slow_talk(flag);
- if (err < 0) {
- ALOGE("s_enable_slow_talk: csd_client error %d", err);
- }
- }
-#endif
- }
-}
-
-void s_set_flags(uint32_t flags)
-{
- ALOGV("s_set_flags: flags %d", flags);
- mDevSettingsFlag = flags;
-}
-
-static status_t s_set_compressed_vol(int value)
-{
- status_t err = NO_ERROR;
-
- ALSAControl control("/dev/snd/controlC0");
- control.set("COMPRESSED RX Volume",value,0);
-
- return err;
-}
-
-#ifdef SEPERATED_AUDIO_INPUT
-void s_setInput(int input)
-{
- input_source = input;
- ALOGD("s_setInput() : input_source = %d",input_source);
-}
-#endif
-
-#ifdef QCOM_CSDCLIENT_ENABLED
-static void s_set_csd_handle(void* handle)
-{
- csd_handle = static_cast<void*>(handle);
- ALOGI("%s csd_handle: %p", __func__, csd_handle);
-
- csd_disable_device = (int (*)())::dlsym(csd_handle,"csd_client_disable_device");
- csd_enable_device = (int (*)(int,int,uint32_t))::dlsym(csd_handle,"csd_client_enable_device");
- csd_start_voice = (int (*)())::dlsym(csd_handle,"csd_client_start_voice");
- csd_stop_voice = (int (*)())::dlsym(csd_handle,"csd_client_stop_voice");
- csd_volume = (int (*)(int))::dlsym(csd_handle,"csd_client_volume");
- csd_mic_mute = (int (*)(int))::dlsym(csd_handle,"csd_client_mic_mute");
- csd_wide_voice = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_wide_voice");
- csd_fens = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_fens");
- csd_slow_talk = (int (*)(uint8_t))::dlsym(csd_handle,"csd_client_slow_talk");
-}
-#endif
-
-}
diff --git a/alsa_sound/audio_hw_hal.cpp b/alsa_sound/audio_hw_hal.cpp
index ab15e27..8e7f208 100644
--- a/alsa_sound/audio_hw_hal.cpp
+++ b/alsa_sound/audio_hw_hal.cpp
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2011 The Android Open Source Project
- * Copyright (c) 2011-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -76,23 +76,14 @@
{ AudioSystem::DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_AUX_DIGITAL },
{ AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET },
{ AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET },
- { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT },
#ifdef QCOM_ANC_HEADSET_ENABLED
{ AudioSystem::DEVICE_OUT_ANC_HEADSET, AUDIO_DEVICE_OUT_ANC_HEADSET },
{ AudioSystem::DEVICE_OUT_ANC_HEADPHONE, AUDIO_DEVICE_OUT_ANC_HEADPHONE },
#endif
-#ifdef QCOM_FM_ENABLED
- { AudioSystem::DEVICE_OUT_FM, AUDIO_DEVICE_OUT_FM },
-#endif
-#ifdef QCOM_FM_TX_ENABLED
- { AudioSystem::DEVICE_OUT_FM_TX, AUDIO_DEVICE_OUT_FM_TX },
-#endif
-#ifdef QCOM_VOIP_ENABLED
- { AudioSystem::DEVICE_OUT_DIRECTOUTPUT, AUDIO_DEVICE_OUT_DIRECTOUTPUT },
-#endif
#ifdef QCOM_PROXY_DEVICE_ENABLED
{ AudioSystem::DEVICE_OUT_PROXY, AUDIO_DEVICE_OUT_PROXY },
#endif
+ { AudioSystem::DEVICE_OUT_DEFAULT, AUDIO_DEVICE_OUT_DEFAULT },
/* input devices */
{ AudioSystem::DEVICE_IN_COMMUNICATION, AUDIO_DEVICE_IN_COMMUNICATION },
{ AudioSystem::DEVICE_IN_AMBIENT, AUDIO_DEVICE_IN_AMBIENT },
@@ -102,16 +93,20 @@
{ AudioSystem::DEVICE_IN_AUX_DIGITAL, AUDIO_DEVICE_IN_AUX_DIGITAL },
{ AudioSystem::DEVICE_IN_VOICE_CALL, AUDIO_DEVICE_IN_VOICE_CALL },
{ AudioSystem::DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BACK_MIC },
- { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT },
#ifdef QCOM_ANC_HEADSET_ENABLED
{ AudioSystem::DEVICE_IN_ANC_HEADSET, AUDIO_DEVICE_IN_ANC_HEADSET },
#endif
-#ifdef QCOM_FM_ENABLED
- { AudioSystem::DEVICE_IN_FM_RX, AUDIO_DEVICE_IN_FM_RX },
- { AudioSystem::DEVICE_IN_FM_RX_A2DP, AUDIO_DEVICE_IN_FM_RX_A2DP },
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ { AudioSystem::DEVICE_IN_PROXY, AUDIO_DEVICE_IN_PROXY },
#endif
+ { AudioSystem::DEVICE_IN_DEFAULT, AUDIO_DEVICE_IN_DEFAULT },
};
+// the "audio_devices" enumeration defined in hardware/libhardware_legacy is obsolete,
+// use type "audio_devices_t" and audio device enumeration from system/audio.h instead.
+// Do not use convert_audio_device if audio hal uses device definition from system/core
+// There's no need to conver audio device if HAL uses AUDIO_DEVICE_XXX defintions instead
+// of AudioSystem::Device_XXX.
static uint32_t convert_audio_device(uint32_t from_device, int from_rev, int to_rev)
{
const uint32_t k_num_devices = sizeof(audio_device_conv_table)/sizeof(uint32_t)/HAL_API_REV_NUM;
@@ -151,7 +146,7 @@
struct qcom_stream_out *out =
reinterpret_cast<struct qcom_stream_out *>(stream);
- ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
/* TODO: implement this */
return 0;
}
@@ -181,7 +176,7 @@
{
struct qcom_stream_out *out =
reinterpret_cast<struct qcom_stream_out *>(stream);
- ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
/* TODO: implement me */
return 0;
}
@@ -301,7 +296,7 @@
struct qcom_stream_in *in =
reinterpret_cast<struct qcom_stream_in *>(stream);
- ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
/* TODO: implement this */
return 0;
}
@@ -331,7 +326,7 @@
{
struct qcom_stream_in *in =
reinterpret_cast<struct qcom_stream_in *>(stream);
- ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ ALOGV("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
/* TODO: implement me */
return 0;
}
@@ -436,6 +431,69 @@
return reinterpret_cast<const struct qcom_audio_device *>(dev);
}
+static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
+{
+ /* XXX: The old AudioHardwareInterface interface is not smart enough to
+ * tell us this, so we'll lie and basically tell AF that we support the
+ * below input/output devices and cross our fingers. To do things properly,
+ * audio hardware interfaces that need advanced features (like this) should
+ * convert to the new HAL interface and not use this wrapper. */
+ return (/* OUT */
+ AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES |
+ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER |
+ AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_USB_ACCESSORY |
+ AUDIO_DEVICE_OUT_USB_DEVICE |
+ AUDIO_DEVICE_OUT_REMOTE_SUBMIX |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ AUDIO_DEVICE_OUT_ANC_HEADSET |
+ AUDIO_DEVICE_OUT_ANC_HEADPHONE |
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ AUDIO_DEVICE_OUT_PROXY |
+#endif
+#ifdef QCOM_FM_ENABLED
+ AUDIO_DEVICE_OUT_FM |
+ AUDIO_DEVICE_OUT_FM_TX |
+#endif
+ AUDIO_DEVICE_OUT_DEFAULT |
+ /* IN */
+ AUDIO_DEVICE_IN_COMMUNICATION |
+ AUDIO_DEVICE_IN_AMBIENT |
+ AUDIO_DEVICE_IN_BUILTIN_MIC |
+ AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET |
+ AUDIO_DEVICE_IN_WIRED_HEADSET |
+ AUDIO_DEVICE_IN_AUX_DIGITAL |
+ AUDIO_DEVICE_IN_VOICE_CALL |
+ AUDIO_DEVICE_IN_BACK_MIC |
+ AUDIO_DEVICE_IN_REMOTE_SUBMIX |
+ AUDIO_DEVICE_IN_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_DGTL_DOCK_HEADSET |
+ AUDIO_DEVICE_IN_USB_ACCESSORY |
+ AUDIO_DEVICE_IN_USB_DEVICE |
+#ifdef QCOM_ANC_HEADSET_ENABLED
+ AUDIO_DEVICE_IN_ANC_HEADSET |
+#endif
+#ifdef QCOM_PROXY_DEVICE_ENABLED
+ AUDIO_DEVICE_IN_PROXY |
+#endif
+#ifdef QCOM_FM_ENABLED
+ AUDIO_DEVICE_IN_FM_RX |
+ AUDIO_DEVICE_IN_FM_RX_A2DP |
+#endif
+ AUDIO_DEVICE_IN_DEFAULT);
+}
+
static int adev_init_check(const struct audio_hw_device *dev)
{
const struct qcom_audio_device *qadev = to_cladev(dev);
@@ -511,43 +569,6 @@
return qadev->hwif->getInputBufferSize(config->sample_rate, config->format, channelCount);
}
-#ifdef QCOM_TUNNEL_LPA_ENABLED
-static int adev_open_output_session(struct audio_hw_device *dev,
- uint32_t devices,
- int *format,
- int sessionId,
- uint32_t samplingRate,
- uint32_t channels,
- struct audio_stream_out **stream_out)
-{
- struct qcom_audio_device *qadev = to_ladev(dev);
- status_t status;
- struct qcom_stream_out *out;
- int ret;
-
- out = (struct qcom_stream_out *)calloc(1, sizeof(*out));
- if (!out)
- return -ENOMEM;
-
- out->qcom_out = qadev->hwif->openOutputSession(devices, format,&status,sessionId,samplingRate,channels);
- if (!out->qcom_out) {
- ret = status;
- goto err_open;
- }
-
- out->stream.common.standby = out_standby;
- out->stream.common.set_parameters = out_set_parameters;
- out->stream.set_volume = out_set_volume;
-
- *stream_out = &out->stream;
- return 0;
-
-err_open:
- free(out);
- *stream_out = NULL;
- return ret;
-}
-#endif
static int adev_open_output_stream(struct audio_hw_device *dev,
audio_io_handle_t handle,
@@ -569,6 +590,9 @@
status = static_cast<audio_output_flags_t> (flags);
out->qcom_out = qadev->hwif->openOutputStream(devices,
+#ifdef QCOM_OUTPUT_FLAGS_ENABLED
+ flags,
+#endif
(int *)&config->format,
&config->channel_mask,
&config->sample_rate,
@@ -721,6 +745,7 @@
qadev->device.common.module = const_cast<hw_module_t*>(module);
qadev->device.common.close = qcom_adev_close;
+ qadev->device.get_supported_devices = adev_get_supported_devices;
qadev->device.init_check = adev_init_check;
qadev->device.set_voice_volume = adev_set_voice_volume;
qadev->device.set_master_volume = adev_set_master_volume;
@@ -735,9 +760,6 @@
qadev->device.get_parameters = adev_get_parameters;
qadev->device.get_input_buffer_size = adev_get_input_buffer_size;
qadev->device.open_output_stream = adev_open_output_stream;
-#ifdef QCOM_TUNNEL_LPA_ENABLED
- qadev->device.open_output_session = adev_open_output_session;
-#endif
qadev->device.close_output_stream = adev_close_output_stream;
qadev->device.open_input_stream = adev_open_input_stream;
qadev->device.close_input_stream = adev_close_input_stream;
diff --git a/alsa_sound/audio_policy_hal.cpp b/alsa_sound/audio_policy_hal.cpp
index 1057a0f..4657295 100644
--- a/alsa_sound/audio_policy_hal.cpp
+++ b/alsa_sound/audio_policy_hal.cpp
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 2012, The Linux Foundation. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -125,45 +125,6 @@
return qap->apm->initCheck();
}
-#ifdef QCOM_TUNNEL_LPA_ENABLED
-static audio_io_handle_t ap_get_session(struct audio_policy *pol,
- audio_stream_type_t stream,
- audio_format_t format,
- audio_policy_output_flags_t flags,
- int sessionId,
- uint32_t samplingRate,
- uint32_t channels)
-{
- struct qcom_audio_policy *qap = to_qap(pol);
-
- ALOGV("%s: tid %d", __func__, gettid());
- return qap->apm->getSession((AudioSystem::stream_type)stream,
- format, (AudioSystem::output_flags)flags,
- sessionId,
- samplingRate,
- channels);
-}
-
-static void ap_pause_session(struct audio_policy *pol, audio_io_handle_t output,
- audio_stream_type_t stream)
-{
- struct qcom_audio_policy *qap = to_qap(pol);
- qap->apm->pauseSession(output, (AudioSystem::stream_type)stream);
-}
-
-static void ap_resume_session(struct audio_policy *pol, audio_io_handle_t output,
- audio_stream_type_t stream)
-{
- struct qcom_audio_policy *qap = to_qap(pol);
- qap->apm->resumeSession(output, (AudioSystem::stream_type)stream);
-}
-
-static void ap_release_session(struct audio_policy *pol, audio_io_handle_t output)
-{
- struct qcom_audio_policy *qap = to_qap(pol);
- qap->apm->releaseSession(output);
-}
-#endif
static audio_io_handle_t ap_get_output(struct audio_policy *pol,
audio_stream_type_t stream,
@@ -248,7 +209,7 @@
struct qcom_audio_policy *qap = to_qap(pol);
return qap->apm->setStreamVolumeIndex((AudioSystem::stream_type)stream,
index,
- AUDIO_DEVICE_OUT_DEFAULT);
+ AUDIO_DEVICE_OUT_DEFAULT);
}
static int ap_get_stream_volume_index(const struct audio_policy *pol,
@@ -298,14 +259,14 @@
}
static audio_io_handle_t ap_get_output_for_effect(struct audio_policy *pol,
- struct effect_descriptor_s *desc)
+ const struct effect_descriptor_s *desc)
{
struct qcom_audio_policy *qap = to_qap(pol);
return qap->apm->getOutputForEffect(desc);
}
static int ap_register_effect(struct audio_policy *pol,
- struct effect_descriptor_s *desc,
+ const struct effect_descriptor_s *desc,
audio_io_handle_t io,
uint32_t strategy,
int session,
@@ -327,7 +288,7 @@
return qap->apm->setEffectEnabled(id, enabled);
}
-static bool ap_is_stream_active(const struct audio_policy *pol,
+static bool ap_is_stream_active(const struct audio_policy *pol,
audio_stream_type_t stream,
uint32_t in_past_ms)
{
@@ -365,12 +326,6 @@
ap_set_can_mute_enforced_audible;
qap->policy.init_check = ap_init_check;
qap->policy.get_output = ap_get_output;
-#ifdef QCOM_TUNNEL_LPA_ENABLED
- qap->policy.get_session = ap_get_session;
- qap->policy.pause_session = ap_pause_session;
- qap->policy.resume_session = ap_resume_session;
- qap->policy.release_session = ap_release_session;
-#endif
qap->policy.start_output = ap_start_output;
qap->policy.stop_output = ap_stop_output;
qap->policy.release_output = ap_release_output;
diff --git a/libalsa-intf/Android.mk b/libalsa-intf/Android.mk
index 5d509b3..cadfa32 100644
--- a/libalsa-intf/Android.mk
+++ b/libalsa-intf/Android.mk
@@ -2,20 +2,25 @@
ifeq ($(strip $(BOARD_USES_ALSA_AUDIO)),true)
# Any prebuilt files with default TAGS can use the below:
-
include $(CLEAR_VARS)
#LOCAL_SRC_FILES:= aplay.c alsa_pcm.c alsa_mixer.c
LOCAL_SRC_FILES:= aplay.c
LOCAL_MODULE:= aplay
LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf
+LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_MODULE_TAGS:= debug
include $(BUILD_EXECUTABLE)
include $(CLEAR_VARS)
#LOCAL_SRC_FILES:= arec.c alsa_pcm.c
LOCAL_SRC_FILES:= arec.c
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_MODULE:= arec
LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf
+LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_MODULE_TAGS:= debug
include $(BUILD_EXECUTABLE)
@@ -23,6 +28,8 @@
LOCAL_SRC_FILES:= amix.c
LOCAL_MODULE:= amix
LOCAL_SHARED_LIBRARIES := libc libcutils libalsa-intf
+LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_MODULE_TAGS:= debug
include $(BUILD_EXECUTABLE)
@@ -30,6 +37,8 @@
LOCAL_SRC_FILES:= alsaucm_test.c
LOCAL_MODULE:= alsaucm_test
LOCAL_SHARED_LIBRARIES:= libc libcutils libalsa-intf
+LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
LOCAL_MODULE_TAGS:= debug
include $(BUILD_EXECUTABLE)
@@ -42,8 +51,14 @@
LOCAL_MODULE:= libalsa-intf
LOCAL_MODULE_TAGS := optional
LOCAL_SHARED_LIBRARIES:= libc libcutils #libutils #libmedia libhardware_legacy
+LOCAL_C_INCLUDES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+ifeq ($(strip $(TARGET_USES_QCOM_MM_AUDIO)),true)
LOCAL_CFLAGS := -DQC_PROP -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\"
-
+LOCAL_CFLAGS += -DCONFIG_DIR=\"/system/etc/snd_soc_msm/\"
+LOCAL_SHARED_LIBRARIES += libacdbloader
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audio-acdb-util
+endif
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
ifeq ($(TARGET_SIMULATOR),true)
LOCAL_LDLIBS += -ldl
else
diff --git a/libalsa-intf/Makefile.am b/libalsa-intf/Makefile.am
index a05d073..58cb7ca 100644
--- a/libalsa-intf/Makefile.am
+++ b/libalsa-intf/Makefile.am
@@ -27,15 +27,25 @@
libalsa_intfdir = $(prefix)/snd_soc_msm
dist_libalsa_intf_DATA = snd_soc_msm/snd_soc_msm \
snd_soc_msm/snd_soc_msm_2x \
+ snd_soc_msm/snd_soc_msm_2x_mpq \
snd_soc_msm/snd_soc_msm_2x_Fusion3 \
- snd_soc_msm/snd_soc_msm_Sitar
+ snd_soc_msm/snd_soc_msm_Sitar \
+ snd_soc_msm/snd_soc_msm_I2S \
+ snd_soc_msm/snd_soc_msm_auxpcm \
+ snd_soc_msm/snd_soc_msm_2x_auxpcm \
+ snd_soc_msm/snd_soc_msm_2x_mpq_auxpcm \
+ snd_soc_msm/snd_soc_msm_2x_Fusion3_auxpcm \
+ snd_soc_msm/snd_soc_msm_Sitar_auxpcm \
+ snd_soc_msm/snd_soc_msm_I2SFusion \
+ snd_soc_msm/snd_soc_msm_Taiko \
+ snd_soc_msm/snd_soc_msm_Taiko_liquid
libalsa_intf_la_CFLAGS = $(AM_CFLAGS) -DUSE_GLIB @GLIB_CFLAGS@ -DCONFIG_DIR=\"/etc/snd_soc_msm/\"
libalsa_intf_la_CPPFLAGS = $(AM_CPPFLAGS) -DUSE_GLIB @GLIB_CFLAGS@
libalsa_intf_la_LDFLAGS = $(ACDBLOADER_LIBS) -lm -lpthread @GLIB_LIBS@ -shared -version-info 1:0:0
requiredlibs = libalsa_intf.la
-bin_PROGRAMS = aplay amix arec
+bin_PROGRAMS = aplay amix arec alsaucm_test
aplay_SOURCES = aplay.c
aplay_LDADD = -lpthread $(requiredlibs)
@@ -45,3 +55,6 @@
arec_SOURCES = arec.c
arec_LDADD = -lpthread $(requiredlibs)
+
+alsaucm_test_SOURCES = alsaucm_test.c
+alsaucm_test_LDADD = -lpthread $(requiredlibs)
diff --git a/libalsa-intf/alsa_audio.h b/libalsa-intf/alsa_audio.h
index 7f2acf0..1555851 100644
--- a/libalsa-intf/alsa_audio.h
+++ b/libalsa-intf/alsa_audio.h
@@ -43,12 +43,6 @@
int device_no;
int start;
};
-
-enum decoder_alias {
- FORMAT_MP3,
- FORMAT_AC3_PASS_THROUGH = 2,
-};
-
#define FORMAT(v) SNDRV_PCM_FORMAT_##v
#define PCM_OUT 0x00000000
@@ -58,6 +52,7 @@
#define PCM_MONO 0x01000000
#define PCM_QUAD 0x02000000
#define PCM_5POINT1 0x04000000
+#define PCM_7POINT1 0x08000000
#define PCM_44100HZ 0x00000000
#define PCM_48000HZ 0x00100000
@@ -149,9 +144,12 @@
int param_set_hw_refine(struct pcm *pcm, struct snd_pcm_hw_params *params);
int param_set_hw_params(struct pcm *pcm, struct snd_pcm_hw_params *params);
int param_set_sw_params(struct pcm *pcm, struct snd_pcm_sw_params *sparams);
+int get_compressed_format(const char *format);
void param_dump(struct snd_pcm_hw_params *p);
int pcm_prepare(struct pcm *pcm);
long pcm_avail(struct pcm *pcm);
+int pcm_set_channel_map(struct pcm *pcm, struct mixer *mixer,
+ int max_channels, char *chmap);
/* Returns a human readable reason for the last error. */
const char *pcm_error(struct pcm *pcm);
@@ -188,104 +186,524 @@
#define MAX_NUM_CODECS 32
+#ifndef QCOM_COMPRESSED_AUDIO_ENABLED
/* compressed audio support */
-#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
-struct snd_compr_caps {
- __u32 num_codecs;
- __u32 min_fragment_size;
- __u32 max_fragment_size;
- __u32 min_fragments;
- __u32 max_fragments;
- __u32 codecs[MAX_NUM_CODECS];
- __u32 reserved[11];
-};
+
+/* AUDIO CODECS SUPPORTED */
+#define MAX_NUM_CODECS 32
+#define MAX_NUM_CODEC_DESCRIPTORS 32
+#define MAX_NUM_BITRATES 32
+
+/* compressed TX */
+#define MAX_NUM_FRAMES_PER_BUFFER 1
+#define COMPRESSED_META_DATA_MODE 0x10
+#define META_DATA_LEN_BYTES 36
+#define Q6_AC3_DECODER 0x00010BF6
+#define Q6_EAC3_DECODER 0x00010C3C
+#define Q6_DTS 0x00010D88
+#define Q6_DTS_LBR 0x00010DBB
+
+/* Codecs are listed linearly to allow for extensibility */
+#define SND_AUDIOCODEC_PCM ((__u32) 0x00000001)
+#define SND_AUDIOCODEC_MP3 ((__u32) 0x00000002)
+#define SND_AUDIOCODEC_AMR ((__u32) 0x00000003)
+#define SND_AUDIOCODEC_AMRWB ((__u32) 0x00000004)
+#define SND_AUDIOCODEC_AMRWBPLUS ((__u32) 0x00000005)
+#define SND_AUDIOCODEC_AAC ((__u32) 0x00000006)
+#define SND_AUDIOCODEC_WMA ((__u32) 0x00000007)
+#define SND_AUDIOCODEC_REAL ((__u32) 0x00000008)
+#define SND_AUDIOCODEC_VORBIS ((__u32) 0x00000009)
+#define SND_AUDIOCODEC_FLAC ((__u32) 0x0000000A)
+#define SND_AUDIOCODEC_IEC61937 ((__u32) 0x0000000B)
+#define SND_AUDIOCODEC_G723_1 ((__u32) 0x0000000C)
+#define SND_AUDIOCODEC_G729 ((__u32) 0x0000000D)
+#define SND_AUDIOCODEC_AC3 ((__u32) 0x0000000E)
+#define SND_AUDIOCODEC_DTS ((__u32) 0x0000000F)
+#define SND_AUDIOCODEC_AC3_PASS_THROUGH ((__u32) 0x00000010)
+#define SND_AUDIOCODEC_WMA_PRO ((__u32) 0x00000011)
+#define SND_AUDIOCODEC_DTS_PASS_THROUGH ((__u32) 0x00000012)
+#define SND_AUDIOCODEC_DTS_LBR ((__u32) 0x00000013)
+#define SND_AUDIOCODEC_DTS_TRANSCODE_LOOPBACK ((__u32) 0x00000014)
+#define SND_AUDIOCODEC_PASS_THROUGH ((__u32) 0x00000015)
+#define SND_AUDIOCODEC_MP2 ((__u32) 0x00000016)
+#define SND_AUDIOCODEC_DTS_LBR_PASS_THROUGH ((__u32) 0x00000017)
+/*
+ * Profile and modes are listed with bit masks. This allows for a
+ * more compact representation of fields that will not evolve
+ * (in contrast to the list of codecs)
+ */
+
+#define SND_AUDIOPROFILE_PCM ((__u32) 0x00000001)
+
+/* MP3 modes are only useful for encoders */
+#define SND_AUDIOCHANMODE_MP3_MONO ((__u32) 0x00000001)
+#define SND_AUDIOCHANMODE_MP3_STEREO ((__u32) 0x00000002)
+#define SND_AUDIOCHANMODE_MP3_JOINTSTEREO ((__u32) 0x00000004)
+#define SND_AUDIOCHANMODE_MP3_DUAL ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_AMR ((__u32) 0x00000001)
+
+/* AMR modes are only useful for encoders */
+#define SND_AUDIOMODE_AMR_DTX_OFF ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMR_VAD1 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMR_VAD2 ((__u32) 0x00000004)
+
+#define SND_AUDIOSTREAMFORMAT_UNDEFINED ((__u32) 0x00000000)
+#define SND_AUDIOSTREAMFORMAT_CONFORMANCE ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_IF1 ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_IF2 ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_FSF ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_RTPPAYLOAD ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_ITU ((__u32) 0x00000020)
+
+#define SND_AUDIOPROFILE_AMRWB ((__u32) 0x00000001)
+
+/* AMRWB modes are only useful for encoders */
+#define SND_AUDIOMODE_AMRWB_DTX_OFF ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AMRWB_VAD1 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AMRWB_VAD2 ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_AMRWBPLUS ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_AAC ((__u32) 0x00000001)
+
+/* AAC modes are required for encoders and decoders */
+#define SND_AUDIOMODE_AAC_MAIN ((__u32) 0x00000001)
+#define SND_AUDIOMODE_AAC_LC ((__u32) 0x00000002)
+#define SND_AUDIOMODE_AAC_SSR ((__u32) 0x00000004)
+#define SND_AUDIOMODE_AAC_LTP ((__u32) 0x00000008)
+#define SND_AUDIOMODE_AAC_HE ((__u32) 0x00000010)
+#define SND_AUDIOMODE_AAC_SCALABLE ((__u32) 0x00000020)
+#define SND_AUDIOMODE_AAC_ERLC ((__u32) 0x00000040)
+#define SND_AUDIOMODE_AAC_LD ((__u32) 0x00000080)
+#define SND_AUDIOMODE_AAC_HE_PS ((__u32) 0x00000100)
+#define SND_AUDIOMODE_AAC_HE_MPS ((__u32) 0x00000200)
+
+/* AAC formats are required for encoders and decoders */
+#define SND_AUDIOSTREAMFORMAT_MP2ADTS ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_MP4ADTS ((__u32) 0x00000002)
+#define SND_AUDIOSTREAMFORMAT_MP4LOAS ((__u32) 0x00000004)
+#define SND_AUDIOSTREAMFORMAT_MP4LATM ((__u32) 0x00000008)
+#define SND_AUDIOSTREAMFORMAT_ADIF ((__u32) 0x00000010)
+#define SND_AUDIOSTREAMFORMAT_MP4FF ((__u32) 0x00000020)
+#define SND_AUDIOSTREAMFORMAT_RAW ((__u32) 0x00000040)
+
+#define SND_AUDIOPROFILE_WMA7 ((__u32) 0x00000001)
+#define SND_AUDIOPROFILE_WMA8 ((__u32) 0x00000002)
+#define SND_AUDIOPROFILE_WMA9 ((__u32) 0x00000004)
+#define SND_AUDIOPROFILE_WMA10 ((__u32) 0x00000008)
+
+#define SND_AUDIOMODE_WMA_LEVEL1 ((__u32) 0x00000001)
+#define SND_AUDIOMODE_WMA_LEVEL2 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_WMA_LEVEL3 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_WMA_LEVEL4 ((__u32) 0x00000008)
+#define SND_AUDIOMODE_WMAPRO_LEVELM0 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_WMAPRO_LEVELM1 ((__u32) 0x00000020)
+#define SND_AUDIOMODE_WMAPRO_LEVELM2 ((__u32) 0x00000040)
+#define SND_AUDIOMODE_WMAPRO_LEVELM3 ((__u32) 0x00000080)
+
+#define SND_AUDIOSTREAMFORMAT_WMA_ASF ((__u32) 0x00000001)
+/*
+ * Some implementations strip the ASF header and only send ASF packets
+ * to the DSP
+ */
+#define SND_AUDIOSTREAMFORMAT_WMA_NOASF_HDR ((__u32) 0x00000002)
+
+#define SND_AUDIOPROFILE_REALAUDIO ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_REALAUDIO_G2 ((__u32) 0x00000001)
+#define SND_AUDIOMODE_REALAUDIO_8 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_REALAUDIO_10 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_REALAUDIO_SURROUND ((__u32) 0x00000008)
+
+#define SND_AUDIOPROFILE_VORBIS ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_VORBIS ((__u32) 0x00000001)
+
+#define SND_AUDIOPROFILE_FLAC ((__u32) 0x00000001)
+
+/*
+ * Define quality levels for FLAC encoders, from LEVEL0 (fast)
+ * to LEVEL8 (best)
+ */
+#define SND_AUDIOMODE_FLAC_LEVEL0 ((__u32) 0x00000001)
+#define SND_AUDIOMODE_FLAC_LEVEL1 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_FLAC_LEVEL2 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_FLAC_LEVEL3 ((__u32) 0x00000008)
+#define SND_AUDIOMODE_FLAC_LEVEL4 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_FLAC_LEVEL5 ((__u32) 0x00000020)
+#define SND_AUDIOMODE_FLAC_LEVEL6 ((__u32) 0x00000040)
+#define SND_AUDIOMODE_FLAC_LEVEL7 ((__u32) 0x00000080)
+#define SND_AUDIOMODE_FLAC_LEVEL8 ((__u32) 0x00000100)
+
+#define SND_AUDIOSTREAMFORMAT_FLAC ((__u32) 0x00000001)
+#define SND_AUDIOSTREAMFORMAT_FLAC_OGG ((__u32) 0x00000002)
+
+/* IEC61937 payloads without CUVP and preambles */
+#define SND_AUDIOPROFILE_IEC61937 ((__u32) 0x00000001)
+/* IEC61937 with S/PDIF preambles+CUVP bits in 32-bit containers */
+#define SND_AUDIOPROFILE_IEC61937_SPDIF ((__u32) 0x00000002)
+
+/*
+ * IEC modes are mandatory for decoders. Format autodetection
+ * will only happen on the DSP side with mode 0. The PCM mode should
+ * not be used, the PCM codec should be used instead.
+ */
+#define SND_AUDIOMODE_IEC_REF_STREAM_HEADER ((__u32) 0x00000000)
+#define SND_AUDIOMODE_IEC_LPCM ((__u32) 0x00000001)
+#define SND_AUDIOMODE_IEC_AC3 ((__u32) 0x00000002)
+#define SND_AUDIOMODE_IEC_MPEG1 ((__u32) 0x00000004)
+#define SND_AUDIOMODE_IEC_MP3 ((__u32) 0x00000008)
+#define SND_AUDIOMODE_IEC_MPEG2 ((__u32) 0x00000010)
+#define SND_AUDIOMODE_IEC_AACLC ((__u32) 0x00000020)
+#define SND_AUDIOMODE_IEC_DTS ((__u32) 0x00000040)
+#define SND_AUDIOMODE_IEC_ATRAC ((__u32) 0x00000080)
+#define SND_AUDIOMODE_IEC_SACD ((__u32) 0x00000100)
+#define SND_AUDIOMODE_IEC_EAC3 ((__u32) 0x00000200)
+#define SND_AUDIOMODE_IEC_DTS_HD ((__u32) 0x00000400)
+#define SND_AUDIOMODE_IEC_MLP ((__u32) 0x00000800)
+#define SND_AUDIOMODE_IEC_DST ((__u32) 0x00001000)
+#define SND_AUDIOMODE_IEC_WMAPRO ((__u32) 0x00002000)
+#define SND_AUDIOMODE_IEC_REF_CXT ((__u32) 0x00004000)
+#define SND_AUDIOMODE_IEC_HE_AAC ((__u32) 0x00008000)
+#define SND_AUDIOMODE_IEC_HE_AAC2 ((__u32) 0x00010000)
+#define SND_AUDIOMODE_IEC_MPEG_SURROUND ((__u32) 0x00020000)
+
+#define SND_AUDIOPROFILE_G723_1 ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G723_1_ANNEX_A ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G723_1_ANNEX_B ((__u32) 0x00000002)
+#define SND_AUDIOMODE_G723_1_ANNEX_C ((__u32) 0x00000004)
+
+#define SND_AUDIOPROFILE_G729 ((__u32) 0x00000001)
+
+#define SND_AUDIOMODE_G729_ANNEX_A ((__u32) 0x00000001)
+#define SND_AUDIOMODE_G729_ANNEX_B ((__u32) 0x00000002)
+
+/* <FIXME: multichannel encoders aren't supported for now. Would need
+ an additional definition of channel arrangement> */
+
+/* VBR/CBR definitions */
+#define SND_RATECONTROLMODE_CONSTANTBITRATE ((__u32) 0x00000001)
+#define SND_RATECONTROLMODE_VARIABLEBITRATE ((__u32) 0x00000002)
+
+/* Encoder options */
struct snd_enc_wma {
- __u32 super_block_align; /* WMA Type-specific data */
+ __u32 super_block_align; /* WMA Type-specific data */
__u32 bits_per_sample;
__u32 channelmask;
__u32 encodeopt;
+ __u32 encodeopt1;
+ __u32 encodeopt2;
};
+
+/**
+ * struct snd_enc_vorbis
+ * @quality: Sets encoding quality to n, between -1 (low) and 10 (high).
+ * In the default mode of operation, the quality level is 3.
+ * Normal quality range is 0 - 10.
+ * @managed: Boolean. Set bitrate management mode. This turns off the
+ * normal VBR encoding, but allows hard or soft bitrate constraints to be
+ * enforced by the encoder. This mode can be slower, and may also be
+ * lower quality. It is primarily useful for streaming.
+ * @max_bit_rate: Enabled only if managed is TRUE
+ * @min_bit_rate: Enabled only if managed is TRUE
+ * @downmix: Boolean. Downmix input from stereo to mono (has no effect on
+ * non-stereo streams). Useful for lower-bitrate encoding.
+ *
+ * These options were extracted from the OpenMAX IL spec and Gstreamer vorbisenc
+ * properties
+ *
+ * For best quality users should specify VBR mode and set quality levels.
+ */
+
struct snd_enc_vorbis {
- int quality;
- __u32 managed;
- __u32 max_bit_rate;
- __u32 min_bit_rate;
- __u32 downmix;
+ __s32 quality;
+ __u32 managed;
+ __u32 max_bit_rate;
+ __u32 min_bit_rate;
+ __u32 downmix;
};
+
+/**
+ * struct snd_enc_real
+ * @quant_bits: number of coupling quantization bits in the stream
+ * @start_region: coupling start region in the stream
+ * @num_regions: number of regions value
+ *
+ * These options were extracted from the OpenMAX IL spec
+ */
+
struct snd_enc_real {
- __u32 quant_bits;
- __u32 start_region;
- __u32 num_regions;
+ __u32 quant_bits;
+ __u32 start_region;
+ __u32 num_regions;
};
+/**
+ * struct snd_enc_flac
+ * @num: serial number, valid only for OGG formats
+ * needs to be set by application
+ * @gain: Add replay gain tags
+ *
+ * These options were extracted from the FLAC online documentation
+ * at http://flac.sourceforge.net/documentation_tools_flac.html
+ *
+ * To make the API simpler, it is assumed that the user will select quality
+ * profiles. Additional options that affect encoding quality and speed can
+ * be added at a later stage if needed.
+ *
+ * By default the Subset format is used by encoders.
+ *
+ * TAGS such as pictures, etc, cannot be handled by an offloaded encoder and are
+ * not supported in this API.
+ */
+
struct snd_enc_flac {
- __u32 num;
- __u32 gain;
+ __u32 num;
+ __u32 gain;
};
struct snd_enc_generic {
- __u32 bw; /* encoder bandwidth */
- int reserved[15];
+ __u32 bw; /* encoder bandwidth */
+ __s32 reserved[15];
+};
+struct snd_dec_dts {
+ __u32 modelIdLength;
+ __u8 *modelId;
};
union snd_codec_options {
- struct snd_enc_wma wma;
- struct snd_enc_vorbis vorbis;
- struct snd_enc_real real;
- struct snd_enc_flac flac;
- struct snd_enc_generic generic;
+ struct snd_enc_wma wma;
+ struct snd_enc_vorbis vorbis;
+ struct snd_enc_real real;
+ struct snd_enc_flac flac;
+ struct snd_enc_generic generic;
+ struct snd_dec_dts dts;
};
+/** struct snd_codec_desc - description of codec capabilities
+ * @max_ch: Maximum number of audio channels
+ * @sample_rates: Sampling rates in Hz, use SNDRV_PCM_RATE_xxx for this
+ * @bit_rate: Indexed array containing supported bit rates
+ * @num_bitrates: Number of valid values in bit_rate array
+ * @rate_control: value is specified by SND_RATECONTROLMODE defines.
+ * @profiles: Supported profiles. See SND_AUDIOPROFILE defines.
+ * @modes: Supported modes. See SND_AUDIOMODE defines
+ * @formats: Supported formats. See SND_AUDIOSTREAMFORMAT defines
+ * @min_buffer: Minimum buffer size handled by codec implementation
+ * @reserved: reserved for future use
+ *
+ * This structure provides a scalar value for profiles, modes and stream
+ * format fields.
+ * If an implementation supports multiple combinations, they will be listed as
+ * codecs with different descriptors, for example there would be 2 descriptors
+ * for AAC-RAW and AAC-ADTS.
+ * This entails some redundancy but makes it easier to avoid invalid
+ * configurations.
+ *
+ */
+
+struct snd_codec_desc {
+ __u32 max_ch;
+ __u32 sample_rates;
+ __u32 bit_rate[MAX_NUM_BITRATES];
+ __u32 num_bitrates;
+ __u32 rate_control;
+ __u32 profiles;
+ __u32 modes;
+ __u32 formats;
+ __u32 min_buffer;
+ __u32 reserved[15];
+};
+
+/** struct snd_codec
+ * @id: Identifies the supported audio encoder/decoder.
+ * See SND_AUDIOCODEC macros.
+ * @ch_in: Number of input audio channels
+ * @ch_out: Number of output channels. In case of contradiction between
+ * this field and the channelMode field, the channelMode field
+ * overrides.
+ * @sample_rate: Audio sample rate of input data
+ * @bit_rate: Bitrate of encoded data. May be ignored by decoders
+ * @rate_control: Encoding rate control. See SND_RATECONTROLMODE defines.
+ * Encoders may rely on profiles for quality levels.
+ * May be ignored by decoders.
+ * @profile: Mandatory for encoders, can be mandatory for specific
+ * decoders as well. See SND_AUDIOPROFILE defines.
+ * @level: Supported level (Only used by WMA at the moment)
+ * @ch_mode: Channel mode for encoder. See SND_AUDIOCHANMODE defines
+ * @format: Format of encoded bistream. Mandatory when defined.
+ * See SND_AUDIOSTREAMFORMAT defines.
+ * @align: Block alignment in bytes of an audio sample.
+ * Only required for PCM or IEC formats.
+ * @options: encoder-specific settings
+ * @reserved: reserved for future use
+ */
+
struct snd_codec {
- __u32 id;
- __u32 ch_in;
- __u32 ch_out;
- __u32 sample_rate;
- __u32 bit_rate;
- __u32 rate_control;
- __u32 profile;
- __u32 level;
- __u32 ch_mode;
- __u32 format;
- __u32 align;
- union snd_codec_options options;
- __u32 reserved[3];
+ __u32 id;
+ __u32 ch_in;
+ __u32 ch_out;
+ __u32 sample_rate;
+ __u32 bit_rate;
+ __u32 rate_control;
+ __u32 profile;
+ __u32 level;
+ __u32 ch_mode;
+ __u32 format;
+ __u32 align;
+ __u32 transcode_dts;
+ struct snd_dec_dts dts;
+ union snd_codec_options options;
+ __u32 reserved[3];
};
+
+
+#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 0)
+/**
+ * struct snd_compressed_buffer: compressed buffer
+ * @fragment_size: size of buffer fragment in bytes
+ * @fragments: number of such fragments
+ */
struct snd_compressed_buffer {
- size_t fragment_size;
- int fragments;
+ __u32 fragment_size;
+ __u32 fragments;
};
-/* */
+/**
+ * struct snd_compr_params: compressed stream params
+ * @buffer: buffer description
+ * @codec: codec parameters
+ * @no_wake_mode: dont wake on fragment elapsed
+ */
struct snd_compr_params {
- struct snd_compressed_buffer buffer;
- struct snd_codec codec;
+ struct snd_compressed_buffer buffer;
+ struct snd_codec codec;
+ __u8 no_wake_mode;
};
+/**
+ * struct snd_compr_tstamp: timestamp descriptor
+ * @byte_offset: Byte offset in ring buffer to DSP
+ * @copied_total: Total number of bytes copied from/to ring buffer to/by DSP
+ * @pcm_frames: Frames decoded or encoded by DSP. This field will evolve by
+ * large steps and should only be used to monitor encoding/decoding
+ * progress. It shall not be used for timing estimates.
+ * @pcm_io_frames: Frames rendered or received by DSP into a mixer or an audio
+ * output/input. This field should be used for A/V sync or time estimates.
+ * @sampling_rate: sampling rate of audio
+ */
struct snd_compr_tstamp {
- size_t copied_bytes;
- size_t copied_total;
- size_t decoded;
- size_t rendered;
- __u32 sampling_rate;
- uint64_t timestamp;
+ __u32 byte_offset;
+ __u32 copied_total;
+ snd_pcm_uframes_t pcm_frames;
+ snd_pcm_uframes_t pcm_io_frames;
+ __u32 sampling_rate;
+ uint64_t timestamp;
};
-#define SNDRV_COMPRESS_GET_CAPS _IOWR('C', 0x00, struct snd_compr_caps *)
-#define SNDRV_COMPRESS_GET_CODEC_CAPS _IOWR('C', 0x01, struct snd_compr_codec_caps *)
-#define SNDRV_COMPRESS_SET_PARAMS _IOW('C', 0x02, struct snd_compr_params *)
-#define SNDRV_COMPRESS_GET_PARAMS _IOR('C', 0x03, struct snd_compr_params *)
-#define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x10, struct snd_compr_tstamp *)
-#define SNDRV_COMPRESS_AVAIL _IOR('C', 0x11, struct snd_compr_avail *)
-#define SNDRV_COMPRESS_PAUSE _IO('C', 0x20)
-#define SNDRV_COMPRESS_RESUME _IO('C', 0x21)
-#define SNDRV_COMPRESS_START _IO('C', 0x22)
-#define SNDRV_COMPRESS_STOP _IO('C', 0x23)
-#define SNDRV_COMPRESS_DRAIN _IO('C', 0x24)
+/**
+ * struct snd_compr_avail: avail descriptor
+ * @avail: Number of bytes available in ring buffer for writing/reading
+ * @tstamp: timestamp infomation
+ */
+struct snd_compr_avail {
+ __u64 avail;
+ struct snd_compr_tstamp tstamp;
+};
+
+enum snd_compr_direction {
+ SND_COMPRESS_PLAYBACK = 0,
+ SND_COMPRESS_CAPTURE
+};
+
+/**
+ * struct snd_compr_caps: caps descriptor
+ * @codecs: pointer to array of codecs
+ * @direction: direction supported. Of type snd_compr_direction
+ * @min_fragment_size: minimum fragment supported by DSP
+ * @max_fragment_size: maximum fragment supported by DSP
+ * @min_fragments: min fragments supported by DSP
+ * @max_fragments: max fragments supported by DSP
+ * @num_codecs: number of codecs supported
+ * @reserved: reserved field
+ */
+struct snd_compr_caps {
+ __u32 num_codecs;
+ __u32 direction;
+ __u32 min_fragment_size;
+ __u32 max_fragment_size;
+ __u32 min_fragments;
+ __u32 max_fragments;
+ __u32 codecs[MAX_NUM_CODECS];
+ __u32 reserved[11];
+};
+
+/**
+ * struct snd_compr_codec_caps: query capability of codec
+ * @codec: codec for which capability is queried
+ * @num_descriptors: number of codec descriptors
+ * @descriptor: array of codec capability descriptor
+ */
+struct snd_compr_codec_caps {
+ __u32 codec;
+ __u32 num_descriptors;
+ struct snd_codec_desc descriptor[MAX_NUM_CODEC_DESCRIPTORS];
+};
+
+/**
+ * struct snd_compr_audio_info: compressed input audio information
+ * @frame_size: legth of the encoded frame with valid data
+ * @reserved: reserved for furture use
+ */
+struct snd_compr_audio_info {
+ uint32_t frame_size;
+ uint32_t reserved[15];
+};
+
+/**
+ * compress path ioctl definitions
+ * SNDRV_COMPRESS_GET_CAPS: Query capability of DSP
+ * SNDRV_COMPRESS_GET_CODEC_CAPS: Query capability of a codec
+ * SNDRV_COMPRESS_SET_PARAMS: Set codec and stream parameters
+ * Note: only codec params can be changed runtime and stream params cant be
+ * SNDRV_COMPRESS_GET_PARAMS: Query codec params
+ * SNDRV_COMPRESS_TSTAMP: get the current timestamp value
+ * SNDRV_COMPRESS_AVAIL: get the current buffer avail value.
+ * This also queries the tstamp properties
+ * SNDRV_COMPRESS_PAUSE: Pause the running stream
+ * SNDRV_COMPRESS_RESUME: resume a paused stream
+ * SNDRV_COMPRESS_START: Start a stream
+ * SNDRV_COMPRESS_STOP: stop a running stream, discarding ring buffer content
+ * and the buffers currently with DSP
+ * SNDRV_COMPRESS_DRAIN: Play till end of buffers and stop after that
+ * SNDRV_COMPRESS_IOCTL_VERSION: Query the API version
+ */
+#define SNDRV_COMPRESS_IOCTL_VERSION _IOR('C', 0x00, int)
+#define SNDRV_COMPRESS_GET_CAPS _IOWR('C', 0x10, struct snd_compr_caps)
+#define SNDRV_COMPRESS_GET_CODEC_CAPS _IOWR('C', 0x11,\
+ struct snd_compr_codec_caps)
+#define SNDRV_COMPRESS_SET_PARAMS _IOW('C', 0x12, struct snd_compr_params)
+#define SNDRV_COMPRESS_GET_PARAMS _IOR('C', 0x13, struct snd_codec)
+#define SNDRV_COMPRESS_TSTAMP _IOR('C', 0x20, struct snd_compr_tstamp)
+#define SNDRV_COMPRESS_AVAIL _IOR('C', 0x21, struct snd_compr_avail)
+#define SNDRV_COMPRESS_PAUSE _IO('C', 0x30)
+#define SNDRV_COMPRESS_RESUME _IO('C', 0x31)
+#define SNDRV_COMPRESS_START _IO('C', 0x32)
+#define SNDRV_COMPRESS_STOP _IO('C', 0x33)
+#define SNDRV_COMPRESS_DRAIN _IO('C', 0x34)
+/*
+ * TODO
+ * 1. add mmap support
+ *
+ */
+#define SND_COMPR_TRIGGER_DRAIN 7 /*FIXME move this to pcm.h */
+
#endif
#endif
diff --git a/libalsa-intf/alsa_mixer.c b/libalsa-intf/alsa_mixer.c
index cdcdcea..81817d9 100644
--- a/libalsa-intf/alsa_mixer.c
+++ b/libalsa-intf/alsa_mixer.c
@@ -488,7 +488,6 @@
if (count < ctl->info->count || count > ctl->info->count)
return -EINVAL;
-
memset(&ev, 0, sizeof(ev));
ev.id.numid = ctl->info->id.numid;
switch (ctl->info->type) {
@@ -511,6 +510,13 @@
}
break;
}
+ case SNDRV_CTL_ELEM_TYPE_ENUMERATED: {
+ for (n = 0; n < ctl->info->count; n++) {
+ fprintf( stderr, "Value: %d idx:%d\n", atoi(argv[n]), n);
+ ev.value.enumerated.item[n] = (unsigned int)atoi(argv[n]);
+ }
+ break;
+ }
default:
errno = EINVAL;
return errno;
diff --git a/libalsa-intf/alsa_pcm.c b/libalsa-intf/alsa_pcm.c
index a814ae8..4f55437 100644
--- a/libalsa-intf/alsa_pcm.c
+++ b/libalsa-intf/alsa_pcm.c
@@ -43,7 +43,9 @@
#include <sys/poll.h>
#include <linux/ioctl.h>
#include <linux/types.h>
-
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
+#include <sound/compress_params.h>
+#endif
#include "alsa_audio.h"
#define __force
@@ -78,7 +80,7 @@
IMA_ADPCM,
MPEG,
GSM,
- SPECIAL = 31,
+ SPECIAL = 31,
S24_3LE,
S24_3BE,
U24_3LE,
@@ -118,7 +120,7 @@
{"A_LAW", "A-Law"},
{"IMA_ADPCM", "Ima-ADPCM"},
{"MPEG", "MPEG"},
- {"GSM", "GSM"},
+ {"GSM", "GSM"},
[31] = {"SPECIAL", "Special"},
{"S24_3LE", "Signed 24 bit Little Endian in 3bytes"},
{"S24_3BE", "Signed 24 bit Big Endian in 3bytes"},
@@ -133,6 +135,18 @@
{"U18_3LE", "Unsigned 18 bit Little Endian in 3bytes"},
{"U18_3BE", "Unsigned 18 bit Big Endian in 3bytes"},
};
+enum decoder_alias {
+ FORMAT_MP3 = SND_AUDIOCODEC_MP3,
+ FORMAT_AAC = SND_AUDIOCODEC_AAC,
+ FORMAT_AC3_PASS_THROUGH = SND_AUDIOCODEC_AC3_PASS_THROUGH,
+ FORMAT_WMA = SND_AUDIOCODEC_WMA,
+ FORMAT_WMA_PRO = SND_AUDIOCODEC_WMA_PRO,
+ FORMAT_DTS = SND_AUDIOCODEC_DTS,
+ FORMAT_DTS_LBR = SND_AUDIOCODEC_DTS_LBR,
+ FORMAT_DTS_PASS_THROUGH = SND_AUDIOCODEC_DTS_PASS_THROUGH,
+ FORMAT_AMRWB = SND_AUDIOCODEC_AMRWB,
+ FORMAT_AMRWB_PLUS = SND_AUDIOCODEC_AMRWBPLUS
+};
int get_compressed_format(const char *format)
{
@@ -143,6 +157,30 @@
} else if (strcmp(ch, "AC3_PASS_THROUGH") == 0) {
printf("AC3 PASS THROUGH is selected\n");
return FORMAT_AC3_PASS_THROUGH;
+ } else if (strcmp(ch, "AAC") == 0) {
+ printf("AAC is selected\n");
+ return FORMAT_AAC;
+ } else if (strcmp(ch, "AC3_PASS_THROUGH") == 0) {
+ printf("AC3_PASS_THROUGH is selected\n");
+ return FORMAT_AC3_PASS_THROUGH;
+ } else if (strcmp(ch, "WMA") == 0) {
+ printf("WMA is selected\n");
+ return FORMAT_WMA;
+ }else if (strcmp(ch, "WMA_PRO") == 0) {
+ printf("WMA_PRO is selected\n");
+ return FORMAT_WMA_PRO;
+ }else if (strcmp(ch, "DTS") == 0) {
+ printf("DTS is selected\n");
+ return FORMAT_DTS;
+ } else if (strcmp(ch, "DTS_LBR") == 0) {
+ printf("DTS_LBR is selected\n");
+ return FORMAT_DTS_LBR;
+ } else if (strcmp(ch, "AMR_WB") == 0) {
+ printf("AMR_WB is selected\n");
+ return FORMAT_AMRWB;
+ }else if (strcmp(ch, "AMR_WB_PLUS") == 0) {
+ printf("FORMAT_AMRWB_PLUS is selected\n");
+ return FORMAT_AMRWB_PLUS;
} else {
printf("invalid format\n");
return -1;
@@ -409,7 +447,20 @@
avail += pcm->sw_p->boundary;
return avail;
} else {
- long avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr + ((pcm->flags & PCM_MONO) ? pcm->buffer_size/2 : pcm->buffer_size/4);
+ int buffer_size = 0;
+ long avail;
+ if(pcm->flags & PCM_MONO)
+ buffer_size = pcm->buffer_size/2;
+ else if(pcm->flags & PCM_QUAD)
+ buffer_size = pcm->buffer_size/8;
+ else if(pcm->flags & PCM_5POINT1)
+ buffer_size = pcm->buffer_size/12;
+ else if(pcm->flags & PCM_7POINT1)
+ buffer_size = pcm->buffer_size/16;
+ else
+ buffer_size = pcm->buffer_size/4;
+
+ avail = sync_ptr->s.status.hw_ptr - sync_ptr->c.control.appl_ptr + buffer_size;
if (avail < 0)
avail += pcm->sw_p->boundary;
else if ((unsigned long) avail >= pcm->sw_p->boundary)
@@ -437,7 +488,18 @@
char *ptr;
unsigned size;
struct snd_pcm_channel_info ch;
- int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
+ int channels;
+
+ if(pcm->flags & PCM_MONO)
+ channels = 1;
+ else if(pcm->flags & PCM_QUAD)
+ channels = 4;
+ else if(pcm->flags & PCM_5POINT1)
+ channels = 6;
+ else if(pcm->flags & PCM_7POINT1)
+ channels = 8;
+ else
+ channels = 2;
size = pcm->buffer_size;
if (pcm->flags & DEBUG_ON)
@@ -461,8 +523,19 @@
unsigned long pcm_offset = 0;
struct snd_pcm_sync_ptr *sync_ptr = pcm->sync_ptr;
unsigned int appl_ptr = 0;
+ int channels;
+ if(pcm->flags & PCM_MONO)
+ channels = 1;
+ else if(pcm->flags & PCM_QUAD)
+ channels = 4;
+ else if(pcm->flags & PCM_5POINT1)
+ channels = 6;
+ else if(pcm->flags & PCM_7POINT1)
+ channels = 8;
+ else
+ channels = 2;
- appl_ptr = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4;
+ appl_ptr = sync_ptr->c.control.appl_ptr*2*channels;
pcm_offset = (appl_ptr % (unsigned long)pcm->buffer_size);
return pcm->addr + pcm_offset;
@@ -475,7 +548,17 @@
unsigned size;
u_int8_t *dst_addr, *mmaped_addr;
u_int8_t *src_addr = data;
- int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
+ int channels;
+ if(pcm->flags & PCM_MONO)
+ channels = 1;
+ else if(pcm->flags & PCM_QUAD)
+ channels = 4;
+ else if(pcm->flags & PCM_5POINT1)
+ channels = 6;
+ else if(pcm->flags & PCM_7POINT1)
+ channels = 8;
+ else
+ channels = 2;
dst_addr = dst_address(pcm);
@@ -497,9 +580,20 @@
unsigned size;
u_int8_t *dst_addr, *mmaped_addr;
u_int8_t *src_addr;
- int channels = (pcm->flags & PCM_MONO) ? 1 : 2;
- unsigned int tmp = (pcm->flags & PCM_MONO) ? sync_ptr->c.control.appl_ptr*2 : sync_ptr->c.control.appl_ptr*4;
+ int channels;
+ unsigned int tmp;
+ if(pcm->flags & PCM_MONO)
+ channels = 1;
+ else if(pcm->flags & PCM_QUAD)
+ channels = 4;
+ else if(pcm->flags & PCM_5POINT1)
+ channels = 6;
+ else if(pcm->flags & PCM_7POINT1)
+ channels = 8;
+ else
+ channels = 2;
+ tmp = sync_ptr->c.control.appl_ptr*2*channels;
pcm_offset = (tmp % (unsigned long)pcm->buffer_size);
dst_addr = data;
src_addr = pcm->addr + pcm_offset;
@@ -528,8 +622,18 @@
long frames;
int err;
int bytes_written;
-
- frames = (pcm->flags & PCM_MONO) ? (count / 2) : (count / 4);
+ int channels;
+ if(pcm->flags & PCM_MONO)
+ channels = 1;
+ else if(pcm->flags & PCM_QUAD)
+ channels = 4;
+ else if(pcm->flags & PCM_5POINT1)
+ channels = 6;
+ else if(pcm->flags & PCM_7POINT1)
+ channels = 8;
+ else
+ channels = 2;
+ frames = count / (2*channels);
pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;
err = sync_ptr(pcm);
@@ -576,7 +680,17 @@
static int pcm_write_nmmap(struct pcm *pcm, void *data, unsigned count)
{
struct snd_xferi x;
- int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 );
+ int channels;
+ if(pcm->flags & PCM_MONO)
+ channels = 1;
+ else if(pcm->flags & PCM_QUAD)
+ channels = 4;
+ else if(pcm->flags & PCM_5POINT1)
+ channels = 6;
+ else if(pcm->flags & PCM_7POINT1)
+ channels = 8;
+ else
+ channels = 2;
if (pcm->flags & PCM_IN)
return -EINVAL;
@@ -626,6 +740,8 @@
x.frames = (count / 8);
} else if (pcm->flags & PCM_5POINT1) {
x.frames = (count / 12);
+ } else if (pcm->flags & PCM_7POINT1) {
+ x.frames = (count / 16);
} else {
x.frames = (count / 4);
}
@@ -647,6 +763,20 @@
pcm->underruns++;
pcm->running = 0;
continue;
+ } else if (errno == ESTRPIPE) {
+ ALOGV("Resume from suspended\n");
+ for (;;) {
+ if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_RESUME)) {
+ if (errno == EAGAIN ) {
+ if (pcm_prepare(pcm))
+ return -errno;
+ }
+ /* send resume command again */
+ continue;
+ } else
+ break;
+ }
+ continue;
}
ALOGE("Arec: error%d\n", errno);
return -errno;
@@ -854,3 +984,46 @@
{
return pcm->fd >= 0;
}
+
+int pcm_set_channel_map(struct pcm *pcm, struct mixer *mixer,
+ int max_channels, char *chmap)
+{
+ struct mixer_ctl *ctl;
+ char control_name[44]; // max length of name is 44 as defined
+ char device_num[3]; // device number upto 2 digit
+ char **set_values;
+ int i;
+
+ ALOGV("pcm_set_channel_map");
+ set_values = (char**)malloc(max_channels*sizeof(char*));
+ if(set_values) {
+ for(i=0; i< max_channels; i++) {
+ set_values[i] = (char*)malloc(4*sizeof(char));
+ if(set_values[i]) {
+ sprintf(set_values[i],"%d",chmap[i]);
+ } else {
+ ALOGE("memory allocation for set channel map failed");
+ return -1;
+ }
+ }
+ } else {
+ ALOGE("memory allocation for set channel map failed");
+ return -1;
+ }
+ strlcpy(control_name, "Playback Channel Map", sizeof(control_name));
+ sprintf(device_num, "%d", pcm->device_no);
+ strcat(control_name, device_num);
+ ALOGV("pcm_set_channel_map: control name:%s", control_name);
+ ctl = mixer_get_control(mixer, control_name, 0);
+ if(ctl == NULL) {
+ ALOGE(stderr, "Could not get the mixer control\n");
+ return -1;
+ }
+ mixer_ctl_set_value(ctl, max_channels, set_values);
+ for(i=0; i< max_channels; i++)
+ if(set_values[i])
+ free(set_values[i]);
+ if(set_values)
+ free(set_values);
+ return 0;
+}
diff --git a/libalsa-intf/alsa_ucm.c b/libalsa-intf/alsa_ucm.c
index 3548f67..0886d54 100644
--- a/libalsa-intf/alsa_ucm.c
+++ b/libalsa-intf/alsa_ucm.c
@@ -58,13 +58,15 @@
#include <sys/time.h>
#include <sys/poll.h>
#include <stdint.h>
-#include <dlfcn.h>
#include <linux/ioctl.h>
#include "msm8960_use_cases.h"
#if defined(QC_PROP)
- static void (*acdb_send_audio_cal)(int,int);
- static void (*acdb_send_voice_cal)(int,int);
+ #include "acdb-loader.h"
+#else
+ #define acdb_loader_send_voice_cal(rxacdb_id, txacdb_id) (-EPERM)
+ #define acdb_loader_send_audio_cal(acdb_id, capability) (-EPERM)
+ #define acdb_loader_send_anc_cal(acdb_id) (-EPERM)
#endif
#define PARSE_DEBUG 0
@@ -442,6 +444,42 @@
ret = -ENODEV;
}
}
+ } else if (!strncmp(ident1, "EC_REF_RXMixerCTL", 17)) {
+ ident2 = strtok_r(NULL, "/", &temp_ptr);
+ index = 0; verb_index = 0;
+ verb_list = uc_mgr->card_ctxt_ptr->use_case_verb_list;
+ if((verb_index < 0) ||
+ (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
+ SND_UCM_END_OF_LIST, 3)) ||
+ (verb_list[verb_index].verb_ctrls == NULL)) {
+ ALOGE("Invalid current verb value: %s - %d",
+ uc_mgr->card_ctxt_ptr->current_verb, verb_index);
+ pthread_mutex_unlock(&uc_mgr->card_ctxt_ptr->card_lock);
+ return -EINVAL;
+ }
+ ctrl_list = verb_list[verb_index].device_ctrls;
+ if (ident2 != NULL) {
+ while(strncmp(ctrl_list[index].case_name, ident2, strlen(ident2)+1)) {
+ if (!strncmp(ctrl_list[index].case_name, SND_UCM_END_OF_LIST,
+ strlen(SND_UCM_END_OF_LIST))){
+ ret = -EINVAL;
+ break;
+ } else {
+ index++;
+ }
+ }
+ }
+ if (ret < 0) {
+ ALOGE("No valid device/modifier found with given identifier: %s",
+ ident2);
+ } else {
+ if (verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl) {
+ *value = strdup(verb_list[verb_index].device_ctrls[index].ec_ref_rx_mixer_ctl);
+ } else {
+ *value = NULL;
+ ret = -ENODEV;
+ }
+ }
} else {
ALOGE("Unsupported identifier value: %s", ident1);
*value = NULL;
@@ -543,10 +581,18 @@
if ((!strncmp(use_case, SND_USE_CASE_VERB_VOICECALL,
strlen(SND_USE_CASE_VERB_VOICECALL))) ||
+ (!strncmp(use_case, SND_USE_CASE_VERB_SGLTECALL,
+ strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+ (!strncmp(use_case, SND_USE_CASE_VERB_VOLTE,
+ strlen(SND_USE_CASE_VERB_VOLTE))) ||
(!strncmp(use_case, SND_USE_CASE_VERB_IP_VOICECALL,
strlen(SND_USE_CASE_VERB_IP_VOICECALL))) ||
(!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOICE,
strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
+ (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_SGLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_SGLTE))) ||
+ (!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) ||
(!strncmp(use_case, SND_USE_CASE_MOD_PLAY_VOIP,
strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
ALOGV("check_devices_for_voice_call(): voice cap detected\n");
@@ -584,8 +630,12 @@
/* Check if voice call use case/modifier exists */
if ((!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
+ SND_USE_CASE_VERB_VOLTE, strlen(SND_USE_CASE_VERB_VOLTE))) ||
+ (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
SND_USE_CASE_VERB_VOICECALL, strlen(SND_USE_CASE_VERB_VOICECALL))) ||
(!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
+ SND_USE_CASE_VERB_SGLTECALL, strlen(SND_USE_CASE_VERB_SGLTECALL))) ||
+ (!strncmp(uc_mgr->card_ctxt_ptr->current_verb,
SND_USE_CASE_VERB_IP_VOICECALL,
strlen(SND_USE_CASE_VERB_IP_VOICECALL)))) {
voice_acdb = 1;
@@ -597,8 +647,12 @@
if ((ident_value =
snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->mod_list_head,
index))) {
- if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE,
+ if ((!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) ||
+ (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOICE,
strlen(SND_USE_CASE_MOD_PLAY_VOICE))) ||
+ (!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_SGLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_SGLTE))) ||
(!strncmp(ident_value, SND_USE_CASE_MOD_PLAY_VOIP,
strlen(SND_USE_CASE_MOD_PLAY_VOIP)))) {
voice_acdb = 1;
@@ -673,15 +727,8 @@
ALOGD("Voice acdb: rx id %d tx id %d",
uc_mgr->current_rx_device,
uc_mgr->current_tx_device);
- if (uc_mgr->acdb_handle) {
- acdb_send_voice_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_voice_cal");
- if (acdb_send_voice_cal == NULL) {
- ALOGE("ucm: dlsym: Error:%s Loading acdb_loader_send_voice_cal", dlerror());
- }else {
- acdb_send_voice_cal(uc_mgr->current_rx_device,
- uc_mgr->current_tx_device);
- }
- }
+ acdb_loader_send_voice_cal(uc_mgr->current_rx_device,
+ uc_mgr->current_tx_device);
} else {
ALOGV("Voice acdb: Required acdb already pushed \
rx id %d tx id %d", uc_mgr->current_rx_device,
@@ -792,22 +839,15 @@
(check_devices_for_voice_call(uc_mgr, use_case) != NULL))
return ret;
ALOGD("Set mixer controls for %s enable %d", use_case, enable);
- if (ctrl_list[uc_index].acdb_id && ctrl_list[uc_index].capability) {
+ if ((ctrl_list[uc_index].acdb_id >= 0) && ctrl_list[uc_index].capability) {
if (enable) {
- if (snd_use_case_apply_voice_acdb(uc_mgr, uc_index)) {
- ALOGV("acdb_id %d cap %d enable %d",
- ctrl_list[uc_index].acdb_id,
+ snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
+ ALOGD("acdb_id %d cap %d enable %d",
+ ctrl_list[uc_index].acdb_id,
ctrl_list[uc_index].capability, enable);
- if (uc_mgr->acdb_handle) {
- acdb_send_audio_cal = dlsym(uc_mgr->acdb_handle,"acdb_loader_send_audio_cal");
- if (acdb_send_audio_cal == NULL) {
- ALOGE("ucm:dlsym:Error:%s Loading acdb_loader_send_audio_cal", dlerror());
- } else {
- acdb_send_audio_cal(ctrl_list[uc_index].acdb_id,
- ctrl_list[uc_index].capability);
- }
- }
- }
+ acdb_loader_send_audio_cal(
+ ctrl_list[uc_index].acdb_id,
+ ctrl_list[uc_index].capability);
}
}
if (enable) {
@@ -826,7 +866,7 @@
mixer_list[index].control_name, 0);
if (ctl) {
if (mixer_list[index].type == TYPE_INT) {
- ALOGV("Setting mixer control: %s, value: %d",
+ ALOGD("Setting mixer control: %s, value: %d",
mixer_list[index].control_name,
mixer_list[index].value);
ret = mixer_ctl_set(ctl, mixer_list[index].value);
@@ -839,7 +879,7 @@
ALOGE("Failed to set multi value control %s\n",
mixer_list[index].control_name);
} else {
- ALOGV("Setting mixer control: %s, value: %s",
+ ALOGD("Setting mixer control: %s, value: %s",
mixer_list[index].control_name,
mixer_list[index].string);
ret = mixer_ctl_select(ctl, mixer_list[index].string);
@@ -885,8 +925,12 @@
MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
!strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL2,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_TUNNEL2)) ||
!strncmp(useCase, SND_USE_CASE_VERB_HIFI2,
MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI2)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI3,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI3)) ||
!strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
MAX_LEN(useCase,SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
@@ -895,25 +939,41 @@
MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC2,
MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC2)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC3,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_MUSIC3)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_LPA)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL2,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_TUNNEL2)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
- MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))) {
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_FM))||
+ !strncmp(useCase, SND_USE_CASE_MOD_PSEUDO_TUNNEL,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PSEUDO_TUNNEL))||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL))) {
return CAP_RX;
} else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC2,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC2)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC_COMPRESSED,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_REC_COMPRESSED)) ||
!strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
MAX_LEN(useCase,SND_USE_CASE_VERB_FM_REC)) ||
!strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
MAX_LEN(useCase,SND_USE_CASE_VERB_FM_A2DP_REC)) ||
!strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC2,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC2)) ||
!strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC,
MAX_LEN(useCase,SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC)) ||
!strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC,
MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_LOWLATENCY_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED)) ||
!strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_FM)) ||
!strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
@@ -921,22 +981,34 @@
return CAP_TX;
} else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
MAX_LEN(useCase,SND_USE_CASE_VERB_VOICECALL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_SGLTECALL,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_SGLTECALL)) ||
!strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
MAX_LEN(useCase,SND_USE_CASE_VERB_IP_VOICECALL)) ||
!strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
MAX_LEN(useCase,SND_USE_CASE_VERB_DL_REC)) ||
!strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
MAX_LEN(useCase,SND_USE_CASE_VERB_UL_DL_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL,
+ MAX_LEN(useCase,SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
!strncmp(useCase, SND_USE_CASE_VERB_INCALL_REC,
MAX_LEN(useCase,SND_USE_CASE_VERB_INCALL_REC)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOICE)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_SGLTE,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_SGLTE)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
MAX_LEN(useCase,SND_USE_CASE_MOD_PLAY_VOIP)) ||
!strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
!strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL,
+ MAX_LEN(useCase,SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL)) ||
!strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
MAX_LEN(useCase,SND_USE_CASE_VERB_VOLTE)) ||
!strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
@@ -960,7 +1032,7 @@
card_mctrl_t *dev_list, *uc_list;
char *current_device, use_case[MAX_UC_LEN];
int list_size, index, uc_index, ret = 0, intdev_flag = 0;
- int verb_index, capability = 0, ident_cap = 0, dev_cap =0;
+ int verb_index, capability = 0, ident_cap = 0, dev_cap = 0;
ALOGV("set_use_case_ident_for_all_devices(): %s", ident);
if ((verb_index = uc_mgr->card_ctxt_ptr->current_verb_index) < 0)
@@ -982,49 +1054,50 @@
current_device =
snd_ucm_get_value_at_index(uc_mgr->card_ctxt_ptr->dev_list_head, index);
if (current_device != NULL) {
- uc_index = get_use_case_index(uc_mgr, current_device,
- CTRL_LIST_DEVICE);
+ if ((uc_index = get_use_case_index(uc_mgr, current_device,
+ CTRL_LIST_DEVICE)) < 0) {
+ ALOGE("No valid device found: %s", current_device);
+ continue;
+ }
dev_cap = dev_list[uc_index].capability;
if (!capability) {
capability = dev_list[uc_index].capability;
} else if (capability != dev_list[uc_index].capability) {
capability = CAP_VOICE;
}
- if (ident_cap == CAP_VOICE || ident_cap == dev_cap) {
+ if (ident_cap == CAP_VOICE || dev_cap == ident_cap) {
if (enable) {
if (!snd_ucm_get_status_at_index(
uc_mgr->card_ctxt_ptr->dev_list_head, current_device)) {
if (uc_index >= 0) {
ALOGV("Applying mixer controls for device: %s",
- current_device);
+ current_device);
ret = snd_use_case_apply_mixer_controls(uc_mgr,
- current_device, enable, CTRL_LIST_DEVICE, uc_index);
+ current_device, enable, CTRL_LIST_DEVICE,
+ uc_index);
if (!ret)
snd_ucm_set_status_at_index(
uc_mgr->card_ctxt_ptr->dev_list_head,
current_device, enable, dev_cap);
}
- } else if (ident_cap == CAP_VOICE) {
+ } else if (ident_cap == CAP_VOICE) {
snd_use_case_apply_voice_acdb(uc_mgr, uc_index);
- }
- }
- strlcpy(use_case, ident, sizeof(use_case));
- strlcat(use_case, current_device, sizeof(use_case));
- ALOGV("Applying mixer controls for use case: %s", use_case);
- if ((uc_index =
- get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
- ALOGV("No valid use case found: %s", use_case);
- intdev_flag++;
- } else {
- if (capability == CAP_VOICE || ident_cap == CAP_VOICE ||
- capability == ident_cap) {
- ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
- enable, ctrl_list_type, uc_index);
- }
- }
- use_case[0] = 0;
- free(current_device);
- }
+ }
+ }
+ strlcpy(use_case, ident, sizeof(use_case));
+ strlcat(use_case, current_device, sizeof(use_case));
+ ALOGV("Applying mixer controls for use case: %s", use_case);
+ if ((uc_index =
+ get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
+ ALOGV("No valid use case found: %s", use_case);
+ intdev_flag++;
+ } else {
+ ret = snd_use_case_apply_mixer_controls(uc_mgr, use_case,
+ enable, ctrl_list_type, uc_index);
+ }
+ use_case[0] = 0;
+ free(current_device);
+ }
}
}
if (intdev_flag) {
@@ -1064,7 +1137,11 @@
uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
if (device != NULL) {
if (enable) {
- dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+ if ((dev_index =
+ get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
+ ALOGE("No valid device found: %s", device);
+ return dev_index;
+ }
capability = dev_list[dev_index].capability;
if (!snd_ucm_get_status_at_index(
uc_mgr->card_ctxt_ptr->dev_list_head, device)) {
@@ -1078,10 +1155,14 @@
}
strlcpy(use_case, ident, sizeof(use_case));
strlcat(use_case, device, sizeof(use_case));
- ALOGV("Applying mixer controls for use case: %s", use_case);
+ ALOGV("Applying mixer controls for use case: %s", use_case);
if ((uc_index = get_use_case_index(uc_mgr, use_case, ctrl_list_type)) < 0) {
ALOGV("No valid use case found: %s", use_case );
- uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
+ if ((uc_index =
+ get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
+ ALOGE("No valid use case found: %s", ident);
+ return uc_index;
+ }
if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
ctrl_list_type, uc_index) < 0) {
ALOGV("use case %s not valid without device combination also",
@@ -1092,7 +1173,11 @@
ctrl_list_type, uc_index);
}
} else {
- uc_index = get_use_case_index(uc_mgr, ident, ctrl_list_type);
+ if ((uc_index =
+ get_use_case_index(uc_mgr, ident, ctrl_list_type)) < 0) {
+ ALOGE("No valid use case found: %s", ident);
+ return uc_index;
+ }
if (snd_use_case_apply_mixer_controls(uc_mgr, ident, enable,
ctrl_list_type, uc_index) < 0) {
ALOGV("use case %s not valid without device combination also",
@@ -1121,7 +1206,11 @@
verb_index = 0;
dev_list =
uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
- dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+ if ((dev_index =
+ get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
+ ALOGE("No valid device %s found", device);
+ return dev_index;
+ }
if (dev_index >= 0)
capability = dev_list[dev_index].capability;
if (strncmp(uc_mgr->card_ctxt_ptr->current_verb, SND_USE_CASE_VERB_INACTIVE,
@@ -1175,8 +1264,10 @@
use_case[0] = 0;
strlcpy(use_case, uc_mgr->card_ctxt_ptr->current_verb,
sizeof(use_case));
- uc_index = get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB);
- if (capability == CAP_VOICE ||
+ if ((uc_index =
+ get_use_case_index(uc_mgr, use_case, CTRL_LIST_VERB)) < 0) {
+ ALOGE("No valid use case %s found", use_case);
+ } else if (capability == CAP_VOICE ||
capability ==
getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ||
getUseCaseType(uc_mgr->card_ctxt_ptr->current_verb) ==
@@ -1246,9 +1337,11 @@
}
use_case[0] = 0;
strlcpy(use_case, ident_value, sizeof(use_case));
- uc_index =
- get_use_case_index(uc_mgr, ident_value, CTRL_LIST_MODIFIER);
- if (capability == CAP_VOICE ||
+ if ((uc_index =
+ get_use_case_index(uc_mgr, ident_value,
+ CTRL_LIST_MODIFIER)) < 0) {
+ ALOGE("No valid use case %s found", ident_value);
+ } else if (capability == CAP_VOICE ||
capability == getUseCaseType(ident_value) ||
getUseCaseType(ident_value) == CAP_VOICE) {
ALOGV("set %d for use case value: %s", enable, use_case);
@@ -1318,14 +1411,29 @@
verb_index = 0;
dev_list =
uc_mgr->card_ctxt_ptr->use_case_verb_list[verb_index].device_ctrls;
- dev_index = get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE);
+ if ((dev_index =
+ get_use_case_index(uc_mgr, device, CTRL_LIST_DEVICE)) < 0) {
+ ALOGE("No valid device %s found", device);
+ return dev_index;
+ }
capability = dev_list[dev_index].capability;
if (usecase != NULL) {
strlcpy(use_case, usecase, sizeof(use_case));
strlcat(use_case, device, sizeof(use_case));
if ((uc_index = get_use_case_index(uc_mgr, use_case,
get_usecase_type(uc_mgr, usecase))) < 0) {
- ALOGV("No valid use case found: %s", use_case);
+ ALOGV("No valid use case found: %s,\
+ set %d for use case value: %s",use_case, enable, usecase);
+ if ((uc_index =
+ get_use_case_index(uc_mgr, usecase, get_usecase_type(uc_mgr, usecase))) < 0) {
+ ALOGE("No valid use case found: %s", usecase);
+ } else {
+ ret = snd_use_case_apply_mixer_controls(uc_mgr, usecase, enable,
+ get_usecase_type(uc_mgr, usecase), uc_index);
+ if (ret != 0)
+ ALOGE("No valid controls exists for usecase %s and device %s, \
+ enable: %d", usecase, device, enable);
+ }
} else {
if (enable) {
if (!snd_ucm_get_status_at_index(
@@ -1539,10 +1647,15 @@
ALOGE("Invalid device: Device not part of enabled device list");
} else {
ALOGV("disdev: device value to be disabled: %s", value);
- index = get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE);
- /* Apply Mixer controls for corresponding device and modifier */
- ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
+ if ((index =
+ get_use_case_index(uc_mgr, value, CTRL_LIST_DEVICE)) < 0) {
+ ALOGE("Device %s not found", value);
+ ret = -EINVAL;
+ } else {
+ /* Apply Mixer controls for device and modifier */
+ ret = snd_use_case_apply_mixer_controls(uc_mgr, value, 0,
CTRL_LIST_DEVICE, index);
+ }
}
}
} else if (!strncmp(identifier, "_enamod", 7)) {
@@ -2297,13 +2410,14 @@
close(fd);
return -EINVAL;
}
- read_buf = (char *) mmap(0, st.st_size, PROT_READ | PROT_WRITE,
+ read_buf = (char *) mmap(0, st.st_size+1, PROT_READ | PROT_WRITE,
MAP_PRIVATE, fd, 0);
if (read_buf == MAP_FAILED) {
ALOGE("failed to mmap file error %d\n", errno);
close(fd);
return -EINVAL;
}
+ read_buf[st.st_size] = '\0';
current_str = read_buf;
verb_count = get_verb_count(current_str);
(*uc_mgr)->card_ctxt_ptr->use_case_verb_list =
@@ -3243,6 +3357,7 @@
list->acdb_id = 0;
list->capability = 0;
list->effects_mixer_ctl = NULL;
+ list->ec_ref_rx_mixer_ctl = NULL;
current_str = *cur_str; next_str = *nxt_str;
while(strncasecmp(current_str, "EndSection", 10)) {
current_str = next_str;
@@ -3300,7 +3415,14 @@
&list->effects_mixer_ctl);
if (ret < 0)
break;
- ALOGV("Effects mixer ctl: %s: %d\n", list->effects_mixer_ctl);
+ ALOGV("Effects mixer ctl: %s:\n", list->effects_mixer_ctl);
+ } else if (strcasestr(current_str, "EC_REF_RXMixerCTL") != NULL) {
+ ret = snd_ucm_extract_ec_ref_rx_mixer_ctl(current_str,
+ &list->ec_ref_rx_mixer_ctl);
+ ALOGV("EC_REF_RX mixer ctl: ret:%d\n", ret);
+ if (ret < 0)
+ break;
+ ALOGE("EC_REF_RX mixer ctl: %s\n", list->ec_ref_rx_mixer_ctl);
}
if (strcasestr(current_str, "EnableSequence") != NULL) {
controls_count = get_controls_count(next_str);
@@ -3420,6 +3542,32 @@
return ret;
}
+
+/* Extract Effects Mixer ID of device from config file
+ * Returns 0 on sucess, negative error code otherwise
+ */
+static int snd_ucm_extract_ec_ref_rx_mixer_ctl(char *buf, char **mixer_name)
+{
+ int ret = 0;
+ char *p, *name = *mixer_name, *temp_ptr;
+
+ p = strtok_r(buf, "\"", &temp_ptr);
+ while (p != NULL) {
+ p = strtok_r(NULL, "\"", &temp_ptr);
+ if (p == NULL)
+ break;
+ name = (char *)malloc((strlen(p)+1)*sizeof(char));
+ if(name == NULL) {
+ ret = -ENOMEM;
+ break;
+ }
+ strlcpy(name, p, (strlen(p)+1)*sizeof(char));
+ *mixer_name = name;
+ break;
+ }
+ return ret;
+}
+
/* Extract a playback and capture device name of use case from config file
* Returns 0 on sucess, negative error code otherwise
*/
@@ -3639,6 +3787,9 @@
if(list[case_index].effects_mixer_ctl) {
list[case_index].effects_mixer_ctl = NULL;
}
+ if(list[case_index].ec_ref_rx_mixer_ctl) {
+ list[case_index].ec_ref_rx_mixer_ctl = NULL;
+ }
}
}
diff --git a/libalsa-intf/alsa_ucm.h b/libalsa-intf/alsa_ucm.h
index a72ca27..d83275c 100644
--- a/libalsa-intf/alsa_ucm.h
+++ b/libalsa-intf/alsa_ucm.h
@@ -102,6 +102,7 @@
#define SND_USE_CASE_VERB_VOICE "Voice"
#define SND_USE_CASE_VERB_VOICE_LOW_POWER "Voice Low Power"
#define SND_USE_CASE_VERB_VOICECALL "Voice Call"
+#define SND_USE_CASE_VERB_SGLTECALL "SGLTE"
#define SND_USE_CASE_VERB_IP_VOICECALL "Voice Call IP"
#define SND_USE_CASE_VERB_ANALOG_RADIO "FM Analog Radio"
#define SND_USE_CASE_VERB_DIGITAL_RADIO "FM Digital Radio"
@@ -149,6 +150,7 @@
#define SND_USE_CASE_MOD_CAPTURE_MUSIC "Capture Music"
#define SND_USE_CASE_MOD_PLAY_MUSIC "Play Music"
#define SND_USE_CASE_MOD_PLAY_VOICE "Play Voice"
+#define SND_USE_CASE_MOD_PLAY_SGLTE "Play SGLTE"
#define SND_USE_CASE_MOD_PLAY_TONE "Play Tone"
#define SND_USE_CASE_MOD_ECHO_REF "Echo Reference"
/* add new modifiers to end of list */
diff --git a/libalsa-intf/alsaucm_test.c b/libalsa-intf/alsaucm_test.c
index e01cf59..e7d927d 100644
--- a/libalsa-intf/alsaucm_test.c
+++ b/libalsa-intf/alsaucm_test.c
@@ -36,6 +36,11 @@
#include <errno.h>
#include <stdlib.h>
+#ifndef ANDROID
+#include <stdint.h>
+#define strlcat g_strlcat
+#endif
+
#include "alsa_ucm.h"
#include "msm8960_use_cases.h"
@@ -208,7 +213,6 @@
fprintf(stderr, "%s: error failed to open sound card %s: %d\n", cmd->cmd_str, identifier, err);
return err;
}
- snd_use_case_mgr_wait_for_parsing(uc_mgr);
break;
case UCM_LISTCARDS:
diff --git a/libalsa-intf/aplay.c b/libalsa-intf/aplay.c
index c060277..62a58fa 100644
--- a/libalsa-intf/aplay.c
+++ b/libalsa-intf/aplay.c
@@ -27,6 +27,10 @@
#include <getopt.h>
#include <sound/asound.h>
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#endif
#include "alsa_audio.h"
#ifndef ANDROID
@@ -41,14 +45,28 @@
#define FORMAT_PCM 1
#define LOG_NDEBUG 1
+
+struct output_metadata_handle_t {
+ uint32_t metadataLength;
+ uint32_t bufferLength;
+ uint64_t timestamp;
+ uint32_t reserved[12];
+};
+
+static struct output_metadata_handle_t outputMetadataTunnel;
+
static pcm_flag = 1;
static debug = 0;
static uint32_t play_max_sz = 2147483648LL;
static int format = SNDRV_PCM_FORMAT_S16_LE;
static int period = 0;
static int compressed = 0;
+static int set_channel_map = 0;
+static char channel_map[8];
static char *compr_codec;
static int piped = 0;
+static int outputMetadataLength = 0;
+static int eosSet = 0;
static struct option long_options[] =
{
@@ -61,6 +79,7 @@
{"format", 1, 0, 'F'},
{"period", 1, 0, 'B'},
{"compressed", 0, 0, 'T'},
+ {"channelMap", 0, 0, 'X'},
{0, 0, 0, 0}
};
@@ -80,6 +99,13 @@
uint32_t data_sz;
};
+
+void updateMetaData(size_t bytes) {
+ outputMetadataTunnel.metadataLength = sizeof(outputMetadataTunnel);
+ outputMetadataTunnel.timestamp = 0;
+ outputMetadataTunnel.bufferLength = bytes;
+ fprintf(stderr, "bytes = %d\n", bytes);
+}
static int set_params(struct pcm *pcm)
{
struct snd_pcm_hw_params *params;
@@ -88,7 +114,17 @@
unsigned long periodSize, bufferSize, reqBuffSize;
unsigned int periodTime, bufferTime;
unsigned int requestedRate = pcm->rate;
- int channels = (pcm->flags & PCM_MONO) ? 1 : ((pcm->flags & PCM_5POINT1)? 6 : 2 );
+ int channels;
+ if(pcm->flags & PCM_MONO)
+ channels = 1;
+ else if(pcm->flags & PCM_QUAD)
+ channels = 4;
+ else if(pcm->flags & PCM_5POINT1)
+ channels = 6;
+ else if(pcm->flags & PCM_7POINT1)
+ channels = 8;
+ else
+ channels = 2;
params = (struct snd_pcm_hw_params*) calloc(1, sizeof(struct snd_pcm_hw_params));
if (!params) {
@@ -161,6 +197,25 @@
return 0;
}
+void send_channel_map_driver(struct pcm *pcm)
+{
+ int i, ret;
+ struct mixer *mixer;
+ const char* device = "/dev/snd/controlC0";
+
+ mixer = mixer_open(device);
+ if (!mixer) {
+ fprintf(stderr,"oops: %s: %d\n", strerror(errno), __LINE__);
+ return;
+ }
+ ret = pcm_set_channel_map(pcm, mixer, 8, channel_map);
+ if (ret < 0)
+ fprintf(stderr, "could not set channel mask\n");
+ mixer_close(mixer);
+
+ return;
+}
+
static int play_file(unsigned rate, unsigned channels, int fd,
unsigned flags, const char *device, unsigned data_sz)
{
@@ -183,8 +238,12 @@
if (channels == 1)
flags |= PCM_MONO;
+ else if (channels == 4)
+ flags |= PCM_QUAD;
else if (channels == 6)
flags |= PCM_5POINT1;
+ else if (channels == 8)
+ flags |= PCM_7POINT1;
else
flags |= PCM_STEREO;
@@ -202,7 +261,6 @@
return -EBADFD;
}
-#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
if (compressed) {
struct snd_compr_caps compr_cap;
struct snd_compr_params compr_params;
@@ -214,12 +272,16 @@
if (!period)
period = compr_cap.min_fragment_size;
switch (get_compressed_format(compr_codec)) {
- case FORMAT_MP3:
- compr_params.codec.id = compr_cap.codecs[FORMAT_MP3];
+ case SND_AUDIOCODEC_MP3:
+ compr_params.codec.id = SND_AUDIOCODEC_MP3;
break;
- case FORMAT_AC3_PASS_THROUGH:
- compr_params.codec.id = compr_cap.codecs[FORMAT_AC3_PASS_THROUGH];
- printf("codec -d = %x\n", compr_params.codec.id);
+ case SND_AUDIOCODEC_AC3_PASS_THROUGH:
+ compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH;
+ printf("codec -d = %x\n", SND_AUDIOCODEC_AC3_PASS_THROUGH);
+ break;
+ case SND_AUDIOCODEC_AAC:
+ compr_params.codec.id = SND_AUDIOCODEC_AAC;
+ printf("codec -d = %x\n", SND_AUDIOCODEC_AAC);
break;
default:
break;
@@ -229,8 +291,12 @@
pcm_close(pcm);
return -errno;
}
+ outputMetadataLength = sizeof(struct output_metadata_handle_t);
+ } else if (channels > 2) {
+ if(set_channel_map) {
+ send_channel_map_driver(pcm);
+ }
}
-#endif
pcm->channels = channels;
pcm->rate = rate;
pcm->flags = flags;
@@ -278,7 +344,7 @@
pfd[0].fd = pcm->timer_fd;
pfd[0].events = POLLIN;
- frames = (pcm->flags & PCM_MONO) ? (bufsize / 2) : (bufsize / 4);
+ frames = bufsize / (2*channels);
for (;;) {
if (!pcm->running) {
if (pcm_prepare(pcm)) {
@@ -338,16 +404,23 @@
if (data_sz && !piped) {
if (remainingData < bufsize) {
bufsize = remainingData;
- frames = (pcm->flags & PCM_MONO) ? (remainingData / 2) : (remainingData / 4);
+ frames = remainingData / (2*channels);
}
}
+ fprintf(stderr, "addr = %d, size = %d \n", (dst_addr + outputMetadataLength),(bufsize - outputMetadataLength));
+ err = read(fd, (dst_addr + outputMetadataLength) , (bufsize - outputMetadataLength));
+ if(compressed) {
+ updateMetaData(err);
+ memcpy(dst_addr, &outputMetadataTunnel, outputMetadataLength);
+ }
- err = read(fd, dst_addr , bufsize);
if (debug)
fprintf(stderr, "read %d bytes from file\n", err);
- if (err <= 0)
+ if (err <= 0 ) {
+ fprintf(stderr," EOS set\n ");
+ eosSet = 1;
break;
-
+ }
if (data_sz && !piped) {
remainingData -= bufsize;
if (remainingData <= 0)
@@ -374,15 +447,13 @@
fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld sync_ptr->c.control.appl_ptr %ld\n",
pcm->sync_ptr->s.status.hw_ptr,
pcm->sync_ptr->c.control.appl_ptr);
-#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
if (compressed && start) {
struct snd_compr_tstamp tstamp;
- if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp))
- fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n");
+ if (ioctl(pcm->fd, SNDRV_COMPRESS_TSTAMP, &tstamp))
+ fprintf(stderr, "Aplay: failed SNDRV_COMPRESS_TSTAMP\n");
else
- fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp);
- }
-#endif
+ fprintf(stderr, "timestamp = %lld\n", tstamp.timestamp);
+ }
}
/*
* If we have reached start threshold of buffer prefill,
@@ -409,6 +480,7 @@
start_done:
offset += frames;
}
+
while(1) {
pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
sync_ptr(pcm);
@@ -420,6 +492,14 @@
fprintf(stderr, "Aplay:sync_ptr->s.status.hw_ptr %ld sync_ptr->c.control.appl_ptr %ld\n",
pcm->sync_ptr->s.status.hw_ptr,
pcm->sync_ptr->c.control.appl_ptr);
+
+ if(compressed && eosSet) {
+ fprintf(stderr,"Audio Drain DONE ++\n");
+ if ( ioctl(pcm->fd, SNDRV_COMPRESS_DRAIN) < 0 ) {
+ fprintf(stderr,"Audio Drain failed\n");
+ }
+ fprintf(stderr,"Audio Drain DONE --\n");
+ }
break;
} else
poll(pfd, nfds, TIMEOUT_INFINITE);
@@ -491,7 +571,7 @@
flag = PCM_NMMAP;
fprintf(stderr, "aplay: Playing '%s': format %s ch = %d\n",
- fn, get_format_desc(format), ch );
+ fn, get_format_desc(format), ch );
return play_file(rate, ch, fd, flag, device, 0);
}
@@ -556,6 +636,45 @@
return play_file(hdr.sample_rate, hdr.num_channels, fd, flag, device, hdr.data_sz);
}
+char get_channel_map_val(char *string)
+{
+ char retval = 0;
+ if( !strncmp(string, "RRC", sizeof(string)) )
+ retval = 16;
+ else if( !strncmp(string, "RLC", sizeof(string)) )
+ retval = 15;
+ else if( !strncmp(string, "FRC", sizeof(string)) )
+ retval = 14;
+ else if( !strncmp(string, "FLC", sizeof(string)) )
+ retval = 13;
+ else if( !strncmp(string, "MS", sizeof(string)) )
+ retval = 12;
+ else if( !strncmp(string, "CVH", sizeof(string)) )
+ retval = 11;
+ else if( !strncmp(string, "TS", sizeof(string)) )
+ retval = 10;
+ else if( !strncmp(string, "RB", sizeof(string)) )
+ retval = 9;
+ else if( !strncmp(string, "LB", sizeof(string)) )
+ retval = 8;
+ else if( !strncmp(string, "CS", sizeof(string)) )
+ retval = 7;
+ else if( !strncmp(string, "LFE", sizeof(string)) )
+ retval = 6;
+ else if( !strncmp(string, "RS", sizeof(string)) )
+ retval = 5;
+ else if( !strncmp(string, "LS", sizeof(string)) )
+ retval = 4;
+ else if( !strncmp(string, "FC", sizeof(string)) )
+ retval = 3;
+ else if( !strncmp(string, "FR", sizeof(string)) )
+ retval = 2;
+ else if( !strncmp(string, "FL", sizeof(string)) )
+ retval = 1;
+
+ return retval;
+}
+
int main(int argc, char **argv)
{
int option_index = 0;
@@ -565,20 +684,25 @@
char *mmap = "N";
char *device = "hw:0,0";
char *filename;
+ char *ptr;
int rc = 0;
if (argc <2) {
printf("\nUsage: aplay [options] <file>\n"
"options:\n"
- "-D <hw:C,D> -- Alsa PCM by name\n"
- "-M -- Mmap stream\n"
- "-P -- Hostless steam[No PCM]\n"
- "-C -- Channels\n"
- "-R -- Rate\n"
- "-V -- verbose\n"
- "-F -- Format\n"
+ "-D <hw:C,D> -- Alsa PCM by name\n"
+ "-M -- Mmap stream\n"
+ "-P -- Hostless steam[No PCM]\n"
+ "-C -- Channels\n"
+ "-R -- Rate\n"
+ "-V -- verbose\n"
+ "-F -- Format\n"
"-B -- Period\n"
"-T <MP3, AAC, AC3_PASS_THROUGH> -- Compressed\n"
+ "-X <\"FL,FR,FC,Ls,Rs,LFE\" for 5.1 configuration\n"
+ " supported channels: \n"
+ " FL, FR, FC, LS, RS, LFE, CS, TS \n"
+ " LB, RB, FLC, FRC, RLC, RRC, CVH, MS\n"
"<file> \n");
fprintf(stderr, "Formats Supported:\n");
for (i = 0; i <= SNDRV_PCM_FORMAT_LAST; ++i)
@@ -587,7 +711,7 @@
fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
return 0;
}
- while ((c = getopt_long(argc, argv, "PVMD:R:C:F:B:T:", long_options, &option_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "PVMD:R:C:F:B:T:X:", long_options, &option_index)) != -1) {
switch (c) {
case 'P':
pcm_flag = 0;
@@ -619,18 +743,35 @@
printf("compressed codec type requested = %s\n", optarg);
compr_codec = optarg;
break;
+ case 'X':
+ set_channel_map = 1; i = 0;
+ memset(channel_map, 0, sizeof(channel_map));
+ ptr = strtok(optarg, ",");
+ while((ptr != NULL) && (i < sizeof(channel_map))) {
+ channel_map[i] = get_channel_map_val(ptr);
+ if (channel_map[i] < 0 || channel_map[i] > 16) {
+ set_channel_map = 0;
+ break;
+ }
+ ptr = strtok(NULL,","); i++;
+ }
+ break;
default:
printf("\nUsage: aplay [options] <file>\n"
"options:\n"
- "-D <hw:C,D> -- Alsa PCM by name\n"
- "-M -- Mmap stream\n"
- "-P -- Hostless steam[No PCM]\n"
- "-V -- verbose\n"
- "-C -- Channels\n"
- "-R -- Rate\n"
- "-F -- Format\n"
+ "-D <hw:C,D> -- Alsa PCM by name\n"
+ "-M -- Mmap stream\n"
+ "-P -- Hostless steam[No PCM]\n"
+ "-V -- verbose\n"
+ "-C -- Channels\n"
+ "-R -- Rate\n"
+ "-F -- Format\n"
"-B -- Period\n"
"-T -- Compressed\n"
+ "-X <\"FL,FR,FC,Ls,Rs,LFE\" for 5.1 configuration\n"
+ " supported channels: \n"
+ " FL, FR, FC, LS, RS, LFE, CS, TS \n"
+ " LB, RB, FLC, FRC, RLC, RRC, CVH, MS\n"
"<file> \n");
fprintf(stderr, "Formats Supported:\n");
for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
@@ -654,7 +795,7 @@
}
if (pcm_flag) {
- if (format == SNDRV_PCM_FORMAT_S16_LE)
+ if (format == SNDRV_PCM_FORMAT_S16_LE)
rc = play_wav(mmap, rate, ch, device, filename);
else
rc = play_raw(mmap, rate, ch, device, filename);
diff --git a/libalsa-intf/arec.c b/libalsa-intf/arec.c
index cab88f1..8f74fe8 100644
--- a/libalsa-intf/arec.c
+++ b/libalsa-intf/arec.c
@@ -28,6 +28,12 @@
#include <getopt.h>
#include <limits.h>
+#include <sound/asound.h>
+#ifdef QCOM_COMPRESSED_AUDIO_ENABLED
+#include <sound/compress_params.h>
+#include <sound/compress_offload.h>
+#endif
+
#include "alsa_audio.h"
#define ID_RIFF 0x46464952
@@ -42,17 +48,20 @@
#define strlcpy g_strlcpy
#endif
+#define COMPR_META_DATA_SIZE 64
static struct wav_header hdr;
static int fd;
static struct pcm *pcm;
-static int debug = 0;
-static int pcm_flag = 1;
-static int duration = 0;
+static debug = 0;
+static pcm_flag = 1;
+static duration = 0;
static char *filename;
static char *data;
static int format = SNDRV_PCM_FORMAT_S16_LE;
static int period = 0;
static int piped = 0;
+static int compressed = 0;
+static char *compr_codec;
static struct option long_options[] =
{
@@ -65,6 +74,7 @@
{"duration", 1, 0, 'T'},
{"format", 1, 0, 'F'},
{"period", 1, 0, 'B'},
+ {"compressed", 1, 0, 'K'},
{0, 0, 0, 0}
};
@@ -177,7 +187,7 @@
int record_file(unsigned rate, unsigned channels, int fd, unsigned count, unsigned flags, const char *device)
{
- unsigned xfer, bufsize;
+ unsigned xfer, bufsize, framesize;
int r, avail;
int nfds = 1;
static int start = 0;
@@ -187,7 +197,7 @@
int err;
struct pollfd pfd[1];
int rec_size = 0;
-
+ framesize = 0;
flags |= PCM_IN;
if (channels == 1)
@@ -204,6 +214,41 @@
pcm_close(pcm);
goto fail;
}
+
+ if (compressed) {
+ struct snd_compr_caps compr_cap;
+ struct snd_compr_params compr_params;
+ printf("SNDRV_COMPRESS_GET_CAPS= 0x%X\n", SNDRV_COMPRESS_GET_CAPS);
+ if (ioctl(pcm->fd, SNDRV_COMPRESS_GET_CAPS, &compr_cap)) {
+ fprintf(stderr, "AREC: SNDRV_COMPRESS_GET_CAPS, failed Error no %d \n", errno);
+ pcm_close(pcm);
+ return -errno;
+ }
+ if (!period)
+ period = compr_cap.min_fragment_size;
+ switch (get_compressed_format(compr_codec)) {
+ case SND_AUDIOCODEC_MP3:
+ compr_params.codec.id = SND_AUDIOCODEC_MP3;
+ break;
+ case SND_AUDIOCODEC_AC3_PASS_THROUGH:
+ compr_params.codec.id = SND_AUDIOCODEC_AC3_PASS_THROUGH;
+ printf("codec -d = %x\n", compr_params.codec.id);
+ break;
+ case SND_AUDIOCODEC_AMRWB:
+ compr_params.codec.id = SND_AUDIOCODEC_AMRWB;
+ compr_params.codec.options.generic.reserved[0] = 8; /*band mode - 23.85 kbps*/
+ compr_params.codec.options.generic.reserved[1] = 0; /*dtx mode - disable*/
+ printf("codec -d = %x\n", compr_params.codec.id);
+ break;
+ default:
+ break;
+ }
+ if (ioctl(pcm->fd, SNDRV_COMPRESS_SET_PARAMS, &compr_params)) {
+ fprintf(stderr, "AREC: SNDRV_COMPRESS_SET_PARAMS,failed Error no %d \n", errno);
+ pcm_close(pcm);
+ return -errno;
+ }
+ }
pcm->channels = channels;
pcm->rate = rate;
pcm->flags = flags;
@@ -248,17 +293,18 @@
}
bufsize = pcm->period_size;
+
if (debug)
- fprintf(stderr, "Arec:bufsize = %d\n", bufsize);
+ fprintf(stderr, "Arec:bufsize = %d\n", bufsize);
if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_START)) {
- if (errno == EPIPE) {
+ if (errno == EPIPE) {
fprintf(stderr, "Arec:Failed in SNDRV_PCM_IOCTL_START\n");
/* we failed to make our window -- try to restart */
pcm->running = 0;
- } else {
- fprintf(stderr, "Arec:Error no %d \n", errno);
- return -errno;
- }
+ } else {
+ fprintf(stderr, "Arec:Error no %d \n", errno);
+ return -errno;
+ }
}
pfd[0].fd = pcm->fd;
@@ -276,20 +322,20 @@
}
x.frames = frames;
for(;;) {
- if (!pcm->running) {
- if (pcm_prepare(pcm))
- return --errno;
- start = 0;
- }
- /* Sync the current Application pointer from the kernel */
- pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;//SNDRV_PCM_SYNC_PTR_HWSYNC;
- err = sync_ptr(pcm);
- if (err == EPIPE) {
- fprintf(stderr, "Arec:Failed in sync_ptr \n");
- /* we failed to make our window -- try to restart */
- //pcm->overruns++;
- pcm->running = 0;
- continue;
+ if (!pcm->running) {
+ if (pcm_prepare(pcm))
+ return --errno;
+ start = 0;
+ }
+ /* Sync the current Application pointer from the kernel */
+ pcm->sync_ptr->flags = SNDRV_PCM_SYNC_PTR_APPL | SNDRV_PCM_SYNC_PTR_AVAIL_MIN;/*SNDRV_PCM_SYNC_PTR_HWSYNC;*/
+ err = sync_ptr(pcm);
+ if (err == EPIPE) {
+ fprintf(stderr, "Arec:Failed in sync_ptr \n");
+ /* we failed to make our window -- try to restart */
+ //pcm->overruns++;
+ pcm->running = 0;
+ continue;
}
/*
* Check for the available data in driver. If available data is
@@ -297,14 +343,16 @@
*/
avail = pcm_avail(pcm);
if (debug)
- fprintf(stderr, "Arec:avail 1 = %d frames = %ld\n",avail, frames);
+ fprintf(stderr, "Arec:avail 1 = %d frames = %ld, avail_min = %d,"
+ "x.frames = %d, bufsize = %d, dst_addr = %p\n",avail, frames,
+ (int)pcm->sw_p->avail_min, (int)x.frames, bufsize, dst_addr);
if (avail < 0)
return avail;
if (avail < pcm->sw_p->avail_min) {
poll(pfd, nfds, TIMEOUT_INFINITE);
continue;
}
- if (x.frames > avail)
+ if (x.frames > avail)
frames = avail;
/*
* Now that we have data size greater than avail_min available to
@@ -312,18 +360,31 @@
* start reading from.
*/
dst_addr = dst_address(pcm);
+ if (compressed) {
+ framesize = (unsigned)(dst_addr[3] << 24) + (unsigned)(dst_addr[2] << 16) +
+ (unsigned) (dst_addr[1] << 8) + (unsigned)dst_addr[0];
+ if (debug)
+ fprintf(stderr, "Arec:dst_addr[0] = %d, dst_addr[1] = %d,"
+ "dst_addr[2] = %d, dst_addr[3] = %d, dst_addr[4] = %d,"
+ "dst_addr[5] = %d, dst_addr = %p, bufsize = %d, framesize = %d\n",
+ dst_addr[0], dst_addr[1], dst_addr[2], dst_addr[3], dst_addr[4],
+ dst_addr[5],dst_addr, bufsize, framesize);
+ dst_addr += COMPR_META_DATA_SIZE;
+ } else {
+ framesize = bufsize;
+ }
/*
* Write to the file at the destination address from kernel mmaped buffer
* This reduces a extra copy of intermediate buffer.
*/
- if (write(fd, dst_addr, bufsize) != bufsize) {
- fprintf(stderr, "Arec:could not write %d bytes\n", bufsize);
+ if (write(fd, dst_addr, framesize) != framesize) {
+ fprintf(stderr, "Arec:could not write %d bytes\n", framesize);
return -errno;
}
x.frames -= frames;
pcm->sync_ptr->c.control.appl_ptr += frames;
- pcm->sync_ptr->flags = 0;
+ pcm->sync_ptr->flags = 0;
err = sync_ptr(pcm);
if (err == EPIPE) {
fprintf(stderr, "Arec:Failed in sync_ptr \n");
@@ -332,12 +393,14 @@
continue;
}
rec_size += bufsize;
- hdr.data_sz += bufsize;
- hdr.riff_sz = hdr.data_sz + 44 - 8;
- if (!piped) {
- lseek(fd, 0, SEEK_SET);
- write(fd, &hdr, sizeof(hdr));
- lseek(fd, 0, SEEK_END);
+ if (!compressed) {
+ hdr.data_sz += bufsize;
+ hdr.riff_sz = hdr.data_sz + 44 - 8;
+ if (!piped) {
+ lseek(fd, 0, SEEK_SET);
+ write(fd, &hdr, sizeof(hdr));
+ lseek(fd, 0, SEEK_END);
+ }
}
if (rec_size >= count)
break;
@@ -391,7 +454,7 @@
uint32_t rec_max_sz = 2147483648LL;
uint32_t count;
int i = 0;
-
+ printf("rec_raw-> pcm_flag = %d\n", pcm_flag);
if (!fn) {
fd = fileno(stdout);
piped = 1;
@@ -427,53 +490,60 @@
uint32_t rec_max_sz = 2147483648LL;
uint32_t count = 0;
int i = 0;
-
+ printf("rec_wav-> pcm_flag = %d\n", pcm_flag);
if (pcm_flag) {
- if (!fn) {
- fd = fileno(stdout);
- piped = 1;
- } else {
- fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
- if (fd < 0) {
- fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
- return -EBADFD;
- }
+ if (!fn) {
+ fd = fileno(stdout);
+ piped = 1;
+ } else {
+ fd = open(fn, O_WRONLY | O_CREAT | O_TRUNC, 0664);
+ if (fd < 0) {
+ fprintf(stderr, "Arec:arec: cannot open '%s'\n", fn);
+ return -EBADFD;
}
- memset(&hdr, 0, sizeof(struct wav_header));
- hdr.riff_id = ID_RIFF;
- hdr.riff_fmt = ID_WAVE;
- hdr.fmt_id = ID_FMT;
- hdr.fmt_sz = 16;
- hdr.audio_format = FORMAT_PCM;
- hdr.num_channels = ch;
- hdr.sample_rate = rate;
- hdr.bits_per_sample = 16;
- hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8;
- hdr.block_align = ( hdr.bits_per_sample * ch ) / 8;
- hdr.data_id = ID_DATA;
- hdr.data_sz = 0;
+ }
+ if (compressed) {
- if (duration == 0) {
- count = rec_max_sz;
- } else {
- count = rate * ch * 2;
- count *= (uint32_t)duration;
- }
- hdr.riff_sz = hdr.data_sz + 44 - 8;
- if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
- if (debug)
- fprintf(stderr, "arec: cannot write header\n");
- return -errno;
- }
- if (debug)
- fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n",
- hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
- hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
- } else {
+ printf("rec_wav-> compressed = %d\n", compressed);
hdr.sample_rate = rate;
hdr.num_channels = ch;
+ goto ignore_header;
+ }
+ memset(&hdr, 0, sizeof(struct wav_header));
+ hdr.riff_id = ID_RIFF;
+ hdr.riff_fmt = ID_WAVE;
+ hdr.fmt_id = ID_FMT;
+ hdr.fmt_sz = 16;
+ hdr.audio_format = FORMAT_PCM;
+ hdr.num_channels = ch;
+ hdr.sample_rate = rate;
+ hdr.bits_per_sample = 16;
+ hdr.byte_rate = (rate * ch * hdr.bits_per_sample) / 8;
+ hdr.block_align = ( hdr.bits_per_sample * ch ) / 8;
+ hdr.data_id = ID_DATA;
+ hdr.data_sz = 0;
+ hdr.riff_sz = hdr.data_sz + 44 - 8;
+ if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
+ if (debug)
+ fprintf(stderr, "arec: cannot write header\n");
+ return -errno;
+ }
+ if (debug)
+ fprintf(stderr, "arec: %d ch, %d hz, %d bit, %s\n",
+ hdr.num_channels, hdr.sample_rate, hdr.bits_per_sample,
+ hdr.audio_format == FORMAT_PCM ? "PCM" : "unknown");
+ } else {
+ hdr.sample_rate = rate;
+ hdr.num_channels = ch;
}
+ignore_header:
+ if (duration == 0) {
+ count = rec_max_sz;
+ } else {
+ count = rate * ch * 2;
+ count *= (uint32_t)duration;
+ }
if (!strncmp(fg, "M", sizeof("M"))) {
flag = PCM_MMAP;
} else if (!strncmp(fg, "N", sizeof("N"))) {
@@ -521,25 +591,26 @@
int rc = 0;
if (argc < 2) {
- printf("\nUsage: arec [options] <file>\n"
- "options:\n"
- "-D <hw:C,D> -- Alsa PCM by name\n"
- "-M -- Mmap stream\n"
- "-P -- Hostless steam[No PCM]\n"
- "-V -- verbose\n"
- "-C -- Channels\n"
- "-R -- Rate\n"
- "-T -- Time in seconds for recording\n"
- "-F -- Format\n"
- "-B -- Period\n"
- "<file> \n");
+ printf("\nUsage: arec [options] <file>\n"
+ "options:\n"
+ "-D <hw:C,D> -- Alsa PCM by name\n"
+ "-M -- Mmap stream\n"
+ "-P -- Hostless steam[No PCM]\n"
+ "-V -- verbose\n"
+ "-C -- Channels\n"
+ "-R -- Rate\n"
+ "-T -- Time in seconds for recording\n"
+ "-F -- Format\n"
+ "-B -- Period\n"
+ "-K <AC3,DTS,etc> -- compressed\n"
+ "<file> \n");
for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
if (get_format_name(i))
fprintf(stderr, "%s ", get_format_name(i));
fprintf(stderr, "\nSome of these may not be available on selected hardware\n");
return 0;
}
- while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:", long_options, &option_index)) != -1) {
+ while ((c = getopt_long(argc, argv, "PVMD:R:C:T:F:B:K:", long_options, &option_index)) != -1) {
switch (c) {
case 'P':
pcm_flag = 0;
@@ -568,18 +639,24 @@
case 'B':
period = (int)strtol(optarg, NULL, 0);
break;
+ case 'K':
+ compressed = 1;
+ printf("compressed codec type requested = %s\n", optarg);
+ compr_codec = optarg;
+ break;
default:
printf("\nUsage: arec [options] <file>\n"
"options:\n"
- "-D <hw:C,D> -- Alsa PCM by name\n"
- "-M -- Mmap stream\n"
- "-P -- Hostless steam[No PCM]\n"
- "-V -- verbose\n"
- "-C -- Channels\n"
- "-R -- Rate\n"
- "-T -- Time in seconds for recording\n"
- "-F -- Format\n"
- "-B -- Period\n"
+ "-D <hw:C,D> -- Alsa PCM by name\n"
+ "-M -- Mmap stream\n"
+ "-P -- Hostless steam[No PCM]\n"
+ "-V -- verbose\n"
+ "-C -- Channels\n"
+ "-R -- Rate\n"
+ "-T -- Time in seconds for recording\n"
+ "-F -- Format\n"
+ "-B -- Period\n"
+ "-K <AC3,DTS,etc> -- compressed\n"
"<file> \n");
for (i = 0; i < SNDRV_PCM_FORMAT_LAST; ++i)
if (get_format_name(i))
diff --git a/libalsa-intf/msm8960_use_cases.h b/libalsa-intf/msm8960_use_cases.h
index ed58d8a..784aa72 100644
--- a/libalsa-intf/msm8960_use_cases.h
+++ b/libalsa-intf/msm8960_use_cases.h
@@ -44,6 +44,7 @@
#define CAP_VOICE 0x4
#define DEVICE_HANDSET_RX_ACDB_ID 7 // HANDSET_SPKR
#define DEVICE_HANDSET_TX_ACDB_ID 4 // HANDSET_MIC
+#define DEVICE_SPEAKER_RX_ACDB_ID 15// SPKR_PHONE_SPKR_STEREO
#define DEVICE_SPEAKER_MONO_RX_ACDB_ID 14// SPKR_PHONE_SPKR_MONO
#define DEVICE_SPEAKER_STEREO_RX_ACDB_ID 15// SPKR_PHONE_SPKR_STEREO
#define DEVICE_SPEAKER_TX_ACDB_ID 11// SPKR_PHONE_MIC
@@ -53,6 +54,8 @@
#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_ACDB_ID 6 // HANDSET_MIC_ENDFIRE
#define DEVICE_DUALMIC_SPEAKER_TX_BROADSIDE_ACDB_ID 12// SPKR_PHONE_MIC_BROADSIDE
#define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_ACDB_ID 13// SPKR_PHONE_MIC_ENDFIRE
+#define DEVICE_DUALMIC_HANDSET_STEREO_ACDB_ID 34
+#define DEVICE_DUALMIC_SPEAKER_PHONE_STEREO_ACDB_ID 35
#define DEVICE_TTY_HEADSET_MONO_RX_ACDB_ID 17// TTY_HEADSET_SPKR
#define DEVICE_TTY_HEADSET_MONO_TX_ACDB_ID 16// TTY_HEADSET_MIC
#define DEVICE_BT_SCO_RX_ACDB_ID 22// BT_SCO_SPKR
@@ -66,10 +69,10 @@
#define DEVICE_PROXY_RX_ACDB_ID DEVICE_HDMI_STEREO_RX_ACDB_ID
#define DEVICE_TTY_VCO_HANDSET_TX_ACDB_ID 36// TTY_VCO_HANDSET_MIC
#define DEVICE_TTY_HCO_HANDSET_RX_ACDB_ID 37// TTY_HCO_HANDSET_SPRK
-#define DEVICE_HANDSET_TX_FV5_ACDB_ID 50
-#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_FV5_ACDB_ID 51
-#define DEVICE_SPEAKER_TX_FV5_ACDB_ID 52
-#define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_FV5_ACDB_ID 53
+#define DEVICE_HANDSET_TX_FV5_ACDB_ID 40
+#define DEVICE_DUALMIC_HANDSET_TX_ENDFIRE_FV5_ACDB_ID 41
+#define DEVICE_SPEAKER_TX_FV5_ACDB_ID 42
+#define DEVICE_DUALMIC_SPEAKER_TX_ENDFIRE_FV5_ACDB_ID 43
#define DEVICE_INCALL_VOICE_RECORD_STEREO_ACDB_ID 45
#define DEVICE_INCALL_MUSIC_DELIVERY_MONO_ACDB_ID 46
#define DEVICE_INCALL_VOICE_RECORD_MONO_ACDB_ID 47
@@ -117,6 +120,7 @@
int acdb_id;
int capability;
char *effects_mixer_ctl;
+ char *ec_ref_rx_mixer_ctl;
}card_mctrl_t;
/* identifier node structure for identifier list*/
@@ -168,7 +172,6 @@
int current_rx_device;
card_ctxt_t *card_ctxt_ptr;
pthread_t thr;
- void *acdb_handle;
};
#define MAX_NUM_CARDS (sizeof(card_list)/sizeof(char *))
@@ -177,8 +180,16 @@
static const char *card_list[] = {
"snd_soc_msm",
"snd_soc_msm_2x",
+ "snd_soc_msm_2x_mpq",
"snd_soc_msm_2x_Fusion3",
"snd_soc_msm_Sitar",
+ "snd_soc_msm_I2S",
+ "snd_soc_msm_Taiko",
+ "snd_soc_msm_Taiko_CDP",
+ "snd_soc_msm_Taiko_Fluid",
+ "snd_soc_msm_Taiko_liquid",
+ "snd_soc_msm_I2SFusion",
+ "us_soc_msm",
};
typedef struct card_mapping {
@@ -190,8 +201,16 @@
static card_mapping_t card_mapping_list[] = {
{"snd_soc_msm", 0},
{"snd_soc_msm_2x", 0},
+ {"snd_soc_msm_2x_mpq", 0},
{"snd_soc_msm_2x_Fusion3", 0},
{"snd_soc_msm_Sitar", 0},
+ {"snd_soc_msm_I2S", 0},
+ {"snd_soc_msm_Taiko", 0},
+ {"snd_soc_msm_Taiko_CDP", 0},
+ {"snd_soc_msm_Taiko_Fluid", 0},
+ {"snd_soc_msm_Taiko_liquid", 0},
+ {"snd_soc_msm_I2SFusion", 0},
+ {"us_soc_msm", 0},
};
/* New use cases, devices and modifiers added
@@ -203,6 +222,8 @@
#define SND_USE_CASE_VERB_HIFI_LOWLATENCY_REC "HiFi Lowlatency Rec"
#define SND_USE_CASE_VERB_DL_REC "DL REC"
#define SND_USE_CASE_VERB_UL_DL_REC "UL DL REC"
+#define SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_DL "Compressed DL REC"
+#define SND_USE_CASE_VERB_CAPTURE_COMPRESSED_VOICE_UL_DL "Compressed UL DL REC"
#define SND_USE_CASE_VERB_HIFI_TUNNEL "HiFi Tunnel"
#define SND_USE_CASE_VERB_HIFI_LOWLATENCY_MUSIC "HiFi Lowlatency"
#define SND_USE_CASE_VERB_HIFI2 "HiFi2"
@@ -210,6 +231,11 @@
#define SND_USE_CASE_VERB_MI2S "MI2S"
#define SND_USE_CASE_VERB_VOLTE "VoLTE"
#define SND_USE_CASE_VERB_ADSP_TESTFWK "ADSP testfwk"
+#define SND_USE_CASE_VERB_HIFI_REC2 "HiFi Rec2"
+#define SND_USE_CASE_VERB_HIFI_REC_COMPRESSED "HiFi Rec Compressed"
+#define SND_USE_CASE_VERB_HIFI3 "HiFi3"
+#define SND_USE_CASE_VERB_HIFI_TUNNEL2 "HiFi Tunnel2"
+#define SND_USE_CASE_VERB_HIFI_PSEUDO_TUNNEL "HiFi Pseudo Tunnel"
#define SND_USE_CASE_DEV_FM_TX "FM Tx"
#define SND_USE_CASE_DEV_ANC_HEADSET "ANC Headset"
@@ -229,16 +255,25 @@
#define SND_USE_CASE_DEV_TTY_HANDSET_ANALOG_TX "TTY Handset Analog Tx"
#define SND_USE_CASE_DEV_DUAL_MIC_BROADSIDE "DMIC Broadside"
#define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE "DMIC Endfire"
+#define SND_USE_CASE_DEV_DUAL_MIC_ENDFIRE_SGLTE "DMIC Endfire SGLTE"
+#define SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO "Handset DMIC Stereo"
+#define SND_USE_CASE_DEV_DUAL_MIC_HANDSET_STEREO_SGLTE "Handset DMIC Stereo SGLTE"
#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_BROADSIDE "Speaker DMIC Broadside"
#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE "Speaker DMIC Endfire"
+#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_ENDFIRE_SGLTE "Speaker DMIC Endfire SGLTE"
+#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO "Speaker DMIC Stereo"
+#define SND_USE_CASE_DEV_SPEAKER_DUAL_MIC_STEREO_SGLTE "Speaker DMIC Stereo SGLTE"
#define SND_USE_CASE_DEV_HDMI_TX "HDMI Tx"
#define SND_USE_CASE_DEV_HDMI_SPDIF "HDMI SPDIF"
+#define SND_USE_CASE_DEV_HDMI_SPDIF_SPEAKER "HDMI SPDIF Speaker"
#define SND_USE_CASE_DEV_QUAD_MIC "QMIC"
#define SND_USE_CASE_DEV_SSR_QUAD_MIC "SSR QMIC"
#define SND_USE_CASE_DEV_PROXY_RX "PROXY Rx"
#define SND_USE_CASE_DEV_PROXY_TX "PROXY Tx"
-#define SND_USE_CASE_DEV_HDMI_SPEAKER "HDMI Speaker"
+#define SND_USE_CASE_DEV_USB_PROXY_RX "USB PROXY Rx"
+#define SND_USE_CASE_DEV_USB_PROXY_TX "USB PROXY Tx"
#define SND_USE_CASE_DEV_SPDIF_SPEAKER "SPDIF Speaker"
+#define SND_USE_CASE_DEV_HDMI_SPEAKER "HDMI Speaker"
#define SND_USE_CASE_DEV_SPDIF_HANDSET "SPDIF Earpiece"
#define SND_USE_CASE_DEV_SPDIF_HEADSET "SPDIF Headphones"
#define SND_USE_CASE_DEV_SPDIF_ANC_HEADSET "SPDIF ANC Headset"
@@ -269,11 +304,20 @@
#define SND_USE_CASE_MOD_CAPTURE_VOIP "Capture VOIP"
#define SND_USE_CASE_MOD_CAPTURE_VOICE_DL "Capture Voice Downlink"
#define SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL "Capture Voice Uplink Downlink"
+#define SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_DL "Capture Compressed Voice DL"
+#define SND_USE_CASE_MOD_CAPTURE_COMPRESSED_VOICE_UL_DL "Capture Compressed Voice UL DL"
#define SND_USE_CASE_MOD_PLAY_TUNNEL "Play Tunnel"
#define SND_USE_CASE_MOD_PLAY_LOWLATENCY_MUSIC "Play Lowlatency Music"
#define SND_USE_CASE_MOD_PLAY_MUSIC2 "Play Music2"
#define SND_USE_CASE_MOD_PLAY_MI2S "Play MI2S"
#define SND_USE_CASE_MOD_PLAY_VOLTE "Play VoLTE"
+#define SND_USE_CASE_MOD_CAPTURE_MUSIC2 "Capture Music2"
+#define SND_USE_CASE_MOD_CAPTURE_MUSIC_COMPRESSED "Capture Music Compressed"
+#define SND_USE_CASE_MOD_PLAY_MUSIC3 "Play Music3"
+#define SND_USE_CASE_MOD_PLAY_TUNNEL1 "Play Tunnel1"
+#define SND_USE_CASE_MOD_PLAY_TUNNEL2 "Play Tunnel2"
+#define SND_USE_CASE_MOD_PSEUDO_TUNNEL "Pseudo Tunnel"
+
/* List utility functions for maintaining enabled devices and modifiers */
static int snd_ucm_add_ident_to_list(struct snd_ucm_ident_node **head, const char *value);
@@ -302,6 +346,7 @@
static int snd_ucm_extract_name(char *buf, char **case_name);
static int snd_ucm_extract_acdb(char *buf, int *id, int *cap);
static int snd_ucm_extract_effects_mixer_ctl(char *buf, char **mixer_name);
+static int snd_ucm_extract_ec_ref_rx_mixer_ctl(char *buf, char **mixer_name);
static int snd_ucm_extract_dev_name(char *buf, char **dev_name);
static int snd_ucm_extract_controls(char *buf, mixer_control_t **mixer_list, int count);
static int snd_ucm_print(snd_use_case_mgr_t *uc_mgr);