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/AudioHardwareALSA.cpp b/alsa_sound/AudioHardwareALSA.cpp
new file mode 100644
index 0000000..0179d1b
--- /dev/null
+++ b/alsa_sound/AudioHardwareALSA.cpp
@@ -0,0 +1,1569 @@
+/* AudioHardwareALSA.cpp
+ **
+ ** Copyright 2008-2010 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>
+#include <math.h>
+
+#define LOG_TAG "AudioHardwareALSA"
+//#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <cutils/properties.h>
+#include <media/AudioRecord.h>
+#include <hardware_legacy/power.h>
+
+#include "AudioHardwareALSA.h"
+#include "AudioUsbALSA.h"
+
+extern "C" {
+#include "csd_client.h"
+}
+
+extern "C"
+{
+ //
+ // Function for dlsym() to look up for creating a new AudioHardwareInterface.
+ //
+ android_audio_legacy::AudioHardwareInterface *createAudioHardware(void) {
+ return android_audio_legacy::AudioHardwareALSA::create();
+ }
+} // extern "C"
+
+namespace android_audio_legacy
+{
+
+// ----------------------------------------------------------------------------
+
+AudioHardwareInterface *AudioHardwareALSA::create() {
+ return new AudioHardwareALSA();
+}
+
+AudioHardwareALSA::AudioHardwareALSA() :
+ mALSADevice(0),mVoipStreamCount(0),mVoipMicMute(false),mVoipBitRate(0)
+ ,mCallState(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;
+ LOGD("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;
+ mAudioUsbALSA = new AudioUsbALSA();
+ mDevSettingsFlag |= TTY_OFF;
+ mBluetoothVGS = false;
+ mFusion3Platform = false;
+ musbPlaybackState = 0;
+ musbRecordingState = 0;
+
+ if((fp = fopen("/proc/asound/cards","r")) == NULL) {
+ LOGE("Cannot open /proc/asound/cards file to get sound card info");
+ } else {
+ while((fgets(soundCardInfo, sizeof(soundCardInfo), fp) != NULL)) {
+ LOGV("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) {
+ LOGV("Detected tabla 1.x sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm");
+ } else if (codec_rev == 3) {
+ LOGV("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)) {
+ LOGV("Detected Fusion tabla 2.x");
+ mFusion3Platform = true;
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x_Fusion3");
+ } else {
+ LOGV("Detected tabla 2.x sound card");
+ snd_use_case_mgr_open(&mUcMgr, "snd_soc_msm_2x");
+ }
+ }
+
+ if (mUcMgr < 0) {
+ LOGE("Failed to open ucm instance: %d", errno);
+ } else {
+ LOGI("ucm instance opened: %u", (unsigned)mUcMgr);
+ }
+ } else {
+ LOGE("ALSA Module could not be opened!!!");
+ }
+ } else {
+ LOGE("ALSA Module not found!!!");
+ }
+}
+
+AudioHardwareALSA::~AudioHardwareALSA()
+{
+ if (mUcMgr != NULL) {
+ LOGD("closing ucm instance: %u", (unsigned)mUcMgr);
+ snd_use_case_mgr_close(mUcMgr);
+ }
+ if (mALSADevice) {
+ mALSADevice->common.close(&mALSADevice->common);
+ }
+ for(ALSAHandleList::iterator it = mDeviceList.begin();
+ it != mDeviceList.end(); ++it) {
+ it->useCase[0] = 0;
+ mDeviceList.erase(it);
+ }
+ delete mAudioUsbALSA;
+}
+
+status_t AudioHardwareALSA::initCheck()
+{
+ if (!mALSADevice)
+ return NO_INIT;
+
+ return NO_ERROR;
+}
+
+status_t AudioHardwareALSA::setVoiceVolume(float v)
+{
+ LOGD("setVoiceVolume(%f)\n", v);
+ if (v < 0.0) {
+ LOGW("setVoiceVolume(%f) under 0.0, assuming 0.0\n", v);
+ v = 0.0;
+ } else if (v > 1.0) {
+ LOGW("setVoiceVolume(%f) over 1.0, assuming 1.0\n", v);
+ v = 1.0;
+ }
+
+ int newMode = mode();
+ LOGD("setVoiceVolume newMode %d",newMode);
+ int vol = lrint(v * 100.0);
+
+ // Voice volume levels from android are mapped to driver volume levels as follows.
+ // 0 -> 5, 20 -> 4, 40 ->3, 60 -> 2, 80 -> 1, 100 -> 0
+ // So adjust the volume to get the correct volume index in driver
+ vol = 100 - vol;
+
+ if (mALSADevice) {
+ if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
+ mALSADevice->setVoipVolume(vol);
+ } else if (newMode == AudioSystem::MODE_IN_CALL){
+ if (mCSCallActive == AudioSystem::CS_ACTIVE)
+ mALSADevice->setVoiceVolume(vol);
+ if (mVolteCallActive == AudioSystem::IMS_ACTIVE)
+ mALSADevice->setVoLTEVolume(vol);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+#ifdef FM_ENABLED
+status_t AudioHardwareALSA::setFmVolume(float value)
+{
+ status_t status = NO_ERROR;
+
+ int vol;
+
+ if (value < 0.0) {
+ LOGW("setFmVolume(%f) under 0.0, assuming 0.0\n", value);
+ value = 0.0;
+ } else if (value > 1.0) {
+ LOGW("setFmVolume(%f) over 1.0, assuming 1.0\n", value);
+ value = 1.0;
+ }
+ vol = lrint((value * 0x2000) + 0.5);
+
+ LOGD("setFmVolume(%f)\n", value);
+ LOGD("Setting FM volume to %d (available range is 0 to 0x2000)\n", vol);
+
+ mALSADevice->setFmVolume(vol);
+
+ return status;
+}
+#endif
+
+status_t AudioHardwareALSA::setMasterVolume(float volume)
+{
+ return NO_ERROR;
+}
+
+status_t AudioHardwareALSA::setMode(int mode)
+{
+ status_t status = NO_ERROR;
+
+ if (mode != mMode) {
+ status = AudioHardwareBase::setMode(mode);
+ }
+
+ if (mode == AudioSystem::MODE_IN_CALL) {
+ mCallState = AudioSystem::CS_ACTIVE;
+ }else if (mode == AudioSystem::MODE_NORMAL) {
+ mCallState = 0;
+ }
+
+ return status;
+}
+
+status_t AudioHardwareALSA::setParameters(const String8& keyValuePairs)
+{
+ AudioParameter param = AudioParameter(keyValuePairs);
+ String8 key;
+ String8 value;
+ status_t status = NO_ERROR;
+ int device;
+ int btRate;
+ int state;
+ LOGD("setParameters() %s", keyValuePairs.string());
+
+ key = String8(TTY_MODE_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ mDevSettingsFlag &= TTY_CLEAR;
+ if (value == "full") {
+ mDevSettingsFlag |= TTY_FULL;
+ } else if (value == "hco") {
+ mDevSettingsFlag |= TTY_HCO;
+ } else if (value == "vco") {
+ mDevSettingsFlag |= TTY_VCO;
+ } else {
+ mDevSettingsFlag |= TTY_OFF;
+ }
+ LOGI("Changed TTY Mode=%s", value.string());
+ mALSADevice->setFlags(mDevSettingsFlag);
+ if(mMode != AudioSystem::MODE_IN_CALL){
+ return NO_ERROR;
+ }
+ doRouting(0);
+ }
+
+ key = String8(FLUENCE_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "quadmic") {
+ mDevSettingsFlag |= QMIC_FLAG;
+ mDevSettingsFlag &= (~DMIC_FLAG);
+ LOGV("Fluence quadMic feature Enabled");
+ } else if (value == "dualmic") {
+ mDevSettingsFlag |= DMIC_FLAG;
+ mDevSettingsFlag &= (~QMIC_FLAG);
+ LOGV("Fluence dualmic feature Enabled");
+ } else if (value == "none") {
+ mDevSettingsFlag &= (~DMIC_FLAG);
+ mDevSettingsFlag &= (~QMIC_FLAG);
+ LOGV("Fluence feature Disabled");
+ }
+ mALSADevice->setFlags(mDevSettingsFlag);
+ doRouting(0);
+ }
+
+ if (mFusion3Platform) {
+ key = String8(INCALLMUSIC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "true") {
+ LOGV("Enabling Incall Music setting in the setparameter\n");
+ csd_client_start_playback();
+ } else {
+ LOGV("Disabling Incall Music setting in the setparameter\n");
+ csd_client_stop_playback();
+ }
+ }
+ }
+
+ key = String8(ANC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "true") {
+ LOGV("Enabling ANC setting in the setparameter\n");
+ mDevSettingsFlag |= ANC_FLAG;
+ } else {
+ LOGV("Disabling ANC setting in the setparameter\n");
+ mDevSettingsFlag &= (~ANC_FLAG);
+ }
+ mALSADevice->setFlags(mDevSettingsFlag);
+ doRouting(0);
+ }
+
+ key = String8(AudioParameter::keyRouting);
+ if (param.getInt(key, device) == NO_ERROR) {
+ // Ignore routing if device is 0.
+ if(device) {
+ doRouting(device);
+ }
+ param.remove(key);
+ }
+
+ key = String8(BT_SAMPLERATE_KEY);
+ if (param.getInt(key, btRate) == NO_ERROR) {
+ mALSADevice->setBtscoRate(btRate);
+ param.remove(key);
+ }
+
+ key = String8(BTHEADSET_VGS);
+ if (param.get(key, value) == NO_ERROR) {
+ if (value == "on") {
+ mBluetoothVGS = true;
+ } else {
+ mBluetoothVGS = false;
+ }
+ }
+
+ key = String8(WIDEVOICE_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ bool flag = false;
+ if (value == "true") {
+ flag = true;
+ }
+ if(mALSADevice) {
+ mALSADevice->enableWideVoice(flag);
+ }
+ param.remove(key);
+ }
+
+ key = String8(VOIPRATE_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ mVoipBitRate = atoi(value);
+ param.remove(key);
+ }
+
+ key = String8(FENS_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ bool flag = false;
+ if (value == "true") {
+ flag = true;
+ }
+ if(mALSADevice) {
+ mALSADevice->enableFENS(flag);
+ }
+ param.remove(key);
+ }
+
+#ifdef FM_ENABLED
+ key = String8(AudioParameter::keyHandleFm);
+ if (param.getInt(key, device) == NO_ERROR) {
+ // Ignore if device is 0
+ if(device) {
+ handleFm(device);
+ }
+ param.remove(key);
+ }
+#endif
+
+ key = String8(ST_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ bool flag = false;
+ if (value == "true") {
+ flag = true;
+ }
+ if(mALSADevice) {
+ mALSADevice->enableSlowTalk(flag);
+ }
+ param.remove(key);
+ }
+ key = String8(MODE_CALL_KEY);
+ if (param.getInt(key,state) == NO_ERROR) {
+ if (mCallState != state) {
+ mCallState = state;
+ doRouting(0);
+ }
+ mCallState = state;
+ }
+ if (param.size()) {
+ status = BAD_VALUE;
+ }
+ return status;
+}
+
+String8 AudioHardwareALSA::getParameters(const String8& keys)
+{
+ AudioParameter param = AudioParameter(keys);
+ String8 value;
+
+ String8 key = String8(DUALMIC_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ value = String8("false");
+ param.add(key, value);
+ }
+
+ key = String8(FLUENCE_KEY);
+ if (param.get(key, value) == NO_ERROR) {
+ if ((mDevSettingsFlag & QMIC_FLAG) &&
+ (mDevSettingsFlag & ~DMIC_FLAG))
+ value = String8("quadmic");
+ else if ((mDevSettingsFlag & DMIC_FLAG) &&
+ (mDevSettingsFlag & ~QMIC_FLAG))
+ value = String8("dualmic");
+ else if ((mDevSettingsFlag & ~DMIC_FLAG) &&
+ (mDevSettingsFlag & ~QMIC_FLAG))
+ value = String8("none");
+ param.add(key, value);
+ }
+
+#ifdef FM_ENABLED
+ key = String8("Fm-radio");
+ if ( param.get(key,value) == NO_ERROR ) {
+ if ( mIsFmActive ) {
+ param.addInt(String8("isFMON"), true );
+ }
+ }
+#endif
+
+ key = String8(BTHEADSET_VGS);
+ if (param.get(key, value) == NO_ERROR) {
+ if(mBluetoothVGS)
+ param.addInt(String8("isVGS"), true);
+ }
+
+ LOGV("AudioHardwareALSA::getParameters() %s", param.toString().string());
+ return param.toString();
+}
+
+void AudioHardwareALSA::closeUSBPlayback()
+{
+ LOGV("closeUSBPlayback, musbPlaybackState: %d", musbPlaybackState);
+ musbPlaybackState = 0;
+ mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_KILLTHREAD);
+}
+
+void AudioHardwareALSA::closeUSBRecording()
+{
+ LOGV("closeUSBRecording");
+ musbRecordingState = 0;
+ mAudioUsbALSA->exitRecordingThread(SIGNAL_EVENT_KILLTHREAD);
+}
+
+void AudioHardwareALSA::closeUsbPlaybackIfNothingActive(){
+ LOGV("closeUsbPlaybackIfNothingActive, musbPlaybackState: %d", musbPlaybackState);
+ if(!musbPlaybackState && mAudioUsbALSA != NULL) {
+ mAudioUsbALSA->exitPlaybackThread(SIGNAL_EVENT_TIMEOUT);
+ }
+}
+
+void AudioHardwareALSA::closeUsbRecordingIfNothingActive(){
+ LOGV("closeUsbRecordingIfNothingActive, musbRecordingState: %d", musbRecordingState);
+ if(!musbRecordingState && mAudioUsbALSA != NULL) {
+ LOGD("Closing USB Recording Session as no stream is active");
+ mAudioUsbALSA->setkillUsbRecordingThread(true);
+ }
+}
+
+void AudioHardwareALSA::startUsbPlaybackIfNotStarted(){
+ LOGV("Starting the USB playback %d kill %d", musbPlaybackState,
+ mAudioUsbALSA->getkillUsbPlaybackThread());
+ if((!musbPlaybackState) || (mAudioUsbALSA->getkillUsbPlaybackThread() == true)) {
+ mAudioUsbALSA->startPlayback();
+ }
+}
+
+void AudioHardwareALSA::startUsbRecordingIfNotStarted(){
+ LOGV("Starting the recording musbRecordingState: %d killUsbRecordingThread %d",
+ musbRecordingState, mAudioUsbALSA->getkillUsbRecordingThread());
+ if((!musbRecordingState) || (mAudioUsbALSA->getkillUsbRecordingThread() == true)) {
+ mAudioUsbALSA->startRecording();
+ }
+}
+
+void AudioHardwareALSA::doRouting(int device)
+{
+ Mutex::Autolock autoLock(mLock);
+ int newMode = mode();
+ bool isRouted = false;
+
+ if ((device == AudioSystem::DEVICE_IN_VOICE_CALL) ||
+ (device == AudioSystem::DEVICE_IN_COMMUNICATION) ) {
+
+#if 0
+ ||
+ (device == AudioSystem::DEVICE_IN_FM_RX) ||
+ (device == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) ||
+ (device == AudioSystem::DEVICE_IN_FM_RX_A2DP)) {
+#endif
+ LOGV("Ignoring routing for FM/INCALL/VOIP recording");
+ return;
+ }
+ if (device == 0)
+ device = mCurDevice;
+ LOGV("doRouting: device %d newMode %d mCSCallActive %d mVolteCallActive %d"
+ "mIsFmActive %d", device, newMode, mCSCallActive, mVolteCallActive,
+ mIsFmActive);
+
+ isRouted = routeVoLTECall(device, newMode);
+ isRouted |= routeVoiceCall(device, newMode);
+
+ if(!isRouted) {
+#if 0
+ if(!(device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET) &&
+ !(device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET) &&
+ !(device & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) &&
+ (musbPlaybackState)){
+ //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);
+ LOGE("USB UNPLUGGED, setting musbPlaybackState to 0");
+ musbPlaybackState = 0;
+ musbRecordingState = 0;
+ closeUSBRecording();
+ closeUSBPlayback();
+ } else if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
+ LOGE("Routing everything to prox now");
+ ALSAHandleList::iterator it = mDeviceList.end();
+ it--;
+ mALSADevice->route(&(*it), AudioSystem::DEVICE_OUT_PROXY,
+ 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))) {
+ LOGD("doRouting: LPA device switch to proxy");
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_LPA;
+ break;
+ } else if((!strcmp(it->useCase, SND_USE_CASE_VERB_VOICECALL)) ||
+ (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOICE))) {
+ LOGD("doRouting: VOICE device switch to proxy");
+ startUsbRecordingIfNotStarted();
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
+ musbRecordingState |= USBPLAYBACKBIT_VOICECALL;
+ break;
+ }else if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
+ (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
+ LOGD("doRouting: FM device switch to proxy");
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_FM;
+ break;
+ }
+ }
+ } else
+#endif
+ if((((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
+ (mCurDevice & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ ((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE))) ||
+ (((device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (device & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)) &&
+ (device & AudioSystem::DEVICE_OUT_SPEAKER) &&
+ ((mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ (mCurDevice & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE)))) {
+ for(ALSAHandleList::iterator it = mDeviceList.begin();
+ it != mDeviceList.end(); ++it) {
+ if((!strncmp(it->useCase, SND_USE_CASE_VERB_HIFI,
+ strlen(SND_USE_CASE_VERB_HIFI))) ||
+ (!strncmp(it->useCase, SND_USE_CASE_MOD_PLAY_MUSIC,
+ strlen(SND_USE_CASE_MOD_PLAY_MUSIC)))) {
+ mALSADevice->route(&(*it),(uint32_t)device, newMode);
+ break;
+ }
+ }
+ } else {
+ ALSAHandleList::iterator it = mDeviceList.end();
+ it--;
+ mALSADevice->route(&(*it), (uint32_t)device, newMode);
+ }
+ }
+ mCurDevice = device;
+}
+
+uint32_t AudioHardwareALSA::getVoipMode(int format)
+{
+ switch(format) {
+ case AudioSystem::PCM_16_BIT:
+ return MODE_PCM;
+ break;
+ case AudioSystem::AMR_NB:
+ return MODE_AMR;
+ break;
+ case AudioSystem::AMR_WB:
+ return MODE_AMR_WB;
+ break;
+
+ case AudioSystem::EVRC:
+ return MODE_IS127;
+ break;
+
+ case AudioSystem::EVRCB:
+ return MODE_4GV_NB;
+ break;
+ case AudioSystem::EVRCWB:
+ return MODE_4GV_WB;
+ break;
+
+ default:
+ return MODE_PCM;
+ }
+}
+
+AudioStreamOut *
+AudioHardwareALSA::openOutputStream(uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status)
+{
+ Mutex::Autolock autoLock(mLock);
+ LOGD("openOutputStream: devices 0x%x channels %d sampleRate %d",
+ devices, *channels, *sampleRate);
+
+ status_t err = BAD_VALUE;
+ AudioStreamOutALSA *out = 0;
+ ALSAHandleList::iterator it;
+
+ if (devices & (devices - 1)) {
+ if (status) *status = err;
+ LOGE("openOutputStream called with bad devices");
+ return out;
+ }
+# if 0
+ if((devices == AudioSystem::DEVICE_OUT_DIRECTOUTPUT) &&
+ ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
+ bool voipstream_active = false;
+ for(it = mDeviceList.begin();
+ it != mDeviceList.end(); ++it) {
+ if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
+ (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+ LOGD("openOutput: it->rxHandle %d it->handle %d",it->rxHandle,it->handle);
+ voipstream_active = true;
+ break;
+ }
+ }
+ if(voipstream_active == false) {
+ mVoipStreamCount = 0;
+ mVoipMicMute = false;
+ alsa_handle_t alsa_handle;
+ unsigned long bufferSize;
+ if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
+ bufferSize = VOIP_BUFFER_SIZE_8K;
+ }
+ else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
+ bufferSize = VOIP_BUFFER_SIZE_16K;
+ }
+ else {
+ LOGE("unsupported samplerate %d for voip",*sampleRate);
+ if (status) *status = err;
+ return out;
+ }
+ alsa_handle.module = mALSADevice;
+ alsa_handle.bufferSize = bufferSize;
+ alsa_handle.devices = devices;
+ alsa_handle.handle = 0;
+ if(*format == AudioSystem::PCM_16_BIT)
+ alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+ else
+ alsa_handle.format = *format;
+ alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
+ alsa_handle.sampleRate = *sampleRate;
+ alsa_handle.latency = VOIP_PLAYBACK_LATENCY;
+ alsa_handle.rxHandle = 0;
+ alsa_handle.ucMgr = mUcMgr;
+ mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
+ char *use_case;
+ 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_IP_VOICECALL, sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
+ }
+ free(use_case);
+ mDeviceList.push_back(alsa_handle);
+ it = mDeviceList.end();
+ it--;
+ LOGV("openoutput: mALSADevice->route useCase %s mCurDevice %d mVoipStreamCount %d mode %d", it->useCase,mCurDevice,mVoipStreamCount, mode());
+ if((mCurDevice & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (mCurDevice & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)||
+ (mCurDevice & AudioSystem::DEVICE_OUT_PROXY)){
+ LOGD("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);
+ LOGD("enabling VOIP in openoutputstream, musbPlaybackState: %d", musbPlaybackState);
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
+ LOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
+ startUsbRecordingIfNotStarted();
+ musbRecordingState |= USBRECBIT_VOIPCALL;
+ } else{
+ mALSADevice->route(&(*it), mCurDevice, AudioSystem::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);
+ } else {
+ snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
+ }
+ err = mALSADevice->startVoipCall(&(*it));
+ if (err) {
+ LOGE("Device open failed");
+ return NULL;
+ }
+ }
+ out = new AudioStreamOutALSA(this, &(*it));
+ err = out->set(format, channels, sampleRate, devices);
+ if(err == NO_ERROR) {
+ mVoipStreamCount++; //increment VoipstreamCount only if success
+ LOGD("openoutput mVoipStreamCount %d",mVoipStreamCount);
+ }
+ if (status) *status = err;
+ return out;
+ } else
+#endif
+ {
+
+ 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 = PLAYBACK_LATENCY;
+ alsa_handle.rxHandle = 0;
+ alsa_handle.ucMgr = mUcMgr;
+
+ char *use_case;
+ 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, 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--;
+ LOGD("useCase %s", it->useCase);
+#if 0
+ if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
+ LOGE("Routing to proxy for normal playback in openOutputStream");
+ devices |= AudioSystem::DEVICE_OUT_PROXY;
+ }
+#endif
+ mALSADevice->route(&(*it), devices, mode());
+ 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) {
+ LOGE("Device open failed");
+ } else {
+ out = new AudioStreamOutALSA(this, &(*it));
+ err = out->set(format, channels, sampleRate, devices);
+ }
+
+ if (status) *status = err;
+ return out;
+ }
+}
+
+void
+AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
+{
+ delete out;
+}
+
+AudioStreamOut *
+AudioHardwareALSA::openOutputSession(uint32_t devices,
+ int *format,
+ status_t *status,
+ int sessionId,
+ uint32_t samplingRate,
+ uint32_t channels)
+{
+ Mutex::Autolock autoLock(mLock);
+ LOGD("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--;
+ LOGD("useCase %s", it->useCase);
+# if 0
+ if((devices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (devices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
+ LOGE("Routing to proxy for LPA in openOutputSession");
+ devices |= AudioSystem::DEVICE_OUT_PROXY;
+ mALSADevice->route(&(*it), devices, mode());
+ devices = AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ LOGD("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;
+}
+
+AudioStreamIn *
+AudioHardwareALSA::openInputStream(uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics)
+{
+ Mutex::Autolock autoLock(mLock);
+ char *use_case;
+ int newMode = mode();
+ uint32_t route_devices;
+
+ status_t err = BAD_VALUE;
+ AudioStreamInALSA *in = 0;
+ ALSAHandleList::iterator it;
+
+ LOGD("openInputStream: devices 0x%x channels %d sampleRate %d", devices, *channels, *sampleRate);
+ if (devices & (devices - 1)) {
+ if (status) *status = err;
+ return in;
+ }
+
+ if((devices == AudioSystem::DEVICE_IN_COMMUNICATION) &&
+ ((*sampleRate == VOIP_SAMPLING_RATE_8K) || (*sampleRate == VOIP_SAMPLING_RATE_16K))) {
+ bool voipstream_active = false;
+ for(it = mDeviceList.begin();
+ it != mDeviceList.end(); ++it) {
+ if((!strcmp(it->useCase, SND_USE_CASE_VERB_IP_VOICECALL)) ||
+ (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_VOIP))) {
+ LOGD("openInput: it->rxHandle %d it->handle %d",it->rxHandle,it->handle);
+ voipstream_active = true;
+ break;
+ }
+ }
+ if(voipstream_active == false) {
+ mVoipStreamCount = 0;
+ mVoipMicMute = false;
+ alsa_handle_t alsa_handle;
+ unsigned long bufferSize;
+ if(*sampleRate == VOIP_SAMPLING_RATE_8K) {
+ bufferSize = VOIP_BUFFER_SIZE_8K;
+ }
+ else if(*sampleRate == VOIP_SAMPLING_RATE_16K) {
+ bufferSize = VOIP_BUFFER_SIZE_16K;
+ }
+ else {
+ LOGE("unsupported samplerate %d for voip",*sampleRate);
+ if (status) *status = err;
+ return in;
+ }
+ alsa_handle.module = mALSADevice;
+ alsa_handle.bufferSize = bufferSize;
+ alsa_handle.devices = devices;
+ alsa_handle.handle = 0;
+ if(*format == AudioSystem::PCM_16_BIT)
+ alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+ else
+ alsa_handle.format = *format;
+ alsa_handle.channels = VOIP_DEFAULT_CHANNEL_MODE;
+ alsa_handle.sampleRate = *sampleRate;
+ alsa_handle.latency = VOIP_RECORD_LATENCY;
+ alsa_handle.rxHandle = 0;
+ alsa_handle.ucMgr = mUcMgr;
+ mALSADevice->setVoipConfig(getVoipMode(*format), mVoipBitRate);
+ 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_MOD_PLAY_VOIP, sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_IP_VOICECALL, sizeof(alsa_handle.useCase));
+ }
+ free(use_case);
+ mDeviceList.push_back(alsa_handle);
+ it = mDeviceList.end();
+ it--;
+ LOGE("mCurrDevice: %d", mCurDevice);
+#if 0
+ if((mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
+ LOGE("Routing everything from proxy for voipcall");
+ mALSADevice->route(&(*it), AudioSystem::DEVICE_IN_PROXY, AudioSystem::MODE_IN_COMMUNICATION);
+ LOGD("enabling VOIP in openInputstream, musbPlaybackState: %d", musbPlaybackState);
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_VOIPCALL;
+ LOGD("Starting recording in openoutputstream, musbRecordingState: %d", musbRecordingState);
+ startUsbRecordingIfNotStarted();
+ musbRecordingState |= USBRECBIT_VOIPCALL;
+ }else
+#endif
+ {
+ mALSADevice->route(&(*it),mCurDevice, AudioSystem::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);
+ } else {
+ snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_VOIP);
+ }
+ if(sampleRate) {
+ it->sampleRate = *sampleRate;
+ }
+ if(channels)
+ it->channels = AudioSystem::popCount(*channels);
+ err = mALSADevice->startVoipCall(&(*it));
+ if (err) {
+ LOGE("Error opening pcm input device");
+ return NULL;
+ }
+ }
+ in = new AudioStreamInALSA(this, &(*it), acoustics);
+ err = in->set(format, channels, sampleRate, devices);
+ if(err == NO_ERROR) {
+ mVoipStreamCount++; //increment VoipstreamCount only if success
+ LOGD("OpenInput mVoipStreamCount %d",mVoipStreamCount);
+ }
+ LOGE("openInput: After Get alsahandle");
+ if (status) *status = err;
+ return in;
+ } else
+ {
+ for(ALSAHandleList::iterator itDev = mDeviceList.begin();
+ itDev != mDeviceList.end(); ++itDev)
+ {
+ if((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_HIFI_REC, MAX_UC_LEN))
+ ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_MUSIC, MAX_UC_LEN))
+ ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_FM, MAX_UC_LEN))
+#if 0
+ ||(0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_REC, MAX_UC_LEN))
+#endif
+ )
+ {
+#if 0
+ if(!(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
+ LOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
+ itDev->useCase, itDev->devices, itDev->module);
+ return in;
+ }
+#endif
+ }
+#if 0
+ else if ((0 == strncmp(itDev->useCase, SND_USE_CASE_VERB_FM_A2DP_REC, MAX_UC_LEN))
+ ||(0 == strncmp(itDev->useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, MAX_UC_LEN)))
+ {
+ if((devices == AudioSystem::DEVICE_IN_FM_RX_A2DP)){
+ LOGD("Input stream already exists, new stream not permitted: useCase:%s, devices:0x%x, module:%p",
+ itDev->useCase, itDev->devices, itDev->module);
+ return in;
+ }
+ }
+#endif
+ }
+
+ alsa_handle_t alsa_handle;
+ unsigned long bufferSize = DEFAULT_IN_BUFFER_SIZE;
+
+ 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 = VOICE_CHANNEL_MODE;
+ alsa_handle.sampleRate = android::AudioRecord::DEFAULT_SAMPLE_RATE;
+ alsa_handle.latency = RECORD_LATENCY;
+ alsa_handle.rxHandle = 0;
+ alsa_handle.ucMgr = mUcMgr;
+ 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)) {
+ LOGD("openInputStream: into incall recording, channels %d", *channels);
+ mIncallMode = *channels;
+ if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
+ (*channels & AudioSystem::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));
+ csd_client_start_record(INCALL_REC_STEREO);
+ } 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) {
+ if (mFusion3Platform) {
+ mALSADevice->setVocRecMode(INCALL_REC_MONO);
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE,
+ sizeof(alsa_handle.useCase));
+ csd_client_start_record(INCALL_REC_MONO);
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_VOICE_DL,
+ sizeof(alsa_handle.useCase));
+ }
+ }
+#if 0
+ } else if((devices == AudioSystem::DEVICE_IN_FM_RX)) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_FM, sizeof(alsa_handle.useCase));
+ } else if(devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_CAPTURE_A2DP_FM, sizeof(alsa_handle.useCase));
+#endif
+ } 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)) {
+ LOGD("openInputStream: incall recording, channels %d", *channels);
+ mIncallMode = *channels;
+ if ((*channels & AudioSystem::CHANNEL_IN_VOICE_UPLINK) &&
+ (*channels & AudioSystem::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));
+ csd_client_start_record(INCALL_REC_STEREO);
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_UL_DL_REC,
+ sizeof(alsa_handle.useCase));
+ }
+ } else if (*channels & AudioSystem::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));
+ csd_client_start_record(INCALL_REC_MONO);
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_DL_REC,
+ sizeof(alsa_handle.useCase));
+ }
+ }
+#if 0
+ } else if(devices == AudioSystem::DEVICE_IN_FM_RX) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_REC, sizeof(alsa_handle.useCase));
+ } else if (devices == AudioSystem::DEVICE_IN_FM_RX_A2DP) {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_FM_A2DP_REC, sizeof(alsa_handle.useCase));
+#endif
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_VERB_HIFI_REC, sizeof(alsa_handle.useCase));
+ }
+ }
+ free(use_case);
+ mDeviceList.push_back(alsa_handle);
+ ALSAHandleList::iterator it = mDeviceList.end();
+ it--;
+ //update channel info before do routing
+ if(channels) {
+ it->channels = AudioSystem::popCount((*channels) &
+ (AudioSystem::CHANNEL_IN_STEREO
+ | AudioSystem::CHANNEL_IN_MONO
+#ifdef SSR_ENABLED
+ | AudioSystem::CHANNEL_IN_5POINT1
+#endif
+ ));
+ LOGV("updated channel info: channels=%d", it->channels);
+ }
+ if (devices == AudioSystem::DEVICE_IN_VOICE_CALL){
+ /* Add current devices info to devices to do route */
+#if 0
+ if(mCurDevice == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET ||
+ mCurDevice == AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET){
+ LOGD("Routing everything from proxy for VOIP call");
+ route_devices = devices | AudioSystem::DEVICE_IN_PROXY;
+ } else
+#endif
+ {
+ route_devices = devices | mCurDevice;
+ }
+ mALSADevice->route(&(*it), route_devices, mode());
+ } else {
+#if 0
+ if(devices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET ||
+ devices & AudioSystem::DEVICE_IN_PROXY) {
+ devices |= AudioSystem::DEVICE_IN_PROXY;
+ LOGE("routing everything from proxy");
+ mALSADevice->route(&(*it), devices, mode());
+ } else
+#endif
+ {
+ mALSADevice->route(&(*it), devices, mode());
+ }
+ }
+
+ if(!strcmp(it->useCase, SND_USE_CASE_VERB_HIFI_REC) ||
+#if 0
+ !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_INCALL_REC)) {
+ snd_use_case_set(mUcMgr, "_verb", it->useCase);
+ } else {
+ snd_use_case_set(mUcMgr, "_enamod", it->useCase);
+ }
+ if(sampleRate) {
+ it->sampleRate = *sampleRate;
+ }
+#ifdef SSR_ENABLED
+ if (6 == it->channels) {
+ 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))) {
+ LOGV("OpenInoutStream: Use larger buffer size for 5.1(%s) recording ", it->useCase);
+ it->bufferSize = getInputBufferSize(it->sampleRate,*format,it->channels);
+ }
+ }
+#endif
+ err = mALSADevice->open(&(*it));
+ if (err) {
+ LOGE("Error opening pcm input device");
+ } else {
+ in = new AudioStreamInALSA(this, &(*it), acoustics);
+ err = in->set(format, channels, sampleRate, devices);
+ }
+ if (status) *status = err;
+ return in;
+ }
+}
+
+void
+AudioHardwareALSA::closeInputStream(AudioStreamIn* in)
+{
+ delete in;
+}
+
+status_t AudioHardwareALSA::setMicMute(bool state)
+{
+ int newMode = mode();
+ LOGD("setMicMute newMode %d",newMode);
+ if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
+ if (mVoipMicMute != state) {
+ mVoipMicMute = state;
+ LOGD("setMicMute: mVoipMicMute %d", mVoipMicMute);
+ if(mALSADevice) {
+ mALSADevice->setVoipMicMute(state);
+ }
+ }
+ } else {
+ if (mMicMute != state) {
+ mMicMute = state;
+ LOGD("setMicMute: mMicMute %d", mMicMute);
+ if(mALSADevice) {
+ if(mCSCallActive == AudioSystem::CS_ACTIVE)
+ mALSADevice->setMicMute(state);
+ if(mVolteCallActive == AudioSystem::IMS_ACTIVE)
+ mALSADevice->setVoLTEMicMute(state);
+ }
+ }
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardwareALSA::getMicMute(bool *state)
+{
+ int newMode = mode();
+ if(newMode == AudioSystem::MODE_IN_COMMUNICATION) {
+ *state = mVoipMicMute;
+ } else {
+ *state = mMicMute;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioHardwareALSA::dump(int fd, const Vector<String16>& args)
+{
+ return NO_ERROR;
+}
+
+size_t AudioHardwareALSA::getInputBufferSize(uint32_t sampleRate, int format, int channelCount)
+{
+ size_t bufferSize;
+ if (format != AudioSystem::PCM_16_BIT
+ && format != AudioSystem::AMR_NB
+ && format != AudioSystem::AMR_WB
+ && format != AudioSystem::EVRC
+ && format != AudioSystem::EVRCB
+ && format != AudioSystem::EVRCWB) {
+ LOGW("getInputBufferSize bad format: %d", format);
+ return 0;
+ }
+ if(sampleRate == 16000) {
+ bufferSize = DEFAULT_IN_BUFFER_SIZE * 2 * channelCount;
+ } else if(sampleRate < 44100) {
+ bufferSize = DEFAULT_IN_BUFFER_SIZE * channelCount;
+ } else {
+ bufferSize = DEFAULT_IN_BUFFER_SIZE * 12;
+ }
+ return bufferSize;
+}
+
+#ifdef FM_ENABLED
+void AudioHardwareALSA::handleFm(int device)
+{
+int newMode = mode();
+ if(device & AudioSystem::DEVICE_OUT_FM && mIsFmActive == 0) {
+ // Start FM Radio on current active device
+ unsigned long bufferSize = FM_BUFFER_SIZE;
+ alsa_handle_t alsa_handle;
+ char *use_case;
+ LOGV("Start FM");
+ 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_DIGITAL_RADIO, sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, SND_USE_CASE_MOD_PLAY_FM, sizeof(alsa_handle.useCase));
+ }
+ free(use_case);
+
+ for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
+ bufferSize &= ~b;
+ alsa_handle.module = mALSADevice;
+ alsa_handle.bufferSize = bufferSize;
+ alsa_handle.devices = device;
+ 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;
+ mIsFmActive = 1;
+ 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;
+ LOGE("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);
+ } else {
+ snd_use_case_set(mUcMgr, "_enamod", SND_USE_CASE_MOD_PLAY_FM);
+ }
+ mALSADevice->startFm(&(*it));
+ if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
+ LOGE("Starting FM, musbPlaybackState %d", musbPlaybackState);
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_FM;
+ }
+ } else if (!(device & AudioSystem::DEVICE_OUT_FM) && mIsFmActive == 1) {
+ //i Stop FM Radio
+ LOGV("Stop FM");
+ for(ALSAHandleList::iterator it = mDeviceList.begin();
+ it != mDeviceList.end(); ++it) {
+ if((!strcmp(it->useCase, SND_USE_CASE_VERB_DIGITAL_RADIO)) ||
+ (!strcmp(it->useCase, SND_USE_CASE_MOD_PLAY_FM))) {
+ mALSADevice->close(&(*it));
+ //mALSADevice->route(&(*it), (uint32_t)device, newMode);
+ mDeviceList.erase(it);
+ break;
+ }
+ }
+ mIsFmActive = 0;
+ musbPlaybackState &= ~USBPLAYBACKBIT_FM;
+ if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
+ closeUsbPlaybackIfNothingActive();
+ }
+ }
+}
+#endif
+
+void AudioHardwareALSA::disableVoiceCall(char* verb, char* modifier, int mode, int device)
+{
+ for(ALSAHandleList::iterator it = mDeviceList.begin();
+ it != mDeviceList.end(); ++it) {
+ if((!strcmp(it->useCase, verb)) ||
+ (!strcmp(it->useCase, modifier))) {
+ LOGV("Disabling voice call");
+ mALSADevice->close(&(*it));
+ mALSADevice->route(&(*it), (uint32_t)device, mode);
+ mDeviceList.erase(it);
+ break;
+ }
+ }
+ if(musbPlaybackState & USBPLAYBACKBIT_VOICECALL) {
+ LOGE("Voice call ended on USB");
+ musbPlaybackState &= ~USBPLAYBACKBIT_VOICECALL;
+ musbRecordingState &= ~USBRECBIT_VOICECALL;
+ closeUsbRecordingIfNothingActive();
+ closeUsbPlaybackIfNothingActive();
+ }
+}
+void AudioHardwareALSA::enableVoiceCall(char* verb, char* modifier, int mode, int device)
+{
+// Start voice call
+unsigned long bufferSize = DEFAULT_BUFFER_SIZE;
+alsa_handle_t alsa_handle;
+char *use_case;
+ 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, verb, sizeof(alsa_handle.useCase));
+ } else {
+ strlcpy(alsa_handle.useCase, modifier, sizeof(alsa_handle.useCase));
+ }
+ free(use_case);
+
+ for (size_t b = 1; (bufferSize & ~b) != 0; b <<= 1)
+ bufferSize &= ~b;
+ alsa_handle.module = mALSADevice;
+ alsa_handle.bufferSize = bufferSize;
+ alsa_handle.devices = device;
+ alsa_handle.handle = 0;
+ alsa_handle.format = SNDRV_PCM_FORMAT_S16_LE;
+ alsa_handle.channels = VOICE_CHANNEL_MODE;
+ alsa_handle.sampleRate = VOICE_SAMPLING_RATE;
+ alsa_handle.latency = VOICE_LATENCY;
+ alsa_handle.rxHandle = 0;
+ alsa_handle.ucMgr = mUcMgr;
+ mDeviceList.push_back(alsa_handle);
+ ALSAHandleList::iterator it = mDeviceList.end();
+ it--;
+#if 0
+ 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
+ mALSADevice->route(&(*it), (uint32_t)device, mode);
+ if (!strcmp(it->useCase, verb)) {
+ snd_use_case_set(mUcMgr, "_verb", verb);
+ } else {
+ snd_use_case_set(mUcMgr, "_enamod", modifier);
+ }
+ mALSADevice->startVoiceCall(&(*it));
+ if((device & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET)||
+ (device & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET)){
+ startUsbRecordingIfNotStarted();
+ startUsbPlaybackIfNotStarted();
+ musbPlaybackState |= USBPLAYBACKBIT_VOICECALL;
+ musbRecordingState |= USBRECBIT_VOICECALL;
+ }
+}
+
+bool AudioHardwareALSA::routeVoiceCall(int device, int newMode)
+{
+int csCallState = mCallState&0xF;
+ bool isRouted = false;
+ switch (csCallState) {
+ case AudioSystem::CS_INACTIVE:
+ if (mCSCallActive != AudioSystem::CS_INACTIVE) {
+ LOGD("doRouting: Disabling voice call");
+ disableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
+ (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
+ isRouted = true;
+ mCSCallActive = AudioSystem::CS_INACTIVE;
+ }
+ break;
+ case AudioSystem::CS_ACTIVE:
+ if (mCSCallActive == AudioSystem::CS_INACTIVE) {
+ LOGD("doRouting: Enabling CS voice call ");
+ enableVoiceCall((char *)SND_USE_CASE_VERB_VOICECALL,
+ (char *)SND_USE_CASE_MOD_PLAY_VOICE, newMode, device);
+ isRouted = true;
+ mCSCallActive = AudioSystem::CS_ACTIVE;
+ } else if (mCSCallActive == AudioSystem::CS_HOLD) {
+ LOGD("doRouting: Resume voice call 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_VOICECALL,
+ strlen(SND_USE_CASE_VERB_VOICECALL))) ||
+ (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
+ alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+ mCSCallActive = AudioSystem::CS_ACTIVE;
+ if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
+ LOGE("VoLTE resume failed");
+ break;
+ }
+ }
+ }
+ break;
+ case AudioSystem::CS_HOLD:
+ if (mCSCallActive == AudioSystem::CS_ACTIVE) {
+ LOGD("doRouting: Voice call 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_VOICECALL,
+ strlen(SND_USE_CASE_VERB_VOICECALL))) ||
+ (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOICE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOICE)))) {
+ mCSCallActive = AudioSystem::CS_HOLD;
+ alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+ if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
+ LOGE("Voice pause failed");
+ break;
+ }
+ }
+ }
+ break;
+ }
+ return isRouted;
+}
+bool AudioHardwareALSA::routeVoLTECall(int device, int newMode)
+{
+int volteCallState = mCallState&0xF0;
+bool isRouted = false;
+switch (volteCallState) {
+ case AudioSystem::IMS_INACTIVE:
+ if (mVolteCallActive != AudioSystem::IMS_INACTIVE) {
+ LOGD("doRouting: Disabling IMS call");
+ disableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
+ (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
+ isRouted = true;
+ mVolteCallActive = AudioSystem::IMS_INACTIVE;
+ }
+ break;
+ case AudioSystem::IMS_ACTIVE:
+ if (mVolteCallActive == AudioSystem::IMS_INACTIVE) {
+ LOGD("doRouting: Enabling IMS voice call ");
+ enableVoiceCall((char *)SND_USE_CASE_VERB_VOLTE,
+ (char *)SND_USE_CASE_MOD_PLAY_VOLTE, newMode, device);
+ isRouted = true;
+ mVolteCallActive = AudioSystem::IMS_ACTIVE;
+ } else if (mVolteCallActive == AudioSystem::IMS_HOLD) {
+ LOGD("doRouting: Resume IMS call 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_VOLTE,
+ strlen(SND_USE_CASE_VERB_VOLTE))) ||
+ (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
+ alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+ mVolteCallActive = AudioSystem::IMS_ACTIVE;
+ if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,0)<0)
+ LOGE("VoLTE resume failed");
+ break;
+ }
+ }
+ }
+ break;
+ case AudioSystem::IMS_HOLD:
+ if (mVolteCallActive == AudioSystem::IMS_ACTIVE) {
+ LOGD("doRouting: IMS ACTIVE 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_VOLTE,
+ strlen(SND_USE_CASE_VERB_VOLTE))) ||
+ (!strncmp(vt_it->useCase, SND_USE_CASE_MOD_PLAY_VOLTE,
+ strlen(SND_USE_CASE_MOD_PLAY_VOLTE)))) {
+ mVolteCallActive = AudioSystem::IMS_HOLD;
+ alsa_handle_t *handle = (alsa_handle_t *)(&(*vt_it));
+ if(ioctl((int)handle->handle->fd,SNDRV_PCM_IOCTL_PAUSE,1)<0)
+ LOGE("VoLTE Pause failed");
+ break;
+ }
+ }
+ }
+ break;
+ }
+ return isRouted;
+}
+
+} // namespace android_audio_legacy