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

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

Powered by Google App Engine
This is Rietveld 408576698