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; }
audio_devices_t Engine::getDeviceForStrategy(routing_strategy strategy) const { const DeviceVector &availableOutputDevices = mApmObserver->getAvailableOutputDevices(); const DeviceVector &availableInputDevices = mApmObserver->getAvailableInputDevices(); const SwAudioOutputCollection &outputs = mApmObserver->getOutputs(); uint32_t device = AUDIO_DEVICE_NONE; uint32_t availableOutputDevicesType = availableOutputDevices.types(); switch (strategy) { case STRATEGY_TRANSMITTED_THROUGH_SPEAKER: device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; if (!device) { ALOGE("getDeviceForStrategy() no device found for "\ "STRATEGY_TRANSMITTED_THROUGH_SPEAKER"); } break; case STRATEGY_SONIFICATION_RESPECTFUL: if (isInCall()) { device = getDeviceForStrategy(STRATEGY_SONIFICATION); } else if (outputs.isStreamActiveRemotely(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { // while media is playing on a remote device, use the the sonification behavior. // Note that we test this usecase before testing if media is playing because // the isStreamActive() method only informs about the activity of a stream, not // if it's for local playback. Note also that we use the same delay between both tests device = getDeviceForStrategy(STRATEGY_SONIFICATION); //user "safe" speaker if available instead of normal speaker to avoid triggering //other acoustic safety mechanisms for notification if ((device & AUDIO_DEVICE_OUT_SPEAKER) && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) { device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE; device &= ~AUDIO_DEVICE_OUT_SPEAKER; } } else if (outputs.isStreamActive(AUDIO_STREAM_MUSIC, SONIFICATION_RESPECTFUL_AFTER_MUSIC_DELAY)) { // while media is playing (or has recently played), use the same device device = getDeviceForStrategy(STRATEGY_MEDIA); } else { // when media is not playing anymore, fall back on the sonification behavior device = getDeviceForStrategy(STRATEGY_SONIFICATION); //user "safe" speaker if available instead of normal speaker to avoid triggering //other acoustic safety mechanisms for notification if ((device & AUDIO_DEVICE_OUT_SPEAKER) && (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER_SAFE)) { device |= AUDIO_DEVICE_OUT_SPEAKER_SAFE; device &= ~AUDIO_DEVICE_OUT_SPEAKER; } } break; case STRATEGY_DTMF: if (!isInCall()) { // when off call, DTMF strategy follows the same rules as MEDIA strategy device = getDeviceForStrategy(STRATEGY_MEDIA); break; } // when in call, DTMF and PHONE strategies follow the same rules // FALL THROUGH case STRATEGY_PHONE: // Force use of only devices on primary output if: // - in call AND // - cannot route from voice call RX OR // - audio HAL version is < 3.0 and TX device is on the primary HW module if (getPhoneState() == AUDIO_MODE_IN_CALL) { audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION); sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput(); audio_devices_t availPrimaryInputDevices = availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle()); audio_devices_t availPrimaryOutputDevices = primaryOutput->supportedDevices() & availableOutputDevices.types(); if (((availableInputDevices.types() & AUDIO_DEVICE_IN_TELEPHONY_RX & ~AUDIO_DEVICE_BIT_IN) == 0) || (((txDevice & availPrimaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) && (primaryOutput->getAudioPort()->getModuleVersion() < AUDIO_DEVICE_API_VERSION_3_0))) { availableOutputDevicesType = availPrimaryOutputDevices; } } // for phone strategy, we first consider the forced use and then the available devices by order // of priority switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) { case AUDIO_POLICY_FORCE_BT_SCO: if (!isInCall() || strategy != STRATEGY_DTMF) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT; if (device) break; } device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET; if (device) break; device = availableOutputDevicesType & AUDIO_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 // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && (outputs.getA2dpOutput() != 0)) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; if (device) break; } device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE; if (device) break; if (!isInCall()) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; if (device) break; } device = availableOutputDevicesType & AUDIO_DEVICE_OUT_EARPIECE; if (device) break; device = mApmObserver->getDefaultOutputDevice()->type(); if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE"); } break; case AUDIO_POLICY_FORCE_SPEAKER: // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to // A2DP speaker when forcing to speaker output if (!isInCall() && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && (outputs.getA2dpOutput() != 0)) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; if (device) break; } if (!isInCall()) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; if (device) break; } device = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE; if (device) break; device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; if (device) break; device = mApmObserver->getDefaultOutputDevice()->type(); if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_PHONE, FORCE_SPEAKER"); } break; } 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); 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 // - in countries where not enforced in which case it follows STRATEGY_MEDIA if ((strategy == STRATEGY_SONIFICATION) || (mForceUse[AUDIO_POLICY_FORCE_FOR_SYSTEM] == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED)) { device = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() speaker device not found for STRATEGY_SONIFICATION"); } } // The second device used for sonification is the same as the device used by media strategy // FALL THROUGH // FIXME: STRATEGY_ACCESSIBILITY and STRATEGY_REROUTING follow STRATEGY_MEDIA for now case STRATEGY_ACCESSIBILITY: if (strategy == STRATEGY_ACCESSIBILITY) { // do not route accessibility prompts to a digital output currently configured with a // compressed format as they would likely not be mixed and dropped. for (size_t i = 0; i < outputs.size(); i++) { sp<AudioOutputDescriptor> desc = outputs.valueAt(i); audio_devices_t devices = desc->device() & (AUDIO_DEVICE_OUT_HDMI | AUDIO_DEVICE_OUT_SPDIF | AUDIO_DEVICE_OUT_HDMI_ARC); if (desc->isActive() && !audio_is_linear_pcm(desc->mFormat) && devices != AUDIO_DEVICE_NONE) { availableOutputDevicesType = availableOutputDevices.types() & ~devices; } } } // FALL THROUGH case STRATEGY_REROUTING: case STRATEGY_MEDIA: { uint32_t device2 = AUDIO_DEVICE_NONE; if (strategy != STRATEGY_SONIFICATION) { // no sonification on remote submix (e.g. WFD) if (availableOutputDevices.getDevice(AUDIO_DEVICE_OUT_REMOTE_SUBMIX, String8("0")) != 0) { device2 = availableOutputDevices.types() & AUDIO_DEVICE_OUT_REMOTE_SUBMIX; } } if (isInCall() && (strategy == STRATEGY_MEDIA)) { device = getDeviceForStrategy(STRATEGY_PHONE); break; } if ((device2 == AUDIO_DEVICE_NONE) && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] != AUDIO_POLICY_FORCE_NO_BT_A2DP) && (outputs.getA2dpOutput() != 0)) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP; if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER; } } if ((device2 == AUDIO_DEVICE_NONE) && (mForceUse[AUDIO_POLICY_FORCE_FOR_MEDIA] == AUDIO_POLICY_FORCE_SPEAKER)) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_LINE; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_WIRED_HEADSET; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_ACCESSORY; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_USB_DEVICE; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET; } if ((device2 == AUDIO_DEVICE_NONE) && (strategy != STRATEGY_SONIFICATION)) { // no sonification on aux digital (e.g. HDMI) device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_DIGITAL; } if ((device2 == AUDIO_DEVICE_NONE) && (mForceUse[AUDIO_POLICY_FORCE_FOR_DOCK] == AUDIO_POLICY_FORCE_ANALOG_DOCK)) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET; } if (device2 == AUDIO_DEVICE_NONE) { device2 = availableOutputDevicesType & AUDIO_DEVICE_OUT_SPEAKER; } int device3 = AUDIO_DEVICE_NONE; if (strategy == STRATEGY_MEDIA) { // ARC, SPDIF and AUX_LINE can co-exist with others. device3 = availableOutputDevicesType & AUDIO_DEVICE_OUT_HDMI_ARC; device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_SPDIF); device3 |= (availableOutputDevicesType & AUDIO_DEVICE_OUT_AUX_LINE); } device2 |= device3; // device is DEVICE_OUT_SPEAKER if we come from case STRATEGY_SONIFICATION or // STRATEGY_ENFORCED_AUDIBLE, AUDIO_DEVICE_NONE otherwise device |= device2; // If hdmi system audio mode is on, remove speaker out of output list. if ((strategy == STRATEGY_MEDIA) && (mForceUse[AUDIO_POLICY_FORCE_FOR_HDMI_SYSTEM_AUDIO] == AUDIO_POLICY_FORCE_HDMI_SYSTEM_AUDIO_ENFORCED)) { device &= ~AUDIO_DEVICE_OUT_SPEAKER; } if (device) break; device = mApmObserver->getDefaultOutputDevice()->type(); if (device == AUDIO_DEVICE_NONE) { ALOGE("getDeviceForStrategy() no device found for STRATEGY_MEDIA"); } } break; default: ALOGW("getDeviceForStrategy() unknown strategy: %d", strategy); break; } ALOGVV("getDeviceForStrategy() strategy %d, device %x", strategy, device); return device; }
status_t AudioPolicyManagerALSA::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); #ifdef WITH_A2DP if (mA2dpOutput != 0 && mPhoneState != AudioSystem::MODE_NORMAL) { mpClientInterface->suspendOutput(mA2dpOutput); } #endif } } break; // handle output device disconnection case AudioSystem::DEVICE_STATE_UNAVAILABLE: { if (!(mAvailableOutputDevices & device)) { LOGW("setDeviceConnectionState() device not connected: %x", device); return INVALID_OPERATION; } LOGV("setDeviceConnectionState() disconnecting device %x", device); // remove device from available output devices mAvailableOutputDevices &= ~device; #ifdef WITH_A2DP // handle A2DP device disconnection if (AudioSystem::isA2dpDevice(device)) { status_t status = handleA2dpDisconnection(device, device_address); if (status != NO_ERROR) { mAvailableOutputDevices |= device; return status; } } else #endif { if (AudioSystem::isBluetoothScoDevice(device)) { mScoDeviceAddress = ""; #ifdef WITH_A2DP if (mA2dpOutput != 0 && mPhoneState != AudioSystem::MODE_NORMAL) { mpClientInterface->restoreOutput(mA2dpOutput); } #endif } } } break; default: LOGE("setDeviceConnectionState() invalid state: %x", state); return BAD_VALUE; } // request routing change if necessary uint32_t newDevice = getNewDevice(mHardwareOutput, false); // force routing if device disconnection occurs when stream is stopped if ((newDevice == 0) && (state == AudioSystem::DEVICE_STATE_UNAVAILABLE)) newDevice = getDeviceForStrategy(STRATEGY_MEDIA, false); #ifdef WITH_A2DP //+++ KBNAM_PORTING /* org checkOutputForAllStrategies(newDevice); */ 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()); } } else { /* LGE_CHANGE_S [email protected] 2010.01.27 */ #ifdef SUPPORT_FM_ANALOG if (device == AudioSystem::DEVICE_IN_FM_ANALOG) { routing_strategy strategy = getStrategy((AudioSystem::stream_type)3); uint32_t curOutdevice = getDeviceForStrategy(strategy); /* If A2DP headset is connected then route FM to Headset */ if (curOutdevice == AudioSystem::DEVICE_OUT_BLUETOOTH_A2DP || curOutdevice == AudioSystem::DEVICE_OUT_BLUETOOTH_SCO) { curOutdevice = AudioSystem::DEVICE_OUT_WIRED_HEADSET; } if (state) { // routing_strategy strategy = getStrategy((AudioSystem::stream_type)3); // uint32_t curOutdevice = getDeviceForStrategy(strategy); /* Get the new input descriptor for FM Rx In */ mfmInput = getFMInput(AUDIO_SOURCE_FM_ANALOG,8000,1, AudioSystem::CHANNEL_IN_MONO,(AudioSystem::audio_in_acoustics)7); /* Forcely open the current output device again for * FM Rx playback path to open */ LOGV("curOutdevice = %x",curOutdevice); setOutputDevice(mHardwareOutput, curOutdevice, true); /* Tell the audio flinger playback thread that * FM Rx is active */ mpClientInterface->setFMRxActive(true); } else { int newDevice=0; AudioParameter param = AudioParameter(); param.addInt(String8(AudioParameter::keyRouting), (int)newDevice); /* Change the input device from FM to default before releasing Input */ mpClientInterface->setParameters(mfmInput, param.toString()); param.addInt(String8("fm_off"), (int)newDevice); /* Close the capture handle */ mpClientInterface->setParameters(mfmInput, param.toString()); /* Release the input descriptor for FM Rx In */ releaseInput(mfmInput); /* Close the playback handle */ mpClientInterface->setParameters(mHardwareOutput, param.toString()); /* Tell the audio flinger playback thread that * FM Rx is not active now. */ mpClientInterface->setFMRxActive(false); } } #endif // SUPPORT_FM_ANALOG /* LGE_CHANGE_E [email protected] 2010.01.27 */ } return NO_ERROR; } LOGW("setDeviceConnectionState() invalid device: %x", device); return BAD_VALUE; }