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