summaryrefslogtreecommitdiffstats
path: root/services
diff options
context:
space:
mode:
Diffstat (limited to 'services')
-rw-r--r--services/audioflinger/AudioFlinger.cpp145
-rw-r--r--services/audioflinger/AudioFlinger.h24
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();