Merge "threadLoop merge"
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8f7b35c..b972548 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1919,10 +1919,10 @@
AudioFlinger::MixerThread::MixerThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output,
audio_io_handle_t id, uint32_t device, type_t type)
- : PlaybackThread(audioFlinger, output, id, device, type),
- mAudioMixer(new AudioMixer(mFrameCount, mSampleRate)),
- mPrevMixerStatus(MIXER_IDLE)
+ : PlaybackThread(audioFlinger, output, id, device, type)
{
+ mAudioMixer = new AudioMixer(mFrameCount, mSampleRate);
+ mPrevMixerStatus = MIXER_IDLE;
// FIXME - Current mixer implementation only supports stereo output
if (mChannelCount == 1) {
ALOGE("Invalid audio hardware channel count");
@@ -1991,44 +1991,67 @@
}
}
-bool AudioFlinger::MixerThread::threadLoop()
+bool AudioFlinger::PlaybackThread::threadLoop()
{
- // DirectOutputThread has single trackToRemove instead of Vector
+ // MIXER || DUPLICATING
Vector< sp<Track> > tracksToRemove;
- // DirectOutputThread has activeTrack here
- nsecs_t standbyTime = systemTime();
- size_t mixBufferSize = mFrameCount * mFrameSize;
+ // DIRECT
+ sp<Track> trackToRemove;
+
+ standbyTime = systemTime();
+ mixBufferSize = mFrameCount * mFrameSize;
+
+ // MIXER
// 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.
nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 15;
nsecs_t lastWarning = 0;
- bool longStandbyExit = false;
+if (mType == MIXER) {
+ longStandbyExit = false;
+}
- uint32_t activeSleepTime = activeSleepTimeUs();
- uint32_t idleSleepTime = idleSleepTimeUs();
- uint32_t sleepTime = idleSleepTime;
+ // DUPLICATING
+ // FIXME could this be made local to while loop?
+ writeFrames = 0;
- uint32_t sleepTimeShift = 0;
+ activeSleepTime = activeSleepTimeUs();
+ idleSleepTime = idleSleepTimeUs();
+ sleepTime = idleSleepTime;
+
+if (mType == MIXER) {
+ sleepTimeShift = 0;
+}
+
+ // MIXER
CpuStats cpuStats;
- // DirectOutputThread has shorter standbyDelay
+ // DIRECT
+if (mType == DIRECT) {
+ // use shorter standby delay as on normal output to release
+ // hardware resources as soon as possible
+ standbyDelay = microseconds(activeSleepTime*2);
+}
acquireWakeLock();
while (!exitPending())
{
+if (mType == MIXER) {
cpuStats.sample();
-
- // DirectOutputThread has rampVolume, leftVol, rightVol
+}
Vector< sp<EffectChain> > effectChains;
processConfigEvents();
- mixer_state mixerStatus = MIXER_IDLE;
+if (mType == DIRECT) {
+ activeTrack.clear();
+}
+
+ mixerStatus = MIXER_IDLE;
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -2036,23 +2059,46 @@
if (checkForNewParameters_l()) {
mixBufferSize = mFrameCount * mFrameSize;
+if (mType == MIXER) {
// 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;
+}
+
+if (mType == DUPLICATING) {
+ updateWaitTime();
+}
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
- // DirectOutputThread updates standbyDelay also
+
+if (mType == DIRECT) {
+ standbyDelay = microseconds(activeSleepTime*2);
+}
+
}
+if (mType == DUPLICATING) {
+#if 0 // see earlier FIXME
+ // Now that this is a field instead of local variable,
+ // clear it so it is empty the first time through the loop,
+ // and later an assignment could combine the clear with the loop below
+ outputTracks.clear();
+#endif
+ for (size_t i = 0; i < mOutputTracks.size(); i++) {
+ outputTracks.add(mOutputTracks[i]);
+ }
+}
+
// put audio hardware into standby after short delay
if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
mSuspended > 0)) {
if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
- mOutput->stream->common.standby(&mOutput->stream->common);
+
+ threadLoop_standby();
+
mStandby = true;
mBytesWritten = 0;
}
@@ -2061,6 +2107,10 @@
// we're about to wait, flush the binder command buffer
IPCThreadState::self()->flushCommands();
+if (mType == DUPLICATING) {
+ outputTracks.clear();
+}
+
if (exitPending()) break;
releaseWakeLock_l();
@@ -2070,17 +2120,41 @@
ALOGV("Thread %p type %d TID %d waking up", this, mType, gettid());
acquireWakeLock_l();
+if (mType == MIXER || mType == DUPLICATING) {
mPrevMixerStatus = MIXER_IDLE;
+}
+
checkSilentMode_l();
+if (mType == MIXER || mType == DUPLICATING) {
standbyTime = systemTime() + mStandbyTimeInNsecs;
+}
+
+if (mType == DIRECT) {
+ standbyTime = systemTime() + standbyDelay;
+}
+
sleepTime = idleSleepTime;
+
+if (mType == MIXER) {
sleepTimeShift = 0;
+}
+
continue;
}
}
+// FIXME merge these
+if (mType == MIXER || mType == DUPLICATING) {
mixerStatus = prepareTracks_l(&tracksToRemove);
+}
+if (mType == DIRECT) {
+ mixerStatus = threadLoop_prepareTracks_l(trackToRemove);
+ // see FIXME in AudioFlinger.h
+ if (mixerStatus == MIXER_CONTINUE) {
+ continue;
+ }
+}
// prevent any changes in effect chain list and in each effect chain
// during mixing and effect process as the audio buffers could be deleted
@@ -2088,7 +2162,130 @@
lockEffectChains_l(effectChains);
}
+if (mType == DIRECT) {
+ // For DirectOutputThread, this test is equivalent to "activeTrack != 0"
+}
+
if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
+ threadLoop_mix();
+ } else {
+ threadLoop_sleepTime();
+ }
+
+ if (mSuspended > 0) {
+ sleepTime = suspendSleepTimeUs();
+ }
+
+ // only process effects if we're going to write
+ if (sleepTime == 0) {
+
+ if (mixerStatus == MIXER_TRACKS_READY) {
+
+ // Non-trivial for DIRECT only
+ applyVolume();
+
+ }
+
+ for (size_t i = 0; i < effectChains.size(); i ++) {
+ effectChains[i]->process_l();
+ }
+ }
+
+ // enable changes in effect chain
+ unlockEffectChains(effectChains);
+
+ // sleepTime == 0 means we must write to audio hardware
+ if (sleepTime == 0) {
+
+ threadLoop_write();
+
+if (mType == MIXER) {
+ // write blocked detection
+ nsecs_t now = systemTime();
+ nsecs_t delta = now - mLastWriteTime;
+ if (!mStandby && delta > maxPeriod) {
+ mNumDelayedWrites++;
+ if ((now - lastWarning) > kWarningThrottleNs) {
+ ALOGW("write blocked for %llu msecs, %d delayed writes, thread %p",
+ ns2ms(delta), mNumDelayedWrites, this);
+ lastWarning = now;
+ }
+ // FIXME this is broken: longStandbyExit should be handled out of the if() and with
+ // a different threshold. Or completely removed for what it is worth anyway...
+ if (mStandby) {
+ longStandbyExit = true;
+ }
+ }
+}
+
+ mStandby = false;
+ } else {
+ usleep(sleepTime);
+ }
+
+ // finally let go of removed track(s), without the lock held
+ // since we can't guarantee the destructors won't acquire that
+ // same lock.
+
+// FIXME merge these
+if (mType == MIXER) {
+ tracksToRemove.clear();
+}
+if (mType == DIRECT) {
+ trackToRemove.clear();
+ activeTrack.clear();
+}
+if (mType == DUPLICATING) {
+ tracksToRemove.clear();
+ outputTracks.clear();
+}
+
+ // 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).
+ }
+
+if (mType == MIXER || mType == DIRECT) {
+ // put output stream into standby mode
+ if (!mStandby) {
+ mOutput->stream->common.standby(&mOutput->stream->common);
+ }
+}
+if (mType == DUPLICATING) {
+ // for DuplicatingThread, standby mode is handled by the outputTracks
+}
+
+ releaseWakeLock();
+
+ ALOGV("Thread %p type %d exiting", this, mType);
+ return false;
+}
+
+// shared by MIXER and DIRECT, overridden by DUPLICATING
+void AudioFlinger::PlaybackThread::threadLoop_write()
+{
+ // FIXME 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;
+}
+
+// shared by MIXER and DIRECT, overridden by DUPLICATING
+void AudioFlinger::PlaybackThread::threadLoop_standby()
+{
+ ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
+ mOutput->stream->common.standby(&mOutput->stream->common);
+}
+
+void AudioFlinger::MixerThread::threadLoop_mix()
+{
// obtain the presentation timestamp of the next output buffer
int64_t pts;
status_t status = INVALID_OPERATION;
@@ -2114,7 +2311,10 @@
sleepTime = 0;
standbyTime = systemTime() + mStandbyTimeInNsecs;
//TODO: delay standby when effects have a tail
- } else {
+}
+
+void AudioFlinger::MixerThread::threadLoop_sleepTime()
+{
// If no tracks are ready, sleep once for the duration of an output
// buffer size, then write 0s to the output
if (sleepTime == 0) {
@@ -2140,79 +2340,6 @@
ALOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
}
// TODO add standby time extension fct of effect tail
- }
-
- 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();
- }
- }
-
- // enable changes in effect chain
- unlockEffectChains(effectChains);
-
- // 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) {
- mNumDelayedWrites++;
- if ((now - lastWarning) > kWarningThrottleNs) {
- ALOGW("write blocked for %llu msecs, %d delayed writes, thread %p",
- ns2ms(delta), mNumDelayedWrites, this);
- lastWarning = now;
- }
- if (mStandby) {
- longStandbyExit = true;
- }
- }
- // end of write blocked detection
-
- mStandby = false;
- } else {
- usleep(sleepTime);
- }
-
- // 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();
-
- // 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);
- }
-
- releaseWakeLock();
-
- ALOGV("Thread %p type %d exiting", this, mType);
- return false;
}
// prepareTracks_l() must be called with ThreadBase::mLock held
@@ -2653,7 +2780,7 @@
{
}
-void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp)
+void AudioFlinger::DirectOutputThread::applyVolume()
{
// Do not apply volume on compressed audio
if (!audio_is_linear_pcm(mFormat)) {
@@ -2672,7 +2799,7 @@
size_t frameCount = mFrameCount;
int16_t *out = mMixBuffer;
- if (ramp) {
+ if (rampVolume) {
if (mChannelCount == 1) {
int32_t d = ((int32_t)leftVol - (int32_t)mLeftVolShort) << 16;
int32_t vlInc = d / (int32_t)frameCount;
@@ -2727,103 +2854,19 @@
mRightVolShort = rightVol;
}
-bool AudioFlinger::DirectOutputThread::threadLoop()
+AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::threadLoop_prepareTracks_l(
+ sp<Track>& trackToRemove
+)
{
- // MixerThread has Vector instead of single trackToRemove
- sp<Track> trackToRemove;
-
- nsecs_t standbyTime = systemTime();
- 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);
-
- acquireWakeLock();
-
- 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;
-
- // different calculations here
- standbyDelay = microseconds(activeSleepTime*2);
-
- activeSleepTime = activeSleepTimeUs();
- idleSleepTime = idleSleepTimeUs();
- standbyDelay = microseconds(activeSleepTime*2);
- }
-
- // put audio hardware into standby after short delay
- if (CC_UNLIKELY((!mActiveTracks.size() && systemTime() > standbyTime) ||
- mSuspended > 0)) {
- if (!mStandby) {
- ALOGV("Audio hardware entering standby, mixer %p, suspend count %u", this, mSuspended);
- mOutput->stream->common.standby(&mOutput->stream->common);
- mStandby = true;
- mBytesWritten = 0;
- }
-
- if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
-
- 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;
+// FIXME Temporarily renamed to avoid confusion with the member "mixerStatus"
+mixer_state mixerStatus_ = MIXER_IDLE;
// find out which tracks need to be processed
if (mActiveTracks.size() != 0) {
sp<Track> t = mActiveTracks[0].promote();
- if (t == 0) continue;
+ // see FIXME in AudioFlinger.h, return MIXER_IDLE might also work
+ if (t == 0) return MIXER_CONTINUE;
+ //if (t == 0) continue;
Track* const track = t.get();
audio_track_cblk_t* cblk = track->cblk();
@@ -2886,9 +2929,9 @@
// Delegate volume control to effect in track effect chain if needed
// only one effect chain can be present on DirectOutputThread, so if
// there is one, the track is connected to it
- if (!effectChains.isEmpty()) {
+ if (!mEffectChains.isEmpty()) {
// Do not ramp volume if volume is controlled by effect
- if(effectChains[0]->setVolume_l(&vl, &vr)) {
+ if (mEffectChains[0]->setVolume_l(&vl, &vr)) {
rampVolume = false;
}
}
@@ -2909,7 +2952,7 @@
// reset retry count
track->mRetryCount = kMaxTrackRetriesDirect;
activeTrack = t;
- mixerStatus = MIXER_TRACKS_READY;
+ mixerStatus_ = MIXER_TRACKS_READY;
} else {
//ALOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
if (track->isStopped()) {
@@ -2926,7 +2969,7 @@
ALOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
trackToRemove = track;
} else {
- mixerStatus = MIXER_TRACKS_ENABLED;
+ mixerStatus_ = MIXER_TRACKS_ENABLED;
}
}
}
@@ -2935,21 +2978,21 @@
// remove all the tracks that need to be...
if (CC_UNLIKELY(trackToRemove != 0)) {
mActiveTracks.remove(trackToRemove);
- if (!effectChains.isEmpty()) {
+ if (!mEffectChains.isEmpty()) {
ALOGV("stopping track on chain %p for session Id: %d", effectChains[0].get(),
trackToRemove->sessionId());
- effectChains[0]->decActiveTrackCnt();
+ mEffectChains[0]->decActiveTrackCnt();
}
if (trackToRemove->isTerminated()) {
removeTrack_l(trackToRemove);
}
}
- lockEffectChains_l(effectChains);
- }
+return mixerStatus_;
+}
- // For DirectOutputThread, this test is equivalent to "activeTrack != 0"
- if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
+void AudioFlinger::DirectOutputThread::threadLoop_mix()
+{
AudioBufferProvider::Buffer buffer;
size_t frameCount = mFrameCount;
int8_t *curBuf = (int8_t *)mMixBuffer;
@@ -2968,7 +3011,10 @@
}
sleepTime = 0;
standbyTime = systemTime() + standbyDelay;
- } else {
+}
+
+void AudioFlinger::DirectOutputThread::threadLoop_sleepTime()
+{
if (sleepTime == 0) {
if (mixerStatus == MIXER_TRACKS_ENABLED) {
sleepTime = activeSleepTime;
@@ -2979,68 +3025,6 @@
memset (mMixBuffer, 0, mFrameCount * mFrameSize);
sleepTime = 0;
}
- }
-
- 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();
- }
- }
-
- // enable changes in effect chain
- unlockEffectChains(effectChains);
-
- // sleepTime == 0 means we must write to audio hardware
- if (sleepTime == 0) {
- mLastWriteTime = systemTime();
- mInWrite = true;
- mBytesWritten += mixBufferSize;
- int bytesWritten = (int)mOutput->stream->write(mOutput->stream, mMixBuffer, mixBufferSize);
- 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(s), without the lock held
- // since we can't guarantee the destructors won't acquire that
- // same lock.
- trackToRemove.clear();
- activeTrack.clear();
-
- // 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);
- }
-
- releaseWakeLock();
-
- ALOGV("Thread %p type %d exiting", this, mType);
- return false;
}
// getTrackName_l() must be called with ThreadBase::mLock held
@@ -3153,96 +3137,8 @@
}
}
-bool AudioFlinger::DuplicatingThread::threadLoop()
+void AudioFlinger::DuplicatingThread::threadLoop_mix()
{
- Vector< sp<Track> > tracksToRemove;
- nsecs_t standbyTime = systemTime();
- 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;
-
- acquireWakeLock();
-
- while (!exitPending())
- {
- // MixerThread has cpuStats.sample
-
- Vector< sp<EffectChain> > effectChains;
-
- processConfigEvents();
-
- mixer_state mixerStatus = MIXER_IDLE;
- { // scope for the mLock
-
- Mutex::Autolock _l(mLock);
-
- if (checkForNewParameters_l()) {
- mixBufferSize = mFrameCount * mFrameSize;
-
- // Only in DuplicatingThread
- updateWaitTime();
-
- activeSleepTime = activeSleepTimeUs();
- idleSleepTime = idleSleepTimeUs();
- }
-
- // 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((!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();
- }
- mStandby = true;
- mBytesWritten = 0;
- }
-
- if (!mActiveTracks.size() && mConfigEvents.isEmpty()) {
- // we're about to wait, flush the binder command buffer
- IPCThreadState::self()->flushCommands();
- outputTracks.clear();
-
- 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();
-
- standbyTime = systemTime() + mStandbyTimeInNsecs;
- sleepTime = idleSleepTime;
- // MixerThread has sleepTimeShift
- continue;
- }
- }
-
- 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
- // or modified if an effect is created or deleted
- lockEffectChains_l(effectChains);
- }
-
- // Duplicating Thread is completely different here
- if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
// mix buffers...
if (outputsReady(outputTracks)) {
mAudioMixer->process(AudioBufferProvider::kInvalidPTS);
@@ -3251,7 +3147,10 @@
}
sleepTime = 0;
writeFrames = mFrameCount;
- } else {
+}
+
+void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()
+{
if (sleepTime == 0) {
if (mixerStatus == MIXER_TRACKS_ENABLED) {
sleepTime = activeSleepTime;
@@ -3269,58 +3168,23 @@
}
}
}
- }
+}
- if (mSuspended > 0) {
- sleepTime = suspendSleepTimeUs();
- }
-
- // only process effects if we're going to write
- if (sleepTime == 0) {
- for (size_t i = 0; i < effectChains.size(); i ++) {
- effectChains[i]->process_l();
- }
- }
-
- // enable changes in effect chain
- unlockEffectChains(effectChains);
-
- // sleepTime == 0 means we must write to audio hardware
- if (sleepTime == 0) {
+void AudioFlinger::DuplicatingThread::threadLoop_write()
+{
standbyTime = systemTime() + mStandbyTimeInNsecs;
for (size_t i = 0; i < outputTracks.size(); i++) {
outputTracks[i]->write(mMixBuffer, writeFrames);
}
- mStandby = false;
mBytesWritten += mixBufferSize;
+}
- // MixerThread has write blocked detection here
-
- } else {
- usleep(sleepTime);
- }
-
- // 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();
- outputTracks.clear();
-
- // 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);
- return false;
+void AudioFlinger::DuplicatingThread::threadLoop_standby()
+{
+ // DuplicatingThread implements standby by stopping all tracks
+ for (size_t i = 0; i < outputTracks.size(); i++) {
+ outputTracks[i]->stop();
+ }
}
void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread)
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index bdaf97c..c7ac0a8 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -207,7 +207,9 @@
// call in any IAudioFlinger method that accesses mPrimaryHardwareDev
status_t initCheck() const { return mPrimaryHardwareDev == NULL ? NO_INIT : NO_ERROR; }
+ // RefBase
virtual void onFirstRef();
+
audio_hw_device_t* findSuitableHwDev_l(uint32_t devices);
void purgeStaleEffects_l();
@@ -581,6 +583,10 @@
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
+#if 1
+ // FIXME remove these hacks for threadLoop_prepareTracks_l
+ , MIXER_CONTINUE // "continue;"
+#endif
};
// playback track
@@ -793,8 +799,33 @@
// Thread virtuals
virtual status_t readyToRun();
+ virtual bool threadLoop();
+
+ // RefBase
virtual void onFirstRef();
+protected:
+ // Code snippets that were lifted up out of threadLoop()
+ virtual void threadLoop_mix() = 0;
+ virtual void threadLoop_sleepTime() = 0;
+ virtual void threadLoop_write();
+ virtual void threadLoop_standby();
+
+ // Non-trivial for DUPLICATING only
+ virtual void updateWaitTime() { }
+
+ // Non-trivial for DIRECT only
+ virtual void applyVolume() { }
+
+ // FIXME merge these
+ // Non-trivial for MIXER and DUPLICATING only
+ virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove) { return MIXER_IDLE; }
+ // Non-trivial for DIRECT only
+ virtual mixer_state threadLoop_prepareTracks_l(sp<Track>& trackToRemove)
+ { return MIXER_IDLE; }
+
+public:
+
virtual status_t initCheck() const { return (mOutput == NULL) ? NO_INIT : NO_ERROR; }
virtual uint32_t latency() const;
@@ -897,6 +928,30 @@
int mNumWrites;
int mNumDelayedWrites;
bool mInWrite;
+
+ // FIXME rename these former local variables of threadLoop to standard "m" names
+ nsecs_t standbyTime;
+ size_t mixBufferSize;
+ uint32_t activeSleepTime;
+ uint32_t idleSleepTime;
+ uint32_t sleepTime;
+ // mixerStatus was local to the while !exitingPending loop
+ mixer_state mixerStatus;
+
+ // FIXME move these declarations into the specific sub-class that needs them
+ // MIXER only
+ bool longStandbyExit;
+ uint32_t sleepTimeShift;
+ // MIXER and DUPLICATING only
+ mixer_state mPrevMixerStatus; // previous status returned by prepareTracks_l()
+ // DIRECT only
+ nsecs_t standbyDelay;
+ // activeTrack was local to the while !exitingPending loop
+ sp<Track> activeTrack;
+ // DUPLICATING only
+ SortedVector < sp<OutputTrack> > outputTracks;
+ uint32_t writeFrames;
+ SortedVector < sp<OutputTrack> > mOutputTracks;
};
class MixerThread : public PlaybackThread {
@@ -909,7 +964,6 @@
virtual ~MixerThread();
// Thread virtuals
- virtual bool threadLoop();
void invalidateTracks(audio_stream_type_t streamType);
virtual bool checkForNewParameters_l();
@@ -920,14 +974,17 @@
// 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 mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove);
virtual int getTrackName_l();
virtual void deleteTrackName_l(int name);
virtual uint32_t idleSleepTimeUs();
virtual uint32_t suspendSleepTimeUs();
+ // threadLoop snippets
+ virtual void threadLoop_mix();
+ virtual void threadLoop_sleepTime();
+
AudioMixer* mAudioMixer;
- mixer_state mPrevMixerStatus; // previous status returned by prepareTracks_l()
};
class DirectOutputThread : public PlaybackThread {
@@ -938,7 +995,6 @@
virtual ~DirectOutputThread();
// Thread virtuals
- virtual bool threadLoop();
virtual bool checkForNewParameters_l();
@@ -949,8 +1005,11 @@
virtual uint32_t idleSleepTimeUs();
virtual uint32_t suspendSleepTimeUs();
- private:
- void applyVolume(uint16_t leftVol, uint16_t rightVol, bool ramp);
+ // threadLoop snippets
+ virtual mixer_state threadLoop_prepareTracks_l(sp<Track>& trackToRemove);
+ virtual void threadLoop_mix();
+ virtual void threadLoop_sleepTime();
+ virtual void applyVolume();
// volumes last sent to audio HAL with stream->set_volume()
// FIXME use standard representation and names
@@ -958,6 +1017,12 @@
float mRightVolFloat;
uint16_t mLeftVolShort;
uint16_t mRightVolShort;
+
+ // FIXME rename these former local variables of threadLoop to standard names
+ // next 3 were local to the while !exitingPending loop
+ bool rampVolume;
+ uint16_t leftVol;
+ uint16_t rightVol;
};
class DuplicatingThread : public MixerThread {
@@ -967,7 +1032,6 @@
virtual ~DuplicatingThread();
// Thread virtuals
- virtual bool threadLoop();
void addOutputTrack(MixerThread* thread);
void removeOutputTrack(MixerThread* thread);
uint32_t waitTimeMs() { return mWaitTimeMs; }
@@ -976,9 +1040,15 @@
private:
bool outputsReady(const SortedVector<sp<OutputTrack> > &outputTracks);
- void updateWaitTime();
+ protected:
+ // threadLoop snippets
+ virtual void threadLoop_mix();
+ virtual void threadLoop_sleepTime();
+ virtual void threadLoop_write();
+ virtual void threadLoop_standby();
+ virtual void updateWaitTime();
+ private:
- SortedVector < sp<OutputTrack> > mOutputTracks;
uint32_t mWaitTimeMs;
};
@@ -1086,8 +1156,11 @@
uint32_t device);
virtual ~RecordThread();
+ // Thread
virtual bool threadLoop();
virtual status_t readyToRun();
+
+ // RefBase
virtual void onFirstRef();
virtual status_t initCheck() const { return (mInput == NULL) ? NO_INIT : NO_ERROR; }