diff options
Diffstat (limited to 'services')
-rw-r--r-- | services/audioflinger/AudioFlinger.cpp | 145 | ||||
-rw-r--r-- | services/audioflinger/AudioFlinger.h | 24 |
2 files changed, 127 insertions, 42 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp index b7ddbb5..8f7b35c 100644 --- a/services/audioflinger/AudioFlinger.cpp +++ b/services/audioflinger/AudioFlinger.cpp @@ -1993,9 +1993,12 @@ void AudioFlinger::PlaybackThread::checkSilentMode_l() bool AudioFlinger::MixerThread::threadLoop() { + // DirectOutputThread has single trackToRemove instead of Vector Vector< sp<Track> > tracksToRemove; + // DirectOutputThread has activeTrack here nsecs_t standbyTime = systemTime(); size_t mixBufferSize = mFrameCount * mFrameSize; + // FIXME: Relaxed timing because of a certain device that can't meet latency // Should be reduced to 2x after the vendor fixes the driver issue // increase threshold again due to low power audio mode. The way this warning threshold is @@ -2003,18 +2006,26 @@ bool AudioFlinger::MixerThread::threadLoop() nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 15; nsecs_t lastWarning = 0; bool longStandbyExit = false; + uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); uint32_t sleepTime = idleSleepTime; + uint32_t sleepTimeShift = 0; - Vector< sp<EffectChain> > effectChains; CpuStats cpuStats; + // DirectOutputThread has shorter standbyDelay + acquireWakeLock(); while (!exitPending()) { cpuStats.sample(); + + // DirectOutputThread has rampVolume, leftVol, rightVol + + Vector< sp<EffectChain> > effectChains; + processConfigEvents(); mixer_state mixerStatus = MIXER_IDLE; @@ -2024,28 +2035,29 @@ bool AudioFlinger::MixerThread::threadLoop() if (checkForNewParameters_l()) { mixBufferSize = mFrameCount * mFrameSize; + // FIXME: Relaxed timing because of a certain device that can't meet latency // Should be reduced to 2x after the vendor fixes the driver issue // increase threshold again due to low power audio mode. The way this warning // threshold is calculated and its usefulness should be reconsidered anyway. maxPeriod = seconds(mFrameCount) / mSampleRate * 15; + activeSleepTime = activeSleepTimeUs(); idleSleepTime = idleSleepTimeUs(); + // DirectOutputThread updates standbyDelay also } - const SortedVector< wp<Track> >& activeTracks = mActiveTracks; - // put audio hardware into standby after short delay - if (CC_UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) || - mSuspended)) { + if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) || + mSuspended > 0)) { if (!mStandby) { - ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d", this, mSuspended); + ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended); mOutput->stream->common.standby(&mOutput->stream->common); mStandby = true; mBytesWritten = 0; } - if (!activeTracks.size() && mConfigEvents.isEmpty()) { + if (!mActiveTracks.size() && mConfigEvents.isEmpty()) { // we're about to wait, flush the binder command buffer IPCThreadState::self()->flushCommands(); @@ -2068,7 +2080,7 @@ bool AudioFlinger::MixerThread::threadLoop() } } - mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove); + mixerStatus = prepareTracks_l(&tracksToRemove); // prevent any changes in effect chain list and in each effect chain // during mixing and effect process as the audio buffers could be deleted @@ -2130,12 +2142,15 @@ bool AudioFlinger::MixerThread::threadLoop() // TODO add standby time extension fct of effect tail } - if (mSuspended) { + if (mSuspended > 0) { sleepTime = suspendSleepTimeUs(); } // only process effects if we're going to write if (sleepTime == 0) { + + // DirectOutputThread adds applyVolume here + for (size_t i = 0; i < effectChains.size(); i ++) { effectChains[i]->process_l(); } @@ -2146,14 +2161,16 @@ bool AudioFlinger::MixerThread::threadLoop() // sleepTime == 0 means we must write to audio hardware if (sleepTime == 0) { + // FIXME Only in MixerThread, and rewrite to reduce number of system calls mLastWriteTime = systemTime(); mInWrite = true; mBytesWritten += mixBufferSize; - int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize); if (bytesWritten < 0) mBytesWritten -= mixBufferSize; mNumWrites++; mInWrite = false; + + // Only in MixerThread: start of write blocked detection nsecs_t now = systemTime(); nsecs_t delta = now - mLastWriteTime; if (!mStandby && delta > maxPeriod) { @@ -2167,12 +2184,14 @@ bool AudioFlinger::MixerThread::threadLoop() longStandbyExit = true; } } + // end of write blocked detection + mStandby = false; } else { usleep(sleepTime); } - // finally let go of all our tracks, without the lock held + // finally let go of removed track(s), without the lock held // since we can't guarantee the destructors won't acquire that // same lock. tracksToRemove.clear(); @@ -2180,8 +2199,12 @@ bool AudioFlinger::MixerThread::threadLoop() // Effect chains will be actually deleted here if they were removed from // mEffectChains list during mixing or effects processing effectChains.clear(); + + // FIXME Note that the above .clear() is no longer necessary since effectChains + // is now local to this block, but will keep it for now (at least until merge done). } + // put output stream into standby mode if (!mStandby) { mOutput->stream->common.standby(&mOutput->stream->common); } @@ -2194,12 +2217,12 @@ bool AudioFlinger::MixerThread::threadLoop() // prepareTracks_l() must be called with ThreadBase::mLock held AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l( - const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove) + Vector< sp<Track> > *tracksToRemove) { mixer_state mixerStatus = MIXER_IDLE; // find out which tracks need to be processed - size_t count = activeTracks.size(); + size_t count = mActiveTracks.size(); size_t mixedTracks = 0; size_t tracksWithEffect = 0; @@ -2219,7 +2242,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac } for (size_t i=0 ; i<count ; i++) { - sp<Track> t = activeTracks[i].promote(); + sp<Track> t = mActiveTracks[i].promote(); if (t == 0) continue; // this const just means the local variable doesn't change @@ -2706,13 +2729,20 @@ void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t ri bool AudioFlinger::DirectOutputThread::threadLoop() { + // MixerThread has Vector instead of single trackToRemove sp<Track> trackToRemove; - sp<Track> activeTrack; + nsecs_t standbyTime = systemTime(); - size_t mixBufferSize = mFrameCount*mFrameSize; + size_t mixBufferSize = mFrameCount * mFrameSize; + + // MixerThread has relaxed timing: maxPeriod, lastWarning, longStandbyExit + uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); uint32_t sleepTime = idleSleepTime; + + // MixerThread has sleepTimeShift and cpuStats + // use shorter standby delay as on normal output to release // hardware resources as soon as possible nsecs_t standbyDelay = microseconds(activeSleepTime*2); @@ -2721,20 +2751,30 @@ bool AudioFlinger::DirectOutputThread::threadLoop() while (!exitPending()) { + // MixerThread has cpuStats.sample() + bool rampVolume; uint16_t leftVol; uint16_t rightVol; + Vector< sp<EffectChain> > effectChains; processConfigEvents(); + // MixerThread does not have activeTrack here + sp<Track> activeTrack; + mixer_state mixerStatus = MIXER_IDLE; { // scope for the mLock Mutex::Autolock _l(mLock); if (checkForNewParameters_l()) { - mixBufferSize = mFrameCount*mFrameSize; + mixBufferSize = mFrameCount * mFrameSize; + + // different calculations here + standbyDelay = microseconds(activeSleepTime*2); + activeSleepTime = activeSleepTimeUs(); idleSleepTime = idleSleepTimeUs(); standbyDelay = microseconds(activeSleepTime*2); @@ -2742,10 +2782,9 @@ bool AudioFlinger::DirectOutputThread::threadLoop() // put audio hardware into standby after short delay if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) || - mSuspended)) { - // wait until we have something to do... + mSuspended > 0)) { if (!mStandby) { - ALOGV("Audio hardware entering standby, mixer %p, mSuspended %d", this, mSuspended); + ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended); mOutput->stream->common.standby(&mOutput->stream->common); mStandby = true; mBytesWritten = 0; @@ -2758,19 +2797,27 @@ bool AudioFlinger::DirectOutputThread::threadLoop() if (exitPending()) break; releaseWakeLock_l(); + // wait until we have something to do... ALOGV("Thread %p type %d TID %d going to sleep", this, mType, gettid()); mWaitWorkCV.wait(mLock); ALOGV("Thread %p type %d TID %d waking up", this, mType, gettid()); acquireWakeLock_l(); + // MixerThread has "mPrevMixerStatus = MIXER_IDLE" checkSilentMode_l(); + // MixerThread has different standbyDelay standbyTime = systemTime() + standbyDelay; sleepTime = idleSleepTime; + // MixerThread has "sleepTimeShift = 0" continue; } } + // MixerThread has "mixerStatus = prepareTracks_l(...)" + + // equivalent to MixerThread's lockEffectChains_l, but without the lock + // FIXME - is it OK to omit the lock here? effectChains = mEffectChains; // find out which tracks need to be processed @@ -2901,6 +2948,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop() lockEffectChains_l(effectChains); } + // For DirectOutputThread, this test is equivalent to "activeTrack != 0" if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) { AudioBufferProvider::Buffer buffer; size_t frameCount = mFrameCount; @@ -2933,15 +2981,18 @@ bool AudioFlinger::DirectOutputThread::threadLoop() } } - if (mSuspended) { + if (mSuspended > 0) { sleepTime = suspendSleepTimeUs(); } // only process effects if we're going to write if (sleepTime == 0) { + + // MixerThread does not have applyVolume if (mixerStatus == MIXER_TRACKS_READY) { applyVolume(leftVol, rightVol, rampVolume); } + for (size_t i = 0; i < effectChains.size(); i ++) { effectChains[i]->process_l(); } @@ -2959,12 +3010,15 @@ bool AudioFlinger::DirectOutputThread::threadLoop() if (bytesWritten < 0) mBytesWritten -= mixBufferSize; mNumWrites++; mInWrite = false; + + // MixerThread has write blocked detection here + mStandby = false; } else { usleep(sleepTime); } - // finally let go of removed track, without the lock held + // finally let go of removed track(s), without the lock held // since we can't guarantee the destructors won't acquire that // same lock. trackToRemove.clear(); @@ -2973,8 +3027,12 @@ bool AudioFlinger::DirectOutputThread::threadLoop() // Effect chains will be actually deleted here if they were removed from // mEffectChains list during mixing or effects processing effectChains.clear(); + + // FIXME Note that the above .clear() is no longer necessary since effectChains + // is now local to this block, but will keep it for now (at least until merge done). } + // put output stream into standby mode if (!mStandby) { mOutput->stream->common.standby(&mOutput->stream->common); } @@ -3099,18 +3157,24 @@ bool AudioFlinger::DuplicatingThread::threadLoop() { Vector< sp<Track> > tracksToRemove; nsecs_t standbyTime = systemTime(); - size_t mixBufferSize = mFrameCount*mFrameSize; + size_t mixBufferSize = mFrameCount * mFrameSize; + + // Only in DuplicatingThread SortedVector< sp<OutputTrack> > outputTracks; uint32_t writeFrames = 0; + uint32_t activeSleepTime = activeSleepTimeUs(); uint32_t idleSleepTime = idleSleepTimeUs(); uint32_t sleepTime = idleSleepTime; - Vector< sp<EffectChain> > effectChains; acquireWakeLock(); while (!exitPending()) { + // MixerThread has cpuStats.sample + + Vector< sp<EffectChain> > effectChains; + processConfigEvents(); mixer_state mixerStatus = MIXER_IDLE; @@ -3119,22 +3183,25 @@ bool AudioFlinger::DuplicatingThread::threadLoop() Mutex::Autolock _l(mLock); if (checkForNewParameters_l()) { - mixBufferSize = mFrameCount*mFrameSize; + mixBufferSize = mFrameCount * mFrameSize; + + // Only in DuplicatingThread updateWaitTime(); + activeSleepTime = activeSleepTimeUs(); idleSleepTime = idleSleepTimeUs(); } - const SortedVector< wp<Track> >& activeTracks = mActiveTracks; - + // Only in DuplicatingThread for (size_t i = 0; i < mOutputTracks.size(); i++) { outputTracks.add(mOutputTracks[i]); } // put audio hardware into standby after short delay - if (CC_UNLIKELY((!activeTracks.size() && systemTime() > standbyTime) || - mSuspended)) { + if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) || + mSuspended > 0)) { if (!mStandby) { + // DuplicatingThread implements standby by stopping all tracks for (size_t i = 0; i < outputTracks.size(); i++) { outputTracks[i]->stop(); } @@ -3142,7 +3209,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() mBytesWritten = 0; } - if (!activeTracks.size() && mConfigEvents.isEmpty()) { + if (!mActiveTracks.size() && mConfigEvents.isEmpty()) { // we're about to wait, flush the binder command buffer IPCThreadState::self()->flushCommands(); outputTracks.clear(); @@ -3156,15 +3223,17 @@ bool AudioFlinger::DuplicatingThread::threadLoop() ALOGV("Thread %p type %d TID %d waking up", this, mType, gettid()); acquireWakeLock_l(); + // MixerThread has "mPrevMixerStatus = MIXER_IDLE" checkSilentMode_l(); standbyTime = systemTime() + mStandbyTimeInNsecs; sleepTime = idleSleepTime; + // MixerThread has sleepTimeShift continue; } } - mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove); + mixerStatus = prepareTracks_l(&tracksToRemove); // prevent any changes in effect chain list and in each effect chain // during mixing and effect process as the audio buffers could be deleted @@ -3172,6 +3241,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() lockEffectChains_l(effectChains); } + // Duplicating Thread is completely different here if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) { // mix buffers... if (outputsReady(outputTracks)) { @@ -3201,7 +3271,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop() } } - if (mSuspended) { + if (mSuspended > 0) { sleepTime = suspendSleepTimeUs(); } @@ -3223,11 +3293,14 @@ bool AudioFlinger::DuplicatingThread::threadLoop() } mStandby = false; mBytesWritten += mixBufferSize; + + // MixerThread has write blocked detection here + } else { usleep(sleepTime); } - // finally let go of all our tracks, without the lock held + // finally let go of removed track(s), without the lock held // since we can't guarantee the destructors won't acquire that // same lock. tracksToRemove.clear(); @@ -3236,8 +3309,14 @@ bool AudioFlinger::DuplicatingThread::threadLoop() // Effect chains will be actually deleted here if they were removed from // mEffectChains list during mixing or effects processing effectChains.clear(); + + // FIXME Note that the above .clear() is no longer necessary since effectChains + // is now local to this block, but will keep it for now (at least until merge done). } + // MixerThread and DirectOutpuThread have standby here, + // but for DuplicatingThread this is handled by the outputTracks + releaseWakeLock(); ALOGV("Thread %p type %d exiting", this, mType); diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 457bd98..bdaf97c 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -455,9 +455,10 @@ private: 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 + // lock all 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. + // Also sets the parameter 'effectChains' to current value of mEffectChains. void lockEffectChains_l(Vector<sp <EffectChain> >& effectChains); // unlock effect chains after process void unlockEffectChains(const Vector<sp<EffectChain> >& effectChains); @@ -575,9 +576,11 @@ private: public: enum mixer_state { - MIXER_IDLE, - MIXER_TRACKS_ENABLED, - MIXER_TRACKS_READY + MIXER_IDLE, // no active tracks + MIXER_TRACKS_ENABLED, // at least one active track, but no track has any data ready + MIXER_TRACKS_READY // at least one active track, and at least one track has data + // standby mode does not have an enum value + // suspend by audio policy manager is orthogonal to mixer state }; // playback track @@ -821,8 +824,8 @@ private: virtual audio_stream_t* stream(); void suspend() { mSuspended++; } - void restore() { if (mSuspended) mSuspended--; } - bool isSuspended() const { return (mSuspended != 0); } + void restore() { if (mSuspended > 0) mSuspended--; } + bool isSuspended() const { return (mSuspended > 0); } virtual String8 getParameters(const String8& keys); virtual void audioConfigChanged_l(int event, int param = 0); virtual status_t getRenderPosition(uint32_t *halFrames, uint32_t *dspFrames); @@ -843,7 +846,7 @@ private: protected: int16_t* mMixBuffer; - int mSuspended; + uint32_t mSuspended; // suspend count, > 0 means suspended int mBytesWritten; private: // mMasterMute is in both PlaybackThread and in AudioFlinger. When a @@ -913,8 +916,11 @@ private: virtual status_t dumpInternals(int fd, const Vector<String16>& args); protected: - mixer_state prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, - Vector< sp<Track> > *tracksToRemove); + // prepareTracks_l reads and writes mActiveTracks, and also returns the + // pending set of tracks to remove via Vector 'tracksToRemove'. The caller is + // responsible for clearing or destroying this Vector later on, when it + // is safe to do so. That will drop the final ref count and destroy the tracks. + mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove); virtual int getTrackName_l(); virtual void deleteTrackName_l(int name); virtual uint32_t idleSleepTimeUs(); |