| /* |
| * 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 |