VolumeShaper: Use VolumeAutomation interface and unhide

Test: Ducking and CTS
Bug: 31015569
Change-Id: I21b77905e86bf336c05aad5378f33ff36a92b3b5
This commit is contained in:
Andy Hung
2017-02-23 16:21:13 -08:00
parent 7da0e98219
commit fef734cec1
7 changed files with 310 additions and 92 deletions

View File

@@ -20998,13 +20998,14 @@ package android.media {
field public long nanoTime;
}
public class AudioTrack implements android.media.AudioRouting {
public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
@@ -22345,7 +22346,7 @@ package android.media {
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
public class MediaPlayer {
public class MediaPlayer implements android.media.VolumeAutomation {
ctor public MediaPlayer();
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22357,6 +22358,7 @@ package android.media {
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
method public static android.media.MediaPlayer create(android.content.Context, int);
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
method public android.media.BufferingParams getBufferingParams();
@@ -23184,6 +23186,10 @@ package android.media {
ctor public UnsupportedSchemeException(java.lang.String);
}
public abstract interface VolumeAutomation {
method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
}
public abstract class VolumeProvider {
ctor public VolumeProvider(int, int, int);
method public final int getCurrentVolume();
@@ -23197,6 +23203,53 @@ package android.media {
field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
}
public final class VolumeShaper implements java.lang.AutoCloseable {
method public void apply(android.media.VolumeShaper.Operation);
method public void close();
method public float getVolume();
method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
}
public static final class VolumeShaper.Configuration implements android.os.Parcelable {
method public int describeContents();
method public double getDurationMs();
method public int getInterpolatorType();
method public static int getMaximumCurvePoints();
method public float[] getTimes();
method public float[] getVolumes();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
}
public static final class VolumeShaper.Configuration.Builder {
ctor public VolumeShaper.Configuration.Builder();
ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
method public android.media.VolumeShaper.Configuration build();
method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
}
public static final class VolumeShaper.Operation implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
field public static final android.media.VolumeShaper.Operation PLAY;
field public static final android.media.VolumeShaper.Operation REVERSE;
}
}
package android.media.audiofx {

View File

@@ -22686,13 +22686,14 @@ package android.media {
field public long nanoTime;
}
public class AudioTrack implements android.media.AudioRouting {
public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
@@ -24033,7 +24034,7 @@ package android.media {
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
public class MediaPlayer {
public class MediaPlayer implements android.media.VolumeAutomation {
ctor public MediaPlayer();
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -24045,6 +24046,7 @@ package android.media {
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
method public static android.media.MediaPlayer create(android.content.Context, int);
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
method public android.media.BufferingParams getBufferingParams();
@@ -24883,6 +24885,10 @@ package android.media {
ctor public UnsupportedSchemeException(java.lang.String);
}
public abstract interface VolumeAutomation {
method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
}
public abstract class VolumeProvider {
ctor public VolumeProvider(int, int, int);
method public final int getCurrentVolume();
@@ -24896,6 +24902,53 @@ package android.media {
field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
}
public final class VolumeShaper implements java.lang.AutoCloseable {
method public void apply(android.media.VolumeShaper.Operation);
method public void close();
method public float getVolume();
method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
}
public static final class VolumeShaper.Configuration implements android.os.Parcelable {
method public int describeContents();
method public double getDurationMs();
method public int getInterpolatorType();
method public static int getMaximumCurvePoints();
method public float[] getTimes();
method public float[] getVolumes();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
}
public static final class VolumeShaper.Configuration.Builder {
ctor public VolumeShaper.Configuration.Builder();
ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
method public android.media.VolumeShaper.Configuration build();
method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
}
public static final class VolumeShaper.Operation implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
field public static final android.media.VolumeShaper.Operation PLAY;
field public static final android.media.VolumeShaper.Operation REVERSE;
}
}
package android.media.audiofx {

View File

@@ -21094,13 +21094,14 @@ package android.media {
field public long nanoTime;
}
public class AudioTrack implements android.media.AudioRouting {
public class AudioTrack implements android.media.AudioRouting android.media.VolumeAutomation {
ctor public deprecated AudioTrack(int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public deprecated AudioTrack(int, int, int, int, int, int, int) throws java.lang.IllegalArgumentException;
ctor public AudioTrack(android.media.AudioAttributes, android.media.AudioFormat, int, int, int) throws java.lang.IllegalArgumentException;
method public void addOnRoutingChangedListener(android.media.AudioRouting.OnRoutingChangedListener, android.os.Handler);
method public deprecated void addOnRoutingChangedListener(android.media.AudioTrack.OnRoutingChangedListener, android.os.Handler);
method public int attachAuxEffect(int);
method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void flush();
method public int getAudioFormat();
method public int getAudioSessionId();
@@ -22441,7 +22442,7 @@ package android.media {
field public static final int MUXER_OUTPUT_WEBM = 1; // 0x1
}
public class MediaPlayer {
public class MediaPlayer implements android.media.VolumeAutomation {
ctor public MediaPlayer();
method public void addTimedTextSource(java.lang.String, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
method public void addTimedTextSource(android.content.Context, android.net.Uri, java.lang.String) throws java.io.IOException, java.lang.IllegalArgumentException, java.lang.IllegalStateException;
@@ -22453,6 +22454,7 @@ package android.media {
method public static android.media.MediaPlayer create(android.content.Context, android.net.Uri, android.view.SurfaceHolder, android.media.AudioAttributes, int);
method public static android.media.MediaPlayer create(android.content.Context, int);
method public static android.media.MediaPlayer create(android.content.Context, int, android.media.AudioAttributes, int);
method public android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
method public void deselectTrack(int) throws java.lang.IllegalStateException;
method public int getAudioSessionId();
method public android.media.BufferingParams getBufferingParams();
@@ -23280,6 +23282,10 @@ package android.media {
ctor public UnsupportedSchemeException(java.lang.String);
}
public abstract interface VolumeAutomation {
method public abstract android.media.VolumeShaper createVolumeShaper(android.media.VolumeShaper.Configuration);
}
public abstract class VolumeProvider {
ctor public VolumeProvider(int, int, int);
method public final int getCurrentVolume();
@@ -23293,6 +23299,53 @@ package android.media {
field public static final int VOLUME_CONTROL_RELATIVE = 1; // 0x1
}
public final class VolumeShaper implements java.lang.AutoCloseable {
method public void apply(android.media.VolumeShaper.Operation);
method public void close();
method public float getVolume();
method public void replace(android.media.VolumeShaper.Configuration, android.media.VolumeShaper.Operation, boolean);
}
public static final class VolumeShaper.Configuration implements android.os.Parcelable {
method public int describeContents();
method public double getDurationMs();
method public int getInterpolatorType();
method public static int getMaximumCurvePoints();
method public float[] getTimes();
method public float[] getVolumes();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Configuration> CREATOR;
field public static final android.media.VolumeShaper.Configuration CUBIC_RAMP;
field public static final int INTERPOLATOR_TYPE_CUBIC = 2; // 0x2
field public static final int INTERPOLATOR_TYPE_CUBIC_MONOTONIC = 3; // 0x3
field public static final int INTERPOLATOR_TYPE_LINEAR = 1; // 0x1
field public static final int INTERPOLATOR_TYPE_STEP = 0; // 0x0
field public static final android.media.VolumeShaper.Configuration LINEAR_RAMP;
field public static final android.media.VolumeShaper.Configuration SCURVE_RAMP;
field public static final android.media.VolumeShaper.Configuration SINE_RAMP;
}
public static final class VolumeShaper.Configuration.Builder {
ctor public VolumeShaper.Configuration.Builder();
ctor public VolumeShaper.Configuration.Builder(android.media.VolumeShaper.Configuration);
method public android.media.VolumeShaper.Configuration build();
method public android.media.VolumeShaper.Configuration.Builder invertVolumes();
method public android.media.VolumeShaper.Configuration.Builder reflectTimes();
method public android.media.VolumeShaper.Configuration.Builder scaleToEndVolume(float);
method public android.media.VolumeShaper.Configuration.Builder scaleToStartVolume(float);
method public android.media.VolumeShaper.Configuration.Builder setCurve(float[], float[]);
method public android.media.VolumeShaper.Configuration.Builder setDurationMs(double);
method public android.media.VolumeShaper.Configuration.Builder setInterpolatorType(int);
}
public static final class VolumeShaper.Operation implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.media.VolumeShaper.Operation> CREATOR;
field public static final android.media.VolumeShaper.Operation PLAY;
field public static final android.media.VolumeShaper.Operation REVERSE;
}
}
package android.media.audiofx {

View File

@@ -79,6 +79,7 @@ import com.android.internal.annotations.GuardedBy;
*/
public class AudioTrack extends PlayerBase
implements AudioRouting
, VolumeAutomation
{
//---------------------------------------------------------
// Constants
@@ -1753,6 +1754,12 @@ public class AudioTrack extends PlayerBase
return native_getVolumeShaperState(id);
}
@Override
public @NonNull VolumeShaper createVolumeShaper(
@NonNull VolumeShaper.Configuration configuration) {
return new VolumeShaper(configuration, this);
}
/**
* Sets the playback sample rate for this track. This sets the sampling rate at which
* the audio data will be consumed and played back

View File

@@ -579,6 +579,7 @@ import java.util.Vector;
*/
public class MediaPlayer extends PlayerBase
implements SubtitleController.Listener
, VolumeAutomation
{
/**
Constant to retrieve only the new metadata since the last
@@ -1373,6 +1374,12 @@ public class MediaPlayer extends PlayerBase
return native_getVolumeShaperState(id);
}
@Override
public @NonNull VolumeShaper createVolumeShaper(
@NonNull VolumeShaper.Configuration configuration) {
return new VolumeShaper(configuration, this);
}
private native int native_applyVolumeShaper(
@NonNull VolumeShaper.Configuration configuration,
@NonNull VolumeShaper.Operation operation);

View File

@@ -0,0 +1,40 @@
/*
* Copyright 2017 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 android.media;
import android.annotation.NonNull;
import android.media.VolumeShaper.Configuration;
/**
* {@code VolumeAutomation} defines an interface for automatic volume control
* of {@link AudioTrack} and {@link MediaPlayer} objects.
*/
public interface VolumeAutomation {
/**
* Returns a {@link VolumeShaper} object that can be used modify the volume envelope
* of the player or track.
*
* @param configuration the {@link VolumeShaper.Configuration configuration}
* that specifies the curve and duration to use.
* @return a {@code VolumeShaper} object
* @throws IllegalArgumentException if the configuration is not allowed by the player.
* @throws IllegalStateException if too many VolumeShapers are requested or the state of
* the player does not permit its creation (e.g. player is released).
*/
public @NonNull VolumeShaper createVolumeShaper(
@NonNull VolumeShaper.Configuration configuration);
}

View File

@@ -23,44 +23,22 @@ import android.os.Parcelable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.AutoCloseable;
import java.lang.ref.WeakReference;
import java.util.Objects;
/**
* TODO: remove @hide
* The {@code VolumeShaper} class is used to automatically control audio volume during media
* playback, allowing for simple implementation of transition effects and ducking.
* playback, allowing simple implementation of transition effects and ducking.
*
* The {@link VolumeShaper} appears as an additional scaling on the audio output,
* and can be used independently of track or stream volume controls.
* and adjusts independently of track or stream volume controls.
*/
public final class VolumeShaper {
public final class VolumeShaper implements AutoCloseable {
/* member variables */
private int mId;
private final WeakReference<PlayerBase> mWeakPlayerBase;
/**
* Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and an
* {@link AudioTrack}.
*
* @param configuration
* @param audioTrack
*/
public VolumeShaper(@NonNull Configuration configuration, @NonNull AudioTrack audioTrack) {
this(configuration, (PlayerBase)audioTrack);
}
/**
* Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and a
* {@link MediaPlayer}.
*
* @param configuration
* @param mediaPlayer
*/
public VolumeShaper(@NonNull Configuration configuration, @NonNull MediaPlayer mediaPlayer) {
this(configuration, (PlayerBase)mediaPlayer);
}
/* package */ VolumeShaper(
@NonNull Configuration configuration, @NonNull PlayerBase playerBase) {
mWeakPlayerBase = new WeakReference<PlayerBase>(playerBase);
@@ -73,7 +51,7 @@ public final class VolumeShaper {
/**
* Applies the {@link VolumeShaper.Operation} to the {@code VolumeShaper}.
* @param operation
* @param operation the {@code operation} to apply.
*/
public void apply(@NonNull Operation operation) {
/* void */ applyPlayer(new VolumeShaper.Configuration(mId), operation);
@@ -81,17 +59,16 @@ public final class VolumeShaper {
/**
* Replaces the current {@code VolumeShaper}
* configuration with a new configuration.
* {@code configuration} with a new {@code configuration}.
*
* This can be used to dynamically change the {@code VolumeShaper}
* configuration by joining several
* {@code VolumeShaper} configurations together.
* This is useful if the user changes the volume while the
* {@code VolumeShaper} is in effect.
* This allows the user to change the volume shape
* while the existing {@code VolumeShaper} is in effect.
*
* @param configuration
* @param operation
* @param join
* @param configuration the new {@code configuration} to use.
* @param operation the operation to apply to the {@code VolumeShaper}
* @param join if true, match the start volume of the
* new {@code configuration} to the current volume of the existing
* {@code VolumeShaper}, to avoid discontinuity.
*/
public void replace(
@NonNull Configuration configuration, @NonNull Operation operation, boolean join) {
@@ -110,10 +87,11 @@ public final class VolumeShaper {
}
/**
* Releases the {@code VolumeShaper}. Any volume scale due to the
* Releases the {@code VolumeShaper} object; any volume scale due to the
* {@code VolumeShaper} is removed.
*/
public void release() {
@Override
public void close() {
try {
/* void */ applyPlayer(
new VolumeShaper.Configuration(mId),
@@ -128,7 +106,7 @@ public final class VolumeShaper {
@Override
protected void finalize() {
release(); // ensure we remove the native volume shaper
close(); // ensure we remove the native volume shaper
}
/**
@@ -188,11 +166,17 @@ public final class VolumeShaper {
}
/**
* The {@code VolumeShaper.Configuration} class contains curve shape
* and parameter information for constructing a {@code VolumeShaper}.
* This curve shape and parameter information is specified
* on {@code VolumeShaper} creation
* and may be replaced through {@link VolumeShaper#replace}.
* The {@code VolumeShaper.Configuration} class contains curve
* and duration information.
* It is constructed by the {@link VolumeShaper.Configuration.Builder}.
* <p>
* A {@code VolumeShaper.Configuration} is used by
* {@link VolumeAutomation#createVolumeShaper(Configuration)
* VolumeAutomation#createVolumeShaper(Configuration)} to create
* a {@code VolumeShaper} and
* by {@link VolumeShaper#replace(Configuration, Operation, boolean)
* VolumeShaper#replace(Configuration, Operation, boolean)}
* to replace an existing {@code configuration}.
*/
public static final class Configuration implements Parcelable {
private static final int MAXIMUM_CURVE_POINTS = 16;
@@ -260,9 +244,9 @@ public final class VolumeShaper {
/**
* Cubic interpolated volume curve
* with local monotonicity preservation.
* that preserves local monotonicity.
* So long as the control points are locally monotonic,
* the curve interpolation will also be locally monotonic.
* the curve interpolation between those points are monotonic.
* This is useful for cubic spline interpolated
* volume ramps and ducks.
*/
@@ -278,6 +262,7 @@ public final class VolumeShaper {
public @interface OptionFlag {}
/**
* @hide
* Use a dB full scale volume range for the volume curve.
*<p>
* The volume scale is typically from 0.f to 1.f on a linear scale;
@@ -287,6 +272,7 @@ public final class VolumeShaper {
public static final int OPTION_FLAG_VOLUME_IN_DBFS = (1 << 0);
/**
* @hide
* Use clock time instead of media time.
*<p>
* The default implementation of {@code VolumeShaper} is to apply
@@ -304,7 +290,8 @@ public final class VolumeShaper {
/**
* A one second linear ramp from silence to full volume.
* Use {@link VolumeShaper.Builder#reflectTimes()} to generate
* Use {@link VolumeShaper.Builder#reflectTimes()}
* or {@link VolumeShaper.Builder#invertVolumes()} to generate
* the matching linear duck.
*/
public static final Configuration LINEAR_RAMP = new VolumeShaper.Configuration.Builder()
@@ -316,7 +303,8 @@ public final class VolumeShaper {
/**
* A one second cubic ramp from silence to full volume.
* Use {@link VolumeShaper.Builder#reflectTimes()} to generate
* Use {@link VolumeShaper.Builder#reflectTimes()}
* or {@link VolumeShaper.Builder#invertVolumes()} to generate
* the matching cubic duck.
*/
public static final Configuration CUBIC_RAMP = new VolumeShaper.Configuration.Builder()
@@ -327,17 +315,19 @@ public final class VolumeShaper {
.build();
/**
* A one second sine curve for energy preserving cross fades.
* A one second sine curve
* from silence to full volume for energy preserving cross fades.
* Use {@link VolumeShaper.Builder#reflectTimes()} to generate
* the matching cosine duck.
*/
public static final Configuration SINE_RAMP;
/**
* A one second sine-squared s-curve ramp.
* A one second sine-squared s-curve ramp
* from silence to full volume.
* Use {@link VolumeShaper.Builder#reflectTimes()}
* or {@link VolumeShaper.Builder#invertVolumes()} to generate
* the matching s-curve duck.
* the matching sine-squared s-curve duck.
*/
public static final Configuration SCURVE_RAMP;
@@ -508,6 +498,7 @@ public final class VolumeShaper {
}
/**
* @hide
* Returns the {@code VolumeShaper} type.
*/
public @Type int getType() {
@@ -530,6 +521,7 @@ public final class VolumeShaper {
}
/**
* @hide
* Returns the option flags
*/
public @OptionFlag int getOptionFlags() {
@@ -541,7 +533,7 @@ public final class VolumeShaper {
}
/**
* Returns the duration of the effect in milliseconds.
* Returns the duration of the volume shape in milliseconds.
*/
public double getDurationMs() {
return mDurationMs;
@@ -663,21 +655,22 @@ public final class VolumeShaper {
private int mType = TYPE_SCALE;
private int mId = -1; // invalid
private int mInterpolatorType = INTERPOLATOR_TYPE_CUBIC;
private int mOptionFlags = 0;
private int mOptionFlags = OPTION_FLAG_CLOCK_TIME;
private double mDurationMs = 1000.;
private float[] mTimes = null;
private float[] mVolumes = null;
/**
* Constructs a new Builder with the defaults.
* Constructs a new {@code Builder} with the defaults.
*/
public Builder() {
}
/**
* Constructs a new Builder from a given {@code VolumeShaper.Configuration}
* Constructs a new {@code Builder} with settings
* copied from a given {@code VolumeShaper.Configuration}.
* @param configuration prototypical configuration
* which will be reused in the new Builder.
* which will be reused in the new {@code Builder}.
*/
public Builder(@NonNull Configuration configuration) {
mType = configuration.getType();
@@ -691,8 +684,6 @@ public final class VolumeShaper {
/**
* @hide
* TODO make SystemApi
*
* Set the id for system defined shapers.
* @param id
* @return
@@ -708,7 +699,11 @@ public final class VolumeShaper {
* If omitted the interplator type is {@link #INTERPOLATOR_TYPE_CUBIC}.
*
* @param interpolatorType method of interpolation used for the volume curve.
* @return the same Builder instance.
* One of {@link #INTERPOLATOR_TYPE_STEP},
* {@link #INTERPOLATOR_TYPE_LINEAR},
* {@link #INTERPOLATOR_TYPE_CUBIC},
* {@link #INTERPOLATOR_TYPE_CUBIC_MONOTONIC}.
* @return the same {@code Builder} instance.
* @throws IllegalArgumentException if {@code interpolatorType} is not valid.
*/
public @NonNull Builder setInterpolatorType(@InterpolatorType int interpolatorType) {
@@ -727,6 +722,7 @@ public final class VolumeShaper {
}
/**
* @hide
* Sets the optional flags
*
* If omitted, flags are 0. If {@link #OPTION_FLAG_VOLUME_IN_DBFS} has
@@ -734,7 +730,7 @@ public final class VolumeShaper {
* volume domain has changed.
*
* @param optionFlags new value to replace the old {@code optionFlags}.
* @return the same Builder instance.
* @return the same {@code Builder} instance.
* @throws IllegalArgumentException if flag is not recognized.
*/
public @NonNull Builder setOptionFlags(@OptionFlag int optionFlags) {
@@ -751,8 +747,9 @@ public final class VolumeShaper {
* If omitted, the default duration is 1 second.
*
* @param durationMs
* @return the same Builder instance.
* @throws IllegalArgumentException if duration is not positive.
* @return the same {@code Builder} instance.
* @throws IllegalArgumentException if {@code durationMs}
* is not strictly positive.
*/
public @NonNull Builder setDurationMs(double durationMs) {
if (durationMs <= 0.) {
@@ -774,19 +771,23 @@ public final class VolumeShaper {
* and no greater than {@link VolumeShaper.Configuration#getMaximumCurvePoints()}.
* <p>
* The volume curve is normalized as follows:
* (1) time (x) coordinates should be monotonically increasing, from 0.f to 1.f;
* (2) volume (y) coordinates must be within 0.f to 1.f for linear and be non-positive
* for log scaling.
* time (x) coordinates should be monotonically increasing, from 0.f to 1.f;
* volume (y) coordinates must be within 0.f to 1.f.
* <p>
* The time scale is set by {@link #setDurationMs} in seconds.
* The time scale is set by {@link #setDurationMs}.
* <p>
* @param times an array of float values representing
* the time line of the volume curve.
* @param volumes an array of float values representing
* the amplitude of the volume curve.
* @return the same Builder instance.
* @return the same {@code Builder} instance.
* @throws IllegalArgumentException if {@code times} or {@code volumes} is invalid.
*/
/* Note: volume (y) coordinates must be non-positive for log scaling,
* if {@link VolumeShaper.Configuration#OPTION_FLAG_VOLUME_IN_DBFS} is set.
*/
public @NonNull Builder setCurve(@NonNull float[] times, @NonNull float[] volumes) {
String error = checkCurveForErrors(
times, volumes, (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0);
@@ -803,7 +804,7 @@ public final class VolumeShaper {
* the shaper changes volume from the end
* to the start.
*
* @return the same Builder instance.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder reflectTimes() {
int i;
@@ -822,7 +823,7 @@ public final class VolumeShaper {
* Inverts the volume curve so that the max volume
* becomes the min volume and vice versa.
*
* @return the same Builder instance.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder invertVolumes() {
if (mVolumes.length >= 2) {
@@ -850,8 +851,9 @@ public final class VolumeShaper {
* Keeps the start volume the same.
* This works best if the volume curve is monotonic.
*
* @return the same Builder instance.
* @throws IllegalArgumentException if volume is not valid.
* @param volume the target end volume to use.
* @return the same {@code Builder} instance.
* @throws IllegalArgumentException if {@code volume} is not valid.
*/
public @NonNull Builder scaleToEndVolume(float volume) {
final boolean log = (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0;
@@ -881,8 +883,9 @@ public final class VolumeShaper {
* Keeps the end volume the same.
* This works best if the volume curve is monotonic.
*
* @return the same Builder instance.
* @throws IllegalArgumentException if volume is not valid.
* @param volume the target start volume to use.
* @return the same {@code Builder} instance.
* @throws IllegalArgumentException if {@code volume} is not valid.
*/
public @NonNull Builder scaleToStartVolume(float volume) {
final boolean log = (mOptionFlags & OPTION_FLAG_VOLUME_IN_DBFS) != 0;
@@ -929,6 +932,8 @@ public final class VolumeShaper {
public static final class Operation implements Parcelable {
/**
* Forward playback from current volume time position.
* At the end of the {@code VolumeShaper} curve,
* the last volume value persists.
*/
public static final Operation PLAY =
new VolumeShaper.Operation.Builder()
@@ -936,6 +941,8 @@ public final class VolumeShaper {
/**
* Reverse playback from current volume time position.
* When the position reaches the start of the {@code VolumeShaper} curve,
* the first volume value persists.
*/
public static final Operation REVERSE =
new VolumeShaper.Operation.Builder()
@@ -1084,15 +1091,13 @@ public final class VolumeShaper {
}
/**
* Replaces the previous {@code VolumeShaper}.
* Replaces the previous {@code VolumeShaper} specified by id.
* It has no other effect if the {@code VolumeShaper} is
* already expired. If the replaceId is the same as the id associated with
* the {@code VolumeShaper} in a {@code setVolumeShaper()} call,
* an error is returned.
* @param handle is a previous volumeShaper {@code VolumeShaper}.
* @param join the start to match the current volume of the previous
* shaper.
* @return the same Builder instance.
* already expired.
* @param id the id of the previous {@code VolumeShaper}.
* @param join if true, match the volume of the previous
* shaper to the start volume of the new {@code VolumeShaper}.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder replace(int id, boolean join) {
mReplaceId = id;
@@ -1106,7 +1111,7 @@ public final class VolumeShaper {
/**
* Defers all operations.
* @return the same Builder instance.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder defer() {
mFlags |= FLAG_DEFER;
@@ -1116,7 +1121,7 @@ public final class VolumeShaper {
/**
* Terminates the VolumeShaper.
* Do not call directly, use {@link VolumeShaper#release()}.
* @return the same Builder instance.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder terminate() {
mFlags |= FLAG_TERMINATE;
@@ -1125,7 +1130,7 @@ public final class VolumeShaper {
/**
* Reverses direction.
* @return the same Builder instance.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder reverse() {
mFlags ^= FLAG_REVERSE;
@@ -1136,7 +1141,7 @@ public final class VolumeShaper {
* Use the id specified in the configuration, creating
* VolumeShaper as needed; the configuration should be
* TYPE_SCALE.
* @return the same Builder instance.
* @return the same {@code Builder} instance.
*/
public @NonNull Builder createIfNeeded() {
mFlags |= FLAG_CREATE_IF_NEEDED;
@@ -1148,7 +1153,7 @@ public final class VolumeShaper {
* other builder methods.
*
* @param flags new value for {@code flags}, consisting of ORed flags.
* @return the same Builder instance.
* @return the same {@code Builder} instance.
*/
private @NonNull Builder setFlags(@Flag int flags) {
if ((flags & ~FLAG_PUBLIC_ALL) != 0) {