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

Commit e89c283a authored by Eric Laurent's avatar Eric Laurent Committed by Android (Google) Code Review
Browse files

Merge "audio policy: update spatializer policy" into sc-v2-dev

parents e96575ed 39095983
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -195,6 +195,10 @@ public:

    audio_output_flags_t getOutputFlags() const { return mFlags; }
    float getSpeed() const { return mSpeed; }

    bool canBeSpatialized() const { return (mAttr.flags
            & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) == 0; }

protected:
    // for numerous
    friend class PlaybackThread;
+76 −23
Original line number Diff line number Diff line
@@ -2039,6 +2039,7 @@ AudioFlinger::PlaybackThread::~PlaybackThread()
    free(mSinkBuffer);
    free(mMixerBuffer);
    free(mEffectBuffer);
    free(mEffectToSinkBuffer);
}

// Thread virtuals
@@ -3001,11 +3002,18 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l()
    // Originally this was int16_t[] array, need to remove legacy implications.
    free(mSinkBuffer);
    mSinkBuffer = NULL;
    free(mEffectToSinkBuffer);
    mEffectToSinkBuffer = nullptr;

    // For sink buffer size, we use the frame size from the downstream sink to avoid problems
    // with non PCM formats for compressed music, e.g. AAC, and Offload threads.
    const size_t sinkBufferSize = mNormalFrameCount * mFrameSize;
    (void)posix_memalign(&mSinkBuffer, 32, sinkBufferSize);

    if (mType == SPATIALIZER) {
        (void)posix_memalign(&mEffectToSinkBuffer, 32, sinkBufferSize);
    }

    // We resize the mMixerBuffer according to the requirements of the sink buffer which
    // drives the output.
    free(mMixerBuffer);
@@ -3836,11 +3844,11 @@ bool AudioFlinger::PlaybackThread::threadLoop()
            //
            // mMixerBufferValid is only set true by MixerThread::prepareTracks_l().
            // TODO use mSleepTimeUs == 0 as an additional condition.
            uint32_t mixerChannelCount = mEffectBufferValid ?
                        audio_channel_count_from_out_mask(mMixerChannelMask) : mChannelCount;
            if (mMixerBufferValid) {
                void *buffer = mEffectBufferValid ? mEffectBuffer : mSinkBuffer;
                audio_format_t format = mEffectBufferValid ? mEffectBufferFormat : mFormat;
                uint32_t channelCount = mEffectBufferValid ?
                            audio_channel_count_from_out_mask(mMixerChannelMask) : mChannelCount;

                // mono blend occurs for mixer threads only (not direct or offloaded)
                // and is handled here if we're going directly to the sink.
@@ -3858,7 +3866,7 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                }

                memcpy_by_audio_format(buffer, format, mMixerBuffer, mMixerBufferFormat,
                        mNormalFrameCount * (channelCount + mHapticChannelCount));
                        mNormalFrameCount * (mixerChannelCount + mHapticChannelCount));

                // If we're going directly to the sink and there are haptic channels,
                // we should adjust channels as the sample data is partially interleaved
