• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.media.audiofx;
18 
19 import android.annotation.NonNull;
20 import android.media.AudioManager;
21 import android.util.Log;
22 
23 import java.util.UUID;
24 
25 /**
26  * Haptic Generator(HG).
27  * <p>HG is an audio post-processor which generates haptic data based on the audio channels. The
28  * generated haptic data is sent along with audio data down to the audio HAL, which will require the
29  * device to support audio-coupled-haptic playback. In that case, the effect will only be created on
30  * device supporting audio-coupled-haptic playback. Call {@link HapticGenerator#isAvailable()} to
31  * check if the device supports this effect.
32  * <p>An application can create a HapticGenerator object to initiate and control this audio effect
33  * in the audio framework.
34  * <p>To attach the HapticGenerator to a particular AudioTrack or MediaPlayer, specify the audio
35  * session ID of this AudioTrack or MediaPlayer when constructing the HapticGenerator.
36  * <p>See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions.
37  * <p>See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio
38  * effects.
39  */
40 public class HapticGenerator extends AudioEffect implements AutoCloseable {
41 
42     private static final String TAG = "HapticGenerator";
43 
44     // For every HapticGenerator, it contains a volume control effect so that the volume control
45     // will always be handled in the effect chain. In that case, the HapticGenerator can generate
46     // haptic data based on the raw audio data.
47     private AudioEffect mVolumeControlEffect;
48 
49     /**
50      * @return true if the HapticGenerator is available on the device.
51      */
isAvailable()52     public static boolean isAvailable() {
53         return AudioManager.isHapticPlaybackSupported()
54                 && AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_HAPTIC_GENERATOR);
55     }
56 
57     /**
58      * Creates a HapticGenerator and attaches it to the given audio session.
59      * Use {@link android.media.AudioTrack#getAudioSessionId()} or
60      * {@link android.media.MediaPlayer#getAudioSessionId()} to
61      * apply this effect on specific AudioTrack or MediaPlayer instance.
62      *
63      * @param audioSession system wide unique audio session identifier. The HapticGenerator will be
64      *                     applied to the players with the same audio session.
65      * @return HapticGenerator created or null if the device does not support HapticGenerator or
66      *                         the audio session is invalid.
67      * @throws java.lang.IllegalArgumentException when HapticGenerator is not supported
68      * @throws java.lang.UnsupportedOperationException when the effect library is not loaded.
69      * @throws java.lang.RuntimeException for all other error
70      */
create(int audioSession)71     public static @NonNull HapticGenerator create(int audioSession) {
72         return new HapticGenerator(audioSession);
73     }
74 
75     /**
76      * Class constructor.
77      *
78      * @param audioSession system wide unique audio session identifier. The HapticGenerator will be
79      *                     attached to the MediaPlayer or AudioTrack in the same audio session.
80      * @throws java.lang.IllegalArgumentException
81      * @throws java.lang.UnsupportedOperationException
82      * @throws java.lang.RuntimeException
83      */
HapticGenerator(int audioSession)84     private HapticGenerator(int audioSession) {
85         super(EFFECT_TYPE_HAPTIC_GENERATOR, EFFECT_TYPE_NULL, 0, audioSession);
86         mVolumeControlEffect = new AudioEffect(
87                 AudioEffect.EFFECT_TYPE_NULL,
88                 UUID.fromString("119341a0-8469-11df-81f9-0002a5d5c51b"),
89                 0,
90                 audioSession);
91     }
92 
93     /**
94      * Enable or disable the effect.
95      *
96      * @param enabled the requested enable state
97      * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
98      *         or {@link #ERROR_DEAD_OBJECT} in case of failure.
99      */
100     @Override
setEnabled(boolean enabled)101     public int setEnabled(boolean enabled) {
102         int ret = super.setEnabled(enabled);
103         if (ret == SUCCESS) {
104             if (mVolumeControlEffect == null
105                     || mVolumeControlEffect.setEnabled(enabled) != SUCCESS) {
106                 Log.w(TAG, "Failed to enable volume control effect for HapticGenerator");
107             }
108         }
109         return ret;
110     }
111 
112     /**
113      * Releases the native AudioEffect resources.
114      */
115     @Override
release()116     public void release() {
117         if (mVolumeControlEffect != null) {
118             mVolumeControlEffect.release();
119         }
120         super.release();
121     }
122 
123     /**
124      * Release the resources that are held by the effect.
125      */
126     @Override
close()127     public void close() {
128         release();
129     }
130 }
131