initial audio HAL implementation for mako
alsa_sound is imported from codeaurora at:
c1217338f349fe746e0933fcf9b1b288b532808d
[remote "quic"]
url = git://git-android.quicinc.com/platform/hardware/alsa_sound.git
review = review-android.quicinc.com
projectname = platform/hardware/alsa_sound
fetch = +refs/heads/*:refs/remotes/quic/*
Change-Id: Ic985cc3a1088c3957b6e2ac5537e2c36caaf7212
Signed-off-by: Iliyan Malchev <malchev@google.com>
diff --git a/alsa_sound/alsa_default.cpp b/alsa_sound/alsa_default.cpp
new file mode 100644
index 0000000..dc3ad11
--- /dev/null
+++ b/alsa_sound/alsa_default.cpp
@@ -0,0 +1,1559 @@
+/* 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 "AudioHardwareALSA.h"
+#include <media/AudioRecord.h>
+extern "C" {
+#include "csd_client.h"
+}
+
+#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
+
+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);
+
+static char mic_type[25];
+static char curRxUCMDevice[50];
+static char curTxUCMDevice[50];
+static int fluence_mode;
+static int fmVolume;
+static uint32_t mDevSettingsFlag = TTY_OFF;
+static int btsco_samplerate = 8000;
+static bool pflag = false;
+static ALSAUseCaseList mUseCaseList;
+
+static hw_module_methods_t s_module_methods = {
+ open : s_device_open
+};
+
+extern "C" const 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;
+
+ *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));
+ LOGD("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);
+ LOGD("Device value returned is %s", (*value));
+ return ret;
+}
+
+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) {
+ LOGE("Failed to allocate ALSA hardware parameters!");
+ return NO_INIT;
+ }
+
+ reqBuffSize = handle->bufferSize;
+ LOGD("setHardwareParams: reqBuffSize %d channels %d sampleRate %d",
+ (int) reqBuffSize, handle->channels, handle->sampleRate);
+
+#ifdef 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))) {
+ LOGV("HWParams: Use 4 channels in kernel for 5.1(%s) recording ", handle->useCase);
+ channels = 4;
+ reqBuffSize = DEFAULT_IN_BUFFER_SIZE;
+ }
+ }
+#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 ||
+ handle->format == AudioSystem::EVRC ||
+ handle->format == AudioSystem::EVRCB ||
+ handle->format == AudioSystem::EVRCWB)
+ 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_min(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)) {
+ LOGE("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;
+ LOGD("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 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))) {
+ LOGV("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)))){
+ LOGV("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/2;
+ params->start_threshold = channels * (periodSize/4);
+ params->stop_threshold = INT_MAX;
+ }
+ params->silence_threshold = 0;
+ params->silence_size = 0;
+
+ if (param_set_sw_params(handle->handle, params)) {
+ LOGE("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;
+ LOGV("%s: device %d", __FUNCTION__, devices);
+
+ 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_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);
+#if 0
+ } 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) {
+ devices = devices | (AudioSystem::DEVICE_OUT_AUX_DIGITAL |
+ AudioSystem::DEVICE_IN_AUX_DIGITAL);
+#if 0
+ } else if ((devices & AudioSystem::DEVICE_OUT_PROXY) ||
+ (devices & AudioSystem::DEVICE_IN_PROXY)) {
+ devices = devices | (AudioSystem::DEVICE_OUT_PROXY |
+ AudioSystem::DEVICE_IN_PROXY);
+#endif
+ }
+ }
+#ifdef 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))) {
+ LOGV(" 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) {
+ if ((handle->handle) && (((!strncmp(rxDevice, DEVICE_SPEAKER_HEADSET, strlen(DEVICE_SPEAKER_HEADSET))) &&
+ ((!strncmp(curRxUCMDevice, DEVICE_HEADPHONES, strlen(DEVICE_HEADPHONES))) ||
+ (!strncmp(curRxUCMDevice, DEVICE_HEADSET, strlen(DEVICE_HEADSET))))) ||
+ (((!strncmp(curRxUCMDevice, DEVICE_SPEAKER_HEADSET, strlen(DEVICE_SPEAKER_HEADSET))) &&
+ ((!strncmp(rxDevice, DEVICE_HEADPHONES, strlen(DEVICE_HEADPHONES))) ||
+ (!strncmp(rxDevice, DEVICE_HEADSET, strlen(DEVICE_HEADSET))))))) &&
+ ((!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI, strlen(SND_USE_CASE_VERB_HIFI))) ||
+ (!strncmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, strlen(SND_USE_CASE_MOD_PLAY_MUSIC))))) {
+ pcm_close(handle->handle);
+ handle->handle=NULL;
+ handle->rxHandle=NULL;
+ pflag = true;
+ }
+ }
+
+ if ((rxDevice != NULL) && (txDevice != NULL)) {
+ if (((strncmp(rxDevice, curRxUCMDevice, MAX_STR_LEN)) ||
+ (strncmp(txDevice, curTxUCMDevice, MAX_STR_LEN))) && (mode == AudioSystem::MODE_IN_CALL))
+ inCallDevSwitch = true;
+ }
+ 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) {
+ LOGD("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) {
+ LOGD("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))) {
+ LOGD("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))) {
+ LOGD("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);
+ }
+ }
+ LOGV("%s,rxDev:%s, txDev:%s, curRxDev:%s, curTxDev:%s\n", __FUNCTION__, rxDevice, txDevice, curRxUCMDevice, curTxUCMDevice);
+#if 0
+ if (mode == AudioSystem::MODE_IN_CALL && platform_is_Fusion3() && (inCallDevSwitch == true)) {
+ err = csd_client_disable_device();
+ if (err < 0)
+ {
+ LOGE("csd_client_disable_device, failed, error %d", err);
+ }
+ }
+#endif
+
+ if (rxDevice != NULL) {
+ snd_use_case_set(handle->ucMgr, "_enadev", rxDevice);
+ strlcpy(curRxUCMDevice, rxDevice, sizeof(curRxUCMDevice));
+#if 0
+ 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) {
+ LOGD("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;
+ }
+ LOGD("switchDevice: curTxUCMDevivce %s curRxDevDevice %s", curTxUCMDevice, curRxUCMDevice);
+
+ if (mode == AudioSystem::MODE_IN_CALL && 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_RX_ACDB_ID && tx_dev_id == DEVICE_HANDSET_TX_ACDB_ID) {
+ tx_dev_id = DEVICE_SPEAKER_TX_ACDB_ID;
+ }
+
+ LOGV("rx_dev_id=%d, tx_dev_id=%d\n", rx_dev_id, tx_dev_id);
+ err = csd_client_enable_device(rx_dev_id, tx_dev_id, mDevSettingsFlag);
+ if (err < 0)
+ {
+ LOGE("csd_client_disable_device failed, error %d", err);
+ }
+ }
+
+ if (rxDevice != NULL) {
+ if (pflag && (((!strncmp(rxDevice, DEVICE_SPEAKER_HEADSET, strlen(DEVICE_SPEAKER_HEADSET))) &&
+ ((!strncmp(curRxUCMDevice, DEVICE_HEADPHONES, strlen(DEVICE_HEADPHONES))) ||
+ (!strncmp(curRxUCMDevice, DEVICE_HEADSET, strlen(DEVICE_HEADSET))))) ||
+ (((!strncmp(curRxUCMDevice, DEVICE_SPEAKER_HEADSET, strlen(DEVICE_SPEAKER_HEADSET))) &&
+ ((!strncmp(rxDevice, DEVICE_HEADPHONES, strlen(DEVICE_HEADPHONES))) ||
+ (!strncmp(rxDevice, DEVICE_HEADSET, strlen(DEVICE_HEADSET))))))) &&
+ ((!strncmp(handle->useCase, SND_USE_CASE_VERB_HIFI, strlen(SND_USE_CASE_VERB_HIFI))) ||
+ (!strncmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC, strlen(SND_USE_CASE_MOD_PLAY_MUSIC))))) {
+ s_open(handle);
+ pflag = false;
+ }
+ }
+
+ 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)
+{
+ LOGD("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;
+
+ /* 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))) {
+ LOGD("s_open: Opening LPA /Tunnel playback");
+ return NO_ERROR;
+ }
+
+ s_close(handle);
+
+ LOGD("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)) ||
+ (!strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_MUSIC))) {
+ flags = PCM_OUT;
+ } else {
+ flags = PCM_IN;
+ }
+ if (handle->channels == 1) {
+ flags |= PCM_MONO;
+ }
+#ifdef 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_MOD_CAPTURE_MUSIC, strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC))) {
+ flags |= PCM_QUAD;
+ } else {
+ flags |= PCM_5POINT1;
+ }
+ }
+#endif
+ else {
+ flags |= PCM_STEREO;
+ }
+ if (deviceName(handle, flags, &devName) < 0) {
+ LOGE("Failed to get pcm device node: %s", devName);
+ return NO_INIT;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (!handle->handle) {
+ LOGE("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) {
+ LOGE("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;
+ LOGV("s_open:s_start_voip_call handle %p", handle);
+
+ if (deviceName(handle, flags, &devName) < 0) {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (!handle->handle) {
+ free(devName);
+ LOGE("s_open: Failed to initialize ALSA device '%s'", devName);
+ return NO_INIT;
+ }
+
+ if (!pcm_ready(handle->handle)) {
+ LOGE(" 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) {
+ LOGE("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);
+ LOGV("s_open: DEVICE_IN_COMMUNICATION ");
+ flags = PCM_IN;
+ flags |= PCM_MONO;
+ handle->handle = 0;
+
+ if (deviceName(handle, flags, &devName1) < 0) {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName1);
+ } else {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+
+ if (!handle->handle) {
+ free(devName);
+ LOGE("s_open: Failed to initialize ALSA device '%s'", devName);
+ return NO_INIT;
+ }
+
+ if (!pcm_ready(handle->handle)) {
+ LOGE(" 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) {
+ LOGE("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;
+
+ LOGD("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) {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (!handle->handle) {
+ LOGE("s_start_voicecall: could not open PCM device");
+ goto Error;
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_voice_call: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_voice_call: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_voice_call: pcm_prepare failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ LOGE("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) {
+ LOGE("Failed to get pcm device node");
+ goto Error;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ LOGE("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) {
+ LOGE("s_start_voice_call: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_voice_call: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_voice_call: pcm_prepare failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ LOGE("s_start_voice_call:SNDRV_PCM_IOCTL_START failed\n");
+ goto Error;
+ }
+
+ if (platform_is_Fusion3()) {
+ err = csd_client_start_voice();
+ if (err < 0) {
+ LOGE("s_start_voice_call: csd_client error %d\n", err);
+ goto Error;
+ }
+ }
+
+ free(devName);
+ return NO_ERROR;
+
+Error:
+ LOGE("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;
+
+ LOGE("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) {
+ LOGE("Failed to get pcm device node");
+ goto Error;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ LOGE("Failed to get pcm device node");
+ return NO_INIT;
+ }
+ if (!handle->handle) {
+ LOGE("s_start_fm: could not open PCM device");
+ goto Error;
+ }
+
+ handle->handle->flags = flags;
+ err = setHardwareParams(handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_fm: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_fm: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_fm: setSoftwareParams failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ LOGE("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) {
+ LOGE("Failed to get pcm device node");
+ goto Error;
+ }
+ if (devName != NULL) {
+ handle->handle = pcm_open(flags, (char*)devName);
+ } else {
+ LOGE("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) {
+ LOGE("s_start_fm: setHardwareParams failed");
+ goto Error;
+ }
+
+ err = setSoftwareParams(handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_fm: setSoftwareParams failed");
+ goto Error;
+ }
+
+ err = pcm_prepare(handle->handle);
+ if(err != NO_ERROR) {
+ LOGE("s_start_fm: pcm_prepare failed");
+ goto Error;
+ }
+
+ if (ioctl(handle->handle->fd, SNDRV_PCM_IOCTL_START)) {
+ LOGE("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) {
+ LOGE("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;
+ LOGD("s_close: handle %p h %p", handle, h);
+ if (h) {
+ LOGV("s_close rxHandle\n");
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ LOGE("s_close: pcm_close failed for rxHandle with err %d", err);
+ }
+ }
+
+ h = handle->handle;
+ handle->handle = 0;
+
+ if (h) {
+ LOGV("s_close handle h %p\n", h);
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ LOGE("s_close: pcm_close failed for handle with err %d", err);
+ }
+
+ if ((!strcmp(handle->useCase, SND_USE_CASE_VERB_VOICECALL) ||
+ !strcmp(handle->useCase, SND_USE_CASE_MOD_PLAY_VOICE)) &&
+ platform_is_Fusion3()) {
+ err = csd_client_stop_voice();
+ if (err < 0) {
+ LOGE("s_close: csd_client error %d\n", 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;
+ LOGD("s_standby: handle %p h %p", handle, h);
+ if (h) {
+ LOGE("s_standby rxHandle\n");
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ LOGE("s_standby: pcm_close failed for rxHandle with err %d", err);
+ }
+ }
+
+ h = handle->handle;
+ handle->handle = 0;
+
+ if (h) {
+ LOGE("s_standby handle h %p\n", h);
+ err = pcm_close(h);
+ if(err != NO_ERROR) {
+ LOGE("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;
+
+ LOGD("s_route: devices 0x%x in mode %d", devices, mode);
+ callMode = mode;
+ switchDevice(handle, devices, mode);
+ return status;
+}
+
+int getUseCaseType(const char *useCase)
+{
+ LOGE("use case is %s\n", useCase);
+ if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI,
+ strlen(SND_USE_CASE_VERB_HIFI)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_LOW_POWER,
+ strlen(SND_USE_CASE_VERB_HIFI_LOW_POWER)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_HIFI_TUNNEL,
+ strlen(SND_USE_CASE_VERB_HIFI_TUNNEL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_DIGITAL_RADIO,
+ strlen(SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
+ strlen(SND_USE_CASE_MOD_PLAY_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_LPA,
+ strlen(SND_USE_CASE_MOD_PLAY_LPA)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_TUNNEL,
+ strlen(SND_USE_CASE_MOD_PLAY_TUNNEL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_FM,
+ strlen(SND_USE_CASE_MOD_PLAY_FM))) {
+ return USECASE_TYPE_RX;
+ } else if (!strncmp(useCase, SND_USE_CASE_VERB_HIFI_REC,
+ strlen(SND_USE_CASE_VERB_HIFI_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_FM_REC,
+ strlen(SND_USE_CASE_VERB_FM_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_FM_A2DP_REC,
+ strlen(SND_USE_CASE_VERB_FM_A2DP_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC,
+ strlen(SND_USE_CASE_MOD_CAPTURE_MUSIC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_FM,
+ strlen(SND_USE_CASE_MOD_CAPTURE_FM)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM,
+ strlen(SND_USE_CASE_MOD_CAPTURE_A2DP_FM))) {
+ return USECASE_TYPE_TX;
+ } else if (!strncmp(useCase, SND_USE_CASE_VERB_VOICECALL,
+ strlen(SND_USE_CASE_VERB_VOICECALL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_IP_VOICECALL,
+ strlen(SND_USE_CASE_VERB_IP_VOICECALL)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_DL_REC,
+ strlen(SND_USE_CASE_VERB_DL_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_UL_DL_REC,
+ strlen(SND_USE_CASE_VERB_UL_DL_REC)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOICE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOICE)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOIP,
+ strlen(SND_USE_CASE_MOD_PLAY_VOIP)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+ strlen(SND_USE_CASE_MOD_CAPTURE_VOICE_DL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL,
+ strlen(SND_USE_CASE_MOD_CAPTURE_VOICE_UL_DL)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
+ strlen(SND_USE_CASE_MOD_CAPTURE_VOICE)) ||
+ !strncmp(useCase, SND_USE_CASE_VERB_VOLTE,
+ strlen(SND_USE_CASE_VERB_VOLTE)) ||
+ !strncmp(useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOLTE))) {
+ return (USECASE_TYPE_RX | USECASE_TYPE_TX);
+ } else {
+ LOGE("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);
+ LOGE("Number of modifiers %d\n", mods_size);
+ if (mods_size) {
+ for(i = 0; i < mods_size; i++) {
+ LOGE("index %d modifier %s\n", i, mods_list[i]);
+ usecase_type |= getUseCaseType(mods_list[i]);
+ }
+ }
+ LOGE("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 {
+ LOGE("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))) {
+#if 0
+ ||
+ (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 */
+ }
+#if 0
+ } 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) {
+ 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) {
+ return strdup(SND_USE_CASE_DEV_ANC_HEADSET); /* ANC HEADSET RX */
+ } else {
+ return strdup(SND_USE_CASE_DEV_HEADPHONES); /* HEADSET RX */
+ }
+#if 0
+ } else if ((devices & AudioSystem::DEVICE_OUT_ANC_HEADSET) ||
+ (devices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE)) {
+ 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) ||
+//commented JB
+/* (devices & AudioSystem::DEVICE_OUT_DIRECTOUTPUT) ||*/
+ (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 */
+#if 0
+ } else if (devices & AudioSystem::DEVICE_OUT_PROXY) {
+ return strdup(SND_USE_CASE_DEV_PROXY_RX); /* PROXY RX */
+ } 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 {
+ LOGD("No valid output device: %u", devices);
+ }
+ } else {
+ if (!(mDevSettingsFlag & TTY_OFF) &&
+ (callMode == AudioSystem::MODE_IN_CALL) &&
+ ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET))) {
+#if 0
+ ||(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) {
+ 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 */
+ }
+ }
+ } else if (mDevSettingsFlag & QMIC_FLAG){
+ return strdup(SND_USE_CASE_DEV_QUAD_MIC);
+ }
+#ifdef SSR_ENABLED
+ else if (mDevSettingsFlag & SSRQMIC_FLAG){
+ LOGV("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
+ 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 */
+#if 0
+ } else if ((devices & AudioSystem::DEVICE_IN_WIRED_HEADSET) ||
+ (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 (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*/
+#if 0
+ } 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);
+ }
+#if 0
+ } 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)) {
+ LOGI("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 {
+ return strdup(SND_USE_CASE_DEV_LINE); /* BUILTIN-MIC TX */
+ }
+ } else {
+ LOGD("No valid input device: %u", devices);
+ }
+ }
+ return NULL;
+}
+
+void s_set_voice_volume(int vol)
+{
+ int err = 0;
+ LOGD("s_set_voice_volume: volume %d", vol);
+ ALSAControl control("/dev/snd/controlC0");
+ control.set("Voice Rx Volume", vol, 0);
+
+ if (platform_is_Fusion3()) {
+ err = csd_client_volume(vol);
+ if (err < 0) {
+ LOGE("s_set_voice_volume: csd_client error %d", err);
+ }
+ }
+}
+
+void s_set_volte_volume(int vol)
+{
+ LOGD("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)
+{
+ LOGD("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;
+ LOGD("s_set_mic_mute: state %d", state);
+ ALSAControl control("/dev/snd/controlC0");
+ control.set("Voice Tx Mute", state, 0);
+
+ if (platform_is_Fusion3()) {
+ err = csd_client_mic_mute(state);
+ if (err < 0) {
+ LOGE("s_set_mic_mute: csd_client error %d", err);
+ }
+ }
+}
+void s_set_volte_mic_mute(int state)
+{
+ LOGD("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)
+{
+ LOGD("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)
+{
+ LOGD("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;
+
+ LOGD("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()) {
+ err == csd_client_wide_voice(flag);
+ if (err < 0) {
+ LOGE("s_enable_wide_voice: csd_client error %d", err);
+ }
+ }
+}
+
+void s_set_voc_rec_mode(uint8_t mode)
+{
+ LOGD("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;
+
+ LOGD("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()) {
+ err = csd_client_fens(flag);
+ if (err < 0) {
+ LOGE("s_enable_fens: csd_client error %d", err);
+ }
+ }
+}
+
+void s_enable_slow_talk(bool flag)
+{
+ int err = 0;
+
+ LOGD("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()) {
+ err = csd_client_slow_talk(flag);
+ if (err < 0) {
+ LOGE("s_enable_slow_talk: csd_client error %d", err);
+ }
+ }
+}
+
+void s_set_flags(uint32_t flags)
+{
+ LOGV("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;
+}
+
+}