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

Commit 861a628a authored by Eric Laurent's avatar Eric Laurent
Browse files

audio policy: fix direct output profile selection

Fix logic in AudioPolicyManager::getProfileForDirectOutput()
to select the direct output with most matching flags and not just
the first compatible one.

Also fixes issue 17783395 which was fixed by commit f7bc29b02
in lmp-tv-dev branch only but in a way that caused a regression
for HW A/V sync (issue 19384172).

Also removed duplicated code lines in getOutputForDevice()

Bug: 20819715.
Bug: 17783395.
Bug: 19384172.

Change-Id: I7fc793b37f9b53fabd92cab6b884ef85cfdafee4
parent 4a95e694
Loading
Loading
Loading
Loading
+44 −12
Original line number Original line Diff line number Diff line
@@ -579,24 +579,43 @@ sp<IOProfile> AudioPolicyManager::getProfileForDirectOutput(
                                                               audio_channel_mask_t channelMask,
                                                               audio_channel_mask_t channelMask,
                                                               audio_output_flags_t flags)
                                                               audio_output_flags_t flags)
{
{
    // only retain flags that will drive the direct output profile selection
    // if explicitly requested
    static const uint32_t kRelevantFlags =
            (AUDIO_OUTPUT_FLAG_HW_AV_SYNC | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
    flags =
        (audio_output_flags_t)((flags & kRelevantFlags) | AUDIO_OUTPUT_FLAG_DIRECT);

    sp<IOProfile> profile;

    for (size_t i = 0; i < mHwModules.size(); i++) {
    for (size_t i = 0; i < mHwModules.size(); i++) {
        if (mHwModules[i]->mHandle == 0) {
        if (mHwModules[i]->mHandle == 0) {
            continue;
            continue;
        }
        }
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
        for (size_t j = 0; j < mHwModules[i]->mOutputProfiles.size(); j++) {
            sp<IOProfile> profile = mHwModules[i]->mOutputProfiles[j];
            sp<IOProfile> curProfile = mHwModules[i]->mOutputProfiles[j];
            bool found = profile->isCompatibleProfile(device, String8(""),
            if (!curProfile->isCompatibleProfile(device, String8(""),
                    samplingRate, NULL /*updatedSamplingRate*/,
                    samplingRate, NULL /*updatedSamplingRate*/,
                    format, NULL /*updatedFormat*/,
                    format, NULL /*updatedFormat*/,
                    channelMask, NULL /*updatedChannelMask*/,
                    channelMask, NULL /*updatedChannelMask*/,
                    flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD ?
                    flags)) {
                        AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD : AUDIO_OUTPUT_FLAG_DIRECT);
                continue;
            if (found && (mAvailableOutputDevices.types() & profile->mSupportedDevices.types())) {
                return profile;
            }
            }
            // reject profiles not corresponding to a device currently available
            if ((mAvailableOutputDevices.types() & curProfile->mSupportedDevices.types()) == 0) {
                continue;
            }
            }
            // if several profiles are compatible, give priority to one with offload capability
            if (profile != 0 && ((curProfile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) == 0)) {
                continue;
            }
            profile = curProfile;
            if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
                break;
            }
            }
    return 0;
        }
    }
    return profile;
}
}


audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
audio_io_handle_t AudioPolicyManager::getOutput(audio_stream_type_t stream,
@@ -819,6 +838,23 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice(
        if (outputDesc != NULL) {
        if (outputDesc != NULL) {
            closeOutput(outputDesc->mIoHandle);
            closeOutput(outputDesc->mIoHandle);
        }
        }

        // if the selected profile is offloaded and no offload info was specified,
        // create a default one
        audio_offload_info_t defaultOffloadInfo = AUDIO_INFO_INITIALIZER;
        if ((profile->mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) && !offloadInfo) {
            flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD);
            defaultOffloadInfo.sample_rate = samplingRate;
            defaultOffloadInfo.channel_mask = channelMask;
            defaultOffloadInfo.format = format;
            defaultOffloadInfo.stream_type = stream;
            defaultOffloadInfo.bit_rate = 0;
            defaultOffloadInfo.duration_us = -1;
            defaultOffloadInfo.has_video = true; // conservative
            defaultOffloadInfo.is_streaming = true; // likely
            offloadInfo = &defaultOffloadInfo;
        }

        outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface);
        outputDesc = new SwAudioOutputDescriptor(profile, mpClientInterface);
        outputDesc->mDevice = device;
        outputDesc->mDevice = device;
        outputDesc->mLatency = 0;
        outputDesc->mLatency = 0;
@@ -854,10 +890,6 @@ audio_io_handle_t AudioPolicyManager::getOutputForDevice(
            if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) {
            if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) {
                goto non_direct_output;
                goto non_direct_output;
            }
            }
            // fall back to mixer output if possible when the direct output could not be open
            if (audio_is_linear_pcm(format) && samplingRate <= MAX_MIXER_SAMPLING_RATE) {
                goto non_direct_output;
            }
            return AUDIO_IO_HANDLE_NONE;
            return AUDIO_IO_HANDLE_NONE;
        }
        }
        outputDesc->mSamplingRate = config.sample_rate;
        outputDesc->mSamplingRate = config.sample_rate;