Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jbuf: adaptive playout time calculation #2757

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
d1a6cd4
jbuf: use clock based playout time
sreimers Oct 8, 2023
9901091
stream, jbuf: add tmr decode fallback
sreimers Oct 9, 2023
1ca7613
add tracing and experimental tmr optimizations
sreimers Oct 12, 2023
f71cab7
stream,rtprecv: add rtprecv_srate
sreimers Oct 26, 2023
5b31f67
rtprecv: add jbuf_set_id
sreimers Oct 26, 2023
bf13b78
rtprecv: add decode timer
sreimers Nov 6, 2023
9397462
refactor jbuf_next_play
sreimers Nov 7, 2023
63a689c
wip
sreimers Nov 12, 2023
e11396e
wip
sreimers Dec 18, 2023
7b6c74a
fix linter
sreimers Jan 7, 2024
65569e3
test/jbuf: fix test_jbuf
sreimers Jan 7, 2024
6d58db6
jbuf: fix adapative test
sreimers Jan 7, 2024
c12eb47
test/jbuf: fix EAGAIN race condition (slow test execution)
sreimers Jan 7, 2024
358a019
jbuf: refactoring testing
sreimers Jan 8, 2024
a04b764
test/jbuf: fix linting and unused warning
sreimers Jan 8, 2024
64a8a99
test/jbuf: add video tests
sreimers Jan 8, 2024
8b366cd
rtprecv: rename rtprecv_set_srate
sreimers Jan 9, 2024
78457f1
jbuf: fix mutex locking (srate, id and jbuf_next_play)
sreimers Jan 12, 2024
ba44d8e
jbuf: refactor jbuf_alloc min/max delay in ms
sreimers Jan 18, 2024
f1f4483
config: use audio_jitter_buffer_ms and video_jitter_buffer_ms
sreimers Jan 19, 2024
18106dc
rtprecv: use 10ms fallback timer
sreimers Feb 1, 2024
1b5cd49
refactoring
sreimers Feb 1, 2024
4de6794
fix linting
sreimers Feb 1, 2024
9867664
fix unused delay warning
sreimers Feb 1, 2024
04ceedf
fix ccheck
sreimers Feb 1, 2024
a59721f
cleanup and clock skew refactoring
sreimers Feb 3, 2024
ec9e2bc
add seq late packets
sreimers Feb 3, 2024
3b03960
fix INT_MIN
sreimers Feb 3, 2024
7204a58
adapt skew only in adaptive mode
sreimers Feb 3, 2024
2f08a0a
fix headers
sreimers Feb 3, 2024
30ab8b2
fix drift detection (check only within drift window)
sreimers Feb 4, 2024
62409d6
cleanup and reset playout on flush
sreimers Feb 4, 2024
7e61b69
jbuf: check invalid ts_arrive header
sreimers Feb 6, 2024
897c58b
fix ts_arrive test
sreimers Feb 6, 2024
ed68f41
rtprecv: fix video max size
sreimers Feb 19, 2024
aade365
jbuf: fix skew drift window handling
sreimers Feb 19, 2024
007b045
jbuf: extend jbuf_stat with late_lost and current delay
sreimers Mar 20, 2024
fe9abc0
refacto skew handling, remove unused n_underflow and re-add n_lost stats
sreimers Apr 4, 2024
f13c0db
include: refactor config_avt audio/video struct
sreimers Apr 5, 2024
f6fc7b7
rename next play handler
sreimers May 7, 2024
8a39ce5
config: decrease default max latency
sreimers May 16, 2024
bbfeec6
jbuf/stats: add current jitter delay and packets
sreimers Jun 27, 2024
b0159f8
jbuf: fix next_play_h usage and use specific errnos
sreimers Jul 11, 2024
7a389d9
jbuf: improve doxygen for jbuf_next_play
sreimers Jul 11, 2024
53f4537
test/jbuf: fix ENOENT empty list return check
sreimers Jul 11, 2024
dbc53e6
jbuf: fix wrong offset handling and improve jitter delay handling
sreimers Jul 11, 2024
d4dc011
jbuf: add TRACE lost
sreimers Aug 5, 2024
823a955
jbuf: add jbuf_stat generic NACKS
sreimers Oct 3, 2024
4958a28
rtprecv: fix err loop check
sreimers Oct 18, 2024
2ad3894
test/jbuf: fix clang analyze warning
sreimers Dec 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
jbuf: refactor jbuf_alloc min/max delay in ms
  • Loading branch information
