From 822173d9b5d516ed95afa0e0a97e977799fc5b7d Mon Sep 17 00:00:00 2001 From: nift4 Date: Sat, 20 Sep 2025 21:14:04 +0200 Subject: [PATCH] supply audio routing information to AudioSink.Listener --- .../media3/exoplayer/audio/AudioSink.java | 8 ++ .../exoplayer/audio/DefaultAudioSink.java | 84 +++++++++++++++---- 2 files changed, 76 insertions(+), 16 deletions(-) diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java index 74ec252ea06..04df2954784 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/AudioSink.java @@ -165,6 +165,14 @@ default void onSilenceSkipped() {} * @param audioSessionId The new audio session ID. */ default void onAudioSessionIdChanged(int audioSessionId) {} + + /** + * Called when the currently routed device changes. + * + * @param router The audio track whose routed device changed. + * @param routedDevice The new routed device. + */ + default void onRoutingChanged(AudioTrack router, @Nullable AudioDeviceInfo routedDevice) {} } /** Configuration parameters used for an {@link AudioTrack}. */ diff --git a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java index b1af65e9bb6..18167f2a0ac 100644 --- a/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java +++ b/libraries/exoplayer/src/main/java/androidx/media3/exoplayer/audio/DefaultAudioSink.java @@ -79,6 +79,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayDeque; +import java.util.Objects; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; @@ -578,7 +579,7 @@ public DefaultAudioSink build() { @Nullable private AudioTrack audioTrack; private @MonotonicNonNull AudioCapabilities audioCapabilities; private @MonotonicNonNull AudioCapabilitiesReceiver audioCapabilitiesReceiver; - @Nullable private OnRoutingChangedListenerApi24 onRoutingChangedListener; + @Nullable private OnRoutingChangedListenerBase onRoutingChangedListener; private AudioAttributes audioAttributes; @Nullable private MediaPositionParameters afterDrainParameters; @@ -909,13 +910,12 @@ private boolean initializeAudioTrack() throws InitializationException { } if (preferredDevice != null) { audioTrack.setPreferredDevice(preferredDevice); - if (audioCapabilitiesReceiver != null) { - audioCapabilitiesReceiver.setRoutedDevice(preferredDevice); - } + onRoutingChanged(audioTrack, preferredDevice); } - if (SDK_INT >= 24 && audioCapabilitiesReceiver != null) { - onRoutingChangedListener = - new OnRoutingChangedListenerApi24(audioTrack, audioCapabilitiesReceiver); + if (SDK_INT >= 24) { + onRoutingChangedListener = new OnRoutingChangedListenerApi24(audioTrack); + } else { + onRoutingChangedListener = new OnRoutingChangedListenerApi23(audioTrack); } startMediaTimeUsNeedsInit = true; @@ -1624,7 +1624,7 @@ public void flush() { pendingConfiguration = null; } audioTrackPositionTracker.reset(); - if (SDK_INT >= 24 && onRoutingChangedListener != null) { + if (onRoutingChangedListener != null) { onRoutingChangedListener.release(); onRoutingChangedListener = null; } @@ -2139,24 +2139,76 @@ private static int getDeviceIdFromContext(Context context) { : C.INDEX_UNSET; } - @RequiresApi(24) - private static final class OnRoutingChangedListenerApi24 { + private void onRoutingChanged(AudioTrack audioTrack, AudioDeviceInfo device) { + if (listener != null) { + listener.onRoutingChanged(audioTrack, device); + } + if (audioCapabilitiesReceiver != null) { + audioCapabilitiesReceiver.setRoutedDevice(device); + } + } + + private interface OnRoutingChangedListenerBase { + void release(); + } + private final class OnRoutingChangedListenerApi23 implements OnRoutingChangedListenerBase { + private final AudioTrack audioTrack; + private final Handler playbackThreadHandler; + + @Nullable private AudioTrack.OnRoutingChangedListener listener; + + public OnRoutingChangedListenerApi23(AudioTrack audioTrack) { + this.audioTrack = audioTrack; + this.listener = this::onRoutingChanged; + playbackThreadHandler = new Handler(Objects.requireNonNull(Looper.myLooper())); + audioTrack.addOnRoutingChangedListener(listener, playbackThreadHandler); + } + + @Override + public void release() { + audioTrack.removeOnRoutingChangedListener(checkNotNull(listener)); + listener = null; + } + + private void onRoutingChanged(AudioTrack router) { + if (listener == null) { + // Stale event. + return; + } + BackgroundExecutor.get() + .execute( + () -> { + @Nullable AudioDeviceInfo routedDevice = router.getRoutedDevice(); + if (routedDevice != null) { + playbackThreadHandler.post( + () -> { + if (listener == null) { + // Stale event. + return; + } + DefaultAudioSink.this.onRoutingChanged(audioTrack, routedDevice); + }); + } + }); + } + } + + @RequiresApi(24) + private final class OnRoutingChangedListenerApi24 implements OnRoutingChangedListenerBase { private final AudioTrack audioTrack; - private final AudioCapabilitiesReceiver capabilitiesReceiver; private final Handler playbackThreadHandler; @Nullable private OnRoutingChangedListener listener; - public OnRoutingChangedListenerApi24( - AudioTrack audioTrack, AudioCapabilitiesReceiver capabilitiesReceiver) { + public OnRoutingChangedListenerApi24(AudioTrack audioTrack) { this.audioTrack = audioTrack; - this.capabilitiesReceiver = capabilitiesReceiver; this.listener = this::onRoutingChanged; - playbackThreadHandler = new Handler(Looper.myLooper()); + playbackThreadHandler = new Handler(Objects.requireNonNull(Looper.myLooper())); audioTrack.addOnRoutingChangedListener(listener, playbackThreadHandler); } + @Override public void release() { audioTrack.removeOnRoutingChangedListener(checkNotNull(listener)); listener = null; @@ -2178,7 +2230,7 @@ private void onRoutingChanged(AudioRouting router) { // Stale event. return; } - capabilitiesReceiver.setRoutedDevice(routedDevice); + DefaultAudioSink.this.onRoutingChanged(audioTrack, routedDevice); }); } });