Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6fb3449e authored by Michael Chan's avatar Michael Chan Committed by Mikhail Naganov
Browse files

APM: Create multiple MSD patches

This change modifies setMsdPatch() by first renaming to setMsdPatches()
and replaces its parameter with a pointer to DeviceVector, so that
multiple devices can be patched from MSD. If none are specified it will
establish MSD patches with all reported downstream output devices. It
tears down existing MSD patches and creates new ones for those MSD
patches that do not support new patch requests. We retain the existing
MSD patches that already support new patch requests.

In getBestMsdAudioProfileFor(), ensure output profiles considered for
evaluating the best matching audio profile is supported by the output
device under consideration.

Refactor by placing common code that tears down current MSD patches into
a new function called releaseMsdPatches().

When obtaining an output, getOutputForAttrInt() returns device ID of the
default device if its ID matches that of one of the output devices
provided by the engine.

Add testing for dual MSD patch creation by parameterizing existing MSD
tests for single and dual MSD patch cases. Add new unit test to exercise
setMsdPatches and releaseMsdPatches. Make private MSD module member
functions protected to enable testing.

Bug: 135620198
Test: audiopolicy_tests
Change-Id: I59a8976ce82dba04ca69347afc192e9143ef3629
parent 40e3a7a2
Loading
Loading
Loading
Loading
+95 −48
Original line number Original line Diff line number Diff line
@@ -1064,8 +1064,7 @@ status_t AudioPolicyManager::getOutputForAttrInt(
    *output = AUDIO_IO_HANDLE_NONE;
    *output = AUDIO_IO_HANDLE_NONE;
    if (!msdDevices.isEmpty()) {
    if (!msdDevices.isEmpty()) {
        *output = getOutputForDevices(msdDevices, session, *stream, config, flags);
        *output = getOutputForDevices(msdDevices, session, *stream, config, flags);
        sp<DeviceDescriptor> device = outputDevices.isEmpty() ? nullptr : outputDevices.itemAt(0);
        if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatches(&outputDevices) == NO_ERROR) {
        if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) {
            ALOGV("%s() Using MSD devices %s instead of devices %s",
            ALOGV("%s() Using MSD devices %s instead of devices %s",
                  __func__, msdDevices.toString().c_str(), outputDevices.toString().c_str());
                  __func__, msdDevices.toString().c_str(), outputDevices.toString().c_str());
        } else {
        } else {
@@ -1081,6 +1080,12 @@ status_t AudioPolicyManager::getOutputForAttrInt(
    }
    }


    *selectedDeviceId = getFirstDeviceId(outputDevices);
    *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)) {
    if (outputDevices.onlyContainsDevicesWithType(AUDIO_DEVICE_OUT_TELEPHONY_TX)) {
        *outputType = API_OUTPUT_TELEPHONY_TX;
        *outputType = API_OUTPUT_TELEPHONY_TX;
@@ -1223,24 +1228,9 @@ status_t AudioPolicyManager::openDirectOutput(audio_stream_type_t stream,
    sp<SwAudioOutputDescriptor> outputDesc =
    sp<SwAudioOutputDescriptor> outputDesc =
            new SwAudioOutputDescriptor(profile, mpClientInterface);
            new SwAudioOutputDescriptor(profile, mpClientInterface);


    String8 address = getFirstDeviceAddress(devices);
    // 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.
    // MSD patch may be using the only output stream that can service this request. Release
    releaseMsdPatches(devices);
    // 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;
            }
        }
    }


    status_t status = outputDesc->open(config, devices, stream, flags, output);
    status_t status = outputDesc->open(config, devices, stream, flags, output);


@@ -1414,7 +1404,8 @@ status_t AudioPolicyManager::getBestMsdAudioProfileFor(const sp<DeviceDescriptor
    }
    }
    AudioProfileVector deviceProfiles;
    AudioProfileVector deviceProfiles;
    for (const auto &outProfile : outputProfiles) {
    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());
            appendAudioProfiles(deviceProfiles, outProfile->getAudioProfiles());
        }
        }
    }
    }
@@ -1482,40 +1473,85 @@ PatchBuilder AudioPolicyManager::buildMsdPatch(const sp<DeviceDescriptor> &outpu
    return patchBuilder;
    return patchBuilder;
}
}


