source: mediastreamer2/linphone/mediastreamer2/src/msconf.c @ 249:7bdaa4c9c454

Last change on this file since 249:7bdaa4c9c454 was 249:7bdaa4c9c454, checked in by aymeric <aymeric@…>, 4 years ago

Add notification for analysing content of echo state and speex preprocessor.

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@252 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 18.4 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#include "mediastreamer2/msfilter.h"
21
22#if defined(_WIN32_WCE)
23#define DISABLE_SPEEX
24#endif
25
26#ifndef DISABLE_SPEEX
27#include <speex/speex_preprocess.h>
28#endif
29
30#ifndef CONF_GRAN_MAX
31#define CONF_GRAN_MAX 12 /* limit for 'too much data' */
32#endif
33
34//#ifndef CONF_GRAN
35//#define CONF_GRAN (160*4)
36//#endif
37#define CONF_NSAMPLES 160*4*4 /* (CONF_GRAN/2) */
38#ifndef CONF_MAX_PINS
39#define CONF_MAX_PINS 32
40#endif
41
42typedef struct Channel{
43        MSBufferizer buff;
44        int16_t input[CONF_NSAMPLES];
45        bool_t has_contributed;
46        bool_t is_used;
47
48        int is_speaking;
49
50        int count;
51        int missed;
52
53        int stat_discarded;
54        int stat_missed;
55        int stat_processed;
56
57#ifndef DISABLE_SPEEX
58        SpeexPreprocessState *speex_pp;
59#endif
60
61} Channel;
62
63typedef struct ConfState{
64        Channel channels[CONF_MAX_PINS];
65        int sum[CONF_NSAMPLES];
66        int enable_directmode;
67        int enable_vad;
68
69        int enable_halfduplex;
70        int vad_prob_start;
71        int vad_prob_continue;
72
73        int agc_level;
74        int mix_mode;
75        int samplerate;
76
77        int adaptative_msconf_buf;
78        int conf_gran;
79        int conf_nsamples;
80} ConfState;
81
82
83static void channel_init(ConfState *s, Channel *chan, int pos){
84        float f;
85        int val;
86        memset(chan, 0, sizeof(Channel));
87        ms_bufferizer_init(&chan->buff);
88#ifndef DISABLE_SPEEX
89        //chan->speex_pp = speex_preprocess_state_init((s->conf_gran/2) *(s->samplerate/8000), s->samplerate);
90        chan->speex_pp = speex_preprocess_state_init(s->conf_gran/2, s->samplerate);
91        if (chan->speex_pp==NULL)
92                return;
93
94        /* configure sound card input on pin 0 */
95        val=0;
96        if (pos==0)
97                val=1;
98
99        if (s->enable_halfduplex>0 && pos%2==1)
100                val=1;
101
102        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DENOISE, &val);
103        val = -30;
104        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_NOISE_SUPPRESS, &val);
105
106        /* enable VAD only on incoming RTP stream */
107        val=0;
108        if (pos%2==1 || (pos==0 && s->enable_halfduplex>0))
109        {
110                val=1;
111        }
112
113        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_VAD, &val);
114        if (s->vad_prob_start>0 && s->vad_prob_continue>0)
115        {
116                val = s->vad_prob_start; // xx%
117                speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_PROB_START, &val);
118                val = s->vad_prob_continue; // xx%
119                speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_PROB_CONTINUE, &val);
120        }
121
122        /* enable AGC only on local soundcard */
123        val=0;
124        f=8000;
125        if (s->agc_level>0 && pos==0)
126                val=1;
127        else if (pos==0 && s->enable_halfduplex>0)
128                val=1;
129        else if ( pos%2==1 && s->enable_halfduplex>0)
130                val=1;
131        if (s->agc_level>0)
132                f=s->agc_level;
133
134
135        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC, &val);
136        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_LEVEL, &f);
137#if 0
138        val=15;
139        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_AGC_MAX_GAIN, &val);
140#endif
141
142        val=0;
143#if 0
144        val=1; // do more testing
145#endif
146        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB, &val);
147        f=.4;
148        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_DECAY, &f);
149        f=.3;
150        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_SET_DEREVERB_LEVEL, &f);
151
152#endif
153}
154
155static void channel_uninit(Channel *chan){
156        ms_bufferizer_uninit(&chan->buff);
157#ifndef DISABLE_SPEEX
158        if (chan->speex_pp!=NULL)
159            speex_preprocess_state_destroy(chan->speex_pp);
160        chan->speex_pp=NULL;
161#endif
162}
163
164static void conf_init(MSFilter *f){
165        ConfState *s=(ConfState *)ms_new0(ConfState,1);
166        int i;
167        s->samplerate=8000;
168        s->conf_gran=((16 * s->samplerate) / 800) *2;
169        s->conf_nsamples=s->conf_gran/2;
170    for (i=0;i<CONF_MAX_PINS;i++)
171                channel_init(s, &s->channels[i], i);
172        s->enable_directmode=FALSE;
173        s->enable_vad=TRUE;
174        s->agc_level=0;
175        s->mix_mode=TRUE;
176        s->adaptative_msconf_buf=2;
177        f->data=s;
178}
179
180static void conf_uninit(MSFilter *f){
181        ConfState *s=(ConfState*)f->data;
182        int i;
183        for (i=0;i<CONF_MAX_PINS;i++)
184                channel_uninit(&s->channels[i]);
185        ms_free(f->data);
186}
187
188static void conf_preprocess(MSFilter *f){
189        ConfState *s=(ConfState*)f->data;
190        int i;
191        for (i=0;i<CONF_MAX_PINS;i++)
192          {
193            s->channels[i].is_used=FALSE;
194            s->channels[i].missed=0;
195            s->channels[i].stat_discarded=0;
196            s->channels[i].stat_missed=0;
197            s->channels[i].stat_processed=0;
198          }
199}
200
201static bool_t should_process(MSFilter *f, ConfState *s){
202        Channel *chan;
203        int active_channel=0;
204        int i;
205
206        if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>s->conf_gran
207            && s->channels[0].is_used==FALSE)
208          {
209            /* soundread has just started */
210            s->channels[0].is_used=TRUE;
211          }
212        else if (s->channels[0].is_used==FALSE)
213          {
214            return FALSE;
215          }
216
217        /* count active channel */
218        for (i=1;i<CONF_MAX_PINS;++i){
219                chan=&s->channels[i];
220                if (chan->is_used == TRUE)
221                {
222                        active_channel++;
223                }
224        }
225
226        if (active_channel<=1) /* disable mix mode when it's not needed */
227                s->mix_mode = FALSE;
228        else
229                s->mix_mode = TRUE;
230
231        if (s->enable_directmode==FALSE)
232        {
233                s->mix_mode = TRUE;
234        }
235
236        if (s->mix_mode == FALSE)
237                return FALSE;
238
239        if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>=s->conf_gran)
240        {
241                return TRUE;
242        }
243        return FALSE;
244}
245
246static void conf_sum(MSFilter *f, ConfState *s){
247        int i,j;
248        Channel *chan;
249        memset(s->sum,0,s->conf_nsamples*sizeof(int));
250
251        chan=&s->channels[0];
252        if (s->adaptative_msconf_buf*s->conf_gran<ms_bufferizer_get_avail(&chan->buff))
253        {
254                i = ms_bufferizer_get_avail(&chan->buff)/s->conf_gran;
255                if (i>5)
256                        ms_message("Increasing buffer because sound card is late. (nb_buf=%i /old=%i)", i, s->adaptative_msconf_buf);
257                s->adaptative_msconf_buf=i;
258                if (s->adaptative_msconf_buf>10)
259                {
260                        while (ms_bufferizer_get_avail(&chan->buff)> s->conf_gran*6)
261                        {
262                                ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran);
263                                ms_message("Deleting extra sound card data %i", ms_bufferizer_get_avail(&chan->buff));
264                        }
265                }
266        }
267        else if (s->adaptative_msconf_buf*s->conf_gran>ms_bufferizer_get_avail(&chan->buff))
268        {
269                if (s->adaptative_msconf_buf>3)
270                {
271                        s->adaptative_msconf_buf--;
272                        s->adaptative_msconf_buf=ms_bufferizer_get_avail(&chan->buff)/s->conf_gran;
273                        //ms_message("decreasing buffer because sound card is in advance. (nb_buf=%i)", s->adaptative_msconf_buf);
274                }
275        }
276
277        if (s->adaptative_msconf_buf>6)
278                s->adaptative_msconf_buf=6;
279
280        for (i=0;i<CONF_MAX_PINS;++i){
281                chan=&s->channels[i];
282
283                /* skip soundread and short buffer entry */
284                if (i>0 
285                        && ms_bufferizer_get_avail(&chan->buff)> s->conf_gran
286                        && ms_bufferizer_get_avail(&chan->buff)> (ms_bufferizer_get_avail(&s->channels[0].buff)+s->conf_gran*6) )
287                {
288#if 0
289                        int loudness;
290#endif
291                        int vad=0;
292                        while (ms_bufferizer_get_avail(&chan->buff)> (ms_bufferizer_get_avail(&s->channels[0].buff)) )
293                        {
294                                ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran);
295#if 0
296                                speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_GET_AGC_LOUDNESS, &loudness);
297#endif
298                                /* we want to remove 4 packets (40ms) in a near future: */
299#ifndef DISABLE_SPEEX
300                                if (chan->speex_pp!=NULL && s->enable_vad==TRUE)
301                                {
302                                        vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL);
303                                        ms_filter_notify(f, MS_CONF_SPEEX_PREPROCESS_MIC, (void*)chan->speex_pp);
304                                        if (vad==1)
305                                                break; /* voice detected: process as usual */
306                                        if (ms_bufferizer_get_avail(&chan->buff)<s->conf_gran)
307                                                break; /* no more data to remove */
308                                        ms_message("No voice detected: discarding sample. (idx=%i - bufsize=%i sncardbufsize=%i)",
309                                                i, ms_bufferizer_get_avail(&chan->buff), ms_bufferizer_get_avail(&s->channels[0].buff));
310                                }
311                                if (ms_bufferizer_get_avail(&chan->buff) == (ms_bufferizer_get_avail(&s->channels[0].buff)))
312                                        ms_message("same data in soundcard and incoming rtp. (idx=%i - bufsize=%i sncardbufsize=%i)",
313                                                i, ms_bufferizer_get_avail(&chan->buff), ms_bufferizer_get_avail(&s->channels[0].buff));
314#endif
315                                chan->stat_discarded++;
316                        }
317
318
319                        if (s->enable_halfduplex>0)
320                        {
321#if 0
322                                ms_message("prob=%i", loudness);
323#endif
324                                // LIMITATION:
325                                // HALF DUPLEX MODE IS TO BE USED WITH ONLY
326                                // ONE SOUND CARD AND ONE RTP STREAM.
327                                if (vad>0) // && loudness>20)
328                                {
329                                        /* speech detected */
330                                        s->channels[0].is_speaking++;
331                                        if (s->channels[0].is_speaking>2)
332                                                s->channels[0].is_speaking=2;
333                                }
334                                else
335                                {
336                                        s->channels[0].is_speaking--;
337                                        if (s->channels[0].is_speaking<-2)
338                                                s->channels[0].is_speaking=-2;
339                                }
340
341                                if (s->channels[0].is_speaking<=0)
342                                        ms_message("silence on! (%i)", s->channels[0].is_speaking);
343                                else
344                                        ms_message("speech on! (%i)", s->channels[0].is_speaking);
345                        }
346
347                        for(j=0;j<s->conf_nsamples;++j){
348                                s->sum[j]+=chan->input[j];
349                        }
350                        chan->has_contributed=TRUE;
351
352                        chan->stat_processed++;
353                }
354                else if (ms_bufferizer_get_avail(&chan->buff)>=s->conf_gran)
355                {
356                        ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran);
357#ifndef DISABLE_SPEEX
358                        if (chan->speex_pp!=NULL && s->enable_vad==TRUE && i==0)
359                        {
360                                int vad;
361                                vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL);
362                                //ms_filter_notify(f, MS_CONF_SPEEX_PREPROCESS_MIC, (void*)chan->speex_pp);
363                        }
364                        else if (chan->speex_pp!=NULL && s->enable_vad==TRUE)
365                        {
366#if 0
367                                int loudness;
368#endif
369                                int vad;
370                                if (s->enable_halfduplex>0)
371                                {
372                                        vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL);
373                                        ms_filter_notify(f, MS_CONF_SPEEX_PREPROCESS_MIC, (void*)chan->speex_pp);
374#if 0
375                                        speex_preprocess_ctl(chan->speex_pp, SPEEX_PREPROCESS_GET_AGC_LOUDNESS, &loudness);
376                                        ms_message("prob=%i", loudness);
377#endif
378                                        // LIMITATION:
379                                        // HALF DUPLEX MODE IS TO BE USED WITH ONLY
380                                        // ONE SOUND CARD AND ONE RTP STREAM.
381                                        if (vad>0) //&& loudness>20)
382                                        {
383                                                s->channels[0].is_speaking++;
384                                                if (s->channels[0].is_speaking>2)
385                                                        s->channels[0].is_speaking=2;
386                                        }
387                                        else
388                                        {
389                                                s->channels[0].is_speaking--;
390                                                if (s->channels[0].is_speaking<-2)
391                                                        s->channels[0].is_speaking=-2;
392                                        }
393
394                                        if (s->channels[0].is_speaking<=0)
395                                                ms_message("silence on! (%i)", s->channels[0].is_speaking);
396                                        else
397                                                ms_message("speech on! (%i)", s->channels[0].is_speaking);
398                                }
399                                else
400                                {
401                                        vad = speex_preprocess(chan->speex_pp, (short*)chan->input, NULL);
402                                        //speex_preprocess_estimate_update(chan->speex_pp, (short*)chan->input);
403                                        ms_filter_notify(f, MS_CONF_SPEEX_PREPROCESS_MIC, (void*)chan->speex_pp);
404                                }
405                        }
406#endif
407
408                        for(j=0;j<s->conf_nsamples;++j){
409                                s->sum[j]+=chan->input[j];
410                        }
411                        chan->has_contributed=TRUE;
412
413                        chan->stat_processed++;
414                } else {
415                        chan->stat_missed++;
416                        if (i>0 && chan->is_used == TRUE)
417                        {
418                                chan->missed++;
419                                /* delete stream if data is missing since a long time */
420                                if (chan->missed>15)
421                                {
422                                        chan->is_used=FALSE;
423                                        ms_message("msconf: deleted contributing stream (pin=%i)", i);
424                                }
425                                /* couldn't we add confort noise for those outputs? */
426                        }
427                        chan->has_contributed=FALSE;
428                }
429        }
430        return;
431}
432
433static inline int16_t saturate(int sample){
434        if (sample>32000)
435                sample=32000;
436        else if (sample<-32000)
437                sample=-32000;
438        return (int16_t)sample;
439}
440
441static mblk_t * conf_output(ConfState *s, Channel *chan){
442        mblk_t *m=allocb(s->conf_gran,0);
443        int i;
444        int tmp;
445        if (chan->has_contributed==TRUE){
446                for (i=0;i<s->conf_nsamples;++i){
447                        tmp=s->sum[i]-(int)chan->input[i];
448                        *((int16_t*)m->b_wptr)=saturate(tmp);
449                        m->b_wptr+=2;
450                }
451        }else{
452                for (i=0;i<s->conf_nsamples;++i){
453                        tmp=s->sum[i];
454                        *((int16_t*)m->b_wptr)=saturate(tmp);
455                        m->b_wptr+=2;
456                }
457        }
458        return m;
459}
460
461static void conf_dispatch(MSFilter *f, ConfState *s){
462        int i;
463        Channel *chan;
464        mblk_t *m;
465        //memset(s->sum,0,s->conf_nsamples*sizeof(int));
466        for (i=0;i<CONF_MAX_PINS;++i){
467                if (f->outputs[i]!=NULL){
468                        chan=&s->channels[i];
469                        if (s->channels[0].is_speaking<=0 || i%2==0) // RTP is silent, work as usual
470                                m=conf_output(s,chan);
471                        else
472                        {
473                                m=allocb(s->conf_gran,0);
474                                int k;
475                                for (k=0;k<s->conf_nsamples;++k){
476                                        *((int16_t*)m->b_wptr)=0;
477                                        m->b_wptr+=2;
478                                }
479                        }
480                        ms_queue_put(f->outputs[i],m);
481                }
482        }
483}
484
485static void conf_process(MSFilter *f){
486        int i;
487        ConfState *s=(ConfState*)f->data;
488        Channel *chan;
489        Channel *chan0;
490        /*read from all inputs and put into bufferizers*/
491        for (i=0;i<CONF_MAX_PINS;++i){
492                if (f->inputs[i]!=NULL){
493                        chan=&s->channels[i];
494                        ms_bufferizer_put_from_queue(&chan->buff,f->inputs[i]);
495                        if (ms_bufferizer_get_avail(&chan->buff)>0)
496                        {
497                                chan->missed=0; /* reset counter of missed packet */
498                                if (i>0 && chan->is_used==FALSE)
499                                {
500                                        chan->is_used=TRUE;
501                                        ms_message("msconf: new contributing stream", ms_bufferizer_get_avail(&chan->buff));
502                                }
503                        }
504                }
505        }
506
507        /*do the job */
508        while(should_process(f,s)==TRUE){
509                conf_sum(f, s);
510                conf_dispatch(f,s);
511        }
512
513        /* mixer is disabled! -> copy A->B and B->A*/
514        if (s->mix_mode == FALSE)
515        {
516                /* get the soundread data and copy it to pinX */
517                for (i=1;i<CONF_MAX_PINS;i=i+2){
518                        if (f->inputs[i]!=NULL){
519                                chan0=&s->channels[0];
520                                chan=&s->channels[i];
521                                if (chan->is_used==TRUE)
522                                {
523                                        while (ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,s->conf_gran)==s->conf_gran)
524                                        {
525                                                if (f->outputs[0]!=NULL)
526                                                {
527                                                        /* send in pin0 */
528                                                        mblk_t *m=allocb(s->conf_gran,0);
529                                                        memcpy(m->b_wptr, chan->input, s->conf_gran);
530                                                        m->b_wptr+=s->conf_gran;
531                                                        ms_queue_put(f->outputs[0],m);
532                                                }
533                                        }
534                                }
535
536                                if (chan0->is_used==TRUE)
537                                {
538                                        while (ms_bufferizer_read(&chan0->buff,(uint8_t*)chan0->input,s->conf_gran)==s->conf_gran)
539                                        {
540                                                if (f->outputs[i]!=NULL)
541                                                {
542                                                        /* send in pinI */
543                                                        mblk_t *m=allocb(s->conf_gran,0);
544                                                        memcpy(m->b_wptr, chan0->input, s->conf_gran);
545                                                        m->b_wptr+=s->conf_gran;
546                                                        ms_queue_put(f->outputs[i],m);
547                                                }
548                                        }
549                                }
550                                break;
551                        }
552                }
553        }
554
555}
556
557static void conf_postprocess(MSFilter *f){
558        int i;
559        ConfState *s=(ConfState*)f->data;
560        for (i=0;i<CONF_MAX_PINS;i++)
561                channel_uninit(&s->channels[i]);
562    for (i=0;i<CONF_MAX_PINS;i++)
563                channel_init(s, &s->channels[i], i);
564}
565
566static int msconf_set_sr(MSFilter *f, void *arg){
567        ConfState *s=(ConfState*)f->data;
568        int i;
569
570        s->samplerate = *(int*)arg;
571        s->conf_gran = ((16 * s->samplerate) / 800) *2;
572        s->conf_nsamples=s->conf_gran/2;
573        for (i=0;i<CONF_MAX_PINS;i++)
574                channel_uninit(&s->channels[i]);
575    for (i=0;i<CONF_MAX_PINS;i++)
576                channel_init(s, &s->channels[i], i);
577        return 0;
578}
579
580static int msconf_enable_directmode(MSFilter *f, void *arg){
581        ConfState *s=(ConfState*)f->data;
582        s->enable_directmode = *(int*)arg;
583        return 0;
584}
585
586static int msconf_enable_agc(MSFilter *f, void *arg){
587        ConfState *s=(ConfState*)f->data;
588        int i;
589        s->agc_level = *(int*)arg;
590
591        for (i=0;i<CONF_MAX_PINS;i++)
592                channel_uninit(&s->channels[i]);
593    for (i=0;i<CONF_MAX_PINS;i++)
594                channel_init(s, &s->channels[i], i);
595        return 0;
596}
597
598static int msconf_enable_halfduplex(MSFilter *f, void *arg){
599        ConfState *s=(ConfState*)f->data;
600        int i;
601        s->enable_halfduplex = *(int*)arg;
602
603        for (i=0;i<CONF_MAX_PINS;i++)
604                channel_uninit(&s->channels[i]);
605    for (i=0;i<CONF_MAX_PINS;i++)
606                channel_init(s, &s->channels[i], i);
607        return 0;
608}
609
610static int msconf_set_vad_prob_start(MSFilter *f, void *arg){
611        ConfState *s=(ConfState*)f->data;
612        int i;
613        s->vad_prob_start = *(int*)arg;
614
615        for (i=0;i<CONF_MAX_PINS;i++)
616                channel_uninit(&s->channels[i]);
617    for (i=0;i<CONF_MAX_PINS;i++)
618                channel_init(s, &s->channels[i], i);
619        return 0;
620}
621
622static int msconf_set_vad_prob_continue(MSFilter *f, void *arg){
623        ConfState *s=(ConfState*)f->data;
624        int i;
625        s->vad_prob_continue = *(int*)arg;
626
627        for (i=0;i<CONF_MAX_PINS;i++)
628                channel_uninit(&s->channels[i]);
629    for (i=0;i<CONF_MAX_PINS;i++)
630                channel_init(s, &s->channels[i], i);
631        return 0;
632}
633
634static int msconf_enable_vad(MSFilter *f, void *arg){
635        ConfState *s=(ConfState*)f->data;
636        int i;
637        s->enable_vad = *(int*)arg;
638
639        for (i=0;i<CONF_MAX_PINS;i++)
640                channel_uninit(&s->channels[i]);
641    for (i=0;i<CONF_MAX_PINS;i++)
642                channel_init(s, &s->channels[i], i);
643        return 0;
644}
645
646static int msconf_get_stat_discarded(MSFilter *f, void *arg){
647        ConfState *s=(ConfState*)f->data;
648        Channel *chan;
649        int i;
650        i = *(int*)arg;
651        /*read from all inputs and put into bufferizers*/
652        if (i<0 || i>CONF_MAX_PINS)
653          return -1;
654
655        if (f->inputs[i]!=NULL){
656                chan=&s->channels[i];
657                return chan->stat_discarded;
658        }
659        return -1;
660}
661
662static int msconf_get_stat_missed(MSFilter *f, void *arg){
663        ConfState *s=(ConfState*)f->data;
664        Channel *chan;
665        int i;
666        i = *(int*)arg;
667        /*read from all inputs and put into bufferizers*/
668        if (i<0 || i>CONF_MAX_PINS)
669          return -1;
670
671        if (f->inputs[i]!=NULL){
672                chan=&s->channels[i];
673                return chan->stat_missed;
674        }
675        return -1;
676}
677
678static int msconf_get_stat_processed(MSFilter *f, void *arg){
679        ConfState *s=(ConfState*)f->data;
680        Channel *chan;
681        int i;
682        i = *(int*)arg;
683        /*read from all inputs and put into bufferizers*/
684        if (i<0 || i>CONF_MAX_PINS)
685          return -1;
686
687        if (f->inputs[i]!=NULL){
688                chan=&s->channels[i];
689                return chan->stat_processed;
690        }
691        return -1;
692}
693
694static MSFilterMethod msconf_methods[]={
695        {       MS_FILTER_SET_SAMPLE_RATE, msconf_set_sr },
696        {       MS_FILTER_ENABLE_DIRECTMODE, msconf_enable_directmode },
697        {       MS_FILTER_ENABLE_VAD, msconf_enable_vad },
698        {       MS_FILTER_ENABLE_AGC, msconf_enable_agc },
699        {       MS_FILTER_GET_STAT_DISCARDED, msconf_get_stat_discarded },
700        {       MS_FILTER_GET_STAT_MISSED, msconf_get_stat_missed },
701        {       MS_FILTER_GET_STAT_OUTPUT, msconf_get_stat_processed },
702
703        {       MS_FILTER_ENABLE_HALFDUPLEX, msconf_enable_halfduplex },
704        {       MS_FILTER_SET_VAD_PROB_START, msconf_set_vad_prob_start },
705        {       MS_FILTER_SET_VAD_PROB_CONTINUE, msconf_set_vad_prob_continue },
706        {       0                       , NULL}
707};
708
709#ifdef _MSC_VER
710
711MSFilterDesc ms_conf_desc={
712        MS_CONF_ID,
713        "MSConf",
714        N_("A filter to make conferencing"),
715        MS_FILTER_OTHER,
716        NULL,
717        CONF_MAX_PINS,
718        CONF_MAX_PINS,
719        conf_init,
720        conf_preprocess,
721        conf_process,
722        conf_postprocess,
723        conf_uninit,
724        msconf_methods
725};
726
727#else
728
729MSFilterDesc ms_conf_desc={
730        .id=MS_CONF_ID,
731        .name="MSConf",
732        .text=N_("A filter to make conferencing"),
733        .category=MS_FILTER_OTHER,
734        .ninputs=CONF_MAX_PINS,
735        .noutputs=CONF_MAX_PINS,
736        .init=conf_init,
737        .preprocess=conf_preprocess,
738        .process=conf_process,
739        .postprocess=conf_postprocess,
740        .uninit=conf_uninit,
741        .methods=msconf_methods
742};
743
744#endif
745
746MS_FILTER_DESC_EXPORT(ms_conf_desc)
Note: See TracBrowser for help on using the repository browser.