Skip to content

Commit

Permalink
Simplify playback parameter state tracking in DefaultAudioSink
Browse files Browse the repository at this point in the history
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
  • Loading branch information
tonihei authored and christosts committed Feb 1, 2023
1 parent 5e44af0 commit 3d82846
Showing 1 changed file with 57 additions and 78 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,8 @@ public DefaultAudioSink build() {
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;
Expand Down Expand Up @@ -552,11 +553,9 @@ private DefaultAudioSink(Builder builder) {
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);
Expand Down Expand Up @@ -859,8 +858,8 @@ public boolean handleBuffer(
startMediaTimeUsNeedsSync = false;
startMediaTimeUsNeedsInit = false;

if (enableAudioTrackPlaybackParams && Util.SDK_INT >= 23) {
setAudioTrackPlaybackParametersV23(audioTrackPlaybackParameters);
if (useAudioTrackPlaybackParams()) {
setAudioTrackPlaybackParametersV23();
}
applyAudioProcessorPlaybackParametersAndSkipSilence(presentationTimeUs);

Expand Down Expand Up @@ -1213,34 +1212,34 @@ public boolean hasPendingData() {

@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
Expand Down Expand Up @@ -1433,10 +1432,7 @@ private void resetSinkStateForFlush() {
framesPerEncodedSample = 0;
mediaPositionParameters =
new MediaPositionParameters(
getAudioProcessorPlaybackParameters(),
getSkipSilenceEnabled(),
/* mediaTimeUs= */ 0,
/* audioTrackPositionUs= */ 0);
playbackParameters, /* mediaTimeUs= */ 0, /* audioTrackPositionUs= */ 0);
startMediaTimeUs = 0;
afterDrainParameters = null;
mediaPositionParametersCheckpoints.clear();
Expand All @@ -1452,77 +1448,62 @@ private void resetSinkStateForFlush() {
}

@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);
} catch (IllegalArgumentException e) {
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 =
shouldApplyAudioProcessorPlaybackParameters()
? audioProcessorChain.applyPlaybackParameters(getAudioProcessorPlaybackParameters())
: PlaybackParameters.DEFAULT;
boolean skipSilenceEnabled =
PlaybackParameters audioProcessorPlaybackParameters;
if (!useAudioTrackPlaybackParams()) {
playbackParameters =
shouldApplyAudioProcessorPlaybackParameters()
? audioProcessorChain.applyPlaybackParameters(playbackParameters)
: PlaybackParameters.DEFAULT;
audioProcessorPlaybackParameters = playbackParameters;
} else {
audioProcessorPlaybackParameters = PlaybackParameters.DEFAULT;
}
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();
Expand All @@ -1548,6 +1529,10 @@ private boolean shouldApplyAudioProcessorPlaybackParameters() {
&& !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.
Expand Down Expand Up @@ -1869,20 +1854,14 @@ private static final class MediaPositionParameters {

/** 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;
}
Expand Down

0 comments on commit 3d82846

Please sign in to comment.