~ubuntu-branches/ubuntu/vivid/linphone/vivid

« back to all changes in this revision

Viewing changes to mediastreamer2/src/msconf.c

  • Committer: Bazaar Package Importer
  • Author(s): Samuel Mimram
  • Date: 2006-11-15 10:34:50 UTC
  • mfrom: (1.2.1 upstream) (2.1.8 feisty)
  • Revision ID: james.westby@ubuntu.com-20061115103450-qgafwcks2lkhctlj
* New upstream release.
* Enable video support.
* Fix mismatched #endif in mscommon.h, closes: #398307.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
mediastreamer2 library - modular sound and video processing and streaming
 
3
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
 
4
 
 
5
This program is free software; you can redistribute it and/or
 
6
modify it under the terms of the GNU General Public License
 
7
as published by the Free Software Foundation; either version 2
 
8
of the License, or (at your option) any later version.
 
9
 
 
10
This program is distributed in the hope that it will be useful,
 
11
but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
GNU General Public License for more details.
 
14
 
 
15
You should have received a copy of the GNU General Public License
 
16
along with this program; if not, write to the Free Software
 
17
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 
18
*/
 
19
 
 
20
#include "mediastreamer2/msfilter.h"
 
21
 
 
22
#ifndef CONF_GRAN_MAX
 
23
#define CONF_GRAN_MAX 12 /* limit for 'too much data' */
 
24
#endif
 
25
 
 
26
#ifndef CONF_GRAN
 
27
#define CONF_GRAN (160)
 
28
#endif
 
29
#define CONF_NSAMPLES (CONF_GRAN/2)
 
30
#ifndef CONF_MAX_PINS
 
31
#define CONF_MAX_PINS 32
 
32
#endif
 
33
 
 
34
typedef struct Channel{
 
35
        MSBufferizer buff;
 
36
        int16_t input[CONF_NSAMPLES];
 
37
        bool_t has_contributed;
 
38
#ifdef AMD_HACK
 
39
        bool_t is_used;
 
40
        int missed;
 
41
        int diff;
 
42
#endif
 
43
} Channel;
 
44
 
 
45
typedef struct ConfState{
 
46
        Channel channels[CONF_MAX_PINS];
 
47
        int sum[CONF_NSAMPLES];
 
48
} ConfState;
 
49
 
 
50
 
 
51
static void channel_init(Channel *chan){
 
52
        ms_bufferizer_init(&chan->buff);
 
53
}
 
54
 
 
55
static void channel_uninit(Channel *chan){
 
56
        ms_bufferizer_uninit(&chan->buff);
 
57
}
 
58
 
 
59
static void conf_init(MSFilter *f){
 
60
        ConfState *s=ms_new0(ConfState,1);
 
61
        int i;
 
62
        for (i=0;i<CONF_MAX_PINS;i++)
 
63
                channel_init(&s->channels[i]);
 
64
        f->data=s;
 
65
}
 
66
 
 
67
static void conf_uninit(MSFilter *f){
 
68
        ConfState *s=(ConfState*)f->data;
 
69
        int i;
 
70
        for (i=0;i<CONF_MAX_PINS;i++)
 
71
                channel_uninit(&s->channels[i]);
 
72
        ms_free(f->data);
 
73
}
 
74
 
 
75
static void conf_preprocess(MSFilter *f){
 
76
#ifdef AMD_HACK
 
77
        ConfState *s=(ConfState*)f->data;
 
78
        int i;
 
79
        for (i=0;i<CONF_MAX_PINS;i++)
 
80
          {
 
81
            s->channels[i].is_used=FALSE;
 
82
            s->channels[i].missed=0;
 
83
          }
 
84
#endif
 
85
}
 
86
 
 
87
#ifndef AMD_HACK
 
88
 
 
89
static bool_t should_process(MSFilter *f, ConfState *s){
 
90
        int i;
 
91
        int has_data=0;
 
92
        int connected=0;
 
93
        Channel *chan;
 
94
        bool_t has_too_much_data=FALSE;
 
95
 
 
96
        for (i=0;i<CONF_MAX_PINS;++i){
 
97
                if (f->inputs[i]!=NULL){
 
98
                        chan=&s->channels[i];
 
99
                        ++connected;
 
100
                        if (ms_bufferizer_get_avail(&chan->buff)>=CONF_GRAN)
 
101
                                ++has_data;
 
102
                        if (ms_bufferizer_get_avail(&chan->buff)>=CONF_GRAN*CONF_GRAN_MAX){
 
103
                                has_too_much_data=TRUE;
 
104
                                break;
 
105
                        }
 
106
                }
 
107
        }
 
108
 
 
109
        return has_too_much_data || (connected==has_data);
 
110
}
 
111
 
 
112
#else
 
113
 
 
114
static bool_t should_process(MSFilter *f, ConfState *s){
 
115
        int i;
 
116
        int do_process=FALSE;
 
117
        int has_data=0;
 
118
        int connected=0;
 
119
        Channel *chan;
 
120
#if 0
 
121
        bool_t has_too_much_data=FALSE;
 
122
#endif
 
123
 
 
124
        if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>CONF_GRAN
 
125
            && s->channels[0].is_used==FALSE)
 
126
          {
 
127
            /* soundread has just started */
 
128
            s->channels[0].is_used=TRUE;
 
129
          }
 
130
        else if (s->channels[0].is_used==FALSE)
 
131
          {
 
132
            return FALSE;
 
133
          }
 
134
 
 
135
        /* check wheter streams are used */
 
136
        for (i=1;i<CONF_MAX_PINS;++i){
 
137
          if (f->inputs[i]!=NULL && (i%2==1) && s->channels[i].is_used==FALSE){
 
138
            chan=&s->channels[i];
 
139
            if (ms_bufferizer_get_avail(&chan->buff)>=3*CONF_GRAN)
 
140
              {
 
141
                int k;
 
142
                /* new contributing stream :) */
 
143
                ms_message("msconf: new contributing stream %i", i);
 
144
                s->channels[i].is_used=TRUE;
 
145
                s->channels[i].missed=0;
 
146
                
 
147
                /* reinitialize checking streams */
 
148
                s->channels[i].diff=0;
 
149
                for (k=0;k<CONF_MAX_PINS;++k){
 
150
                  if (f->inputs[k]!=NULL){
 
151
                    chan=&s->channels[k];
 
152
                    s->channels[i].diff = ms_bufferizer_get_avail(&chan->buff);
 
153
                  }
 
154
                }
 
155
              }
 
156
          }
 
157
        }
 
158
 
 
159
        /* decide wheter to process or not */
 
160
        if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)<CONF_GRAN)
 
161
          {
 
162
            do_process=FALSE;
 
163
          }
 
164
        else if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>=CONF_GRAN*CONF_GRAN_MAX)
 
165
          {
 
166
            do_process=TRUE;
 
167
 
 
168
 
 
169
            /* disable streams that are not contributing any more */
 
170
            for (i=1;i<CONF_MAX_PINS;++i){
 
171
              if (f->inputs[i]!=NULL && (i%2==1) && s->channels[i].is_used==TRUE){
 
172
                chan=&s->channels[i];
 
173
                if (ms_bufferizer_get_avail(&chan->buff)<CONF_GRAN)
 
174
                  s->channels[i].missed++;
 
175
                if (ms_bufferizer_get_avail(&chan->buff)<CONF_GRAN
 
176
                    && s->channels[i].missed==4)
 
177
                  {
 
178
                    /* delete from contributing stream :( */
 
179
                    s->channels[i].is_used=FALSE;
 
180
                    s->channels[i].missed=0;
 
181
                    ms_message("msconf: contributing stream deleted %i", i);
 
182
                  }
 
183
              }
 
184
            }
 
185
            
 
186
          }
 
187
        else
 
