Merge "Dropbox: remove redundant Entry construction." into gingerbread
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
new file mode 100644
index 0000000..2bdba2d
--- /dev/null
+++ b/include/media/AudioEffect.h
@@ -0,0 +1,462 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_AUDIOEFFECT_H
+#define ANDROID_AUDIOEFFECT_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <media/IAudioFlinger.h>
+#include <media/IEffect.h>
+#include <media/IEffectClient.h>
+#include <media/EffectApi.h>
+#include <media/AudioSystem.h>
+
+#include <utils/RefBase.h>
+#include <utils/Errors.h>
+#include <binder/IInterface.h>
+
+
+namespace android {
+
+// ----------------------------------------------------------------------------
+
+class effect_param_cblk_t;
+
+// ----------------------------------------------------------------------------
+
+class AudioEffect : public RefBase
+{
+public:
+
+    /*
+     *  Static methods for effect libraries management.
+     */
+
+    /*
+     *   Loads the effect library which path is given as first argument.
+     *   This must be the full path of a dynamic library (.so) implementing one or
+     *   more effect engines and exposing the effect library interface described in
+     *   EffectApi.h. The function returns a handle on the library for use by
+     *   further call to unloadEffectLibrary() to unload the library.
+     *
+     *   Parameters:
+     *          libPath:    full path of the dynamic library file in the file system.
+     *          handle:     address where to return the library handle
+     *
+     *   Returned status (from utils/Errors.h) can be:
+     *          NO_ERROR    successful operation.
+     *          PERMISSION_DENIED could not get AudioFlinger interface or
+     *                      application does not have permission to configure audio
+     *          NO_INIT     effect factory not initialized or
+     *                      library could not be loaded or
+     *                      library does not implement required functions
+     *          BAD_VALUE   invalid libPath string or handle
+     *
+     *   Returned value:
+     *          *handle updated with library handle
+     */
+    static status_t loadEffectLibrary(const char *libPath, int *handle);
+
+    /*
+     *   Unloads the effect library which handle is given as argument.
+     *
+     *   Parameters:
+     *          handle: library handle
+     *
+     *   Returned status (from utils/Errors.h) can be:
+     *          NO_ERROR    successful operation.
+     *          PERMISSION_DENIED could not get AudioFlinger interface or
+     *                      application does not have permission to configure audio
+     *          NO_INIT     effect factory not initialized
+     *          BAD_VALUE   invalid handle
+     */
+    static status_t unloadEffectLibrary(int handle);
+
+    /*
+     *  Static methods for effects enumeration.
+     */
+
+    /*
+     * Returns the number of effects available. This method together
+     * with EffectQueryNext() is used to enumerate all effects:
+     * The enumeration sequence is:
+     *      QueryNumberEffects(&num_effects);
+     *      while (num_effects--)
+     *          QueryNextEffect();
+     *
+     * Parameters:
+     *      pNumEffects:    address where the number of effects should be returned.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR   successful operation.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *      NO_INIT    effect library failed to initialize
+     *      BAD_VALUE  invalid numEffects pointer
+     *
+     * Returned value
+     *   *numEffects:     updated with number of effects available
+     */
+    static status_t queryNumberEffects(uint32_t *numEffects);
+
+    /*
+     * Returns number effect descriptor during effect
+     * enumeration.
+     *
+     * Parameters:
+     *      pDescriptor:    address where the effect descriptor should be returned.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      NAME_NOT_FOUND  no more effect available
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *      NO_INIT         effect library failed to initialize
+     *      BAD_VALUE       invalid descriptor pointer
+     *      INVALID_OPERATION  effect list has changed since last execution of queryNumberEffects()
+     *
+     * Returned value
+     *   *descriptor:     updated with effect descriptor
+     */
+    static status_t queryNextEffect(effect_descriptor_t *descriptor);
+
+
+    /*
+     * Returns the descriptor for the specified effect uuid.
+     *
+     * Parameters:
+     *      uuid:       pointer to effect uuid.
+     *      descriptor: address where the effect descriptor should be returned.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *      NO_ERROR        successful operation.
+     *      PERMISSION_DENIED could not get AudioFlinger interface
+     *      NO_INIT         effect library failed to initialize
+     *      BAD_VALUE       invalid uuid or descriptor pointers
+     *      NAME_NOT_FOUND  no effect with this uuid found
+     *
+     * Returned value
+     *   *descriptor updated with effect descriptor
+     */
+    static status_t getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor);
+
+
+    /*
+     * Events used by callback function (effect_callback_t).
+     */
+    enum event_type {
+        EVENT_CONTROL_STATUS_CHANGED = 0,
+        EVENT_ENABLE_STATUS_CHANGED = 1,
+        EVENT_PARAMETER_CHANGED = 2,
+        EVENT_ERROR = 3
+    };
+
+    /* Callback function notifying client application of a change in effect engine state or
+     * configuration.
+     * An effect engine can be shared by several applications but only one has the control
+     * of the engine activity and configuration at a time.
+     * The EVENT_CONTROL_STATUS_CHANGED event is received when an application loses or
+     * retrieves the control of the effect engine. Loss of control happens
+     * if another application requests the use of the engine by creating an AudioEffect for
+     * the same effect type but with a higher priority. Control is returned when the
+     * application having the control deletes its AudioEffect object.
+     * The EVENT_ENABLE_STATUS_CHANGED event is received by all applications not having the
+     * control of the effect engine when the effect is enabled or disabled.
+     * The EVENT_PARAMETER_CHANGED event is received by all applications not having the
+     * control of the effect engine when an effect parameter is changed.
+     * The EVENT_ERROR event is received when the media server process dies.
+     *
+     * Parameters:
+     *
+     * event:   type of event notified (see enum AudioEffect::event_type).
+     * user:    Pointer to context for use by the callback receiver.
+     * info:    Pointer to optional parameter according to event type:
+     *  - EVENT_CONTROL_STATUS_CHANGED:  boolean indicating if control is granted (true)
+     *  or stolen (false).
+     *  - EVENT_ENABLE_STATUS_CHANGED: boolean indicating if effect is now enabled (true)
+     *  or disabled (false).
+     *  - EVENT_PARAMETER_CHANGED: pointer to a effect_param_t structure.
+     *  - EVENT_ERROR:  status_t indicating the error (DEAD_OBJECT when media server dies).
+     */
+
+    typedef void (*effect_callback_t)(int32_t event, void* user, void *info);
+
+
+    /* Constructor.
+     * AudioEffect is the base class for creating and controlling an effect engine from
+     * the application process. Creating an AudioEffect object will create the effect engine
+     * in the AudioFlinger if no engine of the specified type exists. If one exists, this engine
+     * will be used. The application creating the AudioEffect object (or a derived class like
+     * Reverb for instance) will either receive control of the effect engine or not, depending
+     * on the priority parameter. If priority is higher than the priority used by the current
+     * effect engine owner, the control will be transfered to the new application. Otherwise
+     * control will remain to the previous application. In this case, the new application will be
+     * notified of changes in effect engine state or control ownership by the effect callback.
+     * After creating the AudioEffect, the application must call the initCheck() method and
+     * check the creation status before trying to control the effect engine (see initCheck()).
+     * If the effect is to be applied to an AudioTrack or MediaPlayer only the application
+     * must specify the audio session ID corresponding to this player.
+     */
+
+    /* Simple Constructor.
+     */
+    AudioEffect();
+
+
+    /* Constructor.
+     *
+     * Parameters:
+     *
+     * type:  type of effect created: can be null if uuid is specified. This corresponds to
+     *        the OpenSL ES interface implemented by this effect.
+     * uuid:  Uuid of effect created: can be null if type is specified. This uuid corresponds to
+     *        a particular implementation of an effect type.
+     * priority:    requested priority for effect control: the priority level corresponds to the
+     *      value of priority parameter: negative values indicate lower priorities, positive values
+     *      higher priorities, 0 being the normal priority.
+     * cbf:         optional callback function (see effect_callback_t)
+     * user:        pointer to context for use by the callback receiver.
+     * sessionID:   audio session this effect is associated to. If 0, the effect will be global to
+     *      the output mix. If not 0, the effect will be applied to all players
+     *      (AudioTrack or MediaPLayer) within the same audio session.
+     * output:  HAL audio output stream to which this effect must be attached. Leave at 0 for
+     *      automatic output selection by AudioFlinger.
+     */
+
+    AudioEffect(const effect_uuid_t *type,
+                const effect_uuid_t *uuid = NULL,
+                  int32_t priority = 0,
+                  effect_callback_t cbf = 0,
+                  void* user = 0,
+                  int sessionId = 0,
+                  audio_io_handle_t output = 0
+                  );
+
+    /* Constructor.
+     *      Same as above but with type and uuid specified by character strings
+     */
+    AudioEffect(const char *typeStr,
+                    const char *uuidStr = NULL,
+                    int32_t priority = 0,
+                    effect_callback_t cbf = 0,
+                    void* user = 0,
+                    int sessionId = 0,
+                    audio_io_handle_t output = 0
+                    );
+
+    /* Terminates the AudioEffect and unregisters it from AudioFlinger.
+     * The effect engine is also destroyed if this AudioEffect was the last controlling
+     * the engine.
+     */
+                        ~AudioEffect();
+
+    /* Initialize an uninitialized AudioEffect.
+    * Returned status (from utils/Errors.h) can be:
+    *  - NO_ERROR or ALREADY_EXISTS: successful initialization
+    *  - INVALID_OPERATION: AudioEffect is already initialized
+    *  - BAD_VALUE: invalid parameter
+    *  - NO_INIT: audio flinger or audio hardware not initialized
+    * */
+            status_t    set(const effect_uuid_t *type,
+                            const effect_uuid_t *uuid = NULL,
+                            int32_t priority = 0,
+                            effect_callback_t cbf = 0,
+                            void* user = 0,
+                            int sessionId = 0,
+                            audio_io_handle_t output = 0
+                            );
+
+    /* Result of constructing the AudioEffect. This must be checked
+     * before using any AudioEffect API.
+     * initCheck() can return:
+     *  - NO_ERROR:    the effect engine is successfully created and the application has control.
+     *  - ALREADY_EXISTS: the effect engine is successfully created but the application does not
+     *              have control.
+     *  - NO_INIT:     the effect creation failed.
+     *
+     */
+            status_t    initCheck() const;
+
+
+    /* Returns the unique effect Id for the controlled effect engine. This ID is unique
+     * system wide and is used for instance in the case of auxiliary effects to attach
+     * the effect to an AudioTrack or MediaPlayer.
+     *
+     */
+            int32_t     id() const { return mId; }
+
+    /* Returns a descriptor for the effect (see effect_descriptor_t in EffectApi.h).
+     */
+            effect_descriptor_t descriptor() const;
+
+    /* Returns effect control priority of this AudioEffect object.
+     */
+            int32_t     priority() const { return mPriority; }
+
+
+    /* Enables the effect engine.
+     *
+     * Parameters:
+     *      None.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the application does not have control of the effect engine
+     */
+            status_t    enable();
+
+    /* Disables the effect engine.
+     *
+     * Parameters:
+     *      None.
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation
+     *  - INVALID_OPERATION: the application does not have control of the effect engine
+     */
+             status_t    disable();
+
+             bool        isEnabled() const;
+
+    /* Sets a parameter value.
+     *
+     * Parameters:
+     *      param:  pointer to effect_param_t structure containing the parameter
+     *          and its value (See EffectApi.h).
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation.
+     *  - INVALID_OPERATION: the application does not have control of the effect engine.
+     *  - BAD_VALUE: invalid parameter identifier or value.
+     *  - DEAD_OBJECT: the effect engine has been deleted.
+     */
+             status_t   setParameter(effect_param_t *param);
+
+    /* Prepare a new parameter value that will be set by next call to
+     * setParameterCommit(). This method can be used to set multiple parameters
+     * in a synchronous manner or to avoid multiple binder calls for each
+     * parameter.
+     *
+     * Parameters:
+     *      param:  pointer to effect_param_t structure containing the parameter
+     *          and its value (See EffectApi.h).
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation.
+     *  - INVALID_OPERATION: the application does not have control of the effect engine.
+     *  - NO_MEMORY: no more space available in shared memory used for deferred parameter
+     *  setting.
+     */
+             status_t   setParameterDeferred(effect_param_t *param);
+
+     /* Commit all parameter values previously prepared by setParameterDeferred().
+      *
+      * Parameters:
+      *     none
+      *
+      * Returned status (from utils/Errors.h) can be:
+      *  - NO_ERROR: successful operation.
+      *  - INVALID_OPERATION: No new parameter values ready for commit.
+      *  - BAD_VALUE: invalid parameter identifier or value: there is no indication
+      *     as to which of the parameters caused this error.
+      *  - DEAD_OBJECT: the effect engine has been deleted.
+      */
+             status_t   setParameterCommit();
+
+    /* Gets a parameter value.
+     *
+     * Parameters:
+     *      param:  pointer to effect_param_t structure containing the parameter
+     *          and the returned value (See EffectApi.h).
+     *
+     * Returned status (from utils/Errors.h) can be:
+     *  - NO_ERROR: successful operation.
+     *  - INVALID_OPERATION: the AudioEffect was not successfully initialized.
+     *  - BAD_VALUE: invalid parameter identifier.
+     *  - DEAD_OBJECT: the effect engine has been deleted.
+     */
+             status_t   getParameter(effect_param_t *param);
+
+     /* Sends a command and receives a response to/from effect engine.
+      *     See EffectApi.h for details on effect command() function, valid command codes
+      *     and formats.
+      */
+             status_t command(int32_t cmdCode, int32_t cmdSize, void *cmdData, int32_t *replySize, void *replyData);
+
+
+     /*
+      * Utility functions.
+      */
+
+     /* Converts the string passed as first argument to the effect_uuid_t
+      * pointed to by second argument
+      */
+     static status_t stringToGuid(const char *str, effect_uuid_t *guid);
+     /* Converts the effect_uuid_t pointed to by first argument to the
+      * string passed as second argument
+      */
+     static status_t guidToString(const effect_uuid_t *guid, char *str, size_t maxLen);
+
+private:
+
+     // Implements the IEffectClient interface
+    class EffectClient : public android::BnEffectClient,  public android::IBinder::DeathRecipient
+    {
+    public:
+
+        EffectClient(AudioEffect *effect) : mEffect(effect){}
+
+        // IEffectClient
+        virtual void controlStatusChanged(bool controlGranted) {mEffect->controlStatusChanged(controlGranted);}
+        virtual void enableStatusChanged(bool enabled) {mEffect->enableStatusChanged(enabled);}
+        virtual void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData) {
+            mEffect->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
+        }
+
+        // IBinder::DeathRecipient
+        virtual void binderDied(const wp<IBinder>& who) {mEffect->binderDied();}
+
+    private:
+        AudioEffect *mEffect;
+    };
+
+
+    friend class EffectClient;
+
+    // IEffectClient
+    void controlStatusChanged(bool controlGranted);
+    void enableStatusChanged(bool enabled);
+    void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData);
+    void binderDied();
+
+
+    sp<IEffect>             mIEffect;           // IEffect binder interface
+    sp<EffectClient>        mIEffectClient;     // IEffectClient implementation
+    sp<IMemory>             mCblkMemory;        // shared memory for deferred parameter setting
+    effect_param_cblk_t*    mCblk;              // control block for deferred parameter setting
+    int32_t                 mPriority;          // priority for effect control
+    status_t                mStatus;            // effect status
+    volatile int32_t        mEnabled;           // enable state
+    effect_callback_t       mCbf;               // callback function for status, control, parameter changes notifications
+    void*                   mUserData;          // client context for callback function
+    effect_descriptor_t     mDescriptor;        // effect descriptor
+    int32_t                 mId;                // system wide unique effect engine instance identifier
+    int32_t                 mSessionId;         // audio session ID
+};
+
+
+}; // namespace android
+
+#endif // ANDROID_AUDIOEFFECT_H
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
new file mode 100644
index 0000000..b1b7fed
--- /dev/null
+++ b/media/java/android/media/AudioEffect.java
@@ -0,0 +1,954 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.util.Log;
+import java.lang.ref.WeakReference;
+import java.io.IOException;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import java.nio.ByteOrder;
+import java.nio.ByteBuffer;
+import java.util.UUID;
+
+/**
+ * AudioEffect is the base class for implementing audio effect control in Java applications.
+ * Creating an AudioEffect object will create the effect engine in audio framework if no
+ * instance of the same effect type exists in the specified audio session.
+ * If one exists, this instance will be used. The application creating the AudioEffect object
+ * (or a derived class) will either receive control of the effect engine or not depending
+ * on the priority parameter. If priority is higher than the priority used by the current
+ * effect engine owner, the control will be transfered to the new object. Otherwise
+ * control will remain with the previous object. In this case, the new application will be
+ * notified of changes in effect engine state or control ownership by the appropiate listener.
+ * If the effect is to be applied to a specific AudioTrack or MediaPlayer instance,
+ * the application must specify the audio session ID of that instance.
+ *
+ * {@hide Pending API council review}
+ */
+public class AudioEffect
+{
+    static {
+        System.loadLibrary("audioeffect_jni");
+        native_init();
+    }
+
+    private final static String TAG = "AudioEffect-JAVA";
+
+    /**
+     * The following UUIDs define effect types corresponding to standard audio effects
+     * whose implementation and interface conform to the OpenSL ES specification.
+     * The definitions match the corresponding interface IDs in OpenSLES_IID.h
+     */
+    public static final UUID EFFECT_TYPE_ENV_REVERB = UUID.fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
+    public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID.fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
+    public static final UUID EFFECT_TYPE_EQUALIZER = UUID.fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
+    public static final UUID EFFECT_TYPE_BASS_BOOST = UUID.fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
+    public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID.fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
+
+    public static final UUID EFFECT_TYPE_INVALID = UUID.fromString("ec7178ec-e5e1-4432-a3f4-4657e6795210");
+
+    /**
+     * State of an AudioEffect object that was not successfully initialized upon creation
+     */
+    public static final int STATE_UNINITIALIZED = 0;
+    /**
+     * State of an AudioEffect object that is ready to be used.
+     */
+    public static final int STATE_INITIALIZED   = 1;
+
+    /**
+     * Event id for engine state change notification.
+     */
+    protected static final int NATIVE_EVENT_ENABLED_STATUS  = 0;
+    /**
+     * Event id for engine control ownership change notification.
+     */
+    protected static final int NATIVE_EVENT_CONTROL_STATUS = 1;
+    /**
+     * Event id for engine parameter change notification.
+     */
+    protected static final int NATIVE_EVENT_PARAMETER_CHANGED = 2;
+
+
+    // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
+    public  static final int SUCCESS              = 0;
+    public  static final int ERROR                = -1;
+    public  static final int ALREADY_EXISTS       = -2;
+    public  static final int NO_INIT              = -3;
+    public  static final int BAD_VALUE            = -4;
+    public  static final int INVALID_OPERATION    = -5;
+    public  static final int NO_MEMORY            = -6;
+    public  static final int DEAD_OBJECT          = -7;
+
+
+     /**
+      * The effect descriptor contains necessary information to facilitate
+      * effects enumeration:
+      * mType: UUID corresponding to the OpenSL ES interface implemented by this effect
+      * mUuid: UUID for this particular implementation
+      * mConnectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}
+      * mName: human readable effect name
+      * mImplementor: human readable effect implementor name
+      */
+     public static class Descriptor {
+
+         public Descriptor() {
+         }
+         public Descriptor(String type,
+                           String uuid,
+                           String connectMode,
+                           String name,
+                           String implementor) {
+             mType = UUID.fromString(type);
+             mUuid = UUID.fromString(uuid);
+             mConnectMode = connectMode;
+             mName = name;
+             mImplementor = implementor;
+         }
+
+         public UUID mType;
+         public UUID mUuid;
+         public String mConnectMode;
+         public String mName;
+         public String mImplementor;
+     };
+
+     public static final String EFFECT_INSERT = "Insert";
+     public static final String EFFECT_AUXILIARY = "Auxiliary";
+
+    //--------------------------------------------------------------------------
+    // Member variables
+    //--------------------
+    /**
+     * Indicates the state of the AudioEffect instance
+     */
+    protected int mState = STATE_UNINITIALIZED;
+    /**
+     * Lock to synchronize access to mState
+     */
+    protected final Object mStateLock = new Object();
+    /**
+     * System wide unique effect ID
+     */
+    protected int mId;
+
+    // accessed by native methods
+    private int mNativeAudioEffect;
+    private int mJniData;
+
+    /**
+     * Effect descriptor
+     */
+    private Descriptor mDescriptor;
+
+    /**
+     * Listener for effect engine state change notifications.
+     *  @see #setEnableStatusListener(OnEnableStatusChangeListener)
+     */
+    protected OnEnableStatusChangeListener mEnableStatusChangeListener = null;
+    /**
+     * Listener for effect engine control ownership change notifications.
+     *  @see #setControlStatusListener(OnControlStatusChangeListener)
+     */
+    protected OnControlStatusChangeListener mControlChangeStatusListener = null;
+    /**
+     * Listener for effect engine control ownership change notifications.
+     *  @see #setParameterListener(OnParameterChangeListener)
+     */
+    protected OnParameterChangeListener mParameterChangeListener = null;
+    /**
+     * Lock to protect listeners updates against event notifications
+     */
+    protected final Object mListenerLock = new Object();
+    /**
+     * Handler for events coming from the native code
+     */
+    protected NativeEventHandler mNativeEventHandler = null;
+
+
+
+    //--------------------------------------------------------------------------
+    // Constructor, Finalize
+    //--------------------
+    /**
+     * Class constructor.
+     * @param type:  type of effect engine created. See
+     *   {@link #EFFECT_TYPE_ENV_REVERB}, {@link #EFFECT_TYPE_EQUALIZER} ...
+     *   Types corresponding to built-in effects are defined by AudioEffect class.
+     *   Other types can be specified provided they correspond an existing OpenSL ES
+     *   interface ID and the corresponsing effect is available on the platform.
+     *   If an unspecified effect type is requested, the constructor with throw the
+     *   IllegalArgumentException.
+     * @param uuid:  unique identifier of a particular effect implementation. Must be
+     *  specified if the caller wants to use a particular implementation of an effect type.
+     *  This parameter can be set to null in which case only the type will be used to select
+     *  the effect.
+     * @param priority:  the priority level requested by the application for controlling
+     *  the effect engine. As the same effect engine can be shared by several applications,
+     *  this parameter indicates how much the requesting application needs control of
+     *  effect parameters. The normal priority is 0, above normal is a positive number,
+     *  below normal a negative number.
+     * @param audioSession:  System wide unique audio session identifier. If audioSession
+     *  is not 0, the effect will be attached to the MediaPlayer or AudioTrack in the
+     *  same audio session. Otherwise, the effect will apply to the output mix.
+     *
+     * @throws java.lang.IllegalArgumentException
+     * @throws java.lang.UnsupportedOperationException
+     * @throws java.lang.RuntimeException
+     */
+
+    public AudioEffect(UUID type, UUID uuid, int priority, int audioSession)
+    throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+        int[] id = new int[1];
+        Descriptor[] desc = new Descriptor[1];
+        // native initialization
+        int initResult = native_setup(new WeakReference<AudioEffect>(this),
+                type.toString(), uuid.toString(), priority, audioSession, id, desc);
+        if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
+            Log.e(TAG, "Error code "+initResult+" when initializing AudioEffect.");
+            switch (initResult) {
+            case BAD_VALUE:
+                throw (new IllegalArgumentException("Effect type: "+type+ " not supported."));
+            case INVALID_OPERATION:
+                throw (new UnsupportedOperationException("Effect library not loaded"));
+            default:
+                throw (new RuntimeException("Cannot initialize effect engine for type: "+type+
+                        "Error: "+ initResult));
+            }
+        }
+        mId = id[0];
+        mDescriptor = desc[0];
+        synchronized (mStateLock) {
+            mState = STATE_INITIALIZED;
+        }
+    }
+
+    /**
+     * Releases the native AudioEffect resources. It is a good practice to release the
+     * effect engine when not in use as control can be returned to other applications
+     * or the native resources released.
+     */
+    public void release() {
+        synchronized (mStateLock) {
+            native_release();
+            mState = STATE_UNINITIALIZED;
+        }
+    }
+
+    @Override
+    protected void finalize() {
+        native_finalize();
+    }
+
+    /**
+     * Get the effect descriptor.
+     * {@see #Descriptor}.
+     * @throws IllegalStateException
+     */
+    public Descriptor getDescriptor()
+    throws IllegalStateException {
+        checkState("getDescriptor()");
+        return mDescriptor;
+    }
+
+    //--------------------------------------------------------------------------
+    // Effects Enumeration
+    //--------------------
+
+    /**
+     * Query all effects available on the platform. Returns an array of
+     * {@link #Descriptor} objects
+     *
+     * @throws IllegalStateException
+     */
+
+    static public Descriptor[] queryEffects() {
+        return (Descriptor[])native_query_effects();
+    }
+
+    //--------------------------------------------------------------------------
+    // Control methods
+    //--------------------
+
+    /**
+     * Enable effect engine.
+     * @return {@link #NO_ERROR} in case of success,
+     * {@link #INVALID_OPERATION} or {@link #DEAD_OBJECT} in case of failure.
+     * @throws IllegalStateException
+     */
+    public int enable()
+    throws IllegalStateException {
+        checkState("enable()");
+        return native_enable();
+    }
+
+    /**
+     * Disable effect engine.
+     * @return NO_ERROR in case of success,
+     * INVALID_OPERATION or DEAD_OBJECT in case of failure.
+     * @throws IllegalStateException
+     */
+    public int disable()
+    throws IllegalStateException {
+        checkState("disable()");
+        return native_disable();
+    }
+
+    /**
+     * Set effect parameter. The setParameter method is provided in several
+     * forms addressing most common parameter formats. This form is the
+     * most generic one where the parameter and its value are both specified
+     * as an array of bytes. The parameter and value type and length are therefore
+     * totally free. For standard effect defined by OpenSL ES, the parameter format
+     * and values must match the definitions in the corresponding OpenSL ES interface.
+     *
+     * @param param:  the identifier of the parameter to set
+     * @param value:  the new value for the specified parameter
+     * @return NO_ERROR in case of success,
+     * {@link #BAD_VALUE}, {@link #NO_MEMORY}, {@link #INVALID_OPERATION} or {@link DEAD_OBJECT} in case of failure
+     * @throws IllegalStateException
+     */
+    public int setParameter(byte[] param, byte[] value)
+    throws IllegalStateException {
+        checkState("setParameter()");
+        return native_setParameter(param.length, param, value.length, value);
+    }
+
+    /**
+     * Set effect parameter. The parameter and its value are integers.
+     *  @see #setParameter(byte[], byte[])
+     */
+    public int setParameter(int param, int value)
+    throws IllegalStateException {
+        byte[] p = intToByteArray(param);
+        byte[] v = intToByteArray(value);
+        return setParameter(p, v);
+    }
+
+    /**
+     * Set effect parameter. The parameter is an integer and the value is a short integer.
+     *  @see #setParameter(byte[], byte[])
+     */
+    public int setParameter(int param, short value)
+    throws IllegalStateException {
+        byte[] p = intToByteArray(param);
+        byte[] v = shortToByteArray(value);
+        return setParameter(p, v);
+    }
+
+    /**
+     * Set effect parameter. The parameter is an integer and the value is an array of bytes.
+     *  @see #setParameter(byte[], byte[])
+     */
+    public int setParameter(int param, byte[] value)
+    throws IllegalStateException {
+        byte[] p = intToByteArray(param);
+        return setParameter(p, value);
+    }
+
+    /**
+     * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
+     *  is also an array of 1 or 2 integers
+     *  @see #setParameter(byte[], byte[])
+     */
+    public int setParameter(int[] param, int[] value)
+    throws IllegalStateException {
+        if (param.length > 2 || value.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param[0]);
+        if (param.length > 1) {
+            byte[] p2 = intToByteArray(param[1]);
+            p = concatArrays(p, p2);
+        }
+        byte[] v = intToByteArray(value[0]);
+        if (value.length > 1) {
+            byte[] v2 = intToByteArray(value[1]);
+            v = concatArrays(v, v2);
+        }
+        return setParameter(p, v);
+    }
+
+    /**
+     * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
+     *  is an array of 1 or 2 short integers
+     *  @see #setParameter(byte[], byte[])
+     */
+    public int setParameter(int[] param, short[] value)
+    throws IllegalStateException {
+        if (param.length > 2 || value.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param[0]);
+        if (param.length > 1) {
+            byte[] p2 = intToByteArray(param[1]);
+            p = concatArrays(p, p2);
+        }
+
+        byte[] v = shortToByteArray(value[0]);
+        if (value.length > 1) {
+            byte[] v2 = shortToByteArray(value[1]);
+            v = concatArrays(v, v2);
+        }
+        return setParameter(p, v);
+    }
+
+    /**
+     * Set effect parameter. The parameter is an array of 1 or 2 integers and the value
+     *  is an array of bytes
+     *  @see #setParameter(byte[], byte[])
+     */
+    public int setParameter(int[] param, byte[] value)
+    throws IllegalStateException {
+        if (param.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param[0]);
+        if (param.length > 1) {
+            byte[] p2 = intToByteArray(param[1]);
+            p = concatArrays(p, p2);
+        }
+        return setParameter(p, value);
+    }
+
+    /**
+     * Get effect parameter. The getParameter method is provided in several
+     * forms addressing most common parameter formats. This form is the
+     * most generic one where the parameter and its value are both specified
+     * as an array of bytes. The parameter and value type and length are therefore
+     * totally free.
+     * @param param:  the identifier of the parameter to set
+     * @param value:  the new value for the specified parameter
+     * @return NO_ERROR in case of success,
+     * {@link #BAD_VALUE}, {@link #NO_MEMORY}, {@link #INVALID_OPERATION} or {@link DEAD_OBJECT} in case of failure
+     * When called, value.length indicates the maximum size of the returned parameters value.
+     * When returning, value.length is updated with the actual size of the returned value.
+     * @throws IllegalStateException
+     */
+    public int getParameter(byte[] param, byte[] value)
+    throws IllegalStateException {
+        checkState("getParameter()");
+        int[] vSize = new int[1];
+        vSize[0] = value.length;
+        int status = native_getParameter(param.length, param, vSize, value);
+        if (value.length > vSize[0]) {
+            byte[] resizedValue = new byte[vSize[0]];
+            System.arraycopy(value, 0, resizedValue, 0, vSize[0]);
+            value = resizedValue;
+        }
+        return status;
+    }
+
+    /**
+     * Get effect parameter. The parameter is an integer and the value is an array of bytes.
+     *  @see #getParameter(byte[], byte[])
+     */
+    public int getParameter(int param, byte[] value)
+    throws IllegalStateException {
+        byte[] p = intToByteArray(param);
+
+        return getParameter(p, value);
+    }
+
+    /**
+     * Get effect parameter. The parameter is an integer and the value
+     *  is an array of 1 or 2 integers
+     *  @see #getParameter(byte[], byte[])
+     */
+    public int getParameter(int param, int[] value)
+    throws IllegalStateException {
+        if (value.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param);
+
+        byte[] v = new byte[value.length * 4];
+
+        int status = getParameter(p, v);
+
+        value[0] = byteArrayToInt(v);
+        if (v.length > 4) {
+            value[1] = byteArrayToInt(v, 4);
+        }
+        return status;
+    }
+
+    /**
+     * Get effect parameter. The parameter is an integer and the value
+     *  is an array of 1 or 2 short integers
+     *  @see #getParameter(byte[], byte[])
+     */
+    public int getParameter(int param, short[] value)
+    throws IllegalStateException {
+        if (value.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param);
+
+        byte[] v = new byte[value.length * 2];
+
+        int status = getParameter(p, v);
+
+        value[0] = byteArrayToShort(v);
+        if (v.length > 2) {
+            value[1] = byteArrayToShort(v, 2);
+        }
+        return status;
+    }
+
+    /**
+     * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
+     *  is also an array of 1 or 2 integers
+     *  @see #getParameter(byte[], byte[])
+     */
+    public int getParameter(int[] param, int[] value)
+    throws IllegalStateException {
+        if (param.length > 2 || value.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param[0]);
+        if (param.length > 1) {
+            byte[] p2 = intToByteArray(param[1]);
+            p = concatArrays(p, p2);
+        }
+        byte[] v = new byte[value.length * 4];
+
+        int status = getParameter(p, v);
+
+        value[0] = byteArrayToInt(v);
+        if (v.length > 4) {
+            value[1] = byteArrayToInt(v, 4);
+        }
+        return status;
+    }
+
+    /**
+     * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
+     *  is an array of 1 or 2 short integers
+     *  @see #getParameter(byte[], byte[])
+     */
+    public int getParameter(int[] param, short[] value)
+    throws IllegalStateException {
+        if (param.length > 2 || value.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param[0]);
+        if (param.length > 1) {
+            byte[] p2 = intToByteArray(param[1]);
+            p = concatArrays(p, p2);
+        }
+        byte[] v = new byte[value.length * 2];
+
+        int status = getParameter(p, v);
+
+        value[0] = byteArrayToShort(v);
+        if (v.length > 2) {
+            value[1] = byteArrayToShort(v, 2);
+        }
+        return status;
+    }
+
+    /**
+     * Get effect parameter. The parameter is an array of 1 or 2 integers and the value
+     *  is an array of bytes
+     *  @see #getParameter(byte[], byte[])
+     */
+    public int getParameter(int[] param, byte[] value)
+    throws IllegalStateException {
+        if (param.length > 2) {
+            return BAD_VALUE;
+        }
+        byte[] p = intToByteArray(param[0]);
+        if (param.length > 1) {
+            byte[] p2 = intToByteArray(param[1]);
+            p = concatArrays(p, p2);
+        }
+
+        return getParameter(p, value);
+    }
+
+
+    /**
+     * Send a command to the effect engine. This method is intended to send proprietary
+     * commands to a particular effect implementation.
+     *
+     */
+    public int command(int cmdCode, byte[] command, byte[] reply)
+    throws IllegalStateException {
+        checkState("command()");
+        int[] replySize = new int[1];
+        replySize[0] = reply.length;
+
+        int status = native_command(cmdCode, command.length, command, replySize, reply);
+
+        if (reply.length > replySize[0]) {
+            byte[] resizedReply = new byte[replySize[0]];
+            System.arraycopy(reply, 0, resizedReply, 0, replySize[0]);
+            reply = resizedReply;
+        }
+        return status;
+    }
+
+    //--------------------------------------------------------------------------
+    // Getters
+    //--------------------
+
+    /**
+     * Returns effect unique identifier. This system wide unique identifier
+     * can be used to attach this effect to a MediaPlayer or an AudioTrack
+     * when the effect is an auxiliary effect (Reverb)
+     * @return the effect identifier.
+     * @throws IllegalStateException
+     */
+    public int getId()
+    throws IllegalStateException {
+        checkState("getId()");
+        return mId;
+    }
+
+    /**
+     * Returns effect engine enable state
+     * @return true if the effect is enabled, false otherwise.
+     * @throws IllegalStateException
+     */
+    public boolean getEnable()
+    throws IllegalStateException {
+        checkState("getEnable()");
+        return native_getEnable();
+    }
+
+    /**
+     * Checks if this AudioEffect object is controlling the effect engine.
+     * @return true if this instance has control of effect engine, false otherwise.
+     * @throws IllegalStateException
+     */
+    public boolean hasControl()
+    throws IllegalStateException {
+        checkState("hasControl()");
+        return native_hasControl();
+    }
+
+    //--------------------------------------------------------------------------
+    // Initialization / configuration
+    //--------------------
+    /**
+     * Sets the listener AudioEffect notifies when the effect engine is enabled
+     * or disabled.
+     * @param listener
+     */
+    public void setEnableStatusListener(OnEnableStatusChangeListener listener) {
+        synchronized (mListenerLock) {
+            mEnableStatusChangeListener = listener;
+        }
+        if ((listener != null) && (mNativeEventHandler == null)) {
+            createNativeEventHandler();
+        }
+    }
+
+    /**
+     * Sets the listener AudioEffect notifies when the effect engine control
+     * is taken or returned.
+     * @param listener
+     */
+    public void setControlStatusListener(OnControlStatusChangeListener listener) {
+        synchronized (mListenerLock) {
+            mControlChangeStatusListener = listener;
+        }
+        if ((listener != null) && (mNativeEventHandler == null)) {
+            createNativeEventHandler();
+        }
+    }
+
+    /**
+     * Sets the listener AudioEffect notifies when a parameter is changed.
+     * @param listener
+     */
+    public void setParameterListener(OnParameterChangeListener listener) {
+        synchronized (mListenerLock) {
+            mParameterChangeListener = listener;
+        }
+        if ((listener != null) && (mNativeEventHandler == null)) {
+            createNativeEventHandler();
+        }
+    }
+
+    // Convenience method for the creation of the native event handler
+    // It is called only when a non-null event listener is set.
+    // precondition:
+    //    mNativeEventHandler is null
+    private void createNativeEventHandler() {
+        Looper looper;
+        if ((looper = Looper.myLooper()) != null) {
+            mNativeEventHandler = new NativeEventHandler(this, looper);
+        } else if ((looper = Looper.getMainLooper()) != null) {
+            mNativeEventHandler = new NativeEventHandler(this, looper);
+        } else {
+            mNativeEventHandler = null;
+        }
+    }
+
+    //---------------------------------------------------------
+    // Interface definitions
+    //--------------------
+    /**
+     * Interface definition for a callback to be invoked when the
+     * effect engine is enabled or disabled.
+     */
+    public interface OnEnableStatusChangeListener  {
+        /**
+         * Called on the listener to notify it that the effect engine
+         * has been enabled or disabled.
+         */
+        void onEnableStatusChange(AudioEffect effect, boolean enabled);
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when the
+     * effect engine control is taken or returned.
+     */
+    public interface OnControlStatusChangeListener  {
+        /**
+         * Called on the listener to notify it that the effect engine
+         * control has been taken or returned.
+         */
+        void onControlStatusChange(AudioEffect effect, boolean controlGranted);
+    }
+
+    /**
+     * Interface definition for a callback to be invoked when a
+     * parameter value has changed.
+     */
+    public interface OnParameterChangeListener  {
+        /**
+         * Called on the listener to notify it that a parameter value has changed.
+         */
+        void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value);
+    }
+
+    //---------------------------------------------------------
+    // Inner classes
+    //--------------------
+    /**
+     * Helper class to handle the forwarding of native events to the appropriate listeners
+     */
+    private class NativeEventHandler extends Handler
+    {
+        private AudioEffect mAudioEffect;
+
+        public NativeEventHandler(AudioEffect ae, Looper looper) {
+            super(looper);
+            mAudioEffect = ae;
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            if (mAudioEffect == null) {
+                return;
+            }
+            switch(msg.what) {
+            case NATIVE_EVENT_ENABLED_STATUS:
+                OnEnableStatusChangeListener enableStatusChangeListener = null;
+                synchronized (mListenerLock) {
+                    enableStatusChangeListener = mAudioEffect.mEnableStatusChangeListener;
+                }
+                if (enableStatusChangeListener != null) {
+                    enableStatusChangeListener.onEnableStatusChange(mAudioEffect, (boolean)(msg.arg1 != 0));
+                }
+                break;
+            case NATIVE_EVENT_CONTROL_STATUS:
+                OnControlStatusChangeListener controlStatusChangeListener = null;
+                synchronized (mListenerLock) {
+                    controlStatusChangeListener = mAudioEffect.mControlChangeStatusListener;
+                }
+                if (controlStatusChangeListener != null) {
+                    controlStatusChangeListener.onControlStatusChange(mAudioEffect, (boolean)(msg.arg1 != 0));
+                }
+                break;
+            case NATIVE_EVENT_PARAMETER_CHANGED:
+                OnParameterChangeListener parameterChangeListener = null;
+                synchronized (mListenerLock) {
+                    parameterChangeListener = mAudioEffect.mParameterChangeListener;
+                }
+                if (parameterChangeListener != null) {
+                    // arg1 contains offset of parameter value from start of byte array
+                    int vOffset = msg.arg1;
+                    byte[] p = (byte[])msg.obj;
+                    // See effect_param_t in EffectApi.h for psize and vsize fields offsets
+                    int status = byteArrayToInt(p, 0);
+                    int psize = byteArrayToInt(p, 4);
+                    int vsize = byteArrayToInt(p, 8);
+                    byte[] param = new byte[psize];
+                    byte[] value = new byte[vsize];
+                    System.arraycopy(p, 12, param, 0, psize);
+                    System.arraycopy(p, vOffset, value, 0, vsize);
+
+                    parameterChangeListener.onParameterChange(mAudioEffect, status, param, value);
+                }
+                break;
+
+             default:
+                Log.e(TAG, "handleMessage() Unknown event type: " + msg.what);
+                break;
+            }
+        }
+    }
+
+
+    //---------------------------------------------------------
+    // Java methods called from the native side
+    //--------------------
+    @SuppressWarnings("unused")
+    private static void postEventFromNative(Object effect_ref,
+            int what, int arg1, int arg2, Object obj) {
+        AudioEffect effect = (AudioEffect)((WeakReference)effect_ref).get();
+        if (effect == null) {
+            return;
+        }
+
+        if (effect.mNativeEventHandler != null) {
+            Message m = effect.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
+            effect.mNativeEventHandler.sendMessage(m);
+        }
+
+    }
+
+
+    //---------------------------------------------------------
+    // Native methods called from the Java side
+    //--------------------
+
+    private static native final void native_init();
+
+    private native final int native_setup(Object audioeffect_this,
+                                          String type,
+                                          String uuid,
+                                          int priority,
+                                          int audioSession,
+                                          int[] id,
+                                          Object[] desc);
+
+    private native final void native_finalize();
+
+    private native final void native_release();
+
+    private native final int native_enable();
+
+    private native final int native_disable();
+
+    private native final boolean native_getEnable();
+
+    private native final boolean native_hasControl();
+
+    private native final int native_setParameter(int psize,
+                                                 byte[] param,
+                                                 int vsize,
+                                                 byte[] value);
+
+    private native final int native_getParameter(int psize,
+                                                 byte[] param,
+                                                 int[] vsize,
+                                                 byte[] value);
+
+    private native final int native_command(int cmdCode,
+                                            int cmdSize,
+                                            byte[] cmdData,
+                                            int[] repSize,
+                                            byte[] repData);
+
+    private static native Object[] native_query_effects();
+
+    //---------------------------------------------------------
+    // Utility methods
+    //------------------
+
+    protected void checkState(String methodName)
+        throws IllegalStateException {
+        synchronized (mStateLock) {
+            if (mState != STATE_INITIALIZED) {
+                throw(new IllegalStateException(methodName+" called on uninitialized AudioEffect."));
+            }
+        }
+    }
+
+    protected void checkStatus(int status) {
+        switch (status) {
+        case AudioEffect.SUCCESS:
+            break;
+        case AudioEffect.BAD_VALUE:
+            throw (new IllegalArgumentException("AudioEffect: bad parameter value"));
+        case AudioEffect.INVALID_OPERATION:
+            throw (new UnsupportedOperationException("AudioEffect: invalid parameter operation"));
+        default:
+            throw (new RuntimeException("AudioEffect: set/get parameter error"));
+        }
+    }
+
+    protected int byteArrayToInt(byte[] valueBuf) {
+        return byteArrayToInt(valueBuf, 0);
+
+    }
+    protected int byteArrayToInt(byte[] valueBuf, int offset) {
+        ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+        converter.order(ByteOrder.nativeOrder());
+        return converter.getInt(offset);
+
+    }
+
+    protected byte[] intToByteArray(int value) {
+        ByteBuffer converter = ByteBuffer.allocate(4);
+        converter.order(ByteOrder.nativeOrder());
+        converter.putInt(value);
+        return converter.array();
+    }
+
+    protected short byteArrayToShort(byte[] valueBuf) {
+        return byteArrayToShort(valueBuf, 0);
+    }
+
+    protected short byteArrayToShort(byte[] valueBuf, int offset) {
+        ByteBuffer converter = ByteBuffer.wrap(valueBuf);
+        converter.order(ByteOrder.nativeOrder());
+        return converter.getShort(offset);
+
+    }
+
+    protected byte[] shortToByteArray(short value) {
+        ByteBuffer converter = ByteBuffer.allocate(2);
+        converter.order(ByteOrder.nativeOrder());
+        short sValue = (short)value;
+        converter.putShort(sValue);
+        return converter.array();
+    }
+
+    protected byte[] concatArrays(byte[] ...arrays) {
+        int len = 0;
+        for (byte[] a : arrays) {
+            len += a.length;
+        }
+        byte[] b = new byte[len];
+
+        int offs = 0;
+        for (byte[] a : arrays) {
+            System.arraycopy(a, 0, b, offs, a.length);
+            offs += a.length;
+        }
+        return b;
+    }
+
+}
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index a6a25cd..698cece 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -65,4 +65,5 @@
 include $(BUILD_SHARED_LIBRARY)
 
 # build libsoundpool.so
