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