Loading include/private/media/AudioTrackShared.h +4 −4 Original line number Diff line number Diff line Loading @@ -83,13 +83,12 @@ struct audio_track_cblk_t uint8_t frameSize; uint8_t channelCount; uint16_t flags; uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger uint16_t waitTimeMs; // Cumulated wait time uint16_t waitTimeMs; // Cumulated wait time uint16_t sendLevel; uint16_t reserved; volatile int32_t flags; // Cache line boundary (32 bytes) audio_track_cblk_t(); uint32_t stepUser(uint32_t frameCount); Loading @@ -98,6 +97,7 @@ struct audio_track_cblk_t uint32_t framesAvailable(); uint32_t framesAvailable_l(); uint32_t framesReady(); bool tryLock(); }; Loading media/libmedia/AudioRecord.cpp +7 −14 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/Timers.h> #include <utils/Atomic.h> #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) Loading Loading @@ -299,7 +300,7 @@ status_t AudioRecord::start() ret = mAudioRecord->start(); cblk->lock.lock(); if (ret == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); } } if (cblk->flags & CBLK_INVALID_MSK) { Loading Loading @@ -467,7 +468,7 @@ status_t AudioRecord::openRecord_l( mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); mCblk->flags &= ~CBLK_DIRECTION_MSK; android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags); mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; mCblk->waitTimeMs = 0; return NO_ERROR; Loading Loading @@ -522,7 +523,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = mAudioRecord->start(); cblk->lock.lock(); if (result == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); create_new_record: result = AudioRecord::restoreRecord_l(cblk); } Loading Loading @@ -722,12 +723,8 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) // Manage overrun callback if (mActive && (cblk->framesAvailable() == 0)) { LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); AutoMutex _l(cblk->lock); if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { cblk->flags |= CBLK_UNDERRUN_ON; cblk->lock.unlock(); if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { mCbf(EVENT_OVERRUN, mUserData, 0); cblk->lock.lock(); } } Loading @@ -746,10 +743,8 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) { status_t result; if (!(cblk->flags & CBLK_RESTORING_MSK)) { if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) { LOGW("dead IAudioRecord, creating a new one"); cblk->flags |= CBLK_RESTORING_ON; // signal old cblk condition so that other threads waiting for available buffers stop // waiting now cblk->cv.broadcast(); Loading @@ -768,10 +763,8 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) } // signal old cblk condition for other threads waiting for restore completion cblk->lock.lock(); cblk->flags |= CBLK_RESTORED_MSK; android_atomic_or(CBLK_RESTORED_ON, &cblk->flags); cblk->cv.broadcast(); cblk->lock.unlock(); } else { if (!(cblk->flags & CBLK_RESTORED_MSK)) { LOGW("dead IAudioRecord, waiting for a new one to be created"); Loading media/libmedia/AudioTrack.cpp +46 −46 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/Timers.h> #include <utils/Atomic.h> #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) Loading Loading @@ -332,7 +333,7 @@ void AudioTrack::start() cblk->lock.lock(); cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; cblk->flags &= ~CBLK_DISABLED_ON; android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); if (t != 0) { t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); } else { Loading @@ -345,7 +346,7 @@ void AudioTrack::start() status = mAudioTrack->start(); cblk->lock.lock(); if (status == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); } } if (cblk->flags & CBLK_INVALID_MSK) { Loading Loading @@ -636,7 +637,7 @@ status_t AudioTrack::setPosition(uint32_t position) if (position > mCblk->user) return BAD_VALUE; mCblk->server = position; mCblk->flags |= CBLK_FORCEREADY_ON; android_atomic_or(CBLK_FORCEREADY_ON, &mCblk->flags); return NO_ERROR; } Loading Loading @@ -793,7 +794,7 @@ status_t AudioTrack::createTrack_l( mCblkMemory.clear(); mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->flags |= CBLK_DIRECTION_OUT; android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags); if (sharedBuffer == 0) { mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else { Loading Loading @@ -873,7 +874,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = mAudioTrack->start(); cblk->lock.lock(); if (result == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); create_new_track: result = restoreTrack_l(cblk, false); } Loading @@ -900,14 +901,9 @@ create_new_track: // restart track if it was disabled by audioflinger due to previous underrun if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { AutoMutex _l(cblk->lock); if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { cblk->flags &= ~CBLK_DISABLED_ON; cblk->lock.unlock(); android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); LOGW("obtainBuffer() track %p disabled, restarting", this); mAudioTrack->start(); cblk->lock.lock(); } } cblk->waitTimeMs = 0; Loading Loading @@ -1026,17 +1022,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) mLock.unlock(); // Manage underrun callback if (mActive && (cblk->framesReady() == 0)) { if (mActive && (cblk->framesAvailable() == cblk->frameCount)) { LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); AutoMutex _l(cblk->lock); if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { cblk->flags |= CBLK_UNDERRUN_ON; cblk->lock.unlock(); if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { mCbf(EVENT_UNDERRUN, mUserData, 0); if (cblk->server == cblk->frameCount) { mCbf(EVENT_BUFFER_END, mUserData, 0); } cblk->lock.lock(); if (mSharedBuffer != 0) return false; } } Loading Loading @@ -1150,12 +1142,10 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) { status_t result; if (!(cblk->flags & CBLK_RESTORING_MSK)) { if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) { LOGW("dead IAudioTrack, creating a new one from %s", fromStart ? "start()" : "obtainBuffer()"); cblk->flags |= CBLK_RESTORING_ON; // signal old cblk condition so that other threads waiting for available buffers stop // waiting now cblk->cv.broadcast(); Loading Loading @@ -1198,10 +1188,8 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) } // signal old cblk condition for other threads waiting for restore completion cblk->lock.lock(); cblk->flags |= CBLK_RESTORED_MSK; android_atomic_or(CBLK_RESTORED_ON, &cblk->flags); cblk->cv.broadcast(); cblk->lock.unlock(); } else { if (!(cblk->flags & CBLK_RESTORED_MSK)) { LOGW("dead IAudioTrack, waiting for a new one"); Loading Loading @@ -1275,11 +1263,12 @@ void AudioTrack::AudioTrackThread::onFirstRef() // ========================================================================= audio_track_cblk_t::audio_track_cblk_t() : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0), loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flags(0), sendLevel(0) sendLevel(0), flags(0) { } Loading Loading @@ -1307,10 +1296,7 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) // Clear flow control error condition as new data has been written/read to/from buffer. if (flags & CBLK_UNDERRUN_MSK) { AutoMutex _l(lock); if (flags & CBLK_UNDERRUN_MSK) { flags &= ~CBLK_UNDERRUN_MSK; } android_atomic_and(~CBLK_UNDERRUN_MSK, &flags); } return u; Loading @@ -1318,18 +1304,8 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) bool audio_track_cblk_t::stepServer(uint32_t frameCount) { // the code below simulates lock-with-timeout // we MUST do this to protect the AudioFlinger server // as this lock is shared with the client. status_t err; err = lock.tryLock(); if (err == -EBUSY) { // just wait a bit usleep(1000); err = lock.tryLock(); } if (err != NO_ERROR) { // probably, the client just died. if (!tryLock()) { LOGW("stepServer() could not lock cblk"); return false; } Loading Loading @@ -1406,18 +1382,42 @@ uint32_t audio_track_cblk_t::framesReady() if (u < loopEnd) { return u - s; } else { Mutex::Autolock _l(lock); // do not block on mutex shared with client on AudioFlinger side if (!tryLock()) { LOGW("framesReady() could not lock cblk"); return 0; } uint32_t frames = UINT_MAX; if (loopCount >= 0) { return (loopEnd - loopStart)*loopCount + u - s; } else { return UINT_MAX; frames = (loopEnd - loopStart)*loopCount + u - s; } lock.unlock(); return frames; } } else { return s - u; } } bool audio_track_cblk_t::tryLock() { // the code below simulates lock-with-timeout // we MUST do this to protect the AudioFlinger server // as this lock is shared with the client. status_t err; err = lock.tryLock(); if (err == -EBUSY) { // just wait a bit usleep(1000); err = lock.tryLock(); } if (err != NO_ERROR) { // probably, the client just died. return false; } return true; } // ------------------------------------------------------------------------- }; // namespace android Loading services/audioflinger/AudioFlinger.cpp +16 −24 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <binder/IPCThreadState.h> #include <utils/String16.h> #include <utils/threads.h> #include <utils/Atomic.h> #include <cutils/properties.h> Loading Loading @@ -1738,10 +1739,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this); tracksToRemove->add(track); // indicate to client process that the track was disabled because of underrun { AutoMutex _l(cblk->lock); cblk->flags |= CBLK_DISABLED_ON; } android_atomic_or(CBLK_DISABLED_ON, &cblk->flags); } else if (mixerStatus != MIXER_TRACKS_READY) { mixerStatus = MIXER_TRACKS_ENABLED; } Loading Loading @@ -1790,8 +1788,7 @@ void AudioFlinger::MixerThread::invalidateTracks(int streamType) for (size_t i = 0; i < size; i++) { sp<Track> t = mTracks[i]; if (t->type() == streamType) { AutoMutex _lcblk(t->mCblk->lock); t->mCblk->flags |= CBLK_INVALID_ON; android_atomic_or(CBLK_INVALID_ON, &t->mCblk->flags); t->mCblk->cv.signal(); } } Loading Loading @@ -2950,9 +2947,8 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { if (mCblk->framesReady() >= mCblk->frameCount || (mCblk->flags & CBLK_FORCEREADY_MSK)) { AutoMutex _l(mCblk->lock); mFillingUpStatus = FS_FILLED; mCblk->flags &= ~CBLK_FORCEREADY_MSK; android_atomic_and(~CBLK_FORCEREADY_MSK, &mCblk->flags); return true; } return false; Loading Loading @@ -3066,26 +3062,25 @@ void AudioFlinger::PlaybackThread::Track::flush() // STOPPED state mState = STOPPED; // NOTE: reset() will reset cblk->user and cblk->server with // the risk that at the same time, the AudioMixer is trying to read // data. In this case, getNextBuffer() would return a NULL pointer // as audio buffer => the AudioMixer code MUST always test that pointer // returned by getNextBuffer() is not NULL! // do not reset the track if it is still in the process of being stopped or paused. // this will be done by prepareTracks_l() when the track is stopped. PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); if (playbackThread->mActiveTracks.indexOf(this) < 0) { reset(); } } } void AudioFlinger::PlaybackThread::Track::reset() { AutoMutex _l(mCblk->lock); // Do not reset twice to avoid discarding data written just after a flush and before // the audioflinger thread detects the track is stopped. if (!mResetDone) { TrackBase::reset(); // Force underrun condition to avoid false underrun callback until first data is // written to buffer mCblk->flags |= CBLK_UNDERRUN_ON; mCblk->flags &= ~CBLK_FORCEREADY_MSK; android_atomic_and(~CBLK_FORCEREADY_MSK, &mCblk->flags); android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags); mFillingUpStatus = FS_FILLING; mResetDone = true; } Loading Loading @@ -3211,13 +3206,10 @@ void AudioFlinger::RecordThread::RecordTrack::stop() if (thread != 0) { RecordThread *recordThread = (RecordThread *)thread.get(); recordThread->stop(this); { AutoMutex _l(mCblk->lock); TrackBase::reset(); // Force overerrun condition to avoid false overrun callback until first data is // read from buffer mCblk->flags |= CBLK_UNDERRUN_ON; } android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags); } } Loading Loading
include/private/media/AudioTrackShared.h +4 −4 Original line number Diff line number Diff line Loading @@ -83,13 +83,12 @@ struct audio_track_cblk_t uint8_t frameSize; uint8_t channelCount; uint16_t flags; uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting audioflinger uint16_t waitTimeMs; // Cumulated wait time uint16_t waitTimeMs; // Cumulated wait time uint16_t sendLevel; uint16_t reserved; volatile int32_t flags; // Cache line boundary (32 bytes) audio_track_cblk_t(); uint32_t stepUser(uint32_t frameCount); Loading @@ -98,6 +97,7 @@ struct audio_track_cblk_t uint32_t framesAvailable(); uint32_t framesAvailable_l(); uint32_t framesReady(); bool tryLock(); }; Loading
media/libmedia/AudioRecord.cpp +7 −14 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/Timers.h> #include <utils/Atomic.h> #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) Loading Loading @@ -299,7 +300,7 @@ status_t AudioRecord::start() ret = mAudioRecord->start(); cblk->lock.lock(); if (ret == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); } } if (cblk->flags & CBLK_INVALID_MSK) { Loading Loading @@ -467,7 +468,7 @@ status_t AudioRecord::openRecord_l( mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); mCblk->flags &= ~CBLK_DIRECTION_MSK; android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags); mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; mCblk->waitTimeMs = 0; return NO_ERROR; Loading Loading @@ -522,7 +523,7 @@ status_t AudioRecord::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = mAudioRecord->start(); cblk->lock.lock(); if (result == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); create_new_record: result = AudioRecord::restoreRecord_l(cblk); } Loading Loading @@ -722,12 +723,8 @@ bool AudioRecord::processAudioBuffer(const sp<ClientRecordThread>& thread) // Manage overrun callback if (mActive && (cblk->framesAvailable() == 0)) { LOGV("Overrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); AutoMutex _l(cblk->lock); if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { cblk->flags |= CBLK_UNDERRUN_ON; cblk->lock.unlock(); if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { mCbf(EVENT_OVERRUN, mUserData, 0); cblk->lock.lock(); } } Loading @@ -746,10 +743,8 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) { status_t result; if (!(cblk->flags & CBLK_RESTORING_MSK)) { if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) { LOGW("dead IAudioRecord, creating a new one"); cblk->flags |= CBLK_RESTORING_ON; // signal old cblk condition so that other threads waiting for available buffers stop // waiting now cblk->cv.broadcast(); Loading @@ -768,10 +763,8 @@ status_t AudioRecord::restoreRecord_l(audio_track_cblk_t*& cblk) } // signal old cblk condition for other threads waiting for restore completion cblk->lock.lock(); cblk->flags |= CBLK_RESTORED_MSK; android_atomic_or(CBLK_RESTORED_ON, &cblk->flags); cblk->cv.broadcast(); cblk->lock.unlock(); } else { if (!(cblk->flags & CBLK_RESTORED_MSK)) { LOGW("dead IAudioRecord, waiting for a new one to be created"); Loading
media/libmedia/AudioTrack.cpp +46 −46 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ #include <binder/Parcel.h> #include <binder/IPCThreadState.h> #include <utils/Timers.h> #include <utils/Atomic.h> #define LIKELY( exp ) (__builtin_expect( (exp) != 0, true )) #define UNLIKELY( exp ) (__builtin_expect( (exp) != 0, false )) Loading Loading @@ -332,7 +333,7 @@ void AudioTrack::start() cblk->lock.lock(); cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; cblk->flags &= ~CBLK_DISABLED_ON; android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); if (t != 0) { t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); } else { Loading @@ -345,7 +346,7 @@ void AudioTrack::start() status = mAudioTrack->start(); cblk->lock.lock(); if (status == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); } } if (cblk->flags & CBLK_INVALID_MSK) { Loading Loading @@ -636,7 +637,7 @@ status_t AudioTrack::setPosition(uint32_t position) if (position > mCblk->user) return BAD_VALUE; mCblk->server = position; mCblk->flags |= CBLK_FORCEREADY_ON; android_atomic_or(CBLK_FORCEREADY_ON, &mCblk->flags); return NO_ERROR; } Loading Loading @@ -793,7 +794,7 @@ status_t AudioTrack::createTrack_l( mCblkMemory.clear(); mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->flags |= CBLK_DIRECTION_OUT; android_atomic_or(CBLK_DIRECTION_OUT, &mCblk->flags); if (sharedBuffer == 0) { mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); } else { Loading Loading @@ -873,7 +874,7 @@ status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) result = mAudioTrack->start(); cblk->lock.lock(); if (result == DEAD_OBJECT) { cblk->flags |= CBLK_INVALID_MSK; android_atomic_or(CBLK_INVALID_ON, &cblk->flags); create_new_track: result = restoreTrack_l(cblk, false); } Loading @@ -900,14 +901,9 @@ create_new_track: // restart track if it was disabled by audioflinger due to previous underrun if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { AutoMutex _l(cblk->lock); if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { cblk->flags &= ~CBLK_DISABLED_ON; cblk->lock.unlock(); android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); LOGW("obtainBuffer() track %p disabled, restarting", this); mAudioTrack->start(); cblk->lock.lock(); } } cblk->waitTimeMs = 0; Loading Loading @@ -1026,17 +1022,13 @@ bool AudioTrack::processAudioBuffer(const sp<AudioTrackThread>& thread) mLock.unlock(); // Manage underrun callback if (mActive && (cblk->framesReady() == 0)) { if (mActive && (cblk->framesAvailable() == cblk->frameCount)) { LOGV("Underrun user: %x, server: %x, flags %04x", cblk->user, cblk->server, cblk->flags); AutoMutex _l(cblk->lock); if ((cblk->flags & CBLK_UNDERRUN_MSK) == CBLK_UNDERRUN_OFF) { cblk->flags |= CBLK_UNDERRUN_ON; cblk->lock.unlock(); if (!(android_atomic_or(CBLK_UNDERRUN_ON, &cblk->flags) & CBLK_UNDERRUN_MSK)) { mCbf(EVENT_UNDERRUN, mUserData, 0); if (cblk->server == cblk->frameCount) { mCbf(EVENT_BUFFER_END, mUserData, 0); } cblk->lock.lock(); if (mSharedBuffer != 0) return false; } } Loading Loading @@ -1150,12 +1142,10 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) { status_t result; if (!(cblk->flags & CBLK_RESTORING_MSK)) { if (!(android_atomic_or(CBLK_RESTORING_ON, &cblk->flags) & CBLK_RESTORING_MSK)) { LOGW("dead IAudioTrack, creating a new one from %s", fromStart ? "start()" : "obtainBuffer()"); cblk->flags |= CBLK_RESTORING_ON; // signal old cblk condition so that other threads waiting for available buffers stop // waiting now cblk->cv.broadcast(); Loading Loading @@ -1198,10 +1188,8 @@ status_t AudioTrack::restoreTrack_l(audio_track_cblk_t*& cblk, bool fromStart) } // signal old cblk condition for other threads waiting for restore completion cblk->lock.lock(); cblk->flags |= CBLK_RESTORED_MSK; android_atomic_or(CBLK_RESTORED_ON, &cblk->flags); cblk->cv.broadcast(); cblk->lock.unlock(); } else { if (!(cblk->flags & CBLK_RESTORED_MSK)) { LOGW("dead IAudioTrack, waiting for a new one"); Loading Loading @@ -1275,11 +1263,12 @@ void AudioTrack::AudioTrackThread::onFirstRef() // ========================================================================= audio_track_cblk_t::audio_track_cblk_t() : lock(Mutex::SHARED), cv(Condition::SHARED), user(0), server(0), userBase(0), serverBase(0), buffers(0), frameCount(0), loopStart(UINT_MAX), loopEnd(UINT_MAX), loopCount(0), volumeLR(0), flags(0), sendLevel(0) sendLevel(0), flags(0) { } Loading Loading @@ -1307,10 +1296,7 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) // Clear flow control error condition as new data has been written/read to/from buffer. if (flags & CBLK_UNDERRUN_MSK) { AutoMutex _l(lock); if (flags & CBLK_UNDERRUN_MSK) { flags &= ~CBLK_UNDERRUN_MSK; } android_atomic_and(~CBLK_UNDERRUN_MSK, &flags); } return u; Loading @@ -1318,18 +1304,8 @@ uint32_t audio_track_cblk_t::stepUser(uint32_t frameCount) bool audio_track_cblk_t::stepServer(uint32_t frameCount) { // the code below simulates lock-with-timeout // we MUST do this to protect the AudioFlinger server // as this lock is shared with the client. status_t err; err = lock.tryLock(); if (err == -EBUSY) { // just wait a bit usleep(1000); err = lock.tryLock(); } if (err != NO_ERROR) { // probably, the client just died. if (!tryLock()) { LOGW("stepServer() could not lock cblk"); return false; } Loading Loading @@ -1406,18 +1382,42 @@ uint32_t audio_track_cblk_t::framesReady() if (u < loopEnd) { return u - s; } else { Mutex::Autolock _l(lock); // do not block on mutex shared with client on AudioFlinger side if (!tryLock()) { LOGW("framesReady() could not lock cblk"); return 0; } uint32_t frames = UINT_MAX; if (loopCount >= 0) { return (loopEnd - loopStart)*loopCount + u - s; } else { return UINT_MAX; frames = (loopEnd - loopStart)*loopCount + u - s; } lock.unlock(); return frames; } } else { return s - u; } } bool audio_track_cblk_t::tryLock() { // the code below simulates lock-with-timeout // we MUST do this to protect the AudioFlinger server // as this lock is shared with the client. status_t err; err = lock.tryLock(); if (err == -EBUSY) { // just wait a bit usleep(1000); err = lock.tryLock(); } if (err != NO_ERROR) { // probably, the client just died. return false; } return true; } // ------------------------------------------------------------------------- }; // namespace android Loading
services/audioflinger/AudioFlinger.cpp +16 −24 Original line number Diff line number Diff line Loading @@ -31,6 +31,7 @@ #include <binder/IPCThreadState.h> #include <utils/String16.h> #include <utils/threads.h> #include <utils/Atomic.h> #include <cutils/properties.h> Loading Loading @@ -1738,10 +1739,7 @@ uint32_t AudioFlinger::MixerThread::prepareTracks_l(const SortedVector< wp<Track LOGV("BUFFER TIMEOUT: remove(%d) from active list on thread %p", track->name(), this); tracksToRemove->add(track); // indicate to client process that the track was disabled because of underrun { AutoMutex _l(cblk->lock); cblk->flags |= CBLK_DISABLED_ON; } android_atomic_or(CBLK_DISABLED_ON, &cblk->flags); } else if (mixerStatus != MIXER_TRACKS_READY) { mixerStatus = MIXER_TRACKS_ENABLED; } Loading Loading @@ -1790,8 +1788,7 @@ void AudioFlinger::MixerThread::invalidateTracks(int streamType) for (size_t i = 0; i < size; i++) { sp<Track> t = mTracks[i]; if (t->type() == streamType) { AutoMutex _lcblk(t->mCblk->lock); t->mCblk->flags |= CBLK_INVALID_ON; android_atomic_or(CBLK_INVALID_ON, &t->mCblk->flags); t->mCblk->cv.signal(); } } Loading Loading @@ -2950,9 +2947,8 @@ bool AudioFlinger::PlaybackThread::Track::isReady() const { if (mCblk->framesReady() >= mCblk->frameCount || (mCblk->flags & CBLK_FORCEREADY_MSK)) { AutoMutex _l(mCblk->lock); mFillingUpStatus = FS_FILLED; mCblk->flags &= ~CBLK_FORCEREADY_MSK; android_atomic_and(~CBLK_FORCEREADY_MSK, &mCblk->flags); return true; } return false; Loading Loading @@ -3066,26 +3062,25 @@ void AudioFlinger::PlaybackThread::Track::flush() // STOPPED state mState = STOPPED; // NOTE: reset() will reset cblk->user and cblk->server with // the risk that at the same time, the AudioMixer is trying to read // data. In this case, getNextBuffer() would return a NULL pointer // as audio buffer => the AudioMixer code MUST always test that pointer // returned by getNextBuffer() is not NULL! // do not reset the track if it is still in the process of being stopped or paused. // this will be done by prepareTracks_l() when the track is stopped. PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); if (playbackThread->mActiveTracks.indexOf(this) < 0) { reset(); } } } void AudioFlinger::PlaybackThread::Track::reset() { AutoMutex _l(mCblk->lock); // Do not reset twice to avoid discarding data written just after a flush and before // the audioflinger thread detects the track is stopped. if (!mResetDone) { TrackBase::reset(); // Force underrun condition to avoid false underrun callback until first data is // written to buffer mCblk->flags |= CBLK_UNDERRUN_ON; mCblk->flags &= ~CBLK_FORCEREADY_MSK; android_atomic_and(~CBLK_FORCEREADY_MSK, &mCblk->flags); android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags); mFillingUpStatus = FS_FILLING; mResetDone = true; } Loading Loading @@ -3211,13 +3206,10 @@ void AudioFlinger::RecordThread::RecordTrack::stop() if (thread != 0) { RecordThread *recordThread = (RecordThread *)thread.get(); recordThread->stop(this); { AutoMutex _l(mCblk->lock); TrackBase::reset(); // Force overerrun condition to avoid false overrun callback until first data is // read from buffer mCblk->flags |= CBLK_UNDERRUN_ON; } android_atomic_or(CBLK_UNDERRUN_ON, &mCblk->flags); } } Loading