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

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

Merge "audio policy: select output with best sample format match" into nyc-dev

parents f25f8410 e693002b
Loading
Loading
Loading
Loading
+15 −0
Original line number Diff line number Diff line
@@ -126,3 +126,18 @@ static inline int32_t source_priority(audio_source_t inputSource)
    }
    return 0;
}

/* Indicates if audio formats are equivalent when considering a match between
 * audio HAL supported formats and client requested formats
 */
static inline bool audio_formats_match(audio_format_t format1,
                                       audio_format_t format2)
{
    if (audio_is_linear_pcm(format1) &&
            (audio_bytes_per_sample(format1) > 2) &&
            audio_is_linear_pcm(format2) &&
            (audio_bytes_per_sample(format2) > 2)) {
        return true;
    }
    return format1 == format2;
}
+6 −0
Original line number Diff line number Diff line
@@ -110,6 +110,12 @@ public:

    static int compareFormats(audio_format_t format1, audio_format_t format2);

    // Used to select an audio HAL output stream with a sample format providing the
    // less degradation for a given AudioTrack sample format.
    static bool isBetterFormatMatch(audio_format_t newFormat,
                                        audio_format_t currentFormat,
                                        audio_format_t targetFormat);

    audio_module_handle_t getModuleHandle() const;
    uint32_t getModuleVersion() const;
    const char *getModuleName() const;
+26 −0
Original line number Diff line number Diff line
@@ -268,6 +268,32 @@ int AudioPort::compareFormats(audio_format_t format1, audio_format_t format2)
    return index1 - index2;
}

bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
                                    audio_format_t currentFormat,
                                    audio_format_t targetFormat)
{
    if (newFormat == currentFormat) {
        return false;
    }
    if (currentFormat == AUDIO_FORMAT_INVALID) {
        return true;
    }
    if (newFormat == targetFormat) {
        return true;
    }
    int currentDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
            audio_bytes_per_sample(currentFormat);
    int newDiffBytes = (int)audio_bytes_per_sample(targetFormat) -
            audio_bytes_per_sample(newFormat);

    if (abs(newDiffBytes) < abs(currentDiffBytes)) {
        return true;
    } else if (abs(newDiffBytes) == abs(currentDiffBytes)) {
        return (newDiffBytes >= 0);
    }
    return false;
}

void AudioPort::pickAudioProfile(uint32_t &samplingRate,
                                 audio_channel_mask_t &channelMask,
                                 audio_format_t &format) const
