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