Skip to content
This repository has been archived by the owner on Feb 16, 2023. It is now read-only.

Commit

Permalink
aubuf: better support for different put/get ptime
Browse files Browse the repository at this point in the history
By default the ptime for writing frames to the aubuf is 20ms. If e.g. module
pulse_async is used the ptime for reading dynamically changes and lies around
5ms.

- Compute ptime for get/put separately, and consider channel number.
- Computed jitter was too low. Reset ts0 and tr0 only if a frame is missing.
- Support wish size values that are not a multiple of written frames, if read
  frames are smaller. This avoids underruns at the beginning of a stream.
- Remove the +1 byte for max_sz. This makes no sense and no difference.
  • Loading branch information
cspiel1 committed Jun 17, 2022
1 parent ec60419 commit 23b910b
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 51 deletions.
2 changes: 1 addition & 1 deletion docs/aubuf/ajb.plot
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
# Choose your preferred gnuplot terminal or use e.g. evince to view the
# ajb.eps!

#set terminal x11
#set terminal qt persist
set terminal postscript eps size 15,10 enhanced color
set output 'ajb.eps'
#set terminal png size 1280,480
Expand Down
8 changes: 4 additions & 4 deletions docs/aubuf/config
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
#audio_path /usr/local/share/baresip
audio_player pulse,
audio_source pulse,
audio_alert pulse,
audio_player pulse_async,
audio_source pulse_async,
audio_alert pulse_async,
audio_level no
audio_buffer 20-250
audio_buffer 30-250
audio_buffer_mode adaptive
audio_silence 0.0

