~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

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

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* 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: delaybuf.c 3841 2011-10-24 09:28:13Z ming $ */
 
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
#include <pjmedia/delaybuf.h>
 
22
#include <pjmedia/circbuf.h>
 
23
#include <pjmedia/errno.h>
 
24
#include <pjmedia/frame.h>
 
25
#include <pjmedia/wsola.h>
 
26
#include <pj/assert.h>
 
27
#include <pj/lock.h>
 
28
#include <pj/log.h>
 
29
#include <pj/math.h>
 
30
#include <pj/pool.h>
 
31
 
 
32
 
 
33
#if 0
 
34
#   define TRACE__(x) PJ_LOG(3,x)
 
35
#else
 
36
#   define TRACE__(x)
 
37
#endif
 
38
 
 
39
/* Operation types of delay buffer */
 
40
enum OP
 
41
{
 
42
    OP_PUT,
 
43
    OP_GET
 
44
};
 
45
 
 
46
/* Specify time for delaybuf to recalculate effective delay, in ms.
 
47
 */
 
48
#define RECALC_TIME         2000
 
49
 
 
50
/* Default value of maximum delay, in ms, this value is used when 
 
51
 * maximum delay requested is less than ptime (one frame length).
 
52
 */
 
53
#define DEFAULT_MAX_DELAY   400
 
54
 
 
55
/* Number of frames to add to learnt level for additional stability.
 
56
 */
 
57
#define SAFE_MARGIN         0
 
58
 
 
59
/* This structure describes internal delaybuf settings and states.
 
60
 */
 
61
struct pjmedia_delay_buf
 
62
{
 
63
    /* Properties and configuration */
 
64
    char             obj_name[PJ_MAX_OBJ_NAME];
 
65
    pj_lock_t       *lock;              /**< Lock object.                    */
 
66
    unsigned         samples_per_frame; /**< Number of samples in one frame  */
 
67
    unsigned         ptime;             /**< Frame time, in ms               */
 
68
    unsigned         channel_count;     /**< Channel count, in ms            */
 
69
    pjmedia_circ_buf *circ_buf;         /**< Circular buffer to store audio
 
70
                                             samples                         */
 
71
    unsigned         max_cnt;           /**< Maximum samples to be buffered  */
 
72
    unsigned         eff_cnt;           /**< Effective count of buffered 
 
73
                                             samples to keep the optimum
 
74
                                             balance between delay and 
 
75
                                             stability. This is calculated 
 
76
                                             based on burst level.           */
 
77
 
 
78
    /* Learning vars */
 
79
    unsigned         level;             /**< Burst level counter             */
 
80
    enum OP          last_op;           /**< Last op (GET or PUT) of learning*/
 
81
    int              recalc_timer;      /**< Timer for recalculating max_level*/
 
82
    unsigned         max_level;         /**< Current max burst level         */
 
83
 
 
84
    /* Drift handler */
 
85
    pjmedia_wsola   *wsola;             /**< Drift handler                   */
 
86
};
 
87
 
 
88
 
 
89
PJ_DEF(pj_status_t) pjmedia_delay_buf_create( pj_pool_t *pool,
 
90
                                              const char *name,
 
91
                                              unsigned clock_rate,
 
92
                                              unsigned samples_per_frame,
 
93
                                              unsigned channel_count,
 
94
                                              unsigned max_delay,
 
95
                                              unsigned options,
 
96
                                              pjmedia_delay_buf **p_b)
 
