diff options
author | Eric Laurent <elaurent@google.com> | 2010-07-13 04:45:46 -0700 |
---|---|---|
committer | Eric Laurent <elaurent@google.com> | 2010-07-20 10:31:57 -0700 |
commit | 8ed6ed0b6216a9dfcbcd6a5ba6a62d28a901baec (patch) | |
tree | 0969f3a936ab2f1e7493146eece22edf5f2f39ec /services | |
parent | ff7049ab2886acc73e145367118646f7741ce333 (diff) | |
download | frameworks_base-8ed6ed0b6216a9dfcbcd6a5ba6a62d28a901baec.zip frameworks_base-8ed6ed0b6216a9dfcbcd6a5ba6a62d28a901baec.tar.gz frameworks_base-8ed6ed0b6216a9dfcbcd6a5ba6a62d28a901baec.tar.bz2 |
Audio policy manager changes for audio effects
Added methods for audio effects management by audio policy manager.
- control of total CPU load and memory used by effect engines
- selection of output stream for global effects
- added audio session id in parameter list for startOutput() and stopOutput().
this is not used in default audio policy manager implementation.
Modifications of audio effect framework in AudioFlinger to allow moving and reconfiguring
effect engines from one output mixer thread to another when audio tracks in the same session
are moved or when requested by audio policy manager.
Also fixed mutex deadlock problem with effect chains locks.
Change-Id: Ida43484b06e9b890d6b9e53c13958d042720ebdb
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 412 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 50 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyManagerBase.cpp | 210 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.cpp | 133 | ||||
-rw-r--r-- | services/audioflinger/AudioPolicyService.h | 47 |
5 files changed, 652 insertions, 200 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index b38a5c8..b88e69d 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -63,6 +63,8 @@ // ---------------------------------------------------------------------------- +extern const char * const gEffectLibPath; + namespace android { static const char* kDeadlockedString = "AudioFlinger may be deadlocked\n"; @@ -127,8 +129,7 @@ static bool settingsAllowed() { AudioFlinger::AudioFlinger() : BnAudioFlinger(), - mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1), - mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0) + mAudioHardware(0), mMasterVolume(1.0f), mMasterMute(false), mNextUniqueId(1) { mHardwareStatus = AUDIO_HW_IDLE; @@ -321,13 +322,19 @@ sp<IAudioTrack> AudioFlinger::createTrack( mClients.add(pid, client); } - // If no audio session id is provided, create one here - // TODO: enforce same stream type for all tracks in same audio session? - // TODO: prevent same audio session on different output threads LOGV("createTrack() sessionId: %d", (sessionId == NULL) ? -2 : *sessionId); - if (sessionId != NULL && *sessionId != 0) { + if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { + // prevent same audio session on different output threads + for (size_t i = 0; i < mPlaybackThreads.size(); i++) { + if (mPlaybackThreads.keyAt(i) != output && + mPlaybackThreads.valueAt(i)->hasAudioSession(*sessionId)) { + lStatus = BAD_VALUE; + goto Exit; + } + } lSessionId = *sessionId; } else { + // if no audio session id is provided, create one here lSessionId = nextUniqueId(); if (sessionId != NULL) { *sessionId = lSessionId; @@ -1141,6 +1148,23 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra { // scope for mLock Mutex::Autolock _l(mLock); + + // all tracks in same audio session must share the same routing strategy otherwise + // conflicts will happen when tracks are moved from one output to another by audio policy + // manager + uint32_t strategy = + AudioSystem::getStrategyForStream((AudioSystem::stream_type)streamType); + for (size_t i = 0; i < mTracks.size(); ++i) { + sp<Track> t = mTracks[i]; + if (t != 0) { + if (sessionId == t->sessionId() && + strategy != AudioSystem::getStrategyForStream((AudioSystem::stream_type)t->type())) { + lStatus = BAD_VALUE; + goto Exit; + } + } + } + track = new Track(this, client, streamType, sampleRate, format, channelCount, frameCount, sharedBuffer, sessionId); if (track->getCblk() == NULL || track->name() < 0) { @@ -1153,6 +1177,7 @@ sp<AudioFlinger::PlaybackThread::Track> AudioFlinger::PlaybackThread::createTra if (chain != 0) { LOGV("createTrack_l() setting main buffer %p", chain->inBuffer()); track->setMainBuffer(chain->inBuffer()); + chain->setStrategy(AudioSystem::getStrategyForStream((AudioSystem::stream_type)track->type())); } } lStatus = NO_ERROR; @@ -1344,7 +1369,16 @@ void AudioFlinger::PlaybackThread::readOutputParameters() mMixBuffer = new int16_t[mFrameCount * 2]; memset(mMixBuffer, 0, mFrameCount * 2 * sizeof(int16_t)); - //TODO handle effects reconfig + // force reconfiguration of effect chains and engines to take new buffer size and audio + // parameters into account + // Note that mLock is not held when readOutputParameters() is called from the constructor + // but in this case nothing is done below as no audio sessions have effect yet so it doesn't + // matter. + // create a copy of mEffectChains as calling moveEffectChain_l() can reorder some effect chains + Vector< sp<EffectChain> > effectChains = mEffectChains; + for (size_t i = 0; i < effectChains.size(); i ++) { + mAudioFlinger->moveEffectChain_l(effectChains[i]->sessionId(), this, this); + } } status_t AudioFlinger::PlaybackThread::getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames) @@ -1369,7 +1403,8 @@ bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) for (size_t i = 0; i < mTracks.size(); ++i) { sp<Track> track = mTracks[i]; - if (sessionId == track->sessionId()) { + if (sessionId == track->sessionId() && + !(track->mCblk->flags & CBLK_INVALID_MSK)) { return true; } } @@ -1377,6 +1412,23 @@ bool AudioFlinger::PlaybackThread::hasAudioSession(int sessionId) return false; } +uint32_t AudioFlinger::PlaybackThread::getStrategyForSession_l(int sessionId) +{ + // session AudioSystem::SESSION_OUTPUT_MIX is placed in same strategy as MUSIC stream so that + // it is moved to correct output by audio policy manager when A2DP is connected or disconnected + if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) { + return AudioSystem::getStrategyForStream(AudioSystem::MUSIC); + } + for (size_t i = 0; i < mTracks.size(); i++) { + sp<Track> track = mTracks[i]; + if (sessionId == track->sessionId() && + !(track->mCblk->flags & CBLK_INVALID_MSK)) { + return AudioSystem::getStrategyForStream((AudioSystem::stream_type) track->type()); + } + } + return AudioSystem::getStrategyForStream(AudioSystem::MUSIC); +} + sp<AudioFlinger::EffectChain> AudioFlinger::PlaybackThread::getEffectChain(int sessionId) { Mutex::Autolock _l(mLock); @@ -1503,8 +1555,7 @@ bool AudioFlinger::MixerThread::threadLoop() // prevent any changes in effect chain list and in each effect chain // during mixing and effect process as the audio buffers could be deleted // or modified if an effect is created or deleted - lockEffectChains_l(); - effectChains = mEffectChains; + lockEffectChains_l(effectChains); } if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { @@ -1540,7 +1591,7 @@ bool AudioFlinger::MixerThread::threadLoop() effectChains[i]->process_l(); } // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); #ifdef LVMX int audioOutputType = LifeVibes::getMixerType(mId, mType); if (LifeVibes::audioOutputTypeIsLifeVibes(audioOutputType)) { @@ -1571,7 +1622,7 @@ bool AudioFlinger::MixerThread::threadLoop() mStandby = false; } else { // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); usleep(sleepTime); } @@ -1625,7 +1676,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track } #endif // Delegate master volume control to effect in output mix effect chain if needed - sp<EffectChain> chain = getEffectChain_l(0); + sp<EffectChain> chain = getEffectChain_l(AudioSystem::SESSION_OUTPUT_MIX); if (chain != 0) { uint32_t v = (uint32_t)(masterVolume * (1 << 24)); chain->setVolume_l(&v, &v); @@ -1814,8 +1865,10 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track void AudioFlinger::MixerThread::invalidateTracks(int streamType) { - LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", this, streamType, mTracks.size()); + LOGV ("MixerThread::invalidateTracks() mixer %p, streamType %d, mTracks.size %d", + this, streamType, mTracks.size()); Mutex::Autolock _l(mLock); + size_t size = mTracks.size(); for (size_t i = 0; i < size; i++) { sp<Track> t = mTracks[i]; @@ -2070,7 +2123,6 @@ bool AudioFlinger::DirectOutputThread::threadLoop() // hardware resources as soon as possible nsecs_t standbyDelay = microseconds(activeSleepTime*2); - while (!exitPending()) { bool rampVolume; @@ -2246,7 +2298,8 @@ bool AudioFlinger::DirectOutputThread::threadLoop() if (UNLIKELY(trackToRemove != 0)) { mActiveTracks.remove(trackToRemove); if (!effectChains.isEmpty()) { - LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), trackToRemove->sessionId()); + LOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(), + trackToRemove->sessionId()); effectChains[0]->stopTrack(); } if (trackToRemove->isTerminated()) { @@ -2255,7 +2308,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } - lockEffectChains_l(); + lockEffectChains_l(effectChains); } if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { @@ -2301,7 +2354,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() for (size_t i = 0; i < effectChains.size(); i ++) { effectChains[i]->process_l(); } - unlockEffectChains(); + unlockEffectChains(effectChains); mLastWriteTime = systemTime(); mInWrite = true; @@ -2312,7 +2365,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() mInWrite = false; mStandby = false; } else { - unlockEffectChains(); + unlockEffectChains(effectChains); usleep(sleepTime); } @@ -2505,8 +2558,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() // prevent any changes in effect chain list and in each effect chain // during mixing and effect process as the audio buffers could be deleted // or modified if an effect is created or deleted - lockEffectChains_l(); - effectChains = mEffectChains; + lockEffectChains_l(effectChains); } if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) { @@ -2547,7 +2599,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() effectChains[i]->process_l(); } // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); standbyTime = systemTime() + kStandbyTimeInNsecs; for (size_t i = 0; i < outputTracks.size(); i++) { @@ -2557,7 +2609,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() mBytesWritten += mixBufferSize; } else { // enable changes in effect chain - unlockEffectChains(); + unlockEffectChains(effectChains); usleep(sleepTime); } @@ -2859,7 +2911,9 @@ void AudioFlinger::PlaybackThread::Track::destroy() if (thread != 0) { if (!isOutputTrack()) { if (mState == ACTIVE || mState == RESUMING) { - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + AudioSystem::stopOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); } AudioSystem::releaseOutput(thread->id()); } @@ -2966,7 +3020,9 @@ status_t AudioFlinger::PlaybackThread::Track::start() if (!isOutputTrack() && state != ACTIVE && state != RESUMING) { thread->mLock.unlock(); - status = AudioSystem::startOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + status = AudioSystem::startOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); thread->mLock.lock(); } if (status == NO_ERROR) { @@ -2999,7 +3055,9 @@ void AudioFlinger::PlaybackThread::Track::stop() } if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) { thread->mLock.unlock(); - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + AudioSystem::stopOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); thread->mLock.lock(); } } @@ -3016,7 +3074,9 @@ void AudioFlinger::PlaybackThread::Track::pause() LOGV("ACTIVE/RESUMING => PAUSING (%d) on thread %p", mName, thread.get()); if (!isOutputTrack()) { thread->mLock.unlock(); - AudioSystem::stopOutput(thread->id(), (AudioSystem::stream_type)mStreamType); + AudioSystem::stopOutput(thread->id(), + (AudioSystem::stream_type)mStreamType, + mSessionId); thread->mLock.lock(); } } @@ -3585,7 +3645,7 @@ sp<IAudioRecord> AudioFlinger::openRecord( } // If no audio session id is provided, create one here - if (sessionId != NULL && *sessionId != 0) { + if (sessionId != NULL && *sessionId != AudioSystem::SESSION_OUTPUT_MIX) { lSessionId = *sessionId; } else { lSessionId = nextUniqueId(); @@ -4416,8 +4476,8 @@ status_t AudioFlinger::setStreamOutput(uint32_t stream, int output) thread->type() != PlaybackThread::DIRECT) { MixerThread *srcThread = (MixerThread *)thread; srcThread->invalidateTracks(stream); - } } + } return NO_ERROR; } @@ -4472,12 +4532,26 @@ int AudioFlinger::nextUniqueId() status_t AudioFlinger::loadEffectLibrary(const char *libPath, int *handle) { + // check calling permissions + if (!settingsAllowed()) { + return PERMISSION_DENIED; + } + // only allow libraries loaded from /system/lib/soundfx for now + if (strncmp(gEffectLibPath, libPath, strlen(gEffectLibPath)) != 0) { + return PERMISSION_DENIED; + } + Mutex::Autolock _l(mLock); return EffectLoadLibrary(libPath, handle); } status_t AudioFlinger::unloadEffectLibrary(int handle) { + // check calling permissions + if (!settingsAllowed()) { + return PERMISSION_DENIED; + } + Mutex::Autolock _l(mLock); return EffectUnloadLibrary(handle); } @@ -4522,7 +4596,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, output %d", + pid, effectClient.get(), priority, sessionId, output); if (pDesc == NULL) { lStatus = BAD_VALUE; @@ -4577,7 +4652,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // an auxiliary version of this effect type is available found = true; memcpy(&d, &desc, sizeof(effect_descriptor_t)); - if (sessionId != 0 || + if (sessionId != AudioSystem::SESSION_OUTPUT_MIX || (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { break; } @@ -4590,22 +4665,23 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, } // For same effect type, chose auxiliary version over insert version if // connect to output mix (Compliance to OpenSL ES) - if (sessionId == 0 && + if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) { memcpy(&desc, &d, sizeof(effect_descriptor_t)); } } // Do not allow auxiliary effects on a session different from 0 (output mix) - if (sessionId != 0 && + if (sessionId != AudioSystem::SESSION_OUTPUT_MIX && (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { lStatus = INVALID_OPERATION; goto Exit; } - // Session -1 is reserved for output stage effects that can only be created - // by audio policy manager (running in same process) - if (sessionId == -1 && getpid() != IPCThreadState::self()->getCallingPid()) { + // Session AudioSystem::SESSION_OUTPUT_STAGE is reserved for output stage effects + // that can only be created by audio policy manager (running in same process) + if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE && + getpid() != IPCThreadState::self()->getCallingPid()) { lStatus = INVALID_OPERATION; goto Exit; } @@ -4617,13 +4693,14 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, // output threads. // TODO: allow attachment of effect to inputs if (output == 0) { - if (sessionId <= 0) { - // default to first output - // TODO: define criteria to choose output when not specified. Or - // receive output from audio policy manager - if (mPlaybackThreads.size() != 0) { - output = mPlaybackThreads.keyAt(0); - } + if (sessionId == AudioSystem::SESSION_OUTPUT_STAGE) { + // output must be specified by AudioPolicyManager when using session + // AudioSystem::SESSION_OUTPUT_STAGE + lStatus = BAD_VALUE; + goto Exit; + } else if (sessionId == AudioSystem::SESSION_OUTPUT_MIX) { + output = AudioSystem::getOutputForEffect(&desc); + LOGV("createEffect() got output %d for effect %s", output, desc.name); } else { // look for the thread where the specified audio session is present for (size_t i = 0; i < mPlaybackThreads.size(); i++) { @@ -4636,7 +4713,7 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, } PlaybackThread *thread = checkPlaybackThread_l(output); if (thread == NULL) { - LOGE("unknown output thread"); + LOGE("createEffect() unknown output thread"); lStatus = BAD_VALUE; goto Exit; } @@ -4651,7 +4728,8 @@ sp<IEffect> AudioFlinger::createEffect(pid_t pid, } // create effect on selected output trhead - handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus); + handle = thread->createEffect_l(client, effectClient, priority, sessionId, + &desc, enabled, &lStatus); if (handle != 0 && id != NULL) { *id = handle->id(); } @@ -4664,31 +4742,64 @@ Exit: return handle; } -status_t AudioFlinger::registerEffectResource_l(effect_descriptor_t *desc) { - if (mTotalEffectsCpuLoad + desc->cpuLoad > MAX_EFFECTS_CPU_LOAD) { - LOGW("registerEffectResource() CPU Load limit exceeded for Fx %s, CPU %f MIPS", - desc->name, (float)desc->cpuLoad/10); - return INVALID_OPERATION; +status_t AudioFlinger::moveEffects(int session, int srcOutput, int dstOutput) +{ + LOGV("moveEffects() session %d, srcOutput %d, dstOutput %d", + session, srcOutput, dstOutput); + Mutex::Autolock _l(mLock); + if (srcOutput == dstOutput) { + LOGW("moveEffects() same dst and src outputs %d", dstOutput); + return NO_ERROR; } - if (mTotalEffectsMemory + desc->memoryUsage > MAX_EFFECTS_MEMORY) { - LOGW("registerEffectResource() memory limit exceeded for Fx %s, Memory %d KB", - desc->name, desc->memoryUsage); - return INVALID_OPERATION; + PlaybackThread *srcThread = checkPlaybackThread_l(srcOutput); + if (srcThread == NULL) { + LOGW("moveEffects() bad srcOutput %d", srcOutput); + return BAD_VALUE; + } + PlaybackThread *dstThread = checkPlaybackThread_l(dstOutput); + if (dstThread == NULL) { + LOGW("moveEffects() bad dstOutput %d", dstOutput); + return BAD_VALUE; } - mTotalEffectsCpuLoad += desc->cpuLoad; - mTotalEffectsMemory += desc->memoryUsage; - LOGV("registerEffectResource_l() effect %s, CPU %d, memory %d", - desc->name, desc->cpuLoad, desc->memoryUsage); - LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); + + Mutex::Autolock _dl(dstThread->mLock); + Mutex::Autolock _sl(srcThread->mLock); + moveEffectChain_l(session, srcThread, dstThread); + return NO_ERROR; } -void AudioFlinger::unregisterEffectResource_l(effect_descriptor_t *desc) { - mTotalEffectsCpuLoad -= desc->cpuLoad; - mTotalEffectsMemory -= desc->memoryUsage; - LOGV("unregisterEffectResource_l() effect %s, CPU %d, memory %d", - desc->name, desc->cpuLoad, desc->memoryUsage); - LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); +// moveEffectChain_l mustbe called with both srcThread and dstThread mLocks held +status_t AudioFlinger::moveEffectChain_l(int session, + AudioFlinger::PlaybackThread *srcThread, + AudioFlinger::PlaybackThread *dstThread) +{ + LOGV("moveEffectChain_l() session %d from thread %p to thread %p", + session, srcThread, dstThread); + + sp<EffectChain> chain = srcThread->getEffectChain_l(session); + if (chain == 0) { + LOGW("moveEffectChain_l() effect chain for session %d not on source thread %p", + session, srcThread); + return INVALID_OPERATION; + } + + // remove chain first. This is usefull only if reconfiguring effect chain on same output thread, + // so that a new chain is created with correct parameters when first effect is added. This is + // otherwise unecessary as removeEffect_l() will remove the chain when last effect is + // removed. + srcThread->removeEffectChain_l(chain); + + // transfer all effects one by one so that new effect chain is created on new thread with + // correct buffer sizes and audio parameters and effect engines reconfigured accordingly + sp<EffectModule> effect = chain->getEffectFromId_l(0); + while (effect != 0) { + srcThread->removeEffect_l(effect); + dstThread->addEffect_l(effect); + effect = chain->getEffectFromId_l(0); + } + + return NO_ERROR; } // PlaybackThread::createEffect_l() must be called with AudioFlinger::mLock held @@ -4707,6 +4818,7 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( status_t lStatus; sp<Track> track; sp<EffectChain> chain; + bool chainCreated = false; bool effectCreated = false; bool effectRegistered = false; @@ -4718,16 +4830,18 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( // Do not allow auxiliary effect on session other than 0 if ((desc->flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY && - sessionId != 0) { - LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); + sessionId != AudioSystem::SESSION_OUTPUT_MIX) { + LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", + desc->name, sessionId); lStatus = BAD_VALUE; goto Exit; } // Do not allow effects with session ID 0 on direct output or duplicating threads // TODO: add rule for hw accelerated effects on direct outputs with non PCM format - if (sessionId == 0 && mType != MIXER) { - LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", desc->name, sessionId); + if (sessionId == AudioSystem::SESSION_OUTPUT_MIX && mType != MIXER) { + LOGW("createEffect_l() Cannot add auxiliary effect %s to session %d", + desc->name, sessionId); lStatus = BAD_VALUE; goto Exit; } @@ -4744,6 +4858,8 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( LOGV("createEffect_l() new effect chain for session %d", sessionId); chain = new EffectChain(this, sessionId); addEffectChain_l(chain); + chain->setStrategy(getStrategyForSession_l(sessionId)); + chainCreated = true; } else { effect = chain->getEffectFromDesc_l(desc); } @@ -4751,14 +4867,15 @@ 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(); // Check CPU and memory usage - lStatus = mAudioFlinger->registerEffectResource_l(desc); + lStatus = AudioSystem::registerEffect(desc, mId, chain->strategy(), sessionId, id); if (lStatus != NO_ERROR) { goto Exit; } effectRegistered = true; // create a new effect module if none present in the chain - effect = new EffectModule(this, chain, desc, mAudioFlinger->nextUniqueId(), sessionId); + effect = new EffectModule(this, chain, desc, id, sessionId); lStatus = effect->status(); if (lStatus != NO_ERROR) { goto Exit; @@ -4782,14 +4899,15 @@ sp<AudioFlinger::EffectHandle> AudioFlinger::PlaybackThread::createEffect_l( Exit: if (lStatus != NO_ERROR && lStatus != ALREADY_EXISTS) { + Mutex::Autolock _l(mLock); if (effectCreated) { - Mutex::Autolock _l(mLock); - if (chain->removeEffect_l(effect) == 0) { - removeEffectChain_l(chain); - } + chain->removeEffect_l(effect); } if (effectRegistered) { - mAudioFlinger->unregisterEffectResource_l(desc); + AudioSystem::unregisterEffect(effect->id()); + } + if (chainCreated) { + removeEffectChain_l(chain); } handle.clear(); } @@ -4800,26 +4918,71 @@ Exit: return handle; } -void AudioFlinger::PlaybackThread::disconnectEffect(const sp< EffectModule>& effect, - const wp<EffectHandle>& handle) { +// PlaybackThread::addEffect_l() must be called with AudioFlinger::mLock and +// PlaybackThread::mLock held +status_t AudioFlinger::PlaybackThread::addEffect_l(const sp<EffectModule>& effect) +{ + // check for existing effect chain with the requested audio session + int sessionId = effect->sessionId(); + sp<EffectChain> chain = getEffectChain_l(sessionId); + bool chainCreated = false; + + if (chain == 0) { + // create a new chain for this session + LOGV("addEffect_l() new effect chain for session %d", sessionId); + chain = new EffectChain(this, sessionId); + addEffectChain_l(chain); + chain->setStrategy(getStrategyForSession_l(sessionId)); + chainCreated = true; + } + LOGV("addEffect_l() %p chain %p effect %p", this, chain.get(), effect.get()); + + if (chain->getEffectFromId_l(effect->id()) != 0) { + LOGW("addEffect_l() %p effect %s already present in chain %p", + this, effect->desc().name, chain.get()); + return BAD_VALUE; + } + + status_t status = chain->addEffect_l(effect); + if (status != NO_ERROR) { + if (chainCreated) { + removeEffectChain_l(chain); + } + return status; + } + + effect->setDevice(mDevice); + effect->setMode(mAudioFlinger->getMode()); + return NO_ERROR; +} + +void AudioFlinger::PlaybackThread::removeEffect_l(const sp<EffectModule>& effect) { + + LOGV("removeEffect_l() %p effect %p", this, effect.get()); effect_descriptor_t desc = effect->desc(); + if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { + detachAuxEffect_l(effect->id()); + } + + sp<EffectChain> chain = effect->chain().promote(); + if (chain != 0) { + // remove effect chain if removing last effect + if (chain->removeEffect_l(effect) == 0) { + removeEffectChain_l(chain); + } + } else { + LOGW("removeEffect_l() %p cannot promote chain for effect %p", this, effect.get()); + } +} + +void AudioFlinger::PlaybackThread::disconnectEffect(const sp<EffectModule>& effect, + const wp<EffectHandle>& handle) { Mutex::Autolock _l(mLock); + LOGV("disconnectEffect() %p effect %p", this, effect.get()); // delete the effect module if removing last handle on it if (effect->removeHandle(handle) == 0) { - if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { - detachAuxEffect_l(effect->id()); - } - sp<EffectChain> chain = effect->chain().promote(); - if (chain != 0) { - // remove effect chain if remove last effect - if (chain->removeEffect_l(effect) == 0) { - removeEffectChain_l(chain); - } - } - mLock.unlock(); - mAudioFlinger->mLock.lock(); - mAudioFlinger->unregisterEffectResource_l(&desc); - mAudioFlinger->mLock.unlock(); + removeEffect_l(effect); + AudioSystem::unregisterEffect(effect->id()); } } @@ -4863,13 +5026,16 @@ status_t AudioFlinger::PlaybackThread::addEffectChain_l(const sp<EffectChain>& c chain->setInBuffer(buffer, ownsBuffer); chain->setOutBuffer(mMixBuffer); - // Effect chain for session -1 is inserted at end of effect chains list - // in order to be processed last as it contains output stage effects - // Effect chain for session 0 is inserted before session -1 to be processed + // Effect chain for session AudioSystem::SESSION_OUTPUT_STAGE is inserted at end of effect + // chains list in order to be processed last as it contains output stage effects + // Effect chain for session AudioSystem::SESSION_OUTPUT_MIX is inserted before + // session AudioSystem::SESSION_OUTPUT_STAGE to be processed // after track specific effects and before output stage - // Effect chain for session other than 0 is inserted at beginning of effect - // chains list to be processed before output mix effects. Relative order between - // sessions other than 0 is not important + // It is therefore mandatory that AudioSystem::SESSION_OUTPUT_MIX == 0 and + // that AudioSystem::SESSION_OUTPUT_STAGE < AudioSystem::SESSION_OUTPUT_MIX + // Effect chain for other sessions are inserted at beginning of effect + // chains list to be processed before output mix effects. Relative order between other + // sessions is not important size_t size = mEffectChains.size(); size_t i = 0; for (i = 0; i < size; i++) { @@ -4896,26 +5062,30 @@ size_t AudioFlinger::PlaybackThread::removeEffectChain_l(const sp<EffectChain>& track->setMainBuffer(mMixBuffer); } } + break; } } return mEffectChains.size(); } -void AudioFlinger::PlaybackThread::lockEffectChains_l() +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() +void AudioFlinger::PlaybackThread::unlockEffectChains( + Vector<sp <AudioFlinger::EffectChain> >& effectChains) { - Mutex::Autolock _l(mLock); - for (size_t i = 0; i < mEffectChains.size(); i++) { - mEffectChains[i]->unlock(); + 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; @@ -4927,21 +5097,23 @@ sp<AudioFlinger::EffectModule> AudioFlinger::PlaybackThread::getEffect_l(int ses return effect; } -status_t AudioFlinger::PlaybackThread::attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) +status_t AudioFlinger::PlaybackThread::attachAuxEffect( + const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) { Mutex::Autolock _l(mLock); return attachAuxEffect_l(track, EffectId); } -status_t AudioFlinger::PlaybackThread::attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) +status_t AudioFlinger::PlaybackThread::attachAuxEffect_l( + const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId) { status_t status = NO_ERROR; if (EffectId == 0) { track->setAuxBuffer(0, NULL); } else { - // Auxiliary effects are always in audio session 0 - sp<EffectModule> effect = getEffect_l(0, EffectId); + // Auxiliary effects are always in audio session AudioSystem::SESSION_OUTPUT_MIX + sp<EffectModule> effect = getEffect_l(AudioSystem::SESSION_OUTPUT_MIX, EffectId); if (effect != 0) { if ((effect->desc().flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { track->setAuxBuffer(EffectId, (int32_t *)effect->inBuffer()); @@ -5137,7 +5309,7 @@ void AudioFlinger::EffectModule::process() if ((mDescriptor.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { AudioMixer::ditherAndClamp(mConfig.inputCfg.buffer.s32, mConfig.inputCfg.buffer.s32, - mConfig.inputCfg.buffer.frameCount); + mConfig.inputCfg.buffer.frameCount/2); } // do the actual processing in the effect engine @@ -5214,7 +5386,8 @@ status_t AudioFlinger::EffectModule::configure() mConfig.outputCfg.bufferProvider.releaseBuffer = NULL; mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ; // Insert effect: - // - in session 0 or -1, always overwrites output buffer: input buffer == output buffer + // - in session AudioSystem::SESSION_OUTPUT_MIX or AudioSystem::SESSION_OUTPUT_STAGE, + // always overwrites output buffer: input buffer == output buffer // - in other sessions: // last effect in the chain accumulates in output buffer: input buffer != output buffer // other effect: overwrites output buffer: input buffer == output buffer @@ -5231,6 +5404,9 @@ status_t AudioFlinger::EffectModule::configure() mConfig.inputCfg.buffer.frameCount = thread->frameCount(); mConfig.outputCfg.buffer.frameCount = mConfig.inputCfg.buffer.frameCount; + LOGV("configure() %p thread %p buffer %p framecount %d", + this, thread.get(), mConfig.inputCfg.buffer.raw, mConfig.inputCfg.buffer.frameCount); + status_t cmdStatus; int size = sizeof(int); status_t status = (*mEffectInterface)->command(mEffectInterface, EFFECT_CMD_CONFIGURE, sizeof(effect_config_t), &mConfig, &size, &cmdStatus); @@ -5753,7 +5929,7 @@ AudioFlinger::EffectChain::EffectChain(const wp<ThreadBase>& wThread, mVolumeCtrlIdx(-1), mLeftVolume(0), mRightVolume(0), mNewLeftVolume(0), mNewRightVolume(0) { - + mStrategy = AudioSystem::getStrategyForStream(AudioSystem::MUSIC); } AudioFlinger::EffectChain::~EffectChain() @@ -5786,7 +5962,8 @@ sp<AudioFlinger::EffectModule> AudioFlinger::EffectChain::getEffectFromId_l(int size_t size = mEffects.size(); for (size_t i = 0; i < size; i++) { - if (mEffects[i]->id() == id) { + // by convention, return first effect if id provided is 0 (0 is never a valid id) + if (id == 0 || mEffects[i]->id() == id) { effect = mEffects[i]; break; } @@ -5816,21 +5993,24 @@ void AudioFlinger::EffectChain::process_l() } // addEffect_l() must be called with PlaybackThread::mLock held -status_t AudioFlinger::EffectChain::addEffect_l(sp<EffectModule>& effect) +status_t AudioFlinger::EffectChain::addEffect_l(const sp<EffectModule>& effect) { effect_descriptor_t desc = effect->desc(); uint32_t insertPref = desc.flags & EFFECT_FLAG_INSERT_MASK; Mutex::Autolock _l(mLock); + effect->setChain(this); + sp<ThreadBase> thread = mThread.promote(); + if (thread == 0) { + return NO_INIT; + } + effect->setThread(thread); if ((desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) { // Auxiliary effects are inserted at the beginning of mEffects vector as // they are processed first and accumulated in chain input buffer mEffects.insertAt(effect, 0); - sp<ThreadBase> thread = mThread.promote(); - if (thread == 0) { - return NO_INIT; - } + // the input buffer for auxiliary effect contains mono samples in // 32 bit format. This is to avoid saturation in AudoMixer // accumulation stage. Saturation is done in EffectModule::process() before diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 99816f9..a8c9a92 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -168,8 +168,7 @@ public: int *id, int *enabled); - status_t registerEffectResource_l(effect_descriptor_t *desc); - void unregisterEffectResource_l(effect_descriptor_t *desc); + virtual status_t moveEffects(int session, int srcOutput, int dstOutput); enum hardware_call_state { AUDIO_HW_IDLE = 0, @@ -619,15 +618,22 @@ private: sp<EffectChain> getEffectChain_l(int sessionId); status_t addEffectChain_l(const sp<EffectChain>& chain); size_t removeEffectChain_l(const sp<EffectChain>& chain); - void lockEffectChains_l(); - void unlockEffectChains(); + 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); - status_t attachAuxEffect(const sp<AudioFlinger::PlaybackThread::Track> track, int EffectId); - status_t attachAuxEffect_l(const sp<AudioFlinger::PlaybackThread::Track> track, 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); + struct stream_type_t { stream_type_t() : volume(1.0f), @@ -690,7 +696,10 @@ private: class MixerThread : public PlaybackThread { public: - MixerThread (const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, int id, uint32_t device); + MixerThread (const sp<AudioFlinger>& audioFlinger, + AudioStreamOut* output, + int id, + uint32_t device); virtual ~MixerThread(); // Thread virtuals @@ -701,7 +710,8 @@ private: virtual status_t dumpInternals(int fd, const Vector<String16>& args); protected: - uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove); + uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, + Vector< sp<Track> > *tracksToRemove); virtual int getTrackName_l(); virtual void deleteTrackName_l(int name); virtual uint32_t activeSleepTimeUs(); @@ -764,6 +774,9 @@ private: void audioConfigChanged_l(int event, int ioHandle, void *param2); int nextUniqueId(); + status_t moveEffectChain_l(int session, + AudioFlinger::PlaybackThread *srcThread, + AudioFlinger::PlaybackThread *dstThread); friend class AudioBuffer; @@ -931,6 +944,9 @@ private: uint32_t status() { return mStatus; } + int sessionId() { + return mSessionId; + } status_t setEnabled(bool enabled); bool isEnabled(); @@ -938,6 +954,8 @@ private: int16_t *inBuffer() { return mConfig.inputCfg.buffer.s16; } void setOutBuffer(int16_t *buffer) { mConfig.outputCfg.buffer.s16 = buffer; } int16_t *outBuffer() { return mConfig.outputCfg.buffer.s16; } + void setChain(const wp<EffectChain>& chain) { mChain = chain; } + void setThread(const wp<ThreadBase>& thread) { mThread = thread; } status_t addHandle(sp<EffectHandle>& handle); void disconnect(const wp<EffectHandle>& handle); @@ -1061,19 +1079,19 @@ private: mLock.unlock(); } - status_t addEffect_l(sp<EffectModule>& handle); + status_t addEffect_l(const sp<EffectModule>& handle); size_t removeEffect_l(const sp<EffectModule>& handle); int sessionId() { return mSessionId; } + sp<EffectModule> getEffectFromDesc_l(effect_descriptor_t *descriptor); sp<EffectModule> getEffectFromId_l(int id); bool setVolume_l(uint32_t *left, uint32_t *right); void setDevice_l(uint32_t device); void setMode_l(uint32_t mode); - void setInBuffer(int16_t *buffer, bool ownsBuffer = false) { mInBuffer = buffer; mOwnInBuffer = ownsBuffer; @@ -1092,6 +1110,10 @@ private: void stopTrack() {mActiveTrackCnt--;} int activeTracks() { return mActiveTrackCnt;} + uint32_t strategy() { return mStrategy; } + void setStrategy(uint32_t strategy) + { mStrategy = strategy; } + status_t dump(int fd, const Vector<String16>& args); protected: @@ -1112,7 +1134,7 @@ private: uint32_t mRightVolume; // previous volume on right channel uint32_t mNewLeftVolume; // new volume on left channel uint32_t mNewRightVolume; // new volume on right channel - + uint32_t mStrategy; // strategy for this effect chain }; friend class RecordThread; @@ -1142,12 +1164,6 @@ private: #endif uint32_t mMode; - // Maximum CPU load allocated to audio effects in 0.1 MIPS (ARMv5TE, 0 WS memory) units - static const uint32_t MAX_EFFECTS_CPU_LOAD = 1000; - // Maximum memory allocated to audio effects in KB - static const uint32_t MAX_EFFECTS_MEMORY = 512; - uint32_t mTotalEffectsCpuLoad; // current CPU load used by effects - uint32_t mTotalEffectsMemory; // current memory used by effects }; // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/AudioPolicyManagerBase.cpp b/services/audioflinger/AudioPolicyManagerBase.cpp index 381a958..1d87c0d 100644 --- a/services/audioflinger/AudioPolicyManagerBase.cpp +++ b/services/audioflinger/AudioPolicyManagerBase.cpp @@ -538,9 +538,11 @@ audio_io_handle_t AudioPolicyManagerBase::getOutput(AudioSystem::stream_type str return output; } -status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { - LOGV("startOutput() output %d, stream %d", output, stream); + LOGV("startOutput() output %d, stream %d, session %d", output, stream, session); ssize_t index = mOutputs.indexOfKey(output); if (index < 0) { LOGW("startOutput() unknow output %d", output); @@ -574,9 +576,11 @@ status_t AudioPolicyManagerBase::startOutput(audio_io_handle_t output, AudioSyst return NO_ERROR; } -status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { - LOGV("stopOutput() output %d, stream %d", output, stream); + LOGV("stopOutput() output %d, stream %d, session %d", output, stream, session); ssize_t index = mOutputs.indexOfKey(output); if (index < 0) { LOGW("stopOutput() unknow output %d", output); @@ -602,8 +606,12 @@ status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output, AudioSyste setOutputDevice(output, getNewDevice(output)); #ifdef WITH_A2DP - if (mA2dpOutput != 0 && !a2dpUsedForSonification() && strategy == STRATEGY_SONIFICATION) { - setStrategyMute(STRATEGY_MEDIA, false, mA2dpOutput, mOutputs.valueFor(mHardwareOutput)->mLatency*2); + if (mA2dpOutput != 0 && !a2dpUsedForSonification() && + strategy == STRATEGY_SONIFICATION) { + setStrategyMute(STRATEGY_MEDIA, + false, + mA2dpOutput, + mOutputs.valueFor(mHardwareOutput)->mLatency*2); } #endif if (output != mHardwareOutput) { @@ -826,6 +834,85 @@ status_t AudioPolicyManagerBase::getStreamVolumeIndex(AudioSystem::stream_type s return NO_ERROR; } +audio_io_handle_t AudioPolicyManagerBase::getOutputForEffect(effect_descriptor_t *desc) +{ + LOGV("getOutputForEffect()"); + // apply simple rule where global effects are attached to the same output as MUSIC streams + return getOutput(AudioSystem::MUSIC); +} + +status_t AudioPolicyManagerBase::registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) +{ + ssize_t index = mOutputs.indexOfKey(output); + if (index < 0) { + LOGW("registerEffect() unknown output %d", output); + return INVALID_OPERATION; + } + + if (mTotalEffectsCpuLoad + desc->cpuLoad > getMaxEffectsCpuLoad()) { + LOGW("registerEffect() CPU Load limit exceeded for Fx %s, CPU %f MIPS", + desc->name, (float)desc->cpuLoad/10); + return INVALID_OPERATION; + } + if (mTotalEffectsMemory + desc->memoryUsage > getMaxEffectsMemory()) { + LOGW("registerEffect() memory limit exceeded for Fx %s, Memory %d KB", + desc->name, desc->memoryUsage); + return INVALID_OPERATION; + } + mTotalEffectsCpuLoad += desc->cpuLoad; + mTotalEffectsMemory += desc->memoryUsage; + LOGV("registerEffect() effect %s, output %d, strategy %d session %d id %d", + desc->name, output, strategy, session, id); + + LOGV("registerEffect() CPU %d, memory %d", desc->cpuLoad, desc->memoryUsage); + LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); + + EffectDescriptor *pDesc = new EffectDescriptor(); + memcpy (&pDesc->mDesc, desc, sizeof(effect_descriptor_t)); + pDesc->mOutput = output; + pDesc->mStrategy = (routing_strategy)strategy; + pDesc->mSession = session; + mEffects.add(id, pDesc); + + return NO_ERROR; +} + +status_t AudioPolicyManagerBase::unregisterEffect(int id) +{ + ssize_t index = mEffects.indexOfKey(id); + if (index < 0) { + LOGW("unregisterEffect() unknown effect ID %d", id); + return INVALID_OPERATION; + } + + EffectDescriptor *pDesc = mEffects.valueAt(index); + + if (mTotalEffectsCpuLoad < pDesc->mDesc.cpuLoad) { + LOGW("unregisterEffect() CPU load %d too high for total %d", + pDesc->mDesc.cpuLoad, mTotalEffectsCpuLoad); + pDesc->mDesc.cpuLoad = mTotalEffectsCpuLoad; + } + mTotalEffectsCpuLoad -= pDesc->mDesc.cpuLoad; + if (mTotalEffectsMemory < pDesc->mDesc.memoryUsage) { + LOGW("unregisterEffect() memory %d too big for total %d", + pDesc->mDesc.memoryUsage, mTotalEffectsMemory); + pDesc->mDesc.memoryUsage = mTotalEffectsMemory; + } + mTotalEffectsMemory -= pDesc->mDesc.memoryUsage; + LOGV("unregisterEffect() effect %s, ID %d, CPU %d, memory %d", + pDesc->mDesc.name, id, pDesc->mDesc.cpuLoad, pDesc->mDesc.memoryUsage); + LOGV(" total CPU %d, total memory %d", mTotalEffectsCpuLoad, mTotalEffectsMemory); + + mEffects.removeItem(id); + delete pDesc; + + return NO_ERROR; +} + status_t AudioPolicyManagerBase::dump(int fd) { const size_t SIZE = 256; @@ -890,6 +977,19 @@ status_t AudioPolicyManagerBase::dump(int fd) write(fd, buffer, strlen(buffer)); } + snprintf(buffer, SIZE, "\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB\n", + (float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory); + write(fd, buffer, strlen(buffer)); + + snprintf(buffer, SIZE, "Registered effects:\n"); + write(fd, buffer, strlen(buffer)); + for (size_t i = 0; i < mEffects.size(); i++) { + snprintf(buffer, SIZE, "- Effect %d dump:\n", mEffects.keyAt(i)); + write(fd, buffer, strlen(buffer)); + mEffects.valueAt(i)->dump(fd); + } + + return NO_ERROR; } @@ -902,7 +1002,8 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien #ifdef AUDIO_POLICY_TEST Thread(false), #endif //AUDIO_POLICY_TEST - mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), mLimitRingtoneVolume(false) + mPhoneState(AudioSystem::MODE_NORMAL), mRingerMode(0), mMusicStopTime(0), + mLimitRingtoneVolume(false), mTotalEffectsCpuLoad(0), mTotalEffectsMemory(0) { mpClientInterface = clientInterface; @@ -938,6 +1039,7 @@ AudioPolicyManagerBase::AudioPolicyManagerBase(AudioPolicyClientInterface *clien } else { addOutput(mHardwareOutput, outputDesc); setOutputDevice(mHardwareOutput, (uint32_t)AudioSystem::DEVICE_OUT_SPEAKER, true); + //TODO: configure audio effect output stage here } updateDeviceForStrategy(); @@ -1152,6 +1254,9 @@ status_t AudioPolicyManagerBase::handleA2dpConnection(AudioSystem::audio_devices if (mA2dpOutput) { // add A2DP output descriptor addOutput(mA2dpOutput, outputDesc); + + //TODO: configure audio effect output stage here + // set initial stream volume for A2DP device applyStreamVolumes(mA2dpOutput, device); if (a2dpUsedForSonification()) { @@ -1269,6 +1374,7 @@ void AudioPolicyManagerBase::closeA2dpOutputs() AudioParameter param; param.add(String8("closing"), String8("true")); mpClientInterface->setParameters(mA2dpOutput, param.toString()); + mpClientInterface->closeOutput(mA2dpOutput); delete mOutputs.valueFor(mA2dpOutput); mOutputs.removeItem(mA2dpOutput); @@ -1282,48 +1388,54 @@ void AudioPolicyManagerBase::checkOutputForStrategy(routing_strategy strategy, u uint32_t curDevice = getDeviceForStrategy(strategy, false); bool a2dpWasUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(prevDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); bool a2dpIsUsed = AudioSystem::isA2dpDevice((AudioSystem::audio_devices)(curDevice & ~AudioSystem::DEVICE_OUT_SPEAKER)); - AudioOutputDescriptor *hwOutputDesc = mOutputs.valueFor(mHardwareOutput); - AudioOutputDescriptor *a2dpOutputDesc; + audio_io_handle_t srcOutput = 0; + audio_io_handle_t dstOutput = 0; if (a2dpWasUsed && !a2dpIsUsed) { bool dupUsed = a2dpUsedForSonification() && a2dpWasUsed && (AudioSystem::popCount(prevDevice) == 2); - + dstOutput = mHardwareOutput; if (dupUsed) { - LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy); - a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); + LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy); + srcOutput = mDuplicatedOutput; } else { - LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy); - a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); + LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy); + srcOutput = mA2dpOutput; } - for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { - if (getStrategy((AudioSystem::stream_type)i) == strategy) { - mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, mHardwareOutput); - } - } // do not change newDevice if it was already set before this call by a previous call to // getNewDevice() or checkOutputForStrategy() for a strategy with higher priority - if (newDevice == 0 && hwOutputDesc->isUsedByStrategy(strategy)) { + if (newDevice == 0 && mOutputs.valueFor(mHardwareOutput)->isUsedByStrategy(strategy)) { newDevice = getDeviceForStrategy(strategy, false); } } if (a2dpIsUsed && !a2dpWasUsed) { bool dupUsed = a2dpUsedForSonification() && a2dpIsUsed && (AudioSystem::popCount(curDevice) == 2); - audio_io_handle_t a2dpOutput; - + srcOutput = mHardwareOutput; if (dupUsed) { - LOGV("checkOutputForStrategy() moving strategy %d from duplicated", strategy); - a2dpOutputDesc = mOutputs.valueFor(mDuplicatedOutput); - a2dpOutput = mDuplicatedOutput; + LOGV("checkOutputForStrategy() moving strategy %d to duplicated", strategy); + dstOutput = mDuplicatedOutput; } else { - LOGV("checkOutputForStrategy() moving strategy %d from a2dp", strategy); - a2dpOutputDesc = mOutputs.valueFor(mA2dpOutput); - a2dpOutput = mA2dpOutput; + LOGV("checkOutputForStrategy() moving strategy %d to a2dp", strategy); + dstOutput = mA2dpOutput; } + } + if (srcOutput != 0 && dstOutput != 0) { + // Move effects associated to this strategy from previous output to new output + for (size_t i = 0; i < mEffects.size(); i++) { + EffectDescriptor *desc = mEffects.valueAt(i); + if (desc->mSession != AudioSystem::SESSION_OUTPUT_STAGE && + desc->mStrategy == strategy && + desc->mOutput == srcOutput) { + LOGV("checkOutputForStrategy() moving effect %d to output %d", mEffects.keyAt(i), dstOutput); + mpClientInterface->moveEffects(desc->mSession, srcOutput, dstOutput); + desc->mOutput = dstOutput; + } + } + // Move tracks associated to this strategy from previous output to new output for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) { if (getStrategy((AudioSystem::stream_type)i) == strategy) { - mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, a2dpOutput); + mpClientInterface->setStreamOutput((AudioSystem::stream_type)i, dstOutput); } } } @@ -1371,8 +1483,12 @@ uint32_t AudioPolicyManagerBase::getNewDevice(audio_io_handle_t output, bool fro return device; } -AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy(AudioSystem::stream_type stream) -{ +uint32_t AudioPolicyManagerBase::getStrategyForStream(AudioSystem::stream_type stream) { + return (uint32_t)getStrategy(stream); +} + +AudioPolicyManagerBase::routing_strategy AudioPolicyManagerBase::getStrategy( + AudioSystem::stream_type stream) { // stream to strategy mapping switch (stream) { case AudioSystem::VOICE_CALL: @@ -1836,6 +1952,16 @@ bool AudioPolicyManagerBase::needsDirectOuput(AudioSystem::stream_type stream, (format !=0 && !AudioSystem::isLinearPCM(format))); } +uint32_t AudioPolicyManagerBase::getMaxEffectsCpuLoad() +{ + return MAX_EFFECTS_CPU_LOAD; +} + +uint32_t AudioPolicyManagerBase::getMaxEffectsMemory() +{ + return MAX_EFFECTS_MEMORY; +} + // --- AudioOutputDescriptor class implementation AudioPolicyManagerBase::AudioOutputDescriptor::AudioOutputDescriptor() @@ -1969,5 +2095,27 @@ void AudioPolicyManagerBase::StreamDescriptor::dump(char* buffer, size_t size) mCanBeMuted); } +// --- EffectDescriptor class implementation + +status_t AudioPolicyManagerBase::EffectDescriptor::dump(int fd) +{ + const size_t SIZE = 256; + char buffer[SIZE]; + String8 result; + + snprintf(buffer, SIZE, " Output: %d\n", mOutput); + result.append(buffer); + snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy); + result.append(buffer); + snprintf(buffer, SIZE, " Session: %d\n", mSession); + result.append(buffer); + snprintf(buffer, SIZE, " Name: %s\n", mDesc.name); + result.append(buffer); + write(fd, result.string(), result.size()); + + return NO_ERROR; +} + + }; // namespace android diff --git a/services/audioflinger/AudioPolicyService.cpp b/services/audioflinger/AudioPolicyService.cpp index bb3905c..f24e08e 100644 --- a/services/audioflinger/AudioPolicyService.cpp +++ b/services/audioflinger/AudioPolicyService.cpp @@ -119,7 +119,8 @@ status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices if (!AudioSystem::isOutputDevice(device) && !AudioSystem::isInputDevice(device)) { return BAD_VALUE; } - if (state != AudioSystem::DEVICE_STATE_AVAILABLE && state != AudioSystem::DEVICE_STATE_UNAVAILABLE) { + if (state != AudioSystem::DEVICE_STATE_AVAILABLE && + state != AudioSystem::DEVICE_STATE_UNAVAILABLE) { return BAD_VALUE; } @@ -128,8 +129,9 @@ status_t AudioPolicyService::setDeviceConnectionState(AudioSystem::audio_devices return mpPolicyManager->setDeviceConnectionState(device, state, device_address); } -AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address) +AudioSystem::device_connection_state AudioPolicyService::getDeviceConnectionState( + AudioSystem::audio_devices device, + const char *device_address) { if (mpPolicyManager == NULL) { return AudioSystem::DEVICE_STATE_UNAVAILABLE; @@ -175,7 +177,8 @@ status_t AudioPolicyService::setRingerMode(uint32_t mode, uint32_t mask) return NO_ERROR; } -status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config) +status_t AudioPolicyService::setForceUse(AudioSystem::force_use usage, + AudioSystem::forced_config config) { if (mpPolicyManager == NULL) { return NO_INIT; @@ -223,24 +226,28 @@ audio_io_handle_t AudioPolicyService::getOutput(AudioSystem::stream_type stream, return mpPolicyManager->getOutput(stream, samplingRate, format, channels, flags); } -status_t AudioPolicyService::startOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyService::startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { if (mpPolicyManager == NULL) { return NO_INIT; } LOGV("startOutput() tid %d", gettid()); Mutex::Autolock _l(mLock); - return mpPolicyManager->startOutput(output, stream); + return mpPolicyManager->startOutput(output, stream, session); } -status_t AudioPolicyService::stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream) +status_t AudioPolicyService::stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session) { if (mpPolicyManager == NULL) { return NO_INIT; } LOGV("stopOutput() tid %d", gettid()); Mutex::Autolock _l(mLock); - return mpPolicyManager->stopOutput(output, stream); + return mpPolicyManager->stopOutput(output, stream, session); } void AudioPolicyService::releaseOutput(audio_io_handle_t output) @@ -339,8 +346,46 @@ status_t AudioPolicyService::getStreamVolumeIndex(AudioSystem::stream_type strea return mpPolicyManager->getStreamVolumeIndex(stream, index); } +uint32_t AudioPolicyService::getStrategyForStream(AudioSystem::stream_type stream) +{ + if (mpPolicyManager == NULL) { + return 0; + } + return mpPolicyManager->getStrategyForStream(stream); +} + +audio_io_handle_t AudioPolicyService::getOutputForEffect(effect_descriptor_t *desc) +{ + if (mpPolicyManager == NULL) { + return NO_INIT; + } + Mutex::Autolock _l(mLock); + return mpPolicyManager->getOutputForEffect(desc); +} + +status_t AudioPolicyService::registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id) +{ + if (mpPolicyManager == NULL) { + return NO_INIT; + } + return mpPolicyManager->registerEffect(desc, output, strategy, session, id); +} + +status_t AudioPolicyService::unregisterEffect(int id) +{ + if (mpPolicyManager == NULL) { + return NO_INIT; + } + return mpPolicyManager->unregisterEffect(id); +} + void AudioPolicyService::binderDied(const wp<IBinder>& who) { - LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), IPCThreadState::self()->getCallingPid()); + LOGW("binderDied() %p, tid %d, calling tid %d", who.unsafe_get(), gettid(), + IPCThreadState::self()->getCallingPid()); } static bool tryLock(Mutex& mutex) @@ -447,10 +492,16 @@ audio_io_handle_t AudioPolicyService::openOutput(uint32_t *pDevices, return 0; } - return af->openOutput(pDevices, pSamplingRate, (uint32_t *)pFormat, pChannels, pLatencyMs, flags); + return af->openOutput(pDevices, + pSamplingRate, + (uint32_t *)pFormat, + pChannels, + pLatencyMs, + flags); } -audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2) +audio_io_handle_t AudioPolicyService::openDuplicateOutput(audio_io_handle_t output1, + audio_io_handle_t output2) { sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == 0) { @@ -514,12 +565,16 @@ status_t AudioPolicyService::closeInput(audio_io_handle_t input) return af->closeInput(input); } -status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs) +status_t AudioPolicyService::setStreamVolume(AudioSystem::stream_type stream, + float volume, + audio_io_handle_t output, + int delayMs) { return mAudioCommandThread->volumeCommand((int)stream, volume, (int)output, delayMs); } -status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output) +status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, + audio_io_handle_t output) { sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); if (af == 0) return PERMISSION_DENIED; @@ -527,8 +582,18 @@ status_t AudioPolicyService::setStreamOutput(AudioSystem::stream_type stream, au return af->setStreamOutput(stream, output); } +status_t AudioPolicyService::moveEffects(int session, audio_io_handle_t srcOutput, + audio_io_handle_t dstOutput) +{ + sp<IAudioFlinger> af = AudioSystem::get_audio_flinger(); + if (af == 0) return PERMISSION_DENIED; + + return af->moveEffects(session, (int)srcOutput, (int)dstOutput); +} -void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs) +void AudioPolicyService::setParameters(audio_io_handle_t ioHandle, + const String8& keyValuePairs, + int delayMs) { mAudioCommandThread->parametersCommand((int)ioHandle, keyValuePairs, delayMs); } @@ -539,7 +604,8 @@ String8 AudioPolicyService::getParameters(audio_io_handle_t ioHandle, const Stri return result; } -status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream) +status_t AudioPolicyService::startTone(ToneGenerator::tone_type tone, + AudioSystem::stream_type stream) { mTonePlaybackThread->startToneCommand(tone, stream); return NO_ERROR; @@ -623,8 +689,11 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() }break; case SET_VOLUME: { VolumeData *data = (VolumeData *)command->mParam; - LOGV("AudioCommandThread() processing set volume stream %d, volume %f, output %d", data->mStream, data->mVolume, data->mIO); - command->mStatus = AudioSystem::setStreamVolume(data->mStream, data->mVolume, data->mIO); + LOGV("AudioCommandThread() processing set volume stream %d, \ + volume %f, output %d", data->mStream, data->mVolume, data->mIO); + command->mStatus = AudioSystem::setStreamVolume(data->mStream, + data->mVolume, + data->mIO); if (command->mWaitStatus) { command->mCond.signal(); mWaitWorkCV.wait(mLock); @@ -633,7 +702,8 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() }break; case SET_PARAMETERS: { ParametersData *data = (ParametersData *)command->mParam; - LOGV("AudioCommandThread() processing set parameters string %s, io %d", data->mKeyValuePairs.string(), data->mIO); + LOGV("AudioCommandThread() processing set parameters string %s, io %d", + data->mKeyValuePairs.string(), data->mIO); command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs); if (command->mWaitStatus) { command->mCond.signal(); @@ -643,7 +713,8 @@ bool AudioPolicyService::AudioCommandThread::threadLoop() }break; case SET_VOICE_VOLUME: { VoiceVolumeData *data = (VoiceVolumeData *)command->mParam; - LOGV("AudioCommandThread() processing set voice volume volume %f", data->mVolume); + LOGV("AudioCommandThread() processing set voice volume volume %f", + data->mVolume); command->mStatus = AudioSystem::setVoiceVolume(data->mVolume); if (command->mWaitStatus) { command->mCond.signal(); @@ -734,7 +805,10 @@ void AudioPolicyService::AudioCommandThread::stopToneCommand() mWaitWorkCV.signal(); } -status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float volume, int output, int delayMs) +status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, + float volume, + int output, + int delayMs) { status_t status = NO_ERROR; @@ -752,7 +826,8 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); - LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", stream, volume, output); + LOGV("AudioCommandThread() adding set volume stream %d, volume %f, output %d", + stream, volume, output); mWaitWorkCV.signal(); if (command->mWaitStatus) { command->mCond.wait(mLock); @@ -762,7 +837,9 @@ status_t AudioPolicyService::AudioCommandThread::volumeCommand(int stream, float return status; } -status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, const String8& keyValuePairs, int delayMs) +status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, + const String8& keyValuePairs, + int delayMs) { status_t status = NO_ERROR; @@ -779,7 +856,8 @@ status_t AudioPolicyService::AudioCommandThread::parametersCommand(int ioHandle, } Mutex::Autolock _l(mLock); insertCommand_l(command, delayMs); - LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", keyValuePairs.string(), ioHandle, delayMs); + LOGV("AudioCommandThread() adding set parameter string %s, io %d ,delay %d", + keyValuePairs.string(), ioHandle, delayMs); mWaitWorkCV.signal(); if (command->mWaitStatus) { command->mCond.wait(mLock); @@ -840,7 +918,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma ParametersData *data = (ParametersData *)command->mParam; ParametersData *data2 = (ParametersData *)command2->mParam; if (data->mIO != data2->mIO) break; - LOGV("Comparing parameter command %s to new command %s", data2->mKeyValuePairs.string(), data->mKeyValuePairs.string()); + LOGV("Comparing parameter command %s to new command %s", + data2->mKeyValuePairs.string(), data->mKeyValuePairs.string()); AudioParameter param = AudioParameter(data->mKeyValuePairs); AudioParameter param2 = AudioParameter(data2->mKeyValuePairs); for (size_t j = 0; j < param.size(); j++) { @@ -872,7 +951,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma VolumeData *data2 = (VolumeData *)command2->mParam; if (data->mIO != data2->mIO) break; if (data->mStream != data2->mStream) break; - LOGV("Filtering out volume command on output %d for stream %d", data->mIO, data->mStream); + LOGV("Filtering out volume command on output %d for stream %d", + data->mIO, data->mStream); removedCommands.add(command2); } break; case START_TONE: @@ -896,7 +976,8 @@ void AudioPolicyService::AudioCommandThread::insertCommand_l(AudioCommand *comma removedCommands.clear(); // insert command at the right place according to its time stamp - LOGV("inserting command: %d at index %d, num commands %d", command->mCommand, (int)i+1, mAudioCommands.size()); + LOGV("inserting command: %d at index %d, num commands %d", + command->mCommand, (int)i+1, mAudioCommands.size()); mAudioCommands.insertAt(command, i + 1); } diff --git a/services/audioflinger/AudioPolicyService.h b/services/audioflinger/AudioPolicyService.h index a13d0bd..558f455 100644 --- a/services/audioflinger/AudioPolicyService.h +++ b/services/audioflinger/AudioPolicyService.h @@ -28,7 +28,8 @@ class String8; // ---------------------------------------------------------------------------- -class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, public IBinder::DeathRecipient +class AudioPolicyService: public BnAudioPolicyService, public AudioPolicyClientInterface, + public IBinder::DeathRecipient { public: @@ -43,8 +44,9 @@ public: virtual status_t setDeviceConnectionState(AudioSystem::audio_devices device, AudioSystem::device_connection_state state, const char *device_address); - virtual AudioSystem::device_connection_state getDeviceConnectionState(AudioSystem::audio_devices device, - const char *device_address); + virtual AudioSystem::device_connection_state getDeviceConnectionState( + AudioSystem::audio_devices device, + const char *device_address); virtual status_t setPhoneState(int state); virtual status_t setRingerMode(uint32_t mode, uint32_t mask); virtual status_t setForceUse(AudioSystem::force_use usage, AudioSystem::forced_config config); @@ -53,15 +55,21 @@ public: uint32_t samplingRate = 0, uint32_t format = AudioSystem::FORMAT_DEFAULT, uint32_t channels = 0, - AudioSystem::output_flags flags = AudioSystem::OUTPUT_FLAG_INDIRECT); - virtual status_t startOutput(audio_io_handle_t output, AudioSystem::stream_type stream); - virtual status_t stopOutput(audio_io_handle_t output, AudioSystem::stream_type stream); + AudioSystem::output_flags flags = + AudioSystem::OUTPUT_FLAG_INDIRECT); + virtual status_t startOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); + virtual status_t stopOutput(audio_io_handle_t output, + AudioSystem::stream_type stream, + int session = 0); virtual void releaseOutput(audio_io_handle_t output); virtual audio_io_handle_t getInput(int inputSource, uint32_t samplingRate = 0, uint32_t format = AudioSystem::FORMAT_DEFAULT, uint32_t channels = 0, - AudioSystem::audio_in_acoustics acoustics = (AudioSystem::audio_in_acoustics)0); + AudioSystem::audio_in_acoustics acoustics = + (AudioSystem::audio_in_acoustics)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); @@ -71,6 +79,16 @@ public: virtual status_t setStreamVolumeIndex(AudioSystem::stream_type stream, int index); virtual status_t getStreamVolumeIndex(AudioSystem::stream_type stream, int *index); + virtual uint32_t getStrategyForStream(AudioSystem::stream_type stream); + + virtual audio_io_handle_t getOutputForEffect(effect_descriptor_t *desc); + virtual status_t registerEffect(effect_descriptor_t *desc, + audio_io_handle_t output, + uint32_t strategy, + int session, + int id); + virtual status_t unregisterEffect(int id); + virtual status_t onTransact( uint32_t code, const Parcel& data, @@ -89,7 +107,8 @@ public: uint32_t *pChannels, uint32_t *pLatencyMs, AudioSystem::output_flags flags); - virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, audio_io_handle_t output2); + virtual audio_io_handle_t openDuplicateOutput(audio_io_handle_t output1, + audio_io_handle_t output2); virtual status_t closeOutput(audio_io_handle_t output); virtual status_t suspendOutput(audio_io_handle_t output); virtual status_t restoreOutput(audio_io_handle_t output); @@ -99,13 +118,21 @@ public: uint32_t *pChannels, uint32_t acoustics); virtual status_t closeInput(audio_io_handle_t input); - virtual status_t setStreamVolume(AudioSystem::stream_type stream, float volume, audio_io_handle_t output, int delayMs = 0); + virtual status_t setStreamVolume(AudioSystem::stream_type stream, + float volume, + audio_io_handle_t output, + int delayMs = 0); virtual status_t setStreamOutput(AudioSystem::stream_type stream, audio_io_handle_t output); - virtual void setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs, int delayMs = 0); + virtual void setParameters(audio_io_handle_t ioHandle, + const String8& keyValuePairs, + int delayMs = 0); virtual String8 getParameters(audio_io_handle_t ioHandle, const String8& keys); virtual status_t startTone(ToneGenerator::tone_type tone, AudioSystem::stream_type stream); virtual status_t stopTone(); virtual status_t setVoiceVolume(float volume, int delayMs = 0); + virtual status_t moveEffects(int session, + audio_io_handle_t srcOutput, + audio_io_handle_t dstOutput); private: AudioPolicyService(); |