| Index: webrtc/video/rtc_event_log_unittest.cc
|
| diff --git a/webrtc/video/rtc_event_log_unittest.cc b/webrtc/video/rtc_event_log_unittest.cc
|
| index 0c18e750cc79cbd5938890211b8b64d43ee45135..6037f3936fac40892b32eebdb80fb4d5ca396cfb 100644
|
| --- a/webrtc/video/rtc_event_log_unittest.cc
|
| +++ b/webrtc/video/rtc_event_log_unittest.cc
|
| @@ -15,9 +15,11 @@
|
| #include <vector>
|
|
|
| #include "testing/gtest/include/gtest/gtest.h"
|
| +#include "webrtc/base/buffer.h"
|
| #include "webrtc/base/checks.h"
|
| #include "webrtc/base/scoped_ptr.h"
|
| #include "webrtc/call.h"
|
| +#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
|
| #include "webrtc/system_wrappers/interface/clock.h"
|
| #include "webrtc/test/test_suite.h"
|
| #include "webrtc/test/testsupport/fileutils.h"
|
| @@ -33,6 +35,23 @@
|
|
|
| namespace webrtc {
|
|
|
| +namespace {
|
| +
|
| +const RTPExtensionType kExtensionTypes[] = {
|
| + RTPExtensionType::kRtpExtensionTransmissionTimeOffset,
|
| + RTPExtensionType::kRtpExtensionAudioLevel,
|
| + RTPExtensionType::kRtpExtensionAbsoluteSendTime,
|
| + RTPExtensionType::kRtpExtensionVideoRotation,
|
| + RTPExtensionType::kRtpExtensionTransportSequenceNumber};
|
| +const char* kExtensionNames[] = {RtpExtension::kTOffset,
|
| + RtpExtension::kAudioLevel,
|
| + RtpExtension::kAbsSendTime,
|
| + RtpExtension::kVideoRotation,
|
| + RtpExtension::kTransportSequenceNumber};
|
| +const size_t kNumExtensions = 5;
|
| +
|
| +} // namepsace
|
| +
|
| // TODO(terelius): Place this definition with other parsing functions?
|
| MediaType GetRuntimeMediaType(rtclog::MediaType media_type) {
|
| switch (media_type) {
|
| @@ -246,6 +265,14 @@ void VerifyRtcpEvent(const rtclog::Event& event,
|
| }
|
| }
|
|
|
| +void VerifyPlayoutEvent(const rtclog::Event& event) {
|
| + ASSERT_TRUE(IsValidBasicEvent(event));
|
| + ASSERT_EQ(rtclog::Event::DEBUG_EVENT, event.type());
|
| + const rtclog::DebugEvent& debug_event = event.debug_event();
|
| + ASSERT_TRUE(debug_event.has_type());
|
| + EXPECT_EQ(rtclog::DebugEvent::AUDIO_PLAYOUT, debug_event.type());
|
| +}
|
| +
|
| void VerifyLogStartEvent(const rtclog::Event& event) {
|
| ASSERT_TRUE(IsValidBasicEvent(event));
|
| ASSERT_EQ(rtclog::Event::DEBUG_EVENT, event.type());
|
| @@ -254,7 +281,71 @@ void VerifyLogStartEvent(const rtclog::Event& event) {
|
| EXPECT_EQ(rtclog::DebugEvent::LOG_START, debug_event.type());
|
| }
|
|
|
| -void GenerateVideoReceiveConfig(VideoReceiveStream::Config* config) {
|
| +/*
|
| + * Bit number i of extension_bitvector is set to indicate the
|
| + * presence of extension number i from kExtensionTypes / kExtensionNames.
|
| + * The least significant bit extension_bitvector has number 0.
|
| + */
|
| +size_t GenerateRtpPacket(uint32_t extensions_bitvector,
|
| + uint32_t csrcs_count,
|
| + uint8_t* packet,
|
| + size_t packet_size) {
|
| + CHECK_GE(packet_size, 16 + 4 * csrcs_count + 4 * kNumExtensions);
|
| + Clock* clock = Clock::GetRealTimeClock();
|
| +
|
| + RTPSender rtp_sender(0, // int32_t id
|
| + false, // bool audio
|
| + clock, // Clock* clock
|
| + nullptr, // Transport*
|
| + nullptr, // RtpAudioFeedback*
|
| + nullptr, // PacedSender*
|
| + nullptr, // PacketRouter*
|
| + nullptr, // SendTimeObserver*
|
| + nullptr, // BitrateStatisticsObserver*
|
| + nullptr, // FrameCountObserver*
|
| + nullptr); // SendSideDelayObserver*
|
| +
|
| + std::vector<uint32_t> csrcs;
|
| + for (unsigned i = 0; i < csrcs_count; i++) {
|
| + csrcs.push_back(rand());
|
| + }
|
| + rtp_sender.SetCsrcs(csrcs);
|
| + rtp_sender.SetSSRC(rand());
|
| + rtp_sender.SetStartTimestamp(rand(), true);
|
| + rtp_sender.SetSequenceNumber(rand());
|
| +
|
| + for (unsigned i = 0; i < kNumExtensions; i++) {
|
| + if (extensions_bitvector & (1u << i)) {
|
| + rtp_sender.RegisterRtpHeaderExtension(kExtensionTypes[i], i + 1);
|
| + }
|
| + }
|
| +
|
| + int8_t payload_type = rand() % 128;
|
| + bool marker_bit = (rand() % 2 == 1);
|
| + uint32_t capture_timestamp = rand();
|
| + int64_t capture_time_ms = rand();
|
| + bool timestamp_provided = (rand() % 2 == 1);
|
| + bool inc_sequence_number = (rand() % 2 == 1);
|
| +
|
| + size_t header_size = rtp_sender.BuildRTPheader(
|
| + packet, payload_type, marker_bit, capture_timestamp, capture_time_ms,
|
| + timestamp_provided, inc_sequence_number);
|
| +
|
| + for (size_t i = header_size; i < packet_size; i++) {
|
| + packet[i] = rand();
|
| + }
|
| +
|
| + return header_size;
|
| +}
|
| +
|
| +void GenerateRtcpPacket(uint8_t* packet, size_t packet_size) {
|
| + for (size_t i = 0; i < packet_size; i++) {
|
| + packet[i] = rand();
|
| + }
|
| +}
|
| +
|
| +void GenerateVideoReceiveConfig(uint32_t extensions_bitvector,
|
| + VideoReceiveStream::Config* config) {
|
| // Create a map from a payload type to an encoder name.
|
| VideoReceiveStream::Decoder decoder;
|
| decoder.payload_type = rand();
|
| @@ -266,24 +357,24 @@ void GenerateVideoReceiveConfig(VideoReceiveStream::Config* config) {
|
| // Add extensions and settings for RTCP.
|
| config->rtp.rtcp_mode = rand() % 2 ? newapi::kRtcpCompound
|
| : newapi::kRtcpReducedSize;
|
| - config->rtp.rtcp_xr.receiver_reference_time_report =
|
| - static_cast<bool>(rand() % 2);
|
| - config->rtp.remb = static_cast<bool>(rand() % 2);
|
| + config->rtp.rtcp_xr.receiver_reference_time_report = (rand() % 2 == 1);
|
| + config->rtp.remb = (rand() % 2 == 1);
|
| // Add a map from a payload type to a new ssrc and a new payload type for RTX.
|
| VideoReceiveStream::Config::Rtp::Rtx rtx_pair;
|
| rtx_pair.ssrc = rand();
|
| rtx_pair.payload_type = rand();
|
| config->rtp.rtx.insert(std::make_pair(rand(), rtx_pair));
|
| - // Add two random header extensions.
|
| - const char* extension_name = rand() % 2 ? RtpExtension::kTOffset
|
| - : RtpExtension::kVideoRotation;
|
| - config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
|
| - extension_name = rand() % 2 ? RtpExtension::kAudioLevel
|
| - : RtpExtension::kAbsSendTime;
|
| - config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
|
| + // Add header extensions.
|
| + for (unsigned i = 0; i < kNumExtensions; i++) {
|
| + if (extensions_bitvector & (1u << i)) {
|
| + config->rtp.extensions.push_back(
|
| + RtpExtension(kExtensionNames[i], rand()));
|
| + }
|
| + }
|
| }
|
|
|
| -void GenerateVideoSendConfig(VideoSendStream::Config* config) {
|
| +void GenerateVideoSendConfig(uint32_t extensions_bitvector,
|
| + VideoSendStream::Config* config) {
|
| // Create a map from a payload type to an encoder name.
|
| config->encoder_settings.payload_type = rand();
|
| config->encoder_settings.payload_name = (rand() % 2 ? "VP8" : "H264");
|
| @@ -294,21 +385,28 @@ void GenerateVideoSendConfig(VideoSendStream::Config* config) {
|
| config->rtp.rtx.payload_type = rand();
|
| // Add a CNAME.
|
| config->rtp.c_name = "some.user@some.host";
|
| - // Add two random header extensions.
|
| - const char* extension_name = rand() % 2 ? RtpExtension::kTOffset
|
| - : RtpExtension::kVideoRotation;
|
| - config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
|
| - extension_name = rand() % 2 ? RtpExtension::kAudioLevel
|
| - : RtpExtension::kAbsSendTime;
|
| - config->rtp.extensions.push_back(RtpExtension(extension_name, rand()));
|
| + // Add header extensions.
|
| + for (unsigned i = 0; i < kNumExtensions; i++) {
|
| + if (extensions_bitvector & (1u << i)) {
|
| + config->rtp.extensions.push_back(
|
| + RtpExtension(kExtensionNames[i], rand()));
|
| + }
|
| + }
|
| }
|
|
|
| // Test for the RtcEventLog class. Dumps some RTP packets to disk, then reads
|
| // them back to see if they match.
|
| -void LogSessionAndReadBack(size_t rtp_count, unsigned random_seed) {
|
| - std::vector<std::vector<uint8_t>> rtp_packets;
|
| - std::vector<uint8_t> incoming_rtcp_packet;
|
| - std::vector<uint8_t> outgoing_rtcp_packet;
|
| +void LogSessionAndReadBack(size_t rtp_count,
|
| + size_t rtcp_count,
|
| + size_t debug_count,
|
| + uint32_t extensions_bitvector,
|
| + uint32_t csrcs_count,
|
| + unsigned random_seed) {
|
| + ASSERT_LE(rtcp_count, rtp_count);
|
| + ASSERT_LE(debug_count, rtp_count);
|
| + std::vector<rtc::Buffer> rtp_packets;
|
| + std::vector<rtc::Buffer> rtcp_packets;
|
| + std::vector<size_t> rtp_header_sizes;
|
|
|
| VideoReceiveStream::Config receiver_config;
|
| VideoSendStream::Config sender_config;
|
| @@ -316,29 +414,23 @@ void LogSessionAndReadBack(size_t rtp_count, unsigned random_seed) {
|
| srand(random_seed);
|
|
|
| // Create rtp_count RTP packets containing random data.
|
| - const size_t rtp_header_size = 20;
|
| for (size_t i = 0; i < rtp_count; i++) {
|
| - size_t packet_size = 1000 + rand() % 30;
|
| - rtp_packets.push_back(std::vector<uint8_t>());
|
| - rtp_packets[i].reserve(packet_size);
|
| - for (size_t j = 0; j < packet_size; j++) {
|
| - rtp_packets[i].push_back(rand());
|
| - }
|
| - }
|
| - // Create two RTCP packets containing random data.
|
| - size_t packet_size = 1000 + rand() % 30;
|
| - outgoing_rtcp_packet.reserve(packet_size);
|
| - for (size_t j = 0; j < packet_size; j++) {
|
| - outgoing_rtcp_packet.push_back(rand());
|
| + size_t packet_size = 1000 + rand() % 64;
|
| + rtp_packets.push_back(rtc::Buffer(packet_size));
|
| + size_t header_size = GenerateRtpPacket(extensions_bitvector, csrcs_count,
|
| + rtp_packets[i].data(), packet_size);
|
| + rtp_header_sizes.push_back(header_size);
|
| }
|
| - packet_size = 1000 + rand() % 30;
|
| - incoming_rtcp_packet.reserve(packet_size);
|
| - for (size_t j = 0; j < packet_size; j++) {
|
| - incoming_rtcp_packet.push_back(rand());
|
| + // Create rtcp_count RTCP packets containing random data.
|
| + for (size_t i = 0; i < rtcp_count; i++) {
|
| + size_t packet_size = 1000 + rand() % 64;
|
| + rtcp_packets.push_back(rtc::Buffer(packet_size));
|
| + GenerateRtcpPacket(rtcp_packets[i].data(), packet_size);
|
| }
|
| // Create configurations for the video streams.
|
| - GenerateVideoReceiveConfig(&receiver_config);
|
| - GenerateVideoSendConfig(&sender_config);
|
| + GenerateVideoReceiveConfig(extensions_bitvector, &receiver_config);
|
| + GenerateVideoSendConfig(extensions_bitvector, &sender_config);
|
| + const int config_count = 2;
|
|
|
| // Find the name of the current test, in order to use it as a temporary
|
| // filename.
|
| @@ -352,76 +444,102 @@ void LogSessionAndReadBack(size_t rtp_count, unsigned random_seed) {
|
| rtc::scoped_ptr<RtcEventLog> log_dumper(RtcEventLog::Create());
|
| log_dumper->LogVideoReceiveStreamConfig(receiver_config);
|
| log_dumper->LogVideoSendStreamConfig(sender_config);
|
| - size_t i = 0;
|
| - for (; i < rtp_count / 2; i++) {
|
| + size_t rtcp_index = 1, debug_index = 1;
|
| + for (size_t i = 1; i <= rtp_count; i++) {
|
| log_dumper->LogRtpHeader(
|
| (i % 2 == 0), // Every second packet is incoming.
|
| (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
|
| - rtp_packets[i].data(), rtp_header_size, rtp_packets[i].size());
|
| - }
|
| - log_dumper->LogRtcpPacket(false, MediaType::AUDIO,
|
| - outgoing_rtcp_packet.data(),
|
| - outgoing_rtcp_packet.size());
|
| - log_dumper->StartLogging(temp_filename, 10000000);
|
| - for (; i < rtp_count; i++) {
|
| - log_dumper->LogRtpHeader(
|
| - (i % 2 == 0), // Every second packet is incoming,
|
| - (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
|
| - rtp_packets[i].data(), rtp_header_size, rtp_packets[i].size());
|
| + rtp_packets[i - 1].data(), rtp_packets[i - 1].size());
|
| + if (i * rtcp_count >= rtcp_index * rtp_count) {
|
| + log_dumper->LogRtcpPacket(
|
| + rtcp_index % 2 == 0, // Every second packet is incoming
|
| + rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO,
|
| + rtcp_packets[rtcp_index - 1].data(),
|
| + rtcp_packets[rtcp_index - 1].size());
|
| + rtcp_index++;
|
| + }
|
| + if (i * debug_count >= debug_index * rtp_count) {
|
| + log_dumper->LogDebugEvent(RtcEventLog::DebugEvent::kAudioPlayout);
|
| + debug_index++;
|
| + }
|
| + if (i == rtp_count / 2) {
|
| + log_dumper->StartLogging(temp_filename, 10000000);
|
| + }
|
| }
|
| - log_dumper->LogRtcpPacket(true, MediaType::VIDEO,
|
| - incoming_rtcp_packet.data(),
|
| - incoming_rtcp_packet.size());
|
| }
|
|
|
| - const int config_count = 2;
|
| - const int rtcp_count = 2;
|
| - const int debug_count = 1; // Only LogStart event,
|
| - const int event_count = config_count + debug_count + rtcp_count + rtp_count;
|
| -
|
| // Read the generated file from disk.
|
| rtclog::EventStream parsed_stream;
|
|
|
| ASSERT_TRUE(RtcEventLog::ParseRtcEventLog(temp_filename, &parsed_stream));
|
|
|
| // Verify the result.
|
| + const int event_count =
|
| + config_count + debug_count + rtcp_count + rtp_count + 1;
|
| EXPECT_EQ(event_count, parsed_stream.stream_size());
|
| VerifyReceiveStreamConfig(parsed_stream.stream(0), receiver_config);
|
| VerifySendStreamConfig(parsed_stream.stream(1), sender_config);
|
| - size_t i = 0;
|
| - for (; i < rtp_count / 2; i++) {
|
| - VerifyRtpEvent(parsed_stream.stream(config_count + i),
|
| + size_t event_index = config_count, rtcp_index = 1, debug_index = 1;
|
| + for (size_t i = 1; i <= rtp_count; i++) {
|
| + VerifyRtpEvent(parsed_stream.stream(event_index),
|
| (i % 2 == 0), // Every second packet is incoming.
|
| (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
|
| - rtp_packets[i].data(), rtp_header_size,
|
| - rtp_packets[i].size());
|
| - }
|
| - VerifyRtcpEvent(parsed_stream.stream(config_count + rtp_count / 2),
|
| - false, // Outgoing RTCP packet.
|
| - MediaType::AUDIO, outgoing_rtcp_packet.data(),
|
| - outgoing_rtcp_packet.size());
|
| -
|
| - VerifyLogStartEvent(parsed_stream.stream(1 + config_count + rtp_count / 2));
|
| - for (; i < rtp_count; i++) {
|
| - VerifyRtpEvent(parsed_stream.stream(2 + config_count + i),
|
| - (i % 2 == 0), // Every second packet is incoming.
|
| - (i % 3 == 0) ? MediaType::AUDIO : MediaType::VIDEO,
|
| - rtp_packets[i].data(), rtp_header_size,
|
| - rtp_packets[i].size());
|
| + rtp_packets[i - 1].data(), rtp_header_sizes[i - 1],
|
| + rtp_packets[i - 1].size());
|
| + event_index++;
|
| + if (i * rtcp_count >= rtcp_index * rtp_count) {
|
| + VerifyRtcpEvent(parsed_stream.stream(event_index),
|
| + rtcp_index % 2 == 0, // Every second packet is incoming.
|
| + rtcp_index % 3 == 0 ? MediaType::AUDIO : MediaType::VIDEO,
|
| + rtcp_packets[rtcp_index - 1].data(),
|
| + rtcp_packets[rtcp_index - 1].size());
|
| + event_index++;
|
| + rtcp_index++;
|
| + }
|
| + if (i * debug_count >= debug_index * rtp_count) {
|
| + VerifyPlayoutEvent(parsed_stream.stream(event_index));
|
| + event_index++;
|
| + debug_index++;
|
| + }
|
| + if (i == rtp_count / 2) {
|
| + VerifyLogStartEvent(parsed_stream.stream(event_index));
|
| + event_index++;
|
| + }
|
| }
|
| - VerifyRtcpEvent(parsed_stream.stream(2 + config_count + rtp_count),
|
| - true, // Incoming RTCP packet.
|
| - MediaType::VIDEO, incoming_rtcp_packet.data(),
|
| - incoming_rtcp_packet.size());
|
|
|
| // Clean up temporary file - can be pretty slow.
|
| remove(temp_filename.c_str());
|
| }
|
|
|
| TEST(RtcEventLogTest, LogSessionAndReadBack) {
|
| - LogSessionAndReadBack(5, 321);
|
| - LogSessionAndReadBack(8, 3141592653u);
|
| - LogSessionAndReadBack(9, 2718281828u);
|
| + // Log 5 RTP, 2 RTCP, and 0 playout events with no header extensions or CSRCS.
|
| + LogSessionAndReadBack(5, 2, 0, 0, 0, 321);
|
| +
|
| + // Enable AbsSendTime and TransportSequenceNumbers
|
| + uint32_t extensions = 0;
|
| + for (uint32_t i = 0; i < kNumExtensions; i++) {
|
| + if (kExtensionTypes[i] == RTPExtensionType::kRtpExtensionAbsoluteSendTime ||
|
| + kExtensionTypes[i] ==
|
| + RTPExtensionType::kRtpExtensionTransportSequenceNumber) {
|
| + extensions |= 1u << i;
|
| + }
|
| + }
|
| + LogSessionAndReadBack(8, 2, 0, extensions, 0, 3141592653u);
|
| +
|
| + extensions = (1u << kNumExtensions) - 1; // Enable all header extensions
|
| + LogSessionAndReadBack(9, 2, 3, extensions, 2, 2718281828u);
|
| +
|
| + // Try all combinations of header extensions and up to 2 CSRCS.
|
| + for (extensions = 0; extensions < (1u << kNumExtensions); extensions++) {
|
| + for (uint32_t csrcs_count = 0; csrcs_count < 3; csrcs_count++) {
|
| + LogSessionAndReadBack(5 + extensions, // Number of RTP packets.
|
| + 2 + csrcs_count, // Number of RTCP packets.
|
| + 3 + csrcs_count, // Number of playout events
|
| + extensions, // Bit vector choosing extensions
|
| + csrcs_count, // Number of contributing sources
|
| + rand());
|
| + }
|
| + }
|
| }
|
|
|
| } // namespace webrtc
|
|
|