From 50bc73cfcb0aa8f1e558ba1094a9d176a9d73efd Mon Sep 17 00:00:00 2001 From: Richard Fuchs Date: Fri, 26 Feb 2016 15:01:23 -0500 Subject: [PATCH] support sending of rtp Change-Id: If832a763c021735357217b69f20891b547a9f6ef --- perl/RTP.pm | 41 +++++++++++++++++++++++++++++++++++++++++ perl/Rtpengine.pm | 2 +- perl/Rtpengine/Test.pm | 36 +++++++++++++++++++++++++++++++----- perl/SDP.pm | 19 +++++++++++++++++-- utils/test-basic.pl | 6 +++++- 5 files changed, 95 insertions(+), 9 deletions(-) diff --git a/perl/RTP.pm b/perl/RTP.pm index 5a371ca91..4c4ab7cb2 100644 --- a/perl/RTP.pm +++ b/perl/RTP.pm @@ -2,5 +2,46 @@ package RTP; use strict; use warnings; +use Time::HiRes qw(time); +use Math::BigInt; + +sub new { + my ($class, $local_socket, $dest) = @_; + + my $self = {}; + bless $self, $class; + + $self->{local_socket} = $local_socket; + $self->{destination} = $dest; + + $self->{ssrc} = int(rand(2**32)); + $self->{next_send} = time(); + $self->{ptime} = 20; + $self->{clockrate} = 8000; + $self->{timestamp} = Math::BigInt->new(int(rand(2**32))); + $self->{seq} = rand(2**16); + $self->{payload} = 100; + + return $self; +} + +sub timer { + my ($self) = @_; + + time() < $self->{next_send} and return; + + my $hdr = pack("CCnNN", 0x80, 0x00, $self->{seq}, $self->{timestamp}->bstr(), $self->{ssrc}); + my $payload = chr(rand(256)) x $self->{payload}; # XXX adapt to codec + + $self->{local_socket}->send($hdr . $payload, 0, $self->{destination}); + + $self->{seq}++; + $self->{seq} > 0xffff and $self->{seq} -= 0x10000; + + $self->{next_send} = $self->{next_send} + $self->{ptime} / 1000; + + $self->{timestamp} += $self->{clockrate} / (1.0 / ($self->{ptime} / 1000)); # XXX might be fractional + $self->{timestamp} > 0xffffffff and $self->{timestamp} -= Math::BigInt->new('0x100000000'); +} 1; diff --git a/perl/Rtpengine.pm b/perl/Rtpengine.pm index 205b1966f..8c9449e36 100644 --- a/perl/Rtpengine.pm +++ b/perl/Rtpengine.pm @@ -19,7 +19,7 @@ sub new { $self->{socket} = $addr; } else { - $self->{socket} = IO::Socket::IP->new(Type => &Socket::SOCK_DGRAM, Proto => 'udp', + $self->{socket} = IO::Socket::IP->new(Type => &SOCK_DGRAM, Proto => 'udp', PeerHost => $addr, PeerPort => $port); } diff --git a/perl/Rtpengine/Test.pm b/perl/Rtpengine/Test.pm index 6df033dc7..4d06c384b 100644 --- a/perl/Rtpengine/Test.pm +++ b/perl/Rtpengine/Test.pm @@ -51,7 +51,7 @@ sub new { $self->{timers} = []; $self->{clients} = []; - $self->{rtpe} = Rtpengine->new('localhost', 2223); + $self->{control} = Rtpengine->new('localhost', 2223); $self->{callid} = rand(); return $self; @@ -66,10 +66,14 @@ sub client { sub run { my ($self) = @_; - $self->{mux}->loop(); } +sub stop { + my ($self) = @_; + $self->{mux}->endloop(); +} + sub timer_once { my ($self, $delay, $sub) = @_; push(@{$self->{timers}}, { sub => $sub, when => time() + $delay }); @@ -140,7 +144,7 @@ sub _new { $self->{main_sockets} = $sockets[0]; # for m= and o= $self->{local_sdp} = SDP->new($self->{main_sockets}->[0]); # no global c= - $self->{component_peers} = []; # keep track of source addresses + $self->{component_peers} = []; # keep track of peer source addresses # default protocol my $proto = 'RTP/AVP'; @@ -193,7 +197,7 @@ sub offer { my $req = $self->_default_req_args('offer', 'from-tag' => $self->{tag}, sdp => $sdp_body, %args); - my $out = $self->{parent}->{rtpe}->req($req); + my $out = $self->{parent}->{control}->req($req); $other->_offered($out); } @@ -218,7 +222,7 @@ sub answer { my $req = $self->_default_req_args('answer', 'from-tag' => $other->{tag}, 'to-tag' => $self->{tag}, sdp => $sdp_body, %args); - my $out = $self->{parent}->{rtpe}->req($req); + my $out = $self->{parent}->{control}->req($req); $other->_answered($out); } @@ -234,6 +238,14 @@ sub _answered { $self->{ice} and $self->{ice}->decode($self->{remote_media}->decode_ice()); } +sub delete { + my ($self, %args) = @_; + + my $req = $self->_default_req_args('delete', 'from-tag' => $self->{tag}, %args); + + my $out = $self->{parent}->{control}->req($req); +} + sub _input { my ($self, $fh, $input, $peer) = @_; @@ -242,11 +254,17 @@ sub _input { $self->{dtls} and $self->{dtls}->input($fh, $input, $peer); $self->{ice} and $self->{ice}->input($fh, $input, $peer); + + $$input eq '' and return; + + # must be RTP input + $$input = ''; } sub _timer { my ($self) = @_; $self->{ice} and $self->{ice}->timer(); + $self->{rtp} and $self->{rtp}->timer(); } sub _peer_addr_check { @@ -255,4 +273,12 @@ sub _peer_addr_check { $dest_list->[$idx] = $peer; } } + +sub start_rtp { + my ($self) = @_; + $self->{rtp} and die; + my $dest = $self->{remote_media}->endpoint(); + $self->{rtp} = RTP->new($self->{rtp_sockets}->[0], $dest) or die; +} + 1; diff --git a/perl/SDP.pm b/perl/SDP.pm index c8f5ce6f1..35fdf8aaa 100644 --- a/perl/SDP.pm +++ b/perl/SDP.pm @@ -4,6 +4,8 @@ use strict; use warnings; use IO::Socket; use Time::HiRes qw(gettimeofday); +use Socket; +use Socket6; sub new { my ($class, $origin, $connection) = @_; @@ -106,10 +108,10 @@ sub encode_address { sub decode_address { my ($s) = @_; if ($s =~ /^IN IP4 (\d+\.\d+\.\d+\.\d+)$/s) { - return $1; + return { address => $1, family => &AF_INET }; } if ($s =~ /^IN IP6 ([0-9a-fA-F:]+)$/s) { - return $1; + return { address => $1, family => &AF_INET6 }; } die $s; } @@ -117,6 +119,10 @@ sub decode_address { package SDP::Media; +use Socket; +use Socket6; +use IO::Socket; + sub new { my ($class, $rtp, $rtcp, $protocol, $type) = @_; @@ -218,4 +224,13 @@ sub decode_ice { return $ret; } +sub endpoint { + my ($self) = @_; + my $conn = $self->connection(); + my $port = $self->{port}; + $conn->{family} == &AF_INET and return pack_sockaddr_in($port, inet_aton($conn->{address})); + $conn->{family} == &AF_INET6 and return pack_sockaddr_in6($port, inet_pton(&AF_INET6, $conn->{address})); + die; +} + 1; diff --git a/utils/test-basic.pl b/utils/test-basic.pl index 2ad89a5e6..43da53bb2 100644 --- a/utils/test-basic.pl +++ b/utils/test-basic.pl @@ -8,8 +8,12 @@ my $r = Rtpengine::Test->new(); my $a = $r->client(); my $b = $r->client(); -$r->timer_once(3, sub { $b->answer($a, ICE => 'remove') }); +$r->timer_once(3, sub { $b->answer($a, ICE => 'remove'); $a->start_rtp(); }); +$r->timer_once(10, sub { $r->stop(); }); $a->offer($b, ICE => 'remove'); +$b->start_rtp(); $r->run(); + +$a->delete();