Loading services/audiopolicy/enginedefault/src/Engine.cpp +81 −109 Original line number Diff line number Diff line Loading @@ -184,16 +184,7 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy, break; case STRATEGY_DTMF: if (!isInCall()) { // when off call, DTMF strategy follows the same rules as MEDIA strategy devices = getDevicesForStrategyInt( STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs); break; } // when in call, DTMF and PHONE strategies follow the same rules FALLTHROUGH_INTENDED; case STRATEGY_PHONE: case STRATEGY_PHONE: { // Force use of only devices on primary output if: // - in call AND // - cannot route from voice call RX OR Loading Loading @@ -223,77 +214,17 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy, availableOutputDevices = availPrimaryOutputDevices; } } // for phone strategy, we first consider the forced use and then the available devices by // order of priority switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) { case AUDIO_POLICY_FORCE_BT_SCO: if (!isInCall() || strategy != STRATEGY_DTMF) { devices = availableOutputDevices.getDevicesFromType( AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO}); if (!devices.isEmpty()) break; // if SCO device is requested but no SCO device is available, fall back to default case FALLTHROUGH_INTENDED; default: // FORCE_NONE devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID); if (!devices.isEmpty()) break; // TODO (b/161358428): remove when preferred device // for strategy phone will be used instead of AUDIO_POLICY_FORCE_FOR_COMMUNICATION devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_BLE_HEADSET); if (!devices.isEmpty()) break; // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP if (!isInCall() && (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) { devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_USB_DEVICE}); if (!devices.isEmpty()) break; if (!isInCall()) { devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET}); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE); 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()) { devices = availableOutputDevices.getDevicesFromType( AUDIO_DEVICE_OUT_BLE_SPEAKER); if (!devices.isEmpty()) break; if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) { devices = availableOutputDevices.getDevicesFromType( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); if (!devices.isEmpty()) break; } } if (!isInCall()) { devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET}); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER); break; } break; } break; case STRATEGY_SONIFICATION: Loading Loading @@ -336,7 +267,8 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy, } } // Use both Bluetooth SCO and phone default output when ringing in normal mode if (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) { if (audio_is_bluetooth_out_sco_device(getPreferredDeviceTypeForLegacyStrategy( availableOutputDevices, STRATEGY_PHONE))) { if (strategy == STRATEGY_SONIFICATION) { devices.replaceDevicesByType( AUDIO_DEVICE_OUT_SPEAKER, Loading Loading @@ -506,13 +438,16 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) } } audio_devices_t commDeviceType = getPreferredDeviceTypeForLegacyStrategy(availableOutputDevices, STRATEGY_PHONE); switch (inputSource) { case AUDIO_SOURCE_DEFAULT: case AUDIO_SOURCE_MIC: device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_A2DP, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) break; if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) { if (audio_is_bluetooth_out_sco_device(commDeviceType)) { device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) break; Loading @@ -533,30 +468,29 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) availableDevices = availablePrimaryDevices; } switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) { case AUDIO_POLICY_FORCE_BT_SCO: if (audio_is_bluetooth_out_sco_device(commDeviceType)) { // if SCO device is requested but no SCO device is available, fall back to default case device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) { break; } FALLTHROUGH_INTENDED; default: // FORCE_NONE // TODO (b/161358428): remove AUDIO_DEVICE_IN_BLE_HEADSET from the list // when preferred device for strategy phone will be used instead of // AUDIO_POLICY_FORCE_FOR_COMMUNICATION. device = availableDevices.getFirstExistingDevice({ AUDIO_DEVICE_IN_BLE_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC}); } switch (commDeviceType) { case AUDIO_DEVICE_OUT_BLE_HEADSET: device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); break; case AUDIO_POLICY_FORCE_SPEAKER: case AUDIO_DEVICE_OUT_SPEAKER: device = availableDevices.getFirstExistingDevice({ AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC}); break; default: // FORCE_NONE device = availableDevices.getFirstExistingDevice({ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC}); break; } break; Loading @@ -569,7 +503,7 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found"); availableDevices = availablePrimaryDevices; } if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) { if (audio_is_bluetooth_out_sco_device(commDeviceType)) { device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) break; Loading Loading @@ -619,6 +553,7 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) ALOGE_IF(device == nullptr, "getDeviceForInputSource() no default device defined"); } ALOGV_IF(device != nullptr, "getDeviceForInputSource()input source %d, device %08x", inputSource, device->type()); Loading @@ -636,17 +571,35 @@ void Engine::updateDeviceSelectionCache() } } DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const { DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); product_strategy_t Engine::getProductStrategyFromLegacy(legacy_strategy legacyStrategy) const { for (const auto& strategyMap : mLegacyStrategyMap) { if (strategyMap.second == legacyStrategy) { return strategyMap.first; } } return PRODUCT_STRATEGY_NONE; } // check if this strategy has a preferred device that is available, // if yes, give priority to it audio_devices_t Engine::getPreferredDeviceTypeForLegacyStrategy( const DeviceVector& availableOutputDevices, legacy_strategy legacyStrategy) const { product_strategy_t strategy = getProductStrategyFromLegacy(legacyStrategy); DeviceVector devices = getPreferredAvailableDevicesForProductStrategy( availableOutputDevices, strategy); if (devices.size() > 0) { return devices[0]->type(); } return AUDIO_DEVICE_NONE; } DeviceVector Engine::getPreferredAvailableDevicesForProductStrategy( const DeviceVector& availableOutputDevices, product_strategy_t strategy) const { DeviceVector preferredAvailableDevVec = {}; AudioDeviceTypeAddrVector preferredStrategyDevices; const status_t status = getDevicesForRoleAndStrategy( strategy, DEVICE_ROLE_PREFERRED, preferredStrategyDevices); if (status == NO_ERROR) { // there is a preferred device, is it available? DeviceVector preferredAvailableDevVec = preferredAvailableDevVec = availableOutputDevices.getDevicesFromDeviceTypeAddrVec(preferredStrategyDevices); if (preferredAvailableDevVec.size() == preferredAvailableDevVec.size()) { ALOGVV("%s using pref device %s for strategy %u", Loading @@ -654,11 +607,30 @@ DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) c return preferredAvailableDevVec; } } return preferredAvailableDevVec; } DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices(); const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs(); DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const { DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ? mLegacyStrategyMap.at(strategy) : STRATEGY_NONE; // When not in call, STRATEGY_PHONE and STRATEGY_DTMF follow STRATEGY_MEDIA if (!isInCall() && (legacyStrategy == STRATEGY_PHONE || legacyStrategy == STRATEGY_DTMF)) { legacyStrategy = STRATEGY_MEDIA; strategy = getProductStrategyFromLegacy(STRATEGY_MEDIA); } // check if this strategy has a preferred device that is available, // if yes, give priority to it. DeviceVector preferredAvailableDevVec = getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, strategy); if (!preferredAvailableDevVec.isEmpty()) { return preferredAvailableDevVec; } DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices(); const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs(); return getDevicesForStrategyInt(legacyStrategy, availableOutputDevices, availableInputDevices, outputs); Loading services/audiopolicy/enginedefault/src/Engine.h +6 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,12 @@ private: sp<DeviceDescriptor> getDeviceForInputSource(audio_source_t inputSource) const; product_strategy_t getProductStrategyFromLegacy(legacy_strategy legacyStrategy) const; audio_devices_t getPreferredDeviceTypeForLegacyStrategy( const DeviceVector& availableOutputDevices, legacy_strategy legacyStrategy) const; DeviceVector getPreferredAvailableDevicesForProductStrategy( const DeviceVector& availableOutputDevices, product_strategy_t strategy) const; DeviceStrategyMap mDevicesForStrategies; std::map<product_strategy_t, legacy_strategy> mLegacyStrategyMap; Loading services/audiopolicy/managerdefault/AudioPolicyManager.cpp +70 −30 Original line number Diff line number Diff line Loading @@ -790,16 +790,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, } updateCallAndOutputRouting(forceVolumeReeval, delayMs); for (const auto& activeDesc : mInputs.getActiveInputs()) { auto newDevice = getNewInputDevice(activeDesc); // Force new input selection if the new device can not be reached via current input if (activeDesc->mProfile->getSupportedDevices().contains(newDevice)) { setInputDevice(activeDesc->mIoHandle, newDevice); } else { closeInput(activeDesc->mIoHandle); } } updateInputRouting(); } void AudioPolicyManager::setSystemProperty(const char* property, const char* value) Loading Loading @@ -3145,6 +3136,7 @@ status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) { return res; } status_t AudioPolicyManager::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role, const AudioDeviceTypeAddrVector &devices) { Loading @@ -3162,7 +3154,17 @@ status_t AudioPolicyManager::setDevicesRoleForStrategy(product_strategy_t strate } checkForDeviceAndOutputChanges(); updateCallAndOutputRouting(); bool forceVolumeReeval = false; // FIXME: workaround for truncated touch sounds // to be removed when the problem is handled by system UI uint32_t delayMs = 0; if (strategy == mCommunnicationStrategy) { forceVolumeReeval = true; delayMs = TOUCH_SOUND_FIXED_DELAY_MS; updateInputRouting(); } updateCallAndOutputRouting(forceVolumeReeval, delayMs); return NO_ERROR; } Loading Loading @@ -3193,6 +3195,18 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint } } void AudioPolicyManager::updateInputRouting() { for (const auto& activeDesc : mInputs.getActiveInputs()) { auto newDevice = getNewInputDevice(activeDesc); // Force new input selection if the new device can not be reached via current input if (activeDesc->mProfile->getSupportedDevices().contains(newDevice)) { setInputDevice(activeDesc->mIoHandle, newDevice); } else { closeInput(activeDesc->mIoHandle); } } } status_t AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) { Loading @@ -3200,12 +3214,23 @@ status_t AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t str status_t status = mEngine->removeDevicesRoleForStrategy(strategy, role); if (status != NO_ERROR) { ALOGW("Engine could not remove preferred device for strategy %d", strategy); ALOGV("Engine could not remove preferred device for strategy %d status %d", strategy, status); return status; } checkForDeviceAndOutputChanges(); updateCallAndOutputRouting(); bool forceVolumeReeval = false; // FIXME: workaround for truncated touch sounds // to be removed when the problem is handled by system UI uint32_t delayMs = 0; if (strategy == mCommunnicationStrategy) { forceVolumeReeval = true; delayMs = TOUCH_SOUND_FIXED_DELAY_MS; updateInputRouting(); } updateCallAndOutputRouting(forceVolumeReeval, delayMs); return NO_ERROR; } Loading Loading @@ -3245,6 +3270,7 @@ status_t AudioPolicyManager::addDevicesRoleForCapturePreset( "Engine could not add preferred devices %s for audio source %d role %d", dumpAudioDeviceTypeAddrVector(devices).c_str(), audioSource, role); updateInputRouting(); return status; } Loading @@ -3263,6 +3289,7 @@ status_t AudioPolicyManager::removeDevicesRoleForCapturePreset( ALOGW_IF(status != NO_ERROR, "Engine could not remove devices role (%d) for capture preset %d", role, audioSource); updateInputRouting(); return status; } Loading @@ -3274,6 +3301,7 @@ status_t AudioPolicyManager::clearDevicesRoleForCapturePreset(audio_source_t aud ALOGW_IF(status != NO_ERROR, "Engine could not clear devices role (%d) for capture preset %d", role, audioSource); updateInputRouting(); return status; } Loading Loading @@ -3343,7 +3371,9 @@ void AudioPolicyManager::dump(String8 *dst) const } dst->appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not "); dst->appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off"); dst->appendFormat(" Communnication Strategy: %d\n", mCommunnicationStrategy); dst->appendFormat(" Config source: %s\n", mConfig.getSource().c_str()); // getConfig not const mAvailableOutputDevices.dump(dst, String8("Available output")); mAvailableInputDevices.dump(dst, String8("Available input")); mHwModulesAll.dump(dst); Loading Loading @@ -4639,6 +4669,9 @@ status_t AudioPolicyManager::initialize() { // Silence ALOGV statements property_set("log.tag." LOG_TAG, "D"); mCommunnicationStrategy = mEngine->getProductStrategyForAttributes( mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL)); updateDevicesAndOutputs(); return status; } Loading Loading @@ -5466,6 +5499,17 @@ void AudioPolicyManager::checkSecondaryOutputs() { } } bool AudioPolicyManager::isScoRequestedForComm() const { AudioDeviceTypeAddrVector devices; mEngine->getDevicesForRoleAndStrategy(mCommunnicationStrategy, DEVICE_ROLE_PREFERRED, devices); for (const auto &device : devices) { if (audio_is_bluetooth_out_sco_device(device.mType)) { return true; } } return false; } void AudioPolicyManager::checkA2dpSuspend() { audio_io_handle_t a2dpOutput = mOutputs.getA2dpOutput(); Loading @@ -5477,23 +5521,21 @@ void AudioPolicyManager::checkA2dpSuspend() bool isScoConnected = (mAvailableInputDevices.types().count(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0 || !Intersection(mAvailableOutputDevices.types(), getAudioDeviceOutAllScoSet()).empty()); bool isScoRequested = isScoRequestedForComm(); // if suspended, restore A2DP output if: // ((SCO device is NOT connected) || // ((forced usage communication is NOT SCO) && (forced usage for record is NOT SCO) && // ((SCO is not requested) && // (phone state is NOT in call) && (phone state is NOT ringing))) // // if not suspended, suspend A2DP output if: // (SCO device is connected) && // ((forced usage for communication is SCO) || (forced usage for record is SCO) || // ((SCO is requested) || // ((phone state is in call) || (phone state is ringing))) // if (mA2dpSuspended) { if (!isScoConnected || ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) != AUDIO_POLICY_FORCE_BT_SCO) && (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) != AUDIO_POLICY_FORCE_BT_SCO) && (!isScoRequested && (mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) && (mEngine->getPhoneState() != AUDIO_MODE_RINGTONE))) { Loading @@ -5502,10 +5544,7 @@ void AudioPolicyManager::checkA2dpSuspend() } } else { if (isScoConnected && ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) || (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) || (isScoRequested || (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) || (mEngine->getPhoneState() == AUDIO_MODE_RINGTONE))) { Loading Loading @@ -6217,16 +6256,17 @@ status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves, bool isVoiceVolSrc = callVolSrc == volumeSource; bool isBtScoVolSrc = btScoVolSrc == volumeSource; audio_policy_forced_cfg_t forceUseForComm = mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION); bool isScoRequested = isScoRequestedForComm(); // do not change in call volume if bluetooth is connected and vice versa // if sco and call follow same curves, bypass forceUseForComm if ((callVolSrc != btScoVolSrc) && ((isVoiceVolSrc && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) || (isBtScoVolSrc && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO))) { ALOGV("%s cannot set volume group %d volume with force use = %d for comm", __func__, volumeSource, forceUseForComm); return INVALID_OPERATION; ((isVoiceVolSrc && isScoRequested) || (isBtScoVolSrc && !isScoRequested))) { ALOGV("%s cannot set volume group %d volume when is%srequested for comm", __func__, volumeSource, isScoRequested ? " " : "n ot "); // Do not return an error here as AudioService will always set both voice call // and bluetooth SCO volumes due to stream aliasing. return NO_ERROR; } if (deviceTypes.empty()) { deviceTypes = outputDesc->devices().types(); Loading services/audiopolicy/managerdefault/AudioPolicyManager.h +10 −0 Original line number Diff line number Diff line Loading @@ -556,6 +556,11 @@ protected: */ void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0); /** * @brief updates routing for all inputs. */ void updateInputRouting(); /** * @brief checkOutputForAttributes checks and if necessary changes outputs used for the * given audio attributes. Loading Loading @@ -812,6 +817,10 @@ protected: std::unordered_set<audio_format_t> mManualSurroundFormats; std::unordered_map<uid_t, audio_flags_mask_t> mAllowedCapturePolicies; // Cached product strategy ID corresponding to legacy strategy STRATEGY_PHONE product_strategy_t mCommunnicationStrategy; private: void onNewAudioModulesAvailableInt(DeviceVector *newDevices); Loading Loading @@ -967,6 +976,7 @@ private: std::function<bool(audio_devices_t)> predicate, const char* context); bool isScoRequestedForComm() const; }; }; Loading
services/audiopolicy/enginedefault/src/Engine.cpp +81 −109 Original line number Diff line number Diff line Loading @@ -184,16 +184,7 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy, break; case STRATEGY_DTMF: if (!isInCall()) { // when off call, DTMF strategy follows the same rules as MEDIA strategy devices = getDevicesForStrategyInt( STRATEGY_MEDIA, availableOutputDevices, availableInputDevices, outputs); break; } // when in call, DTMF and PHONE strategies follow the same rules FALLTHROUGH_INTENDED; case STRATEGY_PHONE: case STRATEGY_PHONE: { // Force use of only devices on primary output if: // - in call AND // - cannot route from voice call RX OR Loading Loading @@ -223,77 +214,17 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy, availableOutputDevices = availPrimaryOutputDevices; } } // for phone strategy, we first consider the forced use and then the available devices by // order of priority switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) { case AUDIO_POLICY_FORCE_BT_SCO: if (!isInCall() || strategy != STRATEGY_DTMF) { devices = availableOutputDevices.getDevicesFromType( AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET, AUDIO_DEVICE_OUT_BLUETOOTH_SCO}); if (!devices.isEmpty()) break; // if SCO device is requested but no SCO device is available, fall back to default case FALLTHROUGH_INTENDED; default: // FORCE_NONE devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_HEARING_AID); if (!devices.isEmpty()) break; // TODO (b/161358428): remove when preferred device // for strategy phone will be used instead of AUDIO_POLICY_FORCE_FOR_COMMUNICATION devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_BLE_HEADSET); if (!devices.isEmpty()) break; // when not in a phone call, phone strategy should route STREAM_VOICE_CALL to A2DP if (!isInCall() && (getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) { devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES}); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_WIRED_HEADPHONE, AUDIO_DEVICE_OUT_WIRED_HEADSET, AUDIO_DEVICE_OUT_LINE, AUDIO_DEVICE_OUT_USB_HEADSET, AUDIO_DEVICE_OUT_USB_DEVICE}); if (!devices.isEmpty()) break; if (!isInCall()) { devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET}); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_EARPIECE); 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()) { devices = availableOutputDevices.getDevicesFromType( AUDIO_DEVICE_OUT_BLE_SPEAKER); if (!devices.isEmpty()) break; if ((getForceUse(AUDIO_POLICY_FORCE_FOR_MEDIA) != AUDIO_POLICY_FORCE_NO_BT_A2DP)) { devices = availableOutputDevices.getDevicesFromType( AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER); if (!devices.isEmpty()) break; } } if (!isInCall()) { devices = availableOutputDevices.getFirstDevicesFromTypes({ AUDIO_DEVICE_OUT_USB_ACCESSORY, AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_DEVICE_OUT_DGTL_DOCK_HEADSET, AUDIO_DEVICE_OUT_AUX_DIGITAL, AUDIO_DEVICE_OUT_ANLG_DOCK_HEADSET}); if (!devices.isEmpty()) break; } devices = availableOutputDevices.getDevicesFromType(AUDIO_DEVICE_OUT_SPEAKER); break; } break; } break; case STRATEGY_SONIFICATION: Loading Loading @@ -336,7 +267,8 @@ DeviceVector Engine::getDevicesForStrategyInt(legacy_strategy strategy, } } // Use both Bluetooth SCO and phone default output when ringing in normal mode if (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) { if (audio_is_bluetooth_out_sco_device(getPreferredDeviceTypeForLegacyStrategy( availableOutputDevices, STRATEGY_PHONE))) { if (strategy == STRATEGY_SONIFICATION) { devices.replaceDevicesByType( AUDIO_DEVICE_OUT_SPEAKER, Loading Loading @@ -506,13 +438,16 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) } } audio_devices_t commDeviceType = getPreferredDeviceTypeForLegacyStrategy(availableOutputDevices, STRATEGY_PHONE); switch (inputSource) { case AUDIO_SOURCE_DEFAULT: case AUDIO_SOURCE_MIC: device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_A2DP, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) break; if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) { if (audio_is_bluetooth_out_sco_device(commDeviceType)) { device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) break; Loading @@ -533,30 +468,29 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) availableDevices = availablePrimaryDevices; } switch (getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION)) { case AUDIO_POLICY_FORCE_BT_SCO: if (audio_is_bluetooth_out_sco_device(commDeviceType)) { // if SCO device is requested but no SCO device is available, fall back to default case device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) { break; } FALLTHROUGH_INTENDED; default: // FORCE_NONE // TODO (b/161358428): remove AUDIO_DEVICE_IN_BLE_HEADSET from the list // when preferred device for strategy phone will be used instead of // AUDIO_POLICY_FORCE_FOR_COMMUNICATION. device = availableDevices.getFirstExistingDevice({ AUDIO_DEVICE_IN_BLE_HEADSET, AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC}); } switch (commDeviceType) { case AUDIO_DEVICE_OUT_BLE_HEADSET: device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); break; case AUDIO_POLICY_FORCE_SPEAKER: case AUDIO_DEVICE_OUT_SPEAKER: device = availableDevices.getFirstExistingDevice({ AUDIO_DEVICE_IN_BACK_MIC, AUDIO_DEVICE_IN_BUILTIN_MIC}); break; default: // FORCE_NONE device = availableDevices.getFirstExistingDevice({ AUDIO_DEVICE_IN_WIRED_HEADSET, AUDIO_DEVICE_IN_USB_HEADSET, AUDIO_DEVICE_IN_USB_DEVICE, AUDIO_DEVICE_IN_BUILTIN_MIC}); break; } break; Loading @@ -569,7 +503,7 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) LOG_ALWAYS_FATAL_IF(availablePrimaryDevices.isEmpty(), "Primary devices not found"); availableDevices = availablePrimaryDevices; } if (getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) { if (audio_is_bluetooth_out_sco_device(commDeviceType)) { device = availableDevices.getDevice( AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET, String8(""), AUDIO_FORMAT_DEFAULT); if (device != nullptr) break; Loading Loading @@ -619,6 +553,7 @@ sp<DeviceDescriptor> Engine::getDeviceForInputSource(audio_source_t inputSource) ALOGE_IF(device == nullptr, "getDeviceForInputSource() no default device defined"); } ALOGV_IF(device != nullptr, "getDeviceForInputSource()input source %d, device %08x", inputSource, device->type()); Loading @@ -636,17 +571,35 @@ void Engine::updateDeviceSelectionCache() } } DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const { DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); product_strategy_t Engine::getProductStrategyFromLegacy(legacy_strategy legacyStrategy) const { for (const auto& strategyMap : mLegacyStrategyMap) { if (strategyMap.second == legacyStrategy) { return strategyMap.first; } } return PRODUCT_STRATEGY_NONE; } // check if this strategy has a preferred device that is available, // if yes, give priority to it audio_devices_t Engine::getPreferredDeviceTypeForLegacyStrategy( const DeviceVector& availableOutputDevices, legacy_strategy legacyStrategy) const { product_strategy_t strategy = getProductStrategyFromLegacy(legacyStrategy); DeviceVector devices = getPreferredAvailableDevicesForProductStrategy( availableOutputDevices, strategy); if (devices.size() > 0) { return devices[0]->type(); } return AUDIO_DEVICE_NONE; } DeviceVector Engine::getPreferredAvailableDevicesForProductStrategy( const DeviceVector& availableOutputDevices, product_strategy_t strategy) const { DeviceVector preferredAvailableDevVec = {}; AudioDeviceTypeAddrVector preferredStrategyDevices; const status_t status = getDevicesForRoleAndStrategy( strategy, DEVICE_ROLE_PREFERRED, preferredStrategyDevices); if (status == NO_ERROR) { // there is a preferred device, is it available? DeviceVector preferredAvailableDevVec = preferredAvailableDevVec = availableOutputDevices.getDevicesFromDeviceTypeAddrVec(preferredStrategyDevices); if (preferredAvailableDevVec.size() == preferredAvailableDevVec.size()) { ALOGVV("%s using pref device %s for strategy %u", Loading @@ -654,11 +607,30 @@ DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) c return preferredAvailableDevVec; } } return preferredAvailableDevVec; } DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices(); const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs(); DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const { DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ? mLegacyStrategyMap.at(strategy) : STRATEGY_NONE; // When not in call, STRATEGY_PHONE and STRATEGY_DTMF follow STRATEGY_MEDIA if (!isInCall() && (legacyStrategy == STRATEGY_PHONE || legacyStrategy == STRATEGY_DTMF)) { legacyStrategy = STRATEGY_MEDIA; strategy = getProductStrategyFromLegacy(STRATEGY_MEDIA); } // check if this strategy has a preferred device that is available, // if yes, give priority to it. DeviceVector preferredAvailableDevVec = getPreferredAvailableDevicesForProductStrategy(availableOutputDevices, strategy); if (!preferredAvailableDevVec.isEmpty()) { return preferredAvailableDevVec; } DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices(); const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs(); return getDevicesForStrategyInt(legacyStrategy, availableOutputDevices, availableInputDevices, outputs); Loading
services/audiopolicy/enginedefault/src/Engine.h +6 −0 Original line number Diff line number Diff line Loading @@ -83,6 +83,12 @@ private: sp<DeviceDescriptor> getDeviceForInputSource(audio_source_t inputSource) const; product_strategy_t getProductStrategyFromLegacy(legacy_strategy legacyStrategy) const; audio_devices_t getPreferredDeviceTypeForLegacyStrategy( const DeviceVector& availableOutputDevices, legacy_strategy legacyStrategy) const; DeviceVector getPreferredAvailableDevicesForProductStrategy( const DeviceVector& availableOutputDevices, product_strategy_t strategy) const; DeviceStrategyMap mDevicesForStrategies; std::map<product_strategy_t, legacy_strategy> mLegacyStrategyMap; Loading
services/audiopolicy/managerdefault/AudioPolicyManager.cpp +70 −30 Original line number Diff line number Diff line Loading @@ -790,16 +790,7 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, } updateCallAndOutputRouting(forceVolumeReeval, delayMs); for (const auto& activeDesc : mInputs.getActiveInputs()) { auto newDevice = getNewInputDevice(activeDesc); // Force new input selection if the new device can not be reached via current input if (activeDesc->mProfile->getSupportedDevices().contains(newDevice)) { setInputDevice(activeDesc->mIoHandle, newDevice); } else { closeInput(activeDesc->mIoHandle); } } updateInputRouting(); } void AudioPolicyManager::setSystemProperty(const char* property, const char* value) Loading Loading @@ -3145,6 +3136,7 @@ status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) { return res; } status_t AudioPolicyManager::setDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role, const AudioDeviceTypeAddrVector &devices) { Loading @@ -3162,7 +3154,17 @@ status_t AudioPolicyManager::setDevicesRoleForStrategy(product_strategy_t strate } checkForDeviceAndOutputChanges(); updateCallAndOutputRouting(); bool forceVolumeReeval = false; // FIXME: workaround for truncated touch sounds // to be removed when the problem is handled by system UI uint32_t delayMs = 0; if (strategy == mCommunnicationStrategy) { forceVolumeReeval = true; delayMs = TOUCH_SOUND_FIXED_DELAY_MS; updateInputRouting(); } updateCallAndOutputRouting(forceVolumeReeval, delayMs); return NO_ERROR; } Loading Loading @@ -3193,6 +3195,18 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint } } void AudioPolicyManager::updateInputRouting() { for (const auto& activeDesc : mInputs.getActiveInputs()) { auto newDevice = getNewInputDevice(activeDesc); // Force new input selection if the new device can not be reached via current input if (activeDesc->mProfile->getSupportedDevices().contains(newDevice)) { setInputDevice(activeDesc->mIoHandle, newDevice); } else { closeInput(activeDesc->mIoHandle); } } } status_t AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t strategy, device_role_t role) { Loading @@ -3200,12 +3214,23 @@ status_t AudioPolicyManager::removeDevicesRoleForStrategy(product_strategy_t str status_t status = mEngine->removeDevicesRoleForStrategy(strategy, role); if (status != NO_ERROR) { ALOGW("Engine could not remove preferred device for strategy %d", strategy); ALOGV("Engine could not remove preferred device for strategy %d status %d", strategy, status); return status; } checkForDeviceAndOutputChanges(); updateCallAndOutputRouting(); bool forceVolumeReeval = false; // FIXME: workaround for truncated touch sounds // to be removed when the problem is handled by system UI uint32_t delayMs = 0; if (strategy == mCommunnicationStrategy) { forceVolumeReeval = true; delayMs = TOUCH_SOUND_FIXED_DELAY_MS; updateInputRouting(); } updateCallAndOutputRouting(forceVolumeReeval, delayMs); return NO_ERROR; } Loading Loading @@ -3245,6 +3270,7 @@ status_t AudioPolicyManager::addDevicesRoleForCapturePreset( "Engine could not add preferred devices %s for audio source %d role %d", dumpAudioDeviceTypeAddrVector(devices).c_str(), audioSource, role); updateInputRouting(); return status; } Loading @@ -3263,6 +3289,7 @@ status_t AudioPolicyManager::removeDevicesRoleForCapturePreset( ALOGW_IF(status != NO_ERROR, "Engine could not remove devices role (%d) for capture preset %d", role, audioSource); updateInputRouting(); return status; } Loading @@ -3274,6 +3301,7 @@ status_t AudioPolicyManager::clearDevicesRoleForCapturePreset(audio_source_t aud ALOGW_IF(status != NO_ERROR, "Engine could not clear devices role (%d) for capture preset %d", role, audioSource); updateInputRouting(); return status; } Loading Loading @@ -3343,7 +3371,9 @@ void AudioPolicyManager::dump(String8 *dst) const } dst->appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not "); dst->appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off"); dst->appendFormat(" Communnication Strategy: %d\n", mCommunnicationStrategy); dst->appendFormat(" Config source: %s\n", mConfig.getSource().c_str()); // getConfig not const mAvailableOutputDevices.dump(dst, String8("Available output")); mAvailableInputDevices.dump(dst, String8("Available input")); mHwModulesAll.dump(dst); Loading Loading @@ -4639,6 +4669,9 @@ status_t AudioPolicyManager::initialize() { // Silence ALOGV statements property_set("log.tag." LOG_TAG, "D"); mCommunnicationStrategy = mEngine->getProductStrategyForAttributes( mEngine->getAttributesForStreamType(AUDIO_STREAM_VOICE_CALL)); updateDevicesAndOutputs(); return status; } Loading Loading @@ -5466,6 +5499,17 @@ void AudioPolicyManager::checkSecondaryOutputs() { } } bool AudioPolicyManager::isScoRequestedForComm() const { AudioDeviceTypeAddrVector devices; mEngine->getDevicesForRoleAndStrategy(mCommunnicationStrategy, DEVICE_ROLE_PREFERRED, devices); for (const auto &device : devices) { if (audio_is_bluetooth_out_sco_device(device.mType)) { return true; } } return false; } void AudioPolicyManager::checkA2dpSuspend() { audio_io_handle_t a2dpOutput = mOutputs.getA2dpOutput(); Loading @@ -5477,23 +5521,21 @@ void AudioPolicyManager::checkA2dpSuspend() bool isScoConnected = (mAvailableInputDevices.types().count(AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) != 0 || !Intersection(mAvailableOutputDevices.types(), getAudioDeviceOutAllScoSet()).empty()); bool isScoRequested = isScoRequestedForComm(); // if suspended, restore A2DP output if: // ((SCO device is NOT connected) || // ((forced usage communication is NOT SCO) && (forced usage for record is NOT SCO) && // ((SCO is not requested) && // (phone state is NOT in call) && (phone state is NOT ringing))) // // if not suspended, suspend A2DP output if: // (SCO device is connected) && // ((forced usage for communication is SCO) || (forced usage for record is SCO) || // ((SCO is requested) || // ((phone state is in call) || (phone state is ringing))) // if (mA2dpSuspended) { if (!isScoConnected || ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) != AUDIO_POLICY_FORCE_BT_SCO) && (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) != AUDIO_POLICY_FORCE_BT_SCO) && (!isScoRequested && (mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) && (mEngine->getPhoneState() != AUDIO_MODE_RINGTONE))) { Loading @@ -5502,10 +5544,7 @@ void AudioPolicyManager::checkA2dpSuspend() } } else { if (isScoConnected && ((mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION) == AUDIO_POLICY_FORCE_BT_SCO) || (mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_RECORD) == AUDIO_POLICY_FORCE_BT_SCO) || (isScoRequested || (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL) || (mEngine->getPhoneState() == AUDIO_MODE_RINGTONE))) { Loading Loading @@ -6217,16 +6256,17 @@ status_t AudioPolicyManager::checkAndSetVolume(IVolumeCurves &curves, bool isVoiceVolSrc = callVolSrc == volumeSource; bool isBtScoVolSrc = btScoVolSrc == volumeSource; audio_policy_forced_cfg_t forceUseForComm = mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_COMMUNICATION); bool isScoRequested = isScoRequestedForComm(); // do not change in call volume if bluetooth is connected and vice versa // if sco and call follow same curves, bypass forceUseForComm if ((callVolSrc != btScoVolSrc) && ((isVoiceVolSrc && forceUseForComm == AUDIO_POLICY_FORCE_BT_SCO) || (isBtScoVolSrc && forceUseForComm != AUDIO_POLICY_FORCE_BT_SCO))) { ALOGV("%s cannot set volume group %d volume with force use = %d for comm", __func__, volumeSource, forceUseForComm); return INVALID_OPERATION; ((isVoiceVolSrc && isScoRequested) || (isBtScoVolSrc && !isScoRequested))) { ALOGV("%s cannot set volume group %d volume when is%srequested for comm", __func__, volumeSource, isScoRequested ? " " : "n ot "); // Do not return an error here as AudioService will always set both voice call // and bluetooth SCO volumes due to stream aliasing. return NO_ERROR; } if (deviceTypes.empty()) { deviceTypes = outputDesc->devices().types(); Loading
services/audiopolicy/managerdefault/AudioPolicyManager.h +10 −0 Original line number Diff line number Diff line Loading @@ -556,6 +556,11 @@ protected: */ void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0); /** * @brief updates routing for all inputs. */ void updateInputRouting(); /** * @brief checkOutputForAttributes checks and if necessary changes outputs used for the * given audio attributes. Loading Loading @@ -812,6 +817,10 @@ protected: std::unordered_set<audio_format_t> mManualSurroundFormats; std::unordered_map<uid_t, audio_flags_mask_t> mAllowedCapturePolicies; // Cached product strategy ID corresponding to legacy strategy STRATEGY_PHONE product_strategy_t mCommunnicationStrategy; private: void onNewAudioModulesAvailableInt(DeviceVector *newDevices); Loading Loading @@ -967,6 +976,7 @@ private: std::function<bool(audio_devices_t)> predicate, const char* context); bool isScoRequestedForComm() const; }; };