summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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