summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2010-06-09 00:17:29 -0700
committerEric Laurent <elaurent@google.com>2010-06-11 06:26:31 -0700
commit948235c06ed0d49190b2f49d9299b473c4dd61a9 (patch)
tree90cdddff4282d9bbf2fc7a4b0ce1cafed058daa8
parent700a95068e7c774963be318c91df5bf40d765397 (diff)
downloadframeworks_base-948235c06ed0d49190b2f49d9299b473c4dd61a9.zip
frameworks_base-948235c06ed0d49190b2f49d9299b473c4dd61a9.tar.gz
frameworks_base-948235c06ed0d49190b2f49d9299b473c4dd61a9.tar.bz2
Issue 2667802: [Audio Effect Framework] AudioEffect base class and JNI.
Added AudioEffect C++ class. AudioEffect is the base class for effect specific implementations, OpenSL ES effect interfaces and audio effect JNI. Added the AudioEffect JNI and AudioEffect JAVA class. AudioEffect is the base class to implement more specific JAVA classes to control audio effects from JAVA applications. Change-Id: If300a1b708f2e6605891261e67bfb4f8330a4624
-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
+