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