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

Commit aa988bf8 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "APM: update logic for output selection with preferred mixer attributes."

parents c66aa06b 5eaf096a
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -792,7 +792,7 @@ void AudioFlinger::PlaybackThread::Track::appendDumpHeader(String8& result)
                        "  Format Chn mask  SRate "
                        "ST Usg CT "
                        " G db  L dB  R dB  VS dB "
                        "  Server FrmCnt  FrmRdy F Underruns  Flushed"
                        "  Server FrmCnt  FrmRdy F Underruns  Flushed BitPerfect"
                        "%s\n",
                        isServerLatencySupported() ? "   Latency" : "");
}
@@ -878,7 +878,7 @@ void AudioFlinger::PlaybackThread::Track::appendDump(String8& result, bool activ
                        "%08X %08X %6u "
                        "%2u %3x %2x "
                        "%5.2g %5.2g %5.2g %5.2g%c "
                        "%08X %6zu%c %6zu %c %9u%c %7u",
                        "%08X %6zu%c %6zu %c %9u%c %7u %10s",
            active ? "yes" : "no",
            (mClient == 0) ? getpid() : mClient->pid(),
            mSessionId,
@@ -907,7 +907,8 @@ void AudioFlinger::PlaybackThread::Track::appendDump(String8& result, bool activ
            fillingStatus,
            mAudioTrackServerProxy->getUnderrunFrames(),
            nowInUnderrun,
            (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000
            (unsigned)mAudioTrackServerProxy->framesFlushed() % 10000000,
            isBitPerfect() ? "true" : "false"
            );

    if (isServerLatencySupported()) {
+13 −4
Original line number Diff line number Diff line
@@ -1280,17 +1280,26 @@ status_t AudioPolicyManager::getOutputForAttrInt(
            info = getPreferredMixerAttributesInfo(
                    outputDevices.itemAt(0)->getId(),
                    mEngine->getProductStrategyForAttributes(*resultAttr));
            if (info != nullptr && info->getUid() != uid && info->getActiveClientCount() == 0) {
                // Only use preferred mixer when the requested uid matched or
                // there is active client on preferred mixer.
            // Only use preferred mixer if the uid matches or the preferred mixer is bit-perfect
            // and it is currently active.
            if (info != nullptr && info->getUid() != uid &&
                ((info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) == AUDIO_OUTPUT_FLAG_NONE ||
                        info->getActiveClientCount() == 0)) {
                info = nullptr;
            }
        }
        *output = getOutputForDevices(outputDevices, session, resultAttr, config,
                flags, isSpatialized, info, resultAttr->flags & AUDIO_FLAG_MUTE_HAPTIC);
        // The client will be active if the client is currently preferred mixer owner and the
        // requested configuration matches the preferred mixer configuration.
        *isBitPerfect = (info != nullptr
                && (info->getFlags() & AUDIO_OUTPUT_FLAG_BIT_PERFECT) != AUDIO_OUTPUT_FLAG_NONE
                && *output != AUDIO_IO_HANDLE_NONE);
                && info->getUid() == uid
                && *output != AUDIO_IO_HANDLE_NONE
                // When bit-perfect output is selected for the preferred mixer attributes owner,
                // only need to consider the config matches.
                && mOutputs.valueFor(*output)->isConfigurationMatched(
                        clientConfig, AUDIO_OUTPUT_FLAG_NONE));
    }
    if (*output == AUDIO_IO_HANDLE_NONE) {
        AudioProfileVector profiles;
+117 −4
Original line number Diff line number Diff line
@@ -161,7 +161,8 @@ class AudioPolicyManagerTest : public testing::Test {
            audio_port_handle_t *portId = nullptr,
            audio_attributes_t attr = {},
            audio_session_t session = AUDIO_SESSION_NONE,
            int uid = 0);
            int uid = 0,
            bool* isBitPerfect = nullptr);
    void getInputForAttr(
            const audio_attributes_t &attr,
            audio_session_t session,
@@ -246,7 +247,8 @@ void AudioPolicyManagerTest::getOutputForAttr(
        audio_port_handle_t *portId,
        audio_attributes_t attr,
        audio_session_t session,
        int uid) {
        int uid,
        bool* isBitPerfect) {
    audio_io_handle_t localOutput;
    if (!output) output = &localOutput;
    *output = AUDIO_IO_HANDLE_NONE;
@@ -260,14 +262,15 @@ void AudioPolicyManagerTest::getOutputForAttr(
    *portId = AUDIO_PORT_HANDLE_NONE;
    AudioPolicyInterface::output_type_t outputType;
    bool isSpatialized;
    bool isBitPerfect;
    bool isBitPerfectInternal;
    // TODO b/182392769: use attribution source util
    AttributionSourceState attributionSource = AttributionSourceState();
    attributionSource.uid = uid;
    attributionSource.token = sp<BBinder>::make();
    ASSERT_EQ(OK, mManager->getOutputForAttr(
                    &attr, output, session, &stream, attributionSource, &config, &flags,
                    selectedDeviceId, portId, {}, &outputType, &isSpatialized, &isBitPerfect));
                    selectedDeviceId, portId, {}, &outputType, &isSpatialized,
                    isBitPerfect == nullptr ? &isBitPerfectInternal : isBitPerfect));
    ASSERT_NE(AUDIO_PORT_HANDLE_NONE, *portId);
    ASSERT_NE(AUDIO_IO_HANDLE_NONE, *output);
}
@@ -1119,6 +1122,116 @@ TEST_F(AudioPolicyManagerTestWithConfigurationFile, RoutingChangedWithPreferredM
                                                           "", "", AUDIO_FORMAT_LDAC));
}

