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

Commit 15be9d2b authored by Mikhail Naganov's avatar Mikhail Naganov
Browse files

audiopolicy: Add support for the MSD prototype

MSD is a Multi-Stream Decoder. It's an optional module
that allows mixing of encoded surround streams with
PCM streams.

This patch adds elementary support for setting up
a patch between the MSD module and actual output device,
and prioritizing the MSD module's device for output.

The patch is always set up, and is automatically
re-establishes itself if the actual output device changes.

Bug: 63901775
Test: MSD prototype
Change-Id: I9efa714455dae10b58bd5cc5cdf5557c0227b40c
parent fa69dc61
Loading
Loading
Loading
Loading
+192 −10
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@

#include <inttypes.h>
#include <math.h>
#include <vector>

#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyEngineInstance.h>
@@ -38,7 +39,6 @@
#include <utils/Log.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicyHelper.h>
#include <media/PatchBuilder.h>
#include <private/android_filesystem_config.h>
#include <soundtrigger/SoundTrigger.h>
#include <system/audio.h>
@@ -82,6 +82,16 @@ static const audio_format_t AAC_FORMATS[] = {
    AUDIO_FORMAT_AAC_XHE,
};

// Compressed formats for MSD module, ordered from most preferred to least preferred.
static const std::vector<audio_format_t> compressedFormatsOrder = {{
        AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
        AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
// Channel masks for MSD module, 3D > 2D > 1D ordering (most preferred to least preferred).
static const std::vector<audio_channel_mask_t> surroundChannelMasksOrder = {{
        AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2,
        AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
        AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};

// ----------------------------------------------------------------------------
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
@@ -225,6 +235,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
            audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
            updateCallRouting(newDevice);
        }
        const audio_devices_t msdOutDevice = getMsdAudioOutDeviceTypes();
        for (size_t i = 0; i < mOutputs.size(); i++) {
            sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
            if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
@@ -232,7 +243,8 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(audio_devices_t device,
                // do not force device change on duplicated output because if device is 0, it will
                // also force a device 0 for the two outputs it is duplicated to which may override
                // a valid device selection on those outputs.
                bool force = !desc->isDuplicated()
                bool force = (msdOutDevice == AUDIO_DEVICE_NONE || msdOutDevice != desc->device())
                        && !desc->isDuplicated()
                        && (!device_distinguishes_on_address(device)
                                // always force when disconnecting (a non-duplicated device)
                                || (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
@@ -525,7 +537,7 @@ sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
}

sp<DeviceDescriptor> AudioPolicyManager::findDevice(
        const DeviceVector& devices, audio_devices_t device) {
        const DeviceVector& devices, audio_devices_t device) const {
    DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
    ALOG_ASSERT(!deviceList.isEmpty(),
            "%s() selected device type %#x is not in devices list", __func__, device);
@@ -777,6 +789,7 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
    routing_strategy strategy;
    audio_devices_t device;
    audio_port_handle_t requestedDeviceId = *selectedDeviceId;
    audio_devices_t msdDevice = getMsdAudioOutDeviceTypes();

    if (attr != NULL) {
        if (!isValidAttributes(attr)) {
@@ -869,7 +882,20 @@ status_t AudioPolicyManager::getOutputForAttr(const audio_attributes_t *attr,
          "flags %#x",
          device, config->sample_rate, config->format, config->channel_mask, *flags);

    *output = AUDIO_IO_HANDLE_NONE;
    if (msdDevice != AUDIO_DEVICE_NONE) {
        *output = getOutputForDevice(msdDevice, session, *stream, config, flags);
        if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) {
            ALOGV("%s() Using MSD device 0x%x instead of device 0x%x",
                    __func__, msdDevice, device);
            device = msdDevice;
        } else {
            *output = AUDIO_IO_HANDLE_NONE;
        }
    }
    if (*output == AUDIO_IO_HANDLE_NONE) {
        *output = getOutputForDevice(device, session, *stream, config, flags);
    }
    if (*output == AUDIO_IO_HANDLE_NONE) {
        mOutputRoutes.removeRoute(session);
        return INVALID_OPERATION;
@@ -1052,6 +1078,164 @@ non_direct_output:
    return output;
}

sp<DeviceDescriptor> AudioPolicyManager::getMsdAudioInDevice() const {
    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
    if (msdModule != 0) {
        DeviceVector msdInputDevices = mAvailableInputDevices.getDevicesFromHwModule(
                msdModule->getHandle());
        if (!msdInputDevices.isEmpty()) return msdInputDevices.itemAt(0);
    }
    return 0;
}

audio_devices_t AudioPolicyManager::getMsdAudioOutDeviceTypes() const {
    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
    if (msdModule != 0) {
        return mAvailableOutputDevices.getDeviceTypesFromHwModule(msdModule->getHandle());
    }
    return AUDIO_DEVICE_NONE;
}

const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
    AudioPatchCollection msdPatches;
    audio_module_handle_t msdModuleHandle = mHwModules.getModuleFromName(
            AUDIO_HARDWARE_MODULE_ID_MSD)->getHandle();
    if (msdModuleHandle == AUDIO_MODULE_HANDLE_NONE) return msdPatches;
    for (size_t i = 0; i < mAudioPatches.size(); ++i) {
        sp<AudioPatch> patch = mAudioPatches.valueAt(i);
        for (size_t j = 0; j < patch->mPatch.num_sources; ++j) {
            const struct audio_port_config *source = &patch->mPatch.sources[j];
            if (source->type == AUDIO_PORT_TYPE_DEVICE &&
                    source->ext.device.hw_module == msdModuleHandle) {
                msdPatches.addAudioPatch(patch->mHandle, patch);
            }
        }
    }
    return msdPatches;
}

status_t AudioPolicyManager::getBestMsdAudioProfileFor(audio_devices_t outputDevice,
        bool hwAvSync, audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
{
    sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
    if (msdModule == nullptr) {
        ALOGE("%s() unable to get MSD module", __func__);
        return NO_INIT;
    }
    sp<HwModule> deviceModule = mHwModules.getModuleForDevice(outputDevice);
    if (deviceModule == nullptr) {
        ALOGE("%s() unable to get module for %#x", __func__, outputDevice);
        return NO_INIT;
    }
    const InputProfileCollection &inputProfiles = msdModule->getInputProfiles();
    if (inputProfiles.isEmpty()) {
        ALOGE("%s() no input profiles for MSD module", __func__);
        return NO_INIT;
    }
    const OutputProfileCollection &outputProfiles = deviceModule->getOutputProfiles();
    if (outputProfiles.isEmpty()) {
        ALOGE("%s() no output profiles for device %#x", __func__, outputDevice);
        return NO_INIT;
    }
    AudioProfileVector msdProfiles;
    // Each IOProfile represents a MixPort from audio_policy_configuration.xml
    for (const auto &inProfile : inputProfiles) {
        if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
            msdProfiles.appendVector(inProfile->getAudioProfiles());
        }
    }
    AudioProfileVector deviceProfiles;
    for (const auto &outProfile : outputProfiles) {
        if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) {
            deviceProfiles.appendVector(outProfile->getAudioProfiles());
        }
    }
    struct audio_config_base bestSinkConfig;
    status_t result = msdProfiles.findBestMatchingOutputConfig(deviceProfiles,
            compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
            &bestSinkConfig);
    if (result != NO_ERROR) {
        return result;
        ALOGD("%s() no matching profiles found for device: %#x, hwAvSync: %d",
                __func__, outputDevice, hwAvSync);
    }
    sinkConfig->sample_rate = bestSinkConfig.sample_rate;
    sinkConfig->channel_mask = bestSinkConfig.channel_mask;
    sinkConfig->format = bestSinkConfig.format;
    // For encoded streams force direct flag to prevent downstream mixing.
    sinkConfig->flags.output = static_cast<audio_output_flags_t>(
            sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_DIRECT);
    sourceConfig->sample_rate = bestSinkConfig.sample_rate;
    // Specify exact channel mask to prevent guessing by bit count in PatchPanel.
    sourceConfig->channel_mask = audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
    sourceConfig->format = bestSinkConfig.format;
    // Copy input stream directly without any processing (e.g. resampling).
    sourceConfig->flags.input = static_cast<audio_input_flags_t>(
            sourceConfig->flags.input | AUDIO_INPUT_FLAG_DIRECT);
    if (hwAvSync) {
        sinkConfig->flags.output = static_cast<audio_output_flags_t>(
                sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
        sourceConfig->flags.input = static_cast<audio_input_flags_t>(
                sourceConfig->flags.input | AUDIO_INPUT_FLAG_HW_AV_SYNC);
    }
    const unsigned int config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE |
            AUDIO_PORT_CONFIG_CHANNEL_MASK | AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_FLAGS;
    sinkConfig->config_mask |= config_mask;
    sourceConfig->config_mask |= config_mask;
    return NO_ERROR;
}

PatchBuilder AudioPolicyManager::buildMsdPatch(audio_devices_t outputDevice) const
{
    PatchBuilder patchBuilder;
    patchBuilder.addSource(getMsdAudioInDevice()).
            addSink(findDevice(mAvailableOutputDevices, outputDevice));
    audio_port_config sourceConfig = patchBuilder.patch()->sources[0];
    audio_port_config sinkConfig = patchBuilder.patch()->sinks[0];
    // TODO: Figure out whether MSD module has HW_AV_SYNC flag set in the AP config file.
    // For now, we just forcefully try with HwAvSync first.
    status_t res = getBestMsdAudioProfileFor(outputDevice, true /*hwAvSync*/,
            &sourceConfig, &sinkConfig) == NO_ERROR ? NO_ERROR :
            getBestMsdAudioProfileFor(
                    outputDevice, false /*hwAvSync*/, &sourceConfig, &sinkConfig);
    if (res == NO_ERROR) {
        // Found a matching profile for encoded audio. Re-create PatchBuilder with this config.
        return (PatchBuilder()).addSource(sourceConfig).addSink(sinkConfig);
    }
    ALOGV("%s() no matching profile found. Fall through to default PCM patch"
            " supporting PCM format conversion.", __func__);
    return patchBuilder;
}

status_t AudioPolicyManager::setMsdPatch(audio_devices_t outputDevice) {
    ALOGV("%s() for outputDevice %#x", __func__, outputDevice);
    if (outputDevice == AUDIO_DEVICE_NONE) {
        // Use media strategy for unspecified output device. This should only
        // occur on checkForDeviceAndOutputChanges(). Device connection events may
        // therefore invalidate explicit routing requests.
        outputDevice = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
    }
    PatchBuilder patchBuilder = buildMsdPatch(outputDevice);
    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(&currentPatch->mPatch, patch)) {
            return NO_ERROR;
        }
        releaseAudioPatch(currentPatch->mHandle, 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:%#x (format:%#x channels:%#x samplerate:%d)", __func__, outputDevice,
           patch->sources[0].format, patch->sources[0].channel_mask, patch->sources[0].sample_rate);
    return status;
}

audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                                       audio_output_flags_t flags,
                                                       audio_format_t format)
@@ -4600,19 +4784,17 @@ SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
    return outputs;
}

void AudioPolicyManager::checkForDeviceAndOutputChanges()
{
    checkForDeviceAndOutputChanges([](){ return false; });
}

void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked)
{
    // checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
    // output is suspended before any tracks are moved to it
    checkA2dpSuspend();
    checkOutputForAllStrategies();
    if (onOutputsChecked()) checkA2dpSuspend();
    if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend();
    updateDevicesAndOutputs();
    if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
        setMsdPatch();
    }
}

void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
+14 −3
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <utils/SortedVector.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
#include <media/PatchBuilder.h>
#include "AudioPolicyInterface.h"

#include <AudioPolicyManagerInterface.h>
@@ -407,8 +408,7 @@ protected:
        // if 'onOutputsChecked' callback is provided, it is executed after the outputs
        // check via 'checkOutputForAllStrategies'. If the callback returns 'true',
        // A2DP suspend status is rechecked.
        void checkForDeviceAndOutputChanges();
        void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked);
        void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked = nullptr);

        // checks and if necessary changes outputs used for all strategies.
        // must be called every time a condition that affects the output choice for a given strategy
