2 * abstract_jb: common implementation-independent jitterbuffer stuff
4 * Copyright (C) 2005, Attractel OOD
7 * Slav Klenov <slav@securax.org>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
19 * A license has been granted to Digium (via disclaimer) for the use of
25 * \brief Common implementation-independent jitterbuffer stuff.
27 * \author Slav Klenov <slav@securax.org>
32 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
37 #include "asterisk/frame.h"
38 #include "asterisk/channel.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/term.h"
41 #include "asterisk/options.h"
42 #include "asterisk/utils.h"
44 #include "asterisk/abstract_jb.h"
45 #include "fixedjitterbuf.h"
46 #include "jitterbuf.h"
48 /*! Internal jb flags */
51 JB_TIMEBASE_INITIALIZED
= (1 << 1),
55 /* Hooks for the abstract jb implementation */
58 typedef void * (*jb_create_impl
)(struct ast_jb_conf
*general_config
, long resynch_threshold
);
60 typedef void (*jb_destroy_impl
)(void *jb
);
61 /*! \brief Put first frame */
62 typedef int (*jb_put_first_impl
)(void *jb
, struct ast_frame
*fin
, long now
);
63 /*! \brief Put frame */
64 typedef int (*jb_put_impl
)(void *jb
, struct ast_frame
*fin
, long now
);
65 /*! \brief Get frame for now */
66 typedef int (*jb_get_impl
)(void *jb
, struct ast_frame
**fout
, long now
, long interpl
);
67 /*! \brief Get next */
68 typedef long (*jb_next_impl
)(void *jb
);
69 /*! \brief Remove first frame */
70 typedef int (*jb_remove_impl
)(void *jb
, struct ast_frame
**fout
);
71 /*! \brief Force resynch */
72 typedef void (*jb_force_resynch_impl
)(void *jb
);
76 * \brief Jitterbuffer implementation private struct.
80 char name
[AST_JB_IMPL_NAME_SIZE
];
81 jb_create_impl create
;
82 jb_destroy_impl destroy
;
83 jb_put_first_impl put_first
;
87 jb_remove_impl remove
;
88 jb_force_resynch_impl force_resync
;
91 /* Implementation functions */
93 static void * jb_create_fixed(struct ast_jb_conf
*general_config
, long resynch_threshold
);
94 static void jb_destroy_fixed(void *jb
);
95 static int jb_put_first_fixed(void *jb
, struct ast_frame
*fin
, long now
);
96 static int jb_put_fixed(void *jb
, struct ast_frame
*fin
, long now
);
97 static int jb_get_fixed(void *jb
, struct ast_frame
**fout
, long now
, long interpl
);
98 static long jb_next_fixed(void *jb
);
99 static int jb_remove_fixed(void *jb
, struct ast_frame
**fout
);
100 static void jb_force_resynch_fixed(void *jb
);
102 static void * jb_create_adaptive(struct ast_jb_conf
*general_config
, long resynch_threshold
);
103 static void jb_destroy_adaptive(void *jb
);
104 static int jb_put_first_adaptive(void *jb
, struct ast_frame
*fin
, long now
);
105 static int jb_put_adaptive(void *jb
, struct ast_frame
*fin
, long now
);
106 static int jb_get_adaptive(void *jb
, struct ast_frame
**fout
, long now
, long interpl
);
107 static long jb_next_adaptive(void *jb
);
108 static int jb_remove_adaptive(void *jb
, struct ast_frame
**fout
);
109 static void jb_force_resynch_adaptive(void *jb
);
111 /* Available jb implementations */
112 static struct ast_jb_impl avail_impl
[] =
116 .create
= jb_create_fixed
,
117 .destroy
= jb_destroy_fixed
,
118 .put_first
= jb_put_first_fixed
,
121 .next
= jb_next_fixed
,
122 .remove
= jb_remove_fixed
,
123 .force_resync
= jb_force_resynch_fixed
127 .create
= jb_create_adaptive
,
128 .destroy
= jb_destroy_adaptive
,
129 .put_first
= jb_put_first_adaptive
,
130 .put
= jb_put_adaptive
,
131 .get
= jb_get_adaptive
,
132 .next
= jb_next_adaptive
,
133 .remove
= jb_remove_adaptive
,
134 .force_resync
= jb_force_resynch_adaptive
138 static int default_impl
= 0;
141 /*! Abstract return codes */
149 /* Translations between impl and abstract return codes */
150 static int fixed_to_abstract_code
[] =
151 {JB_IMPL_OK
, JB_IMPL_DROP
, JB_IMPL_INTERP
, JB_IMPL_NOFRAME
};
152 static int adaptive_to_abstract_code
[] =
153 {JB_IMPL_OK
, JB_IMPL_NOFRAME
, JB_IMPL_NOFRAME
, JB_IMPL_INTERP
, JB_IMPL_DROP
, JB_IMPL_OK
};
155 /* JB_GET actions (used only for the frames log) */
156 static char *jb_get_actions
[] = {"Delivered", "Dropped", "Interpolated", "No"};
158 /*! \brief Macros for the frame log files */
159 #define jb_framelog(...) do { \
161 fprintf(jb->logfile, __VA_ARGS__); \
162 fflush(jb->logfile); \
167 /* Internal utility functions */
168 static void jb_choose_impl(struct ast_channel
*chan
);
169 static void jb_get_and_deliver(struct ast_channel
*chan
);
170 static int create_jb(struct ast_channel
*chan
, struct ast_frame
*first_frame
);
171 static long get_now(struct ast_jb
*jb
, struct timeval
*tv
);
174 /* Interface ast jb functions impl */
177 static void jb_choose_impl(struct ast_channel
*chan
)
179 struct ast_jb
*jb
= &chan
->jb
;
180 struct ast_jb_conf
*jbconf
= &jb
->conf
;
181 struct ast_jb_impl
*test_impl
;
182 int i
, avail_impl_count
= sizeof(avail_impl
) / sizeof(avail_impl
[0]);
184 jb
->impl
= &avail_impl
[default_impl
];
186 if (ast_strlen_zero(jbconf
->impl
))
189 for (i
= 0; i
< avail_impl_count
; i
++) {
190 test_impl
= &avail_impl
[i
];
191 if (!strcasecmp(jbconf
->impl
, test_impl
->name
)) {
192 jb
->impl
= test_impl
;
198 int ast_jb_do_usecheck(struct ast_channel
*c0
, struct ast_channel
*c1
)
200 struct ast_jb
*jb0
= &c0
->jb
;
201 struct ast_jb
*jb1
= &c1
->jb
;
202 struct ast_jb_conf
*conf0
= &jb0
->conf
;
203 struct ast_jb_conf
*conf1
= &jb1
->conf
;
204 int c0_wants_jitter
= c0
->tech
->properties
& AST_CHAN_TP_WANTSJITTER
;
205 int c0_creates_jitter
= c0
->tech
->properties
& AST_CHAN_TP_CREATESJITTER
;
206 int c0_jb_enabled
= ast_test_flag(conf0
, AST_JB_ENABLED
);
207 int c0_force_jb
= ast_test_flag(conf0
, AST_JB_FORCED
);
208 int c0_jb_timebase_initialized
= ast_test_flag(jb0
, JB_TIMEBASE_INITIALIZED
);
209 int c0_jb_created
= ast_test_flag(jb0
, JB_CREATED
);
210 int c1_wants_jitter
= c1
->tech
->properties
& AST_CHAN_TP_WANTSJITTER
;
211 int c1_creates_jitter
= c1
->tech
->properties
& AST_CHAN_TP_CREATESJITTER
;
212 int c1_jb_enabled
= ast_test_flag(conf1
, AST_JB_ENABLED
);
213 int c1_force_jb
= ast_test_flag(conf1
, AST_JB_FORCED
);
214 int c1_jb_timebase_initialized
= ast_test_flag(jb1
, JB_TIMEBASE_INITIALIZED
);
215 int c1_jb_created
= ast_test_flag(jb1
, JB_CREATED
);
218 /* Determine whether audio going to c0 needs a jitter buffer */
219 if (((!c0_wants_jitter
&& c1_creates_jitter
) || (c0_force_jb
&& c1_creates_jitter
)) && c0_jb_enabled
) {
220 ast_set_flag(jb0
, JB_USE
);
221 if (!c0_jb_timebase_initialized
) {
222 if (c1_jb_timebase_initialized
) {
223 memcpy(&jb0
->timebase
, &jb1
->timebase
, sizeof(struct timeval
));
225 gettimeofday(&jb0
->timebase
, NULL
);
227 ast_set_flag(jb0
, JB_TIMEBASE_INITIALIZED
);
230 if (!c0_jb_created
) {
237 /* Determine whether audio going to c1 needs a jitter buffer */
238 if (((!c1_wants_jitter
&& c0_creates_jitter
) || (c1_force_jb
&& c0_creates_jitter
)) && c1_jb_enabled
) {
239 ast_set_flag(jb1
, JB_USE
);
240 if (!c1_jb_timebase_initialized
) {
241 if (c0_jb_timebase_initialized
) {
242 memcpy(&jb1
->timebase
, &jb0
->timebase
, sizeof(struct timeval
));
244 gettimeofday(&jb1
->timebase
, NULL
);
246 ast_set_flag(jb1
, JB_TIMEBASE_INITIALIZED
);
249 if (!c1_jb_created
) {
259 int ast_jb_get_when_to_wakeup(struct ast_channel
*c0
, struct ast_channel
*c1
, int time_left
)
261 struct ast_jb
*jb0
= &c0
->jb
;
262 struct ast_jb
*jb1
= &c1
->jb
;
263 int c0_use_jb
= ast_test_flag(jb0
, JB_USE
);
264 int c0_jb_is_created
= ast_test_flag(jb0
, JB_CREATED
);
265 int c1_use_jb
= ast_test_flag(jb1
, JB_USE
);
266 int c1_jb_is_created
= ast_test_flag(jb1
, JB_CREATED
);
267 int wait
, wait0
, wait1
;
268 struct timeval tv_now
;
270 if (time_left
== 0) {
271 /* No time left - the bridge will be retried */
272 /* TODO: Test disable this */
280 gettimeofday(&tv_now
, NULL
);
282 wait0
= (c0_use_jb
&& c0_jb_is_created
) ? jb0
->next
- get_now(jb0
, &tv_now
) : time_left
;
283 wait1
= (c1_use_jb
&& c1_jb_is_created
) ? jb1
->next
- get_now(jb1
, &tv_now
) : time_left
;
285 wait
= wait0
< wait1
? wait0
: wait1
;
286 wait
= wait
< time_left
? wait
: time_left
;
288 if (wait
== INT_MAX
) {
290 } else if (wait
< 1) {
291 /* don't let wait=0, because this can cause the pbx thread to loop without any sleeping at all */
299 int ast_jb_put(struct ast_channel
*chan
, struct ast_frame
*f
)
301 struct ast_jb
*jb
= &chan
->jb
;
302 struct ast_jb_impl
*jbimpl
= jb
->impl
;
303 void *jbobj
= jb
->jbobj
;
304 struct ast_frame
*frr
;
307 if (!ast_test_flag(jb
, JB_USE
))
310 if (f
->frametype
!= AST_FRAME_VOICE
) {
311 if (f
->frametype
== AST_FRAME_DTMF
&& ast_test_flag(jb
, JB_CREATED
)) {
312 jb_framelog("JB_PUT {now=%ld}: Received DTMF frame. Force resynching jb...\n", now
);
313 jbimpl
->force_resync(jbobj
);
319 /* We consider an enabled jitterbuffer should receive frames with valid timing info. */
320 if (!ast_test_flag(f
, AST_FRFLAG_HAS_TIMING_INFO
) || f
->len
< 2 || f
->ts
< 0) {
321 ast_log(LOG_WARNING
, "%s recieved frame with invalid timing info: "
322 "has_timing_info=%d, len=%ld, ts=%ld, src=%s\n",
323 chan
->name
, ast_test_flag(f
, AST_FRFLAG_HAS_TIMING_INFO
), f
->len
, f
->ts
, f
->src
);
330 ast_log(LOG_ERROR
, "Failed to isolate frame for the jitterbuffer on channel '%s'\n", chan
->name
);
334 if (!ast_test_flag(jb
, JB_CREATED
)) {
335 if (create_jb(chan
, frr
)) {
337 /* Disable the jitterbuffer */
338 ast_clear_flag(jb
, JB_USE
);
342 ast_set_flag(jb
, JB_CREATED
);
345 now
= get_now(jb
, NULL
);
346 if (jbimpl
->put(jbobj
, frr
, now
) != JB_IMPL_OK
) {
347 jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now
, frr
->ts
, frr
->len
);
350 /* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't
351 be delivered at all */
355 jb
->next
= jbimpl
->next(jbobj
);
357 jb_framelog("JB_PUT {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now
, frr
->ts
, frr
->len
);
364 void ast_jb_get_and_deliver(struct ast_channel
*c0
, struct ast_channel
*c1
)
366 struct ast_jb
*jb0
= &c0
->jb
;
367 struct ast_jb
*jb1
= &c1
->jb
;
368 int c0_use_jb
= ast_test_flag(jb0
, JB_USE
);
369 int c0_jb_is_created
= ast_test_flag(jb0
, JB_CREATED
);
370 int c1_use_jb
= ast_test_flag(jb1
, JB_USE
);
371 int c1_jb_is_created
= ast_test_flag(jb1
, JB_CREATED
);
373 if (c0_use_jb
&& c0_jb_is_created
)
374 jb_get_and_deliver(c0
);
376 if (c1_use_jb
&& c1_jb_is_created
)
377 jb_get_and_deliver(c1
);
381 static void jb_get_and_deliver(struct ast_channel
*chan
)
383 struct ast_jb
*jb
= &chan
->jb
;
384 struct ast_jb_impl
*jbimpl
= jb
->impl
;
385 void *jbobj
= jb
->jbobj
;
386 struct ast_frame
*f
, finterp
;
388 int interpolation_len
, res
;
390 now
= get_now(jb
, NULL
);
391 jb
->next
= jbimpl
->next(jbobj
);
392 if (now
< jb
->next
) {
393 jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now
, jb
->next
);
397 while (now
>= jb
->next
) {
398 interpolation_len
= ast_codec_interp_len(jb
->last_format
);
400 res
= jbimpl
->get(jbobj
, &f
, now
, interpolation_len
);
404 /* deliver the frame */
407 jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
408 now
, jb_get_actions
[res
], f
->ts
, f
->len
);
409 jb
->last_format
= f
->subclass
;
413 /* interpolate a frame */
415 f
->frametype
= AST_FRAME_VOICE
;
416 f
->subclass
= jb
->last_format
;
418 f
->samples
= interpolation_len
* 8;
420 f
->src
= "JB interpolation";
422 f
->delivery
= ast_tvadd(jb
->timebase
, ast_samp2tv(jb
->next
, 1000));
423 f
->offset
= AST_FRIENDLY_OFFSET
;
424 /* deliver the interpolated frame */
426 jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now
, interpolation_len
);
428 case JB_IMPL_NOFRAME
:
430 "JB_IMPL_NOFRAME is retuned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
431 jbimpl
->name
, now
, jb
->next
, jbimpl
->next(jbobj
));
432 jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now
);
435 ast_log(LOG_ERROR
, "This should never happen!\n");
436 ast_assert("JB type unknown" == NULL
);
440 jb
->next
= jbimpl
->next(jbobj
);
445 static int create_jb(struct ast_channel
*chan
, struct ast_frame
*frr
)
447 struct ast_jb
*jb
= &chan
->jb
;
448 struct ast_jb_conf
*jbconf
= &jb
->conf
;
449 struct ast_jb_impl
*jbimpl
= jb
->impl
;
451 struct ast_channel
*bridged
;
453 char logfile_pathname
[20 + AST_JB_IMPL_NAME_SIZE
+ 2*AST_CHANNEL_NAME
+ 1];
454 char name1
[AST_CHANNEL_NAME
], name2
[AST_CHANNEL_NAME
], *tmp
;
457 jbobj
= jb
->jbobj
= jbimpl
->create(jbconf
, jbconf
->resync_threshold
);
459 ast_log(LOG_WARNING
, "Failed to create jitterbuffer on channel '%s'\n", chan
->name
);
463 now
= get_now(jb
, NULL
);
464 res
= jbimpl
->put_first(jbobj
, frr
, now
);
466 /* The result of putting the first frame should not differ from OK. However, its possible
467 some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */
468 if (res
!= JB_IMPL_OK
) {
469 ast_log(LOG_WARNING
, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan
->name
);
471 jbimpl->destroy(jbobj);
477 jb
->next
= jbimpl
->next(jbobj
);
479 /* Init last format for a first time. */
480 jb
->last_format
= frr
->subclass
;
482 /* Create a frame log file */
483 if (ast_test_flag(jbconf
, AST_JB_LOG
)) {
484 snprintf(name2
, sizeof(name2
), "%s", chan
->name
);
485 tmp
= strchr(name2
, '/');
489 bridged
= ast_bridged_channel(chan
);
490 /* We should always have bridged chan if a jitterbuffer is in use */
491 ast_assert(bridged
!= NULL
);
493 snprintf(name1
, sizeof(name1
), "%s", bridged
->name
);
494 tmp
= strchr(name1
, '/');
498 snprintf(logfile_pathname
, sizeof(logfile_pathname
),
499 "/tmp/ast_%s_jb_%s--%s.log", jbimpl
->name
, name1
, name2
);
500 jb
->logfile
= fopen(logfile_pathname
, "w+b");
503 ast_log(LOG_WARNING
, "Failed to create frame log file with pathname '%s'\n", logfile_pathname
);
505 if (res
== JB_IMPL_OK
)
506 jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
507 now
, frr
->ts
, frr
->len
);
509 jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n",
510 now
, frr
->ts
, frr
->len
);
513 if (option_verbose
> 2)
514 ast_verbose(VERBOSE_PREFIX_3
"%s jitterbuffer created on channel %s\n", jbimpl
->name
, chan
->name
);
516 /* Free the frame if it has not been queued in the jb */
517 if (res
!= JB_IMPL_OK
)
524 void ast_jb_destroy(struct ast_channel
*chan
)
526 struct ast_jb
*jb
= &chan
->jb
;
527 struct ast_jb_impl
*jbimpl
= jb
->impl
;
528 void *jbobj
= jb
->jbobj
;
536 if (ast_test_flag(jb
, JB_CREATED
)) {
537 /* Remove and free all frames still queued in jb */
538 while (jbimpl
->remove(jbobj
, &f
) == JB_IMPL_OK
) {
542 jbimpl
->destroy(jbobj
);
545 ast_clear_flag(jb
, JB_CREATED
);
547 if (option_verbose
> 2)
548 ast_verbose(VERBOSE_PREFIX_3
"%s jitterbuffer destroyed on channel %s\n", jbimpl
->name
, chan
->name
);
553 static long get_now(struct ast_jb
*jb
, struct timeval
*tv
)
559 gettimeofday(tv
, NULL
);
562 return ast_tvdiff_ms(*tv
, jb
->timebase
);
566 int ast_jb_read_conf(struct ast_jb_conf
*conf
, char *varname
, char *value
)
568 int prefixlen
= sizeof(AST_JB_CONF_PREFIX
) - 1;
572 if (strncasecmp(AST_JB_CONF_PREFIX
, varname
, prefixlen
))
575 name
= varname
+ prefixlen
;
577 if (!strcasecmp(name
, AST_JB_CONF_ENABLE
)) {
578 ast_set2_flag(conf
, ast_true(value
), AST_JB_ENABLED
);
579 } else if (!strcasecmp(name
, AST_JB_CONF_FORCE
)) {
580 ast_set2_flag(conf
, ast_true(value
), AST_JB_FORCED
);
581 } else if (!strcasecmp(name
, AST_JB_CONF_MAX_SIZE
)) {
582 if ((tmp
= atoi(value
)) > 0)
583 conf
->max_size
= tmp
;
584 } else if (!strcasecmp(name
, AST_JB_CONF_RESYNCH_THRESHOLD
)) {
585 if ((tmp
= atoi(value
)) > 0)
586 conf
->resync_threshold
= tmp
;
587 } else if (!strcasecmp(name
, AST_JB_CONF_IMPL
)) {
588 if (!ast_strlen_zero(value
))
589 snprintf(conf
->impl
, sizeof(conf
->impl
), "%s", value
);
590 } else if (!strcasecmp(name
, AST_JB_CONF_LOG
)) {
591 ast_set2_flag(conf
, ast_true(value
), AST_JB_LOG
);
600 void ast_jb_configure(struct ast_channel
*chan
, const struct ast_jb_conf
*conf
)
602 memcpy(&chan
->jb
.conf
, conf
, sizeof(*conf
));
606 void ast_jb_get_config(const struct ast_channel
*chan
, struct ast_jb_conf
*conf
)
608 memcpy(conf
, &chan
->jb
.conf
, sizeof(*conf
));
612 /* Implementation functions */
616 static void * jb_create_fixed(struct ast_jb_conf
*general_config
, long resynch_threshold
)
618 struct fixed_jb_conf conf
;
620 conf
.jbsize
= general_config
->max_size
;
621 conf
.resync_threshold
= resynch_threshold
;
623 return fixed_jb_new(&conf
);
627 static void jb_destroy_fixed(void *jb
)
629 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
632 fixed_jb_destroy(fixedjb
);
636 static int jb_put_first_fixed(void *jb
, struct ast_frame
*fin
, long now
)
638 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
641 res
= fixed_jb_put_first(fixedjb
, fin
, fin
->len
, fin
->ts
, now
);
643 return fixed_to_abstract_code
[res
];
647 static int jb_put_fixed(void *jb
, struct ast_frame
*fin
, long now
)
649 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
652 res
= fixed_jb_put(fixedjb
, fin
, fin
->len
, fin
->ts
, now
);
654 return fixed_to_abstract_code
[res
];
658 static int jb_get_fixed(void *jb
, struct ast_frame
**fout
, long now
, long interpl
)
660 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
661 struct fixed_jb_frame frame
;
664 res
= fixed_jb_get(fixedjb
, &frame
, now
, interpl
);
667 return fixed_to_abstract_code
[res
];
671 static long jb_next_fixed(void *jb
)
673 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
675 return fixed_jb_next(fixedjb
);
679 static int jb_remove_fixed(void *jb
, struct ast_frame
**fout
)
681 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
682 struct fixed_jb_frame frame
;
685 res
= fixed_jb_remove(fixedjb
, &frame
);
688 return fixed_to_abstract_code
[res
];
692 static void jb_force_resynch_fixed(void *jb
)
694 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
696 fixed_jb_set_force_resynch(fixedjb
);
702 static void *jb_create_adaptive(struct ast_jb_conf
*general_config
, long resynch_threshold
)
705 jitterbuf
*adaptivejb
;
707 adaptivejb
= jb_new();
709 jbconf
.max_jitterbuf
= general_config
->max_size
;
710 jbconf
.resync_threshold
= general_config
->resync_threshold
;
711 jbconf
.max_contig_interp
= 10;
712 jb_setconf(adaptivejb
, &jbconf
);
719 static void jb_destroy_adaptive(void *jb
)
721 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
723 jb_destroy(adaptivejb
);
727 static int jb_put_first_adaptive(void *jb
, struct ast_frame
*fin
, long now
)
729 return jb_put_adaptive(jb
, fin
, now
);
733 static int jb_put_adaptive(void *jb
, struct ast_frame
*fin
, long now
)
735 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
738 res
= jb_put(adaptivejb
, fin
, JB_TYPE_VOICE
, fin
->len
, fin
->ts
, now
);
740 return adaptive_to_abstract_code
[res
];
744 static int jb_get_adaptive(void *jb
, struct ast_frame
**fout
, long now
, long interpl
)
746 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
750 res
= jb_get(adaptivejb
, &frame
, now
, interpl
);
753 return adaptive_to_abstract_code
[res
];
757 static long jb_next_adaptive(void *jb
)
759 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
761 return jb_next(adaptivejb
);
765 static int jb_remove_adaptive(void *jb
, struct ast_frame
**fout
)
767 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
771 res
= jb_getall(adaptivejb
, &frame
);
774 return adaptive_to_abstract_code
[res
];
778 static void jb_force_resynch_adaptive(void *jb
)