Commit 3d828460 by tonihei Committed by christosts

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
parent 5e44af0a
...@@ -495,7 +495,8 @@ public final class DefaultAudioSink implements AudioSink { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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;
shouldApplyAudioProcessorPlaybackParameters() if (!useAudioTrackPlaybackParams()) {
? audioProcessorChain.applyPlaybackParameters(getAudioProcessorPlaybackParameters()) playbackParameters =
: PlaybackParameters.DEFAULT; shouldApplyAudioProcessorPlaybackParameters()
boolean skipSilenceEnabled = ? audioProcessorChain.applyPlaybackParameters(playbackParameters)
: PlaybackParameters.DEFAULT;
audioProcessorPlaybackParameters = playbackParameters;
} else {
audioProcessorPlaybackParameters = PlaybackParameters.DEFAULT;
}
skipSilenceEnabled =
shouldApplyAudioProcessorPlaybackParameters() shouldApplyAudioProcessorPlaybackParameters()
? audioProcessorChain.applySkipSilenceEnabled(getSkipSilenceEnabled()) ? audioProcessorChain.applySkipSilenceEnabled(skipSilenceEnabled)
: 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 { ...@@ -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 { ...@@ -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;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment