http://cpansearch.perl.org/src/SULLR/Net-Inspect-0.303/tools/rtpxtract.pl
This files uses "$self->{$fh}" to identify file handles for writing. the problem is I need an infinite number to be available while I read RTP and extract any number of separate audio streams to be written to separate audio files
How is this variable assigned and how do I open multiple file handles for the streams as they are detected in the RTP?
My version of the code is attached below.
This code produces only two file handles for the first and second SSRC values.
#!/usr/bin/perl
use strict;
use warnings;
use Socket;
use Getopt::Long qw(:config posix_default bundling);
#use Net::Pcap qw(:functions);
use Net::Pcap;
use Net::Inspect::Debug qw(:DEFAULT %TRACE $DEBUG);
use Net::Inspect::L2::Pcap;
use Net::Inspect::L3::IP;
use Net::Inspect::L4::UDP;
######################################################################
+######
# Options
######################################################################
+######
my ($infile,$dev,$nopromisc,@trace,$outdir);
GetOptions(
'r=s' => \$infile,
'i=s' => \$dev,
'p' => \$nopromisc,
'h|help' => sub { usage() },
'd|debug' => \$DEBUG,
'T|trace=s' => sub { push @trace,split(m/,/,$_[1]) },
'D|dir=s' => \$outdir,
) or usage();
usage('only interface or file can be set') if $infile and $dev;
$infile ||= '/dev/stdin' if ! $dev;
my $pcapfilter = join(' ',@ARGV);
$TRACE{$_} = 1 for(@trace);
die "cannot write to $outdir: $!" if $outdir and ! -w $outdir || ! -d
+_;
sub usage {
print STDERR "ERROR: @_\n" if @_;
print STDERR <<USAGE;
reads data from pcap file or device and extracts rtp streams.
Depending on the used codec you might use to convert data afterwards.
For G711a:
sox -c1 -r8000 -t al in.rtp out.wav
Usage: $0 [options] [pcap-filter]
Options:
-h|--help this help
-r file.pcap read pcap from file
-i dev read pcap from dev
-p do net set dev into promisc mode
-D dir extract data into dir, right now only for http re
+quests
and responses
-T trace trace messages are enabled in the modules, option
+ can
be given multiple times, trace is last part of mo
+dule name,
e.g. tcp, rawip
To enable all specify '*'
-d|--debug various debug messages are shown
USAGE
exit(2);
}
# open pcap
######################################################################
+######
my $err;
print "Open PCAP File: $infile\n";
my $pcap = $infile ? pcap_open_offline($infile,\$err) : pcap_open_live
+($dev,2**16,!$nopromisc,0,\$err);
$pcap or die $err;
if ( $pcapfilter ) {
print "Apply PCAP Filter: $pcapfilter\n";
pcap_compile($pcap, \(my $compiled), $pcapfilter,0,0xffffffff) ==
+0
or die "bad filter '$pcapfilter'";
pcap_setfilter($pcap,$compiled) == 0 or die;
}
# parse hierarchy
######################################################################
+######
my $udp = Net::Inspect::L4::UDP->new(XTract->new);
my $raw = Net::Inspect::L3::IP->new($udp);
my $pc = Net::Inspect::L2::Pcap->new($pcap,$raw);
# Mainloop
######################################################################
+######
my $time;
print "Begin Main Loop\n";
pcap_loop($pcap,-1,sub {
my (undef,$hdr,$data) = @_;
if ( ! $time || $hdr->{tv_sec}-$time>10 ) {
$udp->expire($time = $hdr->{tv_sec});
}
return $pc->pktin($data,$hdr);
},undef);
package XTract;
use base 'Net::Inspect::Connection';
use Net::Inspect::Debug;
use Data::Dumper;
my %rtp;
sub pktin {
my ($self,$data,$meta) = @_;
my $m;
# are these expected RTP data?
print "Check for expected data\n";
my $s = XTract::RTPStream->new($meta,$m);
$s->pktin(0,$data,$meta->{time});
return $s;
# no connection for packets
return;
}
package XTract::RTPStream;
use base 'Net::Inspect::Connection';
use Net::Inspect::Debug;
use fields qw(meta fh0 fh1 fh2 fh3);
use Data::Dumper;
sub new {
my ($class,$meta) = @_;
#print Dumper(@_);
return bless { meta => $meta }, $class;
}
sub pktin {
my ($self,$dir,$data,$time) = @_;
#print Dumper(@_);
$self->{expire} = $time + 30; # short expiration
#print Dumper($self);
# extract payload from RTP data
my ($vpxcc,$mpt,$seq,$tstamp,$ssrc) = unpack( 'CCnNN',substr( $dat
+a,0,12,'' ));
print "Dir: $dir\n";
my $fh = "fh$dir";
print "fh: $fh\n";
if ( ! $self->{$fh} ) {
my $fname = sprintf "$outdir/%x-%s.%d-%s.%d-%08x.rtp", @{$self
+->{meta}}{qw(time saddr sport daddr dport)},$ssrc;
open( $self->{$fh},'>',$fname) or die $!;
}
my $version = ($vpxcc & 0xc0) >> 6;
#if ( $version != 2 ) {
# debug("RTP version $version");
# return
#}
print sprintf("RTP Version %s, VPXCC: %s, MPT: %s, SEQ: %s, TS: %s
+, SSRC: %08x\n",$version,$vpxcc,$mpt,$seq,$tstamp,$ssrc);
# skip csrc headers
my $cc = $vpxcc & 0x0f;
substr( $data,0,4*$cc,'' ) if $cc;
# skip extension header
my $xh = $vpxcc & 0x10 ? (unpack( 'nn', substr( $data,0,4,'' )))[1
+] : 0;
substr( $data,0,4*$xh,'' ) if $xh;
# ignore padding
my $padding = $vpxcc & 0x20 ? unpack( 'C', substr($data,-1,1)) : 0
+;
my $payload = $padding ? substr( $data,0,length($data)-$padding ):
+ $data;
# XXX if data are lost filling might be useful
# XXX no duplicate detection
sleep 1;
syswrite($self->{$fh},$payload);
return;
}
-
Are you posting in the right place? Check out Where do I post X? to know for sure.
-
Posts may use any of the Perl Monks Approved HTML tags. Currently these include the following:
<code> <a> <b> <big>
<blockquote> <br /> <dd>
<dl> <dt> <em> <font>
<h1> <h2> <h3> <h4>
<h5> <h6> <hr /> <i>
<li> <nbsp> <ol> <p>
<small> <strike> <strong>
<sub> <sup> <table>
<td> <th> <tr> <tt>
<u> <ul>
-
Snippets of code should be wrapped in
<code> tags not
<pre> tags. In fact, <pre>
tags should generally be avoided. If they must
be used, extreme care should be
taken to ensure that their contents do not
have long lines (<70 chars), in order to prevent
horizontal scrolling (and possible janitor
intervention).
-
Want more info? How to link
or How to display code and escape characters
are good places to start.