void AudioPolicyManager::setPhoneState(int state) { ALOGV("setPhoneState() state %d", state); audio_devices_t newDevice = AUDIO_DEVICE_NONE; if (state < 0 || state >= AudioSystem::NUM_MODES) { ALOGW("setPhoneState() invalid state %d", state); return; } if (state == mPhoneState) { ALOGW("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()) { ALOGV("setPhoneState() in call state management: new state is %d", state); for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { handleIncallSonification(stream, false, true); } } // store previous phone state for management of sonification strategy below int oldState = mPhoneState; mPhoneState = state; bool force = false; // are we entering or starting a call if (!isStateInCall(oldState) && isStateInCall(state)) { ALOGV(" 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)) { ALOGV(" 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)) { ALOGV(" 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(mPrimaryOutput, false /*fromCache*/); checkA2dpSuspend(); checkOutputForAllStrategies(); updateDevicesAndOutputs(); AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mPrimaryOutput); // force routing command to audio hardware when ending call // even if no device change is needed if (isStateInCall(oldState) && newDevice == AUDIO_DEVICE_NONE) { newDevice = hwOutputDesc->device(); } // 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, mPrimaryOutput); } if (isStateInCall(state)) { for (size_t i = 0; i < mOutputs.size(); i++) { AudioOutputDescriptor *desc = mOutputs.valueAt(i); //take the biggest latency for all outputs if (delayMs < desc->mLatency*2) { delayMs = desc->mLatency*2; } //mute STRATEGY_MEDIA on all outputs if (desc->strategyRefCount(STRATEGY_MEDIA) != 0) { setStrategyMute(STRATEGY_MEDIA, true, mOutputs.keyAt(i)); setStrategyMute(STRATEGY_MEDIA, false, mOutputs.keyAt(i), MUTE_TIME_MS, getDeviceForStrategy(STRATEGY_MEDIA, true /*fromCache*/)); } } } // Ignore the delay to enable voice call on this target as the enabling the // voice call has enough delay to make sure the ringtone audio completely // played out if (state == AudioSystem::MODE_IN_CALL && oldState == AudioSystem::MODE_RINGTONE) { delayMs = 40; } // change routing is necessary setOutputDevice(mPrimaryOutput, newDevice, force, delayMs); // if entering in call state, handle special case of active streams // pertaining to sonification strategy see handleIncallSonification() if (isStateInCall(state)) { ALOGV("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, mPrimaryOutput, MUTE_TIME_MS); } for (int stream = 0; stream < AudioSystem::NUM_STREAM_TYPES; stream++) { handleIncallSonification(stream, true, true); } } // Flag that ringtone volume must be limited to music volume until we exit MODE_RINGTONE if (state == AudioSystem::MODE_RINGTONE && isStreamActive(AudioSystem::MUSIC, SONIFICATION_HEADSET_MUSIC_DELAY)) { mLimitRingtoneVolume = true; } else { mLimitRingtoneVolume = false; } }
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 = 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 = 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; } #ifdef HAVE_FM_RADIO if (device == AudioSystem::DEVICE_OUT_FM) { AudioOutputDescriptor *out = mOutputs.valueFor(mHardwareOutput); if (state == AudioSystem::DEVICE_STATE_AVAILABLE) { out->changeRefCount(AudioSystem::FM, 1); if (out->mRefCount[AudioSystem::FM] > 0) mpClientInterface->setParameters(0, String8("fm_on=1")); } else { out->changeRefCount(AudioSystem::FM, -1); if (out->mRefCount[AudioSystem::FM] <= 0) mpClientInterface->setParameters(0, String8("fm_off=1")); } } #endif // request routing change if necessary uint32_t newDevice = getNewDevice(mHardwareOutput, false); #ifdef WITH_A2DP checkA2dpSuspend(); checkOutputForAllStrategies(); // A2DP outputs must be closed after checkOutputForAllStrategies() is executed if (state == AudioSystem::DEVICE_STATE_UNAVAILABLE && AudioSystem::isA2dpDevice(device)) { closeA2dpOutputs(); } #endif updateDeviceForStrategy(); 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); 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; }