TEST_F(AudioPolicyManagerTestWithConfigurationFile, BitPerfectPlayback) {
    const audio_format_t bitPerfectFormat = AUDIO_FORMAT_PCM_16_BIT;
    const audio_channel_mask_t bitPerfectChannelMask = AUDIO_CHANNEL_OUT_QUAD;
    const uint32_t bitPerfectSampleRate = 48000;
    mClient->addSupportedFormat(bitPerfectFormat);
    mClient->addSupportedChannelMask(bitPerfectChannelMask);
    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
                                                           AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                                                           "", "", AUDIO_FORMAT_DEFAULT));
    auto devices = mManager->getAvailableOutputDevices();
    audio_port_handle_t usbPortId = AUDIO_PORT_HANDLE_NONE;
    for (auto device : devices) {
        if (device->type() == AUDIO_DEVICE_OUT_USB_DEVICE) {
            usbPortId = device->getId();
            break;
        }
    }
    EXPECT_NE(AUDIO_PORT_HANDLE_NONE, usbPortId);

    const uid_t uid = 1234;
    const uid_t anotherUid = 5678;
    const audio_attributes_t mediaAttr = {
            .content_type = AUDIO_CONTENT_TYPE_MUSIC,
            .usage = AUDIO_USAGE_MEDIA,
    };

    std::vector<audio_mixer_attributes_t> mixerAttributes;
    EXPECT_EQ(NO_ERROR, mManager->getSupportedMixerAttributes(usbPortId, mixerAttributes));
    EXPECT_GT(mixerAttributes.size(), 0);
    size_t bitPerfectIndex = 0;
    for (; bitPerfectIndex < mixerAttributes.size(); ++bitPerfectIndex) {
        if (mixerAttributes[bitPerfectIndex].mixer_behavior == AUDIO_MIXER_BEHAVIOR_BIT_PERFECT) {
            break;
        }
    }
    EXPECT_LT(bitPerfectIndex, mixerAttributes.size());
    EXPECT_EQ(bitPerfectFormat, mixerAttributes[bitPerfectIndex].config.format);
    EXPECT_EQ(bitPerfectChannelMask, mixerAttributes[bitPerfectIndex].config.channel_mask);
    EXPECT_EQ(bitPerfectSampleRate, mixerAttributes[bitPerfectIndex].config.sample_rate);
    EXPECT_EQ(NO_ERROR,
              mManager->setPreferredMixerAttributes(
                      &mediaAttr, usbPortId, uid, &mixerAttributes[bitPerfectIndex]));

    audio_io_handle_t bitPerfectOutput = AUDIO_IO_HANDLE_NONE;
    audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
    audio_port_handle_t selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
    audio_port_handle_t bitPerfectPortId = AUDIO_PORT_HANDLE_NONE;
    audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
    bool isBitPerfect;

    // When there is no active bit-perfect playback, the output selection will follow default
    // routing strategy.
    getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
            48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
            uid, &isBitPerfect);
    EXPECT_FALSE(isBitPerfect);
    EXPECT_NE(AUDIO_IO_HANDLE_NONE, output);
    const auto outputDesc = mManager->getOutputs().valueFor(output);
    EXPECT_NE(nullptr, outputDesc);
    EXPECT_NE(AUDIO_OUTPUT_FLAG_BIT_PERFECT, outputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);

    // Start bit-perfect playback
    getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
            bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &bitPerfectOutput, &bitPerfectPortId,
            mediaAttr, AUDIO_SESSION_NONE, uid, &isBitPerfect);
    status_t status = mManager->startOutput(bitPerfectPortId);
    if (status == DEAD_OBJECT) {
        getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
                bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &bitPerfectOutput, &bitPerfectPortId,
                mediaAttr, AUDIO_SESSION_NONE, uid, &isBitPerfect);
        status = mManager->startOutput(bitPerfectPortId);
    }
    EXPECT_EQ(NO_ERROR, status);
    EXPECT_TRUE(isBitPerfect);
    EXPECT_NE(AUDIO_IO_HANDLE_NONE, bitPerfectOutput);
    const auto bitPerfectOutputDesc = mManager->getOutputs().valueFor(bitPerfectOutput);
    EXPECT_NE(nullptr, bitPerfectOutputDesc);
    EXPECT_EQ(AUDIO_OUTPUT_FLAG_BIT_PERFECT,
              bitPerfectOutputDesc->mFlags & AUDIO_OUTPUT_FLAG_BIT_PERFECT);

    // If the playback is from preferred mixer attributes owner but the request doesn't match
    // preferred mixer attributes, it will not be bit-perfect.
    getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
            48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
            uid, &isBitPerfect);
    EXPECT_FALSE(isBitPerfect);
    EXPECT_EQ(bitPerfectOutput, output);

    // When bit-perfect playback is active, all other playback will be routed to bit-perfect output.
    getOutputForAttr(&selectedDeviceId, AUDIO_FORMAT_PCM_16_BIT, AUDIO_CHANNEL_OUT_STEREO,
            48000, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr, AUDIO_SESSION_NONE,
            anotherUid, &isBitPerfect);
    EXPECT_FALSE(isBitPerfect);
    EXPECT_EQ(bitPerfectOutput, output);

    // When configuration matches preferred mixer attributes, which is bit-perfect, but the client
    // is not the owner of preferred mixer attributes, the playback will not be bit-perfect.
    getOutputForAttr(&selectedDeviceId, bitPerfectFormat, bitPerfectChannelMask,
            bitPerfectSampleRate, AUDIO_OUTPUT_FLAG_NONE, &output, &portId, mediaAttr,
            AUDIO_SESSION_NONE, anotherUid, &isBitPerfect);
    EXPECT_FALSE(isBitPerfect);
    EXPECT_EQ(bitPerfectOutput, output);

    EXPECT_EQ(NO_ERROR,
              mManager->clearPreferredMixerAttributes(&mediaAttr, usbPortId, uid));
    ASSERT_EQ(NO_ERROR, mManager->setDeviceConnectionState(AUDIO_DEVICE_OUT_USB_DEVICE,
                                                           AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
                                                           "", "", AUDIO_FORMAT_LDAC));
}

class AudioPolicyManagerTestDynamicPolicy : public AudioPolicyManagerTestWithConfigurationFile {
protected:
    void TearDown() override;
+1 −1
Original line number Diff line number Diff line
@@ -54,7 +54,7 @@
                    <profile name="" format="AUDIO_FORMAT_PCM_16_BIT"
                           samplingRates="8000 16000 32000 48000" channelMasks="AUDIO_CHANNEL_OUT_STEREO"/>
                </mixPort>
                <mixPort name="hifi_output" role="source"/>
                <mixPort name="hifi_output" role="source" flags="AUDIO_OUTPUT_FLAG_BIT_PERFECT"/>
            </mixPorts>
            <devicePorts>
                <devicePort tagName="Speaker" type="AUDIO_DEVICE_OUT_SPEAKER" role="sink">