@@ -3891,8 +3899,11 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                            && activeHapticSessionId == effectChains[i]->sessionId()) {
                        // Haptic data is active in this case, copy it directly from
                        // in buffer to out buffer.
                        uint32_t channelCount =
                                effectChains[i]->sessionId() == AUDIO_SESSION_OUTPUT_STAGE ?
                                        mixerChannelCount : mChannelCount;
                        const size_t audioBufferSize = mNormalFrameCount
                                * audio_bytes_per_frame(mChannelCount, EFFECT_BUFFER_FORMAT);
                                * audio_bytes_per_frame(channelCount, EFFECT_BUFFER_FORMAT);
                        memcpy_by_audio_format(
                                (uint8_t*)effectChains[i]->outBuffer() + audioBufferSize,
                                EFFECT_BUFFER_FORMAT,
@@ -3932,8 +3943,23 @@ bool AudioFlinger::PlaybackThread::threadLoop()
                mBalance.process((float *)mEffectBuffer, mNormalFrameCount);
            }

            if (mType == SPATIALIZER) {
                memcpy_by_audio_format(mEffectToSinkBuffer, mFormat, mEffectBuffer,
                        mEffectBufferFormat,
                        mNormalFrameCount * (mChannelCount + mHapticChannelCount));
                accumulate_by_audio_format(mSinkBuffer, mEffectToSinkBuffer, mFormat,
                                           mNormalFrameCount * mChannelCount);
                const size_t audioBufferSize = mNormalFrameCount
                        * audio_bytes_per_frame(mChannelCount, mFormat);
                memcpy_by_audio_format(
                        (uint8_t*)mSinkBuffer + audioBufferSize,
                        mFormat,
                        (uint8_t*)mEffectToSinkBuffer + audioBufferSize,
                        mFormat, mNormalFrameCount * mHapticChannelCount);
            } else {
                memcpy_by_audio_format(mSinkBuffer, mFormat, mEffectBuffer, mEffectBufferFormat,
                        mNormalFrameCount * (mChannelCount + mHapticChannelCount));
            }
            // The sample data is partially interleaved when haptic channels exist,
            // we need to adjust channels here.
            if (mHapticChannelCount > 0) {
@@ -4588,6 +4614,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
                && Intersection(outDeviceTypes(), getAudioDeviceOutAllA2dpSet()).empty();
        break;
    }
    ALOG_ASSERT(initFastMixer && mType == SPATIALIZER);
    ALOGW_IF(initFastMixer == false && mFrameCount < mNormalFrameCount,
            "FastMixer is preferred for this sink as frameCount %zu is less than threshold %zu",
            mFrameCount, mNormalFrameCount);
@@ -4946,6 +4973,9 @@ void AudioFlinger::MixerThread::threadLoop_sleepTime()
        // before effects processing or output.
        if (mMixerBufferValid) {
            memset(mMixerBuffer, 0, mMixerBufferSize);
            if (mType == SPATIALIZER) {
                memset(mSinkBuffer, 0, mSinkBufferSize);
            }
        } else {
            memset(mSinkBuffer, 0, mSinkBufferSize);
        }
@@ -5438,11 +5468,21 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                trackId,
                AudioMixer::TRACK,
                AudioMixer::CHANNEL_MASK, (void *)(uintptr_t)track->channelMask());

            if (mType == SPATIALIZER && !track->canBeSpatialized()) {
                mAudioMixer->setParameter(
                    trackId,
                    AudioMixer::TRACK,
                    AudioMixer::MIXER_CHANNEL_MASK,
                    (void *)(uintptr_t)(mChannelMask | mHapticChannelMask));
            } else {
                mAudioMixer->setParameter(
                    trackId,
                    AudioMixer::TRACK,
                    AudioMixer::MIXER_CHANNEL_MASK,
                    (void *)(uintptr_t)(mMixerChannelMask | mHapticChannelMask));
            }

            // limit track sample rate to 2 x output sample rate, which changes at re-configuration
            uint32_t maxSampleRate = mSampleRate * AUDIO_RESAMPLER_DOWN_RATIO_MAX;
            uint32_t reqSampleRate = proxy->getSampleRate();
