~ubuntu-branches/ubuntu/wily/sflphone/wily

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjmedia/src/pjmedia/jbuf.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (1.1.11)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: package-import@ubuntu.com-20140128182336-3xenud1kbnwmf3mz
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: jbuf.c 4369 2013-02-21 21:55:54Z bennylp $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
 
4
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 
5
 *
 
6
 * This program is free software; you can redistribute it and/or modify
 
7
 * it under the terms of the GNU General Public License as published by
 
8
 * the Free Software Foundation; either version 2 of the License, or
 
9
 * (at your option) any later version.
 
10
 *
 
11
 * This program is distributed in the hope that it will be useful,
 
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 * GNU General Public License for more details.
 
15
 *
 
16
 * You should have received a copy of the GNU General Public License
 
17
 * along with this program; if not, write to the Free Software
 
18
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 
19
 */
 
20
/*
 
21
 * Based on implementation kindly contributed by Switchlab, Ltd.
 
22
 */
 
23
#include <pjmedia/jbuf.h>
 
24
#include <pjmedia/errno.h>
 
25
#include <pj/pool.h>
 
26
#include <pj/assert.h>
 
27
#include <pj/log.h>
 
28
#include <pj/math.h>
 
29
#include <pj/string.h>
 
30
 
 
31
 
 
32
#define THIS_FILE   "jbuf.c"
 
33
 
 
34
 
 
35
/* Invalid sequence number, used as the initial value. */
 
36
#define INVALID_OFFSET          -9999
 
37
 
 
38
/* Maximum burst length, whenever an operation is bursting longer than 
 
39
 * this value, JB will assume that the opposite operation was idle.
 
40
 */
 
41
#define MAX_BURST_MSEC          1000
 
42
 
 
43
/* Number of OP switches to be performed in JB_STATUS_INITIALIZING, before
 
44
 * JB can switch its states to JB_STATUS_PROCESSING.
 
45
 */
 
46
#define INIT_CYCLE              10
 
47
 
 
48
 
 
49
/* Minimal difference between JB size and 2*burst-level to perform 
 
50
 * JB shrinking in static discard algorithm. 
 
51
 */
 
52
#define STA_DISC_SAFE_SHRINKING_DIFF    1
 
53
 
 
54
 
 
55
/* Struct of JB internal buffer, represented in a circular buffer containing
 
56
 * frame content, frame type, frame length, and frame bit info.
 
57
 */
 
58
typedef struct jb_framelist_t
 
59
{
 
60
    /* Settings */
 
61
    unsigned         frame_size;        /**< maximum size of frame          */
 
62
    unsigned         max_count;         /**< maximum number of frames       */
 
63
 
 
64
    /* Buffers */
 
65
    char            *content;           /**< frame content array            */
 
66
    int             *frame_type;        /**< frame type array               */
 
67
    pj_size_t       *content_len;       /**< frame length array             */
 
68
    pj_uint32_t     *bit_info;          /**< frame bit info array           */
 
69
    pj_uint32_t     *ts;                /**< timestamp array                */
 
70
    
 
71
    /* States */
 
72
    unsigned         head;              /**< index of head, pointed frame
 
73
                                             will be returned by next GET   */
 
74
    unsigned         size;              /**< current size of framelist, 
 
75
                                             including discarded frames.    */
 
76
    unsigned         discarded_num;     /**< current number of discarded 
 
77
                                             frames.                        */
 
78
    int              origin;            /**< original index of flist_head   */
 
79
 
 
80
} jb_framelist_t;
 
81
 
 
82
 
 
83
typedef void (*discard_algo)(pjmedia_jbuf *jb);
 
84
static void jbuf_discard_static(pjmedia_jbuf *jb);
 
85
static void jbuf_discard_progressive(pjmedia_jbuf *jb);
 
86
 
 
87
 
 
88
struct pjmedia_jbuf
 
89
{
 
90
    /* Settings (consts) */
 
91
    pj_str_t        jb_name;            /**< jitter buffer name             */
 
92
    pj_size_t       jb_frame_size;      /**< frame size                     */
 
93
    unsigned        jb_frame_ptime;     /**< frame duration.                */
 
94
    pj_size_t       jb_max_count;       /**< capacity of jitter buffer, 
 
95
                                             in frames                      */
 
96
    int             jb_init_prefetch;   /**< Initial prefetch               */
 
97
    int             jb_min_prefetch;    /**< Minimum allowable prefetch     */
 
98
    int             jb_max_prefetch;    /**< Maximum allowable prefetch     */
 
99
    int             jb_max_burst;       /**< maximum possible burst, whenever
 
100
                                             burst exceeds this value, it 
 
101
                                             won't be included in level 
 
102
                                             calculation                    */
 
103
    int             jb_min_shrink_gap;  /**< How often can we shrink        */
 
104
    discard_algo    jb_discard_algo;    /**< Discard algorithm              */
 
105
 
 
106
    /* Buffer */
 
107
    jb_framelist_t  jb_framelist;       /**< the buffer                     */
 
108
 
 
109
    /* States */
 
110
    int             jb_level;           /**< delay between source & 
 
111
                                             destination (calculated according 
 
112
                                             of the number of burst get/put 
 
113
                                             operations)                    */
 
114
    int             jb_max_hist_level;  /**< max level during the last level 
 
115
                                             calculations                   */
 
116
    int             jb_stable_hist;     /**< num of times the delay has been 
 
117
                                             lower then the prefetch num    */
 
118
    int             jb_last_op;         /**< last operation executed 
 
119
                                             (put/get)                      */
 
120
    int             jb_eff_level;       /**< effective burst level          */
 
121
    int             jb_prefetch;        /**< no. of frame to insert before 
 
122
                                             removing some (at the beginning 
 
123
                                             of the framelist->content 
 
124
                                             operation), the value may be
 
125
                                             continuously updated based on
 
126
                                             current frame burst level.     */
 
127
    pj_bool_t       jb_prefetching;     /**< flag if jbuf is prefetching.   */
 
128
    int             jb_status;          /**< status is 'init' until the first 
 
129
                                             'put' operation                */
 
130
    int             jb_init_cycle_cnt;  /**< status is 'init' until the first 
 
131
                                             'put' operation                */
 
132
 
 
133
    int             jb_discard_ref;     /**< Seq # of last frame deleted or
 
134
                                             discarded                      */
 
135
    unsigned        jb_discard_dist;    /**< Distance from jb_discard_ref
 
136
                                             to perform discard (in frm)    */
 
137
 
 
138
    /* Statistics */
 
139
    pj_math_stat    jb_delay;           /**< Delay statistics of jitter buffer 
 
140
                                             (in ms)                        */
 
141
    pj_math_stat    jb_burst;           /**< Burst statistics (in frames)   */
 
142
    unsigned        jb_lost;            /**< Number of lost frames.         */
 
143
    unsigned        jb_discard;         /**< Number of discarded frames.    */
 
144
    unsigned        jb_empty;           /**< Number of empty/prefetching frame
 
145
                                             returned by GET. */
 
146
};
 
147
 
 
148
 
 
149
#define JB_STATUS_INITIALIZING  0
 
150
#define JB_STATUS_PROCESSING    1
 
151
 
 
152
 
 
153
 
 
154
/* Progressive discard algorithm introduced to reduce JB latency
 
155
 * by discarding incoming frames with adaptive aggressiveness based on
 
156
 * actual burst level.
 
157
 */
 
158
#define PROGRESSIVE_DISCARD 1
 
159
 
 
160
/* Internal JB frame flag, discarded frame will not be returned by JB to
 
161
 * application, it's just simply discarded.
 
162
 */
 
163
#define PJMEDIA_JB_DISCARDED_FRAME 1024
 
164
 
 
165
 
 
166
 
 
167
/* Enabling this would log the jitter buffer state about once per 
 
168
 * second.
 
169
 */
 
170
#if 0
 
171
#  define TRACE__(args)     PJ_LOG(5,args)
 
172
#else
 
173
#  define TRACE__(args)
 
174
#endif
 
175
 
 
176
static pj_status_t jb_framelist_reset(jb_framelist_t *framelist);
 
177
static unsigned jb_framelist_remove_head(jb_framelist_t *framelist,
 
178
                                         unsigned count);
 
179
 
 
180
static pj_status_t jb_framelist_init( pj_pool_t *pool,
 
181
                                      jb_framelist_t *framelist,
 
182
                                      unsigned frame_size,
 
183
                                      unsigned max_count) 
 
184
{
 
185
    PJ_ASSERT_RETURN(pool && framelist, PJ_EINVAL);
 
186
 
 
187
    pj_bzero(framelist, sizeof(jb_framelist_t));
 
188
 
 
189
    framelist->frame_size   = frame_size;
 
190
    framelist->max_count    = max_count;
 
191
    framelist->content      = (char*) 
 
192
                              pj_pool_alloc(pool,
 
193
                                            framelist->frame_size* 
 
194
                                            framelist->max_count);
 
195
    framelist->frame_type   = (int*)
 
196
                              pj_pool_alloc(pool, 
 
197
                                            sizeof(framelist->frame_type[0])*
 
198
                                            framelist->max_count);
 
199
    framelist->content_len  = (pj_size_t*)
 
200
                              pj_pool_alloc(pool, 
 
201
                                            sizeof(framelist->content_len[0])*
 
202
                                            framelist->max_count);
 
203
    framelist->bit_info     = (pj_uint32_t*)
 
204
                              pj_pool_alloc(pool, 
 
205
                                            sizeof(framelist->bit_info[0])*
 
206
                                            framelist->max_count);
 
207
    framelist->ts           = (pj_uint32_t*)
 
208
                              pj_pool_alloc(pool, 
 
209
                                            sizeof(framelist->ts[0])*
 
210
                                            framelist->max_count);
 
211
 
 
212
    return jb_framelist_reset(framelist);
 
213
 
 
214
}
 
215
 
 
216
static pj_status_t jb_framelist_destroy(jb_framelist_t *framelist) 
 
217
{
 
218
    PJ_UNUSED_ARG(framelist);
 
219
    return PJ_SUCCESS;
 
220
}
 
221
 
 
222
static pj_status_t jb_framelist_reset(jb_framelist_t *framelist) 
 
223
{
 
224
    framelist->head = 0;
 
225
    framelist->origin = INVALID_OFFSET;
 
226
    framelist->size = 0;
 
227
    framelist->discarded_num = 0;
 
228
 
 
229
 
 
230
    //pj_bzero(framelist->content, 
 
231
    //       framelist->frame_size * 
 
232
    //       framelist->max_count);
 
233
 
 
234
    pj_memset(framelist->frame_type,
 
235
              PJMEDIA_JB_MISSING_FRAME,
 
236
              sizeof(framelist->frame_type[0]) * 
 
237
              framelist->max_count);
 
238
 
 
239
    pj_bzero(framelist->content_len, 
 
240
             sizeof(framelist->content_len[0]) * 
 
241
             framelist->max_count);
 
242
 
 
243
    //pj_bzero(framelist->bit_info,
 
244
    //       sizeof(framelist->bit_info[0]) * 
 
245
    //       framelist->max_count);
 
246
 
 
247
    return PJ_SUCCESS;
 
248
}
 
249
 
 
250
 
 
251
static unsigned jb_framelist_size(const jb_framelist_t *framelist) 
 
252
{
 
253
    return framelist->size;
 
254
}
 
255
 
 
256
 
 
257
static unsigned jb_framelist_eff_size(const jb_framelist_t *framelist) 
 
258
{
 
259
    return (framelist->size - framelist->discarded_num);
 
260
}
 
261
 
 
262
static int jb_framelist_origin(const jb_framelist_t *framelist) 
 
263
{
 
264
    return framelist->origin;
 
265
}
 
266
 
 
267
 
 
268
static pj_bool_t jb_framelist_get(jb_framelist_t *framelist,
 
269
                                  void *frame, pj_size_t *size,
 
270
                                  pjmedia_jb_frame_type *p_type,
 
271
                                  pj_uint32_t *bit_info,
 
272
                                  pj_uint32_t *ts,
 
273
                                  int *seq) 
 
274
{
 
275
    if (framelist->size) {
 
276
        pj_bool_t prev_discarded = PJ_FALSE;
 
277
 
 
278
        /* Skip discarded frames */
 
279
        while (framelist->frame_type[framelist->head] ==
 
280
               PJMEDIA_JB_DISCARDED_FRAME)
 
281
        {
 
282
            jb_framelist_remove_head(framelist, 1);
 
283
            prev_discarded = PJ_TRUE;
 
284
        }
 
285
 
 
286
        /* Return the head frame if any */
 
287
        if (framelist->size) {
 
288
            if (prev_discarded) {
 
289
                /* Ticket #1188: when previous frame(s) was discarded, return
 
290
                 * 'missing' frame to trigger PLC to get smoother signal.
 
291
                 */
 
292
                *p_type = PJMEDIA_JB_MISSING_FRAME;
 
293
                if (size)
 
294
                    *size = 0;
 
295
                if (bit_info)
 
296
                    *bit_info = 0;
 
297
            } else {
 
298
                pj_memcpy(frame, 
 
299
                          framelist->content + 
 
300
                          framelist->head * framelist->frame_size,
 
301
                          framelist->frame_size);
 
302
                *p_type = (pjmedia_jb_frame_type) 
 
303
                          framelist->frame_type[framelist->head];
 
304
                if (size)
 
305
                    *size   = framelist->content_len[framelist->head];
 
306
                if (bit_info)
 
307
                    *bit_info = framelist->bit_info[framelist->head];
 
308
            }
 
309
            if (ts)
 
310
                *ts = framelist->ts[framelist->head];
 
311
            if (seq)
 
312
                *seq = framelist->origin;
 
313
 
 
314
            //pj_bzero(framelist->content + 
 
315
            //   framelist->head * framelist->frame_size,
 
316
            //   framelist->frame_size);
 
317
            framelist->frame_type[framelist->head] = PJMEDIA_JB_MISSING_FRAME;
 
318
            framelist->content_len[framelist->head] = 0;
 
319
            framelist->bit_info[framelist->head] = 0;
 
320
            framelist->ts[framelist->head] = 0;
 
321
 
 
322
            framelist->origin++;
 
323
            framelist->head = (framelist->head + 1) % framelist->max_count;
 
324
            framelist->size--;
 
325
        
 
326
            return PJ_TRUE;
 
327
        }
 
328
    }
 
329
 
 
330
    /* No frame available */
 
331
    pj_bzero(frame, framelist->frame_size);
 
332
 
 
333
    return PJ_FALSE;
 
334
}
 
