Loading services/audioflinger/PlaybackTracks.h +2 −2 Original line number Diff line number Diff line Loading @@ -255,7 +255,7 @@ public: class Buffer : public AudioBufferProvider::Buffer { public: int16_t *mBuffer; void *mBuffer; }; OutputTrack(PlaybackThread *thread, Loading @@ -271,7 +271,7 @@ public: AudioSystem::SYNC_EVENT_NONE, int triggerSession = 0); virtual void stop(); bool write(int16_t* data, uint32_t frames); bool write(void* data, uint32_t frames); bool bufferQueueEmpty() const { return mBufferQueue.size() == 0; } bool isActive() const { return mActive; } const wp<ThreadBase>& thread() const { return mThread; } Loading services/audioflinger/Threads.cpp +26 −22 Original line number Diff line number Diff line Loading @@ -172,6 +172,18 @@ static int sFastTrackMultiplier = kFastTrackMultiplier; // and that all "fast" AudioRecord clients read from. In either case, the size can be small. static const size_t kRecordThreadReadOnlyHeapSize = 0x2000; // Returns the source frames needed to resample to destination frames. This is not a precise // value and depends on the resampler (and possibly how it handles rounding internally). // If srcSampleRate and dstSampleRate are equal, then it returns destination frames, which // may not be a true if the resampler is asynchronous. static inline size_t sourceFramesNeeded( uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate) { // +1 for rounding - always do this even if matched ratio // +1 for additional sample needed for interpolation return srcSampleRate == dstSampleRate ? dstFramesRequired : size_t((uint64_t)dstFramesRequired * srcSampleRate / dstSampleRate + 1 + 1); } // ---------------------------------------------------------------------------- static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT; Loading Loading @@ -3453,8 +3465,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac if (sr == mSampleRate) { desiredFrames = mNormalFrameCount; } else { // +1 for rounding and +1 for additional sample needed for interpolation desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1; desiredFrames = sourceFramesNeeded(sr, mNormalFrameCount, mSampleRate); // add frames already consumed but not yet released by the resampler // because mAudioTrackServerProxy->framesReady() will include these frames desiredFrames += mAudioMixer->getUnreleasedFrames(track->name()); Loading Loading @@ -4881,16 +4892,8 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime() ssize_t AudioFlinger::DuplicatingThread::threadLoop_write() { // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT // for delivery downstream as needed. This in-place conversion is safe as // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format // (AUDIO_FORMAT_PCM_8_BIT is not allowed here). if (mFormat != AUDIO_FORMAT_PCM_16_BIT) { memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT, mSinkBuffer, mFormat, writeFrames * mChannelCount); } for (size_t i = 0; i < outputTracks.size(); i++) { outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames); outputTracks[i]->write(mSinkBuffer, writeFrames); } mStandby = false; return (ssize_t)mSinkBufferSize; Loading @@ -4917,25 +4920,26 @@ void AudioFlinger::DuplicatingThread::clearOutputTracks() void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) { Mutex::Autolock _l(mLock); // FIXME explain this formula size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate(); // OutputTrack is forced to AUDIO_FORMAT_PCM_16_BIT regardless of mFormat // due to current usage case and restrictions on the AudioBufferProvider. // Actual buffer conversion is done in threadLoop_write(). // // TODO: This may change in the future, depending on multichannel // (and non int16_t*) support on AF::PlaybackThread::OutputTrack OutputTrack *outputTrack = new OutputTrack(thread, // The downstream MixerThread consumes thread->frameCount() amount of frames per mix pass. // Adjust for thread->sampleRate() to determine minimum buffer frame count. // Then triple buffer because Threads do not run synchronously and may not be clock locked. const size_t frameCount = 3 * sourceFramesNeeded(mSampleRate, thread->frameCount(), thread->sampleRate()); // TODO: Consider asynchronous sample rate conversion to handle clock disparity // from different OutputTracks and their associated MixerThreads (e.g. one may // nearly empty and the other may be dropping data). sp<OutputTrack> outputTrack = new OutputTrack(thread, this, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, mFormat, mChannelMask, frameCount, IPCThreadState::self()->getCallingUid()); if (outputTrack->cblk() != NULL) { thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f); mOutputTracks.add(outputTrack); ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread); ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread); updateWaitTime_l(); } } Loading services/audioflinger/Tracks.cpp +21 −32 Original line number Diff line number Diff line Loading @@ -1710,14 +1710,13 @@ void AudioFlinger::PlaybackThread::OutputTrack::stop() mActive = false; } bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames) bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) { Buffer *pInBuffer; Buffer inBuffer; uint32_t channelCount = mChannelCount; bool outputBufferFull = false; inBuffer.frameCount = frames; inBuffer.i16 = data; inBuffer.raw = data; uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); Loading @@ -1727,13 +1726,17 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (thread != 0) { MixerThread *mixerThread = (MixerThread *)thread.get(); if (mFrameCount > frames) { // For the first write after being inactive, ensure that we have // enough frames to fill mFrameCount (which should be multiples of // the minimum buffer requirements of the downstream MixerThread). // This provides enough frames for the downstream mixer to begin // (see AudioFlinger::PlaybackThread::Track::isReady()). if (mBufferQueue.size() < kMaxOverFlowBuffers) { uint32_t startFrames = (mFrameCount - frames); pInBuffer = new Buffer; pInBuffer->mBuffer = new int16_t[startFrames * channelCount]; pInBuffer->mBuffer = calloc(1, startFrames * mFrameSize); pInBuffer->frameCount = startFrames; pInBuffer->i16 = pInBuffer->mBuffer; memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t)); pInBuffer->raw = pInBuffer->mBuffer; mBufferQueue.add(pInBuffer); } else { ALOGW("OutputTrack::write() %p no more buffers in queue", this); Loading Loading @@ -1774,20 +1777,20 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t)); memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize); Proxy::Buffer buf; buf.mFrameCount = outFrames; buf.mRaw = NULL; mClientProxy->releaseBuffer(&buf); pInBuffer->frameCount -= outFrames; pInBuffer->i16 += outFrames * channelCount; pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize; mOutBuffer.frameCount -= outFrames; mOutBuffer.i16 += outFrames * channelCount; mOutBuffer.raw = (int8_t *)mOutBuffer.raw + outFrames * mFrameSize; if (pInBuffer->frameCount == 0) { if (mBufferQueue.size()) { mBufferQueue.removeAt(0); delete [] pInBuffer->mBuffer; free(pInBuffer->mBuffer); delete pInBuffer; ALOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); Loading @@ -1803,11 +1806,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (thread != 0 && !thread->standby()) { if (mBufferQueue.size() < kMaxOverFlowBuffers) { pInBuffer = new Buffer; pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount]; pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize); pInBuffer->frameCount = inBuffer.frameCount; pInBuffer->i16 = pInBuffer->mBuffer; memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * sizeof(int16_t)); pInBuffer->raw = pInBuffer->mBuffer; memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize); mBufferQueue.add(pInBuffer); ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); Loading @@ -1818,24 +1820,11 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr } } // Calling write() with a 0 length buffer, means that no more data will be written: // If no more buffers are pending, fill output track buffer to make sure it is started // by output mixer. if (frames == 0 && mBufferQueue.size() == 0) { // FIXME borken, replace by getting framesReady() from proxy size_t user = 0; // was mCblk->user if (user < mFrameCount) { frames = mFrameCount - user; pInBuffer = new Buffer; pInBuffer->mBuffer = new int16_t[frames * channelCount]; pInBuffer->frameCount = frames; pInBuffer->i16 = pInBuffer->mBuffer; memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t)); mBufferQueue.add(pInBuffer); } else if (mActive) { // Calling write() with a 0 length buffer means that no more data will be written: // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. if (frames == 0 && mBufferQueue.size() == 0 && mActive) { stop(); } } return outputBufferFull; } Loading @@ -1860,7 +1849,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() for (size_t i = 0; i < size; i++) { Buffer *pBuffer = mBufferQueue.itemAt(i); delete [] pBuffer->mBuffer; free(pBuffer->mBuffer); delete pBuffer; } mBufferQueue.clear(); Loading Loading
services/audioflinger/PlaybackTracks.h +2 −2 Original line number Diff line number Diff line Loading @@ -255,7 +255,7 @@ public: class Buffer : public AudioBufferProvider::Buffer { public: int16_t *mBuffer; void *mBuffer; }; OutputTrack(PlaybackThread *thread, Loading @@ -271,7 +271,7 @@ public: AudioSystem::SYNC_EVENT_NONE, int triggerSession = 0); virtual void stop(); bool write(int16_t* data, uint32_t frames); bool write(void* data, uint32_t frames); bool bufferQueueEmpty() const { return mBufferQueue.size() == 0; } bool isActive() const { return mActive; } const wp<ThreadBase>& thread() const { return mThread; } Loading
services/audioflinger/Threads.cpp +26 −22 Original line number Diff line number Diff line Loading @@ -172,6 +172,18 @@ static int sFastTrackMultiplier = kFastTrackMultiplier; // and that all "fast" AudioRecord clients read from. In either case, the size can be small. static const size_t kRecordThreadReadOnlyHeapSize = 0x2000; // Returns the source frames needed to resample to destination frames. This is not a precise // value and depends on the resampler (and possibly how it handles rounding internally). // If srcSampleRate and dstSampleRate are equal, then it returns destination frames, which // may not be a true if the resampler is asynchronous. static inline size_t sourceFramesNeeded( uint32_t srcSampleRate, size_t dstFramesRequired, uint32_t dstSampleRate) { // +1 for rounding - always do this even if matched ratio // +1 for additional sample needed for interpolation return srcSampleRate == dstSampleRate ? dstFramesRequired : size_t((uint64_t)dstFramesRequired * srcSampleRate / dstSampleRate + 1 + 1); } // ---------------------------------------------------------------------------- static pthread_once_t sFastTrackMultiplierOnce = PTHREAD_ONCE_INIT; Loading Loading @@ -3453,8 +3465,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac if (sr == mSampleRate) { desiredFrames = mNormalFrameCount; } else { // +1 for rounding and +1 for additional sample needed for interpolation desiredFrames = (mNormalFrameCount * sr) / mSampleRate + 1 + 1; desiredFrames = sourceFramesNeeded(sr, mNormalFrameCount, mSampleRate); // add frames already consumed but not yet released by the resampler // because mAudioTrackServerProxy->framesReady() will include these frames desiredFrames += mAudioMixer->getUnreleasedFrames(track->name()); Loading Loading @@ -4881,16 +4892,8 @@ void AudioFlinger::DuplicatingThread::threadLoop_sleepTime() ssize_t AudioFlinger::DuplicatingThread::threadLoop_write() { // We convert the duplicating thread format to AUDIO_FORMAT_PCM_16_BIT // for delivery downstream as needed. This in-place conversion is safe as // AUDIO_FORMAT_PCM_16_BIT is smaller than any other supported format // (AUDIO_FORMAT_PCM_8_BIT is not allowed here). if (mFormat != AUDIO_FORMAT_PCM_16_BIT) { memcpy_by_audio_format(mSinkBuffer, AUDIO_FORMAT_PCM_16_BIT, mSinkBuffer, mFormat, writeFrames * mChannelCount); } for (size_t i = 0; i < outputTracks.size(); i++) { outputTracks[i]->write(reinterpret_cast<int16_t*>(mSinkBuffer), writeFrames); outputTracks[i]->write(mSinkBuffer, writeFrames); } mStandby = false; return (ssize_t)mSinkBufferSize; Loading @@ -4917,25 +4920,26 @@ void AudioFlinger::DuplicatingThread::clearOutputTracks() void AudioFlinger::DuplicatingThread::addOutputTrack(MixerThread *thread) { Mutex::Autolock _l(mLock); // FIXME explain this formula size_t frameCount = (3 * mNormalFrameCount * mSampleRate) / thread->sampleRate(); // OutputTrack is forced to AUDIO_FORMAT_PCM_16_BIT regardless of mFormat // due to current usage case and restrictions on the AudioBufferProvider. // Actual buffer conversion is done in threadLoop_write(). // // TODO: This may change in the future, depending on multichannel // (and non int16_t*) support on AF::PlaybackThread::OutputTrack OutputTrack *outputTrack = new OutputTrack(thread, // The downstream MixerThread consumes thread->frameCount() amount of frames per mix pass. // Adjust for thread->sampleRate() to determine minimum buffer frame count. // Then triple buffer because Threads do not run synchronously and may not be clock locked. const size_t frameCount = 3 * sourceFramesNeeded(mSampleRate, thread->frameCount(), thread->sampleRate()); // TODO: Consider asynchronous sample rate conversion to handle clock disparity // from different OutputTracks and their associated MixerThreads (e.g. one may // nearly empty and the other may be dropping data). sp<OutputTrack> outputTrack = new OutputTrack(thread, this, mSampleRate, AUDIO_FORMAT_PCM_16_BIT, mFormat, mChannelMask, frameCount, IPCThreadState::self()->getCallingUid()); if (outputTrack->cblk() != NULL) { thread->setStreamVolume(AUDIO_STREAM_PATCH, 1.0f); mOutputTracks.add(outputTrack); ALOGV("addOutputTrack() track %p, on thread %p", outputTrack, thread); ALOGV("addOutputTrack() track %p, on thread %p", outputTrack.get(), thread); updateWaitTime_l(); } } Loading
services/audioflinger/Tracks.cpp +21 −32 Original line number Diff line number Diff line Loading @@ -1710,14 +1710,13 @@ void AudioFlinger::PlaybackThread::OutputTrack::stop() mActive = false; } bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t frames) bool AudioFlinger::PlaybackThread::OutputTrack::write(void* data, uint32_t frames) { Buffer *pInBuffer; Buffer inBuffer; uint32_t channelCount = mChannelCount; bool outputBufferFull = false; inBuffer.frameCount = frames; inBuffer.i16 = data; inBuffer.raw = data; uint32_t waitTimeLeftMs = mSourceThread->waitTimeMs(); Loading @@ -1727,13 +1726,17 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (thread != 0) { MixerThread *mixerThread = (MixerThread *)thread.get(); if (mFrameCount > frames) { // For the first write after being inactive, ensure that we have // enough frames to fill mFrameCount (which should be multiples of // the minimum buffer requirements of the downstream MixerThread). // This provides enough frames for the downstream mixer to begin // (see AudioFlinger::PlaybackThread::Track::isReady()). if (mBufferQueue.size() < kMaxOverFlowBuffers) { uint32_t startFrames = (mFrameCount - frames); pInBuffer = new Buffer; pInBuffer->mBuffer = new int16_t[startFrames * channelCount]; pInBuffer->mBuffer = calloc(1, startFrames * mFrameSize); pInBuffer->frameCount = startFrames; pInBuffer->i16 = pInBuffer->mBuffer; memset(pInBuffer->raw, 0, startFrames * channelCount * sizeof(int16_t)); pInBuffer->raw = pInBuffer->mBuffer; mBufferQueue.add(pInBuffer); } else { ALOGW("OutputTrack::write() %p no more buffers in queue", this); Loading Loading @@ -1774,20 +1777,20 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr uint32_t outFrames = pInBuffer->frameCount > mOutBuffer.frameCount ? mOutBuffer.frameCount : pInBuffer->frameCount; memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * channelCount * sizeof(int16_t)); memcpy(mOutBuffer.raw, pInBuffer->raw, outFrames * mFrameSize); Proxy::Buffer buf; buf.mFrameCount = outFrames; buf.mRaw = NULL; mClientProxy->releaseBuffer(&buf); pInBuffer->frameCount -= outFrames; pInBuffer->i16 += outFrames * channelCount; pInBuffer->raw = (int8_t *)pInBuffer->raw + outFrames * mFrameSize; mOutBuffer.frameCount -= outFrames; mOutBuffer.i16 += outFrames * channelCount; mOutBuffer.raw = (int8_t *)mOutBuffer.raw + outFrames * mFrameSize; if (pInBuffer->frameCount == 0) { if (mBufferQueue.size()) { mBufferQueue.removeAt(0); delete [] pInBuffer->mBuffer; free(pInBuffer->mBuffer); delete pInBuffer; ALOGV("OutputTrack::write() %p thread %p released overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); Loading @@ -1803,11 +1806,10 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr if (thread != 0 && !thread->standby()) { if (mBufferQueue.size() < kMaxOverFlowBuffers) { pInBuffer = new Buffer; pInBuffer->mBuffer = new int16_t[inBuffer.frameCount * channelCount]; pInBuffer->mBuffer = malloc(inBuffer.frameCount * mFrameSize); pInBuffer->frameCount = inBuffer.frameCount; pInBuffer->i16 = pInBuffer->mBuffer; memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * channelCount * sizeof(int16_t)); pInBuffer->raw = pInBuffer->mBuffer; memcpy(pInBuffer->raw, inBuffer.raw, inBuffer.frameCount * mFrameSize); mBufferQueue.add(pInBuffer); ALOGV("OutputTrack::write() %p thread %p adding overflow buffer %d", this, mThread.unsafe_get(), mBufferQueue.size()); Loading @@ -1818,24 +1820,11 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr } } // Calling write() with a 0 length buffer, means that no more data will be written: // If no more buffers are pending, fill output track buffer to make sure it is started // by output mixer. if (frames == 0 && mBufferQueue.size() == 0) { // FIXME borken, replace by getting framesReady() from proxy size_t user = 0; // was mCblk->user if (user < mFrameCount) { frames = mFrameCount - user; pInBuffer = new Buffer; pInBuffer->mBuffer = new int16_t[frames * channelCount]; pInBuffer->frameCount = frames; pInBuffer->i16 = pInBuffer->mBuffer; memset(pInBuffer->raw, 0, frames * channelCount * sizeof(int16_t)); mBufferQueue.add(pInBuffer); } else if (mActive) { // Calling write() with a 0 length buffer means that no more data will be written: // We rely on stop() to set the appropriate flags to allow the remaining frames to play out. if (frames == 0 && mBufferQueue.size() == 0 && mActive) { stop(); } } return outputBufferFull; } Loading @@ -1860,7 +1849,7 @@ void AudioFlinger::PlaybackThread::OutputTrack::clearBufferQueue() for (size_t i = 0; i < size; i++) { Buffer *pBuffer = mBufferQueue.itemAt(i); delete [] pBuffer->mBuffer; free(pBuffer->mBuffer); delete pBuffer; } mBufferQueue.clear(); Loading