97
{
 
98
    pjmedia_delay_buf *b;
 
99
    pj_status_t status;
 
100
 
 
101
    PJ_ASSERT_RETURN(pool && samples_per_frame && clock_rate && channel_count &&
 
102
                     p_b, PJ_EINVAL);
 
103
 
 
104
    if (!name) {
 
105
        name = "delaybuf";
 
106
    }
 
107
 
 
108
    b = PJ_POOL_ZALLOC_T(pool, pjmedia_delay_buf);
 
109
 
 
110
    pj_ansi_strncpy(b->obj_name, name, PJ_MAX_OBJ_NAME-1);
 
111
 
 
112
    b->samples_per_frame = samples_per_frame;
 
113
    b->channel_count = channel_count;
 
114
    b->ptime = samples_per_frame * 1000 / clock_rate / channel_count;
 
115
    if (max_delay < b->ptime)
 
116
        max_delay = PJ_MAX(DEFAULT_MAX_DELAY, b->ptime);
 
117
 
 
118
    b->max_cnt = samples_per_frame * max_delay / b->ptime;
 
119
    b->eff_cnt = b->max_cnt >> 1;
 
120
    b->recalc_timer = RECALC_TIME;
 
121
 
 
122
    /* Create circular buffer */
 
123
    status = pjmedia_circ_buf_create(pool, b->max_cnt, &b->circ_buf);
 
124
    if (status != PJ_SUCCESS)
 
125
        return status;
 
126
 
 
127
    if (!(options & PJMEDIA_DELAY_BUF_SIMPLE_FIFO)) {
 
128
        /* Create WSOLA */
 
129
        status = pjmedia_wsola_create(pool, clock_rate, samples_per_frame, 1,
 
130
                                      PJMEDIA_WSOLA_NO_FADING, &b->wsola);
 
131
        if (status != PJ_SUCCESS)
 
132
            return status;
 
133
        PJ_LOG(5, (b->obj_name, "Using delay buffer with WSOLA."));
 
134
    } else {
 
135
        PJ_LOG(5, (b->obj_name, "Using simple FIFO delay buffer."));
 
136
    }
 
137
 
 
138
    /* Finally, create mutex */
 
139
    status = pj_lock_create_recursive_mutex(pool, b->obj_name, 
 
140
                                            &b->lock);
 
141
    if (status != PJ_SUCCESS)
 
142
        return status;
 
143
 
 
144
    *p_b = b;
 
145
 
 
146
    TRACE__((b->obj_name,"Delay buffer created"));
 
147
 
 
148
    return PJ_SUCCESS;
 
149
}
 
150
 
 
151
PJ_DEF(pj_status_t) pjmedia_delay_buf_destroy(pjmedia_delay_buf *b)
 
152
{
 
153
    pj_status_t status = PJ_SUCCESS;
 
154
 
 
155
    PJ_ASSERT_RETURN(b, PJ_EINVAL);
 
156
 
 
157
    pj_lock_acquire(b->lock);
 
158
 
 
159
    if (b->wsola) {
 
160
        status = pjmedia_wsola_destroy(b->wsola);
 
161
        if (status == PJ_SUCCESS)
 
162
            b->wsola = NULL;
 
163
    }
 
164
 
 
165
    pj_lock_release(b->lock);
 
166
 
 
167
    pj_lock_destroy(b->lock);
 
168
    b->lock = NULL;
 
169
 
 
170
    return status;
 
171
}
 
172
 
 
173
/* This function will erase samples from delay buffer.
 
174
 * The number of erased samples is guaranteed to be >= erase_cnt.
 
175
 */
 
176
static void shrink_buffer(pjmedia_delay_buf *b, unsigned erase_cnt)
 
177
{
 
178
    pj_int16_t *buf1, *buf2;
 
179
    unsigned buf1len;
 
180
    unsigned buf2len;
 
181
    pj_status_t status;
 
182
 
 
183
    pj_assert(b && erase_cnt && pjmedia_circ_buf_get_len(b->circ_buf));
 
184
 
 
185
    pjmedia_circ_buf_get_read_regions(b->circ_buf, &buf1, &buf1len, 
 
186
                                      &buf2, &buf2len);
 
187
    status = pjmedia_wsola_discard(b->wsola, buf1, buf1len, buf2, buf2len,
 
188
                                   &erase_cnt);
 
189
 
 
190
    if ((status == PJ_SUCCESS) && (erase_cnt > 0)) {
 
191
        /* WSOLA discard will manage the first buffer to be full, unless 
 
192
         * erase_cnt is greater than second buffer length. So it is safe
 
193
         * to just set the circular buffer length.
 
194
         */
 
195
 
 
196
        pjmedia_circ_buf_set_len(b->circ_buf, 
 
197
                                 pjmedia_circ_buf_get_len(b->circ_buf) - 
 
198
                                 erase_cnt);
 
199
 
 
200
        PJ_LOG(5,(b->obj_name,"%d samples reduced, buf_cnt=%d", 
 
201
               erase_cnt, pjmedia_circ_buf_get_len(b->circ_buf)));
 
202
    }
 
203
}
 
204
 
 
205
/* Fast increase, slow decrease */
 
206
#define AGC_UP(cur, target) cur = (cur + target*3) >> 2
 
207
#define AGC_DOWN(cur, target) cur = (cur*3 + target) >> 2
 
208
#define AGC(cur, target) \
 
209
    if (cur < target) AGC_UP(cur, target); \
 
210
    else AGC_DOWN(cur, target)
 
211
 
 
212
static void update(pjmedia_delay_buf *b, enum OP op)
 
213
{
 
214
    /* Sequential operation */
 
215
    if (op == b->last_op) {
 
216
        ++b->level;
 
217
        return;
 
218
    } 
 
219
 
 
220
    /* Switching operation */
 
221
    if (b->level > b->max_level)
 
222
        b->max_level = b->level;
 
223
 
 
224
    b->recalc_timer -= (b->level * b->ptime) >> 1;
 
225
 
 
226
    b->last_op = op;
 
227
    b->level = 1;
 
228
 
 
229
    /* Recalculate effective count based on max_level */
 
230
    if (b->recalc_timer <= 0) {
 
231
        unsigned new_eff_cnt = (b->max_level+SAFE_MARGIN)*b->samples_per_frame;
 
232
 
 
233
        /* Smoothening effective count transition */
 
234
        AGC(b->eff_cnt, new_eff_cnt);
 
235
        
 
236
        /* Make sure the new effective count is multiplication of 
 
237
         * channel_count, so let's round it up.
 
238
         */
 
239
        if (b->eff_cnt % b->channel_count)
 
240
            b->eff_cnt += b->channel_count - (b->eff_cnt % b->channel_count);
 
241
 
 
242
        TRACE__((b->obj_name,"Cur eff_cnt=%d", b->eff_cnt));
 
243
        
 
244
        b->max_level = 0;
 
245
        b->recalc_timer = RECALC_TIME;
 
246
    }
 
247
 
 
248
    /* See if we need to shrink the buffer to reduce delay */
 
249
    if (op == OP_PUT && pjmedia_circ_buf_get_len(b->circ_buf) > 
 
250
        b->samples_per_frame + b->eff_cnt)
 
251
    {
 
252
        unsigned erase_cnt = b->samples_per_frame >> 1;
 
253
        unsigned old_buf_cnt = pjmedia_circ_buf_get_len(b->circ_buf);
 
254
 
 
255
        shrink_buffer(b, erase_cnt);
 
256
        PJ_LOG(4,(b->obj_name,"Buffer size adjusted from %d to %d (eff_cnt=%d)",
 
257
                  old_buf_cnt,
 
258
                  pjmedia_circ_buf_get_len(b->circ_buf),
 
259
                  b->eff_cnt));
 
260
    }
 
261
}
 
262
 
 
263
PJ_DEF(pj_status_t) pjmedia_delay_buf_put(pjmedia_delay_buf *b,
 
264
                                           pj_int16_t frame[])
 
265
{
 
266
    pj_status_t status;
 
267
 
 
268
    PJ_ASSERT_RETURN(b && frame, PJ_EINVAL);
 
269
 
 
270
    pj_lock_acquire(b->lock);
 
271
 
 
272
    if (b->wsola) {
 
273
        update(b, OP_PUT);
 
274
    
 
275
        status = pjmedia_wsola_save(b->wsola, frame, PJ_FALSE);
 
276
        if (status != PJ_SUCCESS) {
 
277
            pj_lock_release(b->lock);
 
278
            return status;
 
279
        }
 
280
    }
 
281
 
 
282
    /* Overflow checking */
 
283
    if (pjmedia_circ_buf_get_len(b->circ_buf) + b->samples_per_frame > 
 
284
        b->max_cnt)
 
285
    {
 
286
        unsigned erase_cnt;
 
287
 
 
288
        if (b->wsola) {
 
289
            /* shrink one frame or just the diff? */
 
290
            //erase_cnt = b->samples_per_frame;
 
291
            erase_cnt = pjmedia_circ_buf_get_len(b->circ_buf) + 
 
292
                        b->samples_per_frame - b->max_cnt;
 
293
 
 
294
            shrink_buffer(b, erase_cnt);
 
295
        }
 
296
 
 
297
        /* Check if shrinking failed or erased count is less than requested,
 
298
         * delaybuf needs to drop eldest samples, this is bad since the voice
 
299
         * samples get rough transition which may produce tick noise.
 
300
         */
 
301
        if (pjmedia_circ_buf_get_len(b->circ_buf) + b->samples_per_frame > 
 
302
            b->max_cnt) 
 
303
        {
 
304
            erase_cnt = pjmedia_circ_buf_get_len(b->circ_buf) + 
 
305
                        b->samples_per_frame - b->max_cnt;
 
306
 
 
307
            pjmedia_circ_buf_adv_read_ptr(b->circ_buf, erase_cnt);
 
308
 
 
309
            PJ_LOG(4,(b->obj_name,"%sDropping %d eldest samples, buf_cnt=%d",
 
310
                      (b->wsola? "Shrinking failed or insufficient. ": ""),
 
311
                      erase_cnt, pjmedia_circ_buf_get_len(b->circ_buf)));
 
312
        }
 
313
    }
 
314
 
 
315
    pjmedia_circ_buf_write(b->circ_buf, frame, b->samples_per_frame);
 
316
 
 
317
    pj_lock_release(b->lock);
 
318
    return PJ_SUCCESS;
 
319
}
 
