• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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.annotation.Nullable;
21 import android.annotation.RequiresPermission;
22 import android.annotation.SdkConstant;
23 import android.annotation.SdkConstant.SdkConstantType;
24 import android.annotation.SuppressLint;
25 import android.annotation.SystemApi;
26 import android.annotation.TestApi;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.AttributionSource;
29 import android.content.AttributionSource.ScopedParcelState;
30 import android.media.AudioDeviceAttributes;
31 import android.media.AudioDeviceInfo;
32 import android.media.AudioSystem;
33 import android.os.Build;
34 import android.os.Handler;
35 import android.os.Looper;
36 import android.os.Message;
37 import android.os.Parcel;
38 import android.util.Log;
39 
40 import java.lang.ref.WeakReference;
41 import java.nio.ByteBuffer;
42 import java.nio.ByteOrder;
43 import java.util.Objects;
44 import java.util.UUID;
45 
46 /**
47  * AudioEffect is the base class for controlling audio effects provided by the android audio
48  * framework.
49  * <p>Applications should not use the AudioEffect class directly but one of its derived classes to
50  * control specific effects:
51  * <ul>
52  *   <li> {@link android.media.audiofx.Equalizer}</li>
53  *   <li> {@link android.media.audiofx.Virtualizer}</li>
54  *   <li> {@link android.media.audiofx.BassBoost}</li>
55  *   <li> {@link android.media.audiofx.PresetReverb}</li>
56  *   <li> {@link android.media.audiofx.EnvironmentalReverb}</li>
57  *   <li> {@link android.media.audiofx.DynamicsProcessing}</li>
58  *   <li> {@link android.media.audiofx.HapticGenerator}</li>
59  * </ul>
60  * <p>To apply the audio effect to a specific AudioTrack or MediaPlayer instance,
61  * the application must specify the audio session ID of that instance when creating the AudioEffect.
62  * (see {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions).
63  * <p>NOTE: attaching insert effects (equalizer, bass boost, virtualizer) to the global audio output
64  * mix by use of session 0 is deprecated.
65  * <p>Creating an AudioEffect object will create the corresponding effect engine in the audio
66  * framework if no instance of the same effect type exists in the specified audio session.
67  * If one exists, this instance will be used.
68  * <p>The application creating the AudioEffect object (or a derived class) will either receive
69  * control of the effect engine or not depending on the priority parameter. If priority is higher
70  * than the priority used by the current effect engine owner, the control will be transfered to the
71  * new object. Otherwise control will remain with the previous object. In this case, the new
72  * application will be notified of changes in effect engine state or control ownership by the
73  * appropriate listener.
74  */
75 
76 public class AudioEffect {
77     static {
78         System.loadLibrary("audioeffect_jni");
native_init()79         native_init();
80     }
81 
82     private final static String TAG = "AudioEffect-JAVA";
83 
84     // effect type UUIDs are taken
85     //     from hardware/interfaces/audio/aidl/android/hardware/audio/effect/Descriptor.aidl
86 
87     /**
88      * The following UUIDs define effect types corresponding to standard audio
89      * effects whose implementation and interface conform to the OpenSL ES
90      * specification. The definitions match the corresponding interface IDs in
91      * OpenSLES_IID.h
92      */
93     /**
94      * UUID for environmental reverberation effect
95      */
96     public static final UUID EFFECT_TYPE_ENV_REVERB = UUID
97             .fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
98     /**
99      * UUID for preset reverberation effect
100      */
101     public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID
102             .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
103     /**
104      * UUID for equalizer effect
105      */
106     public static final UUID EFFECT_TYPE_EQUALIZER = UUID
107             .fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
108     /**
109      * UUID for bass boost effect
110      */
111     public static final UUID EFFECT_TYPE_BASS_BOOST = UUID
112             .fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
113     /**
114      * UUID for virtualizer effect
115      */
116     public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID
117             .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
118 
119     /**
120      * UUIDs for effect types not covered by OpenSL ES.
121      */
122     /**
123      * UUID for Automatic Gain Control (AGC)
124      */
125     public static final UUID EFFECT_TYPE_AGC = UUID
126             .fromString("0a8abfe0-654c-11e0-ba26-0002a5d5c51b");
127 
128     /**
129      * UUID for Acoustic Echo Canceler (AEC)
130      */
131     public static final UUID EFFECT_TYPE_AEC = UUID
132             .fromString("7b491460-8d4d-11e0-bd61-0002a5d5c51b");
133 
134     /**
135      * UUID for Noise Suppressor (NS)
136      */
137     public static final UUID EFFECT_TYPE_NS = UUID
138             .fromString("58b4b260-8e06-11e0-aa8e-0002a5d5c51b");
139 
140     /**
141      * UUID for Loudness Enhancer
142      */
143     public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID
144               .fromString("fe3199be-aed0-413f-87bb-11260eb63cf1");
145 
146     /**
147      * UUID for Dynamics Processing
148      */
149     public static final UUID EFFECT_TYPE_DYNAMICS_PROCESSING = UUID
150               .fromString("7261676f-6d75-7369-6364-28e2fd3ac39e");
151 
152     /**
153      * @hide
154      * UUID for the Spatializer effect
155      */
156     @SuppressLint("UnflaggedApi") // Test API
157     @TestApi
158     @NonNull
159     public static final UUID EFFECT_TYPE_SPATIALIZER =
160             UUID.fromString("ccd4cf09-a79d-46c2-9aae-06a1698d6c8f");
161 
162     /**
163      * UUID for Haptic Generator.
164      */
165     // This is taken from system/media/audio/include/system/audio_effects/effect_hapticgenerator.h
166     @NonNull
167     public static final UUID EFFECT_TYPE_HAPTIC_GENERATOR = UUID
168               .fromString("1411e6d6-aecd-4021-a1cf-a6aceb0d71e5");
169 
170     /**
171      * Null effect UUID. See {@link AudioEffect(UUID, UUID, int, int)} for use.
172      * @hide
173      */
174     @TestApi
175     public static final UUID EFFECT_TYPE_NULL = UUID
176             .fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
177 
178     /**
179      * State of an AudioEffect object that was not successfully initialized upon
180      * creation
181      * @hide
182      */
183     public static final int STATE_UNINITIALIZED = 0;
184     /**
185      * State of an AudioEffect object that is ready to be used.
186      * @hide
187      */
188     public static final int STATE_INITIALIZED = 1;
189 
190     // to keep in sync with
191     // frameworks/base/include/media/AudioEffect.h
192     /**
193      * Event id for engine control ownership change notification.
194      * @hide
195      */
196     public static final int NATIVE_EVENT_CONTROL_STATUS = 0;
197     /**
198      * Event id for engine state change notification.
199      * @hide
200      */
201     public static final int NATIVE_EVENT_ENABLED_STATUS = 1;
202     /**
203      * Event id for engine parameter change notification.
204      * @hide
205      */
206     public static final int NATIVE_EVENT_PARAMETER_CHANGED = 2;
207 
208     /**
209      * Successful operation.
210      */
211     public static final int SUCCESS = 0;
212     /**
213      * Unspecified error.
214      */
215     public static final int ERROR = -1;
216     /**
217      * Internal operation status. Not returned by any method.
218      */
219     public static final int ALREADY_EXISTS = -2;
220     /**
221      * Operation failed due to bad object initialization.
222      */
223     public static final int ERROR_NO_INIT = -3;
224     /**
225      * Operation failed due to bad parameter value.
226      */
227     public static final int ERROR_BAD_VALUE = -4;
228     /**
229      * Operation failed because it was requested in wrong state.
230      */
231     public static final int ERROR_INVALID_OPERATION = -5;
232     /**
233      * Operation failed due to lack of memory.
234      */
235     public static final int ERROR_NO_MEMORY = -6;
236     /**
237      * Operation failed due to dead remote object.
238      */
239     public static final int ERROR_DEAD_OBJECT = -7;
240 
241     /**
242      * The effect descriptor contains information on a particular effect implemented in the
243      * audio framework:<br>
244      * <ul>
245      *  <li>type: UUID identifying the effect type. May be one of:
246      * {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC},
247      * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB},
248      * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS},
249      * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER},
250      * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING},
251      * {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}.
252      *  </li>
253      *  <li>uuid: UUID for this particular implementation</li>
254      *  <li>connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li>
255      *  <li>name: human readable effect name</li>
256      *  <li>implementor: human readable effect implementor name</li>
257      * </ul>
258      * The method {@link #queryEffects()} returns an array of Descriptors to facilitate effects
259      * enumeration.
260      */
261     public static class Descriptor {
262 
Descriptor()263         public Descriptor() {
264         }
265 
266         /**
267          *  Indicates the generic type of the effect (Equalizer, Bass boost ...).
268          *  One of {@link AudioEffect#EFFECT_TYPE_AEC},
269          *  {@link AudioEffect#EFFECT_TYPE_AGC}, {@link AudioEffect#EFFECT_TYPE_BASS_BOOST},
270          *  {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, {@link AudioEffect#EFFECT_TYPE_EQUALIZER},
271          *  {@link AudioEffect#EFFECT_TYPE_NS}, {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}
272          *  {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER},
273          *  {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING},
274          *  or {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}.<br>
275          *  For reverberation, bass boost, EQ and virtualizer, the UUID
276          *  corresponds to the OpenSL ES Interface ID.
277          */
278         public UUID type;
279         /**
280          *  Indicates the particular implementation of the effect in that type. Several effects
281          *  can have the same type but this uuid is unique to a given implementation.
282          */
283         public UUID uuid;
284         /**
285          *  Indicates if the effect is of insert category {@link #EFFECT_INSERT} or auxiliary
286          *  category {@link #EFFECT_AUXILIARY}.
287          *  Insert effects (typically an {@link Equalizer}) are applied
288          *  to the entire audio source and usually not shared by several sources. Auxiliary effects
289          *  (typically a reverberator) are applied to part of the signal (wet) and the effect output
290          *  is added to the original signal (dry).
291          *  Audio pre processing are applied to audio captured on a particular
292          * {@link android.media.AudioRecord}.
293          */
294         public String connectMode;
295         /**
296          * Human readable effect name
297          */
298         public String name;
299         /**
300          * Human readable effect implementor name
301          */
302         public String implementor;
303 
304         /**
305          * @param type          UUID identifying the effect type. May be one of:
306          * {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC},
307          * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB},
308          * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS},
309          * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB},
310          * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER},
311          * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING},
312          * {@link AudioEffect#EFFECT_TYPE_HAPTIC_GENERATOR}.
313          * @param uuid         UUID for this particular implementation
314          * @param connectMode  {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}
315          * @param name         human readable effect name
316          * @param implementor  human readable effect implementor name
317         *
318         */
Descriptor(String type, String uuid, String connectMode, String name, String implementor)319         public Descriptor(String type, String uuid, String connectMode,
320                 String name, String implementor) {
321             this.type = UUID.fromString(type);
322             this.uuid = UUID.fromString(uuid);
323             this.connectMode = connectMode;
324             this.name = name;
325             this.implementor = implementor;
326         }
327 
328         /** @hide */
329         @TestApi
Descriptor(Parcel in)330         public Descriptor(Parcel in) {
331             type = UUID.fromString(in.readString());
332             uuid = UUID.fromString(in.readString());
333             connectMode = in.readString();
334             name = in.readString();
335             implementor = in.readString();
336         }
337 
338         @Override
hashCode()339         public int hashCode() {
340             return Objects.hash(type, uuid, connectMode, name, implementor);
341         }
342 
343         /** @hide */
344         @TestApi
writeToParcel(Parcel dest)345         public void writeToParcel(Parcel dest) {
346             dest.writeString(type.toString());
347             dest.writeString(uuid.toString());
348             dest.writeString(connectMode);
349             dest.writeString(name);
350             dest.writeString(implementor);
351         }
352 
353         @Override
equals(Object o)354         public boolean equals(Object o) {
355             if (this == o) return true;
356             if (o == null || !(o instanceof Descriptor)) return false;
357 
358             Descriptor that = (Descriptor) o;
359 
360             return (type.equals(that.type)
361                     && uuid.equals(that.uuid)
362                     && connectMode.equals(that.connectMode)
363                     && name.equals(that.name)
364                     && implementor.equals(that.implementor));
365         }
366     }
367 
368     /**
369      * Effect connection mode is insert. Specifying an audio session ID when creating the effect
370      * will insert this effect after all players in the same audio session.
371      */
372     public static final String EFFECT_INSERT = "Insert";
373     /**
374      * Effect connection mode is auxiliary.
375      * <p>Auxiliary effects must be created on session 0 (global output mix). In order for a
376      * MediaPlayer or AudioTrack to be fed into this effect, they must be explicitely attached to
377      * this effect and a send level must be specified.
378      * <p>Use the effect ID returned by {@link #getId()} to designate this particular effect when
379      * attaching it to the MediaPlayer or AudioTrack.
380      */
381     public static final String EFFECT_AUXILIARY = "Auxiliary";
382     /**
383      * Effect connection mode is pre processing.
384      * The audio pre processing effects are attached to an audio input stream or device
385      */
386     public static final String EFFECT_PRE_PROCESSING = "Pre Processing";
387     /**
388      * Effect connection mode is post processing.
389      * The audio post processing effects are attached to an audio output stream or device
390      */
391     public static final String EFFECT_POST_PROCESSING = "Post Processing";
392 
393     // --------------------------------------------------------------------------
394     // Member variables
395     // --------------------
396     /**
397      * Indicates the state of the AudioEffect instance
398      */
399     private int mState = STATE_UNINITIALIZED;
400     /**
401      * Lock to synchronize access to mState
402      */
403     private final Object mStateLock = new Object();
404     /**
405      * System wide unique effect ID
406      */
407     private int mId;
408 
409     // accessed by native methods
410     private long mNativeAudioEffect;
411     private long mJniData;
412 
413     /**
414      * Effect descriptor
415      */
416     private Descriptor mDescriptor;
417 
418     /**
419      * Listener for effect engine state change notifications.
420      *
421      * @see #setEnableStatusListener(OnEnableStatusChangeListener)
422      */
423     private OnEnableStatusChangeListener mEnableStatusChangeListener = null;
424     /**
425      * Listener for effect engine control ownership change notifications.
426      *
427      * @see #setControlStatusListener(OnControlStatusChangeListener)
428      */
429     private OnControlStatusChangeListener mControlChangeStatusListener = null;
430     /**
431      * Listener for effect engine control ownership change notifications.
432      *
433      * @see #setParameterListener(OnParameterChangeListener)
434      */
435     private OnParameterChangeListener mParameterChangeListener = null;
436     /**
437      * Lock to protect listeners updates against event notifications
438      * @hide
439      */
440     public final Object mListenerLock = new Object();
441     /**
442      * Handler for events coming from the native code
443      * @hide
444      */
445     public NativeEventHandler mNativeEventHandler = null;
446 
447     // --------------------------------------------------------------------------
448     // Constructor, Finalize
449     // --------------------
450     /**
451      * Class constructor.
452      *
453      * @param type type of effect engine created. See {@link #EFFECT_TYPE_ENV_REVERB},
454      *            {@link #EFFECT_TYPE_EQUALIZER} ... Types corresponding to
455      *            built-in effects are defined by AudioEffect class. Other types
456      *            can be specified provided they correspond an existing OpenSL
457      *            ES interface ID and the corresponsing effect is available on
458      *            the platform. If an unspecified effect type is requested, the
459      *            constructor with throw the IllegalArgumentException. This
460      *            parameter can be set to {@link #EFFECT_TYPE_NULL} in which
461      *            case only the uuid will be used to select the effect.
462      * @param uuid unique identifier of a particular effect implementation.
463      *            Must be specified if the caller wants to use a particular
464      *            implementation of an effect type. This parameter can be set to
465      *            {@link #EFFECT_TYPE_NULL} in which case only the type will
466      *            be used to select the effect.
467      * @param priority the priority level requested by the application for
468      *            controlling the effect engine. As the same effect engine can
469      *            be shared by several applications, this parameter indicates
470      *            how much the requesting application needs control of effect
471      *            parameters. The normal priority is 0, above normal is a
472      *            positive number, below normal a negative number.
473      * @param audioSession system wide unique audio session identifier.
474      *            The effect will be attached to the MediaPlayer or AudioTrack in
475      *            the same audio session.
476      *
477      * @throws java.lang.IllegalArgumentException
478      * @throws java.lang.UnsupportedOperationException
479      * @throws java.lang.RuntimeException
480      * @hide
481      */
482 
483     @UnsupportedAppUsage
AudioEffect(UUID type, UUID uuid, int priority, int audioSession)484     public AudioEffect(UUID type, UUID uuid, int priority, int audioSession)
485             throws IllegalArgumentException, UnsupportedOperationException,
486             RuntimeException {
487         this(type, uuid, priority, audioSession, null);
488     }
489 
490     /**
491      * Constructs an AudioEffect attached to a particular audio device.
492      * The device does not have to be attached when the effect is created. The effect will only
493      * be applied when the device is actually selected for playback or capture.
494      * @param uuid unique identifier of a particular effect implementation.
495      * @param device the device the effect must be attached to.
496      *
497      * @throws java.lang.IllegalArgumentException
498      * @throws java.lang.UnsupportedOperationException
499      * @throws java.lang.RuntimeException
500      * @hide
501      */
502     @SystemApi
503     @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
AudioEffect(@onNull UUID uuid, @NonNull AudioDeviceAttributes device)504     public AudioEffect(@NonNull UUID uuid, @NonNull AudioDeviceAttributes device) {
505         this(EFFECT_TYPE_NULL, Objects.requireNonNull(uuid),
506                 0, -2, Objects.requireNonNull(device));
507     }
508 
AudioEffect(UUID type, UUID uuid, int priority, int audioSession, @Nullable AudioDeviceAttributes device)509     private AudioEffect(UUID type, UUID uuid, int priority,
510             int audioSession, @Nullable AudioDeviceAttributes device)
511             throws IllegalArgumentException, UnsupportedOperationException,
512             RuntimeException {
513         this(type, uuid, priority, audioSession, device, false);
514     }
515 
AudioEffect(UUID type, UUID uuid, int priority, int audioSession, @Nullable AudioDeviceAttributes device, boolean probe)516     private AudioEffect(UUID type, UUID uuid, int priority,
517             int audioSession, @Nullable AudioDeviceAttributes device, boolean probe)
518             throws IllegalArgumentException, UnsupportedOperationException,
519             RuntimeException {
520         int[] id = new int[1];
521         Descriptor[] desc = new Descriptor[1];
522 
523         int deviceType = AudioSystem.DEVICE_NONE;
524         String deviceAddress = "";
525         if (device != null) {
526             if (device.getRole() == AudioDeviceAttributes.ROLE_OUTPUT) {
527                 deviceType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
528             } else {
529                 deviceType = AudioDeviceInfo.convertDeviceTypeToInternalInputDevice(
530                         device.getType(), device.getAddress());
531             }
532             deviceAddress = device.getAddress();
533         }
534 
535         // native initialization
536         // TODO b/182469354: Make consistent with AudioRecord
537         int initResult;
538         try (ScopedParcelState attributionSourceState =  AttributionSource.myAttributionSource()
539                 .asScopedParcelState()) {
540             initResult = native_setup(new WeakReference<>(this), type.toString(), uuid.toString(),
541                     priority, audioSession, deviceType, deviceAddress, id, desc,
542                     attributionSourceState.getParcel(), probe);
543         }
544         if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
545             Log.e(TAG, "Error code " + initResult
546                     + " when initializing AudioEffect.");
547             switch (initResult) {
548             case ERROR_BAD_VALUE:
549                 throw (new IllegalArgumentException("Effect type: " + type
550                         + " not supported."));
551             case ERROR_INVALID_OPERATION:
552                 throw (new UnsupportedOperationException(
553                         "Effect library not loaded"));
554             default:
555                 throw (new RuntimeException(
556                         "Cannot initialize effect engine for type: " + type
557                                 + " Error: " + initResult));
558             }
559         }
560         mId = id[0];
561         mDescriptor = desc[0];
562         if (!probe) {
563             synchronized (mStateLock) {
564                 mState = STATE_INITIALIZED;
565             }
566         }
567     }
568 
569     /**
570      * Checks if an AudioEffect identified by the supplied uuid can be attached
571      * to an audio device described by the supplied AudioDeviceAttributes.
572      * @param uuid unique identifier of a particular effect implementation.
573      * @param device the device the effect would be attached to.
574      * @return true if possible, false otherwise.
575      * @hide
576      */
577     @SystemApi
578     @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
isEffectSupportedForDevice( @onNull UUID uuid, @NonNull AudioDeviceAttributes device)579     public static boolean isEffectSupportedForDevice(
580             @NonNull UUID uuid, @NonNull AudioDeviceAttributes device) {
581         try {
582             AudioEffect fx = new AudioEffect(
583                     EFFECT_TYPE_NULL, Objects.requireNonNull(uuid),
584                     0, -2, Objects.requireNonNull(device), true);
585             fx.release();
586             return true;
587         } catch (Exception e) {
588             return false;
589         }
590     }
591 
592     /**
593      * Releases the native AudioEffect resources. It is a good practice to
594      * release the effect engine when not in use as control can be returned to
595      * other applications or the native resources released.
596      */
release()597     public void release() {
598         synchronized (mStateLock) {
599             native_release();
600             mState = STATE_UNINITIALIZED;
601         }
602     }
603 
604     @Override
finalize()605     protected void finalize() {
606         native_finalize();
607     }
608 
609     /**
610      * Get the effect descriptor.
611      *
612      * @see android.media.audiofx.AudioEffect.Descriptor
613      * @throws IllegalStateException
614      */
getDescriptor()615     public Descriptor getDescriptor() throws IllegalStateException {
616         checkState("getDescriptor()");
617         return mDescriptor;
618     }
619 
620     // --------------------------------------------------------------------------
621     // Effects Enumeration
622     // --------------------
623 
624     /**
625      * Query all effects available on the platform. Returns an array of
626      * {@link android.media.audiofx.AudioEffect.Descriptor} objects
627      *
628      * @throws IllegalStateException
629      */
630 
queryEffects()631     static public Descriptor[] queryEffects() {
632         return (Descriptor[]) native_query_effects();
633     }
634 
635     /**
636      * Query all audio pre-processing effects applied to the AudioRecord with the supplied
637      * audio session ID. Returns an array of {@link android.media.audiofx.AudioEffect.Descriptor}
638      * objects.
639      * @param audioSession system wide unique audio session identifier.
640      * @throws IllegalStateException
641      * @hide
642      */
643 
queryPreProcessings(int audioSession)644     static public Descriptor[] queryPreProcessings(int audioSession) {
645         return (Descriptor[]) native_query_pre_processing(audioSession);
646     }
647 
648     /**
649      * Checks if the device implements the specified effect type.
650      * @param type the requested effect type.
651      * @return true if the device implements the specified effect type, false otherwise.
652      * @hide
653      */
654     @TestApi
isEffectTypeAvailable(UUID type)655     public static boolean isEffectTypeAvailable(UUID type) {
656         AudioEffect.Descriptor[] desc = AudioEffect.queryEffects();
657         if (desc == null) {
658             return false;
659         }
660 
661         for (int i = 0; i < desc.length; i++) {
662             if (desc[i].type.equals(type)) {
663                 return true;
664             }
665         }
666         return false;
667     }
668 
669     // --------------------------------------------------------------------------
670     // Control methods
671     // --------------------
672 
673     /**
674      * Enable or disable the effect.
675      * Creating an audio effect does not automatically apply this effect on the audio source. It
676      * creates the resources necessary to process this effect but the audio signal is still bypassed
677      * through the effect engine. Calling this method will make that the effect is actually applied
678      * or not to the audio content being played in the corresponding audio session.
679      *
680      * @param enabled the requested enable state
681      * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
682      *         or {@link #ERROR_DEAD_OBJECT} in case of failure.
683      * @throws IllegalStateException
684      */
setEnabled(boolean enabled)685     public int setEnabled(boolean enabled) throws IllegalStateException {
686         checkState("setEnabled()");
687         return native_setEnabled(enabled);
688     }
689 
690     /**
691      * Set effect parameter. The setParameter method is provided in several
692      * forms addressing most common parameter formats. This form is the most
693      * generic one where the parameter and its value are both specified as an
694      * array of bytes. The parameter and value type and length are therefore
695      * totally free. For standard effect defined by OpenSL ES, the parameter
696      * format and values must match the definitions in the corresponding OpenSL
697      * ES interface.
698      *
699      * @param param the identifier of the parameter to set
700      * @param value the new value for the specified parameter
701      * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
702      *         {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
703      *         {@link #ERROR_DEAD_OBJECT} in case of failure
704      * @throws IllegalStateException
705      * @hide
706      */
707     @TestApi
setParameter(byte[] param, byte[] value)708     public int setParameter(byte[] param, byte[] value)
709             throws IllegalStateException {
710         checkState("setParameter()");
711         return native_setParameter(param.length, param, value.length, value);
712     }
713 
714     /**
715      * Set effect parameter. The parameter and its value are integers.
716      *
717      * @see #setParameter(byte[], byte[])
718      * @hide
719      */
720     @TestApi
setParameter(int param, int value)721     public int setParameter(int param, int value) throws IllegalStateException {
722         byte[] p = intToByteArray(param);
723         byte[] v = intToByteArray(value);
724         return setParameter(p, v);
725     }
726 
727     /**
728      * Set effect parameter. The parameter is an integer and the value is a
729      * short integer.
730      *
731      * @see #setParameter(byte[], byte[])
732      * @hide
733      */
734     @TestApi
setParameter(int param, short value)735     public int setParameter(int param, short value)
736             throws IllegalStateException {
737         byte[] p = intToByteArray(param);
738         byte[] v = shortToByteArray(value);
739         return setParameter(p, v);
740     }
741 
742     /**
743      * Set effect parameter. The parameter is an integer and the value is an
744      * array of bytes.
745      *
746      * @see #setParameter(byte[], byte[])
747      * @hide
748      */
749     @TestApi
setParameter(int param, byte[] value)750     public int setParameter(int param, byte[] value)
751             throws IllegalStateException {
752         byte[] p = intToByteArray(param);
753         return setParameter(p, value);
754     }
755 
756     /**
757      * Set effect parameter. The parameter is an array of 1 or 2 integers and
758      * the value is also an array of 1 or 2 integers
759      *
760      * @see #setParameter(byte[], byte[])
761      * @hide
762      */
763     @TestApi
setParameter(int[] param, int[] value)764     public int setParameter(int[] param, int[] value)
765             throws IllegalStateException {
766         if (param.length > 2 || value.length > 2) {
767             return ERROR_BAD_VALUE;
768         }
769         byte[] p = intToByteArray(param[0]);
770         if (param.length > 1) {
771             byte[] p2 = intToByteArray(param[1]);
772             p = concatArrays(p, p2);
773         }
774         byte[] v = intToByteArray(value[0]);
775         if (value.length > 1) {
776             byte[] v2 = intToByteArray(value[1]);
777             v = concatArrays(v, v2);
778         }
779         return setParameter(p, v);
780     }
781 
782     /**
783      * Set effect parameter. The parameter is an array of 1 or 2 integers and
784      * the value is an array of 1 or 2 short integers
785      *
786      * @see #setParameter(byte[], byte[])
787      * @hide
788      */
789     @UnsupportedAppUsage
setParameter(int[] param, short[] value)790     public int setParameter(int[] param, short[] value)
791             throws IllegalStateException {
792         if (param.length > 2 || value.length > 2) {
793             return ERROR_BAD_VALUE;
794         }
795         byte[] p = intToByteArray(param[0]);
796         if (param.length > 1) {
797             byte[] p2 = intToByteArray(param[1]);
798             p = concatArrays(p, p2);
799         }
800 
801         byte[] v = shortToByteArray(value[0]);
802         if (value.length > 1) {
803             byte[] v2 = shortToByteArray(value[1]);
804             v = concatArrays(v, v2);
805         }
806         return setParameter(p, v);
807     }
808 
809     /**
810      * Set effect parameter. The parameter is an array of 1 or 2 integers and
811      * the value is an array of bytes
812      *
813      * @see #setParameter(byte[], byte[])
814      * @hide
815      */
816     @TestApi
setParameter(int[] param, byte[] value)817     public int setParameter(int[] param, byte[] value)
818             throws IllegalStateException {
819         if (param.length > 2) {
820             return ERROR_BAD_VALUE;
821         }
822         byte[] p = intToByteArray(param[0]);
823         if (param.length > 1) {
824             byte[] p2 = intToByteArray(param[1]);
825             p = concatArrays(p, p2);
826         }
827         return setParameter(p, value);
828     }
829 
830     /**
831      * Get effect parameter. The getParameter method is provided in several
832      * forms addressing most common parameter formats. This form is the most
833      * generic one where the parameter and its value are both specified as an
834      * array of bytes. The parameter and value type and length are therefore
835      * totally free.
836      *
837      * @param param the identifier of the parameter to set
838      * @param value the new value for the specified parameter
839      * @return the number of meaningful bytes in value array in case of success or
840      *  {@link #ERROR_BAD_VALUE}, {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION}
841      *  or {@link #ERROR_DEAD_OBJECT} in case of failure.
842      * @throws IllegalStateException
843      * @hide
844      */
845     @TestApi
getParameter(byte[] param, byte[] value)846     public int getParameter(byte[] param, byte[] value)
847             throws IllegalStateException {
848         checkState("getParameter()");
849         return native_getParameter(param.length, param, value.length, value);
850     }
851 
852     /**
853      * Get effect parameter. The parameter is an integer and the value is an
854      * array of bytes.
855      *
856      * @see #getParameter(byte[], byte[])
857      * @hide
858      */
859     @TestApi
getParameter(int param, byte[] value)860     public int getParameter(int param, byte[] value)
861             throws IllegalStateException {
862         byte[] p = intToByteArray(param);
863 
864         return getParameter(p, value);
865     }
866 
867     /**
868      * Get effect parameter. The parameter is an integer and the value is an
869      * array of 1 or 2 integers
870      *
871      * @see #getParameter(byte[], byte[])
872      * In case of success, returns the number of meaningful integers in value array.
873      * @hide
874      */
875     @TestApi
getParameter(int param, int[] value)876     public int getParameter(int param, int[] value)
877             throws IllegalStateException {
878         if (value.length > 2) {
879             return ERROR_BAD_VALUE;
880         }
881         byte[] p = intToByteArray(param);
882 
883         byte[] v = new byte[value.length * 4];
884 
885         int status = getParameter(p, v);
886 
887         if (status == 4 || status == 8) {
888             value[0] = byteArrayToInt(v);
889             if (status == 8) {
890                 value[1] = byteArrayToInt(v, 4);
891             }
892             status /= 4;
893         } else {
894             status = ERROR;
895         }
896         return status;
897     }
898 
899     /**
900      * Get effect parameter. The parameter is an integer and the value is an
901      * array of 1 or 2 short integers
902      *
903      * @see #getParameter(byte[], byte[])
904      * In case of success, returns the number of meaningful short integers in value array.
905      * @hide
906      */
907     @TestApi
getParameter(int param, short[] value)908     public int getParameter(int param, short[] value)
909             throws IllegalStateException {
910         if (value.length > 2) {
911             return ERROR_BAD_VALUE;
912         }
913         byte[] p = intToByteArray(param);
914 
915         byte[] v = new byte[value.length * 2];
916 
917         int status = getParameter(p, v);
918 
919         if (status == 2 || status == 4) {
920             value[0] = byteArrayToShort(v);
921             if (status == 4) {
922                 value[1] = byteArrayToShort(v, 2);
923             }
924             status /= 2;
925         } else {
926             status = ERROR;
927         }
928         return status;
929     }
930 
931     /**
932      * Get effect parameter. The parameter is an array of 1 or 2 integers and
933      * the value is also an array of 1 or 2 integers
934      *
935      * @see #getParameter(byte[], byte[])
936      * In case of success, the returns the number of meaningful integers in value array.
937      * @hide
938      */
939     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getParameter(int[] param, int[] value)940     public int getParameter(int[] param, int[] value)
941             throws IllegalStateException {
942         if (param.length > 2 || value.length > 2) {
943             return ERROR_BAD_VALUE;
944         }
945         byte[] p = intToByteArray(param[0]);
946         if (param.length > 1) {
947             byte[] p2 = intToByteArray(param[1]);
948             p = concatArrays(p, p2);
949         }
950         byte[] v = new byte[value.length * 4];
951 
952         int status = getParameter(p, v);
953 
954         if (status == 4 || status == 8) {
955             value[0] = byteArrayToInt(v);
956             if (status == 8) {
957                 value[1] = byteArrayToInt(v, 4);
958             }
959             status /= 4;
960         } else {
961             status = ERROR;
962         }
963         return status;
964     }
965 
966     /**
967      * Get effect parameter. The parameter is an array of 1 or 2 integers and
968      * the value is an array of 1 or 2 short integers
969      *
970      * @see #getParameter(byte[], byte[])
971      * In case of success, returns the number of meaningful short integers in value array.
972      * @hide
973      */
974     @TestApi
getParameter(int[] param, short[] value)975     public int getParameter(int[] param, short[] value)
976             throws IllegalStateException {
977         if (param.length > 2 || value.length > 2) {
978             return ERROR_BAD_VALUE;
979         }
980         byte[] p = intToByteArray(param[0]);
981         if (param.length > 1) {
982             byte[] p2 = intToByteArray(param[1]);
983             p = concatArrays(p, p2);
984         }
985         byte[] v = new byte[value.length * 2];
986 
987         int status = getParameter(p, v);
988 
989         if (status == 2 || status == 4) {
990             value[0] = byteArrayToShort(v);
991             if (status == 4) {
992                 value[1] = byteArrayToShort(v, 2);
993             }
994             status /= 2;
995         } else {
996             status = ERROR;
997         }
998         return status;
999     }
1000 
1001     /**
1002      * Get effect parameter. The parameter is an array of 1 or 2 integers and
1003      * the value is an array of bytes
1004      *
1005      * @see #getParameter(byte[], byte[])
1006      * @hide
1007      */
1008     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getParameter(int[] param, byte[] value)1009     public int getParameter(int[] param, byte[] value)
1010             throws IllegalStateException {
1011         if (param.length > 2) {
1012             return ERROR_BAD_VALUE;
1013         }
1014         byte[] p = intToByteArray(param[0]);
1015         if (param.length > 1) {
1016             byte[] p2 = intToByteArray(param[1]);
1017             p = concatArrays(p, p2);
1018         }
1019 
1020         return getParameter(p, value);
1021     }
1022 
1023     /**
1024      * Send a command to the effect engine. This method is intended to send
1025      * proprietary commands to a particular effect implementation.
1026      * In case of success, returns the number of meaningful bytes in reply array.
1027      * In case of failure, the returned value is negative and implementation specific.
1028      * @hide
1029      */
1030     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
command(int cmdCode, byte[] command, byte[] reply)1031     public int command(int cmdCode, byte[] command, byte[] reply)
1032             throws IllegalStateException {
1033         checkState("command()");
1034         return native_command(cmdCode, command.length, command, reply.length, reply);
1035     }
1036 
1037     // --------------------------------------------------------------------------
1038     // Getters
1039     // --------------------
1040 
1041     /**
1042      * Returns effect unique identifier. This system wide unique identifier can
1043      * be used to attach this effect to a MediaPlayer or an AudioTrack when the
1044      * effect is an auxiliary effect (Reverb)
1045      *
1046      * @return the effect identifier.
1047      * @throws IllegalStateException
1048      */
getId()1049     public int getId() throws IllegalStateException {
1050         checkState("getId()");
1051         return mId;
1052     }
1053 
1054     /**
1055      * Returns effect enabled state
1056      *
1057      * @return true if the effect is enabled, false otherwise.
1058      * @throws IllegalStateException
1059      */
getEnabled()1060     public boolean getEnabled() throws IllegalStateException {
1061         checkState("getEnabled()");
1062         return native_getEnabled();
1063     }
1064 
1065     /**
1066      * Checks if this AudioEffect object is controlling the effect engine.
1067      *
1068      * @return true if this instance has control of effect engine, false
1069      *         otherwise.
1070      * @throws IllegalStateException
1071      */
hasControl()1072     public boolean hasControl() throws IllegalStateException {
1073         checkState("hasControl()");
1074         return native_hasControl();
1075     }
1076 
1077     // --------------------------------------------------------------------------
1078     // Initialization / configuration
1079     // --------------------
1080     /**
1081      * Sets the listener AudioEffect notifies when the effect engine is enabled
1082      * or disabled.
1083      *
1084      * @param listener
1085      */
setEnableStatusListener(OnEnableStatusChangeListener listener)1086     public void setEnableStatusListener(OnEnableStatusChangeListener listener) {
1087         synchronized (mListenerLock) {
1088             mEnableStatusChangeListener = listener;
1089         }
1090         if ((listener != null) && (mNativeEventHandler == null)) {
1091             createNativeEventHandler();
1092         }
1093     }
1094 
1095     /**
1096      * Sets the listener AudioEffect notifies when the effect engine control is
1097      * taken or returned.
1098      *
1099      * @param listener
1100      */
setControlStatusListener(OnControlStatusChangeListener listener)1101     public void setControlStatusListener(OnControlStatusChangeListener listener) {
1102         synchronized (mListenerLock) {
1103             mControlChangeStatusListener = listener;
1104         }
1105         if ((listener != null) && (mNativeEventHandler == null)) {
1106             createNativeEventHandler();
1107         }
1108     }
1109 
1110     /**
1111      * Sets the listener AudioEffect notifies when a parameter is changed.
1112      *
1113      * @param listener
1114      * @hide
1115      */
1116     @TestApi
setParameterListener(OnParameterChangeListener listener)1117     public void setParameterListener(OnParameterChangeListener listener) {
1118         synchronized (mListenerLock) {
1119             mParameterChangeListener = listener;
1120         }
1121         if ((listener != null) && (mNativeEventHandler == null)) {
1122             createNativeEventHandler();
1123         }
1124     }
1125 
1126     // Convenience method for the creation of the native event handler
1127     // It is called only when a non-null event listener is set.
1128     // precondition:
1129     // mNativeEventHandler is null
createNativeEventHandler()1130     private void createNativeEventHandler() {
1131         Looper looper;
1132         if ((looper = Looper.myLooper()) != null) {
1133             mNativeEventHandler = new NativeEventHandler(this, looper);
1134         } else if ((looper = Looper.getMainLooper()) != null) {
1135             mNativeEventHandler = new NativeEventHandler(this, looper);
1136         } else {
1137             mNativeEventHandler = null;
1138         }
1139     }
1140 
1141     // ---------------------------------------------------------
1142     // Interface definitions
1143     // --------------------
1144     /**
1145      * The OnEnableStatusChangeListener interface defines a method called by the AudioEffect
1146      * when the enabled state of the effect engine was changed by the controlling application.
1147      */
1148     public interface OnEnableStatusChangeListener {
1149         /**
1150          * Called on the listener to notify it that the effect engine has been
1151          * enabled or disabled.
1152          * @param effect the effect on which the interface is registered.
1153          * @param enabled new effect state.
1154          */
onEnableStatusChange(AudioEffect effect, boolean enabled)1155         void onEnableStatusChange(AudioEffect effect, boolean enabled);
1156     }
1157 
1158     /**
1159      * The OnControlStatusChangeListener interface defines a method called by the AudioEffect
1160      * when control of the effect engine is gained or lost by the application
1161      */
1162     public interface OnControlStatusChangeListener {
1163         /**
1164          * Called on the listener to notify it that the effect engine control
1165          * has been taken or returned.
1166          * @param effect the effect on which the interface is registered.
1167          * @param controlGranted true if the application has been granted control of the effect
1168          * engine, false otherwise.
1169          */
onControlStatusChange(AudioEffect effect, boolean controlGranted)1170         void onControlStatusChange(AudioEffect effect, boolean controlGranted);
1171     }
1172 
1173     /**
1174      * The OnParameterChangeListener interface defines a method called by the AudioEffect
1175      * when a parameter is changed in the effect engine by the controlling application.
1176      * @hide
1177      */
1178     @TestApi
1179     public interface OnParameterChangeListener {
1180         /**
1181          * Called on the listener to notify it that a parameter value has changed.
1182          * @param effect the effect on which the interface is registered.
1183          * @param status status of the set parameter operation.
1184          * @param param ID of the modified parameter.
1185          * @param value the new parameter value.
1186          */
onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value)1187         void onParameterChange(AudioEffect effect, int status, byte[] param,
1188                 byte[] value);
1189     }
1190 
1191 
1192     // -------------------------------------------------------------------------
1193     // Audio Effect Control panel intents
1194     // -------------------------------------------------------------------------
1195 
1196     /**
1197      *  Intent to launch an audio effect control panel UI.
1198      *  <p>The goal of this intent is to enable separate implementations of music/media player
1199      *  applications and audio effect control application or services.
1200      *  This will allow platform vendors to offer more advanced control options for standard effects
1201      *  or control for platform specific effects.
1202      *  <p>The intent carries a number of extras used by the player application to communicate
1203      *  necessary pieces of information to the control panel application.
1204      *  <p>The calling application must use the
1205      *  {@link android.app.Activity#startActivityForResult(Intent, int)} method to launch the
1206      *  control panel so that its package name is indicated and used by the control panel
1207      *  application to keep track of changes for this particular application.
1208      *  <p>The {@link #EXTRA_AUDIO_SESSION} extra will indicate an audio session to which the
1209      *  audio effects should be applied. If no audio session is specified, either one of the
1210      *  follownig will happen:
1211      *  <p>- If an audio session was previously opened by the calling application with
1212      *  {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intent, the effect changes will
1213      *  be applied to that session.
1214      *  <p>- If no audio session is opened, the changes will be stored in the package specific
1215      *  storage area and applied whenever a new audio session is opened by this application.
1216      *  <p>The {@link #EXTRA_CONTENT_TYPE} extra will help the control panel application
1217      *  customize both the UI layout and the default audio effect settings if none are already
1218      *  stored for the calling application.
1219      */
1220     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
1221     public static final String ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL =
1222         "android.media.action.DISPLAY_AUDIO_EFFECT_CONTROL_PANEL";
1223 
1224     /**
1225      *  Intent to signal to the effect control application or service that a new audio session
1226      *  is opened and requires audio effects to be applied.
1227      *  <p>This is different from {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} in that no
1228      *  UI should be displayed in this case. Music player applications can broadcast this intent
1229      *  before starting playback to make sure that any audio effect settings previously selected
1230      *  by the user are applied.
1231      *  <p>The effect control application receiving this intent will look for previously stored
1232      *  settings for the calling application, create all required audio effects and apply the
1233      *  effect settings to the specified audio session.
1234      *  <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
1235      *  audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
1236      *  <p>If no stored settings are found for the calling application, default settings for the
1237      *  content type indicated by {@link #EXTRA_CONTENT_TYPE} will be applied. The default settings
1238      *  for a given content type are platform specific.
1239      */
1240     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1241     public static final String ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION =
1242         "android.media.action.OPEN_AUDIO_EFFECT_CONTROL_SESSION";
1243 
1244     /**
1245      *  Intent to signal to the effect control application or service that an audio session
1246      *  is closed and that effects should not be applied anymore.
1247      *  <p>The effect control application receiving this intent will delete all effects on
1248      *  this session and store current settings in package specific storage.
1249      *  <p>The calling package name is indicated by the {@link #EXTRA_PACKAGE_NAME} extra and the
1250      *  audio session ID by the {@link #EXTRA_AUDIO_SESSION} extra. Both extras are mandatory.
1251      *  <p>It is good practice for applications to broadcast this intent when music playback stops
1252      *  and/or when exiting to free system resources consumed by audio effect engines.
1253      */
1254     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
1255     public static final String ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION =
1256         "android.media.action.CLOSE_AUDIO_EFFECT_CONTROL_SESSION";
1257 
1258     /**
1259      * Contains the ID of the audio session the effects should be applied to.
1260      * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL},
1261      * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
1262      * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
1263      * <p>The extra value is of type int and is the audio session ID.
1264      *  @see android.media.MediaPlayer#getAudioSessionId() for details on audio sessions.
1265      */
1266      public static final String EXTRA_AUDIO_SESSION = "android.media.extra.AUDIO_SESSION";
1267 
1268     /**
1269      * Contains the package name of the calling application.
1270      * <p>This extra is for use with {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} and
1271      * {@link #ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION} intents.
1272      * <p>The extra value is a string containing the full package name.
1273      */
1274     public static final String EXTRA_PACKAGE_NAME = "android.media.extra.PACKAGE_NAME";
1275 
1276     /**
1277      * Indicates which type of content is played by the application.
1278      * <p>This extra is for use with {@link #ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL} and
1279      * {@link #ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION} intents.
1280      * <p>This information is used by the effect control application to customize UI and select
1281      * appropriate default effect settings. The content type is one of the following:
1282      * <ul>
1283      *   <li>{@link #CONTENT_TYPE_MUSIC}</li>
1284      *   <li>{@link #CONTENT_TYPE_MOVIE}</li>
1285      *   <li>{@link #CONTENT_TYPE_GAME}</li>
1286      *   <li>{@link #CONTENT_TYPE_VOICE}</li>
1287      * </ul>
1288      * If omitted, the content type defaults to {@link #CONTENT_TYPE_MUSIC}.
1289      */
1290     public static final String EXTRA_CONTENT_TYPE = "android.media.extra.CONTENT_TYPE";
1291 
1292     /**
1293      * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is music
1294      */
1295     public static final int  CONTENT_TYPE_MUSIC = 0;
1296     /**
1297      * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is video or movie
1298      */
1299     public static final int  CONTENT_TYPE_MOVIE = 1;
1300     /**
1301      * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is game audio
1302      */
1303     public static final int  CONTENT_TYPE_GAME = 2;
1304     /**
1305      * Value for {@link #EXTRA_CONTENT_TYPE} when the type of content played is voice audio
1306      */
1307     public static final int  CONTENT_TYPE_VOICE = 3;
1308 
1309 
1310     // ---------------------------------------------------------
1311     // Inner classes
1312     // --------------------
1313     /**
1314      * Helper class to handle the forwarding of native events to the appropriate
1315      * listeners
1316      */
1317     private class NativeEventHandler extends Handler {
1318         private AudioEffect mAudioEffect;
1319 
NativeEventHandler(AudioEffect ae, Looper looper)1320         public NativeEventHandler(AudioEffect ae, Looper looper) {
1321             super(looper);
1322             mAudioEffect = ae;
1323         }
1324 
1325         @Override
handleMessage(Message msg)1326         public void handleMessage(Message msg) {
1327             if (mAudioEffect == null) {
1328                 return;
1329             }
1330             switch (msg.what) {
1331             case NATIVE_EVENT_ENABLED_STATUS:
1332                 OnEnableStatusChangeListener enableStatusChangeListener = null;
1333                 synchronized (mListenerLock) {
1334                     enableStatusChangeListener = mAudioEffect.mEnableStatusChangeListener;
1335                 }
1336                 if (enableStatusChangeListener != null) {
1337                     enableStatusChangeListener.onEnableStatusChange(
1338                             mAudioEffect, (boolean) (msg.arg1 != 0));
1339                 }
1340                 break;
1341             case NATIVE_EVENT_CONTROL_STATUS:
1342                 OnControlStatusChangeListener controlStatusChangeListener = null;
1343                 synchronized (mListenerLock) {
1344                     controlStatusChangeListener = mAudioEffect.mControlChangeStatusListener;
1345                 }
1346                 if (controlStatusChangeListener != null) {
1347                     controlStatusChangeListener.onControlStatusChange(
1348                             mAudioEffect, (boolean) (msg.arg1 != 0));
1349                 }
1350                 break;
1351             case NATIVE_EVENT_PARAMETER_CHANGED:
1352                 OnParameterChangeListener parameterChangeListener = null;
1353                 synchronized (mListenerLock) {
1354                     parameterChangeListener = mAudioEffect.mParameterChangeListener;
1355                 }
1356                 if (parameterChangeListener != null) {
1357                     // arg1 contains offset of parameter value from start of
1358                     // byte array
1359                     int vOffset = msg.arg1;
1360                     byte[] p = (byte[]) msg.obj;
1361                     // See effect_param_t in EffectApi.h for psize and vsize
1362                     // fields offsets
1363                     int status = byteArrayToInt(p, 0);
1364                     int psize = byteArrayToInt(p, 4);
1365                     int vsize = byteArrayToInt(p, 8);
1366                     byte[] param = new byte[psize];
1367                     byte[] value = new byte[vsize];
1368                     System.arraycopy(p, 12, param, 0, psize);
1369                     System.arraycopy(p, vOffset, value, 0, vsize);
1370 
1371                     parameterChangeListener.onParameterChange(mAudioEffect,
1372                             status, param, value);
1373                 }
1374                 break;
1375 
1376             default:
1377                 Log.e(TAG, "handleMessage() Unknown event type: " + msg.what);
1378                 break;
1379             }
1380         }
1381     }
1382 
1383     // ---------------------------------------------------------
1384     // Java methods called from the native side
1385     // --------------------
1386     @SuppressWarnings("unused")
postEventFromNative(Object effect_ref, int what, int arg1, int arg2, Object obj)1387     private static void postEventFromNative(Object effect_ref, int what,
1388             int arg1, int arg2, Object obj) {
1389         AudioEffect effect = (AudioEffect) ((WeakReference) effect_ref).get();
1390         if (effect == null) {
1391             return;
1392         }
1393         if (effect.mNativeEventHandler != null) {
1394             Message m = effect.mNativeEventHandler.obtainMessage(what, arg1,
1395                     arg2, obj);
1396             effect.mNativeEventHandler.sendMessage(m);
1397         }
1398 
1399     }
1400 
1401     // ---------------------------------------------------------
1402     // Native methods called from the Java side
1403     // --------------------
1404 
native_init()1405     private static native final void native_init();
1406 
native_setup(Object audioeffect_this, String type, String uuid, int priority, int audioSession, int deviceType, String deviceAddress, int[] id, Object[] desc, @NonNull Parcel attributionSource, boolean probe)1407     private native final int native_setup(Object audioeffect_this, String type,
1408             String uuid, int priority, int audioSession,
1409             int deviceType, String deviceAddress, int[] id, Object[] desc,
1410             @NonNull Parcel attributionSource, boolean probe);
1411 
native_finalize()1412     private native final void native_finalize();
1413 
native_release()1414     private native final void native_release();
1415 
native_setEnabled(boolean enabled)1416     private native final int native_setEnabled(boolean enabled);
1417 
native_getEnabled()1418     private native final boolean native_getEnabled();
1419 
native_hasControl()1420     private native final boolean native_hasControl();
1421 
native_setParameter(int psize, byte[] param, int vsize, byte[] value)1422     private native final int native_setParameter(int psize, byte[] param,
1423             int vsize, byte[] value);
1424 
native_getParameter(int psize, byte[] param, int vsize, byte[] value)1425     private native final int native_getParameter(int psize, byte[] param,
1426             int vsize, byte[] value);
1427 
native_command(int cmdCode, int cmdSize, byte[] cmdData, int repSize, byte[] repData)1428     private native final int native_command(int cmdCode, int cmdSize,
1429             byte[] cmdData, int repSize, byte[] repData);
1430 
native_query_effects()1431     private static native Object[] native_query_effects();
1432 
native_query_pre_processing(int audioSession)1433     private static native Object[] native_query_pre_processing(int audioSession);
1434 
1435     // ---------------------------------------------------------
1436     // Utility methods
1437     // ------------------
1438 
1439     /**
1440     * @hide
1441     */
1442     @UnsupportedAppUsage
checkState(String methodName)1443     public void checkState(String methodName) throws IllegalStateException {
1444         synchronized (mStateLock) {
1445             if (mState != STATE_INITIALIZED) {
1446                 throw (new IllegalStateException(methodName
1447                         + " called on uninitialized AudioEffect."));
1448             }
1449         }
1450     }
1451 
1452     /**
1453      * @hide
1454      */
checkStatus(int status)1455     public void checkStatus(int status) {
1456         if (isError(status)) {
1457             switch (status) {
1458             case AudioEffect.ERROR_BAD_VALUE:
1459                 throw (new IllegalArgumentException(
1460                         "AudioEffect: bad parameter value"));
1461             case AudioEffect.ERROR_INVALID_OPERATION:
1462                 throw (new UnsupportedOperationException(
1463                         "AudioEffect: invalid parameter operation"));
1464             default:
1465                 throw (new RuntimeException("AudioEffect: set/get parameter error"));
1466             }
1467         }
1468     }
1469 
1470     /**
1471      * @hide
1472      */
1473     @TestApi
isError(int status)1474     public static boolean isError(int status) {
1475         return (status < 0);
1476     }
1477 
1478     /**
1479      * @hide
1480      */
1481     @TestApi
byteArrayToInt(byte[] valueBuf)1482     public static int byteArrayToInt(byte[] valueBuf) {
1483         return byteArrayToInt(valueBuf, 0);
1484 
1485     }
1486 
1487     /**
1488      * @hide
1489      */
byteArrayToInt(byte[] valueBuf, int offset)1490     public static int byteArrayToInt(byte[] valueBuf, int offset) {
1491         ByteBuffer converter = ByteBuffer.wrap(valueBuf);
1492         converter.order(ByteOrder.nativeOrder());
1493         return converter.getInt(offset);
1494 
1495     }
1496 
1497     /**
1498      * @hide
1499      */
1500     @TestApi
intToByteArray(int value)1501     public static byte[] intToByteArray(int value) {
1502         ByteBuffer converter = ByteBuffer.allocate(4);
1503         converter.order(ByteOrder.nativeOrder());
1504         converter.putInt(value);
1505         return converter.array();
1506     }
1507 
1508     /**
1509      * @hide
1510      */
1511     @TestApi
byteArrayToShort(byte[] valueBuf)1512     public static short byteArrayToShort(byte[] valueBuf) {
1513         return byteArrayToShort(valueBuf, 0);
1514     }
1515 
1516     /**
1517      * @hide
1518      */
byteArrayToShort(byte[] valueBuf, int offset)1519     public static short byteArrayToShort(byte[] valueBuf, int offset) {
1520         ByteBuffer converter = ByteBuffer.wrap(valueBuf);
1521         converter.order(ByteOrder.nativeOrder());
1522         return converter.getShort(offset);
1523 
1524     }
1525 
1526     /**
1527      * @hide
1528      */
1529     @TestApi
shortToByteArray(short value)1530     public static byte[] shortToByteArray(short value) {
1531         ByteBuffer converter = ByteBuffer.allocate(2);
1532         converter.order(ByteOrder.nativeOrder());
1533         short sValue = (short) value;
1534         converter.putShort(sValue);
1535         return converter.array();
1536     }
1537 
1538     /**
1539      * @hide
1540      */
byteArrayToFloat(byte[] valueBuf)1541     public static float byteArrayToFloat(byte[] valueBuf) {
1542         return byteArrayToFloat(valueBuf, 0);
1543 
1544     }
1545 
1546     /**
1547      * @hide
1548      */
byteArrayToFloat(byte[] valueBuf, int offset)1549     public static float byteArrayToFloat(byte[] valueBuf, int offset) {
1550         ByteBuffer converter = ByteBuffer.wrap(valueBuf);
1551         converter.order(ByteOrder.nativeOrder());
1552         return converter.getFloat(offset);
1553 
1554     }
1555 
1556     /**
1557      * @hide
1558      */
floatToByteArray(float value)1559     public static byte[] floatToByteArray(float value) {
1560         ByteBuffer converter = ByteBuffer.allocate(4);
1561         converter.order(ByteOrder.nativeOrder());
1562         converter.putFloat(value);
1563         return converter.array();
1564     }
1565 
1566     /**
1567      * @hide
1568      */
concatArrays(byte[]... arrays)1569     public static byte[] concatArrays(byte[]... arrays) {
1570         int len = 0;
1571         for (byte[] a : arrays) {
1572             len += a.length;
1573         }
1574         byte[] b = new byte[len];
1575 
1576         int offs = 0;
1577         for (byte[] a : arrays) {
1578             System.arraycopy(a, 0, b, offs, a.length);
1579             offs += a.length;
1580         }
1581         return b;
1582     }
1583 }
1584