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

Commit e191d1b6 authored by Eric Laurent's avatar Eric Laurent
Browse files

audio policy: create spatializer mixer only when needed

Only open a spatializer output when spatial audio is enabled
in order to save memory resources consumed by the dedicated mixer and
audio effect when instantiated.

For the special case where the spatializer output is the only route
available to a specific device, leave it open. This can happen when the
software necoder path is used for Bluetooth A2DP.

Bug: 227740874
Test: make and music playback with and without spatial audio

Change-Id: Id149d0ce000c939c7f45e63b47f2fd1d7a98995a
parent 09dcfbe9
Loading
Loading
Loading
Loading
+86 −55
Original line number Diff line number Diff line
@@ -287,9 +287,12 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript
                    sp<SwAudioOutputDescriptor> desc = mOutputs.valueFor(output);
                    // close unused outputs after device disconnection or direct outputs that have
                    // been opened by checkOutputsForDevice() to query dynamic parameters
                    // "outputs" vector never contains duplicated outputs
                    if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)
                            || (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
                                (desc->mDirectOpenCount == 0))) {
                                (desc->mDirectOpenCount == 0))
                            || (((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) &&
                                !isOutputOnlyAvailableRouteToSomeDevice(desc))) {
                        clearAudioSourcesForOutput(output);
                        closeOutput(output);
                    }
@@ -5361,6 +5364,29 @@ void AudioPolicyManager::checkVirtualizerClientRoutes() {
    }
}


bool AudioPolicyManager::isOutputOnlyAvailableRouteToSomeDevice(
        const sp<SwAudioOutputDescriptor>& outputDesc) {
    if (outputDesc->isDuplicated()) {
        return false;
    }
    DeviceVector devices = outputDesc->supportedDevices();
    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        if (desc == outputDesc || desc->isDuplicated()) {
            continue;
        }
        DeviceVector sharedDevices = desc->filterSupportedDevices(devices);
        if (!sharedDevices.isEmpty()
                && (desc->devicesSupportEncodedFormats(sharedDevices.types())
                    == outputDesc->devicesSupportEncodedFormats(sharedDevices.types()))) {
            return false;
        }
    }
    return true;
}