@@ -5479,6 +5519,16 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
            if (mMixerBufferEnabled
                    && (track->mainBuffer() == mSinkBuffer
                            || track->mainBuffer() == mMixerBuffer)) {
                if (mType == SPATIALIZER && !track->canBeSpatialized()) {
                    mAudioMixer->setParameter(
                            trackId,
                            AudioMixer::TRACK,
                            AudioMixer::MIXER_FORMAT, (void *)mFormat);
                    mAudioMixer->setParameter(
                            trackId,
                            AudioMixer::TRACK,
                            AudioMixer::MAIN_BUFFER, (void *)mSinkBuffer);
                } else {
                    mAudioMixer->setParameter(
                            trackId,
                            AudioMixer::TRACK,
@@ -5489,6 +5539,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
                            AudioMixer::MAIN_BUFFER, (void *)mMixerBuffer);
                    // TODO: override track->mainBuffer()?
                    mMixerBufferValid = true;
                }
            } else {
                mAudioMixer->setParameter(
                        trackId,
@@ -5678,8 +5729,10 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac
    // sink or mix buffer must be cleared if all tracks are connected to an
    // effect chain as in this case the mixer will not write to the sink or mix buffer
    // and track effects will accumulate into it
    if ((mBytesRemaining == 0) && ((mixedTracks != 0 && mixedTracks == tracksWithEffect) ||
            (mixedTracks == 0 && fastTracks > 0))) {
    // always clear sink buffer for spatializer output as the output of the spatializer
    // effect will be accumulated into it
    if ((mBytesRemaining == 0) && (((mixedTracks != 0 && mixedTracks == tracksWithEffect) ||
            (mixedTracks == 0 && fastTracks > 0)) || (mType == SPATIALIZER))) {
        // FIXME as a performance optimization, should remember previous zero status
        if (mMixerBufferValid) {
            memset(mMixerBuffer, 0, mMixerBufferSize);
+5 −0
Original line number Diff line number Diff line
@@ -1122,6 +1122,11 @@ protected:
    // for any processing (including output processing).
    bool                            mEffectBufferValid;

    // Frame size aligned buffer used to convert mEffectBuffer samples to mSinkBuffer format prior
    // to accumulate into mSinkBuffer on SPATIALIZER threads
    void*                           mEffectToSinkBuffer = nullptr;


    // suspend count, > 0 means suspended.  While suspended, the thread continues to pull from
    // tracks and mix, but doesn't write to HAL.  A2DP and SCO HAL implementations can't handle
    // concurrent use of both of them, so Audio Policy Service suspends one of the threads to
+104 −42
Original line number Diff line number Diff line
@@ -248,9 +248,7 @@ status_t AudioPolicyManager::setDeviceConnectionStateInt(const sp<DeviceDescript
                    // been opened by checkOutputsForDevice() to query dynamic parameters
                    if ((state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE)
                            || (((desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0) &&
                                (desc->mDirectOpenCount == 0))
                            || (((desc->mFlags & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0) &&
                                (desc != mSpatializerOutput))) {
                                (desc->mDirectOpenCount == 0))) {
                        clearAudioSourcesForOutput(output);
                        closeOutput(output);
                    }
@@ -928,8 +926,7 @@ sp<IOProfile> AudioPolicyManager::getProfileForOutput(
}

sp<IOProfile> AudioPolicyManager::getSpatializerOutputProfile(
        const audio_config_t *config __unused, const AudioDeviceTypeAddrVector &devices,
        bool forOpening) const
        const audio_config_t *config __unused, const AudioDeviceTypeAddrVector &devices) const
{
    for (const auto& hwModule : mHwModules) {
        for (const auto& curProfile : hwModule->getOutputProfiles()) {
@@ -947,9 +944,6 @@ sp<IOProfile> AudioPolicyManager::getSpatializerOutputProfile(
                    continue;
                }
            }
            if (forOpening && !curProfile->canOpenNewIo()) {
                continue;
            }
            ALOGV("%s found profile %s", __func__, curProfile->getName().c_str());
            return curProfile;
        }
@@ -4843,6 +4837,21 @@ sp<SourceClientDescriptor> AudioPolicyManager::getSourceForAttributesOnOutput(
    return source;
}

/* static */
bool AudioPolicyManager::isChannelMaskSpatialized(audio_channel_mask_t channels) {
    switch (channels) {
        case AUDIO_CHANNEL_OUT_5POINT1:
        case AUDIO_CHANNEL_OUT_5POINT1POINT2:
        case AUDIO_CHANNEL_OUT_5POINT1POINT4:
        case AUDIO_CHANNEL_OUT_7POINT1:
        case AUDIO_CHANNEL_OUT_7POINT1POINT2:
        case AUDIO_CHANNEL_OUT_7POINT1POINT4:
            return true;
        default:
            return false;
    }
}

bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr,
                                      const audio_config_t *config,
                                      const AudioDeviceTypeAddrVector &devices)  const
@@ -4851,17 +4860,21 @@ bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr,
    // the AUDIO_ATTRIBUTES_INITIALIZER value.
    // If attributes are specified, current policy is to only allow spatialization for media
    // and game usages.
    if (attr != nullptr && *attr != AUDIO_ATTRIBUTES_INITIALIZER &&
            attr->usage != AUDIO_USAGE_MEDIA && attr->usage != AUDIO_USAGE_GAME) {
    if (attr != nullptr && *attr != AUDIO_ATTRIBUTES_INITIALIZER) {
        if (attr->usage != AUDIO_USAGE_MEDIA && attr->usage != AUDIO_USAGE_GAME) {
            return false;
        }
        if ((attr->flags & (AUDIO_FLAG_CONTENT_SPATIALIZED | AUDIO_FLAG_NEVER_SPATIALIZE)) != 0) {
            return false;
        }
    }

    // The caller can have the devices criteria ignored by passing and empty vector, and
    // getSpatializerOutputProfile() will ignore the devices when looking for a match.
    // Otherwise an output profile supporting a spatializer effect that can be routed
    // to the specified devices must exist.
    sp<IOProfile> profile =
            getSpatializerOutputProfile(config, devices, false /*forOpening*/);
            getSpatializerOutputProfile(config, devices);
    if (profile == nullptr) {
        return false;
    }
@@ -4869,37 +4882,36 @@ bool AudioPolicyManager::canBeSpatialized(const audio_attributes_t *attr,
    // The caller can have the audio config criteria ignored by either passing a null ptr or
    // the AUDIO_CONFIG_INITIALIZER value.
    // If an audio config is specified, current policy is to only allow spatialization for
    // 5.1, 7.1and 7.1.4 audio.
    // some positional channel masks.
    // If the spatializer output is already opened, only channel masks included in the
    // spatializer output mixer channel mask are allowed.

    if (config != nullptr && *config != AUDIO_CONFIG_INITIALIZER) {
        if (config->channel_mask != AUDIO_CHANNEL_OUT_5POINT1
                && config->channel_mask != AUDIO_CHANNEL_OUT_7POINT1
                && config->channel_mask != AUDIO_CHANNEL_OUT_7POINT1POINT4) {
        if (!isChannelMaskSpatialized(config->channel_mask)) {
            return false;
        }
        if (mSpatializerOutput != nullptr) {
        if (mSpatializerOutput != nullptr && mSpatializerOutput->mProfile == profile) {
            if ((config->channel_mask & mSpatializerOutput->mMixerChannelMask)
                    != config->channel_mask) {
                return false;
            }
        }
    }

    return true;
}

void AudioPolicyManager::checkVirtualizerClientRoutes() {
    std::set<audio_stream_type_t> streamsToInvalidate;
    for (size_t i = 0; i < mOutputs.size(); i++) {
        const sp<SwAudioOutputDescriptor>& outputDescriptor = mOutputs[i];
        for (const sp<TrackClientDescriptor>& client : outputDescriptor->getClientIterable()) {
        const sp<SwAudioOutputDescriptor>& desc = mOutputs[i];
        for (const sp<TrackClientDescriptor>& client : desc->getClientIterable()) {
            audio_attributes_t attr = client->attributes();
            DeviceVector devices = mEngine->getOutputDevicesForAttributes(attr, nullptr, false);
            AudioDeviceTypeAddrVector devicesTypeAddress = devices.toTypeAddrVector();
            audio_config_base_t clientConfig = client->config();
            audio_config_t config = audio_config_initializer(&clientConfig);
            if (canBeSpatialized(&attr, &config, devicesTypeAddress)) {
            if (desc != mSpatializerOutput
                    && canBeSpatialized(&attr, &config, devicesTypeAddress)) {
                streamsToInvalidate.insert(client->stream());
            }
        }
@@ -4915,10 +4927,6 @@ status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mix
                                                        audio_io_handle_t *output) {
    *output = AUDIO_IO_HANDLE_NONE;

    if (mSpatializerOutput != nullptr) {
        return INVALID_OPERATION;
    }

    DeviceVector devices = mEngine->getOutputDevicesForAttributes(*attr, nullptr, false);
    AudioDeviceTypeAddrVector devicesTypeAddress = devices.toTypeAddrVector();
    audio_config_t *configPtr = nullptr;
@@ -4928,35 +4936,87 @@ status_t AudioPolicyManager::getSpatializerOutput(const audio_config_base_t *mix
        configPtr = &config;
    }
    if (!canBeSpatialized(attr, configPtr, devicesTypeAddress)) {
        ALOGW("%s provided attributes or mixer config cannot be spatialized", __func__);
        return BAD_VALUE;
    }

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

    mSpatializerOutput = new SwAudioOutputDescriptor(profile, mpClientInterface);
    status_t status = mSpatializerOutput->open(nullptr, mixerConfig, devices,
    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();
    for (size_t i = 0; i < mOutputs.size(); i++) {
        sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
        if (!desc->isDuplicated() && desc->mProfile == profile) {
            mSpatializerOutput = desc;
            break;
        }
    }
    if (mSpatializerOutput == nullptr) {
        ALOGW("%s no opened spatializer output for profile %s",
                __func__, profile->getName().c_str());
        return BAD_VALUE;
    }

    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();

        closeOutput(mSpatializerOutput->mIoHandle);
        mSpatializerOutput.clear();

        const sp<SwAudioOutputDescriptor> desc =
                new SwAudioOutputDescriptor(profile, mpClientInterface);
        status_t status = desc->open(nullptr, mixerConfig, devices,
                                                    mEngine->getStreamTypeForAttributes(*attr),
                                                    AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
        if (status != NO_ERROR) {
        ALOGV("%s failed opening output: status %d, output %d", __func__, status, *output);
            ALOGW("%s failed opening output: status %d, output %d", __func__, status, *output);
            if (*output != AUDIO_IO_HANDLE_NONE) {
            mSpatializerOutput->close();
                desc->close();
            }
        mSpatializerOutput.clear();
            // re open the spatializer output with previous channel mask
            status_t newStatus = desc->open(nullptr, &savedMixerConfig, savedDevices,
                                mEngine->getStreamTypeForAttributes(*attr),
                                AUDIO_OUTPUT_FLAG_SPATIALIZER, output);
            if (newStatus != NO_ERROR) {
                if (*output != AUDIO_IO_HANDLE_NONE) {
                    desc->close();
                }
                ALOGE("%s failed to re-open mSpatializerOutput, status %d", __func__, newStatus);
            } else {
                mSpatializerOutput = desc;
                addOutput(*output, desc);
            }
            mPreviousOutputs = mOutputs;
            mpClientInterface->onAudioPortListUpdate();
            *output = AUDIO_IO_HANDLE_NONE;
            return status;
        }

    checkVirtualizerClientRoutes();

    addOutput(*output, mSpatializerOutput);
        mSpatializerOutput = desc;
        addOutput(*output, desc);
        mPreviousOutputs = mOutputs;
        mpClientInterface->onAudioPortListUpdate();
    }

    checkVirtualizerClientRoutes();

    *output = mSpatializerOutput->mIoHandle;
    ALOGV("%s returns new spatializer output %d", __func__, *output);
    return NO_ERROR;
}
@@ -4968,8 +5028,11 @@ status_t AudioPolicyManager::releaseSpatializerOutput(audio_io_handle_t output)
    if (mSpatializerOutput->mIoHandle != output) {
        return BAD_VALUE;
    }
    closeOutput(output);

    mSpatializerOutput.clear();

    checkVirtualizerClientRoutes();

    return NO_ERROR;
}

@@ -5186,8 +5249,7 @@ void AudioPolicyManager::onNewAudioModulesAvailableInt(DeviceVector *newDevices)
                    outProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                mPrimaryOutput = outputDesc;
            }
            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0
                || (outProfile->getFlags() & AUDIO_OUTPUT_FLAG_SPATIALIZER) != 0 ) {
            if ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_DIRECT) != 0) {
                outputDesc->close();
            } else {
                addOutput(output, outputDesc);
+3 −2
Original line number Diff line number Diff line
@@ -962,8 +962,9 @@ private:
                audio_io_handle_t *output);

        sp<IOProfile> getSpatializerOutputProfile(const audio_config_t *config,
                                                       const AudioDeviceTypeAddrVector &devices,
                                                       bool forOpening) const;
                                                  const AudioDeviceTypeAddrVector &devices) const;

        static bool isChannelMaskSpatialized(audio_channel_mask_t channels);

        void checkVirtualizerClientRoutes();

Loading