Merge "Issue 2667801: [Audio Effect Framework] AudioFlinger, AudioMixer AudioTrack modifications." into kraken

This commit is contained in:
Eric Laurent
2010-06-04 00:14:46 -07:00
committed by Android (Google) Code Review
23 changed files with 3332 additions and 386 deletions

View File

@@ -142,7 +142,8 @@ public:
uint32_t flags = 0,
callback_t cbf = 0,
void* user = 0,
int notificationFrames = 0);
int notificationFrames = 0,
int sessionId = 0);
/* Terminates the AudioRecord and unregisters it from AudioFlinger.
@@ -168,7 +169,8 @@ public:
callback_t cbf = 0,
void* user = 0,
int notificationFrames = 0,
bool threadCanCallJava = false);
bool threadCanCallJava = false,
int sessionId = 0);
/* Result of constructing the AudioRecord. This must be checked
@@ -270,6 +272,16 @@ public:
*/
audio_io_handle_t getInput();
/* returns the audio session ID associated to this AudioRecord.
*
* Parameters:
* none.
*
* Returned value:
* AudioRecord session ID.
*/
int getSessionId();
/* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -356,6 +368,7 @@ private:
uint32_t mFlags;
uint32_t mChannels;
audio_io_handle_t mInput;
int mSessionId;
};
}; // namespace android

View File

@@ -230,6 +230,8 @@ public:
static status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int stream = DEFAULT);
static unsigned int getInputFramesLost(audio_io_handle_t ioHandle);
static int newAudioSessionId();
//
// AudioPolicyService interface
//

View File

@@ -138,7 +138,8 @@ public:
uint32_t flags = 0,
callback_t cbf = 0,
void* user = 0,
int notificationFrames = 0);
int notificationFrames = 0,
int sessionId = 0);
/* Creates an audio track and registers it with AudioFlinger. With this constructor,
* The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
@@ -157,7 +158,8 @@ public:
uint32_t flags = 0,
callback_t cbf = 0,
void* user = 0,
int notificationFrames = 0);
int notificationFrames = 0,
int sessionId = 0);
/* Terminates the AudioTrack and unregisters it from AudioFlinger.
* Also destroys all resources assotiated with the AudioTrack.
@@ -182,7 +184,8 @@ public:
void* user = 0,
int notificationFrames = 0,
const sp<IMemory>& sharedBuffer = 0,
bool threadCanCallJava = false);
bool threadCanCallJava = false,
int sessionId = 0);
/* Result of constructing the AudioTrack. This must be checked
@@ -239,10 +242,17 @@ public:
/* set volume for this track, mostly used for games' sound effects
* left and right volumes. Levels must be <= 1.0.
*/
void setVolume(float left, float right);
status_t setVolume(float left, float right);
void getVolume(float* left, float* right);
/* set the send level for this track. An auxiliary effect should be attached
* to the track with attachEffect(). Level must be <= 1.0.
*/
status_t setSendLevel(float level);
void getSendLevel(float* level);
/* set sample rate for this track, mostly used for games' sound effects
*/
status_t setSampleRate(int sampleRate);
@@ -340,6 +350,31 @@ public:
*/
audio_io_handle_t getOutput();
/* returns the unique ID associated to this track.
*
* Parameters:
* none.
*
* Returned value:
* AudioTrack ID.
*/
int getSessionId();
/* Attach track auxiliary output to specified effect. Used effectId = 0
* to detach track from effect.
*
* Parameters:
*
* effectId: effectId obtained from AudioEffect::id().
*
* Returned status (from utils/Errors.h) can be:
* - NO_ERROR: successful operation
* - INVALID_OPERATION: the effect is not an auxiliary effect.
* - BAD_VALUE: The specified effect ID is invalid
*/
status_t attachAuxEffect(int effectId);
/* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -406,6 +441,7 @@ private:
sp<AudioTrackThread> mAudioTrackThread;
float mVolume[2];
float mSendLevel;
uint32_t mFrameCount;
audio_track_cblk_t* mCblk;
@@ -431,6 +467,7 @@ private:
uint32_t mNewPosition;
uint32_t mUpdatePeriod;
uint32_t mFlags;
int mSessionId;
};

View File

@@ -114,7 +114,8 @@ typedef struct effect_descriptor_s {
// +---------------------------+-----------+-----------------------------------
// | Volume management | 5..6 | 0 none
// | | | 1 implements volume control
// | | | 2..3 reserved
// | | | 2 requires volume indication
// | | | 3 reserved
// +---------------------------+-----------+-----------------------------------
// | Device management | 7..8 | 0 none
// | | | 1 requires device updates
@@ -154,6 +155,7 @@ typedef struct effect_descriptor_s {
// volume control
#define EFFECT_FLAG_VOLUME_MASK 0x00000060
#define EFFECT_FLAG_VOLUME_CTRL 0x00000020
#define EFFECT_FLAG_VOLUME_IND 0x00000040
#define EFFECT_FLAG_VOLUME_NONE 0x00000000
// device control
@@ -296,10 +298,12 @@ struct effect_interface_s {
// | Set and get volume. Used by | EFFECT_CMD_SET_VOLUME | size: n * sizeof(uint32_t) | size: n * sizeof(uint32_t)
// | audio framework to delegate | | data: volume for each channel | data: volume for each channel
// | volume control to effect engine| | defined in effect_config_t in | defined in effect_config_t in
// | The engine must return the | | 8.24 fixed point format | 8.24 fixed point format
// | volume that should be applied | | |
// | before the effect is processed | | |
// | The overall volume (the volume | | |
// | If volume control flag is set | | 8.24 fixed point format | 8.24 fixed point format
// | in the effect descriptor, the | | | It is legal to receive a null
// | effect engine must return the | | | pointer as pReplyData in which
// | volume that should be applied | | | case the effect framework has
// | before the effect is processed | | | delegated volume control to
// | The overall volume (the volume | | | another effect.
// | actually applied by the effect | | |
// | multiplied by the returned | | |
// | value) should match the | | |
@@ -370,7 +374,7 @@ typedef struct buffer_provider_s {
// structure that defines both input and output buffer configurations and is
// passed by the EFFECT_CMD_CONFIGURE command.
typedef struct buffer_config_s {
audio_buffer_t buffer; // buffer for use by process() function is not passed explicitly
audio_buffer_t buffer; // buffer for use by process() function if not passed explicitly
uint32_t samplingRate; // sampling rate
uint32_t channels; // channel mask (see audio_channels_e in AudioCommon.h)
buffer_provider_t bufferProvider; // buffer provider
@@ -457,7 +461,7 @@ typedef struct effect_param_s {
//
// Function: EffectQueryNumberEffects
//
// Description: Returns the number of different effect exposed by the
// Description: Returns the number of different effects exposed by the
// library. Each effect must have a unique effect uuid (see
// effect_descriptor_t). This function together with EffectQueryNext()
// is used to enumerate all effects present in the library.
@@ -475,7 +479,7 @@ typedef struct effect_param_s {
// *pNumEffects: updated with number of effects in library
//
////////////////////////////////////////////////////////////////////////////////
typedef int32_t (*effect_QueryNumberEffects_t)(int32_t *pNumEffects);
typedef int32_t (*effect_QueryNumberEffects_t)(uint32_t *pNumEffects);
////////////////////////////////////////////////////////////////////////////////
//
@@ -521,7 +525,7 @@ typedef int32_t (*effect_QueryNextEffect_t)(effect_descriptor_t *pDescriptor);
// returned value: 0 successful operation.
// -ENODEV library failed to initialize
// -EINVAL invalid pEffectUuid or pInterface
// -ENOENT No effect with this uuid found
// -ENOENT no effect with this uuid found
// *pInterface: updated with the effect interface handle.
//
////////////////////////////////////////////////////////////////////////////////

View File

@@ -34,7 +34,7 @@ extern "C" {
//
// Function: EffectQueryNumberEffects
//
// Description: Returns the number of different effect in all loaded libraries.
// Description: Returns the number of different effects in all loaded libraries.
// Each effect must have a different effect uuid (see
// effect_descriptor_t). This function together with EffectQueryNext()
// is used to enumerate all effects present in all loaded libraries.
@@ -52,7 +52,7 @@ extern "C" {
// *pNumEffects: updated with number of effects in factory
//
////////////////////////////////////////////////////////////////////////////////
int EffectQueryNumberEffects(int *pNumEffects);
int EffectQueryNumberEffects(uint32_t *pNumEffects);
////////////////////////////////////////////////////////////////////////////////
//
@@ -98,7 +98,7 @@ int EffectQueryNext(effect_descriptor_t *pDescriptor);
// returned value: 0 successful operation.
// -ENODEV factory failed to initialize
// -EINVAL invalid pEffectUuid or pInterface
// -ENOENT No effect with this uuid found
// -ENOENT no effect with this uuid found
// *pInterface: updated with the effect interface.
//
////////////////////////////////////////////////////////////////////////////////
@@ -140,7 +140,7 @@ int EffectRelease(effect_interface_t interface);
//
// Output:
// returned value: 0 successful operation.
// -ENODEV Effect factory not initialized or
// -ENODEV effect factory not initialized or
// library could not be loaded or
// library does not implement required functions
// -EINVAL invalid libPath string or handle
@@ -159,7 +159,7 @@ int EffectLoadLibrary(const char *libPath, int *handle);
//
// Output:
// returned value: 0 successful operation.
// -ENODEV Effect factory not initialized
// -ENODEV effect factory not initialized
// -ENOENT invalid handle
//
////////////////////////////////////////////////////////////////////////////////
@@ -184,7 +184,7 @@ int EffectUnloadLibrary(int handle);
// returned value: 0 successful operation.
// -ENODEV factory failed to initialize
// -EINVAL invalid pEffectUuid or pDescriptor
// -ENOENT No effect with this uuid found
// -ENOENT no effect with this uuid found
// *pDescriptor: updated with the effect descriptor.
//
////////////////////////////////////////////////////////////////////////////////

View File

@@ -27,6 +27,9 @@
#include <media/IAudioTrack.h>
#include <media/IAudioRecord.h>
#include <media/IAudioFlingerClient.h>
#include <media/EffectApi.h>
#include <media/IEffect.h>
#include <media/IEffectClient.h>
#include <utils/String8.h>
namespace android {
@@ -51,6 +54,7 @@ public:
uint32_t flags,
const sp<IMemory>& sharedBuffer,
int output,
int *sessionId,
status_t *status) = 0;
virtual sp<IAudioRecord> openRecord(
@@ -61,6 +65,7 @@ public:
int channelCount,
int frameCount,
uint32_t flags,
int *sessionId,
status_t *status) = 0;
/* query the audio hardware state. This state never changes,
@@ -134,6 +139,28 @@ public:
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0;
virtual unsigned int getInputFramesLost(int ioHandle) = 0;
virtual int newAudioSessionId() = 0;
virtual status_t loadEffectLibrary(const char *libPath, int *handle) = 0;
virtual status_t unloadEffectLibrary(int handle) = 0;
virtual status_t queryNumberEffects(uint32_t *numEffects) = 0;
virtual status_t queryNextEffect(effect_descriptor_t *pDescriptor) = 0;
virtual status_t getEffectDescriptor(effect_uuid_t *pEffectUUID, effect_descriptor_t *pDescriptor) = 0;
virtual sp<IEffect> createEffect(pid_t pid,
effect_descriptor_t *pDesc,
const sp<IEffectClient>& client,
int32_t priority,
int output,
int sessionId,
status_t *status,
int *id,
int *enabled) = 0;
};

View File

@@ -62,6 +62,11 @@ public:
*/
virtual void pause() = 0;
/* Attach track auxiliary output to specified effect. Use effectId = 0
* to detach track from effect.
*/
virtual status_t attachAuxEffect(int effectId) = 0;
/* get this tracks control block */
virtual sp<IMemory> getCblk() const = 0;
};

