From f191000e206fed1d7fef98ca4cf052e6e0772268 Mon Sep 17 00:00:00 2001 From: tonihei Date: Wed, 17 Feb 2021 10:24:26 +0000 Subject: [PATCH] Report unexpected discontinuity as non-fatal audio sink error. This is preferable to just logging to LogCat so that listeners can report this to analytics systems if required. Issue: #6384 PiperOrigin-RevId: 357906079 --- RELEASENOTES.md | 3 +++ .../analytics/AnalyticsListener.java | 5 ++-- .../audio/AudioRendererEventListener.java | 3 ++- .../android/exoplayer2/audio/AudioSink.java | 25 +++++++++++++++++-- .../exoplayer2/audio/DefaultAudioSink.java | 10 +++----- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 41052a0063..7d1191199c 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -9,6 +9,9 @@ * Audio: * Fix `SimpleExoPlayer` reporting audio session ID as 0 in some cases ([#8585](https://github.com/google/ExoPlayer/issues/8585)). + * Report unexpected discontinuities in + `AnalyticsListener.onAudioSinkError` + ([#6384](https://github.com/google/ExoPlayer/issues/6384)). * Analytics: * Add `onAudioCodecError` and `onVideoCodecError` to `AnalyticsListener`. * Library restructuring: diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java index bf0c8b5d22..a68e2f7fa2 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsListener.java @@ -854,8 +854,9 @@ public interface AnalyticsListener { * wishes to do so. * * @param eventTime The event time. - * @param audioSinkError Either a {@link AudioSink.InitializationException} or a {@link - * AudioSink.WriteException} describing the error. + * @param audioSinkError The error that occurred. Typically an {@link + * AudioSink.InitializationException}, a {@link AudioSink.WriteException}, or an {@link + * AudioSink.UnexpectedDiscontinuityException}. */ default void onAudioSinkError(EventTime eventTime, Exception audioSinkError) {} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java index cfd476a421..69803ceef6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioRendererEventListener.java @@ -144,7 +144,8 @@ public interface AudioRendererEventListener { * wishes to do so. * * @param audioSinkError The error that occurred. Typically an {@link - * AudioSink.InitializationException} or a {@link AudioSink.WriteException}. + * AudioSink.InitializationException}, a {@link AudioSink.WriteException}, or an {@link + * AudioSink.UnexpectedDiscontinuityException}. */ default void onAudioSinkError(Exception audioSinkError) {} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java index 463461916f..e761924586 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioSink.java @@ -126,8 +126,8 @@ public interface AudioSink { *

Fatal errors that cannot be recovered will be reported wrapped in a {@link * ExoPlaybackException} by {@link Player.EventListener#onPlayerError(ExoPlaybackException)}. * - * @param audioSinkError Either an {@link AudioSink.InitializationException} or a {@link - * AudioSink.WriteException} describing the error. + * @param audioSinkError The error that occurred. Typically an {@link InitializationException}, + * a {@link WriteException}, or an {@link UnexpectedDiscontinuityException}. */ default void onAudioSinkError(Exception audioSinkError) {} } @@ -226,6 +226,27 @@ public interface AudioSink { } + /** Thrown when the sink encounters an unexpected timestamp discontinuity. */ + final class UnexpectedDiscontinuityException extends Exception { + /** The actual presentation time of a sample, in microseconds. */ + public final long actualPresentationTimeUs; + /** The expected presentation time of a sample, in microseconds. */ + public final long expectedPresentationTimeUs; + + /** + * Creates an instance. + * + * @param actualPresentationTimeUs The actual presentation time of a sample, in microseconds. + * @param expectedPresentationTimeUs The expected presentation time of a sample, in + * microseconds. + */ + public UnexpectedDiscontinuityException( + long actualPresentationTimeUs, long expectedPresentationTimeUs) { + this.actualPresentationTimeUs = actualPresentationTimeUs; + this.expectedPresentationTimeUs = expectedPresentationTimeUs; + } + } + /** * The level of support the sink provides for a format. One of {@link * #SINK_FORMAT_SUPPORTED_DIRECTLY}, {@link #SINK_FORMAT_SUPPORTED_WITH_TRANSCODING} or {@link 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 826839b3d2..919870c24e 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 @@ -762,13 +762,9 @@ public final class DefaultAudioSink implements AudioSink { getSubmittedFrames() - trimmingAudioProcessor.getTrimmedFrameCount()); if (!startMediaTimeUsNeedsSync && Math.abs(expectedPresentationTimeUs - presentationTimeUs) > 200000) { - Log.e( - TAG, - "Discontinuity detected [expected " - + expectedPresentationTimeUs - + ", got " - + presentationTimeUs - + "]"); + listener.onAudioSinkError( + new AudioSink.UnexpectedDiscontinuityException( + presentationTimeUs, expectedPresentationTimeUs)); startMediaTimeUsNeedsSync = true; } if (startMediaTimeUsNeedsSync) {