Commit c5db69d2 by olly Committed by Oliver Woodman

Fix further issues with decoder re-use

It's no longer guaranteed that onOutputFormatChanged will always be
called when the renderer is re-enabled, since the codec may be kept
and its output format may not change. Hence we need to avoid resetting
state in onDisabled that we need when the renderer is enabled again.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=219821519
parent 251c4207
......@@ -23,29 +23,30 @@ import java.nio.ByteBuffer;
/**
* A sink that consumes audio data.
* <p>
* Before starting playback, specify the input audio format by calling
* {@link #configure(int, int, int, int, int[], int, int)}.
* <p>
* Call {@link #handleBuffer(ByteBuffer, long)} to write data, and {@link #handleDiscontinuity()}
*
* <p>Before starting playback, specify the input audio format by calling {@link #configure(int,
* int, int, int, int[], int, int)}.
*
* <p>Call {@link #handleBuffer(ByteBuffer, long)} to write data, and {@link #handleDiscontinuity()}
* when the data being fed is discontinuous. Call {@link #play()} to start playing the written data.
* <p>
* Call {@link #configure(int, int, int, int, int[], int, int)} whenever the input format changes.
* The sink will be reinitialized on the next call to {@link #handleBuffer(ByteBuffer, long)}.
* <p>
* Call {@link #reset()} to prepare the sink to receive audio data from a new playback position.
* <p>
* Call {@link #playToEndOfStream()} repeatedly to play out all data when no more input buffers will
* be provided via {@link #handleBuffer(ByteBuffer, long)} until the next {@link #reset()}. Call
* {@link #release()} when the instance is no longer required.
* <p>
* The implementation may be backed by a platform {@link AudioTrack}. In this case,
* {@link #setAudioSessionId(int)}, {@link #setAudioAttributes(AudioAttributes)},
* {@link #enableTunnelingV21(int)} and/or {@link #disableTunneling()} may be called before writing
* data to the sink. These methods may also be called after writing data to the sink, in which case
* it will be reinitialized as required. For implementations that are not based on platform
* {@link AudioTrack}s, calling methods relating to audio sessions, audio attributes, and tunneling
* may have no effect.
*
* <p>Call {@link #configure(int, int, int, int, int[], int, int)} whenever the input format
* changes. The sink will be reinitialized on the next call to {@link #handleBuffer(ByteBuffer,
* long)}.
*
* <p>Call {@link #flush()} to prepare the sink to receive audio data from a new playback position.
*
* <p>Call {@link #playToEndOfStream()} repeatedly to play out all data when no more input buffers
* will be provided via {@link #handleBuffer(ByteBuffer, long)} until the next {@link #flush()}.
* Call {@link #reset()} when the instance is no longer required.
*
* <p>The implementation may be backed by a platform {@link AudioTrack}. In this case, {@link
* #setAudioSessionId(int)}, {@link #setAudioAttributes(AudioAttributes)}, {@link
* #enableTunnelingV21(int)} and/or {@link #disableTunneling()} may be called before writing data to
* the sink. These methods may also be called after writing data to the sink, in which case it will
* be reinitialized as required. For implementations that are not based on platform {@link
* AudioTrack}s, calling methods relating to audio sessions, audio attributes, and tunneling may
* have no effect.
*/
public interface AudioSink {
......@@ -197,7 +198,7 @@ public interface AudioSink {
* @param trimStartFrames The number of audio frames to trim from the start of data written to the
* sink after this call.
* @param trimEndFrames The number of audio frames to trim from data written to the sink
* immediately preceding the next call to {@link #reset()} or this method.
* immediately preceding the next call to {@link #flush()} or this method.
* @throws ConfigurationException If an error occurs configuring the sink.
*/
void configure(
......@@ -223,11 +224,11 @@ public interface AudioSink {
* ending at its limit (exclusive). The position of the {@link ByteBuffer} is advanced by the
* number of bytes that were handled. {@link Listener#onPositionDiscontinuity()} will be called if
* {@code presentationTimeUs} is discontinuous with the last buffer handled since the last reset.
* <p>
* Returns whether the data was handled in full. If the data was not handled in full then the same
* {@link ByteBuffer} must be provided to subsequent calls until it has been fully consumed,
* except in the case of an intervening call to {@link #reset()} (or to
* {@link #configure(int, int, int, int, int[], int, int)} that causes the sink to be reset).
*
* <p>Returns whether the data was handled in full. If the data was not handled in full then the
* same {@link ByteBuffer} must be provided to subsequent calls until it has been fully consumed,
* except in the case of an intervening call to {@link #flush()} (or to {@link #configure(int,
* int, int, int, int[], int, int)} that causes the sink to be flushed).
*
* @param buffer The buffer containing audio data.
* @param presentationTimeUs The presentation timestamp of the buffer in microseconds.
......@@ -316,15 +317,12 @@ public interface AudioSink {
void pause();
/**
* Resets the sink, after which it is ready to receive buffers from a new playback position.
* <p>
* The audio session may remain active until {@link #release()} is called.
*/
void reset();
/**
* Releases any resources associated with this instance.
* Flushes the sink, after which it is ready to receive buffers from a new playback position.
*
* <p>The audio session may remain active until {@link #reset()} is called.
*/
void release();
void flush();
/** Resets the renderer, releasing any resources that it currently holds. */
void reset();
}
......@@ -463,7 +463,7 @@ public final class DefaultAudioSink implements AudioSink {
return;
}
reset();
flush();
this.processingEnabled = processingEnabled;
outputSampleRate = sampleRate;
......@@ -681,7 +681,7 @@ public final class DefaultAudioSink implements AudioSink {
if (audioTrackPositionTracker.isStalled(getWrittenFrames())) {
Log.w(TAG, "Resetting stalled audio track");
reset();
flush();
return true;
}
......@@ -871,7 +871,7 @@ public final class DefaultAudioSink implements AudioSink {
// The audio attributes are ignored in tunneling mode, so no need to reset.
return;
}
reset();
flush();
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
}
......@@ -879,7 +879,7 @@ public final class DefaultAudioSink implements AudioSink {
public void setAudioSessionId(int audioSessionId) {
if (this.audioSessionId != audioSessionId) {
this.audioSessionId = audioSessionId;
reset();
flush();
}
}
......@@ -907,7 +907,7 @@ public final class DefaultAudioSink implements AudioSink {
if (!tunneling || audioSessionId != tunnelingAudioSessionId) {
tunneling = true;
audioSessionId = tunnelingAudioSessionId;
reset();
flush();
}
}
......@@ -916,7 +916,7 @@ public final class DefaultAudioSink implements AudioSink {
if (tunneling) {
tunneling = false;
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
reset();
flush();
}
}
......@@ -947,7 +947,7 @@ public final class DefaultAudioSink implements AudioSink {
}
@Override
public void reset() {
public void flush() {
if (isInitialized()) {
submittedPcmBytes = 0;
submittedEncodedFrames = 0;
......@@ -995,8 +995,8 @@ public final class DefaultAudioSink implements AudioSink {
}
@Override
public void release() {
reset();
public void reset() {
flush();
releaseKeepSessionIdAudioTrack();
for (AudioProcessor audioProcessor : toIntPcmAvailableAudioProcessors) {
audioProcessor.reset();
......
......@@ -511,7 +511,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
@Override
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
super.onPositionReset(positionUs, joining);
audioSink.reset();
audioSink.flush();
currentPositionUs = positionUs;
allowFirstBufferPositionDiscontinuity = true;
allowPositionDiscontinuity = true;
......@@ -537,7 +537,7 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
try {
lastInputTimeUs = C.TIME_UNSET;
pendingStreamChangeCount = 0;
audioSink.release();
audioSink.flush();
} finally {
try {
super.onDisabled();
......@@ -549,6 +549,15 @@ public class MediaCodecAudioRenderer extends MediaCodecRenderer implements Media
}
@Override
protected void onReset() {
try {
super.onReset();
} finally {
audioSink.reset();
}
}
@Override
public boolean isEnded() {
return super.isEnded() && audioSink.isEnded();
}
......
......@@ -538,7 +538,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
@Override
protected void onPositionReset(long positionUs, boolean joining) throws ExoPlaybackException {
audioSink.reset();
audioSink.flush();
currentPositionUs = positionUs;
allowFirstBufferPositionDiscontinuity = true;
allowPositionDiscontinuity = true;
......@@ -567,7 +567,7 @@ public abstract class SimpleDecoderAudioRenderer extends BaseRenderer implements
waitingForKeys = false;
try {
releaseDecoder();
audioSink.release();
audioSink.reset();
} finally {
try {
if (drmSession != null) {
......
......@@ -361,18 +361,13 @@ public class MediaCodecVideoRenderer extends MediaCodecRenderer {
@Override
protected void onDisabled() {
currentWidth = Format.NO_VALUE;
currentHeight = Format.NO_VALUE;
currentPixelWidthHeightRatio = Format.NO_VALUE;
pendingPixelWidthHeightRatio = Format.NO_VALUE;
outputStreamOffsetUs = C.TIME_UNSET;
lastInputTimeUs = C.TIME_UNSET;
outputStreamOffsetUs = C.TIME_UNSET;
pendingOutputStreamOffsetCount = 0;
clearReportedVideoSize();
clearRenderedFirstFrame();
frameReleaseTimeHelper.disable();
tunnelingOnFrameRenderedListener = null;
tunneling = false;
try {
super.onDisabled();
} finally {
......
......@@ -104,7 +104,7 @@ public class SimpleDecoderAudioRendererTest {
verify(mockAudioSink, times(1)).playToEndOfStream();
audioRenderer.disable();
audioRenderer.reset();
verify(mockAudioSink, times(1)).release();
verify(mockAudioSink, times(1)).reset();
}
private static final class FakeDecoder
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment