00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369001 $")
00037
00038 #include "jitterbuf.h"
00039 #include "asterisk/utils.h"
00040
00041
00042 #define JB_LONGMAX 2147483647L
00043 #define JB_LONGMIN (-JB_LONGMAX - 1L)
00044
00045 #define jb_warn(...) (warnf ? warnf(__VA_ARGS__) : (void)0)
00046 #define jb_err(...) (errf ? errf(__VA_ARGS__) : (void)0)
00047 #define jb_dbg(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
00048
00049 #ifdef DEEP_DEBUG
00050 #define jb_dbg2(...) (dbgf ? dbgf(__VA_ARGS__) : (void)0)
00051 #else
00052 #define jb_dbg2(...) ((void)0)
00053 #endif
00054
00055 static jb_output_function_t warnf, errf, dbgf;
00056
00057 void jb_setoutput(jb_output_function_t err, jb_output_function_t warn, jb_output_function_t dbg)
00058 {
00059 errf = err;
00060 warnf = warn;
00061 dbgf = dbg;
00062 }
00063
00064 static void increment_losspct(jitterbuf *jb)
00065 {
00066 jb->info.losspct = (100000 + 499 * jb->info.losspct)/500;
00067 }
00068
00069 static void decrement_losspct(jitterbuf *jb)
00070 {
00071 jb->info.losspct = (499 * jb->info.losspct)/500;
00072 }
00073
00074 void jb_reset(jitterbuf *jb)
00075 {
00076
00077 jb_conf s = jb->info.conf;
00078 memset(jb, 0, sizeof(*jb));
00079 jb->info.conf = s;
00080
00081
00082 jb->info.current = jb->info.target = jb->info.conf.target_extra = JB_TARGET_EXTRA;
00083 jb->info.silence_begin_ts = -1;
00084 }
00085
00086 jitterbuf * jb_new()
00087 {
00088 jitterbuf *jb;
00089
00090 if (!(jb = ast_malloc(sizeof(*jb))))
00091 return NULL;
00092
00093 jb_reset(jb);
00094
00095 jb_dbg2("jb_new() = %x\n", jb);
00096 return jb;
00097 }
00098
00099 void jb_destroy(jitterbuf *jb)
00100 {
00101 jb_frame *frame;
00102 jb_dbg2("jb_destroy(%x)\n", jb);
00103
00104
00105 frame = jb->free;
00106 while (frame != NULL) {
00107 jb_frame *next = frame->next;
00108 ast_free(frame);
00109 frame = next;
00110 }
00111
00112
00113 ast_free(jb);
00114 }
00115
00116 static int check_resync(jitterbuf *jb, long ts, long now, long ms, const enum jb_frame_type type, long *delay)
00117 {
00118 long numts = 0;
00119 long threshold = 2 * jb->info.jitter + jb->info.conf.resync_threshold;
00120
00121
00122 if (jb->frames) {
00123 numts = jb->frames->prev->ts - jb->frames->ts;
00124 }
00125
00126 if (numts >= (jb->info.conf.max_jitterbuf)) {
00127 if (!jb->dropem) {
00128 ast_debug(1, "Attempting to exceed Jitterbuf max %ld timeslots\n",
00129 jb->info.conf.max_jitterbuf);
00130 jb->dropem = 1;
00131 }
00132 jb->info.frames_dropped++;
00133 return -1;
00134 } else {
00135 jb->dropem = 0;
00136 }
00137
00138
00139 if (jb->info.conf.resync_threshold != -1) {
00140 if (abs(*delay - jb->info.last_delay) > threshold) {
00141 jb->info.cnt_delay_discont++;
00142
00143
00144 if ((jb->info.cnt_delay_discont > 3) || (type == JB_TYPE_CONTROL)) {
00145 jb->info.cnt_delay_discont = 0;
00146 jb->hist_ptr = 0;
00147 jb->hist_maxbuf_valid = 0;
00148 jb_warn("Resyncing the jb. last_delay %ld, this delay %ld, threshold %ld, new offset %ld\n", jb->info.last_delay, *delay, threshold, ts - now);
00149 jb->info.resync_offset = ts - now;
00150 jb->info.last_delay = *delay = 0;
00151 } else {
00152 jb->info.frames_dropped++;
00153 return -1;
00154 }
00155 } else {
00156 jb->info.last_delay = *delay;
00157 jb->info.cnt_delay_discont = 0;
00158 }
00159 }
00160 return 0;
00161 }
00162
00163 static int history_put(jitterbuf *jb, long ts, long now, long ms, long delay)
00164 {
00165 long kicked;
00166
00167
00168 if (ts <= 0)
00169 return 0;
00170
00171 kicked = jb->history[jb->hist_ptr % JB_HISTORY_SZ];
00172
00173 jb->history[(jb->hist_ptr++) % JB_HISTORY_SZ] = delay;
00174
00175
00176
00177
00178
00179
00180 if (!jb->hist_maxbuf_valid)
00181 return 0;
00182
00183
00184
00185 if (jb->hist_ptr < JB_HISTORY_SZ)
00186 goto invalidate;
00187
00188
00189 if (delay < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
00190 goto invalidate;
00191
00192
00193 if (delay > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
00194 goto invalidate;
00195
00196
00197 if (kicked <= jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1])
00198 goto invalidate;
00199
00200 if (kicked >= jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1])
00201 goto invalidate;
00202
00203
00204
00205 return 0;
00206
00207
00208
00209 invalidate:
00210 jb->hist_maxbuf_valid = 0;
00211 return 0;
00212 }
00213
00214 static void history_calc_maxbuf(jitterbuf *jb)
00215 {
00216 int i,j;
00217
00218 if (jb->hist_ptr == 0)
00219 return;
00220
00221
00222
00223 for (i=0;i<JB_HISTORY_MAXBUF_SZ;i++) {
00224
00225
00226
00227
00228 jb->hist_maxbuf[i] = JB_LONGMIN;
00229 jb->hist_minbuf[i] = JB_LONGMAX;
00230 }
00231
00232
00233
00234
00235
00236 i = (jb->hist_ptr > JB_HISTORY_SZ) ? (jb->hist_ptr - JB_HISTORY_SZ) : 0;
00237
00238 for (;i<jb->hist_ptr;i++) {
00239 long toins = jb->history[i % JB_HISTORY_SZ];
00240
00241
00242 if (toins > jb->hist_maxbuf[JB_HISTORY_MAXBUF_SZ-1]) {
00243
00244
00245 for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
00246
00247 if (toins > jb->hist_maxbuf[j]) {
00248
00249 if (j != JB_HISTORY_MAXBUF_SZ - 1) {
00250 memmove(jb->hist_maxbuf + j + 1, jb->hist_maxbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_maxbuf[0]));
00251 }
00252
00253 jb->hist_maxbuf[j] = toins;
00254
00255 break;
00256 }
00257 }
00258 }
00259
00260
00261 if (toins < jb->hist_minbuf[JB_HISTORY_MAXBUF_SZ-1]) {
00262
00263
00264 for (j=0;j<JB_HISTORY_MAXBUF_SZ;j++) {
00265
00266 if (toins < jb->hist_minbuf[j]) {
00267
00268 if (j != JB_HISTORY_MAXBUF_SZ - 1) {
00269 memmove(jb->hist_minbuf + j + 1, jb->hist_minbuf + j, (JB_HISTORY_MAXBUF_SZ - (j + 1)) * sizeof(jb->hist_minbuf[0]));
00270 }
00271
00272 jb->hist_minbuf[j] = toins;
00273
00274 break;
00275 }
00276 }
00277 }
00278
00279 if (0) {
00280 int k;
00281 fprintf(stderr, "toins = %ld\n", toins);
00282 fprintf(stderr, "maxbuf =");
00283 for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
00284 fprintf(stderr, "%ld ", jb->hist_maxbuf[k]);
00285 fprintf(stderr, "\nminbuf =");
00286 for (k=0;k<JB_HISTORY_MAXBUF_SZ;k++)
00287 fprintf(stderr, "%ld ", jb->hist_minbuf[k]);
00288 fprintf(stderr, "\n");
00289 }
00290 }
00291
00292 jb->hist_maxbuf_valid = 1;
00293 }
00294
00295 static void history_get(jitterbuf *jb)
00296 {
00297 long max, min, jitter;
00298 int idx;
00299 int count;
00300
00301 if (!jb->hist_maxbuf_valid)
00302 history_calc_maxbuf(jb);
00303
00304
00305 count = (jb->hist_ptr < JB_HISTORY_SZ) ? jb->hist_ptr : JB_HISTORY_SZ;
00306
00307
00308 idx = count * JB_HISTORY_DROPPCT / 100;
00309
00310
00311 if (idx > (JB_HISTORY_MAXBUF_SZ - 1))
00312 idx = JB_HISTORY_MAXBUF_SZ - 1;
00313
00314 if (idx < 0) {
00315 jb->info.min = 0;
00316 jb->info.jitter = 0;
00317 return;
00318 }
00319
00320 max = jb->hist_maxbuf[idx];
00321 min = jb->hist_minbuf[idx];
00322
00323 jitter = max - min;
00324
00325
00326
00327
00328
00329
00330
00331
00332 jb->info.min = min;
00333 jb->info.jitter = jitter;
00334 }
00335
00336
00337 static int queue_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts)
00338 {
00339 jb_frame *frame;
00340 jb_frame *p;
00341 int head = 0;
00342 long resync_ts = ts - jb->info.resync_offset;
00343
00344 if ((frame = jb->free)) {
00345 jb->free = frame->next;
00346 } else if (!(frame = ast_malloc(sizeof(*frame)))) {
00347 jb_err("cannot allocate frame\n");
00348 return 0;
00349 }
00350
00351 jb->info.frames_cur++;
00352
00353 frame->data = data;
00354 frame->ts = resync_ts;
00355 frame->ms = ms;
00356 frame->type = type;
00357
00358
00359
00360
00361
00362
00363 if (!jb->frames) {
00364 jb->frames = frame;
00365 frame->next = frame;
00366 frame->prev = frame;
00367 head = 1;
00368 } else if (resync_ts < jb->frames->ts) {
00369 frame->next = jb->frames;
00370 frame->prev = jb->frames->prev;
00371
00372 frame->next->prev = frame;
00373 frame->prev->next = frame;
00374
00375
00376 jb->info.frames_ooo++;
00377
00378 jb->frames = frame;
00379 head = 1;
00380 } else {
00381 p = jb->frames;
00382
00383
00384 if (resync_ts < p->prev->ts) jb->info.frames_ooo++;
00385
00386 while (resync_ts < p->prev->ts && p->prev != jb->frames)
00387 p = p->prev;
00388
00389 frame->next = p;
00390 frame->prev = p->prev;
00391
00392 frame->next->prev = frame;
00393 frame->prev->next = frame;
00394 }
00395 return head;
00396 }
00397
00398 static long queue_next(jitterbuf *jb)
00399 {
00400 if (jb->frames)
00401 return jb->frames->ts;
00402 else
00403 return -1;
00404 }
00405
00406 static long queue_last(jitterbuf *jb)
00407 {
00408 if (jb->frames)
00409 return jb->frames->prev->ts;
00410 else
00411 return -1;
00412 }
00413
00414 static jb_frame *_queue_get(jitterbuf *jb, long ts, int all)
00415 {
00416 jb_frame *frame;
00417 frame = jb->frames;
00418
00419 if (!frame)
00420 return NULL;
00421
00422
00423
00424 if (all || ts >= frame->ts) {
00425
00426 frame->prev->next = frame->next;
00427 frame->next->prev = frame->prev;
00428
00429 if (frame->next == frame)
00430 jb->frames = NULL;
00431 else
00432 jb->frames = frame->next;
00433
00434
00435
00436 frame->next = jb->free;
00437 jb->free = frame;
00438
00439 jb->info.frames_cur--;
00440
00441
00442
00443 return frame;
00444 }
00445
00446 return NULL;
00447 }
00448
00449 static jb_frame *queue_get(jitterbuf *jb, long ts)
00450 {
00451 return _queue_get(jb,ts,0);
00452 }
00453
00454 static jb_frame *queue_getall(jitterbuf *jb)
00455 {
00456 return _queue_get(jb,0,1);
00457 }
00458
00459 #if 0
00460
00461 static void jb_dbginfo(jitterbuf *jb)
00462 {
00463 if (dbgf == NULL)
00464 return;
00465
00466 jb_dbg("\njb info: fin=%ld fout=%ld flate=%ld flost=%ld fdrop=%ld fcur=%ld\n",
00467 jb->info.frames_in, jb->info.frames_out, jb->info.frames_late, jb->info.frames_lost, jb->info.frames_dropped, jb->info.frames_cur);
00468
00469 jb_dbg("jitter=%ld current=%ld target=%ld min=%ld sil=%d len=%d len/fcur=%ld\n",
00470 jb->info.jitter, jb->info.current, jb->info.target, jb->info.min, jb->info.silence_begin_ts, jb->info.current - jb->info.min,
00471 jb->info.frames_cur ? (jb->info.current - jb->info.min)/jb->info.frames_cur : -8);
00472 if (jb->info.frames_in > 0)
00473 jb_dbg("jb info: Loss PCT = %ld%%, Late PCT = %ld%%\n",
00474 jb->info.frames_lost * 100/(jb->info.frames_in + jb->info.frames_lost),
00475 jb->info.frames_late * 100/jb->info.frames_in);
00476 jb_dbg("jb info: queue %d -> %d. last_ts %d (queue len: %d) last_ms %d\n",
00477 queue_next(jb),
00478 queue_last(jb),
00479 jb->info.next_voice_ts,
00480 queue_last(jb) - queue_next(jb),
00481 jb->info.last_voice_ms);
00482 }
00483 #endif
00484
00485 #ifdef DEEP_DEBUG
00486 static void jb_chkqueue(jitterbuf *jb)
00487 {
00488 int i=0;
00489 jb_frame *p = jb->frames;
00490
00491 if (!p) {
00492 return;
00493 }
00494
00495 do {
00496 if (p->next == NULL) {
00497 jb_err("Queue is BROKEN at item [%d]", i);
00498 }
00499 i++;
00500 p=p->next;
00501 } while (p->next != jb->frames);
00502 }
00503
00504 static void jb_dbgqueue(jitterbuf *jb)
00505 {
00506 int i=0;
00507 jb_frame *p = jb->frames;
00508
00509 jb_dbg("queue: ");
00510
00511 if (!p) {
00512 jb_dbg("EMPTY\n");
00513 return;
00514 }
00515
00516 do {
00517 jb_dbg("[%d]=%ld ", i++, p->ts);
00518 p=p->next;
00519 } while (p->next != jb->frames);
00520
00521 jb_dbg("\n");
00522 }
00523 #endif
00524
00525 enum jb_return_code jb_put(jitterbuf *jb, void *data, const enum jb_frame_type type, long ms, long ts, long now)
00526 {
00527 long delay = now - (ts - jb->info.resync_offset);
00528 jb_dbg2("jb_put(%x,%x,%ld,%ld,%ld)\n", jb, data, ms, ts, now);
00529
00530 if (check_resync(jb, ts, now, ms, type, &delay)) {
00531 return JB_DROP;
00532 }
00533
00534 if (type == JB_TYPE_VOICE) {
00535
00536
00537 history_put(jb, ts, now, ms, delay);
00538 }
00539
00540 jb->info.frames_in++;
00541
00542
00543 if (queue_put(jb,data,type,ms,ts)) {
00544 return JB_SCHED;
00545 }
00546 return JB_OK;
00547 }
00548
00549
00550 static enum jb_return_code _jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl)
00551 {
00552 jb_frame *frame;
00553 long diff;
00554 static int dbg_cnt = 0;
00555
00556
00557 history_get(jb);
00558
00559 if (dbg_cnt && dbg_cnt % 50 == 0) {
00560 jb_dbg("\n");
00561 }
00562 dbg_cnt++;
00563
00564
00565 jb->info.target = jb->info.jitter + jb->info.min + jb->info.conf.target_extra;
00566
00567
00568 if ((jb->info.conf.max_jitterbuf) && ((jb->info.target - jb->info.min) > jb->info.conf.max_jitterbuf)) {
00569 jb_dbg("clamping target from %ld to %ld\n", (jb->info.target - jb->info.min), jb->info.conf.max_jitterbuf);
00570 jb->info.target = jb->info.min + jb->info.conf.max_jitterbuf;
00571 }
00572
00573 diff = jb->info.target - jb->info.current;
00574
00575
00576
00577
00578
00579 if (!jb->info.silence_begin_ts) {
00580
00581 if ((diff > 0) &&
00582
00583 (((jb->info.last_adjustment + JB_ADJUST_DELAY) < now) ||
00584
00585 (diff > queue_last(jb) - queue_next(jb)) ) ) {
00586
00587 jb->info.current += interpl;
00588 jb->info.next_voice_ts += interpl;
00589 jb->info.last_voice_ms = interpl;
00590 jb->info.last_adjustment = now;
00591 jb->info.cnt_contig_interp++;
00592 if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00593 jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00594 }
00595 jb_dbg("G");
00596 return JB_INTERP;
00597 }
00598
00599 frame = queue_get(jb, jb->info.next_voice_ts - jb->info.current);
00600
00601
00602 if (frame && frame->type != JB_TYPE_VOICE) {
00603 if (frame->type == JB_TYPE_SILENCE) {
00604 jb->info.silence_begin_ts = frame->ts;
00605 jb->info.cnt_contig_interp = 0;
00606 }
00607
00608 *frameout = *frame;
00609 jb->info.frames_out++;
00610 jb_dbg("o");
00611 return JB_OK;
00612 }
00613
00614
00615
00616 if (frame && frame->ts + jb->info.current < jb->info.next_voice_ts) {
00617 if (frame->ts + jb->info.current > jb->info.next_voice_ts - jb->info.last_voice_ms) {
00618
00619
00620 *frameout = *frame;
00621
00622 jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00623 jb->info.frames_out++;
00624 decrement_losspct(jb);
00625 jb->info.cnt_contig_interp = 0;
00626 jb_dbg("v");
00627 return JB_OK;
00628 } else {
00629
00630 *frameout = *frame;
00631 jb->info.frames_out++;
00632 decrement_losspct(jb);
00633 jb->info.frames_late++;
00634 jb->info.frames_lost--;
00635 jb_dbg("l");
00636 return JB_DROP;
00637 }
00638 }
00639
00640
00641 if (frame && frame->ms > 0) {
00642 jb->info.last_voice_ms = frame->ms;
00643 }
00644
00645
00646
00647
00648
00649 if (diff < -jb->info.conf.target_extra &&
00650 ((!frame && jb->info.last_adjustment + 80 < now) ||
00651 (jb->info.last_adjustment + 500 < now))) {
00652
00653 jb->info.last_adjustment = now;
00654 jb->info.cnt_contig_interp = 0;
00655
00656 if (frame) {
00657 *frameout = *frame;
00658
00659 jb->info.current -= frame->ms;
00660 jb->info.frames_out++;
00661 decrement_losspct(jb);
00662 jb->info.frames_dropped++;
00663 jb_dbg("s");
00664 return JB_DROP;
00665 } else {
00666
00667 jb->info.current -= jb->info.last_voice_ms;
00668 jb->info.frames_lost++;
00669 increment_losspct(jb);
00670 jb_dbg("S");
00671 return JB_NOFRAME;
00672 }
00673 }
00674
00675
00676 if (!frame) {
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698 jb->info.frames_lost++;
00699 increment_losspct(jb);
00700 jb->info.next_voice_ts += interpl;
00701 jb->info.last_voice_ms = interpl;
00702 jb->info.cnt_contig_interp++;
00703 if (jb->info.conf.max_contig_interp && jb->info.cnt_contig_interp >= jb->info.conf.max_contig_interp) {
00704 jb->info.silence_begin_ts = jb->info.next_voice_ts - jb->info.current;
00705 }
00706 jb_dbg("L");
00707 return JB_INTERP;
00708 }
00709
00710
00711 *frameout = *frame;
00712 jb->info.next_voice_ts += frame->ms;
00713 jb->info.frames_out++;
00714 jb->info.cnt_contig_interp = 0;
00715 decrement_losspct(jb);
00716 jb_dbg("v");
00717 return JB_OK;
00718 } else {
00719
00720
00721
00722
00723
00724
00725
00726
00727 if (diff < -jb->info.conf.target_extra &&
00728 jb->info.last_adjustment + 10 <= now) {
00729 jb->info.current -= interpl;
00730 jb->info.last_adjustment = now;
00731 }
00732
00733 frame = queue_get(jb, now - jb->info.current);
00734 if (!frame) {
00735 return JB_NOFRAME;
00736 } else if (frame->type != JB_TYPE_VOICE) {
00737
00738 *frameout = *frame;
00739 jb->info.frames_out++;
00740 return JB_OK;
00741 }
00742 if (frame->ts < jb->info.silence_begin_ts) {
00743
00744 *frameout = *frame;
00745 jb->info.frames_out++;
00746 decrement_losspct(jb);
00747 jb->info.frames_late++;
00748 jb->info.frames_lost--;
00749 jb_dbg("l");
00750 return JB_DROP;
00751 } else {
00752
00753
00754 jb->info.current = jb->info.target;
00755 jb->info.silence_begin_ts = 0;
00756 jb->info.next_voice_ts = frame->ts + jb->info.current + frame->ms;
00757 jb->info.last_voice_ms = frame->ms;
00758 jb->info.frames_out++;
00759 decrement_losspct(jb);
00760 *frameout = *frame;
00761 jb_dbg("V");
00762 return JB_OK;
00763 }
00764 }
00765 }
00766
00767 long jb_next(jitterbuf *jb)
00768 {
00769 if (jb->info.silence_begin_ts) {
00770 if (jb->frames) {
00771 long next = queue_next(jb);
00772 history_get(jb);
00773
00774 if (jb->info.target - jb->info.current < -jb->info.conf.target_extra)
00775 return jb->info.last_adjustment + 10;
00776 return next + jb->info.target;
00777 }
00778 else
00779 return JB_LONGMAX;
00780 } else {
00781 return jb->info.next_voice_ts;
00782 }
00783 }
00784
00785 enum jb_return_code jb_get(jitterbuf *jb, jb_frame *frameout, long now, long interpl)
00786 {
00787 enum jb_return_code ret = _jb_get(jb, frameout, now, interpl);
00788 #if 0
00789 static int lastts=0;
00790 int thists = ((ret == JB_OK) || (ret == JB_DROP)) ? frameout->ts : 0;
00791 jb_warn("jb_get(%x,%x,%ld) = %d (%d)\n", jb, frameout, now, ret, thists);
00792 if (thists && thists < lastts) jb_warn("XXXX timestamp roll-back!!!\n");
00793 lastts = thists;
00794 #endif
00795 if (ret == JB_INTERP)
00796 frameout->ms = jb->info.last_voice_ms;
00797
00798 return ret;
00799 }
00800
00801 enum jb_return_code jb_getall(jitterbuf *jb, jb_frame *frameout)
00802 {
00803 jb_frame *frame;
00804 frame = queue_getall(jb);
00805
00806 if (!frame) {
00807 return JB_NOFRAME;
00808 }
00809
00810 *frameout = *frame;
00811 return JB_OK;
00812 }
00813
00814
00815 enum jb_return_code jb_getinfo(jitterbuf *jb, jb_info *stats)
00816 {
00817
00818 history_get(jb);
00819
00820 *stats = jb->info;
00821
00822 return JB_OK;
00823 }
00824
00825 enum jb_return_code jb_setconf(jitterbuf *jb, jb_conf *conf)
00826 {
00827
00828
00829 jb->info.conf.max_jitterbuf = conf->max_jitterbuf;
00830 jb->info.conf.resync_threshold = conf->resync_threshold;
00831 jb->info.conf.max_contig_interp = conf->max_contig_interp;
00832
00833
00834 jb->info.conf.target_extra = ( conf->target_extra == -1 )
00835 ? JB_TARGET_EXTRA
00836 : conf->target_extra
00837 ;
00838
00839
00840 jb->info.current = jb->info.conf.target_extra;
00841 jb->info.target = jb->info.conf.target_extra;
00842
00843 return JB_OK;
00844 }
00845
00846