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