Loading services/audiopolicy/managerdefault/AudioPolicyManager.cpp +95 −48 Original line number Diff line number Diff line Loading @@ -1037,8 +1037,7 @@ status_t AudioPolicyManager::getOutputForAttrInt( *output = AUDIO_IO_HANDLE_NONE; if (!msdDevices.isEmpty()) { *output = getOutputForDevices(msdDevices, session, *stream, config, flags); sp<DeviceDescriptor> device = outputDevices.isEmpty() ? nullptr : outputDevices.itemAt(0); if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) { if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatches(&outputDevices) == NO_ERROR) { ALOGV("%s() Using MSD devices %s instead of devices %s", __func__, msdDevices.toString().c_str(), outputDevices.toString().c_str()); } else { Loading @@ -1054,6 +1053,12 @@ status_t AudioPolicyManager::getOutputForAttrInt( } *selectedDeviceId = getFirstDeviceId(outputDevices); for (auto &outputDevice : outputDevices) { if (outputDevice->getId() == getConfig().getDefaultOutputDevice()->getId()) { *selectedDeviceId = outputDevice->getId(); break; } } if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX)) { *outputType = API_OUTPUT_TELEPHONY_TX; Loading Loading @@ -1196,24 +1201,9 @@ status_t AudioPolicyManager::openDirectOutput(audio_stream_type_t stream, sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface); String8 address = getFirstDeviceAddress(devices); // MSD patch may be using the only output stream that can service this request. Release // MSD patch to prioritize this request over any active output on MSD. AudioPatchCollection msdPatches = getMsdPatches(); for (size_t i = 0; i < msdPatches.size(); i++) { const auto& patch = msdPatches[i]; for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) { const struct audio_port_config *sink = &patch->mPatch.sinks[j]; if (sink->type == AUDIO_PORT_TYPE_DEVICE && devices.containsDeviceWithType(sink->ext.device.type) && (address.isEmpty() || strncmp(sink->ext.device.address, address.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) { releaseAudioPatch(patch->getHandle(), mUidCached); break; } } } // An MSD patch may be using the only output stream that can service this request. Release // all MSD patches to prioritize this request over any active output on MSD. releaseMsdPatches(devices); status_t status = outputDesc->open(config, devices, stream, flags, output); Loading Loading @@ -1386,7 +1376,8 @@ status_t AudioPolicyManager::getBestMsdAudioProfileFor(const sp<DeviceDescriptor } AudioProfileVector deviceProfiles; for (const auto &outProfile : outputProfiles) { if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) { if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) && outProfile->supportsDevice(outputDevice)) { appendAudioProfiles(deviceProfiles, outProfile->getAudioProfiles()); } } Loading Loading @@ -1454,40 +1445,85 @@ PatchBuilder AudioPolicyManager::buildMsdPatch(const sp<DeviceDescriptor> &outpu return patchBuilder; } status_t AudioPolicyManager::setMsdPatch(const sp<DeviceDescriptor> &outputDevice) { sp<DeviceDescriptor> device = outputDevice; if (device == nullptr) { status_t AudioPolicyManager::setMsdPatches(const DeviceVector *outputDevices) { DeviceVector devices; if (outputDevices != nullptr && outputDevices->size() > 0) { devices.add(*outputDevices); } else { // Use media strategy for unspecified output device. This should only // occur on checkForDeviceAndOutputChanges(). Device connection events may // therefore invalidate explicit routing requests. DeviceVector devices = mEngine->getOutputDevicesForAttributes( devices = mEngine->getOutputDevicesForAttributes( attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, false /*fromCache*/); LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no outpudevice to set Msd Patch"); device = devices.itemAt(0); } ALOGV("%s() for device %s", __func__, device->toString().c_str()); PatchBuilder patchBuilder = buildMsdPatch(device); const struct audio_patch* patch = patchBuilder.patch(); const AudioPatchCollection msdPatches = getMsdPatches(); if (!msdPatches.isEmpty()) { LOG_ALWAYS_FATAL_IF(msdPatches.size() > 1, "The current MSD prototype only supports one output patch"); sp<AudioPatch> currentPatch = msdPatches.valueAt(0); if (audio_patches_are_equal(¤tPatch->mPatch, patch)) { LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no output device to set MSD patch"); } std::vector<PatchBuilder> patchesToCreate; for (auto i = 0u; i < devices.size(); ++i) { ALOGV("%s() for device %s", __func__, devices[i]->toString().c_str()); patchesToCreate.push_back(buildMsdPatch(devices[i])); } // Retain only the MSD patches associated with outputDevices request. // Tear down the others, and create new ones as needed. AudioPatchCollection patchesToRemove = getMsdPatches(); for (auto it = patchesToCreate.begin(); it != patchesToCreate.end(); ) { auto retainedPatch = false; for (auto i = 0u; i < patchesToRemove.size(); ++i) { if (audio_patches_are_equal(it->patch(), &patchesToRemove[i]->mPatch)) { patchesToRemove.removeItemsAt(i); retainedPatch = true; break; } } if (retainedPatch) { it = patchesToCreate.erase(it); continue; } ++it; } if (patchesToCreate.size() == 0 && patchesToRemove.size() == 0) { return NO_ERROR; } for (auto i = 0u; i < patchesToRemove.size(); ++i) { auto ¤tPatch = patchesToRemove.valueAt(i); releaseAudioPatch(currentPatch->getHandle(), mUidCached); } status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/, patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/); ALOGE_IF(status != NO_ERROR, "%s() error %d creating MSD audio patch", __func__, status); ALOGI_IF(status == NO_ERROR, "%s() Patch created from MSD_IN to " "device:%s (format:%#x channels:%#x samplerate:%d)", __func__, device->toString().c_str(), patch->sources[0].format, patch->sources[0].channel_mask, patch->sources[0].sample_rate); status_t status = NO_ERROR; for (const auto &p : patchesToCreate) { auto currStatus = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/, p.patch(), 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/); char message[256]; snprintf(message, sizeof(message), "%s() %s: creating MSD patch from device:IN_BUS to " "device:%#x (format:%#x channels:%#x samplerate:%d)", __func__, currStatus == NO_ERROR ? "Success" : "Error", p.patch()->sinks[0].ext.device.type, p.patch()->sources[0].format, p.patch()->sources[0].channel_mask, p.patch()->sources[0].sample_rate); if (currStatus == NO_ERROR) { ALOGD("%s", message); } else { ALOGE("%s", message); if (status == NO_ERROR) { status = currStatus; } } } return status; } void AudioPolicyManager::releaseMsdPatches(const DeviceVector& devices) { AudioPatchCollection msdPatches = getMsdPatches(); for (size_t i = 0; i < msdPatches.size(); i++) { const auto& patch = msdPatches[i]; for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) { const struct audio_port_config *sink = &patch->mPatch.sinks[j]; if (sink->type == AUDIO_PORT_TYPE_DEVICE && devices.getDevice(sink->ext.device.type, String8(sink->ext.device.address), AUDIO_FORMAT_DEFAULT) != nullptr) { releaseAudioPatch(patch->getHandle(), mUidCached); break; } } } } audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs, audio_output_flags_t flags, audio_format_t format, Loading Loading @@ -5309,8 +5345,13 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output) } } if (!directOutputOpen) { ALOGV("no direct outputs open, reset MSD patch"); setMsdPatch(); ALOGV("no direct outputs open, reset MSD patches"); // TODO: The MSD patches to be established here may differ to current MSD patches due to // how output devices for patching are resolved. Avoid by caching and reusing the // arguments to mEngine->getOutputDevicesForAttributes() when resolving which output // devices to patch to. This may be complicated by the fact that devices may become // unavailable. setMsdPatches(); } } } Loading Loading @@ -5377,7 +5418,13 @@ void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> on if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend(); updateDevicesAndOutputs(); if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) { setMsdPatch(); // TODO: The MSD patches to be established here may differ to current MSD patches due to how // output devices for patching are resolved. Nevertheless, AudioTracks affected by device // configuration changes will ultimately be rerouted correctly. We can still avoid // unnecessary rerouting by caching and reusing the arguments to // mEngine->getOutputDevicesForAttributes() when resolving which output devices to patch to. // This may be complicated by the fact that devices may become unavailable. setMsdPatches(); } } Loading services/audiopolicy/managerdefault/AudioPolicyManager.h +8 −8 Original line number Diff line number Diff line Loading @@ -844,13 +844,6 @@ protected: // end point. audio_port_handle_t mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE; private: void onNewAudioModulesAvailableInt(DeviceVector *newDevices); // Add or remove AC3 DTS encodings based on user preferences. void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr); void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr); // Support for Multi-Stream Decoder (MSD) module sp<DeviceDescriptor> getMsdAudioInDevice() const; DeviceVector getMsdAudioOutDevices() const; Loading @@ -860,7 +853,14 @@ private: audio_port_config *sourceConfig, audio_port_config *sinkConfig) const; PatchBuilder buildMsdPatch(const sp<DeviceDescriptor> &outputDevice) const; status_t setMsdPatch(const sp<DeviceDescriptor> &outputDevice = nullptr); status_t setMsdPatches(const DeviceVector *outputDevices = nullptr); void releaseMsdPatches(const DeviceVector& devices); private: void onNewAudioModulesAvailableInt(DeviceVector *newDevices); // Add or remove AC3 DTS encodings based on user preferences. void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr); void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr); // If any, resolve any "dynamic" fields of an Audio Profiles collection void updateAudioProfiles(const sp<DeviceDescriptor>& devDesc, audio_io_handle_t ioHandle, Loading services/audiopolicy/tests/AudioPolicyTestManager.h +2 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ class AudioPolicyTestManager : public AudioPolicyManager { using AudioPolicyManager::getOutputs; using AudioPolicyManager::getAvailableOutputDevices; using AudioPolicyManager::getAvailableInputDevices; using AudioPolicyManager::releaseMsdPatches; using AudioPolicyManager::setMsdPatches; uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; } }; Loading services/audiopolicy/tests/audiopolicymanager_tests.cpp +82 −17 Original line number Diff line number Diff line Loading @@ -319,7 +319,17 @@ TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) { // TODO: Add patch creation tests that involve already existing patch class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest { enum { MSD_AUDIO_PATCH_COUNT_NUM_AUDIO_PATCHES_INDEX = 0, MSD_AUDIO_PATCH_COUNT_NAME_INDEX = 1 }; using MsdAudioPatchCountSpecification = std::tuple<size_t, std::string>; class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest, public ::testing::WithParamInterface<MsdAudioPatchCountSpecification> { public: AudioPolicyManagerTestMsd(); protected: void SetUpManagerConfig() override; void TearDown() override; Loading @@ -327,8 +337,26 @@ class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest { sp<DeviceDescriptor> mMsdOutputDevice; sp<DeviceDescriptor> mMsdInputDevice; sp<DeviceDescriptor> mDefaultOutputDevice; const size_t mExpectedAudioPatchCount; sp<DeviceDescriptor> mSpdifDevice; }; AudioPolicyManagerTestMsd::AudioPolicyManagerTestMsd() : mExpectedAudioPatchCount(std::get<MSD_AUDIO_PATCH_COUNT_NUM_AUDIO_PATCHES_INDEX>( GetParam())) {} INSTANTIATE_TEST_CASE_P( MsdAudioPatchCount, AudioPolicyManagerTestMsd, ::testing::Values( MsdAudioPatchCountSpecification(1u, "single"), MsdAudioPatchCountSpecification(2u, "dual") ), [](const ::testing::TestParamInfo<MsdAudioPatchCountSpecification> &info) { return std::get<MSD_AUDIO_PATCH_COUNT_NAME_INDEX>(info.param); } ); void AudioPolicyManagerTestMsd::SetUpManagerConfig() { // TODO: Consider using Serializer to load part of the config from a string. AudioPolicyManagerTest::SetUpManagerConfig(); Loading @@ -348,6 +376,19 @@ void AudioPolicyManagerTestMsd::SetUpManagerConfig() { config.addDevice(mMsdOutputDevice); config.addDevice(mMsdInputDevice); if (mExpectedAudioPatchCount == 2) { // Add SPDIF device with PCM output profile as a second device for dual MSD audio patching. mSpdifDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPDIF); mSpdifDevice->addAudioProfile(pcmOutputProfile); config.addDevice(mSpdifDevice); sp<OutputProfile> spdifOutputProfile = new OutputProfile("spdif output"); spdifOutputProfile->addAudioProfile(pcmOutputProfile); spdifOutputProfile->addSupportedDevice(mSpdifDevice); config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)-> addOutputProfile(spdifOutputProfile); } sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/); HwModuleCollection modules = config.getHwModules(); modules.add(msdModule); Loading Loading @@ -383,64 +424,88 @@ void AudioPolicyManagerTestMsd::SetUpManagerConfig() { addOutputProfile(primaryEncodedOutputProfile); mDefaultOutputDevice = config.getDefaultOutputDevice(); if (mExpectedAudioPatchCount == 2) { mSpdifDevice->addAudioProfile(dtsOutputProfile); primaryEncodedOutputProfile->addSupportedDevice(mSpdifDevice); } } void AudioPolicyManagerTestMsd::TearDown() { mMsdOutputDevice.clear(); mMsdInputDevice.clear(); mDefaultOutputDevice.clear(); mSpdifDevice.clear(); AudioPolicyManagerTest::TearDown(); } TEST_F(AudioPolicyManagerTestMsd, InitSuccess) { TEST_P(AudioPolicyManagerTestMsd, InitSuccess) { ASSERT_TRUE(mMsdOutputDevice); ASSERT_TRUE(mMsdInputDevice); ASSERT_TRUE(mDefaultOutputDevice); } TEST_F(AudioPolicyManagerTestMsd, Dump) { TEST_P(AudioPolicyManagerTestMsd, Dump) { dumpToLog(); } TEST_F(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) { TEST_P(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) { const PatchCountCheck patchCount = snapshotPatchCount(); mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_P(AudioPolicyManagerTestMsd, PatchCreationSetReleaseMsdPatches) { const PatchCountCheck patchCount = snapshotPatchCount(); DeviceVector devices = mManager->getAvailableOutputDevices(); // Remove MSD output device to avoid patching to itself devices.remove(mMsdOutputDevice); ASSERT_EQ(mExpectedAudioPatchCount, devices.size()); mManager->setMsdPatches(&devices); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); // Dual patch: exercise creating one new audio patch and reusing another existing audio patch. DeviceVector singleDevice(devices[0]); mManager->releaseMsdPatches(singleDevice); ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot()); mManager->setMsdPatches(&devices); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); mManager->releaseMsdPatches(devices); ASSERT_EQ(0, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, Loading @@ -449,7 +514,7 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) ASSERT_EQ(0, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { // Switch between formats that are supported and not supported by MSD. { const PatchCountCheck patchCount = snapshotPatchCount(); Loading @@ -459,9 +524,9 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT, nullptr /*output*/, &portId); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); mManager->releaseOutput(portId); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } { const PatchCountCheck patchCount = snapshotPatchCount(); Loading @@ -471,7 +536,7 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT, nullptr /*output*/, &portId); ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId()); ASSERT_EQ(-1, patchCount.deltaFromSnapshot()); ASSERT_EQ(-static_cast<int>(mExpectedAudioPatchCount), patchCount.deltaFromSnapshot()); mManager->releaseOutput(portId); ASSERT_EQ(0, patchCount.deltaFromSnapshot()); } Loading Loading
services/audiopolicy/managerdefault/AudioPolicyManager.cpp +95 −48 Original line number Diff line number Diff line Loading @@ -1037,8 +1037,7 @@ status_t AudioPolicyManager::getOutputForAttrInt( *output = AUDIO_IO_HANDLE_NONE; if (!msdDevices.isEmpty()) { *output = getOutputForDevices(msdDevices, session, *stream, config, flags); sp<DeviceDescriptor> device = outputDevices.isEmpty() ? nullptr : outputDevices.itemAt(0); if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) { if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatches(&outputDevices) == NO_ERROR) { ALOGV("%s() Using MSD devices %s instead of devices %s", __func__, msdDevices.toString().c_str(), outputDevices.toString().c_str()); } else { Loading @@ -1054,6 +1053,12 @@ status_t AudioPolicyManager::getOutputForAttrInt( } *selectedDeviceId = getFirstDeviceId(outputDevices); for (auto &outputDevice : outputDevices) { if (outputDevice->getId() == getConfig().getDefaultOutputDevice()->getId()) { *selectedDeviceId = outputDevice->getId(); break; } } if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX)) { *outputType = API_OUTPUT_TELEPHONY_TX; Loading Loading @@ -1196,24 +1201,9 @@ status_t AudioPolicyManager::openDirectOutput(audio_stream_type_t stream, sp<SwAudioOutputDescriptor> outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface); String8 address = getFirstDeviceAddress(devices); // MSD patch may be using the only output stream that can service this request. Release // MSD patch to prioritize this request over any active output on MSD. AudioPatchCollection msdPatches = getMsdPatches(); for (size_t i = 0; i < msdPatches.size(); i++) { const auto& patch = msdPatches[i]; for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) { const struct audio_port_config *sink = &patch->mPatch.sinks[j]; if (sink->type == AUDIO_PORT_TYPE_DEVICE && devices.containsDeviceWithType(sink->ext.device.type) && (address.isEmpty() || strncmp(sink->ext.device.address, address.string(), AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) { releaseAudioPatch(patch->getHandle(), mUidCached); break; } } } // An MSD patch may be using the only output stream that can service this request. Release // all MSD patches to prioritize this request over any active output on MSD. releaseMsdPatches(devices); status_t status = outputDesc->open(config, devices, stream, flags, output); Loading Loading @@ -1386,7 +1376,8 @@ status_t AudioPolicyManager::getBestMsdAudioProfileFor(const sp<DeviceDescriptor } AudioProfileVector deviceProfiles; for (const auto &outProfile : outputProfiles) { if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) { if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) && outProfile->supportsDevice(outputDevice)) { appendAudioProfiles(deviceProfiles, outProfile->getAudioProfiles()); } } Loading Loading @@ -1454,40 +1445,85 @@ PatchBuilder AudioPolicyManager::buildMsdPatch(const sp<DeviceDescriptor> &outpu return patchBuilder; } status_t AudioPolicyManager::setMsdPatch(const sp<DeviceDescriptor> &outputDevice) { sp<DeviceDescriptor> device = outputDevice; if (device == nullptr) { status_t AudioPolicyManager::setMsdPatches(const DeviceVector *outputDevices) { DeviceVector devices; if (outputDevices != nullptr && outputDevices->size() > 0) { devices.add(*outputDevices); } else { // Use media strategy for unspecified output device. This should only // occur on checkForDeviceAndOutputChanges(). Device connection events may // therefore invalidate explicit routing requests. DeviceVector devices = mEngine->getOutputDevicesForAttributes( devices = mEngine->getOutputDevicesForAttributes( attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, false /*fromCache*/); LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no outpudevice to set Msd Patch"); device = devices.itemAt(0); } ALOGV("%s() for device %s", __func__, device->toString().c_str()); PatchBuilder patchBuilder = buildMsdPatch(device); const struct audio_patch* patch = patchBuilder.patch(); const AudioPatchCollection msdPatches = getMsdPatches(); if (!msdPatches.isEmpty()) { LOG_ALWAYS_FATAL_IF(msdPatches.size() > 1, "The current MSD prototype only supports one output patch"); sp<AudioPatch> currentPatch = msdPatches.valueAt(0); if (audio_patches_are_equal(¤tPatch->mPatch, patch)) { LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no output device to set MSD patch"); } std::vector<PatchBuilder> patchesToCreate; for (auto i = 0u; i < devices.size(); ++i) { ALOGV("%s() for device %s", __func__, devices[i]->toString().c_str()); patchesToCreate.push_back(buildMsdPatch(devices[i])); } // Retain only the MSD patches associated with outputDevices request. // Tear down the others, and create new ones as needed. AudioPatchCollection patchesToRemove = getMsdPatches(); for (auto it = patchesToCreate.begin(); it != patchesToCreate.end(); ) { auto retainedPatch = false; for (auto i = 0u; i < patchesToRemove.size(); ++i) { if (audio_patches_are_equal(it->patch(), &patchesToRemove[i]->mPatch)) { patchesToRemove.removeItemsAt(i); retainedPatch = true; break; } } if (retainedPatch) { it = patchesToCreate.erase(it); continue; } ++it; } if (patchesToCreate.size() == 0 && patchesToRemove.size() == 0) { return NO_ERROR; } for (auto i = 0u; i < patchesToRemove.size(); ++i) { auto ¤tPatch = patchesToRemove.valueAt(i); releaseAudioPatch(currentPatch->getHandle(), mUidCached); } status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/, patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/); ALOGE_IF(status != NO_ERROR, "%s() error %d creating MSD audio patch", __func__, status); ALOGI_IF(status == NO_ERROR, "%s() Patch created from MSD_IN to " "device:%s (format:%#x channels:%#x samplerate:%d)", __func__, device->toString().c_str(), patch->sources[0].format, patch->sources[0].channel_mask, patch->sources[0].sample_rate); status_t status = NO_ERROR; for (const auto &p : patchesToCreate) { auto currStatus = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/, p.patch(), 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/); char message[256]; snprintf(message, sizeof(message), "%s() %s: creating MSD patch from device:IN_BUS to " "device:%#x (format:%#x channels:%#x samplerate:%d)", __func__, currStatus == NO_ERROR ? "Success" : "Error", p.patch()->sinks[0].ext.device.type, p.patch()->sources[0].format, p.patch()->sources[0].channel_mask, p.patch()->sources[0].sample_rate); if (currStatus == NO_ERROR) { ALOGD("%s", message); } else { ALOGE("%s", message); if (status == NO_ERROR) { status = currStatus; } } } return status; } void AudioPolicyManager::releaseMsdPatches(const DeviceVector& devices) { AudioPatchCollection msdPatches = getMsdPatches(); for (size_t i = 0; i < msdPatches.size(); i++) { const auto& patch = msdPatches[i]; for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) { const struct audio_port_config *sink = &patch->mPatch.sinks[j]; if (sink->type == AUDIO_PORT_TYPE_DEVICE && devices.getDevice(sink->ext.device.type, String8(sink->ext.device.address), AUDIO_FORMAT_DEFAULT) != nullptr) { releaseAudioPatch(patch->getHandle(), mUidCached); break; } } } } audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs, audio_output_flags_t flags, audio_format_t format, Loading Loading @@ -5309,8 +5345,13 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output) } } if (!directOutputOpen) { ALOGV("no direct outputs open, reset MSD patch"); setMsdPatch(); ALOGV("no direct outputs open, reset MSD patches"); // TODO: The MSD patches to be established here may differ to current MSD patches due to // how output devices for patching are resolved. Avoid by caching and reusing the // arguments to mEngine->getOutputDevicesForAttributes() when resolving which output // devices to patch to. This may be complicated by the fact that devices may become // unavailable. setMsdPatches(); } } } Loading Loading @@ -5377,7 +5418,13 @@ void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> on if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend(); updateDevicesAndOutputs(); if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) { setMsdPatch(); // TODO: The MSD patches to be established here may differ to current MSD patches due to how // output devices for patching are resolved. Nevertheless, AudioTracks affected by device // configuration changes will ultimately be rerouted correctly. We can still avoid // unnecessary rerouting by caching and reusing the arguments to // mEngine->getOutputDevicesForAttributes() when resolving which output devices to patch to. // This may be complicated by the fact that devices may become unavailable. setMsdPatches(); } } Loading
services/audiopolicy/managerdefault/AudioPolicyManager.h +8 −8 Original line number Diff line number Diff line Loading @@ -844,13 +844,6 @@ protected: // end point. audio_port_handle_t mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE; private: void onNewAudioModulesAvailableInt(DeviceVector *newDevices); // Add or remove AC3 DTS encodings based on user preferences. void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr); void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr); // Support for Multi-Stream Decoder (MSD) module sp<DeviceDescriptor> getMsdAudioInDevice() const; DeviceVector getMsdAudioOutDevices() const; Loading @@ -860,7 +853,14 @@ private: audio_port_config *sourceConfig, audio_port_config *sinkConfig) const; PatchBuilder buildMsdPatch(const sp<DeviceDescriptor> &outputDevice) const; status_t setMsdPatch(const sp<DeviceDescriptor> &outputDevice = nullptr); status_t setMsdPatches(const DeviceVector *outputDevices = nullptr); void releaseMsdPatches(const DeviceVector& devices); private: void onNewAudioModulesAvailableInt(DeviceVector *newDevices); // Add or remove AC3 DTS encodings based on user preferences. void modifySurroundFormats(const sp<DeviceDescriptor>& devDesc, FormatVector *formatsPtr); void modifySurroundChannelMasks(ChannelMaskSet *channelMasksPtr); // If any, resolve any "dynamic" fields of an Audio Profiles collection void updateAudioProfiles(const sp<DeviceDescriptor>& devDesc, audio_io_handle_t ioHandle, Loading
services/audiopolicy/tests/AudioPolicyTestManager.h +2 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ class AudioPolicyTestManager : public AudioPolicyManager { using AudioPolicyManager::getOutputs; using AudioPolicyManager::getAvailableOutputDevices; using AudioPolicyManager::getAvailableInputDevices; using AudioPolicyManager::releaseMsdPatches; using AudioPolicyManager::setMsdPatches; uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; } }; Loading
services/audiopolicy/tests/audiopolicymanager_tests.cpp +82 −17 Original line number Diff line number Diff line Loading @@ -319,7 +319,17 @@ TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) { // TODO: Add patch creation tests that involve already existing patch class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest { enum { MSD_AUDIO_PATCH_COUNT_NUM_AUDIO_PATCHES_INDEX = 0, MSD_AUDIO_PATCH_COUNT_NAME_INDEX = 1 }; using MsdAudioPatchCountSpecification = std::tuple<size_t, std::string>; class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest, public ::testing::WithParamInterface<MsdAudioPatchCountSpecification> { public: AudioPolicyManagerTestMsd(); protected: void SetUpManagerConfig() override; void TearDown() override; Loading @@ -327,8 +337,26 @@ class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest { sp<DeviceDescriptor> mMsdOutputDevice; sp<DeviceDescriptor> mMsdInputDevice; sp<DeviceDescriptor> mDefaultOutputDevice; const size_t mExpectedAudioPatchCount; sp<DeviceDescriptor> mSpdifDevice; }; AudioPolicyManagerTestMsd::AudioPolicyManagerTestMsd() : mExpectedAudioPatchCount(std::get<MSD_AUDIO_PATCH_COUNT_NUM_AUDIO_PATCHES_INDEX>( GetParam())) {} INSTANTIATE_TEST_CASE_P( MsdAudioPatchCount, AudioPolicyManagerTestMsd, ::testing::Values( MsdAudioPatchCountSpecification(1u, "single"), MsdAudioPatchCountSpecification(2u, "dual") ), [](const ::testing::TestParamInfo<MsdAudioPatchCountSpecification> &info) { return std::get<MSD_AUDIO_PATCH_COUNT_NAME_INDEX>(info.param); } ); void AudioPolicyManagerTestMsd::SetUpManagerConfig() { // TODO: Consider using Serializer to load part of the config from a string. AudioPolicyManagerTest::SetUpManagerConfig(); Loading @@ -348,6 +376,19 @@ void AudioPolicyManagerTestMsd::SetUpManagerConfig() { config.addDevice(mMsdOutputDevice); config.addDevice(mMsdInputDevice); if (mExpectedAudioPatchCount == 2) { // Add SPDIF device with PCM output profile as a second device for dual MSD audio patching. mSpdifDevice = new DeviceDescriptor(AUDIO_DEVICE_OUT_SPDIF); mSpdifDevice->addAudioProfile(pcmOutputProfile); config.addDevice(mSpdifDevice); sp<OutputProfile> spdifOutputProfile = new OutputProfile("spdif output"); spdifOutputProfile->addAudioProfile(pcmOutputProfile); spdifOutputProfile->addSupportedDevice(mSpdifDevice); config.getHwModules().getModuleFromName(AUDIO_HARDWARE_MODULE_ID_PRIMARY)-> addOutputProfile(spdifOutputProfile); } sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/); HwModuleCollection modules = config.getHwModules(); modules.add(msdModule); Loading Loading @@ -383,64 +424,88 @@ void AudioPolicyManagerTestMsd::SetUpManagerConfig() { addOutputProfile(primaryEncodedOutputProfile); mDefaultOutputDevice = config.getDefaultOutputDevice(); if (mExpectedAudioPatchCount == 2) { mSpdifDevice->addAudioProfile(dtsOutputProfile); primaryEncodedOutputProfile->addSupportedDevice(mSpdifDevice); } } void AudioPolicyManagerTestMsd::TearDown() { mMsdOutputDevice.clear(); mMsdInputDevice.clear(); mDefaultOutputDevice.clear(); mSpdifDevice.clear(); AudioPolicyManagerTest::TearDown(); } TEST_F(AudioPolicyManagerTestMsd, InitSuccess) { TEST_P(AudioPolicyManagerTestMsd, InitSuccess) { ASSERT_TRUE(mMsdOutputDevice); ASSERT_TRUE(mMsdInputDevice); ASSERT_TRUE(mDefaultOutputDevice); } TEST_F(AudioPolicyManagerTestMsd, Dump) { TEST_P(AudioPolicyManagerTestMsd, Dump) { dumpToLog(); } TEST_F(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) { TEST_P(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) { const PatchCountCheck patchCount = snapshotPatchCount(); mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND, AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_P(AudioPolicyManagerTestMsd, PatchCreationSetReleaseMsdPatches) { const PatchCountCheck patchCount = snapshotPatchCount(); DeviceVector devices = mManager->getAvailableOutputDevices(); // Remove MSD output device to avoid patching to itself devices.remove(mMsdOutputDevice); ASSERT_EQ(mExpectedAudioPatchCount, devices.size()); mManager->setMsdPatches(&devices); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); // Dual patch: exercise creating one new audio patch and reusing another existing audio patch. DeviceVector singleDevice(devices[0]); mManager->releaseMsdPatches(singleDevice); ASSERT_EQ(mExpectedAudioPatchCount - 1, patchCount.deltaFromSnapshot()); mManager->setMsdPatches(&devices); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); mManager->releaseMsdPatches(devices); ASSERT_EQ(0, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedRoutesToMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrPcmRoutesToMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrEncodedPlusPcmRoutesToMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) { const PatchCountCheck patchCount = snapshotPatchCount(); audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE; getOutputForAttr(&selectedDeviceId, Loading @@ -449,7 +514,7 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd) ASSERT_EQ(0, patchCount.deltaFromSnapshot()); } TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { // Switch between formats that are supported and not supported by MSD. { const PatchCountCheck patchCount = snapshotPatchCount(); Loading @@ -459,9 +524,9 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT, nullptr /*output*/, &portId); ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId()); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); mManager->releaseOutput(portId); ASSERT_EQ(1, patchCount.deltaFromSnapshot()); ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot()); } { const PatchCountCheck patchCount = snapshotPatchCount(); Loading @@ -471,7 +536,7 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) { AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT, nullptr /*output*/, &portId); ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId()); ASSERT_EQ(-1, patchCount.deltaFromSnapshot()); ASSERT_EQ(-static_cast<int>(mExpectedAudioPatchCount), patchCount.deltaFromSnapshot()); mManager->releaseOutput(portId); ASSERT_EQ(0, patchCount.deltaFromSnapshot()); } Loading