summaryrefslogtreecommitdiff
path: root/services/audioflinger/AudioFlinger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'services/audioflinger/AudioFlinger.cpp')
-rw-r--r--services/audioflinger/AudioFlinger.cpp630
1 files changed, 247 insertions, 383 deletions
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 8f7b35c3dd1d..b97254827521 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -1919,10 +1919,10 @@ uint32_t AudioFlinger::PlaybackThread::activeSleepTimeUs()
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 @@ void AudioFlinger::PlaybackThread::checkSilentMode_l()
}
}
-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 @@ bool AudioFlinger::MixerThread::threadLoop()
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 @@ bool AudioFlinger::MixerThread::threadLoop()
// 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 @@ bool AudioFlinger::MixerThread::threadLoop()
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,58 +2162,14 @@ bool AudioFlinger::MixerThread::threadLoop()
lockEffectChains_l(effectChains);
}
- if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
- // obtain the presentation timestamp of the next output buffer
- int64_t pts;
- status_t status = INVALID_OPERATION;
-
- if (NULL != mOutput->stream->get_next_write_timestamp) {
- status = mOutput->stream->get_next_write_timestamp(
- mOutput->stream, &pts);
- }
-
- if (status != NO_ERROR) {
- pts = AudioBufferProvider::kInvalidPTS;
- }
+if (mType == DIRECT) {
+ // For DirectOutputThread, this test is equivalent to "activeTrack != 0"
+}
- // mix buffers...
- mAudioMixer->process(pts);
- // increase sleep time progressively when application underrun condition clears.
- // Only increase sleep time if the mixer is ready for two consecutive times to avoid
- // that a steady state of alternating ready/not ready conditions keeps the sleep time
- // such that we would underrun the audio HAL.
- if ((sleepTime == 0) && (sleepTimeShift > 0)) {
- sleepTimeShift--;
- }
- sleepTime = 0;
- standbyTime = systemTime() + mStandbyTimeInNsecs;
- //TODO: delay standby when effects have a tail
+ if (CC_LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
+ threadLoop_mix();
} else {
- // If no tracks are ready, sleep once for the duration of an output
- // buffer size, then write 0s to the output
- if (sleepTime == 0) {
- if (mixerStatus == MIXER_TRACKS_ENABLED) {
- sleepTime = activeSleepTime >> sleepTimeShift;
- if (sleepTime < kMinThreadSleepTimeUs) {
- sleepTime = kMinThreadSleepTimeUs;
- }
- // reduce sleep time in case of consecutive application underruns to avoid
- // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
- // duration we would end up writing less data than needed by the audio HAL if
- // the condition persists.
- if (sleepTimeShift < kMaxThreadSleepTimeShift) {
- sleepTimeShift++;
- }
- } else {
- sleepTime = idleSleepTime;
- }
- } else if (mBytesWritten != 0 ||
- (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
- memset (mMixBuffer, 0, mixBufferSize);
- sleepTime = 0;
- ALOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
- }
- // TODO add standby time extension fct of effect tail
+ threadLoop_sleepTime();
}
if (mSuspended > 0) {
@@ -2149,7 +2179,12 @@ bool AudioFlinger::MixerThread::threadLoop()
// only process effects if we're going to write
if (sleepTime == 0) {
- // DirectOutputThread adds applyVolume here
+ if (mixerStatus == MIXER_TRACKS_READY) {
+
+ // Non-trivial for DIRECT only
+ applyVolume();
+
+ }
for (size_t i = 0; i < effectChains.size(); i ++) {
effectChains[i]->process_l();
@@ -2161,16 +2196,11 @@ 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
+ threadLoop_write();
+
+if (mType == MIXER) {
+ // write blocked detection
nsecs_t now = systemTime();
nsecs_t delta = now - mLastWriteTime;
if (!mStandby && delta > maxPeriod) {
@@ -2180,11 +2210,13 @@ bool AudioFlinger::MixerThread::threadLoop()
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;
}
}
- // end of write blocked detection
+}
mStandby = false;
} else {
@@ -2194,7 +2226,19 @@ bool AudioFlinger::MixerThread::threadLoop()
// 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
@@ -2204,10 +2248,15 @@ bool AudioFlinger::MixerThread::threadLoop()
// 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();
@@ -2215,6 +2264,84 @@ bool AudioFlinger::MixerThread::threadLoop()
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;
+
+ if (NULL != mOutput->stream->get_next_write_timestamp) {
+ status = mOutput->stream->get_next_write_timestamp(
+ mOutput->stream, &pts);
+ }
+
+ if (status != NO_ERROR) {
+ pts = AudioBufferProvider::kInvalidPTS;
+ }
+
+ // mix buffers...
+ mAudioMixer->process(pts);
+ // increase sleep time progressively when application underrun condition clears.
+ // Only increase sleep time if the mixer is ready for two consecutive times to avoid
+ // that a steady state of alternating ready/not ready conditions keeps the sleep time
+ // such that we would underrun the audio HAL.
+ if ((sleepTime == 0) && (sleepTimeShift > 0)) {
+ sleepTimeShift--;
+ }
+ sleepTime = 0;
+ standbyTime = systemTime() + mStandbyTimeInNsecs;
+ //TODO: delay standby when effects have a tail
+}
+
+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) {
+ if (mixerStatus == MIXER_TRACKS_ENABLED) {
+ sleepTime = activeSleepTime >> sleepTimeShift;
+ if (sleepTime < kMinThreadSleepTimeUs) {
+ sleepTime = kMinThreadSleepTimeUs;
+ }
+ // reduce sleep time in case of consecutive application underruns to avoid
+ // starving the audio HAL. As activeSleepTimeUs() is larger than a buffer
+ // duration we would end up writing less data than needed by the audio HAL if
+ // the condition persists.
+ if (sleepTimeShift < kMaxThreadSleepTimeShift) {
+ sleepTimeShift++;
+ }
+ } else {
+ sleepTime = idleSleepTime;
+ }
+ } else if (mBytesWritten != 0 ||
+ (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
+ memset (mMixBuffer, 0, mixBufferSize);
+ sleepTime = 0;
+ ALOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
+ }
+ // TODO add standby time extension fct of effect tail
+}
+
// prepareTracks_l() must be called with ThreadBase::mLock held
AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTracks_l(
Vector< sp<Track> > *tracksToRemove)
@@ -2653,7 +2780,7 @@ AudioFlinger::DirectOutputThread::~DirectOutputThread()
{
}
-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 @@ void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t ri
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 @@ void AudioFlinger::DirectOutputThread::applyVolume(uint16_t leftVol, uint16_t ri
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 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
// 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 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
// 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 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
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 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
// 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 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
}
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 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
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 @@ AudioFlinger::DuplicatingThread::~DuplicatingThread()
}
}
-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 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
}
sleepTime = 0;
writeFrames = mFrameCount;
- } else {
+}
+
+void AudioFlinger::DuplicatingThread::threadLoop_sleepTime()
+{
if (sleepTime == 0) {
if (mixerStatus == MIXER_TRACKS_ENABLED) {
sleepTime = activeSleepTime;
@@ -3269,58 +3168,23 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
}
}
}
- }
-
- 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)