diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 522 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 157 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.cpp | 396 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.h | 62 |
4 files changed, 924 insertions, 213 deletions
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 |