OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | |
stefan-webrtc
2016/04/26 18:39:42
2016
terelius
2016/04/27 14:35:26
Done.
| |
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 | |
11 #include "webrtc/call/rtc_event_log_parser.h" | |
12 | |
13 #include <string.h> | |
14 | |
15 #include <fstream> | |
16 | |
17 #include "webrtc/base/checks.h" | |
18 #include "webrtc/base/logging.h" | |
19 #include "webrtc/base/scoped_ptr.h" | |
20 #include "webrtc/call.h" | |
21 #include "webrtc/call/rtc_event_log.h" | |
22 #include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h" | |
23 #include "webrtc/system_wrappers/include/file_wrapper.h" | |
24 | |
25 namespace webrtc { | |
26 | |
27 namespace { | |
28 MediaType GetRuntimeMediaType(rtclog::MediaType media_type) { | |
29 switch (media_type) { | |
30 case rtclog::MediaType::ANY: | |
31 return MediaType::ANY; | |
32 case rtclog::MediaType::AUDIO: | |
33 return MediaType::AUDIO; | |
34 case rtclog::MediaType::VIDEO: | |
35 return MediaType::VIDEO; | |
36 case rtclog::MediaType::DATA: | |
37 return MediaType::DATA; | |
38 } | |
39 RTC_NOTREACHED(); | |
40 return MediaType::ANY; | |
41 } | |
42 | |
43 RtcpMode GetRuntimeRtcpMode(rtclog::VideoReceiveConfig::RtcpMode rtcp_mode) { | |
44 switch (rtcp_mode) { | |
45 case rtclog::VideoReceiveConfig::RTCP_COMPOUND: | |
46 return RtcpMode::kCompound; | |
47 case rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE: | |
48 return RtcpMode::kReducedSize; | |
49 } | |
50 RTC_NOTREACHED(); | |
51 return RtcpMode::kOff; | |
52 } | |
53 | |
54 ParsedRtcEventLog::EventType GetRuntimeEventType( | |
55 rtclog::Event::EventType event_type) { | |
56 switch (event_type) { | |
57 case rtclog::Event::UNKNOWN_EVENT: | |
58 return ParsedRtcEventLog::EventType::UNKNOWN_EVENT; | |
59 case rtclog::Event::LOG_START: | |
60 return ParsedRtcEventLog::EventType::LOG_START; | |
61 case rtclog::Event::LOG_END: | |
62 return ParsedRtcEventLog::EventType::LOG_END; | |
63 case rtclog::Event::RTP_EVENT: | |
64 return ParsedRtcEventLog::EventType::RTP_EVENT; | |
65 case rtclog::Event::RTCP_EVENT: | |
66 return ParsedRtcEventLog::EventType::RTCP_EVENT; | |
67 case rtclog::Event::AUDIO_PLAYOUT_EVENT: | |
68 return ParsedRtcEventLog::EventType::AUDIO_PLAYOUT_EVENT; | |
69 case rtclog::Event::BWE_PACKET_LOSS_EVENT: | |
70 return ParsedRtcEventLog::EventType::BWE_PACKET_LOSS_EVENT; | |
71 case rtclog::Event::BWE_PACKET_DELAY_EVENT: | |
72 return ParsedRtcEventLog::EventType::BWE_PACKET_DELAY_EVENT; | |
73 case rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT: | |
74 return ParsedRtcEventLog::EventType::VIDEO_RECEIVER_CONFIG_EVENT; | |
75 case rtclog::Event::VIDEO_SENDER_CONFIG_EVENT: | |
76 return ParsedRtcEventLog::EventType::VIDEO_SENDER_CONFIG_EVENT; | |
77 case rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT: | |
78 return ParsedRtcEventLog::EventType::AUDIO_RECEIVER_CONFIG_EVENT; | |
79 case rtclog::Event::AUDIO_SENDER_CONFIG_EVENT: | |
80 return ParsedRtcEventLog::EventType::AUDIO_SENDER_CONFIG_EVENT; | |
81 } | |
82 RTC_NOTREACHED(); | |
83 return ParsedRtcEventLog::EventType::UNKNOWN_EVENT; | |
84 } | |
85 | |
86 bool ParseVarInt(std::FILE* file, uint64_t* varint, size_t* bytes_read) { | |
87 uint8_t byte; | |
88 *varint = 0; | |
89 for (*bytes_read = 0; *bytes_read < 10 && fread(&byte, 1, 1, file) == 1; | |
90 (*bytes_read)++) { | |
stefan-webrtc
2016/04/26 18:39:42
++*bytes_read
terelius
2016/04/27 14:35:26
Done.
| |
91 // The most significant bit of each byte is 0 if it is the last byte in | |
92 // the varint and 1 otherwise. Thus, we take the 7 least significant bits | |
93 // of each byte and shift them 7 bits for each byte read previously to get | |
94 // the (unsigned) integer. | |
95 *varint |= static_cast<uint64_t>(byte & 0x7F) << (7 * *bytes_read); | |
96 if ((byte & 0x80) == 0) { | |
97 return true; | |
98 } | |
99 } | |
100 return false; | |
101 } | |
102 | |
103 } // namespace | |
104 | |
105 bool ParsedRtcEventLog::ParseFile(const std::string& filename) { | |
106 stream_.clear(); | |
107 const size_t kMaxEventSize = 1u << 16; | |
108 char tmp_buffer[kMaxEventSize]; | |
109 | |
110 std::FILE* file = fopen(filename.c_str(), "rb"); | |
111 if (!file) { | |
112 LOG(LS_WARNING) << "Could not open file for reading."; | |
113 return false; | |
114 } | |
115 | |
116 while (1) { | |
117 // Peek at the next message tag. The tag number is defined as | |
118 // (fieldnumber << 3) | wire_type. In our case, the field number is | |
119 // supposed to be 1 and the wire type for an length-delimited field is 2. | |
120 uint64_t tag, expected_tag = (1 << 3) | 2; | |
stefan-webrtc
2016/04/26 18:39:42
Declare one variable per line. expected_tag should
terelius
2016/04/27 14:35:27
Done.
| |
121 size_t bytes_read; | |
122 if (!ParseVarInt(file, &tag, &bytes_read) || tag != expected_tag) { | |
123 fclose(file); | |
124 if (bytes_read == 0) { | |
125 return true; // Reached end of file. | |
126 } | |
127 LOG(LS_WARNING) << "Missing field tag from beginning of protobuf event."; | |
128 return false; | |
129 } | |
130 | |
131 // Peek at the length field. | |
132 uint64_t message_length; | |
133 if (!ParseVarInt(file, &message_length, &bytes_read) || | |
134 message_length >= kMaxEventSize) { | |
135 LOG(LS_WARNING) << "Missing message length after protobuf field tag."; | |
stefan-webrtc
2016/04/26 18:39:42
Is it really missing? Can't it also be too large?
terelius
2016/04/27 14:35:27
Done.
| |
136 fclose(file); | |
137 return false; | |
138 } | |
139 | |
140 if (fread(tmp_buffer, 1, message_length, file) != message_length) { | |
141 LOG(LS_WARNING) << "Failed to read protobuf message from file."; | |
142 fclose(file); | |
143 return false; | |
144 } | |
145 | |
146 rtclog::Event event; | |
147 if (!event.ParseFromArray(tmp_buffer, message_length)) { | |
148 LOG(LS_WARNING) << "Failed to parse protobuf message."; | |
149 fclose(file); | |
150 return false; | |
151 } | |
152 stream_.push_back(event); | |
153 } | |
154 } | |
155 | |
156 size_t ParsedRtcEventLog::GetNumberOfEvents() const { | |
157 return stream_.size(); | |
158 } | |
159 | |
160 int64_t ParsedRtcEventLog::GetTimestamp(size_t index) const { | |
161 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
162 const rtclog::Event& event = stream_[index]; | |
163 RTC_CHECK(event.has_timestamp_us()); | |
164 return event.timestamp_us(); | |
165 } | |
166 | |
167 ParsedRtcEventLog::EventType ParsedRtcEventLog::GetEventType( | |
168 size_t index) const { | |
169 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
170 const rtclog::Event& event = stream_[index]; | |
171 RTC_CHECK(event.has_type()); | |
172 return GetRuntimeEventType(event.type()); | |
173 } | |
174 | |
175 // The header must have space for at least IP_PACKET_SIZE bytes. | |
176 void ParsedRtcEventLog::GetRtpHeader(size_t index, | |
177 PacketDirection* incoming, | |
178 MediaType* media_type, | |
179 uint8_t* header, | |
180 size_t* header_length, | |
181 size_t* total_length) const { | |
182 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
183 const rtclog::Event& event = stream_[index]; | |
184 RTC_CHECK(event.has_type()); | |
185 RTC_CHECK_EQ(event.type(), rtclog::Event::RTP_EVENT); | |
186 RTC_CHECK(event.has_rtp_packet()); | |
187 const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); | |
188 // Get direction of packet. | |
189 RTC_CHECK(rtp_packet.has_incoming()); | |
190 if (incoming != nullptr) | |
191 *incoming = rtp_packet.incoming() ? kIncomingPacket : kOutgoingPacket; | |
192 // Get media type. | |
193 RTC_CHECK(rtp_packet.has_type()); | |
194 if (media_type != nullptr) { | |
stefan-webrtc
2016/04/26 18:39:42
Remove {} to be consistent with line 190.
terelius
2016/05/04 11:43:37
As discussed offline, I'll add braces where they a
| |
195 *media_type = GetRuntimeMediaType(rtp_packet.type()); | |
196 } | |
197 // Get packet length. | |
198 RTC_CHECK(rtp_packet.has_packet_length()); | |
199 if (total_length != nullptr) | |
200 *total_length = rtp_packet.packet_length(); | |
201 // Get header length. | |
202 RTC_CHECK(rtp_packet.has_header()); | |
203 if (header_length != nullptr) | |
204 *header_length = rtp_packet.header().size(); | |
205 // Get header contents. | |
206 if (header != nullptr) { | |
207 RTC_CHECK_GE(rtp_packet.header().size(), 12u); | |
stefan-webrtc
2016/04/26 18:39:42
Name the constant.
terelius
2016/04/27 14:35:26
Done.
| |
208 RTC_CHECK_LE(rtp_packet.header().size(), | |
209 static_cast<unsigned>(IP_PACKET_SIZE)); | |
210 memcpy(header, rtp_packet.header().data(), rtp_packet.header().size()); | |
211 } | |
212 } | |
213 | |
214 // The packet must have space for at least IP_PACKET_SIZE bytes. | |
215 void ParsedRtcEventLog::GetRtcpPacket(size_t index, | |
216 PacketDirection* incoming, | |
217 MediaType* media_type, | |
218 uint8_t* packet, | |
219 size_t* length) const { | |
220 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
221 const rtclog::Event& event = stream_[index]; | |
222 RTC_CHECK(event.has_type()); | |
223 RTC_CHECK_EQ(event.type(), rtclog::Event::RTCP_EVENT); | |
224 RTC_CHECK(event.has_rtcp_packet()); | |
225 const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet(); | |
226 // Get direction of packet. | |
227 RTC_CHECK(rtcp_packet.has_incoming()); | |
228 if (incoming != nullptr) | |
229 *incoming = rtcp_packet.incoming() ? kIncomingPacket : kOutgoingPacket; | |
230 // Get media type. | |
231 RTC_CHECK(rtcp_packet.has_type()); | |
232 if (media_type != nullptr) { | |
stefan-webrtc
2016/04/26 18:39:42
Remove {} for consistency
terelius
2016/05/04 11:43:37
Acknowledged.
| |
233 *media_type = GetRuntimeMediaType(rtcp_packet.type()); | |
234 } | |
235 // Get packet length. | |
236 RTC_CHECK(rtcp_packet.has_packet_data()); | |
237 if (length != nullptr) | |
238 *length = rtcp_packet.packet_data().size(); | |
239 // Get packet contents. | |
240 if (packet != nullptr) { | |
241 RTC_CHECK_LE(rtcp_packet.packet_data().size(), | |
242 static_cast<unsigned>(IP_PACKET_SIZE)); | |
243 memcpy(packet, rtcp_packet.packet_data().data(), | |
244 rtcp_packet.packet_data().size()); | |
245 } | |
246 } | |
247 | |
248 void ParsedRtcEventLog::GetVideoReceiveConfig( | |
249 size_t index, | |
250 VideoReceiveStream::Config* config) const { | |
251 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
252 const rtclog::Event& event = stream_[index]; | |
253 RTC_CHECK(config != nullptr); | |
254 RTC_CHECK(event.has_type()); | |
255 RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT); | |
256 RTC_CHECK(event.has_video_receiver_config()); | |
257 const rtclog::VideoReceiveConfig& receiver_config = | |
258 event.video_receiver_config(); | |
259 // Get SSRCs. | |
260 RTC_CHECK(receiver_config.has_remote_ssrc()); | |
261 config->rtp.remote_ssrc = receiver_config.remote_ssrc(); | |
262 RTC_CHECK(receiver_config.has_local_ssrc()); | |
263 config->rtp.local_ssrc = receiver_config.local_ssrc(); | |
264 // Get RTCP settings. | |
265 RTC_CHECK(receiver_config.has_rtcp_mode()); | |
266 config->rtp.rtcp_mode = GetRuntimeRtcpMode(receiver_config.rtcp_mode()); | |
267 RTC_CHECK(receiver_config.has_remb()); | |
268 config->rtp.remb = receiver_config.remb(); | |
stefan-webrtc
2016/04/26 18:39:42
We should probably add transport_cc here too, whic
terelius
2016/04/27 14:35:27
We do have tests that serialize a config and read
stefan-webrtc
2016/05/04 12:10:57
But if we serialize a struct which isn't fully rep
terelius
2016/05/04 15:34:20
True, but we don't represent everything and I don'
| |
269 // Get RTX map. | |
270 config->rtp.rtx.clear(); | |
271 for (int i = 0; i < receiver_config.rtx_map_size(); i++) { | |
272 const rtclog::RtxMap& map = receiver_config.rtx_map(i); | |
273 RTC_CHECK(map.has_payload_type()); | |
274 RTC_CHECK(map.has_config()); | |
275 RTC_CHECK(map.config().has_rtx_ssrc()); | |
276 RTC_CHECK(map.config().has_rtx_payload_type()); | |
277 webrtc::VideoReceiveStream::Config::Rtp::Rtx rtx_pair; | |
278 rtx_pair.ssrc = map.config().rtx_ssrc(); | |
279 rtx_pair.payload_type = map.config().rtx_payload_type(); | |
280 config->rtp.rtx.insert(std::make_pair(map.payload_type(), rtx_pair)); | |
281 } | |
282 // Get header extensions. | |
283 config->rtp.extensions.clear(); | |
284 for (int i = 0; i < receiver_config.header_extensions_size(); i++) { | |
285 RTC_CHECK(receiver_config.header_extensions(i).has_name()); | |
286 RTC_CHECK(receiver_config.header_extensions(i).has_id()); | |
287 const std::string& name = receiver_config.header_extensions(i).name(); | |
288 int id = receiver_config.header_extensions(i).id(); | |
289 config->rtp.extensions.push_back(RtpExtension(name, id)); | |
290 } | |
291 // Get decoders. | |
292 config->decoders.clear(); | |
293 for (int i = 0; i < receiver_config.decoders_size(); i++) { | |
294 RTC_CHECK(receiver_config.decoders(i).has_name()); | |
295 RTC_CHECK(receiver_config.decoders(i).has_payload_type()); | |
296 VideoReceiveStream::Decoder decoder; | |
297 decoder.payload_name = receiver_config.decoders(i).name(); | |
298 decoder.payload_type = receiver_config.decoders(i).payload_type(); | |
299 config->decoders.push_back(decoder); | |
300 } | |
301 } | |
302 | |
303 void ParsedRtcEventLog::GetVideoSendConfig( | |
304 size_t index, | |
305 VideoSendStream::Config* config) const { | |
306 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
307 const rtclog::Event& event = stream_[index]; | |
308 RTC_CHECK(config != nullptr); | |
309 RTC_CHECK(event.has_type()); | |
310 RTC_CHECK_EQ(event.type(), rtclog::Event::VIDEO_SENDER_CONFIG_EVENT); | |
311 RTC_CHECK(event.has_video_sender_config()); | |
312 const rtclog::VideoSendConfig& sender_config = event.video_sender_config(); | |
313 // Get SSRCs. | |
314 config->rtp.ssrcs.clear(); | |
315 for (int i = 0; i < sender_config.ssrcs_size(); i++) { | |
316 config->rtp.ssrcs.push_back(sender_config.ssrcs(i)); | |
317 } | |
318 // Get header extensions. | |
319 config->rtp.extensions.clear(); | |
320 for (int i = 0; i < sender_config.header_extensions_size(); i++) { | |
321 RTC_CHECK(sender_config.header_extensions(i).has_name()); | |
322 RTC_CHECK(sender_config.header_extensions(i).has_id()); | |
323 const std::string& name = sender_config.header_extensions(i).name(); | |
324 int id = sender_config.header_extensions(i).id(); | |
325 config->rtp.extensions.push_back(RtpExtension(name, id)); | |
326 } | |
327 // Get RTX settings. | |
328 config->rtp.rtx.ssrcs.clear(); | |
329 for (int i = 0; i < sender_config.rtx_ssrcs_size(); i++) { | |
330 config->rtp.rtx.ssrcs.push_back(sender_config.rtx_ssrcs(i)); | |
331 } | |
332 if (sender_config.rtx_ssrcs_size() > 0) { | |
333 RTC_CHECK(sender_config.has_rtx_payload_type()); | |
334 config->rtp.rtx.payload_type = sender_config.rtx_payload_type(); | |
335 } else { | |
336 // Reset RTX payload type default value if no RTX SSRCs are used. | |
337 config->rtp.rtx.payload_type = -1; | |
338 } | |
339 // Get encoder. | |
340 RTC_CHECK(sender_config.has_encoder()); | |
341 RTC_CHECK(sender_config.encoder().has_name()); | |
342 RTC_CHECK(sender_config.encoder().has_payload_type()); | |
343 config->encoder_settings.payload_name = sender_config.encoder().name(); | |
344 config->encoder_settings.payload_type = | |
345 sender_config.encoder().payload_type(); | |
346 } | |
347 | |
348 void ParsedRtcEventLog::GetAudioPlayout(size_t index, uint32_t* ssrc) const { | |
349 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
350 const rtclog::Event& event = stream_[index]; | |
351 RTC_CHECK(event.has_type()); | |
352 RTC_CHECK_EQ(event.type(), rtclog::Event::AUDIO_PLAYOUT_EVENT); | |
353 RTC_CHECK(event.has_audio_playout_event()); | |
354 const rtclog::AudioPlayoutEvent& loss_event = event.audio_playout_event(); | |
355 RTC_CHECK(loss_event.has_local_ssrc()); | |
356 if (ssrc != nullptr) | |
357 *ssrc = loss_event.local_ssrc(); | |
358 } | |
359 | |
360 void ParsedRtcEventLog::GetBwePacketLossEvent(size_t index, | |
361 int32_t* bitrate, | |
362 uint8_t* fraction_loss, | |
363 int32_t* total_packets) const { | |
364 RTC_CHECK_LT(index, GetNumberOfEvents()); | |
365 const rtclog::Event& event = stream_[index]; | |
366 RTC_CHECK(event.has_type()); | |
367 RTC_CHECK_EQ(event.type(), rtclog::Event::BWE_PACKET_LOSS_EVENT); | |
368 RTC_CHECK(event.has_bwe_packet_loss_event()); | |
369 const rtclog::BwePacketLossEvent& loss_event = event.bwe_packet_loss_event(); | |
370 RTC_CHECK(loss_event.has_bitrate()); | |
371 if (bitrate != nullptr) | |
372 *bitrate = loss_event.bitrate(); | |
373 RTC_CHECK(loss_event.has_fraction_loss()); | |
374 if (fraction_loss != nullptr) | |
375 *fraction_loss = loss_event.fraction_loss(); | |
376 RTC_CHECK(loss_event.has_total_packets()); | |
377 if (total_packets != nullptr) | |
378 *total_packets = loss_event.total_packets(); | |
379 } | |
380 | |
381 } // namespace webrtc | |
OLD | NEW |