[Asterisk-Dev] Re: [Iaxclient-devel] jitterbuffer

Jesse Kaijen jesse at kayen.nl
Wed Apr 13 09:34:39 MST 2005


Hi,

Basic definition for reference: "Jitter is a measure of the variability over 
time of the latency across a network. A very low amount of jitter is 
important for real-time applications using voice and video."

Jitter calculation is the standard deviation of the historical delay of 
packets during the conversation.
Because calculating std. dev. is very cpu intensive, especially when you 
have to predict which curve you're having (Gauss, Poisson, etc), the jitter 
may be approximated by taking the IQR (inter quartile range).

I am sending this to the asterisk-dev as well because the underlying 
implementation is currently also being worked into Asterisk (-head). 
Hopefully my notes will help all implementations evolve.

----- Original Message ----- 
From: "Steve Kann" <stevek at stevek.com>

> OK, I'm trying to understand what you're doing here.   Here's some 
> comments/questions..
>
> Jesse Kaijen wrote:
>
>> Hello,
>>
>> I did some modifications on the jitterbuffer. Please put it to the test, 
>> here is an sort overview of the changes:
>>
>> - history is kept in two buckets: bucket 1 keeps actual history and 
>> bucket 2 keeps a sorted list of bucket 1.
>>
>> - jitter is calculated as being the Inter Quartile Range of bucket 2. 
>> (more RFC-like then the jitter calc at the moment).*
>
> Being "more RFC-like" isn't really the goal of the jitterbuffer, though. 
> It might be a goal for stats, (for SIP at least), where we report jitter 
> in RTCP RR's the way the RTP RFC specifies.   Also, we're

I thought that IAX2 can make use of that too, within the PONG (as in 
iax_send_pong). Also the E-MOS uses the std.dev.

> less interested in measuring historical jitter in any meaningful way than 
> we are in predicting future delays.  But for the jitterbuffer, the 
> calculation's goal is really to predict future delays.
>
A prediction of future delays can be done in a meaningful way if the actual 
jitter is known.

> So, it seems what you're doing, is from your sorted history buffer, you're 
> throwing away the earliest 25% of delays, and the last 25% of delays, and 
> calling that "jitter", and then calling "min" the median delay.
>
> Later, you're setting the jitterbuffer target to  (jitter)*5/2 + min + 
> JB_TARGET_EXTRA;
>
> The only thing that's real important for the jitterbuffer is how you set 
> target.  So, let's compare the two:
>
> present implementation: jb->info.jitter + jb->info.min + JB_TARGET_EXTRA;
> =  max - min + min + EXTRA
> = max + extra
> = 96%ile + extra  (since we throw away 4% of max) *1
>
> This is designed to approximate the E-MOS calculation, by using a constant 
> EXTRA over the straight "loss-control" method.
>

Indeed the E-MOS calculation says take the
middle+ 2*std.dev. + extra =~ 96% + extra

you take 96% of the history, this is not equal to 96% of the E-MOS 
calculation.

where your extra = 40ms. (why 40ms??) Especially if that is in every *-box 
jitterbuffer. Sometimes there are 3 or 4 *-boxes in a path and the delay is 
increased by more then 40*3=120ms 40*4=160ms. Not needed delay... E-MOS 
states that with longer delay the audioperceptive will drop. So why add more 
potential unnessecary delay?

>
> your implementation:
>    jb->info.target = (jb->info.jitter)*5/2 + jb->info.min + 
> JB_TARGET_EXTRA;
> = (75%ile - 25%ile) * 5/2 + 50%ile + extra
>
>
> I'm not sure I understand the logic behind this..

target = jitter*5/2 + jb->info.min +  JB_TARGET_EXTRA;

= jitter*2 + middle + 1/2*jitter + extra
=~ std.dev*2 + middle * 1/2*std.dev + extra
= 96% + 1/2*std.dev + 0

the 1/2*std.dev. is my extra because I stated JB_TARGET_EXTRA ==0;
So the extra is taken growing with the jitterbuffer and the unneeded delay 
is kept low.