View File

@@ -0,0 +1,51 @@
/*
* 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.
*/
#ifndef ANDROID_EFFECTCBASESHARED_H
#define ANDROID_EFFECTCBASESHARED_H
#include <stdint.h>
#include <sys/types.h>
#include <utils/threads.h>
namespace android {
// ----------------------------------------------------------------------------
// Size of buffer used to exchange parameters between application and mediaserver processes.
#define EFFECT_PARAM_BUFFER_SIZE 1024
// Shared memory area used to exchange parameters between application and mediaserver
// process.
struct effect_param_cblk_t
{
Mutex lock;
volatile uint32_t clientIndex; // Current read/write index for application
volatile uint32_t serverIndex; // Current read/write index for mediaserver
uint8_t* buffer; // start of parameter buffer
effect_param_cblk_t()
: lock(Mutex::SHARED), clientIndex(0), serverIndex(0) {}
};
// ----------------------------------------------------------------------------
}; // namespace android
#endif // ANDROID_EFFECTCBASESHARED_H

View File

@@ -78,7 +78,8 @@ struct audio_track_cblk_t
uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
uint16_t waitTimeMs; // Cumulated wait time
uint32_t reserved;
uint16_t sendLevel;
uint16_t reserved;
// Cache line boundary (32 bytes)
audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount);

View File

@@ -87,7 +87,8 @@ LOCAL_SHARED_LIBRARIES := \
libutils \
libbinder \
libmedia \
libhardware_legacy
libhardware_legacy \
libeffects
ifeq ($(strip $(BOARD_USES_GENERIC_AUDIO)),true)
LOCAL_STATIC_LIBRARIES += libaudiointerface libaudiopolicybase

File diff suppressed because it is too large Load Diff

View File

