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