status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mixerConfig,
                                                        const audio_attributes_t *attr,
                                                        audio_io_handle_t *output) {
@@ -5376,80 +5402,67 @@ status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mix
    }
    if (!canBeSpatializedInt(
            attr, configPtr, devicesTypeAddress)) {
        ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__);
        ALOGV("%s provided attributes or mixer config cannot be spatialized", __func__);
        return BAD_VALUE;
    }

    sp<IOProfile> profile =
            getSpatializerOutputProfile(configPtr, devicesTypeAddress);
    if (profile == nullptr) {
        ALOGW("%s no suitable output profile for provided attributes or mixer config", __func__);
        ALOGV("%s no suitable output profile for provided attributes or mixer config", __func__);
        return BAD_VALUE;
    }

    if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile
            && configPtr != nullptr
            && configPtr->channel_mask == mSpatializerOutput->mMixerChannelMask) {
        *output = mSpatializerOutput->mIoHandle;
        ALOGV("%s returns current spatializer output %d", __func__, *output);
        return NO_ERROR;
    }
    mSpatializerOutput.clear();
    std::vector<sp<SwAudioOutputDescriptor>> spatializerOutputs;
    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        if (!desc->isDuplicated() && desc->mProfile == profile) {
            ALOGV("%s found output %d for spatializer profile", __func__, desc->mIoHandle);
            mSpatializerOutput = desc;
            break;
        if (!desc->isDuplicated()
                && (desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) {
            spatializerOutputs.push_back(desc);
            ALOGV("%s adding opened spatializer Output %d", __func__, desc->mIoHandle);
        }
    }
    if (mSpatializerOutput == nullptr) {
        ALOGW("%s no opened spatializer output for profile %s",
                __func__, profile->getName().c_str());
        return BAD_VALUE;
    mSpatializerOutput.clear();
    bool outputsChanged = false;
    for (const auto& desc : spatializerOutputs) {
        if (desc->mProfile == profile
                && (configPtr == nullptr
                   || configPtr->channel_mask == desc->mMixerChannelMask)) {
            mSpatializerOutput = desc;
            ALOGV("%s reusing current spatializer output %d", __func__, desc->mIoHandle);
        } else {
            ALOGV("%s closing spatializerOutput output %d to match channel mask %#x"
                    " and devices %s", __func__, desc->mIoHandle,
                    configPtr != nullptr ? configPtr->channel_mask : 0,
                    devices.toString().c_str());
            closeOutput(desc->mIoHandle);
            outputsChanged = true;
        }
    }

    if (configPtr != nullptr
            && configPtr->channel_mask != mSpatializerOutput->mMixerChannelMask) {
        audio_config_base_t savedMixerConfig = {
            .sample_rate = mSpatializerOutput->getSamplingRate(),
            .format = mSpatializerOutput->getFormat(),
            .channel_mask = mSpatializerOutput->mMixerChannelMask,
        };
        DeviceVector savedDevices = mSpatializerOutput->devices();

        ALOGV("%s reopening spatializer output to match channel mask %#x (current mask %#x)",
            __func__, configPtr->channel_mask, mSpatializerOutput->mMixerChannelMask);

        closeOutput(mSpatializerOutput->mIoHandle);
        //from now on mSpatializerOutput is null

    if (mSpatializerOutput == nullptr) {
        sp<SwAudioOutputDescriptor> desc =
                openOutputWithProfileAndDevice(profile, devices, mixerConfig);
        if (desc == nullptr) {
            // re open the spatializer output with previous channel mask
            desc = openOutputWithProfileAndDevice(profile, savedDevices, &savedMixerConfig);
            if (desc == nullptr) {
                ALOGE("%s failed to restore mSpatializerOutput with previous config", __func__);
            } else {
        if (desc != nullptr) {
            mSpatializerOutput = desc;
            outputsChanged = true;
        }
            mPreviousOutputs = mOutputs;
            mpClientInterface->onAudioPortListUpdate();
            *output = AUDIO_IO_HANDLE_NONE;
            ALOGW("%s could not open spatializer output with requested config", __func__);
            return BAD_VALUE;
    }
        mSpatializerOutput = desc;

    checkVirtualizerClientRoutes();

    if (outputsChanged) {
        mPreviousOutputs = mOutputs;
        mpClientInterface->onAudioPortListUpdate();
    }

    checkVirtualizerClientRoutes();

    if (mSpatializerOutput == nullptr) {
        ALOGV("%s could not open spatializer output with requested config", __func__);
        return BAD_VALUE;
    }
    *output = mSpatializerOutput->mIoHandle;
    ALOGV("%s returns new spatializer output %d", __func__, *output);
    return NO_ERROR;
    ALOGV("%s returning new spatializer output %d", __func__, *output);
    return OK;
}

status_t AudioPolicyManager::releaseSpatializerOutput(audio_io_handle_t output) {
@@ -5460,9 +5473,12 @@ status_t AudioPolicyManager::releaseSpatializerOutput(audio_io_handle_t output)
        return BAD_VALUE;
    }

    mSpatializerOutput.clear();

    if (!isOutputOnlyAvailableRouteToSomeDevice(mSpatializerOutput)) {
        ALOGV("%s closing spatializer output %d", __func__, mSpatializerOutput->mIoHandle);
        closeOutput(mSpatializerOutput->mIoHandle);
        //from now on mSpatializerOutput is null
        checkVirtualizerClientRoutes();
    }

    return NO_ERROR;
}
@@ -5739,6 +5755,21 @@ void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
            inputDesc->close();
        }
    }

    // Check if spatializer outputs can be closed until used.
    // mOutputs vector never contains duplicated outputs at this point.
    std::vector<audio_io_handle_t> outputsClosed;
    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        if ((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0
                && !isOutputOnlyAvailableRouteToSomeDevice(desc)) {
            outputsClosed.push_back(desc->mIoHandle);
            desc->close();
        }
    }
    for (auto output : outputsClosed) {
        removeOutput(output);
    }
}

void AudioPolicyManager::addOutput(audio_io_handle_t output,
+10 −0
Original line number Diff line number Diff line
@@ -1096,6 +1096,16 @@ private:

        void checkVirtualizerClientRoutes();

        /**
         * @brief Returns true if at least one device can only be reached via the output passed
         * as argument. Always returns false for duplicated outputs.
         * This can be used to decide if an output can be closed without forbidding
         * playback to any given device.
         * @param outputDesc the output to consider
         * @return true if at least one device can only be reached via the output.
         */
        bool isOutputOnlyAvailableRouteToSomeDevice(const sp<SwAudioOutputDescriptor>& outputDesc);

        /**
         * @brief getInputForDevice selects an input handle for a given input device and
         * requester context