@@ -42,6 +42,7 @@
namespace android {
class audio_track_cblk_t;
class effect_param_cblk_t;
class AudioMixer;
class AudioBuffer;
class AudioResampler;
@@ -75,6 +76,7 @@ public:
uint32_t flags,
const sp<IMemory>& sharedBuffer,
int output,
int *sessionId,
status_t *status);
virtual uint32_t sampleRate(int output) const;
@@ -139,6 +141,28 @@ public:
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output);
virtual int newAudioSessionId();
virtual status_t loadEffectLibrary(const char *libPath, int *handle);
virtual status_t unloadEffectLibrary(int handle);
virtual status_t queryNumberEffects(uint32_t *numEffects);
virtual status_t queryNextEffect(effect_descriptor_t *descriptor);
virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *descriptor);
virtual sp<IEffect> createEffect(pid_t pid,
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
int32_t priority,
int output,
int sessionId,
status_t *status,
int *id,
int *enabled);
enum hardware_call_state {
AUDIO_HW_IDLE = 0,
AUDIO_HW_INIT,
@@ -167,6 +191,7 @@ public:
int channelCount,
int frameCount,
uint32_t flags,
int *sessionId,
status_t *status);
virtual status_t onTransact(
@@ -233,6 +258,9 @@ private:
class DuplicatingThread;
class Track;
class RecordTrack;
class EffectModule;
class EffectHandle;
class EffectChain;
class ThreadBase : public Thread {
public:
@@ -268,13 +296,15 @@ private:
int channelCount,
int frameCount,
uint32_t flags,
const sp<IMemory>& sharedBuffer);
const sp<IMemory>& sharedBuffer,
int sessionId);
~TrackBase();
virtual status_t start() = 0;
virtual void stop() = 0;
sp<IMemory> getCblk() const;
audio_track_cblk_t* cblk() const { return mCblk; }
int sessionId() { return mSessionId; }
protected:
friend class ThreadBase;
@@ -323,6 +353,7 @@ private:
int mClientTid;
uint8_t mFormat;
uint32_t mFlags;
int mSessionId;
};
class ConfigEvent {
@@ -405,7 +436,8 @@ private:
int format,
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer);
const sp<IMemory>& sharedBuffer,
int sessionId);
~Track();
void dump(char* buffer, size_t size);
@@ -424,6 +456,12 @@ private:
int type() const {
return mStreamType;
}
status_t attachAuxEffect(int EffectId);
void setAuxBuffer(int EffectId, int32_t *buffer);
int32_t *auxBuffer() { return mAuxBuffer; }
void setMainBuffer(int16_t *buffer) { mMainBuffer = buffer; }
int16_t *mainBuffer() { return mMainBuffer; }
int auxEffectId() { return mAuxEffectId; }
protected:
@@ -464,6 +502,9 @@ private:
bool mResetDone;
int mStreamType;
int mName;
int16_t *mMainBuffer;
int32_t *mAuxBuffer;
int mAuxEffectId;
}; // end of Track
@@ -505,7 +546,7 @@ private:
DuplicatingThread* mSourceThread;
}; // end of OutputTrack
PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
PlaybackThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
virtual ~PlaybackThread();
virtual status_t dump(int fd, const Vector<String16>& args);
@@ -538,6 +579,7 @@ private:
int channelCount,
int frameCount,
const sp<IMemory>& sharedBuffer,
int sessionId,
status_t *status);
AudioStreamOut* getOutput() { return mOutput; }
@@ -549,6 +591,29 @@ private:
virtual String8 getParameters(const String8& keys);
virtual void audioConfigChanged_l(int event, int param = 0);
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames);
int16_t *mixBuffer() { return mMixBuffer; };
sp<EffectHandle> createEffect_l(
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority,
int sessionId,
effect_descriptor_t *desc,
int *enabled,
status_t *status);
bool hasAudioSession(int sessionId);
sp<EffectChain> getEffectChain(int sessionId);
sp<EffectChain> getEffectChain_l(int sessionId);
status_t addEffectChain_l(const sp<EffectChain>& chain);
size_t removeEffectChain_l(const sp<EffectChain>& chain);
void lockEffectChains_l();
void unlockEffectChains();
sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
void detachAuxEffect_l(int effectId);
status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId);
struct stream_type_t {
stream_type_t()
@@ -591,8 +656,11 @@ private:
void readOutputParameters();
uint32_t device() { return mDevice; }
virtual status_t dumpInternals(int fd, const Vector<String16>& args);
status_t dumpTracks(int fd, const Vector<String16>& args);
status_t dumpEffectChains(int fd, const Vector<String16>& args);
SortedVector< sp<Track> > mTracks;
// mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
@@ -603,11 +671,13 @@ private:
int mNumWrites;
int mNumDelayedWrites;
bool mInWrite;
Vector< sp<EffectChain> > mEffectChains;
uint32_t mDevice;
};
class MixerThread : public PlaybackThread {
public:
MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
virtual ~MixerThread();
// Thread virtuals
@@ -630,7 +700,7 @@ private:
class DirectOutputThread : public PlaybackThread {
public:
DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id);
DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
~DirectOutputThread();
// Thread virtuals
@@ -645,8 +715,12 @@ private:
virtual uint32_t idleSleepTimeUs();
private:
float mLeftVolume;
float mRightVolume;
void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
float mLeftVolFloat;
float mRightVolFloat;
uint16_t mLeftVolShort;
uint16_t mRightVolShort;
};
class DuplicatingThread : public MixerThread {
@@ -676,6 +750,8 @@ private:
float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
void audioConfigChanged_l(int event, int ioHandle, void *param2);
int nextUniqueId();
friend class AudioBuffer;
class TrackHandle : public android::BnAudioTrack {
@@ -689,6 +765,7 @@ private:
virtual void pause();
virtual void setVolume(float left, float right);
virtual sp<IMemory> getCblk() const;
virtual status_t attachAuxEffect(int effectId);
virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private:
@@ -717,7 +794,8 @@ private:
int format,
int channelCount,
int frameCount,
uint32_t flags);
uint32_t flags,
int sessionId);
~RecordTrack();
virtual status_t start();
@@ -792,6 +870,215 @@ private:
sp<RecordThread::RecordTrack> mRecordTrack;
};
//--- Audio Effect Management
// EffectModule and EffectChain classes both have their own mutex to protect
// state changes or resource modifications. Always respect the following order
// if multiple mutexes must be acquired to avoid cross deadlock:
// AudioFlinger -> ThreadBase -> EffectChain -> EffectModule
// The EffectModule class is a wrapper object controlling the effect engine implementation
// in the effect library. It prevents concurrent calls to process() and command() functions
// from different client threads. It keeps a list of EffectHandle objects corresponding
// to all client applications using this effect and notifies applications of effect state,
// control or parameter changes. It manages the activation state machine to send appropriate
// reset, enable, disable commands to effect engine and provide volume
// ramping when effects are activated/deactivated.
// When controlling an auxiliary effect, the EffectModule also provides an input buffer used by
// the attached track(s) to accumulate their auxiliary channel.
class EffectModule: public RefBase {
public:
EffectModule(const wp<ThreadBase>& wThread,
const wp<AudioFlinger::EffectChain>& chain,
effect_descriptor_t *desc,
int id,
int sessionId);
~EffectModule();
enum effect_state {
IDLE,
RESET,
STARTING,
ACTIVE,
STOPPING,
STOPPED
};
int id() { return mId; }
void process();
status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
void reset();
status_t configure();
status_t init();
uint32_t state() {
return mState;
}
uint32_t status() {
return mStatus;
}
status_t setEnabled(bool enabled);
bool isEnabled();
void setInBuffer(int16_t *buffer) { mConfig.inputCfg.buffer.s16 = buffer; }
int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; }
void setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; }
int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; }
status_t addHandle(sp<EffectHandle>& handle);
void disconnect(const wp<EffectHandle>& handle);
size_t removeHandle (const wp<EffectHandle>& handle);
effect_descriptor_t& desc() { return mDescriptor; }
status_t setDevice(uint32_t device);
status_t setVolume(uint32_t *left, uint32_t *right, bool controller);
status_t dump(int fd, const Vector<String16>& args);
protected:
EffectModule(const EffectModule&);
EffectModule& operator = (const EffectModule&);
status_t start();
status_t stop();
Mutex mLock; // mutex for process, commands and handles list protection
wp<ThreadBase> mThread; // parent thread
wp<EffectChain> mChain; // parent effect chain
int mId; // this instance unique ID
int mSessionId; // audio session ID
effect_descriptor_t mDescriptor;// effect descriptor received from effect engine
effect_config_t mConfig; // input and output audio configuration
effect_interface_t mEffectInterface; // Effect module C API
status_t mStatus; // initialization status
uint32_t mState; // current activation state (effect_state)
Vector< wp<EffectHandle> > mHandles; // list of client handles
};
// The EffectHandle class implements the IEffect interface. It provides resources
// to receive parameter updates, keeps track of effect control
// ownership and state and has a pointer to the EffectModule object it is controlling.
// There is one EffectHandle object for each application controlling (or using)
// an effect module.
// The EffectHandle is obtained by calling AudioFlinger::createEffect().
class EffectHandle: public android::BnEffect {
public:
EffectHandle(const sp<EffectModule>& effect,
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority);
virtual ~EffectHandle();
// IEffect
virtual status_t enable();
virtual status_t disable();
virtual status_t command(int cmdCode, int cmdSize, void *pCmdData, int *replySize, void *pReplyData);
virtual void disconnect();
virtual sp<IMemory> getCblk() const;
virtual status_t onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags);
// Give or take control of effect module
void setControl(bool hasControl, bool signal);
void commandExecuted(int cmdCode, int cmdSize, void *pCmdData, int replySize, void *pReplyData);
void setEnabled(bool enabled);
// Getters
int id() { return mEffect->id(); }
int priority() { return mPriority; }
bool hasControl() { return mHasControl; }
sp<EffectModule> effect() { return mEffect; }
void dump(char* buffer, size_t size);
protected:
EffectHandle(const EffectHandle&);
EffectHandle& operator =(const EffectHandle&);
sp<EffectModule> mEffect; // pointer to controlled EffectModule
sp<IEffectClient> mEffectClient; // callback interface for client notifications
sp<Client> mClient; // client for shared memory allocation
sp<IMemory> mCblkMemory; // shared memory for control block
effect_param_cblk_t* mCblk; // control block for deferred parameter setting via shared memory
uint8_t* mBuffer; // pointer to parameter area in shared memory
int mPriority; // client application priority to control the effect
bool mHasControl; // true if this handle is controlling the effect
};
// the EffectChain class represents a group of effects associated to one audio session.
// There can be any number of EffectChain objects per output mixer thread (PlaybackThread).
// The EffecChain with session ID 0 contains global effects applied to the output mix.
// Effects in this chain can be insert or auxiliary. Effects in other chains (attached to tracks)
// are insert only. The EffectChain maintains an ordered list of effect module, the order corresponding
// in the effect process order. When attached to a track (session ID != 0), it also provide it's own
// input buffer used by the track as accumulation buffer.
class EffectChain: public RefBase {
public:
EffectChain(const wp<ThreadBase>& wThread, int sessionId);
~EffectChain();
void process_l();
void lock() {
mLock.lock();
}
void unlock() {
mLock.unlock();
}
status_t addEffect(sp<EffectModule>& handle);
size_t removeEffect(const sp<EffectModule>& handle);
int sessionId() {
return mSessionId;
}
sp<EffectModule> getEffectFromDesc(effect_descriptor_t *descriptor);
sp<EffectModule> getEffectFromId(int id);
sp<EffectModule> getVolumeController();
bool setVolume(uint32_t *left, uint32_t *right);
void setDevice(uint32_t device);
void setInBuffer(int16_t *buffer, bool ownsBuffer = false) {
mInBuffer = buffer;
mOwnInBuffer = ownsBuffer;
}
int16_t *inBuffer() {
return mInBuffer;
}
void setOutBuffer(int16_t *buffer) {
mOutBuffer = buffer;
}
int16_t *outBuffer() {
return mOutBuffer;
}
void startTrack() {mActiveTrackCnt++;}
void stopTrack() {mActiveTrackCnt--;}
int activeTracks() { return mActiveTrackCnt;}
status_t dump(int fd, const Vector<String16>& args);
protected:
EffectChain(const EffectChain&);
EffectChain& operator =(const EffectChain&);
wp<ThreadBase> mThread; // parent mixer thread
Mutex mLock; // mutex protecting effect list
Vector<sp<EffectModule> > mEffects; // list of effect modules
int mSessionId; // audio session ID
int16_t *mInBuffer; // chain input buffer
int16_t *mOutBuffer; // chain output buffer
int mVolumeCtrlIdx; // index of insert effect having control over volume
int mActiveTrackCnt; // number of active tracks connected
bool mOwnInBuffer; // true if the chain owns its input buffer
};
friend class RecordThread;
friend class PlaybackThread;
@@ -813,7 +1100,7 @@ private:
DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads;
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
int mNextThreadId;
volatile int32_t mNextUniqueId;
#ifdef LVMX
int mLifeVibesClientPid;
#endif

View File