status_t AudioPolicyManager::setMsdPatch(const sp<DeviceDescriptor> &outputDevice) {
status_t AudioPolicyManager::setMsdPatches(const DeviceVector *outputDevices) {
    sp<DeviceDescriptor> device = outputDevice;
    DeviceVector devices;
    if (device == nullptr) {
    if (outputDevices != nullptr && outputDevices->size() > 0) {
        devices.add(*outputDevices);
    } else {
        // Use media strategy for unspecified output device. This should only
        // Use media strategy for unspecified output device. This should only
        // occur on checkForDeviceAndOutputChanges(). Device connection events may
        // occur on checkForDeviceAndOutputChanges(). Device connection events may
        // therefore invalidate explicit routing requests.
        // therefore invalidate explicit routing requests.
        DeviceVector devices = mEngine->getOutputDevicesForAttributes(
        devices = mEngine->getOutputDevicesForAttributes(
                    attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, false /*fromCache*/);
                    attributes_initializer(AUDIO_USAGE_MEDIA), nullptr, false /*fromCache*/);
        LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no outpudevice to set Msd Patch");
        LOG_ALWAYS_FATAL_IF(devices.isEmpty(), "no output device to set MSD patch");
        device = devices.itemAt(0);
    }
    }
    std::vector<PatchBuilder> patchesToCreate;
    ALOGV("%s() for device %s", __func__, device->toString().c_str());
    for (auto i = 0u; i < devices.size(); ++i) {
    PatchBuilder patchBuilder = buildMsdPatch(device);
        ALOGV("%s() for device %s", __func__, devices[i]->toString().c_str());
    const struct audio_patch* patch = patchBuilder.patch();
        patchesToCreate.push_back(buildMsdPatch(devices[i]));
    const AudioPatchCollection msdPatches = getMsdPatches();
    }
    if (!msdPatches.isEmpty()) {
    // Retain only the MSD patches associated with outputDevices request.
        LOG_ALWAYS_FATAL_IF(msdPatches.size() > 1,
    // Tear down the others, and create new ones as needed.
                "The current MSD prototype only supports one output patch");
    AudioPatchCollection patchesToRemove = getMsdPatches();
        sp<AudioPatch> currentPatch = msdPatches.valueAt(0);
    for (auto it = patchesToCreate.begin(); it != patchesToCreate.end(); ) {
        if (audio_patches_are_equal(&currentPatch->mPatch, patch)) {
        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;
        return NO_ERROR;
    }
    }
    for (auto i = 0u; i < patchesToRemove.size(); ++i) {
        auto &currentPatch = patchesToRemove.valueAt(i);
        releaseAudioPatch(currentPatch->getHandle(), mUidCached);
        releaseAudioPatch(currentPatch->getHandle(), mUidCached);
    }
    }
    status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
    status_t status = NO_ERROR;
            patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
    for (const auto &p : patchesToCreate) {
    ALOGE_IF(status != NO_ERROR, "%s() error %d creating MSD audio patch", __func__, status);
        auto currStatus = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
    ALOGI_IF(status == NO_ERROR, "%s() Patch created from MSD_IN to "
                p.patch(), 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
           "device:%s (format:%#x channels:%#x samplerate:%d)", __func__,
        char message[256];
             device->toString().c_str(), patch->sources[0].format,
        snprintf(message, sizeof(message), "%s() %s: creating MSD patch from device:IN_BUS to "
             patch->sources[0].channel_mask, patch->sources[0].sample_rate);
            "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;
    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_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                                   audio_output_flags_t flags,
                                                   audio_output_flags_t flags,
                                                   audio_format_t format,
                                                   audio_format_t format,
@@ -5319,8 +5355,13 @@ void AudioPolicyManager::closeOutput(audio_io_handle_t output)
            }
            }
        }
        }
        if (!directOutputOpen) {
        if (!directOutputOpen) {
            ALOGV("no direct outputs open, reset MSD patch");
            ALOGV("no direct outputs open, reset MSD patches");
            setMsdPatch();
            // 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();
        }
        }
    }
    }
}
}
@@ -5387,7 +5428,13 @@ void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> on
    if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend();
    if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend();
    updateDevicesAndOutputs();
    updateDevicesAndOutputs();
    if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
    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();
    }
    }
    // an event that changed routing likely occurred, inform upper layers
    // an event that changed routing likely occurred, inform upper layers
    mpClientInterface->onRoutingUpdated();
    mpClientInterface->onRoutingUpdated();
+8 −8
Original line number Original line Diff line number Diff line
@@ -848,13 +848,6 @@ protected:
        // end point.
        // end point.
        audio_port_handle_t mCallRxSourceClientPort = AUDIO_PORT_HANDLE_NONE;
        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
        // Support for Multi-Stream Decoder (MSD) module
        sp<DeviceDescriptor> getMsdAudioInDevice() const;
        sp<DeviceDescriptor> getMsdAudioInDevice() const;
        DeviceVector getMsdAudioOutDevices() const;
        DeviceVector getMsdAudioOutDevices() const;
