summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Laurent <elaurent@google.com>2011-06-17 21:29:58 -0700
committerEric Laurent <elaurent@google.com>2011-07-18 09:42:57 -0700
commit7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745 (patch)
treeeb67cd14e679d97a9b866a0410d8e582f4639274
parent67a124dcac0578aed94aebf451675a5f4c8a1e4e (diff)
downloadframeworks_av-7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745.zip
frameworks_av-7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745.tar.gz
frameworks_av-7c7f10bd4fda9a084e5e7f0eb3a040dfcbf01745.tar.bz2
Audio framework: support for audio pre processing
Audio effect framework is extended to suport effects on output and input audio path. AudioFlinger: Support for audio effects and effect chains is moved from PlaybackThread class to ThreadBase class so that RecordThread can manage effects. Effects of type pre processing are allowed on record thread only. When a pre processing is enabled, the effect interface handle is passed down to the input stream so that the audio HAL can call the process function. The record thread loop calls the effect chain process function that will only manage the effect state and commands and skip the process function. AudioRecord: The audio session is allocated before calling getInput() into audio policy serice so that the session is known before the input theead is created and pre processings can be created on the correct session. AudioPolicyService: default pre processing for a given input source are loaded from audio_effects.conf file. When an input is created, corresponding effects are created and enabled. Change-Id: Id17119e0979b4dcf189b5c7957fec30dc3478790
-rw-r--r--include/media/AudioEffect.h8
-rw-r--r--include/media/AudioSystem.h5
-rw-r--r--include/media/IAudioPolicyService.h5
-rw-r--r--media/libeffects/data/audio_effects.conf69
-rw-r--r--media/libeffects/factory/Android.mk3
-rw-r--r--media/libeffects/factory/EffectsFactory.c1
-rw-r--r--media/libeffects/factory/EffectsFactory.h7
-rw-r--r--media/libmedia/AudioEffect.cpp14
-rw-r--r--media/libmedia/AudioRecord.cpp21
-rw-r--r--media/libmedia/AudioSystem.cpp13
-rw-r--r--media/libmedia/IAudioPolicyService.cpp16
-rw-r--r--services/audioflinger/AudioFlinger.cpp522
-rw-r--r--services/audioflinger/AudioFlinger.h157
-rw-r--r--services/audioflinger/AudioPolicyService.cpp396
-rw-r--r--services/audioflinger/AudioPolicyService.h62
15 files changed, 1048 insertions, 251 deletions
diff --git a/include/media/AudioEffect.h b/include/media/AudioEffect.h
index dd93fd8..496b23e 100644
--- a/include/media/AudioEffect.h
+++ b/include/media/AudioEffect.h
@@ -188,7 +188,7 @@ public:
* sessionID: audio session this effect is associated to. If 0, the effect will be global to
* the output mix. If not 0, the effect will be applied to all players
* (AudioTrack or MediaPLayer) within the same audio session.
- * output: HAL audio output stream to which this effect must be attached. Leave at 0 for
+ * io: HAL audio output or input stream to which this effect must be attached. Leave at 0 for
* automatic output selection by AudioFlinger.
*/
@@ -198,7 +198,7 @@ public:
effect_callback_t cbf = 0,
void* user = 0,
int sessionId = 0,
- audio_io_handle_t output = 0
+ audio_io_handle_t io = 0
);
/* Constructor.
@@ -210,7 +210,7 @@ public:
effect_callback_t cbf = 0,
void* user = 0,
int sessionId = 0,
- audio_io_handle_t output = 0
+ audio_io_handle_t io = 0
);
/* Terminates the AudioEffect and unregisters it from AudioFlinger.
@@ -232,7 +232,7 @@ public:
effect_callback_t cbf = 0,
void* user = 0,
int sessionId = 0,
- audio_io_handle_t output = 0
+ audio_io_handle_t io = 0
);
/* Result of constructing the AudioEffect. This must be checked
diff --git a/include/media/AudioSystem.h b/include/media/AudioSystem.h
index 89213b7..f20e234 100644
--- a/include/media/AudioSystem.h
+++ b/include/media/AudioSystem.h
@@ -160,7 +160,8 @@ public:
uint32_t samplingRate = 0,
uint32_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channels = AUDIO_CHANNEL_IN_MONO,
- audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0);
+ audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0,
+ int sessionId = 0);
static status_t startInput(audio_io_handle_t input);
static status_t stopInput(audio_io_handle_t input);
static void releaseInput(audio_io_handle_t input);
@@ -175,7 +176,7 @@ public:
static audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
static status_t registerEffect(effect_descriptor_t *desc,
- audio_io_handle_t output,
+ audio_io_handle_t io,
uint32_t strategy,
int session,
int id);
diff --git a/include/media/IAudioPolicyService.h b/include/media/IAudioPolicyService.h
index 0fc8dbf..86b9f85 100644
--- a/include/media/IAudioPolicyService.h
+++ b/include/media/IAudioPolicyService.h
@@ -65,7 +65,8 @@ public:
uint32_t samplingRate = 0,
uint32_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channels = 0,
- audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0) = 0;
+ audio_in_acoustics_t acoustics = (audio_in_acoustics_t)0,
+ int audioSession = 0) = 0;
virtual status_t startInput(audio_io_handle_t input) = 0;
virtual status_t stopInput(audio_io_handle_t input) = 0;
virtual void releaseInput(audio_io_handle_t input) = 0;
@@ -78,7 +79,7 @@ public:
virtual uint32_t getDevicesForStream(audio_stream_type_t stream) = 0;
virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc) = 0;
virtual status_t registerEffect(effect_descriptor_t *desc,
- audio_io_handle_t output,
+ audio_io_handle_t io,
uint32_t strategy,
int session,
int id) = 0;
diff --git a/media/libeffects/data/audio_effects.conf b/media/libeffects/data/audio_effects.conf
index e6a7b37..b8fa487 100644
--- a/media/libeffects/data/audio_effects.conf
+++ b/media/libeffects/data/audio_effects.conf
@@ -1,5 +1,10 @@
# List of effect libraries to load. Each library element must contain a "path" element
# giving the full path of the library .so file.
+# libraries {
+# <lib name> {
+# path <lib path>
+# }
+# }
libraries {
bundle {
path /system/lib/soundfx/libbundlewrapper.so
@@ -10,6 +15,9 @@ libraries {
visualizer {
path /system/lib/soundfx/libvisualizer.so
}
+ pre_processing {
+ path /system/lib/soundfx/libaudiopreprocessing.so
+ }
}
# list of effects to load. Each effect element must contain a "library" and a "uuid" element.
@@ -17,6 +25,16 @@ libraries {
# "libraries" element.
# The name of the effect element is indicative, only the value of the "uuid" element
# designates the effect.
+# The uuid is the implementation specific UUID as specified by the effect vendor. This is not the
+# generic effect type UUID.
+# effects {
+# <fx name> {
+# library <lib name>
+# uuid <effect uuid>
+# }
+# ...
+# }
+
effects {
bassboost {
library bundle
@@ -54,4 +72,55 @@ effects {
library visualizer
uuid d069d9e0-8329-11df-9168-0002a5d5c51b
}
+ agc {
+ library pre_processing
+ uuid aa8130e0-66fc-11e0-bad0-0002a5d5c51b
+ }
+ aec {
+ library pre_processing
+ uuid bb392ec0-8d4d-11e0-a896-0002a5d5c51b
+ }
+ ns {
+ library pre_processing
+ uuid c06c8400-8e06-11e0-9cb6-0002a5d5c51b
+ }
}
+# Audio preprocessor configurations.
+# The pre processor configuration consists in a list of elements each describing
+# pre processor settings for a given input source. Valid input source names are:
+# "mic", "camcorder", "voice_recognition", "voice_communication"
+# Each input source element contains a list of effects elements. The name of the effect
+# element must be the name of one of the effects in the "effects" list of the file.
+# Each effect element may optionally contain a list of parameters and their
+# default value to apply when the pre processor effect is created.
+# A parameter is defined by a "param" element and a "value" element. Each of these elements
+# consists in one or more elements specifying a type followed by a value.
+# The types defined are: "int", "short", "float", "bool" and "string"
+# When both "param" and "value" are a single int, a simple form is allowed where just
+# the param and value pair is present in the parameter description
+# pre_processing {
+# <input source name> {
+# <fx name> {
+# <param 1 name> {
+# param {
+# int|short|float|bool|string <value>
+# [ int|short|float|bool|string <value> ]
+# ...
+# }
+# value {
+# int|short|float|bool|string <value>
+# [ int|short|float|bool|string <value> ]
+# ...
+# }
+# }
+# <param 2 name > {<param> <value>}
+# ...
+# }
+# ...
+# }
+# ...
+# }
+
+#
+# TODO: add default audio pre processor configurations after debug and tuning phase
+#
diff --git a/media/libeffects/factory/Android.mk b/media/libeffects/factory/Android.mk
index 26265ae..2f2b974 100644
--- a/media/libeffects/factory/Android.mk
+++ b/media/libeffects/factory/Android.mk
@@ -14,4 +14,7 @@ LOCAL_MODULE:= libeffects
LOCAL_SHARED_LIBRARIES += libdl
+LOCAL_C_INCLUDES := \
+ system/media/audio_effects/include
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index a9689bc..d333510 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -24,6 +24,7 @@
#include <cutils/misc.h>
#include <cutils/config_utils.h>
+#include <audio_effects/audio_effects_conf.h>
static list_elem_t *gEffectList; // list of effect_entry_t: all currently created effects
static list_elem_t *gLibraryList; // list of lib_entry_t: all currently loaded libraries
diff --git a/media/libeffects/factory/EffectsFactory.h b/media/libeffects/factory/EffectsFactory.h
index fcc0dba..c1d4319 100644
--- a/media/libeffects/factory/EffectsFactory.h
+++ b/media/libeffects/factory/EffectsFactory.h
@@ -26,13 +26,6 @@
extern "C" {
#endif
-#define AUDIO_EFFECT_DEFAULT_CONFIG_FILE "/system/etc/audio_effects.conf"
-#define AUDIO_EFFECT_VENDOR_CONFIG_FILE "/vendor/etc/audio_effects.conf"
-#define EFFECTS_TAG "effects"
-#define LIBRARIES_TAG "libraries"
-#define PATH_TAG "path"
-#define LIBRARY_TAG "library"
-#define UUID_TAG "uuid"
typedef struct list_elem_s {
void *object;
diff --git a/media/libmedia/AudioEffect.cpp b/media/libmedia/AudioEffect.cpp
index 8d98900..3919551 100644
--- a/media/libmedia/AudioEffect.cpp
+++ b/media/libmedia/AudioEffect.cpp
@@ -47,11 +47,11 @@ AudioEffect::AudioEffect(const effect_uuid_t *type,
effect_callback_t cbf,
void* user,
int sessionId,
- audio_io_handle_t output
+ audio_io_handle_t io
)
: mStatus(NO_INIT)
{
- mStatus = set(type, uuid, priority, cbf, user, sessionId, output);
+ mStatus = set(type, uuid, priority, cbf, user, sessionId, io);
}
AudioEffect::AudioEffect(const char *typeStr,
@@ -60,7 +60,7 @@ AudioEffect::AudioEffect(const char *typeStr,
effect_callback_t cbf,
void* user,
int sessionId,
- audio_io_handle_t output
+ audio_io_handle_t io
)
: mStatus(NO_INIT)
{
@@ -83,7 +83,7 @@ AudioEffect::AudioEffect(const char *typeStr,
}
}
- mStatus = set(pType, pUuid, priority, cbf, user, sessionId, output);
+ mStatus = set(pType, pUuid, priority, cbf, user, sessionId, io);
}
status_t AudioEffect::set(const effect_uuid_t *type,
@@ -92,13 +92,13 @@ status_t AudioEffect::set(const effect_uuid_t *type,
effect_callback_t cbf,
void* user,
int sessionId,
- audio_io_handle_t output)
+ audio_io_handle_t io)
{
sp<IEffect> iEffect;
sp<IMemory> cblk;
int enabled;
- LOGV("set %p mUserData: %p", this, user);
+ LOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0);
if (mIEffect != 0) {
LOGW("Effect already in use");
@@ -135,7 +135,7 @@ status_t AudioEffect::set(const effect_uuid_t *type,
mIEffectClient = new EffectClient(this);
iEffect = audioFlinger->createEffect(getpid(), (effect_descriptor_t *)&mDescriptor,
- mIEffectClient, priority, output, mSessionId, &mStatus, &mId, &enabled);
+ mIEffectClient, priority, io, mSessionId, &mStatus, &mId, &enabled);
if (iEffect == 0 || (mStatus != NO_ERROR && mStatus != ALREADY_EXISTS)) {
LOGE("set(): AudioFlinger could not create effect, status: %d", mStatus);
diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp
index 4c4aad0..1ec596e 100644
--- a/media/libmedia/AudioRecord.cpp
+++ b/media/libmedia/AudioRecord.cpp
@@ -162,8 +162,19 @@ status_t AudioRecord::set(
int channelCount = popcount(channelMask);
+ if (sessionId == 0 ) {
+ mSessionId = AudioSystem::newAudioSessionId();
+ } else {
+ mSessionId = sessionId;
+ }
+ LOGV("set(): mSessionId %d", mSessionId);
+
audio_io_handle_t input = AudioSystem::getInput(inputSource,
- sampleRate, format, channelMask, (audio_in_acoustics_t)flags);
+ sampleRate,
+ format,
+ channelMask,
+ (audio_in_acoustics_t)flags,
+ mSessionId);
if (input == 0) {
LOGE("Could not get audio input for record source %d", inputSource);
return BAD_VALUE;
@@ -187,8 +198,6 @@ status_t AudioRecord::set(
notificationFrames = frameCount/2;
}
- mSessionId = sessionId;
-
// create the IAudioRecord
status = openRecord_l(sampleRate, format, channelMask,
frameCount, flags, input);
@@ -589,8 +598,10 @@ audio_io_handle_t AudioRecord::getInput_l()
{
mInput = AudioSystem::getInput(mInputSource,
mCblk->sampleRate,
- mFormat, mChannelMask,
- (audio_in_acoustics_t)mFlags);
+ mFormat,
+ mChannelMask,
+ (audio_in_acoustics_t)mFlags,
+ mSessionId);
return mInput;
}
diff --git a/media/libmedia/AudioSystem.cpp b/media/libmedia/AudioSystem.cpp
index 6cb3847..5009957 100644
--- a/media/libmedia/AudioSystem.cpp
+++ b/media/libmedia/AudioSystem.cpp
@@ -605,11 +605,12 @@ audio_io_handle_t AudioSystem::getInput(int inputSource,
uint32_t samplingRate,
uint32_t format,
uint32_t channels,
- audio_in_acoustics_t acoustics)
+ audio_in_acoustics_t acoustics,
+ int sessionId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return 0;
- return aps->getInput(inputSource, samplingRate, format, channels, acoustics);
+ return aps->getInput(inputSource, samplingRate, format, channels, acoustics, sessionId);
}
status_t AudioSystem::startInput(audio_io_handle_t input)
@@ -678,14 +679,14 @@ audio_io_handle_t AudioSystem::getOutputForEffect(effect_descriptor_t *desc)
}
status_t AudioSystem::registerEffect(effect_descriptor_t *desc,
- audio_io_handle_t output,
+ audio_io_handle_t io,
uint32_t strategy,
int session,
int id)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->registerEffect(desc, output, strategy, session, id);
+ return aps->registerEffect(desc, io, strategy, session, id);
}
status_t AudioSystem::unregisterEffect(int id)
@@ -695,9 +696,11 @@ status_t AudioSystem::unregisterEffect(int id)
return aps->unregisterEffect(id);
}
-status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs) {
+status_t AudioSystem::isStreamActive(int stream, bool* state, uint32_t inPastMs)
+{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
+ if (state == NULL) return BAD_VALUE;
*state = aps->isStreamActive(stream, inPastMs);
return NO_ERROR;
}
diff --git a/media/libmedia/IAudioPolicyService.cpp b/media/libmedia/IAudioPolicyService.cpp
index 9fbcee0..49d410f 100644
--- a/media/libmedia/IAudioPolicyService.cpp
+++ b/media/libmedia/IAudioPolicyService.cpp
@@ -184,7 +184,8 @@ public:
uint32_t samplingRate,
uint32_t format,
uint32_t channels,
- audio_in_acoustics_t acoustics)
+ audio_in_acoustics_t acoustics,
+ int audioSession)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
@@ -193,6 +194,7 @@ public:
data.writeInt32(static_cast <uint32_t>(format));
data.writeInt32(channels);
data.writeInt32(static_cast <uint32_t>(acoustics));
+ data.writeInt32(audioSession);
remote()->transact(GET_INPUT, data, &reply);
return static_cast <audio_io_handle_t> (reply.readInt32());
}
@@ -285,7 +287,7 @@ public:
}
virtual status_t registerEffect(effect_descriptor_t *desc,
- audio_io_handle_t output,
+ audio_io_handle_t io,
uint32_t strategy,
int session,
int id)
@@ -293,7 +295,7 @@ public:
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
data.write(desc, sizeof(effect_descriptor_t));
- data.writeInt32(output);
+ data.writeInt32(io);
data.writeInt32(strategy);
data.writeInt32(session);
data.writeInt32(id);
@@ -439,11 +441,13 @@ status_t BnAudioPolicyService::onTransact(
uint32_t channels = data.readInt32();
audio_in_acoustics_t acoustics =
static_cast <audio_in_acoustics_t>(data.readInt32());
+ int audioSession = data.readInt32();
audio_io_handle_t input = getInput(inputSource,
samplingRate,
format,
channels,
- acoustics);
+ acoustics,
+ audioSession);
reply->writeInt32(static_cast <int>(input));
return NO_ERROR;
} break;
@@ -528,12 +532,12 @@ status_t BnAudioPolicyService::onTransact(
CHECK_INTERFACE(IAudioPolicyService, data, reply);
effect_descriptor_t desc;
data.read(&desc, sizeof(effect_descriptor_t));
- audio_io_handle_t output = data.readInt32();
+ audio_io_handle_t io = data.readInt32();
uint32_t strategy = data.readInt32();
int session = data.readInt32();
int id = data.readInt32();
reply->writeInt32(static_cast <int32_t>(registerEffect(&desc,
- output,
+ io,
strategy,
session,
id)));
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 86d4cc3..482336b 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -81,6 +81,8 @@ static const int kDumpLockSleep = 20000;
static const nsecs_t kWarningThrottle = seconds(5);
+// RecordThread loop sleep time upon application overrun or audio HAL read error
+static const int kRecordThreadSleepUs = 5000;
// ----------------------------------------------------------------------------
@@ -417,7 +419,7 @@ sp<IAudioTrack> AudioFlinger::createTrack(
lSessionId = *sessionId;
} else {
// if no audio session id is provided, create one here
- lSessionId = nextUniqueId_l();
+ lSessionId = nextUniqueId();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
@@ -725,6 +727,15 @@ status_t AudioFlinger::setParameters(int ioHandle, const String8& keyValuePairs)
thread = checkPlaybackThread_l(ioHandle);
if (thread == NULL) {
thread = checkRecordThread_l(ioHandle);
+ } else if (thread.get() == primaryPlaybackThread_l()) {
+ // indicate output device change to all input threads for pre processing
+ AudioParameter param = AudioParameter(keyValuePairs);
+ int value;
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ mRecordThreads.valueAt(i)->setParameters(keyValuePairs);
+ }
+ }
}
}
if (thread != NULL) {
@@ -873,10 +884,10 @@ void AudioFlinger::removeClient_l(pid_t pid)
// ----------------------------------------------------------------------------
-AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id)
+AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, int id, uint32_t device)
: Thread(false),
mAudioFlinger(audioFlinger), mSampleRate(0), mFrameCount(0), mChannelCount(0),
- mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false)
+ mFrameSize(1), mFormat(0), mStandby(false), mId(id), mExiting(false), mDevice(device)
{
}
@@ -1032,14 +1043,15 @@ status_t AudioFlinger::ThreadBase::dumpBase(int fd, const Vector<String16>& args
return NO_ERROR;
}
-
// ----------------------------------------------------------------------------
-AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
- : ThreadBase(audioFlinger, id),
+AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinger,
+ AudioStreamOut* output,
+ int id,
+ uint32_t device)
+ : ThreadBase(audioFlinger, id, device),
mMixBuffer(0), mSuspended(0), mBytesWritten(0), mOutput(output),
- mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false),
- mDevice(device)
+ mLastWriteTime(0), mNumWrites(0), mNumDelayedWrites(0), mInWrite(false)
{
readOutputParameters();
@@ -1199,9 +1211,9 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra
}
}
- if (mOutput == 0) {
+ lStatus = initCheck();
+ if (lStatus != NO_ERROR) {
LOGE("Audio driver not initialized.");
- lStatus = NO_INIT;
goto Exit;
}
@@ -1423,7 +1435,7 @@ status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, ui
if (halFrames == 0 || dspFrames == 0) {
return BAD_VALUE;
}
- if (mOutput == 0) {
+ if (initCheck() != NO_ERROR) {
return INVALID_OPERATION;
}
*halFrames = mBytesWritten / audio_stream_frame_size(&mOutput->stream->common);
@@ -1468,34 +1480,6 @@ uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId)
return AudioSystem::getStrategyForStream(AUDIO_STREAM_MUSIC);
}
-sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId)
-{
- Mutex::Autolock _l(mLock);
- return getEffectChain_l(sessionId);
-}
-
-sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain_l(int sessionId)
-{
- sp<EffectChain> chain;
-
- size_t size = mEffectChains.size();
- for (size_t i = 0; i < size; i++) {
- if (mEffectChains[i]->sessionId() == sessionId) {
- chain = mEffectChains[i];
- break;
- }
- }
- return chain;
-}
-
-void AudioFlinger::PlaybackThread::setMode(uint32_t mode)
-{
- Mutex::Autolock _l(mLock);
- size_t size = mEffectChains.size();
- for (size_t i = 0; i < size; i++) {
- mEffectChains[i]->setMode_l(mode);
- }
-}
// ----------------------------------------------------------------------------
@@ -1503,7 +1487,7 @@ AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, Aud
: PlaybackThread(audioFlinger, output, id, device),
mAudioMixer(0)
{
- mType = PlaybackThread::MIXER;
+ mType = ThreadBase::MIXER;
mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
// FIXME - Current mixer implementation only supports stereo output
@@ -2072,7 +2056,7 @@ uint32_t AudioFlinger::MixerThread::suspendSleepTimeUs()
AudioFlinger::DirectOutputThread::DirectOutputThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device)
: PlaybackThread(audioFlinger, output, id, device)
{
- mType = PlaybackThread::DIRECT;
+ mType = ThreadBase::DIRECT;
}
AudioFlinger::DirectOutputThread::~DirectOutputThread()
@@ -2551,7 +2535,7 @@ uint32_t AudioFlinger::DirectOutputThread::suspendSleepTimeUs()
AudioFlinger::DuplicatingThread::DuplicatingThread(const sp<AudioFlinger>& audioFlinger, AudioFlinger::MixerThread* mainThread, int id)
: MixerThread(audioFlinger, mainThread->getOutput(), id, mainThread->device()), mWaitTimeMs(UINT_MAX)
{
- mType = PlaybackThread::DUPLICATING;
+ mType = ThreadBase::DUPLICATING;
addOutputTrack(mainThread);
}
@@ -3751,21 +3735,26 @@ sp<IAudioRecord> AudioFlinger::openRecord(
if (sessionId != NULL && *sessionId != AUDIO_SESSION_OUTPUT_MIX) {
lSessionId = *sessionId;
} else {
- lSessionId = nextUniqueId_l();
+ lSessionId = nextUniqueId();
if (sessionId != NULL) {
*sessionId = lSessionId;
}
}
// create new record track. The record track uses one track in mHardwareMixerThread by convention.
- recordTrack = new RecordThread::RecordTrack(thread, client, sampleRate,
- format, channelMask, frameCount, flags, lSessionId);
- }
- if (recordTrack->getCblk() == NULL) {
+ recordTrack = thread->createRecordTrack_l(client,
+ sampleRate,
+ format,
+ channelMask,
+ frameCount,
+ flags,
+ lSessionId,
+ &lStatus);
+ }
+ if (lStatus != NO_ERROR) {
// remove local strong reference to Client before deleting the RecordTrack so that the Client
// destructor is called by the TrackBase destructor with mLock held
client.clear();
recordTrack.clear();
- lStatus = NO_MEMORY;
goto Exit;
}
@@ -3814,10 +3803,16 @@ status_t AudioFlinger::RecordHandle::onTransact(
// ----------------------------------------------------------------------------
-AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger, AudioStreamIn *input, uint32_t sampleRate, uint32_t channels, int id) :
- ThreadBase(audioFlinger, id),
- mInput(input), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
+AudioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
+ AudioStreamIn *input,
+ uint32_t sampleRate,
+ uint32_t channels,
+ int id,
+ uint32_t device) :
+ ThreadBase(audioFlinger, id, device),
+ mInput(input), mTrack(NULL), mResampler(0), mRsmpOutBuffer(0), mRsmpInBuffer(0)
{
+ mType = ThreadBase::RECORD;
mReqChannelCount = popcount(channels);
mReqSampleRate = sampleRate;
readInputParameters();
@@ -3847,6 +3842,7 @@ bool AudioFlinger::RecordThread::threadLoop()
{
AudioBufferProvider::Buffer buffer;
sp<RecordTrack> activeTrack;
+ Vector< sp<EffectChain> > effectChains;
nsecs_t lastWarning = 0;
@@ -3897,14 +3893,22 @@ bool AudioFlinger::RecordThread::threadLoop()
mStandby = false;
}
}
+ lockEffectChains_l(effectChains);
}
if (mActiveTrack != 0) {
if (mActiveTrack->mState != TrackBase::ACTIVE &&
mActiveTrack->mState != TrackBase::RESUMING) {
- usleep(5000);
+ unlockEffectChains(effectChains);
+ usleep(kRecordThreadSleepUs);
continue;
}
+ for (size_t i = 0; i < effectChains.size(); i ++) {
+ effectChains[i]->process_l();
+ }
+ // enable changes in effect chain
+ unlockEffectChains(effectChains);
+
buffer.frameCount = mFrameCount;
if (LIKELY(mActiveTrack->getNextBuffer(&buffer) == NO_ERROR)) {
size_t framesOut = buffer.frameCount;
@@ -3953,7 +3957,7 @@ bool AudioFlinger::RecordThread::threadLoop()
// Force input into standby so that it tries to
// recover at next read attempt
mInput->stream->common.standby(&mInput->stream->common);
- usleep(5000);
+ usleep(kRecordThreadSleepUs);
}
mRsmpInIndex = mFrameCount;
framesOut = 0;
@@ -4001,9 +4005,12 @@ bool AudioFlinger::RecordThread::threadLoop()
// Release the processor for a while before asking for a new buffer.
// This will give the application more chance to read from the buffer and
// clear the overflow.
- usleep(5000);
+ usleep(kRecordThreadSleepUs);
}
+ } else {
+ unlockEffectChains(effectChains);
}
+ effectChains.clear();
}
if (!mStandby) {
@@ -4017,6 +4024,49 @@ bool AudioFlinger::RecordThread::threadLoop()
return false;
}
+
+sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
+ const sp<AudioFlinger::Client>& client,
+ uint32_t sampleRate,
+ int format,
+ int channelMask,
+ int frameCount,
+ uint32_t flags,
+ int sessionId,
+ status_t *status)
+{
+ sp<RecordTrack> track;
+ status_t lStatus;
+
+ lStatus = initCheck();
+ if (lStatus != NO_ERROR) {
+ LOGE("Audio driver not initialized.");
+ goto Exit;
+ }
+
+ { // scope for mLock
+ Mutex::Autolock _l(mLock);
+
+ track = new RecordTrack(this, client, sampleRate,
+ format, channelMask, frameCount, flags, sessionId);
+
+ if (track->getCblk() == NULL) {
+ lStatus = NO_MEMORY;
+ goto Exit;
+ }
+
+ mTrack = track.get();
+
+ }
+ lStatus = NO_ERROR;
+
+Exit:
+ if (status) {
+ *status = lStatus;
+ }
+ return track;
+}
+
status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack)
{
LOGV("RecordThread::start");
@@ -4146,7 +4196,7 @@ status_t AudioFlinger::RecordThread::getNextBuffer(AudioBufferProvider::Buffer*
// Force input into standby so that it tries to
// recover at next read attempt
mInput->stream->common.standby(&mInput->stream->common);
- usleep(5000);
+ usleep(kRecordThreadSleepUs);
}
buffer->raw = 0;
buffer->frameCount = 0;
@@ -4211,6 +4261,23 @@ bool AudioFlinger::RecordThread::checkForNewParameters_l()
reconfig = true;
}
}
+ if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
+ // forward device change to effects that have requested to be
+ // aware of attached audio device.
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->setDevice_l(value);
+ }
+ // store input device and output device but do not forward output device to audio HAL.
+ // Note that status is ignored by the caller for output device
+ // (see AudioFlinger::setParameters()
+ if (value & AUDIO_DEVICE_OUT_ALL) {
+ mDevice &= (uint32_t)~(value & AUDIO_DEVICE_OUT_ALL);
+ status = BAD_VALUE;
+ } else {
+ mDevice &= (uint32_t)~(value & AUDIO_DEVICE_IN_ALL);
+ }
+ mDevice |= (uint32_t)value;
+ }
if (status == NO_ERROR) {
status = mInput->stream->common.set_parameters(&mInput->stream->common, keyValuePair.string());
if (status == INVALID_OPERATION) {
@@ -4320,6 +4387,21 @@ unsigned int AudioFlinger::RecordThread::getInputFramesLost()
return mInput->stream->get_input_frames_lost(mInput->stream);
}
+uint32_t AudioFlinger::RecordThread::hasAudioSession(int sessionId)
+{
+ Mutex::Autolock _l(mLock);
+ uint32_t result = 0;
+ if (getEffectChain_l(sessionId) != 0) {
+ result = EFFECT_SESSION;
+ }
+
+ if (mTrack != NULL && sessionId == mTrack->sessionId()) {
+ result |= TRACK_SESSION;
+ }
+
+ return result;
+}
+
// ----------------------------------------------------------------------------
int AudioFlinger::openOutput(uint32_t *pDevices,
@@ -4368,7 +4450,7 @@ int AudioFlinger::openOutput(uint32_t *pDevices,
mHardwareStatus = AUDIO_HW_IDLE;
if (outStream != NULL) {
AudioStreamOut *output = new AudioStreamOut(outHwDev, outStream);
- int id = nextUniqueId_l();
+ int id = nextUniqueId();
if ((flags & AUDIO_POLICY_OUTPUT_FLAG_DIRECT) ||
(format != AUDIO_FORMAT_PCM_16_BIT) ||
@@ -4405,7 +4487,7 @@ int AudioFlinger::openDuplicateOutput(int output1, int output2)
return 0;
}
- int id = nextUniqueId_l();
+ int id = nextUniqueId();
DuplicatingThread *thread = new DuplicatingThread(this, thread1, id);
thread->addOutputTrack(thread2);
mPlaybackThreads.add(id, thread);
@@ -4428,9 +4510,9 @@ status_t AudioFlinger::closeOutput(int output)
LOGV("closeOutput() %d", output);
- if (thread->type() == PlaybackThread::MIXER) {
+ if (thread->type() == ThreadBase::MIXER) {
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) {
+ if (mPlaybackThreads.valueAt(i)->type() == ThreadBase::DUPLICATING) {
DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
dupThread->removeOutputTrack((MixerThread *)thread.get());
}
@@ -4442,7 +4524,7 @@ status_t AudioFlinger::closeOutput(int output)
}
thread->exit();
- if (thread->type() != PlaybackThread::DUPLICATING) {
+ if (thread->type() != ThreadBase::DUPLICATING) {
AudioStreamOut *out = thread->getOutput();
out->hwDev->close_output_stream(out->hwDev, out->stream);
delete out;
@@ -4537,9 +4619,17 @@ int AudioFlinger::openInput(uint32_t *pDevices,
if (inStream != NULL) {
AudioStreamIn *input = new AudioStreamIn(inHwDev, inStream);
- int id = nextUniqueId_l();
- // Start record thread
- thread = new RecordThread(this, input, reqSamplingRate, reqChannels, id);
+ int id = nextUniqueId();
+ // Start record thread
+ // RecorThread require both input and output device indication to forward to audio
+ // pre processing modules
+ uint32_t device = (*pDevices) | primaryOutputDevice_l();
+ thread = new RecordThread(this,
+ input,
+ reqSamplingRate,
+ reqChannels,
+ id,
+ device);
mRecordThreads.add(id, thread);
LOGV("openInput() created record thread: ID %d thread %p", id, thread);
if (pSamplingRate) *pSamplingRate = reqSamplingRate;
@@ -4597,7 +4687,7 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
if (thread != dstThread &&
- thread->type() != PlaybackThread::DIRECT) {
+ thread->type() != ThreadBase::DIRECT) {
MixerThread *srcThread = (MixerThread *)thread;
srcThread->invalidateTracks(stream);
}
@@ -4609,8 +4699,7 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output)
int AudioFlinger::newAudioSessionId()
{
- AutoMutex _l(mLock);
- return nextUniqueId_l();
+ return nextUniqueId();
}
// checkPlaybackThread_l() must be called with AudioFlinger::mLock held
@@ -4628,7 +4717,7 @@ AudioFlinger::MixerThread *AudioFlinger::checkMixerThread_l(int output) const
{
PlaybackThread *thread = checkPlaybackThread_l(output);
if (thread != NULL) {
- if (thread->type() == PlaybackThread::DIRECT) {
+ if (thread->type() == ThreadBase::DIRECT) {
thread = NULL;
}
}
@@ -4645,12 +4734,34 @@ AudioFlinger::RecordThread *AudioFlinger::checkRecordThread_l(int input) const
return thread;
}
-// nextUniqueId_l() must be called with AudioFlinger::mLock held
-int AudioFlinger::nextUniqueId_l()
+uint32_t AudioFlinger::nextUniqueId()
+{
+ return android_atomic_inc(&mNextUniqueId);
+}
+
+AudioFlinger::PlaybackThread *AudioFlinger::primaryPlaybackThread_l()
{
- return mNextUniqueId++;
+ for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
+ PlaybackThread *thread = mPlaybackThreads.valueAt(i).get();
+ if (thread->getOutput()->hwDev == mPrimaryHardwareDev) {
+ return thread;
+ }
+ }
+ return NULL;
+}
+
+uint32_t AudioFlinger::primaryOutputDevice_l()
+{
+ PlaybackThread *thread = primaryPlaybackThread_l();
+
+ if (thread == NULL) {
+ return 0;
+ }
+
+ return thread->device();
}
+
// ----------------------------------------------------------------------------
// Effect management
// ----------------------------------------------------------------------------
@@ -4683,7 +4794,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
int32_t priority,
- int output,
+ int io,
int sessionId,
status_t *status,
int *id,
@@ -4695,8 +4806,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
sp<Client> client;
wp<Client> wclient;
- LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, output %d",
- pid, effectClient.get(), priority, sessionId, output);
+ LOGV("createEffect pid %d, client %p, priority %d, sessionId %d, io %d",
+ pid, effectClient.get(), priority, sessionId, io);
if (pDesc == NULL) {
lStatus = BAD_VALUE;
@@ -4724,7 +4835,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
goto Exit;
}
- if (output == 0) {
+ if (io == 0) {
if (sessionId == AUDIO_SESSION_OUTPUT_STAGE) {
// output must be specified by AudioPolicyManager when using session
// AUDIO_SESSION_OUTPUT_STAGE
@@ -4732,9 +4843,9 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
goto Exit;
} else if (sessionId == AUDIO_SESSION_OUTPUT_MIX) {
// if the output returned by getOutputForEffect() is removed before we lock the
- // mutex below, the call to checkPlaybackThread_l(output) below will detect it
+ // mutex below, the call to checkPlaybackThread_l(io) below will detect it
// and we will exit safely
- output = AudioSystem::getOutputForEffect(&desc);
+ io = AudioSystem::getOutputForEffect(&desc);
}
}
@@ -4811,31 +4922,41 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid,
// output threads.
// If output is 0 here, sessionId is neither SESSION_OUTPUT_STAGE nor SESSION_OUTPUT_MIX
// because of code checking output when entering the function.
- if (output == 0) {
+ // Note: io is never 0 when creating an effect on an input
+ if (io == 0) {
// look for the thread where the specified audio session is present
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
if (mPlaybackThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
- output = mPlaybackThreads.keyAt(i);
+ io = mPlaybackThreads.keyAt(i);
break;
}
}
+ if (io == 0) {
+ for (size_t i = 0; i < mRecordThreads.size(); i++) {
+ if (mRecordThreads.valueAt(i)->hasAudioSession(sessionId) != 0) {
+ io = mRecordThreads.keyAt(i);
+ break;
+ }
+ }
+ }
// If no output thread contains the requested session ID, default to
// first output. The effect chain will be moved to the correct output
// thread when a track with the same session ID is created
- if (output == 0 && mPlaybackThreads.size()) {
- output = mPlaybackThreads.keyAt(0);
+ if (io == 0 && mPlaybackThreads.size()) {
+ io = mPlaybackThreads.keyAt(0);
}
+ LOGV("createEffect() got io %d for effect %s", io, desc.name);
}
- LOGV("createEffect() got output %d for effect %s", output, desc.name);
- PlaybackThread *thread = checkPlaybackThread_l(output);
+ ThreadBase *thread = checkRecordThread_l(io);
if (thread == NULL) {
- LOGE("createEffect() unknown output thread");
- lStatus = BAD_VALUE;
- goto Exit;
+ thread = checkPlaybackThread_l(io);
+ if (thread == NULL) {
+ LOGE("createEffect() unknown output thread");
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
}
- // TODO: allow attachment of effect to inputs
-
wclient = mClients.valueFor(pid);
if (wclient != NULL) {
@@ -4943,8 +5064,9 @@ status_t AudioFlinger::moveEffectChain_l(int session,
return NO_ERROR;
}
+
// PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held
-sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
+sp<AudioFlinger::EffectHandle> AudioFlinger::ThreadBase::createEffect_l(
const sp<AudioFlinger::Client>& client,
const sp<IEffectClient>& effectClient,
int32_t priority,
@@ -4957,24 +5079,14 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
sp<EffectModule> effect;
sp<EffectHandle> handle;
status_t lStatus;
- sp<Track> track;
sp<EffectChain> chain;
bool chainCreated = false;
bool effectCreated = false;
bool effectRegistered = false;
- if (mOutput == 0) {
+ lStatus = initCheck();
+ if (lStatus != NO_ERROR) {
LOGW("createEffect_l() Audio driver not initialized.");
- lStatus = NO_INIT;
- goto Exit;
- }
-
- // Do not allow auxiliary effect on session other than 0
- if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY &&
- sessionId != AUDIO_SESSION_OUTPUT_MIX) {
- LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d",
- desc->name, sessionId);
- lStatus = BAD_VALUE;
goto Exit;
}
@@ -4986,6 +5098,16 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
lStatus = BAD_VALUE;
goto Exit;
}
+ // Only Pre processor effects are allowed on input threads and only on input threads
+ if ((mType == RECORD &&
+ (desc->flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_PRE_PROC) ||
+ (mType != RECORD &&
+ (desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC)) {
+ LOGW("createEffect_l() effect %s (flags %08x) created on wrong thread type %d",
+ desc->name, desc->flags, mType);
+ lStatus = BAD_VALUE;
+ goto Exit;
+ }
LOGV("createEffect_l() thread %p effect %s on session %d", this, desc->name, sessionId);
@@ -5008,7 +5130,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l(
LOGV("createEffect_l() got effect %p on chain %p", effect == 0 ? 0 : effect.get(), chain.get());
if (effect == 0) {
- int id = mAudioFlinger->nextUniqueId_l();
+ int id = mAudioFlinger->nextUniqueId();
// Check CPU and memory usage
lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id);
if (lStatus != NO_ERROR) {
@@ -5059,9 +5181,20 @@ Exit:
return handle;
}
+sp<AudioFlinger::EffectModule> AudioFlinger::ThreadBase::getEffect_l(int sessionId, int effectId)
+{
+ sp<EffectModule> effect;
+
+ sp<EffectChain> chain = getEffectChain_l(sessionId);
+ if (chain != 0) {
+ effect = chain->getEffectFromId_l(effectId);
+ }
+ return effect;
+}
+
// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and
// PlaybackThread::mLock held
-status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect)
+status_t AudioFlinger::ThreadBase::addEffect_l(const sp<EffectModule>& effect)
{
// check for existing effect chain with the requested audio session
int sessionId = effect->sessionId();
@@ -5097,7 +5230,7 @@ status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effec
return NO_ERROR;
}
-void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) {
+void AudioFlinger::ThreadBase::removeEffect_l(const sp<EffectModule>& effect) {
LOGV("removeEffect_l() %p effect %p", this, effect.get());
effect_descriptor_t desc = effect->desc();
@@ -5116,7 +5249,53 @@ void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect
}
}
-void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect,
+void AudioFlinger::ThreadBase::lockEffectChains_l(
+ Vector<sp <AudioFlinger::EffectChain> >& effectChains)
+{
+ effectChains = mEffectChains;
+ for (size_t i = 0; i < mEffectChains.size(); i++) {
+ mEffectChains[i]->lock();
+ }
+}
+
+void AudioFlinger::ThreadBase::unlockEffectChains(
+ Vector<sp <AudioFlinger::EffectChain> >& effectChains)
+{
+ for (size_t i = 0; i < effectChains.size(); i++) {
+ effectChains[i]->unlock();
+ }
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain(int sessionId)
+{
+ Mutex::Autolock _l(mLock);
+ return getEffectChain_l(sessionId);
+}
+
+sp<AudioFlinger::EffectChain> AudioFlinger::ThreadBase::getEffectChain_l(int sessionId)
+{
+ sp<EffectChain> chain;
+
+ size_t size = mEffectChains.size();
+ for (size_t i = 0; i < size; i++) {
+ if (mEffectChains[i]->sessionId() == sessionId) {
+ chain = mEffectChains[i];
+ break;
+ }
+ }
+ return chain;
+}
+
+void AudioFlinger::ThreadBase::setMode(uint32_t mode)
+{
+ Mutex::Autolock _l(mLock);
+ size_t size = mEffectChains.size();
+ for (size_t i = 0; i < size; i++) {
+ mEffectChains[i]->setMode_l(mode);
+ }
+}
+
+void AudioFlinger::ThreadBase::disconnectEffect(const sp<EffectModule>& effect,
const wp<EffectHandle>& handle) {
Mutex::Autolock _l(mLock);
LOGV("disconnectEffect() %p effect %p", this, effect.get());
@@ -5222,35 +5401,6 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>&
return mEffectChains.size();
}
-void AudioFlinger::PlaybackThread::lockEffectChains_l(
- Vector<sp <AudioFlinger::EffectChain> >& effectChains)
-{
- effectChains = mEffectChains;
- for (size_t i = 0; i < mEffectChains.size(); i++) {
- mEffectChains[i]->lock();
- }
-}
-
-void AudioFlinger::PlaybackThread::unlockEffectChains(
- Vector<sp <AudioFlinger::EffectChain> >& effectChains)
-{
- for (size_t i = 0; i < effectChains.size(); i++) {
- effectChains[i]->unlock();
- }
-}
-
-
-sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int sessionId, int effectId)
-{
- sp<EffectModule> effect;
-
- sp<EffectChain> chain = getEffectChain_l(sessionId);
- if (chain != 0) {
- effect = chain->getEffectFromId_l(effectId);
- }
- return effect;
-}
-
status_t AudioFlinger::PlaybackThread::attachAuxEffect(
const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId)
{
@@ -5291,6 +5441,34 @@ void AudioFlinger::PlaybackThread::detachAuxEffect_l(int effectId)
}
}
+status_t AudioFlinger::RecordThread::addEffectChain_l(const sp<EffectChain>& chain)
+{
+ // only one chain per input thread
+ if (mEffectChains.size() != 0) {
+ return INVALID_OPERATION;
+ }
+ LOGV("addEffectChain_l() %p on thread %p", chain.get(), this);
+
+ chain->setInBuffer(NULL);
+ chain->setOutBuffer(NULL);
+
+ mEffectChains.add(chain);
+
+ return NO_ERROR;
+}
+
+size_t AudioFlinger::RecordThread::removeEffectChain_l(const sp<EffectChain>& chain)
+{
+ LOGV("removeEffectChain_l() %p from thread %p", chain.get(), this);
+ LOGW_IF(mEffectChains.size() != 1,
+ "removeEffectChain_l() %p invalid chain size %d on thread %p",
+ chain.get(), mEffectChains.size(), this);
+ if (mEffectChains.size() == 1) {
+ mEffectChains.removeAt(0);
+ }
+ return 0;
+}
+
// ----------------------------------------------------------------------------
// EffectModule implementation
// ----------------------------------------------------------------------------
@@ -5312,12 +5490,11 @@ AudioFlinger::EffectModule::EffectModule(const wp<ThreadBase>& wThread,
if (thread == 0) {
return;
}
- PlaybackThread *p = (PlaybackThread *)thread.get();
memcpy(&mDescriptor, desc, sizeof(effect_descriptor_t));
// create effect engine from effect factory
- mStatus = EffectCreate(&desc->uuid, sessionId, p->id(), &mEffectInterface);
+ mStatus = EffectCreate(&desc->uuid, sessionId, thread->id(), &mEffectInterface);
if (mStatus != NO_ERROR) {
return;
@@ -5340,6 +5517,13 @@ AudioFlinger::EffectModule::~EffectModule()
{
LOGV("Destructor %p", this);
if (mEffectInterface != NULL) {
+ if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+ (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC) {
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface);
+ }
+ }
// release effect engine
EffectRelease(mEffectInterface);
}
@@ -5415,8 +5599,7 @@ void AudioFlinger::EffectModule::disconnect(const wp<EffectHandle>& handle)
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
- PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
- playbackThread->disconnectEffect(keep, handle);
+ thread->disconnectEffect(keep, handle);
}
}
}
@@ -5626,6 +5809,14 @@ status_t AudioFlinger::EffectModule::start_l()
if (status == 0) {
status = cmdStatus;
}
+ if (status == 0 &&
+ ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+ (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ thread->stream()->add_audio_effect(thread->stream(), mEffectInterface);
+ }
+ }
return status;
}
@@ -5645,6 +5836,14 @@ status_t AudioFlinger::EffectModule::stop_l()
if (status == 0) {
status = cmdStatus;
}
+ if (status == 0 &&
+ ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_PRE_PROC ||
+ (mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_POST_PROC)) {
+ sp<ThreadBase> thread = mThread.promote();
+ if (thread != 0) {
+ thread->stream()->remove_audio_effect(thread->stream(), mEffectInterface);
+ }
+ }
return status;
}
@@ -5784,17 +5983,41 @@ status_t AudioFlinger::EffectModule::setDevice(uint32_t device)
{
Mutex::Autolock _l(mLock);
status_t status = NO_ERROR;
- if ((mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
- status_t cmdStatus;
- uint32_t size = sizeof(status_t);
- status = (*mEffectInterface)->command(mEffectInterface,
- EFFECT_CMD_SET_DEVICE,
- sizeof(uint32_t),
- &device,
- &size,
- &cmdStatus);
- if (status == NO_ERROR) {
- status = cmdStatus;
+ if (device && (mDescriptor.flags & EFFECT_FLAG_DEVICE_MASK) == EFFECT_FLAG_DEVICE_IND) {
+ // audio pre processing modules on RecordThread can receive both output and
+ // input device indication in the same call
+ uint32_t dev = device & AUDIO_DEVICE_OUT_ALL;
+ if (dev) {
+ status_t cmdStatus;
+ uint32_t size = sizeof(status_t);
+
+ status = (*mEffectInterface)->command(mEffectInterface,
+ EFFECT_CMD_SET_DEVICE,
+ sizeof(uint32_t),
+ &dev,
+ &size,
+ &cmdStatus);
+ if (status == NO_ERROR) {
+ status = cmdStatus;
+ }
+ }
+ dev = device & AUDIO_DEVICE_IN_ALL;
+ if (dev) {
+ status_t cmdStatus;
+ uint32_t size = sizeof(status_t);
+
+ status_t status2 = (*mEffectInterface)->command(mEffectInterface,
+ EFFECT_CMD_SET_INPUT_DEVICE,
+ sizeof(uint32_t),
+ &dev,
+ &size,
+ &cmdStatus);
+ if (status2 == NO_ERROR) {
+ status2 = cmdStatus;
+ }
+ if (status == NO_ERROR) {
+ status = status2;
+ }
}
}
return status;
@@ -6168,7 +6391,6 @@ void AudioFlinger::EffectChain::process_l()
LOGW("process_l(): cannot promote mixer thread");
return;
}
- PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
bool isGlobalSession = (mSessionId == AUDIO_SESSION_OUTPUT_MIX) ||
(mSessionId == AUDIO_SESSION_OUTPUT_STAGE);
bool tracksOnSession = false;
@@ -6180,7 +6402,7 @@ void AudioFlinger::EffectChain::process_l()
// will not do it
if (tracksOnSession &&
activeTrackCnt() == 0) {
- size_t numSamples = playbackThread->frameCount() * playbackThread->channelCount();
+ size_t numSamples = thread->frameCount() * thread->channelCount();
memset(mInBuffer, 0, numSamples * sizeof(int16_t));
}
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 1fad987..fff4f06 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -157,7 +157,7 @@ public:
effect_descriptor_t *pDesc,
const sp<IEffectClient>& effectClient,
int32_t priority,
- int output,
+ int io,
int sessionId,
status_t *status,
int *id,
@@ -273,9 +273,17 @@ private:
class ThreadBase : public Thread {
public:
- ThreadBase (const sp<AudioFlinger>& audioFlinger, int id);
+ ThreadBase (const sp<AudioFlinger>& audioFlinger, int id, uint32_t device);
virtual ~ThreadBase();
+
+ enum type {
+ MIXER, // Thread class is MixerThread
+ DIRECT, // Thread class is DirectOutputThread
+ DUPLICATING, // Thread class is DuplicatingThread
+ RECORD // Thread class is RecordThread
+ };
+
status_t dumpBase(int fd, const Vector<String16>& args);
// base for record and playback
@@ -377,6 +385,8 @@ private:
int mParam;
};
+ virtual status_t initCheck() const = 0;
+ int type() const { return mType; }
uint32_t sampleRate() const;
int channelCount() const;
uint32_t format() const;
@@ -392,6 +402,60 @@ private:
void processConfigEvents();
int id() const { return mId;}
bool standby() { return mStandby; }
+ uint32_t device() { return mDevice; }
+ virtual audio_stream_t* stream() = 0;
+
+ 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);
+ void disconnectEffect(const sp< EffectModule>& effect,
+ const wp<EffectHandle>& handle);
+
+ // return values for hasAudioSession (bit field)
+ enum effect_state {
+ EFFECT_SESSION = 0x1, // the audio session corresponds to at least one
+ // effect
+ TRACK_SESSION = 0x2 // the audio session corresponds to at least one
+ // track
+ };
+
+ // get effect chain corresponding to session Id.
+ sp<EffectChain> getEffectChain(int sessionId);
+ // same as getEffectChain() but must be called with ThreadBase mutex locked
+ sp<EffectChain> getEffectChain_l(int sessionId);
+ // add an effect chain to the chain list (mEffectChains)
+ virtual status_t addEffectChain_l(const sp<EffectChain>& chain) = 0;
+ // remove an effect chain from the chain list (mEffectChains)
+ virtual size_t removeEffectChain_l(const sp<EffectChain>& chain) = 0;
+ // lock mall effect chains Mutexes. Must be called before releasing the
+ // ThreadBase mutex before processing the mixer and effects. This guarantees the
+ // integrity of the chains during the process.
+ void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains);
+ // unlock effect chains after process
+ void unlockEffectChains(Vector<sp <EffectChain> >& effectChains);
+ // set audio mode to all effect chains
+ void setMode(uint32_t mode);
+ // get effect module with corresponding ID on specified audio session
+ sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
+ // add and effect module. Also creates the effect chain is none exists for
+ // the effects audio session
+ status_t addEffect_l(const sp< EffectModule>& effect);
+ // remove and effect module. Also removes the effect chain is this was the last
+ // effect
+ void removeEffect_l(const sp< EffectModule>& effect);
+ // detach all tracks connected to an auxiliary effect
+ virtual void detachAuxEffect_l(int effectId) {}
+ // returns either EFFECT_SESSION if effects on this audio session exist in one
+ // chain, or TRACK_SESSION if tracks on this audio session exist, or both
+ virtual uint32_t hasAudioSession(int sessionId) = 0;
+ // the value returned by default implementation is not important as the
+ // strategy is only meaningful for PlaybackThread which implements this method
+ virtual uint32_t getStrategyForSession_l(int sessionId) { return 0; }
mutable Mutex mLock;
@@ -406,6 +470,7 @@ private:
friend class RecordThread;
friend class RecordTrack;
+ int mType;
Condition mWaitWorkCV;
sp<AudioFlinger> mAudioFlinger;
uint32_t mSampleRate;
@@ -421,18 +486,15 @@ private:
bool mStandby;
int mId;
bool mExiting;
+ Vector< sp<EffectChain> > mEffectChains;
+ uint32_t mDevice; // output device for PlaybackThread
+ // input + output devices for RecordThread
};
// --- PlaybackThread ---
class PlaybackThread : public ThreadBase {
public:
- enum type {
- MIXER,
- DIRECT,
- DUPLICATING
- };
-
enum mixer_state {
MIXER_IDLE,
MIXER_TRACKS_ENABLED,
@@ -569,6 +631,8 @@ private:
virtual status_t readyToRun();
virtual void onFirstRef();
+ virtual status_t initCheck() const { return (mOutput == 0) ? NO_INIT : NO_ERROR; }
+
virtual uint32_t latency() const;
virtual status_t setMasterVolume(float value);
@@ -595,8 +659,8 @@ private:
status_t *status);
AudioStreamOut* getOutput() { return mOutput; }
+ virtual audio_stream_t* stream() { return &mOutput->stream->common; }
- virtual int type() const { return mType; }
void suspend() { mSuspended++; }
void restore() { if (mSuspended) mSuspended--; }
bool isSuspended() { return (mSuspended != 0); }
@@ -605,45 +669,16 @@ private:
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);
- void disconnectEffect(const sp< EffectModule>& effect,
- const wp<EffectHandle>& handle);
-
- // return values for hasAudioSession (bit field)
- enum effect_state {
- EFFECT_SESSION = 0x1, // the audio session corresponds to at least one
- // effect
- TRACK_SESSION = 0x2 // the audio session corresponds to at least one
- // track
- };
-
- uint32_t 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(Vector<sp <EffectChain> >& effectChains);
- void unlockEffectChains(Vector<sp <EffectChain> >& effectChains);
-
- sp<AudioFlinger::EffectModule> getEffect_l(int sessionId, int effectId);
- void detachAuxEffect_l(int effectId);
+ virtual 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);
- void setMode(uint32_t mode);
- status_t addEffect_l(const sp< EffectModule>& effect);
- void removeEffect_l(const sp< EffectModule>& effect);
-
- uint32_t getStrategyForSession_l(int sessionId);
+ virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
+ virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
+ virtual uint32_t hasAudioSession(int sessionId);
+ virtual uint32_t getStrategyForSession_l(int sessionId);
struct stream_type_t {
stream_type_t()
@@ -656,7 +691,6 @@ private:
};
protected:
- int mType;
int16_t* mMixBuffer;
int mSuspended;
int mBytesWritten;
@@ -688,8 +722,6 @@ private:
void readOutputParameters();
- uint32_t device() { return mDevice; }
-
virtual status_t dumpInternals(int fd, const Vector<String16>& args);
status_t dumpTracks(int fd, const Vector<String16>& args);
status_t dumpEffectChains(int fd, const Vector<String16>& args);
@@ -703,8 +735,6 @@ private:
int mNumWrites;
int mNumDelayedWrites;
bool mInWrite;
- Vector< sp<EffectChain> > mEffectChains;
- uint32_t mDevice;
};
class MixerThread : public PlaybackThread {
@@ -788,11 +818,13 @@ private:
float streamVolumeInternal(int stream) const { return mStreamTypes[stream].volume; }
void audioConfigChanged_l(int event, int ioHandle, void *param2);
- int nextUniqueId_l();
+ uint32_t nextUniqueId();
status_t moveEffectChain_l(int session,
AudioFlinger::PlaybackThread *srcThread,
AudioFlinger::PlaybackThread *dstThread,
bool reRegister);
+ PlaybackThread *primaryPlaybackThread_l();
+ uint32_t primaryOutputDevice_l();
friend class AudioBuffer;
@@ -864,18 +896,33 @@ private:
AudioStreamIn *input,
uint32_t sampleRate,
uint32_t channels,
- int id);
+ int id,
+ uint32_t device);
~RecordThread();
virtual bool threadLoop();
virtual status_t readyToRun() { return NO_ERROR; }
virtual void onFirstRef();
+ virtual status_t initCheck() const { return (mInput == 0) ? NO_INIT : NO_ERROR; }
+ sp<AudioFlinger::RecordThread::RecordTrack> createRecordTrack_l(
+ const sp<AudioFlinger::Client>& client,
+ uint32_t sampleRate,
+ int format,
+ int channelMask,
+ int frameCount,
+ uint32_t flags,
+ int sessionId,
+ status_t *status);
+
status_t start(RecordTrack* recordTrack);
void stop(RecordTrack* recordTrack);
status_t dump(int fd, const Vector<String16>& args);
AudioStreamIn* getInput() { return mInput; }
+ virtual audio_stream_t* stream() { return &mInput->stream->common; }
+
+ void setTrack(RecordTrack *recordTrack) { mTrack = recordTrack; }
virtual status_t getNextBuffer(AudioBufferProvider::Buffer* buffer);
virtual void releaseBuffer(AudioBufferProvider::Buffer* buffer);
virtual bool checkForNewParameters_l();
@@ -884,9 +931,14 @@ private:
void readInputParameters();
virtual unsigned int getInputFramesLost();
+ virtual status_t addEffectChain_l(const sp<EffectChain>& chain);
+ virtual size_t removeEffectChain_l(const sp<EffectChain>& chain);
+ virtual uint32_t hasAudioSession(int sessionId);
+
private:
RecordThread();
AudioStreamIn *mInput;
+ RecordTrack* mTrack;
sp<RecordTrack> mActiveTrack;
Condition mStartStopCond;
AudioResampler *mResampler;
@@ -1103,9 +1155,8 @@ private:
status_t addEffect_l(const sp<EffectModule>& handle);
size_t removeEffect_l(const sp<EffectModule>& handle);
- int sessionId() {
- return mSessionId;
- }
+ int sessionId() { return mSessionId; }
+ void setSessionId(int sessionId) { mSessionId = sessionId; }
sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor);
sp<EffectModule> getEffectFromId_l(int id);
diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp
index 8e16d94..dd1e153 100644
--- a/services/audioflinger/AudioPolicyService.cpp
+++ b/services/audioflinger/AudioPolicyService.cpp
@@ -33,11 +33,14 @@
#include <cutils/properties.h>
#include <dlfcn.h>
#include <hardware_legacy/power.h>
+#include <media/AudioEffect.h>
+#include <media/EffectsFactoryApi.h>
#include <hardware/hardware.h>
#include <system/audio.h>
#include <system/audio_policy.h>
#include <hardware/audio_policy.h>
+#include <audio_effects/audio_effects_conf.h>
namespace android {
@@ -101,6 +104,13 @@ AudioPolicyService::AudioPolicyService()
mpAudioPolicy->set_can_mute_enforced_audible(mpAudioPolicy, !forced_val);
LOGI("Loaded audio policy from %s (%s)", module->name, module->id);
+
+ // load audio pre processing modules
+ if (access(AUDIO_EFFECT_VENDOR_CONFIG_FILE, R_OK) == 0) {
+ loadPreProcessorConfig(AUDIO_EFFECT_VENDOR_CONFIG_FILE);
+ } else if (access(AUDIO_EFFECT_DEFAULT_CONFIG_FILE, R_OK) == 0) {
+ loadPreProcessorConfig(AUDIO_EFFECT_DEFAULT_CONFIG_FILE);
+ }
}
AudioPolicyService::~AudioPolicyService()
@@ -110,6 +120,31 @@ AudioPolicyService::~AudioPolicyService()
mAudioCommandThread->exit();
mAudioCommandThread.clear();
+
+ // release audio pre processing resources
+ for (size_t i = 0; i < mInputSources.size(); i++) {
+ InputSourceDesc *source = mInputSources.valueAt(i);
+ Vector <EffectDesc *> effects = source->mEffects;
+ for (size_t j = 0; j < effects.size(); j++) {
+ delete effects[j]->mName;
+ Vector <effect_param_t *> params = effects[j]->mParams;
+ for (size_t k = 0; k < params.size(); k++) {
+ delete params[k];
+ }
+ params.clear();
+ delete effects[j];
+ }
+ effects.clear();
+ delete source;
+ }
+ mInputSources.clear();
+
+ for (size_t i = 0; i < mInputs.size(); i++) {
+ mInputs.valueAt(i)->mEffects.clear();
+ delete mInputs.valueAt(i);
+ }
+ mInputs.clear();
+
if (mpAudioPolicy && mpAudioPolicyDev)
mpAudioPolicyDev->destroy_audio_policy(mpAudioPolicyDev, mpAudioPolicy);
if (mpAudioPolicyDev)
@@ -276,13 +311,51 @@ audio_io_handle_t AudioPolicyService::getInput(int inputSource,
uint32_t samplingRate,
uint32_t format,
uint32_t channels,
- audio_in_acoustics_t acoustics)
+ audio_in_acoustics_t acoustics,
+ int audioSession)
{
if (mpAudioPolicy == NULL) {
return 0;
}
Mutex::Autolock _l(mLock);
- return mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate, format, channels, acoustics);
+ audio_io_handle_t input = mpAudioPolicy->get_input(mpAudioPolicy, inputSource, samplingRate,
+ format, channels, acoustics);
+
+ if (input == 0) {
+ return input;
+ }
+ // create audio pre processors according to input source
+ ssize_t index = mInputSources.indexOfKey((audio_source_t)inputSource);
+ if (index < 0) {
+ return input;
+ }
+ ssize_t idx = mInputs.indexOfKey(input);
+ InputDesc *inputDesc;
+ if (idx < 0) {
+ inputDesc = new InputDesc();
+ inputDesc->mSessionId = audioSession;
+ mInputs.add(input, inputDesc);
+ } else {
+ inputDesc = mInputs.valueAt(idx);
+ }
+
+ Vector <EffectDesc *> effects = mInputSources.valueAt(index)->mEffects;
+ for (size_t i = 0; i < effects.size(); i++) {
+ EffectDesc *effect = effects[i];
+ sp<AudioEffect> fx = new AudioEffect(NULL, &effect->mUuid, -1, 0, 0, audioSession, input);
+ status_t status = fx->initCheck();
+ if (status != NO_ERROR && status != ALREADY_EXISTS) {
+ LOGW("Failed to create Fx %s on input %d", effect->mName, input);
+ // fx goes out of scope and strong ref on AudioEffect is released
+ continue;
+ }
+ for (size_t j = 0; j < effect->mParams.size(); j++) {
+ fx->setParameter(effect->mParams[j]);
+ }
+ inputDesc->mEffects.add(fx);
+ }
+ setPreProcessorEnabled(inputDesc, true);
+ return input;
}
status_t AudioPolicyService::startInput(audio_io_handle_t input)
@@ -291,6 +364,7 @@ status_t AudioPolicyService::startInput(audio_io_handle_t input)
return NO_INIT;
}
Mutex::Autolock _l(mLock);
+
return mpAudioPolicy->start_input(mpAudioPolicy, input);
}
@@ -300,6 +374,7 @@ status_t AudioPolicyService::stopInput(audio_io_handle_t input)
return NO_INIT;
}
Mutex::Autolock _l(mLock);
+
return mpAudioPolicy->stop_input(mpAudioPolicy, input);
}
@@ -310,6 +385,16 @@ void AudioPolicyService::releaseInput(audio_io_handle_t input)
}
Mutex::Autolock _l(mLock);
mpAudioPolicy->release_input(mpAudioPolicy, input);
+
+ ssize_t index = mInputs.indexOfKey(input);
+ if (index < 0) {
+ return;
+ }
+ InputDesc *inputDesc = mInputs.valueAt(index);
+ setPreProcessorEnabled(inputDesc, false);
+ inputDesc->mEffects.clear();
+ delete inputDesc;
+ mInputs.removeItemsAt(index);
}
status_t AudioPolicyService::initStreamVolume(audio_stream_type_t stream,
@@ -384,7 +469,7 @@ audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *de
}
status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
- audio_io_handle_t output,
+ audio_io_handle_t io,
uint32_t strategy,
int session,
int id)
@@ -392,7 +477,7 @@ status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc,
if (mpAudioPolicy == NULL) {
return NO_INIT;
}
- return mpAudioPolicy->register_effect(mpAudioPolicy, desc, output, strategy, session, id);
+ return mpAudioPolicy->register_effect(mpAudioPolicy, desc, io, strategy, session, id);
}
status_t AudioPolicyService::unregisterEffect(int id)
@@ -489,6 +574,15 @@ status_t AudioPolicyService::dumpPermissionDenial(int fd)
return NO_ERROR;
}
+void AudioPolicyService::setPreProcessorEnabled(InputDesc *inputDesc, bool enabled)
+{
+ Vector<sp<AudioEffect> > fxVector = inputDesc->mEffects;
+ for (size_t i = 0; i < fxVector.size(); i++) {
+ sp<AudioEffect> fx = fxVector.itemAt(i);
+ fx->setEnabled(enabled);
+ }
+}
+
status_t AudioPolicyService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
@@ -918,6 +1012,300 @@ int AudioPolicyService::setVoiceVolume(float volume, int delayMs)
return (int)mAudioCommandThread->voiceVolumeCommand(volume, delayMs);
}
+// ----------------------------------------------------------------------------
+// Audio pre-processing configuration
+// ----------------------------------------------------------------------------
+
+const char *AudioPolicyService::kInputSourceNames[AUDIO_SOURCE_CNT -1] = {
+ MIC_SRC_TAG,
+ VOICE_UL_SRC_TAG,
+ VOICE_DL_SRC_TAG,
+ VOICE_CALL_SRC_TAG,
+ CAMCORDER_SRC_TAG,
+ VOICE_REC_SRC_TAG,
+ VOICE_COMM_SRC_TAG
+};
+
+// returns the audio_source_t enum corresponding to the input source name or
+// AUDIO_SOURCE_CNT is no match found
+audio_source_t AudioPolicyService::inputSourceNameToEnum(const char *name)
+{
+ int i;
+ for (i = AUDIO_SOURCE_MIC; i < AUDIO_SOURCE_CNT; i++) {
+ if (strcmp(name, kInputSourceNames[i - AUDIO_SOURCE_MIC]) == 0) {
+ LOGV("inputSourceNameToEnum found source %s %d", name, i);
+ break;
+ }
+ }
+ return (audio_source_t)i;
+}
+
+size_t AudioPolicyService::growParamSize(char *param,
+ size_t size,
+ size_t *curSize,
+ size_t *totSize)
+{
+ // *curSize is at least sizeof(effect_param_t) + 2 * sizeof(int)
+ size_t pos = ((*curSize - 1 ) / size + 1) * size;
+
+ if (pos + size > *totSize) {
+ while (pos + size > *totSize) {
+ *totSize += ((*totSize + 7) / 8) * 4;
+ }
+ param = (char *)realloc(param, *totSize);
+ }
+ *curSize = pos + size;
+ return pos;
+}
+
+size_t AudioPolicyService::readParamValue(cnode *node,
+ char *param,
+ size_t *curSize,
+ size_t *totSize)
+{
+ if (strncmp(node->name, SHORT_TAG, sizeof(SHORT_TAG) + 1) == 0) {
+ size_t pos = growParamSize(param, sizeof(short), curSize, totSize);
+ *(short *)((char *)param + pos) = (short)atoi(node->value);
+ LOGV("readParamValue() reading short %d", *(short *)((char *)param + pos));
+ return sizeof(short);
+ } else if (strncmp(node->name, INT_TAG, sizeof(INT_TAG) + 1) == 0) {
+ size_t pos = growParamSize(param, sizeof(int), curSize, totSize);
+ *(int *)((char *)param + pos) = atoi(node->value);
+ LOGV("readParamValue() reading int %d", *(int *)((char *)param + pos));
+ return sizeof(int);
+ } else if (strncmp(node->name, FLOAT_TAG, sizeof(FLOAT_TAG) + 1) == 0) {
+ size_t pos = growParamSize(param, sizeof(float), curSize, totSize);
+ *(float *)((char *)param + pos) = (float)atof(node->value);
+ LOGV("readParamValue() reading float %f",*(float *)((char *)param + pos));
+ return sizeof(float);
+ } else if (strncmp(node->name, BOOL_TAG, sizeof(BOOL_TAG) + 1) == 0) {
+ size_t pos = growParamSize(param, sizeof(bool), curSize, totSize);
+ if (strncmp(node->value, "false", strlen("false") + 1) == 0) {
+ *(bool *)((char *)param + pos) = false;
+ } else {
+ *(bool *)((char *)param + pos) = true;
+ }
+ LOGV("readParamValue() reading bool %s",*(bool *)((char *)param + pos) ? "true" : "false");
+ return sizeof(bool);
+ } else if (strncmp(node->name, STRING_TAG, sizeof(STRING_TAG) + 1) == 0) {
+ size_t len = strnlen(node->value, EFFECT_STRING_LEN_MAX);
+ if (*curSize + len + 1 > *totSize) {
+ *totSize = *curSize + len + 1;
+ param = (char *)realloc(param, *totSize);
+ }
+ strncpy(param + *curSize, node->value, len);
+ *curSize += len;
+ param[*curSize] = '\0';
+ LOGV("readParamValue() reading string %s", param + *curSize - len);
+ return len;
+ }
+ LOGW("readParamValue() unknown param type %s", node->name);
+ return 0;
+}
+
+effect_param_t *AudioPolicyService::loadEffectParameter(cnode *root)
+{
+ cnode *param;
+ cnode *value;
+ size_t curSize = sizeof(effect_param_t);
+ size_t totSize = sizeof(effect_param_t) + 2 * sizeof(int);
+ effect_param_t *fx_param = (effect_param_t *)malloc(totSize);
+
+ param = config_find(root, PARAM_TAG);
+ value = config_find(root, VALUE_TAG);
+ if (param == NULL && value == NULL) {
+ // try to parse simple parameter form {int int}
+ param = root->first_child;
+ if (param) {
+ // Note: that a pair of random strings is read as 0 0
+ int *ptr = (int *)fx_param->data;
+ int *ptr2 = (int *)((char *)param + sizeof(effect_param_t));
+ LOGW("loadEffectParameter() ptr %p ptr2 %p", ptr, ptr2);
+ *ptr++ = atoi(param->name);
+ *ptr = atoi(param->value);
+ fx_param->psize = sizeof(int);
+ fx_param->vsize = sizeof(int);
+ return fx_param;
+ }
+ }
+ if (param == NULL || value == NULL) {
+ LOGW("loadEffectParameter() invalid parameter description %s", root->name);
+ goto error;
+ }
+
+ fx_param->psize = 0;
+ param = param->first_child;
+ while (param) {
+ LOGV("loadEffectParameter() reading param of type %s", param->name);
+ size_t size = readParamValue(param, (char *)fx_param, &curSize, &totSize);
+ if (size == 0) {
+ goto error;
+ }
+ fx_param->psize += size;
+ param = param->next;
+ }
+
+ // align start of value field on 32 bit boundary
+ curSize = ((curSize - 1 ) / sizeof(int) + 1) * sizeof(int);
+
+ fx_param->vsize = 0;
+ value = value->first_child;
+ while (value) {
+ LOGV("loadEffectParameter() reading value of type %s", value->name);
+ size_t size = readParamValue(value, (char *)fx_param, &curSize, &totSize);
+ if (size == 0) {
+ goto error;
+ }
+ fx_param->vsize += size;
+ value = value->next;
+ }
+
+ return fx_param;
+
+error:
+ delete fx_param;
+ return NULL;
+}
+
+void AudioPolicyService::loadEffectParameters(cnode *root, Vector <effect_param_t *>& params)
+{
+ cnode *node = root->first_child;
+ while (node) {
+ LOGV("loadEffectParameters() loading param %s", node->name);
+ effect_param_t *param = loadEffectParameter(node);
+ if (param == NULL) {
+ node = node->next;
+ continue;
+ }
+ params.add(param);
+ node = node->next;
+ }
+}
+
+AudioPolicyService::InputSourceDesc *AudioPolicyService::loadInputSource(
+ cnode *root,
+ const Vector <EffectDesc *>& effects)
+{
+ cnode *node = root->first_child;
+ if (node == NULL) {
+ LOGW("loadInputSource() empty element %s", root->name);
+ return NULL;
+ }
+ InputSourceDesc *source = new InputSourceDesc();
+ while (node) {
+ size_t i;
+ for (i = 0; i < effects.size(); i++) {
+ if (strncmp(effects[i]->mName, node->name, EFFECT_STRING_LEN_MAX) == 0) {
+ LOGV("loadInputSource() found effect %s in list", node->name);
+ break;
+ }
+ }
+ if (i == effects.size()) {
+ LOGV("loadInputSource() effect %s not in list", node->name);
+ node = node->next;
+ continue;
+ }
+ EffectDesc *effect = new EffectDesc(*effects[i]);
+ loadEffectParameters(node, effect->mParams);
+ LOGV("loadInputSource() adding effect %s uuid %08x", effect->mName, effect->mUuid.timeLow);
+ source->mEffects.add(effect);
+ node = node->next;
+ }
+ if (source->mEffects.size() == 0) {
+ LOGW("loadInputSource() no valid effects found in source %s", root->name);
+ delete source;
+ return NULL;
+ }
+ return source;
+}
+
+status_t AudioPolicyService::loadInputSources(cnode *root, const Vector <EffectDesc *>& effects)
+{
+ cnode *node = config_find(root, PREPROCESSING_TAG);
+ if (node == NULL) {
+ return -ENOENT;
+ }
+ node = node->first_child;
+ while (node) {
+ audio_source_t source = inputSourceNameToEnum(node->name);
+ if (source == AUDIO_SOURCE_CNT) {
+ LOGW("loadInputSources() invalid input source %s", node->name);
+ node = node->next;
+ continue;
+ }
+ LOGV("loadInputSources() loading input source %s", node->name);
+ InputSourceDesc *desc = loadInputSource(node, effects);
+ if (desc == NULL) {
+ node = node->next;
+ continue;
+ }
+ mInputSources.add(source, desc);
+ node = node->next;
+ }
+ return NO_ERROR;
+}
+
+AudioPolicyService::EffectDesc *AudioPolicyService::loadEffect(cnode *root)
+{
+ cnode *node = config_find(root, UUID_TAG);
+ if (node == NULL) {
+ return NULL;
+ }
+ effect_uuid_t uuid;
+ if (AudioEffect::stringToGuid(node->value, &uuid) != NO_ERROR) {
+ LOGW("loadEffect() invalid uuid %s", node->value);
+ return NULL;
+ }
+ EffectDesc *effect = new EffectDesc();
+ effect->mName = strdup(root->name);
+ memcpy(&effect->mUuid, &uuid, sizeof(effect_uuid_t));
+
+ return effect;
+}
+
+status_t AudioPolicyService::loadEffects(cnode *root, Vector <EffectDesc *>& effects)
+{
+ cnode *node = config_find(root, EFFECTS_TAG);
+ if (node == NULL) {
+ return -ENOENT;
+ }
+ node = node->first_child;
+ while (node) {
+ LOGV("loadEffects() loading effect %s", node->name);
+ EffectDesc *effect = loadEffect(node);
+ if (effect == NULL) {
+ node = node->next;
+ continue;
+ }
+ effects.add(effect);
+ node = node->next;
+ }
+ return NO_ERROR;
+}
+
+status_t AudioPolicyService::loadPreProcessorConfig(const char *path)
+{
+ cnode *root;
+ char *data;
+
+ data = (char *)load_file(path, NULL);
+ if (data == NULL) {
+ return -ENODEV;
+ }
+ root = config_node("", "");
+ config_load(root, data);
+
+ Vector <EffectDesc *> effects;
+ loadEffects(root, effects);
+ loadInputSources(root, effects);
+
+ config_free(root);
+ free(root);
+ free(data);
+
+ return NO_ERROR;
+}
+
/* implementation of the interface to the policy manager */
extern "C" {
diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h
index b830120..62ad29e 100644
--- a/services/audioflinger/AudioPolicyService.h
+++ b/services/audioflinger/AudioPolicyService.h
@@ -17,14 +17,17 @@
#ifndef ANDROID_AUDIOPOLICYSERVICE_H
#define ANDROID_AUDIOPOLICYSERVICE_H
-#include <media/IAudioPolicyService.h>
-#include <media/ToneGenerator.h>
+#include <cutils/misc.h>
+#include <cutils/config_utils.h>
#include <utils/Vector.h>
+#include <utils/SortedVector.h>
#include <binder/BinderService.h>
-
#include <system/audio.h>
#include <system/audio_policy.h>
#include <hardware/audio_policy.h>
+#include <media/IAudioPolicyService.h>
+#include <media/ToneGenerator.h>
+#include <media/AudioEffect.h>
namespace android {
@@ -78,7 +81,8 @@ public:
uint32_t format = AUDIO_FORMAT_DEFAULT,
uint32_t channels = 0,
audio_in_acoustics_t acoustics =
- (audio_in_acoustics_t)0);
+ (audio_in_acoustics_t)0,
+ int audioSession = 0);
virtual status_t startInput(audio_io_handle_t input);
virtual status_t stopInput(audio_io_handle_t input);
virtual void releaseInput(audio_io_handle_t input);
@@ -93,7 +97,7 @@ public:
virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc);
virtual status_t registerEffect(effect_descriptor_t *desc,
- audio_io_handle_t output,
+ audio_io_handle_t io,
uint32_t strategy,
int session,
int id);
@@ -218,6 +222,51 @@ private:
String8 mName; // string used by wake lock fo delayed commands
};
+ class EffectDesc {
+ public:
+ EffectDesc() {}
+ virtual ~EffectDesc() {}
+ char *mName;
+ effect_uuid_t mUuid;
+ Vector <effect_param_t *> mParams;
+ };
+
+ class InputSourceDesc {
+ public:
+ InputSourceDesc() {}
+ virtual ~InputSourceDesc() {}
+ Vector <EffectDesc *> mEffects;
+ };
+
+
+ class InputDesc {
+ public:
+ InputDesc() {}
+ virtual ~InputDesc() {}
+ int mSessionId;
+ Vector< sp<AudioEffect> >mEffects;
+ };
+
+ static const char *kInputSourceNames[AUDIO_SOURCE_CNT -1];
+
+ void setPreProcessorEnabled(InputDesc *inputDesc, bool enabled);
+ status_t loadPreProcessorConfig(const char *path);
+ status_t loadEffects(cnode *root, Vector <EffectDesc *>& effects);
+ EffectDesc *loadEffect(cnode *root);
+ status_t loadInputSources(cnode *root, const Vector <EffectDesc *>& effects);
+ audio_source_t inputSourceNameToEnum(const char *name);
+ InputSourceDesc *loadInputSource(cnode *root, const Vector <EffectDesc *>& effects);
+ void loadEffectParameters(cnode *root, Vector <effect_param_t *>& params);
+ effect_param_t *loadEffectParameter(cnode *root);
+ size_t readParamValue(cnode *node,
+ char *param,
+ size_t *curSize,
+ size_t *totSize);
+ size_t growParamSize(char *param,
+ size_t size,
+ size_t *curSize,
+ size_t *totSize);
+
// Internal dump utilities.
status_t dumpPermissionDenial(int fd);
@@ -226,9 +275,10 @@ private:
// device connection state or routing
sp <AudioCommandThread> mAudioCommandThread; // audio commands thread
sp <AudioCommandThread> mTonePlaybackThread; // tone playback thread
-
struct audio_policy_device *mpAudioPolicyDev;
struct audio_policy *mpAudioPolicy;
+ KeyedVector< audio_source_t, InputSourceDesc* > mInputSources;
+ KeyedVector< audio_io_handle_t, InputDesc* > mInputs;
};
}; // namespace android