summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-06-14 09:10:32 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2010-06-14 09:10:32 -0700
commit7f5ee3b58d3dc07b88b313aae83ae424d131b355 (patch)
tree884a424a40bd6aa53ff94d78e82b303a6faf07e5
parenta47078a5b0ac4af7e27846c731c0dedd1a84ca03 (diff)
parent184a3ff64ba71e7e860b70b9a836c0132b447138 (diff)
downloadframeworks_base-7f5ee3b58d3dc07b88b313aae83ae424d131b355.zip
frameworks_base-7f5ee3b58d3dc07b88b313aae83ae424d131b355.tar.gz
frameworks_base-7f5ee3b58d3dc07b88b313aae83ae424d131b355.tar.bz2
am 184a3ff6: am e0219539: am 01f7ac64: Merge "Issue 2667802: [Audio Effect Framework] AudioEffect base class and JNI." into kraken
Merge commit '184a3ff64ba71e7e860b70b9a836c0132b447138' * commit '184a3ff64ba71e7e860b70b9a836c0132b447138': Issue 2667802: [Audio Effect Framework] AudioEffect base class and JNI.
-rw-r--r--include/media/AudioEffect.h462
-rw-r--r--media/java/android/media/AudioEffect.java954
-rw-r--r--media/jni/Android.mk3
-rw-r--r--media/jni/audioeffect/Android.mk16
-rw-r--r--media/jni/audioeffect/android_media_AudioEffect.cpp861
-rw-r--r--media/libmedia/Android.mk3
-rw-r--r--media/libmedia/AudioEffect.cpp462
7 files changed, 2759 insertions, 2 deletions
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 @@ LOCAL_MODULE:= libmedia_jni
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 @@ LOCAL_SRC_FILES:= \
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
+