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

📄 msconf.c

📁 基于osip、eXosip、speex、ffmpeg的VoIP源代码
💻 C
字号:
/*mediastreamer2 library - modular sound and video processing and streamingCopyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)This program is free software; you can redistribute it and/ormodify it under the terms of the GNU General Public Licenseas published by the Free Software Foundation; either version 2of the License, or (at your option) any later version.This program is distributed in the hope that it will be useful,but WITHOUT ANY WARRANTY; without even the implied warranty ofMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See theGNU General Public License for more details.You should have received a copy of the GNU General Public Licensealong with this program; if not, write to the Free SoftwareFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.*/#include "mediastreamer2/msfilter.h"#if defined(_WIN32_WCE)#define DISABLE_SPEEX#endif#ifndef DISABLE_SPEEX#include <speex/speex_preprocess.h>#endif#ifndef CONF_GRAN_MAX#define CONF_GRAN_MAX 12 /* limit for 'too much data' */#endif//#ifndef CONF_GRAN//#define CONF_GRAN (160*4)//#endif#define CONF_NSAMPLES 160*4*4 /* (CONF_GRAN/2) */#ifndef CONF_MAX_PINS#define CONF_MAX_PINS 32#endiftypedef struct Channel{	MSBufferizer buff;	int16_t input[CONF_NSAMPLES];	bool_t has_contributed;	bool_t is_used;	int count;	int missed;	int stat_discarded;	int stat_missed;	int stat_processed;#ifndef DISABLE_SPEEX	SpeexPreprocessState *speex_pp;#endif} Channel;typedef struct ConfState{	Channel channels[CONF_MAX_PINS];	int sum[CONF_NSAMPLES];	int enable_directmode;	int enable_vad;	int agc_level;	int mix_mode;	int samplerate;	int adaptative_msconf_buf;	int conf_gran;	int conf_nsamples;} ConfState;static void channel_init(ConfState *s, Channel *chan, int pos){	ms_bufferizer_init(&chan->buff);#ifndef DISABLE_SPEEX	//chan->speex_pp = speex_preprocess_state_init((s->conf_gran/2) *(s->samplerate/8000), s->samplerate);	chan->speex_pp = speex_preprocess_state_init(s->conf_gran/2, s->samplerate);	if (chan->speex_pp!=NULL) {		float f;		int val;		val=1;		speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DENOISE, &val);		/* enable VAD only on incoming RTP stream */		if (pos%2==1)		{			val=1;			speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_VAD, &val);		}		/* enable AGC only on local soundcard */		if (s->agc_level>0 && pos==0)		{			val=1;			speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC, &val);			f=s->agc_level;			speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);#if 0			val=40;			speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &val);#endif		}		else		{			val=0;			speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC, &val);			f=8000;			speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);		}		val=0;		speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB, &val);		f=.4;		speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);		f=.3;		speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);	}#endif}static void channel_uninit(Channel *chan){	ms_bufferizer_uninit(&chan->buff);#ifndef DISABLE_SPEEX	if (chan->speex_pp!=NULL)	    speex_preprocess_state_destroy(chan->speex_pp);	chan->speex_pp=NULL;#endif}static void conf_init(MSFilter *f){	ConfState *s=(ConfState *)ms_new0(ConfState,1);	int i;	s->samplerate=8000;	s->conf_gran=((16 * s->samplerate) / 800) *2;	s->conf_nsamples=s->conf_gran/2;    for (i=0;i<CONF_MAX_PINS;i++)		channel_init(s, &s->channels[i], i);	s->enable_directmode=FALSE;	s->enable_vad=TRUE;	s->agc_level=0;	s->mix_mode=TRUE;	s->adaptative_msconf_buf=2;	f->data=s;}static void conf_uninit(MSFilter *f){	ConfState *s=(ConfState*)f->data;	int i;	for (i=0;i<CONF_MAX_PINS;i++)		channel_uninit(&s->channels[i]);	ms_free(f->data);}static void conf_preprocess(MSFilter *f){	ConfState *s=(ConfState*)f->data;	int i;	for (i=0;i<CONF_MAX_PINS;i++)	  {	    s->channels[i].is_used=FALSE;	    s->channels[i].missed=0;	    s->channels[i].stat_discarded=0;	    s->channels[i].stat_missed=0;	    s->channels[i].stat_processed=0;	  }}static bool_t should_process(MSFilter *f, ConfState *s){	Channel *chan;	int active_channel=0;	int i;	if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>s->conf_gran	    && s->channels[0].is_used==FALSE)	  {	    /* soundread has just started */	    s->channels[0].is_used=TRUE;	  }	else if (s->channels[0].is_used==FALSE)	  {	    return FALSE;	  }	/* count active channel */	for (i=1;i<CONF_MAX_PINS;++i){		chan=&s->channels[i];		if (chan->is_used == TRUE)		{			active_channel++;		}	}	if (active_channel<=1) /* disable mix mode when it's not needed */		s->mix_mode = FALSE;	else		s->mix_mode = TRUE;	if (s->enable_directmode==FALSE)	{		s->mix_mode = TRUE;	}	if (s->mix_mode == FALSE)		return FALSE;	if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>=s->conf_gran)	{		return TRUE;	}	return FALSE;}static void conf_sum(ConfState *s){	int i,j;	Channel *chan;	memset(s->sum,0,s->conf_nsamples*sizeof(int));	chan=&s->channels[0];	if (s->adaptative_msconf_buf*s->conf_gran<ms_bufferizer_get_avail(&chan->buff))	{		i = ms_bufferizer_get_avail(&chan->buff)/s->conf_gran;		if (i>5)			ms_message("Increasing buffer because sound card is late. (nb_buf=%i /old=%i)", i, s->adaptative_msconf_buf);		s->adaptative_msconf_buf=i;		if (s->adaptative_msconf_buf>10)		{			while (ms_bufferizer_get_avail(&chan->buff)> s->conf_gran*6)			{				ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran);				ms_message("Deleting extra sound card data %i", ms_bufferizer_get_avail(&chan->buff));			}		}	}	else if (s->adaptative_msconf_buf*s->conf_gran>ms_bufferizer_get_avail(&chan->buff))	{		if (s->adaptative_msconf_buf>3)		{			s->adaptative_msconf_buf--;			s->adaptative_msconf_buf=ms_bufferizer_get_avail(&chan->buff)/s->conf_gran;			//ms_message("decreasing buffer because sound card is in advance. (nb_buf=%i)", s->adaptative_msconf_buf);		}	}	if (s->adaptative_msconf_buf>6)		s->adaptative_msconf_buf=6;	for (i=0;i<CONF_MAX_PINS;++i){		chan=&s->channels[i];		/* skip soundread and short buffer entry */#if 0		if (i>0			&& ms_bufferizer_get_avail(&chan->buff)>=s->conf_gran*s->adaptative_msconf_buf)		{			while (ms_bufferizer_get_avail(&chan->buff)>=s->conf_gran*2)#endif		if (i>0 			&& ms_bufferizer_get_avail(&chan->buff)> s->conf_gran			&& ms_bufferizer_get_avail(&chan->buff)> (ms_bufferizer_get_avail(&s->channels[0].buff)+s->conf_gran*6) )		{			while (ms_bufferizer_get_avail(&chan->buff)> (ms_bufferizer_get_avail(&s->channels[0].buff)) )			{				ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran);				/* we want to remove 4 packets (40ms) in a near future: */#ifndef DISABLE_SPEEX				if (chan->speex_pp!=NULL && s->enable_vad==TRUE)				{					int vad;					vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL);					if (vad==1)						break; /* voice detected: process as usual */					if (ms_bufferizer_get_avail(&chan->buff)<s->conf_gran)						break; /* no more data to remove */					ms_message("No voice detected: discarding sample. (idx=%i - bufsize=%i sncardbufsize=%i)",						i, ms_bufferizer_get_avail(&chan->buff), ms_bufferizer_get_avail(&s->channels[0].buff));				}				if (ms_bufferizer_get_avail(&chan->buff) == (ms_bufferizer_get_avail(&s->channels[0].buff)))					ms_message("same data in soundcard and incoming rtp. (idx=%i - bufsize=%i sncardbufsize=%i)",						i, ms_bufferizer_get_avail(&chan->buff), ms_bufferizer_get_avail(&s->channels[0].buff));#endif				chan->stat_discarded++;			}			for(j=0;j<s->conf_nsamples;++j){				s->sum[j]+=chan->input[j];			}			chan->has_contributed=TRUE;			chan->stat_processed++;		}		else if (ms_bufferizer_get_avail(&chan->buff)>=s->conf_gran)		{			ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran);#ifndef DISABLE_SPEEX			if (chan->speex_pp!=NULL && s->enable_vad==TRUE)			{				int vad;				vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL);			}#endif			for(j=0;j<s->conf_nsamples;++j){				s->sum[j]+=chan->input[j];			}			chan->has_contributed=TRUE;			chan->stat_processed++;		} else {			chan->stat_missed++;			if (i>0 && chan->is_used == TRUE)			{				chan->missed++;				/* delete stream if data is missing since a long time */				if (chan->missed>15)				{					chan->is_used=FALSE;					ms_message("msconf: deleted contributing stream (pin=%i)", i);				}				/* couldn't we add confort noise for those outputs? */			}			chan->has_contributed=FALSE;		}	}	return;}static inline int16_t saturate(int sample){	if (sample>32000)		sample=32000;	else if (sample<-32000)		sample=-32000;	return (int16_t)sample;}static mblk_t * conf_output(ConfState *s, Channel *chan){	mblk_t *m=allocb(s->conf_gran,0);	int i;	int tmp;	if (chan->has_contributed==TRUE){		for (i=0;i<s->conf_nsamples;++i){			tmp=s->sum[i]-(int)chan->input[i];			*((int16_t*)m->b_wptr)=saturate(tmp);			m->b_wptr+=2;		}	}else{		for (i=0;i<s->conf_nsamples;++i){			tmp=s->sum[i];			*((int16_t*)m->b_wptr)=saturate(tmp);			m->b_wptr+=2;		}	}	return m;}static void conf_dispatch(MSFilter *f, ConfState *s){	int i;	Channel *chan;	mblk_t *m;	//memset(s->sum,0,s->conf_nsamples*sizeof(int));	for (i=0;i<CONF_MAX_PINS;++i){		if (f->outputs[i]!=NULL){			chan=&s->channels[i];			m=conf_output(s,chan);			ms_queue_put(f->outputs[i],m);		}	}}static void conf_process(MSFilter *f){	int i;	ConfState *s=(ConfState*)f->data;	Channel *chan;	Channel *chan0;	/*read from all inputs and put into bufferizers*/	for (i=0;i<CONF_MAX_PINS;++i){		if (f->inputs[i]!=NULL){			chan=&s->channels[i];			ms_bufferizer_put_from_queue(&chan->buff,f->inputs[i]);			if (ms_bufferizer_get_avail(&chan->buff)>0)			{				chan->missed=0; /* reset counter of missed packet */				if (i>0 && chan->is_used==FALSE)				{					chan->is_used=TRUE;					ms_message("msconf: new contributing stream", ms_bufferizer_get_avail(&chan->buff));				}			}		}	}	/*do the job */	while(should_process(f,s)==TRUE){		conf_sum(s);		conf_dispatch(f,s);	}	/* mixer is disabled! -> copy A->B and B->A*/	if (s->mix_mode == FALSE)	{		/* get the soundread data and copy it to pinX */		for (i=1;i<CONF_MAX_PINS;i=i+2){			if (f->inputs[i]!=NULL){				chan0=&s->channels[0];				chan=&s->channels[i];				if (chan->is_used==TRUE)				{					while (ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran)==s->conf_gran)					{						if (f->outputs[0]!=NULL)						{							/* send in pin0 */							mblk_t *m=allocb(s->conf_gran,0);							memcpy(m->b_wptr, chan->input, s->conf_gran);							m->b_wptr+=s->conf_gran;							ms_queue_put(f->outputs[0],m);						}					}				}				if (chan0->is_used==TRUE)				{					while (ms_bufferizer_read(&chan0->buff,(uint8_t*)chan0->input,s->conf_gran)==s->conf_gran)					{						if (f->outputs[i]!=NULL)						{							/* send in pinI */							mblk_t *m=allocb(s->conf_gran,0);							memcpy(m->b_wptr, chan0->input, s->conf_gran);							m->b_wptr+=s->conf_gran;							ms_queue_put(f->outputs[i],m);						}					}				}				break;			}		}	}}static void conf_postprocess(MSFilter *f){	int i;	ConfState *s=(ConfState*)f->data;	Channel *chan;	/*read from all inputs and put into bufferizers*/	for (i=0;i<CONF_MAX_PINS;++i){		if (f->inputs[i]!=NULL){			chan=&s->channels[i];			ms_bufferizer_uninit(&chan->buff);			ms_bufferizer_init(&chan->buff);		}	}}static int msconf_set_sr(MSFilter *f, void *arg){	ConfState *s=(ConfState*)f->data;	int i;	s->samplerate = *(int*)arg;	s->conf_gran = ((16 * s->samplerate) / 800) *2;	s->conf_nsamples=s->conf_gran/2;	for (i=0;i<CONF_MAX_PINS;i++)		channel_uninit(&s->channels[i]);    for (i=0;i<CONF_MAX_PINS;i++)		channel_init(s, &s->channels[i], i);	return 0;}static int msconf_enable_directmode(MSFilter *f, void *arg){	ConfState *s=(ConfState*)f->data;	s->enable_directmode = *(int*)arg;	return 0;}static int msconf_enable_agc(MSFilter *f, void *arg){	ConfState *s=(ConfState*)f->data;	int i;	s->agc_level = *(int*)arg;	for (i=0;i<CONF_MAX_PINS;i++)		channel_uninit(&s->channels[i]);    for (i=0;i<CONF_MAX_PINS;i++)		channel_init(s, &s->channels[i], i);	return 0;}static int msconf_enable_vad(MSFilter *f, void *arg){	ConfState *s=(ConfState*)f->data;	int i;	s->enable_vad = *(int*)arg;	for (i=0;i<CONF_MAX_PINS;i++)		channel_uninit(&s->channels[i]);    for (i=0;i<CONF_MAX_PINS;i++)		channel_init(s, &s->channels[i], i);	return 0;}static int msconf_get_stat_discarded(MSFilter *f, void *arg){	ConfState *s=(ConfState*)f->data;	Channel *chan;	int i;	i = *(int*)arg;	/*read from all inputs and put into bufferizers*/	if (i<0 || i>CONF_MAX_PINS)	  return -1;	if (f->inputs[i]!=NULL){		chan=&s->channels[i];		return chan->stat_discarded;	}	return -1;}static int msconf_get_stat_missed(MSFilter *f, void *arg){	ConfState *s=(ConfState*)f->data;	Channel *chan;	int i;	i = *(int*)arg;	/*read from all inputs and put into bufferizers*/	if (i<0 || i>CONF_MAX_PINS)	  return -1;	if (f->inputs[i]!=NULL){		chan=&s->channels[i];		return chan->stat_missed;	}	return -1;}static int msconf_get_stat_processed(MSFilter *f, void *arg){	ConfState *s=(ConfState*)f->data;	Channel *chan;	int i;	i = *(int*)arg;	/*read from all inputs and put into bufferizers*/	if (i<0 || i>CONF_MAX_PINS)	  return -1;	if (f->inputs[i]!=NULL){		chan=&s->channels[i];		return chan->stat_processed;	}	return -1;}static MSFilterMethod msconf_methods[]={	{	MS_FILTER_SET_SAMPLE_RATE, msconf_set_sr },	{	MS_FILTER_ENABLE_DIRECTMODE, msconf_enable_directmode },	{	MS_FILTER_ENABLE_VAD, msconf_enable_vad },	{	MS_FILTER_ENABLE_AGC, msconf_enable_agc },	{	MS_FILTER_GET_STAT_DISCARDED, msconf_get_stat_discarded },	{	MS_FILTER_GET_STAT_MISSED, msconf_get_stat_missed },	{	MS_FILTER_GET_STAT_OUTPUT, msconf_get_stat_processed },	{	0			, NULL}};#ifdef _MSC_VERMSFilterDesc ms_conf_desc={	MS_CONF_ID,	"MSConf",	"A filter to make conferencing",	MS_FILTER_OTHER,	NULL,	CONF_MAX_PINS,	CONF_MAX_PINS,	conf_init,	conf_preprocess,	conf_process,	conf_postprocess,	conf_uninit,	msconf_methods};#elseMSFilterDesc ms_conf_desc={	.id=MS_CONF_ID,	.name="MSConf",	.text="A filter to make conferencing",	.category=MS_FILTER_OTHER,	.ninputs=CONF_MAX_PINS,	.noutputs=CONF_MAX_PINS,	.init=conf_init,	.preprocess=conf_preprocess,	.process=conf_process,	.postprocess=conf_postprocess,	.uninit=conf_uninit,	.methods=msconf_methods};#endifMS_FILTER_DESC_EXPORT(ms_conf_desc)

⌨️ 快捷键说明

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