Pipe::Pipe(size_t maxFrames, const NBAIO_Format& format, void *buffer) : NBAIO_Sink(format), // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup mMaxFrames(roundup(maxFrames)), mBuffer(buffer == NULL ? malloc(mMaxFrames * Format_frameSize(format)) : buffer), mFifo(mMaxFrames, Format_frameSize(format), mBuffer, false /*throttlesWriter*/), mFifoWriter(mFifo), mReaders(0), mFreeBufferInDestructor(buffer == NULL) { }
// This is a default implementation; it is expected that subclasses will optimize this. ssize_t NBAIO_Source::readVia(readVia_t via, size_t total, void *user, int64_t readPTS, size_t block) { if (!mNegotiated) { return (ssize_t) NEGOTIATE; } static const size_t maxBlock = 32; size_t frameSize = Format_frameSize(mFormat); ALOG_ASSERT(frameSize > 0 && frameSize <= 8); // double guarantees alignment for stack similar to what malloc() gives for heap if (block == 0 || block > maxBlock) { block = maxBlock; } double buffer[((frameSize * block) + sizeof(double) - 1) / sizeof(double)]; size_t accumulator = 0; while (accumulator < total) { size_t count = total - accumulator; if (count > block) { count = block; } ssize_t ret = read(buffer, count, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= count); size_t maxRet = ret; ret = via(user, buffer, maxRet, readPTS); if (ret > 0) { ALOG_ASSERT((size_t) ret <= maxRet); accumulator += ret; continue; } } return accumulator > 0 ? accumulator : ret; } return accumulator; }
void FastCapture::onWork() { const FastCaptureState * const current = (const FastCaptureState *) mCurrent; FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState; const FastCaptureState::Command command = mCommand; const size_t frameCount = current->mFrameCount; if ((command & FastCaptureState::READ) /*&& isWarm*/) { ALOG_ASSERT(mInputSource != NULL); ALOG_ASSERT(mReadBuffer != NULL); dumpState->mReadSequence++; ATRACE_BEGIN("read"); ssize_t framesRead = mInputSource->read(mReadBuffer, frameCount, AudioBufferProvider::kInvalidPTS); ATRACE_END(); dumpState->mReadSequence++; if (framesRead >= 0) { LOG_ALWAYS_FATAL_IF((size_t) framesRead > frameCount); mTotalNativeFramesRead += framesRead; dumpState->mFramesRead = mTotalNativeFramesRead; mReadBufferState = framesRead; } else { dumpState->mReadErrors++; mReadBufferState = 0; } // FIXME rename to attemptedIO mAttemptedWrite = true; } if (command & FastCaptureState::WRITE) { ALOG_ASSERT(mPipeSink != NULL); ALOG_ASSERT(mReadBuffer != NULL); if (mReadBufferState < 0) { unsigned channelCount = Format_channelCount(mFormat); memset(mReadBuffer, 0, frameCount * Format_frameSize(mFormat)); mReadBufferState = frameCount; } if (mReadBufferState > 0) { ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState); // FIXME This supports at most one fast capture client. // To handle multiple clients this could be converted to an array, // or with a lot more work the control block could be shared by all clients. audio_track_cblk_t* cblk = current->mCblk; if (cblk != NULL && framesWritten > 0) { int32_t rear = cblk->u.mStreaming.mRear; android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear); cblk->mServer += framesWritten; int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex); if (!(old & CBLK_FUTEX_WAKE)) { // client is never in server process, so don't use FUTEX_WAKE_PRIVATE (void) syscall(__NR_futex, &cblk->mFutex, FUTEX_WAKE, 1); } } } } }
MonoPipe::MonoPipe(size_t reqFrames, const NBAIO_Format& format, bool writeCanBlock) : NBAIO_Sink(format), mUpdateSeq(0), mReqFrames(reqFrames), mMaxFrames(roundup(reqFrames)), mBuffer(malloc(mMaxFrames * Format_frameSize(format))), mFront(0), mRear(0), mWriteTsValid(false), // mWriteTs mSetpoint((reqFrames * 11) / 16), mWriteCanBlock(writeCanBlock), mIsShutdown(false), // mTimestampShared mTimestampMutator(&mTimestampShared), mTimestampObserver(&mTimestampShared) { uint64_t N, D; mNextRdPTS = AudioBufferProvider::kInvalidPTS; mSamplesToLocalTime.a_zero = 0; mSamplesToLocalTime.b_zero = 0; mSamplesToLocalTime.a_to_b_numer = 0; mSamplesToLocalTime.a_to_b_denom = 0; D = Format_sampleRate(format); (void) pthread_once(&cacheOnceControl, cacheOnceInit); if (!cacheValid) { // log has already been done return; } N = cacheN; LinearTransform::reduce(&N, &D); static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull); static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull); if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) { ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit" " in a 32/32 bit rational. (max reduction is 0x%016" PRIx64 "/0x%016" PRIx64 "). getNextWriteTimestamp calls will be non-functional", N, D); return; } mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N); mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D); }
MonoPipe::MonoPipe(size_t reqFrames, NBAIO_Format format, bool writeCanBlock) : NBAIO_Sink(format), mUpdateSeq(0), mReqFrames(reqFrames), mMaxFrames(roundup(reqFrames)), mBuffer(malloc(mMaxFrames * Format_frameSize(format))), mFront(0), mRear(0), mWriteTsValid(false), // mWriteTs mSetpoint((reqFrames * 11) / 16), mWriteCanBlock(writeCanBlock), mIsShutdown(false) { CCHelper tmpHelper; status_t res; uint64_t N, D; mNextRdPTS = AudioBufferProvider::kInvalidPTS; mSamplesToLocalTime.a_zero = 0; mSamplesToLocalTime.b_zero = 0; mSamplesToLocalTime.a_to_b_numer = 0; mSamplesToLocalTime.a_to_b_denom = 0; D = Format_sampleRate(format); if (OK != (res = tmpHelper.getLocalFreq(&N))) { ALOGE("Failed to fetch local time frequency when constructing a" " MonoPipe (res = %d). getNextWriteTimestamp calls will be" " non-functional", res); return; } LinearTransform::reduce(&N, &D); static const uint64_t kSignedHiBitsMask = ~(0x7FFFFFFFull); static const uint64_t kUnsignedHiBitsMask = ~(0xFFFFFFFFull); if ((N & kSignedHiBitsMask) || (D & kUnsignedHiBitsMask)) { ALOGE("Cannot reduce sample rate to local clock frequency ratio to fit" " in a 32/32 bit rational. (max reduction is 0x%016llx/0x%016llx" "). getNextWriteTimestamp calls will be non-functional", N, D); return; } mSamplesToLocalTime.a_to_b_numer = static_cast<int32_t>(N); mSamplesToLocalTime.a_to_b_denom = static_cast<uint32_t>(D); }
void FastCapture::onStateChange() { const FastCaptureState * const current = (const FastCaptureState *) mCurrent; const FastCaptureState * const previous = (const FastCaptureState *) mPrevious; FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState; const size_t frameCount = current->mFrameCount; bool eitherChanged = false; // check for change in input HAL configuration NBAIO_Format previousFormat = mFormat; if (current->mInputSourceGen != mInputSourceGen) { mInputSource = current->mInputSource; mInputSourceGen = current->mInputSourceGen; if (mInputSource == NULL) { mFormat = Format_Invalid; mSampleRate = 0; } else { mFormat = mInputSource->format(); mSampleRate = Format_sampleRate(mFormat); unsigned channelCount = Format_channelCount(mFormat); ALOG_ASSERT(channelCount >= 1 && channelCount <= FCC_8); } dumpState->mSampleRate = mSampleRate; eitherChanged = true; } // check for change in pipe if (current->mPipeSinkGen != mPipeSinkGen) { mPipeSink = current->mPipeSink; mPipeSinkGen = current->mPipeSinkGen; eitherChanged = true; } // input source and pipe sink must be compatible if (eitherChanged && mInputSource != NULL && mPipeSink != NULL) { ALOG_ASSERT(Format_isEqual(mFormat, mPipeSink->format())); } if ((!Format_isEqual(mFormat, previousFormat)) || (frameCount != previous->mFrameCount)) { // FIXME to avoid priority inversion, don't free here free(mReadBuffer); mReadBuffer = NULL; if (frameCount > 0 && mSampleRate > 0) { // FIXME new may block for unbounded time at internal mutex of the heap // implementation; it would be better to have normal capture thread allocate for // us to avoid blocking here and to prevent possible priority inversion size_t bufferSize = frameCount * Format_frameSize(mFormat); (void)posix_memalign(&mReadBuffer, 32, bufferSize); memset(mReadBuffer, 0, bufferSize); // if posix_memalign fails, will segv here. mPeriodNs = (frameCount * 1000000000LL) / mSampleRate; // 1.00 mUnderrunNs = (frameCount * 1750000000LL) / mSampleRate; // 1.75 mOverrunNs = (frameCount * 500000000LL) / mSampleRate; // 0.50 mForceNs = (frameCount * 950000000LL) / mSampleRate; // 0.95 mWarmupNsMin = (frameCount * 750000000LL) / mSampleRate; // 0.75 mWarmupNsMax = (frameCount * 1250000000LL) / mSampleRate; // 1.25 } else { mPeriodNs = 0; mUnderrunNs = 0; mOverrunNs = 0; mForceNs = 0; mWarmupNsMin = 0; mWarmupNsMax = LONG_MAX; } mReadBufferState = -1; dumpState->mFrameCount = frameCount; } }