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