335
 
 
336
 
 
337
static pj_bool_t jb_framelist_peek(jb_framelist_t *framelist,
 
338
                                   unsigned offset,
 
339
                                   const void **frame,
 
340
                                   pj_size_t *size,
 
341
                                   pjmedia_jb_frame_type *type,
 
342
                                   pj_uint32_t *bit_info,
 
343
                                   pj_uint32_t *ts,
 
344
                                   int *seq) 
 
345
{
 
346
    unsigned pos, idx;
 
347
 
 
348
    if (offset >= jb_framelist_eff_size(framelist))
 
349
        return PJ_FALSE;
 
350
 
 
351
    pos = framelist->head;
 
352
    idx = offset;
 
353
 
 
354
    /* Find actual peek position, note there may be discarded frames */
 
355
    while (1) {
 
356
        if (framelist->frame_type[pos] != PJMEDIA_JB_DISCARDED_FRAME) {
 
357
            if (idx == 0)
 
358
                break;
 
359
            else
 
360
                --idx;
 
361
        }
 
362
        pos = (pos + 1) % framelist->max_count;
 
363
    }
 
364
 
 
365
    /* Return the frame pointer */
 
366
    if (frame)
 
367
        *frame = framelist->content + pos*framelist->frame_size;
 
368
    if (type)
 
369
        *type = (pjmedia_jb_frame_type) 
 
370
                framelist->frame_type[pos];
 
371
    if (size)
 
372
        *size = framelist->content_len[pos];
 
373
    if (bit_info)
 
374
        *bit_info = framelist->bit_info[pos];
 
375
    if (ts)
 
376
        *ts = framelist->ts[pos];
 
377
    if (seq)
 
378
        *seq = framelist->origin + offset;
 
379
 
 
380
    return PJ_TRUE;
 
381
}
 
382
 
 
383
 
 
384
/* Remove oldest frames as many as param 'count' */
 
385
static unsigned jb_framelist_remove_head(jb_framelist_t *framelist,
 
386
                                         unsigned count) 
 
387
{
 
388
    if (count > framelist->size) 
 
389
        count = framelist->size;
 
390
 
 
391
    if (count) {
 
392
        /* may be done in two steps if overlapping */
 
393
        unsigned step1,step2;
 
394
        unsigned tmp = framelist->head+count;
 
395
        unsigned i;
 
396
 
 
397
        if (tmp > framelist->max_count) {
 
398
            step1 = framelist->max_count - framelist->head;
 
399
            step2 = count-step1;
 
400
        } else {
 
401
            step1 = count;
 
402
            step2 = 0;
 
403
        }
 
404
 
 
405
        for (i = framelist->head; i < (framelist->head + step1); ++i) {
 
406
            if (framelist->frame_type[i] == PJMEDIA_JB_DISCARDED_FRAME) {
 
407
                pj_assert(framelist->discarded_num > 0);
 
408
                framelist->discarded_num--;
 
409
            }
 
410
        }
 
411
 
 
412
        //pj_bzero(framelist->content + 
 
413
        //          framelist->head * framelist->frame_size,
 
414
        //          step1*framelist->frame_size);
 
415
        pj_memset(framelist->frame_type+framelist->head,
 
416
                  PJMEDIA_JB_MISSING_FRAME,
 
417
                  step1*sizeof(framelist->frame_type[0]));
 
418
        pj_bzero(framelist->content_len+framelist->head,
 
419
                 step1*sizeof(framelist->content_len[0]));
 
420
 
 
421
        if (step2) {
 
422
            for (i = 0; i < step2; ++i) {
 
423
                if (framelist->frame_type[i] == PJMEDIA_JB_DISCARDED_FRAME) {
 
424
                    pj_assert(framelist->discarded_num > 0);
 
425
                    framelist->discarded_num--;
 
426
                }
 
427
            }
 
428
            //pj_bzero( framelist->content,
 
429
            //        step2*framelist->frame_size);
 
430
            pj_memset(framelist->frame_type,
 
431
                      PJMEDIA_JB_MISSING_FRAME,
 
432
                      step2*sizeof(framelist->frame_type[0]));
 
433
            pj_bzero (framelist->content_len,
 
434
                      step2*sizeof(framelist->content_len[0]));
 
435
        }
 
436
 
 
437
        /* update states */
 
438
        framelist->origin += count;
 
439
        framelist->head = (framelist->head + count) % framelist->max_count;
 
440
        framelist->size -= count;
 
441
    }
 
442
    
 
443
    return count;
 
444
}
 
445
 
 
446
 
 
447
static pj_status_t jb_framelist_put_at(jb_framelist_t *framelist,
 
448
                                       int index,
 
449
                                       const void *frame,
 
450
                                       unsigned frame_size,
 
451
                                       pj_uint32_t bit_info,
 
452
                                       pj_uint32_t ts,
 
453
                                       unsigned frame_type)
 
