mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Retry AudioTrack init and write before throwing
Retry AudioTrack init and write for 100ms before giving up and aborting playback. This was tested by throwing every 2 init/write and making sure playback did not stopped. #exo-offload PiperOrigin-RevId: 333536841
This commit is contained in:
parent
56cb327f1e
commit
7dfdde9246
1 changed files with 68 additions and 2 deletions
|
|
@ -246,6 +246,12 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
*/
|
*/
|
||||||
private static final int ERROR_NATIVE_DEAD_OBJECT = -32;
|
private static final int ERROR_NATIVE_DEAD_OBJECT = -32;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The duration for which failed attempts to initialize or write to the audio track may be retried
|
||||||
|
* before throwing an exception, in milliseconds.
|
||||||
|
*/
|
||||||
|
private static final int AUDIO_TRACK_RETRY_DURATION_MS = 100;
|
||||||
|
|
||||||
private static final String TAG = "AudioTrack";
|
private static final String TAG = "AudioTrack";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -279,6 +285,9 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
private final boolean enableAudioTrackPlaybackParams;
|
private final boolean enableAudioTrackPlaybackParams;
|
||||||
private final boolean enableOffload;
|
private final boolean enableOffload;
|
||||||
@MonotonicNonNull private StreamEventCallbackV29 offloadStreamEventCallbackV29;
|
@MonotonicNonNull private StreamEventCallbackV29 offloadStreamEventCallbackV29;
|
||||||
|
private final PendingExceptionHolder<InitializationException>
|
||||||
|
initializationExceptionPendingExceptionHolder;
|
||||||
|
private final PendingExceptionHolder<WriteException> writeExceptionPendingExceptionHolder;
|
||||||
|
|
||||||
@Nullable private Listener listener;
|
@Nullable private Listener listener;
|
||||||
/**
|
/**
|
||||||
|
|
@ -425,6 +434,10 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
activeAudioProcessors = new AudioProcessor[0];
|
activeAudioProcessors = new AudioProcessor[0];
|
||||||
outputBuffers = new ByteBuffer[0];
|
outputBuffers = new ByteBuffer[0];
|
||||||
mediaPositionParametersCheckpoints = new ArrayDeque<>();
|
mediaPositionParametersCheckpoints = new ArrayDeque<>();
|
||||||
|
initializationExceptionPendingExceptionHolder =
|
||||||
|
new PendingExceptionHolder<>(AUDIO_TRACK_RETRY_DURATION_MS);
|
||||||
|
writeExceptionPendingExceptionHolder =
|
||||||
|
new PendingExceptionHolder<>(AUDIO_TRACK_RETRY_DURATION_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AudioSink implementation.
|
// AudioSink implementation.
|
||||||
|
|
@ -710,8 +723,17 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isAudioTrackInitialized()) {
|
if (!isAudioTrackInitialized()) {
|
||||||
|
try {
|
||||||
initializeAudioTrack();
|
initializeAudioTrack();
|
||||||
|
} catch (InitializationException e) {
|
||||||
|
if (e.isRecoverable) {
|
||||||
|
throw e; // Do not delay the exception if it can be recovered at higher level.
|
||||||
}
|
}
|
||||||
|
initializationExceptionPendingExceptionHolder.throwExceptionIfDeadlineIsReached(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initializationExceptionPendingExceptionHolder.clear();
|
||||||
|
|
||||||
if (startMediaTimeUsNeedsInit) {
|
if (startMediaTimeUsNeedsInit) {
|
||||||
startMediaTimeUs = max(0, presentationTimeUs);
|
startMediaTimeUs = max(0, presentationTimeUs);
|
||||||
|
|
@ -929,8 +951,14 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.onAudioSinkError(e);
|
listener.onAudioSinkError(e);
|
||||||
}
|
}
|
||||||
throw e;
|
if (e.isRecoverable) {
|
||||||
|
throw e; // Do not delay the exception if it can be recovered at higher level.
|
||||||
}
|
}
|
||||||
|
writeExceptionPendingExceptionHolder.throwExceptionIfDeadlineIsReached(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
writeExceptionPendingExceptionHolder.clear();
|
||||||
|
|
||||||
int bytesWritten = bytesWrittenOrError;
|
int bytesWritten = bytesWrittenOrError;
|
||||||
|
|
||||||
if (isOffloadedPlayback(audioTrack)) {
|
if (isOffloadedPlayback(audioTrack)) {
|
||||||
|
|
@ -1182,6 +1210,8 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
}
|
}
|
||||||
}.start();
|
}.start();
|
||||||
}
|
}
|
||||||
|
writeExceptionPendingExceptionHolder.clear();
|
||||||
|
initializationExceptionPendingExceptionHolder.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -1193,6 +1223,9 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
writeExceptionPendingExceptionHolder.clear();
|
||||||
|
initializationExceptionPendingExceptionHolder.clear();
|
||||||
|
|
||||||
if (!isAudioTrackInitialized()) {
|
if (!isAudioTrackInitialized()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -2065,4 +2098,37 @@ public final class DefaultAudioSink implements AudioSink {
|
||||||
return outputMode == OUTPUT_MODE_OFFLOAD;
|
return outputMode == OUTPUT_MODE_OFFLOAD;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class PendingExceptionHolder<T extends Exception> {
|
||||||
|
|
||||||
|
private final long throwDelayMs;
|
||||||
|
|
||||||
|
@Nullable private T pendingException;
|
||||||
|
private long throwDeadlineMs;
|
||||||
|
|
||||||
|
public PendingExceptionHolder(long throwDelayMs) {
|
||||||
|
this.throwDelayMs = throwDelayMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void throwExceptionIfDeadlineIsReached(T exception) throws T {
|
||||||
|
long nowMs = SystemClock.elapsedRealtime();
|
||||||
|
if (pendingException == null) {
|
||||||
|
pendingException = exception;
|
||||||
|
throwDeadlineMs = nowMs + throwDelayMs;
|
||||||
|
}
|
||||||
|
if (nowMs >= throwDeadlineMs) {
|
||||||
|
if (pendingException != exception) {
|
||||||
|
// All retry exception are probably the same, thus only save the last one to save memory.
|
||||||
|
pendingException.addSuppressed(exception);
|
||||||
|
}
|
||||||
|
T pendingException = this.pendingException;
|
||||||
|
clear();
|
||||||
|
throw pendingException;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
pendingException = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue