From e3aa659e9cee7df5c12a80d285cc29ab3b2cbb39 Mon Sep 17 00:00:00 2001 From: Glenn Kasten Date: Tue, 4 Dec 2012 12:22:46 -0800 Subject: Start isolating control block accesses in a proxy The proxy object will eventually be the only code that understands the details of the control block. This should make it easier to change the control block in the future. Initial set of control block fields that are isolated: - sample rate - send level - volume Prepare for streaming/static separation by adding a union to the control block for the new fields. Fix bug in handling of max sample rate on a track. It was only checking at re-configuration, not at each mix. Simplify OutputTrack::obtainBuffer. Change-Id: I2249f9d04f73a911a922ad1d7f6197292c74cd92 --- services/audioflinger/AudioFlinger.h | 1 + services/audioflinger/PlaybackTracks.h | 3 +- services/audioflinger/RecordTracks.h | 2 - services/audioflinger/Threads.cpp | 21 +++++--- services/audioflinger/TrackBase.h | 9 +++- services/audioflinger/Tracks.cpp | 97 ++++++++++++++-------------------- 6 files changed, 63 insertions(+), 70 deletions(-) (limited to 'services/audioflinger') diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h index 6d3f0a1..64a9871 100644 --- a/services/audioflinger/AudioFlinger.h +++ b/services/audioflinger/AudioFlinger.h @@ -61,6 +61,7 @@ class AudioMixer; class AudioBuffer; class AudioResampler; class FastMixer; +class ServerProxy; // ---------------------------------------------------------------------------- diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index aaa5333..adec938 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -107,7 +107,6 @@ public: bool isInvalid() const { return mIsInvalid; } virtual bool isTimedTrack() const { return false; } bool isFastTrack() const { return (mFlags & IAudioFlinger::TRACK_FAST) != 0; } - virtual bool isOut() const; protected: @@ -277,5 +276,5 @@ private: AudioBufferProvider::Buffer mOutBuffer; bool mActive; DuplicatingThread* const mSourceThread; // for waitTimeMs() in write() - void* mBuffers; // starting address of buffers in plain memory + AudioTrackClientProxy* mClientProxy; }; // end of OutputTrack diff --git a/services/audioflinger/RecordTracks.h b/services/audioflinger/RecordTracks.h index fe681d7..6c0d1d3 100644 --- a/services/audioflinger/RecordTracks.h +++ b/services/audioflinger/RecordTracks.h @@ -45,8 +45,6 @@ public: static void appendDumpHeader(String8& result); void dump(char* buffer, size_t size); - virtual bool isOut() const; - private: friend class AudioFlinger; // for mState diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index d2b2931..82acd3a 100644 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -2643,7 +2643,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // read original volumes with volume control float typeVolume = mStreamTypes[track->streamType()].volume; float v = masterVolume * typeVolume; - uint32_t vlr = cblk->getVolumeLR(); + ServerProxy *proxy = track->mServerProxy; + uint32_t vlr = proxy->getVolumeLR(); vl = vlr & 0xFFFF; vr = vlr >> 16; // track volumes come from shared memory, so can't be trusted and must be clamped @@ -2661,7 +2662,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac // assuming master volume and stream type volume each go up to 1.0, // vl and vr are now in 8.24 format - uint16_t sendLevel = cblk->getSendLevel_U4_12(); + uint16_t sendLevel = proxy->getSendLevel_U4_12(); // send level comes from shared memory and so may be corrupt if (sendLevel > MAX_GAIN_INT) { ALOGV("Track send level out of range: %04X", sendLevel); @@ -2713,11 +2714,19 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::MixerThread::prepareTrac name, AudioMixer::TRACK, AudioMixer::CHANNEL_MASK, (void *)track->channelMask()); + // limit track sample rate to 2 x output sample rate, which changes at re-configuration + uint32_t maxSampleRate = mSampleRate * 2; + uint32_t reqSampleRate = track->mServerProxy->getSampleRate(); + if (reqSampleRate == 0) { + reqSampleRate = mSampleRate; + } else if (reqSampleRate > maxSampleRate) { + reqSampleRate = maxSampleRate; + } mAudioMixer->setParameter( name, AudioMixer::RESAMPLE, AudioMixer::SAMPLE_RATE, - (void *)(cblk->sampleRate)); + (void *)reqSampleRate); mAudioMixer->setParameter( name, AudioMixer::TRACK, @@ -2990,10 +2999,6 @@ bool AudioFlinger::MixerThread::checkForNewParameters_l() break; } mTracks[i]->mName = name; - // limit track sample rate to 2 x new output sample rate - if (mTracks[i]->mCblk->sampleRate > 2 * sampleRate()) { - mTracks[i]->mCblk->sampleRate = 2 * sampleRate(); - } } sendIoConfigEvent_l(AudioSystem::OUTPUT_CONFIG_CHANGED); } @@ -3142,7 +3147,7 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } else { float typeVolume = mStreamTypes[track->streamType()].volume; float v = mMasterVolume * typeVolume; - uint32_t vlr = cblk->getVolumeLR(); + uint32_t vlr = track->mServerProxy->getVolumeLR(); float v_clamped = v * (vlr & 0xFFFF); if (v_clamped > MAX_GAIN) { v_clamped = MAX_GAIN; diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h index 17de49b..e0bd97a 100644 --- a/services/audioflinger/TrackBase.h +++ b/services/audioflinger/TrackBase.h @@ -44,7 +44,8 @@ public: audio_channel_mask_t channelMask, size_t frameCount, const sp& sharedBuffer, - int sessionId); + int sessionId, + bool isOut); virtual ~TrackBase(); virtual status_t start(AudioSystem::sync_event_t event, @@ -108,7 +109,8 @@ protected: bool step(); // mStepCount is an implicit input void reset(); - virtual bool isOut() const = 0; // true for Track and TimedTrack, false for RecordTrack, + bool isOut() const { return mIsOut; } + // true for Track and TimedTrack, false for RecordTrack, // this could be a track type if needed later const wp mThread; @@ -116,6 +118,7 @@ protected: sp mCblkMemory; audio_track_cblk_t* mCblk; void* mBuffer; // start of track buffer, typically in shared memory + // except for OutputTrack when it is in local memory void* mBufferEnd; // &mBuffer[mFrameCount * frameSize], where frameSize // is based on mChannelCount and 16-bit samples uint32_t mStepCount; // saves AudioBufferProvider::Buffer::frameCount as of @@ -136,4 +139,6 @@ protected: bool mStepServerFailed; const int mSessionId; Vector < sp >mSyncEvents; + const bool mIsOut; + ServerProxy* mServerProxy; }; diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 9b611d2..c5f0ed7 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -62,7 +62,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( audio_channel_mask_t channelMask, size_t frameCount, const sp& sharedBuffer, - int sessionId) + int sessionId, + bool isOut) : RefBase(), mThread(thread), mClient(client), @@ -79,7 +80,9 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( mChannelCount * audio_bytes_per_sample(format) : sizeof(int8_t)), mFrameCount(frameCount), mStepServerFailed(false), - mSessionId(sessionId) + mSessionId(sessionId), + mIsOut(isOut), + mServerProxy(NULL) { // client == 0 implies sharedBuffer == 0 ALOG_ASSERT(!(client == 0 && sharedBuffer != 0)); @@ -105,7 +108,8 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( return; } } else { - mCblk = (audio_track_cblk_t *)(new uint8_t[size]); + // this syntax avoids calling the audio_track_cblk_t constructor twice + mCblk = (audio_track_cblk_t *) new uint8_t[size]; // assume mCblk != NULL } @@ -114,7 +118,6 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( new(mCblk) audio_track_cblk_t(); // clear all buffers mCblk->frameCount_ = frameCount; - mCblk->sampleRate = sampleRate; // uncomment the following lines to quickly test 32-bit wraparound // mCblk->user = 0xffff0000; // mCblk->server = 0xffff0000; @@ -130,11 +133,14 @@ AudioFlinger::ThreadBase::TrackBase::TrackBase( mBuffer = sharedBuffer->pointer(); } mBufferEnd = (uint8_t *)mBuffer + bufferSize; + mServerProxy = new ServerProxy(mCblk, mBuffer, frameCount, mFrameSize, isOut); } } AudioFlinger::ThreadBase::TrackBase::~TrackBase() { + // delete the proxy before deleting the shared memory it refers to, to avoid dangling reference + delete mServerProxy; if (mCblk != NULL) { if (mClient == 0) { delete mCblk; @@ -166,10 +172,7 @@ void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buf } bool AudioFlinger::ThreadBase::TrackBase::step() { - bool result; - audio_track_cblk_t* cblk = this->cblk(); - - result = cblk->stepServer(mStepCount, mFrameCount, isOut()); + bool result = mServerProxy->step(mStepCount); if (!result) { ALOGV("stepServer failed acquiring cblk mutex"); mStepServerFailed = true; @@ -189,7 +192,7 @@ void AudioFlinger::ThreadBase::TrackBase::reset() { } uint32_t AudioFlinger::ThreadBase::TrackBase::sampleRate() const { - return mCblk->sampleRate; + return mServerProxy->getSampleRate(); } void* AudioFlinger::ThreadBase::TrackBase::getBuffer(uint32_t offset, uint32_t frames) const { @@ -310,7 +313,7 @@ AudioFlinger::PlaybackThread::Track::Track( int sessionId, IAudioFlinger::track_flags_t flags) : TrackBase(thread, client, sampleRate, format, channelMask, frameCount, sharedBuffer, - sessionId), + sessionId, true /*isOut*/), mFillingUpStatus(FS_INVALID), // mRetryCount initialized later when needed mSharedBuffer(sharedBuffer), @@ -399,7 +402,7 @@ void AudioFlinger::PlaybackThread::Track::destroy() void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) { - uint32_t vlr = mCblk->getVolumeLR(); + uint32_t vlr = mServerProxy->getVolumeLR(); if (isFastTrack()) { sprintf(buffer, " F %2d", mFastIndex); } else { @@ -468,7 +471,7 @@ void AudioFlinger::PlaybackThread::Track::dump(char* buffer, size_t size) mFrameCount, stateChar, mFillingUpStatus, - mCblk->sampleRate, + mServerProxy->getSampleRate(), 20.0 * log10((vlr & 0xFFFF) / 4096.0), 20.0 * log10((vlr >> 16) / 4096.0), mCblk->server, @@ -503,7 +506,7 @@ status_t AudioFlinger::PlaybackThread::Track::getNextBuffer( } // FIXME Same as above - framesReady = cblk->framesReadyOut(); + framesReady = mServerProxy->framesReady(); if (CC_LIKELY(framesReady)) { uint32_t s = cblk->server; @@ -538,7 +541,7 @@ getNextBuffer_exit: // the tryLock() could block for up to 1 ms, and a sequence of these could delay fast mixer. // FIXME Replace AudioTrackShared control block implementation by a non-blocking FIFO queue. size_t AudioFlinger::PlaybackThread::Track::framesReady() const { - return mCblk->framesReadyOut(); + return mServerProxy->framesReady(); } // Don't call for fast tracks; the framesReady() could result in priority inversion @@ -795,7 +798,7 @@ uint32_t AudioFlinger::PlaybackThread::Track::getVolumeLR() { // called by FastMixer, so not allowed to take any locks, block, or do I/O including logs ALOG_ASSERT(isFastTrack() && (mCblk != NULL)); - uint32_t vlr = mCblk->getVolumeLR(); + uint32_t vlr = mServerProxy->getVolumeLR(); uint32_t vl = vlr & 0xFFFF; uint32_t vr = vlr >> 16; // track volumes come from shared memory, so can't be trusted and must be clamped @@ -830,11 +833,6 @@ status_t AudioFlinger::PlaybackThread::Track::setSyncEvent(const sp& return NO_ERROR; } -bool AudioFlinger::PlaybackThread::Track::isOut() const -{ - return true; -} - void AudioFlinger::PlaybackThread::Track::invalidate() { // FIXME should use proxy @@ -1369,17 +1367,19 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( size_t frameCount) : Track(playbackThread, NULL, AUDIO_STREAM_CNT, sampleRate, format, channelMask, frameCount, NULL, 0, IAudioFlinger::TRACK_DEFAULT), - mActive(false), mSourceThread(sourceThread), mBuffers(NULL) + mActive(false), mSourceThread(sourceThread), mClientProxy(NULL) { if (mCblk != NULL) { - mBuffers = (char*)mCblk + sizeof(audio_track_cblk_t); mOutBuffer.frameCount = 0; playbackThread->mTracks.add(this); - ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, mBuffers %p, " \ - "mCblk->frameCount %d, mCblk->sampleRate %u, mChannelMask 0x%08x mBufferEnd %p", - mCblk, mBuffer, mBuffers, - mCblk->frameCount, mCblk->sampleRate, mChannelMask, mBufferEnd); + ALOGV("OutputTrack constructor mCblk %p, mBuffer %p, " + "mCblk->frameCount_ %u, mChannelMask 0x%08x mBufferEnd %p", + mCblk, mBuffer, + mCblk->frameCount_, mChannelMask, mBufferEnd); + // since client and server are in the same process, + // the buffer has the same virtual address on both sides + mClientProxy = new AudioTrackClientProxy(mCblk, mBuffer, mFrameCount, mFrameSize); } else { ALOGW("Error creating output track on thread %p", playbackThread); } @@ -1388,6 +1388,8 @@ AudioFlinger::PlaybackThread::OutputTrack::OutputTrack( AudioFlinger::PlaybackThread::OutputTrack::~OutputTrack() { clearBufferQueue(); + delete mClientProxy; + // superclass destructor will now delete the server proxy and shared memory both refer to } status_t AudioFlinger::PlaybackThread::OutputTrack::start(AudioSystem::sync_event_t event, @@ -1475,7 +1477,7 @@ 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)); - mCblk->stepUserOut(outFrames, mFrameCount); + mClientProxy->stepUser(outFrames); pInBuffer->frameCount -= outFrames; pInBuffer->i16 += outFrames * channelCount; mOutBuffer.frameCount -= outFrames; @@ -1538,40 +1540,29 @@ bool AudioFlinger::PlaybackThread::OutputTrack::write(int16_t* data, uint32_t fr status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer( AudioBufferProvider::Buffer* buffer, uint32_t waitTimeMs) { - int active; - status_t result; audio_track_cblk_t* cblk = mCblk; uint32_t framesReq = buffer->frameCount; ALOGVV("OutputTrack::obtainBuffer user %d, server %d", cblk->user, cblk->server); buffer->frameCount = 0; - uint32_t framesAvail = cblk->framesAvailableOut(mFrameCount); - - - if (framesAvail == 0) { + size_t framesAvail; + { Mutex::Autolock _l(cblk->lock); - goto start_loop_here; - while (framesAvail == 0) { - active = mActive; - if (CC_UNLIKELY(!active)) { + + // read the server count again + while (!(framesAvail = mClientProxy->framesAvailable_l())) { + if (CC_UNLIKELY(!mActive)) { ALOGV("Not active and NO_MORE_BUFFERS"); return NO_MORE_BUFFERS; } - result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); + status_t result = cblk->cv.waitRelative(cblk->lock, milliseconds(waitTimeMs)); if (result != NO_ERROR) { return NO_MORE_BUFFERS; } - // read the server count again - start_loop_here: - framesAvail = cblk->framesAvailableOut_l(mFrameCount); } } -// if (framesAvail < framesReq) { -// return NO_MORE_BUFFERS; -// } - if (framesReq > framesAvail) { framesReq = framesAvail; } @@ -1584,7 +1575,7 @@ status_t AudioFlinger::PlaybackThread::OutputTrack::obtainBuffer( } buffer->frameCount = framesReq; - buffer->raw = cblk->buffer(mBuffers, mFrameSize, u); + buffer->raw = mClientProxy->buffer(u); return NO_ERROR; } @@ -1655,7 +1646,7 @@ AudioFlinger::RecordThread::RecordTrack::RecordTrack( size_t frameCount, int sessionId) : TrackBase(thread, client, sampleRate, format, - channelMask, frameCount, 0 /*sharedBuffer*/, sessionId), + channelMask, frameCount, 0 /*sharedBuffer*/, sessionId, false /*isOut*/), mOverflow(false) { ALOGV("RecordTrack constructor, size %d", (int)mBufferEnd - (int)mBuffer); @@ -1684,7 +1675,7 @@ status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvi } // FIXME lock is not actually held, so overrun is possible - framesAvail = cblk->framesAvailableIn_l(mFrameCount); + framesAvail = mServerProxy->framesAvailableIn_l(); if (CC_LIKELY(framesAvail)) { uint32_t s = cblk->server; @@ -1761,27 +1752,21 @@ void AudioFlinger::RecordThread::RecordTrack::destroy() /*static*/ void AudioFlinger::RecordThread::RecordTrack::appendDumpHeader(String8& result) { - result.append(" Clien Fmt Chn mask Session Step S SRate Serv User FrameCount\n"); + result.append(" Clien Fmt Chn mask Session Step S Serv User FrameCount\n"); } void AudioFlinger::RecordThread::RecordTrack::dump(char* buffer, size_t size) { - snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %05u %08x %08x %05d\n", + snprintf(buffer, size, " %05d %03u 0x%08x %05d %04u %01d %08x %08x %05d\n", (mClient == 0) ? getpid_cached : mClient->pid(), mFormat, mChannelMask, mSessionId, mStepCount, mState, - mCblk->sampleRate, mCblk->server, mCblk->user, mFrameCount); } -bool AudioFlinger::RecordThread::RecordTrack::isOut() const -{ - return false; -} - }; // namespace android -- cgit v1.1