/*============================================================================= CABufferQueue.h $Log: CABufferQueue.h,v $ Revision 1.4 2004/12/16 23:26:39 dwyatt fix warning Revision 1.3 2004/12/15 23:18:35 dwyatt add debug print code Revision 1.2 2004/05/26 00:34:43 dwyatt get rid of the lock on the work thread's queue Revision 1.1 2004/01/14 00:08:09 dwyatt moved from Source/Tests/AudioFileUtility/Utility Revision 1.1 2003/10/15 00:27:11 dwyatt initial checkin created Fri Oct 10 2003, Doug Wyatt Copyright (c) 2003 Apple Computer, Inc. All Rights Reserved $NoKeywords: $ =============================================================================*/ #ifndef __CABufferQueue_h__ #define __CABufferQueue_h__ #include "CAPThread.h" #include "CAGuard.h" #include "CAStreamBasicDescription.h" #include "CABufferList.h" #include #include "CAAtomicFIFO.h" // ____________________________________________________________________________ // Abstraction for moving audio buffers between threads. // Has abstract subclasses for push and pull. class CABufferQueue { friend class CAPushBufferQueue; friend class CAPullBufferQueue; public: CABufferQueue(int nBuffers, UInt32 bufferSizeFrames); virtual ~CABufferQueue(); void SetFormat(const CAStreamBasicDescription &fmt); UInt32 GetBufferSizeFrames() const { return mBufferSizeFrames; } int ErrorCount() const { return mErrorCount; } // ----- class Buffer { public: Buffer(CABufferQueue *owner, const CAStreamBasicDescription &fmt, UInt32 nBytes); ~Buffer() { delete mMemory; } CABufferQueue * Queue() { return mQueue; } CABufferList * GetBufferList() { return mMemory; } UInt32 FrameCount() { return mEndFrame - mStartFrame; } void SetEmpty() { mStartFrame = mEndFrame = 0; } void SetInProgress(bool b) { mInProgress = b; } bool InProgress() const { return mInProgress; } bool ReachedEndOfStream() const { return mEndOfStream; } bool CopyInto(AudioBufferList *destBufferList, int bytesPerFrame, UInt32 &framesProduced, UInt32 &framesRequired); // return true if buffer emptied bool CopyFrom(const AudioBufferList *srcBufferList, int bytesPerFrame, UInt32 &framesProduced, UInt32 &framesRequired); // return true if buffer filled and not end-of-stream Buffer * get_next() { return mNext; } void set_next(Buffer *b) { mNext = b; } #if DEBUG void print() { printf("Buffer %p:\n inProgress %d, endOfStream %d, frames %ld-%ld\n", this, mInProgress, mEndOfStream, mStartFrame, mEndFrame); } #endif protected: Buffer * mNext; CABufferQueue * mQueue; CABufferList * mMemory; UInt32 mByteSize; bool mInProgress; // true if in the work queue bool mEndOfStream; // true if the operation resulted in end-of-stream UInt32 mStartFrame, mEndFrame; // produce/consume pointers within the buffer }; #if DEBUG void print() { printf("BufferQueue %p\n mCurrentBuffer=%d\n", this, mCurrentBuffer); if (mBuffers) for (int i = 0; i < mNumberBuffers; ++i) { Buffer *b = mBuffers[i]; printf(" buffer[%d]: ", i); if (b) b->print(); else printf("NULL\n"); } } #endif protected: virtual Buffer * CreateBuffer(const CAStreamBasicDescription &fmt, UInt32 nBytes) = 0; virtual void ProcessBuffer(Buffer *b) = 0; void CancelBuffers(); void CancelAndDisposeBuffers(); CABufferList * GetBufferList() { return mBufferList; } const Buffer * GetCurrentBuffer() const { return mBuffers[mCurrentBuffer]; } UInt32 GetBytesPerFrame() const { return mBytesPerFrame; } private: // ----- class WorkThread : public CAPThread { public: WorkThread(); static void * ThreadEntry(void *param) { static_cast(param)->Run(); return NULL; } void Run(); void Stop(); void AddBuffer(Buffer *buffer); void RemoveBuffers(CABufferQueue *owner); private: typedef std::list WorkQueue; bool mStopped; WorkQueue mWorkQueue; CAGuard mRunGuard; TStack mBuffersToAdd; }; static WorkThread * sWorkThread; // ----- private: WorkThread * mWorkThread; int mCurrentBuffer; int mNumberBuffers; Buffer ** mBuffers; // array of pointers UInt32 mBufferSizeFrames; UInt32 mBytesPerFrame; // function of client format CABufferList * mBufferList; // maintained in SetFormat protected: int mErrorCount; }; // ____________________________________________________________________________ // Abstract class. // The client pushes buffers in; they are consumed (via ProcessBuffer) on the work thread. // (ex: file recorder) class CAPushBufferQueue : public CABufferQueue { public: CAPushBufferQueue(int nBuffers, UInt32 bufferSizeFrames) : CABufferQueue(nBuffers, bufferSizeFrames) { } void PushBuffer(UInt32 inNumberFrames, const AudioBufferList *inBufferList); // push a buffer in void Flush(); // emit a possibly incomplete final buffer }; // ____________________________________________________________________________ // Abstract class. // The client pulls buffers out; they are produced (via ProcessBuffer) on the work thread. // (ex: file player) class CAPullBufferQueue : public CABufferQueue { public: CAPullBufferQueue(int nBuffers, UInt32 bufferSizeFrames) : CABufferQueue(nBuffers, bufferSizeFrames), mEndOfStream(false) { } void Prime(); // produce initial buffers void PullBuffer(UInt32 &ioFrames, AudioBufferList *outBufferList); // pull a buffer out bool ReachedEndOfStream() const { return mEndOfStream; } protected: bool mEndOfStream; }; #endif // __CABufferQueue_h__