summaryrefslogtreecommitdiffstats
path: root/media/java
diff options
context:
space:
mode:
Diffstat (limited to 'media/java')
-rw-r--r--media/java/android/media/AudioEffect.java713
-rwxr-xr-xmedia/java/android/media/Visualizer.java510
2 files changed, 913 insertions, 310 deletions
diff --git a/media/java/android/media/AudioEffect.java b/media/java/android/media/AudioEffect.java
index b1b7fed..053cc22 100644
--- a/media/java/android/media/AudioEffect.java
+++ b/media/java/android/media/AudioEffect.java
@@ -27,22 +27,25 @@ 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.
+ * AudioEffect is the base class for implementing audio effect control in Java
+ * applications.
+ * <p>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.
+ * <p>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.
+ * <p>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 when calling the AudioEffect
+ * constructor.
*
- * {@hide Pending API council review}
+ * { @hide Pending API council review }
*/
-public class AudioEffect
-{
+public class AudioEffect {
static {
System.loadLibrary("audioeffect_jni");
native_init();
@@ -51,31 +54,60 @@ public class AudioEffect
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
+ * 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");
+ /**
+ * UUID for environmental reverb effect
+ */
+ public static final UUID EFFECT_TYPE_ENV_REVERB = UUID
+ .fromString("c2e5d5f0-94bd-4763-9cac-4e234d06839e");
+ /**
+ * UUID for preset reverb effect
+ */
+ public static final UUID EFFECT_TYPE_PRESET_REVERB = UUID
+ .fromString("47382d60-ddd8-11db-bf3a-0002a5d5c51b");
+ /**
+ * UUID for equalizer effect
+ */
+ public static final UUID EFFECT_TYPE_EQUALIZER = UUID
+ .fromString("0bed4300-ddd6-11db-8f34-0002a5d5c51b");
+ /**
+ * UUID for bass boost effect
+ */
+ public static final UUID EFFECT_TYPE_BASS_BOOST = UUID
+ .fromString("0634f220-ddd4-11db-a0fc-0002a5d5c51b");
+ /**
+ * UUID for virtualizer effect
+ */
+ public static final UUID EFFECT_TYPE_VIRTUALIZER = UUID
+ .fromString("37cc2c00-dddd-11db-8577-0002a5d5c51b");
/**
- * State of an AudioEffect object that was not successfully initialized upon creation
+ * Null effect UUID. Used when the UUID for effect type of
+ */
+ public static final UUID EFFECT_TYPE_NULL = 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;
+ public static final int STATE_INITIALIZED = 1;
+ // to keep in sync with
+ // frameworks/base/media/jni/audioeffect/android_media_AudioEffect.cpp
/**
* Event id for engine state change notification.
*/
- protected static final int NATIVE_EVENT_ENABLED_STATUS = 0;
+ protected static final int NATIVE_EVENT_ENABLED_STATUS = 0;
/**
* Event id for engine control ownership change notification.
*/
@@ -85,56 +117,89 @@ public class AudioEffect
*/
protected static final int NATIVE_EVENT_PARAMETER_CHANGED = 2;
+ /**
+ * Successful operation.
+ */
+ public static final int SUCCESS = 0;
+ /**
+ * Unspecified error.
+ */
+ public static final int ERROR = -1;
+ /**
+ * Internal opreation status. Not returned by any method.
+ */
+ public static final int ALREADY_EXISTS = -2;
+ /**
+ * Operation failed due to bad object initialization.
+ */
+ public static final int ERROR_NO_INIT = -3;
+ /**
+ * Operation failed due to bad parameter value.
+ */
+ public static final int ERROR_BAD_VALUE = -4;
+ /**
+ * Operation failed because it was requested in wrong state.
+ */
+ public static final int ERROR_INVALID_OPERATION = -5;
+ /**
+ * Operation failed due to lack of memory.
+ */
+ public static final int ERROR_NO_MEMORY = -6;
+ /**
+ * Operation failed due to dead remote object.
+ */
+ public static final int ERROR_DEAD_OBJECT = -7;
+
+ /**
+ * The effect descriptor contains necessary information to facilitate
+ * effects enumeration:<br>
+ * <ul>
+ * <li>mType: UUID corresponding to the OpenSL ES interface implemented by this effect</li>
+ * <li>mUuid: UUID for this particular implementation</li>
+ * <li>mConnectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}</li>
+ * <li>mName: human readable effect name</li>
+ * <li>mImplementor: human readable effect implementor name</li>
+ * </ul>
+ */
+ 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;
+ };
+
+ /**
+ * Effect connection mode is insert. Specifying an audio session ID when creating the effect
+ * will insert this effect after all players in the same audio session.
+ */
+ public static final String EFFECT_INSERT = "Insert";
+ /**
+ * Effect connection mode is auxiliary.
+ * <p>Auxiliary effects must be created on session 0 (global output mix). In order for a
+ * MediaPlayer or AudioTrack to be fed into this effect, they must be explicitely attached to
+ * this effect and a send level must be specified.
+ * <p>Use the effect ID returned by {@link #getId()} to designate this particular effect when
+ * attaching it to the MediaPlayer or AudioTrack.
+ */
+ public static final String EFFECT_AUXILIARY = "Auxiliary";
- // 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
*/
@@ -159,17 +224,20 @@ public class AudioEffect
/**
* Listener for effect engine state change notifications.
- * @see #setEnableStatusListener(OnEnableStatusChangeListener)
+ *
+ * @see #setEnableStatusListener(OnEnableStatusChangeListener)
*/
protected OnEnableStatusChangeListener mEnableStatusChangeListener = null;
/**
* Listener for effect engine control ownership change notifications.
- * @see #setControlStatusListener(OnControlStatusChangeListener)
+ *
+ * @see #setControlStatusListener(OnControlStatusChangeListener)
*/
protected OnControlStatusChangeListener mControlChangeStatusListener = null;
/**
* Listener for effect engine control ownership change notifications.
- * @see #setParameterListener(OnParameterChangeListener)
+ *
+ * @see #setParameterListener(OnParameterChangeListener)
*/
protected OnParameterChangeListener mParameterChangeListener = null;
/**
@@ -181,32 +249,36 @@ public class AudioEffect
*/
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.
+ *
+ * @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. This
+ * parameter can be set to {@link #EFFECT_TYPE_NULL} in which
+ * case only the uuid will be used to select the effect.
+ * @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
+ * {@link #EFFECT_TYPE_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
@@ -214,22 +286,28 @@ public class AudioEffect
*/
public AudioEffect(UUID type, UUID uuid, int priority, int audioSession)
- throws IllegalArgumentException, UnsupportedOperationException, RuntimeException {
+ 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);
+ type.toString(), uuid.toString(), priority, audioSession, id,
+ desc);
if (initResult != SUCCESS && initResult != ALREADY_EXISTS) {
- Log.e(TAG, "Error code "+initResult+" when initializing AudioEffect.");
+ 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"));
+ case ERROR_BAD_VALUE:
+ throw (new IllegalArgumentException("Effect type: " + type
+ + " not supported."));
+ case ERROR_INVALID_OPERATION:
+ throw (new UnsupportedOperationException(
+ "Effect library not loaded"));
default:
- throw (new RuntimeException("Cannot initialize effect engine for type: "+type+
- "Error: "+ initResult));
+ throw (new RuntimeException(
+ "Cannot initialize effect engine for type: " + type
+ + "Error: " + initResult));
}
}
mId = id[0];
@@ -240,9 +318,9 @@ public class AudioEffect
}
/**
- * 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.
+ * 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) {
@@ -258,119 +336,115 @@ public class AudioEffect
/**
* Get the effect descriptor.
- * {@see #Descriptor}.
+ *
+ //TODO when AudioEffect class is unhidden @ see android.media.AudioEffect.Descriptor
* @throws IllegalStateException
*/
- public Descriptor getDescriptor()
- 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
+ //TODO when AudioEffect class is unhidden: {@ link android.media.AudioEffect.Descriptor} objects
*
* @throws IllegalStateException
*/
static public Descriptor[] queryEffects() {
- return (Descriptor[])native_query_effects();
+ 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.
+ * Enable or disable effect engine.
+ *
+ * @param enabled the requested enable state
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_INVALID_OPERATION}
+ * or {@link #ERROR_DEAD_OBJECT} in case of failure.
* @throws IllegalStateException
*/
- public int disable()
- throws IllegalStateException {
- checkState("disable()");
- return native_disable();
+ public int setEnabled(boolean enabled) throws IllegalStateException {
+ checkState("setEnabled()");
+ return native_setEnabled(enabled);
}
/**
* 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.
+ * 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
+ * @param param the identifier of the parameter to set
+ * @param value the new value for the specified parameter
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
+ * {@link #ERROR_DEAD_OBJECT} in case of failure
* @throws IllegalStateException
*/
public int setParameter(byte[] param, byte[] value)
- throws IllegalStateException {
+ 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[])
+ *
+ * @see #setParameter(byte[], byte[])
*/
- public int setParameter(int param, int value)
- throws IllegalStateException {
+ 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[])
+ * 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 {
+ 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[])
+ * 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 {
+ 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[])
+ * 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 {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -386,14 +460,15 @@ public class AudioEffect
}
/**
- * 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[])
+ * 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 {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -410,14 +485,15 @@ public class AudioEffect
}
/**
- * 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[])
+ * 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 {
+ throws IllegalStateException {
if (param.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -429,20 +505,23 @@ public class AudioEffect
/**
* 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
+ * 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.
+ *
+ * @param param the identifier of the parameter to set
+ * @param value the new value for the specified parameter
+ * @return {@link #SUCCESS} in case of success, {@link #ERROR_BAD_VALUE},
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or
+ * {@link #ERROR_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 {
+ throws IllegalStateException {
checkState("getParameter()");
int[] vSize = new int[1];
vSize[0] = value.length;
@@ -456,25 +535,28 @@ public class AudioEffect
}
/**
- * Get effect parameter. The parameter is an integer and the value is an array of bytes.
- * @see #getParameter(byte[], byte[])
+ * 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 {
+ 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[])
+ * 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 {
+ throws IllegalStateException {
if (value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param);
@@ -490,14 +572,15 @@ public class AudioEffect
}
/**
- * Get effect parameter. The parameter is an integer and the value
- * is an array of 1 or 2 short integers
- * @see #getParameter(byte[], byte[])
+ * 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 {
+ throws IllegalStateException {
if (value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param);
@@ -513,14 +596,15 @@ public class AudioEffect
}
/**
- * 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[])
+ * 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 {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -539,14 +623,15 @@ public class AudioEffect
}
/**
- * 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[])
+ * 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 {
+ throws IllegalStateException {
if (param.length > 2 || value.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -565,14 +650,15 @@ public class AudioEffect
}
/**
- * 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[])
+ * 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 {
+ throws IllegalStateException {
if (param.length > 2) {
- return BAD_VALUE;
+ return ERROR_BAD_VALUE;
}
byte[] p = intToByteArray(param[0]);
if (param.length > 1) {
@@ -583,19 +669,19 @@ public class AudioEffect
return getParameter(p, value);
}
-
/**
- * Send a command to the effect engine. This method is intended to send proprietary
- * commands to a particular effect implementation.
+ * 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 {
+ throws IllegalStateException {
checkState("command()");
int[] replySize = new int[1];
replySize[0] = reply.length;
- int status = native_command(cmdCode, command.length, command, replySize, reply);
+ int status = native_command(cmdCode, command.length, command,
+ replySize, reply);
if (reply.length > replySize[0]) {
byte[] resizedReply = new byte[replySize[0]];
@@ -605,51 +691,53 @@ public class AudioEffect
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)
+ * 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 {
+ 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();
+ public boolean getEnabled() throws IllegalStateException {
+ checkState("getEnabled()");
+ return native_getEnabled();
}
/**
* Checks if this AudioEffect object is controlling the effect engine.
- * @return true if this instance has control of effect engine, false otherwise.
+ *
+ * @return true if this instance has control of effect engine, false
+ * otherwise.
* @throws IllegalStateException
*/
- public boolean hasControl()
- 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) {
@@ -662,8 +750,9 @@ public class AudioEffect
}
/**
- * Sets the listener AudioEffect notifies when the effect engine control
- * is taken or returned.
+ * Sets the listener AudioEffect notifies when the effect engine control is
+ * taken or returned.
+ *
* @param listener
*/
public void setControlStatusListener(OnControlStatusChangeListener listener) {
@@ -677,6 +766,7 @@ public class AudioEffect
/**
* Sets the listener AudioEffect notifies when a parameter is changed.
+ *
* @param listener
*/
public void setParameterListener(OnParameterChangeListener listener) {
@@ -691,7 +781,7 @@ public class AudioEffect
// 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
+ // mNativeEventHandler is null
private void createNativeEventHandler() {
Looper looper;
if ((looper = Looper.myLooper()) != null) {
@@ -703,52 +793,62 @@ public class AudioEffect
}
}
- //---------------------------------------------------------
+ // ---------------------------------------------------------
// Interface definitions
- //--------------------
+ // --------------------
/**
- * Interface definition for a callback to be invoked when the
- * effect engine is enabled or disabled.
+ * The OnParameterChangeListener interface defines a method called by the AudioEffect
+ * when a the enabled state of the effect engine was changed by the controlling application.
*/
- public interface OnEnableStatusChangeListener {
+ public interface OnEnableStatusChangeListener {
/**
- * Called on the listener to notify it that the effect engine
- * has been enabled or disabled.
+ * Called on the listener to notify it that the effect engine has been
+ * enabled or disabled.
+ * @param effect the effect on which the interface is registered.
+ * @param enabled new effect state.
*/
void onEnableStatusChange(AudioEffect effect, boolean enabled);
}
/**
- * Interface definition for a callback to be invoked when the
- * effect engine control is taken or returned.
+ * The OnControlStatusChangeListener interface defines a method called by the AudioEffect
+ * when a the control of the effect engine is gained or lost by the application
*/
- public interface OnControlStatusChangeListener {
+ public interface OnControlStatusChangeListener {
/**
- * Called on the listener to notify it that the effect engine
- * control has been taken or returned.
+ * Called on the listener to notify it that the effect engine control
+ * has been taken or returned.
+ * @param effect the effect on which the interface is registered.
+ * @param controlGranted true if the application has been granted control of the effect
+ * engine, false otherwise.
*/
void onControlStatusChange(AudioEffect effect, boolean controlGranted);
}
/**
- * Interface definition for a callback to be invoked when a
- * parameter value has changed.
+ * The OnParameterChangeListener interface defines a method called by the AudioEffect
+ * when a parameter is changed in the effect engine by the controlling application.
*/
- public interface OnParameterChangeListener {
+ public interface OnParameterChangeListener {
/**
* Called on the listener to notify it that a parameter value has changed.
+ * @param effect the effect on which the interface is registered.
+ * @param status status of the set parameter operation.
+ * @param param ID of the modified parameter.
+ * @param value the new parameter value.
*/
- void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value);
+ 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
+ * Helper class to handle the forwarding of native events to the appropriate
+ * listeners
*/
- private class NativeEventHandler extends Handler
- {
+ private class NativeEventHandler extends Handler {
private AudioEffect mAudioEffect;
public NativeEventHandler(AudioEffect ae, Looper looper) {
@@ -761,14 +861,15 @@ public class AudioEffect
if (mAudioEffect == null) {
return;
}
- switch(msg.what) {
+ 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));
+ enableStatusChangeListener.onEnableStatusChange(
+ mAudioEffect, (boolean) (msg.arg1 != 0));
}
break;
case NATIVE_EVENT_CONTROL_STATUS:
@@ -777,7 +878,8 @@ public class AudioEffect
controlStatusChangeListener = mAudioEffect.mControlChangeStatusListener;
}
if (controlStatusChangeListener != null) {
- controlStatusChangeListener.onControlStatusChange(mAudioEffect, (boolean)(msg.arg1 != 0));
+ controlStatusChangeListener.onControlStatusChange(
+ mAudioEffect, (boolean) (msg.arg1 != 0));
}
break;
case NATIVE_EVENT_PARAMETER_CHANGED:
@@ -786,10 +888,12 @@ public class AudioEffect
parameterChangeListener = mAudioEffect.mParameterChangeListener;
}
if (parameterChangeListener != null) {
- // arg1 contains offset of parameter value from start of byte array
+ // 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
+ 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);
@@ -798,90 +902,76 @@ public class AudioEffect
System.arraycopy(p, 12, param, 0, psize);
System.arraycopy(p, vOffset, value, 0, vsize);
- parameterChangeListener.onParameterChange(mAudioEffect, status, param, value);
+ parameterChangeListener.onParameterChange(mAudioEffect,
+ status, param, value);
}
break;
- default:
+ 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();
+ 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);
+ 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 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_setEnabled(boolean enabled);
- private native final int native_disable();
-
- private native final boolean native_getEnable();
+ private native final boolean native_getEnabled();
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_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_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 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 {
+ protected void checkState(String methodName) throws IllegalStateException {
synchronized (mStateLock) {
if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException(methodName+" called on uninitialized AudioEffect."));
+ throw (new IllegalStateException(methodName
+ + " called on uninitialized AudioEffect."));
}
}
}
@@ -890,10 +980,12 @@ public class AudioEffect
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"));
+ case AudioEffect.ERROR_BAD_VALUE:
+ throw (new IllegalArgumentException(
+ "AudioEffect: bad parameter value"));
+ case AudioEffect.ERROR_INVALID_OPERATION:
+ throw (new UnsupportedOperationException(
+ "AudioEffect: invalid parameter operation"));
default:
throw (new RuntimeException("AudioEffect: set/get parameter error"));
}
@@ -903,6 +995,7 @@ public class AudioEffect
return byteArrayToInt(valueBuf, 0);
}
+
protected int byteArrayToInt(byte[] valueBuf, int offset) {
ByteBuffer converter = ByteBuffer.wrap(valueBuf);
converter.order(ByteOrder.nativeOrder());
@@ -931,12 +1024,12 @@ public class AudioEffect
protected byte[] shortToByteArray(short value) {
ByteBuffer converter = ByteBuffer.allocate(2);
converter.order(ByteOrder.nativeOrder());
- short sValue = (short)value;
+ short sValue = (short) value;
converter.putShort(sValue);
return converter.array();
}
- protected byte[] concatArrays(byte[] ...arrays) {
+ protected byte[] concatArrays(byte[]... arrays) {
int len = 0;
for (byte[] a : arrays) {
len += a.length;
diff --git a/media/java/android/media/Visualizer.java b/media/java/android/media/Visualizer.java
new file mode 100755
index 0000000..cdd3cdf
--- /dev/null
+++ b/media/java/android/media/Visualizer.java
@@ -0,0 +1,510 @@
+/*
+ * 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;
+
+/**
+ * The Visualizer class enables application to retrieve part of the currently playing audio for
+ * visualization purpose. It is not an audio recording interface and only returns partial and low
+ * quality audio content. However, to protect privacy of certain audio data (e.g voice mail) the use
+ * of the visualizer requires the permission android.permission.RECORD_AUDIO.
+ * <p>The audio session ID passed to the constructor indicates which audio content should be
+ * visualized:<br>
+ * <ul>
+ * <li>If the session is 0, the audio output mix is visualized</li>
+ * <li>If the session is not 0, the audio from a particular {@link MediaPlayer} or
+ * {@link AudioTrack}
+ * using this audio session is visualized </li>
+ * </ul>
+ * <p>Two types of representation of audio content can be captured: <br>
+ * <ul>
+ * <li>Waveform data: consecutive 8-bit (unsigned) mono samples by using the
+ * {@link #getWaveForm(byte[])} method</li>
+ * <li>Frequency data: 8-bit magnitude FFT by using the {@link #getFft(byte[])} method</li>
+ * </ul>
+ * <p>The length of the capture can be retrieved or specified by calling respectively
+ * {@link #getCaptureSize()} and {@link #setCaptureSize(int)} methods. Note that the size of the FFT
+ * is half of the specified capture size but both sides of the spectrum are returned yielding in a
+ * number of bytes equal to the capture size. The capture size must be a power of 2 in the range
+ * returned by {@link #getCaptureSizeRange()}.
+ * <p>In addition to the polling capture mode described above with {@link #getWaveForm(byte[])} and
+ * {@link #getFft(byte[])} methods, a callback mode is also available by installing a listener by
+ * use of the {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+ * The rate at which the listener capture method is called as well as the type of data returned is
+ * specified.
+ * <p>Before capturing data, the Visualizer must be enabled by calling the
+ * {@link #setEnabled(boolean)} method.
+ * When data capture is not needed any more, the Visualizer should be disabled.
+ * <p>It is good practice to call the {@link #release()} method when the Visualizer is not used
+ * anymore to free up native resources associated to the Visualizer instance.
+ *
+ * {@hide Pending API council review}
+ */
+
+public class Visualizer {
+
+ static {
+ System.loadLibrary("audioeffect_jni");
+ native_init();
+ }
+
+ private final static String TAG = "Visualizer-JAVA";
+
+ /**
+ * State of a Visualizer object that was not successfully initialized upon creation
+ */
+ public static final int STATE_UNINITIALIZED = 0;
+ /**
+ * State of a Visualizer object that is ready to be used.
+ */
+ public static final int STATE_INITIALIZED = 1;
+ /**
+ * State of a Visualizer object that is active.
+ */
+ public static final int STATE_ENABLED = 2;
+
+ // to keep in sync with frameworks/base/media/jni/audioeffect/android_media_Visualizer.cpp
+ protected static final int NATIVE_EVENT_PCM_CAPTURE = 0;
+ protected static final int NATIVE_EVENT_FFT_CAPTURE = 1;
+
+ // Error codes:
+ /**
+ * Successful operation.
+ */
+ public static final int SUCCESS = 0;
+ /**
+ * Unspecified error.
+ */
+ public static final int ERROR = -1;
+ /**
+ * Internal opreation status. Not returned by any method.
+ */
+ public static final int ALREADY_EXISTS = -2;
+ /**
+ * Operation failed due to bad object initialization.
+ */
+ public static final int ERROR_NO_INIT = -3;
+ /**
+ * Operation failed due to bad parameter value.
+ */
+ public static final int ERROR_BAD_VALUE = -4;
+ /**
+ * Operation failed because it was requested in wrong state.
+ */
+ public static final int ERROR_INVALID_OPERATION = -5;
+ /**
+ * Operation failed due to lack of memory.
+ */
+ public static final int ERROR_NO_MEMORY = -6;
+ /**
+ * Operation failed due to dead remote object.
+ */
+ public static final int ERROR_DEAD_OBJECT = -7;
+
+ //--------------------------------------------------------------------------
+ // Member variables
+ //--------------------
+ /**
+ * Indicates the state of the Visualizer instance
+ */
+ protected int mState = STATE_UNINITIALIZED;
+ /**
+ * Lock to synchronize access to mState
+ */
+ protected final Object mStateLock = new Object();
+ /**
+ * System wide unique Identifier of the visualizer engine used by this Visualizer instance
+ */
+ protected int mId;
+
+ /**
+ * 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;
+ /**
+ * PCM and FFT capture listener registered by client
+ */
+ protected OnDataCaptureListener mCaptureListener = null;
+
+ // accessed by native methods
+ private int mNativeVisualizer;
+ private int mJniData;
+
+ //--------------------------------------------------------------------------
+ // Constructor, Finalize
+ //--------------------
+ /**
+ * Class constructor.
+ * @param audioSession System wide unique audio session identifier. If audioSession
+ * is not 0, the visualizer will be attached to the MediaPlayer or AudioTrack in the
+ * same audio session. Otherwise, the Visualizer will apply to the output mix.
+ *
+ * @throws java.lang.UnsupportedOperationException
+ * @throws java.lang.RuntimeException
+ */
+
+ public Visualizer(int audioSession)
+ throws UnsupportedOperationException, RuntimeException {
+ int[] id = new int[1];
+
+ synchronized (mStateLock) {
+ mState = STATE_UNINITIALIZED;
+ // native initialization
+ int result = native_setup(new WeakReference<Visualizer>(this), audioSession, id);
+ if (result != SUCCESS && result != ALREADY_EXISTS) {
+ Log.e(TAG, "Error code "+result+" when initializing Visualizer.");
+ switch (result) {
+ case ERROR_INVALID_OPERATION:
+ throw (new UnsupportedOperationException("Effect library not loaded"));
+ default:
+ throw (new RuntimeException("Cannot initialize Visualizer engine, error: "
+ +result));
+ }
+ }
+ mId = id[0];
+ if (native_getEnabled()) {
+ mState = STATE_ENABLED;
+ } else {
+ mState = STATE_INITIALIZED;
+ }
+ }
+ }
+
+ /**
+ * Releases the native Visualizer resources. It is a good practice to release the
+ * visualization engine when not in use.
+ */
+ public void release() {
+ synchronized (mStateLock) {
+ native_release();
+ mState = STATE_UNINITIALIZED;
+ }
+ }
+
+ @Override
+ protected void finalize() {
+ native_finalize();
+ }
+
+ /**
+ * Enable or disable the visualization engine.
+ * @param enabled requested enable state
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT} in case of failure.
+ * @throws IllegalStateException
+ */
+ public int setEnabled(boolean enabled)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if ((enabled && mState != STATE_INITIALIZED) ||
+ (!enabled && mState != STATE_ENABLED)) {
+ throw(new IllegalStateException("setEnabled() called in wrong state: "+mState));
+ }
+ int status = native_setEnabled(enabled);
+ if (status == SUCCESS) {
+ mState = enabled ? STATE_ENABLED : STATE_INITIALIZED;
+ }
+ return status;
+ }
+ }
+
+ /**
+ * Get current activation state of the visualizer.
+ * @return true if the visualizer is active, false otherwise
+ */
+ public boolean getEnabled()
+ {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("getEnabled() called in wrong state: "+mState));
+ }
+ return native_getEnabled();
+ }
+ }
+
+ /**
+ * Returns the capture size range.
+ * @return the mininum capture size is returned in first array element and the maximum in second
+ * array element.
+ */
+ public static native int[] getCaptureSizeRange();
+
+ /**
+ * Returns the maximum capture rate for the callback capture method. This is the maximum value
+ * for the rate parameter of the
+ * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+ * @return the maximum capture rate expressed in milliHertz
+ */
+ public static native int getMaxCaptureRate();
+
+ /**
+ * Sets the capture size, i.e. the number of bytes returned by {@link #getWaveForm(byte[])} and
+ * {@link #getFft(byte[])} methods. The capture size must be a power of 2 in the range returned
+ * by {@link #getCaptureSizeRange()}.
+ * This method must not be called when the Visualizer is enabled.
+ * @param size requested capture size
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_BAD_VALUE} in case of failure.
+ * @throws IllegalStateException
+ */
+ public int setCaptureSize(int size)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState != STATE_INITIALIZED) {
+ throw(new IllegalStateException("setCaptureSize() called in wrong state: "+mState));
+ }
+ return native_setCaptureSize(size);
+ }
+ }
+
+ /**
+ * Returns current capture size.
+ * @return the capture size in bytes.
+ */
+ public int getCaptureSize()
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("getCaptureSize() called in wrong state: "+mState));
+ }
+ return native_getCaptureSize();
+ }
+ }
+
+ /**
+ * Returns the sampling rate of the captured audio.
+ * @return the sampling rate in milliHertz.
+ */
+ public int getSamplingRate()
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState == STATE_UNINITIALIZED) {
+ throw(new IllegalStateException("getSamplingRate() called in wrong state: "+mState));
+ }
+ return native_getSamplingRate();
+ }
+ }
+
+ /**
+ * Returns a waveform capture of currently playing audio content. The capture consists in
+ * a number of consecutive 8-bit (unsigned) mono PCM samples equal to the capture size returned
+ * by {@link #getCaptureSize()}.
+ * <p>This method must be called when the Visualizer is enabled.
+ * @param waveform array of bytes where the waveform should be returned
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+ * in case of failure.
+ * @throws IllegalStateException
+ */
+ public int getWaveForm(byte[] waveform)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState != STATE_ENABLED) {
+ throw(new IllegalStateException("getWaveForm() called in wrong state: "+mState));
+ }
+ return native_getWaveForm(waveform);
+ }
+ }
+ /**
+ * Returns a frequency capture of currently playing audio content. The capture is a 8-bit
+ * magnitude FFT. Note that the size of the FFT is half of the specified capture size but both
+ * sides of the spectrum are returned yielding in a number of bytes equal to the capture size.
+ * {@see #getCaptureSize()}.
+ * <p>This method must be called when the Visualizer is enabled.
+ * @param fft array of bytes where the FFT should be returned
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_NO_MEMORY}, {@link #ERROR_INVALID_OPERATION} or {@link #ERROR_DEAD_OBJECT}
+ * in case of failure.
+ * @throws IllegalStateException
+ */
+ public int getFft(byte[] fft)
+ throws IllegalStateException {
+ synchronized (mStateLock) {
+ if (mState != STATE_ENABLED) {
+ throw(new IllegalStateException("getFft() called in wrong state: "+mState));
+ }
+ return native_getFft(fft);
+ }
+ }
+
+ //---------------------------------------------------------
+ // Interface definitions
+ //--------------------
+ /**
+ * The OnDataCaptureListener interface defines methods called by the Visualizer to periodically
+ * update the audio visualization capture.
+ * The client application can implement this interface and register the listener with the
+ * {@link #setDataCaptureListener(OnDataCaptureListener, int, boolean, boolean)} method.
+ */
+ public interface OnDataCaptureListener {
+ /**
+ * Method called when a new waveform capture is available.
+ * @param visualizer Visualizer object on which the listener is registered.
+ * @param waveform array of bytes containing the waveform representation.
+ * @param samplingRate sampling rate of the audio visualized.
+ */
+ void onWaveFormDataCapture(Visualizer visualizer, byte[] waveform, int samplingRate);
+
+ /**
+ * Method called when a new frequency capture is available.
+ * @param visualizer Visualizer object on which the listener is registered.
+ * @param fft array of bytes containing the frequency representation.
+ * @param samplingRate sampling rate of the audio visualized.
+ */
+ void onFftDataCapture(Visualizer visualizer, byte[] fft, int samplingRate);
+ }
+
+ /**
+ * Registers an OnDataCaptureListener interface and specifies the rate at which the capture
+ * should be updated as well as the type of capture requested.
+ * <p>Call this method with a null listener to stop receiving the capture updates.
+ * @param listener OnDataCaptureListener registered
+ * @param rate rate in milliHertz at which the capture should be updated
+ * @param waveform true if a waveform capture is requested: the onWaveFormDataCapture()
+ * method will be called on the OnDataCaptureListener interface.
+ * @param fft true if a frequency capture is requested: the onFftDataCapture() method will be
+ * called on the OnDataCaptureListener interface.
+ * @return {@link #SUCCESS} in case of success,
+ * {@link #ERROR_NO_INIT} or {@link #ERROR_BAD_VALUE} in case of failure.
+ */
+ public int setDataCaptureListener(OnDataCaptureListener listener,
+ int rate, boolean waveform, boolean fft) {
+ synchronized (mListenerLock) {
+ mCaptureListener = listener;
+ }
+ if (listener == null) {
+ // make sure capture callback is stopped in native code
+ waveform = false;
+ fft = false;
+ }
+ int status = native_setPeriodicCapture(rate, waveform, fft);
+ if (status == SUCCESS) {
+ if ((listener != null) && (mNativeEventHandler == null)) {
+ 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;
+ status = ERROR_NO_INIT;
+ }
+ }
+ }
+ return status;
+ }
+
+ /**
+ * Helper class to handle the forwarding of native events to the appropriate listeners
+ */
+ private class NativeEventHandler extends Handler
+ {
+ private Visualizer mVisualizer;
+
+ public NativeEventHandler(Visualizer v, Looper looper) {
+ super(looper);
+ mVisualizer = v;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mVisualizer == null) {
+ return;
+ }
+ OnDataCaptureListener l = null;
+ synchronized (mListenerLock) {
+ l = mVisualizer.mCaptureListener;
+ }
+
+ if (l != null) {
+ byte[] data = (byte[])msg.obj;
+ int samplingRate = msg.arg1;
+ switch(msg.what) {
+ case NATIVE_EVENT_PCM_CAPTURE:
+ l.onWaveFormDataCapture(mVisualizer, data, samplingRate);
+ break;
+ case NATIVE_EVENT_FFT_CAPTURE:
+ l.onFftDataCapture(mVisualizer, data, samplingRate);
+ break;
+ default:
+ Log.e(TAG,"Unknown native event: "+msg.what);
+ break;
+ }
+ }
+ }
+ }
+
+ //---------------------------------------------------------
+ // Interface definitions
+ //--------------------
+
+ private static native final void native_init();
+
+ private native final int native_setup(Object audioeffect_this,
+ int audioSession,
+ int[] id);
+
+ private native final void native_finalize();
+
+ private native final void native_release();
+
+ private native final int native_setEnabled(boolean enabled);
+
+ private native final boolean native_getEnabled();
+
+ private native final int native_setCaptureSize(int size);
+
+ private native final int native_getCaptureSize();
+
+ private native final int native_getSamplingRate();
+
+ private native final int native_getWaveForm(byte[] waveform);
+
+ private native final int native_getFft(byte[] fft);
+
+ private native final int native_setPeriodicCapture(int rate, boolean waveForm, boolean fft);
+
+ //---------------------------------------------------------
+ // Java methods called from the native side
+ //--------------------
+ @SuppressWarnings("unused")
+ private static void postEventFromNative(Object effect_ref,
+ int what, int arg1, int arg2, Object obj) {
+ Visualizer visu = (Visualizer)((WeakReference)effect_ref).get();
+ if (visu == null) {
+ return;
+ }
+
+ if (visu.mNativeEventHandler != null) {
+ Message m = visu.mNativeEventHandler.obtainMessage(what, arg1, arg2, obj);
+ visu.mNativeEventHandler.sendMessage(m);
+ }
+
+ }
+
+}
+