1function rtpAnalyze( input_file ) 2%RTP_ANALYZE Analyze RTP stream(s) from a txt file 3% The function takes the output from the command line tool rtp_analyze 4% and analyzes the stream(s) therein. First, process your rtpdump file 5% through rtp_analyze (from command line): 6% $ out/Debug/rtp_analyze my_file.rtp my_file.txt 7% Then load it with this function (in Matlab): 8% >> rtpAnalyze('my_file.txt') 9 10% Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. 11% 12% Use of this source code is governed by a BSD-style license 13% that can be found in the LICENSE file in the root of the source 14% tree. An additional intellectual property rights grant can be found 15% in the file PATENTS. All contributing project authors may 16% be found in the AUTHORS file in the root of the source tree. 17 18[SeqNo,TimeStamp,ArrTime,Size,PT,M,SSRC] = importfile(input_file); 19 20%% Filter out RTCP packets. 21% These appear as RTP packets having payload types 72 through 76. 22ix = not(ismember(PT, 72:76)); 23fprintf('Removing %i RTCP packets\n', length(SeqNo) - sum(ix)); 24SeqNo = SeqNo(ix); 25TimeStamp = TimeStamp(ix); 26ArrTime = ArrTime(ix); 27Size = Size(ix); 28PT = PT(ix); 29M = M(ix); 30SSRC = SSRC(ix); 31 32%% Find streams. 33[uSSRC, ~, uix] = unique(SSRC); 34 35% If there are multiple streams, select one and purge the other 36% streams from the data vectors. If there is only one stream, the 37% vectors are good to use as they are. 38if length(uSSRC) > 1 39 for i=1:length(uSSRC) 40 uPT = unique(PT(uix == i)); 41 fprintf('%i: %s (%d packets, pt: %i', i, uSSRC{i}, ... 42 length(find(uix==i)), uPT(1)); 43 if length(uPT) > 1 44 fprintf(', %i', uPT(2:end)); 45 end 46 fprintf(')\n'); 47 end 48 sel = input('Select stream number: '); 49 if sel < 1 || sel > length(uSSRC) 50 error('Out of range'); 51 end 52 ix = find(uix == sel); 53 % This is where the data vectors are trimmed. 54 SeqNo = SeqNo(ix); 55 TimeStamp = TimeStamp(ix); 56 ArrTime = ArrTime(ix); 57 Size = Size(ix); 58 PT = PT(ix); 59 M = M(ix); 60 SSRC = SSRC(ix); 61end 62 63%% Unwrap SeqNo and TimeStamp. 64SeqNoUW = maxUnwrap(SeqNo, 65535); 65TimeStampUW = maxUnwrap(TimeStamp, 4294967295); 66 67%% Generate some stats for the stream. 68fprintf('Statistics:\n'); 69fprintf('SSRC: %s\n', SSRC{1}); 70uPT = unique(PT); 71if length(uPT) > 1 72 warning('This tool cannot yet handle changes in codec sample rate'); 73end 74fprintf('Payload type(s): %i', uPT(1)); 75if length(uPT) > 1 76 fprintf(', %i', uPT(2:end)); 77end 78fprintf('\n'); 79fprintf('Packets: %i\n', length(SeqNo)); 80SortSeqNo = sort(SeqNoUW); 81fprintf('Missing sequence numbers: %i\n', ... 82 length(find(diff(SortSeqNo) > 1))); 83fprintf('Duplicated packets: %i\n', length(find(diff(SortSeqNo) == 0))); 84reorderIx = findReorderedPackets(SeqNoUW); 85fprintf('Reordered packets: %i\n', length(reorderIx)); 86tsdiff = diff(TimeStampUW); 87tsdiff = tsdiff(diff(SeqNoUW) == 1); 88[utsdiff, ~, ixtsdiff] = unique(tsdiff); 89fprintf('Common packet sizes:\n'); 90for i = 1:length(utsdiff) 91 fprintf(' %i samples (%i%%)\n', ... 92 utsdiff(i), ... 93 round(100 * length(find(ixtsdiff == i))/length(ixtsdiff))); 94end 95 96%% Trying to figure out sample rate. 97fs_est = (TimeStampUW(end) - TimeStampUW(1)) / (ArrTime(end) - ArrTime(1)); 98fs_vec = [8, 16, 32, 48]; 99fs = 0; 100for f = fs_vec 101 if abs((fs_est-f)/f) < 0.05 % 5% margin 102 fs = f; 103 break; 104 end 105end 106if fs == 0 107 fprintf('Cannot determine sample rate. I get it to %.2f kHz\n', ... 108 fs_est); 109 fs = input('Please, input a sample rate (in kHz): '); 110else 111 fprintf('Sample rate estimated to %i kHz\n', fs); 112end 113 114SendTimeMs = (TimeStampUW - TimeStampUW(1)) / fs; 115 116fprintf('Stream duration at sender: %.1f seconds\n', ... 117 (SendTimeMs(end) - SendTimeMs(1)) / 1000); 118 119fprintf('Stream duration at receiver: %.1f seconds\n', ... 120 (ArrTime(end) - ArrTime(1)) / 1000); 121 122fprintf('Clock drift: %.2f%%\n', ... 123 100 * ((ArrTime(end) - ArrTime(1)) / ... 124 (SendTimeMs(end) - SendTimeMs(1)) - 1)); 125 126fprintf('Sent average bitrate: %i kbps\n', ... 127 round(sum(Size) * 8 / (SendTimeMs(end)-SendTimeMs(1)))); 128 129fprintf('Received average bitrate: %i kbps\n', ... 130 round(sum(Size) * 8 / (ArrTime(end)-ArrTime(1)))); 131 132%% Plots. 133delay = ArrTime - SendTimeMs; 134delay = delay - min(delay); 135delayOrdered = delay; 136delayOrdered(reorderIx) = nan; % Set reordered packets to NaN. 137delayReordered = delay(reorderIx); % Pick the reordered packets. 138sendTimeMsReordered = SendTimeMs(reorderIx); 139 140% Sort time arrays in packet send order. 141[~, sortix] = sort(SeqNoUW); 142SendTimeMs = SendTimeMs(sortix); 143Size = Size(sortix); 144delayOrdered = delayOrdered(sortix); 145 146figure 147plot(SendTimeMs / 1000, delayOrdered, ... 148 sendTimeMsReordered / 1000, delayReordered, 'r.'); 149xlabel('Send time [s]'); 150ylabel('Relative transport delay [ms]'); 151title(sprintf('SSRC: %s', SSRC{1})); 152 153SendBitrateKbps = 8 * Size(1:end-1) ./ diff(SendTimeMs); 154figure 155plot(SendTimeMs(1:end-1)/1000, SendBitrateKbps); 156xlabel('Send time [s]'); 157ylabel('Send bitrate [kbps]'); 158end 159 160%% Subfunctions. 161 162% findReorderedPackets returns the index to all packets that are considered 163% old compared with the largest seen sequence number. The input seqNo must 164% be unwrapped for this to work. 165function reorderIx = findReorderedPackets(seqNo) 166largestSeqNo = seqNo(1); 167reorderIx = []; 168for i = 2:length(seqNo) 169 if seqNo(i) < largestSeqNo 170 reorderIx = [reorderIx; i]; %#ok<AGROW> 171 else 172 largestSeqNo = seqNo(i); 173 end 174end 175end 176 177%% Auto-generated subfunction. 178function [SeqNo,TimeStamp,SendTime,Size,PT,M,SSRC] = ... 179 importfile(filename, startRow, endRow) 180%IMPORTFILE Import numeric data from a text file as column vectors. 181% [SEQNO,TIMESTAMP,SENDTIME,SIZE,PT,M,SSRC] = IMPORTFILE(FILENAME) Reads 182% data from text file FILENAME for the default selection. 183% 184% [SEQNO,TIMESTAMP,SENDTIME,SIZE,PT,M,SSRC] = IMPORTFILE(FILENAME, 185% STARTROW, ENDROW) Reads data from rows STARTROW through ENDROW of text 186% file FILENAME. 187% 188% Example: 189% [SeqNo,TimeStamp,SendTime,Size,PT,M,SSRC] = 190% importfile('rtpdump_recv.txt',2, 123); 191% 192% See also TEXTSCAN. 193 194% Auto-generated by MATLAB on 2015/05/28 09:55:50 195 196%% Initialize variables. 197if nargin<=2 198 startRow = 2; 199 endRow = inf; 200end 201 202%% Format string for each line of text: 203% column1: double (%f) 204% column2: double (%f) 205% column3: double (%f) 206% column4: double (%f) 207% column5: double (%f) 208% column6: double (%f) 209% column7: text (%s) 210% For more information, see the TEXTSCAN documentation. 211formatSpec = '%5f%11f%11f%6f%6f%3f%s%[^\n\r]'; 212 213%% Open the text file. 214fileID = fopen(filename,'r'); 215 216%% Read columns of data according to format string. 217% This call is based on the structure of the file used to generate this 218% code. If an error occurs for a different file, try regenerating the code 219% from the Import Tool. 220dataArray = textscan(fileID, formatSpec, endRow(1)-startRow(1)+1, ... 221 'Delimiter', '', 'WhiteSpace', '', 'HeaderLines', startRow(1)-1, ... 222 'ReturnOnError', false); 223for block=2:length(startRow) 224 frewind(fileID); 225 dataArrayBlock = textscan(fileID, formatSpec, ... 226 endRow(block)-startRow(block)+1, 'Delimiter', '', 'WhiteSpace', ... 227 '', 'HeaderLines', startRow(block)-1, 'ReturnOnError', false); 228 for col=1:length(dataArray) 229 dataArray{col} = [dataArray{col};dataArrayBlock{col}]; 230 end 231end 232 233%% Close the text file. 234fclose(fileID); 235 236%% Post processing for unimportable data. 237% No unimportable data rules were applied during the import, so no post 238% processing code is included. To generate code which works for 239% unimportable data, select unimportable cells in a file and regenerate the 240% script. 241 242%% Allocate imported array to column variable names 243SeqNo = dataArray{:, 1}; 244TimeStamp = dataArray{:, 2}; 245SendTime = dataArray{:, 3}; 246Size = dataArray{:, 4}; 247PT = dataArray{:, 5}; 248M = dataArray{:, 6}; 249SSRC = dataArray{:, 7}; 250end 251 252