⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 beaudio.cxx

📁 安装 H323需要的pwlib库
💻 CXX
📖 第 1 页 / 共 4 页
字号:
BOOL PSound::PlayFile(const PFilePath & file, BOOL wait){	entry_ref 			ref;	status_t			err; // can't use dwLastError because this function is static	// using pointers for these objects so that we don't have to	// construct them here but can nevertheless use the if(ok)'s	BEntry 			   *pentry = NULL;		{		// Create BEntry from file name		pentry = new BEntry(file, true);		err = pentry->InitCheck();	}	if (err==B_OK)	{		// Create entry_ref from BEntry			err = pentry->GetRef(&ref);	}		if (err==B_OK)	{		// Play the sound. Return value is a handle or a negative value for errors		// Errors in BeOS are always negative values		err=play_sound(&ref, true, !wait, wait);		if (err>=0)		{			err=B_OK;		}	}	return (err==B_OK);}void PSound::Beep(){	::beep();}////////////////////////////////////////////////////////////////////////////////// CircularBufferclass Guard{private:	sem_id mSem;public:	Guard(sem_id sem) { acquire_sem(mSem=sem); }	~Guard() { release_sem(mSem); }};/*	This class represents a circular FIFO buffer.	The buffer has a head and a tail that chase each other.	The data is added to the buffer at the tail side by using Fill.	The data from the buffer can be read starting at the head side using	Drain.	It is possible to use two threads to fill and drain the buffer but	there should not be more than 2 threads doing draining and filling.	Resetting (flushing) or destroying from a third thread is allowed;	do make sure that any threads that operate on buffer data are stopped	before destroying a buffer.	Normally, filling and draining operations block the thread as short as	possible (i.e. only when the other thread needs to update the head and	tail pointers etc). If the filling thread tries to put data into a full	or almost full buffer, it just returns after filling as much data as	it can, and if the draining thread tries to get more data out than is	in the buffer, it will simply return with the data that is there.	In order to move all the data from an external buffer into an object	of this class, the caller would have to call Fill repeatedly until	all the data has been processed (similarly it would have to call Drain	until it receives sufficient data). But if the application has nothing	else to do in the mean time, this constitutes a Busy Waiting loop	on either the filling or draining side of the FIFO buffer that slurps	up as much CPU time as possible.	To improve this behaviour, it's possible to specify a threshold value	that is used to change the state to FullEnough and EmptyEnough. By using	these states (instead of Full and Empty), one thread can block until the	other thread has determined that there is enough data or enough room for	data.*/class CircularBuffer{public:	// Internal state for the buffer	// Note the nifty bit patterns for comparing the current state	// with a desired state	typedef enum	{							// Headspace		Tailspace		Empty			=1,		// 0                size		Filled			=2,		// 0<h<size			0<t<size		NotFull			=3,		// 0<=h<size		0<t<=size	(for comparing)		Full			=4,		// size				0		NotEmpty		=6,		// 0<h<=size		0<=t<size	(for comparing)		Flushed     	=8,		// 								(extra signal to threads waiting on full)		FullEnough		=16,	// h>=drainthreshold		EmptyEnough		=32,	//                  t>=fillthreshold	} State;protected:	friend class ResamplingBuffer; // needed for one of their constructors	BYTE		   *mBuffer;			// the buffer	PINDEX			mSize;				// size of the buffer in bytes		volatile PINDEX	mHead;				// index where to start reading	volatile PINDEX	mTail;				// index where to start writing	volatile PINDEX	mHeadRoom;			// consecutive space from head to end-of-buffer or tail	volatile PINDEX	mTailRoom;			// consecutive space from tail to end-of-buffer or head	volatile PINDEX mSizeUsed;			// total bytes in use	volatile PINDEX mFillThreshold;		// see above	volatile PINDEX mDrainThreshold;	// see above	volatile State	mState;				// current state of the buffer	sem_id			mSemInUse;			// used to guard data integrity	sem_id			mSemStateChange;	// used to wait for state changesprotected:	// Check if the state changed. Private because it's not guarded by semaphore	void UpdateState(void)	{		// Determine current state		State newstate;				if (mSizeUsed==mSize)		{			PRINTCB(("State is FULL"));			newstate=Full;		}		else if (mSizeUsed==0)		{			PRINTCB(("State is EMPTY"));			newstate=Empty;		}		else		{			PRINTCB(("State is FILLED"));			newstate=Filled;		}				// Check thresholds		if (mSize-mSizeUsed>=mFillThreshold)		{			PRINTCB(("...and EMPTYENOUGH"));			newstate=(State)(newstate | EmptyEnough);		}		if (mSizeUsed>=mDrainThreshold)		{			PRINTCB(("...and FULLENOUGH"));			newstate=(State)(newstate | FullEnough);		}				// Check if the state changed		if (newstate!=mState)		{			PRINTCB(("Updating state from %X to %X", mState, newstate));						// Set the new state			mState=newstate;						// Signal state change			release_sem(mSemStateChange);		}	}	virtual size_t Write(		BYTE *dest,					// destination		const BYTE **extbuf,		// source, to be updated		size_t size,				// space in destination		size_t *extsize)			// data in source, to be updated	{		// This function is called to put data into the buffer		size_t todo=MIN(size, *extsize);		memcpy(dest, *extbuf, todo);		*extbuf   +=todo; // The external pointer moves forward...		*extsize  -=todo; // ... so the remaining size decreases		return todo;	}		virtual size_t Read(		BYTE **extbuf,				// destination, to be updated		const BYTE *src,			// source		size_t *extsize,			// space in destination, to be updated		size_t size)				// data in source	{		// This function is called to read data out of the buffer		size_t todo=MIN(size, *extsize);		memcpy(*extbuf, src, todo);		*extbuf   +=todo; // The external pointer moves forward...		*extsize  -=todo; // ... so the remaining size decreases		return todo;	}	public:	// Reset buffer so that it can be filled again	void Reset(void)	{		Guard _(mSemInUse); // guard data integrity		mHead=mHeadRoom=mTail=mSizeUsed=0;		mTailRoom=GetSize();		mState=(State)(Flushed|Empty|EmptyEnough);	}	// Constructor	CircularBuffer(		PINDEX size,		PINDEX fillthreshold = 0,		PINDEX drainthreshold = 0) 	: mFillThreshold(fillthreshold), mDrainThreshold(drainthreshold), mState(Empty)	{		PAssert(size!=0, "Attempting to create a buffer with size 0");				mSemInUse=create_sem(1, "mSemInUse");		mSemStateChange=create_sem(0, "mSemStateChange");				PAssert(mSemInUse>=0 && mSemStateChange>=0, "Unable to create semaphores");				mBuffer=new BYTE[(mSize=size)];				Reset();	}	// Destructor	virtual ~CircularBuffer()	{	  // make sure the in-use semaphore is free and stays free	  while (acquire_sem_etc(mSemInUse,1,B_RELATIVE_TIMEOUT,0)==B_WOULD_BLOCK)	  {	    // nothing to do, just busy-wait	  }	  delete_sem(mSemInUse);		  delete_sem(mSemStateChange);		  Reset();			  if(mBuffer)	    delete[] mBuffer;	}	// Check if buffer is empty	bool IsEmpty() { return (mState==Empty); }		// Check if buffer is full	bool IsFull() { return (mState==Full); }		// Get the size of the buffer	PINDEX GetSize(void) { return mSize; }	// Wait asynchronously for a buffer state or one of a number of states	void WaitForState(State state)	{		PRINTCB(("Waiting for state %X, current state=%X this=%p", state, mState, this));		// reset the Flushed bit so it only stops the loop if the buffer		// is flushed DURING an operation		{			Guard _(mSemInUse);			mState=(State)(mState & ~Flushed);		}		for(;;)		{			if ((mState & (state|Flushed))!=0) // bit patterns allowed			{				PRINTCB(("Detected state %X, wanted %X, returning", mState, state));				return;			}			PRINTCB(("Waiting for %X; headroom=%u tailroom=%u this=%p",state,mHeadRoom,mTailRoom,this));			// To prevent a race condition here in case the state			// gets changed just after the GetState call, the next			// semaphore call has a timeout.			acquire_sem_etc(mSemStateChange,1,B_RELATIVE_TIMEOUT,1000000);		}	}		// Fill buffer with data.	void Fill(const BYTE **extbuf, size_t *extsize)	{		PRINTCB(("start: head %d tail %d headroom %d tailroom %d extsize %d buffer %p this %p", mHead, mTail, mHeadRoom, mTailRoom, *extsize, mBuffer, this));		// Make a local copy of the queue.		// This is ok because there is only one filler thread and		// one drainer thread. The drainer is not going to make the		// free area for the filler any smaller and the filler is not		// going to overwrite the drainer's data if we do this.		// This way we can keep the semaphore busy as short as possible.		PINDEX lTail;		PINDEX lTailRoom;		PINDEX lHead; // read only		{			Guard _(mSemInUse); // guard data integrity			lTail=mTail;			lTailRoom=mTailRoom;			lHead=mHead;		}				bool needhousekeeping=false;		PINDEX totaldone=0;				while (*extsize!=0 && lTailRoom!=0 && totaldone<mSize)		{			needhousekeeping=true;						PINDEX done=Write(				mBuffer+lTail,				extbuf,			    lTailRoom,				extsize);						totaldone +=done;						lTail     +=done; // The tail moves forward...			lTailRoom -=done; // ... so there will be less room at the tail			// Check if we should wrap around			if (lTail==mSize)			{				lTail=0;				lTailRoom=lHead;			}		}		if (needhousekeeping)		{			Guard _(mSemInUse);						// Copy the local values back			mTail=lTail;			mTailRoom=lTailRoom;			mSizeUsed+=totaldone;						// Recalculate headroom			if (mTail>mHead)			{				mHeadRoom=mTail-mHead;			}			else			{				mHeadRoom=mSize-mHead;			}			// Check if we need to change the state			UpdateState();			PRINTCB(("  end: head %d tail %d headroom %d tailroom %d extsize %d", mHead, mTail, mHeadRoom, mTailRoom, *extsize));		}	}	// Empty data out of buffer	void Drain(BYTE **extbuf, size_t *extsize)	{		PTRACE(7, "Drain: head " << mHead 	    << " tail " << mTail 	    << " headroom " << mHeadRoom 	    << " tailroom " << mTailRoom 	    << " extsize " << *extsize	    << " buffer " << mBuffer	    << " this " << this);		// Make a local copy of the queue.		// This is ok because there is only one filler thread and		// one drainer thread. The drainer is not going to make the		// free area for the filler any smaller and the filler is not		// going to overwrite the drainer's data if we do this.		// This way we can keep the semaphore busy as short as possible.		PINDEX lHead;		PINDEX lHeadRoom;		PINDEX lTail; // read only		{			Guard _(mSemInUse); // guard data integrity			lHead=mHead;			lHeadRoom=mHeadRoom;			lTail=mTail;		}		bool needhousekeeping=false;		PINDEX totaldone=0;				while (*extsize!=0 && lHeadRoom!=0 && totaldone<mSize)		{			needhousekeeping=true;						size_t done=Read(				extbuf,				mBuffer+lHead,				extsize,				lHeadRoom);							totaldone +=done;						lHead     +=done; // The head moves forward...			lHeadRoom -=done; // ... so there will be less room at the head					// Check if we should wrap around			if (lHead==mSize)			{				lHead=0;				lHeadRoom=mTail;			}		}		if (needhousekeeping)		{			Guard _(mSemInUse);						// Copy the local values back			mHead=lHead;			mHeadRoom=lHeadRoom;			mSizeUsed-=totaldone;						// Recalculate tailroom			if (mHead>mTail)			{				mTailRoom=mHead-mTail;			}			else			{				mTailRoom=GetSize()-mTail;			}						// Check if we need to change the state			UpdateState();			PRINTCB(("  end: head %d tail %d headroom %d tailroom %d extsize %d", mHead, mTail, mHeadRoom, mTailRoom, *extsize));		}	}};////////////////////////////////////////////////////////////////////////////////class ResamplingBuffer : public CircularBuffer{protected:	Resampler	   *mResampler;	protected:	virtual size_t Write(		BYTE *dest,					// destination		const BYTE **extbuf,		// source, to be updated		size_t size,				// space in destination		size_t *extsize)			// data in source, to be updated	{		size_t todo=*extsize/mResampler->InFrameSize();		size_t done=mResampler->InFrames(			(const short **)extbuf,			(short **)&dest,			&todo,			size/mResampler->OutFrameSize());		done*=mResampler->OutFrameSize();		*extsize=todo*mResampler->InFrameSize();				return done;	}	public:	void SetResampler(Resampler *resampler)	{		Guard _(mSemInUse); // guard data integrity				mResampler=resampler;	}	ResamplingBuffer(		Resampler *resampler,		PINDEX size,		PINDEX fillthreshold=0,		PINDEX drainthreshold=0) 		: CircularBuffer(size, fillthreshold, drainthreshold), mResampler(NULL)	{		SetResampler(resampler);	}	ResamplingBuffer(		Resampler *resampler,		CircularBuffer *other) 	  : CircularBuffer(other->mSize, other->mFillThreshold, other->mDrainThreshold), mResampler(NULL)	{		SetResampler(resampler);	}};////////////////////////////////////////////////////////////////////////////////static void PlayBuffer(void *cookie, void *buffer, size_t size, const media_raw_audio_format &format){	// This function is called by the BSoundPlayer object whenever it needs some more	// data to play.	DETECTVARS(buffer, size/2)	((CircularBuffer *)cookie)->Drain((BYTE **)&buffer, &size);		DETECTSOUND();}static void RecordBuffer(void *cookie, const void *buffer, size_t size, const media_header &header){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -