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

📄 jvoipnormalmixer.cpp

📁 使用VOIP进行网络传输声音的类库
💻 CPP
字号:
/*    This file is a part of JVOIPLIB, a library designed to facilitate    the use of Voice over IP (VoIP).    Copyright (C) 2000-2004  Jori Liesenborgs (jori@lumumba.luc.ac.be)    This library (JVOIPLIB) is based upon work done for my thesis at    the School for Knowledge Technology (Belgium/The Netherlands)    This file was developed at the 'Expertise Centre for Digital    Media' (EDM) in Diepenbeek, Belgium (http://www.edm.luc.ac.be).    The EDM is a research institute of the 'Limburgs Universitair    Centrum' (LUC) (http://www.luc.ac.be).    The full GNU Library General Public License can be found in the    file LICENSE.LGPL which is included in the source code archive.    This library is free software; you can redistribute it and/or    modify it under the terms of the GNU Library General Public    License as published by the Free Software Foundation; either    version 2 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    Library General Public License for more details.    You should have received a copy of the GNU Library General Public    License along with this library; if not, write to the Free    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307    USA*/#include "jvoipconfig.h"#include "jvoipnormalmixer.h"#include "jvoiperrors.h"#include "voiceblock.h"#include <iostream>#include <string.h>#include "debugnew.h"#define JVOIPNORMMIX_MAXFUTUREDIST						10.0 // ten seconds// the component state	class JVOIPNormalMixerState : public JVOIPComponentState{public:	JVOIPNormalMixerState(VoIPFramework::VOIPdouble off) { offset = off; }		VoIPFramework::VOIPdouble Offset() { return offset; }private:	VoIPFramework::VOIPdouble offset;};	// the componentJVOIPNormalMixer::JVOIPNormalMixer(JVOIPSession *sess) : JVOIPMixer(sess){	init = false;}JVOIPNormalMixer::~JVOIPNormalMixer(){	Cleanup();}int JVOIPNormalMixer::Init(int sampinterval,int outputsamprate,int outputbytespersample,bool stereo,const JVOIPComponentParams *componentparams){	if (init)		return ERR_JVOIPLIB_GENERAL_COMPONENTALREADYINIT;	sampleinterval = sampinterval;	samplerate = outputsamprate;	bytespersample = outputbytespersample;	isstereo = stereo;			sampleoffset = 0;	realtotaltime = 0;	wantedtotaltime = 0;		init = true;	return 0;}int JVOIPNormalMixer::Cleanup(){	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;		DeleteMixerBlocks();	init = false;	return 0;}int JVOIPNormalMixer::AddBlock(VoIPFramework::VoiceBlock *vb,VoIPFramework::VOIPuint64 sourceid){	VoIPFramework::VOIPuint64 samplenum;	std::list<MixerBlock*>::iterator it;	int status;	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	if (vb->GetSamples(false) == NULL)		return 0;		// if the samples are too far into the future, we're gonna ignore them (to avoid memory shortage)	if ((vb->GetSampleOffset() - sampleoffset) > JVOIPNORMMIX_MAXFUTUREDIST)		return 0;		// if the sample block is too late, we'll ignore it too	if (IsTooLate(vb))		return 0;		// convert to the right sample rate etc	if ((status = AdjustSamples(vb)) < 0)		return status;		if (vb->GetSamples(false) == NULL)		return 0;			// search for the mixer block where we have to start inserting the data	samplenum = CalculateSampleNumber(vb->GetSampleOffset());	if ((status = GetStartMixerBlock(samplenum,&it)) < 0)		return status;	if ((status = CreateAllMemoryBlocks(it,samplenum+vb->GetNumSamples()-1)) < 0)		return status;			FillInSamples(it,vb,samplenum);	return 0;}int JVOIPNormalMixer::GetSampleBlock(VoIPFramework::VoiceBlock *vb){	std::list<MixerBlock*>::iterator it;	unsigned char *data;	int num,len;	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	vb->SetSampleOffset(sampleoffset);					it = mixerblocks.begin();	if (it == mixerblocks.end())	{		num = CalculateNewNumSamples();		len = num;		if (isstereo)			len *= 2;		if (bytespersample != 1)			len *= 2;					data = new unsigned char[len];		if (data == NULL)			return ERR_JVOIPLIB_GENERAL_OUTOFMEM;		SetSilence(data,num);				sampleoffset += ((VoIPFramework::VOIPdouble)num)/((VoIPFramework::VOIPdouble)samplerate);	}	else	{		data = (*it)->data;		num = (*it)->numsamples;		len = (*it)->datalen;#ifdef WIN32		// the conversion from uint64 to double isn't implemented in Visual C++ 6		sampleoffset = VoIPFramework::GetVOIPdouble((*it)->samplenum+(*it)->numsamples)/((VoIPFramework::VOIPdouble)samplerate);#else		sampleoffset = ((VoIPFramework::VOIPdouble)((*it)->samplenum+(*it)->numsamples))/((VoIPFramework::VOIPdouble)samplerate);#endif // WIN32				(*it)->data = NULL; // to avoid it being deleted in the destructor of mixerblock		delete (*it);		mixerblocks.erase(it);				if (data == NULL)		{			len = num;			if (isstereo)				len *= 2;			if (bytespersample != 1)				len *= 2;						data = new unsigned char[len];			if (data == NULL)				return ERR_JVOIPLIB_GENERAL_OUTOFMEM;			SetSilence(data,num);		}	}	vb->SetSamples(data,len);	vb->SetNumSamples(num);	vb->SetStereo(isstereo);	vb->SetBytesPerSample(bytespersample);	vb->SetSampleRate(samplerate);	vb->SetIsSilence(false);	vb->SetInfo3D(NULL,0);	vb->SetMajorCompressionID(0);	vb->SetMinorCompressionID(0);		return 0;}int JVOIPNormalMixer::GetSampleOffset(VoIPFramework::VOIPdouble *offset){	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	*offset = sampleoffset;	return 0;}bool JVOIPNormalMixer::SupportsSampleInterval(int ival){	if (!init)		return false;	return true;}bool JVOIPNormalMixer::SupportsOutputSamplingRate(int orate){	if (!init)		return false;	return true;}bool JVOIPNormalMixer::SupportsOutputBytesPerSample(int outputbytespersample){	if (!init)		return false;	return true;}int JVOIPNormalMixer::SetSampleInterval(int ival){	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;		DeleteMixerBlocks();	sampleinterval = ival;	return 0;}int JVOIPNormalMixer::SetOutputSamplingRate(int orate){	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;		DeleteMixerBlocks();	samplerate = orate;	return 0;}int JVOIPNormalMixer::SetOutputBytesPerSample(int outputbytespersample){	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;		DeleteMixerBlocks();	bytespersample = outputbytespersample;	return 0;}int JVOIPNormalMixer::SetStereo(bool s){	if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;		DeleteMixerBlocks();	isstereo = s;	return 0;}int JVOIPNormalMixer::GetComponentState(JVOIPComponentState **compstate){	JVOIPNormalMixerState *state;		if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;		state = new JVOIPNormalMixerState(sampleoffset);	if (state == NULL)		return ERR_JVOIPLIB_GENERAL_OUTOFMEM;	*compstate = state;	return 0;}int JVOIPNormalMixer::SetComponentState(JVOIPComponentState *compstate){	JVOIPNormalMixerState *state;		if (!init)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	if (compstate == NULL)		return ERR_JVOIPLIB_GENERAL_ILLEGALSTATEPARAMETER;		state = dynamic_cast<JVOIPNormalMixerState *>(compstate);	if (state == NULL)		return ERR_JVOIPLIB_GENERAL_ILLEGALSTATEPARAMETER;		sampleoffset = state->Offset();	return 0;}std::string JVOIPNormalMixer::GetComponentName(){	return std::string("JVOIPNormalMixer");}std::string JVOIPNormalMixer::GetComponentDescription(){	return std::string("JVOIPLIB Internal mixer");}std::vector<JVOIPCompParamInfo> *JVOIPNormalMixer::GetComponentParameters() throw (JVOIPException){	// NOTE: this mixer doens't have any options	return NULL;}void JVOIPNormalMixer::DeleteMixerBlocks(){	std::list<MixerBlock*>::const_iterator it;		for (it = mixerblocks.begin() ; it != mixerblocks.end() ; ++it)		delete (*it);	mixerblocks.clear();}inline VoIPFramework::VOIPuint64 JVOIPNormalMixer::CalculateSampleNumber(VoIPFramework::VOIPdouble offset){	VoIPFramework::VOIPuint64 id;		// we're gonna calculate the sample number at this offset	id = (VoIPFramework::VOIPuint64)((offset*((VoIPFramework::VOIPdouble)samplerate))+0.5);	return id;}int JVOIPNormalMixer::AdjustSamples(VoIPFramework::VoiceBlock *vb){	int len,newlen,numsamples;	unsigned char *data;		sampconv.SetConversionParams((int)vb->GetSampleRate(),vb->IsStereo(),vb->GetBytesPerSample(),false,false,				     samplerate,isstereo,bytespersample,false,false);		numsamples = (int)((((double)vb->GetNumSamples())*((double)samplerate))/((double)vb->GetSampleRate()));	len = numsamples;	if (isstereo)		len *= 2;	if (bytespersample != 1)		len *= 2;	data = new unsigned char[len];	if (data == NULL)		return ERR_JVOIPLIB_GENERAL_OUTOFMEM;	if ((newlen = sampconv.Convert(vb->GetSamples(false),vb->GetNumBytes(),data,len)) < 0)	{		delete [] data;		vb->SetSamples(NULL,0);		return 0;	}		numsamples = newlen;	if (isstereo)		numsamples /= 2;	if (bytespersample != 1)		numsamples /= 2;		vb->SetSamples(data,newlen);	vb->SetNumSamples(numsamples);	vb->SetSampleRate(samplerate);	vb->SetBytesPerSample(bytespersample);	vb->SetStereo(isstereo);	return 0;}inline bool JVOIPNormalMixer::IsTooLate(VoIPFramework::VoiceBlock *vb){	VoIPFramework::VOIPdouble lastsampleoffset;		lastsampleoffset = vb->GetSampleOffset();	lastsampleoffset += ((VoIPFramework::VOIPdouble)vb->GetNumSamples())/((VoIPFramework::VOIPdouble)vb->GetSampleRate());	if (lastsampleoffset < sampleoffset)		return true;	return false;}int JVOIPNormalMixer::GetStartMixerBlock(VoIPFramework::VOIPuint64 samplenum,std::list<MixerBlock*>::iterator *i){	std::list<MixerBlock*>::iterator it;	VoIPFramework::VOIPuint64 lastsamplenum,startsamplenum;	bool found,gotlastsamplenum,done;			found = false;	gotlastsamplenum = false;	it = mixerblocks.begin();	while (!found && it != mixerblocks.end())	{		if (samplenum < (*it)->samplenum)			found = true;		else if (samplenum >= (*it)->samplenum && samplenum < ((*it)->samplenum+(*it)->numsamples))			found = true;		else		{			gotlastsamplenum = true;			lastsamplenum = (*it)->samplenum+(*it)->numsamples-1;			++it;		}	}	if (found)	{		*i = it;		return 0;	}		// In this case, we have to build the list	if (gotlastsamplenum)		startsamplenum = lastsamplenum+1;	else		startsamplenum = CalculateSampleNumber(sampleoffset);		done = false;	while (!done)	{		int num;		MixerBlock *blk;				num = CalculateNewNumSamples();		blk = new MixerBlock(startsamplenum);		if (blk == NULL)			return ERR_JVOIPLIB_GENERAL_OUTOFMEM;		blk->numsamples = num;				mixerblocks.push_back(blk);		if (samplenum < startsamplenum || (samplenum >= startsamplenum && samplenum < (startsamplenum + num)))		{			it = mixerblocks.end();			--it;			done = true;		}		else			startsamplenum += num;	}	*i = it;	return 0;}int JVOIPNormalMixer::CalculateNewNumSamples(){	double diff;	int numsamples;	wantedtotaltime += ((double)sampleinterval)/1000.0;	diff = wantedtotaltime - realtotaltime;		numsamples = (int)((((double)samplerate)*diff)+0.5);	if (numsamples < 1)		numsamples = 1;	realtotaltime += ((double)numsamples)/((double)samplerate);		return numsamples;}int JVOIPNormalMixer::CreateAllMemoryBlocks(std::list<MixerBlock*>::iterator i,VoIPFramework::VOIPuint64 endsamplenum){	bool done;	VoIPFramework::VOIPuint64 lastsampnum;	std::list<MixerBlock*>::iterator it = i;	int multiplier;		multiplier = 1;	if (isstereo)		multiplier *= 2;	if (bytespersample != 1)		multiplier *= 2;		done = false;	while (!done)	{		lastsampnum = (*it)->samplenum+(*it)->numsamples-1;				if ((*it)->data == NULL)		{			int len;			unsigned char *data;						len = (*it)->numsamples*multiplier;			data = new unsigned char[len];			if (data == NULL)				return ERR_JVOIPLIB_GENERAL_OUTOFMEM;			(*it)->data = data;			(*it)->datalen = len;			SetSilence(data,(*it)->numsamples);		}				if ((*it)->samplenum >= endsamplenum && endsamplenum < ((*it)->samplenum+(*it)->numsamples))			done = true;		else		{			++it;			if (it == mixerblocks.end())			{				MixerBlock *blk;								blk = new MixerBlock(lastsampnum+1);				if (blk == NULL)					return ERR_JVOIPLIB_GENERAL_OUTOFMEM;				blk->numsamples = CalculateNewNumSamples();				mixerblocks.push_back(blk);				it = mixerblocks.end();				--it;			}		}	}	return 0;}void JVOIPNormalMixer::SetSilence(unsigned char *data,int numsamples){	int steps;		steps = numsamples;	if (isstereo)		steps *= 2;		if (bytespersample == 1)	{		// unsigned!		memset(data,127,steps);	}	else	{		int i,j;				for (i = 0,j = 0 ; i < steps ; i++,j += 2)		{			// big endian and unsigned!			data[j] = 127;			data[j+1] = 255;		}	}}void JVOIPNormalMixer::FillInSamples(std::list<MixerBlock*>::iterator it2,VoIPFramework::VoiceBlock *vb,VoIPFramework::VOIPuint64 startsamplenum){	std::list<MixerBlock*>::iterator it = it2;	VoIPFramework::VOIPuint64 cursamplenum,endsamplenum;	bool done;	int offset,loops,i,j;	int val,val2;	unsigned char *data,*data2;		if (isstereo)		loops = 2;	else		loops = 1;		endsamplenum = startsamplenum+vb->GetNumSamples()-1;	if (startsamplenum < (*it)->samplenum)	{		cursamplenum = (*it)->samplenum;		offset = 0;				j = cursamplenum-startsamplenum;		if (isstereo)			j *= 2;		if (bytespersample != 1)			j *= 2;	}	else	{		cursamplenum = startsamplenum;				offset = cursamplenum-(*it)->samplenum;		if (isstereo)			offset *= 2;		if (bytespersample != 1)			offset *= 2;				j = 0;	}		data = (*it)->data;	data2 = vb->GetSamples(false);	done = false;	while(!done)	{		for (i = 0 ; i < loops ; i++)		{			if (bytespersample == 1)			{				val = (int)data[offset];				val -= 127;				val2 = (int)data2[j];				val2 -= 127;								val += val2;				val += 127;				if (val < 0)					val = 0;				else if (val > 255)					val = 255;								data[offset] = (unsigned char)val;				offset++;				j++;			}			else			{				val = (int)((((int)data[offset])<<8)|((int)data[offset+1]));				val -= 32767;				val2 = (int)((((int)data2[j])<<8)|((int)data2[j+1]));				val2 -= 32767;							val += val2;				val += 32767;				if (val < 0)					val = 0;				else if (val > 65535)					val = 65535;									data[offset] = (unsigned char)((val>>8)&0xFF);				data[offset+1] = (unsigned char)(val&0xFF);				offset += 2;				j += 2;			}		}				cursamplenum++;		if (cursamplenum > endsamplenum)			done = true;		else		{			if (offset >= (*it)->datalen)			{				++it;				offset = 0;				data = (*it)->data;			}			}	}}

⌨️ 快捷键说明

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