>
> One thing that I do notice, though is that you never take into account the 
> top 25% of delays at all;  That means, if delay is increasing, you may not 
> notice it for up to 25% of history size packets (i.e. for your 250-packet 
> history, that's 62.5 packets, or about 3 seconds.
>
first of all 62.5 * 20 = 1250ms
second the current jitterbuffersize has be played to the end-user entirely 
before packets will be dropped and the end-user notices.
third jitter normally doesn't increase explosive, but grows steadily (other 
than spikes ofcourse, see next).
fourth a jitterspike is rare and not predictable (spike is only one for 
explosive increase, see previous ;-))

> *1: doh, this makes me realize that throwing away 4% of min is pretty 
> meaningless in the current implementation, since it gets factored out of 
> target anyway?
>
>>
>> - jb->info.min (the minimum delay) is set as the middle of bucket 2
>>
>> - Out Of Order count is correct.
>
>
> Is that this chunk?

yes it is.

>
> static void queue_put(jitterbuf *jb, void *data, int type, long ms, long 
> ts)
> @@ -307,14 +208,6 @@
>        jb->frames = frame;
>        frame->next = frame;
>        frame->prev = frame;
> -    } else if(ts < jb->frames->ts) {
> -       frame->next = jb->frames;
> -       frame->prev = jb->frames->prev;
> -
> -       frame->next->prev = frame;
> -       frame->prev->next = frame;
> -
> -       jb->frames = frame;
>     } else {
>        p = jb->frames;
>
>
>>
>> - JB_HISTORY_SZ is set to 250. This is because a jitter calculation is 
>> best over 5 - 8 seconds. 250 is 5 seconds with 20ms frames and 7,5 
>> seconds with 30ms frames and will cover it. **
>
> I chose 500 based on the E-MOS paper.
>
ok, do you have the link for me? Can't find it in my history any more.

>>
>> - jb_info is only valid after half JB_HISTORY_SZ.
>>
>> -  jb->info.target = (jb->info.jitter)*5/2 + jb->info.min + 
>> JB_TARGET_EXTRA;
>> with JB_TARGET_EXTRA ==0;
>> In theory this would be sufficient to handle over 99% of the packets and 
>> still keeping the jitterbuffer small.
>
> see above -- I'd like to understand the derivation of this..
>
> In the larger context, it was my understanding that (one of?) your goals 
> is to use the jitterbuffer to detect congestion, and then change codecs or 
> something to try to avoid the congestion.
>
the jitterbuffer is only for creating the correct stats, a monitor in the 
application layer will handle codec changes, this because you may prefer fax 
detection and stuff like that. However, an application like that is only as 
good as its foundation, hence the work on the underlying jitterbuffer :)

> As I said before, the idea of congestion avoidance (and increasing call 
> quality by avoiding loss), is interesting, but I don't think that changing 
> codecs alone is really the best solution, since you have the constant 
> 12kb/s overhead for sending 50 packets per second.  However, if you do 
> figure out how to detect congestion well, there's several things you can 
> do:
>
> 1) change codecs.
> 2) Change codec settings for variable/adjustable bitrate codecs (i.e. 
> speex).
> 3) Change the packetization interval.  (going from 20ms frames to 40ms 
> frames saves you 6kb/s without touching the payload).

This can be done by the monitor as well and I certainly take it in account.

> 4) If you're doing video, you have a lot more bandwidth to reduce.
>
That's why I only look at voice. I don't know the requirements of video and 
I think that loss handling is totally different with video.

> P.S.  I've been experimenting with (4) and iaxclient:  I presently have a 
> version of "testcall", which captures video, compresses it, and can show 
> previews of raw or compressed video;  I'll probably be posting interim 
> work on this soon, but it would be something quite experimental.

We'll be looking forward to it.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: jitterbuf.h
Type: application/octet-stream
Size: 4818 bytes
Desc: not available
Url : http://lists.digium.com/pipermail/asterisk-dev/attachments/20050413/414c69b0/jitterbuf.obj
-------------- next part --------------
A non-text attachment was scrubbed...
Name: jitterbuf.c
Type: application/octet-stream
Size: 16815 bytes
Desc: not available
Url : http://lists.digium.com/pipermail/asterisk-dev/attachments/20050413/414c69b0/jitterbuf-0001.obj


More information about the asterisk-dev mailing list