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

Commit 34a740d5 authored by Andy Hung's avatar Andy Hung Committed by Android (Google) Code Review
Browse files

Merge "aaudio: fix multichannel legacy streams" into qt-dev

parents 92e11689 16c66dd1
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -63,7 +63,9 @@ aaudio_result_t AudioStreamRecord::open(const AudioStreamBuilder& builder)
    // TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
    int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                              ? 2 : getSamplesPerFrame();
    audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(samplesPerFrame);
    audio_channel_mask_t channelMask = samplesPerFrame <= 2 ?
                               audio_channel_in_mask_from_count(samplesPerFrame) :
                               audio_channel_mask_for_index_assignment_from_count(samplesPerFrame);

    size_t frameCount = (builder.getBufferCapacity() == AAUDIO_UNSPECIFIED) ? 0
                        : builder.getBufferCapacity();
+3 −1
Original line number Diff line number Diff line
@@ -66,7 +66,9 @@ aaudio_result_t AudioStreamTrack::open(const AudioStreamBuilder& builder)
    // Use stereo if unspecified.
    int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
                              ? 2 : getSamplesPerFrame();
    audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
    audio_channel_mask_t channelMask = samplesPerFrame <= 2 ?
                            audio_channel_out_mask_from_count(samplesPerFrame) :
                            audio_channel_mask_for_index_assignment_from_count(samplesPerFrame);

    audio_output_flags_t flags;
    aaudio_performance_mode_t perfMode = getPerformanceMode();
+3 −0
Original line number Diff line number Diff line
@@ -112,6 +112,9 @@ public:
    static bool isBetterFormatMatch(audio_format_t newFormat,
                                        audio_format_t currentFormat,
                                        audio_format_t targetFormat);
    static uint32_t formatDistance(audio_format_t format1,
                                   audio_format_t format2);
    static const uint32_t kFormatDistanceMax = 4;

    audio_module_handle_t getModuleHandle() const;
    uint32_t getModuleVersionMajor() const;
