[Asterisk-Dev] iax2 bridge optimization screwing with timestamps

Andrew Kohlsmith akohlsmith-asterisk at benshaw.com
Fri Feb 11 20:59:00 MST 2005


Steve Kann and myself were working on the new packet loss concealing jitter 
buffer today and we ran across a (potential?) bug in the iax2 bridge 
optimization code.  I'm soliciting comments before I open a bug, since the 
bug marshals seem a little overzealous at times.  :-)

Normal frames are 20ms long and are sent out as such.  The timestamps on the 
outgoing iax2 packets are lock-step 20ms apart.  e.g.

0 20 40 60 80 100 120 140 160 180 200 220 240 260 280...

However if you have an asterisk box (all tested with todays CVS HEAD) in the 
middle and it's natively bridging you will see the actual timestamps inside 
the packets look like this periodically.  Sending DTMF seems to really 
aggravate it, although it does occur on its own:

0 20 40 60 80 81 82 83 84 180 200 220 221 260 280...

The same number of packets, and physically they're sent out at the right times 
(i.e. packet capture timestamps are showing ~20ms between UDP packets).  It 
is also curious to note that the original timestamps aren't "lost" -- they're 
just replaced with lastframets+1 on occassion, sometimes for runs as long as 
8 or 9 packets I've seen.

This seems to occur only when bridge optimization is used, in the 
calc_fakestamp() function:

/* FIXME? SLD would rather remove this and leave it to the end system to deal 
with */
if (fakets <= p2->lastsent)
  fakets = p2->lastsent + 1;
p2->lastsent = fakets;

Now this isn't intuitive to me -- What exactly is this code fragment trying to 
do, and why on earth would you send it as the lastpacket+1 when it's supposed 
to be 20ms (or more generally, a codec frametime) later?

I was more or less able to compensate for it with the following code near the 
end of schedule_delivery():

if(fr->af.frametype == AST_FRAME_VOICE) {
  type = JB_TYPE_VOICE;
  len = get_samples(&fr->af)/8;

  if(fr->ts < iaxs[fr->callno]->last_real_ts + ((len / 2)+1)) {
    iaxs[fr->callno]->num_fake_ts++;
    fr->ts = iaxs[fr->callno]->last_real_ts + (iaxs[fr->callno]->num_fake_ts * 
len) - 1;
  } else {
    iaxs[fr->callno]->last_real_ts = fr->ts;
    iaxs[fr->callno]->num_fake_ts = 0;
  }

What it does is rewrite the frame's timestamp if the frame comes in and it has 
a timestamp that is closer to the last timestamp than it is to what the next 
timestamp should be.  Obviously this is a band-aid solution and in 
practicality it works moderately well, but not perfectly.

If I undefine/comment out BRIDGE_OPTIMIZATION in chan_iax2.c the problem goes 
away completely and my received frame timestamps are not screwed with but I 
am not sure what this means in terms of chan_iax2 in general.

Can someone assist me in understanding this?  The new packet-loss-concealing 
jitter buffer completely barfs on this kind of timestamp stream, like because 
(as stevekstevek put it) it gets a packet with timestamp n, then gets a 
packet for timestamp n+1, only it's 20ms later and hterefore declares the 
packet late and drops it, as it's claiming to be for timestamp n+1 when the 
jitter buffer's working on timestamp n+20 now.

The old (current) jitter buffer doesn't seem to have an issue with this but, 
then again, the current system is timed from the received stream to begin 
with.

-A.



More information about the asterisk-dev mailing list