Merge change Iad79689a into eclair

* changes:
  Improvements for issue 2197683:	English IME key-press latency is noticeably higher on passion than sholes
This commit is contained in:
Android (Google) Code Review
2009-11-12 22:53:28 -08:00
3 changed files with 122 additions and 80 deletions

View File

@ -1185,7 +1185,6 @@ void AudioFlinger::PlaybackThread::readOutputParameters()
mFrameSize = mOutput->frameSize();
mFrameCount = mOutput->bufferSize() / mFrameSize;
mMinBytesToWrite = (mOutput->latency() * mSampleRate * mFrameSize) / 1000;
// FIXME - Current mixer implementation only supports stereo output: Always
// Allocate a stereo buffer even if HW output is mono.
if (mMixBuffer != NULL) delete mMixBuffer;
@ -1215,23 +1214,25 @@ AudioFlinger::MixerThread::~MixerThread()
bool AudioFlinger::MixerThread::threadLoop()
{
uint32_t sleepTime = 1000;
uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
int16_t* curBuf = mMixBuffer;
Vector< sp<Track> > tracksToRemove;
size_t enabledTracks = 0;
uint32_t mixerStatus = MIXER_IDLE;
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
nsecs_t maxPeriod = seconds(mFrameCount) / mSampleRate * 3;
nsecs_t lastWarning = 0;
bool longStandbyExit = false;
uint32_t activeSleepTime = activeSleepTimeUs();
uint32_t idleSleepTime = idleSleepTimeUs();
uint32_t sleepTime = idleSleepTime;
while (!exitPending())
{
processConfigEvents();
enabledTracks = 0;
mixerStatus = MIXER_IDLE;
{ // scope for mLock
Mutex::Autolock _l(mLock);
@ -1241,7 +1242,8 @@ bool AudioFlinger::MixerThread::threadLoop()
// 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
maxPeriod = seconds(mFrameCount) / mSampleRate * 3;
maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
}
const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
@ -1277,15 +1279,15 @@ bool AudioFlinger::MixerThread::threadLoop()
}
standbyTime = systemTime() + kStandbyTimeInNsecs;
sleepTime = 1000;
sleepTime = idleSleepTime;
continue;
}
}
enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
}
if (LIKELY(enabledTracks)) {
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
// mix buffers...
mAudioMixer->process(curBuf);
sleepTime = 0;
@ -1294,15 +1296,22 @@ bool AudioFlinger::MixerThread::threadLoop()
// If no tracks are ready, sleep once for the duration of an output
// buffer size, then write 0s to the output
if (sleepTime == 0) {
sleepTime = maxBufferRecoveryInUsecs;
} else if (mBytesWritten != 0) {
if (mixerStatus == MIXER_TRACKS_ENABLED) {
sleepTime = activeSleepTime;
} else {
sleepTime = idleSleepTime;
}
} else if (mBytesWritten != 0 ||
(mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)) {
LOGV("NO DATA READY, %p", this);
memset (curBuf, 0, mixBufferSize);
sleepTime = 0;
LOGV_IF((mBytesWritten == 0 && (mixerStatus == MIXER_TRACKS_ENABLED && longStandbyExit)), "anticipated start");
}
}
if (mSuspended) {
sleepTime = maxBufferRecoveryInUsecs;
sleepTime = idleSleepTime;
}
// sleepTime == 0 means we must write to audio hardware
if (sleepTime == 0) {
@ -1312,7 +1321,6 @@ bool AudioFlinger::MixerThread::threadLoop()
if (bytesWritten > 0) mBytesWritten += bytesWritten;
mNumWrites++;
mInWrite = false;
mStandby = false;
nsecs_t now = systemTime();
nsecs_t delta = now - mLastWriteTime;
if (delta > maxPeriod) {
@ -1322,7 +1330,11 @@ bool AudioFlinger::MixerThread::threadLoop()
ns2ms(delta), mNumDelayedWrites, this);
lastWarning = now;
}
if (mStandby) {
longStandbyExit = true;
}
}
mStandby = false;
} else {
usleep(sleepTime);
}
@ -1342,10 +1354,10 @@ bool AudioFlinger::MixerThread::threadLoop()
}
// prepareTracks_l() must be called with ThreadBase::mLock held
size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove)
{
size_t enabledTracks = 0;
uint32_t mixerStatus = MIXER_IDLE;
// find out which tracks need to be processed
size_t count = activeTracks.size();
for (size_t i=0 ; i<count ; i++) {
@ -1415,7 +1427,7 @@ size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track>
// reset retry count
track->mRetryCount = kMaxTrackRetries;
enabledTracks++;
mixerStatus = MIXER_TRACKS_READY;
} else {
//LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
if (track->isStopped()) {
@ -1432,16 +1444,11 @@ size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track>
if (--(track->mRetryCount) <= 0) {
LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this);
tracksToRemove->add(track);
} else if (mixerStatus != MIXER_TRACKS_READY) {
mixerStatus = MIXER_TRACKS_ENABLED;
}
// For tracks using static shared memory buffer, make sure that we have
// written enough data to audio hardware before disabling the track
// NOTE: this condition with arrive before track->mRetryCount <= 0 so we
// don't care about code removing track from active list above.
if ((track->mSharedBuffer == 0) || (mBytesWritten >= mMinBytesToWrite)) {
mAudioMixer->disable(AudioMixer::MIXING);
} else {
enabledTracks++;
}
mAudioMixer->disable(AudioMixer::MIXING);
}
}
}
@ -1459,7 +1466,7 @@ size_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track>
}
}
return enabledTracks;
return mixerStatus;
}
void AudioFlinger::MixerThread::getTracks(
@ -1621,14 +1628,14 @@ status_t AudioFlinger::MixerThread::dumpInternals(int fd, const Vector<String16>
return NO_ERROR;
}
uint32_t AudioFlinger::MixerThread::getMaxBufferRecoveryInUsecs()
uint32_t AudioFlinger::MixerThread::activeSleepTimeUs()
{
uint32_t time = ((mFrameCount * 1000) / mSampleRate) * 1000;
// Add some margin with regard to scheduling precision
if (time > 10000) {
time -= 10000;
}
return time;
return (uint32_t)(mOutput->latency() * 1000) / 2;
}
uint32_t AudioFlinger::MixerThread::idleSleepTimeUs()
{
return (uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000;
}
// ----------------------------------------------------------------------------
@ -1646,25 +1653,31 @@ AudioFlinger::DirectOutputThread::~DirectOutputThread()
bool AudioFlinger::DirectOutputThread::threadLoop()
{
uint32_t sleepTime = 1000;
uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
uint32_t mixerStatus = MIXER_IDLE;
sp<Track> trackToRemove;
sp<Track> activeTrack;
nsecs_t standbyTime = systemTime();
int8_t *curBuf;
size_t mixBufferSize = mFrameCount*mFrameSize;
uint32_t activeSleepTime = activeSleepTimeUs();
uint32_t idleSleepTime = idleSleepTimeUs();
uint32_t sleepTime = idleSleepTime;
while (!exitPending())
{
processConfigEvents();
mixerStatus = MIXER_IDLE;
{ // scope for the mLock
Mutex::Autolock _l(mLock);
if (checkForNewParameters_l()) {
mixBufferSize = mFrameCount*mFrameSize;
maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
}
// put audio hardware into standby after short delay
@ -1698,7 +1711,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
}
standbyTime = systemTime() + kStandbyTimeInNsecs;
sleepTime = 1000;
sleepTime = idleSleepTime;
continue;
}
}
@ -1753,6 +1766,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
// reset retry count
track->mRetryCount = kMaxTrackRetries;
activeTrack = t;
mixerStatus = MIXER_TRACKS_READY;
} else {
//LOGV("track %d u=%08x, s=%08x [NOT READY]", track->name(), cblk->user, cblk->server);
if (track->isStopped()) {
@ -1768,16 +1782,10 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
if (--(track->mRetryCount) <= 0) {
LOGV("BUFFER TIMEOUT: remove(%d) from active list", track->name());
trackToRemove = track;
} else {
mixerStatus = MIXER_TRACKS_ENABLED;
}
// For tracks using static shared memry buffer, make sure that we have
// written enough data to audio hardware before disabling the track
// NOTE: this condition with arrive before track->mRetryCount <= 0 so we
// don't care about code removing track from active list above.
if ((track->mSharedBuffer != 0) && (mBytesWritten < mMinBytesToWrite)) {
activeTrack = t;
}
}
}
}
}
@ -1791,7 +1799,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
}
}
if (activeTrack != 0) {
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
AudioBufferProvider::Buffer buffer;
size_t frameCount = mFrameCount;
curBuf = (int8_t *)mMixBuffer;
@ -1812,7 +1820,11 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
standbyTime = systemTime() + kStandbyTimeInNsecs;
} else {
if (sleepTime == 0) {
sleepTime = maxBufferRecoveryInUsecs;
if (mixerStatus == MIXER_TRACKS_ENABLED) {
sleepTime = activeSleepTime;
} else {
sleepTime = idleSleepTime;
}
} else if (mBytesWritten != 0 && AudioSystem::isLinearPCM(mFormat)) {
memset (mMixBuffer, 0, mFrameCount * mFrameSize);
sleepTime = 0;
@ -1820,7 +1832,7 @@ bool AudioFlinger::DirectOutputThread::threadLoop()
}
if (mSuspended) {
sleepTime = maxBufferRecoveryInUsecs;
sleepTime = idleSleepTime;
}
// sleepTime == 0 means we must write to audio hardware
if (sleepTime == 0) {
@ -1905,15 +1917,22 @@ bool AudioFlinger::DirectOutputThread::checkForNewParameters_l()
return reconfig;
}
uint32_t AudioFlinger::DirectOutputThread::getMaxBufferRecoveryInUsecs()
uint32_t AudioFlinger::DirectOutputThread::activeSleepTimeUs()
{
uint32_t time;
if (AudioSystem::isLinearPCM(mFormat)) {
time = ((mFrameCount * 1000) / mSampleRate) * 1000;
// Add some margin with regard to scheduling precision
if (time > 10000) {
time -= 10000;
}
time = (uint32_t)(mOutput->latency() * 1000) / 2;
} else {
time = 10000;
}
return time;
}
uint32_t AudioFlinger::DirectOutputThread::idleSleepTimeUs()
{
uint32_t time;
if (AudioSystem::isLinearPCM(mFormat)) {
time = (uint32_t)((mFrameCount * 1000) / mSampleRate) * 1000;
} else {
time = 10000;
}
@ -1936,28 +1955,30 @@ AudioFlinger::DuplicatingThread::~DuplicatingThread()
bool AudioFlinger::DuplicatingThread::threadLoop()
{
uint32_t sleepTime = 1000;
uint32_t maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
int16_t* curBuf = mMixBuffer;
Vector< sp<Track> > tracksToRemove;
size_t enabledTracks = 0;
uint32_t mixerStatus = MIXER_IDLE;
nsecs_t standbyTime = systemTime();
size_t mixBufferSize = mFrameCount*mFrameSize;
SortedVector< sp<OutputTrack> > outputTracks;
uint32_t writeFrames = 0;
uint32_t activeSleepTime = activeSleepTimeUs();
uint32_t idleSleepTime = idleSleepTimeUs();
uint32_t sleepTime = idleSleepTime;
while (!exitPending())
{
processConfigEvents();
enabledTracks = 0;
mixerStatus = MIXER_IDLE;
{ // scope for the mLock
Mutex::Autolock _l(mLock);
if (checkForNewParameters_l()) {
mixBufferSize = mFrameCount*mFrameSize;
maxBufferRecoveryInUsecs = getMaxBufferRecoveryInUsecs();
activeSleepTime = activeSleepTimeUs();
idleSleepTime = idleSleepTimeUs();
}
const SortedVector< wp<Track> >& activeTracks = mActiveTracks;
@ -1997,22 +2018,26 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
}
standbyTime = systemTime() + kStandbyTimeInNsecs;
sleepTime = 1000;
sleepTime = idleSleepTime;
continue;
}
}
enabledTracks = prepareTracks_l(activeTracks, &tracksToRemove);
mixerStatus = prepareTracks_l(activeTracks, &tracksToRemove);
}
if (LIKELY(enabledTracks)) {
if (LIKELY(mixerStatus == MIXER_TRACKS_READY)) {
// mix buffers...
mAudioMixer->process(curBuf);
sleepTime = 0;
writeFrames = mFrameCount;
} else {
if (sleepTime == 0) {
sleepTime = maxBufferRecoveryInUsecs;
if (mixerStatus == MIXER_TRACKS_ENABLED) {
sleepTime = activeSleepTime;
} else {
sleepTime = idleSleepTime;
}
} else if (mBytesWritten != 0) {
// flush remaining overflow buffers in output tracks
for (size_t i = 0; i < outputTracks.size(); i++) {
@ -2026,7 +2051,7 @@ bool AudioFlinger::DuplicatingThread::threadLoop()
}
if (mSuspended) {
sleepTime = maxBufferRecoveryInUsecs;
sleepTime = idleSleepTime;
}
// sleepTime == 0 means we must write to audio hardware
if (sleepTime == 0) {

View File

@ -361,6 +361,12 @@ private:
DUPLICATING
};
enum mixer_state {
MIXER_IDLE,
MIXER_TRACKS_ENABLED,
MIXER_TRACKS_READY
};
// playback track
class Track : public TrackBase {
public:
@ -530,7 +536,8 @@ private:
virtual int getTrackName_l() = 0;
virtual void deleteTrackName_l(int name) = 0;
virtual uint32_t getMaxBufferRecoveryInUsecs() = 0;
virtual uint32_t activeSleepTimeUs() = 0;
virtual uint32_t idleSleepTimeUs() = 0;
private:
@ -562,7 +569,6 @@ private:
int mNumWrites;
int mNumDelayedWrites;
bool mInWrite;
int mMinBytesToWrite;
};
class MixerThread : public PlaybackThread {
@ -582,10 +588,11 @@ private:
virtual status_t dumpInternals(int fd, const Vector<String16>& args);
protected:
size_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove);
uint32_t prepareTracks_l(const SortedVector< wp<Track> >& activeTracks, Vector< sp<Track> > *tracksToRemove);
virtual int getTrackName_l();
virtual void deleteTrackName_l(int name);
virtual uint32_t getMaxBufferRecoveryInUsecs();
virtual uint32_t activeSleepTimeUs();
virtual uint32_t idleSleepTimeUs();
AudioMixer* mAudioMixer;
};
@ -604,7 +611,8 @@ private:
protected:
virtual int getTrackName_l();
virtual void deleteTrackName_l(int name);
virtual uint32_t getMaxBufferRecoveryInUsecs();
virtual uint32_t activeSleepTimeUs();
virtual uint32_t idleSleepTimeUs();
private:
float mLeftVolume;

View File

@ -318,26 +318,35 @@ void AudioTrack::start()
}
if (android_atomic_or(1, &mActive) == 0) {
audio_io_handle_t output = AudioTrack::getOutput();
audio_io_handle_t output = getOutput();
AudioSystem::startOutput(output, (AudioSystem::stream_type)mStreamType);
mNewPosition = mCblk->server + mUpdatePeriod;
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
}
status_t status = mAudioTrack->start();
if (status == DEAD_OBJECT) {
LOGV("start() dead IAudioTrack: creating a new one");
status = createTrack(mStreamType, mCblk->sampleRate, mFormat, mChannelCount,
mFrameCount, mFlags, mSharedBuffer, output);
}
if (status == NO_ERROR) {
AudioSystem::startOutput(output, (AudioSystem::stream_type)mStreamType);
mNewPosition = mCblk->server + mUpdatePeriod;
mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS;
mCblk->waitTimeMs = 0;
if (t != 0) {
t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT);
} else {
setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT);
}
} else {
}
if (status != NO_ERROR) {
LOGV("start() failed");
android_atomic_and(~1, &mActive);
if (t != 0) {
t->requestExit();
} else {
setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
}
AudioSystem::stopOutput(output, (AudioSystem::stream_type)mStreamType);
}
}