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