454
{
 
455
    int distance;
 
456
    unsigned pos;
 
457
    enum { MAX_MISORDER = 100 };
 
458
    enum { MAX_DROPOUT = 3000 };
 
459
 
 
460
    PJ_ASSERT_RETURN(frame_size <= framelist->frame_size, PJ_EINVAL);
 
461
 
 
462
    /* too late or sequence restart */
 
463
    if (index < framelist->origin) {
 
464
        if (framelist->origin - index < MAX_MISORDER) {
 
465
            /* too late */
 
466
            return PJ_ETOOSMALL;
 
467
        } else {
 
468
            /* sequence restart */
 
469
            framelist->origin = index - framelist->size;
 
470
        }
 
471
    }
 
472
 
 
473
    /* if jbuf is empty, just reset the origin */
 
474
    if (framelist->size == 0) {
 
475
        pj_assert(framelist->discarded_num == 0);
 
476
        framelist->origin = index;
 
477
    }
 
478
 
 
479
    /* get distance of this frame to the first frame in the buffer */
 
480
    distance = index - framelist->origin;
 
481
 
 
482
    /* far jump, the distance is greater than buffer capacity */
 
483
    if (distance >= (int)framelist->max_count) {
 
484
        if (distance > MAX_DROPOUT) {
 
485
            /* jump too far, reset the buffer */
 
486
            jb_framelist_reset(framelist);
 
487
            framelist->origin = index;
 
488
            distance = 0;
 
489
        } else {
 
490
            /* otherwise, reject the frame */
 
491
            return PJ_ETOOMANY;
 
492
        }
 
493
    }
 
494
 
 
495
    /* get the slot position */
 
496
    pos = (framelist->head + distance) % framelist->max_count;
 
497
 
 
498
    /* if the slot is occupied, it must be duplicated frame, ignore it. */
 
499
    if (framelist->frame_type[pos] != PJMEDIA_JB_MISSING_FRAME)
 
500
        return PJ_EEXISTS;
 
501
 
 
502
    /* put the frame into the slot */
 
503
    framelist->frame_type[pos] = frame_type;
 
504
    framelist->content_len[pos] = frame_size;
 
505
    framelist->bit_info[pos] = bit_info;
 
506
    framelist->ts[pos] = ts;
 
507
 
 
508
    /* update framelist size */
 
509
    if (framelist->origin + (int)framelist->size <= index)
 
510
        framelist->size = distance + 1;
 
511
 
 
512
    if(PJMEDIA_JB_NORMAL_FRAME == frame_type) {
 
513
        /* copy frame content */
 
514
        pj_memcpy(framelist->content + pos * framelist->frame_size,
 
515
                  frame, frame_size);
 
516
    }
 
517
 
 
518
    return PJ_SUCCESS;
 
519
}
 
520
 
 
521
 
 
522
static pj_status_t jb_framelist_discard(jb_framelist_t *framelist,
 
523
                                        int index)
 
524
{
 
525
    unsigned pos;
 
526
 
 
527
    PJ_ASSERT_RETURN(index >= framelist->origin &&
 
528
                     index <  framelist->origin + (int)framelist->size,
 
529
                     PJ_EINVAL);
 
530
 
 
531
    /* Get the slot position */
 
532
    pos = (framelist->head + (index - framelist->origin)) %
 
533
          framelist->max_count;
 
534
 
 
535
    /* Discard the frame */
 
536
    framelist->frame_type[pos] = PJMEDIA_JB_DISCARDED_FRAME;
 
537
    framelist->discarded_num++;
 
538
 
 
539
    return PJ_SUCCESS;
 
540
}
 
541
 
 
542
 
 
543
enum pjmedia_jb_op
 
544
{
 
545
    JB_OP_INIT  = -1,
 
546
    JB_OP_PUT   = 1,
 
547
    JB_OP_GET   = 2
 
548
};
 
549
 
 
550
 
 
551
PJ_DEF(pj_status_t) pjmedia_jbuf_create(pj_pool_t *pool, 
 
552
                                        const pj_str_t *name,
 
553
                                        unsigned frame_size, 
 
554
                                        unsigned ptime,
 
555
                                        unsigned max_count,
 
556
                                        pjmedia_jbuf **p_jb)
 
557
{
 
558
    pjmedia_jbuf *jb;
 
559
    pj_status_t status;
 
560
 
 
561
    jb = PJ_POOL_ZALLOC_T(pool, pjmedia_jbuf);
 
562
 
 
563
    status = jb_framelist_init(pool, &jb->jb_framelist, frame_size, max_count);
 
564
    if (status != PJ_SUCCESS)
 
565
        return status;
 
566
 
 
567
    pj_strdup_with_null(pool, &jb->jb_name, name);
 
568
    jb->jb_frame_size    = frame_size;
 
569
    jb->jb_frame_ptime   = ptime;
 
570
    jb->jb_prefetch      = PJ_MIN(PJMEDIA_JB_DEFAULT_INIT_DELAY,max_count*4/5);
 
571
    jb->jb_min_prefetch  = 0;
 
572
    jb->jb_max_prefetch  = max_count*4/5;
 
573
    jb->jb_max_count     = max_count;
 
574
    jb->jb_min_shrink_gap= PJMEDIA_JBUF_DISC_MIN_GAP / ptime;
 
575
    jb->jb_max_burst     = PJ_MAX(MAX_BURST_MSEC / ptime, max_count*3/4);
 
576
 
 
577
    pj_math_stat_init(&jb->jb_delay);
 
578
    pj_math_stat_init(&jb->jb_burst);
 
579
 
 
580
    pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_PROGRESSIVE);
 
581
    pjmedia_jbuf_reset(jb);
 
582
 
 
583
    *p_jb = jb;
 
584
    return PJ_SUCCESS;
 
585
}
 
586
 
 
587
 
 
588
/*
 
589
 * Set the jitter buffer to fixed delay mode. The default behavior
 
590
 * is to adapt the delay with actual packet delay.
 
591
 *
 
592
 */
 
593
PJ_DEF(pj_status_t) pjmedia_jbuf_set_fixed( pjmedia_jbuf *jb,
 
594
                                            unsigned prefetch)
 
595
{
 
596
    PJ_ASSERT_RETURN(jb, PJ_EINVAL);
 
597
    PJ_ASSERT_RETURN(prefetch <= jb->jb_max_count, PJ_EINVAL);
 
598
 
 
599
    jb->jb_min_prefetch = jb->jb_max_prefetch = 
 
600
        jb->jb_prefetch = jb->jb_init_prefetch = prefetch;
 
601
 
 
602
    pjmedia_jbuf_set_discard(jb, PJMEDIA_JB_DISCARD_NONE);
 
603
    return PJ_SUCCESS;
 
604
}
 
605
 
 
606
 
 
607
/*
 
608
 * Set the jitter buffer to adaptive mode.
 
609
 */
 
610
PJ_DEF(pj_status_t) pjmedia_jbuf_set_adaptive( pjmedia_jbuf *jb,
 
611
                                               unsigned prefetch,
 
612
                                               unsigned min_prefetch,
 
613
                                               unsigned max_prefetch)
 
614
{
 
615
    PJ_ASSERT_RETURN(jb, PJ_EINVAL);
 
616
    PJ_ASSERT_RETURN(min_prefetch <= max_prefetch &&
 
617
                     prefetch <= max_prefetch &&
 
618
                     max_prefetch <= jb->jb_max_count,
 
619
                     PJ_EINVAL);
 
620
 
 
621
    jb->jb_prefetch = jb->jb_init_prefetch = prefetch;
 
622
    jb->jb_min_prefetch = min_prefetch;
 
623
    jb->jb_max_prefetch = max_prefetch;
 
624
 
 
625
    return PJ_SUCCESS;
 
626
}
 
627
 
 
628
 
 
629
PJ_DEF(pj_status_t) pjmedia_jbuf_set_discard( pjmedia_jbuf *jb,
 
630
                                              pjmedia_jb_discard_algo algo)
 
