diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 1b2c273cd2..fbc0238a35 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -32,6 +32,9 @@ * Fix the default audio sink position not advancing correctly when using `AudioTrack`-based speed adjustment ([#7982](https://github.com/google/ExoPlayer/issues/7982)). + * Fix `NoClassDefFoundError` warning for `AudioTrack$StreamEventCallback` + even though the class was not used + ([#8058](https://github.com/google/ExoPlayer/issues/8058)). * Extractors: * Add support for .mp2 boxes in the `AtomParsers` ([#7967](https://github.com/google/ExoPlayer/issues/7967)). diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java index 478eb0d04b..2ebd744812 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DefaultAudioSink.java @@ -1696,37 +1696,43 @@ public final class DefaultAudioSink implements AudioSink { } @RequiresApi(29) - private final class StreamEventCallbackV29 extends AudioTrack.StreamEventCallback { + private final class StreamEventCallbackV29 { private final Handler handler; + private final AudioTrack.StreamEventCallback callback; public StreamEventCallbackV29() { handler = new Handler(); - } + // StreamEventCallbackV29 can NOT inherit directly from AudioTrack.StreamEventCallback as it + // would cause a NoClassDefFoundError on the first load of DefaultAudioSink for SDK < 29 + // fatal on some devices. See: https://github.com/google/ExoPlayer/issues/8058 + callback = + new AudioTrack.StreamEventCallback() { + @Override + public void onDataRequest(AudioTrack track, int size) { + Assertions.checkState(track == DefaultAudioSink.this.audioTrack); + if (listener != null) { + listener.onOffloadBufferEmptying(); + } + } - @Override - public void onDataRequest(AudioTrack track, int size) { - Assertions.checkState(track == DefaultAudioSink.this.audioTrack); - if (listener != null) { - listener.onOffloadBufferEmptying(); - } - } - - @Override - public void onTearDown(@NonNull AudioTrack track) { - if (listener != null && playing) { - // A new Audio Track needs to be created and it's buffer filled, which will be done on the - // next handleBuffer call. - // Request this call explicitly in case ExoPlayer is sleeping waiting for a data request. - listener.onOffloadBufferEmptying(); - } + @Override + public void onTearDown(@NonNull AudioTrack track) { + if (listener != null && playing) { + // A new Audio Track needs to be created and it's buffer filled, which will be done + // on the next handleBuffer call. Request this call explicitly in case ExoPlayer is + // sleeping waiting for a data request. + listener.onOffloadBufferEmptying(); + } + } + }; } public void register(AudioTrack audioTrack) { - audioTrack.registerStreamEventCallback(handler::post, this); + audioTrack.registerStreamEventCallback(handler::post, callback); } public void unregister(AudioTrack audioTrack) { - audioTrack.unregisterStreamEventCallback(this); + audioTrack.unregisterStreamEventCallback(callback); handler.removeCallbacksAndMessages(/* token= */ null); } }