Expand Down
6 changes: 3 additions & 3 deletions docs/aubuf/generate_plots.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ function init_jitter () {

function enable_jitter() {
echo "ENABLE JITTER ..."
sudo tc qdisc add dev ifb1 root netem delay 200ms 100ms
sudo tc qdisc add dev ifb1 root netem delay 0ms 150ms
}


Expand Down Expand Up @@ -47,11 +47,11 @@ i=1
for ptime in 20 10 5 15 30 40; do

sed -e "s/ptime=[0-9]*/ptime=$ptime/" -i accounts
for buf in $ptime $(( 2*ptime )) $(( 3*ptime )) $(( 4*ptime )) $(( 6*ptime )); do
for buf in $(( ptime + ptime/2 )) $(( ptime )) $(( 2*ptime )) $(( 4*ptime )) $(( 6*ptime )); do
echo "########### ptime $ptime buffer $buf ###############"

sed -e "s/audio_buffer\s*[0-9]*\-.*/audio_buffer $buf-250/" -i config
baresip -f . > /tmp/b.log 2>&1 &
baresip -v -f . > /tmp/b.log 2>&1 &
sleep 1
echo "/dial $target" | nc -N localhost 5555

Expand Down
46 changes: 27 additions & 19 deletions src/aubuf/ajb.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ struct ajb {
int32_t jitter; /**< Jitter in [us] */
mtx_t *lock;

uint64_t ts0; /**< previous timestamp */
uint64_t tr0; /**< previous time of arrival */
uint64_t ts; /**< previous timestamp */
uint64_t ts0; /**< reference timestamp */
uint64_t tr0; /**< reference time of arrival */
uint64_t tr00; /**< arrival of first packet */
#if DEBUG_LEVEL >= 6
struct {
Expand All @@ -51,7 +52,6 @@ struct ajb {

enum ajb_state as; /**< computed jitter buffer state */

uint32_t ptime; /**< Packet time [us] */
int32_t avbuftime; /**< average buffered time [us] */
bool started; /**< Started flag */
uint32_t bufmin; /**< Minimum buffer time [us] */
Expand Down Expand Up @@ -170,6 +170,7 @@ void ajb_reset(struct ajb *ajb)
return;

mtx_lock(ajb->lock);
ajb->ts = 0;
ajb->ts0 = 0;
ajb->tr0 = 0;

Expand All @@ -194,23 +195,23 @@ void ajb_calc(struct ajb *ajb, const struct auframe *af, size_t cur_sz)
int32_t d; /**< Time shift in [us] */
int32_t da; /**< Absolut time shift in [us] */
int32_t s; /**< EMA coefficient */
int64_t ts; /**< Time stamp */
uint64_t ts; /**< Time stamp */
uint64_t ds; /**< Time stamp duration */
uint32_t ptime; /**< Packet time [us] */
size_t sz;


if (!ajb || !af || !af->srate)
return;

mtx_lock(ajb->lock);
sz = aufmt_sample_size(af->fmt);
ts = (int64_t) af->timestamp;
ts = af->timestamp;
tr = tmr_jiffies_usec();
if (!ajb->ts0)
goto out;

d = (int32_t) ( ((int64_t) tr - (int64_t) ajb->tr0) -
(ts - (int64_t) ajb->ts0) );

ds = ts - ajb->ts0;
d = (int32_t) (int64_t) ( (tr - ajb->tr0) - ds );
da = abs(d);

buftime = (uint32_t) (cur_sz * 1000 /
Expand All @@ -230,9 +231,6 @@ void ajb_calc(struct ajb *ajb, const struct auframe *af, size_t cur_sz)
ajb->started = true;
}

if (!ajb->ptime)
goto out;

s = da > ajb->jitter ? JITTER_UP_SPEED : 1;

ajb->jitter += (da - ajb->jitter) * s / JITTER_EMA_COEFF;
Expand All @@ -242,10 +240,15 @@ void ajb_calc(struct ajb *ajb, const struct auframe *af, size_t cur_sz)
bufmin = (uint32_t) ajb->jitter * BUFTIME_LO / 100;
bufmax = (uint32_t) ajb->jitter * BUFTIME_HI / 100;

bufmin = MAX(bufmin, ajb->ptime * 2 / 3);
bufmax = MAX(bufmax, bufmin + 7 * ajb->ptime / 6);
ptime = (uint32_t) (af->sampc * AUDIO_TIMEBASE / (af->srate * af->ch));
bufmin = MAX(bufmin, ptime * 2 / 3);
bufmax = MAX(bufmax, bufmin + 7 * ptime / 6);
ajb->bufmin = bufmin;

/* reset time base if a frame is missing */
if (ts - ajb->ts > ptime)
ajb->ts0 = 0;

if ((uint32_t) ajb->avbuftime < bufmin)
ajb->as = AJB_LOW;
else if ((uint32_t) ajb->avbuftime > bufmax)
Expand All @@ -261,8 +264,11 @@ void ajb_calc(struct ajb *ajb, const struct auframe *af, size_t cur_sz)
plot_ajb(ajb, tr / 1000);
#endif
out:
ajb->ts0 = ts;
ajb->tr0 = tr;
ajb->ts = ts;
if (!ajb->ts0) {
ajb->ts0 = ts;
ajb->tr0 = tr;
}
mtx_unlock(ajb->lock);
}

Expand All @@ -273,6 +279,7 @@ void ajb_set_ts0(struct ajb *ajb, uint64_t timestamp)
return;

mtx_lock(ajb->lock);
ajb->ts = timestamp;
ajb->ts0 = timestamp;
ajb->tr0 = tmr_jiffies_usec();
mtx_unlock(ajb->lock);
Expand All @@ -282,6 +289,7 @@ void ajb_set_ts0(struct ajb *ajb, uint64_t timestamp)
enum ajb_state ajb_get(struct ajb *ajb, struct auframe *af)
{
enum ajb_state as = AJB_GOOD;
uint32_t ptime; /**< Packet time [us] */

if (!ajb || !af || !af->srate || !af->sampc)
return AJB_GOOD;
Expand All @@ -290,7 +298,7 @@ enum ajb_state ajb_get(struct ajb *ajb, struct auframe *af)
ajb->af = *af;

/* ptime in [us] */
ajb->ptime = (uint32_t) (af->sampc * 1000 * 1000 / af->srate);
ptime = (uint32_t) (af->sampc * AUDIO_TIMEBASE / (af->srate * af->ch));
if (!ajb->avbuftime)
goto out;

Expand All @@ -301,7 +309,7 @@ enum ajb_state ajb_get(struct ajb *ajb, struct auframe *af)
as = ajb->as;
if (as == AJB_HIGH) {
/* early adjustment of avbuftime */
ajb->avbuftime -= ajb->ptime;
ajb->avbuftime -= ptime;
ajb->as = AJB_GOOD;
#if DEBUG_LEVEL >= 6
ajb->plot.as = AJB_HIGH;
Expand All @@ -311,7 +319,7 @@ enum ajb_state ajb_get(struct ajb *ajb, struct auframe *af)
}
else if (as == AJB_LOW) {
/* early adjustment */
ajb->avbuftime += ajb->ptime;
ajb->avbuftime += ptime;
ajb->as = AJB_GOOD;
#if DEBUG_LEVEL >= 6
ajb->plot.as = AJB_LOW;
Expand Down
1 change: 1 addition & 0 deletions src/aubuf/ajb.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Copyright (C) 2022 Commend.com - c.spielberger@commend.com
*/

#define AUDIO_TIMEBASE 1000000U

enum ajb_state {
AJB_GOOD = 0,
Expand Down
61 changes: 37 additions & 24 deletions src/aubuf/aubuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@


#define AUBUF_DEBUG 0
#define AUDIO_TIMEBASE 1000000U


/** Locked audio-buffer with almost zero-copy */
Expand All @@ -23,7 +22,8 @@ struct aubuf {
size_t wish_sz;
size_t cur_sz;
size_t max_sz;
bool filling;
size_t fill_sz; /**< To fill size */
uint32_t pkt_sz; /**< Packet size */
bool started;
uint64_t ts;

Expand Down Expand Up @@ -130,8 +130,8 @@ int aubuf_alloc(struct aubuf **abp, size_t min_sz, size_t max_sz)
goto out;

ab->wish_sz = min_sz;
ab->max_sz = max_sz;
ab->filling = true;
ab->max_sz = max_sz;
ab->fill_sz = min_sz;

out:
if (err)
Expand Down Expand Up @@ -216,6 +216,7 @@ int aubuf_append_auframe(struct aubuf *ab, struct mbuf *mb,
{
struct frame *f;
size_t max_sz;
size_t sz;

if (!ab || !mb)
return EINVAL;
Expand All @@ -228,12 +229,17 @@ int aubuf_append_auframe(struct aubuf *ab, struct mbuf *mb,
if (af)
f->af = *af;

sz = mbuf_get_left(mb);

mtx_lock(ab->lock);
ab->pkt_sz = sz;
if (ab->fill_sz >= ab->pkt_sz)
ab->fill_sz -= ab->pkt_sz;

list_insert_sorted(&ab->afl, frame_less_equal, NULL, &f->le, f);
ab->cur_sz += mbuf_get_left(mb);
ab->cur_sz += sz;

max_sz = ab->started ? ab->max_sz : ab->wish_sz + 1;
max_sz = ab->started ? ab->max_sz : ab->wish_sz;
if (ab->max_sz && ab->cur_sz > max_sz) {
#if AUBUF_DEBUG
if (ab->started) {
Expand All @@ -244,16 +250,12 @@ int aubuf_append_auframe(struct aubuf *ab, struct mbuf *mb,
#endif
f = list_ledata(ab->afl.head);
if (f) {
ab->cur_sz -= mbuf_get_left(f->mb);
ab->cur_sz -= sz;
mem_deref(f);
}
}

if (ab->filling && ab->cur_sz >= ab->wish_sz)
ab->filling = false;

mtx_unlock(ab->lock);

return 0;
}

Expand Down Expand Up @@ -294,7 +296,7 @@ int aubuf_write_auframe(struct aubuf *ab, const struct auframe *af)

mtx_lock(ab->lock);
mem_deref(mb);
ajb = !ab->filling && ab->ajb;
ajb = !ab->fill_sz && ab->ajb;
mtx_unlock(ab->lock);

if (ajb)
Expand All @@ -320,6 +322,7 @@ void aubuf_read_auframe(struct aubuf *ab, struct auframe *af)
if (!ab || !af)
return;

sz = auframe_size(af);
if (!ab->ajb && ab->mode == AUBUF_ADAPTIVE)
ab->ajb = ajb_alloc(ab->silence);

Expand All @@ -333,27 +336,28 @@ void aubuf_read_auframe(struct aubuf *ab, struct auframe *af)
goto out;
}

sz = auframe_size(af);
if (ab->cur_sz < (ab->filling ? ab->wish_sz : sz)) {
if (ab->fill_sz || ab->cur_sz < sz) {
#if AUBUF_DEBUG
if (!ab->filling) {
if (!ab->fill_sz) {
++ab->stats.ur;
(void)re_printf("aubuf: %p underrun (cur=%zu)\n",
ab, ab->cur_sz);
(void)re_printf("aubuf: %p underrun "
"(cur=%zu, sz=%zu)\n",
ab, ab->cur_sz, sz);
fflush(stdout);
plot_underrun(ab->ajb);
}
#endif
if (!ab->filling)
if (!ab->fill_sz)
ajb_set_ts0(ab->ajb, 0);

filling = ab->filling;
ab->filling = true;
filling = ab->fill_sz > 0;
memset(af->sampv, 0, sz);
if (filling)
goto out;
else
ab->fill_sz = ab->wish_sz;
}

ab->started = true;
read_auframe(ab, af);
if (as == AJB_HIGH) {
#if AUBUF_DEBUG
Expand All @@ -364,6 +368,15 @@ void aubuf_read_auframe(struct aubuf *ab, struct auframe *af)
}

out:

if (ab->fill_sz && ab->fill_sz < ab->pkt_sz) {
if (ab->fill_sz >= sz)
ab->fill_sz -= sz;
else
ab->fill_sz = 0;
}

ab->started = true;
mtx_unlock(ab->lock);
}

Expand Down Expand Up @@ -426,7 +439,7 @@ void aubuf_flush(struct aubuf *ab)
mtx_lock(ab->lock);

list_flush(&ab->afl);
ab->filling = true;
ab->fill_sz = ab->wish_sz;
ab->cur_sz = 0;
ab->ts = 0;

Expand All @@ -451,8 +464,8 @@ int aubuf_debug(struct re_printf *pf, const struct aubuf *ab)
return 0;

mtx_lock(ab->lock);
err = re_hprintf(pf, "wish_sz=%zu cur_sz=%zu filling=%d",
ab->wish_sz, ab->cur_sz, ab->filling);
err = re_hprintf(pf, "wish_sz=%zu cur_sz=%zu fill_sz=%zu",
ab->wish_sz, ab->cur_sz, ab->fill_sz);

#if AUBUF_DEBUG
err |= re_hprintf(pf, " [overrun=%zu underrun=%zu]",
Expand Down

0 comments on commit 23b910b

Please sign in to comment.