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

Commit 5eaf096a authored by jiabin's avatar jiabin Committed by Jiabin Huang
Browse files

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

1. All playback from the preferred mixer attributes owner will be routed
   to output with preferred mixer.
2. If bit-perfect playback is active, APM will route all playback to the
   preferred mixer when the routed device is the same as the targeted
   device for preferred mixer.
3. The client will be bit-perfect only when it is from the owner of
   preferred mixer attributes and the request matches the preferred
   mixer attributes.

Bug: 263279716
Test: manually
Test: atest audiopolicy_tests
Change-Id: I74efef10909d888dd47cc66444685f5b19a08a43
parent f91a4fcc
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
@@ -1281,17 +1281,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">