diff --git a/api/current.txt b/api/current.txt index c754f10329273..d55fb7c0f36d4 100644 --- a/api/current.txt +++ b/api/current.txt @@ -27905,6 +27905,7 @@ package android.media.audiofx { field public static final java.util.UUID EFFECT_TYPE_DYNAMICS_PROCESSING; field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB; field public static final java.util.UUID EFFECT_TYPE_EQUALIZER; + field @NonNull public static final java.util.UUID EFFECT_TYPE_HAPTIC_GENERATOR; field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER; field public static final java.util.UUID EFFECT_TYPE_NS; field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB; @@ -28257,6 +28258,13 @@ package android.media.audiofx { field public short numBands; } + public class HapticGenerator extends android.media.audiofx.AudioEffect implements java.lang.AutoCloseable { + method public void close(); + method @NonNull public static android.media.audiofx.HapticGenerator create(int); + method public static boolean isAvailable(); + method public int setEnabled(boolean); + } + public class LoudnessEnhancer extends android.media.audiofx.AudioEffect { ctor public LoudnessEnhancer(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.RuntimeException, java.lang.UnsupportedOperationException; method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException; diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 42635216e98f3..f4fd1fca2ff9f 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -53,6 +53,7 @@ import java.util.UUID; *
To apply the audio effect to a specific AudioTrack or MediaPlayer instance, * the application must specify the audio session ID of that instance when creating the AudioEffect. @@ -145,6 +146,14 @@ public class AudioEffect { public static final UUID EFFECT_TYPE_DYNAMICS_PROCESSING = UUID .fromString("7261676f-6d75-7369-6364-28e2fd3ac39e"); + /** + * UUID for Haptic Generator. + */ + // This is taken from system/media/audio/include/system/audio_effects/effect_hapticgenerator.h + @NonNull + public static final UUID EFFECT_TYPE_HAPTIC_GENERATOR = UUID + .fromString("1411e6d6-aecd-4021-a1cf-a6aceb0d71e5"); + /** * Null effect UUID. See {@link AudioEffect(UUID, UUID, int, int)} for use. * @hide @@ -225,7 +234,8 @@ public class AudioEffect { * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, - * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}. + * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}, + * {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}. * *
HG is an audio post-processor which generates haptic data based on the audio channels. The + * generated haptic data is sent along with audio data down to the audio HAL, which will require the + * device to support audio-coupled-haptic playback. In that case, the effect will only be created on + * device supporting audio-coupled-haptic playback. Call {@link HapticGenerator#isAvailable()} to + * check if the device supports this effect. + *
An application can create a HapticGenerator object to initiate and control this audio effect + * in the audio framework. An application can set which audio channel to be used to generate + * haptic data. + *
To attach the HapticGenerator to a particular AudioTrack or MediaPlayer, specify the audio + * session ID of this AudioTrack or MediaPlayer when constructing the HapticGenerator. + *
See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. + *
See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio + * effects. + */ +public class HapticGenerator extends AudioEffect implements AutoCloseable { + + private static final String TAG = "HapticGenerator"; + + // For every HapticGenerator, it contains a volume control effect so that the volume control + // will always be handled in the effect chain. In that case, the HapticGenerator can generate + // haptic data based on the raw audio data. + private AudioEffect mVolumeControlEffect; + + public static boolean isAvailable() { + return AudioManager.isHapticPlaybackSupported() + && AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_HAPTIC_GENERATOR); + } + + /** + * Creates a HapticGenerator and attaches it to the given audio session. + * Use {@link android.media.AudioTrack#getAudioSessionId()} or + * {@link android.media.MediaPlayer#getAudioSessionId()} to + * apply this effect on specific AudioTrack or MediaPlayer instance. + * + * @param audioSession system wide unique audio session identifier. The HapticGenerator will be + * applied to the players with the same audio session. + * @return HapticGenerator created or null if the device does not support HapticGenerator or + * the audio session is invalid. + * @throws java.lang.IllegalArgumentException when HapticGenerator is not supported + * @throws java.lang.UnsupportedOperationException when the effect library is not loaded. + * @throws java.lang.RuntimeException for all other error + */ + public static @NonNull HapticGenerator create(int audioSession) { + return new HapticGenerator(audioSession); + } + + /** + * Class constructor. + * + * @param audioSession system wide unique audio session identifier. The HapticGenerator will be + * attached to the MediaPlayer or AudioTrack in the same audio session. + * @throws java.lang.IllegalArgumentException + * @throws java.lang.UnsupportedOperationException + * @throws java.lang.RuntimeException + */ + private HapticGenerator(int audioSession) { + super(EFFECT_TYPE_HAPTIC_GENERATOR, EFFECT_TYPE_NULL, 0, audioSession); + mVolumeControlEffect = new AudioEffect( + AudioEffect.EFFECT_TYPE_NULL, + UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"), + 0, + audioSession); + } + + /** + * Enable or disable the effect. + * + * @param enabled the requested enable state + * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION} + * or {@link #ERROR_DEAD_OBJECT} in case of failure. + */ + @Override + public int setEnabled(boolean enabled) { + int ret = super.setEnabled(enabled); + if (ret == SUCCESS) { + if (mVolumeControlEffect == null + || mVolumeControlEffect.setEnabled(enabled) != SUCCESS) { + Log.w(TAG, "Failed to enable volume control effect for HapticGenerator"); + } + } + return ret; + } + + /** + * Releases the native AudioEffect resources. + */ + @Override + public void release() { + if (mVolumeControlEffect != null) { + mVolumeControlEffect.release(); + } + super.release(); + } + + /** + * Release the resources that are held by the effect. + */ + @Override + public void close() { + release(); + } +} diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index 34f16f83460da..fbb1afcd307e3 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -27666,6 +27666,7 @@ package android.media.audiofx { field public static final java.util.UUID EFFECT_TYPE_DYNAMICS_PROCESSING; field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB; field public static final java.util.UUID EFFECT_TYPE_EQUALIZER; + field @NonNull public static final java.util.UUID EFFECT_TYPE_HAPTIC_GENERATOR; field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER; field public static final java.util.UUID EFFECT_TYPE_NS; field public static final java.util.UUID EFFECT_TYPE_PRESET_REVERB; @@ -28018,6 +28019,13 @@ package android.media.audiofx { field public short numBands; } + public class HapticGenerator extends android.media.audiofx.AudioEffect implements java.lang.AutoCloseable { + method public void close(); + method @NonNull public static android.media.audiofx.HapticGenerator create(int); + method public static boolean isAvailable(); + method public int setEnabled(boolean); + } + public class LoudnessEnhancer extends android.media.audiofx.AudioEffect { ctor public LoudnessEnhancer(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.RuntimeException, java.lang.UnsupportedOperationException; method public float getTargetGain() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException;