status_t FMRadioSource::openRecord(int frameCount, audio_io_handle_t input) { status_t status; const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); if (audioFlinger == 0) { return NO_INIT; } sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input, kSampleRate, kAudioFormat, kChannelMask, frameCount, IAudioFlinger::TRACK_DEFAULT, &mSessionId, &status); if (record == 0) { ALOGE("AudioFlinger could not create record track, status: %d", status); return status; } sp<IMemory> cblk = record->getCblk(); if (cblk == 0) { ALOGE("Could not get control block"); return NO_INIT; } mAudioRecord = record; mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags); return NO_ERROR; }
status_t AudioRecord::stop() { sp<ClientRecordThread> t = mClientRecordThread; LOGV("stop"); if (t != 0) { t->mLock.lock(); } if (android_atomic_and(~1, &mActive) == 1) { mAudioRecord->stop(); if (t != 0) { t->requestExit(); } else { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); } } if (t != 0) { t->mLock.unlock(); } return NO_ERROR; }
void AudioTrack::stop() { sp<AudioTrackThread> t = mAudioTrackThread; LOGV("stop %p", this); if (t != 0) { t->mLock.lock(); } if (android_atomic_and(~1, &mActive) == 1) { mCblk->cv.signal(); mAudioTrack->stop(); // Cancel loops (If we are in the middle of a loop, playback // would not stop until loopCount reaches 0). setLoop(0, 0, 0); // the playback head position will reset to 0, so if a marker is set, we need // to activate it again mMarkerReached = false; // Force flush if a shared buffer is used otherwise audioflinger // will not stop before end of buffer is reached. if (mSharedBuffer != 0) { flush(); } if (t != 0) { t->requestExit(); } else { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); } } if (t != 0) { t->mLock.unlock(); } }
void LayerBase::unlockPageFlip( const Transform& planeTransform, Region& outDirtyRegion) { if ((android_atomic_and(~1, &mInvalidate)&1) == 1) { outDirtyRegion.orSelf(visibleRegionScreen); } }
status_t AudioRecord::stop() { sp<ClientRecordThread> t = mClientRecordThread; LOGV("stop"); if (t != 0) { t->mLock.lock(); } if (android_atomic_and(~1, &mActive) == 1) { mCblk->cv.signal(); mAudioRecord->stop(); // the record head position will reset to 0, so if a marker is set, we need // to activate it again mMarkerReached = false; if (t != 0) { t->requestExit(); } else { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); } } if (t != 0) { t->mLock.unlock(); } return NO_ERROR; }
void AudioTrack::pause() { LOGV("pause"); if (android_atomic_and(~1, &mActive) == 1) { mAudioTrack->pause(); } }
void MessageQueue::Handler::handleMessage(const Message& message) { switch (message.what) { case INVALIDATE: android_atomic_and(~eventMaskInvalidate, &mEventMask); mQueue.mFlinger->onMessageReceived(message.what); break; case REFRESH: android_atomic_and(~eventMaskRefresh, &mEventMask); mQueue.mFlinger->onMessageReceived(message.what); mQueue.mEvents->requestNextVsync(); break; case TRANSACTION: android_atomic_and(~eventMaskTransaction, &mEventMask); mQueue.mFlinger->onMessageReceived(message.what); break; } }
void CameraClient::disableMsgType(int32_t msgType) { android_atomic_and(~msgType, &mMsgEnabled); //!++ #if 1 if (mHardware == 0) { ALOGW("[disableMsgType] mHardware == 0 (CallingPid %d) (tid %d)", getCallingPid(), ::gettid()); return; } #endif //!-- mHardware->disableMsgType(msgType); }
status_t AudioRecord::start() { status_t ret = NO_ERROR; sp<ClientRecordThread> t = mClientRecordThread; LOGV("start"); if (t != 0) { if (t->exitPending()) { if (t->requestExitAndWait() == WOULD_BLOCK) { LOGE("AudioRecord::start called from thread"); return WOULD_BLOCK; } } t->mLock.lock(); } if (android_atomic_or(1, &mActive) == 0) { ret = mAudioRecord->start(); if (ret == DEAD_OBJECT) { LOGV("start() dead IAudioRecord: creating a new one"); ret = openRecord(mCblk->sampleRate, mFormat, mChannelCount, mFrameCount, mFlags, getInput()); if (ret == NO_ERROR) { ret = mAudioRecord->start(); } } if (ret == NO_ERROR) { mNewPosition = mCblk->user + mUpdatePeriod; mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; mCblk->waitTimeMs = 0; if (t != 0) { t->run("ClientRecordThread", THREAD_PRIORITY_AUDIO_CLIENT); } else { setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); } } else { LOGV("start() failed"); android_atomic_and(~1, &mActive); } } if (t != 0) { t->mLock.unlock(); } return ret; }
void AudioTrack::pause() { LOGD("pause"); if ( mAudioSession != -1 ) { if ( NO_ERROR != AudioSystem::pauseSession(mAudioSession, (AudioSystem::stream_type)mStreamType) ) { LOGE("PauseSession failed"); } return; } if (android_atomic_and(~1, &mActive) == 1) { mAudioTrack->pause(); } }
// must be called with mLock held status_t AudioRecord::openRecord_l( uint32_t sampleRate, uint32_t format, uint32_t channelMask, int frameCount, uint32_t flags, audio_io_handle_t input) { status_t status; const sp<IAudioFlinger>& audioFlinger = AudioSystem::get_audio_flinger(); if (audioFlinger == 0) { return NO_INIT; } sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input, sampleRate, format, channelMask, frameCount, ((uint16_t)flags) << 16, &mSessionId, &status); if (record == 0) { LOGE("AudioFlinger could not create record track, status: %d", status); return status; } sp<IMemory> cblk = record->getCblk(); if (cblk == 0) { LOGE("Could not get control block"); return NO_INIT; } mAudioRecord.clear(); mAudioRecord = record; mCblkMemory.clear(); mCblkMemory = cblk; mCblk = static_cast<audio_track_cblk_t*>(cblk->pointer()); mCblk->buffers = (char*)mCblk + sizeof(audio_track_cblk_t); android_atomic_and(~CBLK_DIRECTION_MSK, &mCblk->flags); mCblk->bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; mCblk->waitTimeMs = 0; return NO_ERROR; }
int main(int argc, const char *argv[]) { pthread_t id[TEST_THREADS]; int i = 0; int32_t ret; for(i=0; i<TEST_THREADS; ++i){ pthread_create(&id[i],NULL,test_func,NULL); } for(i=0; i<TEST_THREADS; ++i){ pthread_join(id[i],NULL); } printf("%d\n",count); printf("flags = 0x%x\n", flags); ret = android_atomic_or(0x01, &flags); printf("android_atomic_or 0x01 flags = 0x%x, ret = 0x%x\n", flags, ret); ret = android_atomic_and(~0x01, &flags); printf("android_atomic_and ~0x01 flags = 0x%x, ret = 0x%x\n", flags, ret); return 0; }
uint32_t audio_track_cblk_t::stepUser(size_t stepCount, size_t frameCount, bool isOut) { ALOGV("stepuser %08x %08x %d", user, server, stepCount); uint32_t u = user; u += stepCount; // Ensure that user is never ahead of server for AudioRecord if (isOut) { // If stepServer() has been called once, switch to normal obtainBuffer() timeout period if (bufferTimeoutMs == MAX_STARTUP_TIMEOUT_MS-1) { bufferTimeoutMs = MAX_RUN_TIMEOUT_MS; } } else if (u > server) { ALOGW("stepUser occurred after track reset"); u = server; } if (u >= frameCount) { // common case, user didn't just wrap if (u - frameCount >= userBase ) { userBase += frameCount; } } else if (u >= userBase + frameCount) { // user just wrapped userBase += frameCount; } user = u; // Clear flow control error condition as new data has been written/read to/from buffer. if (flags & CBLK_UNDERRUN) { android_atomic_and(~CBLK_UNDERRUN, &flags); } return u; }
int32_t OSAtomicAnd32Orig(uint32_t value,volatile uint32_t* target) { return android_atomic_and(value,target); }
status_t AudioTrack::obtainBuffer(Buffer* audioBuffer, int32_t waitCount) { AutoMutex lock(mLock); int active; status_t result = NO_ERROR; audio_track_cblk_t* cblk = mCblk; uint32_t framesReq = audioBuffer->frameCount; uint32_t waitTimeMs = (waitCount < 0) ? cblk->bufferTimeoutMs : WAIT_PERIOD_MS; audioBuffer->frameCount = 0; audioBuffer->size = 0; uint32_t framesAvail = cblk->framesAvailable(); cblk->lock.lock(); if (cblk->flags & CBLK_INVALID_MSK) { goto create_new_track; } cblk->lock.unlock(); if (framesAvail == 0) { cblk->lock.lock(); goto start_loop_here; while (framesAvail == 0) { active = mActive; if (UNLIKELY(!active)) { LOGV("Not active and NO_MORE_BUFFERS"); cblk->lock.unlock(); return NO_MORE_BUFFERS; } if (UNLIKELY(!waitCount)) { cblk->lock.unlock(); return WOULD_BLOCK; } if (!(cblk->flags & CBLK_INVALID_MSK)) { mLock.unlock(); result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); cblk->lock.unlock(); mLock.lock(); if (mActive == 0) { return status_t(STOPPED); } cblk->lock.lock(); } if (cblk->flags & CBLK_INVALID_MSK) { goto create_new_track; } if (__builtin_expect(result!=NO_ERROR, false)) { cblk->waitTimeMs += waitTimeMs; if (cblk->waitTimeMs >= cblk->bufferTimeoutMs) { // timing out when a loop has been set and we have already written upto loop end // is a normal condition: no need to wake AudioFlinger up. if (cblk->user < cblk->loopEnd) { LOGW( "obtainBuffer timed out (is the CPU pegged?) %p " "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(); cblk->lock.lock(); if (result == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); create_new_track: result = restoreTrack_l(cblk, false); } if (result != NO_ERROR) { LOGW("obtainBuffer create Track error %d", result); cblk->lock.unlock(); return result; } } cblk->waitTimeMs = 0; } if (--waitCount == 0) { cblk->lock.unlock(); return TIMED_OUT; } } // read the server count again start_loop_here: framesAvail = cblk->framesAvailable_l(); } cblk->lock.unlock(); } // restart track if it was disabled by audioflinger due to previous underrun if (mActive && (cblk->flags & CBLK_DISABLED_MSK)) { android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); LOGW("obtainBuffer() track %p disabled, restarting", this); mAudioTrack->start(); } cblk->waitTimeMs = 0; if (framesReq > framesAvail) { framesReq = framesAvail; } uint32_t u = cblk->user; uint32_t bufferEnd = cblk->userBase + cblk->frameCount; if (u + framesReq > bufferEnd && u < bufferEnd) { framesReq = bufferEnd - u; } audioBuffer->flags = mMuted ? Buffer::MUTE : 0; audioBuffer->channelCount = mChannelCount; audioBuffer->frameCount = framesReq; audioBuffer->size = framesReq * cblk->frameSize; if (audio_is_linear_pcm(mFormat)) { audioBuffer->format = AUDIO_FORMAT_PCM_16_BIT; } else { audioBuffer->format = mFormat; } audioBuffer->raw = (int8_t *)cblk->buffer(u); active = mActive; return active ? status_t(NO_ERROR) : status_t(STOPPED); }
bool SharedBufferClient::needNewBuffer(int buf) const { SharedBufferStack& stack( *mSharedStack ); const uint32_t mask = 1<<(31-buf); return (android_atomic_and(~mask, &stack.reallocMask) & mask) != 0; }
status_t ClientProxy::obtainBuffer(Buffer* buffer, const struct timespec *requested, struct timespec *elapsed) { LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0); struct timespec total; // total elapsed time spent waiting total.tv_sec = 0; total.tv_nsec = 0; bool measure = elapsed != NULL; // whether to measure total elapsed time spent waiting status_t status; enum { TIMEOUT_ZERO, // requested == NULL || *requested == 0 TIMEOUT_INFINITE, // *requested == infinity TIMEOUT_FINITE, // 0 < *requested < infinity TIMEOUT_CONTINUE, // additional chances after TIMEOUT_FINITE } timeout; if (requested == NULL) { timeout = TIMEOUT_ZERO; } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) { timeout = TIMEOUT_ZERO; } else if (requested->tv_sec == INT_MAX) { timeout = TIMEOUT_INFINITE; } else { timeout = TIMEOUT_FINITE; if (requested->tv_sec > 0 || requested->tv_nsec >= MEASURE_NS) { measure = true; } } struct timespec before; bool beforeIsValid = false; audio_track_cblk_t* cblk = mCblk; bool ignoreInitialPendingInterrupt = true; // check for shared memory corruption if (mIsShutdown) { status = NO_INIT; goto end; } for (;;) { int32_t flags = android_atomic_and(~CBLK_INTERRUPT, &cblk->mFlags); // check for track invalidation by server, or server death detection if (flags & CBLK_INVALID) { ALOGV("Track invalidated"); status = DEAD_OBJECT; goto end; } // check for obtainBuffer interrupted by client if (!ignoreInitialPendingInterrupt && (flags & CBLK_INTERRUPT)) { ALOGV("obtainBuffer() interrupted by client"); status = -EINTR; goto end; } ignoreInitialPendingInterrupt = false; // compute number of frames available to write (AudioTrack) or read (AudioRecord) int32_t front; int32_t rear; if (mIsOut) { // The barrier following the read of mFront is probably redundant. // We're about to perform a conditional branch based on 'filled', // which will force the processor to observe the read of mFront // prior to allowing data writes starting at mRaw. // However, the processor may support speculative execution, // and be unable to undo speculative writes into shared memory. // The barrier will prevent such speculative execution. front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront); rear = cblk->u.mStreaming.mRear; } else { // On the other hand, this barrier is required. rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear); front = cblk->u.mStreaming.mFront; } ssize_t filled = rear - front; // pipe should not be overfull if (!(0 <= filled && (size_t) filled <= mFrameCount)) { if (mIsOut) { ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); " "shutting down", filled, mFrameCount); mIsShutdown = true; status = NO_INIT; goto end; } // for input, sync up on overrun filled = 0; cblk->u.mStreaming.mFront = rear; (void) android_atomic_or(CBLK_OVERRUN, &cblk->mFlags); } // don't allow filling pipe beyond the nominal size size_t avail = mIsOut ? mFrameCount - filled : filled; if (avail > 0) { // 'avail' may be non-contiguous, so return only the first contiguous chunk size_t part1; if (mIsOut) { rear &= mFrameCountP2 - 1; part1 = mFrameCountP2 - rear; } else { front &= mFrameCountP2 - 1; part1 = mFrameCountP2 - front; } if (part1 > avail) { part1 = avail; } if (part1 > buffer->mFrameCount) { part1 = buffer->mFrameCount; } buffer->mFrameCount = part1; buffer->mRaw = part1 > 0 ? &((char *) mBuffers)[(mIsOut ? rear : front) * mFrameSize] : NULL; buffer->mNonContig = avail - part1; mUnreleased = part1; status = NO_ERROR; break; } struct timespec remaining; const struct timespec *ts; switch (timeout) { case TIMEOUT_ZERO: status = WOULD_BLOCK; goto end; case TIMEOUT_INFINITE: ts = NULL; break; case TIMEOUT_FINITE: timeout = TIMEOUT_CONTINUE; if (MAX_SEC == 0) { ts = requested; break; } // fall through case TIMEOUT_CONTINUE: // FIXME we do not retry if requested < 10ms? needs documentation on this state machine if (!measure || requested->tv_sec < total.tv_sec || (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) { status = TIMED_OUT; goto end; } remaining.tv_sec = requested->tv_sec - total.tv_sec; if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) { remaining.tv_nsec += 1000000000; remaining.tv_sec++; } if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) { remaining.tv_sec = MAX_SEC; remaining.tv_nsec = 0; } ts = &remaining; break; default: LOG_ALWAYS_FATAL("obtainBuffer() timeout=%d", timeout); ts = NULL; break; } int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex); if (!(old & CBLK_FUTEX_WAKE)) { if (measure && !beforeIsValid) { clock_gettime(CLOCK_MONOTONIC, &before); beforeIsValid = true; } errno = 0; (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts); // update total elapsed time spent waiting if (measure) { struct timespec after; clock_gettime(CLOCK_MONOTONIC, &after); total.tv_sec += after.tv_sec - before.tv_sec; long deltaNs = after.tv_nsec - before.tv_nsec; if (deltaNs < 0) { deltaNs += 1000000000; total.tv_sec--; } if ((total.tv_nsec += deltaNs) >= 1000000000) { total.tv_nsec -= 1000000000; total.tv_sec++; } before = after; beforeIsValid = true; } switch (errno) { case 0: // normal wakeup by server, or by binderDied() case EWOULDBLOCK: // benign race condition with server case EINTR: // wait was interrupted by signal or other spurious wakeup case ETIMEDOUT: // time-out expired // FIXME these error/non-0 status are being dropped break; default: status = errno; ALOGE("%s unexpected error %s", __func__, strerror(status)); goto end; } } } end: if (status != NO_ERROR) { buffer->mFrameCount = 0; buffer->mRaw = NULL; buffer->mNonContig = 0; mUnreleased = 0; } if (elapsed != NULL) { *elapsed = total; } if (requested == NULL) { requested = &kNonBlocking; } if (measure) { ALOGV("requested %ld.%03ld elapsed %ld.%03ld", requested->tv_sec, requested->tv_nsec / 1000000, total.tv_sec, total.tv_nsec / 1000000); } return status; }
void AudioTrack::start() { sp<AudioTrackThread> t = mAudioTrackThread; status_t status = NO_ERROR; LOGV("start %p", this); if (t != 0) { if (t->exitPending()) { if (t->requestExitAndWait() == WOULD_BLOCK) { LOGE("AudioTrack::start called from thread"); return; } } t->mLock.lock(); } AutoMutex lock(mLock); // acquire a strong reference on the IMemory and IAudioTrack so that they cannot be destroyed // while we are accessing the cblk sp <IAudioTrack> audioTrack = mAudioTrack; sp <IMemory> iMem = mCblkMemory; audio_track_cblk_t* cblk = mCblk; if (mActive == 0) { mFlushed = false; mActive = 1; mNewPosition = cblk->server + mUpdatePeriod; cblk->lock.lock(); cblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; cblk->waitTimeMs = 0; android_atomic_and(~CBLK_DISABLED_ON, &cblk->flags); if (t != 0) { t->run("AudioTrackThread", ANDROID_PRIORITY_AUDIO); } else { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_AUDIO); } LOGV("start %p before lock cblk %p", this, mCblk); if (!(cblk->flags & CBLK_INVALID_MSK)) { cblk->lock.unlock(); status = mAudioTrack->start(); cblk->lock.lock(); if (status == DEAD_OBJECT) { android_atomic_or(CBLK_INVALID_ON, &cblk->flags); } } if (cblk->flags & CBLK_INVALID_MSK) { status = restoreTrack_l(cblk, true); } cblk->lock.unlock(); if (status != NO_ERROR) { LOGV("start() failed"); mActive = 0; if (t != 0) { t->requestExit(); } else { setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL); } } } if (t != 0) { t->mLock.unlock(); } }
status_t AudioTrackClientProxy::waitStreamEndDone(const struct timespec *requested) { struct timespec total; // total elapsed time spent waiting total.tv_sec = 0; total.tv_nsec = 0; audio_track_cblk_t* cblk = mCblk; status_t status; enum { TIMEOUT_ZERO, // requested == NULL || *requested == 0 TIMEOUT_INFINITE, // *requested == infinity TIMEOUT_FINITE, // 0 < *requested < infinity TIMEOUT_CONTINUE, // additional chances after TIMEOUT_FINITE } timeout; if (requested == NULL) { timeout = TIMEOUT_ZERO; } else if (requested->tv_sec == 0 && requested->tv_nsec == 0) { timeout = TIMEOUT_ZERO; } else if (requested->tv_sec == INT_MAX) { timeout = TIMEOUT_INFINITE; } else { timeout = TIMEOUT_FINITE; } for (;;) { int32_t flags = android_atomic_and(~(CBLK_INTERRUPT|CBLK_STREAM_END_DONE), &cblk->mFlags); // check for track invalidation by server, or server death detection if (flags & CBLK_INVALID) { ALOGV("Track invalidated"); status = DEAD_OBJECT; goto end; } if (flags & CBLK_STREAM_END_DONE) { ALOGV("stream end received"); status = NO_ERROR; goto end; } // check for obtainBuffer interrupted by client if (flags & CBLK_INTERRUPT) { ALOGV("waitStreamEndDone() interrupted by client"); status = -EINTR; goto end; } struct timespec remaining; const struct timespec *ts; switch (timeout) { case TIMEOUT_ZERO: status = WOULD_BLOCK; goto end; case TIMEOUT_INFINITE: ts = NULL; break; case TIMEOUT_FINITE: timeout = TIMEOUT_CONTINUE; if (MAX_SEC == 0) { ts = requested; break; } // fall through case TIMEOUT_CONTINUE: // FIXME we do not retry if requested < 10ms? needs documentation on this state machine if (requested->tv_sec < total.tv_sec || (requested->tv_sec == total.tv_sec && requested->tv_nsec <= total.tv_nsec)) { status = TIMED_OUT; goto end; } remaining.tv_sec = requested->tv_sec - total.tv_sec; if ((remaining.tv_nsec = requested->tv_nsec - total.tv_nsec) < 0) { remaining.tv_nsec += 1000000000; remaining.tv_sec++; } if (0 < MAX_SEC && MAX_SEC < remaining.tv_sec) { remaining.tv_sec = MAX_SEC; remaining.tv_nsec = 0; } ts = &remaining; break; default: LOG_ALWAYS_FATAL("waitStreamEndDone() timeout=%d", timeout); ts = NULL; break; } int32_t old = android_atomic_and(~CBLK_FUTEX_WAKE, &cblk->mFutex); if (!(old & CBLK_FUTEX_WAKE)) { errno = 0; (void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAIT_PRIVATE : FUTEX_WAIT, old & ~CBLK_FUTEX_WAKE, ts); switch (errno) { case 0: // normal wakeup by server, or by binderDied() case EWOULDBLOCK: // benign race condition with server case EINTR: // wait was interrupted by signal or other spurious wakeup case ETIMEDOUT: // time-out expired break; default: status = errno; ALOGE("%s unexpected error %s", __func__, strerror(status)); goto end; } } } end: if (requested == NULL) { requested = &kNonBlocking; } return status; }
bool AudioTrackClientProxy::clearStreamEndDone() { return (android_atomic_and(~CBLK_STREAM_END_DONE, &mCblk->mFlags) & CBLK_STREAM_END_DONE) != 0; }
nsecs_t AudioRecord::processAudioBuffer() { mLock.lock(); if (mAwaitBoost) { mAwaitBoost = false; mLock.unlock(); static const int32_t kMaxTries = 5; int32_t tryCounter = kMaxTries; uint32_t pollUs = 10000; do { int policy = sched_getscheduler(0); if (policy == SCHED_FIFO || policy == SCHED_RR) { break; } usleep(pollUs); pollUs <<= 1; } while (tryCounter-- > 0); if (tryCounter < 0) { ALOGE("did not receive expected priority boost on time"); } // Run again immediately return 0; } // Can only reference mCblk while locked int32_t flags = android_atomic_and(~CBLK_OVERRUN, &mCblk->mFlags); // Check for track invalidation if (flags & CBLK_INVALID) { (void) restoreRecord_l("processAudioBuffer"); mLock.unlock(); // Run again immediately, but with a new IAudioRecord return 0; } bool active = mActive; // Manage overrun callback, must be done under lock to avoid race with releaseBuffer() bool newOverrun = false; if (flags & CBLK_OVERRUN) { if (!mInOverrun) { mInOverrun = true; newOverrun = true; } } // Get current position of server size_t position = mProxy->getPosition(); // Manage marker callback bool markerReached = false; size_t markerPosition = mMarkerPosition; // FIXME fails for wraparound, need 64 bits #ifdef MTK_AOSP_ENHANCEMENT if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition) && mActive) { #else if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) { #endif mMarkerReached = markerReached = true; } // Determine the number of new position callback(s) that will be needed, while locked size_t newPosCount = 0; size_t newPosition = mNewPosition; uint32_t updatePeriod = mUpdatePeriod; // FIXME fails for wraparound, need 64 bits if (updatePeriod > 0 && position >= newPosition) { newPosCount = ((position - newPosition) / updatePeriod) + 1; mNewPosition += updatePeriod * newPosCount; } // Cache other fields that will be needed soon uint32_t notificationFrames = mNotificationFramesAct; if (mRefreshRemaining) { mRefreshRemaining = false; mRemainingFrames = notificationFrames; mRetryOnPartialBuffer = false; } size_t misalignment = mProxy->getMisalignment(); uint32_t sequence = mSequence; // These fields don't need to be cached, because they are assigned only by set(): // mTransfer, mCbf, mUserData, mSampleRate, mFrameSize mLock.unlock(); // perform callbacks while unlocked if (newOverrun) { mCbf(EVENT_OVERRUN, mUserData, NULL); } if (markerReached) { mCbf(EVENT_MARKER, mUserData, &markerPosition); } while (newPosCount > 0) { size_t temp = newPosition; mCbf(EVENT_NEW_POS, mUserData, &temp); newPosition += updatePeriod; newPosCount--; } if (mObservedSequence != sequence) { mObservedSequence = sequence; mCbf(EVENT_NEW_IAUDIORECORD, mUserData, NULL); } // if inactive, then don't run me again until re-started if (!active) { return NS_INACTIVE; } // Compute the estimated time until the next timed event (position, markers) uint32_t minFrames = ~0; if (!markerReached && position < markerPosition) { minFrames = markerPosition - position; } if (updatePeriod > 0 && updatePeriod < minFrames) { minFrames = updatePeriod; } // If > 0, poll periodically to recover from a stuck server. A good value is 2. static const uint32_t kPoll = 0; if (kPoll > 0 && mTransfer == TRANSFER_CALLBACK && kPoll * notificationFrames < minFrames) { minFrames = kPoll * notificationFrames; } // Convert frame units to time units nsecs_t ns = NS_WHENEVER; if (minFrames != (uint32_t) ~0) { // This "fudge factor" avoids soaking CPU, and compensates for late progress by server static const nsecs_t kFudgeNs = 10000000LL; // 10 ms ns = ((minFrames * 1000000000LL) / mSampleRate) + kFudgeNs; } // If not supplying data by EVENT_MORE_DATA, then we're done if (mTransfer != TRANSFER_CALLBACK) { return ns; } struct timespec timeout; const struct timespec *requested = &ClientProxy::kForever; if (ns != NS_WHENEVER) { timeout.tv_sec = ns / 1000000000LL; timeout.tv_nsec = ns % 1000000000LL; ALOGV("timeout %ld.%03d", timeout.tv_sec, (int) timeout.tv_nsec / 1000000); requested = &timeout; } while (mRemainingFrames > 0) { Buffer audioBuffer; audioBuffer.frameCount = mRemainingFrames; size_t nonContig; status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig); LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0), "obtainBuffer() err=%d frameCount=%zu", err, audioBuffer.frameCount); requested = &ClientProxy::kNonBlocking; size_t avail = audioBuffer.frameCount + nonContig; ALOGV("obtainBuffer(%u) returned %zu = %zu + %zu err %d", mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err); if (err != NO_ERROR) { /* #ifdef MTK_AOSP_ENHANCEMENT if (err != TIMED_OUT) mCbf(EVENT_WAIT_TIEMOUT, mUserData, 0); #endif */ if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) { break; } ALOGE("Error %d obtaining an audio buffer, giving up.", err); return NS_NEVER; } if (mRetryOnPartialBuffer) { mRetryOnPartialBuffer = false; if (avail < mRemainingFrames) { int64_t myns = ((mRemainingFrames - avail) * 1100000000LL) / mSampleRate; if (ns < 0 || myns < ns) { ns = myns; } return ns; } } size_t reqSize = audioBuffer.size; mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer); size_t readSize = audioBuffer.size; // Sanity check on returned size if (ssize_t(readSize) < 0 || readSize > reqSize) { ALOGE("EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes", reqSize, ssize_t(readSize)); return NS_NEVER; } if (readSize == 0) { // The callback is done consuming buffers // Keep this thread going to handle timed events and // still try to provide more data in intervals of WAIT_PERIOD_MS // but don't just loop and block the CPU, so wait return WAIT_PERIOD_MS * 1000000LL; } size_t releasedFrames = readSize / mFrameSize; audioBuffer.frameCount = releasedFrames; mRemainingFrames -= releasedFrames; if (misalignment >= releasedFrames) { misalignment -= releasedFrames; } else { misalignment = 0; } releaseBuffer(&audioBuffer); // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer // if callback doesn't like to accept the full chunk if (readSize < reqSize) { continue; } // There could be enough non-contiguous frames available to satisfy the remaining request if (mRemainingFrames <= nonContig) { continue; } #if 0 // This heuristic tries to collapse a series of EVENT_MORE_DATA that would total to a // sum <= notificationFrames. It replaces that series by at most two EVENT_MORE_DATA // that total to a sum == notificationFrames. if (0 < misalignment && misalignment <= mRemainingFrames) { mRemainingFrames = misalignment; return (mRemainingFrames * 1100000000LL) / mSampleRate; } #endif } mRemainingFrames = notificationFrames; mRetryOnPartialBuffer = true; // A lot has transpired since ns was calculated, so run again immediately and re-calculate return 0; } status_t AudioRecord::restoreRecord_l(const char *from) { ALOGW("dead IAudioRecord, creating a new one from %s()", from); ++mSequence; status_t result; // if the new IAudioRecord is created, openRecord_l() will modify the // following member variables: mAudioRecord, mCblkMemory, mCblk, mBufferMemory. // It will also delete the strong references on previous IAudioRecord and IMemory size_t position = mProxy->getPosition(); mNewPosition = position + mUpdatePeriod; result = openRecord_l(position); if (result == NO_ERROR) { if (mActive) { // callback thread or sync event hasn't changed // FIXME this fails if we have a new AudioFlinger instance result = mAudioRecord->start(AudioSystem::SYNC_EVENT_SAME, 0); } } if (result != NO_ERROR) { ALOGW("restoreRecord_l() failed status %d", result); mActive = false; } return result; }
void CameraService::Client::disableMsgType(int32_t msgType) { android_atomic_and(~msgType, &mMsgEnabled); mHardware->disableMsgType(msgType); }
void AudioTrack::start() { sp<AudioTrackThread> t = mAudioTrackThread; status_t status; LOGV("start %p", this); if (t != 0) { if (t->exitPending()) { if (t->requestExitAndWait() == WOULD_BLOCK) { LOGE("AudioTrack::start called from thread"); return; } } t->mLock.lock(); } if (android_atomic_or(1, &mActive) == 0) { mNewPosition = mCblk->server + mUpdatePeriod; mCblk->bufferTimeoutMs = MAX_STARTUP_TIMEOUT_MS; mCblk->waitTimeMs = 0; mCblk->flags &= ~CBLK_DISABLED_ON; if (t != 0) { t->run("AudioTrackThread", THREAD_PRIORITY_AUDIO_CLIENT); } else { setpriority(PRIO_PROCESS, 0, THREAD_PRIORITY_AUDIO_CLIENT); } if (mCblk->flags & CBLK_INVALID_MSK) { LOGW("start() track %p invalidated, creating a new one", this); // no need to clear the invalid flag as this cblk will not be used anymore // force new track creation status = DEAD_OBJECT; } else { 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, getOutput(), false); if (status == NO_ERROR) { status = mAudioTrack->start(); if (status == NO_ERROR) { mNewPosition = mCblk->server + mUpdatePeriod; } } } 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); } } } if (t != 0) { t->mLock.unlock(); } }
uint32_t LayerBase::getTransactionFlags(uint32_t flags) { return android_atomic_and(~flags, &mTransactionFlags) & flags; }
/* * Start tests, show results. */ bool dvmTestAtomicSpeed() { pthread_t threads[THREAD_COUNT]; void *(*startRoutine)(void *) = atomicTest; int64_t startWhen, endWhen; #if defined(__ARM_ARCH__) dvmFprintf(stdout, "__ARM_ARCH__ is %d\n", __ARM_ARCH__); #endif #if defined(ANDROID_SMP) dvmFprintf(stdout, "ANDROID_SMP is %d\n", ANDROID_SMP); #endif dvmFprintf(stdout, "Creating threads\n"); int i; for (i = 0; i < THREAD_COUNT; i++) { void *arg = (void *) i; if (pthread_create(&threads[i], NULL, startRoutine, arg) != 0) { dvmFprintf(stderr, "thread create failed\n"); } } /* wait for all the threads to reach the starting line */ while (1) { pthread_mutex_lock(&waitLock); if (threadsStarted == THREAD_COUNT) { dvmFprintf(stdout, "Starting test\n"); startWhen = getRelativeTimeNsec(); pthread_cond_broadcast(&waitCond); pthread_mutex_unlock(&waitLock); break; } pthread_mutex_unlock(&waitLock); usleep(100000); } for (i = 0; i < THREAD_COUNT; i++) { void *retval; if (pthread_join(threads[i], &retval) != 0) { dvmFprintf(stderr, "thread join (%d) failed\n", i); } } endWhen = getRelativeTimeNsec(); dvmFprintf(stdout, "All threads stopped, time is %.6fms\n", (endWhen - startWhen) / 1000000.0); /* * Show results; expecting: * * incTest = 5000000 * decTest = -5000000 * addTest = 7500000 * casTest = 10000000 * wideCasTest = 0x6600000077000000 */ dvmFprintf(stdout, "incTest = %d\n", incTest); dvmFprintf(stdout, "decTest = %d\n", decTest); dvmFprintf(stdout, "addTest = %d\n", addTest); dvmFprintf(stdout, "casTest = %d\n", casTest); dvmFprintf(stdout, "wideCasTest = 0x%llx\n", wideCasTest); /* do again, serially (SMP check) */ startWhen = getRelativeTimeNsec(); for (i = 0; i < THREAD_COUNT; i++) { doAtomicTest(i); } endWhen = getRelativeTimeNsec(); dvmFprintf(stdout, "Same iterations done serially: time is %.6fms\n", (endWhen - startWhen) / 1000000.0); /* * Hard to do a meaningful thrash test on these, so just do a simple * function test. */ andTest = 0xffd7fa96; orTest = 0x122221ff; android_atomic_and(0xfffdaf96, &andTest); android_atomic_or(0xdeaaeb00, &orTest); if (android_atomic_release_cas(failingCasTest + 1, failingCasTest - 1, &failingCasTest) == 0) dvmFprintf(stdout, "failing test did not fail!\n"); dvmFprintf(stdout, "andTest = %#x\n", andTest); dvmFprintf(stdout, "orTest = %#x\n", orTest); dvmFprintf(stdout, "failingCasTest = %d\n", failingCasTest); #ifdef TEST_BIONIC /* * Quick function test on the bionic ops. */ int prev; int tester = 7; prev = __atomic_inc(&tester); __atomic_inc(&tester); __atomic_inc(&tester); dvmFprintf(stdout, "bionic 3 inc: %d -> %d\n", prev, tester); prev = __atomic_dec(&tester); __atomic_dec(&tester); __atomic_dec(&tester); dvmFprintf(stdout, "bionic 3 dec: %d -> %d\n", prev, tester); prev = __atomic_swap(27, &tester); dvmFprintf(stdout, "bionic swap: %d -> %d\n", prev, tester); int swapok = __atomic_cmpxchg(27, 72, &tester); dvmFprintf(stdout, "bionic cmpxchg: %d (%d)\n", tester, swapok); #endif testAtomicSpeed(); return 0; }