From 4b0e39e4b9dd8cdf7c90cc6e2054ca727538b96c Mon Sep 17 00:00:00 2001 From: andrewlewis Date: Fri, 21 Aug 2020 16:01:07 +0100 Subject: [PATCH] Add an event for the audio position advancing Currently the audio renderer can become ready before the AudioTrack actually has enough data to play something, which means that the player may transition to the ready state before audio starts playing. This makes the player's current state transition not very useful for detecting when audio actually starts playing. This change adds a new event to notify apps when the audio position is increasing after a pause or seek/flush/reset event, and includes an estimate of the system time at which audio playout started. Issue: #7577 PiperOrigin-RevId: 327810040 --- RELEASENOTES.md | 3 + .../android/exoplayer2/SimpleExoPlayer.java | 7 +++ .../analytics/AnalyticsCollector.java | 8 +++ .../analytics/AnalyticsListener.java | 10 ++++ .../audio/AudioRendererEventListener.java | 56 ++++++++++--------- .../android/exoplayer2/audio/AudioSink.java | 13 ++++- .../audio/AudioTrackPositionTracker.java | 23 ++++++++ .../audio/DecoderAudioRenderer.java | 5 ++ .../exoplayer2/audio/DefaultAudioSink.java | 7 +++ .../audio/MediaCodecAudioRenderer.java | 5 ++ .../android/exoplayer2/util/EventLogger.java | 6 ++ .../analytics/AnalyticsCollectorTest.java | 45 ++++++++++----- .../testutil/FakeAudioRenderer.java | 6 ++ 13 files changed, 152 insertions(+), 42 deletions(-) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 60913dc485..f517a255ec 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -2,6 +2,9 @@ ### dev-v2 (not yet released) +* Audio: Add an event for the audio position starting to advance, to make it + easier for apps to determine when audio playout started + ([#7577](https://github.com/google/ExoPlayer/issues/7577)). ### 2.12.0 (not yet released - targeted for 2020-08-TBD) ### diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 00c1e0bcc5..d927161d16 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -2231,6 +2231,13 @@ public class SimpleExoPlayer extends BasePlayer } } + @Override + public void onAudioPositionAdvancing(long playoutStartSystemTimeMs) { + for (AudioRendererEventListener audioDebugListener : audioDebugListeners) { + audioDebugListener.onAudioPositionAdvancing(playoutStartSystemTimeMs); + } + } + @Override public void onAudioUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { for (AudioRendererEventListener audioDebugListener : audioDebugListeners) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index 7c170742d7..0193c94deb 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -205,6 +205,14 @@ public class AnalyticsCollector } } + @Override + public final void onAudioPositionAdvancing(long playoutStartSystemTimeMs) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + for (AnalyticsListener listener : listeners) { + listener.onAudioPositionAdvancing(eventTime, playoutStartSystemTimeMs); + } + } + @Override public final void onAudioUnderrun( int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { 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 f01d11ec25..d80ef5f70a 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 @@ -479,6 +479,16 @@ public interface AnalyticsListener { */ default void onAudioInputFormatChanged(EventTime eventTime, Format format) {} + /** + * Called when the audio position has increased for the first time since the last pause or + * position reset. + * + * @param eventTime The event time. + * @param playoutStartSystemTimeMs The approximate derived {@link System#currentTimeMillis()} at + * which playout started. + */ + default void onAudioPositionAdvancing(EventTime eventTime, long playoutStartSystemTimeMs) {} + /** * Called when an audio underrun occurs. * 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 c366f27f81..f921141f24 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 @@ -65,6 +65,15 @@ public interface AudioRendererEventListener { */ default void onAudioInputFormatChanged(Format format) {} + /** + * Called when the audio position has increased for the first time since the last pause or + * position reset. + * + * @param playoutStartSystemTimeMs The approximate derived {@link System#currentTimeMillis()} at + * which playout started. + */ + default void onAudioPositionAdvancing(long playoutStartSystemTimeMs) {} + /** * Called when an audio underrun occurs. * @@ -89,7 +98,7 @@ public interface AudioRendererEventListener { */ default void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) {} - /** Dispatches events to a {@link AudioRendererEventListener}. */ + /** Dispatches events to an {@link AudioRendererEventListener}. */ final class EventDispatcher { @Nullable private final Handler handler; @@ -106,20 +115,16 @@ public interface AudioRendererEventListener { this.listener = listener; } - /** - * Invokes {@link AudioRendererEventListener#onAudioEnabled(DecoderCounters)}. - */ - public void enabled(final DecoderCounters decoderCounters) { + /** Invokes {@link AudioRendererEventListener#onAudioEnabled(DecoderCounters)}. */ + public void enabled(DecoderCounters decoderCounters) { if (handler != null) { handler.post(() -> castNonNull(listener).onAudioEnabled(decoderCounters)); } } - /** - * Invokes {@link AudioRendererEventListener#onAudioDecoderInitialized(String, long, long)}. - */ - public void decoderInitialized(final String decoderName, - final long initializedTimestampMs, final long initializationDurationMs) { + /** Invokes {@link AudioRendererEventListener#onAudioDecoderInitialized(String, long, long)}. */ + public void decoderInitialized( + String decoderName, long initializedTimestampMs, long initializationDurationMs) { if (handler != null) { handler.post( () -> @@ -129,18 +134,23 @@ public interface AudioRendererEventListener { } } - /** - * Invokes {@link AudioRendererEventListener#onAudioInputFormatChanged(Format)}. - */ - public void inputFormatChanged(final Format format) { + /** Invokes {@link AudioRendererEventListener#onAudioInputFormatChanged(Format)}. */ + public void inputFormatChanged(Format format) { if (handler != null) { handler.post(() -> castNonNull(listener).onAudioInputFormatChanged(format)); } } + /** Invokes {@link AudioRendererEventListener#onAudioPositionAdvancing(long)}. */ + public void positionAdvancing(long playoutStartSystemTimeMs) { + if (handler != null) { + handler.post( + () -> castNonNull(listener).onAudioPositionAdvancing(playoutStartSystemTimeMs)); + } + } + /** Invokes {@link AudioRendererEventListener#onAudioUnderrun(int, long, long)}. */ - public void underrun( - final int bufferSize, final long bufferSizeMs, final long elapsedSinceLastFeedMs) { + public void underrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { if (handler != null) { handler.post( () -> @@ -149,10 +159,8 @@ public interface AudioRendererEventListener { } } - /** - * Invokes {@link AudioRendererEventListener#onAudioDisabled(DecoderCounters)}. - */ - public void disabled(final DecoderCounters counters) { + /** Invokes {@link AudioRendererEventListener#onAudioDisabled(DecoderCounters)}. */ + public void disabled(DecoderCounters counters) { counters.ensureUpdated(); if (handler != null) { handler.post( @@ -163,17 +171,15 @@ public interface AudioRendererEventListener { } } - /** - * Invokes {@link AudioRendererEventListener#onAudioSessionId(int)}. - */ - public void audioSessionId(final int audioSessionId) { + /** Invokes {@link AudioRendererEventListener#onAudioSessionId(int)}. */ + public void audioSessionId(int audioSessionId) { if (handler != null) { handler.post(() -> castNonNull(listener).onAudioSessionId(audioSessionId)); } } /** Invokes {@link AudioRendererEventListener#onSkipSilenceEnabledChanged(boolean)}. */ - public void skipSilenceEnabledChanged(final boolean skipSilenceEnabled) { + public void skipSilenceEnabledChanged(boolean skipSilenceEnabled) { if (handler != null) { handler.post(() -> castNonNull(listener).onSkipSilenceEnabledChanged(skipSilenceEnabled)); } 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 b0f76c0afb..21683bda48 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 @@ -72,10 +72,19 @@ public interface AudioSink { */ void onPositionDiscontinuity(); + /** + * Called when the audio sink's position has increased for the first time since it was last + * paused or flushed. + * + * @param playoutStartSystemTimeMs The approximate derived {@link System#currentTimeMillis()} at + * which playout started. Only valid if the audio track has not underrun. + */ + default void onPositionAdvancing(long playoutStartSystemTimeMs) {} + /** * Called when the audio sink runs out of data. - *

- * An audio sink implementation may never call this method (for example, if audio data is + * + *

An audio sink implementation may never call this method (for example, if audio data is * consumed in batches rather than based on the sink's own clock). * * @param bufferSize The size of the sink's buffer, in bytes. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java index c1d8df5c75..540ee098ee 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioTrackPositionTracker.java @@ -48,6 +48,15 @@ import java.lang.reflect.Method; /** Listener for position tracker events. */ public interface Listener { + /** + * Called when the position tracker's position has increased for the first time since it was + * last paused or reset. + * + * @param playoutStartSystemTimeMs The approximate derived {@link System#currentTimeMillis()} at + * which playout started. + */ + void onPositionAdvancing(long playoutStartSystemTimeMs); + /** * Called when the frame position is too far from the expected frame position. * @@ -145,6 +154,7 @@ import java.lang.reflect.Method; private boolean needsPassthroughWorkarounds; private long bufferSizeUs; private float audioTrackPlaybackSpeed; + private boolean notifiedPositionIncreasing; private long smoothedPlayheadOffsetUs; private long lastPlayheadSampleTimeUs; @@ -287,9 +297,21 @@ import java.lang.reflect.Method; positionUs /= 1000; } + if (!notifiedPositionIncreasing && positionUs > lastPositionUs) { + notifiedPositionIncreasing = true; + long mediaDurationSinceLastPositionUs = C.usToMs(positionUs - lastPositionUs); + long playoutDurationSinceLastPositionUs = + Util.getPlayoutDurationForMediaDuration( + mediaDurationSinceLastPositionUs, audioTrackPlaybackSpeed); + long playoutStartSystemTimeMs = + System.currentTimeMillis() - C.usToMs(playoutDurationSinceLastPositionUs); + listener.onPositionAdvancing(playoutStartSystemTimeMs); + } + lastSystemTimeUs = systemTimeUs; lastPositionUs = positionUs; lastSampleUsedGetTimestampMode = useGetTimestampMode; + return positionUs; } @@ -512,6 +534,7 @@ import java.lang.reflect.Method; lastPlayheadSampleTimeUs = 0; lastSystemTimeUs = 0; previousModeSystemTimeUs = 0; + notifiedPositionIncreasing = false; } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java index bc8237c911..84a4e36d07 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/DecoderAudioRenderer.java @@ -708,6 +708,11 @@ public abstract class DecoderAudioRenderer< DecoderAudioRenderer.this.onPositionDiscontinuity(); } + @Override + public void onPositionAdvancing(long playoutStartSystemTimeMs) { + eventDispatcher.positionAdvancing(playoutStartSystemTimeMs); + } + @Override public void onUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { eventDispatcher.underrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs); 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 2da648b303..7075fce5d0 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 @@ -1776,6 +1776,13 @@ public final class DefaultAudioSink implements AudioSink { Log.w(TAG, "Ignoring impossibly large audio latency: " + latencyUs); } + @Override + public void onPositionAdvancing(long playoutStartSystemTimeMs) { + if (listener != null) { + listener.onPositionAdvancing(playoutStartSystemTimeMs); + } + } + @Override public void onUnderrun(int bufferSize, long bufferSizeMs) { if (listener != null) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java index 91c0f946ce..dfcc41d670 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/MediaCodecAudioRenderer.java @@ -828,6 +828,11 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media MediaCodecAudioRenderer.this.onPositionDiscontinuity(); } + @Override + public void onPositionAdvancing(long playoutStartSystemTimeMs) { + eventDispatcher.positionAdvancing(playoutStartSystemTimeMs); + } + @Override public void onUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { eventDispatcher.underrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java index 9c55248fea..4d1ebe0111 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java @@ -316,6 +316,12 @@ public class EventLogger implements AnalyticsListener { logd(eventTime, "audioInputFormat", Format.toLogString(format)); } + @Override + public void onAudioPositionAdvancing(EventTime eventTime, long playoutStartSystemTimeMs) { + long timeSincePlayoutStartMs = System.currentTimeMillis() - playoutStartSystemTimeMs; + logd(eventTime, "audioPositionAdvancing", "timeSincePlayoutStartMs=" + timeSincePlayoutStartMs); + } + @Override public void onAudioUnderrun( EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { diff --git a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java index 7d3dfdf103..5e483c9a22 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/analytics/AnalyticsCollectorTest.java @@ -106,21 +106,22 @@ public final class AnalyticsCollectorTest { private static final int EVENT_AUDIO_INPUT_FORMAT_CHANGED = 26; private static final int EVENT_AUDIO_DISABLED = 27; private static final int EVENT_AUDIO_SESSION_ID = 28; - private static final int EVENT_AUDIO_UNDERRUN = 29; - private static final int EVENT_VIDEO_ENABLED = 30; - private static final int EVENT_VIDEO_DECODER_INIT = 31; - private static final int EVENT_VIDEO_INPUT_FORMAT_CHANGED = 32; - private static final int EVENT_DROPPED_FRAMES = 33; - private static final int EVENT_VIDEO_DISABLED = 34; - private static final int EVENT_RENDERED_FIRST_FRAME = 35; - private static final int EVENT_VIDEO_FRAME_PROCESSING_OFFSET = 36; - private static final int EVENT_VIDEO_SIZE_CHANGED = 37; - private static final int EVENT_DRM_KEYS_LOADED = 38; - private static final int EVENT_DRM_ERROR = 39; - private static final int EVENT_DRM_KEYS_RESTORED = 40; - private static final int EVENT_DRM_KEYS_REMOVED = 41; - private static final int EVENT_DRM_SESSION_ACQUIRED = 42; - private static final int EVENT_DRM_SESSION_RELEASED = 43; + private static final int EVENT_AUDIO_POSITION_ADVANCING_ID = 29; + private static final int EVENT_AUDIO_UNDERRUN = 30; + private static final int EVENT_VIDEO_ENABLED = 31; + private static final int EVENT_VIDEO_DECODER_INIT = 32; + private static final int EVENT_VIDEO_INPUT_FORMAT_CHANGED = 33; + private static final int EVENT_DROPPED_FRAMES = 34; + private static final int EVENT_VIDEO_DISABLED = 35; + private static final int EVENT_RENDERED_FIRST_FRAME = 36; + private static final int EVENT_VIDEO_FRAME_PROCESSING_OFFSET = 37; + private static final int EVENT_VIDEO_SIZE_CHANGED = 38; + private static final int EVENT_DRM_KEYS_LOADED = 39; + private static final int EVENT_DRM_ERROR = 40; + private static final int EVENT_DRM_KEYS_RESTORED = 41; + private static final int EVENT_DRM_KEYS_REMOVED = 42; + private static final int EVENT_DRM_SESSION_ACQUIRED = 43; + private static final int EVENT_DRM_SESSION_RELEASED = 44; private static final UUID DRM_SCHEME_UUID = UUID.nameUUIDFromBytes(TestUtil.createByteArray(7, 8, 9)); @@ -226,6 +227,7 @@ public final class AnalyticsCollectorTest { assertThat(listener.getEvents(EVENT_AUDIO_DECODER_INIT)).containsExactly(period0); assertThat(listener.getEvents(EVENT_AUDIO_INPUT_FORMAT_CHANGED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period0); + assertThat(listener.getEvents(EVENT_AUDIO_POSITION_ADVANCING_ID)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_ENABLED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_DECODER_INIT)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_INPUT_FORMAT_CHANGED)).containsExactly(period0); @@ -305,6 +307,7 @@ public final class AnalyticsCollectorTest { .containsExactly(period0, period1) .inOrder(); assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period0); + assertThat(listener.getEvents(EVENT_AUDIO_POSITION_ADVANCING_ID)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_ENABLED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_DECODER_INIT)) .containsExactly(period0, period1) @@ -380,6 +383,7 @@ public final class AnalyticsCollectorTest { assertThat(listener.getEvents(EVENT_AUDIO_DECODER_INIT)).containsExactly(period1); assertThat(listener.getEvents(EVENT_AUDIO_INPUT_FORMAT_CHANGED)).containsExactly(period1); assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period1); + assertThat(listener.getEvents(EVENT_AUDIO_POSITION_ADVANCING_ID)).containsExactly(period1); assertThat(listener.getEvents(EVENT_VIDEO_ENABLED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_DECODER_INIT)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_INPUT_FORMAT_CHANGED)).containsExactly(period0); @@ -476,6 +480,9 @@ public final class AnalyticsCollectorTest { assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)) .containsExactly(period0, period1) .inOrder(); + assertThat(listener.getEvents(EVENT_AUDIO_POSITION_ADVANCING_ID)) + .containsExactly(period0, period1) + .inOrder(); assertThat(listener.getEvents(EVENT_AUDIO_DISABLED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_ENABLED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_DECODER_INIT)).containsExactly(period0); @@ -576,6 +583,9 @@ public final class AnalyticsCollectorTest { assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)) .containsExactly(period1Seq1, period1Seq2) .inOrder(); + assertThat(listener.getEvents(EVENT_AUDIO_POSITION_ADVANCING_ID)) + .containsExactly(period1Seq1, period1Seq2) + .inOrder(); assertThat(listener.getEvents(EVENT_AUDIO_DISABLED)).containsExactly(period0); assertThat(listener.getEvents(EVENT_VIDEO_ENABLED)).containsExactly(period0, period0); assertThat(listener.getEvents(EVENT_VIDEO_DECODER_INIT)) @@ -1922,6 +1932,11 @@ public final class AnalyticsCollectorTest { reportedEvents.add(new ReportedEvent(EVENT_AUDIO_SESSION_ID, eventTime)); } + @Override + public void onAudioPositionAdvancing(EventTime eventTime, long playoutStartSystemTimeMs) { + reportedEvents.add(new ReportedEvent(EVENT_AUDIO_POSITION_ADVANCING_ID, eventTime)); + } + @Override public void onAudioUnderrun( EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAudioRenderer.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAudioRenderer.java index 5ed4e5bf5f..1e2f6159a5 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAudioRenderer.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/FakeAudioRenderer.java @@ -30,6 +30,7 @@ public class FakeAudioRenderer extends FakeRenderer { private final AudioRendererEventListener.EventDispatcher eventDispatcher; private final DecoderCounters decoderCounters; private boolean notifiedAudioSessionId; + private boolean notifiedPositionAdvancing; public FakeAudioRenderer(Handler handler, AudioRendererEventListener eventListener) { super(C.TRACK_TYPE_AUDIO); @@ -43,6 +44,7 @@ public class FakeAudioRenderer extends FakeRenderer { super.onEnabled(joining, mayRenderStartOfStream); eventDispatcher.enabled(decoderCounters); notifiedAudioSessionId = false; + notifiedPositionAdvancing = false; } @Override @@ -67,6 +69,10 @@ public class FakeAudioRenderer extends FakeRenderer { eventDispatcher.audioSessionId(/* audioSessionId= */ 1); notifiedAudioSessionId = true; } + if (shouldProcess && !notifiedPositionAdvancing) { + eventDispatcher.positionAdvancing(System.currentTimeMillis()); + notifiedPositionAdvancing = true; + } return shouldProcess; } }