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;
@Nullable private MediaPositionParameters afterDrainParameters;
private MediaPositionParameters mediaPositionParameters;
private PlaybackParameters audioTrackPlaybackParameters;
private PlaybackParameters playbackParameters;
private boolean skipSilenceEnabled;
@Nullable private ByteBuffer avSyncHeader;
private int bytesUntilNextAvSync;
@ -552,11 +553,9 @@ public final class DefaultAudioSink implements AudioSink {
auxEffectInfo = new AuxEffectInfo(AuxEffectInfo.NO_AUX_EFFECT_ID, 0f);
mediaPositionParameters =
new MediaPositionParameters(
PlaybackParameters.DEFAULT,
DEFAULT_SKIP_SILENCE,
/* mediaTimeUs= */ 0,
/* audioTrackPositionUs= */ 0);
audioTrackPlaybackParameters = PlaybackParameters.DEFAULT;
PlaybackParameters.DEFAULT, /* mediaTimeUs= */ 0, /* audioTrackPositionUs= */ 0);
playbackParameters = PlaybackParameters.DEFAULT;
skipSilenceEnabled = DEFAULT_SKIP_SILENCE;
mediaPositionParametersCheckpoints = new ArrayDeque<>();
initializationExceptionPendingExceptionHolder =
new PendingExceptionHolder<>(AUDIO_TRACK_RETRY_DURATION_MS);
@ -859,8 +858,8 @@ public final class DefaultAudioSink implements AudioSink {
startMediaTimeUsNeedsSync = false;
startMediaTimeUsNeedsInit = false;
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) {
setAudioTrackPlaybackParametersV23(audioTrackPlaybackParameters);
if (useAudioTrackPlaybackParams()) {
setAudioTrackPlaybackParametersV23();
}
applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs);
@ -1213,34 +1212,34 @@ public final class DefaultAudioSink implements AudioSink {
@Override
public void setPlaybackParameters(PlaybackParameters playbackParameters) {
playbackParameters =
this.playbackParameters =
new PlaybackParameters(
constrainValue(playbackParameters.speed, MIN_PLAYBACK_SPEED, MAX_PLAYBACK_SPEED),
constrainValue(playbackParameters.pitch, MIN_PITCH, MAX_PITCH));
if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) {
setAudioTrackPlaybackParametersV23(playbackParameters);
if (useAudioTrackPlaybackParams()) {
setAudioTrackPlaybackParametersV23();
} else {
setAudioProcessorPlaybackParametersAndSkipSilence(
playbackParameters, getSkipSilenceEnabled());
setAudioProcessorPlaybackParameters(playbackParameters);
}
}
@Override
public PlaybackParameters getPlaybackParameters() {
return enableAudioTrackPlaybackParams
? audioTrackPlaybackParameters
: getAudioProcessorPlaybackParameters();
return playbackParameters;
}
@Override
public void setSkipSilenceEnabled(boolean skipSilenceEnabled) {
setAudioProcessorPlaybackParametersAndSkipSilence(
getAudioProcessorPlaybackParameters(), skipSilenceEnabled);
this.skipSilenceEnabled = 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
public boolean getSkipSilenceEnabled() {
return getMediaPositionParameters().skipSilence;
return skipSilenceEnabled;
}
@Override
@ -1433,10 +1432,7 @@ public final class DefaultAudioSink implements AudioSink {
framesPerEncodedSample = 0;
mediaPositionParameters =
new MediaPositionParameters(
getAudioProcessorPlaybackParameters(),
getSkipSilenceEnabled(),
/* mediaTimeUs= */ 0,
/* audioTrackPositionUs= */ 0);
playbackParameters, /* mediaTimeUs= */ 0, /* audioTrackPositionUs= */ 0);
startMediaTimeUs = 0;
afterDrainParameters = null;
mediaPositionParametersCheckpoints.clear();
@ -1452,13 +1448,13 @@ public final class DefaultAudioSink implements AudioSink {
}
@RequiresApi(23)
private void setAudioTrackPlaybackParametersV23(PlaybackParameters audioTrackPlaybackParameters) {
private void setAudioTrackPlaybackParametersV23() {
if (isAudioTrackInitialized()) {
PlaybackParams playbackParams =
new PlaybackParams()
.allowDefaults()
.setSpeed(audioTrackPlaybackParameters.speed)
.setPitch(audioTrackPlaybackParameters.pitch)
.setSpeed(playbackParameters.speed)
.setPitch(playbackParameters.pitch)
.setAudioFallbackMode(PlaybackParams.AUDIO_FALLBACK_MODE_FAIL);
try {
audioTrack.setPlaybackParams(playbackParams);
@ -1466,63 +1462,48 @@ public final class DefaultAudioSink implements AudioSink {
Log.w(TAG, "Failed to set playback params", e);
}
// Update the speed using the actual effective speed from the audio track.
audioTrackPlaybackParameters =
playbackParameters =
new PlaybackParameters(
audioTrack.getPlaybackParams().getSpeed(), audioTrack.getPlaybackParams().getPitch());
audioTrackPositionTracker.setAudioTrackPlaybackSpeed(audioTrackPlaybackParameters.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;
}
audioTrackPositionTracker.setAudioTrackPlaybackSpeed(playbackParameters.speed);
}
}
private PlaybackParameters getAudioProcessorPlaybackParameters() {
return getMediaPositionParameters().playbackParameters;
}
private MediaPositionParameters getMediaPositionParameters() {
// Mask the already set parameters.
return afterDrainParameters != null
? afterDrainParameters
: !mediaPositionParametersCheckpoints.isEmpty()
? mediaPositionParametersCheckpoints.getLast()
: mediaPositionParameters;
private void setAudioProcessorPlaybackParameters(PlaybackParameters playbackParameters) {
MediaPositionParameters mediaPositionParameters =
new MediaPositionParameters(
playbackParameters,
/* 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 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()
? audioProcessorChain.applyPlaybackParameters(getAudioProcessorPlaybackParameters())
: PlaybackParameters.DEFAULT;
boolean skipSilenceEnabled =
shouldApplyAudioProcessorPlaybackParameters()
? audioProcessorChain.applySkipSilenceEnabled(getSkipSilenceEnabled())
? audioProcessorChain.applySkipSilenceEnabled(skipSilenceEnabled)
: DEFAULT_SKIP_SILENCE;
mediaPositionParametersCheckpoints.add(
new MediaPositionParameters(
playbackParameters,
skipSilenceEnabled,
audioProcessorPlaybackParameters,
/* mediaTimeUs= */ max(0, presentationTimeUs),
/* audioTrackPositionUs= */ configuration.framesToDurationUs(getWrittenFrames())));
setupAudioProcessors();
@ -1548,6 +1529,10 @@ public final class DefaultAudioSink implements AudioSink {
&& !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
* float PCM.
@ -1869,20 +1854,14 @@ public final class DefaultAudioSink implements AudioSink {
/** The playback parameters. */
public final PlaybackParameters playbackParameters;
/** Whether to skip silences. */
public final boolean skipSilence;
/** The media time from which the playback parameters apply, in microseconds. */
public final long mediaTimeUs;
/** The audio track position from which the playback parameters apply, in microseconds. */
public final long audioTrackPositionUs;
private MediaPositionParameters(
PlaybackParameters playbackParameters,
boolean skipSilence,
long mediaTimeUs,
long audioTrackPositionUs) {
PlaybackParameters playbackParameters, long mediaTimeUs, long audioTrackPositionUs) {
this.playbackParameters = playbackParameters;
this.skipSilence = skipSilence;
this.mediaTimeUs = mediaTimeUs;
this.audioTrackPositionUs = audioTrackPositionUs;
}