188
          {
 
189
            /* if a stream is_used, then check its availability.
 
190
               if a stream !is_used, then don't check it.
 
191
               only check RTP incoming stream pins.
 
192
            */
 
193
            for (i=1;i<CONF_MAX_PINS;++i){
 
194
              if (f->inputs[i]!=NULL && (i%2==1) && s->channels[i].is_used==TRUE){
 
195
                chan=&s->channels[i];
 
196
                ++connected;
 
197
                if (ms_bufferizer_get_avail(&chan->buff)>=CONF_GRAN)
 
198
                  ++has_data;
 
199
                }
 
200
            }
 
201
            if (connected==has_data)
 
202
                do_process=TRUE;
 
203
          }
 
204
 
 
205
        if (do_process==TRUE && s->channels[0].missed==500)
 
206
          {
 
207
            s->channels[0].missed=0;
 
208
            /* compare incoming and soundread streams */
 
209
            for (i=1;i<CONF_MAX_PINS;++i){
 
210
              if (f->inputs[i]!=NULL && (i%2==1) && s->channels[i].is_used==TRUE){
 
211
                int new_diff;
 
212
                int old_diff;
 
213
                chan=&s->channels[i];
 
214
                old_diff = s->channels[0].diff - s->channels[i].diff;
 
215
                new_diff = ms_bufferizer_get_avail(&s->channels[0].buff) - ms_bufferizer_get_avail(&s->channels[i].buff);
 
216
                if (new_diff-old_diff>(CONF_GRAN*2))
 
217
                  {
 
218
                    ms_message("msconf: missing data from contributing stream", new_diff-old_diff);
 
219
                  }
 
220
                else if (old_diff-new_diff>(CONF_GRAN*2))
 
221
                  {
 
222
                    int xtra_data = ms_bufferizer_get_avail(&chan->buff) - 6*CONF_GRAN;
 
223
                    int k=0;
 
224
                    if (xtra_data>0)
 
225
                      {
 
226
                        while (ms_bufferizer_get_avail(&chan->buff)>CONF_GRAN*6)
 
227
                          {
 
228
                            k++;
 
229
                            ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,CONF_GRAN);
 
230
                          }
 
231
                      }
 
232
                    ms_message("msconf: extra data from contributing stream %i", old_diff-new_diff, k*CONF_GRAN);
 
233
                    
 
234
                  }
 
235
              }
 
236
            } 
 
237
          }
 
238
        else if (do_process==TRUE)
 
239
          s->channels[0].missed++;
 
240
 
 
241
 
 
242
        return (do_process==TRUE);
 
243
#if 0
 
244
        /* case where: every one has enough data */
 
245
        if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)<CONF_GRAN)
 
246
          {
 
247
            return FALSE;
 
248
          }
 
249
        if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>=CONF_GRAN*CONF_GRAN_MAX)
 
250
          {
 
251
            for (i=1;i<CONF_MAX_PINS;++i){
 
252
              if (f->inputs[i]!=NULL && (i%2==1)){
 
253
                chan=&s->channels[i];
 
254
                ++connected;
 
255
                if (ms_bufferizer_get_avail(&chan->buff)>=CONF_GRAN)
 
256
                  ++has_data;
 
257
                if (ms_bufferizer_get_avail(&chan->buff)>=CONF_GRAN*CONF_GRAN_MAX){
 
258
                  has_too_much_data=TRUE;
 
259
                  break;
 
260
                }
 
261
              }
 
262
            }
 
263
 
 
264
            /* don't wait for missing incoming RTP packets */
 
265
            /* return has_too_much_data || (connected==has_data); */
 
266
            return TRUE;
 
267
          }
 
268
 
 
269
 
 
270
        /* The conversation timing HAS TO BE driven by soundread wich is
 
271
           the best clock we can found.
 
272
 
 
273
           To make the whole process obey this clock, the decision to
 
274
           process data for conference is decided by pin0 (soundread).
 
275
        */
 
276
 
 
277
        if (s->is_starting==TRUE)
 
