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

Commit adcd00a7 authored by François Gaffie's avatar François Gaffie Committed by Hongwei Wang
Browse files

AudioVolumeGroup introspection & callback JAVA APIs



This CL adds introspection APIs for Audio Volume group
and callback notification on group volume change.
It allows to keep the same level of service available today
in CarAudioManager and is a starting point to get rid of Stream Alias
hard coded in AudioServer.

Bug: 124767636
Test: dumpsys media.audio_policy
Change-Id: I48909df93c146f071acd24cd3ecc608cb98b4d7e
Signed-off-by: default avatarFrançois Gaffie <francois.gaffie@renault.com>
parent 4ed935a5
Loading
Loading
Loading
Loading
+31 −0
Original line number Diff line number Diff line
@@ -3456,15 +3456,18 @@ package android.media {
    method public void clearAudioServerStateCallback();
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int dispatchAudioFocusChange(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioProductStrategies getAudioProductStrategies();
    method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public android.media.audiopolicy.AudioVolumeGroups getAudioVolumeGroups();
    method public boolean isAudioServerRunning();
    method public boolean isHdmiSystemAudioSupported();
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int registerAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
    method public void registerVolumeGroupCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.VolumeGroupCallback);
    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int) throws java.lang.IllegalArgumentException;
    method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.MODIFY_PHONE_STATE, android.Manifest.permission.MODIFY_AUDIO_ROUTING}) public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, @NonNull android.media.AudioAttributes, int, int, android.media.audiopolicy.AudioPolicy) throws java.lang.IllegalArgumentException;
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int requestAudioFocus(@NonNull android.media.AudioFocusRequest, @Nullable android.media.audiopolicy.AudioPolicy);
    method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
    method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
    method public void unregisterVolumeGroupCallback(@NonNull android.media.AudioManager.VolumeGroupCallback);
    field public static final int AUDIOFOCUS_FLAG_DELAY_OK = 1; // 0x1
    field public static final int AUDIOFOCUS_FLAG_LOCK = 4; // 0x4
    field public static final int AUDIOFOCUS_FLAG_PAUSES_ON_DUCKABLE_LOSS = 2; // 0x2
