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 (!f
->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
, f
->has_timing_info
, f
->len
, f
->ts
, f
->src
);
327 if (f
->mallocd
& AST_MALLOCD_HDR
)
330 frr
= ast_frisolate(f
);
333 ast_log(LOG_ERROR
, "Failed to isolate frame for the jitterbuffer on channel '%s'\n", chan
->name
);
337 if (!ast_test_flag(jb
, JB_CREATED
)) {
338 if (create_jb(chan
, frr
)) {
340 /* Disable the jitterbuffer */
341 ast_clear_flag(jb
, JB_USE
);
345 ast_set_flag(jb
, JB_CREATED
);
348 now
= get_now(jb
, NULL
);
349 if (jbimpl
->put(jbobj
, frr
, now
) != JB_IMPL_OK
) {
350 jb_framelog("JB_PUT {now=%ld}: Dropped frame with ts=%ld and len=%ld\n", now
, frr
->ts
, frr
->len
);
353 /* TODO: Check this fix - should return 0 here, because the dropped frame shouldn't
354 be delivered at all */
358 jb
->next
= jbimpl
->next(jbobj
);
360 jb_framelog("JB_PUT {now=%ld}: Queued frame with ts=%ld and len=%ld\n", now
, frr
->ts
, frr
->len
);
367 void ast_jb_get_and_deliver(struct ast_channel
*c0
, struct ast_channel
*c1
)
369 struct ast_jb
*jb0
= &c0
->jb
;
370 struct ast_jb
*jb1
= &c1
->jb
;
371 int c0_use_jb
= ast_test_flag(jb0
, JB_USE
);
372 int c0_jb_is_created
= ast_test_flag(jb0
, JB_CREATED
);
373 int c1_use_jb
= ast_test_flag(jb1
, JB_USE
);
374 int c1_jb_is_created
= ast_test_flag(jb1
, JB_CREATED
);
376 if (c0_use_jb
&& c0_jb_is_created
)
377 jb_get_and_deliver(c0
);
379 if (c1_use_jb
&& c1_jb_is_created
)
380 jb_get_and_deliver(c1
);
384 static void jb_get_and_deliver(struct ast_channel
*chan
)
386 struct ast_jb
*jb
= &chan
->jb
;
387 struct ast_jb_impl
*jbimpl
= jb
->impl
;
388 void *jbobj
= jb
->jbobj
;
389 struct ast_frame
*f
, finterp
;
391 int interpolation_len
, res
;
393 now
= get_now(jb
, NULL
);
394 jb
->next
= jbimpl
->next(jbobj
);
395 if (now
< jb
->next
) {
396 jb_framelog("\tJB_GET {now=%ld}: now < next=%ld\n", now
, jb
->next
);
400 while (now
>= jb
->next
) {
401 interpolation_len
= ast_codec_interp_len(jb
->last_format
);
403 res
= jbimpl
->get(jbobj
, &f
, now
, interpolation_len
);
407 /* deliver the frame */
410 jb_framelog("\tJB_GET {now=%ld}: %s frame with ts=%ld and len=%ld\n",
411 now
, jb_get_actions
[res
], f
->ts
, f
->len
);
412 jb
->last_format
= f
->subclass
;
416 /* interpolate a frame */
418 f
->frametype
= AST_FRAME_VOICE
;
419 f
->subclass
= jb
->last_format
;
421 f
->samples
= interpolation_len
* 8;
423 f
->src
= "JB interpolation";
425 f
->delivery
= ast_tvadd(jb
->timebase
, ast_samp2tv(jb
->next
, 1000));
426 f
->offset
= AST_FRIENDLY_OFFSET
;
427 /* deliver the interpolated frame */
429 jb_framelog("\tJB_GET {now=%ld}: Interpolated frame with len=%d\n", now
, interpolation_len
);
431 case JB_IMPL_NOFRAME
:
433 "JB_IMPL_NOFRAME is retuned from the %s jb when now=%ld >= next=%ld, jbnext=%ld!\n",
434 jbimpl
->name
, now
, jb
->next
, jbimpl
->next(jbobj
));
435 jb_framelog("\tJB_GET {now=%ld}: No frame for now!?\n", now
);
438 ast_log(LOG_ERROR
, "This should never happen!\n");
443 jb
->next
= jbimpl
->next(jbobj
);
448 static int create_jb(struct ast_channel
*chan
, struct ast_frame
*frr
)
450 struct ast_jb
*jb
= &chan
->jb
;
451 struct ast_jb_conf
*jbconf
= &jb
->conf
;
452 struct ast_jb_impl
*jbimpl
= jb
->impl
;
454 struct ast_channel
*bridged
;
456 char logfile_pathname
[20 + AST_JB_IMPL_NAME_SIZE
+ 2*AST_CHANNEL_NAME
+ 1];
457 char name1
[AST_CHANNEL_NAME
], name2
[AST_CHANNEL_NAME
], *tmp
;
460 jbobj
= jb
->jbobj
= jbimpl
->create(jbconf
, jbconf
->resync_threshold
);
462 ast_log(LOG_WARNING
, "Failed to create jitterbuffer on channel '%s'\n", chan
->name
);
466 now
= get_now(jb
, NULL
);
467 res
= jbimpl
->put_first(jbobj
, frr
, now
);
469 /* The result of putting the first frame should not differ from OK. However, its possible
470 some implementations (i.e. adaptive's when resynch_threshold is specified) to drop it. */
471 if (res
!= JB_IMPL_OK
) {
472 ast_log(LOG_WARNING
, "Failed to put first frame in the jitterbuffer on channel '%s'\n", chan
->name
);
474 jbimpl->destroy(jbobj);
480 jb
->next
= jbimpl
->next(jbobj
);
482 /* Init last format for a first time. */
483 jb
->last_format
= frr
->subclass
;
485 /* Create a frame log file */
486 if (ast_test_flag(jbconf
, AST_JB_LOG
)) {
487 snprintf(name2
, sizeof(name2
), "%s", chan
->name
);
488 tmp
= strchr(name2
, '/');
492 bridged
= ast_bridged_channel(chan
);
494 /* We should always have bridged chan if a jitterbuffer is in use */
497 snprintf(name1
, sizeof(name1
), "%s", bridged
->name
);
498 tmp
= strchr(name1
, '/');
502 snprintf(logfile_pathname
, sizeof(logfile_pathname
),
503 "/tmp/ast_%s_jb_%s--%s.log", jbimpl
->name
, name1
, name2
);
504 jb
->logfile
= fopen(logfile_pathname
, "w+b");
507 ast_log(LOG_WARNING
, "Failed to create frame log file with pathname '%s'\n", logfile_pathname
);
509 if (res
== JB_IMPL_OK
)
510 jb_framelog("JB_PUT_FIRST {now=%ld}: Queued frame with ts=%ld and len=%ld\n",
511 now
, frr
->ts
, frr
->len
);
513 jb_framelog("JB_PUT_FIRST {now=%ld}: Dropped frame with ts=%ld and len=%ld\n",
514 now
, frr
->ts
, frr
->len
);
517 if (option_verbose
> 2)
518 ast_verbose(VERBOSE_PREFIX_3
"%s jitterbuffer created on channel %s\n", jbimpl
->name
, chan
->name
);
520 /* Free the frame if it has not been queued in the jb */
521 if (res
!= JB_IMPL_OK
)
528 void ast_jb_destroy(struct ast_channel
*chan
)
530 struct ast_jb
*jb
= &chan
->jb
;
531 struct ast_jb_impl
*jbimpl
= jb
->impl
;
532 void *jbobj
= jb
->jbobj
;
540 if (ast_test_flag(jb
, JB_CREATED
)) {
541 /* Remove and free all frames still queued in jb */
542 while (jbimpl
->remove(jbobj
, &f
) == JB_IMPL_OK
) {
546 jbimpl
->destroy(jbobj
);
549 ast_clear_flag(jb
, JB_CREATED
);
551 if (option_verbose
> 2)
552 ast_verbose(VERBOSE_PREFIX_3
"%s jitterbuffer destroyed on channel %s\n", jbimpl
->name
, chan
->name
);
557 static long get_now(struct ast_jb
*jb
, struct timeval
*tv
)
563 gettimeofday(tv
, NULL
);
566 return ast_tvdiff_ms(*tv
, jb
->timebase
);
570 int ast_jb_read_conf(struct ast_jb_conf
*conf
, char *varname
, char *value
)
572 int prefixlen
= sizeof(AST_JB_CONF_PREFIX
) - 1;
576 if (strncasecmp(AST_JB_CONF_PREFIX
, varname
, prefixlen
))
579 name
= varname
+ prefixlen
;
581 if (!strcasecmp(name
, AST_JB_CONF_ENABLE
)) {
582 ast_set2_flag(conf
, ast_true(value
), AST_JB_ENABLED
);
583 } else if (!strcasecmp(name
, AST_JB_CONF_FORCE
)) {
584 ast_set2_flag(conf
, ast_true(value
), AST_JB_FORCED
);
585 } else if (!strcasecmp(name
, AST_JB_CONF_MAX_SIZE
)) {
586 if ((tmp
= atoi(value
)) > 0)
587 conf
->max_size
= tmp
;
588 } else if (!strcasecmp(name
, AST_JB_CONF_RESYNCH_THRESHOLD
)) {
589 if ((tmp
= atoi(value
)) > 0)
590 conf
->resync_threshold
= tmp
;
591 } else if (!strcasecmp(name
, AST_JB_CONF_IMPL
)) {
592 if (!ast_strlen_zero(value
))
593 snprintf(conf
->impl
, sizeof(conf
->impl
), "%s", value
);
594 } else if (!strcasecmp(name
, AST_JB_CONF_LOG
)) {
595 ast_set2_flag(conf
, ast_true(value
), AST_JB_LOG
);
604 void ast_jb_configure(struct ast_channel
*chan
, const struct ast_jb_conf
*conf
)
606 memcpy(&chan
->jb
.conf
, conf
, sizeof(*conf
));
610 void ast_jb_get_config(const struct ast_channel
*chan
, struct ast_jb_conf
*conf
)
612 memcpy(conf
, &chan
->jb
.conf
, sizeof(*conf
));
616 /* Implementation functions */
620 static void * jb_create_fixed(struct ast_jb_conf
*general_config
, long resynch_threshold
)
622 struct fixed_jb_conf conf
;
624 conf
.jbsize
= general_config
->max_size
;
625 conf
.resync_threshold
= resynch_threshold
;
627 return fixed_jb_new(&conf
);
631 static void jb_destroy_fixed(void *jb
)
633 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
636 fixed_jb_destroy(fixedjb
);
640 static int jb_put_first_fixed(void *jb
, struct ast_frame
*fin
, long now
)
642 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
645 res
= fixed_jb_put_first(fixedjb
, fin
, fin
->len
, fin
->ts
, now
);
647 return fixed_to_abstract_code
[res
];
651 static int jb_put_fixed(void *jb
, struct ast_frame
*fin
, long now
)
653 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
656 res
= fixed_jb_put(fixedjb
, fin
, fin
->len
, fin
->ts
, now
);
658 return fixed_to_abstract_code
[res
];
662 static int jb_get_fixed(void *jb
, struct ast_frame
**fout
, long now
, long interpl
)
664 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
665 struct fixed_jb_frame frame
;
668 res
= fixed_jb_get(fixedjb
, &frame
, now
, interpl
);
671 return fixed_to_abstract_code
[res
];
675 static long jb_next_fixed(void *jb
)
677 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
679 return fixed_jb_next(fixedjb
);
683 static int jb_remove_fixed(void *jb
, struct ast_frame
**fout
)
685 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
686 struct fixed_jb_frame frame
;
689 res
= fixed_jb_remove(fixedjb
, &frame
);
692 return fixed_to_abstract_code
[res
];
696 static void jb_force_resynch_fixed(void *jb
)
698 struct fixed_jb
*fixedjb
= (struct fixed_jb
*) jb
;
700 fixed_jb_set_force_resynch(fixedjb
);
706 static void *jb_create_adaptive(struct ast_jb_conf
*general_config
, long resynch_threshold
)
709 jitterbuf
*adaptivejb
;
711 adaptivejb
= jb_new();
713 jbconf
.max_jitterbuf
= general_config
->max_size
;
714 jbconf
.resync_threshold
= general_config
->resync_threshold
;
715 jbconf
.max_contig_interp
= 10;
716 jb_setconf(adaptivejb
, &jbconf
);
723 static void jb_destroy_adaptive(void *jb
)
725 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
727 jb_destroy(adaptivejb
);
731 static int jb_put_first_adaptive(void *jb
, struct ast_frame
*fin
, long now
)
733 return jb_put_adaptive(jb
, fin
, now
);
737 static int jb_put_adaptive(void *jb
, struct ast_frame
*fin
, long now
)
739 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
742 res
= jb_put(adaptivejb
, fin
, JB_TYPE_VOICE
, fin
->len
, fin
->ts
, now
);
744 return adaptive_to_abstract_code
[res
];
748 static int jb_get_adaptive(void *jb
, struct ast_frame
**fout
, long now
, long interpl
)
750 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
754 res
= jb_get(adaptivejb
, &frame
, now
, interpl
);
757 return adaptive_to_abstract_code
[res
];
761 static long jb_next_adaptive(void *jb
)
763 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
765 return jb_next(adaptivejb
);
769 static int jb_remove_adaptive(void *jb
, struct ast_frame
**fout
)
771 jitterbuf
*adaptivejb
= (jitterbuf
*) jb
;
775 res
= jb_getall(adaptivejb
, &frame
);
778 return adaptive_to_abstract_code
[res
];
782 static void jb_force_resynch_adaptive(void *jb
)