diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2013-11-22 10:35:20 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2013-11-22 10:35:20 -0800 |
commit | 5bf2560ce9b70bee077e0c264ac06648f0f63acc (patch) | |
tree | f17ecec5321e8d583d045135f29f14f3c7418e71 /include/private/media | |
parent | eb76f318e9daf91dbf195bcb74852b3bd736a32a (diff) | |
parent | b2059ff384eee8ffb70a7ec8fc5570405201c734 (diff) | |
download | frameworks_av-5bf2560ce9b70bee077e0c264ac06648f0f63acc.zip frameworks_av-5bf2560ce9b70bee077e0c264ac06648f0f63acc.tar.gz frameworks_av-5bf2560ce9b70bee077e0c264ac06648f0f63acc.tar.bz2 |
Merge commit 'b2059ff384eee8ffb70a7ec8fc5570405201c734' into HEAD
Diffstat (limited to 'include/private/media')
-rw-r--r-- | include/private/media/AudioTrackShared.h | 426 |
1 files changed, 298 insertions, 128 deletions
diff --git a/include/private/media/AudioTrackShared.h b/include/private/media/AudioTrackShared.h index 41e20f8..395f164 100644 --- a/include/private/media/AudioTrackShared.h +++ b/include/private/media/AudioTrackShared.h @@ -22,32 +22,51 @@ #include <utils/threads.h> #include <utils/Log.h> +#include <utils/RefBase.h> +#include <media/nbaio/roundup.h> +#include <media/SingleStateQueue.h> +#include <private/media/StaticAudioTrackState.h> namespace android { // ---------------------------------------------------------------------------- -// Maximum cumulated timeout milliseconds before restarting audioflinger thread -#define MAX_STARTUP_TIMEOUT_MS 3000 // Longer timeout period at startup to cope with A2DP - // init time -#define MAX_RUN_TIMEOUT_MS 1000 -#define WAIT_PERIOD_MS 10 - -#define CBLK_UNDERRUN 0x01 // set: underrun (out) or overrrun (in), clear: no underrun or overrun +// for audio_track_cblk_t::mFlags +#define CBLK_UNDERRUN 0x01 // set by server immediately on output underrun, cleared by client #define CBLK_FORCEREADY 0x02 // set: track is considered ready immediately by AudioFlinger, // clear: track is ready when buffer full #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 +#define CBLK_DISABLED 0x08 // output track disabled by AudioFlinger due to underrun, + // need to re-start. Unlike CBLK_UNDERRUN, this is not set + // immediately, but only after a long string of underruns. +// 0x10 unused +#define CBLK_LOOP_CYCLE 0x20 // set by server each time a loop cycle other than final one completes +#define CBLK_LOOP_FINAL 0x40 // set by server when the final loop cycle completes +#define CBLK_BUFFER_END 0x80 // set by server when the position reaches end of buffer if not looping +#define CBLK_OVERRUN 0x100 // set by server immediately on input overrun, cleared by client +#define CBLK_INTERRUPT 0x200 // set by client on interrupt(), cleared by client in obtainBuffer() +#define CBLK_STREAM_END_DONE 0x400 // set by server on render completion, cleared by client + +//EL_FIXME 20 seconds may not be enough and must be reconciled with new obtainBuffer implementation +#define MAX_RUN_OFFLOADED_TIMEOUT_MS 20000 //assuming upto a maximum of 20 seconds of offloaded struct AudioTrackSharedStreaming { // similar to NBAIO MonoPipe - volatile int32_t mFront; - volatile int32_t mRear; + // in continuously incrementing frame units, take modulo buffer size, which must be a power of 2 + volatile int32_t mFront; // read by server + volatile int32_t mRear; // write by client + volatile int32_t mFlush; // incremented by client to indicate a request to flush; + // server notices and discards all data between mFront and mRear + volatile uint32_t mUnderrunFrames; // server increments for each unavailable but desired frame }; -// future +typedef SingleStateQueue<StaticAudioTrackState> StaticAudioTrackSingleStateQueue; + struct AudioTrackSharedStatic { - int mReserved; + StaticAudioTrackSingleStateQueue::Shared + mSingleStateQueue; + size_t mBufferPosition; // updated asynchronously by server, + // "for entertainment purposes only" }; // ---------------------------------------------------------------------------- @@ -55,65 +74,63 @@ struct AudioTrackSharedStatic { // Important: do not add any virtual methods, including ~ struct audio_track_cblk_t { + // 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(); + /*virtual*/ ~audio_track_cblk_t() { } + friend class Proxy; + friend class ClientProxy; friend class AudioTrackClientProxy; friend class AudioRecordClientProxy; friend class ServerProxy; + friend class AudioTrackServerProxy; + friend class AudioRecordServerProxy; // The data members are grouped so that members accessed frequently and in the same context // are in the same line of data cache. - Mutex lock; // sizeof(int) - Condition cv; // sizeof(int) - // next 4 are offsets within "buffers" - volatile uint32_t user; - volatile uint32_t server; - uint32_t userBase; - uint32_t serverBase; - - int mPad1; // unused, but preserves cache line alignment + uint32_t mServer; // Number of filled frames consumed by server (mIsOut), + // or filled frames provided by server (!mIsOut). + // It is updated asynchronously by server without a barrier. + // The value should be used "for entertainment purposes only", + // which means don't make important decisions based on it. size_t frameCount_; // used during creation to pass actual track buffer size // from AudioFlinger to client, and not referenced again - // FIXME remove here and replace by createTrack() in/out parameter + // FIXME remove here and replace by createTrack() in/out + // parameter // renamed to "_" to detect incorrect use - // Cache line boundary (32 bytes) + volatile int32_t mFutex; // event flag: down (P) by client, + // up (V) by server or binderDied() or interrupt() +#define CBLK_FUTEX_WAKE 1 // if event flag bit is set, then a deferred wake is pending - uint32_t loopStart; - uint32_t loopEnd; // read-only for server, read/write for client - int loopCount; // read/write for client +private: + + size_t mMinimum; // server wakes up client if available >= mMinimum // Channel volumes are fixed point U4.12, so 0x1000 means 1.0. // Left channel is in [0:15], right channel is in [16:31]. // Always read and write the combined pair atomically. // For AudioTrack only, not used by AudioRecord. -private: uint32_t mVolumeLR; 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 - - // used by client only - uint16_t bufferTimeoutMs; // Maximum cumulated timeout before restarting - // audioflinger - - uint16_t waitTimeMs; // Cumulated wait time, used by client only -private: // client write-only, server read-only uint16_t mSendLevel; // Fixed point U4.12 so 0x1000 means 1.0 + + uint16_t mPad2; // unused + public: - volatile int32_t flags; + + volatile int32_t mFlags; // combinations of CBLK_* // Cache line boundary (32 bytes) -#if 0 +public: union { AudioTrackSharedStreaming mStreaming; AudioTrackSharedStatic mStatic; @@ -121,25 +138,6 @@ public: } 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(); - -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, size_t offset) const; - - bool tryLock(); - - // 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); }; // ---------------------------------------------------------------------------- @@ -147,29 +145,32 @@ private: // 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 { +class Proxy : public RefBase { protected: - Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize) - : mCblk(cblk), mBuffers(buffers), mFrameCount(frameCount), mFrameSize(frameSize) { } + Proxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, bool isOut, + bool clientInServer); virtual ~Proxy() { } public: - void* buffer(size_t offset) const { - return mCblk->buffer(mBuffers, mFrameSize, offset); - } + struct Buffer { + size_t mFrameCount; // number of frames available in this buffer + void* mRaw; // pointer to first frame + size_t mNonContig; // number of additional non-contiguous frames available + }; 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 - + 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 + const size_t mFrameCountP2; // mFrameCount rounded to power of 2, streaming mode + const bool mIsOut; // true for AudioTrack, false for AudioRecord + const bool mClientInServer; // true for OutputTrack, false for AudioTrack & AudioRecord + bool mIsShutdown; // latch set to true when shared memory corruption detected + size_t mUnreleased; // unreleased frames remaining from most recent obtainBuffer }; // ---------------------------------------------------------------------------- @@ -177,9 +178,88 @@ protected: // 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) { } + ClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, + bool isOut, bool clientInServer); virtual ~ClientProxy() { } + +public: + static const struct timespec kForever; + static const struct timespec kNonBlocking; + + // Obtain a buffer with filled frames (reading) or empty frames (writing). + // It is permitted to call obtainBuffer() multiple times in succession, without any intervening + // calls to releaseBuffer(). In that case, the final obtainBuffer() is the one that effectively + // sets or extends the unreleased frame count. + // On entry: + // buffer->mFrameCount should be initialized to maximum number of desired frames, + // which must be > 0. + // buffer->mNonContig is unused. + // buffer->mRaw is unused. + // requested is the requested timeout in local monotonic delta time units: + // NULL or &kNonBlocking means non-blocking (zero timeout). + // &kForever means block forever (infinite timeout). + // Other values mean a specific timeout in local monotonic delta time units. + // elapsed is a pointer to a location that will hold the total local monotonic time that + // elapsed while blocked, or NULL if not needed. + // On exit: + // buffer->mFrameCount has the actual number of contiguous available frames, + // which is always 0 when the return status != NO_ERROR. + // buffer->mNonContig is the number of additional non-contiguous available frames. + // buffer->mRaw is a pointer to the first available frame, + // or NULL when buffer->mFrameCount == 0. + // The return status is one of: + // NO_ERROR Success, buffer->mFrameCount > 0. + // WOULD_BLOCK Non-blocking mode and no frames are available. + // TIMED_OUT Timeout occurred before any frames became available. + // This can happen even for infinite timeout, due to a spurious wakeup. + // In this case, the caller should investigate and then re-try as appropriate. + // DEAD_OBJECT Server has died or invalidated, caller should destroy this proxy and re-create. + // -EINTR Call has been interrupted. Look around to see why, and then perhaps try again. + // NO_INIT Shared memory is corrupt. + // Assertion failure on entry, if buffer == NULL or buffer->mFrameCount == 0. + status_t obtainBuffer(Buffer* buffer, const struct timespec *requested = NULL, + struct timespec *elapsed = NULL); + + // Release (some of) the frames last obtained. + // On entry, buffer->mFrameCount should have the number of frames to release, + // which must (cumulatively) be <= the number of frames last obtained but not yet released. + // buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer(). + // It is permitted to call releaseBuffer() multiple times to release the frames in chunks. + // On exit: + // buffer->mFrameCount is zero. + // buffer->mRaw is NULL. + void releaseBuffer(Buffer* buffer); + + // Call after detecting server's death + void binderDied(); + + // Call to force an obtainBuffer() to return quickly with -EINTR + void interrupt(); + + size_t getPosition() { + return mEpoch + mCblk->mServer; + } + + void setEpoch(size_t epoch) { + mEpoch = epoch; + } + + void setMinimum(size_t minimum) { + mCblk->mMinimum = minimum; + } + + // Return the number of frames that would need to be obtained and released + // in order for the client to be aligned at start of buffer + virtual size_t getMisalignment(); + + size_t getEpoch() const { + return mEpoch; + } + + size_t getFramesFilled(); + +private: + size_t mEpoch; }; // ---------------------------------------------------------------------------- @@ -187,8 +267,10 @@ protected: // 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) { } + AudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, + size_t frameSize, bool clientInServer = false) + : ClientProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, + clientInServer) { } virtual ~AudioTrackClientProxy() { } // No barriers on the following operations, so the ordering of loads/stores @@ -208,27 +290,42 @@ public: 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*/); + virtual void flush(); + + virtual uint32_t getUnderrunFrames() const { + return mCblk->u.mStreaming.mUnderrunFrames; } - // called by AudioTrack::obtainBuffer and AudioTrack::processBuffer - size_t framesAvailable() { - return mCblk->framesAvailable(mFrameCount, true /*isOut*/); + bool clearStreamEndDone(); // and return previous value + + bool getStreamEndDone() const; + + status_t waitStreamEndDone(const struct timespec *requested); +}; + +class StaticAudioTrackClientProxy : public AudioTrackClientProxy { +public: + StaticAudioTrackClientProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, + size_t frameSize); + virtual ~StaticAudioTrackClientProxy() { } + + virtual void flush(); + +#define MIN_LOOP 16 // minimum length of each loop iteration in frames + void setLoop(size_t loopStart, size_t loopEnd, int loopCount); + size_t getBufferPosition(); + + virtual size_t getMisalignment() { + return 0; } - // 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*/); + virtual uint32_t getUnderrunFrames() const { + return 0; } +private: + StaticAudioTrackSingleStateQueue::Mutator mMutator; + size_t mBufferPosition; // so that getBufferPosition() appears to be synchronous }; // ---------------------------------------------------------------------------- @@ -236,60 +333,133 @@ public: // 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(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, + size_t frameSize) + : ClientProxy(cblk, buffers, frameCount, frameSize, + false /*isOut*/, false /*clientInServer*/) { } ~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 { +protected: + ServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, size_t frameSize, + bool isOut, bool clientInServer); 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); } + // Obtain a buffer with filled frames (writing) or empty frames (reading). + // It is permitted to call obtainBuffer() multiple times in succession, without any intervening + // calls to releaseBuffer(). In that case, the final obtainBuffer() is the one that effectively + // sets or extends the unreleased frame count. + // Always non-blocking. + // On entry: + // buffer->mFrameCount should be initialized to maximum number of desired frames, + // which must be > 0. + // buffer->mNonContig is unused. + // buffer->mRaw is unused. + // On exit: + // buffer->mFrameCount has the actual number of contiguous available frames, + // which is always 0 when the return status != NO_ERROR. + // buffer->mNonContig is the number of additional non-contiguous available frames. + // buffer->mRaw is a pointer to the first available frame, + // or NULL when buffer->mFrameCount == 0. + // The return status is one of: + // NO_ERROR Success, buffer->mFrameCount > 0. + // WOULD_BLOCK No frames are available. + // NO_INIT Shared memory is corrupt. + virtual status_t obtainBuffer(Buffer* buffer); + + // Release (some of) the frames last obtained. + // On entry, buffer->mFrameCount should have the number of frames to release, + // which must (cumulatively) be <= the number of frames last obtained but not yet released. + // It is permitted to call releaseBuffer() multiple times to release the frames in chunks. + // buffer->mRaw is ignored, but is normally same pointer returned by last obtainBuffer(). + // On exit: + // buffer->mFrameCount is zero. + // buffer->mRaw is NULL. + virtual void releaseBuffer(Buffer* buffer); +protected: + size_t mAvailToClient; // estimated frames available to client prior to releaseBuffer() + int32_t mFlush; // our copy of cblk->u.mStreaming.mFlush, for streaming output only +}; + +// Proxy used by AudioFlinger for servicing AudioTrack +class AudioTrackServerProxy : public ServerProxy { +public: + AudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, + size_t frameSize, bool clientInServer = false) + : ServerProxy(cblk, buffers, frameCount, frameSize, true /*isOut*/, clientInServer) { } +protected: + virtual ~AudioTrackServerProxy() { } + +public: // 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); - } + // estimated total number of filled frames available to server to read, + // which may include non-contiguous frames + virtual size_t framesReady(); - // 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); - } + // Currently AudioFlinger will call framesReady() for a fast track from two threads: + // FastMixer thread, and normal mixer thread. This is dangerous, as the proxy is intended + // to be called from at most one thread of server, and one thread of client. + // As a temporary workaround, this method informs the proxy implementation that it + // should avoid doing a state queue poll from within framesReady(). + // FIXME Change AudioFlinger to not call framesReady() from normal mixer thread. + virtual void framesReadyIsCalledByMultipleThreads() { } + + bool setStreamEndDone(); // and return previous value + + // Add to the tally of underrun frames, and inform client of underrun + virtual void tallyUnderrunFrames(uint32_t frameCount); + + // Return the total number of frames which AudioFlinger desired but were unavailable, + // and thus which resulted in an underrun. + virtual uint32_t getUnderrunFrames() const { return mCblk->u.mStreaming.mUnderrunFrames; } + + // Return the total number of frames that AudioFlinger has obtained and released + virtual size_t framesReleased() const { return mCblk->mServer; } +}; + +class StaticAudioTrackServerProxy : public AudioTrackServerProxy { +public: + StaticAudioTrackServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, + size_t frameSize); +protected: + virtual ~StaticAudioTrackServerProxy() { } + +public: + virtual size_t framesReady(); + virtual void framesReadyIsCalledByMultipleThreads(); + virtual status_t obtainBuffer(Buffer* buffer); + virtual void releaseBuffer(Buffer* buffer); + virtual void tallyUnderrunFrames(uint32_t frameCount); + virtual uint32_t getUnderrunFrames() const { return 0; } private: - const bool mIsOut; // true for AudioTrack, false for AudioRecord + ssize_t pollPosition(); // poll for state queue update, and return current position + StaticAudioTrackSingleStateQueue::Observer mObserver; + size_t mPosition; // server's current play position in frames, relative to 0 + size_t mEnd; // cached value computed from mState, safe for asynchronous read + bool mFramesReadyIsCalledByMultipleThreads; + StaticAudioTrackState mState; +}; +// Proxy used by AudioFlinger for servicing AudioRecord +class AudioRecordServerProxy : public ServerProxy { +public: + AudioRecordServerProxy(audio_track_cblk_t* cblk, void *buffers, size_t frameCount, + size_t frameSize) + : ServerProxy(cblk, buffers, frameCount, frameSize, false /*isOut*/, + false /*clientInServer*/) { } +protected: + virtual ~AudioRecordServerProxy() { } }; // ---------------------------------------------------------------------------- |