sreimers committed Jan 8, 2025
commit ba44d8e332ae685ff330b843a93203fae67d4abf
9 changes: 6 additions & 3 deletions include/baresip.h
Original file line number Diff line number Diff line change
Expand Up @@ -428,11 +428,13 @@ struct config_avt {
bool rtcp_mux; /**< RTP/RTCP multiplexing */
struct {
enum jbuf_type jbtype; /**< Jitter buffer type */
struct range jbuf_del; /**< Delay, number of frames*/
struct range jbuf_del; /**< Max./Min. Delay [ms] */
uint32_t jbuf_sz; /**< Max. buffer [packets] */
} audio;
struct {
enum jbuf_type jbtype; /**< Jitter buffer type */
struct range jbuf_del; /**< Delay, number of frames*/
struct range jbuf_del; /**< Max./Min. Delay [ms] */
uint32_t jbuf_sz; /**< Max. buffer [packets] */
} video;
sreimers marked this conversation as resolved.
Show resolved Hide resolved
bool rtp_stats; /**< Enable RTP statistics */
uint32_t rtp_timeout; /**< RTP Timeout in seconds (0=off) */
Expand Down Expand Up @@ -1556,7 +1558,8 @@ struct jbuf_stat {
};


int jbuf_alloc(struct jbuf **jbp, uint32_t min, uint32_t max);
int jbuf_alloc(struct jbuf **jbp, uint32_t mind, uint32_t maxd,
uint32_t maxsz);
void jbuf_set_srate(struct jbuf *jb, uint32_t srate);
void jbuf_set_id(struct jbuf *jb, struct pl *id);
int jbuf_set_type(struct jbuf *jb, enum jbuf_type jbtype);
Expand Down
47 changes: 24 additions & 23 deletions src/config.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,13 @@ static struct config core_config = {
.rtcp_mux = false,
.audio = {
JBUF_FIXED,
{5, 10},
{100, 500},
50
},
.video = {
JBUF_FIXED,
{5, 50},
{100, 500},
250
},
.rtp_stats = false,
.rtp_timeout = 0,
Expand Down Expand Up @@ -504,31 +506,24 @@ int config_parse_conf(struct config *cfg, const struct conf *conf)
cfg->avt.rtp_bw.max *= 1000;
}

if (0 == conf_get(conf, "jitter_buffer_type", &jbtype)) {
cfg->avt.video.jbtype = conf_get_jbuf_type(&jbtype);
cfg->avt.audio.jbtype = conf_get_jbuf_type(&jbtype);
warning("config: jitter_buffer_* config is deprecated, use "
"audio_jitter_buffer_* and "
"video_jitter_buffer_* options\n");
}

(void)conf_get_range(conf, "jitter_buffer_delay",
&cfg->avt.video.jbuf_del);
(void)conf_get_range(conf, "jitter_buffer_delay",
&cfg->avt.audio.jbuf_del);

if (0 == conf_get(conf, "audio_jitter_buffer_type", &jbtype))
cfg->avt.audio.jbtype = conf_get_jbuf_type(&jbtype);

(void)conf_get_range(conf, "audio_jitter_buffer_delay",
(void)conf_get_range(conf, "audio_jitter_buffer_delay_ms",
sreimers marked this conversation as resolved.
Show resolved Hide resolved
&cfg->avt.audio.jbuf_del);

(void)conf_get_u32(conf, "audio_jitter_buffer_size",
&cfg->avt.audio.jbuf_sz);

if (0 == conf_get(conf, "video_jitter_buffer_type", &jbtype))
cfg->avt.video.jbtype = conf_get_jbuf_type(&jbtype);

(void)conf_get_range(conf, "video_jitter_buffer_delay",
(void)conf_get_range(conf, "video_jitter_buffer_delay_ms",
&cfg->avt.video.jbuf_del);

(void)conf_get_u32(conf, "audio_jitter_buffer_size",
&cfg->avt.video.jbuf_sz);

(void)conf_get_bool(conf, "rtp_stats", &cfg->avt.rtp_stats);
(void)conf_get_u32(conf, "rtp_timeout", &cfg->avt.rtp_timeout);

Expand Down Expand Up @@ -684,9 +679,11 @@ int config_print(struct re_printf *pf, const struct config *cfg)
"rtp_ports\t\t%H\n"
"rtp_bandwidth\t\t%H\n"
"audio_jitter_buffer_type\t%s\n"
"audio_jitter_buffer_delay\t%H\n"
"audio_jitter_buffer_delay_ms\t%H\n"
"audio_jitter_buffer_size\t%u\n"
"video_jitter_buffer_type\t%s\n"
"video_jitter_buffer_delay\t%H\n"
"video_jitter_buffer_delay_ms\t%H\n"
"video_jitter_buffer_size\t%u\n"
"rtp_stats\t\t%s\n"
"rtp_timeout\t\t%u # in seconds\n"
"avt_bundle\t\t%s\n"
Expand All @@ -703,8 +700,10 @@ int config_print(struct re_printf *pf, const struct config *cfg)
range_print, &cfg->avt.rtp_bw,
jbuf_type_str(cfg->avt.audio.jbtype),
range_print, &cfg->avt.audio.jbuf_del,
cfg->avt.audio.jbuf_sz,
jbuf_type_str(cfg->avt.video.jbtype),
range_print, &cfg->avt.video.jbuf_del,
cfg->avt.video.jbuf_sz,
cfg->avt.rtp_stats ? "yes" : "no",
cfg->avt.rtp_timeout,
cfg->avt.bundle ? "yes" : "no",
Expand Down Expand Up @@ -934,12 +933,14 @@ static int core_config_template(struct re_printf *pf, const struct config *cfg)
"#rtp_bandwidth\t\t512-1024 # [kbit/s]\n"
"audio_jitter_buffer_type\tfixed\t\t# off, fixed,"
" adaptive\n"
"audio_jitter_buffer_delay\t%u-%u\t\t"
"# (min. frames)-(max. packets)\n"
"audio_jitter_buffer_delay_ms\t%u-%u\t\t"
"# Min. - Max. [ms]\n"
"audio_jitter_buffer_size\t50\t\t# [packets]\n"
"video_jitter_buffer_type\tfixed\t\t# off, fixed,"
" adaptive\n"
"video_jitter_buffer_delay\t%u-%u\t\t"
"# (min. frames)-(max. packets)\n"
"video_jitter_buffer_delay_ms\t%u-%u\t\t"
"# Min. - Max. [ms]\n"
"video_jitter_buffer_size\t250\t\t# [packets]\n"
"rtp_stats\t\tno\n"
"#rtp_timeout\t\t60\n"
"#avt_bundle\t\tno\n"
Expand Down
39 changes: 23 additions & 16 deletions src/jbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,9 @@ struct jbuf {
struct list pooll; /**< List of free packets in pool */
struct list packetl; /**< List of buffered packets */
uint32_t n; /**< [# packets] Current # of packets in buffer */
uint32_t min; /**< Minimum time in [ms] to buffer */
uint32_t max; /**< [# frames] Maximum # of frames to buffer */
uint32_t wish; /**< [# frames] Wish size for adaptive mode */
uint32_t mind; /**< Minimum time in [ms] to delay */
uint32_t maxd; /**< Maximum time in [ms] to delay */
uint32_t maxsz; /**< [# packets] Maximum # of packets to buffer */
uint16_t seq_put; /**< Sequence number for last jbuf_put() */
uint16_t seq_get; /**< Sequence number of last played frame */
uint32_t ssrc; /**< Previous ssrc */
Expand Down Expand Up @@ -195,12 +195,13 @@ static void jbuf_destructor(void *data)
* Allocate a new jitter buffer
*
* @param jbp Pointer to returned jitter buffer
* @param min Minimum delay in [ms]
* @param max Maximum packets
* @param mind Minimum delay in [ms]
* @param maxd Maximum delay in [ms]
* @param maxsz Maximum size in [packets]
*
* @return 0 if success, otherwise errorcode
*/
int jbuf_alloc(struct jbuf **jbp, uint32_t min, uint32_t max)
int jbuf_alloc(struct jbuf **jbp, uint32_t mind, uint32_t maxd, uint32_t maxsz)
{
struct jbuf *jb;
uint32_t i;
Expand All @@ -223,9 +224,9 @@ int jbuf_alloc(struct jbuf **jbp, uint32_t min, uint32_t max)
list_init(&jb->packetl);

jb->jbtype = JBUF_FIXED;
jb->min = min;
jb->max = max;
jb->wish = min;
jb->mind = mind;
jb->maxd = maxd;
jb->maxsz = maxsz;
jb->next_play_fn = next_play;

DEBUG_INFO("alloc: delay=%u-%u packets\n", min, max);
Expand All @@ -238,7 +239,7 @@ int jbuf_alloc(struct jbuf **jbp, uint32_t min, uint32_t max)
mem_destructor(jb, jbuf_destructor);

/* Allocate all packets now */
for (i = 0; i < jb->max; i++) {
for (i = 0; i < jb->maxsz; i++) {
struct packet *f = mem_zalloc(sizeof(*f), NULL);
if (!f) {
err = ENOMEM;
Expand Down Expand Up @@ -437,7 +438,7 @@ static inline uint32_t offset(struct packet *p)

static uint32_t calc_playout_time(struct jbuf *jb, struct packet *p)
{
uint32_t base_offset = 0;
uint32_t jitter_offset = 0;
uint32_t play_time_base;

/* Fragmented frames (like video) have equal playout_time.
Expand Down Expand Up @@ -466,18 +467,24 @@ static uint32_t calc_playout_time(struct jbuf *jb, struct packet *p)
(void)adjust_due_to_skew(jb, p);

/* Add Jitter compensation */
base_offset += adjust_due_to_jitter(jb, p);
jitter_offset += adjust_due_to_jitter(jb, p);
}

/* Check min/max latency requirements */
base_offset += (jb->p.srate / 1000) * jb->min;
uint32_t min_lat = (jb->p.srate / 1000) * jb->mind;
uint32_t max_lat = (jb->p.srate / 1000) * jb->maxd;

if (jitter_offset < min_lat)
jitter_offset = min_lat;
else if (jitter_offset > max_lat)
jitter_offset = max_lat;

RE_TRACE_ID_INSTANT_I("jbuf", "recv_delay",
delay_ms(jb->p.last_delay, jb->p.srate), jb->id);
RE_TRACE_ID_INSTANT_I("jbuf", "play_delay",
delay_ms(base_offset, jb->p.srate), jb->id);

return play_time_base + base_offset;
return play_time_base + jitter_offset;
}


Expand Down Expand Up @@ -904,8 +911,8 @@ int jbuf_debug(struct re_printf *pf, const struct jbuf *jb)

mtx_lock(jb->lock);
err |= mbuf_printf(mb, " running=%d", jb->running);
err |= mbuf_printf(mb, " min=%u cur=%u max=%u [packets]\n",
jb->min, jb->n, jb->max);
err |= mbuf_printf(mb, " min=%ums cur=%u max=%ums [packets]\n",
jb->mind, jb->n, jb->maxd);
err |= mbuf_printf(mb, " seq_put=%u\n", jb->seq_put);

#if JBUF_STAT
Expand Down
4 changes: 2 additions & 2 deletions src/rtprecv.c
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ int rtprecv_alloc(struct rtp_receiver **rxp,
cfg->audio.jbtype != JBUF_OFF && cfg->audio.jbuf_del.max) {

err = jbuf_alloc(&rx->jbuf, cfg->audio.jbuf_del.min,
cfg->audio.jbuf_del.max);
cfg->audio.jbuf_del.max, cfg->audio.jbuf_sz);
if (err)
goto out;

Expand All @@ -743,7 +743,7 @@ int rtprecv_alloc(struct rtp_receiver **rxp,
cfg->video.jbtype != JBUF_OFF && cfg->video.jbuf_del.max) {

err = jbuf_alloc(&rx->jbuf, cfg->video.jbuf_del.min,
cfg->video.jbuf_del.max);
cfg->video.jbuf_del.max, cfg->audio.jbuf_sz);
if (err)
goto out;

Expand Down
8 changes: 5 additions & 3 deletions test/jbuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ int test_jbuf(void)
void *mem = NULL;
int err;

err = jbuf_alloc(&jb, 0, 10);
err = jbuf_alloc(&jb, 0, 100, 10);
if (err)
return err;

Expand Down Expand Up @@ -190,10 +190,11 @@ int test_jbuf_adaptive(void)
struct jbuf *jb = NULL;
char *frv[4];
uint32_t min_lat = 100; /* [ms] */
uint32_t max_lat = 500; /* [ms] */
void *mem = NULL;
int err;

err = jbuf_alloc(&jb, min_lat, 10);
err = jbuf_alloc(&jb, min_lat, max_lat, 50);
TEST_ERR(err);
err = jbuf_set_type(jb, JBUF_ADAPTIVE);
TEST_ERR(err);
Expand Down Expand Up @@ -247,10 +248,11 @@ int test_jbuf_video(void)
struct jbuf *jb = NULL;
char *frv[4];
uint32_t min_lat = 100; /* [ms] */
uint32_t max_lat = 500; /* [ms] */
void *mem = NULL;
int err;

err = jbuf_alloc(&jb, min_lat, 10);
err = jbuf_alloc(&jb, min_lat, max_lat, 50);
TEST_ERR(err);
err = jbuf_set_type(jb, JBUF_ADAPTIVE);
TEST_ERR(err);
Expand Down