Simplify playback parameter state tracking in DefaultAudioSink

This makes it easier to reason about some parts of the code and
will eventually allow to easily switch between AudioProcessor-
based on AudioSink-based speed adjustment.

The current state saves the applicable playback parameters
in separate variables depending on which speed adjustment
path is used. Moreover, the AudioProcessor-based logic keeps
a chain of pending parameter changes and we derive the last
applicable one everytime we need the current parameters.

After this change, this is simplified by
 - keeping a common value for playback parameters independent
   of the actual path we use for adjustment.
 - keeping the final ("current") parameters directly, instead
   of deriving it from a chain of yet to be applied parameters.

PiperOrigin-RevId: 505097294
This commit is contained in:
tonihei 2023-01-27 13:55:32 +00:00 committed by christosts
parent 5e44af0ad9
commit 3d82846074

View File

@ -495,7 +495,8 @@ public final class DefaultAudioSink implements AudioSink {
private AudioAttributes audioAttributes; private AudioAttributes audioAttributes;
@Nullable private MediaPositionParameters afterDrainParameters; @Nullable private MediaPositionParameters afterDrainParameters;
private MediaPositionParameters mediaPositionParameters; private MediaPositionParameters mediaPositionParameters;
private PlaybackParameters audioTrackPlaybackParameters; private PlaybackParameters playbackParameters;
private boolean skipSilenceEnabled;
@Nullable private ByteBuffer avSyncHeader; @Nullable private ByteBuffer avSyncHeader;
private int bytesUntilNextAvSync; private int bytesUntilNextAvSync;
@ -552,11 +553,9 @@ public final class DefaultAudioSink implements AudioSink {
auxEffectInfo = new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, 0f); auxEffectInfo = new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, 0f);
mediaPositionParameters = mediaPositionParameters =
new MediaPositionParameters( new MediaPositionParameters(
PlaybackParameters.DEFAULT, PlaybackParameters.DEFAULT, /* mediaTimeUs= */ 0, /* audioTrackPositionUs= */ 0);
DEFAULT_SKIP_SILENCE, playbackParameters = PlaybackParameters.DEFAULT;
/* mediaTimeUs= */ 0, skipSilenceEnabled = DEFAULT_SKIP_SILENCE;
/* audioTrackPositionUs= */ 0);
audioTrackPlaybackParameters = PlaybackParameters.DEFAULT;
mediaPositionParametersCheckpoints = new ArrayDeque<>(); mediaPositionParametersCheckpoints = new ArrayDeque<>();
initializationExceptionPendingExceptionHolder = initializationExceptionPendingExceptionHolder =
new PendingExceptionHolder<>(AUDIO_TRACK_RETRY_DURATION_MS); new PendingExceptionHolder<>(AUDIO_TRACK_RETRY_DURATION_MS);
@ -859,8 +858,8 @@ public final class DefaultAudioSink implements AudioSink {
startMediaTimeUsNeedsSync = false; startMediaTimeUsNeedsSync = false;
startMediaTimeUsNeedsInit = false; startMediaTimeUsNeedsInit = false;
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) { if (useAudioTrackPlaybackParams()) {
setAudioTrackPlaybackParametersV23(audioTrackPlaybackParameters); setAudioTrackPlaybackParametersV23();
} }
applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs); applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs);
@ -1213,34 +1212,34 @@ public final class DefaultAudioSink implements AudioSink {
@Override @Override
public void setPlaybackParameters(PlaybackParameters playbackParameters) { public void setPlaybackParameters(PlaybackParameters playbackParameters) {
playbackParameters = this.playbackParameters =
new PlaybackParameters( new PlaybackParameters(
constrainValue(playbackParameters.speed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED), constrainValue(playbackParameters.speed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED),
constrainValue(playbackParameters.pitch, MIN_PITCH, MAX_PITCH)); constrainValue(playbackParameters.pitch, MIN_PITCH, MAX_PITCH));
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) { if (useAudioTrackPlaybackParams()) {
setAudioTrackPlaybackParametersV23(playbackParameters); setAudioTrackPlaybackParametersV23();
} else { } else {
setAudioProcessorPlaybackParametersAndSkipSilence( setAudioProcessorPlaybackParameters(playbackParameters);
playbackParameters, getSkipSilenceEnabled());
} }
} }
@Override @Override
public PlaybackParameters getPlaybackParameters() { public PlaybackParameters getPlaybackParameters() {
return enableAudioTrackPlaybackParams return playbackParameters;
? audioTrackPlaybackParameters
: getAudioProcessorPlaybackParameters();
} }
@Override @Override
public void setSkipSilenceEnabled(boolean skipSilenceEnabled) { public void setSkipSilenceEnabled(boolean skipSilenceEnabled) {
setAudioProcessorPlaybackParametersAndSkipSilence( this.skipSilenceEnabled = skipSilenceEnabled;
getAudioProcessorPlaybackParameters(), skipSilenceEnabled); // Skip silence is applied together with the AudioProcessor playback parameters after draining
// the pipeline. Force a drain by re-applying the current playback parameters.
setAudioProcessorPlaybackParameters(
useAudioTrackPlaybackParams() ? PlaybackParameters.DEFAULT : playbackParameters);
} }
@Override @Override
public boolean getSkipSilenceEnabled() { public boolean getSkipSilenceEnabled() {
return getMediaPositionParameters().skipSilence; return skipSilenceEnabled;
} }
@Override @Override
@ -1433,10 +1432,7 @@ public final class DefaultAudioSink implements AudioSink {
framesPerEncodedSample = 0; framesPerEncodedSample = 0;
mediaPositionParameters = mediaPositionParameters =
new MediaPositionParameters( new MediaPositionParameters(
getAudioProcessorPlaybackParameters(), playbackParameters, /* mediaTimeUs= */ 0, /* audioTrackPositionUs= */ 0);
getSkipSilenceEnabled(),
/* mediaTimeUs= */ 0,
/* audioTrackPositionUs= */ 0);
startMediaTimeUs = 0; startMediaTimeUs = 0;
afterDrainParameters = null; afterDrainParameters = null;
mediaPositionParametersCheckpoints.clear(); mediaPositionParametersCheckpoints.clear();
@ -1452,13 +1448,13 @@ public final class DefaultAudioSink implements AudioSink {
} }
@RequiresApi(23) @RequiresApi(23)
private void setAudioTrackPlaybackParametersV23(PlaybackParameters audioTrackPlaybackParameters) { private void setAudioTrackPlaybackParametersV23() {
if (isAudioTrackInitialized()) { if (isAudioTrackInitialized()) {
PlaybackParams playbackParams = PlaybackParams playbackParams =
new PlaybackParams() new PlaybackParams()
.allowDefaults() .allowDefaults()
.setSpeed(audioTrackPlaybackParameters.speed) .setSpeed(playbackParameters.speed)
.setPitch(audioTrackPlaybackParameters.pitch) .setPitch(playbackParameters.pitch)
.setAudioFallbackMode(PlaybackParams.AUDIO_FALLBACK_MODE_FAIL); .setAudioFallbackMode(PlaybackParams.AUDIO_FALLBACK_MODE_FAIL);
try { try {
audioTrack.setPlaybackParams(playbackParams); audioTrack.setPlaybackParams(playbackParams);
@ -1466,63 +1462,48 @@ public final class DefaultAudioSink implements AudioSink {
Log.w(TAG, "Failed to set playback params", e); Log.w(TAG, "Failed to set playback params", e);
} }
// Update the speed using the actual effective speed from the audio track. // Update the speed using the actual effective speed from the audio track.
audioTrackPlaybackParameters = playbackParameters =
new PlaybackParameters( new PlaybackParameters(
audioTrack.getPlaybackParams().getSpeed(), audioTrack.getPlaybackParams().getPitch()); audioTrack.getPlaybackParams().getSpeed(), audioTrack.getPlaybackParams().getPitch());
audioTrackPositionTracker.setAudioTrackPlaybackSpeed(audioTrackPlaybackParameters.speed); audioTrackPositionTracker.setAudioTrackPlaybackSpeed(playbackParameters.speed);
}
this.audioTrackPlaybackParameters = audioTrackPlaybackParameters;
}
private void setAudioProcessorPlaybackParametersAndSkipSilence(
PlaybackParameters playbackParameters, boolean skipSilence) {
MediaPositionParameters currentMediaPositionParameters = getMediaPositionParameters();
if (!playbackParameters.equals(currentMediaPositionParameters.playbackParameters)
|| skipSilence != currentMediaPositionParameters.skipSilence) {
MediaPositionParameters mediaPositionParameters =
new MediaPositionParameters(
playbackParameters,
skipSilence,
/* mediaTimeUs= */ C.TIME_UNSET,
/* audioTrackPositionUs= */ C.TIME_UNSET);
if (isAudioTrackInitialized()) {
// Drain the audio processors so we can determine the frame position at which the new
// parameters apply.
this.afterDrainParameters = mediaPositionParameters;
} else {
// Update the audio processor chain parameters now. They will be applied to the audio
// processors during initialization.
this.mediaPositionParameters = mediaPositionParameters;
}
} }
} }
private PlaybackParameters getAudioProcessorPlaybackParameters() { private void setAudioProcessorPlaybackParameters(PlaybackParameters playbackParameters) {
return getMediaPositionParameters().playbackParameters; MediaPositionParameters mediaPositionParameters =
} new MediaPositionParameters(
playbackParameters,
private MediaPositionParameters getMediaPositionParameters() { /* mediaTimeUs= */ C.TIME_UNSET,
// Mask the already set parameters. /* audioTrackPositionUs= */ C.TIME_UNSET);
return afterDrainParameters != null if (isAudioTrackInitialized()) {
? afterDrainParameters // Drain the audio processors so we can determine the frame position at which the new
: !mediaPositionParametersCheckpoints.isEmpty() // parameters apply.
? mediaPositionParametersCheckpoints.getLast() this.afterDrainParameters = mediaPositionParameters;
: mediaPositionParameters; } else {
// Update the audio processor chain parameters now. They will be applied to the audio
// processors during initialization.
this.mediaPositionParameters = mediaPositionParameters;
}
} }
private void applyAudioProcessorPlaybackParametersAndSkipSilence(long presentationTimeUs) { private void applyAudioProcessorPlaybackParametersAndSkipSilence(long presentationTimeUs) {
PlaybackParameters playbackParameters = PlaybackParameters audioProcessorPlaybackParameters;
if (!useAudioTrackPlaybackParams()) {
playbackParameters =
shouldApplyAudioProcessorPlaybackParameters()
? audioProcessorChain.applyPlaybackParameters(playbackParameters)
: PlaybackParameters.DEFAULT;
audioProcessorPlaybackParameters = playbackParameters;
} else {
audioProcessorPlaybackParameters = PlaybackParameters.DEFAULT;
}
skipSilenceEnabled =
shouldApplyAudioProcessorPlaybackParameters() shouldApplyAudioProcessorPlaybackParameters()
? audioProcessorChain.applyPlaybackParameters(getAudioProcessorPlaybackParameters()) ? audioProcessorChain.applySkipSilenceEnabled(skipSilenceEnabled)
: PlaybackParameters.DEFAULT;
boolean skipSilenceEnabled =
shouldApplyAudioProcessorPlaybackParameters()
? audioProcessorChain.applySkipSilenceEnabled(getSkipSilenceEnabled())
: DEFAULT_SKIP_SILENCE; : DEFAULT_SKIP_SILENCE;
mediaPositionParametersCheckpoints.add( mediaPositionParametersCheckpoints.add(
new MediaPositionParameters( new MediaPositionParameters(
playbackParameters, audioProcessorPlaybackParameters,
skipSilenceEnabled,
/* mediaTimeUs= */ max(0, presentationTimeUs), /* mediaTimeUs= */ max(0, presentationTimeUs),
/* audioTrackPositionUs= */ configuration.framesToDurationUs(getWrittenFrames()))); /* audioTrackPositionUs= */ configuration.framesToDurationUs(getWrittenFrames())));
setupAudioProcessors(); setupAudioProcessors();
@ -1548,6 +1529,10 @@ public final class DefaultAudioSink implements AudioSink {
&& !shouldUseFloatOutput(configuration.inputFormat.pcmEncoding); && !shouldUseFloatOutput(configuration.inputFormat.pcmEncoding);
} }
private boolean useAudioTrackPlaybackParams() {
return configuration != null && enableAudioTrackPlaybackParams && Util.SDK_INT >= 23;
}
/** /**
* Returns whether audio in the specified PCM encoding should be written to the audio track as * Returns whether audio in the specified PCM encoding should be written to the audio track as
* float PCM. * float PCM.
@ -1869,20 +1854,14 @@ public final class DefaultAudioSink implements AudioSink {
/** The playback parameters. */ /** The playback parameters. */
public final PlaybackParameters playbackParameters; public final PlaybackParameters playbackParameters;
/** Whether to skip silences. */
public final boolean skipSilence;
/** The media time from which the playback parameters apply, in microseconds. */ /** The media time from which the playback parameters apply, in microseconds. */
public final long mediaTimeUs; public final long mediaTimeUs;
/** The audio track position from which the playback parameters apply, in microseconds. */ /** The audio track position from which the playback parameters apply, in microseconds. */
public final long audioTrackPositionUs; public final long audioTrackPositionUs;
private MediaPositionParameters( private MediaPositionParameters(
PlaybackParameters playbackParameters, PlaybackParameters playbackParameters, long mediaTimeUs, long audioTrackPositionUs) {
boolean skipSilence,
long mediaTimeUs,
long audioTrackPositionUs) {
this.playbackParameters = playbackParameters; this.playbackParameters = playbackParameters;
this.skipSilence = skipSilence;
this.mediaTimeUs = mediaTimeUs; this.mediaTimeUs = mediaTimeUs;
this.audioTrackPositionUs = audioTrackPositionUs; this.audioTrackPositionUs = audioTrackPositionUs;
} }