Merge "Issue 2667801: [Audio Effect Framework] AudioFlinger, AudioMixer AudioTrack modifications." into kraken
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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.
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -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.
|
||||||
//
|
//
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
51
include/private/media/AudioEffectShared.h
Normal file
51
include/private/media/AudioEffectShared.h
Normal 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
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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,30 +539,44 @@ int32_t mulRL(int left, uint32_t inRL, uint32_t vRL)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp)
|
void AudioMixer::track__genericResample(track_t* t, int32_t* out, size_t outFrameCount, int32_t* temp, int32_t* aux)
|
||||||
{
|
{
|
||||||
t->resampler->setSampleRate(t->sampleRate);
|
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 UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
|
if (aux != NULL) {
|
||||||
|
// always resample with unity gain when sending to auxiliary buffer to be able
|
||||||
|
// to apply send level after resampling
|
||||||
|
// TODO: modify each resampler to support aux channel?
|
||||||
t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
|
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);
|
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
|
||||||
}
|
volumeRampStereo(t, out, outFrameCount, temp, aux);
|
||||||
|
} else {
|
||||||
|
volumeStereo(t, out, outFrameCount, temp, aux);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
|
||||||
|
t->resampler->setVolume(UNITY_GAIN, UNITY_GAIN);
|
||||||
|
memset(temp, 0, outFrameCount * MAX_NUM_CHANNELS * sizeof(int32_t));
|
||||||
|
t->resampler->resample(temp, outFrameCount, t->bufferProvider);
|
||||||
|
volumeRampStereo(t, out, outFrameCount, temp, aux);
|
||||||
|
}
|
||||||
|
|
||||||
// constant gain
|
// constant gain
|
||||||
else {
|
else {
|
||||||
t->resampler->setVolume(t->volume[0], t->volume[1]);
|
t->resampler->setVolume(t->volume[0], t->volume[1]);
|
||||||
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,96 +588,236 @@ 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
|
||||||
do {
|
if UNLIKELY(aux != NULL) {
|
||||||
*out++ += (vl >> 16) * (*temp++ >> 12);
|
int32_t va = t->prevAuxLevel;
|
||||||
*out++ += (vr >> 16) * (*temp++ >> 12);
|
const int32_t vaInc = t->auxInc;
|
||||||
vl += vlInc;
|
int32_t l;
|
||||||
vr += vrInc;
|
int32_t r;
|
||||||
} while (--frameCount);
|
|
||||||
|
|
||||||
t->prevVolume[0] = vl;
|
|
||||||
t->prevVolume[1] = vr;
|
|
||||||
t->adjustVolumeRamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp)
|
|
||||||
{
|
|
||||||
int16_t const *in = static_cast<int16_t const *>(t->in);
|
|
||||||
|
|
||||||
// ramp gain
|
|
||||||
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
|
|
||||||
int32_t vl = t->prevVolume[0];
|
|
||||||
int32_t vr = t->prevVolume[1];
|
|
||||||
const int32_t vlInc = t->volumeInc[0];
|
|
||||||
const int32_t vrInc = t->volumeInc[1];
|
|
||||||
|
|
||||||
// LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
|
|
||||||
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
|
|
||||||
// (vl + vlInc*frameCount)/65536.0f, frameCount);
|
|
||||||
|
|
||||||
do {
|
do {
|
||||||
*out++ += (vl >> 16) * (int32_t) *in++;
|
l = (*temp++ >> 12);
|
||||||
*out++ += (vr >> 16) * (int32_t) *in++;
|
r = (*temp++ >> 12);
|
||||||
|
*out++ += (vl >> 16) * l;
|
||||||
|
*out++ += (vr >> 16) * r;
|
||||||
|
*aux++ += (va >> 17) * (l + r);
|
||||||
|
vl += vlInc;
|
||||||
|
vr += vrInc;
|
||||||
|
va += vaInc;
|
||||||
|
} while (--frameCount);
|
||||||
|
t->prevAuxLevel = va;
|
||||||
|
} else {
|
||||||
|
do {
|
||||||
|
*out++ += (vl >> 16) * (*temp++ >> 12);
|
||||||
|
*out++ += (vr >> 16) * (*temp++ >> 12);
|
||||||
vl += vlInc;
|
vl += vlInc;
|
||||||
vr += vrInc;
|
vr += vrInc;
|
||||||
} while (--frameCount);
|
} while (--frameCount);
|
||||||
|
|
||||||
t->prevVolume[0] = vl;
|
|
||||||
t->prevVolume[1] = vr;
|
|
||||||
t->adjustVolumeRamp();
|
|
||||||
}
|
}
|
||||||
|
t->prevVolume[0] = vl;
|
||||||
|
t->prevVolume[1] = vr;
|
||||||
|
t->adjustVolumeRamp((aux != NULL));
|
||||||
|
}
|
||||||
|
|
||||||
// constant gain
|
void AudioMixer::volumeStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
|
||||||
else {
|
{
|
||||||
const uint32_t vrl = t->volumeRL;
|
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 {
|
do {
|
||||||
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
|
int16_t l = (int16_t)(*temp++ >> 12);
|
||||||
in += 2;
|
int16_t r = (int16_t)(*temp++ >> 12);
|
||||||
out[0] = mulAddRL(1, rl, vrl, out[0]);
|
out[0] = mulAdd(l, vl, out[0]);
|
||||||
out[1] = mulAddRL(0, rl, vrl, out[1]);
|
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;
|
out += 2;
|
||||||
} while (--frameCount);
|
} while (--frameCount);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioMixer::track__16BitsStereo(track_t* t, int32_t* out, size_t frameCount, int32_t* temp, int32_t* aux)
|
||||||
|
{
|
||||||
|
int16_t const *in = static_cast<int16_t const *>(t->in);
|
||||||
|
|
||||||
|
if UNLIKELY(aux != NULL) {
|
||||||
|
int32_t l;
|
||||||
|
int32_t r;
|
||||||
|
// ramp gain
|
||||||
|
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
|
||||||
|
int32_t vl = t->prevVolume[0];
|
||||||
|
int32_t vr = t->prevVolume[1];
|
||||||
|
int32_t va = t->prevAuxLevel;
|
||||||
|
const int32_t vlInc = t->volumeInc[0];
|
||||||
|
const int32_t vrInc = t->volumeInc[1];
|
||||||
|
const int32_t vaInc = t->auxInc;
|
||||||
|
// LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
|
||||||
|
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
|
||||||
|
// (vl + vlInc*frameCount)/65536.0f, frameCount);
|
||||||
|
|
||||||
|
do {
|
||||||
|
l = (int32_t)*in++;
|
||||||
|
r = (int32_t)*in++;
|
||||||
|
*out++ += (vl >> 16) * l;
|
||||||
|
*out++ += (vr >> 16) * r;
|
||||||
|
*aux++ += (va >> 17) * (l + r);
|
||||||
|
vl += vlInc;
|
||||||
|
vr += vrInc;
|
||||||
|
va += vaInc;
|
||||||
|
} while (--frameCount);
|
||||||
|
|
||||||
|
t->prevVolume[0] = vl;
|
||||||
|
t->prevVolume[1] = vr;
|
||||||
|
t->prevAuxLevel = va;
|
||||||
|
t->adjustVolumeRamp(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// constant gain
|
||||||
|
else {
|
||||||
|
const uint32_t vrl = t->volumeRL;
|
||||||
|
const int16_t va = (int16_t)t->auxLevel;
|
||||||
|
do {
|
||||||
|
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
|
||||||
|
int16_t a = (int16_t)(((int32_t)in[0] + in[1]) >> 1);
|
||||||
|
in += 2;
|
||||||
|
out[0] = mulAddRL(1, rl, vrl, out[0]);
|
||||||
|
out[1] = mulAddRL(0, rl, vrl, out[1]);
|
||||||
|
out += 2;
|
||||||
|
aux[0] = mulAdd(a, va, aux[0]);
|
||||||
|
aux++;
|
||||||
|
} while (--frameCount);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ramp gain
|
||||||
|
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
|
||||||
|
int32_t vl = t->prevVolume[0];
|
||||||
|
int32_t vr = t->prevVolume[1];
|
||||||
|
const int32_t vlInc = t->volumeInc[0];
|
||||||
|
const int32_t vrInc = t->volumeInc[1];
|
||||||
|
|
||||||
|
// LOGD("[1] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
|
||||||
|
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
|
||||||
|
// (vl + vlInc*frameCount)/65536.0f, frameCount);
|
||||||
|
|
||||||
|
do {
|
||||||
|
*out++ += (vl >> 16) * (int32_t) *in++;
|
||||||
|
*out++ += (vr >> 16) * (int32_t) *in++;
|
||||||
|
vl += vlInc;
|
||||||
|
vr += vrInc;
|
||||||
|
} while (--frameCount);
|
||||||
|
|
||||||
|
t->prevVolume[0] = vl;
|
||||||
|
t->prevVolume[1] = vr;
|
||||||
|
t->adjustVolumeRamp(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// constant gain
|
||||||
|
else {
|
||||||
|
const uint32_t vrl = t->volumeRL;
|
||||||
|
do {
|
||||||
|
uint32_t rl = *reinterpret_cast<uint32_t const *>(in);
|
||||||
|
in += 2;
|
||||||
|
out[0] = mulAddRL(1, rl, vrl, out[0]);
|
||||||
|
out[1] = mulAddRL(0, rl, vrl, out[1]);
|
||||||
|
out += 2;
|
||||||
|
} while (--frameCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
t->in = in;
|
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);
|
||||||
|
|
||||||
// ramp gain
|
if UNLIKELY(aux != NULL) {
|
||||||
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
|
// ramp gain
|
||||||
int32_t vl = t->prevVolume[0];
|
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]|t->auxInc) {
|
||||||
int32_t vr = t->prevVolume[1];
|
int32_t vl = t->prevVolume[0];
|
||||||
const int32_t vlInc = t->volumeInc[0];
|
int32_t vr = t->prevVolume[1];
|
||||||
const int32_t vrInc = t->volumeInc[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",
|
// LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
|
||||||
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
|
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
|
||||||
// (vl + vlInc*frameCount)/65536.0f, frameCount);
|
// (vl + vlInc*frameCount)/65536.0f, frameCount);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
int32_t l = *in++;
|
int32_t l = *in++;
|
||||||
*out++ += (vl >> 16) * l;
|
*out++ += (vl >> 16) * l;
|
||||||
*out++ += (vr >> 16) * l;
|
*out++ += (vr >> 16) * l;
|
||||||
vl += vlInc;
|
*aux++ += (va >> 16) * l;
|
||||||
vr += vrInc;
|
vl += vlInc;
|
||||||
} while (--frameCount);
|
vr += vrInc;
|
||||||
|
va += vaInc;
|
||||||
|
} while (--frameCount);
|
||||||
|
|
||||||
t->prevVolume[0] = vl;
|
t->prevVolume[0] = vl;
|
||||||
t->prevVolume[1] = vr;
|
t->prevVolume[1] = vr;
|
||||||
t->adjustVolumeRamp();
|
t->prevAuxLevel = va;
|
||||||
}
|
t->adjustVolumeRamp(true);
|
||||||
// constant gain
|
}
|
||||||
else {
|
// constant gain
|
||||||
const int16_t vl = t->volume[0];
|
else {
|
||||||
const int16_t vr = t->volume[1];
|
const int16_t vl = t->volume[0];
|
||||||
do {
|
const int16_t vr = t->volume[1];
|
||||||
int16_t l = *in++;
|
const int16_t va = (int16_t)t->auxLevel;
|
||||||
out[0] = mulAdd(l, vl, out[0]);
|
do {
|
||||||
out[1] = mulAdd(l, vr, out[1]);
|
int16_t l = *in++;
|
||||||
out += 2;
|
out[0] = mulAdd(l, vl, out[0]);
|
||||||
} while (--frameCount);
|
out[1] = mulAdd(l, vr, out[1]);
|
||||||
|
out += 2;
|
||||||
|
aux[0] = mulAdd(l, va, aux[0]);
|
||||||
|
aux++;
|
||||||
|
} while (--frameCount);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// ramp gain
|
||||||
|
if UNLIKELY(t->volumeInc[0]|t->volumeInc[1]) {
|
||||||
|
int32_t vl = t->prevVolume[0];
|
||||||
|
int32_t vr = t->prevVolume[1];
|
||||||
|
const int32_t vlInc = t->volumeInc[0];
|
||||||
|
const int32_t vrInc = t->volumeInc[1];
|
||||||
|
|
||||||
|
// LOGD("[2] %p: inc=%f, v0=%f, v1=%d, final=%f, count=%d",
|
||||||
|
// t, vlInc/65536.0f, vl/65536.0f, t->volume[0],
|
||||||
|
// (vl + vlInc*frameCount)/65536.0f, frameCount);
|
||||||
|
|
||||||
|
do {
|
||||||
|
int32_t l = *in++;
|
||||||
|
*out++ += (vl >> 16) * l;
|
||||||
|
*out++ += (vr >> 16) * l;
|
||||||
|
vl += vlInc;
|
||||||
|
vr += vrInc;
|
||||||
|
} while (--frameCount);
|
||||||
|
|
||||||
|
t->prevVolume[0] = vl;
|
||||||
|
t->prevVolume[1] = vr;
|
||||||
|
t->adjustVolumeRamp(false);
|
||||||
|
}
|
||||||
|
// constant gain
|
||||||
|
else {
|
||||||
|
const int16_t vl = t->volume[0];
|
||||||
|
const int16_t vr = t->volume[1];
|
||||||
|
do {
|
||||||
|
int16_t l = *in++;
|
||||||
|
out[0] = mulAdd(l, vl, out[0]);
|
||||||
|
out[1] = mulAdd(l, vr, out[1]);
|
||||||
|
out += 2;
|
||||||
|
} while (--frameCount);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
t->in = in;
|
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);
|
||||||
size_t outFrames = state->frameCount;
|
track_t& t1 = state->tracks[i];
|
||||||
while (outFrames) {
|
e2 &= ~(1<<i);
|
||||||
t.buffer.frameCount = outFrames;
|
while (e2) {
|
||||||
t.bufferProvider->getNextBuffer(&t.buffer);
|
i = 31 - __builtin_clz(e2);
|
||||||
if (!t.buffer.raw) break;
|
e2 &= ~(1<<i);
|
||||||
outFrames -= t.buffer.frameCount;
|
track_t& t2 = state->tracks[i];
|
||||||
t.bufferProvider->releaseBuffer(&t.buffer);
|
if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
|
||||||
|
e1 &= ~(1<<i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e0 &= ~(e1);
|
||||||
|
|
||||||
|
memset(t1.mainBuffer, 0, bufSize);
|
||||||
|
|
||||||
|
while (e1) {
|
||||||
|
i = 31 - __builtin_clz(e1);
|
||||||
|
e1 &= ~(1<<i);
|
||||||
|
t1 = state->tracks[i];
|
||||||
|
size_t outFrames = state->frameCount;
|
||||||
|
while (outFrames) {
|
||||||
|
t1.buffer.frameCount = outFrames;
|
||||||
|
t1.bufferProvider->getNextBuffer(&t1.buffer);
|
||||||
|
if (!t1.buffer.raw) break;
|
||||||
|
outFrames -= t1.buffer.frameCount;
|
||||||
|
t1.bufferProvider->releaseBuffer(&t1.buffer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// generic code without resampling
|
// 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// this assumes output 16 bits stereo, no resampling
|
e0 = enabledTracks;
|
||||||
int32_t* out = static_cast<int32_t*>(output);
|
while (e0) {
|
||||||
size_t numFrames = state->frameCount;
|
// process by group of tracks with same output buffer to
|
||||||
do {
|
// optimize cache use
|
||||||
memset(outTemp, 0, sizeof(outTemp));
|
uint32_t e1 = e0, e2 = e0;
|
||||||
|
int j = 31 - __builtin_clz(e1);
|
||||||
en = enabledTracks;
|
track_t& t1 = state->tracks[j];
|
||||||
while (en) {
|
e2 &= ~(1<<j);
|
||||||
const int i = 31 - __builtin_clz(en);
|
while (e2) {
|
||||||
en &= ~(1<<i);
|
j = 31 - __builtin_clz(e2);
|
||||||
track_t& t = state->tracks[i];
|
e2 &= ~(1<<j);
|
||||||
size_t outFrames = BLOCKSIZE;
|
track_t& t2 = state->tracks[j];
|
||||||
|
if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
|
||||||
while (outFrames) {
|
e1 &= ~(1<<j);
|
||||||
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
|
|
||||||
if (inFrames) {
|
|
||||||
(t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp);
|
|
||||||
t.frameCount -= inFrames;
|
|
||||||
outFrames -= inFrames;
|
|
||||||
}
|
|
||||||
if (t.frameCount == 0 && outFrames) {
|
|
||||||
t.bufferProvider->releaseBuffer(&t.buffer);
|
|
||||||
t.buffer.frameCount = numFrames - (BLOCKSIZE - outFrames);
|
|
||||||
t.bufferProvider->getNextBuffer(&t.buffer);
|
|
||||||
t.in = t.buffer.raw;
|
|
||||||
if (t.in == NULL) {
|
|
||||||
enabledTracks &= ~(1<<i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
t.frameCount = t.buffer.frameCount;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
e0 &= ~(e1);
|
||||||
ditherAndClamp(out, outTemp, BLOCKSIZE);
|
// this assumes output 16 bits stereo, no resampling
|
||||||
out += BLOCKSIZE;
|
int32_t *out = t1.mainBuffer;
|
||||||
numFrames -= BLOCKSIZE;
|
size_t numFrames = 0;
|
||||||
} while (numFrames);
|
do {
|
||||||
|
memset(outTemp, 0, sizeof(outTemp));
|
||||||
|
e2 = e1;
|
||||||
|
while (e2) {
|
||||||
|
const int i = 31 - __builtin_clz(e2);
|
||||||
|
e2 &= ~(1<<i);
|
||||||
|
track_t& t = state->tracks[i];
|
||||||
|
size_t outFrames = BLOCKSIZE;
|
||||||
|
int32_t *aux = NULL;
|
||||||
|
if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
|
||||||
|
aux = t.auxBuffer + numFrames;
|
||||||
|
}
|
||||||
|
while (outFrames) {
|
||||||
|
size_t inFrames = (t.frameCount > outFrames)?outFrames:t.frameCount;
|
||||||
|
if (inFrames) {
|
||||||
|
(t.hook)(&t, outTemp + (BLOCKSIZE-outFrames)*MAX_NUM_CHANNELS, inFrames, state->resampleTemp, aux);
|
||||||
|
t.frameCount -= inFrames;
|
||||||
|
outFrames -= inFrames;
|
||||||
|
if UNLIKELY(aux != NULL) {
|
||||||
|
aux += inFrames;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (t.frameCount == 0 && outFrames) {
|
||||||
|
t.bufferProvider->releaseBuffer(&t.buffer);
|
||||||
|
t.buffer.frameCount = (state->frameCount - numFrames) - (BLOCKSIZE - outFrames);
|
||||||
|
t.bufferProvider->getNextBuffer(&t.buffer);
|
||||||
|
t.in = t.buffer.raw;
|
||||||
|
if (t.in == NULL) {
|
||||||
|
enabledTracks &= ~(1<<i);
|
||||||
|
e1 &= ~(1<<i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t.frameCount = t.buffer.frameCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ditherAndClamp(out, outTemp, BLOCKSIZE);
|
||||||
|
out += BLOCKSIZE;
|
||||||
|
numFrames += BLOCKSIZE;
|
||||||
|
} while (numFrames < state->frameCount);
|
||||||
|
}
|
||||||
|
|
||||||
// release each track's buffer
|
// 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
|
|
||||||
void AudioMixer::process__genericResampling(state_t* state, void* output)
|
// generic code with resampling
|
||||||
|
void AudioMixer::process__genericResampling(state_t* state)
|
||||||
{
|
{
|
||||||
int32_t* const outTemp = state->outputTemp;
|
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
|
||||||
track_t& t = state->tracks[i];
|
uint32_t e1 = e0, e2 = e0;
|
||||||
|
int j = 31 - __builtin_clz(e1);
|
||||||
// this is a little goofy, on the resampling case we don't
|
track_t& t1 = state->tracks[j];
|
||||||
// acquire/release the buffers because it's done by
|
e2 &= ~(1<<j);
|
||||||
// the resampler.
|
while (e2) {
|
||||||
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
|
j = 31 - __builtin_clz(e2);
|
||||||
(t.hook)(&t, outTemp, numFrames, state->resampleTemp);
|
e2 &= ~(1<<j);
|
||||||
} else {
|
track_t& t2 = state->tracks[j];
|
||||||
|
if UNLIKELY(t2.mainBuffer != t1.mainBuffer) {
|
||||||
size_t outFrames = numFrames;
|
e1 &= ~(1<<j);
|
||||||
|
|
||||||
while (outFrames) {
|
|
||||||
t.buffer.frameCount = outFrames;
|
|
||||||
t.bufferProvider->getNextBuffer(&t.buffer);
|
|
||||||
t.in = t.buffer.raw;
|
|
||||||
// t.in == NULL can happen if the track was flushed just after having
|
|
||||||
// been enabled for mixing.
|
|
||||||
if (t.in == NULL) break;
|
|
||||||
|
|
||||||
(t.hook)(&t, outTemp + (numFrames-outFrames)*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp);
|
|
||||||
outFrames -= t.buffer.frameCount;
|
|
||||||
t.bufferProvider->releaseBuffer(&t.buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
e0 &= ~(e1);
|
||||||
|
int32_t *out = t1.mainBuffer;
|
||||||
|
while (e1) {
|
||||||
|
const int i = 31 - __builtin_clz(e1);
|
||||||
|
e1 &= ~(1<<i);
|
||||||
|
track_t& t = state->tracks[i];
|
||||||
|
int32_t *aux = NULL;
|
||||||
|
if UNLIKELY((t.needs & NEEDS_AUX__MASK) == NEEDS_AUX_ENABLED) {
|
||||||
|
aux = t.auxBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
ditherAndClamp(out, outTemp, numFrames);
|
// this is a little goofy, on the resampling case we don't
|
||||||
|
// acquire/release the buffers because it's done by
|
||||||
|
// the resampler.
|
||||||
|
if ((t.needs & NEEDS_RESAMPLE__MASK) == NEEDS_RESAMPLE_ENABLED) {
|
||||||
|
(t.hook)(&t, outTemp, numFrames, state->resampleTemp, aux);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
size_t outFrames = 0;
|
||||||
|
|
||||||
|
while (outFrames < numFrames) {
|
||||||
|
t.buffer.frameCount = numFrames - outFrames;
|
||||||
|
t.bufferProvider->getNextBuffer(&t.buffer);
|
||||||
|
t.in = t.buffer.raw;
|
||||||
|
// t.in == NULL can happen if the track was flushed just after having
|
||||||
|
// been enabled for mixing.
|
||||||
|
if (t.in == NULL) break;
|
||||||
|
|
||||||
|
if UNLIKELY(aux != NULL) {
|
||||||
|
aux += outFrames;
|
||||||
|
}
|
||||||
|
(t.hook)(&t, outTemp + outFrames*MAX_NUM_CHANNELS, t.buffer.frameCount, state->resampleTemp, aux);
|
||||||
|
outFrames += t.buffer.frameCount;
|
||||||
|
t.bufferProvider->releaseBuffer(&t.buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ditherAndClamp(out, outTemp, numFrames);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// one track, 16 bits stereo without resampling is the most common case
|
// 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;
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
};
|
};
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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,19 +402,49 @@ 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)
|
||||||
{
|
{
|
||||||
*left = mVolume[LEFT];
|
if (left != NULL) {
|
||||||
*right = mVolume[RIGHT];
|
*left = mVolume[LEFT];
|
||||||
|
}
|
||||||
|
if (right != NULL) {
|
||||||
|
*right = mVolume[RIGHT];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t AudioTrack::setSendLevel(float level)
|
||||||
|
{
|
||||||
|
if (level > 1.0f) {
|
||||||
|
return BAD_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
mSendLevel = level;
|
||||||
|
|
||||||
|
mCblk->sendLevel = uint16_t(level * 0x1000);
|
||||||
|
|
||||||
|
return NO_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioTrack::getSendLevel(float* level)
|
||||||
|
{
|
||||||
|
if (level != NULL) {
|
||||||
|
*level = mSendLevel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t AudioTrack::setSampleRate(int rate)
|
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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user