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