Tristan Matthews | 0a329cc | 2013-07-17 13:20:14 -0400 | [diff] [blame] | 1 | /* $Id$ */ |
| 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 | |