631
{
 
632
    PJ_ASSERT_RETURN(jb, PJ_EINVAL);
 
633
    PJ_ASSERT_RETURN(algo >= PJMEDIA_JB_DISCARD_NONE &&
 
634
                     algo <= PJMEDIA_JB_DISCARD_PROGRESSIVE,
 
635
                     PJ_EINVAL);
 
636
 
 
637
    switch(algo) {
 
638
    case PJMEDIA_JB_DISCARD_PROGRESSIVE:
 
639
        jb->jb_discard_algo = &jbuf_discard_progressive;
 
640
        break;
 
641
    case PJMEDIA_JB_DISCARD_STATIC:
 
642
        jb->jb_discard_algo = &jbuf_discard_static;
 
643
        break;
 
644
    default:
 
645
        jb->jb_discard_algo = NULL;
 
646
        break;
 
647
    }
 
648
 
 
649
    return PJ_SUCCESS;
 
650
}
 
651
 
 
652
 
 
653
PJ_DEF(pj_status_t) pjmedia_jbuf_reset(pjmedia_jbuf *jb)
 
654
{
 
655
    jb->jb_level         = 0;
 
656
    jb->jb_last_op       = JB_OP_INIT;
 
657
    jb->jb_stable_hist   = 0;
 
658
    jb->jb_status        = JB_STATUS_INITIALIZING;
 
659
    jb->jb_init_cycle_cnt= 0;
 
660
    jb->jb_max_hist_level= 0;
 
661
    jb->jb_prefetching   = (jb->jb_prefetch != 0);
 
662
    jb->jb_discard_dist  = 0;
 
663
 
 
664
    jb_framelist_reset(&jb->jb_framelist);
 
665
 
 
666
    return PJ_SUCCESS;
 
667
}
 
668
 
 
669
 
 
670
PJ_DEF(pj_status_t) pjmedia_jbuf_destroy(pjmedia_jbuf *jb)
 
671
{
 
672
    PJ_LOG(5, (jb->jb_name.ptr, ""
 
673
               "JB summary:\n"
 
674
               "  size=%d/eff=%d prefetch=%d level=%d\n"
 
675
               "  delay (min/max/avg/dev)=%d/%d/%d/%d ms\n"
 
676
               "  burst (min/max/avg/dev)=%d/%d/%d/%d frames\n"
 
677
               "  lost=%d discard=%d empty=%d",
 
678
               jb_framelist_size(&jb->jb_framelist), 
 
679
               jb_framelist_eff_size(&jb->jb_framelist), 
 
680
               jb->jb_prefetch, jb->jb_eff_level,
 
681
               jb->jb_delay.min, jb->jb_delay.max, jb->jb_delay.mean, 
 
682
               pj_math_stat_get_stddev(&jb->jb_delay),
 
683
               jb->jb_burst.min, jb->jb_burst.max, jb->jb_burst.mean, 
 
684
               pj_math_stat_get_stddev(&jb->jb_burst),
 
685
               jb->jb_lost, jb->jb_discard, jb->jb_empty));
 
686
 
 
687
    return jb_framelist_destroy(&jb->jb_framelist);
 
688
}
 
689
 
 
690
PJ_DEF(pj_bool_t) pjmedia_jbuf_is_full(const pjmedia_jbuf *jb)
 
691
{
 
692
    return jb->jb_framelist.size == jb->jb_framelist.max_count;
 
693
}
 
694
 
 
695
static void jbuf_calculate_jitter(pjmedia_jbuf *jb)
 
696
{
 
697
    int diff, cur_size;
 
698
 
 
699
    cur_size = jb_framelist_eff_size(&jb->jb_framelist);
 
700
    pj_math_stat_update(&jb->jb_burst, jb->jb_level);
 
701
    jb->jb_max_hist_level = PJ_MAX(jb->jb_max_hist_level, jb->jb_level);
 
702
 
 
703
    /* Burst level is decreasing */
 
704
    if (jb->jb_level < jb->jb_eff_level) {
 
705
 
 
706
        enum { STABLE_HISTORY_LIMIT = 20 };
 
707
        
 
708
        jb->jb_stable_hist++;
 
709
        
 
710
        /* Only update the effective level (and prefetch) if 'stable' 
 
711
         * condition is reached (not just short time impulse)
 
712
         */
 
713
        if (jb->jb_stable_hist > STABLE_HISTORY_LIMIT) {
 
714
        
 
715
            diff = (jb->jb_eff_level - jb->jb_max_hist_level) / 3;
 
716
 
 
717
            if (diff < 1)
 
718
                diff = 1;
 
719
 
 
720
            /* Update effective burst level */
 
721
            jb->jb_eff_level -= diff;
 
722
 
 
723
            /* Update prefetch based on level */
 
724
            if (jb->jb_init_prefetch) {
 
725
                jb->jb_prefetch = jb->jb_eff_level;
 
726
                if (jb->jb_prefetch < jb->jb_min_prefetch) 
 
727
                    jb->jb_prefetch = jb->jb_min_prefetch;
 
728
                if (jb->jb_prefetch > jb->jb_max_prefetch)
 
729
                    jb->jb_prefetch = jb->jb_max_prefetch;
 
730
            }
 
731
 
 
732
            /* Reset history */
 
733
            jb->jb_max_hist_level = 0;
 
734
            jb->jb_stable_hist = 0;
 
735
 
 
736
            TRACE__((jb->jb_name.ptr,"jb updated(1), lvl=%d pre=%d, size=%d",
 
737
                     jb->jb_eff_level, jb->jb_prefetch, cur_size));
 
738
        }
 
739
    }
 
740
 
 
741
    /* Burst level is increasing */
 
742
    else if (jb->jb_level > jb->jb_eff_level) {
 
743
 
 
744
        /* Instaneous set effective burst level to recent maximum level */
 
745
        jb->jb_eff_level = PJ_MIN(jb->jb_max_hist_level,
 
746
                                  (int)(jb->jb_max_count*4/5));
 
747
 
 
748
        /* Update prefetch based on level */
 
749
        if (jb->jb_init_prefetch) {
 
750
            jb->jb_prefetch = jb->jb_eff_level;
 
751
            if (jb->jb_prefetch > jb->jb_max_prefetch)
 
752
                jb->jb_prefetch = jb->jb_max_prefetch;
 
753
            if (jb->jb_prefetch < jb->jb_min_prefetch)
 
754
                jb->jb_prefetch = jb->jb_min_prefetch;
 
755
        }
 
756
 
 
757
        jb->jb_stable_hist = 0;
 
758
        /* Do not reset max_hist_level. */
 
759
        //jb->jb_max_hist_level = 0;
 
760
 
 
761
        TRACE__((jb->jb_name.ptr,"jb updated(2), lvl=%d pre=%d, size=%d", 
 
762
                 jb->jb_eff_level, jb->jb_prefetch, cur_size));
 
763
    }
 
764
 
 
765
    /* Level is unchanged */
 
766
    else {
 
767
        jb->jb_stable_hist = 0;
 
768
    }
 
769
}
 
770
 
 
771
 
 
772
static void jbuf_discard_static(pjmedia_jbuf *jb)
 
