Call stop() to fully play out remaining audio!

Issue: #707
This commit is contained in:
Oliver Woodman 2015-09-10 18:17:13 +01:00
parent 9bcc00f369
commit 820433de06
4 changed files with 31 additions and 13 deletions

View file

@ -212,6 +212,7 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
if (outputBuffer.getFlag(OpusDecoderWrapper.FLAG_END_OF_STREAM)) { if (outputBuffer.getFlag(OpusDecoderWrapper.FLAG_END_OF_STREAM)) {
outputStreamEnded = true; outputStreamEnded = true;
audioTrack.handleEndOfStream();
decoder.releaseOutputBuffer(outputBuffer); decoder.releaseOutputBuffer(outputBuffer);
outputBuffer = null; outputBuffer = null;
return; return;
@ -304,8 +305,7 @@ public final class LibopusAudioTrackRenderer extends SampleSourceTrackRenderer
@Override @Override
protected boolean isEnded() { protected boolean isEnded() {
return outputStreamEnded && (!audioTrack.hasPendingData() return outputStreamEnded && !audioTrack.hasPendingData();
|| !audioTrack.hasEnoughDataToBeginPlayback());
} }
@Override @Override

View file

@ -265,10 +265,7 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
@Override @Override
protected boolean isEnded() { protected boolean isEnded() {
// We've exhausted the output stream, and the AudioTrack has either played all of the data return super.isEnded() && !audioTrack.hasPendingData();
// submitted, or has been fed insufficient data to begin playback.
return super.isEnded() && (!audioTrack.hasPendingData()
|| !audioTrack.hasEnoughDataToBeginPlayback());
} }
@Override @Override
@ -366,6 +363,11 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem
return false; return false;
} }
@Override
protected void onOutputStreamEnded() {
audioTrack.handleEndOfStream();
}
protected void handleDiscontinuity() { protected void handleDiscontinuity() {
// Do nothing // Do nothing
} }

View file

@ -719,6 +719,17 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
// Do nothing. // Do nothing.
} }
/**
* Invoked when the output stream ends, meaning that the last output buffer has been processed
* and the {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} flag has been propagated through the
* decoder.
* <p>
* The default implementation is a no-op.
*/
protected void onOutputStreamEnded() {
// Do nothing.
}
/** /**
* Determines whether the existing {@link MediaCodec} should be reconfigured for a new format by * Determines whether the existing {@link MediaCodec} should be reconfigured for a new format by
* sending codec specific initialization data at the start of the next input buffer. If true is * sending codec specific initialization data at the start of the next input buffer. If true is
@ -846,6 +857,7 @@ public abstract class MediaCodecTrackRenderer extends SampleSourceTrackRenderer
maybeInitCodec(); maybeInitCodec();
} else { } else {
outputStreamEnded = true; outputStreamEnded = true;
onOutputStreamEnded();
} }
} }

View file

@ -562,6 +562,17 @@ public final class AudioTrack {
return result; return result;
} }
/**
* Ensures that the last data passed to {@link #handleBuffer(ByteBuffer, int, int, long)} is
* played out in full.
*/
public void handleEndOfStream() {
if (audioTrack != null) {
// Required to ensure that the media written to the AudioTrack is played out in full.
audioTrack.stop();
}
}
@TargetApi(21) @TargetApi(21)
private static int writeNonBlockingV21( private static int writeNonBlockingV21(
android.media.AudioTrack audioTrack, ByteBuffer buffer, int size) { android.media.AudioTrack audioTrack, ByteBuffer buffer, int size) {
@ -575,13 +586,6 @@ public final class AudioTrack {
|| audioTrackUtil.overrideHasPendingData()); || audioTrackUtil.overrideHasPendingData());
} }
/** Returns whether enough data has been supplied via {@link #handleBuffer} to begin playback. */
public boolean hasEnoughDataToBeginPlayback() {
// The value of minBufferSize can be slightly less than what's actually required for playback
// to start, hence the multiplication factor.
return submittedBytes > (minBufferSize * 3) / 2;
}
/** Sets the playback volume. */ /** Sets the playback volume. */
public void setVolume(float volume) { public void setVolume(float volume) {
if (this.volume != volume) { if (this.volume != volume) {