-include $(LOCAL_PATH)/soundpool/Android.mk
+# build libaudioeffect_jni.so
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/media/jni/audioeffect/Android.mk b/media/jni/audioeffect/Android.mk
new file mode 100644
index 0000000..d03b63b
--- /dev/null
+++ b/media/jni/audioeffect/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	android_media_AudioEffect.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libutils \
+	libandroid_runtime \
+	libnativehelper \
+	libmedia
+
+LOCAL_MODULE:= libaudioeffect_jni
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
new file mode 100644
index 0000000..de01dd3
--- /dev/null
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -0,0 +1,861 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdio.h>
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioEffects-JNI"
+
+#include <utils/Log.h>
+#include <nativehelper/jni.h>
+#include <nativehelper/JNIHelp.h>
+#include <android_runtime/AndroidRuntime.h>
+#include "media/AudioEffect.h"
+
+using namespace android;
+
+#define AUDIOEFFECT_SUCCESS                      0
+#define AUDIOEFFECT_ERROR                       -1
+#define AUDIOEFFECT_ERROR_ALREADY_EXISTS        -2
+#define AUDIOEFFECT_ERROR_NO_INIT               -3
+#define AUDIOEFFECT_ERROR_BAD_VALUE             -4
+#define AUDIOEFFECT_ERROR_INVALID_OPERATION     -5
+#define AUDIOEFFECT_ERROR_NO_MEMORY             -6
+#define AUDIOEFFECT_ERROR_DEAD_OBJECT           -7
+
+// ----------------------------------------------------------------------------
+static const char* const kClassPathName = "android/media/AudioEffect";
+
+struct fields_t {
+    // these fields provide access from C++ to the...
+    jclass    clazzEffect;          // AudioEffect class
+    jmethodID midPostNativeEvent;   // event post callback method
+    jfieldID  fidNativeAudioEffect; // stores in Java the native AudioEffect object
+    jfieldID  fidJniData;           // stores in Java additional resources used by the native AudioEffect
+    jclass    clazzDesc;            // AudioEffect.Descriptor class
+    jmethodID midDescCstor;         // AudioEffect.Descriptor class constructor
+};
+static fields_t fields;
+
+struct effect_callback_cookie {
+    jclass      audioEffect_class;  // AudioEffect class
+    jobject     audioEffect_ref;    // AudioEffect object instance
+ };
+
+// ----------------------------------------------------------------------------
+class AudioEffectJniStorage {
+    public:
+        effect_callback_cookie mCallbackData;
+
+    AudioEffectJniStorage() {
+    }
+
+    ~AudioEffectJniStorage() {
+    }
+
+};
+
+
+static jint translateError(int code) {
+    switch(code) {
+    case NO_ERROR:
+        return AUDIOEFFECT_SUCCESS;
+    case ALREADY_EXISTS:
+        return AUDIOEFFECT_ERROR_ALREADY_EXISTS;
+    case NO_INIT:
+        return AUDIOEFFECT_ERROR_NO_INIT;
+    case BAD_VALUE:
+        return AUDIOEFFECT_ERROR_BAD_VALUE;
+    case INVALID_OPERATION:
+        return AUDIOEFFECT_ERROR_INVALID_OPERATION;
+    case NO_MEMORY:
+        return AUDIOEFFECT_ERROR_NO_MEMORY;
+    case DEAD_OBJECT:
+        return AUDIOEFFECT_ERROR_DEAD_OBJECT;
+    default:
+        return AUDIOEFFECT_ERROR;
+    }
+}
+
+
+// ----------------------------------------------------------------------------
+static void effectCallback(int event, void* user, void *info) {
+
+    effect_param_t *p;
+    int arg1 = 0;
+    int arg2 = 0;
+    jobject obj = NULL;
+    jbyteArray array = NULL;
+    jbyte *bytes;
+    bool param;
+    size_t size;
+
+    effect_callback_cookie *callbackInfo = (effect_callback_cookie *)user;
+    JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+    LOGV("effectCallback: callbackInfo %p, audioEffect_ref %p audioEffect_class %p",
+            callbackInfo,
+            callbackInfo->audioEffect_ref,
+            callbackInfo->audioEffect_class);
+
+    if (!user || !env) {
+        LOGW("effectCallback error user %p, env %p", user, env);
+        return;
+    }
+
+    switch (event) {
+    case AudioEffect::EVENT_CONTROL_STATUS_CHANGED:
+        if (info == 0) {
+            LOGW("EVENT_CONTROL_STATUS_CHANGED info == NULL");
+            goto effectCallback_Exit;
+        }
+        param = *(bool *)info;
+        arg1 = (int)param;
+        LOGV("EVENT_CONTROL_STATUS_CHANGED");
+        break;
+    case AudioEffect::EVENT_ENABLE_STATUS_CHANGED:
+        if (info == 0) {
+            LOGW("EVENT_ENABLE_STATUS_CHANGED info == NULL");
+            goto effectCallback_Exit;
+        }
+        param = *(bool *)info;
+        arg1 = (int)param;
+        LOGV("EVENT_ENABLE_STATUS_CHANGED");
+        break;
+    case AudioEffect::EVENT_PARAMETER_CHANGED:
+        if (info == 0) {
+            LOGW("EVENT_PARAMETER_CHANGED info == NULL");
+            goto effectCallback_Exit;
+        }
+        p = (effect_param_t *)info;
+        if (p->psize == 0 || p->vsize == 0) {
+            goto effectCallback_Exit;
+        }
+        // arg1 contains offset of parameter value from start of byte array
+        arg1 = sizeof(effect_param_t) + ((p->psize - 1) / sizeof(int) + 1) * sizeof(int);
+        size = arg1 + p->vsize;
+        array = env->NewByteArray(size);
+        if (array == NULL) {
+            LOGE("effectCallback: Couldn't allocate byte array for parameter data");
+            goto effectCallback_Exit;
+        }
+        bytes = env->GetByteArrayElements(array, NULL);
+        memcpy(bytes, p, size);
+        env->ReleaseByteArrayElements(array, bytes, 0);
+        obj = array;
+        LOGV("EVENT_PARAMETER_CHANGED");
+       break;
+    case AudioEffect::EVENT_ERROR:
+        LOGW("EVENT_ERROR");
+        break;
+    }
+
+    env->CallStaticVoidMethod(
+        callbackInfo->audioEffect_class,
+        fields.midPostNativeEvent,
+        callbackInfo->audioEffect_ref, event, arg1, arg2, obj);
+
+effectCallback_Exit:
+    if (array) {
+        env->DeleteLocalRef(array);
+    }
+
+    if (env->ExceptionCheck()) {
+        env->ExceptionDescribe();
+        env->ExceptionClear();
+    }
+}
+
+// ----------------------------------------------------------------------------
+// This function gets some field IDs, which in turn causes class initialization.
+// It is called from a static block in AudioEffect, which won't run until the
+// first time an instance of this class is used.
+static void
+android_media_AudioEffect_native_init(JNIEnv *env)
+{
+
+    LOGV("android_media_AudioEffect_native_init");
+
+    fields.clazzEffect = NULL;
+    fields.clazzDesc = NULL;
+
+    // Get the AudioEffect class
+    jclass clazz = env->FindClass(kClassPathName);
+    if (clazz == NULL) {
+        LOGE("Can't find %s", kClassPathName);
+        return;
+    }
+
+    fields.clazzEffect = (jclass)env->NewGlobalRef(clazz);
+
+    // Get the postEvent method
+    fields.midPostNativeEvent = env->GetStaticMethodID(
+            fields.clazzEffect,
+            "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V");
+    if (fields.midPostNativeEvent == NULL) {
+        LOGE("Can't find AudioEffect.%s", "postEventFromNative");
+        return;
+    }
+
+    // Get the variables fields
+    //      nativeTrackInJavaObj
+    fields.fidNativeAudioEffect = env->GetFieldID(
+            fields.clazzEffect,
+            "mNativeAudioEffect", "I");
+    if (fields.fidNativeAudioEffect == NULL) {
+        LOGE("Can't find AudioEffect.%s", "mNativeAudioEffect");
+        return;
+    }
+    //      fidJniData;
+    fields.fidJniData = env->GetFieldID(
+            fields.clazzEffect,
+            "mJniData", "I");
+    if (fields.fidJniData == NULL) {
+        LOGE("Can't find AudioEffect.%s", "mJniData");
+        return;
+    }
+
+    clazz = env->FindClass("android/media/AudioEffect$Descriptor");
+    if (clazz == NULL) {
+        LOGE("Can't find android/media/AudioEffect$Descriptor class");
+        return;
+    }
+    fields.clazzDesc = (jclass)env->NewGlobalRef(clazz);
+
+    fields.midDescCstor
+            = env->GetMethodID(
+                    fields.clazzDesc,
+                    "<init>",
+                    "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
+    if (fields.midDescCstor == NULL) {
+        LOGE("Can't find android/media/AudioEffect$Descriptor class constructor");
+        return;
+    }
+}
+
+
+static jint
+android_media_AudioEffect_native_setup(JNIEnv *env, jobject thiz, jobject weak_this,
+        jstring type, jstring uuid, jint priority, jint sessionId, jintArray jId, jobjectArray javadesc)
+{
+    LOGV("android_media_AudioEffect_native_setup");
+    AudioEffectJniStorage* lpJniStorage = NULL;
+    int lStatus = AUDIOEFFECT_ERROR_NO_MEMORY;
+    AudioEffect* lpAudioEffect = NULL;
+    jint* nId = NULL;
+    const char *typeStr = NULL;
+    const char *uuidStr = NULL;
+    effect_descriptor_t desc;
+    jobject jdesc;
+    char str[EFFECT_STRING_LEN_MAX];
+    jstring jdescType;
+    jstring jdescUuid;
+    jstring jdescConnect;
+    jstring jdescName;
+    jstring jdescImplementor;
+
+    if (type != NULL) {
+        typeStr = env->GetStringUTFChars(type, NULL);
+        if (typeStr == NULL) {  // Out of memory
+            jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+            goto setup_failure;
+        }
+    }
+
+    if (uuid != NULL) {
+        uuidStr = env->GetStringUTFChars(uuid, NULL);
+        if (uuidStr == NULL) {  // Out of memory
+            jniThrowException(env, "java/lang/RuntimeException", "Out of memory");
+            goto setup_failure;
+        }
+    }
+
+    if (typeStr == NULL && uuidStr == NULL) {
+        lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+        goto setup_failure;
+    }
+
+    lpJniStorage = new AudioEffectJniStorage();
+    if (lpJniStorage == NULL) {
+        LOGE("setup: Error creating JNI Storage");
+        goto setup_failure;
+    }
+
+    lpJniStorage->mCallbackData.audioEffect_class = (jclass)env->NewGlobalRef(fields.clazzEffect);
+    // we use a weak reference so the AudioEffect object can be garbage collected.
+    lpJniStorage->mCallbackData.audioEffect_ref = env->NewGlobalRef(weak_this);
+
+    LOGV("setup: lpJniStorage: %p audioEffect_ref %p audioEffect_class %p, &mCallbackData %p",
+            lpJniStorage,
+            lpJniStorage->mCallbackData.audioEffect_ref,
+            lpJniStorage->mCallbackData.audioEffect_class,
+            &lpJniStorage->mCallbackData);
+
+    if (jId) {
+        nId = (jint *) env->GetPrimitiveArrayCritical(jId, NULL);
+        if (nId == NULL) {
+            LOGE("setup: Error retrieving id pointer");
+            lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+            goto setup_failure;
+        }
+    } else {
+        LOGE("setup: NULL java array for id pointer");
+        lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+        goto setup_failure;
+    }
+
+    // create the native AudioEffect object
+    lpAudioEffect = new AudioEffect(typeStr,
+                                    uuidStr,
+                                    priority,
+                                    effectCallback,
+                                    &lpJniStorage->mCallbackData,
+                                    0,
+                                    sessionId);
+    if (lpAudioEffect == NULL) {
+        LOGE("Error creating AudioEffect");
+        goto setup_failure;
+    }
+
+    lStatus = translateError(lpAudioEffect->initCheck());
+    if (lStatus != AUDIOEFFECT_SUCCESS && lStatus != AUDIOEFFECT_ERROR_ALREADY_EXISTS) {
+        LOGE("AudioEffect initCheck failed %d", lStatus);
+        goto setup_failure;
+    }
+
+    nId[0] = lpAudioEffect->id();
+
+    env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+    nId = NULL;
+
+    if (typeStr) {
+        env->ReleaseStringUTFChars(type, typeStr);
+        typeStr = NULL;
+    }
+
+    if (uuidStr) {
+        env->ReleaseStringUTFChars(uuid, uuidStr);
+        uuidStr = NULL;
+    }
+
+    // get the effect descriptor
+    desc = lpAudioEffect->descriptor();
+
+    AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
+    jdescType = env->NewStringUTF(str);
+
+    AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
+    jdescUuid = env->NewStringUTF(str);
+
+    if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+        jdescConnect = env->NewStringUTF("Auxiliary");
+    } else {
+        jdescConnect = env->NewStringUTF("Insert");
+    }
+
+    jdescName = env->NewStringUTF(desc.name);
+    jdescImplementor = env->NewStringUTF(desc.implementor);
+
+    jdesc = env->NewObject(fields.clazzDesc,
+                           fields.midDescCstor,
+                           jdescType,
+                           jdescUuid,
+                           jdescConnect,
+                           jdescName,
+                           jdescImplementor);
+    env->DeleteLocalRef(jdescType);
+    env->DeleteLocalRef(jdescUuid);
+    env->DeleteLocalRef(jdescConnect);
+    env->DeleteLocalRef(jdescName);
+    env->DeleteLocalRef(jdescImplementor);
+    if (jdesc == NULL) {
+        LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
+        goto setup_failure;
+    }
+
+    env->SetObjectArrayElement(javadesc, 0, jdesc);
+
+    env->SetIntField(thiz, fields.fidNativeAudioEffect, (int)lpAudioEffect);
+
+    env->SetIntField(thiz, fields.fidJniData, (int)lpJniStorage);
+
+    return AUDIOEFFECT_SUCCESS;
+
+    // failures:
+setup_failure:
+
+    if (nId != NULL) {
+        env->ReleasePrimitiveArrayCritical(jId, nId, 0);
+    }
+
+    if (lpAudioEffect) {
+        delete lpAudioEffect;
+    }
+    env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
+
+    if (lpJniStorage) {
+        delete lpJniStorage;
+    }
+    env->SetIntField(thiz, fields.fidJniData, 0);
+
+    if (uuidStr != NULL) {
+        env->ReleaseStringUTFChars(uuid, uuidStr);
+    }
+
+    if (typeStr != NULL) {
+        env->ReleaseStringUTFChars(type, typeStr);
+    }
+
+    return lStatus;
+}
+
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioEffect_native_finalize(JNIEnv *env,  jobject thiz) {
+    LOGV("android_media_AudioEffect_native_finalize jobject: %x\n", (int)thiz);
+
+    // delete the AudioEffect object
+    AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+        thiz, fields.fidNativeAudioEffect);
+    if (lpAudioEffect) {
+        LOGV("deleting AudioEffect: %x\n", (int)lpAudioEffect);
+        delete lpAudioEffect;
+    }
+
+    // delete the JNI data
+    AudioEffectJniStorage* lpJniStorage = (AudioEffectJniStorage *)env->GetIntField(
+        thiz, fields.fidJniData);
+    if (lpJniStorage) {
+        LOGV("deleting pJniStorage: %x\n", (int)lpJniStorage);
+        delete lpJniStorage;
+    }
+}
+
+// ----------------------------------------------------------------------------
+static void android_media_AudioEffect_native_release(JNIEnv *env,  jobject thiz) {
+
+    // do everything a call to finalize would
+    android_media_AudioEffect_native_finalize(env, thiz);
+    // + reset the native resources in the Java object so any attempt to access
+    // them after a call to release fails.
+    env->SetIntField(thiz, fields.fidNativeAudioEffect, 0);
+    env->SetIntField(thiz, fields.fidJniData, 0);
+}
+
+
+static jint
+android_media_AudioEffect_native_enable(JNIEnv *env, jobject thiz)
+{
+    // retrieve the AudioEffect object
+    AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+        thiz, fields.fidNativeAudioEffect);
+
+    if (lpAudioEffect == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioEffect pointer for enable()");
+        return AUDIOEFFECT_ERROR_NO_INIT;
+    }
+
+    return translateError(lpAudioEffect->enable());
+}
+
+
+static jint
+android_media_AudioEffect_native_disable(JNIEnv *env, jobject thiz)
+{
+    // retrieve the AudioEffect object
+    AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+        thiz, fields.fidNativeAudioEffect);
+
+    if (lpAudioEffect == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioEffect pointer for disable()");
+        return AUDIOEFFECT_ERROR_NO_INIT;
+    }
+
+    return translateError(lpAudioEffect->disable());
+}
+
+
+static jboolean
+android_media_AudioEffect_native_getEnable(JNIEnv *env, jobject thiz)
+{
+    // retrieve the AudioEffect object
+    AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+        thiz, fields.fidNativeAudioEffect);
+
+    if (lpAudioEffect == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioEffect pointer for getEnabled()");
+        return false;
+    }
+
+    return (jboolean)lpAudioEffect->isEnabled();
+}
+
+
+static jboolean
+android_media_AudioEffect_native_hasControl(JNIEnv *env, jobject thiz)
+{
+    // retrieve the AudioEffect object
+    AudioEffect* lpAudioEffect = (AudioEffect *)env->GetIntField(
+        thiz, fields.fidNativeAudioEffect);
+
+    if (lpAudioEffect == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioEffect pointer for getEnabled()");
+        return false;
+    }
+
+    if (lpAudioEffect->initCheck() == NO_ERROR) {
+        return true;
+    } else {
+        return false;
+    }
+}
+
+static jint android_media_AudioEffect_native_setParameter(JNIEnv *env,
+        jobject thiz, int psize, jbyteArray pJavaParam, int vsize,
+        jbyteArray pJavaValue) {
+    // retrieve the AudioEffect object
+    jbyte* lpValue = NULL;
+    jbyte* lpParam = NULL;
+    jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+    effect_param_t *p;
+    int voffset;
+
+    AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
+            fields.fidNativeAudioEffect);
+
+    if (lpAudioEffect == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Unable to retrieve AudioEffect pointer for setParameter()");
+        return AUDIOEFFECT_ERROR_NO_INIT;
+    }
+
+    if (psize == 0 || vsize == 0 || pJavaParam == NULL || pJavaValue == NULL) {
+        return AUDIOEFFECT_ERROR_BAD_VALUE;
+    }
+
+    // get the pointer for the param from the java array
+    lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
+    if (lpParam == NULL) {
+        LOGE("setParameter: Error retrieving param pointer");
+        goto setParameter_Exit;
+    }
+
+    // get the pointer for the value from the java array
+    lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
+    if (lpValue == NULL) {
+        LOGE("setParameter: Error retrieving value pointer");
+        goto setParameter_Exit;
+    }
+
+    voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
+    p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset + vsize);
+    memcpy(p->data, lpParam, psize);
+    p->psize = psize;
+    memcpy(p->data + voffset, lpValue, psize);
+    p->vsize = vsize;
+
+    lStatus = lpAudioEffect->setParameter(p);
+    if (lStatus == NO_ERROR) {
+        lStatus = p->status;
+    }
+
+    free(p);
+
+setParameter_Exit:
+
+    if (lpParam != NULL) {
+        env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
+    }
+    if (lpValue != NULL) {
+        env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
+    }
+    return translateError(lStatus);
+}
+
+static jint
+android_media_AudioEffect_native_getParameter(JNIEnv *env,
+        jobject thiz, int psize, jbyteArray pJavaParam,
+        jintArray pJavaValueSize, jbyteArray pJavaValue) {
+    // retrieve the AudioEffect object
+    jbyte* lpParam = NULL;
+    jbyte* lpValue = NULL;
+    jbyte* lpValueSize = NULL;
+    jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+    effect_param_t *p;
+    int voffset;
+
+    AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
+            fields.fidNativeAudioEffect);
+
+    if (lpAudioEffect == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Unable to retrieve AudioEffect pointer for getParameter()");
+        return AUDIOEFFECT_ERROR_NO_INIT;
+    }
+
+    if (psize == 0 || pJavaValueSize == NULL || pJavaParam == NULL || pJavaValue == NULL) {
+        return AUDIOEFFECT_ERROR_BAD_VALUE;
+    }
+
+    // get the pointer for the param from the java array
+    lpParam = (jbyte *) env->GetPrimitiveArrayCritical(pJavaParam, NULL);
+    if (lpParam == NULL) {
+        LOGE("getParameter: Error retrieving param pointer");
+        goto getParameter_Exit;
+    }
+
+    // get the pointer for the value from the java array
+    lpValue = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValue, NULL);
+    if (lpValue == NULL) {
+        LOGE("getParameter: Error retrieving value pointer");
+        goto getParameter_Exit;
+    }
+
+    // get the pointer for the value size from the java array
+    lpValueSize = (jbyte *) env->GetPrimitiveArrayCritical(pJavaValueSize, NULL);
+    if (lpValueSize == NULL) {
+        LOGE("getParameter: Error retrieving value size pointer");
+        goto getParameter_Exit;
+    }
+
+    voffset = ((psize - 1) / sizeof(int) + 1) * sizeof(int);
+    p = (effect_param_t *) malloc(sizeof(effect_param_t) + voffset
+            + lpValueSize[0]);
+    memcpy(p->data, lpParam, psize);
+    p->psize = psize;
+    p->vsize = lpValueSize[0];
+
+    lStatus = lpAudioEffect->getParameter(p);
+    if (lStatus == NO_ERROR) {
+        lStatus = p->status;
+        if (lStatus == NO_ERROR) {
+            memcpy(lpValue, p->data + voffset, p->vsize);
+            lpValueSize[0] = p->vsize;
+        }
+    }
+
+    free(p);
+
+getParameter_Exit:
+
+    if (lpParam != NULL) {
+        env->ReleasePrimitiveArrayCritical(pJavaParam, lpParam, 0);
+    }
+    if (lpValue != NULL) {
+        env->ReleasePrimitiveArrayCritical(pJavaValue, lpValue, 0);
+    }
+    if (lpValueSize != NULL) {
+        env->ReleasePrimitiveArrayCritical(pJavaValueSize, lpValueSize, 0);
+    }
+
+    return translateError(lStatus);
+}
+
+static jint android_media_AudioEffect_native_command(JNIEnv *env, jobject thiz,
+        jint cmdCode, jint cmdSize, jbyteArray jCmdData, jintArray jReplySize,
+        jbyteArray jReplyData) {
+    jbyte* pCmdData = NULL;
+    jbyte* pReplyData = NULL;
+    jint* pReplySize = NULL;
+    jint lStatus = AUDIOEFFECT_ERROR_BAD_VALUE;
+
+    // retrieve the AudioEffect object
+    AudioEffect* lpAudioEffect = (AudioEffect *) env->GetIntField(thiz,
+            fields.fidNativeAudioEffect);
+
+    if (lpAudioEffect == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Unable to retrieve AudioEffect pointer for setParameter()");
+        return AUDIOEFFECT_ERROR_NO_INIT;
+    }
+
+    if ((cmdSize != 0 && jCmdData == NULL) || (jReplySize != NULL && jReplyData == NULL)) {
+        return AUDIOEFFECT_ERROR_BAD_VALUE;
+    }
+
+    // get the pointer for the command from the java array
+    if (cmdSize != 0) {
+        pCmdData = (jbyte *) env->GetPrimitiveArrayCritical(jCmdData, NULL);
+        if (pCmdData == NULL) {
+            LOGE("setParameter: Error retrieving command pointer");
+            goto command_Exit;
+        }
+    }
+
+    // get the pointer for the reply size from the java array
+    if (jReplySize != NULL) {
+        pReplySize = (jint *) env->GetPrimitiveArrayCritical(jReplySize, NULL);
+        if (pReplySize == NULL) {
+            LOGE("setParameter: Error retrieving reply pointer");
+            goto command_Exit;
+        }
+    }
+
+    // get the pointer for the reply from the java array
+    if (pReplySize != NULL && pReplySize[0] != 0 && jReplyData != NULL) {
+        pReplyData = (jbyte *) env->GetPrimitiveArrayCritical(jReplyData, NULL);
+        if (pReplyData == NULL) {
+            LOGE("setParameter: Error retrieving reply pointer");
+            goto command_Exit;
+        }
+    }
+
+    lStatus = translateError(lpAudioEffect->command(cmdCode, cmdSize, pCmdData,
+            pReplySize, pReplyData));
+
+command_Exit:
+
+    if (pCmdData != NULL) {
+        env->ReleasePrimitiveArrayCritical(jCmdData, pCmdData, 0);
+    }
+    if (pReplyData != NULL) {
+        env->ReleasePrimitiveArrayCritical(jReplyData, pReplyData, 0);
+    }
+    if (pReplySize != NULL) {
+        env->ReleasePrimitiveArrayCritical(jReplySize, pReplySize, 0);
+    }
+
+    return lStatus;
+}
+
+static jobjectArray
+android_media_AudioEffect_native_queryEffects(JNIEnv *env, jclass clazz)
+{
+    effect_descriptor_t desc;
+    char str[EFFECT_STRING_LEN_MAX];
+    uint32_t numEffects;
+    uint32_t i = 0;
+    jstring jdescType;
+    jstring jdescUuid;
+    jstring jdescConnect;
+    jstring jdescName;
+    jstring jdescImplementor;
+    jobject jdesc;
+
+    AudioEffect::queryNumberEffects(&numEffects);
+    jobjectArray ret = env->NewObjectArray(numEffects, fields.clazzDesc, NULL);
+    if (ret == NULL) {
+        return ret;
+    }
+
+    LOGV("queryEffects() numEffects: %d", numEffects);
+
+    for (i = 0; i < numEffects; i++) {
+        if (AudioEffect::queryNextEffect(&desc) != NO_ERROR) {
+            goto queryEffects_failure;
+        }
+
+        AudioEffect::guidToString(&desc.type, str, EFFECT_STRING_LEN_MAX);
+        jdescType = env->NewStringUTF(str);
+
+        AudioEffect::guidToString(&desc.uuid, str, EFFECT_STRING_LEN_MAX);
+        jdescUuid = env->NewStringUTF(str);
+
+        if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
+            jdescConnect = env->NewStringUTF("Auxiliary");
+        } else {
+            jdescConnect = env->NewStringUTF("Insert");
+        }
+
+        jdescName = env->NewStringUTF(desc.name);
+        jdescImplementor = env->NewStringUTF(desc.implementor);
+
+        jdesc = env->NewObject(fields.clazzDesc,
+                               fields.midDescCstor,
+                               jdescType,
+                               jdescUuid,
+                               jdescConnect,
+                               jdescName,
+                               jdescImplementor);
+        env->DeleteLocalRef(jdescType);
+        env->DeleteLocalRef(jdescUuid);
+        env->DeleteLocalRef(jdescConnect);
+        env->DeleteLocalRef(jdescName);
+        env->DeleteLocalRef(jdescImplementor);
+        if (jdesc == NULL) {
+            LOGE("env->NewObject(fields.clazzDesc, fields.midDescCstor)");
+            goto queryEffects_failure;
+        }
+
+        env->SetObjectArrayElement(ret, i, jdesc);
+   }
+
+    return ret;
+
+queryEffects_failure:
+
+    if (ret != NULL) {
+        env->DeleteLocalRef(ret);
+    }
+    return NULL;
+
+}
+
+// ----------------------------------------------------------------------------
+
+// Dalvik VM type signatures
+static JNINativeMethod gMethods[] = {
+    {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
+    {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;)I",
+                                         (void *)android_media_AudioEffect_native_setup},
+    {"native_finalize",      "()V",      (void *)android_media_AudioEffect_native_finalize},
+    {"native_release",       "()V",      (void *)android_media_AudioEffect_native_release},
+    {"native_enable",        "()I",      (void *)android_media_AudioEffect_native_enable},
+    {"native_disable",       "()I",      (void *)android_media_AudioEffect_native_disable},
+    {"native_getEnable",     "()Z",      (void *)android_media_AudioEffect_native_getEnable},
+    {"native_hasControl",    "()Z",      (void *)android_media_AudioEffect_native_hasControl},
+    {"native_setParameter",  "(I[BI[B)I",  (void *)android_media_AudioEffect_native_setParameter},
+    {"native_getParameter",  "(I[B[I[B)I",  (void *)android_media_AudioEffect_native_getParameter},
+    {"native_command",       "(II[B[I[B)I", (void *)android_media_AudioEffect_native_command},
+    {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects},
+};
+
+
+// ----------------------------------------------------------------------------
+
+int register_android_media_AudioEffect(JNIEnv *env)
+{
+    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+
+    JNIEnv* env = NULL;
+    jint result = -1;
+
+    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+        LOGE("ERROR: GetEnv failed\n");
+        goto bail;
+    }
+    assert(env != NULL);
+
+    if (register_android_media_AudioEffect(env) < 0) {
+        LOGE("ERROR: AudioEffect native registration failed\n");
+        goto bail;
+    }
+
+    /* success -- return valid version number */
+    result = JNI_VERSION_1_4;
+
+bail:
+    return result;
+}
+
diff --git a/media/libmedia/Android.mk b/media/libmedia/Android.mk
index 29cd2ee..7908f5d 100644
--- a/media/libmedia/Android.mk
+++ b/media/libmedia/Android.mk
@@ -28,7 +28,8 @@
     IMediaDeathNotifier.cpp \
     MediaProfiles.cpp \
     IEffect.cpp \
