summaryrefslogtreecommitdiffstats
path: root/media
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 /media
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
Diffstat (limited to 'media')
-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
6 files changed, 2297 insertions, 2 deletions
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
+