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

Commit cbd48023 authored by Glenn Kasten's avatar Glenn Kasten
Browse files

audio policy: compatible sample rates and channel masks

Change-Id: I50d068a968aa6bd9e53e5b3111a1b09a6c2d219c
parent 0fb47759
Loading
Loading
Loading
Loading
+146 −40
Original line number Diff line number Diff line
@@ -623,20 +623,10 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getProfileForDirectOutput(
        }
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
            sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
            bool found = false;
            if (flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) {
                if (profile->isCompatibleProfile(device, samplingRate, format,
                                           channelMask,
                                           AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD)) {
                    found = true;
                }
            } else {
                if (profile->isCompatibleProfile(device, samplingRate, format,
                                           channelMask,
                                           AUDIO_OUTPUT_FLAG_DIRECT)) {
                    found = true;
                }
            }
            bool found = profile->isCompatibleProfile(device, samplingRate,
                    NULL /*updatedSamplingRate*/, format, channelMask,
                    flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ?
                        AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT);
            if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) {
                return profile;
            }
@@ -1901,6 +1891,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,

        if (!outputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
                                                       patch->sources[0].sample_rate,
                                                     NULL,  // updatedSamplingRate
                                                     patch->sources[0].format,
                                                     patch->sources[0].channel_mask,
                                                     AUDIO_OUTPUT_FLAG_NONE /*FIXME*/)) {
@@ -1947,6 +1938,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,

            if (!inputDesc->mProfile->isCompatibleProfile(devDesc->mDeviceType,
                                                         patch->sinks[0].sample_rate,
                                                         NULL, /*updatedSampleRate*/
                                                         patch->sinks[0].format,
                                                         patch->sinks[0].channel_mask,
                                                         // FIXME for the parameter type,
@@ -4006,10 +3998,10 @@ status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input,
}

sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devices_t device,
                                                   uint32_t samplingRate,
                                                   uint32_t& samplingRate,
                                                   audio_format_t format,
                                                   audio_channel_mask_t channelMask,
                                                   audio_input_flags_t flags __unused)
                                                   audio_input_flags_t flags)
{
    // Choose an input profile based on the requested capture parameters: select the first available
    // profile supporting all requested parameters.
@@ -4023,8 +4015,9 @@ sp<AudioPolicyManager::IOProfile> AudioPolicyManager::getInputProfile(audio_devi
        {
            sp<IOProfile> profile = mHwModules[i]->mInputProfiles[j];
            // profile->log();
            if (profile->isCompatibleProfile(device, samplingRate, format,
                                             channelMask, AUDIO_OUTPUT_FLAG_NONE)) {
            if (profile->isCompatibleProfile(device, samplingRate,
                                             &samplingRate /*updatedSamplingRate*/,
                                             format, channelMask, (audio_output_flags_t) flags)) {
                return profile;
            }
        }
@@ -5330,7 +5323,7 @@ void AudioPolicyManager::AudioPort::loadGains(cnode *root)
    }
}

status_t AudioPolicyManager::AudioPort::checkSamplingRate(uint32_t samplingRate) const
status_t AudioPolicyManager::AudioPort::checkExactSamplingRate(uint32_t samplingRate) const
{
    for (size_t i = 0; i < mSamplingRates.size(); i ++) {
        if (mSamplingRates[i] == samplingRate) {
@@ -5340,7 +5333,66 @@ status_t AudioPolicyManager::AudioPort::checkSamplingRate(uint32_t samplingRate)
    return BAD_VALUE;
}

status_t AudioPolicyManager::AudioPort::checkChannelMask(audio_channel_mask_t channelMask) const
status_t AudioPolicyManager::AudioPort::checkCompatibleSamplingRate(uint32_t samplingRate,
        uint32_t *updatedSamplingRate) const
{
    // Search for the closest supported sampling rate that is above (preferred)
    // or below (acceptable) the desired sampling rate, within a permitted ratio.
    // The sampling rates do not need to be sorted in ascending order.
    ssize_t maxBelow = -1;
    ssize_t minAbove = -1;
    uint32_t candidate;
    for (size_t i = 0; i < mSamplingRates.size(); i++) {
        candidate = mSamplingRates[i];
        if (candidate == samplingRate) {
            if (updatedSamplingRate != NULL) {
                *updatedSamplingRate = candidate;
            }
            return NO_ERROR;
        }
        // candidate < desired
        if (candidate < samplingRate) {
            if (maxBelow < 0 || candidate > mSamplingRates[maxBelow]) {
                maxBelow = i;
            }
        // candidate > desired
        } else {
            if (minAbove < 0 || candidate < mSamplingRates[minAbove]) {
                minAbove = i;
            }
        }
    }
    // This uses hard-coded knowledge about AudioFlinger resampling ratios.
    // TODO Move these assumptions out.
    static const uint32_t kMaxDownSampleRatio = 6;  // beyond this aliasing occurs
    static const uint32_t kMaxUpSampleRatio = 256;  // beyond this sample rate inaccuracies occur
                                                    // due to approximation by an int32_t of the
                                                    // phase increments
    // Prefer to down-sample from a higher sampling rate, as we get the desired frequency spectrum.
    if (minAbove >= 0) {
        candidate = mSamplingRates[minAbove];
        if (candidate / kMaxDownSampleRatio <= samplingRate) {
            if (updatedSamplingRate != NULL) {
                *updatedSamplingRate = candidate;
            }
            return NO_ERROR;
        }
    }
    // But if we have to up-sample from a lower sampling rate, that's OK.
    if (maxBelow >= 0) {
        candidate = mSamplingRates[maxBelow];
        if (candidate * kMaxUpSampleRatio >= samplingRate) {
            if (updatedSamplingRate != NULL) {
                *updatedSamplingRate = candidate;
            }
            return NO_ERROR;
        }
    }
    // leave updatedSamplingRate unmodified
    return BAD_VALUE;
}

status_t AudioPolicyManager::AudioPort::checkExactChannelMask(audio_channel_mask_t channelMask) const
{
    for (size_t i = 0; i < mChannelMasks.size(); i++) {
        if (mChannelMasks[i] == channelMask) {
@@ -5350,6 +5402,30 @@ status_t AudioPolicyManager::AudioPort::checkChannelMask(audio_channel_mask_t ch
    return BAD_VALUE;
}

status_t AudioPolicyManager::AudioPort::checkCompatibleChannelMask(audio_channel_mask_t channelMask)
        const
{
    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
    for (size_t i = 0; i < mChannelMasks.size(); i ++) {
        // FIXME Does not handle multi-channel automatic conversions yet
        audio_channel_mask_t supported = mChannelMasks[i];
        if (supported == channelMask) {
            return NO_ERROR;
        }
        if (isRecordThread) {
            // This uses hard-coded knowledge that AudioFlinger can silently down-mix and up-mix.
            // FIXME Abstract this out to a table.
            if (((supported == AUDIO_CHANNEL_IN_FRONT_BACK || supported == AUDIO_CHANNEL_IN_STEREO)
                    && channelMask == AUDIO_CHANNEL_IN_MONO) ||
                (supported == AUDIO_CHANNEL_IN_MONO && (channelMask == AUDIO_CHANNEL_IN_FRONT_BACK
                    || channelMask == AUDIO_CHANNEL_IN_STEREO))) {
                return NO_ERROR;
            }
        }
    }
    return BAD_VALUE;
}

status_t AudioPolicyManager::AudioPort::checkFormat(audio_format_t format) const
{
    for (size_t i = 0; i < mFormats.size(); i ++) {
@@ -5684,14 +5760,14 @@ status_t AudioPolicyManager::AudioPortConfig::applyAudioPortConfig(
        goto exit;
    }
    if (config->config_mask & AUDIO_PORT_CONFIG_SAMPLE_RATE) {
        status = mAudioPort->checkSamplingRate(config->sample_rate);
        status = mAudioPort->checkExactSamplingRate(config->sample_rate);
        if (status != NO_ERROR) {
            goto exit;
        }
        mSamplingRate = config->sample_rate;
    }
    if (config->config_mask & AUDIO_PORT_CONFIG_CHANNEL_MASK) {
        status = mAudioPort->checkChannelMask(config->channel_mask);
        status = mAudioPort->checkExactChannelMask(config->channel_mask);
        if (status != NO_ERROR) {
            goto exit;
        }
@@ -5782,29 +5858,59 @@ AudioPolicyManager::IOProfile::~IOProfile()
// get a valid a match
bool AudioPolicyManager::IOProfile::isCompatibleProfile(audio_devices_t device,
                                                            uint32_t samplingRate,
                                                            uint32_t *updatedSamplingRate,
                                                            audio_format_t format,
                                                            audio_channel_mask_t channelMask,
                                                            audio_output_flags_t flags) const
{
    if (samplingRate == 0 || !audio_is_valid_format(format) || channelMask == 0) {
    const bool isPlaybackThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SOURCE;
    const bool isRecordThread = mType == AUDIO_PORT_TYPE_MIX && mRole == AUDIO_PORT_ROLE_SINK;
    ALOG_ASSERT(isPlaybackThread != isRecordThread);

    if ((mSupportedDevices.types() & device) != device) {
        return false;
    }

     if ((mSupportedDevices.types() & device) != device) {
    if (samplingRate == 0) {
         return false;
    }
     if ((mFlags & flags) != flags) {
    uint32_t myUpdatedSamplingRate = samplingRate;
    if (isPlaybackThread && checkExactSamplingRate(samplingRate) != NO_ERROR) {
         return false;
    }
     if (checkSamplingRate(samplingRate) != NO_ERROR) {
    if (isRecordThread && checkCompatibleSamplingRate(samplingRate, &myUpdatedSamplingRate) !=
            NO_ERROR) {
         return false;
    }
     if (checkChannelMask(channelMask) != NO_ERROR) {

    if (!audio_is_valid_format(format) || checkFormat(format) != NO_ERROR) {
        return false;
    }
     if (checkFormat(format) != NO_ERROR) {

    if (isPlaybackThread && (!audio_is_output_channel(channelMask) ||
            checkExactChannelMask(channelMask) != NO_ERROR)) {
        return false;
    }
    if (isRecordThread && (!audio_is_input_channel(channelMask) ||
            checkCompatibleChannelMask(channelMask) != NO_ERROR)) {
        return false;
    }

    if (isPlaybackThread && (mFlags & flags) != flags) {
        return false;
    }
    // The only input flag that is allowed to be different is the fast flag.
    // An existing fast stream is compatible with a normal track request.
    // An existing normal stream is compatible with a fast track request,
    // but the fast request will be denied by AudioFlinger and converted to normal track.
    if (isRecordThread && (((audio_input_flags_t) mFlags ^ (audio_input_flags_t) flags) &
            ~AUDIO_INPUT_FLAG_FAST)) {
        return false;
    }

    if (updatedSamplingRate != NULL) {
        *updatedSamplingRate = myUpdatedSamplingRate;
    }
    return true;
}

+16 −3
Original line number Diff line number Diff line
@@ -240,8 +240,15 @@ protected:
            void loadGain(cnode *root, int index);
            void loadGains(cnode *root);

            status_t checkSamplingRate(uint32_t samplingRate) const;
            status_t checkChannelMask(audio_channel_mask_t channelMask) const;
            // searches for an exact match
            status_t checkExactSamplingRate(uint32_t samplingRate) const;
            // searches for a compatible match, and returns the best match via updatedSamplingRate
            status_t checkCompatibleSamplingRate(uint32_t samplingRate,
                    uint32_t *updatedSamplingRate) const;
            // searches for an exact match
            status_t checkExactChannelMask(audio_channel_mask_t channelMask) const;
            // searches for a compatible match, currently implemented for input channel masks only
            status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask) const;
            status_t checkFormat(audio_format_t format) const;
            status_t checkGain(const struct audio_gain_config *gainConfig, int index) const;

@@ -358,8 +365,13 @@ protected:
            IOProfile(const String8& name, audio_port_role_t role, const sp<HwModule>& module);
            virtual ~IOProfile();

            // This method is used for both output and input.
            // If parameter updatedSamplingRate is non-NULL, it is assigned the actual sample rate.
            // For input, flags is interpreted as audio_input_flags_t.
            // TODO: merge audio_output_flags_t and audio_input_flags_t.
            bool isCompatibleProfile(audio_devices_t device,
                                     uint32_t samplingRate,
                                     uint32_t *updatedSamplingRate,
                                     audio_format_t format,
                                     audio_channel_mask_t channelMask,
                                     audio_output_flags_t flags) const;
@@ -676,8 +688,9 @@ protected:

        audio_io_handle_t selectOutput(const SortedVector<audio_io_handle_t>& outputs,
                                       audio_output_flags_t flags);
        // samplingRate parameter is an in/out and so may be modified
        sp<IOProfile> getInputProfile(audio_devices_t device,
                                   uint32_t samplingRate,
                                   uint32_t& samplingRate,
                                   audio_format_t format,
                                   audio_channel_mask_t channelMask,
                                   audio_input_flags_t flags);