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

📄 jvoipgsmcompression.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"#ifndef JVOIPDISABLE_COMPRESSION_GSM#include "jvoipgsmcompression.h"#include "jvoiperrors.h"#include <stdio.h>#include <string.h>#include <time.h>#include <list>#ifdef WIN32	#include <winsock2.h>#else	#include <sys/time.h>	#include <sys/types.h>	#include <unistd.h>#endif // WIN32#include "debugnew.h"#define JVOIPGSMCOMPRESSION_SAMPLEINTERVAL			20#define JVOIPGSMCOMPRESSION_SAMPLERATE				8000#define JVOIPGSMCOMPRESSION_FRAMESIZE				33#define JVOIPGSMCOMPRESSION_EIGHTBITSCALE			256#define JVOIPGSMCOMPRESSION_CHECKDELAY				(60*4)#define JVOIPGSMCOMPRESSION_TIMEOUTDELAY			(60*10)JVOIPGSMCompression::JVOIPGSMCompression(JVOIPSession *sess) : JVOIPCompressionModule(sess){	compinit = false;	localgsmstate = NULL;	stopthreadmutex.Init();	statemutex.Init();}JVOIPGSMCompression::~JVOIPGSMCompression(){	CleanupCompressor();	CleanupDecompressor();}int JVOIPGSMCompression::InitCompressor(int sampinterval,int inputsamprate,int inputbytespersample,const JVOIPComponentParams *componentparams){	if (compinit)		return ERR_JVOIPLIB_GENERAL_COMPONENTALREADYINIT;	if (sampinterval <= 0 || sampinterval%JVOIPGSMCOMPRESSION_SAMPLEINTERVAL != 0)		return ERR_JVOIPLIB_GSMCOMP_UNSUPPORTEDSAMPLEINTERVAL;	if (inputsamprate != JVOIPGSMCOMPRESSION_SAMPLERATE)		return ERR_JVOIPLIB_GSMCOMP_UNSUPPORTEDSAMPLERATE;	localgsmstate = gsm_create();	if (localgsmstate == NULL)		return ERR_JVOIPLIB_GENERAL_OUTOFMEM;			compinit = true;	return 0;}int JVOIPGSMCompression::CleanupCompressor(){	if (!compinit)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;		gsm_destroy(localgsmstate);	compinit = false;	return 0;}int JVOIPGSMCompression::InitDecompressor(){	stopthread = false;	if (Start() < 0) // Start the thread which cleans the GSM state info map from time to time		return ERR_JVOIPLIB_GSMCOMP_CANTSTARTTHREAD;	return 0;}int JVOIPGSMCompression::CleanupDecompressor(){	// We have to clean up the gsm states	std::map<VoIPFramework::VOIPuint64,GSMStateInfo *>::const_iterator it;	StopThread();		for (it = gsmstates.begin() ; it != gsmstates.end() ; ++it)		delete it->second; // delete the GSMStateInfo part;	gsmstates.clear();	return 0;}int JVOIPGSMCompression::Compress(VoIPFramework::VoiceBlock *vb){	unsigned char *frame,*data;	gsm_signal signalbuf[160];	int datalen,numsamples,numframes;	int i,j,offset,frameoffset;	offset = 0;	frameoffset = 0;		data = vb->GetSamples(false);	datalen = vb->GetNumBytes();	numsamples = vb->GetNumSamples();	numframes = numsamples / 160;	if (numsamples % 160 != 0)		numframes++;	frame = new unsigned char[JVOIPGSMCOMPRESSION_FRAMESIZE*numframes];	if (frame == NULL)		return ERR_JVOIPLIB_GENERAL_OUTOFMEM;				while (offset < numsamples)	{		int samp;		samp = numsamples-offset;		if (samp > 160)			samp = 160;					memset(signalbuf,0,sizeof(gsm_signal) * 160);		// fill in the signal buffer		if (vb->GetBytesPerSample() == 1)		{			for (i = 0 ; i < samp ; i++)			{				int val;					val = (((int)data[i+offset])-127)*JVOIPGSMCOMPRESSION_EIGHTBITSCALE;				signalbuf[i] = (gsm_signal)val;			}		}		else // two bytes per sample		{			for (i = 0,j = offset*2 ; i < samp ; i++,j += 2)			{				int val;							val = (((int)data[j])<<8)|((int)data[j+1]);				val -= 32767;				signalbuf[i] = (gsm_signal)val;			}		}				gsm_encode(localgsmstate,signalbuf,frame+frameoffset);		frameoffset += JVOIPGSMCOMPRESSION_FRAMESIZE;		offset += 160;	}	vb->SetSamples(frame,JVOIPGSMCOMPRESSION_FRAMESIZE*numframes);	return 0;}int JVOIPGSMCompression::Decompress(VoIPFramework::VoiceBlock *vb,VoIPFramework::VOIPuint64 sourceid){	unsigned char *frame;	unsigned char *speech;	gsm_signal signalbuf[160];	int framelen,i,j,frameoff,numframes,off;	GSMStateInfo *stateinf;	frame = vb->GetSamples(false);	if (frame == NULL)		return 0;	framelen = vb->GetNumBytes();	if (framelen <= 0 || (framelen % JVOIPGSMCOMPRESSION_FRAMESIZE) != 0)	{		vb->Clear();		return 0;	}	numframes = framelen/JVOIPGSMCOMPRESSION_FRAMESIZE;	// Obtain the gsm state info for this participant. This is done by the	// map. If the key isn't found, the map creates a default entry, so	// in that case the gsmstate will be NULL.	statemutex.Lock();		stateinf = gsmstates[sourceid];	if (stateinf == NULL)	{		stateinf = new GSMStateInfo();		if (stateinf == NULL)		{			statemutex.Unlock();			return ERR_JVOIPLIB_GENERAL_OUTOFMEM;		}		gsmstates[sourceid] = stateinf;	}		if (stateinf->gsmstate == NULL)	{		stateinf->gsmstate = gsm_create();		if (stateinf->gsmstate == NULL)		{			statemutex.Unlock();			return ERR_JVOIPLIB_GENERAL_OUTOFMEM;		}	}	else	{		// update the time so we can delete a member after a long		// time of inactivity...		stateinf->lasttime = time(NULL);	}	// We'll encode it in 16 bit values. This way we have more precision.	// Conversion to the right output rate and sample type will be done	// in the mixer.	speech = new unsigned char[160*2*numframes];	if (speech == NULL)	{		statemutex.Unlock();		return ERR_JVOIPLIB_GENERAL_OUTOFMEM;	}	// Now, we simply have to decode the frame and put it in the voiceblock	for (frameoff = 0,off = 0 ; frameoff < framelen ; frameoff += JVOIPGSMCOMPRESSION_FRAMESIZE,off += 160*2)	{		gsm_decode(stateinf->gsmstate,frame+frameoff,signalbuf);  				for (i = 0,j = off ; i < 160 ; i++,j += 2)		{			int val;			val = (int)signalbuf[i];			val = val+32767;			if (val < 0)				val = 0;			else if (val > 65535)				val = 65535;			speech[j] = (unsigned char)((val>>8)&0xFF);			speech[j+1] = (unsigned char)(val&0xFF);		}	}		statemutex.Unlock();	// Now, we simply have to store the decodes samples in the voiceblock	vb->SetSamples(speech,160*2*numframes);	vb->SetNumSamples(160*numframes);	vb->SetBytesPerSample(2);		return 0;}bool JVOIPGSMCompression::SupportsSampleInterval(int ival){	if (!compinit)		return false;	if (ival <= 0 || ival%JVOIPGSMCOMPRESSION_SAMPLEINTERVAL != 0)		return false;	return true;}int JVOIPGSMCompression::SetSampleInterval(int ival){	if (!compinit)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	if (ival <= 0 || ival%JVOIPGSMCOMPRESSION_SAMPLEINTERVAL != 0)		return ERR_JVOIPLIB_GSMCOMP_UNSUPPORTEDSAMPLEINTERVAL;	return 0;}bool JVOIPGSMCompression::SupportsInputSamplingRate(int irate){	if (!compinit)		return false;	if (irate != JVOIPGSMCOMPRESSION_SAMPLERATE)		return false;	return true;}int JVOIPGSMCompression::SetInputSamplingRate(int irate){	if (!compinit)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	if (irate != JVOIPGSMCOMPRESSION_SAMPLERATE)		return ERR_JVOIPLIB_GSMCOMP_UNSUPPORTEDSAMPLERATE;	return 0;}bool JVOIPGSMCompression::SupportsInputBytesPerSample(int inputbytespersample){	if (!compinit)		return false;	return true;}int JVOIPGSMCompression::SetInputBytesPerSample(int inputbytespersample){	if (!compinit)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	return 0;}int JVOIPGSMCompression::GetComponentState(JVOIPComponentState **compstate){	if (!compinit)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	*compstate = NULL;	return 0;}int JVOIPGSMCompression::SetComponentState(JVOIPComponentState *compstate){	if (!compinit)		return ERR_JVOIPLIB_GENERAL_COMPONENTNOTINIT;	return 0;}std::string JVOIPGSMCompression::GetComponentName(){	return std::string("JVOIPGSMCompression");}std::string JVOIPGSMCompression::GetComponentDescription(){	return std::string("JVOIPLIB Internal GSM 06.10 13kbps compression module (uses libgsm)");}std::vector<JVOIPCompParamInfo> *JVOIPGSMCompression::GetComponentParameters() throw (JVOIPException){	return NULL;}void *JVOIPGSMCompression::Thread(){	JThread::ThreadStarted();		bool stop;	time_t prevchecktime;	prevchecktime = time(NULL);	stopthreadmutex.Lock();	stop = stopthread;	stopthreadmutex.Unlock();	while (!stop)	{		time_t curtime;		struct timeval tv;				tv.tv_sec = 0;		tv.tv_usec = 100000; // 100 millisecods -> make sure we don't have to wait too long#ifndef WIN32		select(FD_SETSIZE,NULL,NULL,NULL,&tv);#else		Sleep((DWORD)(((double)tv.tv_sec)*1000.0+((double)tv.tv_usec)/1000.0));#endif // WIN32		curtime = time(NULL);		if ((curtime - prevchecktime) > JVOIPGSMCOMPRESSION_CHECKDELAY)		{			std::map<VoIPFramework::VOIPuint64,GSMStateInfo *>::iterator it;			std::list<VoIPFramework::VOIPuint64> sourceids;			std::list<VoIPFramework::VOIPuint64>::const_iterator it2;						statemutex.Lock();			it = gsmstates.begin();			while (it != gsmstates.end())			{				if ((curtime - it->second->lasttime) > JVOIPGSMCOMPRESSION_TIMEOUTDELAY)				{					// NOTE: we cannot simply call an 'erase'					// function because the map::erase function					// does not return a new iterator. So, we'll					// store the keys which need to be erased					// in a list and delete all entries afterwards					// Also note that we do need to erase the					// GSMStateInfo* here					delete it->second; 					sourceids.push_back(it->first);				}				it++;			}			for (it2 = sourceids.begin() ; it2 != sourceids.end() ; ++it2)				gsmstates.erase(*it2);			statemutex.Unlock();					prevchecktime = curtime;		}				stopthreadmutex.Lock();		stop = stopthread;		stopthreadmutex.Unlock();	}	return NULL;}void JVOIPGSMCompression::StopThread(){	time_t t = time(NULL);	stopthreadmutex.Lock();	stopthread = true;	stopthreadmutex.Unlock();	while (IsRunning() && (time(NULL) - t) < 5)		;	if (IsRunning())	{		std::cerr << "JVOIPGSMCompression::StopThread -- warning: having to kill thread" << std::endl;		Kill();	}}#endif // JVOIPDISABLE_COMPRESSION_GSM

⌨️ 快捷键说明

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