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