|
|
|
@ -4,6 +4,7 @@ use strict; |
|
|
|
use warnings; |
|
|
|
use Time::HiRes qw(time); |
|
|
|
use Math::BigInt; |
|
|
|
use Math::BigFloat; |
|
|
|
|
|
|
|
sub new { |
|
|
|
my ($class, $cb_obj) = @_; |
|
|
|
@ -20,6 +21,9 @@ sub new { |
|
|
|
$self->{timestamp} = Math::BigInt->new(int(rand(2**32))); |
|
|
|
$self->{seq} = rand(2**16); |
|
|
|
$self->{payload} = 100; |
|
|
|
$self->{packet_count} = 0; |
|
|
|
$self->{octet_count} = 0; |
|
|
|
$self->{other_ssrcs} = {}; |
|
|
|
|
|
|
|
return $self; |
|
|
|
} |
|
|
|
@ -41,6 +45,106 @@ sub timer { |
|
|
|
|
|
|
|
$self->{timestamp} += $self->{clockrate} / (1.0 / ($self->{ptime} / 1000)); # XXX might be fractional |
|
|
|
$self->{timestamp} > 0xffffffff and $self->{timestamp} -= Math::BigInt->new('0x100000000'); |
|
|
|
|
|
|
|
$self->{packet_count}++; |
|
|
|
$self->{octet_count} += length($payload); |
|
|
|
} |
|
|
|
|
|
|
|
sub input { |
|
|
|
my ($self, $packet) = @_; |
|
|
|
|
|
|
|
my $now = time(); |
|
|
|
|
|
|
|
my ($vpxcc, $pt, $seq, $ts, $ssrc, $payload) = unpack("CCnNN a*", $packet); |
|
|
|
$vpxcc == 0x80 or die; |
|
|
|
$pt == 0 or die; |
|
|
|
|
|
|
|
my $remote = ($self->{other_ssrcs}->{$ssrc} //= { |
|
|
|
ssrc => $ssrc, |
|
|
|
packets_received => 0, |
|
|
|
packets_lost => 0, |
|
|
|
octets_received => 0, |
|
|
|
roc => 0, |
|
|
|
seq => $seq, # highest seen |
|
|
|
jitter => 0, |
|
|
|
queue_seq => $seq, # next expected seq -- to detect lost packets |
|
|
|
queue => {}, |
|
|
|
lost_last => 0, # since last SR/RR |
|
|
|
received_last => 0, # since last SR/RR |
|
|
|
dupes => 0, |
|
|
|
}); |
|
|
|
|
|
|
|
$remote->{packets_received}++; |
|
|
|
$remote->{received_last}++; |
|
|
|
$remote->{octets_received} += length($payload); |
|
|
|
|
|
|
|
# normalize seq using roc |
|
|
|
my $extseq = ($remote->{roc} << 16) | $seq; |
|
|
|
my $diff = $extseq - $remote->{seq}; |
|
|
|
if ($diff < -0x8000) { |
|
|
|
$extseq += 0x10000; |
|
|
|
} |
|
|
|
elsif ($diff >= 0x8000) { |
|
|
|
$extseq -= 0x10000; |
|
|
|
} |
|
|
|
|
|
|
|
# update seq/roc if necessary -- highest seq seen |
|
|
|
if ($extseq > $remote->{seq}) { |
|
|
|
$remote->{seq} = $extseq; |
|
|
|
$remote->{roc} = $extseq >> 16; |
|
|
|
} |
|
|
|
|
|
|
|
# check dupes and packet loss |
|
|
|
if ($extseq == $remote->{queue_seq}) { |
|
|
|
# in sequence and expected |
|
|
|
$remote->{queue_seq}++; |
|
|
|
# see if we can pull packets out of the queue |
|
|
|
while (exists($remote->{queue}->{$remote->{queue_seq}})) { |
|
|
|
delete($remote->{queue}->{$remote->{queue_seq}}); |
|
|
|
$remote->{queue_seq}++; |
|
|
|
} |
|
|
|
} |
|
|
|
elsif ($extseq < $remote->{queue_seq}) { |
|
|
|
$remote->{dupes}++; |
|
|
|
} |
|
|
|
else { |
|
|
|
# ahead of sequence -- queue it up if not a dupe |
|
|
|
if (exists($remote->{queue}->{$extseq})) { |
|
|
|
$remote->{dupes}++; |
|
|
|
} |
|
|
|
else { |
|
|
|
$remote->{queue}->{$extseq} = $packet; |
|
|
|
# see if our "jitter buffer" is full and account for packet loss |
|
|
|
my @seqs = keys(%{$remote->{queue}}); |
|
|
|
if (@seqs >= 20) { |
|
|
|
@seqs = sort {$a <=> $b} (@seqs); |
|
|
|
# seek up to the lowest seq in buffer and count each missing |
|
|
|
# seq as a lost packet |
|
|
|
my $min = $seqs[0]; |
|
|
|
$remote->{lost_since} += $min - $remote->{queue_seq}; |
|
|
|
$remote->{packets_lost} += $min - $remote->{queue_seq}; |
|
|
|
# now unqueue what we have as much as we can |
|
|
|
$remote->{queue_seq} = $min; |
|
|
|
while (my $qseq = shift(@seqs)) { |
|
|
|
$qseq != $remote->{queue_seq} and last; |
|
|
|
delete($remote->{queue}->{$qseq}); |
|
|
|
$remote->{queue_seq}++; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
# calc jitter |
|
|
|
if ($remote->{last_ts} && $remote->{last_seq}) { |
|
|
|
my $lt = Math::BigFloat->new($remote->{last_ts}); |
|
|
|
$lt->bsub(Math::BigFloat->new($now)); |
|
|
|
$lt->bmul($self->{clockrate}); |
|
|
|
my $diff = $lt->bstr() - ($remote->{last_seq} - $extseq); |
|
|
|
$remote->{jitter} = $remote->{jitter} + (abs($diff) - $remote->{jitter}) / 16; |
|
|
|
} |
|
|
|
$remote->{last_ts} = $now; |
|
|
|
$remote->{last_seq} = $extseq; |
|
|
|
} |
|
|
|
|
|
|
|
1; |