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