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