#!/usr/bin/perl ########################################################################### # Invite other party, recv RTP data for some seconds or until other side # hangs up, then BYE # optional registration # # Most of the code is option parsing and usage, the Net::SIP related code # is at the end ########################################################################### use strict; use warnings; use IO::Socket::INET; use Getopt::Long qw(:config posix_default bundling); use Net::SIP; use Net::SIP::Util 'create_socket_to'; use Net::SIP::Debug; sub usage { print STDERR "ERROR: @_\n" if @_; print STDERR < \$debug, 'h|help' => sub { usage() }, 'P|proxy=s' => \$proxy, 'R|registrar=s' => \$registrar, 'O|outfile=s' => \$outfile, 'T|time=i' => \$hangup, 'L|leg=s' => \$local_leg, 'C|contact=s' => \$contact, 'username=s' =>\$username, 'password=s' =>\$password, 'route=s' => \@routes, ) || usage( "bad option" ); Net::SIP::Debug->level( $debug || 1 ) if defined $debug; my ($from,$to) = @ARGV; $to || usage( "no target" ); # register at proxy if proxy given and no registrar $registrar ||= $proxy; ################################################### # find local leg ################################################### my ($local_host,$local_port); if ( $local_leg ) { ($local_host,$local_port) = split( m/:/,$local_leg,2 ); } elsif ( ! $proxy ) { # if no proxy is given we need to find out # about the leg using the IP given from FROM ($local_host,$local_port) = $from =~m{\@([\w\-\.]+)(?::(\d+))?} or Vdie ("cannot find SIP domain in '$from'",3); } my $leg; if ( $local_host ) { my $addr = gethostbyname( $local_host ) || Vdie ("cannot get IP from SIP domain '$local_host'",3); $addr = inet_ntoa( $addr ); $leg = IO::Socket::INET->new( Proto => 'udp', LocalAddr => $addr, LocalPort => $local_port || 5060, ); # if no port given and port 5060 is already used try another one if ( !$leg && !$local_port ) { $leg = IO::Socket::INET->new( Proto => 'udp', LocalAddr => $addr, LocalPort => 0 ) || Vdie ("cannot create leg at $addr: $!",3); } $leg = Net::SIP::Leg->new( sock => $leg ); } ################################################### # SIP code starts here ################################################### # create necessary legs # If I have an only outgoing proxy I could skip this step because constructor # can make leg to outgoing_proxy itself my @legs; push @legs,$leg if $leg; foreach my $addr ( $proxy,$registrar) { $addr || next; if ( ! grep { $_->can_deliver_to( $addr ) } @legs ) { my $sock = create_socket_to($addr) || Vdie ("cannot create socket to $addr",3); push @legs, Net::SIP::Leg->new( sock => $sock ); } } # create user agent my $ua = Net::SIP::Simple->new( from => $from, outgoing_proxy => $proxy, route => \@routes, legs => \@legs, $contact ? ( contact => $contact ):(), $username ? ( auth => [ $username,$password ] ):(), ); # optional registration if ( $registrar && $registrar ne '-' ) { $ua->register( registrar => $registrar ); Vdie ("registration failed: ".$ua->error,1) if $ua->error } # invite peer my $peer_hangup; # did peer hang up? my $call = $ua->invite( $to, # echo back, use -1 instead of 0 for not echoing back init_media => $ua->rtp( 'recv_echo', $outfile,0 ), recv_bye => \$peer_hangup, ) || Vdie ("invite failed: ".$ua->error,2); Vdie ("invite failed(call): ".$call->error,2) if $call->error; # mainloop until other party hangs up or we hang up after # $hangup seconds my $stopvar; $ua->add_timer( $hangup, \$stopvar ) if $hangup; $ua->loop( \$stopvar,\$peer_hangup ); # timeout, I need to hang up if ( $stopvar ) { $stopvar = undef; $call->bye( cb_final => \$stopvar ); $ua->loop( \$stopvar ); } print ("Test Call OK: $to");