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 --- include/private/media/AudioTrackShared.h | 228 +++++++++++++++++++++++++------ 1 file changed, 183 insertions(+), 45 deletions(-) (limited to 'include/private/media') diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 48b6b21..41e20f8 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -21,6 +21,7 @@ #include #include +#include namespace android { @@ -38,9 +39,26 @@ namespace android { #define CBLK_INVALID 0x04 // track buffer invalidated by AudioFlinger, need to re-create #define CBLK_DISABLED 0x08 // track disabled by AudioFlinger due to underrun, need to re-start +struct AudioTrackSharedStreaming { + // similar to NBAIO MonoPipe + volatile int32_t mFront; + volatile int32_t mRear; +}; + +// future +struct AudioTrackSharedStatic { + int mReserved; +}; + +// ---------------------------------------------------------------------------- + // Important: do not add any virtual methods, including ~ struct audio_track_cblk_t { + friend class Proxy; + friend class AudioTrackClientProxy; + friend class AudioRecordClientProxy; + friend class ServerProxy; // The data members are grouped so that members accessed frequently and in the same context // are in the same line of data cache. @@ -72,12 +90,13 @@ struct audio_track_cblk_t // For AudioTrack only, not used by AudioRecord. private: uint32_t mVolumeLR; -public: - uint32_t sampleRate; + uint32_t mSampleRate; // AudioTrack only: client's requested sample rate in Hz + // or 0 == default. Write-only client, read-only server. uint8_t mPad2; // unused +public: // read-only for client, server writes once at initialization and is then read-only uint8_t mName; // normal tracks: track name, fast tracks: track index @@ -94,65 +113,184 @@ public: // Cache line boundary (32 bytes) +#if 0 + union { + AudioTrackSharedStreaming mStreaming; + AudioTrackSharedStatic mStatic; + int mAlign[8]; + } u; + + // Cache line boundary (32 bytes) +#endif + // Since the control block is always located in shared memory, this constructor // is only used for placement new(). It is never used for regular new() or stack. audio_track_cblk_t(); - // called by client only, where client includes regular - // AudioTrack and AudioFlinger::PlaybackThread::OutputTrack - uint32_t stepUserIn(size_t stepCount, size_t frameCount) { return stepUser(stepCount, frameCount, false); } - uint32_t stepUserOut(size_t stepCount, size_t frameCount) { return stepUser(stepCount, frameCount, true); } - - bool stepServer(size_t stepCount, size_t frameCount, bool isOut); - +private: // if there is a shared buffer, "buffers" is the value of pointer() for the shared // buffer, otherwise "buffers" points immediately after the control block - void* buffer(void *buffers, uint32_t frameSize, uint32_t offset) const; - - uint32_t framesAvailableIn(size_t frameCount) - { return framesAvailable(frameCount, false); } - uint32_t framesAvailableOut(size_t frameCount) - { return framesAvailable(frameCount, true); } - uint32_t framesAvailableIn_l(size_t frameCount) - { return framesAvailable_l(frameCount, false); } - uint32_t framesAvailableOut_l(size_t frameCount) - { return framesAvailable_l(frameCount, true); } - uint32_t framesReadyIn() { return framesReady(false); } - uint32_t framesReadyOut() { return framesReady(true); } + void* buffer(void *buffers, uint32_t frameSize, size_t offset) const; bool tryLock(); - // No barriers on the following operations, so the ordering of loads/stores - // with respect to other parameters is UNPREDICTABLE. That's considered safe. - - // for AudioTrack client only, caller must limit to 0.0 <= sendLevel <= 1.0 - void setSendLevel(float sendLevel) { - mSendLevel = uint16_t(sendLevel * 0x1000); - } - - // for AudioFlinger only; the return value must be validated by the caller - uint16_t getSendLevel_U4_12() const { - return mSendLevel; - } - - // for AudioTrack client only, caller must limit to 0 <= volumeLR <= 0x10001000 - void setVolumeLR(uint32_t volumeLR) { - mVolumeLR = volumeLR; - } - - // for AudioFlinger only; the return value must be validated by the caller - uint32_t getVolumeLR() const { - return mVolumeLR; - } - -private: // isOut == true means AudioTrack, isOut == false means AudioRecord + bool stepServer(size_t stepCount, size_t frameCount, bool isOut); uint32_t stepUser(size_t stepCount, size_t frameCount, bool isOut); uint32_t framesAvailable(size_t frameCount, bool isOut); uint32_t framesAvailable_l(size_t frameCount, bool isOut); uint32_t framesReady(bool isOut); }; +// ---------------------------------------------------------------------------- + +// Proxy for shared memory control block, to isolate callers from needing to know the details. +// There is exactly one ClientProxy and one ServerProxy per shared memory control block. +// The proxies are located in normal memory, and are not multi-thread safe within a given side. +class Proxy { +protected: + Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize) + : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize) { } + virtual ~Proxy() { } + +public: + void* buffer(size_t offset) const { + return mCblk->buffer(mBuffers, mFrameSize, offset); + } + +protected: + // These refer to shared memory, and are virtual addresses with respect to the current process. + // They may have different virtual addresses within the other process. + audio_track_cblk_t* const mCblk; // the control block + void* const mBuffers; // starting address of buffers + + const size_t mFrameCount; // not necessarily a power of 2 + const size_t mFrameSize; // in bytes +#if 0 + const size_t mFrameCountP2; // mFrameCount rounded to power of 2, streaming mode +#endif + +}; + +// ---------------------------------------------------------------------------- + +// Proxy seen by AudioTrack client and AudioRecord client +class ClientProxy : public Proxy { +protected: + ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize) + : Proxy(cblk, buffers, frameCount, frameSize) { } + virtual ~ClientProxy() { } +}; + +// ---------------------------------------------------------------------------- + +// Proxy used by AudioTrack client, which also includes AudioFlinger::PlaybackThread::OutputTrack +class AudioTrackClientProxy : public ClientProxy { +public: + AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize) + : ClientProxy(cblk, buffers, frameCount, frameSize) { } + virtual ~AudioTrackClientProxy() { } + + // No barriers on the following operations, so the ordering of loads/stores + // with respect to other parameters is UNPREDICTABLE. That's considered safe. + + // caller must limit to 0.0 <= sendLevel <= 1.0 + void setSendLevel(float sendLevel) { + mCblk->mSendLevel = uint16_t(sendLevel * 0x1000); + } + + // caller must limit to 0 <= volumeLR <= 0x10001000 + void setVolumeLR(uint32_t volumeLR) { + mCblk->mVolumeLR = volumeLR; + } + + void setSampleRate(uint32_t sampleRate) { + mCblk->mSampleRate = sampleRate; + } + + // called by: + // PlaybackThread::OutputTrack::write + // AudioTrack::createTrack_l + // AudioTrack::releaseBuffer + // AudioTrack::reload + // AudioTrack::restoreTrack_l (2 places) + size_t stepUser(size_t stepCount) { + return mCblk->stepUser(stepCount, mFrameCount, true /*isOut*/); + } + + // called by AudioTrack::obtainBuffer and AudioTrack::processBuffer + size_t framesAvailable() { + return mCblk->framesAvailable(mFrameCount, true /*isOut*/); + } + + // called by AudioTrack::obtainBuffer and PlaybackThread::OutputTrack::obtainBuffer + // FIXME remove this API since it assumes a lock that should be invisible to caller + size_t framesAvailable_l() { + return mCblk->framesAvailable_l(mFrameCount, true /*isOut*/); + } + +}; + +// ---------------------------------------------------------------------------- + +// Proxy used by AudioRecord client +class AudioRecordClientProxy : public ClientProxy { +public: + AudioRecordClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize) + : ClientProxy(cblk, buffers, frameCount, frameSize) { } + ~AudioRecordClientProxy() { } + + // called by AudioRecord::releaseBuffer + size_t stepUser(size_t stepCount) { + return mCblk->stepUser(stepCount, mFrameCount, false /*isOut*/); + } + + // called by AudioRecord::processBuffer + size_t framesAvailable() { + return mCblk->framesAvailable(mFrameCount, false /*isOut*/); + } + + // called by AudioRecord::obtainBuffer + size_t framesReady() { + return mCblk->framesReady(false /*isOut*/); + } + +}; + +// ---------------------------------------------------------------------------- + +// Proxy used by AudioFlinger server +class ServerProxy : public Proxy { +public: + ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut) + : Proxy(cblk, buffers, frameCount, frameSize), mIsOut(isOut) { } + virtual ~ServerProxy() { } + + // for AudioTrack and AudioRecord + bool step(size_t stepCount) { return mCblk->stepServer(stepCount, mFrameCount, mIsOut); } + + // return value of these methods must be validated by the caller + uint32_t getSampleRate() const { return mCblk->mSampleRate; } + uint16_t getSendLevel_U4_12() const { return mCblk->mSendLevel; } + uint32_t getVolumeLR() const { return mCblk->mVolumeLR; } + + // for AudioTrack only + size_t framesReady() { + ALOG_ASSERT(mIsOut); + return mCblk->framesReady(true); + } + + // for AudioRecord only, called by RecordThread::RecordTrack::getNextBuffer + // FIXME remove this API since it assumes a lock that should be invisible to caller + size_t framesAvailableIn_l() { + ALOG_ASSERT(!mIsOut); + return mCblk->framesAvailable_l(mFrameCount, false); + } + +private: + const bool mIsOut; // true for AudioTrack, false for AudioRecord + +}; // ---------------------------------------------------------------------------- -- cgit v1.1