@@ -3478,6 +3481,11 @@ package android.media {
    method public void onAudioServerUp();
  }
  public abstract static class AudioManager.VolumeGroupCallback {
    ctor public AudioManager.VolumeGroupCallback();
    method public void onAudioVolumeGroupChanged(int, int);
  }
  public final class AudioPlaybackConfiguration implements android.os.Parcelable {
    method public int getClientPid();
    method public int getClientUid();
@@ -3649,6 +3657,8 @@ package android.media.audiopolicy {
    method @Nullable public android.media.audiopolicy.AudioProductStrategy getById(int);
    method public int getLegacyStreamTypeForAudioAttributes(@NonNull android.media.AudioAttributes);
    method @Nullable public android.media.audiopolicy.AudioProductStrategy getProductStrategyForAudioAttributes(@NonNull android.media.AudioAttributes);
    method public int getVolumeGroupIdForAttributes(@NonNull android.media.AudioAttributes);
    method public int getVolumeGroupIdForLegacyStreamType(int);
    method public java.util.Iterator<android.media.audiopolicy.AudioProductStrategy> iterator();
    method public int size();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
@@ -3664,6 +3674,27 @@ package android.media.audiopolicy {
    field public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioProductStrategy> CREATOR;
  }
  public final class AudioVolumeGroup implements android.os.Parcelable {
    method public int describeContents();
    method public java.util.List<android.media.AudioAttributes> getAudioAttributes();
    method public int getId();
    method @NonNull public int[] getLegacyStreamTypes();
    method @NonNull public String name();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioVolumeGroup> CREATOR;
  }
  public final class AudioVolumeGroups implements java.lang.Iterable<android.media.audiopolicy.AudioVolumeGroup> android.os.Parcelable {
    ctor public AudioVolumeGroups();
    method public int describeContents();
    method @Nullable public android.media.audiopolicy.AudioVolumeGroup getById(int);
    method public java.util.Iterator<android.media.audiopolicy.AudioVolumeGroup> iterator();
    method public int size();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field public static final android.os.Parcelable.Creator<android.media.audiopolicy.AudioVolumeGroups> CREATOR;
    field public static final int DEFAULT_VOLUME_GROUP = -1; // 0xffffffff
  }
}
package android.media.session {
+2 −0
Original line number Diff line number Diff line
@@ -165,6 +165,8 @@ cc_library_shared {
        "android_media_AudioTrack.cpp",
        "android_media_AudioAttributes.cpp",
        "android_media_AudioProductStrategies.cpp",
        "android_media_AudioVolumeGroups.cpp",
        "android_media_AudioVolumeGroupCallback.cpp",
        "android_media_DeviceCallback.cpp",
        "android_media_JetPlayer.cpp",
        "android_media_MediaMetricsJNI.cpp",
+4 −0
Original line number Diff line number Diff line
@@ -110,6 +110,8 @@ extern int register_android_media_AudioSystem(JNIEnv *env);
extern int register_android_media_AudioTrack(JNIEnv *env);
extern int register_android_media_AudioAttributes(JNIEnv *env);
extern int register_android_media_AudioProductStrategies(JNIEnv *env);
extern int register_android_media_AudioVolumeGroups(JNIEnv *env);
extern int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env);
extern int register_android_media_MicrophoneInfo(JNIEnv *env);
extern int register_android_media_JetPlayer(JNIEnv *env);
extern int register_android_media_ToneGenerator(JNIEnv *env);
@@ -1524,6 +1526,8 @@ static const RegJNIRec gRegJNI[] = {
    REG_JNI(register_android_media_AudioTrack),
    REG_JNI(register_android_media_AudioAttributes),
    REG_JNI(register_android_media_AudioProductStrategies),
    REG_JNI(register_android_media_AudioVolumeGroups),
    REG_JNI(register_android_media_AudioVolumeGroupChangeHandler),
    REG_JNI(register_android_media_JetPlayer),
    REG_JNI(register_android_media_MicrophoneInfo),
    REG_JNI(register_android_media_RemoteDisplay),
+4 −4
Original line number Diff line number Diff line
@@ -57,7 +57,7 @@ static struct {
static jclass gAudioAttributesGroupClass;
static jmethodID gAudioAttributesGroupCstor;
static struct {
    jfieldID    mGroupId;
    jfieldID    mVolumeGroupId;
    jfieldID    mLegacyStreamType;
    jfieldID    mAudioAttributes;
} gAudioAttributesGroupsFields;
@@ -249,8 +249,8 @@ int register_android_media_AudioProductStrategies(JNIEnv *env)
    gAudioAttributesGroupClass = MakeGlobalRefOrDie(env, audioAttributesGroupClass);
    gAudioAttributesGroupCstor = GetMethodIDOrDie(env, audioAttributesGroupClass, "<init>",
                                                  "(II[Landroid/media/AudioAttributes;)V");
    gAudioAttributesGroupsFields.mGroupId = GetFieldIDOrDie(
                env, audioAttributesGroupClass, "mGroupId", "I");
    gAudioAttributesGroupsFields.mVolumeGroupId = GetFieldIDOrDie(
                env, audioAttributesGroupClass, "mVolumeGroupId", "I");
    gAudioAttributesGroupsFields.mLegacyStreamType = GetFieldIDOrDie(
                env, audioAttributesGroupClass, "mLegacyStreamType", "I");
    gAudioAttributesGroupsFields.mAudioAttributes = GetFieldIDOrDie(
+175 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//#define LOG_NDEBUG 0

#define LOG_TAG "AudioVolumeGroupCallback-JNI"

#include <utils/Log.h>
#include <nativehelper/JNIHelp.h>
#include "core_jni_helpers.h"

#include "android_media_AudioVolumeGroupCallback.h"


// ----------------------------------------------------------------------------
using namespace android;

static const char* const kAudioVolumeGroupChangeHandlerClassPathName =
        "android/media/audiopolicy/AudioVolumeGroupChangeHandler";

static struct {
    jfieldID    mJniCallback;
} gAudioVolumeGroupChangeHandlerFields;

static struct {
    jmethodID    postEventFromNative;
} gAudioVolumeGroupChangeHandlerMethods;

static Mutex gLock;

JNIAudioVolumeGroupCallback::JNIAudioVolumeGroupCallback(JNIEnv* env,
                                                         jobject thiz,
                                                         jobject weak_thiz)
{
    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
        ALOGE("Can't find class %s", kAudioVolumeGroupChangeHandlerClassPathName);
        return;
    }
    mClass = (jclass)env->NewGlobalRef(clazz);

    // We use a weak reference so the AudioVolumeGroupChangeHandler object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    mObject  = env->NewGlobalRef(weak_thiz);
}

JNIAudioVolumeGroupCallback::~JNIAudioVolumeGroupCallback()
{
    // remove global references
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        return;
    }
    env->DeleteGlobalRef(mObject);
    env->DeleteGlobalRef(mClass);
}

void JNIAudioVolumeGroupCallback::onAudioVolumeGroupChanged(volume_group_t group, int flags)
{
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        return;
    }
    ALOGV("%s volume group id %d", __FUNCTION__, group);
    env->CallStaticVoidMethod(mClass,
                              gAudioVolumeGroupChangeHandlerMethods.postEventFromNative,
                              mObject,
                              AUDIOVOLUMEGROUP_EVENT_VOLUME_CHANGED, group, flags, NULL);
    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while notifying an event.");
        env->ExceptionClear();
    }
}

void JNIAudioVolumeGroupCallback::onServiceDied()
{
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        return;
    }
    env->CallStaticVoidMethod(mClass,
                              gAudioVolumeGroupChangeHandlerMethods.postEventFromNative,
                              mObject,
                              AUDIOVOLUMEGROUP_EVENT_SERVICE_DIED, 0, 0, NULL);
    if (env->ExceptionCheck()) {
        ALOGW("An exception occurred while notifying an event.");
        env->ExceptionClear();
    }
}

