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

📄 portaudiodevice.cxx

📁 MiniSip Client with DomainKeys Authentication, Sip, Audio communications, Echo Cancel
💻 CXX
字号:
/* Copyright (C) 2005-2006  Mikael Magnusson <mikma@users.sourceforge.net>  This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more details.  You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA*/#include<config.h>#include"PortAudioDevice.h"#include<portaudio.h>#include<math.h>#include<cstdlib>#include<iostream>using namespace std;const int BUFFER_WIDTH = sizeof(short);//#define PA_DEBUGstatic PaSampleFormat toPaSampleFormat( int format ){	switch( format ){		case SOUND_S16LE:			return paInt16;		case SOUND_S16BE:			return 0;		case SOUND_U16LE:			return 0;		case SOUND_U16BE:			return 0;		case SOUND_S8LE:			return paInt8;		case SOUND_U8LE:			return paUInt8;		case SOUND_S32LE:			return paInt32;		case SOUND_U32LE:			return 0;		default:			return 0;	}}//PortAudioDevice::PortAudioDevice( string device ): SoundDevice( device )PortAudioDevice::PortAudioDevice( PaDeviceIndex device ): SoundDevice("!PORTAUDIO!"), inId( device ), outId( device ){	initialized = false;	outStream = NULL;	inStream = NULL;	outRing = NULL;	inRing = NULL;	outBytesPerSample = 1;	inBytesPerSample = 1;	// non initialized SoundDevice members!	nChannelsPlay = 1;	nChannelsRecord = 1;// 	outId = atoi(device.c_str());// 	inId = outId;	latency = 0.020;	PaError res = Pa_Initialize();	if( res == paNoError ){		initialized = true;	}}PortAudioDevice::~PortAudioDevice(){	if( initialized ){		Pa_Terminate();		initialized = false;	}}int PortAudioDevice::readFromDevice( byte_t * buffer, uint32_t nSamples ){	long nBytes = nSamples * inBytesPerSample * nChannelsRecord;#ifdef PA_DEBUG	cerr << "readFromDevice" << endl;#endif	while( inRing ){		inMutex.lock();		long available = inRing->getSize() * BUFFER_WIDTH;		if( available < nBytes ){#ifdef PA_DEBUG			char buf[128];			snprintf(buf, sizeof(buf), "readFromDevice wait %ld < %ld");			merr << buf << end;#endif			inMutex.unlock();			inCond.wait();			continue;		}		bool res = inRing->read((short *)buffer, nBytes / BUFFER_WIDTH );		inMutex.unlock();		return res ? nBytes / inBytesPerSample / nChannelsRecord : 0;	}	return -1;}int PortAudioDevice::writeToDevice( byte_t * buffer, uint32_t nSamples ){	long nBytes = nSamples * outBytesPerSample * nChannelsPlay;#ifdef PA_DEBUG	cerr << "writeToDevice" << endl;#endif	while( outRing ){		outMutex.lock();		long available = outRing->getFree() * BUFFER_WIDTH;		if( available < nBytes ){#ifdef PA_DEBUG			char buf[128];			snprintf(buf, sizeof(buf), "writeToDevice wait %ld < %ld");			merr << buf << end;#endif			outMutex.unlock();			inCond.wait();			continue;		}		bool res = outRing->write( (const short *)buffer, nBytes / BUFFER_WIDTH );		outMutex.unlock();		return res ? nBytes / outBytesPerSample / nChannelsPlay : 0;	}	return -1;}				int PortAudioDevice::readError( int errcode, byte_t * buffer, uint32_t nSamples ){	// TODO	cerr << "PortAudioDevice::readError unimplemented" << endl;	return -1;}int PortAudioDevice::writeError( int errcode, byte_t * buffer, uint32_t nSamples ){	// TODO	cerr << "PortAudioDevice::writeError unimplemented" << endl;	return -1;}		int PortAudioDevice::openPlayback( int32_t samplingRate, int nChannels, int format ){	PaError err;	PaSampleFormat sampleFormat = toPaSampleFormat( format );	PaStreamParameters outParams;	memset(&outParams, 0, sizeof(outParams));	outParams.device = outId;	outParams.channelCount = nChannels;	outParams.sampleFormat = sampleFormat;	outParams.suggestedLatency = latency;	err = Pa_OpenStream( &outStream,			     NULL,			     &outParams,			     samplingRate,			     (unsigned long)(latency * samplingRate),			     0,			     paCallback, this );	if( err != paNoError ){		cerr << "openPlayback " << Pa_GetErrorText( err ) << endl;		return -1;	}	nChannelsPlay = nChannels;	outBytesPerSample = Pa_GetSampleSize( sampleFormat );	long num = 2 << int(ceil(log(samplingRate * latency * 2 * nChannels * sizeof(short))/log(2)));#ifdef DEBUG_OUTPUT	cerr << "RingBuffer playback size: " << num << endl;#endif		outRing = new CircularBuffer(num / BUFFER_WIDTH);	if( Pa_StartStream( outStream ) != paNoError ){		cerr << "Pa_StartStream failed" << endl;		return -1;	}	openedPlayback = true;	return 0;}int PortAudioDevice::openRecord( int32_t samplingRate, int nChannels, int format ){	PaError err;	PaSampleFormat sampleFormat = toPaSampleFormat( format );	PaStreamParameters inParams;	memset(&inParams, 0, sizeof(inParams));	inParams.device = inId;	inParams.channelCount = nChannels;	inParams.sampleFormat = sampleFormat;	inParams.suggestedLatency = latency;	err = Pa_OpenStream( &inStream,			     &inParams,			     NULL,			     samplingRate,			     (unsigned long)(latency * samplingRate),			     0,			     paCallback, this );	if( err != paNoError ){		cerr << "openRecord " << Pa_GetErrorText( err ) << endl;		return -1;	}	nChannelsRecord = nChannels;	inBytesPerSample = Pa_GetSampleSize( sampleFormat );	long num = 2 << int(ceil(log(samplingRate * latency * 2 * nChannels * sizeof(short)) / log(2)));#ifdef DEBUG_OUTPUT	cerr << "RingBuffer record size: " << num << endl;#endif	inRing = new CircularBuffer(num / BUFFER_WIDTH);	if( Pa_StartStream( inStream ) != paNoError ){		cerr << "Pa_StartStream failed" << endl;		return -1;	}	openedRecord = true;	return 0;}		int PortAudioDevice::closePlayback(){	if( outStream ){		Pa_StopStream( outStream );		Pa_CloseStream( outStream );		outStream = NULL;		outMutex.lock();		if( outRing ){			delete outRing;			outRing = NULL;		}				outMutex.unlock();		openedPlayback = false;		return 0;	}	return -1;}int PortAudioDevice::closeRecord(){	if( inStream ){		Pa_StopStream( inStream );		Pa_CloseStream( inStream );		inStream = NULL;		inMutex.lock();		if( inRing ){			delete inRing;			inRing = NULL;		}				inMutex.unlock();		openedRecord = false;		return 0;	}	return -1;}void PortAudioDevice::sync(){	// TODO	cerr << "PortAudioDevice::sync unimplemented" << endl;}int PortAudioDevice::paCallback( const void *inputBuffer,				 void *outputBuffer,				 unsigned long frameCount,				 const PaStreamCallbackTimeInfo *timeinfo,				 PaStreamCallbackFlags statusFlags,				 void *userData ){	PortAudioDevice *device = (PortAudioDevice*)userData;	return device->callback( inputBuffer, outputBuffer,				 frameCount, timeinfo, statusFlags );}int PortAudioDevice::callback( const void *inputBuffer,			       void *outputBuffer,			       unsigned long frameCount,			       const PaStreamCallbackTimeInfo *timeinfo,			       PaStreamCallbackFlags statusFlags ){	if( inputBuffer && inRing ){		inMutex.lock();		//		cerr << frameCount << ',';		long nBytes = frameCount * inBytesPerSample * nChannelsRecord;		long available = inRing->getFree() * BUFFER_WIDTH;		if( available > nBytes ){			available = nBytes;		} else if( available < nBytes ){			cerr << 'V';		}		inRing->write( (short *)inputBuffer, available / BUFFER_WIDTH );		inCond.broadcast();#ifdef PA_DEBUG		cerr << '<';#endif		inMutex.unlock();	}	if( outputBuffer ) {		long nBytes = frameCount * outBytesPerSample * nChannelsPlay;		if ( outRing ){			outMutex.lock();			long available = outRing->getSize() * BUFFER_WIDTH;			if( available > nBytes ){				available = nBytes;			} else if( available < nBytes ){				cerr << '^';			}			outRing->read( (short *)outputBuffer, available / BUFFER_WIDTH );			outCond.broadcast();						if( available < nBytes ){				memset( (byte_t*)outputBuffer + available, 0, nBytes - available );			}#ifdef PA_DEBUG			cerr << '>';#endif			outMutex.unlock();		}		else {			memset( outputBuffer, 0, nBytes );		}	}	return 0;}

⌨️ 快捷键说明

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