-    IEffectClient.cpp
+    IEffectClient.cpp \
+    AudioEffect.cpp
 
 LOCAL_SHARED_LIBRARIES := \
 	libui libcutils libutils libbinder libsonivox libicuuc libexpat libsurfaceflinger_client libcamera_client
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
new file mode 100644
index 0000000..8648211
--- /dev/null
+++ b/media/libmedia/AudioEffect.cpp
@@ -0,0 +1,462 @@
+/*
+**
+** Copyright 2010, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "AudioEffect"
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <limits.h>
+
+#include <private/media/AudioEffectShared.h>
+#include <media/AudioEffect.h>
+
+#include <utils/Log.h>
+#include <cutils/atomic.h>
+#include <binder/IPCThreadState.h>
+
+
+
+namespace android {
+
+// ---------------------------------------------------------------------------
+
+AudioEffect::AudioEffect()
+    : mStatus(NO_INIT)
+{
+}
+
+
+AudioEffect::AudioEffect(const effect_uuid_t *type,
+                const effect_uuid_t *uuid,
+                int32_t priority,
+                effect_callback_t cbf,
+                void* user,
+                int sessionId,
+                audio_io_handle_t output
+                )
+    : mStatus(NO_INIT)
+{
+    mStatus = set(type, uuid, priority, cbf, user, output, sessionId);
+}
+
+AudioEffect::AudioEffect(const char *typeStr,
+                const char *uuidStr,
+                int32_t priority,
+                effect_callback_t cbf,
+                void* user,
+                int sessionId,
+                audio_io_handle_t output
+                )
+    : mStatus(NO_INIT)
+{
+    effect_uuid_t type;
+    effect_uuid_t *pType = NULL;
+    effect_uuid_t uuid;
+    effect_uuid_t *pUuid = NULL;
+
+    LOGV("Constructor string\n - type: %s\n - uuid: %s", typeStr, uuidStr);
+
+    if (typeStr != NULL) {
+        if (stringToGuid(typeStr, &type) == NO_ERROR) {
+            pType = &type;
+        }
+    }
+
+    if (uuidStr != NULL) {
+        if (stringToGuid(uuidStr, &uuid) == NO_ERROR) {
+            pUuid = &uuid;
+        }
+    }
+
+    mStatus = set(pType, pUuid, priority, cbf, user, output, sessionId);
+}
+
+status_t AudioEffect::set(const effect_uuid_t *type,
+                const effect_uuid_t *uuid,
+                int32_t priority,
+                effect_callback_t cbf,
+                void* user,
+                int sessionId,
+                audio_io_handle_t output)
+{
+    sp<IEffect> iEffect;
+    sp<IMemory> cblk;
+    int enabled;
+
+    LOGV("set %p mUserData: %p", this, user);
+
+    if (mIEffect != 0) {
+        LOGW("Effect already in use");
+        return INVALID_OPERATION;
+    }
+
+    const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger();
+    if (audioFlinger == 0) {
+        LOGE("set(): Could not get audioflinger");
+        return NO_INIT;
+    }
+
+    if (type == NULL && uuid == NULL) {
+        LOGW("Must specify at least type or uuid");
+        return BAD_VALUE;
+    }
+
+    mPriority = priority;
+    mCbf = cbf;
+    mUserData = user;
+    mSessionId = sessionId;
+
+    memset(&mDescriptor, 0, sizeof(effect_descriptor_t));
+    memcpy(&mDescriptor.type, EFFECT_UUID_NULL, sizeof(effect_uuid_t));
+    memcpy(&mDescriptor.uuid, EFFECT_UUID_NULL, sizeof(effect_uuid_t));
+
+    if (type != NULL) {
+        memcpy(&mDescriptor.type, type, sizeof(effect_uuid_t));
+    }
+    if (uuid != NULL) {
+        memcpy(&mDescriptor.uuid, uuid, sizeof(effect_uuid_t));
+    }
+
+    mIEffectClient = new EffectClient(this);
+
+    iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor,
+            mIEffectClient, priority, output, mSessionId, &mStatus, &mId, &enabled);
+
+    if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
+        LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);
+        return mStatus;
+    }
+
+    mEnabled = (volatile int32_t)enabled;
+
+    mIEffect = iEffect;
+    cblk = iEffect->getCblk();
+    if (cblk == 0) {
+        mStatus = NO_INIT;
+        LOGE("Could not get control block");
+        return mStatus;
+    }
+
+    mIEffect = iEffect;
+    mCblkMemory = cblk;
+    mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer());
+    int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int);
+    mCblk->buffer = (uint8_t *)mCblk + bufOffset;
+
+    iEffect->asBinder()->linkToDeath(mIEffectClient);
+    LOGV("set() %p OK effect: %s id: %d status %d enabled %d, ", this, mDescriptor.name, mId, mStatus, mEnabled);
+
+    return mStatus;
+}
+
+
+AudioEffect::~AudioEffect()
+{
+    LOGV("Destructor %p", this);
+
+    if (mStatus == NO_ERROR || mStatus == ALREADY_EXISTS) {
+        disable();
+        if (mIEffect != NULL) {
+            mIEffect->disconnect();
+            mIEffect->asBinder()->unlinkToDeath(mIEffectClient);
+        }
+         IPCThreadState::self()->flushCommands();
+    }
+    mIEffect.clear();
+    mIEffectClient.clear();
+    mCblkMemory.clear();
+}
+
+
+status_t AudioEffect::initCheck() const
+{
+    return mStatus;
+}
+
+// -------------------------------------------------------------------------
+
+effect_descriptor_t AudioEffect::descriptor() const
+{
+    return mDescriptor;
+}
+
+bool AudioEffect::isEnabled() const
+{
+    return (mEnabled != 0);
+}
+
+status_t AudioEffect::enable()
+{
+    if (mStatus != NO_ERROR) {
+        return INVALID_OPERATION;
+    }
+    LOGV("enable %p", this);
+
+    if (android_atomic_or(1, &mEnabled) == 0) {
+       return mIEffect->enable();
+    }
+
+    return INVALID_OPERATION;
+}
+
+status_t AudioEffect::disable()
+{
+    if (mStatus != NO_ERROR) {
+        return INVALID_OPERATION;
+    }
+    LOGV("disable %p", this);
+
+    if (android_atomic_and(~1, &mEnabled) == 1) {
+       return mIEffect->disable();
+    }
+
+    return INVALID_OPERATION;
+}
+
+status_t AudioEffect::command(int32_t cmdCode, int32_t cmdSize, void *cmdData, int32_t *replySize, void *replyData)
+{
+    if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
+        return INVALID_OPERATION;
+    }
+
+    return mIEffect->command(cmdCode, cmdSize, cmdData, replySize, replyData);
+}
+
+
+status_t AudioEffect::setParameter(effect_param_t *param)
+{
+    if (mStatus != NO_ERROR) {
+        return INVALID_OPERATION;
+    }
+
+    if (param == NULL || param->psize == 0 || param->vsize == 0) {
+        return BAD_VALUE;
+    }
+
+    int size = sizeof(int);
+    int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
+
+    LOGV("setParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1);
+
+    return mIEffect->command(EFFECT_CMD_SET_PARAM, sizeof (effect_param_t) + psize, param, &size, &param->status);
+}
+
+status_t AudioEffect::setParameterDeferred(effect_param_t *param)
+{
+    if (mStatus != NO_ERROR) {
+        return INVALID_OPERATION;
+    }
+
+    if (param == NULL || param->psize == 0 || param->vsize == 0) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mCblk->lock);
+
+    int psize = ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
+    int size = ((sizeof(effect_param_t) + psize - 1) / sizeof(int) + 1) * sizeof(int);
+
+    if (mCblk->clientIndex + size > EFFECT_PARAM_BUFFER_SIZE) {
+        return NO_MEMORY;
+    }
+    int *p = (int *)(mCblk->buffer + mCblk->clientIndex);
+    *p++ = size;
+    memcpy(p, param, sizeof(effect_param_t) + psize);
+    mCblk->clientIndex += size;
+
+    return NO_ERROR;
+}
+
+status_t AudioEffect::setParameterCommit()
+{
+    if (mStatus != NO_ERROR) {
+        return INVALID_OPERATION;
+    }
+
+    Mutex::Autolock _l(mCblk->lock);
+    if (mCblk->clientIndex == 0) {
+        return INVALID_OPERATION;
+    }
+    int size = 0;
+    return mIEffect->command(EFFECT_CMD_SET_PARAM_COMMIT, 0, NULL, &size, NULL);
+}
+
+status_t AudioEffect::getParameter(effect_param_t *param)
+{
+    if (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS) {
+        return INVALID_OPERATION;
+    }
+
+    if (param == NULL || param->psize == 0 || param->vsize == 0) {
+        return BAD_VALUE;
+    }
+
+    LOGV("getParameter: param: %d, param2: %d", *(int *)param->data, (param->psize == 8) ? *((int *)param->data + 1): -1);
+
+    int psize = sizeof(effect_param_t) + ((param->psize - 1) / sizeof(int) + 1) * sizeof(int) + param->vsize;
+
+    return mIEffect->command(EFFECT_CMD_GET_PARAM, sizeof(effect_param_t) + param->psize, param, &psize, param);
+}
+
+
+// -------------------------------------------------------------------------
+
+void AudioEffect::binderDied()
+{
+    LOGW("IEffect died");
+    mStatus = NO_INIT;
+    if (mCbf) {
+        status_t status = DEAD_OBJECT;
+        mCbf(EVENT_ERROR, mUserData, &status);
+    }
+    mIEffect.clear();
+}
+
+// -------------------------------------------------------------------------
+
+void AudioEffect::controlStatusChanged(bool controlGranted)
+{
+    LOGV("controlStatusChanged %p control %d callback %p mUserData %p", this, controlGranted, mCbf, mUserData);
+    if (controlGranted) {
+        if (mStatus == ALREADY_EXISTS) {
+            mStatus = NO_ERROR;
+        }
+    } else {
+        if (mStatus == NO_ERROR) {
+            mStatus = ALREADY_EXISTS;
+        }
+    }
+    if (mCbf) {
+        mCbf(EVENT_CONTROL_STATUS_CHANGED, mUserData, &controlGranted);
+    }
+}
+
+void AudioEffect::enableStatusChanged(bool enabled)
+{
+    LOGV("enableStatusChanged %p enabled %d", this, enabled);
+    if (mStatus == ALREADY_EXISTS) {
+        mEnabled = enabled;
+        if (mCbf) {
+            mCbf(EVENT_ENABLE_STATUS_CHANGED, mUserData, &enabled);
+        }
+    }
+}
+
+void AudioEffect::commandExecuted(int cmdCode, int cmdSize, void *cmdData, int replySize, void *replyData)
+{
+    if (cmdData == NULL || replyData == NULL) {
+        return;
+    }
+
+    if (mCbf && cmdCode == EFFECT_CMD_SET_PARAM) {
+        effect_param_t *cmd = (effect_param_t *)cmdData;
+        cmd->status = *(int32_t *)replyData;
+        mCbf(EVENT_PARAMETER_CHANGED, mUserData, cmd);
+    }
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioEffect::loadEffectLibrary(const char *libPath, int *handle)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->loadEffectLibrary(libPath, handle);
+}
+
+status_t AudioEffect::unloadEffectLibrary(int handle)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->unloadEffectLibrary(handle);
+}
+
+status_t AudioEffect::queryNumberEffects(uint32_t *numEffects)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->queryNumberEffects(numEffects);
+}
+
+status_t AudioEffect::queryNextEffect(effect_descriptor_t *descriptor)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->queryNextEffect(descriptor);
+}
+
+status_t AudioEffect::getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor)
+{
+    const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+    if (af == 0) return PERMISSION_DENIED;
+    return af->getEffectDescriptor(uuid, descriptor);
+}
+
+// -------------------------------------------------------------------------
+
+status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid)
+{
+    if (str == NULL || guid == NULL) {
+        return BAD_VALUE;
+    }
+
+    int tmp[10];
+
+    if (sscanf(str, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+            tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5, tmp+6, tmp+7, tmp+8, tmp+9) < 10) {
+        return BAD_VALUE;
+    }
+    guid->timeLow = (uint32_t)tmp[0];
+    guid->timeMid = (uint16_t)tmp[1];
+    guid->timeHiAndVersion = (uint16_t)tmp[2];
+    guid->clockSeq = (uint16_t)tmp[3];
+    guid->node[0] = (uint8_t)tmp[4];
+    guid->node[1] = (uint8_t)tmp[5];
+    guid->node[2] = (uint8_t)tmp[6];
+    guid->node[3] = (uint8_t)tmp[7];
+    guid->node[4] = (uint8_t)tmp[8];
+    guid->node[5] = (uint8_t)tmp[9];
+
+    return NO_ERROR;
+}
+
+status_t AudioEffect::guidToString(const effect_uuid_t *guid, char *str, size_t maxLen)
+{
+    if (guid == NULL || str == NULL) {
+        return BAD_VALUE;
+    }
+
+    snprintf(str, maxLen, "%08x-%04x-%04x-%04x-%02x%02x%02x%02x%02x%02x",
+            guid->timeLow,
+            guid->timeMid,
+            guid->timeHiAndVersion,
+            guid->clockSeq,
+            guid->node[0],
+            guid->node[1],
+            guid->node[2],
+            guid->node[3],
+            guid->node[4],
+            guid->node[5]);
+
+    return NO_ERROR;
+}
+
+
+}; // namespace android
+