From 3acbd053c842e76e1a40fc8a0bf62de87eebf00f Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 28 Feb 2012 10:39:56 -0800 Subject: Configure policy of mediaserver threads Change-Id: Ifd825590ba36996064a458f64453a94b84722cb0 --- media/libmedia/AudioRecord.cpp | 8 +-- media/libmedia/AudioTrack.cpp | 113 ++++++++++++++++++++++++++++----------- media/libmedia/IAudioFlinger.cpp | 5 +- media/libmedia/IAudioRecord.cpp | 6 +-- media/libmedia/IAudioTrack.cpp | 5 +- 5 files changed, 93 insertions(+), 44 deletions(-) (limited to 'media') diff --git a/media/libmedia/AudioRecord.cpp b/media/libmedia/AudioRecord.cpp index 1fdc536..950f5c6 100644 --- a/media/libmedia/AudioRecord.cpp +++ b/media/libmedia/AudioRecord.cpp @@ -321,8 +321,8 @@ status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession) cblk->lock.lock(); if (!(cblk->flags & CBLK_INVALID_MSK)) { cblk->lock.unlock(); - ALOGV("mAudioRecord->start(tid=%d)", tid); - ret = mAudioRecord->start(tid, event, triggerSession); + ALOGV("mAudioRecord->start()"); + ret = mAudioRecord->start(event, triggerSession); cblk->lock.lock(); if (ret == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -542,7 +542,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) "user=%08x, server=%08x", cblk->user, cblk->server); cblk->lock.unlock(); // callback thread or sync event hasn't changed - result = mAudioRecord->start(0, AudioSystem::SYNC_EVENT_SAME, 0); + result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0); cblk->lock.lock(); if (result == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -781,7 +781,7 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) mFrameCount, getInput_l()); if (result == NO_ERROR) { // callback thread or sync event hasn't changed - result = mAudioRecord->start(0, AudioSystem::SYNC_EVENT_SAME, 0); + result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0); } if (result != NO_ERROR) { mActive = false; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 25d79d6..9d338f3 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -73,6 +73,8 @@ status_t AudioTrack::getMinFrameCount( *frameCount = (sampleRate == 0) ? afFrameCount * minBufCount : afFrameCount * minBufCount * sampleRate / afSampleRate; + ALOGV("getMinFrameCount=%d: afFrameCount=%d, minBufCount=%d, afSampleRate=%d, afLatency=%d", + *frameCount, afFrameCount, minBufCount, afSampleRate, afLatency); return NO_ERROR; } @@ -159,6 +161,7 @@ AudioTrack::~AudioTrack() // Otherwise the callback thread will never exit. stop(); if (mAudioTrackThread != 0) { + mAudioTrackThread->requestExit(); // see comment in AudioTrack.h mAudioTrackThread->requestExitAndWait(); mAudioTrackThread.clear(); } @@ -223,6 +226,7 @@ status_t AudioTrack::set( // force direct flag if format is not linear PCM if (!audio_is_linear_pcm(format)) { flags = (audio_output_flags_t) + // FIXME why can't we allow direct AND fast? ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST); } // only allow deep buffering for music stream type @@ -255,6 +259,11 @@ status_t AudioTrack::set( mAuxEffectId = 0; mCbf = cbf; + if (cbf != NULL) { + mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava); + mAudioTrackThread->run("AudioTrack", ANDROID_PRIORITY_AUDIO, 0 /*stack*/); + } + // create the IAudioTrack status_t status = createTrack_l(streamType, sampleRate, @@ -266,13 +275,13 @@ status_t AudioTrack::set( output); if (status != NO_ERROR) { + if (mAudioTrackThread != 0) { + mAudioTrackThread->requestExit(); + mAudioTrackThread.clear(); + } return status; } - if (cbf != NULL) { - mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava); - } - mStatus = NO_ERROR; mStreamType = streamType; @@ -349,14 +358,6 @@ void AudioTrack::start() status_t status = NO_ERROR; ALOGV("start %p", this); - if (t != 0) { - if (t->exitPending()) { - if (t->requestExitAndWait() == WOULD_BLOCK) { - ALOGE("AudioTrack::start called from thread"); - return; - } - } - } AutoMutex lock(mLock); // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed @@ -373,26 +374,19 @@ void AudioTrack::start() cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); - pid_t tid; if (t != 0) { - t->run("AudioTrack", ANDROID_PRIORITY_AUDIO); - tid = t->getTid(); // pid_t is unknown until run() - ALOGV("getTid=%d", tid); - if (tid == -1) { - tid = 0; - } + t->resume(); } else { mPreviousPriority = getpriority(PRIO_PROCESS, 0); mPreviousSchedulingGroup = androidGetThreadSchedulingGroup(0); androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO); - tid = 0; // not gettid() } ALOGV("start %p before lock cblk %p", this, mCblk); if (!(cblk->flags & CBLK_INVALID_MSK)) { cblk->lock.unlock(); - ALOGV("mAudioTrack->start(tid=%d)", tid); - status = mAudioTrack->start(tid); + ALOGV("mAudioTrack->start()"); + status = mAudioTrack->start(); cblk->lock.lock(); if (status == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -406,7 +400,7 @@ void AudioTrack::start() ALOGV("start() failed"); mActive = false; if (t != 0) { - t->requestExit(); + t->pause(); } else { setpriority(PRIO_PROCESS, 0, mPreviousPriority); androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup); @@ -439,7 +433,7 @@ void AudioTrack::stop() flush_l(); } if (t != 0) { - t->requestExit(); + t->pause(); } else { setpriority(PRIO_PROCESS, 0, mPreviousPriority); androidSetThreadSchedulingGroup(0, mPreviousSchedulingGroup); @@ -771,7 +765,7 @@ status_t AudioTrack::createTrack_l( (sharedBuffer != 0) || // use case 2: callback handler (mCbf != NULL))) { - ALOGW("AUDIO_OUTPUT_FLAG_FAST denied"); + ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by client"); flags = (audio_output_flags_t) (flags & ~AUDIO_OUTPUT_FLAG_FAST); } ALOGV("createTrack_l() output %d afFrameCount %d afLatency %d", output, afFrameCount, afLatency); @@ -787,6 +781,13 @@ status_t AudioTrack::createTrack_l( if (minBufCount < 2) minBufCount = 2; int minFrameCount = (afFrameCount*sampleRate*minBufCount)/afSampleRate; + ALOGV("minFrameCount: %d, afFrameCount=%d, minBufCount=%d, sampleRate=%d, afSampleRate=%d" + ", afLatency=%d", + minFrameCount, afFrameCount, minBufCount, sampleRate, afSampleRate, afLatency); +#define MIN_FRAME_COUNT_FAST 128 // FIXME hard-coded + if ((flags & AUDIO_OUTPUT_FLAG_FAST) && (minFrameCount > MIN_FRAME_COUNT_FAST)) { + minFrameCount = MIN_FRAME_COUNT_FAST; + } if (sharedBuffer == 0) { if (frameCount == 0) { @@ -800,7 +801,7 @@ status_t AudioTrack::createTrack_l( if (mNotificationFramesAct > (uint32_t)frameCount/2) { mNotificationFramesAct = frameCount/2; } - if (frameCount < minFrameCount && !(flags & AUDIO_OUTPUT_FLAG_FAST)) { + if (frameCount < minFrameCount) { // not ALOGW because it happens all the time when playing key clicks over A2DP ALOGV("Minimum buffer size corrected from %d to %d", frameCount, minFrameCount); @@ -821,8 +822,13 @@ status_t AudioTrack::createTrack_l( if (mIsTimed) { trackFlags |= IAudioFlinger::TRACK_TIMED; } + + pid_t tid = -1; if (flags & AUDIO_OUTPUT_FLAG_FAST) { trackFlags |= IAudioFlinger::TRACK_FAST; + if (mAudioTrackThread != 0) { + tid = mAudioTrackThread->getTid(); + } } sp track = audioFlinger->createTrack(getpid(), @@ -834,6 +840,7 @@ status_t AudioTrack::createTrack_l( trackFlags, sharedBuffer, output, + tid, &mSessionId, &status); @@ -849,7 +856,15 @@ status_t AudioTrack::createTrack_l( mAudioTrack = track; mCblkMemory = cblk; mCblk = static_cast(cblk->pointer()); - android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags); + // old has the previous value of mCblk->flags before the "or" operation + int32_t old = android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags); + if (flags & AUDIO_OUTPUT_FLAG_FAST) { + if (old & CBLK_FAST) { + ALOGI("AUDIO_OUTPUT_FLAG_FAST successful; frameCount %u", mCblk->frameCount); + } else { + ALOGW("AUDIO_OUTPUT_FLAG_FAST denied by server; frameCount %u", mCblk->frameCount); + } + } if (sharedBuffer == 0) { mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else { @@ -926,7 +941,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) "user=%08x, server=%08x", this, cblk->user, cblk->server); //unlock cblk mutex before calling mAudioTrack->start() (see issue #1617140) cblk->lock.unlock(); - result = mAudioTrack->start(0); // callback thread hasn't changed + result = mAudioTrack->start(); cblk->lock.lock(); if (result == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); @@ -958,7 +973,7 @@ create_new_track: if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); ALOGW("obtainBuffer() track %p disabled, restarting", this); - mAudioTrack->start(0); // callback thread hasn't changed + mAudioTrack->start(); } cblk->waitTimeMs = 0; @@ -1096,7 +1111,7 @@ status_t TimedAudioTrack::queueTimedBuffer(const sp& buffer, if (mActive && (mCblk->flags & CBLK_DISABLED_MSK)) { android_atomic_and(~CBLK_DISABLED_ON, &mCblk->flags); ALOGW("queueTimedBuffer() track %p disabled, restarting", this); - mAudioTrack->start(0); + mAudioTrack->start(); } return mAudioTrack->queueTimedBuffer(buffer, pts); @@ -1301,7 +1316,7 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) } } if (mActive) { - result = mAudioTrack->start(0); // callback thread hasn't changed + result = mAudioTrack->start(); ALOGW_IF(result != NO_ERROR, "restoreTrack_l() start() failed status %d", result); } if (fromStart && result == NO_ERROR) { @@ -1369,12 +1384,24 @@ status_t AudioTrack::dump(int fd, const Vector& args) const // ========================================================================= AudioTrack::AudioTrackThread::AudioTrackThread(AudioTrack& receiver, bool bCanCallJava) - : Thread(bCanCallJava), mReceiver(receiver) + : Thread(bCanCallJava), mReceiver(receiver), mPaused(true) +{ +} + +AudioTrack::AudioTrackThread::~AudioTrackThread() { } bool AudioTrack::AudioTrackThread::threadLoop() { + { + AutoMutex _l(mMyLock); + if (mPaused) { + mMyCond.wait(mMyLock); + // caller will check for exitPending() + return true; + } + } return mReceiver.processAudioBuffer(this); } @@ -1387,6 +1414,28 @@ void AudioTrack::AudioTrackThread::onFirstRef() { } +void AudioTrack::AudioTrackThread::requestExit() +{ + // must be in this order to avoid a race condition + Thread::requestExit(); + mMyCond.signal(); +} + +void AudioTrack::AudioTrackThread::pause() +{ + AutoMutex _l(mMyLock); + mPaused = true; +} + +void AudioTrack::AudioTrackThread::resume() +{ + AutoMutex _l(mMyLock); + if (mPaused) { + mPaused = false; + mMyCond.signal(); + } +} + // ========================================================================= diff --git a/media/libmedia/IAudioFlinger.cpp b/media/libmedia/IAudioFlinger.cpp index 2b5126f..e8dd438 100644 --- a/media/libmedia/IAudioFlinger.cpp +++ b/media/libmedia/IAudioFlinger.cpp @@ -91,6 +91,7 @@ public: track_flags_t flags, const sp& sharedBuffer, audio_io_handle_t output, + pid_t tid, int *sessionId, status_t *status) { @@ -106,6 +107,7 @@ public: data.writeInt32((int32_t) flags); data.writeStrongBinder(sharedBuffer->asBinder()); data.writeInt32((int32_t) output); + data.writeInt32((int32_t) tid); int lSessionId = 0; if (sessionId != NULL) { lSessionId = *sessionId; @@ -701,11 +703,12 @@ status_t BnAudioFlinger::onTransact( track_flags_t flags = (track_flags_t) data.readInt32(); sp buffer = interface_cast(data.readStrongBinder()); audio_io_handle_t output = (audio_io_handle_t) data.readInt32(); + pid_t tid = (pid_t) data.readInt32(); int sessionId = data.readInt32(); status_t status; sp track = createTrack(pid, (audio_stream_type_t) streamType, sampleRate, format, - channelCount, bufferCount, flags, buffer, output, &sessionId, &status); + channelCount, bufferCount, flags, buffer, output, tid, &sessionId, &status); reply->writeInt32(sessionId); reply->writeInt32(status); reply->writeStrongBinder(track->asBinder()); diff --git a/media/libmedia/IAudioRecord.cpp b/media/libmedia/IAudioRecord.cpp index 58c6d38..57a80a9 100644 --- a/media/libmedia/IAudioRecord.cpp +++ b/media/libmedia/IAudioRecord.cpp @@ -42,11 +42,10 @@ public: { } - virtual status_t start(pid_t tid, int event, int triggerSession) + virtual status_t start(int event, int triggerSession) { Parcel data, reply; data.writeInterfaceToken(IAudioRecord::getInterfaceDescriptor()); - data.writeInt32(tid); data.writeInt32(event); data.writeInt32(triggerSession); status_t status = remote()->transact(START, data, &reply); @@ -93,10 +92,9 @@ status_t BnAudioRecord::onTransact( } break; case START: { CHECK_INTERFACE(IAudioRecord, data, reply); - pid_t tid = (pid_t) data.readInt32(); int event = data.readInt32(); int triggerSession = data.readInt32(); - reply->writeInt32(start(tid, event, triggerSession)); + reply->writeInt32(start(event, triggerSession)); return NO_ERROR; } break; case STOP: { diff --git a/media/libmedia/IAudioTrack.cpp b/media/libmedia/IAudioTrack.cpp index 09f31a7..867d1a5 100644 --- a/media/libmedia/IAudioTrack.cpp +++ b/media/libmedia/IAudioTrack.cpp @@ -61,11 +61,10 @@ public: return cblk; } - virtual status_t start(pid_t tid) + virtual status_t start() { Parcel data, reply; data.writeInterfaceToken(IAudioTrack::getInterfaceDescriptor()); - data.writeInt32(tid); status_t status = remote()->transact(START, data, &reply); if (status == NO_ERROR) { status = reply.readInt32(); @@ -180,7 +179,7 @@ status_t BnAudioTrack::onTransact( } break; case START: { CHECK_INTERFACE(IAudioTrack, data, reply); - reply->writeInt32(start(data.readInt32())); + reply->writeInt32(start()); return NO_ERROR; } break; case STOP: { -- cgit v1.1