773
{
 
774
    /* These code is used for shortening the delay in the jitter buffer.
 
775
     * It needs shrink only when there is possibility of drift. Drift
 
776
     * detection is performed by inspecting the jitter buffer size, if
 
777
     * its size is twice of current burst level, there can be drift.
 
778
     *
 
779
     * Moreover, normally drift level is quite low, so JB shouldn't need
 
780
     * to shrink aggresively, it will shrink maximum one frame per 
 
781
     * PJMEDIA_JBUF_DISC_MIN_GAP ms. Theoritically, JB may handle drift level 
 
782
     * as much as = FRAME_PTIME/PJMEDIA_JBUF_DISC_MIN_GAP * 100%
 
783
     *
 
784
     * Whenever there is drift, where PUT > GET, this method will keep 
 
785
     * the latency (JB size) as much as twice of burst level.
 
786
     */
 
787
 
 
788
    /* Shrinking due of drift will be implicitly done by progressive discard,
 
789
     * so just disable it when progressive discard is active.
 
790
     */
 
791
    int diff, burst_level;
 
792
 
 
793
    burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level);
 
794
    diff = jb_framelist_eff_size(&jb->jb_framelist) - burst_level*2;
 
795
 
 
796
    if (diff >= STA_DISC_SAFE_SHRINKING_DIFF) {
 
797
        int seq_origin;
 
798
 
 
799
        /* Check and adjust jb_discard_ref, in case there was 
 
800
         * seq restart 
 
801
         */
 
802
        seq_origin = jb_framelist_origin(&jb->jb_framelist);
 
803
        if (seq_origin < jb->jb_discard_ref)
 
804
            jb->jb_discard_ref = seq_origin;
 
805
 
 
806
        if (seq_origin - jb->jb_discard_ref >= jb->jb_min_shrink_gap)
 
807
        {
 
808
            /* Shrink slowly, one frame per cycle */
 
809
            diff = 1;
 
810
 
 
811
            /* Drop frame(s)! */
 
812
            diff = jb_framelist_remove_head(&jb->jb_framelist, diff);
 
813
            jb->jb_discard_ref = jb_framelist_origin(&jb->jb_framelist);
 
814
            jb->jb_discard += diff;
 
815
 
 
816
            TRACE__((jb->jb_name.ptr, 
 
817
                     "JB shrinking %d frame(s), cur size=%d", diff,
 
818
                     jb_framelist_eff_size(&jb->jb_framelist)));
 
819
        }
 
820
    }
 
821
}
 
822
 
 
823
 
 
824
static void jbuf_discard_progressive(pjmedia_jbuf *jb)
 
825
{
 
826
    unsigned cur_size, burst_level, overflow, T, discard_dist;
 
827
    int last_seq;
 
828
 
 
829
    /* Should be done in PUT operation */
 
830
    if (jb->jb_last_op != JB_OP_PUT)
 
831
        return;
 
832
 
 
833
    /* Check if latency is longer than burst */
 
834
    cur_size = jb_framelist_eff_size(&jb->jb_framelist);
 
835
    burst_level = PJ_MAX(jb->jb_eff_level, jb->jb_level);
 
836
    if (cur_size <= burst_level) {
 
837
        /* Reset any scheduled discard */
 
838
        jb->jb_discard_dist = 0;
 
839
        return;
 
840
    }
 
841
 
 
842
    /* Estimate discard duration needed for adjusting latency */
 
843
    if (burst_level <= PJMEDIA_JBUF_PRO_DISC_MIN_BURST)
 
844
        T = PJMEDIA_JBUF_PRO_DISC_T1;
 
845
    else if (burst_level >= PJMEDIA_JBUF_PRO_DISC_MAX_BURST)
 
846
        T = PJMEDIA_JBUF_PRO_DISC_T2;
 
847
    else
 
848
        T = PJMEDIA_JBUF_PRO_DISC_T1 + 
 
849
            (PJMEDIA_JBUF_PRO_DISC_T2 - PJMEDIA_JBUF_PRO_DISC_T1) *
 
850
            (burst_level - PJMEDIA_JBUF_PRO_DISC_MIN_BURST) /
 
851
            (PJMEDIA_JBUF_PRO_DISC_MAX_BURST-PJMEDIA_JBUF_PRO_DISC_MIN_BURST);
 
852
 
 
853
    /* Calculate current discard distance */
 
854
    overflow = cur_size - burst_level;
 
855
    discard_dist = T / overflow / jb->jb_frame_ptime;
 
856
 
 
857
    /* Get last seq number in the JB */
 
858
    last_seq = jb_framelist_origin(&jb->jb_framelist) +
 
859
               jb_framelist_size(&jb->jb_framelist) - 1;
 
860
 
 
861
    /* Setup new discard schedule if none, otherwise, update the existing
 
862
     * discard schedule (can be delayed or accelerated).
 
863
     */
 
864
    if (jb->jb_discard_dist == 0) {
 
865
        /* Setup new discard schedule */
 
866
        jb->jb_discard_ref = last_seq;
 
867
    } else if (last_seq < jb->jb_discard_ref) {
 
868
        /* Seq restarted, update discard reference */
 
869
        jb->jb_discard_ref = last_seq;
 
870
    }
 
871
    jb->jb_discard_dist = PJ_MAX(jb->jb_min_shrink_gap, (int)discard_dist);
 
872
 
 
873
    /* Check if we need to discard now */
 
874
    if (last_seq >= (jb->jb_discard_ref + (int)jb->jb_discard_dist)) {
 
875
        int discard_seq;
 
876
        
 
877
        discard_seq = jb->jb_discard_ref + jb->jb_discard_dist;
 
878
        if (discard_seq < jb_framelist_origin(&jb->jb_framelist))
 
879
            discard_seq = jb_framelist_origin(&jb->jb_framelist);
 
880
 
 
881
        jb_framelist_discard(&jb->jb_framelist, discard_seq);
 
882
 
 
883
        TRACE__((jb->jb_name.ptr, 
 
884
                "Discard #%d: ref=#%d dist=%d orig=%d size=%d/%d "
 
885
                "burst=%d/%d",
 
886
                discard_seq,
 
887
                jb->jb_discard_ref,
 
888
                jb->jb_discard_dist,
 
889
                jb_framelist_origin(&jb->jb_framelist),
 
890
                cur_size,
 
891
                jb_framelist_size(&jb->jb_framelist),
 
892
                jb->jb_eff_level,
 
893
                burst_level));
 
894
 
 
895
        /* Update discard reference */
 
896
        jb->jb_discard_ref = discard_seq;
 
897
    }
 
898
}
 
899
    
 
900
 
 
901
PJ_INLINE(void) jbuf_update(pjmedia_jbuf *jb, int oper)
 
