mirror of
https://github.com/androidx/media.git
synced 2025-05-09 16:40:55 +08:00
Handle AV sync timestamps when draining the audio sink during tunneling
When audio processors are enabled during tunneling, they must produce output immediately, ensuring that the timestamps of the output samples correspond to the input and that no additional samples are produced. This requirement is documented in the Javadoc of DefaultAudioSink. However, this alone doesn't guarantee all buffers are immediately written to the AudioTrack, because the AudioTrack writes are non-blocking and may need multiple attempts. When draining the audio sink at the end of the stream, we currently fail in this situation because we assert that the timestamp must be set (=the drain operation is a no-op). But this may not be true when the previous non-blocking write wasn't fully handled. We can fix this by saving the last timestamp and reusing it during draining. Issue: google/ExoPlayer#10847 PiperOrigin-RevId: 500943891
This commit is contained in:
parent
2693b6025f
commit
3c6b8c5d7b
@ -511,6 +511,7 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
private AuxEffectInfo auxEffectInfo;
|
||||
@Nullable private AudioDeviceInfoApi23 preferredDevice;
|
||||
private boolean tunneling;
|
||||
private long lastTunnelingAvSyncPresentationTimeUs;
|
||||
private long lastFeedElapsedRealtimeMs;
|
||||
private boolean offloadDisabledUntilNextConfiguration;
|
||||
private boolean isWaitingForOffloadEndOfStreamHandled;
|
||||
@ -1001,6 +1002,9 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
* <p>If the {@link AudioProcessingPipeline} is not {@linkplain
|
||||
* AudioProcessingPipeline#isOperational() operational}, input buffers are passed straight to
|
||||
* {@link #writeBuffer(ByteBuffer, long)}.
|
||||
*
|
||||
* @param avSyncPresentationTimeUs The tunneling AV sync presentation time for the current buffer,
|
||||
* or {@link C#TIME_END_OF_SOURCE} when draining remaining buffers at the end of the stream.
|
||||
*/
|
||||
private void processBuffers(long avSyncPresentationTimeUs) throws WriteException {
|
||||
if (!audioProcessingPipeline.isOperational()) {
|
||||
@ -1034,17 +1038,24 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
if (outputBuffer == null) {
|
||||
return true;
|
||||
}
|
||||
writeBuffer(outputBuffer, C.TIME_UNSET);
|
||||
writeBuffer(outputBuffer, C.TIME_END_OF_SOURCE);
|
||||
return outputBuffer == null;
|
||||
}
|
||||
|
||||
audioProcessingPipeline.queueEndOfStream();
|
||||
processBuffers(C.TIME_UNSET);
|
||||
processBuffers(C.TIME_END_OF_SOURCE);
|
||||
return audioProcessingPipeline.isEnded()
|
||||
&& (outputBuffer == null || !outputBuffer.hasRemaining());
|
||||
}
|
||||
|
||||
@SuppressWarnings("ReferenceEquality")
|
||||
/**
|
||||
* Writes the provided buffer to the audio track.
|
||||
*
|
||||
* @param buffer The buffer to write.
|
||||
* @param avSyncPresentationTimeUs The tunneling AV sync presentation time for the buffer, or
|
||||
* {@link C#TIME_END_OF_SOURCE} when draining remaining buffers at the end of the stream.
|
||||
*/
|
||||
private void writeBuffer(ByteBuffer buffer, long avSyncPresentationTimeUs) throws WriteException {
|
||||
if (!buffer.hasRemaining()) {
|
||||
return;
|
||||
@ -1080,6 +1091,14 @@ public final class DefaultAudioSink implements AudioSink {
|
||||
}
|
||||
} else if (tunneling) {
|
||||
Assertions.checkState(avSyncPresentationTimeUs != C.TIME_UNSET);
|
||||
if (avSyncPresentationTimeUs == C.TIME_END_OF_SOURCE) {
|
||||
// Audio processors during tunneling are required to produce buffers immediately when
|
||||
// queuing, so we can assume the timestamp during draining at the end of the stream is the
|
||||
// same as the timestamp of the last sample we processed.
|
||||
avSyncPresentationTimeUs = lastTunnelingAvSyncPresentationTimeUs;
|
||||
} else {
|
||||
lastTunnelingAvSyncPresentationTimeUs = avSyncPresentationTimeUs;
|
||||
}
|
||||
bytesWrittenOrError =
|
||||
writeNonBlockingWithAvSyncV21(
|
||||
audioTrack, buffer, bytesRemaining, avSyncPresentationTimeUs);
|
||||
|
Loading…
x
Reference in New Issue
Block a user