mirror of
https://github.com/Telecominfraproject/wlan-lanforge-scripts.git
synced 2025-10-29 18:02:35 +00:00
l3_video: produces buffer fill traffic pattern
This commit is contained in:
213
l3_video_em.pl
213
l3_video_em.pl
@@ -20,7 +20,7 @@ use LANforge::Port;
|
||||
use LANforge::Utils;
|
||||
use Net::Telnet ();
|
||||
use Getopt::Long;
|
||||
|
||||
my $NA ='NA';
|
||||
our $resource = 1;
|
||||
our $quiet = "yes";
|
||||
our $endp_name = "";
|
||||
@@ -32,16 +32,16 @@ our $lfmgr_port = 4001;
|
||||
our $tx_style = "";
|
||||
our $cx_name = "";
|
||||
our $tx_side = "B";
|
||||
our $min_tx = undef;
|
||||
our $min_tx = 0;
|
||||
our $max_tx = -1;
|
||||
our $buf_size = -1;
|
||||
our $log_cli = "unset"; # do not set to 0, it turns into logfile "./0"
|
||||
our $stream_res = undef;
|
||||
our @frame_rates = ( 10, 12, 15, 24, 25, 29.97, 30, 50, 59.94, 60);
|
||||
our $frame_rates_desc = join(", ", @::frame_rates);
|
||||
our $frame_rate = 30;
|
||||
our $audio_rate = 32000; # 128k is used on Blueray DVDs
|
||||
our @audio_rates = 128000; # 128k
|
||||
our $stream_key = undef;
|
||||
#our @frame_rates = ( 10, 12, 15, 24, 25, 29.97, 30, 50, 59.94, 60);
|
||||
#our $frame_rates_desc = join(", ", @::frame_rates);
|
||||
#our $frame_rate = 30;
|
||||
#our $audio_rate = 32000; # 128k is used on Blueray DVDs
|
||||
#our @audio_rates = 128000; # 128k
|
||||
|
||||
# https://en.wikipedia.org/wiki/Standard-definition_television
|
||||
# https://www.adobe.com/devnet/adobe-media-server/articles/dynstream_live/popup.html
|
||||
@@ -160,21 +160,21 @@ our $resolution = "720p";
|
||||
my $list_streams = 0;
|
||||
|
||||
our $usage = "$0 # modulates a Layer 3 CX to emulate a video server
|
||||
--mgr {hostname | IP}
|
||||
--mgr_port {ip port}
|
||||
--tx_style { constant | bufferfill }
|
||||
--cx_name {name}
|
||||
--set_tx {A|B} # which side is emulating the server,
|
||||
# default $tx_side
|
||||
--min_tx {speed in bps}
|
||||
--max_tx {speed in bps|SAME}
|
||||
--buf_size {kilobytes} # fill a buffer at max_tx for this long
|
||||
--mgr {hostname | IP}
|
||||
--mgr_port {ip port}
|
||||
--tx_style { constant | bufferfill }
|
||||
--cx_name {name}
|
||||
--tx_side {A|B} # which side is emulating the server,
|
||||
# default $tx_side
|
||||
--max_tx {speed in bps [K|M|G]} # use this to fill buffer
|
||||
--min_tx {speed in bps [K|M|G]} # use when not filling buffer, default 0
|
||||
--buf_size {size[K|M|G]} # fill a buffer at max_tx for this long
|
||||
--stream_res {$avail_stream_desc}
|
||||
--list_streams # show stream bps table and exit
|
||||
# default $resolution
|
||||
--log_cli {0|1} # use this to record cli commands
|
||||
|
||||
# default $frame_rate
|
||||
--stream_res {$avail_stream_desc}
|
||||
--list_streams # show stream bps table and exit
|
||||
# default $resolution
|
||||
--log_cli {0|1}
|
||||
Example: $0 --cx_name bursty-udp --stream 720p --buf_size 8M --max_tx 40000000
|
||||
";
|
||||
# --frame_rate {$frame_rates_desc} # not really applicable
|
||||
# the stream resolution (kbps) is really a better burn rate
|
||||
@@ -187,18 +187,18 @@ if (@ARGV < 2) {
|
||||
}
|
||||
GetOptions
|
||||
(
|
||||
'help|h' => \$show_help,
|
||||
'mgr|m=s' => \$::lfmgr_host,
|
||||
'mgr_port|p=i' => \$::lfmgr_port,
|
||||
'log_cli=s{0,1}' => \$log_cli,
|
||||
'tx_style|style=s' => \$::tx_style,
|
||||
'cx_name|e=s' => \$::cx_name,
|
||||
'set_tx|side|s=s' => \$::tx_side,
|
||||
'min_tx=i' => \$::min_tx,
|
||||
'max_tx=i' => \$::max_tx,
|
||||
'buf_size|buf=i' => \$::buf_size,
|
||||
'stream_res=s' => \$::stream_res,
|
||||
'list_streams' => \$list_streams,
|
||||
'help|h' => \$show_help,
|
||||
'mgr|m=s' => \$::lfmgr_host,
|
||||
'mgr_port|p=i' => \$::lfmgr_port,
|
||||
'log_cli=s{0,1}' => \$log_cli,
|
||||
'tx_style|style=s' => \$::tx_style,
|
||||
'cx_name|e=s' => \$::cx_name,
|
||||
'tx_side|side|s=s' => \$::tx_side,
|
||||
'max_tx=s' => \$::max_tx,
|
||||
'min_tx=s' => \$::min_tx,
|
||||
'buf_size|buf=s' => \$::buf_size,
|
||||
'stream_res|stream=s' => \$::stream_key,
|
||||
'list_streams' => \$list_streams,
|
||||
) || die($::usage);
|
||||
|
||||
|
||||
@@ -209,8 +209,8 @@ if ($show_help) {
|
||||
|
||||
if ($list_streams) {
|
||||
print "Predefined Video Streams\n";
|
||||
print "=" x 72;
|
||||
print "\n";
|
||||
print "=" x 72, "\n";
|
||||
print " Stream W H Audio+Video\n";
|
||||
my %sortedkeys = ();
|
||||
foreach my $oldkey (keys(%::avail_stream_res)) {
|
||||
my $ra_row = $::avail_stream_res{$oldkey};
|
||||
@@ -228,7 +228,7 @@ if ($list_streams) {
|
||||
my $bps = int(@$ra_row1[$stream_keys{stream_bps}]);
|
||||
my $bps_sum = int(@$ra_row1[$stream_keys{video_bps}]) + int(@$ra_row1[$stream_keys{audio_bps}]);
|
||||
#my $warning = "";
|
||||
printf("[ %15s ] %5s x %5s using %13s", $key, $x, $y, $bps);
|
||||
printf("[ %15s ] %4s x %4s using %8s kbps", $key, $x, $y, ($bps/1000));
|
||||
if ($bps != $bps_sum) {
|
||||
print " Invalid BPS $bps, correct to $bps_sum";
|
||||
}
|
||||
@@ -258,6 +258,23 @@ if (defined $log_cli) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$SIG{INT} = \&cleanexit;
|
||||
|
||||
sub cleanexit {
|
||||
if ((defined $::cx_name) && ("" ne $::cx_name)) {
|
||||
if (defined $::utils->telnet) {
|
||||
print STDERR "Stopping $::cx_name\n";
|
||||
$::utils->doAsyncCmd($::utils->fmt_cmd("set_cx_state", "all", $::cx_name, "STOPPED"));
|
||||
# prolly want to set tx rate back to min-tx
|
||||
#$::utils->doCmd($::utils->fmt_cmd("add_endp",
|
||||
#sleep 1;
|
||||
}
|
||||
}
|
||||
exit 0;
|
||||
}
|
||||
|
||||
|
||||
if ($::quiet eq "1" ) {
|
||||
$::quiet = "yes";
|
||||
}
|
||||
@@ -266,8 +283,8 @@ my $t = new Net::Telnet(Prompt => '/default\@btbits\>\>/',
|
||||
Timeout => 60);
|
||||
|
||||
$t->open(Host => $::lfmgr_host,
|
||||
Port => $::lfmgr_port,
|
||||
Timeout => 10);
|
||||
Port => $::lfmgr_port,
|
||||
Timeout => 10);
|
||||
|
||||
$t->max_buffer_length(16 * 1024 * 1000); # 16 MB buffer
|
||||
$t->waitfor("/btbits\>\>/");
|
||||
@@ -291,8 +308,124 @@ else {
|
||||
$::utils->log_cli("# $0 ".`date "+%Y-%m-%d %H:%M:%S"`);
|
||||
|
||||
|
||||
die ("Please provide buffer size")
|
||||
unless((defined $buf_size) && ("" ne $buf_size));
|
||||
if ($buf_size =~ /[kmg]$/i) {
|
||||
my($n) = $buf_size =~ /(\d+)/;
|
||||
if ($buf_size =~ /k$/i) {
|
||||
$buf_size = $n * 1024;
|
||||
}
|
||||
elsif ($buf_size =~ /m$/i) {
|
||||
$buf_size = $n * 1024 * 1024;
|
||||
}
|
||||
elsif ($buf_size =~ /g$/i) {
|
||||
$buf_size = $n * 1024 * 1024 * 1024;
|
||||
}
|
||||
else {
|
||||
die("Whhhhhuuuuuut?");
|
||||
}
|
||||
}
|
||||
|
||||
die("Please specify max tx bps")
|
||||
unless("" ne $::max_tx);
|
||||
if ($::max_tx =~ /[kmg]$/i) {
|
||||
my($n) = $::max_tx =~ /(\d+)/;
|
||||
if ($::max_tx =~ /k$/i) {
|
||||
$::max_tx = $n * 1000;
|
||||
}
|
||||
elsif ($::max_tx =~ /m$/i) {
|
||||
$::max_tx = $n * 1000 * 1000;
|
||||
}
|
||||
elsif ($::max_tx =~ /g$/i) {
|
||||
$::max_tx = $n * 1000 * 1000 * 1000;
|
||||
}
|
||||
else {
|
||||
die("Whhhhhuuuuuut?");
|
||||
}
|
||||
}
|
||||
if ($::min_tx =~ /[kmg]$/i) {
|
||||
my($n) = $::min_tx =~ /(\d+)/;
|
||||
if ($::min_tx =~ /k$/i) {
|
||||
$::min_tx = $n * 1000;
|
||||
}
|
||||
elsif ($::min_tx =~ /m$/i) {
|
||||
$::min_tx = $n * 1000 * 1000;
|
||||
}
|
||||
elsif ($::min_tx =~ /g$/i) {
|
||||
$::min_tx = $n * 1000 * 1000 * 1000;
|
||||
}
|
||||
else {
|
||||
die("Whhhhhuuuuuut?");
|
||||
}
|
||||
}
|
||||
|
||||
my $stream_bps = 0;
|
||||
die("Unknown stream key $::stream_key")
|
||||
unless(exists $::avail_stream_res{$::stream_key});
|
||||
|
||||
$stream_bps = @{$::avail_stream_res{$stream_key}}[$stream_keys{stream_bps}];
|
||||
|
||||
my $fill_time = $::buf_size / $max_tx;
|
||||
my $drain_time = $::buf_size / $stream_bps;
|
||||
print "Filling $::buf_size buffer for $::stream_key takes $fill_time s, empties in $drain_time s\n";
|
||||
|
||||
|
||||
die ("Please provide cx_name")
|
||||
unless((defined $::cx_name) && ("" ne $::cx_name));
|
||||
# print out choices for now
|
||||
print $::utils->doAsyncCmd($::utils->fmt_cmd("show_cx", "all", $::cx_name));
|
||||
my @lines = split("\r?\n", $::utils->doAsyncCmd($::utils->fmt_cmd("show_cx", "all", $::cx_name)));
|
||||
my @matches = grep {/Could not find/} @lines;
|
||||
die($matches[0])
|
||||
unless (@matches == 0);
|
||||
|
||||
print "Stopping and configuring $::cx_name...";
|
||||
$::utils->doCmd($::utils->fmt_cmd("set_cx_state", "all", $::cx_name, "STOPPED"));
|
||||
|
||||
my $endp = "$::cx_name-${tx_side}";
|
||||
@lines = split("\r?\n", $::utils->doAsyncCmd($::utils->fmt_cmd("nc_show_endp", $endp)));
|
||||
#print "=" x 72, "\n";
|
||||
#print join("\n", @lines), "\n";
|
||||
#print "=" x 72, "\n";
|
||||
|
||||
|
||||
|
||||
@matches = grep {/ Shelf: 1, Card: /} @lines;
|
||||
die ("No matches for show endp $endp")
|
||||
unless($matches[0]);
|
||||
|
||||
#print "=" x 72, "\n";
|
||||
#print $matches[0], "\n";
|
||||
#print "=" x 72, "\n";
|
||||
|
||||
my ($res, $port, $type) = $matches[0] =~ /, Card: (\d+)\s+Port: (\d+)\s+Endpoint: \d+ Type: ([^ ]+)\s+/;
|
||||
#print "=" x 72, "\n";
|
||||
#print join("\n", @lines), "\n";
|
||||
#print "=" x 72, "\n";
|
||||
|
||||
|
||||
my $cmd = $::utils->fmt_cmd("add_endp", $endp, 1, $res, $port, $type,
|
||||
$NA, # ip_port
|
||||
$NA, # is_rate_bursty
|
||||
$::min_tx, # min_rate
|
||||
$::min_tx # max_rate
|
||||
);
|
||||
#print "CMD: $cmd\n";
|
||||
$::utils->doAsyncCmd($cmd);
|
||||
|
||||
$::utils->doCmd($::utils->fmt_cmd("set_cx_state", "all", $::cx_name, "RUNNING"));
|
||||
|
||||
do {
|
||||
$cmd = $::utils->fmt_cmd("add_endp", $endp, 1, $res, $port, $type, $NA, $NA, $::max_tx, $::max_tx);
|
||||
print "+";
|
||||
$::utils->doAsyncCmd($cmd);
|
||||
`sleep $fill_time`;
|
||||
|
||||
$cmd = $::utils->fmt_cmd("add_endp", $endp, 1, $res, $port, $type, $NA, $NA, $::min_tx, $::min_tx);
|
||||
print "-";
|
||||
$::utils->doAsyncCmd($cmd);
|
||||
my $drain_wait = $drain_time - $fill_time;
|
||||
`sleep $drain_wait`;
|
||||
|
||||
} while(1);
|
||||
|
||||
#
|
||||
Reference in New Issue
Block a user