From 2deb47896c1a3604468f9b9144c7114f5d678b33 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Fri, 1 Nov 2019 11:04:15 -0700 Subject: [PATCH] APM: support product strategy routing Audio policy engine supports receiving a preferred device to use for a given strategy (Engine superclass). Use of the preferred device intervenes at the level of the each engine implementation, here in the default engine in getDevicesForProductStrategy() method so it is saved in the routing cache, and respects existing routing priorities. Refactor the loops for call and output rerouting into a new updateCallAndOutputRouting() method. Bug: 144440677 Test: atest AudioServiceHostTest#testPreferredDeviceRouting Change-Id: Ic4c690e1b0d8020c4335979e40e14e6df5887879 Merged-In: Ic4c690e1b0d8020c4335979e40e14e6df5887879 --- media/libaudioclient/AudioSystem.cpp | 29 ++++++ media/libaudioclient/IAudioPolicyService.cpp | 93 ++++++++++++++++++- .../include/media/AudioSystem.h | 11 +++ .../include/media/IAudioPolicyService.h | 8 ++ .../include/media/AudioDeviceTypeAddr.h | 2 + services/audiopolicy/AudioPolicyInterface.h | 8 ++ .../engine/common/include/EngineBase.h | 8 ++ .../engine/common/include/ProductStrategy.h | 7 ++ .../engine/common/src/EngineBase.cpp | 48 ++++++++++ .../engine/common/src/ProductStrategy.cpp | 10 ++ .../engine/interface/EngineInterface.h | 33 +++++++ .../audiopolicy/enginedefault/src/Engine.cpp | 28 ++++-- .../managerdefault/AudioPolicyManager.cpp | 87 +++++++++++++---- .../managerdefault/AudioPolicyManager.h | 14 ++- .../service/AudioPolicyInterfaceImpl.cpp | 29 ++++++ .../audiopolicy/service/AudioPolicyService.h | 9 ++ 16 files changed, 397 insertions(+), 27 deletions(-) diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp index 6665c43c63..cb9c7ba920 100644 --- a/media/libaudioclient/AudioSystem.cpp +++ b/media/libaudioclient/AudioSystem.cpp @@ -1525,6 +1525,35 @@ status_t AudioSystem::setRttEnabled(bool enabled) return aps->setRttEnabled(enabled); } +status_t AudioSystem::setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) { + return PERMISSION_DENIED; + } + return aps->setPreferredDeviceForStrategy(strategy, device); +} + +status_t AudioSystem::removePreferredDeviceForStrategy(product_strategy_t strategy) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) { + return PERMISSION_DENIED; + } + return aps->removePreferredDeviceForStrategy(strategy); +} + +status_t AudioSystem::getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) +{ + const sp& aps = AudioSystem::get_audio_policy_service(); + if (aps == 0) { + return PERMISSION_DENIED; + } + return aps->getPreferredDeviceForStrategy(strategy, device); +} + // --------------------------------------------------------------------------- int AudioSystem::AudioPolicyServiceClient::addAudioPortCallback( diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp index 7cc95e5e60..0facaf8f88 100644 --- a/media/libaudioclient/IAudioPolicyService.cpp +++ b/media/libaudioclient/IAudioPolicyService.cpp @@ -104,7 +104,10 @@ enum { GET_VOLUME_GROUP_FOR_ATTRIBUTES, SET_ALLOWED_CAPTURE_POLICY, MOVE_EFFECTS_TO_IO, - SET_RTT_ENABLED + SET_RTT_ENABLED, + SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY, + REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY, + GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY, }; #define MAX_ITEMS_PER_LIST 1024 @@ -1284,6 +1287,55 @@ public: } return static_cast(reply.readInt32()); } + + virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeUint32(static_cast(strategy)); + status_t status = device.writeToParcel(&data); + if (status != NO_ERROR) { + return BAD_VALUE; + } + status = remote()->transact(SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY, + data, &reply); + if (status != NO_ERROR) { + return status; + } + return static_cast(reply.readInt32()); + } + + virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeUint32(static_cast(strategy)); + status_t status = remote()->transact(REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY, + data, &reply); + if (status != NO_ERROR) { + return status; + } + return static_cast(reply.readInt32()); + } + + virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) + { + Parcel data, reply; + data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor()); + data.writeUint32(static_cast(strategy)); + status_t status = remote()->transact(GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY, + data, &reply); + if (status != NO_ERROR) { + return status; + } + status = device.readFromParcel(&reply); + if (status != NO_ERROR) { + return status; + } + return static_cast(reply.readInt32()); + } }; IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService"); @@ -1346,7 +1398,10 @@ status_t BnAudioPolicyService::onTransact( case GET_OFFLOAD_FORMATS_A2DP: case LIST_AUDIO_VOLUME_GROUPS: case GET_VOLUME_GROUP_FOR_ATTRIBUTES: - case SET_RTT_ENABLED: { + case SET_RTT_ENABLED: + case SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: + case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: + case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: { if (!isServiceUid(IPCThreadState::self()->getCallingUid())) { ALOGW("%s: transaction %d received from PID %d unauthorized UID %d", __func__, code, IPCThreadState::self()->getCallingPid(), @@ -2369,6 +2424,40 @@ status_t BnAudioPolicyService::onTransact( return NO_ERROR; } + case SET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + product_strategy_t strategy = (product_strategy_t) data.readUint32(); + AudioDeviceTypeAddr device; + status_t status = device.readFromParcel((Parcel*)&data); + if (status != NO_ERROR) { + return status; + } + status = setPreferredDeviceForStrategy(strategy, device); + reply->writeInt32(status); + return NO_ERROR; + } + + case REMOVE_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + product_strategy_t strategy = (product_strategy_t) data.readUint32(); + status_t status = removePreferredDeviceForStrategy(strategy); + reply->writeInt32(status); + return NO_ERROR; + } + + case GET_PREFERRED_DEVICE_FOR_PRODUCT_STRATEGY: { + CHECK_INTERFACE(IAudioPolicyService, data, reply); + product_strategy_t strategy = (product_strategy_t) data.readUint32(); + AudioDeviceTypeAddr device; + status_t status = getPreferredDeviceForStrategy(strategy, device); + status_t marshall_status = device.writeToParcel(reply); + if (marshall_status != NO_ERROR) { + return marshall_status; + } + reply->writeInt32(status); + return NO_ERROR; + } + default: return BBinder::onTransact(code, data, reply, flags); } diff --git a/media/libaudioclient/include/media/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h index f29a775dac..a86297d5cc 100644 --- a/media/libaudioclient/include/media/AudioSystem.h +++ b/media/libaudioclient/include/media/AudioSystem.h @@ -403,6 +403,17 @@ public: */ static status_t setAudioHalPids(const std::vector& pids); + static status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device); + + static status_t removePreferredDeviceForStrategy(product_strategy_t strategy); + + static status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device); + + static status_t getDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device); + // ---------------------------------------------------------------------------- class AudioVolumeGroupCallback : public RefBase diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h index 8669ee6b88..9b91d6dfcb 100644 --- a/media/libaudioclient/include/media/IAudioPolicyService.h +++ b/media/libaudioclient/include/media/IAudioPolicyService.h @@ -223,6 +223,14 @@ public: volume_group_t &volumeGroup) = 0; virtual status_t setRttEnabled(bool enabled) = 0; + + virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) = 0; + + virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0; + + virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) = 0; }; diff --git a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h index 5e5e7622ec..acc37ca964 100644 --- a/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h +++ b/media/libaudiofoundation/include/media/AudioDeviceTypeAddr.h @@ -37,6 +37,8 @@ struct AudioDeviceTypeAddr : public Parcelable { bool equals(const AudioDeviceTypeAddr& other) const; + AudioDeviceTypeAddr& operator= (const AudioDeviceTypeAddr&) = default; + void reset(); status_t readFromParcel(const Parcel *parcel) override; diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h index 1155987db4..1fe60d4975 100644 --- a/services/audiopolicy/AudioPolicyInterface.h +++ b/services/audiopolicy/AudioPolicyInterface.h @@ -271,6 +271,14 @@ public: virtual status_t getVolumeGroupFromAudioAttributes(const AudioAttributes &aa, volume_group_t &volumeGroup) = 0; + + virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) = 0; + + virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0; + + virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) = 0; }; diff --git a/services/audiopolicy/engine/common/include/EngineBase.h b/services/audiopolicy/engine/common/include/EngineBase.h index 4cf0b904c2..7f339dcfe4 100755 --- a/services/audiopolicy/engine/common/include/EngineBase.h +++ b/services/audiopolicy/engine/common/include/EngineBase.h @@ -93,6 +93,13 @@ public: void dump(String8 *dst) const override; + status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) override; + + status_t removePreferredDeviceForStrategy(product_strategy_t strategy) override; + + status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) const override; engineConfig::ParsingResult loadAudioPolicyEngineConfig(); @@ -124,6 +131,7 @@ private: AudioPolicyManagerObserver *mApmObserver = nullptr; ProductStrategyMap mProductStrategies; + ProductStrategyPreferredRoutingMap mProductStrategyPreferredDevices; VolumeGroupMap mVolumeGroups; LastRemovableMediaDevices mLastRemovableMediaDevices; audio_mode_t mPhoneState = AUDIO_MODE_NORMAL; /**< current phone state. */ diff --git a/services/audiopolicy/engine/common/include/ProductStrategy.h b/services/audiopolicy/engine/common/include/ProductStrategy.h index ab8eff3d10..3ebe7d1960 100644 --- a/services/audiopolicy/engine/common/include/ProductStrategy.h +++ b/services/audiopolicy/engine/common/include/ProductStrategy.h @@ -28,6 +28,7 @@ #include #include #include +#include namespace android { @@ -163,4 +164,10 @@ private: product_strategy_t mDefaultStrategy = PRODUCT_STRATEGY_NONE; }; +class ProductStrategyPreferredRoutingMap : public std::map +{ +public: + void dump(String8 *dst, int spaces = 0) const; +}; + } // namespace android diff --git a/services/audiopolicy/engine/common/src/EngineBase.cpp b/services/audiopolicy/engine/common/src/EngineBase.cpp index 45c43d8387..01efc7a041 100644 --- a/services/audiopolicy/engine/common/src/EngineBase.cpp +++ b/services/audiopolicy/engine/common/src/EngineBase.cpp @@ -283,9 +283,57 @@ status_t EngineBase::listAudioVolumeGroups(AudioVolumeGroupVector &groups) const return NO_ERROR; } +status_t EngineBase::setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) +{ + // verify strategy exists + if (mProductStrategies.find(strategy) == mProductStrategies.end()) { + ALOGE("%s invalid strategy %u", __func__, strategy); + return BAD_VALUE; + } + + mProductStrategyPreferredDevices[strategy] = device; + return NO_ERROR; +} + +status_t EngineBase::removePreferredDeviceForStrategy(product_strategy_t strategy) +{ + // verify strategy exists + if (mProductStrategies.find(strategy) == mProductStrategies.end()) { + ALOGE("%s invalid strategy %u", __func__, strategy); + return BAD_VALUE; + } + + if (mProductStrategyPreferredDevices.erase(strategy) == 0) { + // no preferred device was set + return NAME_NOT_FOUND; + } + return NO_ERROR; +} + +status_t EngineBase::getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) const +{ + // verify strategy exists + if (mProductStrategies.find(strategy) == mProductStrategies.end()) { + ALOGE("%s unknown strategy %u", __func__, strategy); + return BAD_VALUE; + } + // preferred device for this strategy? + auto devIt = mProductStrategyPreferredDevices.find(strategy); + if (devIt == mProductStrategyPreferredDevices.end()) { + ALOGV("%s no preferred device for strategy %u", __func__, strategy); + return NAME_NOT_FOUND; + } + + device = devIt->second; + return NO_ERROR; +} + void EngineBase::dump(String8 *dst) const { mProductStrategies.dump(dst, 2); + mProductStrategyPreferredDevices.dump(dst, 2); mVolumeGroups.dump(dst, 2); } diff --git a/services/audiopolicy/engine/common/src/ProductStrategy.cpp b/services/audiopolicy/engine/common/src/ProductStrategy.cpp index 14c9dd1205..fe15ff698f 100644 --- a/services/audiopolicy/engine/common/src/ProductStrategy.cpp +++ b/services/audiopolicy/engine/common/src/ProductStrategy.cpp @@ -310,5 +310,15 @@ void ProductStrategyMap::dump(String8 *dst, int spaces) const } } +void ProductStrategyPreferredRoutingMap::dump(android::String8* dst, int spaces) const { + dst->appendFormat("\n%*sPreferred devices per product strategy dump:", spaces, ""); + for (const auto& iter : *this) { + dst->appendFormat("\n%*sStrategy %u dev:%08x addr:%s", + spaces + 2, "", + (uint32_t) iter.first, + iter.second.mType, iter.second.mAddress.c_str()); + } + dst->appendFormat("\n"); +} } diff --git a/services/audiopolicy/engine/interface/EngineInterface.h b/services/audiopolicy/engine/interface/EngineInterface.h index 0c58a7ca5f..dfb20b5274 100644 --- a/services/audiopolicy/engine/interface/EngineInterface.h +++ b/services/audiopolicy/engine/interface/EngineInterface.h @@ -292,6 +292,39 @@ public: */ virtual status_t listAudioVolumeGroups(AudioVolumeGroupVector &groups) const = 0; + /** + * @brief setPreferredDeviceForStrategy sets the default device to be used for a + * strategy when available + * @param strategy the audio strategy whose routing will be affected + * @param device the audio device to route to when available + * @return BAD_VALUE if the strategy is invalid, + * or NO_ERROR if the preferred device was set + */ + virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) = 0; + + /** + * @brief removePreferredDeviceForStrategy removes the preferred device previously set + * for the given strategy + * @param strategy the audio strategy whose routing will be affected + * @return BAD_VALUE if the strategy is invalid, + * or NO_ERROR if the preferred device was removed + */ + virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy) = 0; + + /** + * @brief getPreferredDeviceForStrategy queries which device is set as the + * preferred device for the given strategy + * @param strategy the strategy to query + * @param device returns configured as the preferred device if one was set + * @return BAD_VALUE if the strategy is invalid, + * or NAME_NOT_FOUND if no preferred device was set + * or NO_ERROR if the device parameter was initialized to the preferred device + */ + virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) const = 0; + + virtual void dump(String8 *dst) const = 0; protected: diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp index de7e7cea3d..02b99d0c90 100755 --- a/services/audiopolicy/enginedefault/src/Engine.cpp +++ b/services/audiopolicy/enginedefault/src/Engine.cpp @@ -604,7 +604,7 @@ sp Engine::getDeviceForInputSource(audio_source_t inputSource) void Engine::updateDeviceSelectionCache() { for (const auto &iter : getProductStrategies()) { - const auto &strategy = iter.second; + const auto& strategy = iter.second; auto devices = getDevicesForProductStrategy(strategy->getId()); mDevicesForStrategies[strategy->getId()] = devices; strategy->setDeviceTypes(devices.types()); @@ -612,14 +612,30 @@ void Engine::updateDeviceSelectionCache() } } -DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const -{ +DeviceVector Engine::getDevicesForProductStrategy(product_strategy_t strategy) const { DeviceVector availableOutputDevices = getApmObserver()->getAvailableOutputDevices(); - DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices(); - const SwAudioOutputCollection &outputs = getApmObserver()->getOutputs(); + // check if this strategy has a preferred device that is available, + // if yes, give priority to it + AudioDeviceTypeAddr preferredStrategyDevice; + const status_t status = getPreferredDeviceForStrategy(strategy, preferredStrategyDevice); + if (status == NO_ERROR) { + // there is a preferred device, is it available? + sp preferredAvailableDevDescr = availableOutputDevices.getDevice( + preferredStrategyDevice.mType, + String8(preferredStrategyDevice.mAddress.c_str()), + AUDIO_FORMAT_DEFAULT); + if (preferredAvailableDevDescr != nullptr) { + ALOGVV("%s using pref device 0x%08x/%s for strategy %u", __FUNCTION__, + preferredStrategyDevice.mType, preferredStrategyDevice.mAddress, strategy); + return DeviceVector(preferredAvailableDevDescr); + } + } + + DeviceVector availableInputDevices = getApmObserver()->getAvailableInputDevices(); + const SwAudioOutputCollection& outputs = getApmObserver()->getOutputs(); auto legacyStrategy = mLegacyStrategyMap.find(strategy) != end(mLegacyStrategyMap) ? - mLegacyStrategyMap.at(strategy) : STRATEGY_NONE; + mLegacyStrategyMap.at(strategy) : STRATEGY_NONE; return getDevicesForStrategyInt(legacyStrategy, availableOutputDevices, availableInputDevices, outputs); diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp index 718142f1d2..23c0a12b15 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp @@ -794,27 +794,11 @@ void AudioPolicyManager::setForceUse(audio_policy_force_use_t usage, //FIXME: workaround for truncated touch sounds // to be removed when the problem is handled by system UI uint32_t delayMs = 0; - uint32_t waitMs = 0; if (usage == AUDIO_POLICY_FORCE_FOR_COMMUNICATION) { delayMs = TOUCH_SOUND_FIXED_DELAY_MS; } - if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { - DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/); - waitMs = updateCallRouting(newDevices, delayMs); - } - for (size_t i = 0; i < mOutputs.size(); i++) { - sp outputDesc = mOutputs.valueAt(i); - DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/); - if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) { - // As done in setDeviceConnectionState, we could also fix default device issue by - // preventing the force re-routing in case of default dev that distinguishes on address. - // Let's give back to engine full device choice decision however. - waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs); - } - if (forceVolumeReeval && !newDevices.isEmpty()) { - applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true); - } - } + + updateCallAndOutputRouting(forceVolumeReeval, delayMs); for (const auto& activeDesc : mInputs.getActiveInputs()) { auto newDevice = getNewInputDevice(activeDesc); @@ -3084,6 +3068,72 @@ status_t AudioPolicyManager::removeUidDeviceAffinities(uid_t uid) { return res; } +status_t AudioPolicyManager::setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) { + ALOGI("%s() strategy=%d device=%08x addr=%s", __FUNCTION__, + strategy, device.mType, device.mAddress.c_str()); + // strategy preferred device is only for output devices + if (!audio_is_output_device(device.mType)) { + ALOGE("%s() device=%08x is NOT an output device", __FUNCTION__, device.mType); + return BAD_VALUE; + } + + status_t status = mEngine->setPreferredDeviceForStrategy(strategy, device); + if (status != NO_ERROR) { + ALOGW("Engine could not set preferred device %08x %s for strategy %d", + device.mType, device.mAddress.c_str(), strategy); + return status; + } + + checkForDeviceAndOutputChanges(); + updateCallAndOutputRouting(); + + return NO_ERROR; +} + +void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint32_t delayMs) +{ + uint32_t waitMs = 0; + if (mEngine->getPhoneState() == AUDIO_MODE_IN_CALL && hasPrimaryOutput()) { + DeviceVector newDevices = getNewOutputDevices(mPrimaryOutput, true /*fromCache*/); + waitMs = updateCallRouting(newDevices, delayMs); + } + for (size_t i = 0; i < mOutputs.size(); i++) { + sp outputDesc = mOutputs.valueAt(i); + DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/); + if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (outputDesc != mPrimaryOutput)) { + // As done in setDeviceConnectionState, we could also fix default device issue by + // preventing the force re-routing in case of default dev that distinguishes on address. + // Let's give back to engine full device choice decision however. + waitMs = setOutputDevices(outputDesc, newDevices, !newDevices.isEmpty(), delayMs); + } + if (forceVolumeReeval && !newDevices.isEmpty()) { + applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true); + } + } +} + +status_t AudioPolicyManager::removePreferredDeviceForStrategy(product_strategy_t strategy) +{ + ALOGI("%s() strategy=%d", __FUNCTION__, strategy); + + status_t status = mEngine->removePreferredDeviceForStrategy(strategy); + if (status != NO_ERROR) { + ALOGW("Engine could not remove preferred device for strategy %d", strategy); + return status; + } + + checkForDeviceAndOutputChanges(); + updateCallAndOutputRouting(); + + return NO_ERROR; +} + +status_t AudioPolicyManager::getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) { + return mEngine->getPreferredDeviceForStrategy(strategy, device); +} + void AudioPolicyManager::dump(String8 *dst) const { dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this); @@ -5056,6 +5106,7 @@ void AudioPolicyManager::checkOutputForAttributes(const audio_attributes_t &attr DeviceVector oldDevices = mEngine->getOutputDevicesForAttributes(attr, 0, true /*fromCache*/); DeviceVector newDevices = mEngine->getOutputDevicesForAttributes(attr, 0, false /*fromCache*/); + SortedVector srcOutputs = getOutputsForDevices(oldDevices, mPreviousOutputs); SortedVector dstOutputs = getOutputsForDevices(newDevices, mOutputs); diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h index cff6983d77..d516d7ba28 100644 --- a/services/audiopolicy/managerdefault/AudioPolicyManager.h +++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h @@ -258,6 +258,12 @@ public: const Vector& devices); virtual status_t removeUidDeviceAffinities(uid_t uid); + virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device); + virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy); + virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device); + virtual status_t startAudioSource(const struct audio_port_config *source, const audio_attributes_t *attributes, audio_port_handle_t *portId, @@ -496,12 +502,18 @@ protected: // close an input. void closeInput(audio_io_handle_t input); - // runs all the checks required for accomodating changes in devices and outputs + // runs all the checks required for accommodating changes in devices and outputs // if 'onOutputsChecked' callback is provided, it is executed after the outputs // check via 'checkOutputForAllStrategies'. If the callback returns 'true', // A2DP suspend status is rechecked. void checkForDeviceAndOutputChanges(std::function onOutputsChecked = nullptr); + /** + * @brief updates routing for all outputs (including call if call in progress). + * @param delayMs delay for unmuting if required + */ + void updateCallAndOutputRouting(bool forceVolumeReeval = true, uint32_t delayMs = 0); + /** * @brief checkOutputForAttributes checks and if necessary changes outputs used for the * given audio attributes. diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp index fa8da8916e..47a103b0bd 100644 --- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp +++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp @@ -1325,4 +1325,33 @@ status_t AudioPolicyService::setRttEnabled(bool enabled) return NO_ERROR; } +status_t AudioPolicyService::setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + Mutex::Autolock _l(mLock); + return mAudioPolicyManager->setPreferredDeviceForStrategy(strategy, device); +} + +status_t AudioPolicyService::removePreferredDeviceForStrategy(product_strategy_t strategy) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + Mutex::Autolock _l(mLock); + return mAudioPolicyManager->removePreferredDeviceForStrategy(strategy); +} + +status_t AudioPolicyService::getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device) +{ + if (mAudioPolicyManager == NULL) { + return NO_INIT; + } + Mutex::Autolock _l(mLock); + return mAudioPolicyManager->getPreferredDeviceForStrategy(strategy, device); +} + } // namespace android diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h index bed1b0417f..7b72dc198e 100644 --- a/services/audiopolicy/service/AudioPolicyService.h +++ b/services/audiopolicy/service/AudioPolicyService.h @@ -224,6 +224,15 @@ public: virtual status_t removeUidDeviceAffinities(uid_t uid); + virtual status_t setPreferredDeviceForStrategy(product_strategy_t strategy, + const AudioDeviceTypeAddr &device); + + virtual status_t removePreferredDeviceForStrategy(product_strategy_t strategy); + + + virtual status_t getPreferredDeviceForStrategy(product_strategy_t strategy, + AudioDeviceTypeAddr &device); + virtual status_t startAudioSource(const struct audio_port_config *source, const audio_attributes_t *attributes, audio_port_handle_t *portId);