am e0219539: am 01f7ac64: Merge "Issue 2667802: [Audio Effect Framework] AudioEffect base class and JNI." into kraken

Merge commit 'e0219539c6c3e60de4a35cd836df3b68c963e9e0' into gingerbread-plus-aosp

* commit 'e0219539c6c3e60de4a35cd836df3b68c963e9e0':
  Issue 2667802: [Audio Effect Framework] AudioEffect base class and JNI.
This commit is contained in:
Eric Laurent
2010-06-14 09:07:03 -07:00
committed by Android Git Automerger
7 changed files with 2759 additions and 2 deletions

462
include/media/AudioEffect.h Normal file
View File

@ -0,0 +1,462 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ANDROID_AUDIOEFFECT_H
#define ANDROID_AUDIOEFFECT_H
#include <stdint.h>
#include <sys/types.h>
#include <media/IAudioFlinger.h>
#include <media/IEffect.h>
#include <media/IEffectClient.h>
#include <media/EffectApi.h>
#include <media/AudioSystem.h>
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <binder/IInterface.h>
namespace android {
// ----------------------------------------------------------------------------
class effect_param_cblk_t;
// ----------------------------------------------------------------------------
class AudioEffect : public RefBase
{
public:
/*
* Static methods for effect libraries management.
*/
/*
* Loads the effect library which path is given as first argument.
* This must be the full path of a dynamic library (.so) implementing one or
* more effect engines and exposing the effect library interface described in
* EffectApi.h. The function returns a handle on the library for use by
* further call to unloadEffectLibrary() to unload the library.
*
* Parameters:
* libPath: full path of the dynamic library file in the file system.
* handle: address where to return the library handle
*
* Returned status (from utils/Errors.h) can be:
* NO_ERROR successful operation.
* PERMISSION_DENIED could not get AudioFlinger interface or
* application does not have permission to configure audio
* NO_INIT effect factory not initialized or
* library could not be loaded or
* library does not implement required functions
* BAD_VALUE invalid libPath string or handle
*
* Returned value:
* *handle updated with library handle
*/
static status_t loadEffectLibrary(const char *libPath, int *handle);
/*
* Unloads the effect library which handle is given as argument.
*
* Parameters:
* handle: library handle
*
* Returned status (from utils/Errors.h) can be:
* NO_ERROR successful operation.
* PERMISSION_DENIED could not get AudioFlinger interface or
* application does not have permission to configure audio
* NO_INIT effect factory not initialized
* BAD_VALUE invalid handle
*/
static status_t unloadEffectLibrary(int handle);
/*
* Static methods for effects enumeration.
*/
/*
* Returns the number of effects available. This method together
* with EffectQueryNext() is used to enumerate all effects:
* The enumeration sequence is:
* QueryNumberEffects(&num_effects);
* while (num_effects--)
* QueryNextEffect();
*
* Parameters:
* pNumEffects: address where the number of effects should be returned.
*
* Returned status (from utils/Errors.h) can be:
* NO_ERROR successful operation.
* PERMISSION_DENIED could not get AudioFlinger interface
* NO_INIT effect library failed to initialize
* BAD_VALUE invalid numEffects pointer
*
* Returned value
* *numEffects: updated with number of effects available
*/
static status_t queryNumberEffects(uint32_t *numEffects);
/*
* Returns number effect descriptor during effect
* enumeration.
*
* Parameters:
* pDescriptor: address where the effect descriptor should be returned.
*
* Returned status (from utils/Errors.h) can be:
* NO_ERROR successful operation.
* NAME_NOT_FOUND no more effect available
* PERMISSION_DENIED could not get AudioFlinger interface
* NO_INIT effect library failed to initialize
* BAD_VALUE invalid descriptor pointer
* INVALID_OPERATION effect list has changed since last execution of queryNumberEffects()
*
* Returned value
* *descriptor: updated with effect descriptor
*/
static status_t queryNextEffect(effect_descriptor_t *descriptor);
/*
* Returns the descriptor for the specified effect uuid.
*
* Parameters:
* uuid: pointer to effect uuid.
* descriptor: address where the effect descriptor should be returned.
*
* Returned status (from utils/Errors.h) can be:
* NO_ERROR successful operation.
* PERMISSION_DENIED could not get AudioFlinger interface
* NO_INIT effect library failed to initialize
* BAD_VALUE invalid uuid or descriptor pointers
* NAME_NOT_FOUND no effect with this uuid found
*
* Returned value
* *descriptor updated with effect descriptor
*/
static status_t getEffectDescriptor(effect_uuid_t *uuid, effect_descriptor_t *descriptor);
/*
* Events used by callback function (effect_callback_t).
*/
enum event_type {
EVENT_CONTROL_STATUS_CHANGED = 0,
EVENT_ENABLE_STATUS_CHANGED = 1,
EVENT_PARAMETER_CHANGED = 2,
EVENT_ERROR = 3
};
/* Callback function notifying client application of a change in effect engine state or
* configuration.
* An effect engine can be shared by several applications but only one has the control
* of the engine activity and configuration at a time.
* The EVENT_CONTROL_STATUS_CHANGED event is received when an application loses or
* retrieves the control of the effect engine. Loss of control happens
* if another application requests the use of the engine by creating an AudioEffect for
* the same effect type but with a higher priority. Control is returned when the
* application having the control deletes its AudioEffect object.
* The EVENT_ENABLE_STATUS_CHANGED event is received by all applications not having the
* control of the effect engine when the effect is enabled or disabled.
* The EVENT_PARAMETER_CHANGED event is received by all applications not having the
* control of the effect engine when an effect parameter is changed.
* The EVENT_ERROR event is received when the media server process dies.
*
* Parameters:
*
* event: type of event notified (see enum AudioEffect::event_type).
* user: Pointer to context for use by the callback receiver.
* info: Pointer to optional parameter according to event type:
* - EVENT_CONTROL_STATUS_CHANGED: boolean indicating if control is granted (true)
* or stolen (false).
* - EVENT_ENABLE_STATUS_CHANGED: boolean indicating if effect is now enabled (true)
* or disabled (false).
* - EVENT_PARAMETER_CHANGED: pointer to a effect_param_t structure.
* - EVENT_ERROR: status_t indicating the error (DEAD_OBJECT when media server dies).
*/
typedef void (*effect_callback_t)(int32_t event, void* user, void *info);
/* Constructor.
* AudioEffect is the base class for creating and controlling an effect engine from
* the application process. Creating an AudioEffect object will create the effect engine
* in the AudioFlinger if no engine of the specified type exists. If one exists, this engine
* will be used. The application creating the AudioEffect object (or a derived class like
* Reverb for instance) will either receive control of the effect engine or not, depending
* on the priority parameter. If priority is higher than the priority used by the current
* effect engine owner, the control will be transfered to the new application. Otherwise
* control will remain to the previous application. In this case, the new application will be
* notified of changes in effect engine state or control ownership by the effect callback.
* After creating the AudioEffect, the application must call the initCheck() method and
* check the creation status before trying to control the effect engine (see initCheck()).
* If the effect is to be applied to an AudioTrack or MediaPlayer only the application
* must specify the audio session ID corresponding to this player.
*/
/* Simple Constructor.
*/
AudioEffect();
/* Constructor.
*
* Parameters:
*
* type: type of effect created: can be null if uuid is specified. This corresponds to
* the OpenSL ES interface implemented by this effect.
* uuid: Uuid of effect created: can be null if type is specified. This uuid corresponds to
* a particular implementation of an effect type.
* priority: requested priority for effect control: the priority level corresponds to the
* value of priority parameter: negative values indicate lower priorities, positive values
* higher priorities, 0 being the normal priority.
* cbf: optional callback function (see effect_callback_t)
* user: pointer to context for use by the callback receiver.
* sessionID: audio session this effect is associated to. If 0, the effect will be global to
* the output mix. If not 0, the effect will be applied to all players
* (AudioTrack or MediaPLayer) within the same audio session.
* output: HAL audio output stream to which this effect must be attached. Leave at 0 for
* automatic output selection by AudioFlinger.
*/
AudioEffect(const effect_uuid_t *type,
const effect_uuid_t *uuid = NULL,
int32_t priority = 0,
effect_callback_t cbf = 0,
void* user = 0,
int sessionId = 0,
audio_io_handle_t output = 0
);
/* Constructor.
* Same as above but with type and uuid specified by character strings
*/
AudioEffect(const char *typeStr,
const char *uuidStr = NULL,
int32_t priority = 0,
effect_callback_t cbf = 0,
void* user = 0,
int sessionId = 0,
audio_io_handle_t output = 0
);
/* Terminates the AudioEffect and unregisters it from AudioFlinger.
* The effect engine is also destroyed if this AudioEffect was the last controlling
* the engine.
*/
~AudioEffect();
/* Initialize an uninitialized AudioEffect.
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR or ALREADY_EXISTS: successful initialization
* - INVALID_OPERATION: AudioEffect is already initialized
* - BAD_VALUE: invalid parameter
* - NO_INIT: audio flinger or audio hardware not initialized
* */
status_t set(const effect_uuid_t *type,
const effect_uuid_t *uuid = NULL,
int32_t priority = 0,
effect_callback_t cbf = 0,
void* user = 0,
int sessionId = 0,
audio_io_handle_t output = 0
);
/* Result of constructing the AudioEffect. This must be checked
* before using any AudioEffect API.
* initCheck() can return:
* - NO_ERROR: the effect engine is successfully created and the application has control.
* - ALREADY_EXISTS: the effect engine is successfully created but the application does not
* have control.
* - NO_INIT: the effect creation failed.
*
*/
status_t initCheck() const;
/* Returns the unique effect Id for the controlled effect engine. This ID is unique
* system wide and is used for instance in the case of auxiliary effects to attach
* the effect to an AudioTrack or MediaPlayer.
*
*/
int32_t id() const { return mId; }
/* Returns a descriptor for the effect (see effect_descriptor_t in EffectApi.h).
*/
effect_descriptor_t descriptor() const;
/* Returns effect control priority of this AudioEffect object.
*/
int32_t priority() const { return mPriority; }
/* Enables the effect engine.
*
* Parameters:
* None.
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
* - INVALID_OPERATION: the application does not have control of the effect engine
*/
status_t enable();
/* Disables the effect engine.
*
* Parameters:
* None.
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
* - INVALID_OPERATION: the application does not have control of the effect engine
*/
status_t disable();
bool isEnabled() const;
/* Sets a parameter value.
*
* Parameters:
* param: pointer to effect_param_t structure containing the parameter
* and its value (See EffectApi.h).
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation.
* - INVALID_OPERATION: the application does not have control of the effect engine.
* - BAD_VALUE: invalid parameter identifier or value.
* - DEAD_OBJECT: the effect engine has been deleted.
*/
status_t setParameter(effect_param_t *param);
/* Prepare a new parameter value that will be set by next call to
* setParameterCommit(). This method can be used to set multiple parameters
* in a synchronous manner or to avoid multiple binder calls for each
* parameter.
*
* Parameters:
* param: pointer to effect_param_t structure containing the parameter
* and its value (See EffectApi.h).
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation.
* - INVALID_OPERATION: the application does not have control of the effect engine.
* - NO_MEMORY: no more space available in shared memory used for deferred parameter
* setting.
*/
status_t setParameterDeferred(effect_param_t *param);
/* Commit all parameter values previously prepared by setParameterDeferred().
*
* Parameters:
* none
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation.
* - INVALID_OPERATION: No new parameter values ready for commit.
* - BAD_VALUE: invalid parameter identifier or value: there is no indication
* as to which of the parameters caused this error.
* - DEAD_OBJECT: the effect engine has been deleted.
*/
status_t setParameterCommit();
/* Gets a parameter value.
*
* Parameters:
* param: pointer to effect_param_t structure containing the parameter
* and the returned value (See EffectApi.h).
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation.
* - INVALID_OPERATION: the AudioEffect was not successfully initialized.
* - BAD_VALUE: invalid parameter identifier.
* - DEAD_OBJECT: the effect engine has been deleted.
*/
status_t getParameter(effect_param_t *param);
/* Sends a command and receives a response to/from effect engine.
* See EffectApi.h for details on effect command() function, valid command codes
* and formats.
*/
status_t command(int32_t cmdCode, int32_t cmdSize, void *cmdData, int32_t *replySize, void *replyData);
/*
* Utility functions.
*/
/* Converts the string passed as first argument to the effect_uuid_t
* pointed to by second argument
*/
static status_t stringToGuid(const char *str, effect_uuid_t *guid);
/* Converts the effect_uuid_t pointed to by first argument to the
* string passed as second argument
*/
static status_t guidToString(const effect_uuid_t *guid, char *str, size_t maxLen);
private:
// Implements the IEffectClient interface
class EffectClient : public android::BnEffectClient, public android::IBinder::DeathRecipient
{
public:
EffectClient(AudioEffect *effect) : mEffect(effect){}
// IEffectClient
virtual void controlStatusChanged(bool controlGranted) {mEffect->controlStatusChanged(controlGranted);}
virtual void enableStatusChanged(bool enabled) {mEffect->enableStatusChanged(enabled);}
virtual void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData) {
mEffect->commandExecuted(cmdCode, cmdSize, pCmdData, replySize, pReplyData);
}
// IBinder::DeathRecipient
virtual void binderDied(const wp<IBinder>& who) {mEffect->binderDied();}
private:
AudioEffect *mEffect;
};
friend class EffectClient;
// IEffectClient
void controlStatusChanged(bool controlGranted);
void enableStatusChanged(bool enabled);
void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData);
void binderDied();
sp<IEffect> mIEffect; // IEffect binder interface
sp<EffectClient> mIEffectClient; // IEffectClient implementation
sp<IMemory> mCblkMemory; // shared memory for deferred parameter setting
effect_param_cblk_t* mCblk; // control block for deferred parameter setting
int32_t mPriority; // priority for effect control
status_t mStatus; // effect status
volatile int32_t mEnabled; // enable state
effect_callback_t mCbf; // callback function for status, control, parameter changes notifications
void* mUserData; // client context for callback function
effect_descriptor_t mDescriptor; // effect descriptor
int32_t mId; // system wide unique effect engine instance identifier
int32_t mSessionId; // audio session ID
};
}; // namespace android
#endif // ANDROID_AUDIOEFFECT_H

View File

@ -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;
}
}

View File

@ -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))

View File

@ -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)

View File

@ -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;
}

View File

@ -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

View File

@ -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