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 85d380309b..a91e22b124 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 @@ -334,6 +334,7 @@ public class SimpleExoPlayer extends BasePlayer private int audioSessionId; private AudioAttributes audioAttributes; private float audioVolume; + private boolean skipSilenceEnabled; private List currentCues; @Nullable private VideoFrameMetadataListener videoFrameMetadataListener; @Nullable private CameraMotionListener cameraMotionListener; @@ -929,6 +930,11 @@ public class SimpleExoPlayer extends BasePlayer } } + /** Returns whether skipping silences in the audio stream is enabled. */ + public boolean isSkipSilenceEnabled() { + return skipSilenceEnabled; + } + /** * Sets a listener to receive video events, removing all existing listeners. * @@ -1347,6 +1353,7 @@ public class SimpleExoPlayer extends BasePlayer @Override public void setPlaybackParameters(@Nullable PlaybackParameters playbackParameters) { verifyApplicationThread(); + setSkipSilenceEnabled(playbackParameters != null && playbackParameters.skipSilence); player.setPlaybackParameters(playbackParameters); } @@ -1659,6 +1666,24 @@ public class SimpleExoPlayer extends BasePlayer : PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST; } + @SuppressWarnings("SuspiciousMethodCalls") + private void setSkipSilenceEnabled(boolean skipSilenceEnabled) { + if (this.skipSilenceEnabled == skipSilenceEnabled) { + return; + } + this.skipSilenceEnabled = skipSilenceEnabled; + for (AudioListener listener : audioListeners) { + // Prevent duplicate notification if a listener is both a AudioRendererEventListener and + // a AudioListener, as they have the same method signature. + if (!audioDebugListeners.contains(listener)) { + listener.onSkipSilenceEnabledChanged(skipSilenceEnabled); + } + } + for (AudioRendererEventListener listener : audioDebugListeners) { + listener.onSkipSilenceEnabledChanged(skipSilenceEnabled); + } + } + private final class ComponentListener implements VideoRendererEventListener, AudioRendererEventListener, @@ -1814,6 +1839,11 @@ public class SimpleExoPlayer extends BasePlayer audioSessionId = C.AUDIO_SESSION_ID_UNSET; } + @Override + public void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) { + setSkipSilenceEnabled(skipSilenceEnabled); + } + // TextOutput implementation @Override 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 90b35ad459..71a369e3ca 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 @@ -220,6 +220,14 @@ public class AnalyticsCollector } } + @Override + public void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) { + EventTime eventTime = generateReadingMediaPeriodEventTime(); + for (AnalyticsListener listener : listeners) { + listener.onSkipSilenceEnabledChanged(eventTime, skipSilenceEnabled); + } + } + @Override public void onVolumeChanged(float audioVolume) { EventTime eventTime = generateReadingMediaPeriodEventTime(); 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 a6173787f1..fbaa6a9781 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 @@ -450,6 +450,14 @@ public interface AnalyticsListener { default void onAudioUnderrun( EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {} + /** + * Called when skipping silences is enabled or disabled in the audio stream. + * + * @param eventTime The event time. + * @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled. + */ + default void onSkipSilenceEnabledChanged(EventTime eventTime, boolean skipSilenceEnabled) {} + /** * Called after video frames have been dropped. * diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioListener.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioListener.java index 8ce365b283..f208f602e1 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/AudioListener.java @@ -38,4 +38,11 @@ public interface AudioListener { * @param volume The new volume, with 0 being silence and 1 being unity gain. */ default void onVolumeChanged(float volume) {} + + /** + * Called when skipping silences is enabled or disabled in the audio stream. + * + * @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled. + */ + default void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) {} } 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 bf5822caf6..7cb05cfa0d 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 @@ -85,8 +85,13 @@ public interface AudioRendererEventListener { default void onAudioDisabled(DecoderCounters counters) {} /** - * Dispatches events to a {@link AudioRendererEventListener}. + * Called when skipping silences is enabled or disabled in the audio stream. + * + * @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled. */ + default void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) {} + + /** Dispatches events to a {@link AudioRendererEventListener}. */ final class EventDispatcher { @Nullable private final Handler handler; @@ -170,5 +175,12 @@ public interface AudioRendererEventListener { handler.post(() -> castNonNull(listener).onAudioSessionId(audioSessionId)); } } + + /** Invokes {@link AudioRendererEventListener#onSkipSilenceEnabledChanged(boolean)}. */ + public void skipSilenceEnabledChanged(final 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 c03ad0f4af..477b1fd1c1 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 @@ -84,6 +84,12 @@ public interface AudioSink { */ void onUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs); + /** + * Called when skipping silences is enabled or disabled. + * + * @param skipSilenceEnabled Whether skipping silences is enabled. + */ + void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled); } /** 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 d4b2b9b874..3482cbe9b6 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 @@ -884,9 +884,6 @@ public final class DefaultAudioSink implements AudioSink { @Override public void setPlaybackSpeed(float playbackSpeed) { - if (configuration != null && !configuration.canApplyPlaybackParameters) { - playbackSpeed = DEFAULT_PLAYBACK_SPEED; - } setPlaybackSpeedAndSkipSilence(playbackSpeed, getSkipSilenceEnabled()); } @@ -897,9 +894,6 @@ public final class DefaultAudioSink implements AudioSink { @Override public void setSkipSilenceEnabled(boolean skipSilenceEnabled) { - if (configuration != null && !configuration.canApplyPlaybackParameters) { - skipSilenceEnabled = DEFAULT_SKIP_SILENCE; - } setPlaybackSpeedAndSkipSilence(getPlaybackSpeed(), skipSilenceEnabled); } @@ -1080,10 +1074,6 @@ public final class DefaultAudioSink implements AudioSink { } private void setPlaybackSpeedAndSkipSilence(float playbackSpeed, boolean skipSilence) { - if (configuration != null && !configuration.canApplyPlaybackParameters) { - playbackSpeed = DEFAULT_PLAYBACK_SPEED; - skipSilence = DEFAULT_SKIP_SILENCE; - } MediaPositionParameters currentMediaPositionParameters = getMediaPositionParameters(); if (playbackSpeed != currentMediaPositionParameters.playbackSpeed || skipSilence != currentMediaPositionParameters.skipSilence) { @@ -1119,17 +1109,20 @@ public final class DefaultAudioSink implements AudioSink { configuration.canApplyPlaybackParameters ? audioProcessorChain.applyPlaybackSpeed(getPlaybackSpeed()) : DEFAULT_PLAYBACK_SPEED; - boolean skipSilence = + boolean skipSilenceEnabled = configuration.canApplyPlaybackParameters ? audioProcessorChain.applySkipSilenceEnabled(getSkipSilenceEnabled()) : DEFAULT_SKIP_SILENCE; mediaPositionParametersCheckpoints.add( new MediaPositionParameters( playbackSpeed, - skipSilence, + skipSilenceEnabled, /* mediaTimeUs= */ Math.max(0, presentationTimeUs), /* audioTrackPositionUs= */ configuration.framesToDurationUs(getWrittenFrames()))); setupAudioProcessors(); + if (listener != null) { + listener.onSkipSilenceEnabledChanged(skipSilenceEnabled); + } } /** 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 8c496e4ffd..0448c60a5f 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 @@ -469,24 +469,25 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media * order to spatialize the audio channels. For this use case, any {@link Virtualizer} instances * should be released in {@link #onDisabled()} (if not before). * - * @see AudioSink.Listener#onAudioSessionId(int) + *

See {@link AudioSink.Listener#onAudioSessionId(int)}. */ protected void onAudioSessionId(int audioSessionId) { // Do nothing. } - /** - * @see AudioSink.Listener#onPositionDiscontinuity() - */ + /** See {@link AudioSink.Listener#onPositionDiscontinuity()}. */ protected void onAudioTrackPositionDiscontinuity() { // Do nothing. } - /** - * @see AudioSink.Listener#onUnderrun(int, long, long) - */ - protected void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, - long elapsedSinceLastFeedMs) { + /** See {@link AudioSink.Listener#onUnderrun(int, long, long)}. */ + protected void onAudioTrackUnderrun( + int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { + // Do nothing. + } + + /** See {@link AudioSink.Listener#onSkipSilenceEnabledChanged(boolean)}. */ + protected void onAudioTrackSkipSilenceEnabledChanged(boolean skipSilenceEnabled) { // Do nothing. } @@ -843,6 +844,10 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media onAudioTrackUnderrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs); } + @Override + public void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) { + eventDispatcher.skipSilenceEnabledChanged(skipSilenceEnabled); + onAudioTrackSkipSilenceEnabledChanged(skipSilenceEnabled); + } } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java index 7da3ac9c6e..ee812138fe 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/audio/SimpleDecoderAudioRenderer.java @@ -270,24 +270,25 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements * order to spatialize the audio channels. For this use case, any {@link Virtualizer} instances * should be released in {@link #onDisabled()} (if not before). * - * @see AudioSink.Listener#onAudioSessionId(int) + *

See {@link AudioSink.Listener#onAudioSessionId(int)}. */ protected void onAudioSessionId(int audioSessionId) { // Do nothing. } - /** - * @see AudioSink.Listener#onPositionDiscontinuity() - */ + /** See {@link AudioSink.Listener#onPositionDiscontinuity()}. */ protected void onAudioTrackPositionDiscontinuity() { // Do nothing. } - /** - * @see AudioSink.Listener#onUnderrun(int, long, long) - */ - protected void onAudioTrackUnderrun(int bufferSize, long bufferSizeMs, - long elapsedSinceLastFeedMs) { + /** See {@link AudioSink.Listener#onUnderrun(int, long, long)}. */ + protected void onAudioTrackUnderrun( + int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) { + // Do nothing. + } + + /** See {@link AudioSink.Listener#onSkipSilenceEnabledChanged(boolean)}. */ + protected void onAudioTrackSkipSilenceEnabledChanged(boolean skipSilenceEnabled) { // Do nothing. } @@ -693,6 +694,10 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements onAudioTrackUnderrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs); } + @Override + public void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) { + eventDispatcher.skipSilenceEnabledChanged(skipSilenceEnabled); + onAudioTrackSkipSilenceEnabledChanged(skipSilenceEnabled); + } } - } 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 99dde4fabf..b2e15d69e4 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 @@ -319,6 +319,11 @@ public class EventLogger implements AnalyticsListener { + audioAttributes.allowedCapturePolicy); } + @Override + public void onSkipSilenceEnabledChanged(EventTime eventTime, boolean skipSilenceEnabled) { + logd(eventTime, "skipSilenceEnabled", Boolean.toString(skipSilenceEnabled)); + } + @Override public void onVolumeChanged(EventTime eventTime, float volume) { logd(eventTime, "volume", Float.toString(volume));