git-svn-id: http://webrtc.googlecode.com/svn/trunk@4 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
function outStruct = parse_delay_file(file)
|
||||
|
||||
fid = fopen(file, 'rb');
|
||||
if fid == -1
|
||||
error('Cannot open file %s', file);
|
||||
end
|
||||
|
||||
textline = fgetl(fid);
|
||||
if ~strncmp(textline, '#!NetEQ_Delay_Logging', 21)
|
||||
error('Wrong file format');
|
||||
end
|
||||
|
||||
ver = sscanf(textline, '#!NetEQ_Delay_Logging%d.%d');
|
||||
if ~all(ver == [2; 0])
|
||||
error('Wrong version of delay logging function')
|
||||
end
|
||||
|
||||
|
||||
start_pos = ftell(fid);
|
||||
fseek(fid, -12, 'eof');
|
||||
textline = fgetl(fid);
|
||||
if ~strncmp(textline, 'End of file', 21)
|
||||
error('File ending is not correct. Seems like the simulation ended abnormally.');
|
||||
end
|
||||
|
||||
fseek(fid,-12-4, 'eof');
|
||||
Npackets = fread(fid, 1, 'int32');
|
||||
fseek(fid, start_pos, 'bof');
|
||||
|
||||
rtpts = zeros(Npackets, 1);
|
||||
seqno = zeros(Npackets, 1);
|
||||
pt = zeros(Npackets, 1);
|
||||
plen = zeros(Npackets, 1);
|
||||
recin_t = nan*ones(Npackets, 1);
|
||||
decode_t = nan*ones(Npackets, 1);
|
||||
playout_delay = zeros(Npackets, 1);
|
||||
optbuf = zeros(Npackets, 1);
|
||||
|
||||
fs_ix = 1;
|
||||
clock = 0;
|
||||
ts_ix = 1;
|
||||
ended = 0;
|
||||
late_packets = 0;
|
||||
fs_now = 8000;
|
||||
last_decode_k = 0;
|
||||
tot_expand = 0;
|
||||
tot_accelerate = 0;
|
||||
tot_preemptive = 0;
|
||||
|
||||
while not(ended)
|
||||
signal = fread(fid, 1, '*int32');
|
||||
|
||||
switch signal
|
||||
case 3 % NETEQ_DELAY_LOGGING_SIGNAL_CLOCK
|
||||
clock = fread(fid, 1, '*float32');
|
||||
|
||||
% keep on reading batches of M until the signal is no longer "3"
|
||||
% read int32 + float32 in one go
|
||||
% this is to save execution time
|
||||
temp = [3; 0];
|
||||
M = 120;
|
||||
while all(temp(1,:) == 3)
|
||||
fp = ftell(fid);
|
||||
temp = fread(fid, [2 M], '*int32');
|
||||
end
|
||||
|
||||
% back up to last clock event
|
||||
fseek(fid, fp - ftell(fid) + ...
|
||||
(find(temp(1,:) ~= 3, 1 ) - 2) * 2 * 4 + 4, 'cof');
|
||||
% read the last clock value
|
||||
clock = fread(fid, 1, '*float32');
|
||||
|
||||
case 1 % NETEQ_DELAY_LOGGING_SIGNAL_RECIN
|
||||
temp_ts = fread(fid, 1, 'uint32');
|
||||
|
||||
if late_packets > 0
|
||||
temp_ix = ts_ix - 1;
|
||||
while (temp_ix >= 1) && (rtpts(temp_ix) ~= temp_ts)
|
||||
% TODO(hlundin): use matlab vector search instead?
|
||||
temp_ix = temp_ix - 1;
|
||||
end
|
||||
|
||||
if temp_ix >= 1
|
||||
% the ts was found in the vector
|
||||
late_packets = late_packets - 1;
|
||||
else
|
||||
temp_ix = ts_ix;
|
||||
ts_ix = ts_ix + 1;
|
||||
end
|
||||
else
|
||||
temp_ix = ts_ix;
|
||||
ts_ix = ts_ix + 1;
|
||||
end
|
||||
|
||||
rtpts(temp_ix) = temp_ts;
|
||||
seqno(temp_ix) = fread(fid, 1, 'uint16');
|
||||
pt(temp_ix) = fread(fid, 1, 'int32');
|
||||
plen(temp_ix) = fread(fid, 1, 'int16');
|
||||
recin_t(temp_ix) = clock;
|
||||
|
||||
case 2 % NETEQ_DELAY_LOGGING_SIGNAL_FLUSH
|
||||
% do nothing
|
||||
|
||||
case 4 % NETEQ_DELAY_LOGGING_SIGNAL_EOF
|
||||
ended = 1;
|
||||
|
||||
case 5 % NETEQ_DELAY_LOGGING_SIGNAL_DECODE
|
||||
last_decode_ts = fread(fid, 1, 'uint32');
|
||||
temp_delay = fread(fid, 1, 'uint16');
|
||||
|
||||
k = find(rtpts(1:(ts_ix - 1))==last_decode_ts,1,'last');
|
||||
if ~isempty(k)
|
||||
decode_t(k) = clock;
|
||||
playout_delay(k) = temp_delay + ...
|
||||
5 * fs_now / 8000; % add overlap length
|
||||
last_decode_k = k;
|
||||
end
|
||||
|
||||
case 6 % NETEQ_DELAY_LOGGING_SIGNAL_CHANGE_FS
|
||||
fsvec(fs_ix) = fread(fid, 1, 'uint16');
|
||||
fschange_ts(fs_ix) = last_decode_ts;
|
||||
fs_now = fsvec(fs_ix);
|
||||
fs_ix = fs_ix + 1;
|
||||
|
||||
case 7 % NETEQ_DELAY_LOGGING_SIGNAL_MERGE_INFO
|
||||
playout_delay(last_decode_k) = playout_delay(last_decode_k) ...
|
||||
+ fread(fid, 1, 'int32');
|
||||
|
||||
case 8 % NETEQ_DELAY_LOGGING_SIGNAL_EXPAND_INFO
|
||||
temp = fread(fid, 1, 'int32');
|
||||
if last_decode_k ~= 0
|
||||
tot_expand = tot_expand + temp / (fs_now / 1000);
|
||||
end
|
||||
|
||||
case 9 % NETEQ_DELAY_LOGGING_SIGNAL_ACCELERATE_INFO
|
||||
temp = fread(fid, 1, 'int32');
|
||||
if last_decode_k ~= 0
|
||||
tot_accelerate = tot_accelerate + temp / (fs_now / 1000);
|
||||
end
|
||||
|
||||
case 10 % NETEQ_DELAY_LOGGING_SIGNAL_PREEMPTIVE_INFO
|
||||
temp = fread(fid, 1, 'int32');
|
||||
if last_decode_k ~= 0
|
||||
tot_preemptive = tot_preemptive + temp / (fs_now / 1000);
|
||||
end
|
||||
|
||||
case 11 % NETEQ_DELAY_LOGGING_SIGNAL_OPTBUF
|
||||
optbuf(last_decode_k) = fread(fid, 1, 'int32');
|
||||
|
||||
case 12 % NETEQ_DELAY_LOGGING_SIGNAL_DECODE_ONE_DESC
|
||||
last_decode_ts = fread(fid, 1, 'uint32');
|
||||
k = ts_ix - 1;
|
||||
|
||||
while (k >= 1) && (rtpts(k) ~= last_decode_ts)
|
||||
% TODO(hlundin): use matlab vector search instead?
|
||||
k = k - 1;
|
||||
end
|
||||
|
||||
if k < 1
|
||||
% packet not received yet
|
||||
k = ts_ix;
|
||||
rtpts(ts_ix) = last_decode_ts;
|
||||
late_packets = late_packets + 1;
|
||||
end
|
||||
|
||||
decode_t(k) = clock;
|
||||
playout_delay(k) = fread(fid, 1, 'uint16') + ...
|
||||
5 * fs_now / 8000; % add overlap length
|
||||
last_decode_k = k;
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
fclose(fid);
|
||||
|
||||
outStruct = struct(...
|
||||
'ts', rtpts, ...
|
||||
'sn', seqno, ...
|
||||
'pt', pt,...
|
||||
'plen', plen,...
|
||||
'arrival', recin_t,...
|
||||
'decode', decode_t,...
|
||||
'fs', fsvec(:),...
|
||||
'fschange_ts', fschange_ts(:),...
|
||||
'playout_delay', playout_delay,...
|
||||
'tot_expand', tot_expand,...
|
||||
'tot_accelerate', tot_accelerate,...
|
||||
'tot_preemptive', tot_preemptive,...
|
||||
'optbuf', optbuf);
|
||||
@@ -0,0 +1,187 @@
|
||||
function [delay_struct, delayvalues] = plot_neteq_delay(delayfile, varargin)
|
||||
|
||||
% InfoStruct = plot_neteq_delay(delayfile)
|
||||
% InfoStruct = plot_neteq_delay(delayfile, 'skipdelay', skip_seconds)
|
||||
%
|
||||
% Henrik Lundin, 2006-11-17
|
||||
% Henrik Lundin, 2011-05-17
|
||||
%
|
||||
|
||||
try
|
||||
s = parse_delay_file(delayfile);
|
||||
catch
|
||||
error(lasterr);
|
||||
end
|
||||
|
||||
delayskip=0;
|
||||
noplot=0;
|
||||
arg_ptr=1;
|
||||
delaypoints=[];
|
||||
|
||||
s.sn=unwrap_seqno(s.sn);
|
||||
|
||||
while arg_ptr+1 <= nargin
|
||||
switch lower(varargin{arg_ptr})
|
||||
case {'skipdelay', 'delayskip'}
|
||||
% skip a number of seconds in the beginning when calculating delays
|
||||
delayskip = varargin{arg_ptr+1};
|
||||
arg_ptr = arg_ptr + 2;
|
||||
case 'noplot'
|
||||
noplot=1;
|
||||
arg_ptr = arg_ptr + 1;
|
||||
case {'get_delay', 'getdelay'}
|
||||
% return a vector of delay values for the points in the given vector
|
||||
delaypoints = varargin{arg_ptr+1};
|
||||
arg_ptr = arg_ptr + 2;
|
||||
otherwise
|
||||
warning('Unknown switch %s\n', varargin{arg_ptr});
|
||||
arg_ptr = arg_ptr + 1;
|
||||
end
|
||||
end
|
||||
|
||||
% find lost frames that were covered by one-descriptor decoding
|
||||
one_desc_ix=find(isnan(s.arrival));
|
||||
for k=1:length(one_desc_ix)
|
||||
ix=find(s.ts==max(s.ts(s.ts(one_desc_ix(k))>s.ts)));
|
||||
s.sn(one_desc_ix(k))=s.sn(ix)+1;
|
||||
s.pt(one_desc_ix(k))=s.pt(ix);
|
||||
s.arrival(one_desc_ix(k))=s.arrival(ix)+s.decode(one_desc_ix(k))-s.decode(ix);
|
||||
end
|
||||
|
||||
% remove duplicate received frames that were never decoded (RED codec)
|
||||
if length(unique(s.ts(isfinite(s.ts)))) < length(s.ts(isfinite(s.ts)))
|
||||
ix=find(isfinite(s.decode));
|
||||
s.sn=s.sn(ix);
|
||||
s.ts=s.ts(ix);
|
||||
s.arrival=s.arrival(ix);
|
||||
s.playout_delay=s.playout_delay(ix);
|
||||
s.pt=s.pt(ix);
|
||||
s.optbuf=s.optbuf(ix);
|
||||
plen=plen(ix);
|
||||
s.decode=s.decode(ix);
|
||||
end
|
||||
|
||||
% find non-unique sequence numbers
|
||||
[~,un_ix]=unique(s.sn);
|
||||
nonun_ix=setdiff(1:length(s.sn),un_ix);
|
||||
if ~isempty(nonun_ix)
|
||||
warning('RTP sequence numbers are in error');
|
||||
end
|
||||
|
||||
% sort vectors
|
||||
[s.sn,sort_ix]=sort(s.sn);
|
||||
s.ts=s.ts(sort_ix);
|
||||
s.arrival=s.arrival(sort_ix);
|
||||
s.decode=s.decode(sort_ix);
|
||||
s.playout_delay=s.playout_delay(sort_ix);
|
||||
s.pt=s.pt(sort_ix);
|
||||
|
||||
send_t=s.ts-s.ts(1);
|
||||
if length(s.fs)<1
|
||||
warning('No info about sample rate found in file. Using default 8000.');
|
||||
s.fs(1)=8000;
|
||||
s.fschange_ts(1)=min(s.ts);
|
||||
elseif s.fschange_ts(1)>min(s.ts)
|
||||
s.fschange_ts(1)=min(s.ts);
|
||||
end
|
||||
|
||||
end_ix=length(send_t);
|
||||
for k=length(s.fs):-1:1
|
||||
start_ix=find(s.ts==s.fschange_ts(k));
|
||||
send_t(start_ix:end_ix)=send_t(start_ix:end_ix)/s.fs(k)*1000;
|
||||
s.playout_delay(start_ix:end_ix)=s.playout_delay(start_ix:end_ix)/s.fs(k)*1000;
|
||||
s.optbuf(start_ix:end_ix)=s.optbuf(start_ix:end_ix)/s.fs(k)*1000;
|
||||
end_ix=start_ix-1;
|
||||
end
|
||||
|
||||
tot_time=max(send_t)-min(send_t);
|
||||
|
||||
seq_ix=s.sn-min(s.sn)+1;
|
||||
send_t=send_t+max(min(s.arrival-send_t),0);
|
||||
|
||||
plot_send_t=nan*ones(max(seq_ix),1);
|
||||
plot_send_t(seq_ix)=send_t;
|
||||
plot_nw_delay=nan*ones(max(seq_ix),1);
|
||||
plot_nw_delay(seq_ix)=s.arrival-send_t;
|
||||
|
||||
cng_ix=find(s.pt~=13); % find those packets that are not CNG/SID
|
||||
|
||||
if noplot==0
|
||||
h=plot(plot_send_t/1000,plot_nw_delay);
|
||||
set(h,'color',0.75*[1 1 1]);
|
||||
hold on
|
||||
if any(s.optbuf~=0)
|
||||
peak_ix=find(s.optbuf(cng_ix)<0); % peak mode is labeled with negative values
|
||||
no_peak_ix=find(s.optbuf(cng_ix)>0); %setdiff(1:length(cng_ix),peak_ix);
|
||||
h1=plot(send_t(cng_ix(peak_ix))/1000,...
|
||||
s.arrival(cng_ix(peak_ix))+abs(s.optbuf(cng_ix(peak_ix)))-send_t(cng_ix(peak_ix)),...
|
||||
'r.');
|
||||
h2=plot(send_t(cng_ix(no_peak_ix))/1000,...
|
||||
s.arrival(cng_ix(no_peak_ix))+abs(s.optbuf(cng_ix(no_peak_ix)))-send_t(cng_ix(no_peak_ix)),...
|
||||
'g.');
|
||||
set([h1, h2],'markersize',1)
|
||||
end
|
||||
%h=plot(send_t(seq_ix)/1000,s.decode+s.playout_delay-send_t(seq_ix));
|
||||
h=plot(send_t(cng_ix)/1000,s.decode(cng_ix)+s.playout_delay(cng_ix)-send_t(cng_ix));
|
||||
set(h,'linew',1.5);
|
||||
hold off
|
||||
ax1=axis;
|
||||
axis tight
|
||||
ax2=axis;
|
||||
axis([ax2(1:3) ax1(4)])
|
||||
end
|
||||
|
||||
|
||||
% calculate delays and other parameters
|
||||
|
||||
delayskip_ix = find(send_t-send_t(1)>=delayskip*1000, 1 );
|
||||
|
||||
use_ix = intersect(cng_ix,... % use those that are not CNG/SID frames...
|
||||
intersect(find(isfinite(s.decode)),... % ... that did arrive ...
|
||||
(delayskip_ix:length(s.decode))')); % ... and are sent after delayskip seconds
|
||||
|
||||
mean_delay = mean(s.decode(use_ix)+s.playout_delay(use_ix)-send_t(use_ix));
|
||||
neteq_delay = mean(s.decode(use_ix)+s.playout_delay(use_ix)-s.arrival(use_ix));
|
||||
|
||||
Npack=max(s.sn(delayskip_ix:end))-min(s.sn(delayskip_ix:end))+1;
|
||||
nw_lossrate=(Npack-length(s.sn(delayskip_ix:end)))/Npack;
|
||||
neteq_lossrate=(length(s.sn(delayskip_ix:end))-length(use_ix))/Npack;
|
||||
|
||||
delay_struct=struct('mean_delay',mean_delay,'neteq_delay',neteq_delay,...
|
||||
'nw_lossrate',nw_lossrate,'neteq_lossrate',neteq_lossrate,...
|
||||
'tot_expand',round(s.tot_expand),'tot_accelerate',round(s.tot_accelerate),...
|
||||
'tot_preemptive',round(s.tot_preemptive),'tot_time',tot_time,...
|
||||
'filename',delayfile,'units','ms','fs',unique(s.fs));
|
||||
|
||||
if not(isempty(delaypoints))
|
||||
delayvalues=interp1(send_t(cng_ix),...
|
||||
s.decode(cng_ix)+s.playout_delay(cng_ix)-send_t(cng_ix),...
|
||||
delaypoints,'nearest',NaN);
|
||||
else
|
||||
delayvalues=[];
|
||||
end
|
||||
|
||||
|
||||
|
||||
% SUBFUNCTIONS %
|
||||
|
||||
function y=unwrap_seqno(x)
|
||||
|
||||
jumps=find(abs((diff(x)-1))>65000);
|
||||
|
||||
while ~isempty(jumps)
|
||||
n=jumps(1);
|
||||
if x(n+1)-x(n) < 0
|
||||
% negative jump
|
||||
x(n+1:end)=x(n+1:end)+65536;
|
||||
else
|
||||
% positive jump
|
||||
x(n+1:end)=x(n+1:end)-65536;
|
||||
end
|
||||
|
||||
jumps=find(abs((diff(x(n+1:end))-1))>65000);
|
||||
end
|
||||
|
||||
y=x;
|
||||
|
||||
return;
|
||||
Reference in New Issue
Block a user