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