@@ -56,6 +56,8 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
t->volume[1] = UNITY_GAIN;
t->volumeInc[0] = 0;
t->volumeInc[1] = 0;
t->auxLevel = 0;
t->auxInc = 0;
t->channelCount = 2;
t->enabled = 0;
t->format = 16;
@@ -65,6 +67,8 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
t->resampler = 0;
t->sampleRate = mSampleRate;
t->in = 0;
t->mainBuffer = NULL;
t->auxBuffer = NULL;
t++;
}
}
@@ -169,28 +173,48 @@ status_t AudioMixer::setActiveTrack(int track)
return NO_ERROR;
}
status_t AudioMixer::setParameter(int target, int name, int value)
status_t AudioMixer::setParameter(int target, int name, void *value)
{
int valueInt = (int)value;
int32_t *valueBuf = (int32_t *)value;
switch (target) {
case TRACK:
if (name == CHANNEL_COUNT) {
if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) {
if (mState.tracks[ mActiveTrack ].channelCount != value) {
mState.tracks[ mActiveTrack ].channelCount = value;
LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value);
if ((uint32_t(valueInt) <= MAX_NUM_CHANNELS) && (valueInt)) {
if (mState.tracks[ mActiveTrack ].channelCount != valueInt) {
mState.tracks[ mActiveTrack ].channelCount = valueInt;
LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", valueInt);
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
}
}
if (name == MAIN_BUFFER) {
if (mState.tracks[ mActiveTrack ].mainBuffer != valueBuf) {
mState.tracks[ mActiveTrack ].mainBuffer = valueBuf;
LOGV("setParameter(TRACK, MAIN_BUFFER, %p)", valueBuf);
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
}
if (name == AUX_BUFFER) {
if (mState.tracks[ mActiveTrack ].auxBuffer != valueBuf) {
mState.tracks[ mActiveTrack ].auxBuffer = valueBuf;
LOGV("setParameter(TRACK, AUX_BUFFER, %p)", valueBuf);
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
}
break;
case RESAMPLE:
if (name == SAMPLE_RATE) {
if (value > 0) {
if (valueInt > 0) {
track_t& track = mState.tracks[ mActiveTrack ];
if (track.setResampler(uint32_t(value), mSampleRate)) {
if (track.setResampler(uint32_t(valueInt), mSampleRate)) {
LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
uint32_t(value));
uint32_t(valueInt));
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
@@ -201,18 +225,39 @@ status_t AudioMixer::setParameter(int target, int name, int value)
case VOLUME:
if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
track_t& track = mState.tracks[ mActiveTrack ];
if (track.volume[name-VOLUME0] != value) {
if (track.volume[name-VOLUME0] != valueInt) {
LOGV("setParameter(VOLUME, VOLUME0/1: %04x)", valueInt);
track.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
track.volume[name-VOLUME0] = value;
track.volume[name-VOLUME0] = valueInt;
if (target == VOLUME) {
track.prevVolume[name-VOLUME0] = value << 16;
track.prevVolume[name-VOLUME0] = valueInt << 16;
track.volumeInc[name-VOLUME0] = 0;
} else {
int32_t d = (value<<16) - track.prevVolume[name-VOLUME0];
int32_t d = (valueInt<<16) - track.prevVolume[name-VOLUME0];
int32_t volInc = d / int32_t(mState.frameCount);
track.volumeInc[name-VOLUME0] = volInc;
if (volInc == 0) {
track.prevVolume[name-VOLUME0] = value << 16;
track.prevVolume[name-VOLUME0] = valueInt << 16;
}
}
invalidateState(1<<mActiveTrack);
}
return NO_ERROR;
} else if (name == AUXLEVEL) {
track_t& track = mState.tracks[ mActiveTrack ];
if (track.auxLevel != valueInt) {
LOGV("setParameter(VOLUME, AUXLEVEL: %04x)", valueInt);
track.prevAuxLevel = track.auxLevel << 16;
track.auxLevel = valueInt;
if (target == VOLUME) {
track.prevAuxLevel = valueInt << 16;
track.auxInc = 0;
} else {
int32_t d = (valueInt<<16) - track.prevAuxLevel;
int32_t volInc = d / int32_t(mState.frameCount);
track.auxInc = volInc;
if (volInc == 0) {
track.prevAuxLevel = valueInt << 16;
}
}
invalidateState(1<<mActiveTrack);
@@ -245,7 +290,7 @@ bool AudioMixer::track_t::doesResample() const
}
inline
void AudioMixer::track_t::adjustVolumeRamp()
void AudioMixer::track_t::adjustVolumeRamp(bool aux)
{
for (int i=0 ; i<2 ; i++) {
if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[i])) ||
@@ -254,6 +299,13 @@ void AudioMixer::track_t::adjustVolumeRamp()
prevVolume[i] = volume[i]<<16;
}
}
if (aux) {
if (((auxInc>0) && (((prevAuxLevel+auxInc)>>16) >= auxLevel)) ||
((auxInc<0) && (((prevAuxLevel+auxInc)>>16) <= auxLevel))) {
auxInc = 0;
prevAuxLevel = auxLevel<<16;
}
}
}
@@ -265,13 +317,13 @@ status_t AudioMixer::setBufferProvider(AudioBufferProvider* buffer)
void AudioMixer::process(void* output)
void AudioMixer::process()
{
mState.hook(&mState, output);
mState.hook(&mState);
}
void AudioMixer::process__validate(state_t* state, void* output)
void AudioMixer::process__validate(state_t* state)
{
LOGW_IF(!state->needsChanged,
"in process__validate() but nothing's invalid");
@@ -308,7 +360,10 @@ void AudioMixer::process__validate(state_t* state, void* output)
n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
n |= NEEDS_FORMAT_16;
n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED;
if (t.auxLevel != 0 && t.auxBuffer != NULL) {
n |= NEEDS_AUX_ENABLED;
}
if (t.volumeInc[0]|t.volumeInc[1]) {
volumeRamp = 1;
} else if (!t.doesResample() && t.volumeRL == 0) {
@@ -319,6 +374,9 @@ void AudioMixer::process__validate(state_t* state, void* output)
if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
t.hook = track__nop;
} else {
if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
all16BitsStereoNoResample = 0;
}
if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
all16BitsStereoNoResample = 0;
resampling = 1;
@@ -369,7 +427,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
countActiveTracks, state->enabledTracks,
all16BitsStereoNoResample, resampling, volumeRamp);
state->hook(state, output);
state->hook(state);
// Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process
@@ -390,7 +448,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
}
if (allMuted) {
state->hook = process__nop;
} else if (!resampling && all16BitsStereoNoResample) {
} else if (all16BitsStereoNoResample) {
if (countActiveTracks == 1) {
state->hook = process__OneTrack16BitsStereoNoResampling;
}
@@ -481,30 +539,44 @@ int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
}
void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
{
t->resampler->setSampleRate(t->sampleRate);
// ramp gain - resample to temp buffer and scale/mix in 2nd step
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
if (aux != NULL) {
// always resample with unity gain when sending to auxiliary buffer to be able
// to apply send level after resampling
// TODO: modify each resampler to support aux channel?
t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
t->resampler->resample(temp, outFrameCount, t->bufferProvider);
volumeRampStereo(t, out, outFrameCount, temp);
}
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
volumeRampStereo(t, out, outFrameCount, temp, aux);
} else {
volumeStereo(t, out, outFrameCount, temp, aux);
}
} else {
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
t->resampler->resample(temp, outFrameCount, t->bufferProvider);
volumeRampStereo(t, out, outFrameCount, temp, aux);
}
// constant gain
else {
t->resampler->setVolume(t->volume[0], t->volume[1]);
t->resampler->resample(out, outFrameCount, t->bufferProvider);
// constant gain
else {
t->resampler->setVolume(t->volume[0], t->volume[1]);
t->resampler->resample(out, outFrameCount, t->bufferProvider);
}
}
}
void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
void AudioMixer::track__nop(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
{
}
void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
{
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
@@ -514,98 +586,238 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i
//LOGD("[0] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
// ramp volume
do {
*out++ += (vl >> 16) * (*temp++ >> 12);
*out++ += (vr >> 16) * (*temp++ >> 12);
vl += vlInc;
vr += vrInc;
} while (--frameCount);
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp();
}
void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
{
int16_t const *in = static_cast<int16_t const *>(t->in);
// ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
const int32_t vlInc = t->volumeInc[0];
const int32_t vrInc = t->volumeInc[1];
// LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
if UNLIKELY(aux != NULL) {
int32_t va = t->prevAuxLevel;
const int32_t vaInc = t->auxInc;
int32_t l;
int32_t r;
do {
*out++ += (vl >> 16) * (int32_t) *in++;
*out++ += (vr >> 16) * (int32_t) *in++;
l = (*temp++ >> 12);
r = (*temp++ >> 12);
*out++ += (vl >> 16) * l;
*out++ += (vr >> 16) * r;
*aux++ += (va >> 17) * (l + r);
vl += vlInc;
vr += vrInc;
va += vaInc;
} while (--frameCount);
t->prevAuxLevel = va;
} else {
do {
*out++ += (vl >> 16) * (*temp++ >> 12);
*out++ += (vr >> 16) * (*temp++ >> 12);
vl += vlInc;
vr += vrInc;
} while (--frameCount);
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp();
}
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp((aux != NULL));
}
// constant gain
else {
const uint32_t vrl = t->volumeRL;
void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
{
const int16_t vl = t->volume[0];
const int16_t vr = t->volume[1];
if UNLIKELY(aux != NULL) {
const int16_t va = (int16_t)t->auxLevel;
do {
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
in += 2;
out[0] = mulAddRL(1, rl, vrl, out[0]);
out[1] = mulAddRL(0, rl, vrl, out[1]);
int16_t l = (int16_t)(*temp++ >> 12);
int16_t r = (int16_t)(*temp++ >> 12);
out[0] = mulAdd(l, vl, out[0]);
int16_t a = (int16_t)(((int32_t)l + r) >> 1);
out[1] = mulAdd(r, vr, out[1]);
out += 2;
aux[0] = mulAdd(a, va, aux[0]);
aux++;
} while (--frameCount);
} else {
do {
int16_t l = (int16_t)(*temp++ >> 12);
int16_t r = (int16_t)(*temp++ >> 12);
out[0] = mulAdd(l, vl, out[0]);
out[1] = mulAdd(r, vr, out[1]);
out += 2;
} while (--frameCount);
}
}
void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
{
int16_t const *in = static_cast<int16_t const *>(t->in);
if UNLIKELY(aux != NULL) {
int32_t l;
int32_t r;
// ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
int32_t va = t->prevAuxLevel;
const int32_t vlInc = t->volumeInc[0];
const int32_t vrInc = t->volumeInc[1];
const int32_t vaInc = t->auxInc;
// LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
do {
l = (int32_t)*in++;
r = (int32_t)*in++;
*out++ += (vl >> 16) * l;
*out++ += (vr >> 16) * r;
*aux++ += (va >> 17) * (l + r);
vl += vlInc;
vr += vrInc;
va += vaInc;
} while (--frameCount);
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->prevAuxLevel = va;
t->adjustVolumeRamp(true);
}
// constant gain
else {
const uint32_t vrl = t->volumeRL;
const int16_t va = (int16_t)t->auxLevel;
do {
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
in += 2;
out[0] = mulAddRL(1, rl, vrl, out[0]);
out[1] = mulAddRL(0, rl, vrl, out[1]);
out += 2;
aux[0] = mulAdd(a, va, aux[0]);
aux++;
} while (--frameCount);
}
} else {
// ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
const int32_t vlInc = t->volumeInc[0];
const int32_t vrInc = t->volumeInc[1];
// LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
do {
*out++ += (vl >> 16) * (int32_t) *in++;
*out++ += (vr >> 16) * (int32_t) *in++;
vl += vlInc;
vr += vrInc;
} while (--frameCount);
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp(false);
}
// constant gain
else {
const uint32_t vrl = t->volumeRL;
do {
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
in += 2;
out[0] = mulAddRL(1, rl, vrl, out[0]);
out[1] = mulAddRL(0, rl, vrl, out[1]);
out += 2;
} while (--frameCount);
}
}
t->in = in;
}
void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
{
int16_t const *in = static_cast<int16_t const *>(t->in);
// ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
const int32_t vlInc = t->volumeInc[0];
const int32_t vrInc = t->volumeInc[1];
if UNLIKELY(aux != NULL) {
// ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
int32_t va = t->prevAuxLevel;
const int32_t vlInc = t->volumeInc[0];
const int32_t vrInc = t->volumeInc[1];
const int32_t vaInc = t->auxInc;
// LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
// LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
do {
int32_t l = *in++;
*out++ += (vl >> 16) * l;
*out++ += (vr >> 16) * l;
vl += vlInc;
vr += vrInc;
} while (--frameCount);
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp();
}
// constant gain
else {
const int16_t vl = t->volume[0];
const int16_t vr = t->volume[1];
do {
int16_t l = *in++;
out[0] = mulAdd(l, vl, out[0]);
out[1] = mulAdd(l, vr, out[1]);
out += 2;
} while (--frameCount);
do {
int32_t l = *in++;
*out++ += (vl >> 16) * l;
*out++ += (vr >> 16) * l;
*aux++ += (va >> 16) * l;
vl += vlInc;
vr += vrInc;
va += vaInc;
} while (--frameCount);
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->prevAuxLevel = va;
t->adjustVolumeRamp(true);
}
// constant gain
else {
const int16_t vl = t->volume[0];
const int16_t vr = t->volume[1];
const int16_t va = (int16_t)t->auxLevel;
do {
int16_t l = *in++;
out[0] = mulAdd(l, vl, out[0]);
out[1] = mulAdd(l, vr, out[1]);
out += 2;
aux[0] = mulAdd(l, va, aux[0]);
aux++;
} while (--frameCount);
}
} else {
// ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1];
const int32_t vlInc = t->volumeInc[0];
const int32_t vrInc = t->volumeInc[1];
// LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
// (vl + vlInc*frameCount)/65536.0f, frameCount);
do {
int32_t l = *in++;
*out++ += (vl >> 16) * l;
*out++ += (vr >> 16) * l;
vl += vlInc;
vr += vrInc;
} while (--frameCount);
t->prevVolume[0] = vl;
t->prevVolume[1] = vr;
t->adjustVolumeRamp(false);
}
// constant gain
else {
const int16_t vl = t->volume[0];
const int16_t vr = t->volume[1];
do {
int16_t l = *in++;
out[0] = mulAdd(l, vl, out[0]);
out[1] = mulAdd(l, vr, out[1]);
out += 2;
} while (--frameCount);
}
}
t->in = in;
}
@@ -624,37 +836,56 @@ void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
}
// no-op case
void AudioMixer::process__nop(state_t* state, void* output)
void AudioMixer::process__nop(state_t* state)
{
// this assumes output 16 bits stereo, no resampling
memset(output, 0, state->frameCount*4);
uint32_t en = state->enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
track_t& t = state->tracks[i];
size_t outFrames = state->frameCount;
while (outFrames) {
t.buffer.frameCount = outFrames;
t.bufferProvider->getNextBuffer(&t.buffer);
if (!t.buffer.raw) break;
outFrames -= t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
uint32_t e0 = state->enabledTracks;
size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
while (e0) {
// process by group of tracks with same output buffer to
// avoid multiple memset() on same buffer
uint32_t e1 = e0, e2 = e0;
int i = 31 - __builtin_clz(e1);
track_t& t1 = state->tracks[i];
e2 &= ~(1<<i);
while (e2) {
i = 31 - __builtin_clz(e2);
e2 &= ~(1<<i);
track_t& t2 = state->tracks[i];
if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
e1 &= ~(1<<i);
}
}
e0 &= ~(e1);
memset(t1.mainBuffer, 0, bufSize);
while (e1) {
i = 31 - __builtin_clz(e1);
e1 &= ~(1<<i);
t1 = state->tracks[i];
size_t outFrames = state->frameCount;
while (outFrames) {
t1.buffer.frameCount = outFrames;
t1.bufferProvider->getNextBuffer(&t1.buffer);
if (!t1.buffer.raw) break;
outFrames -= t1.buffer.frameCount;
t1.bufferProvider->releaseBuffer(&t1.buffer);
}
}
}
}
// generic code without resampling
void AudioMixer::process__genericNoResampling(state_t* state, void* output)
void AudioMixer::process__genericNoResampling(state_t* state)
{
int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
// acquire each track's buffer
uint32_t enabledTracks = state->enabledTracks;
uint32_t en = enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
uint32_t e0 = enabledTracks;
while (e0) {
const int i = 31 - __builtin_clz(e0);
e0 &= ~(1<<i);
track_t& t = state->tracks[i];
t.buffer.frameCount = state->frameCount;
t.bufferProvider->getNextBuffer(&t.buffer);
@@ -666,110 +897,156 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
enabledTracks &= ~(1<<i);
}
// this assumes output 16 bits stereo, no resampling
int32_t* out = static_cast<int32_t*>(output);
size_t numFrames = state->frameCount;
do {
memset(outTemp, 0, sizeof(outTemp));
en = enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
track_t& t = state->tracks[i];
size_t outFrames = BLOCKSIZE;
while (outFrames) {
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
if (inFrames) {
(t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
t.frameCount -= inFrames;
outFrames -= inFrames;
}
if (t.frameCount == 0 && outFrames) {
t.bufferProvider->releaseBuffer(&t.buffer);
t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw;
if (t.in == NULL) {
enabledTracks &= ~(1<<i);
break;
}
t.frameCount = t.buffer.frameCount;
}
e0 = enabledTracks;
while (e0) {
// process by group of tracks with same output buffer to
// optimize cache use
uint32_t e1 = e0, e2 = e0;
int j = 31 - __builtin_clz(e1);
track_t& t1 = state->tracks[j];
e2 &= ~(1<<j);
while (e2) {
j = 31 - __builtin_clz(e2);
e2 &= ~(1<<j);
track_t& t2 = state->tracks[j];
if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
e1 &= ~(1<<j);
}
}
ditherAndClamp(out, outTemp, BLOCKSIZE);
out += BLOCKSIZE;
numFrames -= BLOCKSIZE;
} while (numFrames);
e0 &= ~(e1);
// this assumes output 16 bits stereo, no resampling
int32_t *out = t1.mainBuffer;
size_t numFrames = 0;
do {
memset(outTemp, 0, sizeof(outTemp));
e2 = e1;
while (e2) {
const int i = 31 - __builtin_clz(e2);
e2 &= ~(1<<i);
track_t& t = state->tracks[i];
size_t outFrames = BLOCKSIZE;
int32_t *aux = NULL;
if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
aux = t.auxBuffer + numFrames;
}
while (outFrames) {
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
if (inFrames) {
(t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
t.frameCount -= inFrames;
outFrames -= inFrames;
if UNLIKELY(aux != NULL) {
aux += inFrames;
}
}
if (t.frameCount == 0 && outFrames) {
t.bufferProvider->releaseBuffer(&t.buffer);
t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw;
if (t.in == NULL) {
enabledTracks &= ~(1<<i);
e1 &= ~(1<<i);
break;
}
t.frameCount = t.buffer.frameCount;
}
}
}
ditherAndClamp(out, outTemp, BLOCKSIZE);
out += BLOCKSIZE;
numFrames += BLOCKSIZE;
} while (numFrames < state->frameCount);
}
// release each track's buffer
en = enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
e0 = enabledTracks;
while (e0) {
const int i = 31 - __builtin_clz(e0);
e0 &= ~(1<<i);
track_t& t = state->tracks[i];
t.bufferProvider->releaseBuffer(&t.buffer);
}
}
// generic code with resampling
void AudioMixer::process__genericResampling(state_t* state, void* output)
// generic code with resampling
void AudioMixer::process__genericResampling(state_t* state)
{
int32_t* const outTemp = state->outputTemp;
const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
memset(outTemp, 0, size);
int32_t* out = static_cast<int32_t*>(output);
size_t numFrames = state->frameCount;
uint32_t en = state->enabledTracks;
while (en) {
const int i = 31 - __builtin_clz(en);
en &= ~(1<<i);
track_t& t = state->tracks[i];
// this is a little goofy, on the resampling case we don't
// acquire/release the buffers because it's done by
// the resampler.
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
(t.hook)(&t, outTemp, numFrames, state->resampleTemp);
} else {
size_t outFrames = numFrames;
while (outFrames) {
t.buffer.frameCount = outFrames;
t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having
// been enabled for mixing.
if (t.in == NULL) break;
(t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
outFrames -= t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
uint32_t e0 = state->enabledTracks;
while (e0) {
// process by group of tracks with same output buffer
// to optimize cache use
uint32_t e1 = e0, e2 = e0;
int j = 31 - __builtin_clz(e1);
track_t& t1 = state->tracks[j];
e2 &= ~(1<<j);
while (e2) {
j = 31 - __builtin_clz(e2);
e2 &= ~(1<<j);
track_t& t2 = state->tracks[j];
if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
e1 &= ~(1<<j);
}
}
}
e0 &= ~(e1);
int32_t *out = t1.mainBuffer;
while (e1) {
const int i = 31 - __builtin_clz(e1);
e1 &= ~(1<<i);
track_t& t = state->tracks[i];
int32_t *aux = NULL;
if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
aux = t.auxBuffer;
}
ditherAndClamp(out, outTemp, numFrames);
// this is a little goofy, on the resampling case we don't
// acquire/release the buffers because it's done by
// the resampler.
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
(t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
} else {
size_t outFrames = 0;
while (outFrames < numFrames) {
t.buffer.frameCount = numFrames - outFrames;
t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having
// been enabled for mixing.
if (t.in == NULL) break;
if UNLIKELY(aux != NULL) {
aux += outFrames;
}
(t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
outFrames += t.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer);
}
}
}
ditherAndClamp(out, outTemp, numFrames);
}
}
// one track, 16 bits stereo without resampling is the most common case
void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void* output)
void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state)
{
const int i = 31 - __builtin_clz(state->enabledTracks);
const track_t& t = state->tracks[i];
AudioBufferProvider::Buffer& b(t.buffer);
int32_t* out = static_cast<int32_t*>(output);
int32_t* out = t.mainBuffer;
size_t numFrames = state->frameCount;
const int16_t vl = t.volume[0];
const int16_t vr = t.volume[1];
const uint32_t vrl = t.volumeRL;
@@ -787,7 +1064,7 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void*
return;
}
size_t outFrames = b.frameCount;
if (UNLIKELY(uint32_t(vl) > UNITY_GAIN || uint32_t(vr) > UNITY_GAIN)) {
// volume is boosted, so we might need to clamp even though
// we process only one track.
@@ -816,7 +1093,9 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void*
}
// 2 tracks is also a common case
void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output)
// NEVER used in current implementation of process__validate()
// only use if the 2 tracks have the same output buffer
void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state)
{
int i;
uint32_t en = state->enabledTracks;
@@ -829,24 +1108,25 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void
i = 31 - __builtin_clz(en);
const track_t& t1 = state->tracks[i];
AudioBufferProvider::Buffer& b1(t1.buffer);
int16_t const *in0;
const int16_t vl0 = t0.volume[0];
const int16_t vr0 = t0.volume[1];
size_t frameCount0 = 0;
int16_t const *in1;
const int16_t vl1 = t1.volume[0];
const int16_t vr1 = t1.volume[1];
size_t frameCount1 = 0;
int32_t* out = static_cast<int32_t*>(output);
//FIXME: only works if two tracks use same buffer
int32_t* out = t0.mainBuffer;
size_t numFrames = state->frameCount;
int16_t const *buff = NULL;
while (numFrames) {
if (frameCount0 == 0) {
b0.frameCount = numFrames;
t0.bufferProvider->getNextBuffer(&b0);
@@ -875,13 +1155,13 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void
}
frameCount1 = b1.frameCount;
}
size_t outFrames = frameCount0 < frameCount1?frameCount0:frameCount1;
numFrames -= outFrames;
frameCount0 -= outFrames;
frameCount1 -= outFrames;
do {
int32_t l0 = *in0++;
int32_t r0 = *in0++;
@@ -896,17 +1176,17 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void
r = clamp16(r);
*out++ = (r<<16) | (l & 0xFFFF);
} while (--outFrames);
if (frameCount0 == 0) {
t0.bufferProvider->releaseBuffer(&b0);
}
if (frameCount1 == 0) {
t1.bufferProvider->releaseBuffer(&b1);
}
}
}
if (buff != NULL) {
delete [] buff;
delete [] buff;
}
}

