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/AudioPolicyManagerALSA.cpp b/alsa_sound/AudioPolicyManagerALSA.cpp
new file mode 100644
index 0000000..2a8e528
--- /dev/null
+++ b/alsa_sound/AudioPolicyManagerALSA.cpp
@@ -0,0 +1,1142 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#define LOG_TAG "AudioPolicyManagerALSA"
+//#define LOG_NDEBUG 0
+#define LOG_NDDEBUG 0
+#include <utils/Log.h>
+#include "AudioPolicyManagerALSA.h"
+#include <media/mediarecorder.h>
+
+namespace android_audio_legacy {
+
+// ----------------------------------------------------------------------------
+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 (!isInCall()) {
+ // 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 (!isInCall() || 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_PROXY;
+ if (device) break;
+#ifdef WITH_A2DP
+ // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP
+ if (!isInCall()) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES;
+ if (device) break;
+ }
+#endif
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_WIRED_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_EARPIECE;
+ if (device == 0) {
+ LOGE("getDeviceForStrategy() earpiece device not found");
+ }
+ break;
+
+ case AudioSystem::FORCE_SPEAKER:
+ if (!isInCall() || 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 (!isInCall()) {
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER;
+ if (device) break;
+ }
+#endif
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_DGTL_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ if (device) break;
+ device = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_SPEAKER;
+ if (device == 0) {
+ LOGE("getDeviceForStrategy() speaker device not found");
+ }
+ break;
+ }
+#ifdef FM_ENABLED
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) {
+ device |= AudioSystem::DEVICE_OUT_FM;
+ if (mForceUse[AudioSystem::FOR_MEDIA] == AudioSystem::FORCE_SPEAKER) {
+ device &= ~(AudioSystem::DEVICE_OUT_WIRED_HEADSET);
+ device &= ~(AudioSystem::DEVICE_OUT_WIRED_HEADPHONE);
+ device |= AudioSystem::DEVICE_OUT_SPEAKER;
+ }
+ }
+#endif
+ break;
+
+ case STRATEGY_SONIFICATION:
+
+ // If incall, just select the STRATEGY_PHONE device: The rest of the behavior is handled by
+ // handleIncallSonification().
+ if (isInCall()) {
+ device = getDeviceForStrategy(STRATEGY_PHONE, false);
+ 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
+
+ case STRATEGY_MEDIA: {
+ //To route FM stream to speaker when headset is connected, a new switch case is added.
+ //case AudioSystem::FORCE_SPEAKER for STRATEGY_MEDIA will come only when we need to route
+ //FM stream to speaker.
+ switch (mForceUse[AudioSystem::FOR_MEDIA]) {
+ default:{
+ uint32_t device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_PROXY;
+ if(device2 != 0) {
+ // No combo device allowed with proxy device
+ device = 0;
+ }
+ #ifdef WITH_A2DP
+ if (mA2dpOutput != 0) {
+ 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_DGTL_DOCK_HEADSET;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_AUX_DIGITAL;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET;
+ }
+ 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_ANC_HEADPHONE;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET;
+ }
+ if (device2 == 0) {
+ device2 = mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM_TX;
+ }
+ 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;
+ }
+#ifdef FM_ENABLED
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_FM) {
+ device |= AudioSystem::DEVICE_OUT_FM;
+ }
+#endif
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+ device |= AudioSystem::DEVICE_OUT_ANC_HEADSET;
+ }
+ if (mAvailableOutputDevices & AudioSystem::DEVICE_OUT_ANC_HEADPHONE) {
+ device |= AudioSystem::DEVICE_OUT_ANC_HEADPHONE;
+ }
+ // 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 (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 = AudioPolicyManagerBase::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);
+ }
+ }
+ break;
+ // handle output device disconnection
+ case AudioSystem::DEVICE_STATE_UNAVAILABLE: {
+ 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 = AudioPolicyManagerBase::handleA2dpDisconnection(device, device_address);
+ if (status != NO_ERROR) {
+ mAvailableOutputDevices |= device;
+ return status;
+ }
+ } else
+#endif
+ {
+ if (AudioSystem::isBluetoothScoDevice(device)) {
+ mScoDeviceAddress = "";
+ }
+ }
+ } break;
+
+ default:
+ LOGE("setDeviceConnectionState() invalid state: %x", state);
+ return BAD_VALUE;
+ }
+
+ // request routing change if necessary
+ uint32_t newDevice = AudioPolicyManagerBase::getNewDevice(mHardwareOutput, false);
+
+ if(newDevice == 0 && mLPADecodeOutput != -1) {
+ newDevice = AudioPolicyManagerBase::getNewDevice(mLPADecodeOutput, false);
+ }
+#ifdef FM_ENABLED
+ 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);
+ }
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyHandleFm), (int)newDevice);
+ mpClientInterface->setParameters(mHardwareOutput, param.toString());
+ }
+#endif
+ if(device == AudioSystem::DEVICE_OUT_ANC_HEADPHONE ||
+ device == AudioSystem::DEVICE_OUT_ANC_HEADSET) {
+ if(newDevice == 0){
+ newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ }
+ }
+#ifdef WITH_A2DP
+ AudioPolicyManagerBase::checkA2dpSuspend();
+ AudioPolicyManagerBase::checkOutputForAllStrategies();
+ // A2DP outputs must be closed after checkOutputForAllStrategies() is executed
+ if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) {
+ AudioPolicyManagerBase::closeA2dpOutputs();
+ }
+#endif
+ AudioPolicyManagerBase::updateDeviceForStrategy();
+
+ int delayMs = 0;
+ if (AudioSystem::DEVICE_OUT_SPEAKER == newDevice
+ && AudioSystem::DEVICE_OUT_WIRED_HEADSET == device) {
+ //Add some delay(192ms) while switching from wired headset to speaker before pause
+ //music keeps playing from speaker if there's not delay or delay is too small.
+ delayMs = mOutputs.valueFor(mHardwareOutput)->mLatency*8;
+ }
+
+ if(mLPADecodeOutput != -1)
+ setOutputDevice(mLPADecodeOutput, newDevice, false, delayMs);
+ setOutputDevice(mHardwareOutput, newDevice, false, delayMs);
+
+ 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 if(device == AudioSystem::DEVICE_OUT_ANLG_DOCK_HEADSET){
+ device = AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET;
+ } else if(device == AudioSystem::DEVICE_OUT_ANC_HEADSET){
+ device = AudioSystem::DEVICE_IN_ANC_HEADSET; //wait for actual ANC device
+ } 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 = AudioPolicyManagerBase::getActiveInput();
+ if (activeInput != 0) {
+ AudioInputDescriptor *inputDesc = mInputs.valueFor(activeInput);
+ uint32_t newDevice = AudioPolicyManagerBase::getDeviceForInputSource(inputDesc->mInputSource);
+ if (newDevice != inputDesc->mDevice) {
+ 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);
+ mpClientInterface->setParameters(activeInput, param.toString());
+ }
+ }
+
+ return NO_ERROR;
+ }
+
+ LOGW("setDeviceConnectionState() invalid device: %x", device);
+ return BAD_VALUE;
+}
+
+
+void AudioPolicyManager::setPhoneState(int state)
+{
+ LOGD("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) && (state == AudioSystem::MODE_NORMAL)) {
+ 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 = AudioPolicyManagerBase::getNewDevice(mHardwareOutput, false);
+ if (newDevice == 0 && (mLPADecodeOutput != -1 &&
+ mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false);
+ }
+
+#ifdef WITH_A2DP
+ AudioPolicyManagerBase::checkA2dpSuspend();
+ AudioPolicyManagerBase::checkOutputForAllStrategies();
+#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();
+ if(state == AudioSystem::MODE_NORMAL) {
+ 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() - hwOutputDesc->mStopTime[AudioSystem::MUSIC]) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) {
+ // (systemTime() - mMusicStopTime) < seconds(SONIFICATION_HEADSET_MUSIC_DELAY))) {
+ mLimitRingtoneVolume = true;
+ } else {
+ mLimitRingtoneVolume = false;
+ }
+}
+
+#ifdef TUNNEL_LPA_ENABLED
+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) ) {
+ AudioPolicyManager::stopOutput(output, 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;
+ AudioPolicyManager::startOutput(mLPADecodeOutput, mLPAStreamType);
+
+ // Set Volume if the music stream volume is changed in the Pause state of LPA Jagan
+ mLPAActiveOuput = -1;
+ mLPAActiveStreamType = AudioSystem::DEFAULT;
+ }
+}
+
+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;
+}
+#endif
+
+status_t AudioPolicyManager::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session)
+{
+ LOGV("startOutput() output %d, stream %d", output, stream);
+ 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);
+#ifdef FM_ENABLED
+ if(stream == AudioSystem::FM && output == mA2dpOutput) {
+ setOutputDevice(output, AudioPolicyManagerBase::getNewDevice(output), true);
+ } else
+#endif
+#ifdef TUNNEL_LPA_ENABLED
+ if (output != mLPADecodeOutput) {
+ setOutputDevice(output, AudioPolicyManagerBase::getNewDevice(output));
+ } else
+#endif
+ {
+ 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::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream, int session)
+{
+ LOGV("stopOutput() output %d, stream %d", output, stream);
+ 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 (stream == AudioSystem::MUSIC) {
+ outputDesc->mStopTime[stream] = systemTime();
+ // mMusicStopTime = systemTime();
+ }
+
+ uint32_t newDevice = AudioPolicyManagerBase::getNewDevice(mHardwareOutput, false);
+
+ if(newDevice == 0 && mLPADecodeOutput != -1) {
+ newDevice = AudioPolicyManagerBase::getNewDevice(mLPADecodeOutput, false);
+ }
+
+ 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;
+ }
+}
+// ----------------------------------------------------------------------------
+// AudioPolicyManagerALSA
+// ----------------------------------------------------------------------------
+
+// --- class factory
+
+extern "C" AudioPolicyInterface* createAudioPolicyManager(AudioPolicyClientInterface *clientInterface)
+{
+ return new AudioPolicyManager(clientInterface);
+}
+
+extern "C" void destroyAudioPolicyManager(AudioPolicyInterface *interface)
+{
+ delete interface;
+}
+
+// ---
+
+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_ANC_HEADSET)
+ || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_ANC_HEADPHONE)
+ || 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_HEADPHONE | AudioSystem::DEVICE_OUT_FM)
+ || device == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_FM_TX)) {
+ setStrategyMute(STRATEGY_MEDIA, true, output);
+ // 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);
+ }
+ // Mute hardware output also if it belongs to STRATEGY_MEDIA
+ 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);
+ }
+
+ // wait for output buffers to be played on the HDMI device before routing to new device
+ if(prevDevice == AudioSystem::DEVICE_OUT_AUX_DIGITAL) {
+ if((mLPADecodeOutput != -1 && output == mLPADecodeOutput &&
+ mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ checkAndSetVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, mLPADecodeOutput, device, delayMs, force);
+ usleep(150*1000);
+ } else {
+ checkAndSetVolume(AudioSystem::MUSIC, mStreams[AudioSystem::MUSIC].mIndexCur, output, device, delayMs, force);
+ usleep(outputDesc->mLatency*6*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
+ AudioPolicyManagerBase::applyStreamVolumes(output, device, delayMs);
+ if((mLPADecodeOutput != -1 &&
+ mOutputs.valueFor(mLPADecodeOutput)->isUsedByStrategy(STRATEGY_MEDIA))) {
+ AudioPolicyManagerBase::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_ANC_HEADSET)
+ || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_ANC_HEADPHONE)
+ || 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_HEADPHONE | AudioSystem::DEVICE_OUT_FM)
+ || prevDevice == (AudioSystem::DEVICE_OUT_SPEAKER | AudioSystem::DEVICE_OUT_FM_TX)) {
+ setStrategyMute(STRATEGY_MEDIA, false, output, delayMs);
+ // 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);
+ }
+ // Unmute hardware output also if it belongs to STRATEGY_MEDIA
+ 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);
+ // do not set volume if the float value did not change
+ if ((volume != mOutputs.valueFor(output)->mCurVolume[stream]) || (stream == AudioSystem::VOICE_CALL) ||
+#ifdef FM_ENABLED
+ (stream == AudioSystem::FM) ||
+#endif
+ force) {
+ mOutputs.valueFor(output)->mCurVolume[stream] = volume;
+ LOGD("setStreamVolume() for output %d stream %d, volume %f, delay %d", output, stream, volume, delayMs);
+ if (stream == AudioSystem::VOICE_CALL ||
+ stream == AudioSystem::DTMF ||
+ stream == AudioSystem::BLUETOOTH_SCO) {
+ float voiceVolume = -1.0;
+ // 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;
+ if (stream == AudioSystem::VOICE_CALL) {
+ voiceVolume = (float)index/(float)mStreams[stream].mIndexMax;
+ } else if (stream == AudioSystem::BLUETOOTH_SCO) {
+ String8 key ("bt_headset_vgs");
+ mpClientInterface->getParameters(output,key);
+ AudioParameter result(mpClientInterface->getParameters(0,key));
+ int value;
+ if(result.getInt(String8("isVGS"),value) == NO_ERROR){
+ 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) {
+ mpClientInterface->setVoiceVolume(voiceVolume, delayMs);
+ }
+ }
+#ifdef FM_ENABLED
+ else if (stream == AudioSystem::FM) {
+ float fmVolume = -1.0;
+ fmVolume = computeVolume(stream, index, output, device);
+ if (fmVolume >= 0) {
+ if(output == mHardwareOutput)
+ mpClientInterface->setFmVolume(fmVolume, delayMs);
+ else if(output == mA2dpOutput)
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, delayMs);
+ }
+ return NO_ERROR;
+ }
+#endif
+ mpClientInterface->setStreamVolume((AudioSystem::stream_type)stream, volume, output, 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);
+ }
+ }
+ }
+}
+
+void AudioPolicyManager::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config)
+{
+ LOGD("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
+ AudioPolicyManagerBase::checkA2dpSuspend();
+ checkOutputForAllStrategies();
+#endif
+ updateDeviceForStrategy();
+ setOutputDevice(mHardwareOutput, newDevice);
+ if (forceVolumeReeval) {
+ applyStreamVolumes(mHardwareOutput, newDevice);
+ }
+}
+
+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 if (mAvailableInputDevices & AudioSystem::DEVICE_IN_ANC_HEADSET) {
+ device = AudioSystem::DEVICE_IN_ANC_HEADSET;
+ } else if (mAvailableInputDevices & AudioSystem::DEVICE_IN_ANLG_DOCK_HEADSET) {
+ device = AudioSystem::DEVICE_IN_PROXY;
+ } 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;
+}
+
+/*
+Overwriting this function from base class to allow 2 acitve AudioRecord clients in case of FM.
+One for FM A2DP playbck and other for FM recording.
+*/
+status_t AudioPolicyManager::startInput(audio_io_handle_t input)
+{
+ LOGV("startInput() input %d", input);
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ LOGW("startInput() unknow input %d", input);
+ return BAD_VALUE;
+ }
+ AudioInputDescriptor *inputDesc = mInputs.valueAt(index);
+ AudioParameter param = AudioParameter();
+ param.addInt(String8(AudioParameter::keyRouting), (int)inputDesc->mDevice);
+ // use Voice Recognition mode or not for this input based on input source
+ int vr_enabled = inputDesc->mInputSource == AUDIO_SOURCE_VOICE_RECOGNITION ? 1 : 0;
+ param.addInt(String8("vr_mode"), vr_enabled);
+ LOGV("AudioPolicyManager::startInput(%d), setting vr_mode to %d", inputDesc->mInputSource, vr_enabled);
+ mpClientInterface->setParameters(input, param.toString());
+ inputDesc->mRefCount = 1;
+ return NO_ERROR;
+}
+
+}; // namespace androidi_audio_legacy