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

Commit 4672efb1 authored by Oscar Azucena's avatar Oscar Azucena Committed by Android (Google) Code Review
Browse files

Merge "Added Android user id based audio routing."

parents d7d9c3e3 76788f0b
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -24191,8 +24191,10 @@ package android.media {
  public final class AudioPlaybackCaptureConfiguration {
    method @NonNull public int[] getExcludeUids();
    method @NonNull public int[] getExcludeUsages();
    method @NonNull public int[] getExcludeUserIds();
    method @NonNull public int[] getMatchingUids();
    method @NonNull public int[] getMatchingUsages();
    method @NonNull public int[] getMatchingUserIds();
    method @NonNull public android.media.projection.MediaProjection getMediaProjection();
  }
@@ -24200,9 +24202,11 @@ package android.media {
    ctor public AudioPlaybackCaptureConfiguration.Builder(@NonNull android.media.projection.MediaProjection);
    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUid(int);
    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUsage(int);
    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder addMatchingUserId(int);
    method @NonNull public android.media.AudioPlaybackCaptureConfiguration build();
    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUid(int);
    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUsage(int);
    method @NonNull public android.media.AudioPlaybackCaptureConfiguration.Builder excludeUserId(int);
  }
  public final class AudioPlaybackConfiguration implements android.os.Parcelable {
+3 −0
Original line number Diff line number Diff line
@@ -4367,6 +4367,7 @@ package android.media.audiopolicy {
    field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
    field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
    field public static final int RULE_MATCH_UID = 4; // 0x4
    field public static final int RULE_MATCH_USERID = 8; // 0x8
  }
  public static class AudioMixingRule.Builder {
@@ -4387,9 +4388,11 @@ package android.media.audiopolicy {
    method public int getFocusDuckingBehavior();
    method public int getStatus();
    method public boolean removeUidDeviceAffinity(int);
    method public boolean removeUserIdDeviceAffinity(int);
    method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public void setRegistration(String);
    method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
    method public boolean setUserIdDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
    method public String toLogFriendlyString();
    field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
    field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
+3 −0
Original line number Diff line number Diff line
@@ -1397,6 +1397,7 @@ package android.media.audiopolicy {
    field public static final int RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET = 2; // 0x2
    field public static final int RULE_MATCH_ATTRIBUTE_USAGE = 1; // 0x1
    field public static final int RULE_MATCH_UID = 4; // 0x4
    field public static final int RULE_MATCH_USERID = 8; // 0x8
  }

  public static class AudioMixingRule.Builder {
@@ -1417,9 +1418,11 @@ package android.media.audiopolicy {
    method public int getFocusDuckingBehavior();
    method public int getStatus();
    method public boolean removeUidDeviceAffinity(int);
    method public boolean removeUserIdDeviceAffinity(int);
    method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public void setRegistration(String);
    method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
    method public boolean setUserIdDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
    method public String toLogFriendlyString();
    field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
    field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
+64 −32
Original line number Diff line number Diff line
@@ -307,6 +307,43 @@ static int _check_AudioSystem_Command(const char* caller, status_t status)
    return kAudioStatusError;
}

static jint getVectorOfAudioDeviceTypeAddr(JNIEnv *env, jintArray deviceTypes,
                                           jobjectArray deviceAddresses,
                                           Vector<AudioDeviceTypeAddr> &audioDeviceTypeAddrVector) {
    if (deviceTypes == nullptr || deviceAddresses == nullptr) {
        return (jint)AUDIO_JAVA_BAD_VALUE;
    }
    jsize deviceCount = env->GetArrayLength(deviceTypes);
    if (deviceCount == 0 || deviceCount != env->GetArrayLength(deviceAddresses)) {
        return (jint)AUDIO_JAVA_BAD_VALUE;
    }
    // retrieve all device types
    std::vector<audio_devices_t> deviceTypesVector;
    jint *typesPtr = nullptr;
    typesPtr = env->GetIntArrayElements(deviceTypes, 0);
    if (typesPtr == nullptr) {
        return (jint)AUDIO_JAVA_BAD_VALUE;
    }
    for (jint i = 0; i < deviceCount; i++) {
        deviceTypesVector.push_back((audio_devices_t)typesPtr[i]);
    }
    // check each address is a string and add device type/address to list
    jclass stringClass = FindClassOrDie(env, "java/lang/String");
    for (jint i = 0; i < deviceCount; i++) {
        jobject addrJobj = env->GetObjectArrayElement(deviceAddresses, i);
        if (!env->IsInstanceOf(addrJobj, stringClass)) {
            return (jint)AUDIO_JAVA_BAD_VALUE;
        }
        const char *address = env->GetStringUTFChars((jstring)addrJobj, NULL);
        AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
        audioDeviceTypeAddrVector.add(dev);
        env->ReleaseStringUTFChars((jstring)addrJobj, address);
    }
    env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);

    return (jint)NO_ERROR;
}

static jint
android_media_AudioSystem_muteMicrophone(JNIEnv *env, jobject thiz, jboolean on)
{
@@ -1905,6 +1942,10 @@ static jint convertAudioMixToNative(JNIEnv *env,
            nCriterion.mValue.mUid = env->GetIntField(jCriterion,
                    gAudioMixMatchCriterionFields.mIntProp);
            break;
        case RULE_MATCH_USERID:
            nCriterion.mValue.mUserId =
                    env->GetIntField(jCriterion, gAudioMixMatchCriterionFields.mIntProp);
            break;
        case RULE_MATCH_ATTRIBUTE_USAGE:
        case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET: {
            jobject jAttributes = env->GetObjectField(jCriterion, gAudioMixMatchCriterionFields.mAttr);
@@ -1990,39 +2031,11 @@ exit:

static jint android_media_AudioSystem_setUidDeviceAffinities(JNIEnv *env, jobject clazz,
        jint uid, jintArray deviceTypes, jobjectArray deviceAddresses) {
    if (deviceTypes == nullptr || deviceAddresses == nullptr) {
        return (jint) AUDIO_JAVA_BAD_VALUE;
    }
    jsize nb = env->GetArrayLength(deviceTypes);
    if (nb == 0 || nb != env->GetArrayLength(deviceAddresses)) {
        return (jint) AUDIO_JAVA_BAD_VALUE;
    }
    // retrieve all device types
    std::vector<audio_devices_t> deviceTypesVector;
    jint* typesPtr = nullptr;
    typesPtr = env->GetIntArrayElements(deviceTypes, 0);
    if (typesPtr == nullptr) {
        return (jint) AUDIO_JAVA_BAD_VALUE;
    }
    for (jint i = 0; i < nb; i++) {
        deviceTypesVector.push_back((audio_devices_t) typesPtr[i]);
    }

    // check each address is a string and add device type/address to list for device affinity
    Vector<AudioDeviceTypeAddr> deviceVector;
    jclass stringClass = FindClassOrDie(env, "java/lang/String");
    for (jint i = 0; i < nb; i++) {
        jobject addrJobj = env->GetObjectArrayElement(deviceAddresses, i);
        if (!env->IsInstanceOf(addrJobj, stringClass)) {
            return (jint) AUDIO_JAVA_BAD_VALUE;
        }
        const char* address = env->GetStringUTFChars((jstring) addrJobj, NULL);
        AudioDeviceTypeAddr dev = AudioDeviceTypeAddr(typesPtr[i], address);
        deviceVector.add(dev);
        env->ReleaseStringUTFChars((jstring) addrJobj, address);
    jint results = getVectorOfAudioDeviceTypeAddr(env, deviceTypes, deviceAddresses, deviceVector);
    if (results != NO_ERROR) {
        return results;
    }
    env->ReleaseIntArrayElements(deviceTypes, typesPtr, 0);

    status_t status = AudioSystem::setUidDeviceAffinities((uid_t) uid, deviceVector);
    return (jint) nativeToJavaStatus(status);
}
@@ -2033,6 +2046,23 @@ static jint android_media_AudioSystem_removeUidDeviceAffinities(JNIEnv *env, job
    return (jint) nativeToJavaStatus(status);
}

static jint android_media_AudioSystem_setUserIdDeviceAffinities(JNIEnv *env, jobject clazz,
                                                                jint userId, jintArray deviceTypes,
                                                                jobjectArray deviceAddresses) {
    Vector<AudioDeviceTypeAddr> deviceVector;
    jint results = getVectorOfAudioDeviceTypeAddr(env, deviceTypes, deviceAddresses, deviceVector);
    if (results != NO_ERROR) {
        return results;
    }
    status_t status = AudioSystem::setUserIdDeviceAffinities((int)userId, deviceVector);
    return (jint)nativeToJavaStatus(status);
}

static jint android_media_AudioSystem_removeUserIdDeviceAffinities(JNIEnv *env, jobject clazz,
                                                                   jint userId) {
    status_t status = AudioSystem::removeUserIdDeviceAffinities((int)userId);
    return (jint)nativeToJavaStatus(status);
}

static jint
android_media_AudioSystem_systemReady(JNIEnv *env, jobject thiz)
@@ -2463,7 +2493,9 @@ static const JNINativeMethod gMethods[] = {
    {"setPreferredDeviceForStrategy", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setPreferredDeviceForStrategy},
    {"removePreferredDeviceForStrategy", "(I)I", (void *)android_media_AudioSystem_removePreferredDeviceForStrategy},
    {"getPreferredDeviceForStrategy", "(I[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getPreferredDeviceForStrategy},
    {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getDevicesForAttributes}
    {"getDevicesForAttributes", "(Landroid/media/AudioAttributes;[Landroid/media/AudioDeviceAddress;)I", (void *)android_media_AudioSystem_getDevicesForAttributes},
    {"setUserIdDeviceAffinities", "(I[I[Ljava/lang/String;)I", (void *)android_media_AudioSystem_setUserIdDeviceAffinities},
    {"removeUserIdDeviceAffinities", "(I)I", (void *)android_media_AudioSystem_removeUserIdDeviceAffinities}
};

static const JNINativeMethod gEventHandlerMethods[] = {
+48 −0
Original line number Diff line number Diff line
@@ -102,6 +102,12 @@ public final class AudioPlaybackCaptureConfiguration {
                                criterion -> criterion.getIntProp());
    }

    /** @return the userId's passed to {@link Builder#addMatchingUserId(int)}. */
    public @NonNull int[] getMatchingUserIds() {
        return getIntPredicates(AudioMixingRule.RULE_MATCH_USERID,
                criterion -> criterion.getIntProp());
    }

    /** @return the usages passed to {@link Builder#excludeUsage(int)}. */
    @AttributeUsage
    public @NonNull int[] getExcludeUsages() {
@@ -115,6 +121,12 @@ public final class AudioPlaybackCaptureConfiguration {
                                criterion -> criterion.getIntProp());
    }

    /** @return the userId's passed to {@link Builder#excludeUserId(int)}.  */
    public @NonNull int[] getExcludeUserIds() {
        return getIntPredicates(AudioMixingRule.RULE_EXCLUDE_USERID,
                criterion -> criterion.getIntProp());
    }

    private int[] getIntPredicates(int rule,
                                   ToIntFunction<AudioMixMatchCriterion> getPredicate) {
        return mAudioMixingRule.getCriteria().stream()
@@ -153,6 +165,7 @@ public final class AudioPlaybackCaptureConfiguration {
        private final MediaProjection mProjection;
        private int mUsageMatchType = MATCH_TYPE_UNSPECIFIED;
        private int mUidMatchType = MATCH_TYPE_UNSPECIFIED;
        private int mUserIdMatchType = MATCH_TYPE_UNSPECIFIED;

        /** @param projection A MediaProjection that supports audio projection. */
        public Builder(@NonNull MediaProjection projection) {
@@ -201,6 +214,23 @@ public final class AudioPlaybackCaptureConfiguration {
            return this;
        }

        /**
         * Only capture audio output by app with the matching {@code userId}.
         *
         * <p>If called multiple times, will capture audio output by apps whose userId is any of the
         * given userId's.
         *
         * @throws IllegalStateException if called in conjunction with {@link #excludeUserId(int)}.
         */
        public @NonNull Builder addMatchingUserId(int userId) {
            Preconditions.checkState(
                    mUserIdMatchType != MATCH_TYPE_EXCLUSIVE,
                    ERROR_MESSAGE_MISMATCHED_RULES);
            mAudioMixingRuleBuilder.addMixRule(AudioMixingRule.RULE_MATCH_USERID, userId);
            mUserIdMatchType = MATCH_TYPE_INCLUSIVE;
            return this;
        }

        /**
         * Only capture audio output that does not match the given {@link AudioAttributes}.
         *
@@ -237,6 +267,24 @@ public final class AudioPlaybackCaptureConfiguration {
            return this;
        }

        /**
         * Only capture audio output by apps that do not have the matching {@code userId}.
         *
         * <p>If called multiple times, will capture audio output by apps whose userId is not any of
         * the given userId's.
         *
         * @throws IllegalStateException if called in conjunction with
         * {@link #addMatchingUserId(int)}.
         */
        public @NonNull Builder excludeUserId(int userId) {
            Preconditions.checkState(
                    mUserIdMatchType != MATCH_TYPE_INCLUSIVE,
                    ERROR_MESSAGE_MISMATCHED_RULES);
            mAudioMixingRuleBuilder.excludeMixRule(AudioMixingRule.RULE_MATCH_USERID, userId);
            mUserIdMatchType = MATCH_TYPE_EXCLUSIVE;
            return this;
        }

        /**
         * Builds the configuration instance.
         *
Loading