Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2ea6a26b authored by jiabin's avatar jiabin Committed by Jean-Michel Trivi
Browse files

Add HapticGenerator.

Add HapticGenertor, which is an audio effect that can generate haptic
data from audio data.

Bug: 136490803
Test: atest HapticGeneratorTest
Change-Id: Ib677f0ad82ae4a164546300c7a86760cdb6a52b4
parent 05425133
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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;
+16 −4
Original line number Diff line number Diff line
@@ -53,6 +53,7 @@ import java.util.UUID;
 *   <li> {@link android.media.audiofx.PresetReverb}</li>
 *   <li> {@link android.media.audiofx.EnvironmentalReverb}</li>
 *   <li> {@link android.media.audiofx.DynamicsProcessing}</li>
 *   <li> {@link android.media.audiofx.HapticGenerator}</li>
 * </ul>
 * <p>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}.
     *  </li>
     *  <li>uuid: UUID for this particular implementation</li>
     *  <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li>
@@ -246,8 +256,9 @@ public class AudioEffect {
         *  {@link AudioEffect#EFFECT_TYPE_AGC}, {@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}
         *   or {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}.<br>
         *  {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER},
         *  {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING},
         *  or {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}.<br>
         *  For reverberation, bass boost, EQ and virtualizer, the UUID
         *  corresponds to the OpenSL ES Interface ID.
         */
@@ -284,7 +295,8 @@ public class AudioEffect {
         * {@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}.
         * @param uuid         UUID for this particular implementation
         * @param connectMode  {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}
         * @param name         human readable effect name
+128 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.audiofx;

import android.annotation.NonNull;
import android.media.AudioManager;
import android.util.Log;

import java.util.UUID;

/**
 * Haptic Generator(HG).
 * <p>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.
 * <p>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.
 * <p>To attach the HapticGenerator to a particular AudioTrack or MediaPlayer, specify the audio
 * session ID of this AudioTrack or MediaPlayer when constructing the HapticGenerator.
 * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions.
 * <p>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();
    }
}
+8 −0
Original line number Diff line number Diff line
@@ -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;