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

This commit is contained in:
Eric Laurent
2010-06-04 00:16:05 -07:00
committed by Android Git Automerger
23 changed files with 3332 additions and 386 deletions

View File

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

View File

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

View File

@@ -138,7 +138,8 @@ public:
uint32_t flags = 0, uint32_t flags = 0,
callback_t cbf = 0, callback_t cbf = 0,
void* user = 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, /* 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 * The PCM data to be rendered by AudioTrack is passed in a shared memory buffer
@@ -157,7 +158,8 @@ public:
uint32_t flags = 0, uint32_t flags = 0,
callback_t cbf = 0, callback_t cbf = 0,
void* user = 0, void* user = 0,
int notificationFrames = 0); int notificationFrames = 0,
int sessionId = 0);
/* Terminates the AudioTrack and unregisters it from AudioFlinger. /* Terminates the AudioTrack and unregisters it from AudioFlinger.
* Also destroys all resources assotiated with the AudioTrack. * Also destroys all resources assotiated with the AudioTrack.
@@ -182,7 +184,8 @@ public:
void* user = 0, void* user = 0,
int notificationFrames = 0, int notificationFrames = 0,
const sp<IMemory>& sharedBuffer = 0, const sp<IMemory>& sharedBuffer = 0,
bool threadCanCallJava = false); bool threadCanCallJava = false,
int sessionId = 0);
/* Result of constructing the AudioTrack. This must be checked /* 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 /* 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); 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 /* set sample rate for this track, mostly used for games' sound effects
*/ */
status_t setSampleRate(int sampleRate); status_t setSampleRate(int sampleRate);
@@ -340,6 +350,31 @@ public:
*/ */
audio_io_handle_t getOutput(); 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 /* obtains a buffer of "frameCount" frames. The buffer must be
* filled entirely. If the track is stopped, obtainBuffer() returns * filled entirely. If the track is stopped, obtainBuffer() returns
* STOPPED instead of NO_ERROR as long as there are buffers availlable, * STOPPED instead of NO_ERROR as long as there are buffers availlable,
@@ -406,6 +441,7 @@ private:
sp<AudioTrackThread> mAudioTrackThread; sp<AudioTrackThread> mAudioTrackThread;
float mVolume[2]; float mVolume[2];
float mSendLevel;
uint32_t mFrameCount; uint32_t mFrameCount;
audio_track_cblk_t* mCblk; audio_track_cblk_t* mCblk;
@@ -431,6 +467,7 @@ private:
uint32_t mNewPosition; uint32_t mNewPosition;
uint32_t mUpdatePeriod; uint32_t mUpdatePeriod;
uint32_t mFlags; uint32_t mFlags;
int mSessionId;
}; };

View File

@@ -114,7 +114,8 @@ typedef struct effect_descriptor_s {
// +---------------------------+-----------+----------------------------------- // +---------------------------+-----------+-----------------------------------
// | Volume management | 5..6 | 0 none // | Volume management | 5..6 | 0 none
// | | | 1 implements volume control // | | | 1 implements volume control
// | | | 2..3 reserved // | | | 2 requires volume indication
// | | | 3 reserved
// +---------------------------+-----------+----------------------------------- // +---------------------------+-----------+-----------------------------------
// | Device management | 7..8 | 0 none // | Device management | 7..8 | 0 none
// | | | 1 requires device updates // | | | 1 requires device updates
@@ -154,6 +155,7 @@ typedef struct effect_descriptor_s {
// volume control // volume control
#define EFFECT_FLAG_VOLUME_MASK 0x00000060 #define EFFECT_FLAG_VOLUME_MASK 0x00000060
#define EFFECT_FLAG_VOLUME_CTRL 0x00000020 #define EFFECT_FLAG_VOLUME_CTRL 0x00000020
#define EFFECT_FLAG_VOLUME_IND 0x00000040
#define EFFECT_FLAG_VOLUME_NONE 0x00000000 #define EFFECT_FLAG_VOLUME_NONE 0x00000000
// device control // 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) // | 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 // | 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 // | 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 // | If volume control flag is set | | 8.24 fixed point format | 8.24 fixed point format
// | volume that should be applied | | | // | in the effect descriptor, the | | | It is legal to receive a null
// | before the effect is processed | | | // | effect engine must return the | | | pointer as pReplyData in which
// | The overall volume (the volume | | | // | 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 | | | // | actually applied by the effect | | |
// | multiplied by the returned | | | // | multiplied by the returned | | |
// | value) should match the | | | // | value) should match the | | |
@@ -370,7 +374,7 @@ typedef struct buffer_provider_s {
// structure that defines both input and output buffer configurations and is // structure that defines both input and output buffer configurations and is
// passed by the EFFECT_CMD_CONFIGURE command. // passed by the EFFECT_CMD_CONFIGURE command.
typedef struct buffer_config_s { 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 samplingRate; // sampling rate
uint32_t channels; // channel mask (see audio_channels_e in AudioCommon.h) uint32_t channels; // channel mask (see audio_channels_e in AudioCommon.h)
buffer_provider_t bufferProvider; // buffer provider buffer_provider_t bufferProvider; // buffer provider
@@ -457,7 +461,7 @@ typedef struct effect_param_s {
// //
// Function: EffectQueryNumberEffects // 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 // library. Each effect must have a unique effect uuid (see
// effect_descriptor_t). This function together with EffectQueryNext() // effect_descriptor_t). This function together with EffectQueryNext()
// is used to enumerate all effects present in the library. // 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 // *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. // returned value: 0 successful operation.
// -ENODEV library failed to initialize // -ENODEV library failed to initialize
// -EINVAL invalid pEffectUuid or pInterface // -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. // *pInterface: updated with the effect interface handle.
// //
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////

View File

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

View File

@@ -27,6 +27,9 @@
#include <media/IAudioTrack.h> #include <media/IAudioTrack.h>
#include <media/IAudioRecord.h> #include <media/IAudioRecord.h>
#include <media/IAudioFlingerClient.h> #include <media/IAudioFlingerClient.h>
#include <media/EffectApi.h>
#include <media/IEffect.h>
#include <media/IEffectClient.h>
#include <utils/String8.h> #include <utils/String8.h>
namespace android { namespace android {
@@ -51,6 +54,7 @@ public:
uint32_t flags, uint32_t flags,
const sp<IMemory>& sharedBuffer, const sp<IMemory>& sharedBuffer,
int output, int output,
int *sessionId,
status_t *status) = 0; status_t *status) = 0;
virtual sp<IAudioRecord> openRecord( virtual sp<IAudioRecord> openRecord(
@@ -61,6 +65,7 @@ public:
int channelCount, int channelCount,
int frameCount, int frameCount,
uint32_t flags, uint32_t flags,
int *sessionId,
status_t *status) = 0; status_t *status) = 0;
/* query the audio hardware state. This state never changes, /* 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 status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames, int output) = 0;
virtual unsigned int getInputFramesLost(int ioHandle) = 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; 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 */ /* get this tracks control block */
virtual sp<IMemory> getCblk() const = 0; 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 bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger
uint16_t waitTimeMs; // Cumulated wait time uint16_t waitTimeMs; // Cumulated wait time
uint32_t reserved; uint16_t sendLevel;
uint16_t reserved;
// Cache line boundary (32 bytes) // Cache line boundary (32 bytes)
audio_track_cblk_t(); audio_track_cblk_t();
uint32_t stepUser(uint32_t frameCount); uint32_t stepUser(uint32_t frameCount);

