OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | |
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 #ifdef ENABLE_RTC_EVENT_LOG | |
12 | |
13 #include <stdio.h> | |
14 #include <string> | |
15 #include <vector> | |
16 | |
17 #include "testing/gtest/include/gtest/gtest.h" | |
18 #include "webrtc/base/buffer.h" | |
19 #include "webrtc/base/checks.h" | |
20 #include "webrtc/base/scoped_ptr.h" | |
21 #include "webrtc/call.h" | |
22 #include "webrtc/modules/rtp_rtcp/source/rtp_sender.h" | |
23 #include "webrtc/system_wrappers/interface/clock.h" | |
24 #include "webrtc/test/test_suite.h" | |
25 #include "webrtc/test/testsupport/fileutils.h" | |
26 #include "webrtc/test/testsupport/gtest_disable.h" | |
27 #include "webrtc/video/rtc_event_log.h" | |
28 | |
29 // Files generated at build-time by the protobuf compiler. | |
30 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD | |
31 #include "external/webrtc/webrtc/video/rtc_event_log.pb.h" | |
32 #else | |
33 #include "webrtc/video/rtc_event_log.pb.h" | |
34 #endif | |
35 | |
36 namespace webrtc { | |
37 | |
38 namespace { | |
39 | |
40 const RTPExtensionType kExtensionTypes[] = { | |
41 RTPExtensionType::kRtpExtensionTransmissionTimeOffset, | |
42 RTPExtensionType::kRtpExtensionAudioLevel, | |
43 RTPExtensionType::kRtpExtensionAbsoluteSendTime, | |
44 RTPExtensionType::kRtpExtensionVideoRotation, | |
45 RTPExtensionType::kRtpExtensionTransportSequenceNumber}; | |
46 const char* kExtensionNames[] = {RtpExtension::kTOffset, | |
47 RtpExtension::kAudioLevel, | |
48 RtpExtension::kAbsSendTime, | |
49 RtpExtension::kVideoRotation, | |
50 RtpExtension::kTransportSequenceNumber}; | |
51 const size_t kNumExtensions = 5; | |
52 | |
53 } // namepsace | |
54 | |
55 // TODO(terelius): Place this definition with other parsing functions? | |
56 MediaType GetRuntimeMediaType(rtclog::MediaType media_type) { | |
57 switch (media_type) { | |
58 case rtclog::MediaType::ANY: | |
59 return MediaType::ANY; | |
60 case rtclog::MediaType::AUDIO: | |
61 return MediaType::AUDIO; | |
62 case rtclog::MediaType::VIDEO: | |
63 return MediaType::VIDEO; | |
64 case rtclog::MediaType::DATA: | |
65 return MediaType::DATA; | |
66 } | |
67 RTC_NOTREACHED(); | |
68 return MediaType::ANY; | |
69 } | |
70 | |
71 // Checks that the event has a timestamp, a type and exactly the data field | |
72 // corresponding to the type. | |
73 ::testing::AssertionResult IsValidBasicEvent(const rtclog::Event& event) { | |
74 if (!event.has_timestamp_us()) | |
75 return ::testing::AssertionFailure() << "Event has no timestamp"; | |
76 if (!event.has_type()) | |
77 return ::testing::AssertionFailure() << "Event has no event type"; | |
78 rtclog::Event_EventType type = event.type(); | |
79 if ((type == rtclog::Event::RTP_EVENT) != event.has_rtp_packet()) | |
80 return ::testing::AssertionFailure() | |
81 << "Event of type " << type << " has " | |
82 << (event.has_rtp_packet() ? "" : "no ") << "RTP packet"; | |
83 if ((type == rtclog::Event::RTCP_EVENT) != event.has_rtcp_packet()) | |
84 return ::testing::AssertionFailure() | |
85 << "Event of type " << type << " has " | |
86 << (event.has_rtcp_packet() ? "" : "no ") << "RTCP packet"; | |
87 if ((type == rtclog::Event::DEBUG_EVENT) != event.has_debug_event()) | |
88 return ::testing::AssertionFailure() | |
89 << "Event of type " << type << " has " | |
90 << (event.has_debug_event() ? "" : "no ") << "debug event"; | |
91 if ((type == rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT) != | |
92 event.has_video_receiver_config()) | |
93 return ::testing::AssertionFailure() | |
94 << "Event of type " << type << " has " | |
95 << (event.has_video_receiver_config() ? "" : "no ") | |
96 << "receiver config"; | |
97 if ((type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT) != | |
98 event.has_video_sender_config()) | |
99 return ::testing::AssertionFailure() | |
100 << "Event of type " << type << " has " | |
101 << (event.has_video_sender_config() ? "" : "no ") << "sender config"; | |
102 if ((type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT) != | |
103 event.has_audio_receiver_config()) { | |
104 return ::testing::AssertionFailure() | |
105 << "Event of type " << type << " has " | |
106 << (event.has_audio_receiver_config() ? "" : "no ") | |
107 << "audio receiver config"; | |
108 } | |
109 if ((type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT) != | |
110 event.has_audio_sender_config()) { | |
111 return ::testing::AssertionFailure() | |
112 << "Event of type " << type << " has " | |
113 << (event.has_audio_sender_config() ? "" : "no ") | |
114 << "audio sender config"; | |
115 } | |
116 return ::testing::AssertionSuccess(); | |
117 } | |
118 | |
119 void VerifyReceiveStreamConfig(const rtclog::Event& event, | |
120 const VideoReceiveStream::Config& config) { | |
121 ASSERT_TRUE(IsValidBasicEvent(event)); | |
122 ASSERT_EQ(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT, event.type()); | |
123 const rtclog::VideoReceiveConfig& receiver_config = | |
124 event.video_receiver_config(); | |
125 // Check SSRCs. | |
126 ASSERT_TRUE(receiver_config.has_remote_ssrc()); | |
127 EXPECT_EQ(config.rtp.remote_ssrc, receiver_config.remote_ssrc()); | |
128 ASSERT_TRUE(receiver_config.has_local_ssrc()); | |
129 EXPECT_EQ(config.rtp.local_ssrc, receiver_config.local_ssrc()); | |
130 // Check RTCP settings. | |
131 ASSERT_TRUE(receiver_config.has_rtcp_mode()); | |
132 if (config.rtp.rtcp_mode == newapi::kRtcpCompound) | |
133 EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_COMPOUND, | |
134 receiver_config.rtcp_mode()); | |
135 else | |
136 EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE, | |
137 receiver_config.rtcp_mode()); | |
138 ASSERT_TRUE(receiver_config.has_receiver_reference_time_report()); | |
139 EXPECT_EQ(config.rtp.rtcp_xr.receiver_reference_time_report, | |
140 receiver_config.receiver_reference_time_report()); | |
141 ASSERT_TRUE(receiver_config.has_remb()); | |
142 EXPECT_EQ(config.rtp.remb, receiver_config.remb()); | |
143 // Check RTX map. | |
144 ASSERT_EQ(static_cast<int>(config.rtp.rtx.size()), | |
145 receiver_config.rtx_map_size()); | |
146 for (const rtclog::RtxMap& rtx_map : receiver_config.rtx_map()) { | |
147 ASSERT_TRUE(rtx_map.has_payload_type()); | |
148 ASSERT_TRUE(rtx_map.has_config()); | |
149 EXPECT_EQ(1u, config.rtp.rtx.count(rtx_map.payload_type())); | |
150 const rtclog::RtxConfig& rtx_config = rtx_map.config(); | |
151 const VideoReceiveStream::Config::Rtp::Rtx& rtx = | |
152 config.rtp.rtx.at(rtx_map.payload_type()); | |
153 ASSERT_TRUE(rtx_config.has_rtx_ssrc()); | |
154 ASSERT_TRUE(rtx_config.has_rtx_payload_type()); | |
155 EXPECT_EQ(rtx.ssrc, rtx_config.rtx_ssrc()); | |
156 EXPECT_EQ(rtx.payload_type, rtx_config.rtx_payload_type()); | |
157 } | |
158 // Check header extensions. | |
159 ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()), | |
160 receiver_config.header_extensions_size()); | |
161 for (int i = 0; i < receiver_config.header_extensions_size(); i++) { | |
162 ASSERT_TRUE(receiver_config.header_extensions(i).has_name()); | |
163 ASSERT_TRUE(receiver_config.header_extensions(i).has_id()); | |
164 const std::string& name = receiver_config.header_extensions(i).name(); | |
165 int id = receiver_config.header_extensions(i).id(); | |
166 EXPECT_EQ(config.rtp.extensions[i].id, id); | |
167 EXPECT_EQ(config.rtp.extensions[i].name, name); | |
168 } | |
169 // Check decoders. | |
170 ASSERT_EQ(static_cast<int>(config.decoders.size()), | |
171 receiver_config.decoders_size()); | |
172 for (int i = 0; i < receiver_config.decoders_size(); i++) { | |
173 ASSERT_TRUE(receiver_config.decoders(i).has_name()); | |
174 ASSERT_TRUE(receiver_config.decoders(i).has_payload_type()); | |
175 const std::string& decoder_name = receiver_config.decoders(i).name(); | |
176 int decoder_type = receiver_config.decoders(i).payload_type(); | |
177 EXPECT_EQ(config.decoders[i].payload_name, decoder_name); | |
178 EXPECT_EQ(config.decoders[i].payload_type, decoder_type); | |
179 } | |
180 } | |
181 | |
182 void VerifySendStreamConfig(const rtclog::Event& event, | |
183 const VideoSendStream::Config& config) { | |
184 ASSERT_TRUE(IsValidBasicEvent(event)); | |
185 ASSERT_EQ(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT, event.type()); | |
186 const rtclog::VideoSendConfig& sender_config = event.video_sender_config(); | |
187 // Check SSRCs. | |
188 ASSERT_EQ(static_cast<int>(config.rtp.ssrcs.size()), | |
189 sender_config.ssrcs_size()); | |
190 for (int i = 0; i < sender_config.ssrcs_size(); i++) { | |
191 EXPECT_EQ(config.rtp.ssrcs[i], sender_config.ssrcs(i)); | |
192 } | |
193 // Check header extensions. | |
194 ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()), | |
195 sender_config.header_extensions_size()); | |
196 for (int i = 0; i < sender_config.header_extensions_size(); i++) { | |
197 ASSERT_TRUE(sender_config.header_extensions(i).has_name()); | |
198 ASSERT_TRUE(sender_config.header_extensions(i).has_id()); | |
199 const std::string& name = sender_config.header_extensions(i).name(); | |
200 int id = sender_config.header_extensions(i).id(); | |
201 EXPECT_EQ(config.rtp.extensions[i].id, id); | |
202 EXPECT_EQ(config.rtp.extensions[i].name, name); | |
203 } | |
204 // Check RTX settings. | |
205 ASSERT_EQ(static_cast<int>(config.rtp.rtx.ssrcs.size()), | |
206 sender_config.rtx_ssrcs_size()); | |
207 for (int i = 0; i < sender_config.rtx_ssrcs_size(); i++) { | |
208 EXPECT_EQ(config.rtp.rtx.ssrcs[i], sender_config.rtx_ssrcs(i)); | |
209 } | |
210 if (sender_config.rtx_ssrcs_size() > 0) { | |
211 ASSERT_TRUE(sender_config.has_rtx_payload_type()); | |
212 EXPECT_EQ(config.rtp.rtx.payload_type, sender_config.rtx_payload_type()); | |
213 } | |
214 // Check CNAME. | |
215 ASSERT_TRUE(sender_config.has_c_name()); | |
216 EXPECT_EQ(config.rtp.c_name, sender_config.c_name()); | |
217 // Check encoder. | |
218 ASSERT_TRUE(sender_config.has_encoder()); | |
219 ASSERT_TRUE(sender_config.encoder().has_name()); | |
220 ASSERT_TRUE(sender_config.encoder().has_payload_type()); | |
221 EXPECT_EQ(config.encoder_settings.payload_name, | |
222 sender_config.encoder().name()); | |
223 EXPECT_EQ(config.encoder_settings.payload_type, | |
224 sender_config.encoder().payload_type()); | |
225 } | |
226 | |
227 void VerifyRtpEvent(const rtclog::Event& event, | |
228 bool incoming, | |
229 MediaType media_type, | |
230 uint8_t* header, | |
231 size_t header_size, | |
232 size_t total_size) { | |
233 ASSERT_TRUE(IsValidBasicEvent(event)); | |
234 ASSERT_EQ(rtclog::Event::RTP_EVENT, event.type()); | |
235 const rtclog::RtpPacket& rtp_packet = event.rtp_packet(); | |
236 ASSERT_TRUE(rtp_packet.has_incoming()); | |
237 EXPECT_EQ(incoming, rtp_packet.incoming()); | |
238 ASSERT_TRUE(rtp_packet.has_type()); | |
239 EXPECT_EQ(media_type, GetRuntimeMediaType(rtp_packet.type())); | |
240 ASSERT_TRUE(rtp_packet.has_packet_length()); | |
241 EXPECT_EQ(total_size, rtp_packet.packet_length()); | |
242 ASSERT_TRUE(rtp_packet.has_header()); | |
243 ASSERT_EQ(header_size, rtp_packet.header().size()); | |
244 for (size_t i = 0; i < header_size; i++) { | |
245 EXPECT_EQ(header[i], static_cast<uint8_t>(rtp_packet.header()[i])); | |
246 } | |
247 } | |
248 | |
249 void VerifyRtcpEvent(const rtclog::Event& event, | |
250 bool incoming, | |
251 MediaType media_type, | |
252 uint8_t* packet, | |
253 size_t total_size) { | |
254 ASSERT_TRUE(IsValidBasicEvent(event)); | |
255 ASSERT_EQ(rtclog::Event::RTCP_EVENT, event.type()); | |
256 const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet(); | |
257 ASSERT_TRUE(rtcp_packet.has_incoming()); | |
258 EXPECT_EQ(incoming, rtcp_packet.incoming()); | |
259 ASSERT_TRUE(rtcp_packet.has_type()); | |
260 EXPECT_EQ(media_type, GetRuntimeMediaType(rtcp_packet.type())); | |
261 ASSERT_TRUE(rtcp_packet.has_packet_data()); | |
262 ASSERT_EQ(total_size, rtcp_packet.packet_data().size()); | |
263 for (size_t i = 0; i < total_size; i++) { | |
264 EXPECT_EQ(packet[i], static_cast<uint8_t>(rtcp_packet.packet_data()[i])); | |
265 } | |
266 } | |
267 | |
268 void VerifyPlayoutEvent(const rtclog::Event& event, uint32_t ssrc) { | |
269 ASSERT_TRUE(IsValidBasicEvent(event)); | |
270 ASSERT_EQ(rtclog::Event::DEBUG_EVENT, event.type()); | |
271 const rtclog::DebugEvent& debug_event = event.debug_event(); | |
272 ASSERT_TRUE(debug_event.has_type()); | |
273 EXPECT_EQ(rtclog::DebugEvent::AUDIO_PLAYOUT, debug_event.type()); | |
274 ASSERT_TRUE(debug_event.has_local_ssrc()); | |
275 EXPECT_EQ(ssrc, debug_event.local_ssrc()); | |
276 } | |
277 | |
278 void VerifyLogStartEvent(const rtclog::Event& event) { | |
279 ASSERT_TRUE(IsValidBasicEvent(event)); | |
280 ASSERT_EQ(rtclog::Event::DEBUG_EVENT, event.type()); | |
281 const rtclog::DebugEvent& debug_event = event.debug_event(); | |
282 ASSERT_TRUE(debug_event.has_type()); | |
283 EXPECT_EQ(rtclog::DebugEvent::LOG_START, debug_event.type()); | |
284 } | |
285 | |
286 /* | |
287 * Bit number i of extension_bitvector is set to indicate the | |
288 * presence of extension number i from kExtensionTypes / kExtensionNames. | |
289 * The least significant bit extension_bitvector has number 0. | |
290 */ | |
291 size_t GenerateRtpPacket(uint32_t extensions_bitvector, | |
292 uint32_t csrcs_count, | |
293 uint8_t* packet, | |
294 size_t packet_size) { | |
295 RTC_CHECK_GE(packet_size, 16 + 4 * csrcs_count + 4 * kNumExtensions); | |
296 Clock* clock = Clock::GetRealTimeClock(); | |
297 | |
298 RTPSender rtp_sender(false, // bool audio | |
299 clock, // Clock* clock | |
300 nullptr, // Transport* | |
301 nullptr, // RtpAudioFeedback* | |
302 nullptr, // PacedSender* | |
303 nullptr, // PacketRouter* | |
304 nullptr, // SendTimeObserver* | |
305 nullptr, // BitrateStatisticsObserver* | |
306 nullptr, // FrameCountObserver* | |
307 nullptr); // SendSideDelayObserver* | |
308 | |
309 std::vector<uint32_t> csrcs; | |
310 for (unsigned i = 0; i < csrcs_count; i++) { | |
311 csrcs.push_back(rand()); | |
312 } | |
313 rtp_sender.SetCsrcs(csrcs); | |
314 rtp_sender.SetSSRC(rand()); | |
315 rtp_sender.SetStartTimestamp(rand(), true); | |
316 rtp_sender.SetSequenceNumber(rand()); | |
317 | |
318 for (unsigned i = 0; i < kNumExtensions; i++) { | |
319 if (extensions_bitvector & (1u << i)) { | |
320 rtp_sender.RegisterRtpHeaderExtension(kExtensionTypes[i], i + 1); | |
321 } | |
322 } | |
323 | |
324 int8_t payload_type = rand() % 128; | |
325 bool marker_bit = (rand() % 2 == 1); | |
326 uint32_t capture_timestamp = rand(); | |
327 int64_t capture_time_ms = rand(); | |
328 bool timestamp_provided = (rand() % 2 == 1); | |
329 bool inc_sequence_number = (rand() % 2 == 1); | |
330 | |
331 size_t header_size = rtp_sender.BuildRTPheader( | |
332 packet, payload_type, marker_bit, capture_timestamp, capture_time_ms, | |
333 timestamp_provided, inc_sequence_number); | |
334 | |
335 for (size_t i = header_size; i < packet_size; i++) { | |
336 packet[i] = rand(); | |
337 } | |
338 | |
339 return header_size; | |
340 } | |
341 | |
342 void GenerateRtcpPacket(uint8_t* packet, size_t packet_size) { | |
343 for (size_t i = 0; i < packet_size; i++) { | |
344 packet[i] = rand(); | |
345 } | |
346 } | |
347 | |
348 void GenerateVideoReceiveConfig(uint32_t extensions_bitvector, | |
349 VideoReceiveStream::Config* config) { | |
350 // Create a map from a payload type to an encoder name. | |
351 VideoReceiveStream::Decoder decoder; | |
352 decoder.payload_type = rand(); | |
353 decoder.payload_name = (rand() % 2 ? "VP8" : "H264"); | |
354 config->decoders.push_back(decoder); | |
355 // Add SSRCs for the stream. | |
356 config->rtp.remote_ssrc = rand(); | |
357 config->rtp.local_ssrc = rand(); | |
358 // Add extensions and settings for RTCP. | |
359 config->rtp.rtcp_mode = rand() % 2 ? newapi::kRtcpCompound | |
360 : newapi::kRtcpReducedSize; | |
361 config->rtp.rtcp_xr.receiver_reference_time_report = (rand() % 2 == 1); | |
362 config->rtp.remb = (rand() % 2 == 1); | |
363 // Add a map from a payload type to a new ssrc and a new payload type for RTX. | |
364 VideoReceiveStream::Config::Rtp::Rtx rtx_pair; | |
365 rtx_pair.ssrc = rand(); | |
366 rtx_pair.payload_type = rand(); | |
367 config->rtp.rtx.insert(std::make_pair(rand(), rtx_pair)); | |
368 // Add header extensions. | |
369 for (unsigned i = 0; i < kNumExtensions; i++) { | |
370 if (extensions_bitvector & (1u << i)) { | |
371 config->rtp.extensions.push_back( | |
372 RtpExtension(kExtensionNames[i], rand())); | |
373 } | |
374 } | |
375 } | |
376 | |
377 void GenerateVideoSendConfig(uint32_t extensions_bitvector, | |
378 VideoSendStream::Config* config) { | |
379 // Create a map from a payload type to an encoder name. | |
380 config->encoder_settings.payload_type = rand(); | |
381 config->encoder_settings.payload_name = (rand() % 2 ? "VP8" : "H264"); | |
382 // Add SSRCs for the stream. | |
383 config->rtp.ssrcs.push_back(rand()); | |
384 // Add a map from a payload type to new ssrcs and a new payload type for RTX. | |
385 config->rtp.rtx.ssrcs.push_back(rand()); | |
386 config->rtp.rtx.payload_type = rand(); | |
387 // Add a CNAME. | |
388 config->rtp.c_name = "some.user@some.host"; | |
389 // Add header extensions. | |
390 for (unsigned i = 0; i < kNumExtensions; i++) { | |
391 if (extensions_bitvector & (1u << i)) { | |
392 config->rtp.extensions.push_back( | |
393 RtpExtension(kExtensionNames[i], rand())); | |
394 } | |
395 } | |
396 } | |
397 | |
398 // Test for the RtcEventLog class. Dumps some RTP packets to disk, then reads | |
399 // them back to see if they match. | |
400 void LogSessionAndReadBack(size_t rtp_count, | |
401 size_t rtcp_count, | |
402 size_t debug_count, | |
403 uint32_t extensions_bitvector, | |
404 uint32_t csrcs_count, | |
405 unsigned random_seed) { | |
406 ASSERT_LE(rtcp_count, rtp_count); | |
407 ASSERT_LE(debug_count, rtp_count); | |
408 std::vector<rtc::Buffer> rtp_packets; | |
409 std::vector<rtc::Buffer> rtcp_packets; | |
410 std::vector<size_t> rtp_header_sizes; | |
411 std::vector<uint32_t> playout_ssrcs; | |
412 | |
413 VideoReceiveStream::Config receiver_config(nullptr); | |
414 VideoSendStream::Config sender_config(nullptr); | |
415 | |
416 srand(random_seed); | |
417 | |
418 // Create rtp_count RTP packets containing random data. | |
419 for (size_t i = 0; i < rtp_count; i++) { | |
420 size_t packet_size = 1000 + rand() % 64; | |
421 rtp_packets.push_back(rtc::Buffer(packet_size)); | |
422 size_t header_size = GenerateRtpPacket(extensions_bitvector, csrcs_count, | |
423 rtp_packets[i].data(), packet_size); | |
424 rtp_header_sizes.push_back(header_size); | |
425 } | |
426 // Create rtcp_count RTCP packets containing random data. | |
427 for (size_t i = 0; i < rtcp_count; i++) { | |
428 size_t packet_size = 1000 + rand() % 64; | |
429 rtcp_packets.push_back(rtc::Buffer(packet_size)); | |
430 GenerateRtcpPacket(rtcp_packets[i].data(), packet_size); | |
431 } | |
432 // Create debug_count random SSRCs to use when logging AudioPlayout events. | |
433 for (size_t i = 0; i < debug_count; i++) { | |
434 playout_ssrcs.push_back(static_cast<uint32_t>(rand())); | |
435 } | |
436 // Create configurations for the video streams. | |
437 GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config); | |
438 GenerateVideoSendConfig(extensions_bitvector, &sender_config); | |
439 const int config_count = 2; | |
440 | |
441 // Find the name of the current test, in order to use it as a temporary | |
442 // filename. | |
443 auto test_info = ::testing::UnitTest::GetInstance()->current_test_info(); | |
444 const std::string temp_filename = | |
445 test::OutputPath() + test_info->test_case_name() + test_info->name(); | |
446 | |
447 // When log_dumper goes out of scope, it causes the log file to be flushed | |
448 // to disk. | |
449 { | |
450 rtc::scoped_ptr<RtcEventLog> log_dumper(RtcEventLog::Create()); | |
451 log_dumper->LogVideoReceiveStreamConfig(receiver_config); | |
452 log_dumper->LogVideoSendStreamConfig(sender_config); | |
453 size_t rtcp_index = 1, debug_index = 1; | |
454 for (size_t i = 1; i <= rtp_count; i++) { | |
455 log_dumper->LogRtpHeader( | |
456 (i % 2 == 0), // Every second packet is incoming. | |
457 (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO, | |
458 rtp_packets[i - 1].data(), rtp_packets[i - 1].size()); | |
459 if (i * rtcp_count >= rtcp_index * rtp_count) { | |
460 log_dumper->LogRtcpPacket( | |
461 rtcp_index % 2 == 0, // Every second packet is incoming | |
462 rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO, | |
463 rtcp_packets[rtcp_index - 1].data(), | |
464 rtcp_packets[rtcp_index - 1].size()); | |
465 rtcp_index++; | |
466 } | |
467 if (i * debug_count >= debug_index * rtp_count) { | |
468 log_dumper->LogAudioPlayout(playout_ssrcs[debug_index - 1]); | |
469 debug_index++; | |
470 } | |
471 if (i == rtp_count / 2) { | |
472 log_dumper->StartLogging(temp_filename, 10000000); | |
473 } | |
474 } | |
475 } | |
476 | |
477 // Read the generated file from disk. | |
478 rtclog::EventStream parsed_stream; | |
479 | |
480 ASSERT_TRUE(RtcEventLog::ParseRtcEventLog(temp_filename, &parsed_stream)); | |
481 | |
482 // Verify the result. | |
483 const int event_count = | |
484 config_count + debug_count + rtcp_count + rtp_count + 1; | |
485 EXPECT_EQ(event_count, parsed_stream.stream_size()); | |
486 VerifyReceiveStreamConfig(parsed_stream.stream(0), receiver_config); | |
487 VerifySendStreamConfig(parsed_stream.stream(1), sender_config); | |
488 size_t event_index = config_count, rtcp_index = 1, debug_index = 1; | |
489 for (size_t i = 1; i <= rtp_count; i++) { | |
490 VerifyRtpEvent(parsed_stream.stream(event_index), | |
491 (i % 2 == 0), // Every second packet is incoming. | |
492 (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO, | |
493 rtp_packets[i - 1].data(), rtp_header_sizes[i - 1], | |
494 rtp_packets[i - 1].size()); | |
495 event_index++; | |
496 if (i * rtcp_count >= rtcp_index * rtp_count) { | |
497 VerifyRtcpEvent(parsed_stream.stream(event_index), | |
498 rtcp_index % 2 == 0, // Every second packet is incoming. | |
499 rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO, | |
500 rtcp_packets[rtcp_index - 1].data(), | |
501 rtcp_packets[rtcp_index - 1].size()); | |
502 event_index++; | |
503 rtcp_index++; | |
504 } | |
505 if (i * debug_count >= debug_index * rtp_count) { | |
506 VerifyPlayoutEvent(parsed_stream.stream(event_index), | |
507 playout_ssrcs[debug_index - 1]); | |
508 event_index++; | |
509 debug_index++; | |
510 } | |
511 if (i == rtp_count / 2) { | |
512 VerifyLogStartEvent(parsed_stream.stream(event_index)); | |
513 event_index++; | |
514 } | |
515 } | |
516 | |
517 // Clean up temporary file - can be pretty slow. | |
518 remove(temp_filename.c_str()); | |
519 } | |
520 | |
521 TEST(RtcEventLogTest, LogSessionAndReadBack) { | |
522 // Log 5 RTP, 2 RTCP, and 0 playout events with no header extensions or CSRCS. | |
523 LogSessionAndReadBack(5, 2, 0, 0, 0, 321); | |
524 | |
525 // Enable AbsSendTime and TransportSequenceNumbers | |
526 uint32_t extensions = 0; | |
527 for (uint32_t i = 0; i < kNumExtensions; i++) { | |
528 if (kExtensionTypes[i] == RTPExtensionType::kRtpExtensionAbsoluteSendTime || | |
529 kExtensionTypes[i] == | |
530 RTPExtensionType::kRtpExtensionTransportSequenceNumber) { | |
531 extensions |= 1u << i; | |
532 } | |
533 } | |
534 LogSessionAndReadBack(8, 2, 0, extensions, 0, 3141592653u); | |
535 | |
536 extensions = (1u << kNumExtensions) - 1; // Enable all header extensions | |
537 LogSessionAndReadBack(9, 2, 3, extensions, 2, 2718281828u); | |
538 | |
539 // Try all combinations of header extensions and up to 2 CSRCS. | |
540 for (extensions = 0; extensions < (1u << kNumExtensions); extensions++) { | |
541 for (uint32_t csrcs_count = 0; csrcs_count < 3; csrcs_count++) { | |
542 LogSessionAndReadBack(5 + extensions, // Number of RTP packets. | |
543 2 + csrcs_count, // Number of RTCP packets. | |
544 3 + csrcs_count, // Number of playout events | |
545 extensions, // Bit vector choosing extensions | |
546 csrcs_count, // Number of contributing sources | |
547 rand()); | |
548 } | |
549 } | |
550 } | |
551 | |
552 } // namespace webrtc | |
553 | |
554 #endif // ENABLE_RTC_EVENT_LOG | |
OLD | NEW |