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>
34 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include "asterisk/frame.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/term.h"
39 #include "asterisk/utils.h"
41 #include "asterisk/abstract_jb.h"
42 #include "fixedjitterbuf.h"
43 #include "jitterbuf.h"
45 /*! Internal jb flags */
48 JB_TIMEBASE_INITIALIZED
= (1 << 1),
52 /* Hooks for the abstract jb implementation */
55 typedef void * (*jb_create_impl
)(struct ast_jb_conf
*general_config
, long resynch_threshold
);
57 typedef void (*jb_destroy_impl
)(void *jb
);
58 /*! \brief Put first frame */
59 typedef int (*jb_put_first_impl
)(void *jb
, struct ast_frame
*fin
, long now
);
60 /*! \brief Put frame */
61 typedef int (*jb_put_impl
)(void *jb
, struct ast_frame
*fin
, long now
);
62 /*! \brief Get frame for now */
63 typedef int (*jb_get_impl
)(void *jb
, struct ast_frame
**fout
, long now
, long interpl
);
64 /*! \brief Get next */
65 typedef long (*jb_next_impl
)(void *jb
);
66 /*! \brief Remove first frame */
67 typedef int (*jb_remove_impl
)(void *jb
, struct ast_frame
**fout
);
68 /*! \brief Force resynch */
69 typedef void (*jb_force_resynch_impl
)(void *jb
);
73 * \brief Jitterbuffer implementation private struct.
77 char name
[AST_JB_IMPL_NAME_SIZE
];
78 jb_create_impl create
;
79 jb_destroy_impl destroy
;
80 jb_put_first_impl put_first
;
84 jb_remove_impl remove
;
85 jb_force_resynch_impl force_resync
;
88 /* Implementation functions */
90 static void *jb_create_fixed(struct ast_jb_conf
*general_config
, long resynch_threshold
);
91 static void jb_destroy_fixed(void *jb
);
92 static int jb_put_first_fixed(void *jb
, struct ast_frame
*fin
, long now
);
93 static int jb_put_fixed(void *jb
, struct ast_frame
*fin
, long now
);
94 static int jb_get_fixed(void *jb
, struct ast_frame
**fout
, long now
, long interpl
);
95 static long jb_next_fixed(void *jb
);
96 static int jb_remove_fixed(void *jb
, struct ast_frame
**fout
);
97 static void jb_force_resynch_fixed(void *jb
);
99 static void * jb_create_adaptive(struct ast_jb_conf
*general_config
, long resynch_threshold
);
100 static void jb_destroy_adaptive(void *jb
);
101 static int jb_put_first_adaptive(void *jb
, struct ast_frame
*fin
, long now
);
102 static int jb_put_adaptive(void *jb
, struct ast_frame
*fin
, long now
);
103 static int jb_get_adaptive(void *jb
, struct ast_frame
**fout
, long now
, long interpl
);
104 static long jb_next_adaptive(void *jb
);
105 static int jb_remove_adaptive(void *jb
, struct ast_frame
**fout
);
106 static void jb_force_resynch_adaptive(void *jb
);
108 /* Available jb implementations */
109 static struct ast_jb_impl avail_impl
[] =
113 .create
= jb_create_fixed
,
114 .destroy
= jb_destroy_fixed
,
115 .put_first
= jb_put_first_fixed
,
118 .next
= jb_next_fixed
,
119 .remove
= jb_remove_fixed
,
120 .force_resync
= jb_force_resynch_fixed
124 .create
= jb_create_adaptive
,
125 .destroy
= jb_destroy_adaptive
,
126 .put_first
= jb_put_first_adaptive
,
127 .put
= jb_put_adaptive
,
128 .get
= jb_get_adaptive
,
129 .next
= jb_next_adaptive
,
130 .remove
= jb_remove_adaptive
,
131 .force_resync
= jb_force_resynch_adaptive
135 static int default_impl
= 0;
138 /*! Abstract return codes */
146 /* Translations between impl and abstract return codes */
147 static int fixed_to_abstract_code
[] =
148 {JB_IMPL_OK
, JB_IMPL_DROP
, JB_IMPL_INTERP
, JB_IMPL_NOFRAME
};
149 static int adaptive_to_abstract_code
[] =
150 {JB_IMPL_OK
, JB_IMPL_NOFRAME
, JB_IMPL_NOFRAME
, JB_IMPL_INTERP
, JB_IMPL_DROP
, JB_IMPL_OK
};
152 /* JB_GET actions (used only for the frames log) */
153 static char *jb_get_actions
[] = {"Delivered", "Dropped", "Interpolated", "No"};
155 /*! \brief Macros for the frame log files */
156 #define jb_framelog(...) do { \
158 fprintf(jb->logfile, __VA_ARGS__); \
159 fflush(jb->logfile); \
164 /* Internal utility functions */
165 static void jb_choose_impl(struct ast_channel
*chan
);
166 static void jb_get_and_deliver(struct ast_channel
*chan
);
167 static int create_jb(struct ast_channel
*chan
, struct ast_frame
*first_frame
);
168 static long get_now(struct ast_jb
*jb
, struct timeval
*tv
);
171 /* Interface ast jb functions impl */
174 static void jb_choose_impl(struct ast_channel
*chan
)
176 struct ast_jb
*jb
= &chan
->jb
;
177 struct ast_jb_conf
*jbconf
= &jb
->conf
;
178 struct ast_jb_impl
*test_impl
;
179 int i
, avail_impl_count
= sizeof(avail_impl
) / sizeof(avail_impl
[0]);
181 jb
->impl
= &avail_impl
[default_impl
];
183 if (ast_strlen_zero(jbconf
->impl
))
186 for (i
= 0; i
< avail_impl_count
; i
++) {
187 test_impl
= &avail_impl
[i
];
188 if (!strcasecmp(jbconf
->impl
, test_impl
->name
)) {
189 jb
->impl
= test_impl
;
195 int ast_jb_do_usecheck(struct ast_channel
*c0
, struct ast_channel
*c1
)
197 struct ast_jb
*jb0
= &c0
->jb
;
198 struct ast_jb
*jb1
= &c1
->jb
;
199 struct ast_jb_conf
*conf0
= &jb0
->conf
;
200 struct ast_jb_conf
*conf1
= &jb1
->conf
;
201 int c0_wants_jitter
= c0
->tech
->properties
& AST_CHAN_TP_WANTSJITTER
;
202 int c0_creates_jitter
= c0
->tech
->properties
& AST_CHAN_TP_CREATESJITTER
;
203 int c0_jb_enabled
= ast_test_flag(conf0
, AST_JB_ENABLED
);
204 int c0_force_jb
= ast_test_flag(conf0
, AST_JB_FORCED
);
205 int c0_jb_timebase_initialized
= ast_test_flag(jb0
, JB_TIMEBASE_INITIALIZED
);
206 int c0_jb_created
= ast_test_flag(jb0
, JB_CREATED
);
207 int c1_wants_jitter
= c1
->tech
->properties
& AST_CHAN_TP_WANTSJITTER
;
208 int c1_creates_jitter
= c1
->tech
->properties
& AST_CHAN_TP_CREATESJITTER
;
209 int c1_jb_enabled
= ast_test_flag(conf1
, AST_JB_ENABLED
);
210 int c1_force_jb
= ast_test_flag(conf1
, AST_JB_FORCED
);
211 int c1_jb_timebase_initialized
= ast_test_flag(jb1
, JB_TIMEBASE_INITIALIZED
);
212 int c1_jb_created
= ast_test_flag(jb1
, JB_CREATED
);
215 /* Determine whether audio going to c0 needs a jitter buffer */
216 if (((!c0_wants_jitter
&& c1_creates_jitter
) || (c0_force_jb
&& c1_creates_jitter
)) && c0_jb_enabled
) {
217 ast_set_flag(jb0
, JB_USE
);
218 if (!c0_jb_timebase_initialized
) {
219 if (c1_jb_timebase_initialized
) {
220 memcpy(&jb0
->timebase
, &jb1
->timebase
, sizeof(struct timeval
));
222 gettimeofday(&jb0
->timebase
, NULL
);
224 ast_set_flag(jb0
, JB_TIMEBASE_INITIALIZED
);
227 if (!c0_jb_created
) {
234 /* Determine whether audio going to c1 needs a jitter buffer */
235 if (((!c1_wants_jitter
&& c0_creates_jitter
) || (c1_force_jb
&& c0_creates_jitter
)) && c1_jb_enabled
) {
236 ast_set_flag(jb1
, JB_USE
);
237 if (!c1_jb_timebase_initialized
) {
238 if (c0_jb_timebase_initialized
) {
239 memcpy(&jb1
->timebase
, &jb0
->timebase
, sizeof(struct timeval
));
241 gettimeofday(&jb1
->timebase
, NULL
);
243 ast_set_flag(jb1
, JB_TIMEBASE_INITIALIZED
);
246 if (!c1_jb_created
) {
256 int ast_jb_get_when_to_wakeup(struct ast_channel
*c0
, struct ast_channel
*c1
, int time_left
)
258 struct ast_jb
*jb0
= &c0
->jb
;
259 struct ast_jb
*jb1
= &c1
->jb
;
260 int c0_use_jb
= ast_test_flag(jb0
, JB_USE
);
261 int c0_jb_is_created
= ast_test_flag(jb0
, JB_CREATED
);
262 int c1_use_jb
= ast_test_flag(jb1
, JB_USE
);
263 int c1_jb_is_created
= ast_test_flag(jb1
, JB_CREATED
);
264 int wait
, wait0
, wait1
;
265 struct timeval tv_now
;
267 if (time_left
== 0) {
268 /* No time left - the bridge will be retried */
269 /* TODO: Test disable this */
277 gettimeofday(&tv_now
, NULL
);
279 wait0
= (c0_use_jb
&& c0_jb_is_created
) ? jb0
->next
- get_now(jb0
, &tv_now
) : time_left
;
280 wait1
= (c1_use_jb
&& c1_jb_is_created
) ? jb1
->next
- get_now(jb1
, &tv_now
) : time_left
;
282 wait
= wait0
< wait1
? wait0
: wait1
;
283 wait
= wait
< time_left
? wait
: time_left
;
285 if (wait
== INT_MAX
) {
287 } else if (wait
< 1) {
288 /* don't let wait=0, because this can cause the pbx thread to loop without any sleeping at all */
296 int ast_jb_put(struct ast_channel
*chan
, struct ast_frame
*f
)
298 struct ast_jb
*jb
= &chan
->jb
;
299 struct ast_jb_impl
*jbimpl
= jb
->impl
;
300 void *jbobj
= jb
->jbobj
;
301 struct ast_frame
*frr
;
304 if (!ast_test_flag(jb
, JB_USE
))
307 if (f
->frametype
!= AST_FRAME_VOICE
) {
308 if (f
->frametype
== AST_FRAME_DTMF
&& ast_test_flag(jb
, JB_CREATED
)) {
309 jb_framelog("JB_PUT {now=%ld}: Received DTMF frame. Force resynching jb...\n", now
);
310 jbimpl
->force_resync(jbobj
);
316 /* We consider an enabled jitterbuffer should receive frames with valid timing info. */
317 if (!ast_test_flag(f
, AST_FRFLAG_HAS_TIMING_INFO
) || f
->len
< 2 || f
->ts
< 0) {
318 ast_log(LOG_WARNING
, "%s received frame with invalid timing info: "
319 "has_timing_info=%d, len=%ld, ts=%ld, src=%s\n",
320 chan
->name
, ast_test_flag(f
, AST_FRFLAG_HAS_TIMING_INFO
), f
->len
, f
->ts
, f
->src
);
327 ast_log(LOG_ERROR
, "Failed to isolate frame for the jitterbuffer on channel '%s'\n", chan
->name
);
331 if (!ast_test_flag(jb
, JB_CREATED
)) {
332 if (create_jb(chan
, frr
)) {
334 /* Disable the jitterbuffer */
335 ast_clear_flag(jb
, JB_USE
);
339 ast_set_flag(jb
, JB_CREATED
);
342 now
= get_now(jb
, NULL
);
343 if (jbimpl
->put(jbobj
, frr
, now
) != JB_IMPL_OK
) {
344 jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now
, frr
->ts
, frr
->len
);
347 /* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't
348 be delivered at all */
352 jb
->next
= jbimpl
->next(jbobj
);
354 jb_framelog("JB_PUT {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now
, frr
->ts
, frr
->len
);
361 void ast_jb_get_and_deliver(struct ast_channel
*c0
, struct ast_channel
*c1
)
363 struct ast_jb
*jb0
= &c0
->jb
;
364 struct ast_jb
*jb1
= &c1
->jb
;
365 int c0_use_jb
= ast_test_flag(jb0
, JB_USE
);
366 int c0_jb_is_created
= ast_test_flag(jb0
, JB_CREATED
);
367 int c1_use_jb
= ast_test_flag(jb1
, JB_USE
);
368 int c1_jb_is_created
= ast_test_flag(jb1
, JB_CREATED
);
370 if (c0_use_jb
&& c0_jb_is_created
)
371 jb_get_and_deliver(c0
);
373 if (c1_use_jb
&& c1_jb_is_created
)
374 jb_get_and_deliver(c1
);
378 static void jb_get_and_deliver(struct ast_channel
*chan
)
380 struct ast_jb
*jb
= &chan
->jb
;
381 struct ast_jb_impl
*jbimpl
= jb
->impl
;
382 void *jbobj
= jb
->jbobj
;
383 struct ast_frame
*f
, finterp
;
385 int interpolation_len
, res
;
387 now
= get_now(jb
, NULL
);
388 jb
->next
= jbimpl
->next(jbobj
);
389 if (now
< jb
->next
) {
390 jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now
, jb
->next
);
394 while (now
>= jb
->next
) {
395 interpolation_len
= ast_codec_interp_len(jb
->last_format
);
397 res
= jbimpl
->get(jbobj
, &f
, now
, interpolation_len
);
401 /* deliver the frame */
404 jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
405 now
, jb_get_actions
[res
], f
->ts
, f
->len
);
406 jb
->last_format
= f
->subclass
;
410 /* interpolate a frame */
412 f
->frametype
= AST_FRAME_VOICE
;
413 f
->subclass
= jb
->last_format
;
415 f
->samples
= interpolation_len
* 8;
417 f
->src
= "JB interpolation";
419 f
->delivery
= ast_tvadd(jb
->timebase
, ast_samp2tv(jb
->next
, 1000));
420 f
->offset
= AST_FRIENDLY_OFFSET
;
421 /* deliver the interpolated frame */
423 jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now
, interpolation_len
);
425 case JB_IMPL_NOFRAME
:
427 "JB_IMPL_NOFRAME is returned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
428 jbimpl
->name
, now
, jb
->next
, jbimpl
->next(jbobj
));
429 jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now
);
432 ast_log(LOG_ERROR
, "This should never happen!\n");
433 ast_assert("JB type unknown" == NULL
);
437 jb
->next
= jbimpl
->next(jbobj
);
442 static int create_jb(struct ast_channel
*chan
, struct ast_frame
*frr
)
444 struct ast_jb
*jb
= &chan
->jb
;
445 struct ast_jb_conf
*jbconf
= &jb
->conf
;
446 struct ast_jb_impl
*jbimpl
= jb
->impl
;
448 struct ast_channel
*bridged
;
450 char logfile_pathname
[20 + AST_JB_IMPL_NAME_SIZE
+ 2*AST_CHANNEL_NAME
+ 1];
451 char name1
[AST_CHANNEL_NAME
], name2
[AST_CHANNEL_NAME
], *tmp
;
454 jbobj
= jb
->jbobj
= jbimpl
->create(jbconf
, jbconf
->resync_threshold
);
456 ast_log(LOG_WARNING
, "Failed to create jitterbuffer on channel '%s'\n", chan
->name
);
460 now
= get_now(jb
, NULL
);
461 res
= jbimpl
->put_first(jbobj
, frr
, now
);
463 /* The result of putting the first frame should not differ from OK. However, its possible
464 some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */
465 if (res
!= JB_IMPL_OK
) {
466 ast_log(LOG_WARNING
, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan
->name
);
468 jbimpl->destroy(jbobj);
474 jb
->next
= jbimpl
->next(jbobj
);
476 /* Init last format for a first time. */
477 jb
->last_format
= frr
->subclass
;
479 /* Create a frame log file */
480 if (ast_test_flag(jbconf
, AST_JB_LOG
)) {
481 snprintf(name2
, sizeof(name2
), "%s", chan
->name
);
482 tmp
= strchr(name2
, '/');
486 bridged
= ast_bridged_channel(chan
);
487 /* We should always have bridged chan if a jitterbuffer is in use */
488 ast_assert(bridged
!= NULL
);
490 snprintf(name1
, sizeof(name1
), "%s", bridged
->name
);
491 tmp
= strchr(name1
, '/');
495 snprintf(logfile_pathname
, sizeof(logfile_pathname
),
496 "/tmp/ast_%s_jb_%s--%s.log", jbimpl
->name
, name1
, name2
);
497 jb
->logfile
= fopen(logfile_pathname
, "w+b");
500 ast_log(LOG_ERROR
, "Failed to create frame log file with pathname '%s'\n", logfile_pathname
);
502 if (res
== JB_IMPL_OK
)
503 jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
504 now
, frr
->ts
, frr
->len
);
506 jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n",
507 now
, frr
->ts
, frr
->len
);
510 ast_verb(3, "%s jitterbuffer created on channel %s\n", jbimpl
->name
, chan
->name
);
512 /* Free the frame if it has not been queued in the jb */
513 if (res
!= JB_IMPL_OK
)
520 void ast_jb_destroy(struct ast_channel
*chan
)
522 struct ast_jb
*jb
= &chan
->jb
;
523 struct ast_jb_impl
*jbimpl
= jb
->impl
;
524 void *jbobj
= jb
->jbobj
;
532 if (ast_test_flag(jb
, JB_CREATED
)) {
533 /* Remove and free all frames still queued in jb */
534 while (jbimpl
->remove(jbobj
, &f
) == JB_IMPL_OK
) {
538 jbimpl
->destroy(jbobj
);
541 ast_clear_flag(jb
, JB_CREATED
);
543 ast_verb(3, "%s jitterbuffer destroyed on channel %s\n", jbimpl
->name
, chan
->name
);
548 static long get_now(struct ast_jb
*jb
, struct timeval
*tv
)
554 gettimeofday(tv
, NULL
);
557 return ast_tvdiff_ms(*tv
, jb
->timebase
);
561 int ast_jb_read_conf(struct ast_jb_conf
*conf
, const char *varname
, const char *value
)
563 int prefixlen
= sizeof(AST_JB_CONF_PREFIX
) - 1;
567 if (strncasecmp(AST_JB_CONF_PREFIX
, varname
, prefixlen
))
570 name
= varname
+ prefixlen
;
572 if (!strcasecmp(name
, AST_JB_CONF_ENABLE
)) {
573 ast_set2_flag(conf
, ast_true(value
), AST_JB_ENABLED
);
574 } else if (!strcasecmp(name
, AST_JB_CONF_FORCE
)) {
575 ast_set2_flag(conf
, ast_true(value
), AST_JB_FORCED
);
576 } else if (!strcasecmp(name
, AST_JB_CONF_MAX_SIZE
)) {
577 if ((tmp
= atoi(value
)) > 0)
578 conf
->max_size
= tmp
;
579 } else if (!strcasecmp(name
, AST_JB_CONF_RESYNCH_THRESHOLD
)) {
580 if ((tmp
= atoi(value
)) > 0)
581 conf
->resync_threshold
= tmp
;
582 } else if (!strcasecmp(name
, AST_JB_CONF_IMPL
)) {
583 if (!ast_strlen_zero(value
))
584 snprintf(conf
->impl
, sizeof(conf
->impl
), "%s", value
);
585 } else if (!strcasecmp(name
, AST_JB_CONF_LOG
)) {
586 ast_set2_flag(conf
, ast_true(value
), AST_JB_LOG
);
595 void ast_jb_configure(struct ast_channel
*chan
, const struct ast_jb_conf
*conf
)
597 memcpy(&chan
->jb
.conf
, conf
, sizeof(*conf
));
601 void ast_jb_get_config(const struct ast_channel
*chan
, struct ast_jb_conf
*conf
)
603 memcpy(conf
, &chan
->jb
.conf
, sizeof(*conf
));
607 /* Implementation functions */
611 static void * jb_create_fixed(struct ast_jb_conf
*general_config
, long resynch_threshold
)
613 struct fixed_jb_conf conf
;
615 conf
.jbsize
= general_config
->max_size
;
616 conf
.resync_threshold
= resynch_threshold
;
618 return fixed_jb_new(&conf
);
622 static void jb_destroy_fixed(void *jb
)
624 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
627 fixed_jb_destroy(fixedjb
);
631 static int jb_put_first_fixed(void *jb
, struct ast_frame
*fin
, long now
)
633 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
636 res
= fixed_jb_put_first(fixedjb
, fin
, fin
->len
, fin
->ts
, now
);
638 return fixed_to_abstract_code
[res
];
642 static int jb_put_fixed(void *jb
, struct ast_frame
*fin
, long now
)
644 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
647 res
= fixed_jb_put(fixedjb
, fin
, fin
->len
, fin
->ts
, now
);
649 return fixed_to_abstract_code
[res
];
653 static int jb_get_fixed(void *jb
, struct ast_frame
**fout
, long now
, long interpl
)
655 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
656 struct fixed_jb_frame frame
;
659 res
= fixed_jb_get(fixedjb
, &frame
, now
, interpl
);
662 return fixed_to_abstract_code
[res
];
666 static long jb_next_fixed(void *jb
)
668 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
670 return fixed_jb_next(fixedjb
);
674 static int jb_remove_fixed(void *jb
, struct ast_frame
**fout
)
676 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
677 struct fixed_jb_frame frame
;
680 res
= fixed_jb_remove(fixedjb
, &frame
);
683 return fixed_to_abstract_code
[res
];
687 static void jb_force_resynch_fixed(void *jb
)
689 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
691 fixed_jb_set_force_resynch(fixedjb
);
697 static void *jb_create_adaptive(struct ast_jb_conf
*general_config
, long resynch_threshold
)
700 jitterbuf
*adaptivejb
;
702 adaptivejb
= jb_new();
704 jbconf
.max_jitterbuf
= general_config
->max_size
;
705 jbconf
.resync_threshold
= general_config
->resync_threshold
;
706 jbconf
.max_contig_interp
= 10;
707 jb_setconf(adaptivejb
, &jbconf
);
714 static void jb_destroy_adaptive(void *jb
)
716 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
718 jb_destroy(adaptivejb
);
722 static int jb_put_first_adaptive(void *jb
, struct ast_frame
*fin
, long now
)
724 return jb_put_adaptive(jb
, fin
, now
);
728 static int jb_put_adaptive(void *jb
, struct ast_frame
*fin
, long now
)
730 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
733 res
= jb_put(adaptivejb
, fin
, JB_TYPE_VOICE
, fin
->len
, fin
->ts
, now
);
735 return adaptive_to_abstract_code
[res
];
739 static int jb_get_adaptive(void *jb
, struct ast_frame
**fout
, long now
, long interpl
)
741 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
745 res
= jb_get(adaptivejb
, &frame
, now
, interpl
);
748 return adaptive_to_abstract_code
[res
];
752 static long jb_next_adaptive(void *jb
)
754 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
756 return jb_next(adaptivejb
);
760 static int jb_remove_adaptive(void *jb
, struct ast_frame
**fout
)
762 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
766 res
= jb_getall(adaptivejb
, &frame
);
769 return adaptive_to_abstract_code
[res
];
773 static void jb_force_resynch_adaptive(void *jb
)