@@ -864,7 +857,14 @@ private:
                                           audio_port_config *sourceConfig,
                                           audio_port_config *sourceConfig,
                                           audio_port_config *sinkConfig) const;
                                           audio_port_config *sinkConfig) const;
        PatchBuilder buildMsdPatch(const sp<DeviceDescriptor> &outputDevice) 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
        // If any, resolve any "dynamic" fields of an Audio Profiles collection
        void updateAudioProfiles(const sp<DeviceDescriptor>& devDesc, audio_io_handle_t ioHandle,
        void updateAudioProfiles(const sp<DeviceDescriptor>& devDesc, audio_io_handle_t ioHandle,
+2 −0
Original line number Original line Diff line number Diff line
@@ -29,6 +29,8 @@ class AudioPolicyTestManager : public AudioPolicyManager {
    using AudioPolicyManager::getOutputs;
    using AudioPolicyManager::getOutputs;
    using AudioPolicyManager::getAvailableOutputDevices;
    using AudioPolicyManager::getAvailableOutputDevices;
    using AudioPolicyManager::getAvailableInputDevices;
    using AudioPolicyManager::getAvailableInputDevices;
    using AudioPolicyManager::releaseMsdPatches;
    using AudioPolicyManager::setMsdPatches;
    using AudioPolicyManager::setSurroundFormatEnabled;
    using AudioPolicyManager::setSurroundFormatEnabled;
    uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
    uint32_t getAudioPortGeneration() const { return mAudioPortGeneration; }
};
};
+82 −17
Original line number Original line Diff line number Diff line
@@ -349,7 +349,17 @@ TEST_F(AudioPolicyManagerTest, CreateAudioPatchFromMix) {


// TODO: Add patch creation tests that involve already existing patch
// 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:
  protected:
    void SetUpManagerConfig() override;
    void SetUpManagerConfig() override;
    void TearDown() override;
    void TearDown() override;
@@ -357,8 +367,26 @@ class AudioPolicyManagerTestMsd : public AudioPolicyManagerTest {
    sp<DeviceDescriptor> mMsdOutputDevice;
    sp<DeviceDescriptor> mMsdOutputDevice;
    sp<DeviceDescriptor> mMsdInputDevice;
    sp<DeviceDescriptor> mMsdInputDevice;
    sp<DeviceDescriptor> mDefaultOutputDevice;
    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() {
void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
    // TODO: Consider using Serializer to load part of the config from a string.
    // TODO: Consider using Serializer to load part of the config from a string.
    AudioPolicyManagerTest::SetUpManagerConfig();
    AudioPolicyManagerTest::SetUpManagerConfig();
@@ -378,6 +406,19 @@ void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
    config.addDevice(mMsdOutputDevice);
    config.addDevice(mMsdOutputDevice);
    config.addDevice(mMsdInputDevice);
    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*/);
    sp<HwModule> msdModule = new HwModule(AUDIO_HARDWARE_MODULE_ID_MSD, 2 /*halVersionMajor*/);
    HwModuleCollection modules = config.getHwModules();
    HwModuleCollection modules = config.getHwModules();
    modules.add(msdModule);
    modules.add(msdModule);
@@ -413,64 +454,88 @@ void AudioPolicyManagerTestMsd::SetUpManagerConfig() {
            addOutputProfile(primaryEncodedOutputProfile);
            addOutputProfile(primaryEncodedOutputProfile);


    mDefaultOutputDevice = config.getDefaultOutputDevice();
    mDefaultOutputDevice = config.getDefaultOutputDevice();
    if (mExpectedAudioPatchCount == 2) {
        mSpdifDevice->addAudioProfile(dtsOutputProfile);
        primaryEncodedOutputProfile->addSupportedDevice(mSpdifDevice);
    }
}
}


void AudioPolicyManagerTestMsd::TearDown() {
void AudioPolicyManagerTestMsd::TearDown() {
    mMsdOutputDevice.clear();
    mMsdOutputDevice.clear();
    mMsdInputDevice.clear();
    mMsdInputDevice.clear();
    mDefaultOutputDevice.clear();
    mDefaultOutputDevice.clear();
    mSpdifDevice.clear();
    AudioPolicyManagerTest::TearDown();
    AudioPolicyManagerTest::TearDown();
}
}


TEST_F(AudioPolicyManagerTestMsd, InitSuccess) {
TEST_P(AudioPolicyManagerTestMsd, InitSuccess) {
    ASSERT_TRUE(mMsdOutputDevice);
    ASSERT_TRUE(mMsdOutputDevice);
    ASSERT_TRUE(mMsdInputDevice);
    ASSERT_TRUE(mMsdInputDevice);
    ASSERT_TRUE(mDefaultOutputDevice);
    ASSERT_TRUE(mDefaultOutputDevice);
}
}


TEST_F(AudioPolicyManagerTestMsd, Dump) {
TEST_P(AudioPolicyManagerTestMsd, Dump) {
    dumpToLog();
    dumpToLog();
}
}


TEST_F(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) {
TEST_P(AudioPolicyManagerTestMsd, PatchCreationOnSetForceUse) {
    const PatchCountCheck patchCount = snapshotPatchCount();
    const PatchCountCheck patchCount = snapshotPatchCount();
    mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND,
    mManager->setForceUse(AUDIO_POLICY_FORCE_FOR_ENCODED_SURROUND,
            AUDIO_POLICY_FORCE_ENCODED_SURROUND_ALWAYS);
            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();
    const PatchCountCheck patchCount = snapshotPatchCount();
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    getOutputForAttr(&selectedDeviceId,
    getOutputForAttr(&selectedDeviceId,
            AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
            AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
    ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
    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();
    const PatchCountCheck patchCount = snapshotPatchCount();
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    getOutputForAttr(&selectedDeviceId,
    getOutputForAttr(&selectedDeviceId,
            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
    ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
    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();
    const PatchCountCheck patchCount = snapshotPatchCount();
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    getOutputForAttr(&selectedDeviceId,
    getOutputForAttr(&selectedDeviceId,
            AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
            AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT);
    ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
    ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
    ASSERT_EQ(1, patchCount.deltaFromSnapshot());
    ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
    selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    getOutputForAttr(&selectedDeviceId,
    getOutputForAttr(&selectedDeviceId,
            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
            AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO, 48000);
    ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
    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();
    const PatchCountCheck patchCount = snapshotPatchCount();
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    getOutputForAttr(&selectedDeviceId,
    getOutputForAttr(&selectedDeviceId,
@@ -479,7 +544,7 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrUnsupportedFormatBypassesMsd)
    ASSERT_EQ(0, patchCount.deltaFromSnapshot());
    ASSERT_EQ(0, patchCount.deltaFromSnapshot());
}
}


TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
TEST_P(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
    // Switch between formats that are supported and not supported by MSD.
    // Switch between formats that are supported and not supported by MSD.
    {
    {
        const PatchCountCheck patchCount = snapshotPatchCount();
        const PatchCountCheck patchCount = snapshotPatchCount();
@@ -489,9 +554,9 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
                AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                AUDIO_FORMAT_AC3, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                nullptr /*output*/, &portId);
                nullptr /*output*/, &portId);
        ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
        ASSERT_EQ(selectedDeviceId, mDefaultOutputDevice->getId());
        ASSERT_EQ(1, patchCount.deltaFromSnapshot());
        ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
        mManager->releaseOutput(portId);
        mManager->releaseOutput(portId);
        ASSERT_EQ(1, patchCount.deltaFromSnapshot());
        ASSERT_EQ(mExpectedAudioPatchCount, patchCount.deltaFromSnapshot());
    }
    }
    {
    {
        const PatchCountCheck patchCount = snapshotPatchCount();
        const PatchCountCheck patchCount = snapshotPatchCount();
@@ -501,7 +566,7 @@ TEST_F(AudioPolicyManagerTestMsd, GetOutputForAttrFormatSwitching) {
                AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                AUDIO_FORMAT_DTS, AUDIO_CHANNEL_OUT_5POINT1, 48000, AUDIO_OUTPUT_FLAG_DIRECT,
                nullptr /*output*/, &portId);
                nullptr /*output*/, &portId);
        ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
        ASSERT_NE(selectedDeviceId, mMsdOutputDevice->getId());
        ASSERT_EQ(-1, patchCount.deltaFromSnapshot());
        ASSERT_EQ(-static_cast<int>(mExpectedAudioPatchCount), patchCount.deltaFromSnapshot());
        mManager->releaseOutput(portId);
        mManager->releaseOutput(portId);
        ASSERT_EQ(0, patchCount.deltaFromSnapshot());
        ASSERT_EQ(0, patchCount.deltaFromSnapshot());
    }
    }