1function [delay_struct, delayvalues] = plot_neteq_delay(delayfile, varargin)
2
3% InfoStruct = plot_neteq_delay(delayfile)
4% InfoStruct = plot_neteq_delay(delayfile, 'skipdelay', skip_seconds)
5%
6% Henrik Lundin, 2006-11-17
7% Henrik Lundin, 2011-05-17
8%
9
10try
11    s = parse_delay_file(delayfile);
12catch
13    error(lasterr);
14end
15
16delayskip=0;
17noplot=0;
18arg_ptr=1;
19delaypoints=[];
20
21s.sn=unwrap_seqno(s.sn);
22
23while arg_ptr+1 <= nargin
24    switch lower(varargin{arg_ptr})
25    case {'skipdelay', 'delayskip'}
26        % skip a number of seconds in the beginning when calculating delays
27        delayskip = varargin{arg_ptr+1};
28        arg_ptr = arg_ptr + 2;
29    case 'noplot'
30        noplot=1;
31        arg_ptr = arg_ptr + 1;
32    case {'get_delay', 'getdelay'}
33        % return a vector of delay values for the points in the given vector
34        delaypoints = varargin{arg_ptr+1};
35        arg_ptr = arg_ptr + 2;
36    otherwise
37        warning('Unknown switch %s\n', varargin{arg_ptr});
38        arg_ptr = arg_ptr + 1;
39    end
40end
41
42% find lost frames that were covered by one-descriptor decoding
43one_desc_ix=find(isnan(s.arrival));
44for k=1:length(one_desc_ix)
45    ix=find(s.ts==max(s.ts(s.ts(one_desc_ix(k))>s.ts)));
46    s.sn(one_desc_ix(k))=s.sn(ix)+1;
47    s.pt(one_desc_ix(k))=s.pt(ix);
48    s.arrival(one_desc_ix(k))=s.arrival(ix)+s.decode(one_desc_ix(k))-s.decode(ix);
49end
50
51% remove duplicate received frames that were never decoded (RED codec)
52if length(unique(s.ts(isfinite(s.ts)))) < length(s.ts(isfinite(s.ts)))
53    ix=find(isfinite(s.decode));
54    s.sn=s.sn(ix);
55    s.ts=s.ts(ix);
56    s.arrival=s.arrival(ix);
57    s.playout_delay=s.playout_delay(ix);
58    s.pt=s.pt(ix);
59    s.optbuf=s.optbuf(ix);
60    plen=plen(ix);
61    s.decode=s.decode(ix);
62end
63
64% find non-unique sequence numbers
65[~,un_ix]=unique(s.sn);
66nonun_ix=setdiff(1:length(s.sn),un_ix);
67if ~isempty(nonun_ix)
68    warning('RTP sequence numbers are in error');
69end
70            
71% sort vectors
72[s.sn,sort_ix]=sort(s.sn);
73s.ts=s.ts(sort_ix);
74s.arrival=s.arrival(sort_ix);
75s.decode=s.decode(sort_ix);
76s.playout_delay=s.playout_delay(sort_ix);
77s.pt=s.pt(sort_ix);
78
79send_t=s.ts-s.ts(1);
80if length(s.fs)<1
81    warning('No info about sample rate found in file. Using default 8000.');
82    s.fs(1)=8000;
83    s.fschange_ts(1)=min(s.ts);
84elseif s.fschange_ts(1)>min(s.ts)
85    s.fschange_ts(1)=min(s.ts);
86end
87
88end_ix=length(send_t);
89for k=length(s.fs):-1:1
90    start_ix=find(s.ts==s.fschange_ts(k));
91    send_t(start_ix:end_ix)=send_t(start_ix:end_ix)/s.fs(k)*1000;
92    s.playout_delay(start_ix:end_ix)=s.playout_delay(start_ix:end_ix)/s.fs(k)*1000;
93    s.optbuf(start_ix:end_ix)=s.optbuf(start_ix:end_ix)/s.fs(k)*1000;
94    end_ix=start_ix-1;
95end
96
97tot_time=max(send_t)-min(send_t);
98
99seq_ix=s.sn-min(s.sn)+1;
100send_t=send_t+max(min(s.arrival-send_t),0);
101
102plot_send_t=nan*ones(max(seq_ix),1);
103plot_send_t(seq_ix)=send_t;
104plot_nw_delay=nan*ones(max(seq_ix),1);
105plot_nw_delay(seq_ix)=s.arrival-send_t;
106
107cng_ix=find(s.pt~=13); % find those packets that are not CNG/SID
108    
109if noplot==0
110    h=plot(plot_send_t/1000,plot_nw_delay);
111    set(h,'color',0.75*[1 1 1]);
112    hold on
113    if any(s.optbuf~=0)
114        peak_ix=find(s.optbuf(cng_ix)<0); % peak mode is labeled with negative values
115        no_peak_ix=find(s.optbuf(cng_ix)>0); %setdiff(1:length(cng_ix),peak_ix);
116        h1=plot(send_t(cng_ix(peak_ix))/1000,...
117            s.arrival(cng_ix(peak_ix))+abs(s.optbuf(cng_ix(peak_ix)))-send_t(cng_ix(peak_ix)),...
118            'r.');
119        h2=plot(send_t(cng_ix(no_peak_ix))/1000,...
120            s.arrival(cng_ix(no_peak_ix))+abs(s.optbuf(cng_ix(no_peak_ix)))-send_t(cng_ix(no_peak_ix)),...
121            'g.');
122        set([h1, h2],'markersize',1)
123    end
124    %h=plot(send_t(seq_ix)/1000,s.decode+s.playout_delay-send_t(seq_ix));
125    h=plot(send_t(cng_ix)/1000,s.decode(cng_ix)+s.playout_delay(cng_ix)-send_t(cng_ix));
126    set(h,'linew',1.5);
127    hold off
128    ax1=axis;
129    axis tight
130    ax2=axis;
131    axis([ax2(1:3) ax1(4)])
132end
133
134
135% calculate delays and other parameters
136
137delayskip_ix = find(send_t-send_t(1)>=delayskip*1000, 1 );
138
139use_ix = intersect(cng_ix,... % use those that are not CNG/SID frames...
140    intersect(find(isfinite(s.decode)),... % ... that did arrive ...
141    (delayskip_ix:length(s.decode))')); % ... and are sent after delayskip seconds
142
143mean_delay = mean(s.decode(use_ix)+s.playout_delay(use_ix)-send_t(use_ix));
144neteq_delay = mean(s.decode(use_ix)+s.playout_delay(use_ix)-s.arrival(use_ix));
145
146Npack=max(s.sn(delayskip_ix:end))-min(s.sn(delayskip_ix:end))+1;
147nw_lossrate=(Npack-length(s.sn(delayskip_ix:end)))/Npack;
148neteq_lossrate=(length(s.sn(delayskip_ix:end))-length(use_ix))/Npack;
149
150delay_struct=struct('mean_delay',mean_delay,'neteq_delay',neteq_delay,...
151    'nw_lossrate',nw_lossrate,'neteq_lossrate',neteq_lossrate,...
152    'tot_expand',round(s.tot_expand),'tot_accelerate',round(s.tot_accelerate),...
153    'tot_preemptive',round(s.tot_preemptive),'tot_time',tot_time,...
154    'filename',delayfile,'units','ms','fs',unique(s.fs));
155    
156if not(isempty(delaypoints))
157    delayvalues=interp1(send_t(cng_ix),...
158        s.decode(cng_ix)+s.playout_delay(cng_ix)-send_t(cng_ix),...
159        delaypoints,'nearest',NaN);
160else
161    delayvalues=[];
162end
163
164
165
166% SUBFUNCTIONS %
167
168function y=unwrap_seqno(x)
169
170jumps=find(abs((diff(x)-1))>65000);
171
172while ~isempty(jumps)
173    n=jumps(1);
174    if x(n+1)-x(n) < 0
175        % negative jump
176        x(n+1:end)=x(n+1:end)+65536;
177    else
178        % positive jump
179        x(n+1:end)=x(n+1:end)-65536;
180    end
181    
182    jumps=find(abs((diff(x(n+1:end))-1))>65000);
183end
184
185y=x;
186
187return;
188