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