902
{
 
903
    if(jb->jb_last_op != oper) {
 
904
        jb->jb_last_op = oper;
 
905
 
 
906
        if (jb->jb_status == JB_STATUS_INITIALIZING) {
 
907
            /* Switch status 'initializing' -> 'processing' after some OP 
 
908
             * switch cycles and current OP is GET (burst level is calculated 
 
909
             * based on PUT burst), so burst calculation is guaranted to be
 
910
             * performed right after the status switching.
 
911
             */
 
912
            if (++jb->jb_init_cycle_cnt >= INIT_CYCLE && oper == JB_OP_GET) {
 
913
                jb->jb_status = JB_STATUS_PROCESSING;
 
914
                /* To make sure the burst calculation will be done right after
 
915
                 * this, adjust burst level if it exceeds max burst level.
 
916
                 */
 
917
                jb->jb_level = PJ_MIN(jb->jb_level, jb->jb_max_burst);
 
918
            } else {
 
919
                jb->jb_level = 0;
 
920
                return;
 
921
            }
 
922
        }
 
923
 
 
924
        /* Perform jitter calculation based on PUT burst-level only, since 
 
925
         * GET burst-level may not be accurate, e.g: when VAD is active.
 
926
         * Note that when burst-level is too big, i.e: exceeds jb_max_burst,
 
927
         * the GET op may be idle, in this case, we better skip the jitter 
 
928
         * calculation.
 
929
         */
 
930
        if (oper == JB_OP_GET && jb->jb_level <= jb->jb_max_burst)
 
931
            jbuf_calculate_jitter(jb);
 
932
 
 
933
        jb->jb_level = 0;
 
934
    }
 
935
 
 
936
    /* Call discard algorithm */
 
937
    if (jb->jb_status == JB_STATUS_PROCESSING && jb->jb_discard_algo) {
 
938
        (*jb->jb_discard_algo)(jb);
 
939
    }
 
940
}
 
941
 
 
942
PJ_DEF(void) pjmedia_jbuf_put_frame( pjmedia_jbuf *jb, 
 
943
                                     const void *frame, 
 
944
                                     pj_size_t frame_size, 
 
945
                                     int frame_seq)
 
946
{
 
947
    pjmedia_jbuf_put_frame3(jb, frame, frame_size, 0, frame_seq, 0, NULL);
 
948
}
 
949
 
 
950
PJ_DEF(void) pjmedia_jbuf_put_frame2(pjmedia_jbuf *jb, 
 
951
                                     const void *frame, 
 
952
                                     pj_size_t frame_size, 
 
953
                                     pj_uint32_t bit_info,
 
954
                                     int frame_seq,
 
955
                                     pj_bool_t *discarded)
 
956
{
 
957
    pjmedia_jbuf_put_frame3(jb, frame, frame_size, bit_info, frame_seq, 0, 
 
958
                            discarded);
 
959
}
 
960
 
 
961
PJ_DEF(void) pjmedia_jbuf_put_frame3(pjmedia_jbuf *jb, 
 
962
                                     const void *frame, 
 
963
                                     pj_size_t frame_size, 
 
964
                                     pj_uint32_t bit_info,
 
965
                                     int frame_seq,
 
966
                                     pj_uint32_t ts,
 
967
                                     pj_bool_t *discarded)
 
968
{
 
969
    pj_size_t min_frame_size;
 
970
    int new_size, cur_size;
 
971
    pj_status_t status;
 
972
 
 
973
    cur_size = jb_framelist_eff_size(&jb->jb_framelist);
 
974
 
 
975
    /* Attempt to store the frame */
 
976
    min_frame_size = PJ_MIN(frame_size, jb->jb_frame_size);
 
977
    status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame,
 
978
                                 min_frame_size, bit_info, ts,
 
979
                                 PJMEDIA_JB_NORMAL_FRAME);
 
980
    
 
981
    /* Jitter buffer is full, remove some older frames */
 
982
    while (status == PJ_ETOOMANY) {
 
983
        int distance;
 
984
        unsigned removed;
 
985
 
 
986
        /* Remove as few as possible just to make this frame in. Note that
 
987
         * the cases of seq-jump, out-of-order, and seq restart should have
 
988
         * been handled/normalized by previous call of jb_framelist_put_at().
 
989
         * So we're confident about 'distance' value here.
 
990
         */
 
991
        distance = (frame_seq - jb_framelist_origin(&jb->jb_framelist)) -
 
992
                   jb->jb_max_count + 1;
 
993
        pj_assert(distance > 0);
 
994
 
 
995
        removed = jb_framelist_remove_head(&jb->jb_framelist, distance);
 
996
        status = jb_framelist_put_at(&jb->jb_framelist, frame_seq, frame,
 
997
                                     min_frame_size, bit_info, ts,
 
998
                                     PJMEDIA_JB_NORMAL_FRAME);
 
999
 
 
1000
        jb->jb_discard += removed;
 
1001
    }
 
1002
 
 
1003
    /* Get new JB size after PUT */
 
1004
    new_size = jb_framelist_eff_size(&jb->jb_framelist);
 
1005
 
 
1006
    /* Return the flag if this frame is discarded */
 
1007
    if (discarded)
 
1008
        *discarded = (status != PJ_SUCCESS);
 
1009
 
 
1010
    if (status == PJ_SUCCESS) {
 
1011
        if (jb->jb_prefetching) {
 
1012
            TRACE__((jb->jb_name.ptr, "PUT prefetch_cnt=%d/%d", 
 
1013
                     new_size, jb->jb_prefetch));
 
1014
            if (new_size >= jb->jb_prefetch)
 
1015
                jb->jb_prefetching = PJ_FALSE;
 
1016
        }
 
1017
        jb->jb_level += (new_size > cur_size ? new_size-cur_size : 1);
 
1018
        jbuf_update(jb, JB_OP_PUT);
 
1019
    } else
 
1020
        jb->jb_discard++;
 
1021
}
 
1022
 
 
1023
/*
 
1024
 * Get frame from jitter buffer.
 
1025
 */
 
1026
PJ_DEF(void) pjmedia_jbuf_get_frame( pjmedia_jbuf *jb, 
 
1027
                                     void *frame, 
 
1028
                                     char *p_frame_type)
 
1029
{
 
1030
    pjmedia_jbuf_get_frame3(jb, frame, NULL, p_frame_type, NULL,
 
1031
                            NULL, NULL);
 
1032
}
 
1033
 
 
1034
/*
 
1035
 * Get frame from jitter buffer.
 
1036
 */
 
1037
PJ_DEF(void) pjmedia_jbuf_get_frame2(pjmedia_jbuf *jb, 
 
1038
                                     void *frame, 
 
1039
                                     pj_size_t *size,
 
1040
                                     char *p_frame_type,
 
1041
                                     pj_uint32_t *bit_info)
 
1042
{
 
1043
    pjmedia_jbuf_get_frame3(jb, frame, size, p_frame_type, bit_info,
 
1044
                            NULL, NULL);
 
1045
}
 
1046
 
 
1047
/*
 
1048
 * Get frame from jitter buffer.
 
1049
 */
 
