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

Commit 287d330c authored by Nadav Bar's avatar Nadav Bar
Browse files

Fix voice communication audio playback capture

This change fixes the CTS failure in AudioPlaybackCaptureTest caused
by ag/10111312 and ag/10111311.
It contains the following fixes/changes:
  - Mix match for playback capture of USAGE_VOICE_COMMUNICATION now
    also respects a new flag (AudioMix's mVoiceCommunicationCaptureAllowed)
    which is set by AudioService only if the caller explicitly asked
    to capture USAGE_VOICE_COMMUNICATION and have the
    CAPTURE_VOICE_COMMUNICATION_OUTPUT.
  - A permission check on the native side in case
    mVoiceCommunicationCaptureAllowed is set.
  - Code cleanup, mainly in AudioPolicy.h and AudioPolicy.cpp.

This change is accompanied by ag/10242955 on the Java side.

Bug: 148559127
Test: manual
Test: atest PlaybackCaptureTest (with the version prior to ag/10220852)
Test: atest com.google.android.gts.audio.AudioHostTest
Change-Id: I8ae6249f4da1de35e962c838d91f690eb906570e
parent 93fb84c8
Loading
Loading
Loading
Loading
+2 −7
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ status_t AudioMix::readFromParcel(Parcel *parcel)
    mDeviceAddress = parcel->readString8();
    mCbFlags = (uint32_t)parcel->readInt32();
    mAllowPrivilegedPlaybackCapture = parcel->readBool();
    mVoiceCommunicationCaptureAllowed = parcel->readBool();
    size_t size = (size_t)parcel->readInt32();
    if (size > MAX_CRITERIA_PER_MIX) {
        size = MAX_CRITERIA_PER_MIX;
@@ -110,6 +111,7 @@ status_t AudioMix::writeToParcel(Parcel *parcel) const
    parcel->writeString8(mDeviceAddress);
    parcel->writeInt32(mCbFlags);
    parcel->writeBool(mAllowPrivilegedPlaybackCapture);
    parcel->writeBool(mVoiceCommunicationCaptureAllowed);
    size_t size = mCriteria.size();
    if (size > MAX_CRITERIA_PER_MIX) {
        size = MAX_CRITERIA_PER_MIX;
@@ -206,11 +208,4 @@ bool AudioMix::isDeviceAffinityCompatible() const {
            && (mRouteFlags == MIX_ROUTE_FLAG_RENDER));
}

bool AudioMix::hasMatchingRuleForUsage(std::function<bool (audio_usage_t)>const& func) const {
    return std::any_of(mCriteria.begin(), mCriteria.end(), [func](auto& criterion) {
            return criterion.mRule == RULE_MATCH_ATTRIBUTE_USAGE
              && func(criterion.mValue.mUsage);
          });
}

} // namespace android
+2 −8
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@
#ifndef ANDROID_AUDIO_POLICY_H
#define ANDROID_AUDIO_POLICY_H

#include <functional>
#include <binder/Parcel.h>
#include <media/AudioDeviceTypeAddr.h>
#include <system/audio.h>
@@ -113,13 +112,6 @@ public:
    /** returns true if this mix can be used for uid-device affinity routing */
    bool isDeviceAffinityCompatible() const;

    /**
     * returns true if the mix has a capture rule for a usage that
     * matches the given predicate
     */
    bool hasMatchingRuleForUsage(
        std::function<bool (audio_usage_t)>const& func) const;

    mutable Vector<AudioMixMatchCriterion> mCriteria;
    uint32_t        mMixType;
    audio_config_t  mFormat;
@@ -129,6 +121,8 @@ public:
    uint32_t        mCbFlags; // flags indicating which callbacks to use, see kCbFlag*
    /** Ignore the AUDIO_FLAG_NO_MEDIA_PROJECTION */
    bool            mAllowPrivilegedPlaybackCapture = false;
    /** Indicates if the caller can capture voice communication output */
    bool            mVoiceCommunicationCaptureAllowed = false;
};


+4 −0
Original line number Diff line number Diff line
@@ -224,6 +224,10 @@ AudioPolicyMixCollection::MixMatchStatus AudioPolicyMixCollection::mixMatch(
                hasFlag(attributes.flags, AUDIO_FLAG_NO_MEDIA_PROJECTION)) {
                return MixMatchStatus::NO_MATCH;
            }
            if (attributes.usage == AUDIO_USAGE_VOICE_COMMUNICATION &&
                !mix->mVoiceCommunicationCaptureAllowed) {
                return MixMatchStatus::NO_MATCH;
            }
            if (!(attributes.usage == AUDIO_USAGE_UNKNOWN ||
                  attributes.usage == AUDIO_USAGE_MEDIA ||
                  attributes.usage == AUDIO_USAGE_GAME ||
+0 −1
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ LOCAL_SHARED_LIBRARIES := \
    libaudioutils \
    libaudiofoundation \
    libhardware_legacy \
    libaudiopolicy \
    libaudiopolicymanager \
    libmedia_helper \
    libmediametrics \
+5 −17
Original line number Diff line number Diff line
@@ -1215,26 +1215,14 @@ status_t AudioPolicyService::registerPolicyMixes(const Vector<AudioMix>& mixes,
        return PERMISSION_DENIED;
    }

    // Require CAPTURE_VOICE_COMMUNICATION_OUTPUT if one of the
    // mixes is a render|loopback mix that aim to capture audio played with
    // USAGE_VOICE_COMMUNICATION.
    // If one of the mixes has needCaptureVoiceCommunicationOutput set to true, then we
    // need to verify that the caller still has CAPTURE_VOICE_COMMUNICATION_OUTPUT
    bool needCaptureVoiceCommunicationOutput =
        std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
            return is_mix_loopback_render(mix.mRouteFlags) &&
                mix.hasMatchingRuleForUsage([] (auto usage) {
                    return usage == AUDIO_USAGE_VOICE_COMMUNICATION;});
            });

    // Require CAPTURE_MEDIA_OUTPUT if there is a mix for priveliged capture
    // which is trying to capture any usage which is not USAGE_VOICE_COMMUNICATION.
    // (If USAGE_VOICE_COMMUNICATION should be captured, then CAPTURE_VOICE_COMMUNICATION_OUTPUT
    //  is required, even if it is not privileged capture).
            return mix.mVoiceCommunicationCaptureAllowed; });

    bool needCaptureMediaOutput = std::any_of(mixes.begin(), mixes.end(), [](auto& mix) {
            return mix.mAllowPrivilegedPlaybackCapture &&
                mix.hasMatchingRuleForUsage([] (auto usage) {
                    return usage != AUDIO_USAGE_VOICE_COMMUNICATION;
                });
            });
            return mix.mAllowPrivilegedPlaybackCapture; });

    const uid_t callingUid = IPCThreadState::self()->getCallingUid();
    const pid_t callingPid = IPCThreadState::self()->getCallingPid();