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