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