Home | History | Annotate | Download | only in matlab
      1 function 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.
     22 ix = not(ismember(PT, 72:76));
     23 fprintf('Removing %i RTCP packets\n', length(SeqNo) - sum(ix));
     24 SeqNo = SeqNo(ix);
     25 TimeStamp = TimeStamp(ix);
     26 ArrTime = ArrTime(ix);
     27 Size = Size(ix);
     28 PT = PT(ix);
     29 M = M(ix);
     30 SSRC = 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.
     38 if 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);
     61 end
     62 
     63 %% Unwrap SeqNo and TimeStamp.
     64 SeqNoUW = maxUnwrap(SeqNo, 65535);
     65 TimeStampUW = maxUnwrap(TimeStamp, 4294967295);
     66 
     67 %% Generate some stats for the stream.
     68 fprintf('Statistics:\n');
     69 fprintf('SSRC: %s\n', SSRC{1});
     70 uPT = unique(PT);
     71 if length(uPT) > 1
     72     warning('This tool cannot yet handle changes in codec sample rate');
     73 end
     74 fprintf('Payload type(s): %i', uPT(1));
     75 if length(uPT) > 1
     76     fprintf(', %i', uPT(2:end));
     77 end
     78 fprintf('\n');
     79 fprintf('Packets: %i\n', length(SeqNo));
     80 SortSeqNo = sort(SeqNoUW);
     81 fprintf('Missing sequence numbers: %i\n', ...
     82     length(find(diff(SortSeqNo) > 1)));
     83 fprintf('Duplicated packets: %i\n', length(find(diff(SortSeqNo) == 0)));
     84 reorderIx = findReorderedPackets(SeqNoUW);
     85 fprintf('Reordered packets: %i\n', length(reorderIx));
     86 tsdiff = diff(TimeStampUW);
     87 tsdiff = tsdiff(diff(SeqNoUW) == 1);
     88 [utsdiff, ~, ixtsdiff] = unique(tsdiff);
     89 fprintf('Common packet sizes:\n');
     90 for i = 1:length(utsdiff)
     91     fprintf('  %i samples (%i%%)\n', ...
     92         utsdiff(i), ...
     93         round(100 * length(find(ixtsdiff == i))/length(ixtsdiff)));
     94 end
     95 
     96 %% Trying to figure out sample rate.
     97 fs_est = (TimeStampUW(end) - TimeStampUW(1)) / (ArrTime(end) - ArrTime(1));
     98 fs_vec = [8, 16, 32, 48];
     99 fs = 0;
    100 for f = fs_vec
    101     if abs((fs_est-f)/f) < 0.05  % 5% margin
    102         fs = f;
    103         break;
    104     end
    105 end
    106 if 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): ');
    110 else
    111     fprintf('Sample rate estimated to %i kHz\n', fs);
    112 end
    113 
    114 SendTimeMs = (TimeStampUW - TimeStampUW(1)) / fs;
    115 
    116 fprintf('Stream duration at sender: %.1f seconds\n', ...
    117     (SendTimeMs(end) - SendTimeMs(1)) / 1000);
    118 
    119 fprintf('Stream duration at receiver: %.1f seconds\n', ...
    120     (ArrTime(end) - ArrTime(1)) / 1000);
    121 
    122 fprintf('Clock drift: %.2f%%\n', ...
    123     100 * ((ArrTime(end) - ArrTime(1)) / ...
    124     (SendTimeMs(end) - SendTimeMs(1)) - 1));
    125 
    126 fprintf('Sent average bitrate: %i kbps\n', ...
    127     round(sum(Size) * 8 / (SendTimeMs(end)-SendTimeMs(1))));
    128 
    129 fprintf('Received average bitrate: %i kbps\n', ...
    130     round(sum(Size) * 8 / (ArrTime(end)-ArrTime(1))));
    131 
    132 %% Plots.
    133 delay = ArrTime - SendTimeMs;
    134 delay = delay - min(delay);
    135 delayOrdered = delay;
    136 delayOrdered(reorderIx) = nan;  % Set reordered packets to NaN.
    137 delayReordered = delay(reorderIx);  % Pick the reordered packets.
    138 sendTimeMsReordered = SendTimeMs(reorderIx);
    139 
    140 % Sort time arrays in packet send order.
    141 [~, sortix] = sort(SeqNoUW);
    142 SendTimeMs = SendTimeMs(sortix);
    143 Size = Size(sortix);
    144 delayOrdered = delayOrdered(sortix);
    145 
    146 figure
    147 plot(SendTimeMs / 1000, delayOrdered, ...
    148     sendTimeMsReordered / 1000, delayReordered, 'r.');
    149 xlabel('Send time [s]');
    150 ylabel('Relative transport delay [ms]');
    151 title(sprintf('SSRC: %s', SSRC{1}));
    152 
    153 SendBitrateKbps = 8 * Size(1:end-1) ./ diff(SendTimeMs);
    154 figure
    155 plot(SendTimeMs(1:end-1)/1000, SendBitrateKbps);
    156 xlabel('Send time [s]');
    157 ylabel('Send bitrate [kbps]');
    158 end
    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.
    165 function reorderIx = findReorderedPackets(seqNo)
    166 largestSeqNo = seqNo(1);
    167 reorderIx = [];
    168 for i = 2:length(seqNo)
    169     if seqNo(i) < largestSeqNo
    170         reorderIx = [reorderIx; i]; %#ok<AGROW>
    171     else
    172         largestSeqNo = seqNo(i);
    173     end
    174 end
    175 end
    176 
    177 %% Auto-generated subfunction.
    178 function [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.
    197 if nargin<=2
    198     startRow = 2;
    199     endRow = inf;
    200 end
    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.
    211 formatSpec = '%5f%11f%11f%6f%6f%3f%s%[^\n\r]';
    212 
    213 %% Open the text file.
    214 fileID = 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.
    220 dataArray = textscan(fileID, formatSpec, endRow(1)-startRow(1)+1, ...
    221     'Delimiter', '', 'WhiteSpace', '', 'HeaderLines', startRow(1)-1, ...
    222     'ReturnOnError', false);
    223 for 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
    231 end
    232 
    233 %% Close the text file.
    234 fclose(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
    243 SeqNo = dataArray{:, 1};
    244 TimeStamp = dataArray{:, 2};
    245 SendTime = dataArray{:, 3};
    246 Size = dataArray{:, 4};
    247 PT = dataArray{:, 5};
    248 M = dataArray{:, 6};
    249 SSRC = dataArray{:, 7};
    250 end
    251 
    252