Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

audio/msm7627a: Initial Audio HAL for 7x27A

Initial Audio HAL for 7x27A

Change-Id: I1949703fff7b1db770700020536a14483c4efa47
  • Loading branch information...
commit b62bfa96194878c0143c41688fa2c6b9f0646593 1 parent 9c6de87
Shashi Kumar authored Channagoud Kadabi committed
View
102 msm7627a/Android.mk
@@ -0,0 +1,102 @@
+# Copyright 2011 The Android Open Source Project
+
+#AUDIO_POLICY_TEST := true
+#ENABLE_AUDIO_DUMP := true
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioHardware.cpp \
+ audio_hw_hal.cpp \
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+ifeq ($(BOARD_HAVE_QCOM_FM),true)
+ LOCAL_CFLAGS += -DWITH_QCOM_FM
+endif
+
+ifeq ($(call is-android-codename-in-list,ICECREAM_SANDWICH),true)
+ LOCAL_CFLAGS += -DREG_KERNEL_UPDATE
+endif
+
+ifeq ($(strip $(BOARD_USES_SRS_TRUEMEDIA)),true)
+LOCAL_CFLAGS += -DSRS_PROCESSING
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia
+
+ifneq ($(TARGET_SIMULATOR),true)
+LOCAL_SHARED_LIBRARIES += libdl
+endif
+
+LOCAL_STATIC_LIBRARIES := \
+ libmedia_helper \
+ libaudiohw_legacy
+
+LOCAL_MODULE := audio.primary.msm7627a
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += -fno-short-enums
+
+LOCAL_C_INCLUDES := $(TARGET_OUT_HEADERS)/mm-audio/audio-alsa
+LOCAL_C_INCLUDES += $(TARGET_OUT_HEADERS)/mm-audio/audcal
+LOCAL_C_INCLUDES += hardware/libhardware/include
+LOCAL_C_INCLUDES += hardware/libhardware_legacy/include
+LOCAL_C_INCLUDES += frameworks/base/include
+LOCAL_C_INCLUDES += system/core/include
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+include $(BUILD_SHARED_LIBRARY)
+
+ifeq ("x","y") # use default audio policy manager
+
+# The audio policy is implemented on top of legacy policy code
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ AudioPolicyManager.cpp \
+ audio_policy_hal.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libutils \
+ libmedia
+
+LOCAL_STATIC_LIBRARIES := \
+ libaudiohw_legacy \
+ libmedia_helper \
+ libaudiopolicy_legacy
+
+LOCAL_MODULE := audio_policy.msm7627a
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+
+ifeq ($(BOARD_HAVE_BLUETOOTH),true)
+ LOCAL_CFLAGS += -DWITH_A2DP
+endif
+
+LOCAL_C_INCLUDES := hardware/libhardware_legacy/audio
+
+LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
+LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+
+include $(BUILD_SHARED_LIBRARY)
+endif
+
+# Load audio_policy.conf to system/etc/
+include $(CLEAR_VARS)
+LOCAL_MODULE := audio_policy.conf
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)
+LOCAL_SRC_FILES := audio_policy.conf
+include $(BUILD_PREBUILT)
View
3,359 msm7627a/AudioHardware.cpp
3,359 additions, 0 deletions not shown
View
497 msm7627a/AudioHardware.h
@@ -0,0 +1,497 @@
+/*
+** Copyright 2008, The Android Open-Source Project
+** 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.
+*/
+
+#ifndef ANDROID_AUDIO_HARDWARE_H
+#define ANDROID_AUDIO_HARDWARE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/threads.h>
+#include <utils/SortedVector.h>
+
+#include <hardware_legacy/AudioHardwareBase.h>
+
+extern "C" {
+#include <linux/msm_audio.h>
+#include <linux/msm_audio_voicememo.h>
+#ifdef QCOM_VOIP_ENABLED
+#include <linux/msm_audio_mvs.h>
+#endif
+}
+
+namespace android_audio_legacy {
+using android::SortedVector;
+using android::Mutex;
+
+// ----------------------------------------------------------------------------
+// Kernel driver interface
+//
+
+#define SAMP_RATE_INDX_8000 0
+#define SAMP_RATE_INDX_11025 1
+#define SAMP_RATE_INDX_12000 2
+#define SAMP_RATE_INDX_16000 3
+#define SAMP_RATE_INDX_22050 4
+#define SAMP_RATE_INDX_24000 5
+#define SAMP_RATE_INDX_32000 6
+#define SAMP_RATE_INDX_44100 7
+#define SAMP_RATE_INDX_48000 8
+
+#define EQ_MAX_BAND_NUM 12
+
+#define ADRC_ENABLE 0x0001
+#define ADRC_DISABLE 0xFFFE
+#define EQ_ENABLE 0x0002
+#define EQ_DISABLE 0xFFFD
+#define RX_IIR_ENABLE 0x0004
+#define RX_IIR_DISABLE 0xFFFB
+#define MBADRC_ENABLE 0x0010
+#define MBADRC_DISABLE 0xFFEF
+#define SRS_ENABLE 0x0020
+#define SRS_DISABLE 0xFFDF
+
+#define AGC_ENABLE 0x0001
+#define NS_ENABLE 0x0002
+#define TX_IIR_ENABLE 0x0004
+
+struct eq_filter_type {
+ int16_t gain;
+ uint16_t freq;
+ uint16_t type;
+ uint16_t qf;
+};
+
+struct eqalizer {
+ uint16_t bands;
+ uint16_t params[132];
+};
+
+struct rx_iir_filter {
+ uint16_t num_bands;
+ uint16_t iir_params[48];
+};
+
+struct adrc_filter {
+ uint16_t adrc_params[8];
+};
+
+struct msm_audio_stats {
+ uint32_t out_bytes;
+ uint32_t unused[3];
+};
+
+struct tx_iir {
+ uint16_t cmd_id;
+ uint16_t active_flag;
+ uint16_t num_bands;
+ uint16_t iir_params[48];
+};
+
+struct ns {
+ uint16_t cmd_id;
+ uint16_t ec_mode_new;
+ uint16_t dens_gamma_n;
+ uint16_t dens_nfe_block_size;
+ uint16_t dens_limit_ns;
+ uint16_t dens_limit_ns_d;
+ uint16_t wb_gamma_e;
+ uint16_t wb_gamma_n;
+};
+
+struct tx_agc {
+ uint16_t cmd_id;
+ uint16_t tx_agc_param_mask;
+ uint16_t tx_agc_enable_flag;
+ uint16_t static_gain;
+ int16_t adaptive_gain_flag;
+ uint16_t agc_params[19];
+};
+
+struct adrc_config {
+ uint16_t adrc_band_params[10];
+};
+
+struct adrc_ext_buf {
+ int16_t buff[196];
+};
+
+struct mbadrc_filter {
+ uint16_t num_bands;
+ uint16_t down_samp_level;
+ uint16_t adrc_delay;
+ uint16_t ext_buf_size;
+ uint16_t ext_partition;
+ uint16_t ext_buf_msw;
+ uint16_t ext_buf_lsw;
+ struct adrc_config adrc_band[5];
+ struct adrc_ext_buf ext_buf;
+};
+
+enum tty_modes {
+ TTY_OFF = 0,
+ TTY_VCO = 1,
+ TTY_HCO = 2,
+ TTY_FULL = 3
+};
+
+#define CODEC_TYPE_PCM 0
+#define AUDIO_HW_NUM_OUT_BUF 2 // Number of buffers in audio driver for output
+// TODO: determine actual audio DSP and hardware latency
+#define AUDIO_HW_OUT_LATENCY_MS 0 // Additionnal latency introduced by audio DSP and hardware in ms
+
+#define AUDIO_HW_IN_SAMPLERATE 8000 // Default audio input sample rate
+#define AUDIO_HW_IN_CHANNELS (AudioSystem::CHANNEL_IN_MONO) // Default audio input channel mask
+#define AUDIO_HW_IN_BUFFERSIZE 2048 // Default audio input buffer size
+#define AUDIO_HW_IN_FORMAT (AudioSystem::PCM_16_BIT) // Default audio input sample format
+#ifdef QCOM_VOIP_ENABLED
+#define AUDIO_HW_VOIP_BUFFERSIZE_8K 320
+#define AUDIO_HW_VOIP_BUFFERSIZE_16K 640
+#define AUDIO_HW_VOIP_SAMPLERATE_8K 8000
+#define AUDIO_HW_VOIP_SAMPLERATE_16K 16000
+#endif
+
+// ----------------------------------------------------------------------------
+using android_audio_legacy::AudioHardwareBase;
+using android_audio_legacy::AudioStreamOut;
+using android_audio_legacy::AudioStreamIn;
+using android_audio_legacy::AudioSystem;
+using android_audio_legacy::AudioHardwareInterface;
+class AudioHardware : public AudioHardwareBase
+{
+ class AudioStreamOutMSM72xx;
+ class AudioStreamInMSM72xx;
+#ifdef QCOM_VOIP_ENABLED
+ class AudioStreamOutDirect;
+ class AudioStreamInVoip;
+#endif
+public:
+ AudioHardware();
+ virtual ~AudioHardware();
+ virtual status_t initCheck();
+
+ virtual status_t setVoiceVolume(float volume);
+#ifdef QCOM_FM_ENABLED
+ virtual status_t setFmVolume(float volume);
+#endif
+ virtual status_t setMasterVolume(float volume);
+
+ virtual status_t setMode(int mode);
+
+ // mic mute
+ virtual status_t setMicMute(bool state);
+ virtual status_t getMicMute(bool* state);
+
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+
+ // create I/O streams
+ virtual AudioStreamOut* openOutputStream(
+ uint32_t devices,
+ int *format=0,
+ uint32_t *channels=0,
+ uint32_t *sampleRate=0,
+ status_t *status=0);
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ virtual AudioStreamOut* openOutputSession(
+ uint32_t devices,
+ int *format=0,
+ status_t *status=0,
+ int sessionId=-1,
+ uint32_t samplingRate=0,
+ uint32_t channels=0);
+#endif
+ virtual AudioStreamIn* openInputStream(
+
+ uint32_t devices,
+ int *format,
+ uint32_t *channels,
+ uint32_t *sampleRate,
+ status_t *status,
+ AudioSystem::audio_in_acoustics acoustics);
+
+ virtual void closeOutputStream(AudioStreamOut* out);
+ virtual void closeInputStream(AudioStreamIn* in);
+
+ virtual size_t getInputBufferSize(uint32_t sampleRate, int format, int channelCount);
+ void clearCurDevice() { mCurSndDevice = -1; }
+#ifdef QCOM_FM_ENABLED
+ int IsFmon() const { return (mFmFd != -1); }
+ int IsFmA2dpOn() const { return FmA2dpStatus; }
+ void SwitchOffFmA2dp() { FmA2dpStatus = false; }
+ bool isFMAnalog();
+#endif
+protected:
+ virtual status_t dump(int fd, const Vector<String16>& args);
+
+private:
+
+ status_t doAudioRouteOrMute(uint32_t device);
+ status_t setMicMute_nosync(bool state);
+ status_t checkMicMute();
+ status_t dumpInternals(int fd, const Vector<String16>& args);
+ uint32_t getInputSampleRate(uint32_t sampleRate);
+ bool checkOutputStandby();
+ status_t doRouting(AudioStreamInMSM72xx *input);
+#ifdef QCOM_FM_ENABLED
+ status_t enableFM();
+ status_t disableFM();
+#endif
+ AudioStreamInMSM72xx* getActiveInput_l();
+#ifdef QCOM_VOIP_ENABLED
+ AudioStreamInVoip* getActiveVoipInput_l();
+#endif
+
+ class AudioStreamOutMSM72xx : public AudioStreamOut {
+ public:
+ AudioStreamOutMSM72xx();
+ virtual ~AudioStreamOutMSM72xx();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate() const { return 44100; }
+ // must be 32-bit aligned - driver only seems to like 4800
+ virtual size_t bufferSize() const { return 4800; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+ virtual int format() const { return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return (1000*AUDIO_HW_NUM_OUT_BUF*(bufferSize()/frameSize()))/sampleRate()+AUDIO_HW_OUT_LATENCY_MS; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t devices() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ private:
+ AudioHardware* mHardware;
+ int mFd;
+ int mStartCount;
+ int mRetryCount;
+ bool mStandby;
+ uint32_t mDevices;
+ };
+#ifdef QCOM_VOIP_ENABLED
+ class AudioStreamOutDirect : public AudioStreamOut {
+ public:
+ AudioStreamOutDirect();
+ virtual ~AudioStreamOutDirect();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate);
+ virtual uint32_t sampleRate() const { return 8000; }
+ // must be 32-bit aligned - driver only seems to like 4800
+ virtual size_t bufferSize() const { return 320; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const {return AudioSystem::PCM_16_BIT; }
+ virtual uint32_t latency() const { return (1000*AUDIO_HW_NUM_OUT_BUF*(bufferSize()/frameSize()))/sampleRate()+AUDIO_HW_OUT_LATENCY_MS; }
+ virtual status_t setVolume(float left, float right) { return INVALID_OPERATION; }
+ virtual ssize_t write(const void* buffer, size_t bytes);
+ virtual status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t devices() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ private:
+ AudioHardware* mHardware;
+ int mFd;
+ int mRetryCount;
+ int mStartCount;
+ bool mStandby;
+ uint32_t mDevices;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ int mFormat;
+ };
+#endif
+ class AudioStreamInMSM72xx : public AudioStreamIn {
+ public:
+ enum input_state {
+ AUDIO_INPUT_CLOSED,
+ AUDIO_INPUT_OPENED,
+ AUDIO_INPUT_STARTED
+ };
+
+ AudioStreamInMSM72xx();
+ virtual ~AudioStreamInMSM72xx();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual size_t bufferSize() const { return mBufferSize; }
+ virtual uint32_t channels() const { return mChannels; }
+ virtual int format() const { return mFormat; }
+ virtual uint32_t sampleRate() const { return mSampleRate; }
+ virtual status_t setGain(float gain) { return INVALID_OPERATION; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const { return 0; }
+ uint32_t devices() { return mDevices; }
+ int state() const { return mState; }
+ virtual status_t addAudioEffect(effect_interface_s**) { return 0;}
+ virtual status_t removeAudioEffect(effect_interface_s**) { return 0;}
+
+ private:
+ AudioHardware* mHardware;
+ int mFd;
+ int mState;
+ int mRetryCount;
+ int mFormat;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ AudioSystem::audio_in_acoustics mAcoustics;
+ uint32_t mDevices;
+ bool mFirstread;
+ static int InstanceCount;
+ };
+ class AudioSessionOutMSM7xxx : public AudioStreamOut {
+ public:
+ AudioSessionOutMSM7xxx();
+ virtual ~AudioSessionOutMSM7xxx();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat
+#ifdef QCOM_TUNNEL_LPA_ENABLED
+ ,int32_t sessionId
+#endif
+ );
+ virtual uint32_t sampleRate() const { return 44100; }
+ // must be 32-bit aligned - driver only seems to like 4800
+ virtual size_t bufferSize() const { return 4800; }
+ virtual uint32_t channels() const { return AudioSystem::CHANNEL_OUT_STEREO; }
+ virtual int format() const { return AudioSystem::MP3; }
+ virtual uint32_t latency() const { return 0; }
+ virtual status_t setVolume(float left, float right);
+ virtual ssize_t write(const void* buffer, size_t bytes) {return 0;};
+ virtual status_t standby();
+ virtual status_t dump(int fd, const Vector<String16>& args) {return 0;};
+ bool checkStandby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ uint32_t devices() { return mDevices; }
+ virtual status_t getRenderPosition(uint32_t *dspFrames);
+
+ private:
+ AudioHardware* mHardware;
+ int mStartCount;
+ int mRetryCount;
+ bool mStandby;
+ uint32_t mDevices;
+ int mLPADriverFd;
+ };
+#ifdef QCOM_VOIP_ENABLED
+ class AudioStreamInVoip : public AudioStreamInMSM72xx {
+ public:
+ enum input_state {
+ AUDIO_INPUT_CLOSED,
+ AUDIO_INPUT_OPENED,
+ AUDIO_INPUT_STARTED
+ };
+
+ AudioStreamInVoip();
+ virtual ~AudioStreamInVoip();
+ status_t set(AudioHardware* mHardware,
+ uint32_t devices,
+ int *pFormat,
+ uint32_t *pChannels,
+ uint32_t *pRate,
+ AudioSystem::audio_in_acoustics acoustics);
+ virtual size_t bufferSize() const { return 320; }
+ virtual uint32_t channels() const {ALOGD(" AudioStreamInVoip: channels %d \n",mChannels); return mChannels; }
+ virtual int format() const { return AUDIO_HW_IN_FORMAT; }
+ virtual uint32_t sampleRate() const { return 8000; }
+ virtual status_t setGain(float gain) { return INVALID_OPERATION; }
+ virtual ssize_t read(void* buffer, ssize_t bytes);
+ virtual status_t dump(int fd, const Vector<String16>& args);
+ virtual status_t standby();
+ virtual status_t setParameters(const String8& keyValuePairs);
+ virtual String8 getParameters(const String8& keys);
+ virtual unsigned int getInputFramesLost() const { return 0; }
+ uint32_t devices() { return mDevices; }
+ int state() const { return mState; }
+
+ private:
+ AudioHardware* mHardware;
+ int mFd;
+ int mState;
+ int mRetryCount;
+ int mFormat;
+ uint32_t mChannels;
+ uint32_t mSampleRate;
+ size_t mBufferSize;
+ AudioSystem::audio_in_acoustics mAcoustics;
+ uint32_t mDevices;
+ bool mFirstread;
+#ifdef QCOM_FM_ENABLED
+ uint32_t mFmRec;
+#endif
+ };
+#endif
+ static const uint32_t inputSamplingRates[];
+ bool mInit;
+ bool mMicMute;
+#ifdef QCOM_FM_ENABLED
+ int mFmFd;
+ int FmA2dpStatus;
+#endif
+ bool mBluetoothNrec;
+ bool mBluetoothVGS;
+ uint32_t mBluetoothId;
+ AudioStreamOutMSM72xx* mOutput;
+#ifdef QCOM_VOIP_ENABLED
+ AudioStreamOutDirect* mDirectOutput;
+#endif
+ SortedVector <AudioStreamInMSM72xx*> mInputs;
+#ifdef QCOM_VOIP_ENABLED
+ SortedVector <AudioStreamInVoip*> mVoipInputs;
+#endif
+ msm_snd_endpoint *mSndEndpoints;
+ int mNumSndEndpoints;
+ int mCurSndDevice;
+ int m7xsnddriverfd;
+ bool mDualMicEnabled;
+ int mTtyMode;
+#ifdef QCOM_VOIP_ENABLED
+ int mVoipFd;
+ int mNumVoipStreams;
+#endif
+
+ friend class AudioStreamInMSM72xx;
+ Mutex mLock;
+};
+
+// ----------------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_AUDIO_HARDWARE_MSM72XX_H
View
1,139 msm7627a/AudioPolicyManager.cpp
@@ -0,0 +1,1139 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (c) 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 "AudioPolicyManager7627a"
+//#define LOG_NDEBUG 0
+#include <utils/Log.h>
+#include "AudioPolicyManager.h"
+#include <media/mediarecorder.h>
+#include <fcntl.h>
+#include <cutils/properties.h> // for property_get
+
+namespace android_audio_legacy {
+
+
+
+// ----------------------------------------------------------------------------
+// AudioPolicyManager for msm7k platform
+// Common audio policy manager code is implemented in AudioPolicyManagerBase class
+// ----------------------------------------------------------------------------
+
+// --- class factory
+
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+ return new AudioPolicyManager(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+ delete interface;
+}
+
+
+void AudioPolicyManager::setPhoneState(int state)
+{
+ LOGE("setPhoneState() state %d", state);
+ uint32_t newDevice = 0;
+ if (state < 0 || state >= AudioSystem::NUM_MODES) {
+ LOGW("setPhoneState() invalid state %d", state);
+ return;
+ }
+
+ if (state == mPhoneState ) {
+ LOGW("setPhoneState() setting same state %d", state);
+ return;
+ }
+
+ // if leaving call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isInCall()) {
+ LOGV("setPhoneState() in call state management: new state is %d", state);
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ AudioPolicyManagerBase::handleIncallSonification(stream, false, true);
+ }
+ }
+
+ // store previous phone state for management of sonification strategy below
+ int oldState = mPhoneState;
+ mPhoneState = state;
+ // force routing command to audio hardware when starting call
+ // even if no device change is needed
+ bool force = (mPhoneState == AudioSystem::MODE_IN_CALL);
+
+ // are we entering or starting a call
+ if (!isStateInCall(oldState) && isStateInCall(state)) {
+ LOGV(" Entering call in setPhoneState()");
+ // force routing command to audio hardware when starting a call
+ // even if no device change is needed
+ force = true;
+ } else if (isStateInCall(oldState) && !isStateInCall(state)) {
+ LOGV(" Exiting call in setPhoneState()");
+ // force routing command to audio hardware when exiting a call
+ // even if no device change is needed
+ force = true;
+ } else if (isStateInCall(state) && (state != oldState)) {
+ LOGV(" Switching between telephony and VoIP in setPhoneState()");
+ // force routing command to audio hardware when switching between telephony and VoIP
+ // even if no device change is needed
+ force = true;
+ }
+
+ // check for device and output changes triggered by new phone state
+ newDevice = getNewDevice(mHardwareOutput, false);
+ if (newDevice == 0 && (mLPADecodeOutput != -1 &&
+ mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ }
+
+#ifdef WITH_A2DP
+ AudioPolicyManagerBase::checkOutputForAllStrategies();
+ // suspend A2DP output if a SCO device is present.
+ if (mA2dpOutput != 0 && mScoDeviceAddress != "") {
+ if (oldState == AudioSystem::MODE_NORMAL) {
+ mpClientInterface->suspendOutput(mA2dpOutput);
+ } else if (state == AudioSystem::MODE_NORMAL) {
+ mpClientInterface->restoreOutput(mA2dpOutput);
+ }
+ }
+#endif
+ AudioPolicyManagerBase::updateDeviceForStrategy();
+
+ AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput);
+
+ // force routing command to audio hardware when ending call
+ // even if no device change is needed
+ if (isStateInCall(oldState) && newDevice == 0) {
+ newDevice = hwOutputDesc->device();
+ force = true;
+ }
+
+ // when changing from ring tone to in call mode, mute the ringing tone
+ // immediately and delay the route change to avoid sending the ring tone
+ // tail into the earpiece or headset.
+ int delayMs = 0;
+ if (isStateInCall(state) && oldState == AudioSystem::MODE_RINGTONE) {
+ // delay the device change command by twice the output latency to have some margin
+ // and be sure that audio buffers not yet affected by the mute are out when
+ // we actually apply the route change
+ delayMs = hwOutputDesc->mLatency*2;
+ setStreamMute(AudioSystem::RING, true, mHardwareOutput);
+ }
+
+ // change routing is necessary
+ setOutputDevice(mHardwareOutput, newDevice, force, delayMs);
+
+ // if entering in call state, handle special case of active streams
+ // pertaining to sonification strategy see handleIncallSonification()
+ if (isStateInCall(state)) {
+ LOGV("setPhoneState() in call state management: new state is %d", state);
+ // unmute the ringing tone after a sufficient delay if it was muted before
+ // setting output device above
+ if (oldState == AudioSystem::MODE_RINGTONE) {
+ setStreamMute(AudioSystem::RING, false, mHardwareOutput, MUTE_TIME_MS);
+ }
+ for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) {
+ AudioPolicyManagerBase::handleIncallSonification(stream, true, true);
+ }
+ }
+
+ // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE
+ if (state == AudioSystem::MODE_RINGTONE &&
+ (hwOutputDesc->mRefCount[AudioSystem::MUSIC])) {
+// (systemTime() - mMusicStopTime) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) {
+ mLimitRingtoneVolume = true;
+ } else {
+ mLimitRingtoneVolume = false;
+ }
+}
+
+
+audio_io_handle_t AudioPolicyManager::getSession(AudioSystem::stream_type stream,
+ uint32_t format,
+ AudioSystem::output_flags flags,
+ int32_t sessionId,
+ uint32_t samplingRate,
+ uint32_t channels)
+{
+ audio_io_handle_t output = 0;
+ uint32_t latency = 0;
+ routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+ uint32_t device = getDeviceForStrategy(strategy);
+ LOGV("getSession() stream %d, format %d, sessionId %x, flags %x device %d", stream, format, sessionId, flags, device);
+ AudioOutputDescriptor *outputDesc = new AudioOutputDescriptor();
+ outputDesc->mDevice = device;
+ outputDesc->mSamplingRate = 0;
+ outputDesc->mFormat = format;
+ outputDesc->mChannels = 2;
+ outputDesc->mLatency = 0;
+ outputDesc->mFlags = (AudioSystem::output_flags)(flags | AudioSystem::OUTPUT_FLAG_DIRECT);
+ outputDesc->mRefCount[stream] = 0;
+ output = mpClientInterface->openSession(&outputDesc->mDevice,
+ &outputDesc->mFormat,
+ outputDesc->mFlags,
+ stream,
+ sessionId,
+ samplingRate,
+ channels);
+
+ // only accept an output with the requeted parameters
+ if ((format != 0 && format != outputDesc->mFormat) || !output) {
+ LOGE("openSession() failed opening a session: format %d, sessionId %d output %d",
+ format, sessionId, output);
+ if(output) {
+ mpClientInterface->closeSession(output);
+ }
+ delete outputDesc;
+ return 0;
+ }
+
+ //reset it here, it will get updated in startoutput
+ outputDesc->mDevice = 0;
+
+ mOutputs.add(output, outputDesc);
+ mLPADecodeOutput = output;
+ mLPAStreamType = stream;
+ return output;
+}
+
+void AudioPolicyManager::pauseSession(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("pauseSession() Output [%d] and stream is [%d]", output, stream);
+
+ if ( (output == mLPADecodeOutput) &&
+ (stream == mLPAStreamType) ) {
+
+ mLPAActiveOuput = mLPADecodeOutput;
+ mLPAActiveStreamType = mLPAStreamType;
+ mLPADecodeOutput = -1;
+ mLPAStreamType = AudioSystem::DEFAULT;
+ mLPAMuted = false;
+ }
+}
+
+void AudioPolicyManager::resumeSession(audio_io_handle_t output, AudioSystem::stream_type stream)
+{
+ LOGV("resumeSession() Output [%d] and stream is [%d]", output, stream);
+
+ if (output == mLPAActiveOuput)
+ {
+ mLPADecodeOutput = mLPAActiveOuput;
+ mLPAStreamType = stream;
+
+ // Set Volume if the music stream volume is changed in the Pause state of LPA Jagan
+ mLPAActiveOuput = -1;
+ mLPAActiveStreamType = AudioSystem::DEFAULT;
+ AudioPolicyManager::startOutput(mLPADecodeOutput, mLPAStreamType);
+ }
+}
+
+void AudioPolicyManager::releaseSession(audio_io_handle_t output)
+{
+ LOGV("releaseSession() %d", output);
+
+ // This means the Output is put into Pause state
+ if (output == mLPAActiveOuput && mLPADecodeOutput == -1) {
+ mLPADecodeOutput = mLPAActiveOuput;
+ mLPAStreamType = mLPAActiveStreamType;
+ }
+
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("releaseSession() releasing unknown output %d", output);
+ return;
+ }
+
+ AudioPolicyManager::stopOutput(output, mLPAStreamType);
+ delete mOutputs.valueAt(index);
+ mOutputs.removeItem(output);
+ mLPADecodeOutput = -1;
+ mLPAActiveOuput = -1;
+ mLPAStreamType = AudioSystem::DEFAULT;
+ mLPAActiveStreamType = AudioSystem::DEFAULT;
+ mLPAMuted = false;
+}
+
+uint32_t AudioPolicyManager::getDeviceForStrategy(routing_strategy strategy, bool fromCache)
+{
+ uint32_t device = 0;
+
+ if (fromCache) {
+ LOGV("getDeviceForStrategy() from cache strategy %d, device %x", strategy, mDeviceForStrategy[strategy]);
+ return mDeviceForStrategy[strategy];
+ }
+
+ switch (strategy) {
+ case STRATEGY_DTMF:
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ // when off call, DTMF strategy follows the same rules as MEDIA strategy
+ device = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ break;
+ }
+ // when in call, DTMF and PHONE strategies follow the same rules
+ // FALL THROUGH
+
+ case STRATEGY_PHONE:
+ // for phone strategy, we first consider the forced use and then the available devices by order
+ // of priority
+ switch (mForceUse[AudioSystem::FOR_COMMUNICATION]) {
+ case AudioSystem::FORCE_BT_SCO:
+ if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO;
+ if (device) break;
+ // if SCO device is requested but no SCO device is available, fall back to default case
+ // FALL THROUGH
+
+ default: // FORCE_NONE
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+#ifdef WITH_A2DP
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+#endif
+ if (mPhoneState == AudioSystem::MODE_RINGTONE)
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (device) break;
+
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
+ if (device == 0) {
+ LOGE("getDeviceForStrategy() earpiece device not found");
+ }
+ break;
+
+ case AudioSystem::FORCE_SPEAKER:
+ if (mPhoneState != AudioSystem::MODE_IN_CALL || strategy != STRATEGY_DTMF) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+ if (device) break;
+ }
+#ifdef WITH_A2DP
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to
+ // A2DP speaker when forcing to speaker output
+ if (mPhoneState != AudioSystem::MODE_IN_CALL) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+#endif
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (device == 0) {
+ LOGE("getDeviceForStrategy() speaker device not found");
+ }
+ break;
+ }
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (mPhoneState == AudioSystem::MODE_IN_CALL) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, false);
+ break;
+ }
+ // FALL THROUGH
+
+ case STRATEGY_ENFORCED_AUDIBLE:
+ // strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
+ // except when in call where it doesn't default to STRATEGY_PHONE behavior
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (device == 0) {
+ LOGE("getDeviceForStrategy() speaker device not found");
+ }
+ // The second device used for sonification is the same as the device used by media strategy
+ // FALL THROUGH
+
+ // for analog FM alerts should be played on the speaker only
+ if(FM_ANALOG == getFMMode())
+ break;
+
+ case STRATEGY_MEDIA: {
+ switch (mForceUse[AudioSystem::FOR_MEDIA]) {
+ default:{
+ uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
+#ifdef WITH_A2DP
+ if ((mA2dpOutput != 0) && !(FM_ANALOG == getFMMode())) {
+ /* analog fm over a2dp not supported */
+ if (strategy == STRATEGY_SONIFICATION && !a2dpUsedForSonification()) {
+ break;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ }
+ }
+#endif
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
+ }
+
+ // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or
+ // STRATEGY_ENFORCED_AUDIBLE, 0 otherwise
+ device |= device2;
+ }
+ break;
+ case AudioSystem::FORCE_SPEAKER:
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ break;
+ }
+
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) {
+ device |= AudioSystem::DEVICE_OUT_FM;
+ if(FM_ANALOG == getFMMode()){
+ if (device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_FM))
+ device = AudioSystem::DEVICE_OUT_SPEAKER;
+ else if(device & AudioSystem::DEVICE_OUT_WIRED_HEADSET)
+ device &= ~(device & AudioSystem::DEVICE_OUT_WIRED_HEADSET);
+ }
+ }
+ // Do not play media stream if in call and the requested device would change the hardware
+ // output routing
+ if (mPhoneState == AudioSystem::MODE_IN_CALL &&
+ !AudioSystem::isA2dpDevice((AudioSystem::audio_devices)device) &&
+ device != getDeviceForStrategy(STRATEGY_PHONE)) {
+ device = getDeviceForStrategy(STRATEGY_PHONE);
+ LOGV("getDeviceForStrategy() incompatible media and phone devices");
+ }
+ } break;
+
+ default:
+ LOGW("getDeviceForStrategy() unknown strategy: %d", strategy);
+ break;
+ }
+
+ LOGV("getDeviceForStrategy() strategy %d, device %x", strategy, device);
+ return device;
+}
+
+status_t AudioPolicyManager::setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address)
+{
+
+ LOGV("setDeviceConnectionState() device: %x, state %d, address %s", device, state, device_address);
+
+ // connect/disconnect only 1 device at a time
+ if (AudioSystem::popCount(device) != 1) return BAD_VALUE;
+
+ if (strlen(device_address) >= MAX_DEVICE_ADDRESS_LEN) {
+ LOGE("setDeviceConnectionState() invalid address: %s", device_address);
+ return BAD_VALUE;
+ }
+
+ // handle output devices
+ if (AudioSystem::isOutputDevice(device)) {
+
+#ifndef WITH_A2DP
+ if (AudioSystem::isA2dpDevice(device)) {
+ LOGE("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+ }
+#endif
+
+ switch (state)
+ {
+ // handle output device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE:
+
+ if(device == AudioSystem::DEVICE_OUT_FM){
+ char value[PROPERTY_VALUE_MAX];
+ fm_modes fmMode = FM_DIGITAL;
+
+ if (property_get("hw.fm.isAnalog", value, NULL)
+ && !strcasecmp(value, "true")){
+ fmMode = FM_ANALOG ;
+ }
+
+ LOGD("Current FM mode %d, New Fm Mode %d",getFMMode(),fmMode);
+
+ if (fmMode == getFMMode()){
+ LOGE("FM is already connected in %d Mode",fmMode);
+ return INVALID_OPERATION;
+ } else if (FM_NONE != getFMMode()){
+ LOGE("Rejctng dev conction:Anlg FM & Dgtl FM Mutuly xclusve");
+ return INVALID_OPERATION;
+ }else{
+ setFmMode(fmMode);
+ LOGW("FM started in %d Mode",fmMode);
+ }
+ }
+ if (mAvailableOutputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %x", device);
+ return INVALID_OPERATION;
+ }
+ LOGV("setDeviceConnectionState() connecting device %x", device);
+
+ // register new device as available
+ mAvailableOutputDevices |= device;
+
+#ifdef WITH_A2DP
+ // handle A2DP device connection
+ if (AudioSystem::isA2dpDevice(device)) {
+ status_t status = handleA2dpConnection(device, device_address);
+ if (status != NO_ERROR) {
+ mAvailableOutputDevices &= ~device;
+ return status;
+ }
+ } else
+#endif
+ {
+ if (AudioSystem::isBluetoothScoDevice(device)) {
+ LOGV("setDeviceConnectionState() BT SCO device, address %s", device_address);
+ // keep track of SCO device address
+ mScoDeviceAddress = String8(device_address, MAX_DEVICE_ADDRESS_LEN);
+#ifdef WITH_A2DP
+ if (mA2dpOutput != 0 &&
+ mPhoneState != AudioSystem::MODE_NORMAL) {
+ mpClientInterface->suspendOutput(mA2dpOutput);
+ }
+#endif
+ }
+ }
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+
+ if(device == AudioSystem::DEVICE_OUT_FM){
+ uint32_t newDevice;
+ fm_modes prevFmMode = getFMMode();
+
+ LOGD("turning off Fm device in Mode %d",getFMMode());
+ setFmMode(FM_NONE);
+ newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ if((FM_ANALOG == prevFmMode) && ((newDevice & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP) ||
+ (newDevice & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES)||
+ (newDevice & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER))) {
+ LOGW("setDeviceConnectionState() FM off, switch to Wired Headset");
+ setOutputDevice(mHardwareOutput, (AudioSystem::DEVICE_OUT_WIRED_HEADSET), true);
+ }
+ }
+ if (!(mAvailableOutputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %x", device);
+ return INVALID_OPERATION;
+ }
+
+
+ LOGV("setDeviceConnectionState() disconnecting device %x", device);
+ // remove device from available output devices
+ mAvailableOutputDevices &= ~device;
+
+#ifdef WITH_A2DP
+ // handle A2DP device disconnection
+ if (AudioSystem::isA2dpDevice(device)) {
+ status_t status = handleA2dpDisconnection(device, device_address);
+ if (status != NO_ERROR) {
+ mAvailableOutputDevices |= device;
+ return status;
+ }
+ } else
+#endif
+ {
+ if (AudioSystem::isBluetoothScoDevice(device)) {
+ mScoDeviceAddress = "";
+#ifdef WITH_A2DP
+ if (mA2dpOutput != 0 &&
+ mPhoneState != AudioSystem::MODE_NORMAL) {
+ mpClientInterface->restoreOutput(mA2dpOutput);
+ }
+#endif
+ }
+ }
+ } break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ // request routing change if necessary
+ uint32_t newDevice = getNewDevice(mHardwareOutput, false);
+ if(newDevice == 0 && mLPADecodeOutput != -1) {
+ newDevice = AudioPolicyManagerBase::getNewDevice(mLPADecodeOutput, false);
+ }
+ if (device == AudioSystem::DEVICE_OUT_FM) {
+ if (state == AudioSystem::DEVICE_STATE_AVAILABLE) {
+ mOutputs.valueFor(mHardwareOutput)->changeRefCount(AudioSystem::FM, 1);
+ }
+ else {
+ mOutputs.valueFor(mHardwareOutput)->changeRefCount(AudioSystem::FM, -1);
+ }
+ if (newDevice == 0) {
+ newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ }
+ }
+#ifdef WITH_A2DP
+ AudioPolicyManagerBase::checkOutputForAllStrategies();
+ // A2DP outputs must be closed after checkOutputForAllStrategies() is executed
+ if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) {
+ closeA2dpOutputs();
+ }
+#endif
+ updateDeviceForStrategy();
+ if (mLPADecodeOutput != -1) {
+ setOutputDevice(mLPADecodeOutput, newDevice);
+ }
+ setOutputDevice(mHardwareOutput, newDevice);
+
+ if (device == AudioSystem::DEVICE_OUT_WIRED_HEADSET) {
+ device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+ } else if (device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO ||
+ device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET ||
+ device == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT) {
+ device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else {
+ return NO_ERROR;
+ }
+ }
+ // handle input devices
+ if (AudioSystem::isInputDevice(device)) {
+ switch (state)
+ {
+ // handle input device connection
+ case AudioSystem::DEVICE_STATE_AVAILABLE: {
+ if (mAvailableInputDevices & device) {
+ LOGW("setDeviceConnectionState() device already connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices |= device;
+ }
+ break;
+
+ // handle input device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ if (!(mAvailableInputDevices & device)) {
+ LOGW("setDeviceConnectionState() device not connected: %d", device);
+ return INVALID_OPERATION;
+ }
+ mAvailableInputDevices &= ~device;
+ } break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ uint32_t newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ LOGV("setDeviceConnectionState() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ LOGV("String to set param in setDeviceconnection %s\n", param.toString().string());
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+
+ return NO_ERROR;
+ }
+
+ LOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ LOGV("setForceUse() usage %d, config %d, mPhoneState %d", usage, config, mPhoneState);
+
+ bool forceVolumeReeval = false;
+ switch(usage) {
+ case AudioSystem::FOR_COMMUNICATION:
+ if (config != AudioSystem::FORCE_SPEAKER && config != AudioSystem::FORCE_BT_SCO &&
+ config != AudioSystem::FORCE_NONE) {
+ LOGW("setForceUse() invalid config %d for FOR_COMMUNICATION", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_MEDIA:
+ if (config != AudioSystem::FORCE_HEADPHONES && config != AudioSystem::FORCE_BT_A2DP &&
+ config != AudioSystem::FORCE_WIRED_ACCESSORY && config != AudioSystem::FORCE_NONE &&
+ config != AudioSystem::FORCE_SPEAKER) {
+ LOGW("setForceUse() invalid config %d for FOR_MEDIA", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ {
+ uint32_t device = getDeviceForStrategy(STRATEGY_MEDIA);
+ setOutputDevice(mHardwareOutput, device);
+ }
+ break;
+ case AudioSystem::FOR_RECORD:
+ if (config != AudioSystem::FORCE_BT_SCO && config != AudioSystem::FORCE_WIRED_ACCESSORY &&
+ config != AudioSystem::FORCE_NONE) {
+ LOGW("setForceUse() invalid config %d for FOR_RECORD", config);
+ return;
+ }
+ mForceUse[usage] = config;
+ break;
+ case AudioSystem::FOR_DOCK:
+ if (config != AudioSystem::FORCE_NONE && config != AudioSystem::FORCE_BT_CAR_DOCK &&
+ config != AudioSystem::FORCE_BT_DESK_DOCK && config != AudioSystem::FORCE_WIRED_ACCESSORY) {
+ LOGW("setForceUse() invalid config %d for FOR_DOCK", config);
+ }
+ forceVolumeReeval = true;
+ mForceUse[usage] = config;
+ break;
+ default:
+ LOGW("setForceUse() invalid usage %d", usage);
+ break;
+ }
+
+ // check for device and output changes triggered by new phone state
+ uint32_t newDevice = getNewDevice(mHardwareOutput, false);
+#ifdef WITH_A2DP
+ checkOutputForAllStrategies();
+#endif
+ updateDeviceForStrategy();
+ setOutputDevice(mHardwareOutput, newDevice);
+ if (forceVolumeReeval) {
+ applyStreamVolumes(mHardwareOutput, newDevice);
+ }
+
+ audio_io_handle_t activeInput = getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ newDevice = getDeviceForInputSource(inputDesc->mInputSource);
+ if (newDevice != inputDesc->mDevice) {
+ LOGV("setForceUse() changing device from %x to %x for input %d",
+ inputDesc->mDevice, newDevice, activeInput);
+ inputDesc->mDevice = newDevice;
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+}
+
+uint32_t AudioPolicyManager::getDeviceForInputSource(int inputSource)
+{
+ uint32_t device;
+
+ switch(inputSource) {
+ case AUDIO_SOURCE_DEFAULT:
+ case AUDIO_SOURCE_MIC:
+ case AUDIO_SOURCE_VOICE_RECOGNITION:
+ if (mForceUse[AudioSystem::FOR_RECORD] == AudioSystem::FORCE_BT_SCO &&
+ mAvailableInputDevices & AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET) {
+ device = AudioSystem::DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+ } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_WIRED_HEADSET) {
+ device = AudioSystem::DEVICE_IN_WIRED_HEADSET;
+ } else {
+ device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_COMMUNICATION:
+ device = AudioSystem::DEVICE_IN_COMMUNICATION;
+ break;
+ case AUDIO_SOURCE_CAMCORDER:
+ if (hasBackMicrophone()) {
+ device = AudioSystem::DEVICE_IN_BACK_MIC;
+ } else {
+ device = AudioSystem::DEVICE_IN_BUILTIN_MIC;
+ }
+ break;
+ case AUDIO_SOURCE_VOICE_UPLINK:
+ case AUDIO_SOURCE_VOICE_DOWNLINK:
+ case AUDIO_SOURCE_VOICE_CALL:
+ device = AudioSystem::DEVICE_IN_VOICE_CALL;
+ break;
+ case AUDIO_SOURCE_FM_RX:
+ device = AudioSystem::DEVICE_IN_FM_RX;
+ break;
+ case AUDIO_SOURCE_FM_RX_A2DP:
+ device = AudioSystem::DEVICE_IN_FM_RX_A2DP;
+ break;
+ default:
+ LOGW("getInput() invalid input source %d", inputSource);
+ device = 0;
+ break;
+ }
+ LOGV("getDeviceForInputSource()input source %d, device %08x", inputSource, device);
+ return device;
+}
+
+status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ LOGI("startOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("startOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+ routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
+
+#ifdef WITH_A2DP
+ if (mA2dpOutput != 0 && !a2dpUsedForSonification() &&
+ (strategy == STRATEGY_SONIFICATION || strategy == STRATEGY_ENFORCED_AUDIBLE)) {
+ setStrategyMute(STRATEGY_MEDIA, true, mA2dpOutput);
+ }
+#endif
+
+ // incremenent usage count for this stream on the requested output:
+ // NOTE that the usage count is the same for duplicated output and hardware output which is
+ // necassary for a correct control of hardware output routing by startOutput() and stopOutput()
+ outputDesc->changeRefCount(stream, 1);
+
+ uint32_t NewDevice = AudioPolicyManagerBase::getNewDevice(output);
+
+ if((stream == AudioSystem::SYSTEM) && (FM_ANALOG == getFMMode())
+ && (NewDevice == AudioSystem::DEVICE_OUT_FM)){
+ NewDevice |= AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ LOGE("Selecting AnlgFM + CODEC device %x",NewDevice);
+ setOutputDevice(output, NewDevice, true);
+ }
+ else if (output != mLPADecodeOutput){
+ setOutputDevice(output, NewDevice);
+ }
+ else{
+ setOutputDevice(output, AudioPolicyManagerBase::getNewDevice(output), true);
+ }
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ AudioPolicyManagerBase::handleIncallSonification(stream, true, false);
+ }
+
+ // apply volume rules for current stream and device if necessary
+ checkAndSetVolume(stream, mStreams[stream].mIndexCur, output, outputDesc->device());
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::stopInput(audio_io_handle_t input)
+{
+ LOGV("stopInput() input %d", input);
+ uint32_t newDevice = NULL;
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("stopInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+
+ if (inputDesc->mRefCount == 0) {
+ LOGW("stopInput() input %d already stopped", input);
+ return INVALID_OPERATION;
+ } else {
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), 0);
+ LOGV("stopInput string to setParam %s\n", param.toString().string());
+ mpClientInterface->setParameters(input, param.toString());
+ inputDesc->mRefCount = 0;
+
+ newDevice = AudioPolicyManagerBase::getNewDevice(mHardwareOutput);
+ param.addInt(String8(AudioParameter::keyRouting), (int)newDevice);
+ mpClientInterface->setParameters(mHardwareOutput, param.toString());
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
+ AudioSystem::stream_type stream,
+ int session)
+{
+ LOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
+ ssize_t index = mOutputs.indexOfKey(output);
+ if (index < 0) {
+ LOGW("stopOutput() unknow output %d", output);
+ return BAD_VALUE;
+ }
+
+ AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
+ routing_strategy strategy = AudioPolicyManagerBase::getStrategy((AudioSystem::stream_type)stream);
+
+ // handle special case for sonification while in call
+ if (isInCall()) {
+ AudioPolicyManagerBase::handleIncallSonification(stream, false, false);
+ }
+
+ if (outputDesc->mRefCount[stream] > 0) {
+ // decrement usage count of this stream on the output
+ outputDesc->changeRefCount(stream, -1);
+ // store time at which the last music track was stopped - see computeVolume()
+#if 0 //TODO
+ if (stream == AudioSystem::MUSIC) {
+ mMusicStopTime = systemTime();
+ }
+#endif
+ uint32_t newDevice = AudioPolicyManagerBase::getNewDevice(mHardwareOutput, false);
+
+ if(newDevice == 0 && mLPADecodeOutput != -1) {
+ newDevice = AudioPolicyManagerBase::getNewDevice(mLPADecodeOutput, false);
+ }
+
+ if(FM_ANALOG == getFMMode())
+ setOutputDevice(output, newDevice,true);
+ else
+ setOutputDevice(output, newDevice);
+
+#ifdef WITH_A2DP
+ if (mA2dpOutput != 0 && !a2dpUsedForSonification() &&
+ (strategy == STRATEGY_SONIFICATION || strategy == STRATEGY_ENFORCED_AUDIBLE)) {
+ setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2);
+ }
+#endif
+ if (output != mHardwareOutput) {
+ setOutputDevice(mHardwareOutput, AudioPolicyManagerBase::getNewDevice(mHardwareOutput), true);
+ }
+ return NO_ERROR;
+ } else {
+ LOGW("stopOutput() refcount is already 0 for output %d", output);
+ return INVALID_OPERATION;
+ }
+}
+
+
+void AudioPolicyManager::setOutputDevice(audio_io_handle_t output, uint32_t device, bool force, int delayMs)
+{
+ LOGV("setOutputDevice() output %d device %x delayMs %d", output, device, delayMs);
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+
+
+ if (outputDesc->isDuplicated()) {
+ setOutputDevice(outputDesc->mOutput1->mId, device, force, delayMs);
+ setOutputDevice(outputDesc->mOutput2->mId, device, force, delayMs);
+ return;
+ }
+#ifdef WITH_A2DP
+ // filter devices according to output selected
+ if (output == mA2dpOutput) {
+ device &= AudioSystem::DEVICE_OUT_ALL_A2DP;
+ } else {
+ device &= ~AudioSystem::DEVICE_OUT_ALL_A2DP;
+ }
+#endif
+
+ uint32_t prevDevice = (uint32_t)outputDesc->device();
+ // Do not change the routing if:
+ // - the requestede device is 0
+ // - the requested device is the same as current device and force is not specified.
+ // Doing this check here allows the caller to call setOutputDevice() without conditions
+ if ((device == 0 || device == prevDevice) && !force) {
+ LOGV("setOutputDevice() setting same device %x or null device for output %d", device, output);
+ return;
+ }
+
+ outputDesc->mDevice = device;
+ // mute media streams if both speaker and headset are selected
+ if (device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) ||
+ device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_FM) ||
+ device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_FM) ||
+ device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_FM_TX)){
+ setStrategyMute(STRATEGY_MEDIA, true, output);
+
+ LOGV("setOutputDevice: muting output:%d mLPADecodeOutput:%d mHardwareOutput:%d",output,mLPADecodeOutput,mHardwareOutput);
+ // Mute LPA output also if it belongs to STRATEGY_MEDIA
+ if(((mLPADecodeOutput != -1) && (mLPADecodeOutput != output) &&
+ mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ LOGV("setOutputDevice: muting mLPADecodeOutput:%d", mLPADecodeOutput);
+ setStrategyMute(STRATEGY_MEDIA, true, mLPADecodeOutput);
+ }
+ if(((mHardwareOutput != -1) && (mHardwareOutput != output) &&
+ mOutputs.valueFor(mHardwareOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ LOGV("setOutputDevice: muting mHardwareOutput:%d", mHardwareOutput);
+ setStrategyMute(STRATEGY_MEDIA, true, mHardwareOutput);
+ }
+
+ // wait for the PCM output buffers to empty before proceeding with the rest of the command
+ usleep(outputDesc->mLatency*2*1000);
+ }
+
+ // do the routing
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)device);
+ mpClientInterface->setParameters(mHardwareOutput, param.toString(), delayMs);
+ // update stream volumes according to new device
+ applyStreamVolumes(output, device, delayMs);
+
+ if((mLPADecodeOutput != -1 &&
+ mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ applyStreamVolumes(mLPADecodeOutput, device, delayMs);
+ }
+
+ // if changing from a combined headset + speaker route, unmute media streams
+ if (prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET) ||
+ prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADPHONE) ||
+ prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_FM) ||
+ prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_WIRED_HEADSET | AudioSystem::DEVICE_OUT_FM) ||
+ prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_FM_TX)){
+ setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);
+ LOGV("setOutputDevice: Unmuting output:%d mLPADecodeOutput:%d mHardwareOutput:%d",output,mLPADecodeOutput,mHardwareOutput);
+ // Unmute LPA output also if it belongs to STRATEGY_MEDIA
+ if((mLPADecodeOutput != -1 && (mLPADecodeOutput != output) &&
+ mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ LOGV("setOutputDevice: Unmuting mLPADecodeOutput:%d delayMs:%d", mLPADecodeOutput,delayMs);
+ setStrategyMute(STRATEGY_MEDIA, false, mLPADecodeOutput, delayMs);
+ }
+ if(((mHardwareOutput != -1) && (mHardwareOutput != output) &&
+ mOutputs.valueFor(mHardwareOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ LOGV("setOutputDevice: Unmuting mHardwareOutput:%d delayMs:%d", mHardwareOutput,delayMs);
+ setStrategyMute(STRATEGY_MEDIA, false, mHardwareOutput, delayMs);
+ }
+ }
+}
+
+status_t AudioPolicyManager::checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs, bool force)
+{
+
+ // do not change actual stream volume if the stream is muted
+ if ((mOutputs.valueFor(output)->mMuteCount[stream] != 0 && output != mLPADecodeOutput) ||
+ (output == mLPADecodeOutput && stream == mLPAStreamType && mLPAMuted == true)){
+ LOGV("checkAndSetVolume() stream %d muted count %d", stream, mOutputs.valueFor(output)->mMuteCount[stream]);
+ return NO_ERROR;
+ }
+
+ // do not change in call volume if bluetooth is connected and vice versa
+ if ((stream == AudioSystem::VOICE_CALL && mForceUse[AudioSystem::FOR_COMMUNICATION] == AudioSystem::FORCE_BT_SCO) ||
+ (stream == AudioSystem::BLUETOOTH_SCO && mForceUse[AudioSystem::FOR_COMMUNICATION] != AudioSystem::FORCE_BT_SCO)) {
+ LOGV("checkAndSetVolume() cannot set stream %d volume with force use = %d for comm",
+ stream, mForceUse[AudioSystem::FOR_COMMUNICATION]);
+ return INVALID_OPERATION;
+ }
+
+ float volume = computeVolume(stream, index, output, device);
+ // We actually change the volume if:
+ // - the float value returned by computeVolume() changed
+ // - the force flag is set
+ if (volume != mOutputs.valueFor(output)->mCurVolume[stream] ||
+ (stream == AudioSystem::VOICE_CALL) || (stream == AudioSystem::FM) || force) {
+ mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+ LOGV("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+
+ if (stream == mLPAActiveStreamType && mLPAActiveOuput > 0 ) {
+ mOutputs.valueFor(mLPAActiveOuput)->mCurVolume[mLPAActiveStreamType] = volume;
+ }
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::DTMF ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ // offset value to reflect actual hardware volume that never reaches 0
+ // 1% corresponds roughly to first step in VOICE_CALL stream volume setting (see AudioService.java)
+ volume = 0.01 + 0.99 * volume;
+ }
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume;
+ // Force voice volume to max for bluetooth SCO as volume is managed by the headset
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else {
+ String8 key ("bt_headset_vgs");
+ mpClientInterface->getParameters(output,key);
+ AudioParameter result(mpClientInterface->getParameters(0,key));
+ int value;
+ if(result.getInt(String8("isVGS"),value) == NO_ERROR){
+ LOGD("BT-SCO Voice Volume %f",(float)index/(float)mStreams[stream].mIndexMax);
+ voiceVolume = 1.0;
+ } else {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ }
+ }
+ if ((voiceVolume >= 0 && output == mHardwareOutput) &&
+ (!(mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM))) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ mLastVoiceVolume = voiceVolume;
+ }
+ } else if ((stream == AudioSystem::FM) && (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM)) {
+ float fmVolume = -1.0;
+ fmVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ if (fmVolume >= 0 && output == mHardwareOutput) {
+ mpClientInterface->setFmVolume(fmVolume, delayMs);
+ }
+ }
+ return NO_ERROR;
+}
+
+
+void AudioPolicyManager::setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs)
+{
+ StreamDescriptor &streamDesc = mStreams[stream];
+ AudioOutputDescriptor *outputDesc = mOutputs.valueFor(output);
+
+ LOGV("setStreamMute() stream %d, mute %d, output %d, mMuteCount %d", stream, on, output, outputDesc->mMuteCount[stream]);
+
+ if (on) {
+ if ((outputDesc->mMuteCount[stream] == 0 && output != mLPADecodeOutput) ||
+ (output == mLPADecodeOutput && stream == mLPAStreamType && false == mLPAMuted)) {
+ if (streamDesc.mCanBeMuted) {
+ checkAndSetVolume(stream, 0, output, outputDesc->device(), delayMs);
+ }
+ }
+ // increment mMuteCount after calling checkAndSetVolume() so that volume change is not ignored
+ if(output == mLPADecodeOutput) {
+ if(stream == mLPAStreamType && false == mLPAMuted) {
+ mLPAMuted = true;
+ }
+ } else {
+ outputDesc->mMuteCount[stream]++;
+ }
+ } else {
+ if ((outputDesc->mMuteCount[stream] == 0 && output != mLPADecodeOutput) ||
+ (output == mLPADecodeOutput && stream == mLPAStreamType && false == mLPAMuted)) {
+ LOGW("setStreamMute() unmuting non muted stream!");
+ return;
+ }
+ if(output == mLPADecodeOutput) {
+ if(stream == mLPAStreamType && true == mLPAMuted) {
+ mLPAMuted = false;
+ checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs);
+ }
+ } else {
+ if(--outputDesc->mMuteCount[stream] == 0){
+ checkAndSetVolume(stream, streamDesc.mIndexCur, output, outputDesc->device(), delayMs);
+ }
+ }
+ }
+}
+
+
+}; // namespace android
View
92 msm7627a/AudioPolicyManager.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 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 <stdint.h>
+#include <sys/types.h>
+#include <utils/Timers.h>
+#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
+#include <hardware_legacy/AudioPolicyManagerBase.h>
+
+
+namespace android_audio_legacy {
+
+enum fm_modes{
+ FM_DIGITAL=1,
+ FM_ANALOG,
+ FM_NONE
+};
+
+class AudioPolicyManager: public AudioPolicyManagerBase
+{
+
+public:
+ AudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+ : AudioPolicyManagerBase(clientInterface),fmMode(FM_NONE){
+ mLPADecodeOutput = -1;
+ mLPAMuted = false;
+ mLPAStreamType = AudioSystem::DEFAULT;
+ }
+
+ virtual ~AudioPolicyManager() {}
+
+ virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device,
+ AudioSystem::device_connection_state state,
+ const char *device_address);
+
+ virtual uint32_t getDeviceForStrategy(routing_strategy strategy, bool fromCache = true);
+ virtual audio_io_handle_t getSession(AudioSystem::stream_type stream,
+ uint32_t format,
+ AudioSystem::output_flags flags,
+ int32_t sessionId, uint32_t samplingRate,
+ uint32_t channels);
+ virtual void pauseSession(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void resumeSession(audio_io_handle_t output, AudioSystem::stream_type stream);
+ virtual void releaseSession(audio_io_handle_t output);
+ virtual void setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config);
+protected:
+ fm_modes fmMode;
+
+ // true is current platform implements a back microphone
+ virtual bool hasBackMicrophone() const { return false; }
+#ifdef WITH_A2DP
+ // true is current platform supports suplication of notifications and ringtones over A2DP output
+ virtual bool a2dpUsedForSonification() const { return true; }
+#endif
+ // check that volume change is permitted, compute and send new volume to audio hardware
+ status_t checkAndSetVolume(int stream, int index, audio_io_handle_t output, uint32_t device, int delayMs = 0, bool force = false);
+ // select input device corresponding to requested audio source
+ virtual uint32_t getDeviceForInputSource(int inputSource);
+ status_t stopInput(audio_io_handle_t input);
+ // change the route of the specified output
+ virtual void setPhoneState(int state);
+ virtual void setOutputDevice(audio_io_handle_t output,uint32_t device,bool force = false,int delayMs = 0);
+ virtual status_t startOutput(audio_io_handle_t output,AudioSystem::stream_type stream,int session = 0);
+ virtual status_t stopOutput(audio_io_handle_t output,AudioSystem::stream_type stream,int session = 0);
+ void setStreamMute(int stream, bool on, audio_io_handle_t output, int delayMs = 0);
+ virtual void setFmMode(fm_modes mode) { fmMode = mode; }
+ virtual fm_modes getFMMode() const { return fmMode; }
+ audio_io_handle_t mLPADecodeOutput; // active output handler
+ audio_io_handle_t mLPAActiveOuput; // LPA Output Handler during inactive state
+ bool mLPAMuted;
+ AudioSystem::stream_type mLPAStreamType;
+ AudioSystem::stream_type mLPAActiveStreamType;
+
+
+};
+};
View
240 msm7627a/HardwarePinSwitching.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <HardwarePinSwitching.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dlfcn.h>
+#include <fcntl.h>
+#include <linux/i2c.h>
+#include <linux/i2c-dev.h>
+
+#define LOG_TAG "BTFMPinSwitching"
+#include <utils/Log.h>
+//#define DEBUG_CHK 1
+
+#define BT_PCM_BCLK_MODE 0x88
+#define BT_PCM_DIN_MODE 0x89
+#define BT_PCM_DOUT_MODE 0x8A
+#define BT_PCM_SYNC_MODE 0x8B
+#define FM_I2S_SD_MODE 0x8E
+#define FM_I2S_WS_MODE 0x8F
+#define FM_I2S_SCK_MODE 0x90
+#define I2C_PIN_CTL 0x15
+#define I2C_NORMAL 0x40
+
+
+#define MARIMBA_ADDR (0x0C)
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a))
+
+#define LINE_LEN 80
+#define FM_DEVICE_PATH "/dev/i2c-1"
+
+
+/*==============================================================
+FUNCTION: do_rdwr
+==============================================================*/
+
+static int do_rdwr(int fd, struct i2c_msg *msgs, int nmsgs) {
+ struct i2c_rdwr_ioctl_data msgset;
+ msgset.msgs = msgs;
+ msgset.nmsgs = nmsgs;
+
+ if (NULL == msgs || nmsgs <= 0) {
+ return -1;
+ }
+
+ if (ioctl(fd, I2C_RDWR, &msgset) < 0) {
+ return -1;
+ }
+
+ return 0;
+}
+/*==============================================================
+FUNCTION: marimba_read
+=============================================================*/
+static int marimba_read(int fd, unsigned char offset, unsigned char* buf, int count)
+{
+
+ unsigned char offset_data[] = {offset};
+ struct i2c_msg msgs[2];
+ msgs[0].addr = MARIMBA_ADDR;
+ msgs[0].flags = 0;
+ msgs[0].buf = (__u8*)offset_data;
+ msgs[0].len = ARRAY_SIZE(offset_data);
+ msgs[1].addr = MARIMBA_ADDR;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].buf = (__u8*)buf;
+ msgs[1].len = count;
+
+ return do_rdwr(fd, msgs, ARRAY_SIZE(msgs));
+}
+/*==============================================================
+FUNCTION: marimba_write
+==============================================================*/
+/**
+* This function provides bus interface to write to the Marimba chip
+*
+* @return int - negative number on failure.
+*
+*/
+static int marimba_write
+(
+ int fd,
+ unsigned char offset,
+ const unsigned char* buf,
+ unsigned char len
+)
+{
+ unsigned char offset_data[((1 + len) * sizeof(unsigned char))];
+ struct i2c_msg msgs[1];
+ msgs[0].addr = MARIMBA_ADDR;
+ msgs[0].flags = 0;
+ msgs[0].buf = (__u8*)offset_data;
+ msgs[0].len = (1 + len) * sizeof(*offset_data);
+
+ if (NULL == offset_data) {
+ return -1;
+ }
+
+ offset_data[0] = offset;
+ memcpy(offset_data + 1, buf, len);
+
+ return do_rdwr(fd, msgs, ARRAY_SIZE(msgs));
+}
+
+/*==============================================================
+FUNCTION: switch_pins
+==============================================================*/
+/**
+* This function provides interface to change the mode of operation
+* from I2S mode to AUX PCM or vice versa. This function programs the
+* wcn2243 registers to TRISTATE or ON mode.
+*
+* @return int - negative number on failure.
+*
+*/
+static int switch_pins( int fd, int nPath )
+{
+ unsigned char value =0;
+ unsigned char reg =0;
+ int retval = -1;
+ unsigned char set = I2C_PIN_CTL; // SET PIN CTL mode
+ unsigned char unset = I2C_NORMAL; // UNSET PIN CTL MODE
+ if(nPath == MODE_FM ) {
+ // as we need to switch path to FM we need to move
+ // BT AUX PCM lines to PIN CONTROL mode then move
+ // FM to normal mode.
+ for( reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++ ) {
+#ifdef DEBUG_CHK
+ retval = marimba_read(fd, reg,&value, 1);
+ ALOGD("value read is:%d\n",value);
+#endif
+ retval = marimba_write(fd, reg, &set,1);
+ if (retval < 0) {
+ goto err_all;
+ }
+ }
+ for( reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++ ) {
+#ifdef DEBUG_CHK
+ retval = marimba_read(fd, reg,&value, 1);
+ ALOGD("value read is:%d\n",value);
+#endif
+ retval = marimba_write(fd, reg, &unset,1);
+ if (retval < 0) {
+ goto err_all;
+ }
+ }
+ } else {
+ // as we need to switch path to AUXPCM we need to move
+ // FM I2S lines to PIN CONTROL mode then move
+ // BT AUX_PCM to normal mode.
+ for( reg = FM_I2S_SD_MODE; reg <= FM_I2S_SCK_MODE; reg++ ) {
+#ifdef DEBUG_CHK
+ retval = marimba_read(fd, reg,&value, 1);
+ ALOGD("value read is:%d\n",value);
+#endif
+ retval = marimba_write(fd, reg, &set,1);
+ if (retval < 0) {
+ goto err_all;
+ }
+ }
+ for( reg = BT_PCM_BCLK_MODE; reg <= BT_PCM_SYNC_MODE; reg++ ) {
+#ifdef DEBUG_CHK
+ retval = marimba_read(fd, reg,&value, 1);
+ ALOGD("value read is:%d\n",value);
+#endif
+ retval = marimba_write(fd, reg, &unset,1);
+ if (retval < 0) {
+ goto err_all;
+ }
+ }
+ }
+ ALOGD("switch pin called with : %d\n",nPath);
+ return 0;
+
+err_all:
+ return retval;
+}
+
+/*==============================================================
+FUNCTION: switch_mode
+==============================================================*/
+/**
+* This function provides interface to change the mode of operation
+* from I2S mode to AUX PCM or vice versa. This function programs the
+* wcn2243 registers to TRISTATE or ON mode.
+*
+* @return int - negative number on failure.
+*
+*/
+extern int switch_mode( int nMode ) {
+ int i2cfd = -1, rc= -1 ;
+#ifdef REG_KERNEL_UPDATE
+ //media server doesnt have permissions to update
+ return 0;
+#endif
+#ifdef WITH_QCOM_FM
+ i2cfd = open(FM_DEVICE_PATH, O_RDWR);
+ if( i2cfd >= 0) {
+ rc = switch_pins(i2cfd, nMode);
+ close(i2cfd);
+ }
+ if( 0 != rc ) {
+ ALOGE("switch mode failed with error:%d",rc);
+ }
+#else
+ ALOGE("switch mode failed because QCOM_FM feature is not available");
+#endif
+ return rc;
+}
View
42 msm7627a/HardwarePinSwitching.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Code Aurora nor
+ * the names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior written
+ * permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ANDROID_HARDWARE_PIN_SWITCHING_H
+#define ANDROID_HARDWARE_PIN_SWITCHING_H
+
+
+
+#define MODE_FM 0
+#define MODE_BTSCO 1
+
+
+int switch_mode( int nMode );
+
+
+
+#endif // ANDROID_HARDWARE_PIN_SWITCHING_H
View
685 msm7627a/audio_hw_hal.cpp
@@ -0,0 +1,685 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (c) 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 "audio.primary.msm7627a"
+//#define LOG_NDEBUG 0
+
+#include <stdint.h>
+
+#include <hardware/hardware.h>
+#include <system/audio.h>
+#include <hardware/audio.h>
+
+#include <hardware_legacy/AudioHardwareInterface.h>
+#include <hardware_legacy/AudioSystemLegacy.h>
+
+namespace android_audio_legacy {
+
+extern "C" {
+
+struct qcom_audio_module {
+ struct audio_module module;
+};
+
+struct qcom_audio_device {
+ struct audio_hw_device device;
+
+ struct AudioHardwareInterface *hwif;
+};
+
+struct qcom_stream_out {
+ struct audio_stream_out stream;
+
+ AudioStreamOut *qcom_out;
+};
+
+struct qcom_stream_in {
+ struct audio_stream_in stream;
+
+ AudioStreamIn *qcom_in;
+};
+
+/** audio_stream_out implementation **/
+static uint32_t out_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->sampleRate();
+}
+
+static int out_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t out_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->bufferSize();
+}
+
+static audio_channel_mask_t out_get_channels(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->channels();
+}
+
+static audio_format_t out_get_format(const struct audio_stream *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return (audio_format_t)out->qcom_out->format();
+}
+
+static int out_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int out_standby(struct audio_stream *stream)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->standby();
+}
+
+static int out_dump(const struct audio_stream *stream, int fd)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ Vector<String16> args;
+ return out->qcom_out->dump(fd, args);
+}
+
+static int out_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->setParameters(String8(kvpairs));
+}
+
+static char * out_get_parameters(const struct audio_stream *stream, const char *keys)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ String8 s8;
+ s8 = out->qcom_out->getParameters(String8(keys));
+ return strdup(s8.string());
+}
+
+static uint32_t out_get_latency(const struct audio_stream_out *stream)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->latency();
+}
+
+static int out_set_volume(struct audio_stream_out *stream, float left,
+ float right)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->setVolume(left, right);
+}
+
+static ssize_t out_write(struct audio_stream_out *stream, const void* buffer,
+ size_t bytes)
+{
+ struct qcom_stream_out *out =
+ reinterpret_cast<struct qcom_stream_out *>(stream);
+ return out->qcom_out->write(buffer, bytes);
+}
+
+static int out_get_render_position(const struct audio_stream_out *stream,
+ uint32_t *dsp_frames)
+{
+ const struct qcom_stream_out *out =
+ reinterpret_cast<const struct qcom_stream_out *>(stream);
+ return out->qcom_out->getRenderPosition(dsp_frames);
+}
+
+static int out_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int out_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ return 0;
+}
+
+static int out_get_next_write_timestamp(const struct audio_stream_out *stream,
+ int64_t *timestamp)
+{
+ return -EINVAL;
+}
+
+/** audio_stream_in implementation **/
+static uint32_t in_get_sample_rate(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->sampleRate();
+}
+
+static int in_set_sample_rate(struct audio_stream *stream, uint32_t rate)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement this */
+ return 0;
+}
+
+static size_t in_get_buffer_size(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->bufferSize();
+}
+
+static audio_channel_mask_t in_get_channels(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->channels();
+}
+
+static audio_format_t in_get_format(const struct audio_stream *stream)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return (audio_format_t)in->qcom_in->format();
+}
+
+static int in_set_format(struct audio_stream *stream, audio_format_t format)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ ALOGE("(%s:%d) %s: Implement me!", __FILE__, __LINE__, __func__);
+ /* TODO: implement me */
+ return 0;
+}
+
+static int in_standby(struct audio_stream *stream)
+{
+ struct qcom_stream_in *in = reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->standby();
+}
+
+static int in_dump(const struct audio_stream *stream, int fd)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ Vector<String16> args;
+ return in->qcom_in->dump(fd, args);
+}
+
+static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->setParameters(String8(kvpairs));
+}
+
+static char * in_get_parameters(const struct audio_stream *stream,
+ const char *keys)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ String8 s8;
+ s8 = in->qcom_in->getParameters(String8(keys));
+ return strdup(s8.string());
+}
+
+static int in_set_gain(struct audio_stream_in *stream, float gain)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->setGain(gain);
+}
+
+static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
+ size_t bytes)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->read(buffer, bytes);
+}
+
+static uint32_t in_get_input_frames_lost(struct audio_stream_in *stream)
+{
+ struct qcom_stream_in *in =
+ reinterpret_cast<struct qcom_stream_in *>(stream);
+ return in->qcom_in->getInputFramesLost();
+}
+
+static int in_add_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->addAudioEffect(effect);
+}
+
+static int in_remove_audio_effect(const struct audio_stream *stream, effect_handle_t effect)
+{
+ const struct qcom_stream_in *in =
+ reinterpret_cast<const struct qcom_stream_in *>(stream);
+ return in->qcom_in->removeAudioEffect(effect);
+}
+
+/** audio_hw_device implementation **/
+static inline struct qcom_audio_device * to_ladev(struct audio_hw_device *dev)
+{
+ return reinterpret_cast<struct qcom_audio_device *>(dev);
+}
+
+static inline const struct qcom_audio_device * to_cladev(const struct audio_hw_device *dev)
+{
+ return reinterpret_cast<const struct qcom_audio_device *>(dev);
+}
+
+static uint32_t adev_get_supported_devices(const struct audio_hw_device *dev)
+{
+ /* XXX: The old AudioHardwareInterface interface is not smart enough to
+ * tell us this, so we'll lie and basically tell AF that we support the
+ * below input/output devices and cross our fingers. To do things properly,
+ * audio hardware interfaces that need advanced features (like this) should
+ * convert to the new HAL interface and not use this wrapper. */
+ return (/* OUT */
+ AUDIO_DEVICE_OUT_EARPIECE |
+ AUDIO_DEVICE_OUT_SPEAKER |
+ AUDIO_DEVICE_OUT_WIRED_HEADSET |
+ AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
+ AUDIO_DEVICE_OUT_AUX_DIGITAL |
+ AUDIO_DEVICE_OUT_ALL_SCO |
+ AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET |
+ AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET |
+#ifdef QCOM_FM_ENABLED
+// AUDIO_DEVICE_OUT_FM |
+#endif
+#ifdef QCOM_VOIP_ENABLED
+// AUDIO_DEVICE_OUT_DIRECTOUTPUT |
+#endif
+ AUDIO_DEVICE_OUT_DEFAULT |
+ /* IN */
+ AUDIO_DEVICE_IN_VOICE_CALL |