278
          {
 
279
            /* we don't want to wait for incoming stream before
 
280
               we send outgoing stream! */
 
281
            
 
282
            for (i=1;i<CONF_MAX_PINS;++i){
 
283
              if (f->inputs[i]!=NULL && (i%2==1)){
 
284
                chan=&s->channels[i];
 
285
                if (ms_bufferizer_get_avail(&chan->buff)>=CONF_GRAN)
 
286
                  {
 
287
                    s->is_starting=FALSE;
 
288
                    break;
 
289
                  }
 
290
              }
 
291
            }
 
292
            if (ms_bufferizer_get_avail(&(&s->channels[0])->buff)>=CONF_GRAN)
 
293
              {
 
294
                return TRUE;
 
295
              }
 
296
            return FALSE;
 
297
          }
 
298
 
 
299
        if (has_too_much_data==TRUE)
 
300
        {
 
301
                int discarded_data;
 
302
                chan=&s->channels[0];
 
303
                discarded_data = ms_bufferizer_get_avail(&chan->buff);
 
304
                /* check if the inputs provide enough data */
 
305
                if (discarded_data>=CONF_GRAN*CONF_GRAN_MAX)
 
306
                {
 
307
                        while (ms_bufferizer_get_avail(&chan->buff)>CONF_GRAN*4)
 
308
                        {
 
309
                                ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,CONF_GRAN);
 
310
                        }
 
311
                        ms_message("msconf: data from soundread -> (%i discarded)", discarded_data - ms_bufferizer_get_avail(&chan->buff));
 
312
 
 
313
                        for (i=1;i<CONF_MAX_PINS;i=i+2){
 
314
                                if (f->inputs[i]!=NULL){
 
315
                                        chan=&s->channels[i];
 
316
                                        discarded_data = ms_bufferizer_get_avail(&chan->buff);
 
317
                                        while (ms_bufferizer_get_avail(&chan->buff)>CONF_GRAN*4)
 
318
                                        {
 
319
                                                ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,CONF_GRAN);
 
320
                                        }
 
321
                                        ms_message("msconf: data from channel%i -> (%i discarded)", i, discarded_data - ms_bufferizer_get_avail(&chan->buff));
 
322
                                }
 
323
                        }
 
324
                }
 
325
                else
 
326
                {
 
327
                        for (i=1;i<CONF_MAX_PINS;i=i+2){
 
328
                                if (f->inputs[i]!=NULL){
 
329
                                        chan=&s->channels[i];
 
330
                                        discarded_data = ms_bufferizer_get_avail(&chan->buff);
 
331
                                        if (discarded_data>=CONF_GRAN*CONF_GRAN_MAX)
 
332
                                        {
 
333
                                                while (ms_bufferizer_get_avail(&chan->buff)>CONF_GRAN*4)
 
334
                                                {
 
335
                                                        ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,CONF_GRAN);
 
336
                                                }
 
337
                                                ms_message("msconf: data from channel%i -> (%i discarded)", i, discarded_data - ms_bufferizer_get_avail(&chan->buff));
 
338
                                        }
 
339
                                }
 
340
                        }
 
341
                }
 
342
        }
 
343
 
 
344
        return has_too_much_data || (connected==has_data);
 
345
#endif
 
346
}
 
347
 
 
348
#endif
 
349
 
 
350
static void conf_sum(ConfState *s){
 
351
        int i,j;
 
352
        Channel *chan;
 
353
        memset(s->sum,0,CONF_NSAMPLES*sizeof(int));
 
354
        for (i=0;i<CONF_MAX_PINS;++i){
 
355
                chan=&s->channels[i];
 
356
                if (ms_bufferizer_read(&chan->buff,(uint8_t*)chan->input,CONF_GRAN)
 
357
                        ==CONF_GRAN){
 
358
                        for(j=0;j<CONF_NSAMPLES;++j){
 
359
                                s->sum[j]+=chan->input[j];
 
360
                        }
 
361
                        chan->has_contributed=TRUE;
 
362
                }else{
 
363
                        chan->has_contributed=FALSE;
 
364
                }
 
365
        }
 
366
}
 
