Merge changes I21b77905,Ia98ec539
* changes: VolumeShaper: Use VolumeAutomation interface and unhide VolumeShaper: Remove PlayerProxy constructor
This commit is contained in:
@@ -20999,13 +20999,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();
|
||||
@@ -22346,7 +22347,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;
|
||||
@@ -22358,6 +22359,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();
|
||||
@@ -23185,6 +23187,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();
|
||||
@@ -23198,6 +23204,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 {
|
||||
|
||||
@@ -22687,13 +22687,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();
|
||||
@@ -24034,7 +24035,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;
|
||||
@@ -24046,6 +24047,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();
|
||||
@@ -24884,6 +24886,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();
|
||||
@@ -24897,6 +24903,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 {
|
||||
|
||||
@@ -21095,13 +21095,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();
|
||||
@@ -22442,7 +22443,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;
|
||||
@@ -22454,6 +22455,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();
|
||||
@@ -23281,6 +23283,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();
|
||||
@@ -23294,6 +23300,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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
40
media/java/android/media/VolumeAutomation.java
Normal file
40
media/java/android/media/VolumeAutomation.java
Normal 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);
|
||||
}
|
||||
@@ -23,78 +23,25 @@ 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;
|
||||
private final WeakReference<PlayerProxy> mWeakPlayerProxy;
|
||||
private PlayerProxy mPlayerProxy;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
mPlayerProxy = null;
|
||||
mWeakPlayerProxy = null;
|
||||
mId = applyPlayer(configuration, new Operation.Builder().defer().build());
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Constructs a {@code VolumeShaper} from a {@link VolumeShaper.Configuration} and a
|
||||
* {@code PlayerProxy} object. The PlayerProxy object requires that the configuration
|
||||
* be set with a system VolumeShaper id (this is a reserved value).
|
||||
*
|
||||
* @param configuration
|
||||
* @param playerProxy
|
||||
*/
|
||||
public VolumeShaper(
|
||||
@NonNull Configuration configuration,
|
||||
@NonNull PlayerProxy playerProxy,
|
||||
boolean keepReference) {
|
||||
if (configuration.getId() < 0) {
|
||||
throw new IllegalArgumentException("playerProxy configuration id must be specified");
|
||||
}
|
||||
if (keepReference) {
|
||||
mPlayerProxy = playerProxy;
|
||||
mWeakPlayerProxy = null;
|
||||
} else {
|
||||
mWeakPlayerProxy = new WeakReference<PlayerProxy>(playerProxy);
|
||||
mPlayerProxy = null;
|
||||
}
|
||||
mWeakPlayerBase = null;
|
||||
mId = applyPlayer(configuration, new Operation.Builder().defer().build());
|
||||
}
|
||||
|
||||
@@ -104,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);
|
||||
@@ -112,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) {
|
||||
@@ -141,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),
|
||||
@@ -155,15 +102,11 @@ public final class VolumeShaper {
|
||||
if (mWeakPlayerBase != null) {
|
||||
mWeakPlayerBase.clear();
|
||||
}
|
||||
if (mWeakPlayerProxy != null) {
|
||||
mWeakPlayerProxy.clear();
|
||||
}
|
||||
mPlayerProxy = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() {
|
||||
release(); // ensure we remove the native volume shaper
|
||||
close(); // ensure we remove the native volume shaper
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,20 +120,7 @@ public final class VolumeShaper {
|
||||
@NonNull VolumeShaper.Configuration configuration,
|
||||
@NonNull VolumeShaper.Operation operation) {
|
||||
final int id;
|
||||
if (mPlayerProxy != null || mWeakPlayerProxy != null) {
|
||||
// The PlayerProxy accepts only one way transactions so
|
||||
// the Configuration must have an id set to one of the system
|
||||
// ids (a positive value less than 16).
|
||||
PlayerProxy player = mWeakPlayerProxy != null ? mWeakPlayerProxy.get() : mPlayerProxy;
|
||||
if (player == null) {
|
||||
throw new IllegalStateException("player deallocated");
|
||||
}
|
||||
id = configuration.getId();
|
||||
if (id < 0) {
|
||||
throw new IllegalArgumentException("proxy requires configuration with id");
|
||||
}
|
||||
player.applyVolumeShaper(configuration, operation);
|
||||
} else if (mWeakPlayerBase != null) {
|
||||
if (mWeakPlayerBase != null) {
|
||||
PlayerBase player = mWeakPlayerBase.get();
|
||||
if (player == null) {
|
||||
throw new IllegalStateException("player deallocated");
|
||||
@@ -220,9 +150,7 @@ public final class VolumeShaper {
|
||||
*/
|
||||
private @NonNull VolumeShaper.State getStatePlayer(int id) {
|
||||
final VolumeShaper.State state;
|
||||
if (mPlayerProxy != null || mWeakPlayerProxy != null) {
|
||||
throw new IllegalStateException("getStatePlayer not permitted through proxy");
|
||||
} else if (mWeakPlayerBase != null) {
|
||||
if (mWeakPlayerBase != null) {
|
||||
PlayerBase player = mWeakPlayerBase.get();
|
||||
if (player == null) {
|
||||
throw new IllegalStateException("player deallocated");
|
||||
@@ -238,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;
|
||||
@@ -310,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.
|
||||
*/
|
||||
@@ -328,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;
|
||||
@@ -337,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
|
||||
@@ -354,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()
|
||||
@@ -366,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()
|
||||
@@ -377,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;
|
||||
|
||||
@@ -510,6 +450,7 @@ public final class VolumeShaper {
|
||||
};
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Constructs a volume shaper from an id.
|
||||
*
|
||||
* This is an opaque handle for controlling a {@code VolumeShaper} that has
|
||||
@@ -522,7 +463,7 @@ public final class VolumeShaper {
|
||||
* @param id
|
||||
* @throws IllegalArgumentException if id is negative.
|
||||
*/
|
||||
private Configuration(int id) {
|
||||
public Configuration(int id) {
|
||||
if (id < 0) {
|
||||
throw new IllegalArgumentException("negative id " + id);
|
||||
}
|
||||
@@ -557,6 +498,7 @@ public final class VolumeShaper {
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns the {@code VolumeShaper} type.
|
||||
*/
|
||||
public @Type int getType() {
|
||||
@@ -579,6 +521,7 @@ public final class VolumeShaper {
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* Returns the option flags
|
||||
*/
|
||||
public @OptionFlag int getOptionFlags() {
|
||||
@@ -590,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;
|
||||
@@ -712,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();
|
||||
@@ -740,8 +684,6 @@ public final class VolumeShaper {
|
||||
|
||||
/**
|
||||
* @hide
|
||||
* TODO make SystemApi
|
||||
*
|
||||
* Set the id for system defined shapers.
|
||||
* @param id
|
||||
* @return
|
||||
@@ -757,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) {
|
||||
@@ -776,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
|
||||
@@ -783,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) {
|
||||
@@ -800,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.) {
|
||||
@@ -823,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);
|
||||
@@ -852,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;
|
||||
@@ -871,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) {
|
||||
@@ -899,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;
|
||||
@@ -930,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;
|
||||
@@ -978,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()
|
||||
@@ -985,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()
|
||||
@@ -1039,6 +997,13 @@ public final class VolumeShaper {
|
||||
*/
|
||||
private static final int FLAG_DEFER = 1 << 3;
|
||||
|
||||
/**
|
||||
* Use the id specified in the configuration, creating
|
||||
* VolumeShaper as needed; the configuration should be
|
||||
* TYPE_SCALE.
|
||||
*/
|
||||
private static final int FLAG_CREATE_IF_NEEDED = 1 << 4;
|
||||
|
||||
private static final int FLAG_PUBLIC_ALL = FLAG_REVERSE | FLAG_TERMINATE;
|
||||
|
||||
private final int mFlags;
|
||||
@@ -1126,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;
|
||||
@@ -1148,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;
|
||||
@@ -1158,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;
|
||||
@@ -1167,19 +1130,30 @@ public final class VolumeShaper {
|
||||
|
||||
/**
|
||||
* Reverses direction.
|
||||
* @return the same Builder instance.
|
||||
* @return the same {@code Builder} instance.
|
||||
*/
|
||||
public @NonNull Builder reverse() {
|
||||
mFlags ^= FLAG_REVERSE;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the id specified in the configuration, creating
|
||||
* VolumeShaper as needed; the configuration should be
|
||||
* TYPE_SCALE.
|
||||
* @return the same {@code Builder} instance.
|
||||
*/
|
||||
public @NonNull Builder createIfNeeded() {
|
||||
mFlags |= FLAG_CREATE_IF_NEEDED;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the operation flag. Do not call this directly but one of the
|
||||
* 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) {
|
||||
|
||||
@@ -51,14 +51,36 @@ public final class PlaybackActivityMonitor
|
||||
private final static boolean DEBUG = false;
|
||||
private final static int VOLUME_SHAPER_SYSTEM_DUCK_ID = 1;
|
||||
|
||||
private ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
|
||||
private final VolumeShaper.Configuration DUCK_VSHAPE =
|
||||
new VolumeShaper.Configuration.Builder()
|
||||
.setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
|
||||
.setCurve(new float[] { 0.f, 1.f } /* times */,
|
||||
new float[] { 1.f, 0.2f } /* volumes */)
|
||||
.setOptionFlags(VolumeShaper.Configuration.OPTION_FLAG_CLOCK_TIME)
|
||||
.setDurationMs(MediaFocusControl.getFocusRampTimeMs(
|
||||
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
|
||||
new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
||||
.build()))
|
||||
.build();
|
||||
private final VolumeShaper.Configuration DUCK_ID =
|
||||
new VolumeShaper.Configuration(VOLUME_SHAPER_SYSTEM_DUCK_ID);
|
||||
private final VolumeShaper.Operation PLAY_CREATE_IF_NEEDED =
|
||||
new VolumeShaper.Operation.Builder(VolumeShaper.Operation.PLAY)
|
||||
.createIfNeeded()
|
||||
.build();
|
||||
private final VolumeShaper.Operation TERMINATE =
|
||||
new VolumeShaper.Operation.Builder()
|
||||
.terminate()
|
||||
.build();
|
||||
|
||||
private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
|
||||
// a public client is one that needs an anonymized version of the playback configurations, we
|
||||
// keep track of whether there is at least one to know when we need to create the list of
|
||||
// playback configurations that do not contain uid/pid/package name information.
|
||||
private boolean mHasPublicClients = false;
|
||||
|
||||
private final Object mPlayerLock = new Object();
|
||||
private HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
|
||||
private final HashMap<Integer, AudioPlaybackConfiguration> mPlayers =
|
||||
new HashMap<Integer, AudioPlaybackConfiguration>();
|
||||
|
||||
PlaybackActivityMonitor() {
|
||||
@@ -130,12 +152,10 @@ public final class PlaybackActivityMonitor
|
||||
synchronized(mPlayerLock) {
|
||||
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
|
||||
if (checkConfigurationCaller(piid, apc, binderUid)) {
|
||||
apc.getPlayerProxy().applyVolumeShaper(
|
||||
DUCK_ID,
|
||||
TERMINATE);
|
||||
mPlayers.remove(new Integer(piid));
|
||||
final VolumeShaper vs = mDuckVolumeShapers.get(new Integer(piid));
|
||||
if (vs != null) {
|
||||
vs.release();
|
||||
mDuckVolumeShapers.remove(new Integer(piid));
|
||||
}
|
||||
} else {
|
||||
Log.e(TAG, "Error releasing player " + piid);
|
||||
}
|
||||
@@ -252,20 +272,6 @@ public final class PlaybackActivityMonitor
|
||||
private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
|
||||
private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
|
||||
|
||||
private final VolumeShaper.Configuration DUCK_VSHAPE =
|
||||
new VolumeShaper.Configuration.Builder()
|
||||
.setId(VOLUME_SHAPER_SYSTEM_DUCK_ID)
|
||||
.setCurve(new float[] { 0.f, 1.f } /* times */,
|
||||
new float[] { 1.f, 0.2f } /* volumes */)
|
||||
.setDurationMs(MediaFocusControl.getFocusRampTimeMs(
|
||||
AudioManager.AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK,
|
||||
new AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
||||
.build()))
|
||||
.build();
|
||||
|
||||
private final HashMap<Integer, VolumeShaper> mDuckVolumeShapers =
|
||||
new HashMap<Integer, VolumeShaper>();
|
||||
|
||||
@Override
|
||||
public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
|
||||
if (DEBUG) {
|
||||
@@ -302,17 +308,9 @@ public final class PlaybackActivityMonitor
|
||||
} else {
|
||||
try {
|
||||
if (DEBUG) { Log.v(TAG, "ducking player " + piid); }
|
||||
final VolumeShaper ducker;
|
||||
if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
|
||||
ducker = mDuckVolumeShapers.get(new Integer(piid));
|
||||
} else {
|
||||
ducker = new VolumeShaper(
|
||||
DUCK_VSHAPE,
|
||||
apc.getPlayerProxy(),
|
||||
true /* keepReference */);
|
||||
mDuckVolumeShapers.put(new Integer(piid), ducker);
|
||||
}
|
||||
ducker.apply(VolumeShaper.Operation.PLAY); // duck
|
||||
apc.getPlayerProxy().applyVolumeShaper(
|
||||
DUCK_VSHAPE,
|
||||
PLAY_CREATE_IF_NEEDED);
|
||||
mDuckedPlayers.add(piid);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error ducking player " + piid, e);
|
||||
@@ -341,10 +339,9 @@ public final class PlaybackActivityMonitor
|
||||
try {
|
||||
if (DEBUG) { Log.v(TAG, "unducking player" + piid); }
|
||||
mDuckedPlayers.remove(new Integer(piid));
|
||||
if (mDuckVolumeShapers.containsKey(new Integer(piid))) {
|
||||
final VolumeShaper ducker = mDuckVolumeShapers.get(new Integer(piid));
|
||||
ducker.apply(VolumeShaper.Operation.REVERSE); // unduck
|
||||
}
|
||||
apc.getPlayerProxy().applyVolumeShaper(
|
||||
DUCK_ID,
|
||||
VolumeShaper.Operation.REVERSE);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error unducking player " + piid, e);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user