@@ -506,7 +506,7 @@ protected:
        uint32_t updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs = 0);
        sp<AudioPatch> createTelephonyPatch(bool isRx, audio_devices_t device, uint32_t delayMs);
        sp<DeviceDescriptor> findDevice(
                const DeviceVector& devices, audio_devices_t device);
                const DeviceVector& devices, audio_devices_t device) const;

        // if argument "device" is different from AUDIO_DEVICE_NONE,  startSource() will force
        // the re-evaluation of the output device.
@@ -620,6 +620,17 @@ private:

        status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats);

        // Support for Multi-Stream Decoder (MSD) module
        sp<DeviceDescriptor> getMsdAudioInDevice() const;
        audio_devices_t getMsdAudioOutDeviceTypes() const;
        const AudioPatchCollection getMsdPatches() const;
        status_t getBestMsdAudioProfileFor(audio_devices_t outputDevice,
                                           bool hwAvSync,
                                           audio_port_config *sourceConfig,
                                           audio_port_config *sinkConfig) const;
        PatchBuilder buildMsdPatch(audio_devices_t outputDevice) const;
        status_t setMsdPatch(audio_devices_t outputDevice = AUDIO_DEVICE_NONE);

        // If any, resolve any "dynamic" fields of an Audio Profiles collection
        void updateAudioProfiles(audio_devices_t device, audio_io_handle_t ioHandle,
                AudioProfileVector &profiles);