Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(171)

Side by Side Diff: webrtc/video/rtc_event_log_unittest.cc

Issue 1230973005: Adds logging of configuration information for VideoReceiveStream (Closed) Base URL: https://chromium.googlesource.com/external/webrtc.git@master
Patch Set: Added silly return values in unreachable path. Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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/scoped_ptr.h"
19 #include "webrtc/video/rtc_event_log.h"
ivoc 2015/07/17 12:14:29 Could you sort these alphabetically?
terelius 2015/07/17 15:17:40 Done.
20 #include "webrtc/system_wrappers/interface/clock.h"
21 #include "webrtc/test/test_suite.h"
22 #include "webrtc/test/testsupport/fileutils.h"
23 #include "webrtc/test/testsupport/gtest_disable.h"
24
25 // Files generated at build-time by the protobuf compiler.
26 #ifdef WEBRTC_ANDROID_PLATFORM_BUILD
27 #include "external/webrtc/webrtc/video/rtc_event_log.pb.h"
28 #else
29 #include "webrtc/video/rtc_event_log.pb.h"
30 #endif
31
32 namespace webrtc {
33
34 // Checks that the event has a timestamp, a type and exactly the data field
35 // corresponding to the type.
36 ::testing::AssertionResult IsValidBasicEvent(const RelEvent& event) {
37 if (!event.has_timestamp_us())
38 return ::testing::AssertionFailure() << "Event has no timestamp";
39 if (!event.has_type())
40 return ::testing::AssertionFailure() << "Event has no event type";
41 RelEvent_EventType type = event.type();
42 if ((type == RelEvent::RTP_EVENT) != event.has_rtp_packet())
43 return ::testing::AssertionFailure() << "Event of type" << type
44 << "has" << (event.has_rtp_packet()?"":"no") << "RTP packet";
ivoc 2015/07/17 12:14:29 I wonder how this error message would look. It see
terelius 2015/07/17 15:17:40 You're right about the spaces. I'll fix that. We
45 if ((type == RelEvent::RTCP_EVENT) != event.has_rtcp_packet())
46 return ::testing::AssertionFailure() << "Event of type" << type
47 << "has" << (event.has_rtcp_packet()?"":"no") << "RTCP packet";
48 if ((type == RelEvent::DEBUG_EVENT) != event.has_debug_event())
49 return ::testing::AssertionFailure() << "Event of type" << type
50 << "has" << (event.has_debug_event()?"":"no") << "debug event";
51 if ((type == RelEvent::RECEIVER_CONFIG_EVENT) != event.has_receiver_config())
52 return ::testing::AssertionFailure() << "Event of type" << type
53 << "has" << (event.has_receiver_config()?"":"no") << "receiver config";
54 if ((type == RelEvent::SENDER_CONFIG_EVENT) != event.has_sender_config())
55 return ::testing::AssertionFailure() << "Event of type" << type
56 << "has" << (event.has_sender_config()?"":"no") << "sender config";
57 if ((type == RelEvent::AUDIO_RECEIVER_CONFIG_EVENT)
58 != event.has_audio_receiver_config()) {
59 return ::testing::AssertionFailure() << "Event of type" << type
60 << "has" << (event.has_audio_receiver_config()?"":"no")
61 << "audio receiver config";
62 }
63 if ((type == RelEvent::AUDIO_SENDER_CONFIG_EVENT)
64 != event.has_audio_sender_config()) {
65 return ::testing::AssertionFailure() << "Event of type" << type
66 << "has" << (event.has_audio_sender_config()?"":"no")
67 << "audio sender config";
68 }
69 return ::testing::AssertionSuccess();
70 }
71
72 void VerifyReceiveStreamConfig(const RelEvent& event,
73 const VideoReceiveStream::Config& config) {
74 ASSERT_TRUE(IsValidBasicEvent(event));
75 ASSERT_EQ(RelEvent::RECEIVER_CONFIG_EVENT, event.type());
76 const RelVideoReceiveConfig& receiver_config = event.receiver_config();
77 // Check SSRCs.
78 ASSERT_TRUE(receiver_config.has_remote_ssrc());
79 EXPECT_EQ(config.rtp.remote_ssrc, receiver_config.remote_ssrc());
80 ASSERT_TRUE(receiver_config.has_local_ssrc());
81 EXPECT_EQ(config.rtp.local_ssrc, receiver_config.local_ssrc());
82 // Check RTCP settings.
83 ASSERT_TRUE(receiver_config.has_rtcp_mode());
84 if (config.rtp.rtcp_mode == newapi::kRtcpCompound)
85 EXPECT_EQ(RelVideoReceiveConfig::RTCP_COMPOUND,
86 receiver_config.rtcp_mode());
87 else
88 EXPECT_EQ(RelVideoReceiveConfig::RTCP_REDUCEDSIZE,
89 receiver_config.rtcp_mode());
90 ASSERT_TRUE(receiver_config.has_receiver_reference_time_report());
91 EXPECT_EQ(config.rtp.rtcp_xr.receiver_reference_time_report,
92 receiver_config.receiver_reference_time_report());
93 ASSERT_TRUE(receiver_config.has_remb());
94 EXPECT_EQ(config.rtp.remb, receiver_config.remb());
95 // Check RTX map.
96 ASSERT_EQ(static_cast<int>(config.rtp.rtx.size()),
97 receiver_config.rtx_map_size());
98 for (int i = 0; i < receiver_config.rtx_map_size(); i++) {
99 const RtxMap& mapping = receiver_config.rtx_map(i);
100 ASSERT_TRUE(mapping.has_payload_type());
101 ASSERT_TRUE(mapping.has_config());
102 EXPECT_EQ(1,
103 static_cast<int>(config.rtp.rtx.count(mapping.payload_type())));
104 const RtxConfig& rtx_config = mapping.config();
105 const VideoReceiveStream::Config::Rtp::Rtx& rtx =
106 config.rtp.rtx.at(mapping.payload_type());
107 ASSERT_TRUE(rtx_config.has_rtx_ssrc());
108 ASSERT_TRUE(rtx_config.has_rtx_payload_type());
109 EXPECT_EQ(rtx.ssrc, rtx_config.rtx_ssrc());
110 EXPECT_EQ(rtx.payload_type, rtx_config.rtx_payload_type());
111 }
112 // Check header extensions.
113 ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
114 receiver_config.header_extensions_size());
115 for (int i = 0; i < receiver_config.header_extensions_size(); i++) {
116 ASSERT_TRUE(receiver_config.header_extensions(i).has_name());
117 ASSERT_TRUE(receiver_config.header_extensions(i).has_id());
118 const std::string& name = receiver_config.header_extensions(i).name();
119 int id = receiver_config.header_extensions(i).id();
120 EXPECT_EQ(config.rtp.extensions[i].id, id);
121 EXPECT_EQ(config.rtp.extensions[i].name, name);
122 }
123 // Check decoders.
124 ASSERT_EQ(static_cast<int>(config.decoders.size()),
125 receiver_config.decoders_size());
126 for (int i = 0; i < receiver_config.decoders_size(); i++) {
127 ASSERT_TRUE(receiver_config.decoders(i).has_name());
128 ASSERT_TRUE(receiver_config.decoders(i).has_payload_type());
129 const std::string& decoder_name = receiver_config.decoders(i).name();
130 int decoder_type = receiver_config.decoders(i).payload_type();
131 EXPECT_EQ(config.decoders[i].payload_name, decoder_name);
132 EXPECT_EQ(config.decoders[i].payload_type, decoder_type);
133 }
134 }
135
136 void VerifySendStreamConfig(const RelEvent& event,
137 const VideoSendStream::Config& config) {
138 ASSERT_TRUE(IsValidBasicEvent(event));
139 ASSERT_EQ(RelEvent::SENDER_CONFIG_EVENT, event.type());
140 const RelVideoSendConfig& sender_config = event.sender_config();
141 // Check SSRCs.
142 ASSERT_EQ(static_cast<int>(config.rtp.ssrcs.size()),
143 sender_config.ssrcs_size());
144 for (int i = 0; i < sender_config.ssrcs_size(); i++) {
145 EXPECT_EQ(config.rtp.ssrcs[i], sender_config.ssrcs(i));
146 }
147 // Check header extensions.
148 ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
149 sender_config.header_extensions_size());
150 for (int i = 0; i < sender_config.header_extensions_size(); i++) {
151 ASSERT_TRUE(sender_config.header_extensions(i).has_name());
152 ASSERT_TRUE(sender_config.header_extensions(i).has_id());
153 const std::string& name = sender_config.header_extensions(i).name();
154 int id = sender_config.header_extensions(i).id();
155 EXPECT_EQ(config.rtp.extensions[i].id, id);
156 EXPECT_EQ(config.rtp.extensions[i].name, name);
157 }
158 // Check RTX settings.
159 ASSERT_EQ(static_cast<int>(config.rtp.rtx.ssrcs.size()),
160 sender_config.rtx_ssrcs_size());
161 for (int i = 0; i < sender_config.rtx_ssrcs_size(); i++) {
162 EXPECT_EQ(config.rtp.rtx.ssrcs[i], sender_config.rtx_ssrcs(i));
163 }
164 if (sender_config.rtx_ssrcs_size() > 0) {
165 ASSERT_TRUE(sender_config.has_rtx_payload_type());
166 EXPECT_EQ(config.rtp.rtx.payload_type, sender_config.rtx_payload_type());
167 }
168 // Check CNAME.
169 ASSERT_TRUE(sender_config.has_c_name());
170 EXPECT_EQ(config.rtp.c_name, sender_config.c_name());
171 // Check encoder.
172 ASSERT_TRUE(sender_config.has_encoder());
173 ASSERT_TRUE(sender_config.encoder().has_name());
174 ASSERT_TRUE(sender_config.encoder().has_payload_type());
175 EXPECT_EQ(config.encoder_settings.payload_name,
176 sender_config.encoder().name());
177 EXPECT_EQ(config.encoder_settings.payload_type,
178 sender_config.encoder().payload_type());
179 }
180
181 void VerifyRtpEvent(const RelEvent& event,
182 bool incoming,
183 MediaType media_type,
184 uint8_t* header,
185 size_t header_size,
186 size_t total_size) {
187 ASSERT_TRUE(IsValidBasicEvent(event));
188 ASSERT_EQ(RelEvent::RTP_EVENT, event.type());
189 const RelRtpPacket& rtp_packet = event.rtp_packet();
190 ASSERT_TRUE(rtp_packet.has_direction());
191 EXPECT_EQ(incoming ? RelRtpPacket::INCOMING : RelRtpPacket::OUTGOING,
192 rtp_packet.direction());
193 ASSERT_TRUE(rtp_packet.has_type());
194 if (media_type == MediaType::VIDEO)
195 EXPECT_EQ(RelRtpPacket::VIDEO, rtp_packet.type());
196 else if (media_type == MediaType::AUDIO)
197 EXPECT_EQ(RelRtpPacket::AUDIO, rtp_packet.type());
198 else
199 EXPECT_EQ(RelRtpPacket::UNKNOWN_TYPE, rtp_packet.type());
200 ASSERT_TRUE(rtp_packet.has_packet_length());
201 EXPECT_EQ(total_size, rtp_packet.packet_length());
202 ASSERT_TRUE(rtp_packet.has_header());
203 ASSERT_EQ(header_size, rtp_packet.header().size());
204 for (size_t i = 0; i < header_size; i++) {
205 EXPECT_EQ(header[i], static_cast<uint8_t>(rtp_packet.header()[i]));
206 }
207 }
208
209 void VerifyRtcpEvent(const RelEvent& event,
210 bool incoming,
211 MediaType media_type,
212 uint8_t* packet,
213 size_t total_size) {
214 ASSERT_TRUE(IsValidBasicEvent(event));
215 ASSERT_EQ(RelEvent::RTCP_EVENT, event.type());
216 const RelRtcpPacket& rtcp_packet = event.rtcp_packet();
217 ASSERT_TRUE(rtcp_packet.has_direction());
218 EXPECT_EQ(incoming ? RelRtcpPacket::INCOMING : RelRtcpPacket::OUTGOING,
219 rtcp_packet.direction());
220 ASSERT_TRUE(rtcp_packet.has_type());
221 if (media_type == MediaType::VIDEO)
222 EXPECT_EQ(RelRtcpPacket::VIDEO, rtcp_packet.type());
223 else if (media_type == MediaType::AUDIO)
224 EXPECT_EQ(RelRtcpPacket::AUDIO, rtcp_packet.type());
225 else
226 EXPECT_EQ(RelRtcpPacket::UNKNOWN_TYPE, rtcp_packet.type());
227 ASSERT_TRUE(rtcp_packet.has_data());
228 ASSERT_EQ(total_size, rtcp_packet.data().size());
229 for (size_t i = 0; i < total_size; i++) {
230 EXPECT_EQ(packet[i], static_cast<uint8_t>(rtcp_packet.data()[i]));
231 }
232 }
233
234 void VerifyLogStartEvent(const RelEvent& event) {
235 ASSERT_TRUE(IsValidBasicEvent(event));
236 ASSERT_EQ(RelEvent::DEBUG_EVENT, event.type());
237 const RelDebugEvent& debug_event = event.debug_event();
238 ASSERT_TRUE(debug_event.has_type());
239 EXPECT_EQ(RelDebugEvent::LOG_START, debug_event.type());
240 // TODO(terelius): Deliberately not verifying that there is a message field
241 // since our protobuf file says that the message is optional. Make a decision.
242 }
243
244 void GenerateVideoReceiveConfig(webrtc::VideoReceiveStream::Config* config) {
245 // Create a map from a payload type to an encoder name.
246 VideoReceiveStream::Decoder decoder;
247 decoder.payload_type = rand();
248 decoder.payload_name = (rand() % 2 ? "VP8" : "H264");
249 config->decoders.push_back(decoder);
250 // Add SSRCs for the stream.
251 config->rtp.remote_ssrc = rand();
252 config->rtp.local_ssrc = rand();
253 // Add extensions and settings for RTCP.
254 config->rtp.rtcp_mode = rand() % 2 ? newapi::kRtcpCompound
255 : newapi::kRtcpReducedSize;
256 config->rtp.rtcp_xr.receiver_reference_time_report =
257 static_cast<bool>(rand() % 2);
258 config->rtp.remb = static_cast<bool>(rand() % 2);
259 // Add a map from a payload type to a new ssrc and a new payload type for RTX.
260 webrtc::VideoReceiveStream::Config::Rtp::Rtx rtx_pair;
261 rtx_pair.ssrc = rand();
262 rtx_pair.payload_type = rand();
263 config->rtp.rtx.insert(std::make_pair(rand(), rtx_pair));
264 // Add two random header extensions.
265 const char* extension_name = rand() % 2 ? RtpExtension::kTOffset
266 : RtpExtension::kVideoRotation;
267 config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
268 extension_name = rand() % 2 ? RtpExtension::kAudioLevel
269 : RtpExtension::kAbsSendTime;
270 config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
271 }
272
273 void GenerateVideoSendConfig(webrtc::VideoSendStream::Config* config) {
274 // Create a map from a payload type to an encoder name.
275 config->encoder_settings.payload_type = rand();
276 config->encoder_settings.payload_name = (rand() % 2 ? "VP8" : "H264");
277 // Add SSRCs for the stream.
278 config->rtp.ssrcs.push_back(rand());
279 // Add a map from a payload type to new ssrcs and a new payload type for RTX.
280 config->rtp.rtx.ssrcs.push_back(rand());
281 config->rtp.rtx.payload_type = rand();
282 // Add a CNAME.
283 config->rtp.c_name = "some.user@some.host";
284 // Add two random header extensions.
285 const char* extension_name = rand() % 2 ? RtpExtension::kTOffset
286 : RtpExtension::kVideoRotation;
287 config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
288 extension_name = rand() % 2 ? RtpExtension::kAudioLevel
289 : RtpExtension::kAbsSendTime;
290 config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
291 }
292
293 // Test for the RtcEventLog class. Dumps some RTP packets to disk, then reads
294 // them back to see if they match.
295 void LogSessionAndReadBack(size_t rtp_count, unsigned random_seed) {
296 std::vector<std::vector<uint8_t>> rtp_packets;
297 std::vector<uint8_t> incoming_rtcp_packet;
298 std::vector<uint8_t> outgoing_rtcp_packet;
299
300 webrtc::VideoReceiveStream::Config receiver_config;
301 webrtc::VideoSendStream::Config sender_config;
302
303 srand(random_seed);
304
305 // Create rtp_count RTP packets containing random data.
306 const size_t rtp_header_size = 20;
307 for (size_t i = 0; i < rtp_count; i++) {
308 size_t packet_size = 1000 + rand() % 30;
309 rtp_packets.push_back(std::vector<uint8_t>());
ivoc 2015/07/17 12:14:29 It would be good to call reserve here as well.
terelius 2015/07/17 15:17:40 Done. Well spotted! I initially used the construc
310 for (size_t j = 0; j < packet_size; j++) {
311 rtp_packets[i].push_back(rand());
312 }
313 }
314 // Create two RTCP packets containing random data.
315 size_t packet_size = 1000 + rand() % 30;
316 outgoing_rtcp_packet.reserve(packet_size);
317 for (size_t j = 0; j < packet_size; j++) {
318 outgoing_rtcp_packet.push_back(rand());
319 }
320 packet_size = 1000 + rand() % 30;
321 incoming_rtcp_packet.reserve(packet_size);
322 for (size_t j = 0; j < packet_size; j++) {
323 incoming_rtcp_packet.push_back(rand());
324 }
325 // Create configurations for the video streams.
326 GenerateVideoReceiveConfig(&receiver_config);
327 GenerateVideoSendConfig(&sender_config);
328
329 // Find the name of the current test, in order to use it as a temporary
330 // filename.
331 auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();
332 const std::string temp_filename =
333 test::OutputPath() + test_info->test_case_name() + test_info->name();
334
335 // When log_dumper goes out of scope, it causes the log file to be flushed
336 // to disk.
337 {
338 rtc::scoped_ptr<RtcEventLog> log_dumper(RtcEventLog::Create());
339 log_dumper->LogVideoReceiveStreamConfig(receiver_config);
340 log_dumper->LogVideoSendStreamConfig(sender_config);
341 size_t i = 0;
342 for (; i < rtp_count / 2; i++) {
343 log_dumper->LogRtpHeader(
344 (i % 2 == 0), // Every second packet is incoming.
345 (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
346 rtp_packets[i].data(),
347 rtp_header_size,
348 rtp_packets[i].size());
349 }
350 log_dumper->LogRtcpPacket(false,
351 MediaType::AUDIO,
352 outgoing_rtcp_packet.data(),
353 outgoing_rtcp_packet.size());
354 log_dumper->StartLogging(temp_filename, 10000000);
355 for (; i < rtp_count; i++) {
356 log_dumper->LogRtpHeader(
357 (i % 2 == 0), // Every second packet is incoming,
358 (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
359 rtp_packets[i].data(),
360 rtp_header_size,
361 rtp_packets[i].size());
362 }
363 log_dumper->LogRtcpPacket(true,
364 MediaType::VIDEO,
365 incoming_rtcp_packet.data(),
366 incoming_rtcp_packet.size());
367 }
368
369 const int config_count = 2;
370 const int rtcp_count = 2;
371 const int debug_count = 1; // Only LogStart event,
372 const int event_count = config_count + debug_count + rtcp_count + rtp_count;
373
374 // Read the generated file from disk.
375 RelEventStream parsed_stream;
376
377 ASSERT_TRUE(RtcEventLog::ParseRtcEventLog(temp_filename, &parsed_stream));
378
379 // Verify the result.
380 EXPECT_EQ(event_count, parsed_stream.stream_size());
381 VerifyReceiveStreamConfig(parsed_stream.stream(0), receiver_config);
382 VerifySendStreamConfig(parsed_stream.stream(1), sender_config);
383 size_t i = 0;
384 for (; i < rtp_count / 2; i++) {
385 VerifyRtpEvent(parsed_stream.stream(config_count + i),
386 (i % 2 == 0), // Every second packet is incoming.
387 (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
388 rtp_packets[i].data(),
389 rtp_header_size,
390 rtp_packets[i].size());
391 }
392 VerifyRtcpEvent(parsed_stream.stream(config_count + rtp_count / 2),
393 false,
394 MediaType::AUDIO,
395 outgoing_rtcp_packet.data(),
396 outgoing_rtcp_packet.size());
397
398 VerifyLogStartEvent(parsed_stream.stream(1 + config_count + rtp_count / 2));
399 for (; i < rtp_count; i++) {
400 VerifyRtpEvent(parsed_stream.stream(2 + config_count + i),
401 (i % 2 == 0), // Every second packet is incoming.
402 (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
403 rtp_packets[i].data(),
404 rtp_header_size,
405 rtp_packets[i].size());
406 }
407 VerifyRtcpEvent(parsed_stream.stream(2 + config_count + rtp_count),
408 true,
409 MediaType::VIDEO,
410 incoming_rtcp_packet.data(),
411 incoming_rtcp_packet.size());
412
413 // Clean up temporary file - can be pretty slow.
414 remove(temp_filename.c_str());
415 }
416
417 TEST(RtcEventLogTest, LogSessionAndReadBack) {
418 LogSessionAndReadBack(5, 321);
419 LogSessionAndReadBack(8, 3141592653U);
420 LogSessionAndReadBack(9, 2718281828U);
421 }
422
423 } // namespace webrtc
424
425 #endif // ENABLE_RTC_EVENT_LOG
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698