View File

@@ -63,11 +63,14 @@ public:
// for target TRACK
CHANNEL_COUNT = 0x4000,
FORMAT = 0x4001,
MAIN_BUFFER = 0x4002,
AUX_BUFFER = 0x4003,
// for TARGET RESAMPLE
SAMPLE_RATE = 0x4100,
// for TARGET VOLUME (8 channels max)
VOLUME0 = 0x4200,
VOLUME1 = 0x4201,
AUXLEVEL = 0x4210,
};
@@ -78,10 +81,10 @@ public:
status_t disable(int name);
status_t setActiveTrack(int track);
status_t setParameter(int target, int name, int value);
status_t setParameter(int target, int name, void *value);
status_t setBufferProvider(AudioBufferProvider* bufferProvider);
void process(void* output);
void process();
uint32_t trackNames() const { return mTrackNames; }
@@ -94,6 +97,7 @@ private:
NEEDS_FORMAT__MASK = 0x000000F0,
NEEDS_MUTE__MASK = 0x00000100,
NEEDS_RESAMPLE__MASK = 0x00001000,
NEEDS_AUX__MASK = 0x00010000,
};
enum {
@@ -107,6 +111,9 @@ private:
NEEDS_RESAMPLE_DISABLED = 0x00000000,
NEEDS_RESAMPLE_ENABLED = 0x00001000,
NEEDS_AUX_DISABLED = 0x00000000,
NEEDS_AUX_ENABLED = 0x00010000,
};
static inline int32_t applyVolume(int32_t in, int32_t v) {
@@ -115,9 +122,10 @@ private:
struct state_t;
struct track_t;
typedef void (*mix_t)(state_t* state, void* output);
typedef void (*mix_t)(state_t* state);
typedef void (*hook_t)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp, int32_t* aux);
static const int BLOCKSIZE = 16; // 4 cache lines
struct track_t {
@@ -131,6 +139,9 @@ private:
int32_t prevVolume[2];
int32_t volumeInc[2];
int32_t auxLevel;
int32_t auxInc;
int32_t prevAuxLevel;
uint16_t frameCount;
@@ -142,15 +153,17 @@ private:
AudioBufferProvider* bufferProvider;
mutable AudioBufferProvider::Buffer buffer;
void (*hook)(track_t* t, int32_t* output, size_t numOutFrames, int32_t* temp);
hook_t hook;
void const* in; // current location in buffer
AudioResampler* resampler;
uint32_t sampleRate;
int32_t* mainBuffer;
int32_t* auxBuffer;
bool setResampler(uint32_t sampleRate, uint32_t devSampleRate);
bool doesResample() const;
void adjustVolumeRamp();
void adjustVolumeRamp(bool aux);
};
// pad to 32-bytes to fill cache line
@@ -173,18 +186,19 @@ private:
void invalidateState(uint32_t mask);
static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp);
static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp);
static void track__genericResample(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
static void track__nop(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
static void track__16BitsStereo(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
static void track__16BitsMono(track_t* t, int32_t* out, size_t numFrames, int32_t* temp, int32_t* aux);
static void volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
static void volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux);
static void process__validate(state_t* state, void* output);
static void process__nop(state_t* state, void* output);
static void process__genericNoResampling(state_t* state, void* output);
static void process__genericResampling(state_t* state, void* output);
static void process__OneTrack16BitsStereoNoResampling(state_t* state, void* output);
static void process__TwoTracks16BitsStereoNoResampling(state_t* state, void* output);
static void process__validate(state_t* state);
static void process__nop(state_t* state);
static void process__genericNoResampling(state_t* state);
static void process__genericResampling(state_t* state);
static void process__OneTrack16BitsStereoNoResampling(state_t* state);
static void process__TwoTracks16BitsStereoNoResampling(state_t* state);
};
// ----------------------------------------------------------------------------

View File

@@ -114,7 +114,7 @@ int Equalizer_setParameter(AudioEqualizer * pEqualizer, int32_t *pParam, void *p
//--- Effect Library Interface Implementation
//
extern "C" int EffectQueryNumberEffects(int *pNumEffects) {
extern "C" int EffectQueryNumberEffects(uint32_t *pNumEffects) {
*pNumEffects = 1;
gEffectIndex = 0;
return 0;

View File

@@ -18,7 +18,8 @@
//
#define LOG_NDEBUG 0
#include <cutils/log.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "EffectReverb.h"
#include "EffectsMath.h"
@@ -86,7 +87,7 @@ static const effect_descriptor_t * const gDescriptors[] = {
/*--- Effect Library Interface Implementation ---*/
int EffectQueryNumberEffects(int *pNumEffects) {
int EffectQueryNumberEffects(uint32_t *pNumEffects) {
*pNumEffects = sizeof(gDescriptors) / sizeof(const effect_descriptor_t *)
- 1;
gEffectIndex = 0;

View File

@@ -292,7 +292,7 @@ typedef struct reverb_module_s {
* Effect API
*------------------------------------
*/
int EffectQueryNumberEffects(int *pNumEffects);
int EffectQueryNumberEffects(uint32_t *pNumEffects);
int EffectQueryNext(effect_descriptor_t *pDescriptor);
int EffectCreate(effect_uuid_t *effectUID, effect_interface_t *pInterface);
int EffectRelease(effect_interface_t interface);

View File

@@ -39,7 +39,7 @@ static int gInitDone; // true is global initialization has been preformed
static int init();
static int loadLibrary(const char *libPath, int *handle);
static int unloadLibrary(int handle);
static int numEffectModules();
static uint32_t numEffectModules();
static int findEffect(effect_uuid_t *uuid, lib_entry_t **lib, effect_descriptor_t **desc);
static void dumpEffectDescriptor(effect_descriptor_t *desc, char *str, size_t len);
@@ -96,7 +96,7 @@ const struct effect_interface_s gInterface = {
// Effect Factory Interface functions
/////////////////////////////////////////////////
int EffectQueryNumberEffects(int *pNumEffects)
int EffectQueryNumberEffects(uint32_t *pNumEffects)
{
int ret = init();
if (ret < 0) {
@@ -353,8 +353,8 @@ int loadLibrary(const char *libPath, int *handle)
effect_QueryNextEffect_t queryFx;
effect_CreateEffect_t createFx;
effect_ReleaseEffect_t releaseFx;
int numFx;
int fx;
uint32_t numFx;
uint32_t fx;
int ret;
list_elem_t *e, *descHead = NULL;
lib_entry_t *l;
@@ -525,9 +525,9 @@ int unloadLibrary(int handle)
int numEffectModules() {
uint32_t numEffectModules() {
list_elem_t *e = gLibraryList;
int cnt = 0;
uint32_t cnt = 0;
// Reset pointers for EffectQueryNext()
gCurLib = e;

View File

@@ -45,7 +45,7 @@ namespace android {
// ---------------------------------------------------------------------------
AudioRecord::AudioRecord()
: mStatus(NO_INIT)
: mStatus(NO_INIT), mSessionId(0)
{
}
@@ -58,11 +58,12 @@ AudioRecord::AudioRecord(
uint32_t flags,
callback_t cbf,
void* user,
int notificationFrames)
: mStatus(NO_INIT)
int notificationFrames,
int sessionId)
: mStatus(NO_INIT), mSessionId(0)
{
mStatus = set(inputSource, sampleRate, format, channels,
frameCount, flags, cbf, user, notificationFrames);
frameCount, flags, cbf, user, notificationFrames, sessionId);
}
AudioRecord::~AudioRecord()
@@ -91,7 +92,8 @@ status_t AudioRecord::set(
callback_t cbf,
void* user,
int notificationFrames,
bool threadCanCallJava)
bool threadCanCallJava,
int sessionId)
{
LOGV("set(): sampleRate %d, channels %d, frameCount %d",sampleRate, channels, frameCount);
@@ -119,6 +121,7 @@ status_t AudioRecord::set(
if (!AudioSystem::isInputChannel(channels)) {
return BAD_VALUE;
}
int channelCount = AudioSystem::popCount(channels);
audio_io_handle_t input = AudioSystem::getInput(inputSource,
@@ -164,6 +167,8 @@ status_t AudioRecord::set(
notificationFrames = frameCount/2;
}
mSessionId = sessionId;
// create the IAudioRecord
status_t status = openRecord(sampleRate, format, channelCount,
frameCount, flags, input);
@@ -414,6 +419,7 @@ status_t AudioRecord::openRecord(
channelCount,
frameCount,
((uint16_t)flags) << 16,
&mSessionId,
&status);
if (record == 0) {
LOGE("AudioFlinger could not create record track, status: %d", status);
@@ -532,6 +538,11 @@ audio_io_handle_t AudioRecord::getInput()
return mInput;
}
int AudioRecord::getSessionId()
{
return mSessionId;
}
// -------------------------------------------------------------------------
ssize_t AudioRecord::read(void* buffer, size_t userSize)

View File

@@ -364,6 +364,12 @@ unsigned int AudioSystem::getInputFramesLost(audio_io_handle_t ioHandle) {
return result;
}
int AudioSystem::newAudioSessionId() {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return 0;
return af->newAudioSessionId();
}
// ---------------------------------------------------------------------------
void AudioSystem::AudioFlingerClient::binderDied(const wp<IBinder>& who) {

View File

@@ -58,7 +58,8 @@ AudioTrack::AudioTrack(
uint32_t flags,
callback_t cbf,
void* user,
int notificationFrames)
int notificationFrames,
int sessionId)
: mStatus(NO_INIT)
{
mStatus = set(streamType, sampleRate, format, channels,
@@ -74,7 +75,8 @@ AudioTrack::AudioTrack(
uint32_t flags,
callback_t cbf,
void* user,
int notificationFrames)
int notificationFrames,
int sessionId)
: mStatus(NO_INIT)
{
mStatus = set(streamType, sampleRate, format, channels,
@@ -110,7 +112,8 @@ status_t AudioTrack::set(
void* user,
int notificationFrames,
const sp<IMemory>& sharedBuffer,
bool threadCanCallJava)
bool threadCanCallJava,
int sessionId)
{
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size());
@@ -171,8 +174,11 @@ status_t AudioTrack::set(
mVolume[LEFT] = 1.0f;
mVolume[RIGHT] = 1.0f;
mSendLevel = 0;
mFrameCount = frameCount;
mNotificationFramesReq = notificationFrames;
mSessionId = sessionId;
// create the IAudioTrack
status_t status = createTrack(streamType, sampleRate, format, channelCount,
frameCount, flags, sharedBuffer, output, true);
@@ -396,19 +402,49 @@ bool AudioTrack::muted() const
return mMuted;
}
void AudioTrack::setVolume(float left, float right)
status_t AudioTrack::setVolume(float left, float right)
{
if (left > 1.0f || right > 1.0f) {
return BAD_VALUE;
}
mVolume[LEFT] = left;
mVolume[RIGHT] = right;
// write must be atomic
mCblk->volumeLR = (int32_t(int16_t(left * 0x1000)) << 16) | int16_t(right * 0x1000);
mCblk->volumeLR = (uint32_t(uint16_t(right * 0x1000)) << 16) | uint16_t(left * 0x1000);
return NO_ERROR;
}
void AudioTrack::getVolume(float* left, float* right)
{
*left = mVolume[LEFT];
*right = mVolume[RIGHT];
if (left != NULL) {
*left = mVolume[LEFT];
}
if (right != NULL) {
*right = mVolume[RIGHT];
}
}
status_t AudioTrack::setSendLevel(float level)
{
if (level > 1.0f) {
return BAD_VALUE;
}
mSendLevel = level;
mCblk->sendLevel = uint16_t(level * 0x1000);
return NO_ERROR;
}
void AudioTrack::getSendLevel(float* level)
{
if (level != NULL) {
*level = mSendLevel;
}
}
status_t AudioTrack::setSampleRate(int rate)
@@ -563,6 +599,16 @@ audio_io_handle_t AudioTrack::getOutput()
mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags);
}
int AudioTrack::getSessionId()
{
return mSessionId;
}
status_t AudioTrack::attachAuxEffect(int effectId)
{
return mAudioTrack->attachAuxEffect(effectId);
}
// -------------------------------------------------------------------------
status_t AudioTrack::createTrack(
@@ -647,6 +693,7 @@ status_t AudioTrack::createTrack(
((uint16_t)flags) << 16,
sharedBuffer,
output,
&mSessionId,
&status);
if (track == 0) {
@@ -672,7 +719,8 @@ status_t AudioTrack::createTrack(
mCblk->stepUser(mCblk->frameCount);
}
mCblk->volumeLR = (int32_t(int16_t(mVolume[LEFT] * 0x1000)) << 16) | int16_t(mVolume[RIGHT] * 0x1000);
mCblk->volumeLR = (uint32_t(uint16_t(mVolume[RIGHT] * 0x1000)) << 16) | uint16_t(mVolume[LEFT] * 0x1000);
mCblk->sendLevel = uint16_t(mSendLevel * 0x1000);
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
mRemainingFrames = mNotificationFramesAct;
@@ -1016,7 +1064,7 @@ audio_track_cblk_t::audio_track_cblk_t()
: lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
userBase(0), serverBase(0), buffers(0), frameCount(0),
loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0),
flags(0)
flags(0), sendLevel(0)
{
}

View File

@@ -62,7 +62,14 @@ enum {
SET_STREAM_OUTPUT,
SET_VOICE_VOLUME,
GET_RENDER_POSITION,
GET_INPUT_FRAMES_LOST
GET_INPUT_FRAMES_LOST,
NEW_AUDIO_SESSION_ID,
LOAD_EFFECT_LIBRARY,
UNLOAD_EFFECT_LIBRARY,
QUERY_NUM_EFFECTS,
QUERY_NEXT_EFFECT,
GET_EFFECT_DESCRIPTOR,
CREATE_EFFECT
};
class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -83,6 +90,7 @@ public:
uint32_t flags,
const sp<IMemory>& sharedBuffer,
int output,
int *sessionId,
status_t *status)
{
Parcel data, reply;
@@ -97,10 +105,19 @@ public:
data.writeInt32(flags);
data.writeStrongBinder(sharedBuffer->asBinder());
data.writeInt32(output);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
data.writeInt32(lSessionId);
status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
if (lStatus != NO_ERROR) {
LOGE("createTrack error: %s", strerror(-lStatus));
} else {
lSessionId = reply.readInt32();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
lStatus = reply.readInt32();
track = interface_cast<IAudioTrack>(reply.readStrongBinder());
}
@@ -118,6 +135,7 @@ public:
int channelCount,
int frameCount,
uint32_t flags,
int *sessionId,
status_t *status)
{
Parcel data, reply;
@@ -130,10 +148,19 @@ public:
data.writeInt32(channelCount);
data.writeInt32(frameCount);
data.writeInt32(flags);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
data.writeInt32(lSessionId);
status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
if (lStatus != NO_ERROR) {
LOGE("openRecord error: %s", strerror(-lStatus));
} else {
lSessionId = reply.readInt32();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
lStatus = reply.readInt32();
record = interface_cast<IAudioRecord>(reply.readStrongBinder());
}
@@ -497,6 +524,157 @@ public:
remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
return reply.readInt32();
}
virtual int newAudioSessionId()
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
status_t status = remote()->transact(NEW_AUDIO_SESSION_ID, data, &reply);
int id = 0;
if (status == NO_ERROR) {
id = reply.readInt32();
}
return id;
}
virtual status_t loadEffectLibrary(const char *libPath, int *handle)
{
if (libPath == NULL || handle == NULL) {
return BAD_VALUE;
}
*handle = 0;
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeCString(libPath);
status_t status = remote()->transact(LOAD_EFFECT_LIBRARY, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
if (status == NO_ERROR) {
*handle = reply.readInt32();
}
}
return status;
}
virtual status_t unloadEffectLibrary(int handle)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(handle);
status_t status = remote()->transact(UNLOAD_EFFECT_LIBRARY, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
}
return status;
}
virtual status_t queryNumberEffects(uint32_t *numEffects)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
status_t status = remote()->transact(QUERY_NUM_EFFECTS, data, &reply);
if (status != NO_ERROR) {
return status;
}
status = reply.readInt32();
if (status != NO_ERROR) {
return status;
}
if (numEffects) {
*numEffects = (uint32_t)reply.readInt32();
}
return NO_ERROR;
}
virtual status_t queryNextEffect(effect_descriptor_t *pDescriptor)
{
if (pDescriptor == NULL) {
return BAD_VALUE;
}
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
status_t status = remote()->transact(QUERY_NEXT_EFFECT, data, &reply);
if (status != NO_ERROR) {
return status;
}
status = reply.readInt32();
if (status != NO_ERROR) {
return status;
}
reply.read(pDescriptor, sizeof(effect_descriptor_t));
return NO_ERROR;
}
virtual status_t getEffectDescriptor(effect_uuid_t *pUuid, effect_descriptor_t *pDescriptor)
{
if (pUuid == NULL || pDescriptor == NULL) {
return BAD_VALUE;
}
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.write(pUuid, sizeof(effect_uuid_t));
status_t status = remote()->transact(GET_EFFECT_DESCRIPTOR, data, &reply);
if (status != NO_ERROR) {
return status;
}
status = reply.readInt32();
if (status != NO_ERROR) {
return status;
}
reply.read(pDescriptor, sizeof(effect_descriptor_t));
return NO_ERROR;
}
virtual sp<IEffect> createEffect(pid_t pid,
effect_descriptor_t *pDesc,
const sp<IEffectClient>& client,
int32_t priority,
int output,
int sessionId,
status_t *status,
int *id,
int *enabled)
{
Parcel data, reply;
sp<IEffect> effect;
if (pDesc == NULL) {
return effect;
if (status) {
*status = BAD_VALUE;
}
}
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.writeInt32(pid);
data.write(pDesc, sizeof(effect_descriptor_t));
data.writeStrongBinder(client->asBinder());
data.writeInt32(priority);
data.writeInt32(output);
data.writeInt32(sessionId);
status_t lStatus = remote()->transact(CREATE_EFFECT, data, &reply);
if (lStatus != NO_ERROR) {
LOGE("createEffect error: %s", strerror(-lStatus));
} else {
lStatus = reply.readInt32();
int tmp = reply.readInt32();
if (id) {
*id = tmp;
}
tmp = reply.readInt32();
if (enabled) {
*enabled = tmp;
}
effect = interface_cast<IEffect>(reply.readStrongBinder());
reply.read(pDesc, sizeof(effect_descriptor_t));
}
if (status) {
*status = lStatus;
}
return effect;
}
};
IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -518,10 +696,12 @@ status_t BnAudioFlinger::onTransact(
uint32_t flags = data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
int output = data.readInt32();
int sessionId = data.readInt32();
status_t status;
sp<IAudioTrack> track = createTrack(pid,
streamType, sampleRate, format,
channelCount, bufferCount, flags, buffer, output, &status);
channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
reply->writeInt32(sessionId);
reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder());
return NO_ERROR;
@@ -535,9 +715,11 @@ status_t BnAudioFlinger::onTransact(
int channelCount = data.readInt32();
size_t bufferCount = data.readInt32();
uint32_t flags = data.readInt32();
int sessionId = data.readInt32();
status_t status;
sp<IAudioRecord> record = openRecord(pid, input,
sampleRate, format, channelCount, bufferCount, flags, &status);
sampleRate, format, channelCount, bufferCount, flags, &sessionId, &status);
reply->writeInt32(sessionId);
reply->writeInt32(status);
reply->writeStrongBinder(record->asBinder());
return NO_ERROR;
@@ -768,7 +950,79 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32(getInputFramesLost(ioHandle));
return NO_ERROR;
} break;
case NEW_AUDIO_SESSION_ID: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32(newAudioSessionId());
return NO_ERROR;
} break;
case LOAD_EFFECT_LIBRARY: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
int handle;
status_t status = loadEffectLibrary(data.readCString(), &handle);
reply->writeInt32(status);
if (status == NO_ERROR) {
reply->writeInt32(handle);
}
return NO_ERROR;
}
case UNLOAD_EFFECT_LIBRARY: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
reply->writeInt32(unloadEffectLibrary(data.readInt32()));
return NO_ERROR;
}
case QUERY_NUM_EFFECTS: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
uint32_t numEffects;
status_t status = queryNumberEffects(&numEffects);
reply->writeInt32(status);
if (status == NO_ERROR) {
reply->writeInt32((int32_t)numEffects);
}
return NO_ERROR;
}
case QUERY_NEXT_EFFECT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
effect_descriptor_t desc;
status_t status = queryNextEffect(&desc);
reply->writeInt32(status);
if (status == NO_ERROR) {
reply->write(&desc, sizeof(effect_descriptor_t));
}
return NO_ERROR;
}
case GET_EFFECT_DESCRIPTOR: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
effect_uuid_t uuid;
data.read(&uuid, sizeof(effect_uuid_t));
effect_descriptor_t desc;
status_t status = getEffectDescriptor(&uuid, &desc);
reply->writeInt32(status);
if (status == NO_ERROR) {
reply->write(&desc, sizeof(effect_descriptor_t));
}
return NO_ERROR;
}
case CREATE_EFFECT: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
pid_t pid = data.readInt32();
effect_descriptor_t desc;
data.read(&desc, sizeof(effect_descriptor_t));
sp<IEffectClient> client = interface_cast<IEffectClient>(data.readStrongBinder());
int32_t priority = data.readInt32();
int output = data.readInt32();
int sessionId = data.readInt32();
status_t status;
int id;
int enabled;
sp<IEffect> effect = createEffect(pid, &desc, client, priority, output, sessionId, &status, &id, &enabled);
reply->writeInt32(status);
reply->writeInt32(id);
reply->writeInt32(enabled);
reply->writeStrongBinder(effect->asBinder());
reply->write(&desc, sizeof(effect_descriptor_t));
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}

View File

@@ -34,7 +34,8 @@ enum {
STOP,
FLUSH,
MUTE,
PAUSE
PAUSE,
ATTACH_AUX_EFFECT
};
class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -97,7 +98,21 @@ public:
cblk = interface_cast<IMemory>(reply.readStrongBinder());
}
return cblk;
}
}
virtual status_t attachAuxEffect(int effectId)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor());
data.writeInt32(effectId);
status_t status = remote()->transact(ATTACH_AUX_EFFECT, data, &reply);
if (status == NO_ERROR) {
status = reply.readInt32();
} else {
LOGW("attachAuxEffect() error: %s", strerror(-status));
}
return status;
}
};
IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -138,6 +153,11 @@ status_t BnAudioTrack::onTransact(
pause();
return NO_ERROR;
}
case ATTACH_AUX_EFFECT: {
CHECK_INTERFACE(IAudioTrack, data, reply);
reply->writeInt32(attachAuxEffect(data.readInt32()));
return NO_ERROR;
} break;
default:
return BBinder::onTransact(code, data, reply, flags);
}