xref: /aosp_15_r20/external/webrtc/tools_webrtc/matlab/rtpAnalyze.m (revision d9f758449e529ab9291ac668be2861e7a55c2422)
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