View File

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

File diff suppressed because it is too large Load Diff

View File

@@ -42,6 +42,7 @@
namespace android { namespace android {
class audio_track_cblk_t; class audio_track_cblk_t;
class effect_param_cblk_t;
class AudioMixer; class AudioMixer;
class AudioBuffer; class AudioBuffer;
class AudioResampler; class AudioResampler;
@@ -75,6 +76,7 @@ public:
uint32_t flags, uint32_t flags,
const sp<IMemory>& sharedBuffer, const sp<IMemory>& sharedBuffer,
int output, int output,
int *sessionId,
status_t *status); status_t *status);
virtual uint32_t sampleRate(int output) const; 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 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 { enum hardware_call_state {
AUDIO_HW_IDLE = 0, AUDIO_HW_IDLE = 0,
AUDIO_HW_INIT, AUDIO_HW_INIT,
@@ -167,6 +191,7 @@ public:
int channelCount, int channelCount,
int frameCount, int frameCount,
uint32_t flags, uint32_t flags,
int *sessionId,
status_t *status); status_t *status);
virtual status_t onTransact( virtual status_t onTransact(
@@ -233,6 +258,9 @@ private:
class DuplicatingThread; class DuplicatingThread;
class Track; class Track;
class RecordTrack; class RecordTrack;
class EffectModule;
class EffectHandle;
class EffectChain;
class ThreadBase : public Thread { class ThreadBase : public Thread {
public: public:
@@ -268,13 +296,15 @@ private:
int channelCount, int channelCount,
int frameCount, int frameCount,
uint32_t flags, uint32_t flags,
const sp<IMemory>& sharedBuffer); const sp<IMemory>& sharedBuffer,
int sessionId);
~TrackBase(); ~TrackBase();
virtual status_t start() = 0; virtual status_t start() = 0;
virtual void stop() = 0; virtual void stop() = 0;
sp<IMemory> getCblk() const; sp<IMemory> getCblk() const;
audio_track_cblk_t* cblk() const { return mCblk; } audio_track_cblk_t* cblk() const { return mCblk; }
int sessionId() { return mSessionId; }
protected: protected:
friend class ThreadBase; friend class ThreadBase;
@@ -323,6 +353,7 @@ private:
int mClientTid; int mClientTid;
uint8_t mFormat; uint8_t mFormat;
uint32_t mFlags; uint32_t mFlags;
int mSessionId;
}; };
class ConfigEvent { class ConfigEvent {
@@ -405,7 +436,8 @@ private:
int format, int format,
int channelCount, int channelCount,
int frameCount, int frameCount,
const sp<IMemory>& sharedBuffer); const sp<IMemory>& sharedBuffer,
int sessionId);
~Track(); ~Track();
void dump(char* buffer, size_t size); void dump(char* buffer, size_t size);
@@ -424,6 +456,12 @@ private:
int type() const { int type() const {
return mStreamType; 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: protected:
@@ -464,6 +502,9 @@ private:
bool mResetDone; bool mResetDone;
int mStreamType; int mStreamType;
int mName; int mName;
int16_t *mMainBuffer;
int32_t *mAuxBuffer;
int mAuxEffectId;
}; // end of Track }; // end of Track
@@ -505,7 +546,7 @@ private:
DuplicatingThread* mSourceThread; DuplicatingThread* mSourceThread;
}; // end of OutputTrack }; // 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 ~PlaybackThread();
virtual status_t dump(int fd, const Vector<String16>& args); virtual status_t dump(int fd, const Vector<String16>& args);
@@ -538,6 +579,7 @@ private:
int channelCount, int channelCount,
int frameCount, int frameCount,
const sp<IMemory>& sharedBuffer, const sp<IMemory>& sharedBuffer,
int sessionId,
status_t *status); status_t *status);
AudioStreamOut* getOutput() { return mOutput; } AudioStreamOut* getOutput() { return mOutput; }
@@ -549,6 +591,29 @@ private:
virtual String8 getParameters(const String8& keys); virtual String8 getParameters(const String8& keys);
virtual void audioConfigChanged_l(int event, int param = 0); virtual void audioConfigChanged_l(int event, int param = 0);
virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); 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 { struct stream_type_t {
stream_type_t() stream_type_t()
@@ -591,8 +656,11 @@ private:
void readOutputParameters(); void readOutputParameters();
uint32_t device() { return mDevice; }
virtual status_t dumpInternals(int fd, const Vector<String16>& args); virtual status_t dumpInternals(int fd, const Vector<String16>& args);
status_t dumpTracks(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; SortedVector< sp<Track> > mTracks;
// mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread // mStreamTypes[] uses 1 additionnal stream type internally for the OutputTrack used by DuplicatingThread
@@ -603,11 +671,13 @@ private:
int mNumWrites; int mNumWrites;
int mNumDelayedWrites; int mNumDelayedWrites;
bool mInWrite; bool mInWrite;
Vector< sp<EffectChain> > mEffectChains;
uint32_t mDevice;
}; };
class MixerThread : public PlaybackThread { class MixerThread : public PlaybackThread {
public: public:
MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id); MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
virtual ~MixerThread(); virtual ~MixerThread();
// Thread virtuals // Thread virtuals
@@ -630,7 +700,7 @@ private:
class DirectOutputThread : public PlaybackThread { class DirectOutputThread : public PlaybackThread {
public: public:
DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id); DirectOutputThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device);
~DirectOutputThread(); ~DirectOutputThread();
// Thread virtuals // Thread virtuals
@@ -645,8 +715,12 @@ private:
virtual uint32_t idleSleepTimeUs(); virtual uint32_t idleSleepTimeUs();
private: private:
float mLeftVolume; void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
float mRightVolume;
float mLeftVolFloat;
float mRightVolFloat;
uint16_t mLeftVolShort;
uint16_t mRightVolShort;
}; };
class DuplicatingThread : public MixerThread { class DuplicatingThread : public MixerThread {
@@ -676,6 +750,8 @@ private:
float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; } float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
void audioConfigChanged_l(int event, int ioHandle, void *param2); void audioConfigChanged_l(int event, int ioHandle, void *param2);
int nextUniqueId();
friend class AudioBuffer; friend class AudioBuffer;
class TrackHandle : public android::BnAudioTrack { class TrackHandle : public android::BnAudioTrack {
@@ -689,6 +765,7 @@ private:
virtual void pause(); virtual void pause();
virtual void setVolume(float left, float right); virtual void setVolume(float left, float right);
virtual sp<IMemory> getCblk() const; virtual sp<IMemory> getCblk() const;
virtual status_t attachAuxEffect(int effectId);
virtual status_t onTransact( virtual status_t onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags); uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
private: private:
@@ -717,7 +794,8 @@ private:
int format, int format,
int channelCount, int channelCount,
int frameCount, int frameCount,
uint32_t flags); uint32_t flags,
int sessionId);
~RecordTrack(); ~RecordTrack();
virtual status_t start(); virtual status_t start();
@@ -792,6 +870,215 @@ private:
sp<RecordThread::RecordTrack> mRecordTrack; 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 RecordThread;
friend class PlaybackThread; friend class PlaybackThread;
@@ -813,7 +1100,7 @@ private:
DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads; DefaultKeyedVector< int, sp<RecordThread> > mRecordThreads;
DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients; DefaultKeyedVector< pid_t, sp<NotificationClient> > mNotificationClients;
int mNextThreadId; volatile int32_t mNextUniqueId;
#ifdef LVMX #ifdef LVMX
int mLifeVibesClientPid; int mLifeVibesClientPid;
#endif #endif

View File

@@ -56,6 +56,8 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
t->volume[1] = UNITY_GAIN; t->volume[1] = UNITY_GAIN;
t->volumeInc[0] = 0; t->volumeInc[0] = 0;
t->volumeInc[1] = 0; t->volumeInc[1] = 0;
t->auxLevel = 0;
t->auxInc = 0;
t->channelCount = 2; t->channelCount = 2;
t->enabled = 0; t->enabled = 0;
t->format = 16; t->format = 16;
@@ -65,6 +67,8 @@ AudioMixer::AudioMixer(size_t frameCount, uint32_t sampleRate)
t->resampler = 0; t->resampler = 0;
t->sampleRate = mSampleRate; t->sampleRate = mSampleRate;
t->in = 0; t->in = 0;
t->mainBuffer = NULL;
t->auxBuffer = NULL;
t++; t++;
} }
} }
@@ -169,28 +173,48 @@ status_t AudioMixer::setActiveTrack(int track)
return NO_ERROR; 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) { switch (target) {
case TRACK: case TRACK:
if (name == CHANNEL_COUNT) { if (name == CHANNEL_COUNT) {
if ((uint32_t(value) <= MAX_NUM_CHANNELS) && (value)) { if ((uint32_t(valueInt) <= MAX_NUM_CHANNELS) && (valueInt)) {
if (mState.tracks[ mActiveTrack ].channelCount != value) { if (mState.tracks[ mActiveTrack ].channelCount != valueInt) {
mState.tracks[ mActiveTrack ].channelCount = value; mState.tracks[ mActiveTrack ].channelCount = valueInt;
LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", value); LOGV("setParameter(TRACK, CHANNEL_COUNT, %d)", valueInt);
invalidateState(1<<mActiveTrack); invalidateState(1<<mActiveTrack);
} }
return NO_ERROR; 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; break;
case RESAMPLE: case RESAMPLE:
if (name == SAMPLE_RATE) { if (name == SAMPLE_RATE) {
if (value > 0) { if (valueInt > 0) {
track_t& track = mState.tracks[ mActiveTrack ]; 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)", LOGV("setParameter(RESAMPLE, SAMPLE_RATE, %u)",
uint32_t(value)); uint32_t(valueInt));
invalidateState(1<<mActiveTrack); invalidateState(1<<mActiveTrack);
} }
return NO_ERROR; return NO_ERROR;
@@ -201,18 +225,39 @@ status_t AudioMixer::setParameter(int target, int name, int value)
case VOLUME: case VOLUME:
if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) { if ((uint32_t(name-VOLUME0) < MAX_NUM_CHANNELS)) {
track_t& track = mState.tracks[ mActiveTrack ]; 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.prevVolume[name-VOLUME0] = track.volume[name-VOLUME0] << 16;
track.volume[name-VOLUME0] = value; track.volume[name-VOLUME0] = valueInt;
if (target == VOLUME) { if (target == VOLUME) {
track.prevVolume[name-VOLUME0] = value << 16; track.prevVolume[name-VOLUME0] = valueInt << 16;
track.volumeInc[name-VOLUME0] = 0; track.volumeInc[name-VOLUME0] = 0;
} else { } 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); int32_t volInc = d / int32_t(mState.frameCount);
track.volumeInc[name-VOLUME0] = volInc; track.volumeInc[name-VOLUME0] = volInc;
if (volInc == 0) { 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); invalidateState(1<<mActiveTrack);
@@ -245,7 +290,7 @@ bool AudioMixer::track_t::doesResample() const
} }
inline inline
void AudioMixer::track_t::adjustVolumeRamp() void AudioMixer::track_t::adjustVolumeRamp(bool aux)
{ {
for (int i=0 ; i<2 ; i++) { for (int i=0 ; i<2 ; i++) {
if (((volumeInc[i]>0) && (((prevVolume[i]+volumeInc[i])>>16) >= volume[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; 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, LOGW_IF(!state->needsChanged,
"in process__validate() but nothing's invalid"); "in process__validate() but nothing's invalid");
@@ -308,6 +360,9 @@ void AudioMixer::process__validate(state_t* state, void* output)
n |= NEEDS_CHANNEL_1 + t.channelCount - 1; n |= NEEDS_CHANNEL_1 + t.channelCount - 1;
n |= NEEDS_FORMAT_16; n |= NEEDS_FORMAT_16;
n |= t.doesResample() ? NEEDS_RESAMPLE_ENABLED : NEEDS_RESAMPLE_DISABLED; 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]) { if (t.volumeInc[0]|t.volumeInc[1]) {
volumeRamp = 1; volumeRamp = 1;
@@ -319,6 +374,9 @@ void AudioMixer::process__validate(state_t* state, void* output)
if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) { if ((n & NEEDS_MUTE__MASK) == NEEDS_MUTE_ENABLED) {
t.hook = track__nop; t.hook = track__nop;
} else { } else {
if ((n & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
all16BitsStereoNoResample = 0;
}
if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { if ((n & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
all16BitsStereoNoResample = 0; all16BitsStereoNoResample = 0;
resampling = 1; resampling = 1;
@@ -369,7 +427,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
countActiveTracks, state->enabledTracks, countActiveTracks, state->enabledTracks,
all16BitsStereoNoResample, resampling, volumeRamp); all16BitsStereoNoResample, resampling, volumeRamp);
state->hook(state, output); state->hook(state);
// Now that the volume ramp has been done, set optimal state and // Now that the volume ramp has been done, set optimal state and
// track hooks for subsequent mixer process // track hooks for subsequent mixer process
@@ -390,7 +448,7 @@ void AudioMixer::process__validate(state_t* state, void* output)
} }
if (allMuted) { if (allMuted) {
state->hook = process__nop; state->hook = process__nop;
} else if (!resampling && all16BitsStereoNoResample) { } else if (all16BitsStereoNoResample) {
if (countActiveTracks == 1) { if (countActiveTracks == 1) {
state->hook = process__OneTrack16BitsStereoNoResampling; state->hook = process__OneTrack16BitsStereoNoResampling;
} }
@@ -481,16 +539,29 @@ 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); t->resampler->setSampleRate(t->sampleRate);
// ramp gain - resample to temp buffer and scale/mix in 2nd step // ramp gain - resample to temp buffer and scale/mix in 2nd step
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);
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]) { if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN); t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t)); memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
t->resampler->resample(temp, outFrameCount, t->bufferProvider); t->resampler->resample(temp, outFrameCount, t->bufferProvider);
volumeRampStereo(t, out, outFrameCount, temp); volumeRampStereo(t, out, outFrameCount, temp, aux);
} }
// constant gain // constant gain
@@ -499,12 +570,13 @@ void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFram
t->resampler->resample(out, outFrameCount, t->bufferProvider); 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 vl = t->prevVolume[0];
int32_t vr = t->prevVolume[1]; int32_t vr = t->prevVolume[1];
@@ -516,22 +588,116 @@ void AudioMixer::volumeRampStereo(track_t* t, int32_t* out, size_t frameCount, i
// (vl + vlInc*frameCount)/65536.0f, frameCount); // (vl + vlInc*frameCount)/65536.0f, frameCount);
// ramp volume // ramp volume
if UNLIKELY(aux != NULL) {
int32_t va = t->prevAuxLevel;
const int32_t vaInc = t->auxInc;
int32_t l;
int32_t r;
do {
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 { do {
*out++ += (vl >> 16) * (*temp++ >> 12); *out++ += (vl >> 16) * (*temp++ >> 12);
*out++ += (vr >> 16) * (*temp++ >> 12); *out++ += (vr >> 16) * (*temp++ >> 12);
vl += vlInc; vl += vlInc;
vr += vrInc; vr += vrInc;
} while (--frameCount); } while (--frameCount);
}
t->prevVolume[0] = vl; t->prevVolume[0] = vl;
t->prevVolume[1] = vr; t->prevVolume[1] = vr;
t->adjustVolumeRamp(); t->adjustVolumeRamp((aux != NULL));
} }
void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp) 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 {
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); 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 // ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0]; int32_t vl = t->prevVolume[0];
@@ -552,7 +718,7 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount
t->prevVolume[0] = vl; t->prevVolume[0] = vl;
t->prevVolume[1] = vr; t->prevVolume[1] = vr;
t->adjustVolumeRamp(); t->adjustVolumeRamp(false);
} }
// constant gain // constant gain
@@ -566,13 +732,58 @@ void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount
out += 2; out += 2;
} while (--frameCount); } while (--frameCount);
} }
}
t->in = in; 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); int16_t const *in = static_cast<int16_t const *>(t->in);
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);
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 // ramp gain
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) { if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
int32_t vl = t->prevVolume[0]; int32_t vl = t->prevVolume[0];
@@ -594,7 +805,7 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
t->prevVolume[0] = vl; t->prevVolume[0] = vl;
t->prevVolume[1] = vr; t->prevVolume[1] = vr;
t->adjustVolumeRamp(); t->adjustVolumeRamp(false);
} }
// constant gain // constant gain
else { else {
@@ -607,6 +818,7 @@ void AudioMixer::track__16BitsMono(track_t* t, int32_t* out, size_t frameCount,
out += 2; out += 2;
} while (--frameCount); } while (--frameCount);
} }
}
t->in = in; t->in = in;
} }
@@ -624,37 +836,56 @@ void AudioMixer::ditherAndClamp(int32_t* out, int32_t const *sums, size_t c)
} }
// no-op case // 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 uint32_t e0 = state->enabledTracks;
memset(output, 0, state->frameCount*4); size_t bufSize = state->frameCount * sizeof(int16_t) * MAX_NUM_CHANNELS;
uint32_t en = state->enabledTracks; while (e0) {
while (en) { // process by group of tracks with same output buffer to
const int i = 31 - __builtin_clz(en); // avoid multiple memset() on same buffer
en &= ~(1<<i); uint32_t e1 = e0, e2 = e0;
track_t& t = state->tracks[i]; 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; size_t outFrames = state->frameCount;
while (outFrames) { while (outFrames) {
t.buffer.frameCount = outFrames; t1.buffer.frameCount = outFrames;
t.bufferProvider->getNextBuffer(&t.buffer); t1.bufferProvider->getNextBuffer(&t1.buffer);
if (!t.buffer.raw) break; if (!t1.buffer.raw) break;
outFrames -= t.buffer.frameCount; outFrames -= t1.buffer.frameCount;
t.bufferProvider->releaseBuffer(&t.buffer); t1.bufferProvider->releaseBuffer(&t1.buffer);
}
} }
} }
} }
// generic code without resampling // 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))); int32_t outTemp[BLOCKSIZE * MAX_NUM_CHANNELS] __attribute__((aligned(32)));
// acquire each track's buffer // acquire each track's buffer
uint32_t enabledTracks = state->enabledTracks; uint32_t enabledTracks = state->enabledTracks;
uint32_t en = enabledTracks; uint32_t e0 = enabledTracks;
while (en) { while (e0) {
const int i = 31 - __builtin_clz(en); const int i = 31 - __builtin_clz(e0);
en &= ~(1<<i); e0 &= ~(1<<i);
track_t& t = state->tracks[i]; track_t& t = state->tracks[i];
t.buffer.frameCount = state->frameCount; t.buffer.frameCount = state->frameCount;
t.bufferProvider->getNextBuffer(&t.buffer); t.bufferProvider->getNextBuffer(&t.buffer);
@@ -666,108 +897,154 @@ void AudioMixer::process__genericNoResampling(state_t* state, void* output)
enabledTracks &= ~(1<<i); enabledTracks &= ~(1<<i);
} }
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);
}
}
e0 &= ~(e1);
// this assumes output 16 bits stereo, no resampling // this assumes output 16 bits stereo, no resampling
int32_t* out = static_cast<int32_t*>(output); int32_t *out = t1.mainBuffer;
size_t numFrames = state->frameCount; size_t numFrames = 0;
do { do {
memset(outTemp, 0, sizeof(outTemp)); memset(outTemp, 0, sizeof(outTemp));
e2 = e1;
en = enabledTracks; while (e2) {
while (en) { const int i = 31 - __builtin_clz(e2);
const int i = 31 - __builtin_clz(en); e2 &= ~(1<<i);
en &= ~(1<<i);
track_t& t = state->tracks[i]; track_t& t = state->tracks[i];
size_t outFrames = BLOCKSIZE; size_t outFrames = BLOCKSIZE;
int32_t *aux = NULL;
if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
aux = t.auxBuffer + numFrames;
}
while (outFrames) { while (outFrames) {
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount; size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
if (inFrames) { if (inFrames) {
(t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp); (t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
t.frameCount -= inFrames; t.frameCount -= inFrames;
outFrames -= inFrames; outFrames -= inFrames;
if UNLIKELY(aux != NULL) {
aux += inFrames;
}
} }
if (t.frameCount == 0 && outFrames) { if (t.frameCount == 0 && outFrames) {
t.bufferProvider->releaseBuffer(&t.buffer); t.bufferProvider->releaseBuffer(&t.buffer);
t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames); t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
t.bufferProvider->getNextBuffer(&t.buffer); t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw; t.in = t.buffer.raw;
if (t.in == NULL) { if (t.in == NULL) {
enabledTracks &= ~(1<<i); enabledTracks &= ~(1<<i);
e1 &= ~(1<<i);
break; break;
} }
t.frameCount = t.buffer.frameCount; t.frameCount = t.buffer.frameCount;
} }
} }
} }
ditherAndClamp(out, outTemp, BLOCKSIZE); ditherAndClamp(out, outTemp, BLOCKSIZE);
out += BLOCKSIZE; out += BLOCKSIZE;
numFrames -= BLOCKSIZE; numFrames += BLOCKSIZE;
} while (numFrames); } while (numFrames < state->frameCount);
}
// release each track's buffer // release each track's buffer
en = enabledTracks; e0 = enabledTracks;
while (en) { while (e0) {
const int i = 31 - __builtin_clz(en); const int i = 31 - __builtin_clz(e0);
en &= ~(1<<i); e0 &= ~(1<<i);
track_t& t = state->tracks[i]; track_t& t = state->tracks[i];
t.bufferProvider->releaseBuffer(&t.buffer); t.bufferProvider->releaseBuffer(&t.buffer);
} }
} }
// generic code with resampling // generic code with resampling
void AudioMixer::process__genericResampling(state_t* state, void* output) void AudioMixer::process__genericResampling(state_t* state)
{ {
int32_t* const outTemp = state->outputTemp; int32_t* const outTemp = state->outputTemp;
const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount; const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
memset(outTemp, 0, size); memset(outTemp, 0, size);
int32_t* out = static_cast<int32_t*>(output);
size_t numFrames = state->frameCount; size_t numFrames = state->frameCount;
uint32_t en = state->enabledTracks; uint32_t e0 = state->enabledTracks;
while (en) { while (e0) {
const int i = 31 - __builtin_clz(en); // process by group of tracks with same output buffer
en &= ~(1<<i); // 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]; track_t& t = state->tracks[i];
int32_t *aux = NULL;
if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
aux = t.auxBuffer;
}
// this is a little goofy, on the resampling case we don't // this is a little goofy, on the resampling case we don't
// acquire/release the buffers because it's done by // acquire/release the buffers because it's done by
// the resampler. // the resampler.
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) { if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
(t.hook)(&t, outTemp, numFrames, state->resampleTemp); (t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
} else { } else {
size_t outFrames = numFrames; size_t outFrames = 0;
while (outFrames) { while (outFrames < numFrames) {
t.buffer.frameCount = outFrames; t.buffer.frameCount = numFrames - outFrames;
t.bufferProvider->getNextBuffer(&t.buffer); t.bufferProvider->getNextBuffer(&t.buffer);
t.in = t.buffer.raw; t.in = t.buffer.raw;
// t.in == NULL can happen if the track was flushed just after having // t.in == NULL can happen if the track was flushed just after having
// been enabled for mixing. // been enabled for mixing.
if (t.in == NULL) break; if (t.in == NULL) break;
(t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp); if UNLIKELY(aux != NULL) {
outFrames -= t.buffer.frameCount; 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); t.bufferProvider->releaseBuffer(&t.buffer);
} }
} }
} }
ditherAndClamp(out, outTemp, numFrames); ditherAndClamp(out, outTemp, numFrames);
} }
}
// one track, 16 bits stereo without resampling is the most common case // 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 int i = 31 - __builtin_clz(state->enabledTracks);
const track_t& t = state->tracks[i]; const track_t& t = state->tracks[i];
AudioBufferProvider::Buffer& b(t.buffer); AudioBufferProvider::Buffer& b(t.buffer);
int32_t* out = static_cast<int32_t*>(output); int32_t* out = t.mainBuffer;
size_t numFrames = state->frameCount; size_t numFrames = state->frameCount;
const int16_t vl = t.volume[0]; const int16_t vl = t.volume[0];
@@ -816,7 +1093,9 @@ void AudioMixer::process__OneTrack16BitsStereoNoResampling(state_t* state, void*
} }
// 2 tracks is also a common case // 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; int i;
uint32_t en = state->enabledTracks; uint32_t en = state->enabledTracks;
@@ -840,7 +1119,8 @@ void AudioMixer::process__TwoTracks16BitsStereoNoResampling(state_t* state, void
const int16_t vr1 = t1.volume[1]; const int16_t vr1 = t1.volume[1];
size_t frameCount1 = 0; 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; size_t numFrames = state->frameCount;
int16_t const *buff = NULL; int16_t const *buff = NULL;

View File

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

View File

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

View File

@@ -292,7 +292,7 @@ typedef struct reverb_module_s {
* Effect API * Effect API
*------------------------------------ *------------------------------------
*/ */
int EffectQueryNumberEffects(int *pNumEffects); int EffectQueryNumberEffects(uint32_t *pNumEffects);
int EffectQueryNext(effect_descriptor_t *pDescriptor); int EffectQueryNext(effect_descriptor_t *pDescriptor);
int EffectCreate(effect_uuid_t *effectUID, effect_interface_t *pInterface); int EffectCreate(effect_uuid_t *effectUID, effect_interface_t *pInterface);
int EffectRelease(effect_interface_t interface); 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 init();
static int loadLibrary(const char *libPath, int *handle); static int loadLibrary(const char *libPath, int *handle);
static int unloadLibrary(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 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); 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 // Effect Factory Interface functions
///////////////////////////////////////////////// /////////////////////////////////////////////////
int EffectQueryNumberEffects(int *pNumEffects) int EffectQueryNumberEffects(uint32_t *pNumEffects)
{ {
int ret = init(); int ret = init();
if (ret < 0) { if (ret < 0) {
@@ -353,8 +353,8 @@ int loadLibrary(const char *libPath, int *handle)
effect_QueryNextEffect_t queryFx; effect_QueryNextEffect_t queryFx;
effect_CreateEffect_t createFx; effect_CreateEffect_t createFx;
effect_ReleaseEffect_t releaseFx; effect_ReleaseEffect_t releaseFx;
int numFx; uint32_t numFx;
int fx; uint32_t fx;
int ret; int ret;
list_elem_t *e, *descHead = NULL; list_elem_t *e, *descHead = NULL;
lib_entry_t *l; lib_entry_t *l;
@@ -525,9 +525,9 @@ int unloadLibrary(int handle)
int numEffectModules() { uint32_t numEffectModules() {
list_elem_t *e = gLibraryList; list_elem_t *e = gLibraryList;
int cnt = 0; uint32_t cnt = 0;
// Reset pointers for EffectQueryNext() // Reset pointers for EffectQueryNext()
gCurLib = e; gCurLib = e;

View File

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

View File

@@ -58,7 +58,8 @@ AudioTrack::AudioTrack(
uint32_t flags, uint32_t flags,
callback_t cbf, callback_t cbf,
void* user, void* user,
int notificationFrames) int notificationFrames,
int sessionId)
: mStatus(NO_INIT) : mStatus(NO_INIT)
{ {
mStatus = set(streamType, sampleRate, format, channels, mStatus = set(streamType, sampleRate, format, channels,
@@ -74,7 +75,8 @@ AudioTrack::AudioTrack(
uint32_t flags, uint32_t flags,
callback_t cbf, callback_t cbf,
void* user, void* user,
int notificationFrames) int notificationFrames,
int sessionId)
: mStatus(NO_INIT) : mStatus(NO_INIT)
{ {
mStatus = set(streamType, sampleRate, format, channels, mStatus = set(streamType, sampleRate, format, channels,
@@ -110,7 +112,8 @@ status_t AudioTrack::set(
void* user, void* user,
int notificationFrames, int notificationFrames,
const sp<IMemory>& sharedBuffer, const sp<IMemory>& sharedBuffer,
bool threadCanCallJava) bool threadCanCallJava,
int sessionId)
{ {
LOGV_IF(sharedBuffer != 0, "sharedBuffer: %p, size: %d", sharedBuffer->pointer(), sharedBuffer->size()); 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[LEFT] = 1.0f;
mVolume[RIGHT] = 1.0f; mVolume[RIGHT] = 1.0f;
mSendLevel = 0;
mFrameCount = frameCount; mFrameCount = frameCount;
mNotificationFramesReq = notificationFrames; mNotificationFramesReq = notificationFrames;
mSessionId = sessionId;
// create the IAudioTrack // create the IAudioTrack
status_t status = createTrack(streamType, sampleRate, format, channelCount, status_t status = createTrack(streamType, sampleRate, format, channelCount,
frameCount, flags, sharedBuffer, output, true); frameCount, flags, sharedBuffer, output, true);
@@ -396,20 +402,50 @@ bool AudioTrack::muted() const
return mMuted; 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[LEFT] = left;
mVolume[RIGHT] = right; mVolume[RIGHT] = right;
// write must be atomic // 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) void AudioTrack::getVolume(float* left, float* right)
{ {
if (left != NULL) {
*left = mVolume[LEFT]; *left = mVolume[LEFT];
}
if (right != NULL) {
*right = mVolume[RIGHT]; *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) status_t AudioTrack::setSampleRate(int rate)
{ {
@@ -563,6 +599,16 @@ audio_io_handle_t AudioTrack::getOutput()
mCblk->sampleRate, mFormat, mChannels, (AudioSystem::output_flags)mFlags); 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( status_t AudioTrack::createTrack(
@@ -647,6 +693,7 @@ status_t AudioTrack::createTrack(
((uint16_t)flags) << 16, ((uint16_t)flags) << 16,
sharedBuffer, sharedBuffer,
output, output,
&mSessionId,
&status); &status);
if (track == 0) { if (track == 0) {
@@ -672,7 +719,8 @@ status_t AudioTrack::createTrack(
mCblk->stepUser(mCblk->frameCount); 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->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0; mCblk->waitTimeMs = 0;
mRemainingFrames = mNotificationFramesAct; mRemainingFrames = mNotificationFramesAct;
@@ -1016,7 +1064,7 @@ audio_track_cblk_t::audio_track_cblk_t()
: lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0),
userBase(0), serverBase(0), buffers(0), frameCount(0), userBase(0), serverBase(0), buffers(0), frameCount(0),
loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(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_STREAM_OUTPUT,
SET_VOICE_VOLUME, SET_VOICE_VOLUME,
GET_RENDER_POSITION, 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> class BpAudioFlinger : public BpInterface<IAudioFlinger>
@@ -83,6 +90,7 @@ public:
uint32_t flags, uint32_t flags,
const sp<IMemory>& sharedBuffer, const sp<IMemory>& sharedBuffer,
int output, int output,
int *sessionId,
status_t *status) status_t *status)
{ {
Parcel data, reply; Parcel data, reply;
@@ -97,10 +105,19 @@ public:
data.writeInt32(flags); data.writeInt32(flags);
data.writeStrongBinder(sharedBuffer->asBinder()); data.writeStrongBinder(sharedBuffer->asBinder());
data.writeInt32(output); data.writeInt32(output);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
data.writeInt32(lSessionId);
status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply); status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
if (lStatus != NO_ERROR) { if (lStatus != NO_ERROR) {
LOGE("createTrack error: %s", strerror(-lStatus)); LOGE("createTrack error: %s", strerror(-lStatus));
} else { } else {
lSessionId = reply.readInt32();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
lStatus = reply.readInt32(); lStatus = reply.readInt32();
track = interface_cast<IAudioTrack>(reply.readStrongBinder()); track = interface_cast<IAudioTrack>(reply.readStrongBinder());
} }
@@ -118,6 +135,7 @@ public:
int channelCount, int channelCount,
int frameCount, int frameCount,
uint32_t flags, uint32_t flags,
int *sessionId,
status_t *status) status_t *status)
{ {
Parcel data, reply; Parcel data, reply;
@@ -130,10 +148,19 @@ public:
data.writeInt32(channelCount); data.writeInt32(channelCount);
data.writeInt32(frameCount); data.writeInt32(frameCount);
data.writeInt32(flags); data.writeInt32(flags);
int lSessionId = 0;
if (sessionId != NULL) {
lSessionId = *sessionId;
}
data.writeInt32(lSessionId);
status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply); status_t lStatus = remote()->transact(OPEN_RECORD, data, &reply);
if (lStatus != NO_ERROR) { if (lStatus != NO_ERROR) {
LOGE("openRecord error: %s", strerror(-lStatus)); LOGE("openRecord error: %s", strerror(-lStatus));
} else { } else {
lSessionId = reply.readInt32();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
lStatus = reply.readInt32(); lStatus = reply.readInt32();
record = interface_cast<IAudioRecord>(reply.readStrongBinder()); record = interface_cast<IAudioRecord>(reply.readStrongBinder());
} }
@@ -497,6 +524,157 @@ public:
remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply); remote()->transact(GET_INPUT_FRAMES_LOST, data, &reply);
return reply.readInt32(); 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"); IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");
@@ -518,10 +696,12 @@ status_t BnAudioFlinger::onTransact(
uint32_t flags = data.readInt32(); uint32_t flags = data.readInt32();
sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder()); sp<IMemory> buffer = interface_cast<IMemory>(data.readStrongBinder());
int output = data.readInt32(); int output = data.readInt32();
int sessionId = data.readInt32();
status_t status; status_t status;
sp<IAudioTrack> track = createTrack(pid, sp<IAudioTrack> track = createTrack(pid,
streamType, sampleRate, format, streamType, sampleRate, format,
channelCount, bufferCount, flags, buffer, output, &status); channelCount, bufferCount, flags, buffer, output, &sessionId, &status);
reply->writeInt32(sessionId);
reply->writeInt32(status); reply->writeInt32(status);
reply->writeStrongBinder(track->asBinder()); reply->writeStrongBinder(track->asBinder());
return NO_ERROR; return NO_ERROR;
@@ -535,9 +715,11 @@ status_t BnAudioFlinger::onTransact(
int channelCount = data.readInt32(); int channelCount = data.readInt32();
size_t bufferCount = data.readInt32(); size_t bufferCount = data.readInt32();
uint32_t flags = data.readInt32(); uint32_t flags = data.readInt32();
int sessionId = data.readInt32();
status_t status; status_t status;
sp<IAudioRecord> record = openRecord(pid, input, 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->writeInt32(status);
reply->writeStrongBinder(record->asBinder()); reply->writeStrongBinder(record->asBinder());
return NO_ERROR; return NO_ERROR;
@@ -768,7 +950,79 @@ status_t BnAudioFlinger::onTransact(
reply->writeInt32(getInputFramesLost(ioHandle)); reply->writeInt32(getInputFramesLost(ioHandle));
return NO_ERROR; return NO_ERROR;
} break; } 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: default:
return BBinder::onTransact(code, data, reply, flags); return BBinder::onTransact(code, data, reply, flags);
} }

View File

@@ -34,7 +34,8 @@ enum {
STOP, STOP,
FLUSH, FLUSH,
MUTE, MUTE,
PAUSE PAUSE,
ATTACH_AUX_EFFECT
}; };
class BpAudioTrack : public BpInterface<IAudioTrack> class BpAudioTrack : public BpInterface<IAudioTrack>
@@ -98,6 +99,20 @@ public:
} }
return cblk; 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"); IMPLEMENT_META_INTERFACE(AudioTrack, "android.media.IAudioTrack");
@@ -138,6 +153,11 @@ status_t BnAudioTrack::onTransact(
pause(); pause();
return NO_ERROR; return NO_ERROR;
} }
case ATTACH_AUX_EFFECT: {
CHECK_INTERFACE(IAudioTrack, data, reply);
reply->writeInt32(attachAuxEffect(data.readInt32()));
return NO_ERROR;
} break;
default: default:
return BBinder::onTransact(code, data, reply, flags); return BBinder::onTransact(code, data, reply, flags);
} }