diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 7105a4f909c14..ceec849dc202d 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -6592,6 +6592,7 @@ package android.media { method @NonNull @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int[] getSupportedSystemUsages(); method @IntRange(from=0) @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public int getVolumeIndexForAttributes(@NonNull android.media.AudioAttributes); method public boolean isAudioServerRunning(); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean isBluetoothVariableLatencyEnabled(); method public boolean isHdmiSystemAudioSupported(); method @RequiresPermission(android.Manifest.permission.CALL_AUDIO_INTERCEPTION) public boolean isPstnCallAudioInterceptable(); method @RequiresPermission(android.Manifest.permission.ACCESS_ULTRASOUND) public boolean isUltrasoundSupported(); @@ -6610,6 +6611,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setActiveAssistantServiceUids(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setAdditionalOutputDeviceDelay(@NonNull android.media.AudioDeviceInfo, @IntRange(from=0) long); method public void setAudioServerStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.media.AudioManager.AudioServerStateCallback); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setBluetoothVariableLatencyEnabled(boolean); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setDeviceVolumeBehavior(@NonNull android.media.AudioDeviceAttributes, int); 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 boolean setPreferredDeviceForCapturePreset(int, @NonNull android.media.AudioDeviceAttributes); @@ -6617,6 +6619,7 @@ package android.media { method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean setPreferredDevicesForStrategy(@NonNull android.media.audiopolicy.AudioProductStrategy, @NonNull java.util.List); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setSupportedSystemUsages(@NonNull int[]); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void setVolumeIndexForAttributes(@NonNull android.media.AudioAttributes, int, int); + method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public boolean supportsBluetoothVariableLatency(); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy); method @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) public void unregisterMuteAwaitConnectionCallback(@NonNull android.media.AudioManager.MuteAwaitConnectionCallback); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 28ac464bdf72e..19cb30e4b6cb6 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -3201,6 +3201,30 @@ static jint android_media_AudioSystem_clearPreferredMixerAttributes(JNIEnv *env, return nativeToJavaStatus(status); } +static jboolean android_media_AudioSystem_supportsBluetoothVariableLatency(JNIEnv *env, + jobject thiz) { + bool supports; + if (AudioSystem::supportsBluetoothVariableLatency(&supports) != NO_ERROR) { + supports = false; + } + return supports; +} + +static int android_media_AudioSystem_setBluetoothVariableLatencyEnabled(JNIEnv *env, jobject thiz, + jboolean enabled) { + return (jint)check_AudioSystem_Command( + AudioSystem::setBluetoothVariableLatencyEnabled(enabled)); +} + +static jboolean android_media_AudioSystem_isBluetoothVariableLatencyEnabled(JNIEnv *env, + jobject thiz) { + bool enabled; + if (AudioSystem::isBluetoothVariableLatencyEnabled(&enabled) != NO_ERROR) { + enabled = false; + } + return enabled; +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gMethods[] = @@ -3364,7 +3388,13 @@ static const JNINativeMethod gMethods[] = {"getPreferredMixerAttributes", "(Landroid/media/AudioAttributes;ILjava/util/List;)I", (void *)android_media_AudioSystem_getPreferredMixerAttributes}, {"clearPreferredMixerAttributes", "(Landroid/media/AudioAttributes;II)I", - (void *)android_media_AudioSystem_clearPreferredMixerAttributes}}; + (void *)android_media_AudioSystem_clearPreferredMixerAttributes}, + {"supportsBluetoothVariableLatency", "()Z", + (void *)android_media_AudioSystem_supportsBluetoothVariableLatency}, + {"setBluetoothVariableLatencyEnabled", "(Z)I", + (void *)android_media_AudioSystem_setBluetoothVariableLatencyEnabled}, + {"isBluetoothVariableLatencyEnabled", "()Z", + (void *)android_media_AudioSystem_isBluetoothVariableLatencyEnabled}}; static const JNINativeMethod gEventHandlerMethods[] = { {"native_setup", diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index b0609ec88e43a..3a559937d7f4b 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -8773,6 +8773,55 @@ public class AudioManager { } } + /** + * Requests if the implementation supports controlling the latency modes + * over the Bluetooth A2DP or LE Audio links. + * + * @return true if supported, false otherwise + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean supportsBluetoothVariableLatency() { + try { + return getService().supportsBluetoothVariableLatency(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Enables or disables the variable Bluetooth latency control mechanism in the + * audio framework and the audio HAL. This does not apply to the latency mode control + * on the spatializer output as this is a built-in feature. + * + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void setBluetoothVariableLatencyEnabled(boolean enabled) { + try { + getService().setBluetoothVariableLatencyEnabled(enabled); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled. + * @hide + */ + @SystemApi + @RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean isBluetoothVariableLatencyEnabled() { + try { + return getService().isBluetoothVariableLatencyEnabled(); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + //==================================================================== // Mute await connection diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 3e0d657588e5c..a7435868f98e2 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -2476,4 +2476,30 @@ public class AudioSystem */ public static native int clearPreferredMixerAttributes( @NonNull AudioAttributes attributes, int portId, int uid); + + + /** + * Requests if the implementation supports controlling the latency modes + * over the Bluetooth A2DP or LE Audio links. + * + * @return true if supported, false otherwise + * + * @hide + */ + public static native boolean supportsBluetoothVariableLatency(); + + /** + * Enables or disables the variable Bluetooth latency control mechanism in the + * audio framework and the audio HAL. This does not apply to the latency mode control + * on the spatializer output as this is a built-in feature. + * + * @hide + */ + public static native int setBluetoothVariableLatencyEnabled(boolean enabled); + + /** + * Indicates if the variable Bluetooth latency control mechanism is enabled or disabled. + * @hide + */ + public static native boolean isBluetoothVariableLatencyEnabled(); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 05a0b865dd3a2..0f63cc40ca361 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -587,4 +587,16 @@ interface IAudioService { IPreferredMixerAttributesDispatcher dispatcher); oneway void unregisterPreferredMixerAttributesDispatcher( IPreferredMixerAttributesDispatcher dispatcher); + + @EnforcePermission("MODIFY_AUDIO_ROUTING") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)") + boolean supportsBluetoothVariableLatency(); + + @EnforcePermission("MODIFY_AUDIO_ROUTING") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)") + void setBluetoothVariableLatencyEnabled(boolean enabled); + + @EnforcePermission("MODIFY_AUDIO_ROUTING") + @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING)") + boolean isBluetoothVariableLatencyEnabled(); } diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 8c3c0c934240d..b505396000ddf 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -131,6 +131,8 @@ import android.media.audiopolicy.AudioPolicyConfig; import android.media.audiopolicy.AudioProductStrategy; import android.media.audiopolicy.AudioVolumeGroup; import android.media.audiopolicy.IAudioPolicyCallback; +import android.media.permission.ClearCallingIdentityContext; +import android.media.permission.SafeCloseable; import android.media.projection.IMediaProjection; import android.media.projection.IMediaProjectionCallback; import android.media.projection.IMediaProjectionManager; @@ -11219,6 +11221,34 @@ public class AudioService extends IAudioService.Stub mPrefMixerAttrDispatcher.finishBroadcast(); } + + /** @see AudioManager#supportsBluetoothVariableLatency() */ + @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean supportsBluetoothVariableLatency() { + super.supportsBluetoothVariableLatency_enforcePermission(); + try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { + return AudioSystem.supportsBluetoothVariableLatency(); + } + } + + /** @see AudioManager#setBluetoothVariableLatencyEnabled(boolean) */ + @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public void setBluetoothVariableLatencyEnabled(boolean enabled) { + super.setBluetoothVariableLatencyEnabled_enforcePermission(); + try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { + AudioSystem.setBluetoothVariableLatencyEnabled(enabled); + } + } + + /** @see AudioManager#isBluetoothVariableLatencyEnabled(boolean) */ + @android.annotation.EnforcePermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING) + public boolean isBluetoothVariableLatencyEnabled() { + super.isBluetoothVariableLatencyEnabled_enforcePermission(); + try (SafeCloseable ignored = ClearCallingIdentityContext.create()) { + return AudioSystem.isBluetoothVariableLatencyEnabled(); + } + } + private final Object mExtVolumeControllerLock = new Object(); private IAudioPolicyCallback mExtVolumeController; private void setExtVolumeController(IAudioPolicyCallback apc) {