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

📄 soundinput.cxx

📁 基于VXWORKS H323通信技术源代码
💻 CXX
字号:
//
// (c) Yuri Kiryanov, home.att.net/~bevox
// for www.Openh323.org
//
// Portions Be, Inc.
//
// resample needed some stuff
#include "SoundInput.h"

#define MAX_SOUND_FILE_SIZE (3 * 1024 * 1024)

static const char* gsNotifyCodes[] = {
	"",
	"B_WILL_START",
	"B_WILL_STOP"
	"B_WILL_SEEK",
	"B_WILL_TIMEWARP"
	"B_CONNECTED",
	"B_DISCONNECTED",
	"B_FORMAT_CHANGED",
	"B_NODE_DIES",
	"B_HOOKS_CHANGED",
	"B_OP_TIMED_OUT",
	"B_PRODUCER_DATA_STATUS",
	"B_LATE_NOTICE",
};

PSoundInput::PSoundInput(PSoundChannel* pChannel) :
	SoundConsumer("PWLSoundInput", NULL, NULL, pChannel), 
			BMediaNode("PWLSoundInput"), mpChannel(pChannel), 
			mpSound(NULL), bytesToWrite(0)
{ 
	m_roster = BMediaRoster::Roster(&mError);
	if( m_roster )
	{
		mError = m_roster->GetAudioInput(&m_audioInputNode);
		if (mError == B_OK) 
		{
			mError = m_roster->RegisterNode(this);
		}
	}

}

bool PSoundInput::StartRecording() 
{
	//	Find an available output for the given input node.
	int32 count = 0;
	mError = m_roster->GetFreeOutputsFor(m_audioInputNode, 
			&m_audioOutput, 1, &count, B_MEDIA_RAW_AUDIO);
	if (mError == B_OK && count >= 0 ) 
	{
		//	Find an available input for our own Node. 
		mError = m_roster->GetFreeInputsFor(Node(), &m_recInput, 1, &count, B_MEDIA_RAW_AUDIO);
		if (mError == B_OK && count >=0 ) 
		{
			//	Get a format, any format.
			media_format fmt;
			fmt.u.raw_audio = m_audioOutput.format.u.raw_audio;
			fmt.type = B_MEDIA_RAW_AUDIO;

			// Resample this rate to 8000
			mResampler.Create(fmt.u.raw_audio.frame_rate, 8000,
				fmt.u.raw_audio.channel_count, (fmt.u.raw_audio.format & 0xf)*8);
	
			//	Using the same structs for input and output is OK in BMediaRoster::Connect().
			mError = m_roster->Connect(m_audioOutput.source, 
					m_recInput.destination, &fmt, &m_audioOutput, &m_recInput);
			if ( mError == B_OK )
			{
				//	Find out what the time source of the input is.
				media_node use_time_source;
				BTimeSource * tsobj = m_roster->MakeTimeSourceFor(m_audioInputNode);
				if( tsobj )
				{
					mError = m_roster->SetTimeSourceFor(Node().node, tsobj->Node().node);
				}
	
				//	Start the time source if it's not running.
				if ((tsobj->Node() != m_audioInputNode) && !tsobj->IsRunning()) {
					m_roster->StartNode(tsobj->Node(), BTimeSource::RealTime());
				}
				tsobj->Release();	//	we're done with this time source instance!
		
				// Start
				bigtime_t then = TimeSource()->Now()+50000LL;
				m_roster->StartNode(Node(), then);
				if (m_audioInputNode.kind & B_TIME_SOURCE) 
				{
					mError = m_roster->StartNode(m_audioInputNode, TimeSource()->RealTimeFor(then, 0));
				}
				else 
				{
					mError = m_roster->StartNode(m_audioInputNode, then);
 				}
			}
		}
	}

	return mError == B_OK; 
}

bool PSoundInput::StopRecording()
{
	m_roster = BMediaRoster::Roster(&mError);

	//	If we are the last connection, the Node will stop automatically since it
	//	has nowhere to send data to.
	mError = m_roster->StopNode(m_recInput.node, 0);
	mError = m_roster->Disconnect(m_audioOutput.node.node, m_audioOutput.source, m_recInput.node.node, m_recInput.destination);
	m_audioOutput.source = media_source::null;
	m_recInput.destination = media_destination::null;

	return mError == B_OK;
}

PSoundInput::~PSoundInput() {
	
	m_roster = BMediaRoster::Roster(&mError);
	mError = m_roster->StopNode(m_recInput.node, 0);
	mError = m_roster->Disconnect(m_audioOutput.node.node, 
			m_audioOutput.source, m_recInput.node.node, m_recInput.destination);
	m_audioOutput.source = media_source::null;
	m_recInput.destination = media_destination::null;

//	Release();
	mError = m_roster->UnregisterNode(this);
}

void PSoundInput::Notify(int32 code, ...)
{
	PAssertNULL(mpChannel);
	PAssert( code < (int32) (sizeof(gsNotifyCodes) / sizeof(char*)), PInvalidParameter );
#if EXT_DEBUG
	PError << "Notify received, Code: " << gsNotifyCodes[code] << endl;
#endif
}

void PSoundInput::Record(bigtime_t /* time */,
	const void * data, size_t size,
	const media_raw_audio_format & fmt )
{
#if EXT_DEBUG
	PError << "\tBuffer received. Size: " << size << \
		", sample size: " << ((fmt.format & 0x0f) * 8) << \
		", float? " << ((fmt.format == media_raw_audio_format::B_AUDIO_FLOAT)? 1 : 0) << \
		", channels: " << fmt.channel_count << \
		", rate: " << fmt.frame_rate << \
		endl;
#endif

	PSound* pSound = new PSound;
	PAssertNULL(pSound);
	pSound->SetFormat(fmt.channel_count, fmt.frame_rate, (fmt.format & 0xf) * 8); 
	pSound->SetSize(size * (fmt.format & 0xf)); // 16bit, 2 channels

	int16* pd = (int16*) data;
	int16* ps = (int16*) pSound->GetPointer(); 
	memcpy( ps, pd, size );
	mResampler.Resample(*pSound);

	PMutex lock;
	lock.Wait();
	mSounds.Enqueue(pSound);
	if ( (pSound->GetSize() * mSounds.GetSize()) > MAX_SOUND_FILE_SIZE )
	{
		delete mSounds.Dequeue();
		PError << "Input buffer overflow!" << endl;
		StopRecording();
	}
	lock.Signal();
}

bool PSoundInput::GetBuffer( void * buf, PINDEX len, bool fRelease = true )
{
	PMutex lock;
	lock.Wait();
		
	if( !mpSound  )
	{	
getSound:	
		if( mSounds.GetSize() )
		{
			mpSound = mSounds.Dequeue();
		}
		else
		{
			mpSound = NULL; // Nothing in buffer
			bytesToWrite = 0;
		}
		
		if( mpSound )
			bytesToWrite = mpSound->GetSize();
	}
	
	if( mpSound )
	{
		if( len <= bytesToWrite ) 
		{
			memcpy(buf, mpSound->GetPointer(), len);
			bytesToWrite -= len;
			
#ifdef EXT_DEBUG
			PError << "Buffer returned, size: " << len << ", left:" << bytesToWrite << endl;
#endif			
			if ( bytesToWrite > 0 )
				goto getSound;	
			else
			{
				delete mpSound;
				mpSound = NULL;
				bytesToWrite = 0;
			}
		}
		else
		{
			goto getSound;	
		}		
	}
	lock.Signal();

	return mpSound != NULL;
}

⌨️ 快捷键说明

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