367
 
 
368
static inline int16_t saturate(int sample){
 
369
        if (sample>32000)
 
370
                sample=32000;
 
371
        else if (sample<-32000)
 
372
                sample=-32000;
 
373
        return (int16_t)sample;
 
374
}
 
375
 
 
376
static mblk_t * conf_output(ConfState *s, Channel *chan){
 
377
        mblk_t *m=allocb(CONF_GRAN,0);
 
378
        int i;
 
379
        int tmp;
 
380
        if (chan->has_contributed==TRUE){
 
381
                for (i=0;i<CONF_NSAMPLES;++i){
 
382
                        tmp=s->sum[i]-(int)chan->input[i];
 
383
                        *((int16_t*)m->b_wptr)=saturate(tmp);
 
384
                        m->b_wptr+=2;
 
385
                }
 
386
        }else{
 
387
                for (i=0;i<CONF_NSAMPLES;++i){
 
388
                        tmp=s->sum[i];
 
389
                        *((int16_t*)m->b_wptr)=saturate(tmp);
 
390
                        m->b_wptr+=2;
 
391
                }
 
392
        }
 
393
        return m;
 
394
}
 
395
 
 
396
static void conf_dispatch(MSFilter *f, ConfState *s){
 
397
        int i;
 
398
        Channel *chan;
 
399
        mblk_t *m;
 
400
        //memset(s->sum,0,CONF_NSAMPLES*sizeof(int));
 
401
        for (i=0;i<CONF_MAX_PINS;++i){
 
402
                if (f->outputs[i]!=NULL){
 
403
                        chan=&s->channels[i];
 
404
                        m=conf_output(s,chan);
 
405
                        ms_queue_put(f->outputs[i],m);
 
406
                }
 
407
        }
 
408
}
 
409
 
 
410
static void conf_process(MSFilter *f){
 
411
        int i;
 
412
        ConfState *s=(ConfState*)f->data;
 
413
        Channel *chan;
 
414
        /*read from all inputs and put into bufferizers*/
 
415
        for (i=0;i<CONF_MAX_PINS;++i){
 
416
                if (f->inputs[i]!=NULL){
 
417
                        chan=&s->channels[i];
 
418
                        ms_bufferizer_put_from_queue(&chan->buff,f->inputs[i]);
 
419
                }
 
420
        }
 
421
 
 
422
        /*do the job */
 
423
        while(should_process(f,s)==TRUE){
 
424
                conf_sum(s);
 
425
                conf_dispatch(f,s);
 
426
        }
 
427
}
 
428
 
 
429
#ifdef _MSC_VER
 
430
 
 
431
MSFilterDesc ms_conf_desc={
 
432
        MS_CONF_ID,
 
433
        "MSConf",
 
434
        "A filter to make conferencing",
 
435
        MS_FILTER_OTHER,
 
436
        NULL,
 
437
        CONF_MAX_PINS,
 
438
        CONF_MAX_PINS,
 
439
        conf_init,
 
440
        conf_preprocess,
 
441
        conf_process,
 
442
        NULL,
 
443
        conf_uninit,
 
444
        NULL
 
445
};
 
446
 
 
447
#else
 
448
 
 
449
MSFilterDesc ms_conf_desc={
 
450
        .id=MS_CONF_ID,
 
451
        .name="MSConf",
 
452
        .text="A filter to make conferencing",
 
453
        .category=MS_FILTER_OTHER,
 
454
        .ninputs=CONF_MAX_PINS,
 
455
        .noutputs=CONF_MAX_PINS,
 
456
        .init=conf_init,
 
457
        .preprocess=conf_preprocess,
 
458
        .process=conf_process,
 
459
        .uninit=conf_uninit,
 
460
};
 
461
 
 
462
#endif
 
463
 
 
464
MS_FILTER_DESC_EXPORT(ms_conf_desc)