+1 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ namespace android {
status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
                                  audio_format_t format) const
{
    if (format == mFormat &&
    if (audio_formats_match(format, mFormat) &&
            (mChannelMasks.isEmpty() || supportsChannels(channelMask)) &&
            (mSamplingRates.isEmpty() || supportsRate(samplingRate))) {
        return NO_ERROR;
+38 −17
Original line number Diff line number Diff line
@@ -876,7 +876,7 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice(
                outputDesc = desc;
                // reuse direct output if currently open and configured with same parameters
                if ((samplingRate == outputDesc->mSamplingRate) &&
                        (format == outputDesc->mFormat) &&
                        audio_formats_match(format, outputDesc->mFormat) &&
                        (channelMask == outputDesc->mChannelMask)) {
                    outputDesc->mDirectOpenCount++;
                    ALOGV("getOutput() reusing direct output %d", mOutputs.keyAt(i));
@@ -927,7 +927,7 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice(
        // only accept an output with the requested parameters
        if (status != NO_ERROR ||
            (samplingRate != 0 && samplingRate != config.sample_rate) ||
            (format != AUDIO_FORMAT_DEFAULT && format != config.format) ||
            (format != AUDIO_FORMAT_DEFAULT && !audio_formats_match(format, config.format)) ||
            (channelMask != 0 && channelMask != config.channel_mask)) {
            ALOGV("getOutput() failed opening direct output: output %d samplingRate %d %d,"
                    "format %d %d, channelMask %04x %04x", output, samplingRate,
@@ -992,8 +992,9 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
    // devices (the list was previously build by getOutputsForDevice()).
    // The priority is as follows:
    // 1: the output with the highest number of requested policy flags
    // 2: the primary output
    // 3: the first output in the list
    // 2: the output with the bit depth the closest to the requested one
    // 3: the primary output
    // 4: the first output in the list

    if (outputs.size() == 0) {
        return 0;
@@ -1003,8 +1004,11 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
    }

    int maxCommonFlags = 0;
    audio_io_handle_t outputFlags = 0;
    audio_io_handle_t outputPrimary = 0;
    audio_io_handle_t outputForFlags = 0;
    audio_io_handle_t outputForPrimary = 0;
    audio_io_handle_t outputForFormat = 0;
    audio_format_t bestFormat = AUDIO_FORMAT_INVALID;
    audio_format_t bestFormatForFlags = AUDIO_FORMAT_INVALID;

    for (size_t i = 0; i < outputs.size(); i++) {
        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(outputs[i]);
@@ -1012,31 +1016,48 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
            // if a valid format is specified, skip output if not compatible
            if (format != AUDIO_FORMAT_INVALID) {
                if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
                    if (format != outputDesc->mFormat) {
                    if (!audio_formats_match(format, outputDesc->mFormat)) {
                        continue;
                    }
                } else if (!audio_is_linear_pcm(format)) {
                    continue;
                }
                if (AudioPort::isBetterFormatMatch(
                        outputDesc->mFormat, bestFormat, format)) {
                    outputForFormat = outputs[i];
                    bestFormat = outputDesc->mFormat;
                }
            }

            int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
            if (commonFlags > maxCommonFlags) {
                outputFlags = outputs[i];
            if (commonFlags >= maxCommonFlags) {
                if (commonFlags == maxCommonFlags) {
                    if (AudioPort::isBetterFormatMatch(
                            outputDesc->mFormat, bestFormatForFlags, format)) {
                        outputForFlags = outputs[i];
                        bestFormatForFlags = outputDesc->mFormat;
                    }
                } else {
                    outputForFlags = outputs[i];
                    maxCommonFlags = commonFlags;
                    bestFormatForFlags = outputDesc->mFormat;
                }
                ALOGV("selectOutput() commonFlags for output %d, %04x", outputs[i], commonFlags);
            }
            if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                outputPrimary = outputs[i];
                outputForPrimary = outputs[i];
            }
        }
    }

    if (outputFlags != 0) {
        return outputFlags;
    if (outputForFlags != 0) {
        return outputForFlags;
    }
    if (outputForFormat != 0) {
        return outputForFormat;
    }
    if (outputPrimary != 0) {
        return outputPrimary;
    if (outputForPrimary != 0) {
        return outputForPrimary;
    }

    return outputs[0];
@@ -1509,7 +1530,7 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
            // and current input properties are not exactly as requested.
            if ((desc->mSamplingRate != samplingRate ||
                    desc->mChannelMask != channelMask ||
                    desc->mFormat != format) &&
                    !audio_formats_match(desc->mFormat, format)) &&
                    (source_priority(desc->getHighestPrioritySource(false /*activeOnly*/)) <
                     source_priority(inputSource))) {
                ALOGV("%s: ", __FUNCTION__);
@@ -1544,7 +1565,7 @@ audio_io_handle_t AudioPolicyManager::getInputForDevice(audio_devices_t device,
    // only accept input with the exact requested set of parameters
    if (status != NO_ERROR || input == AUDIO_IO_HANDLE_NONE ||
        (profileSamplingRate != config.sample_rate) ||
        (profileFormat != config.format) ||
        !audio_formats_match(profileFormat, config.format) ||
        (profileChannelMask != config.channel_mask)) {
        ALOGW("getInputForAttr() failed opening input: samplingRate %d"
              ", format %d, channelMask %x",