static
sp<JNIAudioVolumeGroupCallback> setJniCallback(JNIEnv* env,
                                               jobject thiz,
                                               const sp<JNIAudioVolumeGroupCallback>& callback)
{
    Mutex::Autolock l(gLock);
    sp<JNIAudioVolumeGroupCallback> old = (JNIAudioVolumeGroupCallback*)env->GetLongField(
                thiz, gAudioVolumeGroupChangeHandlerFields.mJniCallback);
    if (callback.get()) {
        callback->incStrong((void*)setJniCallback);
    }
    if (old != 0) {
        old->decStrong((void*)setJniCallback);
    }
    env->SetLongField(thiz, gAudioVolumeGroupChangeHandlerFields.mJniCallback,
                      (jlong)callback.get());
    return old;
}

static void
android_media_AudioVolumeGroupChangeHandler_eventHandlerSetup(JNIEnv *env,
                                                              jobject thiz,
                                                              jobject weak_this)
{
    ALOGV("%s", __FUNCTION__);
    sp<JNIAudioVolumeGroupCallback> callback =
            new JNIAudioVolumeGroupCallback(env, thiz, weak_this);

    if (AudioSystem::addAudioVolumeGroupCallback(callback) == NO_ERROR) {
        setJniCallback(env, thiz, callback);
    }
}

static void
android_media_AudioVolumeGroupChangeHandler_eventHandlerFinalize(JNIEnv *env, jobject thiz)
{
    ALOGV("%s", __FUNCTION__);
    sp<JNIAudioVolumeGroupCallback> callback = setJniCallback(env, thiz, 0);
    if (callback != 0) {
        AudioSystem::removeAudioVolumeGroupCallback(callback);
    }
}

/*
 * JNI registration.
 */
static const JNINativeMethod gMethods[] = {
    {"native_setup", "(Ljava/lang/Object;)V",
        (void *)android_media_AudioVolumeGroupChangeHandler_eventHandlerSetup},
    {"native_finalize",  "()V",
        (void *)android_media_AudioVolumeGroupChangeHandler_eventHandlerFinalize},
};

int register_android_media_AudioVolumeGroupChangeHandler(JNIEnv *env)
{
    jclass audioVolumeGroupChangeHandlerClass =
            FindClassOrDie(env, kAudioVolumeGroupChangeHandlerClassPathName);
    gAudioVolumeGroupChangeHandlerMethods.postEventFromNative =
            GetStaticMethodIDOrDie(env, audioVolumeGroupChangeHandlerClass, "postEventFromNative",
                                   "(Ljava/lang/Object;IIILjava/lang/Object;)V");

    gAudioVolumeGroupChangeHandlerFields.mJniCallback =
            GetFieldIDOrDie(env, audioVolumeGroupChangeHandlerClass, "mJniCallback", "J");

    env->DeleteLocalRef(audioVolumeGroupChangeHandlerClass);

    return RegisterMethodsOrDie(env,
                                kAudioVolumeGroupChangeHandlerClassPathName,
                                gMethods,
                                NELEM(gMethods));
}
Loading