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

Commit 29149e4b authored by Marvin Ramin's avatar Marvin Ramin Committed by Android (Google) Code Review
Browse files

Merge "Add TestApis to get currently registered AudioMixes" into main

parents c89fa236 a4c942d8
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -1879,6 +1879,7 @@ package android.media {
    method @FlaggedApi("android.media.audio.focus_freeze_test_api") @RequiresPermission("android.permission.QUERY_AUDIO_STATE") public long getFocusUnmuteDelayAfterFadeOutForTest();
    method @Nullable public static android.media.AudioHalVersionInfo getHalVersion();
    method public static final int[] getPublicStreamTypes();
    method @FlaggedApi("android.media.audiopolicy.audio_mix_test_api") @NonNull public java.util.List<android.media.audiopolicy.AudioMix> getRegisteredPolicyMixes();
    method @NonNull public java.util.List<java.lang.Integer> getReportedSurroundFormats();
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_SETTINGS_PRIVILEGED) public float getRs2Value();
    method public int getStreamMinVolumeInt(int);
@@ -2052,6 +2053,10 @@ package android.media.audiofx {

package android.media.audiopolicy {

  public class AudioPolicy {
    method @FlaggedApi("android.media.audiopolicy.audio_mix_test_api") @NonNull public java.util.List<android.media.audiopolicy.AudioMix> getMixes();
  }

  public static class AudioPolicy.Builder {
    method @NonNull public android.media.audiopolicy.AudioPolicy.Builder setIsTestFocusPolicy(boolean);
  }
+1 −0
Original line number Diff line number Diff line
@@ -98,6 +98,7 @@ cc_library_shared_for_libandroid_runtime {
        "libminikin",
        "libz",
        "server_configurable_flags",
        "android.media.audiopolicy-aconfig-cc",
    ],

    static_libs: [
+183 −0
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@
#include <android/media/INativeSpatializerCallback.h>
#include <android/media/ISpatializer.h>
#include <android/media/audio/common/AudioConfigBase.h>
#include <android_media_audiopolicy.h>
#include <android_os_Parcel.h>
#include <audiomanager/AudioManager.h>
#include <jni.h>
@@ -55,6 +56,8 @@

// ----------------------------------------------------------------------------

namespace audio_flags = android::media::audiopolicy;

using namespace android;
using media::audio::common::AudioConfigBase;

@@ -145,6 +148,7 @@ static struct {
} gAudioPatchFields;

static jclass gAudioMixClass;
static jmethodID gAudioMixCstor;
static struct {
    jfieldID    mRule;
    jfieldID    mFormat;
@@ -165,7 +169,15 @@ static struct {
    // other fields unused by JNI
} gAudioFormatFields;

static jclass gAudioAttributesClass;
static jmethodID gAudioAttributesCstor;
static struct {
    jfieldID mSource;
    jfieldID mUsage;
} gAudioAttributesFields;

static jclass gAudioMixingRuleClass;
static jmethodID gAudioMixingRuleCstor;
static struct {
    jfieldID    mCriteria;
    jfieldID    mAllowPrivilegedPlaybackCapture;
@@ -174,6 +186,8 @@ static struct {
} gAudioMixingRuleFields;

static jclass gAudioMixMatchCriterionClass;
static jmethodID gAudioMixMatchCriterionAttrCstor;
static jmethodID gAudioMixMatchCriterionIntPropCstor;
static struct {
    jfieldID    mAttr;
    jfieldID    mIntProp;
@@ -2087,6 +2101,39 @@ jobject nativeAudioConfigBaseToJavaAudioFormat(JNIEnv *env, const audio_config_b
                          channelMask, channelIndexMask);
}

jint nativeAudioConfigToJavaAudioFormat(JNIEnv *env, const audio_config_t *nConfigBase,
                                        jobject *jAudioFormat, bool isInput) {
    if (!audio_flags::audio_mix_test_api()) {
        return AUDIO_JAVA_INVALID_OPERATION;
    }

    if (nConfigBase == nullptr) {
        return AUDIO_JAVA_BAD_VALUE;
    }
    int propertyMask = AUDIO_FORMAT_HAS_PROPERTY_ENCODING | AUDIO_FORMAT_HAS_PROPERTY_SAMPLE_RATE;
    int channelMask = 0;
    int channelIndexMask = 0;
    switch (audio_channel_mask_get_representation(nConfigBase->channel_mask)) {
        case AUDIO_CHANNEL_REPRESENTATION_POSITION:
            channelMask = isInput ? inChannelMaskFromNative(nConfigBase->channel_mask)
                                  : outChannelMaskFromNative(nConfigBase->channel_mask);
            propertyMask |= AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_MASK;
            break;
        case AUDIO_CHANNEL_REPRESENTATION_INDEX:
            channelIndexMask = audio_channel_mask_get_bits(nConfigBase->channel_mask);
            propertyMask |= AUDIO_FORMAT_HAS_PROPERTY_CHANNEL_INDEX_MASK;
            break;
        default:
            // This must not happen
            break;
    }

    *jAudioFormat = env->NewObject(gAudioFormatClass, gAudioFormatCstor, propertyMask,
                                   audioFormatFromNative(nConfigBase->format),
                                   nConfigBase->sample_rate, channelMask, channelIndexMask);
    return AUDIO_JAVA_SUCCESS;
}

jint convertAudioMixerAttributesToNative(JNIEnv *env, const jobject jAudioMixerAttributes,
                                         audio_mixer_attributes_t *nMixerAttributes) {
    ScopedLocalRef<jobject> jFormat(env,
@@ -2179,6 +2226,88 @@ static jint convertAudioMixingRuleToNative(JNIEnv *env, const jobject audioMixin
    return AUDIO_JAVA_SUCCESS;
}

static jint nativeAudioMixToJavaAudioMixingRule(JNIEnv *env, const AudioMix &nAudioMix,
                                                jobject *jAudioMixingRule) {
    if (!audio_flags::audio_mix_test_api()) {
        return AUDIO_JAVA_INVALID_OPERATION;
    }

    jobject jAudioMixMatchCriterionList = env->NewObject(gArrayListClass, gArrayListMethods.cstor);
    for (const auto &criteria : nAudioMix.mCriteria) {
        jobject jAudioAttributes = NULL;
        jobject jMixMatchCriterion = NULL;
        jobject jValueInteger = NULL;
        switch (criteria.mRule) {
            case RULE_MATCH_UID:
                jValueInteger = env->NewObject(gIntegerClass, gIntegerCstor, criteria.mValue.mUid);
                jMixMatchCriterion = env->NewObject(gAudioMixMatchCriterionClass,
                                                    gAudioMixMatchCriterionIntPropCstor,
                                                    jValueInteger, criteria.mRule);
                break;
            case RULE_MATCH_USERID:
                jValueInteger =
                        env->NewObject(gIntegerClass, gIntegerCstor, criteria.mValue.mUserId);
                jMixMatchCriterion = env->NewObject(gAudioMixMatchCriterionClass,
                                                    gAudioMixMatchCriterionIntPropCstor,
                                                    jValueInteger, criteria.mRule);
                break;
            case RULE_MATCH_AUDIO_SESSION_ID:
                jValueInteger = env->NewObject(gIntegerClass, gIntegerCstor,
                                               criteria.mValue.mAudioSessionId);
                jMixMatchCriterion = env->NewObject(gAudioMixMatchCriterionClass,
                                                    gAudioMixMatchCriterionIntPropCstor,
                                                    jValueInteger, criteria.mRule);
                break;
            case RULE_MATCH_ATTRIBUTE_USAGE:
                jAudioAttributes = env->NewObject(gAudioAttributesClass, gAudioAttributesCstor);
                env->SetIntField(jAudioAttributes, gAudioAttributesFields.mUsage,
                                 criteria.mValue.mUsage);
                jMixMatchCriterion = env->NewObject(gAudioMixMatchCriterionClass,
                                                    gAudioMixMatchCriterionAttrCstor,
                                                    jMixMatchCriterion, criteria.mRule);
                break;
            case RULE_MATCH_ATTRIBUTE_CAPTURE_PRESET:
                jAudioAttributes = env->NewObject(gAudioAttributesClass, gAudioAttributesCstor);
                env->SetIntField(jAudioAttributes, gAudioAttributesFields.mSource,
                                 criteria.mValue.mSource);
                jMixMatchCriterion = env->NewObject(gAudioMixMatchCriterionClass,
                                                    gAudioMixMatchCriterionAttrCstor,
                                                    jMixMatchCriterion, criteria.mRule);
                break;
        }
        env->CallBooleanMethod(jAudioMixMatchCriterionList, gArrayListMethods.add,
                               jMixMatchCriterion);
    }

    *jAudioMixingRule = env->NewObject(gAudioMixingRuleClass, gAudioMixingRuleCstor,
                                       nAudioMix.mMixType, jAudioMixMatchCriterionList,
                                       nAudioMix.mAllowPrivilegedMediaPlaybackCapture,
                                       nAudioMix.mVoiceCommunicationCaptureAllowed);
    return AUDIO_JAVA_SUCCESS;
}

static jint convertAudioMixFromNative(JNIEnv *env, jobject *jAudioMix, const AudioMix &nAudioMix) {
    if (!audio_flags::audio_mix_test_api()) {
        return AUDIO_JAVA_INVALID_OPERATION;
    }
    jobject jAudioMixingRule = NULL;
    int status = nativeAudioMixToJavaAudioMixingRule(env, nAudioMix, &jAudioMixingRule);
    if (status != AUDIO_JAVA_SUCCESS) {
        return status;
    }
    jobject jAudioFormat = NULL;
    status = nativeAudioConfigToJavaAudioFormat(env, &nAudioMix.mFormat, &jAudioFormat, false);
    if (status != AUDIO_JAVA_SUCCESS) {
        return status;
    }

    jstring deviceAddress = env->NewStringUTF(nAudioMix.mDeviceAddress.c_str());
    *jAudioMix = env->NewObject(gAudioMixClass, gAudioMixCstor, jAudioMixingRule, jAudioFormat,
                                nAudioMix.mRouteFlags, nAudioMix.mCbFlags, nAudioMix.mDeviceType,
                                deviceAddress);
    return AUDIO_JAVA_SUCCESS;
}

static jint convertAudioMixToNative(JNIEnv *env, AudioMix *nAudioMix, const jobject jAudioMix) {
    nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
    nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
@@ -2252,6 +2381,34 @@ android_media_AudioSystem_registerPolicyMixes(JNIEnv *env, jobject clazz,
    return nativeToJavaStatus(status);
}

static jint android_media_AudioSystem_getRegisteredPolicyMixes(JNIEnv *env, jobject clazz,
                                                               jobject jMixes) {
    if (!audio_flags::audio_mix_test_api()) {
        return AUDIO_JAVA_INVALID_OPERATION;
    }

    status_t status;
    std::vector<AudioMix> mixes;
    ALOGV("AudioSystem::getRegisteredPolicyMixes");
    status = AudioSystem::getRegisteredPolicyMixes(mixes);
    ALOGV("AudioSystem::getRegisteredPolicyMixes() returned %zu mixes. Status=%d", mixes.size(),
          status);
    if (status != NO_ERROR) {
        return nativeToJavaStatus(status);
    }

    for (const auto &mix : mixes) {
        jobject jAudioMix = NULL;
        int conversionStatus = convertAudioMixFromNative(env, &jAudioMix, mix);
        if (conversionStatus != AUDIO_JAVA_SUCCESS) {
            return conversionStatus;
        }
        env->CallBooleanMethod(jMixes, gListMethods.add, jAudioMix);
    }

    return AUDIO_JAVA_SUCCESS;
}

static jint android_media_AudioSystem_updatePolicyMixes(JNIEnv *env, jobject clazz,
                                                        jobjectArray mixes,
                                                        jobjectArray updatedMixingRules) {
@@ -3251,6 +3408,8 @@ static const JNINativeMethod gMethods[] =
         MAKE_AUDIO_SYSTEM_METHOD(getAudioHwSyncForSession),
         MAKE_JNI_NATIVE_METHOD("registerPolicyMixes", "(Ljava/util/ArrayList;Z)I",
                                android_media_AudioSystem_registerPolicyMixes),
         MAKE_JNI_NATIVE_METHOD("getRegisteredPolicyMixes", "(Ljava/util/List;)I",
                                android_media_AudioSystem_getRegisteredPolicyMixes),
         MAKE_JNI_NATIVE_METHOD("updatePolicyMixes",
                                "([Landroid/media/audiopolicy/AudioMix;[Landroid/media/audiopolicy/"
                                "AudioMixingRule;)I",
@@ -3499,6 +3658,11 @@ int register_android_media_AudioSystem(JNIEnv *env)

    jclass audioMixClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMix");
    gAudioMixClass = MakeGlobalRefOrDie(env, audioMixClass);
    if (audio_flags::audio_mix_test_api()) {
        gAudioMixCstor = GetMethodIDOrDie(env, audioMixClass, "<init>",
                                          "(Landroid/media/audiopolicy/AudioMixingRule;Landroid/"
                                          "media/AudioFormat;IIILjava/lang/String;)V");
    }
    gAudioMixFields.mRule = GetFieldIDOrDie(env, audioMixClass, "mRule",
                                                "Landroid/media/audiopolicy/AudioMixingRule;");
    gAudioMixFields.mFormat = GetFieldIDOrDie(env, audioMixClass, "mFormat",
@@ -3521,6 +3685,10 @@ int register_android_media_AudioSystem(JNIEnv *env)

    jclass audioMixingRuleClass = FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule");
    gAudioMixingRuleClass = MakeGlobalRefOrDie(env, audioMixingRuleClass);
    if (audio_flags::audio_mix_test_api()) {
        gAudioMixingRuleCstor = GetMethodIDOrDie(env, audioMixingRuleClass, "<init>",
                                                 "(ILjava/util/Collection;ZZ)V");
    }
    gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
                                                       "Ljava/util/ArrayList;");
    gAudioMixingRuleFields.mAllowPrivilegedPlaybackCapture =
@@ -3529,9 +3697,24 @@ int register_android_media_AudioSystem(JNIEnv *env)
    gAudioMixingRuleFields.mVoiceCommunicationCaptureAllowed =
            GetFieldIDOrDie(env, audioMixingRuleClass, "mVoiceCommunicationCaptureAllowed", "Z");

    if (audio_flags::audio_mix_test_api()) {
        jclass audioAttributesClass = FindClassOrDie(env, "android/media/AudioAttributes");
        gAudioAttributesClass = MakeGlobalRefOrDie(env, audioAttributesClass);
        gAudioAttributesCstor = GetMethodIDOrDie(env, gAudioAttributesClass, "<init>", "()V");
        gAudioAttributesFields.mSource = GetFieldIDOrDie(env, gAudioAttributesClass, "mUsage", "I");
        gAudioAttributesFields.mUsage = GetFieldIDOrDie(env, gAudioAttributesClass, "mSource", "I");
    }

    jclass audioMixMatchCriterionClass =
                FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
    gAudioMixMatchCriterionClass = MakeGlobalRefOrDie(env,audioMixMatchCriterionClass);
    if (audio_flags::audio_mix_test_api()) {
        gAudioMixMatchCriterionAttrCstor =
                GetMethodIDOrDie(env, gAudioMixMatchCriterionClass, "<init>",
                                 "(Landroid/media/AudioAttributes;I)V");
        gAudioMixMatchCriterionIntPropCstor = GetMethodIDOrDie(env, gAudioMixMatchCriterionClass,
                                                               "<init>", "(Ljava/lang/Integer;I)V");
    }
    gAudioMixMatchCriterionFields.mAttr = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mAttr",
                                                       "Landroid/media/AudioAttributes;");
    gAudioMixMatchCriterionFields.mIntProp = GetFieldIDOrDie(env, audioMixMatchCriterionClass, "mIntProp",
+20 −0
Original line number Diff line number Diff line
@@ -5511,6 +5511,26 @@ public class AudioManager {
        }
    }

    /**
     * @hide
     * @return All currently registered audio policy mixes.
     */
    @TestApi
    @FlaggedApi(android.media.audiopolicy.Flags.FLAG_AUDIO_MIX_TEST_API)
    @NonNull
    public List<android.media.audiopolicy.AudioMix> getRegisteredPolicyMixes() {
        if (!android.media.audiopolicy.Flags.audioMixTestApi()) {
            return Collections.emptyList();
        }

        final IAudioService service = getService();
        try {
            return service.getRegisteredPolicyMixes();
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * @hide
     * @return true if an AudioPolicy was previously registered
+3 −0
Original line number Diff line number Diff line
@@ -1983,6 +1983,9 @@ public class AudioSystem
    /** @hide */
    public static native int registerPolicyMixes(ArrayList<AudioMix> mixes, boolean register);

    /** @hide */
    public static native int getRegisteredPolicyMixes(@NonNull List<AudioMix> devices);

    /** @hide */
    public static native int updatePolicyMixes(
            AudioMix[] mixes,
Loading