diff --git a/RELEASENOTES.md b/RELEASENOTES.md index c70da55360..e814645c9e 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -154,6 +154,8 @@ This release includes the following changes since the * Audio: * Allow renderer recovery by disabling offload if audio track fails to initialize in offload mode. + * For offloaded playback, use the `AudioTrack.StreamEventCallback` method + `onPresentationEnded` to identify when all pending data has been played. * Video: * Add workaround for a device issue on Galaxy Tab S7 FE, Chromecast with Google TV, and Lenovo M10 FHD Plus that causes 60fps H265 streams to be 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 e2238fca0b..ad572d92c4 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 @@ -543,6 +543,7 @@ public final class DefaultAudioSink implements AudioSink { private int preV21OutputBufferOffset; private boolean handledEndOfStream; private boolean stoppedAudioTrack; + private boolean handledOffloadOnPresentationEnded; private boolean playing; private boolean externalAudioSessionIdProvided; @@ -1298,6 +1299,9 @@ public final class DefaultAudioSink implements AudioSink { @Override public boolean hasPendingData() { return isAudioTrackInitialized() + && (Util.SDK_INT < 29 + || !audioTrack.isOffloadedPlayback() + || !handledOffloadOnPresentationEnded) && audioTrackPositionTracker.hasPendingData(getWrittenFrames()); } @@ -1553,6 +1557,7 @@ public final class DefaultAudioSink implements AudioSink { outputBuffer = null; stoppedAudioTrack = false; handledEndOfStream = false; + handledOffloadOnPresentationEnded = false; avSyncHeader = null; bytesUntilNextAvSync = 0; trimmingAudioProcessor.resetTrimmedFrameCount(); @@ -1966,6 +1971,15 @@ public final class DefaultAudioSink implements AudioSink { } } + @Override + public void onPresentationEnded(AudioTrack track) { + if (!track.equals(audioTrack)) { + // Stale event. + return; + } + handledOffloadOnPresentationEnded = true; + } + @Override public void onTearDown(AudioTrack track) { if (!track.equals(audioTrack)) {