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

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

Powered by Google App Engine
This is Rietveld 408576698