1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.media.audiofx;
18
19import android.annotation.SdkConstant;
20import android.annotation.SdkConstant.SdkConstantType;
21import android.annotation.TestApi;
22import android.app.ActivityThread;
23import android.os.Handler;
24import android.os.Looper;
25import android.os.Message;
26import android.util.Log;
27import java.lang.ref.WeakReference;
28import java.nio.ByteOrder;
29import java.nio.ByteBuffer;
30import 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
61public class AudioEffect {
62    static {
63        System.loadLibrary("audioeffect_jni");
64        native_init();
65    }
66
67    private final static String TAG = "AudioEffect-JAVA";
68
69    // 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