Loading services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h +1 −0 Original line number Diff line number Diff line Loading @@ -452,6 +452,7 @@ public: audio_session_t mDirectClientSession; // session id of the direct output client bool mPendingReopenToQueryProfiles = false; audio_channel_mask_t mMixerChannelMask = AUDIO_CHANNEL_NONE; bool mUsePreferredMixerAttributes = false; }; // Audio output driven by an input device directly. Loading services/audiopolicy/managerdefault/AudioPolicyManager.cpp +110 −26 Original line number Diff line number Diff line Loading @@ -319,10 +319,10 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript checkCloseOutputs(); } (void)updateCallRouting(false /*fromCache*/); std::vector<audio_io_handle_t> outputsToReopen; const DeviceVector msdOutDevices = getMsdAudioOutDevices(); const DeviceVector activeMediaDevices = mEngine->getActiveMediaDevices(mAvailableOutputDevices); std::map<audio_io_handle_t, DeviceVector> outputsToReopenWithDevices; for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); if (desc->isActive() && ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || Loading @@ -336,6 +336,13 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript && (!device_distinguishes_on_address(device->type()) // always force when disconnecting (a non-duplicated device) || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)); if (desc->mUsePreferredMixerAttributes && newDevices != desc->devices()) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices outputsToReopenWithDevices.emplace(mOutputs.keyAt(i), newDevices); continue; } setOutputDevices(desc, newDevices, force, 0); } if (!desc->isDuplicated() && desc->mProfile->hasDynamicAudioProfile() && Loading @@ -346,7 +353,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript // `mPendingReopenToQueryProfiles` in the SwOutputDescriptor so that the output // can be reopened to query dynamic profiles when all clients are inactive. if (areAllActiveTracksRerouted(desc)) { outputsToReopen.push_back(mOutputs.keyAt(i)); outputsToReopenWithDevices.emplace(mOutputs.keyAt(i), activeMediaDevices); } else { desc->mPendingReopenToQueryProfiles = true; } Loading @@ -356,11 +363,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript desc->mPendingReopenToQueryProfiles = false; } } for (const auto& output : outputsToReopen) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output); closeOutput(output); openOutputWithProfileAndDevice(desc->mProfile, activeMediaDevices); } reopenOutputsWithDevices(outputsToReopenWithDevices); if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) { cleanUpForDevice(device); Loading Loading @@ -885,16 +888,25 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } } std::map<audio_io_handle_t, DeviceVector> outputsToReopen; // reevaluate routing on all outputs in case tracks have been started during the call for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); DeviceVector newDevices = getNewOutputDevices(desc, true /*fromCache*/); if (state != AUDIO_MODE_IN_CALL || (desc != mPrimaryOutput && !isTelephonyRxOrTx(desc))) { bool forceRouting = !newDevices.isEmpty(); if (desc->mUsePreferredMixerAttributes && newDevices != desc->devices()) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices); continue; } setOutputDevices(desc, newDevices, forceRouting, 0 /*delayMs*/, nullptr, true /*requiresMuteCheck*/, !forceRouting /*requiresVolumeCheck*/); } } reopenOutputsWithDevices(outputsToReopen); checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs); Loading Loading @@ -2059,6 +2071,16 @@ status_t AudioPolicyManager::startOutput(audio_port_handle_t portId) if (status != NO_ERROR) { outputDesc->stop(); if (status == DEAD_OBJECT) { sp<SwAudioOutputDescriptor> desc = reopenOutput(outputDesc, nullptr /*config*/, AUDIO_OUTPUT_FLAG_NONE, __func__); if (desc == nullptr) { // This is not common, it may indicate something wrong with the HAL. ALOGE("%s unable to open output with default config", __func__); return status; } desc->mUsePreferredMixerAttributes = true; } return status; } Loading @@ -2076,10 +2098,12 @@ status_t AudioPolicyManager::startOutput(audio_port_handle_t portId) config.channel_mask = info->getConfigBase().channel_mask; config.sample_rate = info->getConfigBase().sample_rate; config.format = info->getConfigBase().format; status_t status = reopenOutput(outputDesc, &config, info->getFlags(), __func__); if (status != NO_ERROR) { return status; sp<SwAudioOutputDescriptor> desc = reopenOutput(outputDesc, &config, info->getFlags(), __func__); if (desc == nullptr) { return BAD_VALUE; } desc->mUsePreferredMixerAttributes = true; // Intentionally return error to let the client side resending request for // creating and starting. return DEAD_OBJECT; Loading Loading @@ -2236,8 +2260,14 @@ status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outp } } if (outputDesc->mUsePreferredMixerAttributes && devices != outputDesc->devices()) { // If the output is open with preferred mixer attributes, but the routed device is // changed when calling this function, returning DEAD_OBJECT to indicate routing // changed. return DEAD_OBJECT; } const uint32_t muteWaitMs = setOutputDevices(outputDesc, devices, force, 0, NULL, requiresMuteCheck); setOutputDevices(outputDesc, devices, force, 0, nullptr, requiresMuteCheck); // apply volume rules for current stream and device if necessary auto &curves = getVolumeCurves(client->attributes()); Loading Loading @@ -2300,6 +2330,7 @@ void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive, bool isUnicastActive = isLeUnicastActive(); if (wasUnicastActive != isUnicastActive) { std::map<audio_io_handle_t, DeviceVector> outputsToReopen; //reroute all outputs routed to LE broadcast if LE unicast activy changed on any output for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); Loading @@ -2312,6 +2343,13 @@ void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive, getAudioDeviceOutLeAudioUnicastSet()).isEmpty()))) { DeviceVector newDevices = getNewOutputDevices(desc, false /*fromCache*/); bool force = desc->devices() != newDevices; if (desc->mUsePreferredMixerAttributes && force) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices); continue; } setOutputDevices(desc, newDevices, force, delayMs); // re-apply device specific volume if not done by setOutputDevice() if (!force) { Loading @@ -2319,6 +2357,7 @@ void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive, } } } reopenOutputsWithDevices(outputsToReopen); } } Loading Loading @@ -2412,6 +2451,7 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu // force restoring the device selection on other active outputs if it differs from the // one being selected for this output std::map<audio_io_handle_t, DeviceVector> outputsToReopen; uint32_t delayMs = outputDesc->latency()*2; for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); Loading @@ -2422,6 +2462,13 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu DeviceVector newDevices2 = getNewOutputDevices(desc, false /*fromCache*/); bool force = desc->devices() != newDevices2; if (desc->mUsePreferredMixerAttributes && force) { // If the device is using preferred mixer attributes, the output need to // reopen with default configuration when the new selected devices are // different from current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices2); continue; } setOutputDevices(desc, newDevices2, force, delayMs); // re-apply device specific volume if not done by setOutputDevice() Loading @@ -2430,6 +2477,7 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu } } } reopenOutputsWithDevices(outputsToReopen); // update the outputs if stopping one with a stream that can affect notification routing handleNotificationRoutingForStream(stream); } Loading Loading @@ -3760,6 +3808,7 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint // Only apply special touch sound delay once delayMs = 0; } std::map<audio_io_handle_t, DeviceVector> outputsToReopen; for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i); DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/); Loading @@ -3769,6 +3818,13 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint // 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. bool forceRouting = !newDevices.isEmpty(); if (outputDesc->mUsePreferredMixerAttributes && newDevices != outputDesc->devices()) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices); continue; } waitMs = setOutputDevices(outputDesc, newDevices, forceRouting, delayMs, nullptr, true /*requiresMuteCheck*/, !forceRouting /*requiresVolumeCheck*/); Loading @@ -3779,6 +3835,7 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true); } } reopenOutputsWithDevices(outputsToReopen); checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs); } Loading Loading @@ -4306,8 +4363,10 @@ status_t AudioPolicyManager::setPreferredMixerAttributes( std::vector<audio_io_handle_t> outputsToReopen; for (size_t i = 0; i < mOutputs.size(); i++) { const auto output = mOutputs.valueAt(i); if (output->mProfile == profile && output->devices().onlyContainsDevice(deviceDescriptor) && !output->isConfigurationMatched(mixerAttributes->config, flags)) { if (output->mProfile == profile && output->devices().onlyContainsDevice(deviceDescriptor)) { if (output->isConfigurationMatched(mixerAttributes->config, flags)) { output->mUsePreferredMixerAttributes = true; } else { for (const auto &client: output->getActiveClients()) { if (client->uid() == uid && client->strategy() == strategy) { client->setIsInvalid(); Loading @@ -4316,12 +4375,19 @@ status_t AudioPolicyManager::setPreferredMixerAttributes( } } } } audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = mixerAttributes->config.sample_rate; config.channel_mask = mixerAttributes->config.channel_mask; config.format = mixerAttributes->config.format; for (const auto output : outputsToReopen) { sp<SwAudioOutputDescriptor> desc = reopenOutput(mOutputs.valueFor(output), &config, flags, __func__); if (desc == nullptr) { ALOGE("%s, failed to reopen output with preferred mixer attributes", __func__); continue; } desc->mUsePreferredMixerAttributes = true; } return NO_ERROR; Loading Loading @@ -5093,6 +5159,7 @@ void AudioPolicyManager::checkStrategyRoute(product_strategy_t ps, audio_io_hand auto attributes = mEngine->getAllAttributesForProductStrategy(ps).front(); DeviceVector devices = mEngine->getOutputDevicesForAttributes(attributes, nullptr, false); SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs); std::map<audio_io_handle_t, DeviceVector> outputsToReopen; for (size_t j = 0; j < mOutputs.size(); j++) { if (mOutputs.keyAt(j) == ouptutToSkip) { continue; Loading @@ -5109,10 +5176,18 @@ void AudioPolicyManager::checkStrategyRoute(product_strategy_t ps, audio_io_hand mpClientInterface->invalidateStream(stream); } } else { setOutputDevices( outputDesc, getNewOutputDevices(outputDesc, false /*fromCache*/), false); DeviceVector newDevices = getNewOutputDevices(outputDesc, false /*fromCache*/); if (outputDesc->mUsePreferredMixerAttributes && outputDesc->devices() != newDevices) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(j), newDevices); continue; } setOutputDevices(outputDesc, newDevices, false); } } reopenOutputsWithDevices(outputsToReopen); } void AudioPolicyManager::clearSessionRoutes(uid_t uid) Loading Loading @@ -7139,6 +7214,7 @@ uint32_t AudioPolicyManager::setOutputDevices(const sp<SwAudioOutputDescriptor>& audio_patch_handle_t *patchHandle, bool requiresMuteCheck, bool requiresVolumeCheck) { // TODO(b/262404095): Consider if the output need to be reopened. ALOGV("%s device %s delayMs %d", __func__, devices.toString().c_str(), delayMs); uint32_t muteWaitMs; Loading Loading @@ -8222,7 +8298,7 @@ status_t AudioPolicyManager::getProfilesForDevices(const DeviceVector& devices, return NO_ERROR; } status_t AudioPolicyManager::reopenOutput(sp<SwAudioOutputDescriptor> outputDesc, sp<SwAudioOutputDescriptor> AudioPolicyManager::reopenOutput(sp<SwAudioOutputDescriptor> outputDesc, const audio_config_t *config, audio_output_flags_t flags, const char* caller) { Loading @@ -8232,9 +8308,17 @@ status_t AudioPolicyManager::reopenOutput(sp<SwAudioOutputDescriptor> outputDesc if (preferredOutput == nullptr) { ALOGE("%s failed to reopen output device=%d, caller=%s", __func__, outputDesc->devices()[0]->getId(), caller); return BAD_VALUE; } return NO_ERROR; return preferredOutput; } void AudioPolicyManager::reopenOutputsWithDevices( const std::map<audio_io_handle_t, DeviceVector> &outputsToReopen) { for (const auto& [output, devices] : outputsToReopen) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output); closeOutput(output); openOutputWithProfileAndDevice(desc->mProfile, devices); } } } // namespace android services/audiopolicy/managerdefault/AudioPolicyManager.h +8 −4 Original line number Diff line number Diff line Loading @@ -1305,10 +1305,14 @@ private: sp<PreferredMixerAttributesInfo> getPreferredMixerAttributesInfo( audio_port_handle_t devicePortId, product_strategy_t strategy); status_t reopenOutput(sp<SwAudioOutputDescriptor> outputDesc, sp<SwAudioOutputDescriptor> reopenOutput( sp<SwAudioOutputDescriptor> outputDesc, const audio_config_t *config, audio_output_flags_t flags, const char* caller); void reopenOutputsWithDevices( const std::map<audio_io_handle_t, DeviceVector>& outputsToReopen); }; }; services/audiopolicy/tests/AudioPolicyManagerTestClient.h +1 −1 Original line number Diff line number Diff line Loading @@ -189,7 +189,7 @@ public: mAudioParameters.addInt(String8(AudioParameter::keyStreamSupportedSamplingRates), 48000); std::string channelMasks; for (const auto& cm : mSupportedChannelMasks) { if (audio_channel_mask_is_valid(cm)) { if (!audio_channel_mask_is_valid(cm)) { continue; } if (!channelMasks.empty()) channelMasks += AUDIO_PARAMETER_VALUE_LIST_SEPARATOR; Loading services/audiopolicy/tests/audiopolicymanager_tests.cpp +69 −3 Original line number Diff line number Diff line Loading @@ -160,7 +160,8 @@ class AudioPolicyManagerTest : public testing::Test { audio_io_handle_t *output = nullptr, audio_port_handle_t *portId = nullptr, audio_attributes_t attr = {}, audio_session_t session = AUDIO_SESSION_NONE); audio_session_t session = AUDIO_SESSION_NONE, int uid = 0); void getInputForAttr( const audio_attributes_t &attr, audio_session_t session, Loading Loading @@ -244,7 +245,8 @@ void AudioPolicyManagerTest::getOutputForAttr( audio_io_handle_t *output, audio_port_handle_t *portId, audio_attributes_t attr, audio_session_t session) { audio_session_t session, int uid) { audio_io_handle_t localOutput; if (!output) output = &localOutput; *output = AUDIO_IO_HANDLE_NONE; Loading @@ -261,7 +263,7 @@ void AudioPolicyManagerTest::getOutputForAttr( bool isBitPerfect; // TODO b/182392769: use attribution source util AttributionSourceState attributionSource = AttributionSourceState(); attributionSource.uid = 0; attributionSource.uid = uid; attributionSource.token = sp<BBinder>::make(); ASSERT_EQ(OK, mManager->getOutputForAttr( &attr, output, session, &stream, attributionSource, &config, &flags, Loading Loading @@ -1053,6 +1055,70 @@ TEST_F(AudioPolicyManagerTestWithConfigurationFile, PreferredMixerAttributes) { "", "", AUDIO_FORMAT_LDAC)); } TEST_F(AudioPolicyManagerTestWithConfigurationFile, RoutingChangedWithPreferredMixerAttributes) { mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT); mClient->addSupportedChannelMask(AUDIO_CHANNEL_OUT_STEREO); ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_AVAILABLE, "", "", AUDIO_FORMAT_DEFAULT)); auto devices = mManager->getAvailableOutputDevices(); audio_port_handle_t usbPortId = AUDIO_PORT_HANDLE_NONE; for (auto device : devices) { if (device->type() == AUDIO_DEVICE_OUT_USB_DEVICE) { usbPortId = device->getId(); break; } } EXPECT_NE(AUDIO_PORT_HANDLE_NONE, usbPortId); const uid_t uid = 1234; const audio_attributes_t mediaAttr = { .content_type = AUDIO_CONTENT_TYPE_MUSIC, .usage = AUDIO_USAGE_MEDIA, }; std::vector<audio_mixer_attributes_t> mixerAttributes; EXPECT_EQ(NO_ERROR, mManager->getSupportedMixerAttributes(usbPortId, mixerAttributes)); EXPECT_GT(mixerAttributes.size(), 0); EXPECT_EQ(NO_ERROR, mManager->setPreferredMixerAttributes( &mediaAttr, usbPortId, uid, &mixerAttributes[0])); audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE, uid); status_t status = mManager->startOutput(portId); if (status == DEAD_OBJECT) { getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE, uid); status = mManager->startOutput(portId); } EXPECT_EQ(NO_ERROR, status); EXPECT_NE(AUDIO_IO_HANDLE_NONE, output); EXPECT_NE(nullptr, mManager->getOutputs().valueFor(output)); EXPECT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_POLICY_DEVICE_STATE_AVAILABLE, "", "", AUDIO_FORMAT_LDAC)); // When BT device is connected, it will be selected as media device and trigger routing changed. // When this happens, existing output that is opened with preferred mixer attributes will be // closed and reopened with default config. EXPECT_EQ(nullptr, mManager->getOutputs().valueFor(output)); EXPECT_EQ(NO_ERROR, mManager->clearPreferredMixerAttributes(&mediaAttr, usbPortId, uid)); EXPECT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "", "", AUDIO_FORMAT_LDAC)); ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "", "", AUDIO_FORMAT_LDAC)); } class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile { protected: void TearDown() override; Loading Loading
services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h +1 −0 Original line number Diff line number Diff line Loading @@ -452,6 +452,7 @@ public: audio_session_t mDirectClientSession; // session id of the direct output client bool mPendingReopenToQueryProfiles = false; audio_channel_mask_t mMixerChannelMask = AUDIO_CHANNEL_NONE; bool mUsePreferredMixerAttributes = false; }; // Audio output driven by an input device directly. Loading
services/audiopolicy/managerdefault/AudioPolicyManager.cpp +110 −26 Original line number Diff line number Diff line Loading @@ -319,10 +319,10 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript checkCloseOutputs(); } (void)updateCallRouting(false /*fromCache*/); std::vector<audio_io_handle_t> outputsToReopen; const DeviceVector msdOutDevices = getMsdAudioOutDevices(); const DeviceVector activeMediaDevices = mEngine->getActiveMediaDevices(mAvailableOutputDevices); std::map<audio_io_handle_t, DeviceVector> outputsToReopenWithDevices; for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); if (desc->isActive() && ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || Loading @@ -336,6 +336,13 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript && (!device_distinguishes_on_address(device->type()) // always force when disconnecting (a non-duplicated device) || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)); if (desc->mUsePreferredMixerAttributes && newDevices != desc->devices()) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices outputsToReopenWithDevices.emplace(mOutputs.keyAt(i), newDevices); continue; } setOutputDevices(desc, newDevices, force, 0); } if (!desc->isDuplicated() && desc->mProfile->hasDynamicAudioProfile() && Loading @@ -346,7 +353,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript // `mPendingReopenToQueryProfiles` in the SwOutputDescriptor so that the output // can be reopened to query dynamic profiles when all clients are inactive. if (areAllActiveTracksRerouted(desc)) { outputsToReopen.push_back(mOutputs.keyAt(i)); outputsToReopenWithDevices.emplace(mOutputs.keyAt(i), activeMediaDevices); } else { desc->mPendingReopenToQueryProfiles = true; } Loading @@ -356,11 +363,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript desc->mPendingReopenToQueryProfiles = false; } } for (const auto& output : outputsToReopen) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output); closeOutput(output); openOutputWithProfileAndDevice(desc->mProfile, activeMediaDevices); } reopenOutputsWithDevices(outputsToReopenWithDevices); if (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE) { cleanUpForDevice(device); Loading Loading @@ -885,16 +888,25 @@ void AudioPolicyManager::setPhoneState(audio_mode_t state) } } std::map<audio_io_handle_t, DeviceVector> outputsToReopen; // reevaluate routing on all outputs in case tracks have been started during the call for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); DeviceVector newDevices = getNewOutputDevices(desc, true /*fromCache*/); if (state != AUDIO_MODE_IN_CALL || (desc != mPrimaryOutput && !isTelephonyRxOrTx(desc))) { bool forceRouting = !newDevices.isEmpty(); if (desc->mUsePreferredMixerAttributes && newDevices != desc->devices()) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices); continue; } setOutputDevices(desc, newDevices, forceRouting, 0 /*delayMs*/, nullptr, true /*requiresMuteCheck*/, !forceRouting /*requiresVolumeCheck*/); } } reopenOutputsWithDevices(outputsToReopen); checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs); Loading Loading @@ -2059,6 +2071,16 @@ status_t AudioPolicyManager::startOutput(audio_port_handle_t portId) if (status != NO_ERROR) { outputDesc->stop(); if (status == DEAD_OBJECT) { sp<SwAudioOutputDescriptor> desc = reopenOutput(outputDesc, nullptr /*config*/, AUDIO_OUTPUT_FLAG_NONE, __func__); if (desc == nullptr) { // This is not common, it may indicate something wrong with the HAL. ALOGE("%s unable to open output with default config", __func__); return status; } desc->mUsePreferredMixerAttributes = true; } return status; } Loading @@ -2076,10 +2098,12 @@ status_t AudioPolicyManager::startOutput(audio_port_handle_t portId) config.channel_mask = info->getConfigBase().channel_mask; config.sample_rate = info->getConfigBase().sample_rate; config.format = info->getConfigBase().format; status_t status = reopenOutput(outputDesc, &config, info->getFlags(), __func__); if (status != NO_ERROR) { return status; sp<SwAudioOutputDescriptor> desc = reopenOutput(outputDesc, &config, info->getFlags(), __func__); if (desc == nullptr) { return BAD_VALUE; } desc->mUsePreferredMixerAttributes = true; // Intentionally return error to let the client side resending request for // creating and starting. return DEAD_OBJECT; Loading Loading @@ -2236,8 +2260,14 @@ status_t AudioPolicyManager::startSource(const sp<SwAudioOutputDescriptor>& outp } } if (outputDesc->mUsePreferredMixerAttributes && devices != outputDesc->devices()) { // If the output is open with preferred mixer attributes, but the routed device is // changed when calling this function, returning DEAD_OBJECT to indicate routing // changed. return DEAD_OBJECT; } const uint32_t muteWaitMs = setOutputDevices(outputDesc, devices, force, 0, NULL, requiresMuteCheck); setOutputDevices(outputDesc, devices, force, 0, nullptr, requiresMuteCheck); // apply volume rules for current stream and device if necessary auto &curves = getVolumeCurves(client->attributes()); Loading Loading @@ -2300,6 +2330,7 @@ void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive, bool isUnicastActive = isLeUnicastActive(); if (wasUnicastActive != isUnicastActive) { std::map<audio_io_handle_t, DeviceVector> outputsToReopen; //reroute all outputs routed to LE broadcast if LE unicast activy changed on any output for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); Loading @@ -2312,6 +2343,13 @@ void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive, getAudioDeviceOutLeAudioUnicastSet()).isEmpty()))) { DeviceVector newDevices = getNewOutputDevices(desc, false /*fromCache*/); bool force = desc->devices() != newDevices; if (desc->mUsePreferredMixerAttributes && force) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices); continue; } setOutputDevices(desc, newDevices, force, delayMs); // re-apply device specific volume if not done by setOutputDevice() if (!force) { Loading @@ -2319,6 +2357,7 @@ void AudioPolicyManager::checkLeBroadcastRoutes(bool wasUnicastActive, } } } reopenOutputsWithDevices(outputsToReopen); } } Loading Loading @@ -2412,6 +2451,7 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu // force restoring the device selection on other active outputs if it differs from the // one being selected for this output std::map<audio_io_handle_t, DeviceVector> outputsToReopen; uint32_t delayMs = outputDesc->latency()*2; for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i); Loading @@ -2422,6 +2462,13 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu DeviceVector newDevices2 = getNewOutputDevices(desc, false /*fromCache*/); bool force = desc->devices() != newDevices2; if (desc->mUsePreferredMixerAttributes && force) { // If the device is using preferred mixer attributes, the output need to // reopen with default configuration when the new selected devices are // different from current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices2); continue; } setOutputDevices(desc, newDevices2, force, delayMs); // re-apply device specific volume if not done by setOutputDevice() Loading @@ -2430,6 +2477,7 @@ status_t AudioPolicyManager::stopSource(const sp<SwAudioOutputDescriptor>& outpu } } } reopenOutputsWithDevices(outputsToReopen); // update the outputs if stopping one with a stream that can affect notification routing handleNotificationRoutingForStream(stream); } Loading Loading @@ -3760,6 +3808,7 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint // Only apply special touch sound delay once delayMs = 0; } std::map<audio_io_handle_t, DeviceVector> outputsToReopen; for (size_t i = 0; i < mOutputs.size(); i++) { sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(i); DeviceVector newDevices = getNewOutputDevices(outputDesc, true /*fromCache*/); Loading @@ -3769,6 +3818,13 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint // 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. bool forceRouting = !newDevices.isEmpty(); if (outputDesc->mUsePreferredMixerAttributes && newDevices != outputDesc->devices()) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(i), newDevices); continue; } waitMs = setOutputDevices(outputDesc, newDevices, forceRouting, delayMs, nullptr, true /*requiresMuteCheck*/, !forceRouting /*requiresVolumeCheck*/); Loading @@ -3779,6 +3835,7 @@ void AudioPolicyManager::updateCallAndOutputRouting(bool forceVolumeReeval, uint applyStreamVolumes(outputDesc, newDevices.types(), waitMs, true); } } reopenOutputsWithDevices(outputsToReopen); checkLeBroadcastRoutes(wasLeUnicastActive, nullptr, delayMs); } Loading Loading @@ -4306,8 +4363,10 @@ status_t AudioPolicyManager::setPreferredMixerAttributes( std::vector<audio_io_handle_t> outputsToReopen; for (size_t i = 0; i < mOutputs.size(); i++) { const auto output = mOutputs.valueAt(i); if (output->mProfile == profile && output->devices().onlyContainsDevice(deviceDescriptor) && !output->isConfigurationMatched(mixerAttributes->config, flags)) { if (output->mProfile == profile && output->devices().onlyContainsDevice(deviceDescriptor)) { if (output->isConfigurationMatched(mixerAttributes->config, flags)) { output->mUsePreferredMixerAttributes = true; } else { for (const auto &client: output->getActiveClients()) { if (client->uid() == uid && client->strategy() == strategy) { client->setIsInvalid(); Loading @@ -4316,12 +4375,19 @@ status_t AudioPolicyManager::setPreferredMixerAttributes( } } } } audio_config_t config = AUDIO_CONFIG_INITIALIZER; config.sample_rate = mixerAttributes->config.sample_rate; config.channel_mask = mixerAttributes->config.channel_mask; config.format = mixerAttributes->config.format; for (const auto output : outputsToReopen) { sp<SwAudioOutputDescriptor> desc = reopenOutput(mOutputs.valueFor(output), &config, flags, __func__); if (desc == nullptr) { ALOGE("%s, failed to reopen output with preferred mixer attributes", __func__); continue; } desc->mUsePreferredMixerAttributes = true; } return NO_ERROR; Loading Loading @@ -5093,6 +5159,7 @@ void AudioPolicyManager::checkStrategyRoute(product_strategy_t ps, audio_io_hand auto attributes = mEngine->getAllAttributesForProductStrategy(ps).front(); DeviceVector devices = mEngine->getOutputDevicesForAttributes(attributes, nullptr, false); SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs); std::map<audio_io_handle_t, DeviceVector> outputsToReopen; for (size_t j = 0; j < mOutputs.size(); j++) { if (mOutputs.keyAt(j) == ouptutToSkip) { continue; Loading @@ -5109,10 +5176,18 @@ void AudioPolicyManager::checkStrategyRoute(product_strategy_t ps, audio_io_hand mpClientInterface->invalidateStream(stream); } } else { setOutputDevices( outputDesc, getNewOutputDevices(outputDesc, false /*fromCache*/), false); DeviceVector newDevices = getNewOutputDevices(outputDesc, false /*fromCache*/); if (outputDesc->mUsePreferredMixerAttributes && outputDesc->devices() != newDevices) { // If the device is using preferred mixer attributes, the output need to reopen // with default configuration when the new selected devices are different from // current routing devices. outputsToReopen.emplace(mOutputs.keyAt(j), newDevices); continue; } setOutputDevices(outputDesc, newDevices, false); } } reopenOutputsWithDevices(outputsToReopen); } void AudioPolicyManager::clearSessionRoutes(uid_t uid) Loading Loading @@ -7139,6 +7214,7 @@ uint32_t AudioPolicyManager::setOutputDevices(const sp<SwAudioOutputDescriptor>& audio_patch_handle_t *patchHandle, bool requiresMuteCheck, bool requiresVolumeCheck) { // TODO(b/262404095): Consider if the output need to be reopened. ALOGV("%s device %s delayMs %d", __func__, devices.toString().c_str(), delayMs); uint32_t muteWaitMs; Loading Loading @@ -8222,7 +8298,7 @@ status_t AudioPolicyManager::getProfilesForDevices(const DeviceVector& devices, return NO_ERROR; } status_t AudioPolicyManager::reopenOutput(sp<SwAudioOutputDescriptor> outputDesc, sp<SwAudioOutputDescriptor> AudioPolicyManager::reopenOutput(sp<SwAudioOutputDescriptor> outputDesc, const audio_config_t *config, audio_output_flags_t flags, const char* caller) { Loading @@ -8232,9 +8308,17 @@ status_t AudioPolicyManager::reopenOutput(sp<SwAudioOutputDescriptor> outputDesc if (preferredOutput == nullptr) { ALOGE("%s failed to reopen output device=%d, caller=%s", __func__, outputDesc->devices()[0]->getId(), caller); return BAD_VALUE; } return NO_ERROR; return preferredOutput; } void AudioPolicyManager::reopenOutputsWithDevices( const std::map<audio_io_handle_t, DeviceVector> &outputsToReopen) { for (const auto& [output, devices] : outputsToReopen) { sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output); closeOutput(output); openOutputWithProfileAndDevice(desc->mProfile, devices); } } } // namespace android
services/audiopolicy/managerdefault/AudioPolicyManager.h +8 −4 Original line number Diff line number Diff line Loading @@ -1305,10 +1305,14 @@ private: sp<PreferredMixerAttributesInfo> getPreferredMixerAttributesInfo( audio_port_handle_t devicePortId, product_strategy_t strategy); status_t reopenOutput(sp<SwAudioOutputDescriptor> outputDesc, sp<SwAudioOutputDescriptor> reopenOutput( sp<SwAudioOutputDescriptor> outputDesc, const audio_config_t *config, audio_output_flags_t flags, const char* caller); void reopenOutputsWithDevices( const std::map<audio_io_handle_t, DeviceVector>& outputsToReopen); }; };
services/audiopolicy/tests/AudioPolicyManagerTestClient.h +1 −1 Original line number Diff line number Diff line Loading @@ -189,7 +189,7 @@ public: mAudioParameters.addInt(String8(AudioParameter::keyStreamSupportedSamplingRates), 48000); std::string channelMasks; for (const auto& cm : mSupportedChannelMasks) { if (audio_channel_mask_is_valid(cm)) { if (!audio_channel_mask_is_valid(cm)) { continue; } if (!channelMasks.empty()) channelMasks += AUDIO_PARAMETER_VALUE_LIST_SEPARATOR; Loading
services/audiopolicy/tests/audiopolicymanager_tests.cpp +69 −3 Original line number Diff line number Diff line Loading @@ -160,7 +160,8 @@ class AudioPolicyManagerTest : public testing::Test { audio_io_handle_t *output = nullptr, audio_port_handle_t *portId = nullptr, audio_attributes_t attr = {}, audio_session_t session = AUDIO_SESSION_NONE); audio_session_t session = AUDIO_SESSION_NONE, int uid = 0); void getInputForAttr( const audio_attributes_t &attr, audio_session_t session, Loading Loading @@ -244,7 +245,8 @@ void AudioPolicyManagerTest::getOutputForAttr( audio_io_handle_t *output, audio_port_handle_t *portId, audio_attributes_t attr, audio_session_t session) { audio_session_t session, int uid) { audio_io_handle_t localOutput; if (!output) output = &localOutput; *output = AUDIO_IO_HANDLE_NONE; Loading @@ -261,7 +263,7 @@ void AudioPolicyManagerTest::getOutputForAttr( bool isBitPerfect; // TODO b/182392769: use attribution source util AttributionSourceState attributionSource = AttributionSourceState(); attributionSource.uid = 0; attributionSource.uid = uid; attributionSource.token = sp<BBinder>::make(); ASSERT_EQ(OK, mManager->getOutputForAttr( &attr, output, session, &stream, attributionSource, &config, &flags, Loading Loading @@ -1053,6 +1055,70 @@ TEST_F(AudioPolicyManagerTestWithConfigurationFile, PreferredMixerAttributes) { "", "", AUDIO_FORMAT_LDAC)); } TEST_F(AudioPolicyManagerTestWithConfigurationFile, RoutingChangedWithPreferredMixerAttributes) { mClient->addSupportedFormat(AUDIO_FORMAT_PCM_16_BIT); mClient->addSupportedChannelMask(AUDIO_CHANNEL_OUT_STEREO); ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_AVAILABLE, "", "", AUDIO_FORMAT_DEFAULT)); auto devices = mManager->getAvailableOutputDevices(); audio_port_handle_t usbPortId = AUDIO_PORT_HANDLE_NONE; for (auto device : devices) { if (device->type() == AUDIO_DEVICE_OUT_USB_DEVICE) { usbPortId = device->getId(); break; } } EXPECT_NE(AUDIO_PORT_HANDLE_NONE, usbPortId); const uid_t uid = 1234; const audio_attributes_t mediaAttr = { .content_type = AUDIO_CONTENT_TYPE_MUSIC, .usage = AUDIO_USAGE_MEDIA, }; std::vector<audio_mixer_attributes_t> mixerAttributes; EXPECT_EQ(NO_ERROR, mManager->getSupportedMixerAttributes(usbPortId, mixerAttributes)); EXPECT_GT(mixerAttributes.size(), 0); EXPECT_EQ(NO_ERROR, mManager->setPreferredMixerAttributes( &mediaAttr, usbPortId, uid, &mixerAttributes[0])); audio_io_handle_t output = AUDIO_IO_HANDLE_NONE; audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE, uid); status_t status = mManager->startOutput(portId); if (status == DEAD_OBJECT) { getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE, uid); status = mManager->startOutput(portId); } EXPECT_EQ(NO_ERROR, status); EXPECT_NE(AUDIO_IO_HANDLE_NONE, output); EXPECT_NE(nullptr, mManager->getOutputs().valueFor(output)); EXPECT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_POLICY_DEVICE_STATE_AVAILABLE, "", "", AUDIO_FORMAT_LDAC)); // When BT device is connected, it will be selected as media device and trigger routing changed. // When this happens, existing output that is opened with preferred mixer attributes will be // closed and reopened with default config. EXPECT_EQ(nullptr, mManager->getOutputs().valueFor(output)); EXPECT_EQ(NO_ERROR, mManager->clearPreferredMixerAttributes(&mediaAttr, usbPortId, uid)); EXPECT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_BLUETOOTH_A2DP, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "", "", AUDIO_FORMAT_LDAC)); ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE, AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, "", "", AUDIO_FORMAT_LDAC)); } class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile { protected: void TearDown() override; Loading