320
 
 
321
PJ_DEF(pj_status_t) pjmedia_delay_buf_get( pjmedia_delay_buf *b,
 
322
                                           pj_int16_t frame[])
 
323
{
 
324
    pj_status_t status = PJ_SUCCESS;
 
325
 
 
326
    PJ_ASSERT_RETURN(b && frame, PJ_EINVAL);
 
327
 
 
328
    pj_lock_acquire(b->lock);
 
329
 
 
330
    if (b->wsola)
 
331
        update(b, OP_GET);
 
332
 
 
333
    /* Starvation checking */
 
334
    if (pjmedia_circ_buf_get_len(b->circ_buf) < b->samples_per_frame) {
 
335
 
 
336
        PJ_LOG(4,(b->obj_name,"Underflow, buf_cnt=%d, will generate 1 frame",
 
337
                  pjmedia_circ_buf_get_len(b->circ_buf)));
 
338
 
 
339
        if (b->wsola) {
 
340
            status = pjmedia_wsola_generate(b->wsola, frame);
 
341
 
 
342
            if (status == PJ_SUCCESS) {
 
343
                TRACE__((b->obj_name,"Successfully generate 1 frame"));
 
344
                if (pjmedia_circ_buf_get_len(b->circ_buf) == 0) {
 
345
                    pj_lock_release(b->lock);
 
346
                    return PJ_SUCCESS;
 
347
                }
 
348
 
 
349
                /* Put generated frame into buffer */
 
350
                pjmedia_circ_buf_write(b->circ_buf, frame,
 
351
                                       b->samples_per_frame);
 
352
            }
 
353
        }
 
354
 
 
355
        if (!b->wsola || status != PJ_SUCCESS) {
 
356
            unsigned buf_len = pjmedia_circ_buf_get_len(b->circ_buf);
 
357
            
 
358
            /* Give all what delay buffer has, then pad with zeroes */
 
359
            if (b->wsola)
 
360
                PJ_LOG(4,(b->obj_name,"Error generating frame, status=%d", 
 
361
                          status));
 
362
 
 
363
            pjmedia_circ_buf_read(b->circ_buf, frame, buf_len);
 
364
            pjmedia_zero_samples(&frame[buf_len], 
 
365
                                 b->samples_per_frame - buf_len);
 
366
 
 
367
            /* The buffer is empty now, reset it */
 
368
            pjmedia_circ_buf_reset(b->circ_buf);
 
369
 
 
370
            pj_lock_release(b->lock);
 
371
 
 
372
            return PJ_SUCCESS;
 
373
        }
 
374
    }
 
375
 
 
376
    pjmedia_circ_buf_read(b->circ_buf, frame, b->samples_per_frame);
 
377
 
 
378
    pj_lock_release(b->lock);
 
379
 
 
380
    return PJ_SUCCESS;
 
381
}
 
382
 
 
383
 
 
384
PJ_DEF(pj_status_t) pjmedia_delay_buf_reset(pjmedia_delay_buf *b)
 
385
{
 
386
    PJ_ASSERT_RETURN(b, PJ_EINVAL);
 
387
 
 
388
    pj_lock_acquire(b->lock);
 
389
 
 
390
    b->recalc_timer = RECALC_TIME;
 
391
 
 
392
    /* Reset buffer */
 
393
    pjmedia_circ_buf_reset(b->circ_buf);
 
394
 
 
395
    /* Reset WSOLA */
 
396
    if (b->wsola)
 
397
        pjmedia_wsola_reset(b->wsola, 0);
 
398
 
 
399
    pj_lock_release(b->lock);
 
400
 
 
401
    PJ_LOG(5,(b->obj_name,"Delay buffer is reset"));
 
402
 
 
403
    return PJ_SUCCESS;
 
404
}
 
405