[go: nahoru, domu]

blob: 7f1be4ae8e7327409f5c14cbd0fa2c0d58a270cc [file] [log] [blame]
/*
* Copyright 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media2.player;
import static androidx.annotation.RestrictTo.Scope.LIBRARY;
import android.media.AudioTrack;
import android.os.Build;
import androidx.annotation.DoNotInline;
import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.annotation.RestrictTo;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* Structure for common playback params.
*
* Used by {@link MediaPlayer} {@link MediaPlayer#getPlaybackParams()} and
* {@link MediaPlayer#setPlaybackParams(PlaybackParams)}
* to control playback behavior.
* <p>
* PlaybackParams returned by {@link MediaPlayer#getPlaybackParams()} will always have values.
* In case of {@link MediaPlayer#setPlaybackParams}, the player will not update the param if the
* value is not set. For example, if pitch is set while speed is not set, only pitch will be
* updated.
* <p>
* Note that the speed value does not change the player state. For example, if
* {@link MediaPlayer#getPlaybackParams()} is called with the speed of 2.0f in
* {@link MediaPlayer#PLAYER_STATE_PAUSED}, the player will just update internal property and stay
* paused. Once {@link MediaPlayer#play()} is called afterwards, the player will start
* playback with the given speed. Calling this with zero speed is not allowed.
* <p>
* <strong>audio fallback mode:</strong> select out-of-range parameter handling.
* <ul>
* <li> {@link PlaybackParams#AUDIO_FALLBACK_MODE_DEFAULT}:
* System will determine best handling. </li>
* <li> {@link PlaybackParams#AUDIO_FALLBACK_MODE_MUTE}:
* Play silence for params normally out of range.</li>
* <li> {@link PlaybackParams#AUDIO_FALLBACK_MODE_FAIL}:
* Return {@link java.lang.IllegalArgumentException} from
* <code>AudioTrack.setPlaybackParams(PlaybackParams)</code>.</li>
* </ul>
* <p> <strong>pitch:</strong> increases or decreases the tonal frequency of the audio content.
* It is expressed as a multiplicative factor, where normal pitch is 1.0f.
* <p> <strong>speed:</strong> increases or decreases the time to
* play back a set of audio or video frames.
* It is expressed as a multiplicative factor, where normal speed is 1.0f.
* <p> Different combinations of speed and pitch may be used for audio playback;
* some common ones:
* <ul>
* <li> <em>Pitch equals 1.0f.</em> Speed change will be done with pitch preserved,
* often called <em>timestretching</em>.</li>
* <li> <em>Pitch equals speed.</em> Speed change will be done by <em>resampling</em>,
* similar to {@link AudioTrack#setPlaybackRate(int)}.</li>
* </ul>
*/
public final class PlaybackParams {
@RestrictTo(LIBRARY)
@IntDef(
value = {
AUDIO_FALLBACK_MODE_DEFAULT,
AUDIO_FALLBACK_MODE_MUTE,
AUDIO_FALLBACK_MODE_FAIL,
}
)
@Retention(RetentionPolicy.SOURCE)
public @interface AudioFallbackMode {}
public static final int AUDIO_FALLBACK_MODE_DEFAULT = 0;
public static final int AUDIO_FALLBACK_MODE_MUTE = 1;
public static final int AUDIO_FALLBACK_MODE_FAIL = 2;
// params
private Integer mAudioFallbackMode;
private Float mPitch;
private Float mSpeed;
private android.media.PlaybackParams mPlaybackParams;
PlaybackParams(Integer audioFallbackMode, Float pitch, Float speed) {
mAudioFallbackMode = audioFallbackMode;
mPitch = pitch;
mSpeed = speed;
}
@RequiresApi(23)
PlaybackParams(android.media.PlaybackParams playbackParams) {
mPlaybackParams = playbackParams;
}
/**
* Returns the audio fallback mode. {@code null} if a value is not set.
*/
public @AudioFallbackMode @Nullable Integer getAudioFallbackMode() {
if (Build.VERSION.SDK_INT >= 23) {
try {
return Api23Impl.getAudioFallbackMode(mPlaybackParams);
} catch (IllegalStateException e) {
return null;
}
} else {
return mAudioFallbackMode;
}
}
/**
* Returns the pitch factor. {@code null} if a value is not set.
*/
public @Nullable Float getPitch() {
if (Build.VERSION.SDK_INT >= 23) {
try {
return Api23Impl.getPitch(mPlaybackParams);
} catch (IllegalStateException e) {
return null;
}
} else {
return mPitch;
}
}
/**
* Returns the speed factor. {@code null} if a value is not set.
*/
public @Nullable Float getSpeed() {
if (Build.VERSION.SDK_INT >= 23) {
try {
return Api23Impl.getSpeed(mPlaybackParams);
} catch (IllegalStateException e) {
return null;
}
} else {
return mSpeed;
}
}
/**
* Returns the underlying framework {@link android.media.PlaybackParams} object. {@code null}
* if it is not available.
* <p>
* This method is only supported on {@link android.os.Build.VERSION_CODES#M} and later.
* </p>
*
*/
@RestrictTo(LIBRARY)
@RequiresApi(23)
public android.media.PlaybackParams getPlaybackParams() {
if (Build.VERSION.SDK_INT >= 23) {
return mPlaybackParams;
} else {
return null;
}
}
/**
* The builder class that makes it easy to chain setters to create a {@link PlaybackParams}
* object.
*/
public static final class Builder {
private Integer mAudioFallbackMode;
private Float mPitch;
private Float mSpeed;
private android.media.PlaybackParams mPlaybackParams;
/**
* Default constructor
*/
public Builder() {
if (Build.VERSION.SDK_INT >= 23) {
mPlaybackParams = Api23Impl.createPlaybackParams();
}
}
@RestrictTo(LIBRARY)
@RequiresApi(23)
public Builder(android.media.PlaybackParams playbackParams) {
mPlaybackParams = playbackParams;
}
/**
* Constructs a new PlaybackParams builder using data from {@code playbackParams}.
*
* @param playbackParams the non-null instance to initialize from.
*/
public Builder(@NonNull PlaybackParams playbackParams) {
if (playbackParams == null) {
throw new NullPointerException("playbakcParams shouldn't be null");
}
if (Build.VERSION.SDK_INT >= 23) {
mPlaybackParams = playbackParams.getPlaybackParams();
} else {
mAudioFallbackMode = playbackParams.getAudioFallbackMode();
mPitch = playbackParams.getPitch();
mSpeed = playbackParams.getSpeed();
}
}
/**
* Sets the audio fallback mode.
*
* @return this <code>Builder</code> instance.
*/
public @NonNull Builder setAudioFallbackMode(@AudioFallbackMode int audioFallbackMode) {
if (Build.VERSION.SDK_INT >= 23) {
Api23Impl.setAudioFallbackMode(mPlaybackParams, audioFallbackMode);
} else {
mAudioFallbackMode = audioFallbackMode;
}
return this;
}
/**
* Sets the pitch factor.
*
* @return this <code>Builder</code> instance.
* @throws IllegalArgumentException if the pitch is negative or zero.
*/
public @NonNull Builder setPitch(
@FloatRange(from = 0.0f, to = Float.MAX_VALUE, fromInclusive = false) float pitch) {
if (pitch == 0.f) {
throw new IllegalArgumentException("0 pitch is not allowed");
}
if (pitch < 0.f) {
throw new IllegalArgumentException("pitch must not be negative");
}
if (Build.VERSION.SDK_INT >= 23) {
Api23Impl.setPitch(mPlaybackParams, pitch);
} else {
mPitch = pitch;
}
return this;
}
/**
* Sets the speed factor.
*
* @return this <code>Builder</code> instance.
* @throws IllegalArgumentException if the speed is negative or zero.
*/
public @NonNull Builder setSpeed(
@FloatRange(from = 0.0f, to = Float.MAX_VALUE, fromInclusive = false) float speed) {
if (speed == 0.f) {
throw new IllegalArgumentException("0 speed is not allowed");
}
if (speed < 0.f) {
throw new IllegalArgumentException("negative speed is not supported");
}
if (Build.VERSION.SDK_INT >= 23) {
Api23Impl.setSpeed(mPlaybackParams, speed);
} else {
mSpeed = speed;
}
return this;
}
/**
* Takes the values of the Builder object and creates a PlaybackParams object.
*
* @return PlaybackParams object with values from the Builder.
*/
public @NonNull PlaybackParams build() {
if (Build.VERSION.SDK_INT >= 23) {
return new PlaybackParams(mPlaybackParams);
} else {
return new PlaybackParams(mAudioFallbackMode, mPitch, mSpeed);
}
}
}
@RequiresApi(23)
static class Api23Impl {
@DoNotInline
static android.media.PlaybackParams createPlaybackParams() {
return new android.media.PlaybackParams();
}
@DoNotInline
static int getAudioFallbackMode(android.media.PlaybackParams playbackParams) {
return playbackParams.getAudioFallbackMode();
}
@DoNotInline
static float getPitch(android.media.PlaybackParams playbackParams) {
return playbackParams.getPitch();
}
@DoNotInline
static float getSpeed(android.media.PlaybackParams playbackParams) {
return playbackParams.getSpeed();
}
@DoNotInline
static android.media.PlaybackParams setAudioFallbackMode(
android.media.PlaybackParams playbackParams, int audioFallbackMode) {
return playbackParams.setAudioFallbackMode(audioFallbackMode);
}
@DoNotInline
static android.media.PlaybackParams setPitch(android.media.PlaybackParams playbackParams,
float pitch) {
return playbackParams.setPitch(pitch);
}
@DoNotInline
static android.media.PlaybackParams setSpeed(android.media.PlaybackParams playbackParams,
float speed) {
return playbackParams.setSpeed(speed);
}
private Api23Impl() {}
}
}