From 6570ef0e483cf6bc2908c0e4b4ff7316a9453f8e Mon Sep 17 00:00:00 2001 From: aquilescanta Date: Mon, 30 Nov 2015 02:20:24 -0800 Subject: [PATCH] Add support for AudioTrack pitch/speed alteration on API 23. Issue #26 ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=108958826 --- .../MediaCodecAudioTrackRenderer.java | 23 ++++-- .../android/exoplayer/audio/AudioTrack.java | 71 ++++++++++++++++++- 2 files changed, 87 insertions(+), 7 deletions(-) diff --git a/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java b/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java index 1a3057fcc2..df322af3a2 100644 --- a/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java +++ b/library/src/main/java/com/google/android/exoplayer/MediaCodecAudioTrackRenderer.java @@ -24,6 +24,7 @@ import com.google.android.exoplayer.util.MimeTypes; import android.annotation.TargetApi; import android.media.AudioManager; import android.media.MediaCodec; +import android.media.PlaybackParams; import android.media.audiofx.Virtualizer; import android.os.Handler; import android.os.SystemClock; @@ -76,6 +77,14 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem */ public static final int MSG_SET_VOLUME = 1; + /** + * The type of a message that can be passed to an instance of this class via + * {@link ExoPlayer#sendMessage} or {@link ExoPlayer#blockingSendMessage}. The message object + * should be a {@link android.media.PlaybackParams}. This will be used to configure the + * underlying {@link android.media.AudioTrack}. + */ + public static final int MSG_SET_PLAYBACK_PARAMS = 2; + /** * The name for the raw (passthrough) decoder OMX component. */ @@ -401,10 +410,16 @@ public class MediaCodecAudioTrackRenderer extends MediaCodecTrackRenderer implem @Override public void handleMessage(int messageType, Object message) throws ExoPlaybackException { - if (messageType == MSG_SET_VOLUME) { - audioTrack.setVolume((Float) message); - } else { - super.handleMessage(messageType, message); + switch (messageType) { + case MSG_SET_VOLUME: + audioTrack.setVolume((Float) message); + break; + case MSG_SET_PLAYBACK_PARAMS: + audioTrack.setPlaybackParams((PlaybackParams) message); + break; + default: + super.handleMessage(messageType, message); + break; } } diff --git a/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java b/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java index 6cdf6c6ede..8f0633fb32 100644 --- a/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java +++ b/library/src/main/java/com/google/android/exoplayer/audio/AudioTrack.java @@ -26,6 +26,7 @@ import android.media.AudioFormat; import android.media.AudioManager; import android.media.AudioTimestamp; import android.media.MediaFormat; +import android.media.PlaybackParams; import android.os.ConditionVariable; import android.os.SystemClock; import android.util.Log; @@ -248,7 +249,9 @@ public final class AudioTrack { // There's no guarantee this method exists. Do nothing. } } - if (Util.SDK_INT >= 19) { + if (Util.SDK_INT >= 23) { + audioTrackUtil = new AudioTrackUtilV23(); + } else if (Util.SDK_INT >= 19) { audioTrackUtil = new AudioTrackUtilV19(); } else { audioTrackUtil = new AudioTrackUtil(); @@ -300,7 +303,10 @@ public final class AudioTrack { if (audioTimestampSet) { // How long ago in the past the audio timestamp is (negative if it's in the future). long presentationDiff = systemClockUs - (audioTrackUtil.getTimestampNanoTime() / 1000); - long framesDiff = durationUsToFrames(presentationDiff); + // Fixes such difference if the playback speed is not real time speed. + long actualSpeedPresentationDiff = (long) (presentationDiff + * audioTrackUtil.getPlaybackSpeed()); + long framesDiff = durationUsToFrames(actualSpeedPresentationDiff); // The position of the frame that's currently being presented. long currentFramePosition = audioTrackUtil.getTimestampFramePosition() + framesDiff; currentPositionUs = framesToDurationUs(currentFramePosition) + startMediaTimeUs; @@ -652,9 +658,20 @@ public final class AudioTrack { public boolean hasPendingData() { return isInitialized() && (getSubmittedFrames() > audioTrackUtil.getPlaybackHeadPosition() - || overrideHasPendingData()); + || overrideHasPendingData()); } + /** + * Sets the playback parameters. Only available for SDK_INT >= 23 + * + * @throws UnsupportedOperationException if the Playback Parameters are not supported. That is, + * SDK_INT < 23. + */ + public void setPlaybackParams(PlaybackParams playbackParams) { + audioTrackUtil.setPlaybackParameters(playbackParams); + } + + /** * Sets the playback volume. */ @@ -1100,6 +1117,27 @@ public final class AudioTrack { throw new UnsupportedOperationException(); } + /** + * Sets the Playback Parameters to be used by the underlying {@link android.media.AudioTrack}. + * + * @param playbackParams to be used by the {@link android.media.AudioTrack}. + * @throws UnsupportedOperationException If Playback Parameters are not supported + * (i.e. SDK_INT < 23). + */ + public void setPlaybackParameters(PlaybackParams playbackParams) { + throw new UnsupportedOperationException(); + } + + /** + * Returns the configured playback speed according to the used Playback Parameters. If these are + * not supported, 1.0f(normal speed) is returned. + * + * @return The speed factor used by the underlying {@link android.media.AudioTrack}. + */ + public float getPlaybackSpeed() { + return 1.0f; + } + } @TargetApi(19) @@ -1151,4 +1189,31 @@ public final class AudioTrack { } + @TargetApi(23) + private static class AudioTrackUtilV23 extends AudioTrackUtilV19 { + + private PlaybackParams playbackParams; + + @Override + public void reconfigure(android.media.AudioTrack audioTrack, + boolean needsPassthroughWorkaround) { + super.reconfigure(audioTrack, needsPassthroughWorkaround); + setPlaybackParameters(playbackParams); + } + + public void setPlaybackParameters(PlaybackParams playbackParams) { + this.playbackParams = playbackParams; + if (audioTrack != null && playbackParams != null) { + audioTrack.setPlaybackParams(playbackParams); + } + } + + public float getPlaybackSpeed() { + if (playbackParams != null) { + return playbackParams.getSpeed(); + } else { + return 1.0f; + } + } + } }