1050
PJ_DEF(void) pjmedia_jbuf_get_frame3(pjmedia_jbuf *jb, 
 
1051
                                     void *frame, 
 
1052
                                     pj_size_t *size,
 
1053
                                     char *p_frame_type,
 
1054
                                     pj_uint32_t *bit_info,
 
1055
                                     pj_uint32_t *ts,
 
1056
                                     int *seq)
 
1057
{
 
1058
    if (jb->jb_prefetching) {
 
1059
 
 
1060
        /* Can't return frame because jitter buffer is filling up
 
1061
         * minimum prefetch.
 
1062
         */
 
1063
 
 
1064
        //pj_bzero(frame, jb->jb_frame_size);
 
1065
        *p_frame_type = PJMEDIA_JB_ZERO_PREFETCH_FRAME;
 
1066
        if (size)
 
1067
            *size = 0;
 
1068
 
 
1069
        TRACE__((jb->jb_name.ptr, "GET prefetch_cnt=%d/%d",
 
1070
                 jb_framelist_eff_size(&jb->jb_framelist), jb->jb_prefetch));
 
1071
 
 
1072
        jb->jb_empty++;
 
1073
 
 
1074
    } else {
 
1075
 
 
1076
        pjmedia_jb_frame_type ftype = PJMEDIA_JB_NORMAL_FRAME;
 
1077
        pj_bool_t res;
 
1078
 
 
1079
        /* Try to retrieve a frame from frame list */
 
1080
        res = jb_framelist_get(&jb->jb_framelist, frame, size, &ftype, 
 
1081
                               bit_info, ts, seq);
 
1082
        if (res) {
 
1083
            /* We've successfully retrieved a frame from the frame list, but
 
1084
             * the frame could be a blank frame!
 
1085
             */
 
1086
            if (ftype == PJMEDIA_JB_NORMAL_FRAME) {
 
1087
                *p_frame_type = PJMEDIA_JB_NORMAL_FRAME;
 
1088
            } else {
 
1089
                *p_frame_type = PJMEDIA_JB_MISSING_FRAME;
 
1090
                jb->jb_lost++;
 
1091
            }
 
1092
 
 
1093
            /* Store delay history at the first GET */
 
1094
            if (jb->jb_last_op == JB_OP_PUT) {
 
1095
                unsigned cur_size;
 
1096
 
 
1097
                /* We've just retrieved one frame, so add one to cur_size */
 
1098
                cur_size = jb_framelist_eff_size(&jb->jb_framelist) + 1;
 
1099
                pj_math_stat_update(&jb->jb_delay, 
 
1100
                                    cur_size*jb->jb_frame_ptime);
 
1101
            }
 
1102
        } else {
 
1103
            /* Jitter buffer is empty */
 
1104
            if (jb->jb_prefetch)
 
1105
                jb->jb_prefetching = PJ_TRUE;
 
1106
 
 
1107
            //pj_bzero(frame, jb->jb_frame_size);
 
1108
            *p_frame_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
 
1109
            if (size)
 
1110
                *size = 0;
 
1111
 
 
1112
            jb->jb_empty++;
 
1113
        }
 
1114
    }
 
1115
 
 
1116
    jb->jb_level++;
 
1117
    jbuf_update(jb, JB_OP_GET);
 
1118
}
 
1119
 
 
1120
/*
 
1121
 * Get jitter buffer state.
 
1122
 */
 
1123
PJ_DEF(pj_status_t) pjmedia_jbuf_get_state( const pjmedia_jbuf *jb,
 
1124
                                            pjmedia_jb_state *state )
 
1125
{
 
1126
    PJ_ASSERT_RETURN(jb && state, PJ_EINVAL);
 
1127
 
 
1128
    state->frame_size = jb->jb_frame_size;
 
1129
    state->min_prefetch = jb->jb_min_prefetch;
 
1130
    state->max_prefetch = jb->jb_max_prefetch;
 
1131
    
 
1132
    state->burst = jb->jb_eff_level;
 
1133
    state->prefetch = jb->jb_prefetch;
 
1134
    state->size = jb_framelist_eff_size(&jb->jb_framelist);
 
1135
    
 
1136
    state->avg_delay = jb->jb_delay.mean;
 
1137
    state->min_delay = jb->jb_delay.min;
 
1138
    state->max_delay = jb->jb_delay.max;
 
1139
    state->dev_delay = pj_math_stat_get_stddev(&jb->jb_delay);
 
1140
    
 
1141
    state->avg_burst = jb->jb_burst.mean;
 
1142
    state->empty = jb->jb_empty;
 
1143
    state->discard = jb->jb_discard;
 
1144
    state->lost = jb->jb_lost;
 
1145
 
 
1146
    return PJ_SUCCESS;
 
1147
}
 
1148
 
 
1149
 
 
1150
PJ_DEF(void) pjmedia_jbuf_peek_frame( pjmedia_jbuf *jb,
 
1151
                                      unsigned offset,
 
1152
                                      const void **frame, 
 
1153
                                      pj_size_t *size, 
 
1154
                                      char *p_frm_type,
 
1155
                                      pj_uint32_t *bit_info,
 
1156
                                      pj_uint32_t *ts,
 
1157
                                      int *seq)
 
1158
{
 
1159
    pjmedia_jb_frame_type ftype;
 
1160
    pj_bool_t res;
 
1161
 
 
1162
    res = jb_framelist_peek(&jb->jb_framelist, offset, frame, size, &ftype,
 
1163
                            bit_info, ts, seq);
 
1164
    if (!res)
 
1165
        *p_frm_type = PJMEDIA_JB_ZERO_EMPTY_FRAME;
 
1166
    else if (ftype == PJMEDIA_JB_NORMAL_FRAME)
 
1167
        *p_frm_type = PJMEDIA_JB_NORMAL_FRAME;
 
1168
    else
 
1169
        *p_frm_type = PJMEDIA_JB_MISSING_FRAME;
 
1170
}
 
1171
 
 
1172
 
 
1173
PJ_DEF(unsigned) pjmedia_jbuf_remove_frame(pjmedia_jbuf *jb, 
 
1174
                                           unsigned frame_cnt)
 
1175
{
 
1176
    unsigned count, last_discard_num;
 
1177
 
 
1178
    last_discard_num = jb->jb_framelist.discarded_num;
 
1179
    count = jb_framelist_remove_head(&jb->jb_framelist, frame_cnt);
 
1180
 
 
1181
    /* Remove some more when there were discarded frames included */
 
1182
    while (jb->jb_framelist.discarded_num < last_discard_num) {
 
1183
        /* Calculate frames count to be removed next */
 
1184
        frame_cnt = last_discard_num - jb->jb_framelist.discarded_num;
 
1185
 
 
1186
        /* Normalize non-discarded frames count just been removed */
 
1187
        count -= frame_cnt;
 
1188
 
 
1189
        /* Remove more frames */
 
1190
        last_discard_num = jb->jb_framelist.discarded_num;
 
1191
        count += jb_framelist_remove_head(&jb->jb_framelist, frame_cnt);
 
1192
    }
 
1193
 
 
1194
    return count;
 
1195
}