+15 −20
Original line number Diff line number Diff line
@@ -282,30 +282,25 @@ 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)
uint32_t AudioPort::formatDistance(audio_format_t format1, audio_format_t format2)
{
    if (newFormat == currentFormat) {
        return false;
    }
    if (currentFormat == AUDIO_FORMAT_INVALID) {
        return true;
    if (format1 == format2) {
        return 0;
    }
    if (newFormat == targetFormat) {
        return true;
    if (format1 == AUDIO_FORMAT_INVALID || format2 == AUDIO_FORMAT_INVALID) {
        return kFormatDistanceMax;
    }
    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);
    int diffBytes = (int)audio_bytes_per_sample(format1) -
            audio_bytes_per_sample(format2);

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

bool AudioPort::isBetterFormatMatch(audio_format_t newFormat,
                                    audio_format_t currentFormat,
                                    audio_format_t targetFormat)
{
    return formatDistance(newFormat, targetFormat) < formatDistance(currentFormat, targetFormat);
}

void AudioPort::pickAudioProfile(uint32_t &samplingRate,
+108 −91
Original line number Diff line number Diff line
@@ -36,12 +36,12 @@
#define AUDIO_POLICY_BLUETOOTH_LEGACY_HAL_XML_CONFIG_FILE_NAME \
        "audio_policy_configuration_bluetooth_legacy_hal.xml"

#include <algorithm>
#include <inttypes.h>
#include <math.h>
#include <set>
#include <unordered_set>
#include <vector>

#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyEngineInstance.h>
#include <cutils/properties.h>
@@ -592,7 +592,7 @@ sp<AudioPatch> AudioPolicyManager::createTelephonyPatch(
                    AUDIO_DEVICE_OUT_TELEPHONY_TX, String8(), AUDIO_FORMAT_DEFAULT);
    SortedVector<audio_io_handle_t> outputs =
            getOutputsForDevices(DeviceVector(outputDevice), mOutputs);
    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
    const audio_io_handle_t output = selectOutput(outputs);
    // request to reuse existing output stream if one is already opened to reach the target device
    if (output != AUDIO_IO_HANDLE_NONE) {
        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
@@ -883,7 +883,7 @@ audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream)
    // and AudioSystem::getOutputSamplingRate().

    SortedVector<audio_io_handle_t> outputs = getOutputsForDevices(devices, mOutputs);
    audio_io_handle_t output = selectOutput(outputs, AUDIO_OUTPUT_FLAG_NONE, AUDIO_FORMAT_INVALID);
    const audio_io_handle_t output = selectOutput(outputs);

    ALOGV("getOutput() stream %d selected devices %s, output %d", stream,
          devices.toString().c_str(), output);
@@ -1430,108 +1430,125 @@ audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_h
                                                       audio_channel_mask_t channelMask,
                                                       uint32_t samplingRate)
{
    LOG_ALWAYS_FATAL_IF(!(format == AUDIO_FORMAT_INVALID || audio_is_linear_pcm(format)),
        "%s called with format %#x", __func__, format);

    // Flags disqualifying an output: the match must happen before calling selectOutput()
    static const audio_output_flags_t kExcludedFlags = (audio_output_flags_t)
        (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ | AUDIO_OUTPUT_FLAG_DIRECT);

    // Flags expressing a functional request: must be honored in priority over
    // other criteria
    static const audio_output_flags_t kFunctionalFlags = (audio_output_flags_t)
        (AUDIO_OUTPUT_FLAG_VOIP_RX | AUDIO_OUTPUT_FLAG_INCALL_MUSIC |
            AUDIO_OUTPUT_FLAG_TTS | AUDIO_OUTPUT_FLAG_DIRECT_PCM);
    // Flags expressing a performance request: have lower priority than serving
    // requested sampling rate or channel mask
    static const audio_output_flags_t kPerformanceFlags = (audio_output_flags_t)
        (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_DEEP_BUFFER |
            AUDIO_OUTPUT_FLAG_RAW | AUDIO_OUTPUT_FLAG_SYNC);

    const audio_output_flags_t functionalFlags =
        (audio_output_flags_t)(flags & kFunctionalFlags);
    const audio_output_flags_t performanceFlags =
        (audio_output_flags_t)(flags & kPerformanceFlags);

    audio_io_handle_t bestOutput = (outputs.size() == 0) ? AUDIO_IO_HANDLE_NONE : outputs[0];

    // select one output among several that provide a path to a particular device or set of
    // devices (the list was previously build by getOutputsForDevices()).
    // The priority is as follows:
    // 1: the output supporting haptic playback when requesting haptic playback
    // 2: the output with the highest number of requested policy flags
    // 3: the output with the bit depth the closest to the requested one
    // 4: the primary output
    // 5: the first output in the list

    if (outputs.size() == 0) {
        return AUDIO_IO_HANDLE_NONE;
    }
    if (outputs.size() == 1) {
        return outputs[0];
    }

    int maxCommonFlags = 0;
    const size_t hapticChannelCount = audio_channel_count_from_out_mask(
    // 2: the output with the highest number of requested functional flags
    // 3: the output supporting the exact channel mask
    // 4: the output with a higher channel count than requested
    // 5: the output with a higher sampling rate than requested
    // 6: the output with the highest number of requested performance flags
    // 7: the output with the bit depth the closest to the requested one
    // 8: the primary output
    // 9: the first output in the list

    // matching criteria values in priority order for best matching output so far
    std::vector<uint32_t> bestMatchCriteria(8, 0);

    const uint32_t channelCount = audio_channel_count_from_out_mask(channelMask);
    const uint32_t hapticChannelCount = audio_channel_count_from_out_mask(
        channelMask & AUDIO_CHANNEL_HAPTIC_ALL);
    audio_io_handle_t outputForFlags = AUDIO_IO_HANDLE_NONE;
    audio_io_handle_t outputForPrimary = AUDIO_IO_HANDLE_NONE;
    audio_io_handle_t outputForFormat = AUDIO_IO_HANDLE_NONE;
    audio_format_t bestFormat = AUDIO_FORMAT_INVALID;
    audio_format_t bestFormatForFlags = AUDIO_FORMAT_INVALID;

    // Flags which must be present on both the request and the selected output
    static const audio_output_flags_t kMandatedFlags = (audio_output_flags_t)
        (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_MMAP_NOIRQ);

    for (audio_io_handle_t output : outputs) {
        sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
        if (!outputDesc->isDuplicated()) {
            if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
        // matching criteria values in priority order for current output
        std::vector<uint32_t> currentMatchCriteria(8, 0);

        if (outputDesc->isDuplicated()) {
            continue;
        }
        if ((kExcludedFlags & outputDesc->mFlags) != 0) {
            continue;
        }

        // If haptic channel is specified, use the haptic output if present.
        // When using haptic output, same audio format and sample rate are required.
            if (hapticChannelCount > 0) {
                // If haptic channel is specified, use the first output that
                // support haptic playback.
                if (audio_channel_count_from_out_mask(
                        outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) >= hapticChannelCount
        const uint32_t outputHapticChannelCount = audio_channel_count_from_out_mask(
            outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL);
        if ((hapticChannelCount == 0) != (outputHapticChannelCount == 0)) {
            continue;
        }
        if (outputHapticChannelCount >= hapticChannelCount
            && format == outputDesc->mFormat
            && samplingRate == outputDesc->mSamplingRate) {
                    return output;
                currentMatchCriteria[0] = outputHapticChannelCount;
        }
            } else {
                // When haptic channel is not specified, skip haptic output.
                if (outputDesc->mChannelMask & AUDIO_CHANNEL_HAPTIC_ALL) {
                    continue;

        // functional flags match
        currentMatchCriteria[1] = popcount(outputDesc->mFlags & functionalFlags);

        // channel mask and channel count match
        uint32_t outputChannelCount = audio_channel_count_from_out_mask(outputDesc->mChannelMask);
        if (channelMask != AUDIO_CHANNEL_NONE && channelCount > 2 &&
            channelCount <= outputChannelCount) {
            if ((audio_channel_mask_get_representation(channelMask) ==
                    audio_channel_mask_get_representation(outputDesc->mChannelMask)) &&
                    ((channelMask & outputDesc->mChannelMask) == channelMask)) {
                currentMatchCriteria[2] = outputChannelCount;
            }
            currentMatchCriteria[3] = outputChannelCount;
        }
            if ((kMandatedFlags & flags) !=
                (kMandatedFlags & outputDesc->mProfile->getFlags())) {
                continue;

        // sampling rate match
        if (samplingRate > SAMPLE_RATE_HZ_DEFAULT &&
                samplingRate <= outputDesc->mSamplingRate) {
            currentMatchCriteria[4] = outputDesc->mSamplingRate;
        }

            // if a valid format is specified, skip output if not compatible
        // performance flags match
        currentMatchCriteria[5] = popcount(outputDesc->mFlags & performanceFlags);

        // format match
        if (format != AUDIO_FORMAT_INVALID) {
                if (!audio_is_linear_pcm(format)) {
                    continue;
                }
                if (AudioPort::isBetterFormatMatch(
                        outputDesc->mFormat, bestFormat, format)) {
                    outputForFormat = output;
                    bestFormat = outputDesc->mFormat;
                }
            currentMatchCriteria[6] =
                AudioPort::kFormatDistanceMax -
                AudioPort::formatDistance(format, outputDesc->mFormat);
        }

            int commonFlags = popcount(outputDesc->mProfile->getFlags() & flags);
            if (commonFlags >= maxCommonFlags) {
                if (commonFlags == maxCommonFlags) {
                    if (format != AUDIO_FORMAT_INVALID
                            && AudioPort::isBetterFormatMatch(
                                    outputDesc->mFormat, bestFormatForFlags, format)) {
                        outputForFlags = output;
                        bestFormatForFlags = outputDesc->mFormat;
                    }
                } else {
                    outputForFlags = output;
                    maxCommonFlags = commonFlags;
                    bestFormatForFlags = outputDesc->mFormat;
                }
                ALOGV("selectOutput() commonFlags for output %d, %04x", output, commonFlags);
            }
            if (outputDesc->mProfile->getFlags() & AUDIO_OUTPUT_FLAG_PRIMARY) {
                outputForPrimary = output;
            }
        }
    }
        // primary output match
        currentMatchCriteria[7] = outputDesc->mFlags & AUDIO_OUTPUT_FLAG_PRIMARY;

    if (outputForFlags != AUDIO_IO_HANDLE_NONE) {
        return outputForFlags;
    }
    if (outputForFormat != AUDIO_IO_HANDLE_NONE) {
        return outputForFormat;
        // compare match criteria by priority then value
        if (std::lexicographical_compare(bestMatchCriteria.begin(), bestMatchCriteria.end(),
                currentMatchCriteria.begin(), currentMatchCriteria.end())) {
            bestMatchCriteria = currentMatchCriteria;
            bestOutput = output;

            std::stringstream result;
            std::copy(bestMatchCriteria.begin(), bestMatchCriteria.end(),
                std::ostream_iterator<int>(result, " "));
            ALOGV("%s new bestOutput %d criteria %s",
                __func__, bestOutput, result.str().c_str());
        }
    if (outputForPrimary != AUDIO_IO_HANDLE_NONE) {
        return outputForPrimary;
    }

    return outputs[0];
    return bestOutput;
}

status_t AudioPolicyManager::startOutput(audio_port_handle_t portId)
@@ -3474,7 +3491,7 @@ status_t AudioPolicyManager::createAudioPatch(const struct audio_patch *patch,
                            getOutputsForDevices(DeviceVector(sinkDevice), mOutputs);
                    // if the sink device is reachable via an opened output stream, request to go via
                    // this output stream by adding a second source to the patch description
                    audio_io_handle_t output = selectOutput(outputs);
                    const audio_io_handle_t output = selectOutput(outputs);
                    if (output != AUDIO_IO_HANDLE_NONE) {
                        sp<AudioOutputDescriptor> outputDesc = mOutputs.valueFor(output);
                        if (outputDesc->isDuplicated()) {