webrtc_m130/webrtc/call/rtc_event_log_unittest_helper.cc
terelius d5c1a0bd5d New parser for event log. Manually parse the outermost EventStream to more easily deal with corrupt or partially written logs.
Changed rtpdump converter and neteq tool to use new parser, but still aborting if the file is corrupt.

Review-Url: https://codereview.webrtc.org/1768773002
Cr-Commit-Position: refs/heads/master@{#12714}
2016-05-13 07:43:04 +00:00

410 lines
17 KiB
C++

/*
* Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree. An additional intellectual property rights grant can be found
* in the file PATENTS. All contributing project authors may
* be found in the AUTHORS file in the root of the source tree.
*/
#ifdef ENABLE_RTC_EVENT_LOG
#include "webrtc/call/rtc_event_log_unittest_helper.h"
#include <string.h>
#include <string>
#include "testing/gtest/include/gtest/gtest.h"
#include "webrtc/base/checks.h"
#include "webrtc/test/test_suite.h"
#include "webrtc/test/testsupport/fileutils.h"
// Files generated at build-time by the protobuf compiler.
#ifdef WEBRTC_ANDROID_PLATFORM_BUILD
#include "external/webrtc/webrtc/call/rtc_event_log.pb.h"
#else
#include "webrtc/call/rtc_event_log.pb.h"
#endif
namespace webrtc {
namespace {
MediaType GetRuntimeMediaType(rtclog::MediaType media_type) {
switch (media_type) {
case rtclog::MediaType::ANY:
return MediaType::ANY;
case rtclog::MediaType::AUDIO:
return MediaType::AUDIO;
case rtclog::MediaType::VIDEO:
return MediaType::VIDEO;
case rtclog::MediaType::DATA:
return MediaType::DATA;
}
RTC_NOTREACHED();
return MediaType::ANY;
}
} // namespace
// Checks that the event has a timestamp, a type and exactly the data field
// corresponding to the type.
::testing::AssertionResult IsValidBasicEvent(const rtclog::Event& event) {
if (!event.has_timestamp_us()) {
return ::testing::AssertionFailure() << "Event has no timestamp";
}
if (!event.has_type()) {
return ::testing::AssertionFailure() << "Event has no event type";
}
rtclog::Event_EventType type = event.type();
if ((type == rtclog::Event::RTP_EVENT) != event.has_rtp_packet()) {
return ::testing::AssertionFailure()
<< "Event of type " << type << " has "
<< (event.has_rtp_packet() ? "" : "no ") << "RTP packet";
}
if ((type == rtclog::Event::RTCP_EVENT) != event.has_rtcp_packet()) {
return ::testing::AssertionFailure()
<< "Event of type " << type << " has "
<< (event.has_rtcp_packet() ? "" : "no ") << "RTCP packet";
}
if ((type == rtclog::Event::AUDIO_PLAYOUT_EVENT) !=
event.has_audio_playout_event()) {
return ::testing::AssertionFailure()
<< "Event of type " << type << " has "
<< (event.has_audio_playout_event() ? "" : "no ")
<< "audio_playout event";
}
if ((type == rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT) !=
event.has_video_receiver_config()) {
return ::testing::AssertionFailure()
<< "Event of type " << type << " has "
<< (event.has_video_receiver_config() ? "" : "no ")
<< "receiver config";
}
if ((type == rtclog::Event::VIDEO_SENDER_CONFIG_EVENT) !=
event.has_video_sender_config()) {
return ::testing::AssertionFailure()
<< "Event of type " << type << " has "
<< (event.has_video_sender_config() ? "" : "no ") << "sender config";
}
if ((type == rtclog::Event::AUDIO_RECEIVER_CONFIG_EVENT) !=
event.has_audio_receiver_config()) {
return ::testing::AssertionFailure()
<< "Event of type " << type << " has "
<< (event.has_audio_receiver_config() ? "" : "no ")
<< "audio receiver config";
}
if ((type == rtclog::Event::AUDIO_SENDER_CONFIG_EVENT) !=
event.has_audio_sender_config()) {
return ::testing::AssertionFailure()
<< "Event of type " << type << " has "
<< (event.has_audio_sender_config() ? "" : "no ")
<< "audio sender config";
}
return ::testing::AssertionSuccess();
}
void RtcEventLogTestHelper::VerifyReceiveStreamConfig(
const ParsedRtcEventLog& parsed_log,
size_t index,
const VideoReceiveStream::Config& config) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
ASSERT_EQ(rtclog::Event::VIDEO_RECEIVER_CONFIG_EVENT, event.type());
const rtclog::VideoReceiveConfig& receiver_config =
event.video_receiver_config();
// Check SSRCs.
ASSERT_TRUE(receiver_config.has_remote_ssrc());
EXPECT_EQ(config.rtp.remote_ssrc, receiver_config.remote_ssrc());
ASSERT_TRUE(receiver_config.has_local_ssrc());
EXPECT_EQ(config.rtp.local_ssrc, receiver_config.local_ssrc());
// Check RTCP settings.
ASSERT_TRUE(receiver_config.has_rtcp_mode());
if (config.rtp.rtcp_mode == RtcpMode::kCompound) {
EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_COMPOUND,
receiver_config.rtcp_mode());
} else {
EXPECT_EQ(rtclog::VideoReceiveConfig::RTCP_REDUCEDSIZE,
receiver_config.rtcp_mode());
}
ASSERT_TRUE(receiver_config.has_remb());
EXPECT_EQ(config.rtp.remb, receiver_config.remb());
// Check RTX map.
ASSERT_EQ(static_cast<int>(config.rtp.rtx.size()),
receiver_config.rtx_map_size());
for (const rtclog::RtxMap& rtx_map : receiver_config.rtx_map()) {
ASSERT_TRUE(rtx_map.has_payload_type());
ASSERT_TRUE(rtx_map.has_config());
EXPECT_EQ(1u, config.rtp.rtx.count(rtx_map.payload_type()));
const rtclog::RtxConfig& rtx_config = rtx_map.config();
const VideoReceiveStream::Config::Rtp::Rtx& rtx =
config.rtp.rtx.at(rtx_map.payload_type());
ASSERT_TRUE(rtx_config.has_rtx_ssrc());
ASSERT_TRUE(rtx_config.has_rtx_payload_type());
EXPECT_EQ(rtx.ssrc, rtx_config.rtx_ssrc());
EXPECT_EQ(rtx.payload_type, rtx_config.rtx_payload_type());
}
// Check header extensions.
ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
receiver_config.header_extensions_size());
for (int i = 0; i < receiver_config.header_extensions_size(); i++) {
ASSERT_TRUE(receiver_config.header_extensions(i).has_name());
ASSERT_TRUE(receiver_config.header_extensions(i).has_id());
const std::string& name = receiver_config.header_extensions(i).name();
int id = receiver_config.header_extensions(i).id();
EXPECT_EQ(config.rtp.extensions[i].id, id);
EXPECT_EQ(config.rtp.extensions[i].name, name);
}
// Check decoders.
ASSERT_EQ(static_cast<int>(config.decoders.size()),
receiver_config.decoders_size());
for (int i = 0; i < receiver_config.decoders_size(); i++) {
ASSERT_TRUE(receiver_config.decoders(i).has_name());
ASSERT_TRUE(receiver_config.decoders(i).has_payload_type());
const std::string& decoder_name = receiver_config.decoders(i).name();
int decoder_type = receiver_config.decoders(i).payload_type();
EXPECT_EQ(config.decoders[i].payload_name, decoder_name);
EXPECT_EQ(config.decoders[i].payload_type, decoder_type);
}
// Check consistency of the parser.
VideoReceiveStream::Config parsed_config(nullptr);
parsed_log.GetVideoReceiveConfig(index, &parsed_config);
EXPECT_EQ(config.rtp.remote_ssrc, parsed_config.rtp.remote_ssrc);
EXPECT_EQ(config.rtp.local_ssrc, parsed_config.rtp.local_ssrc);
// Check RTCP settings.
EXPECT_EQ(config.rtp.rtcp_mode, parsed_config.rtp.rtcp_mode);
EXPECT_EQ(config.rtp.remb, parsed_config.rtp.remb);
// Check RTX map.
EXPECT_EQ(config.rtp.rtx.size(), parsed_config.rtp.rtx.size());
for (const auto& kv : config.rtp.rtx) {
auto parsed_kv = parsed_config.rtp.rtx.find(kv.first);
EXPECT_EQ(kv.first, parsed_kv->first);
EXPECT_EQ(kv.second.ssrc, parsed_kv->second.ssrc);
EXPECT_EQ(kv.second.payload_type, parsed_kv->second.payload_type);
}
// Check header extensions.
EXPECT_EQ(config.rtp.extensions.size(), parsed_config.rtp.extensions.size());
for (size_t i = 0; i < parsed_config.rtp.extensions.size(); i++) {
EXPECT_EQ(config.rtp.extensions[i].name,
parsed_config.rtp.extensions[i].name);
EXPECT_EQ(config.rtp.extensions[i].id, parsed_config.rtp.extensions[i].id);
}
// Check decoders.
EXPECT_EQ(config.decoders.size(), parsed_config.decoders.size());
for (size_t i = 0; i < parsed_config.decoders.size(); i++) {
EXPECT_EQ(config.decoders[i].payload_name,
parsed_config.decoders[i].payload_name);
EXPECT_EQ(config.decoders[i].payload_type,
parsed_config.decoders[i].payload_type);
}
}
void RtcEventLogTestHelper::VerifySendStreamConfig(
const ParsedRtcEventLog& parsed_log,
size_t index,
const VideoSendStream::Config& config) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
ASSERT_EQ(rtclog::Event::VIDEO_SENDER_CONFIG_EVENT, event.type());
const rtclog::VideoSendConfig& sender_config = event.video_sender_config();
// Check SSRCs.
ASSERT_EQ(static_cast<int>(config.rtp.ssrcs.size()),
sender_config.ssrcs_size());
for (int i = 0; i < sender_config.ssrcs_size(); i++) {
EXPECT_EQ(config.rtp.ssrcs[i], sender_config.ssrcs(i));
}
// Check header extensions.
ASSERT_EQ(static_cast<int>(config.rtp.extensions.size()),
sender_config.header_extensions_size());
for (int i = 0; i < sender_config.header_extensions_size(); i++) {
ASSERT_TRUE(sender_config.header_extensions(i).has_name());
ASSERT_TRUE(sender_config.header_extensions(i).has_id());
const std::string& name = sender_config.header_extensions(i).name();
int id = sender_config.header_extensions(i).id();
EXPECT_EQ(config.rtp.extensions[i].id, id);
EXPECT_EQ(config.rtp.extensions[i].name, name);
}
// Check RTX settings.
ASSERT_EQ(static_cast<int>(config.rtp.rtx.ssrcs.size()),
sender_config.rtx_ssrcs_size());
for (int i = 0; i < sender_config.rtx_ssrcs_size(); i++) {
EXPECT_EQ(config.rtp.rtx.ssrcs[i], sender_config.rtx_ssrcs(i));
}
if (sender_config.rtx_ssrcs_size() > 0) {
ASSERT_TRUE(sender_config.has_rtx_payload_type());
EXPECT_EQ(config.rtp.rtx.payload_type, sender_config.rtx_payload_type());
}
// Check encoder.
ASSERT_TRUE(sender_config.has_encoder());
ASSERT_TRUE(sender_config.encoder().has_name());
ASSERT_TRUE(sender_config.encoder().has_payload_type());
EXPECT_EQ(config.encoder_settings.payload_name,
sender_config.encoder().name());
EXPECT_EQ(config.encoder_settings.payload_type,
sender_config.encoder().payload_type());
// Check consistency of the parser.
VideoSendStream::Config parsed_config(nullptr);
parsed_log.GetVideoSendConfig(index, &parsed_config);
// Check SSRCs
EXPECT_EQ(config.rtp.ssrcs.size(), parsed_config.rtp.ssrcs.size());
for (size_t i = 0; i < config.rtp.ssrcs.size(); i++) {
EXPECT_EQ(config.rtp.ssrcs[i], parsed_config.rtp.ssrcs[i]);
}
// Check header extensions.
EXPECT_EQ(config.rtp.extensions.size(), parsed_config.rtp.extensions.size());
for (size_t i = 0; i < parsed_config.rtp.extensions.size(); i++) {
EXPECT_EQ(config.rtp.extensions[i].name,
parsed_config.rtp.extensions[i].name);
EXPECT_EQ(config.rtp.extensions[i].id, parsed_config.rtp.extensions[i].id);
}
// Check RTX settings.
EXPECT_EQ(config.rtp.rtx.ssrcs.size(), parsed_config.rtp.rtx.ssrcs.size());
for (size_t i = 0; i < config.rtp.rtx.ssrcs.size(); i++) {
EXPECT_EQ(config.rtp.rtx.ssrcs[i], parsed_config.rtp.rtx.ssrcs[i]);
}
EXPECT_EQ(config.rtp.rtx.payload_type, parsed_config.rtp.rtx.payload_type);
// Check encoder.
EXPECT_EQ(config.encoder_settings.payload_name,
parsed_config.encoder_settings.payload_name);
EXPECT_EQ(config.encoder_settings.payload_type,
parsed_config.encoder_settings.payload_type);
}
void RtcEventLogTestHelper::VerifyRtpEvent(const ParsedRtcEventLog& parsed_log,
size_t index,
PacketDirection direction,
MediaType media_type,
const uint8_t* header,
size_t header_size,
size_t total_size) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
ASSERT_EQ(rtclog::Event::RTP_EVENT, event.type());
const rtclog::RtpPacket& rtp_packet = event.rtp_packet();
ASSERT_TRUE(rtp_packet.has_incoming());
EXPECT_EQ(direction == kIncomingPacket, rtp_packet.incoming());
ASSERT_TRUE(rtp_packet.has_type());
EXPECT_EQ(media_type, GetRuntimeMediaType(rtp_packet.type()));
ASSERT_TRUE(rtp_packet.has_packet_length());
EXPECT_EQ(total_size, rtp_packet.packet_length());
ASSERT_TRUE(rtp_packet.has_header());
ASSERT_EQ(header_size, rtp_packet.header().size());
for (size_t i = 0; i < header_size; i++) {
EXPECT_EQ(header[i], static_cast<uint8_t>(rtp_packet.header()[i]));
}
// Check consistency of the parser.
PacketDirection parsed_direction;
MediaType parsed_media_type;
uint8_t parsed_header[1500];
size_t parsed_header_size, parsed_total_size;
parsed_log.GetRtpHeader(index, &parsed_direction, &parsed_media_type,
parsed_header, &parsed_header_size,
&parsed_total_size);
EXPECT_EQ(direction, parsed_direction);
EXPECT_EQ(media_type, parsed_media_type);
ASSERT_EQ(header_size, parsed_header_size);
EXPECT_EQ(0, std::memcmp(header, parsed_header, header_size));
EXPECT_EQ(total_size, parsed_total_size);
}
void RtcEventLogTestHelper::VerifyRtcpEvent(const ParsedRtcEventLog& parsed_log,
size_t index,
PacketDirection direction,
MediaType media_type,
const uint8_t* packet,
size_t total_size) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
ASSERT_EQ(rtclog::Event::RTCP_EVENT, event.type());
const rtclog::RtcpPacket& rtcp_packet = event.rtcp_packet();
ASSERT_TRUE(rtcp_packet.has_incoming());
EXPECT_EQ(direction == kIncomingPacket, rtcp_packet.incoming());
ASSERT_TRUE(rtcp_packet.has_type());
EXPECT_EQ(media_type, GetRuntimeMediaType(rtcp_packet.type()));
ASSERT_TRUE(rtcp_packet.has_packet_data());
ASSERT_EQ(total_size, rtcp_packet.packet_data().size());
for (size_t i = 0; i < total_size; i++) {
EXPECT_EQ(packet[i], static_cast<uint8_t>(rtcp_packet.packet_data()[i]));
}
// Check consistency of the parser.
PacketDirection parsed_direction;
MediaType parsed_media_type;
uint8_t parsed_packet[1500];
size_t parsed_total_size;
parsed_log.GetRtcpPacket(index, &parsed_direction, &parsed_media_type,
parsed_packet, &parsed_total_size);
EXPECT_EQ(direction, parsed_direction);
EXPECT_EQ(media_type, parsed_media_type);
ASSERT_EQ(total_size, parsed_total_size);
EXPECT_EQ(0, std::memcmp(packet, parsed_packet, total_size));
}
void RtcEventLogTestHelper::VerifyPlayoutEvent(
const ParsedRtcEventLog& parsed_log,
size_t index,
uint32_t ssrc) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
ASSERT_EQ(rtclog::Event::AUDIO_PLAYOUT_EVENT, event.type());
const rtclog::AudioPlayoutEvent& playout_event = event.audio_playout_event();
ASSERT_TRUE(playout_event.has_local_ssrc());
EXPECT_EQ(ssrc, playout_event.local_ssrc());
// Check consistency of the parser.
uint32_t parsed_ssrc;
parsed_log.GetAudioPlayout(index, &parsed_ssrc);
EXPECT_EQ(ssrc, parsed_ssrc);
}
void RtcEventLogTestHelper::VerifyBweLossEvent(
const ParsedRtcEventLog& parsed_log,
size_t index,
int32_t bitrate,
uint8_t fraction_loss,
int32_t total_packets) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
ASSERT_EQ(rtclog::Event::BWE_PACKET_LOSS_EVENT, event.type());
const rtclog::BwePacketLossEvent& bwe_event = event.bwe_packet_loss_event();
ASSERT_TRUE(bwe_event.has_bitrate());
EXPECT_EQ(bitrate, bwe_event.bitrate());
ASSERT_TRUE(bwe_event.has_fraction_loss());
EXPECT_EQ(fraction_loss, bwe_event.fraction_loss());
ASSERT_TRUE(bwe_event.has_total_packets());
EXPECT_EQ(total_packets, bwe_event.total_packets());
// Check consistency of the parser.
int32_t parsed_bitrate;
uint8_t parsed_fraction_loss;
int32_t parsed_total_packets;
parsed_log.GetBwePacketLossEvent(
index, &parsed_bitrate, &parsed_fraction_loss, &parsed_total_packets);
EXPECT_EQ(bitrate, parsed_bitrate);
EXPECT_EQ(fraction_loss, parsed_fraction_loss);
EXPECT_EQ(total_packets, parsed_total_packets);
}
void RtcEventLogTestHelper::VerifyLogStartEvent(
const ParsedRtcEventLog& parsed_log,
size_t index) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
EXPECT_EQ(rtclog::Event::LOG_START, event.type());
}
void RtcEventLogTestHelper::VerifyLogEndEvent(
const ParsedRtcEventLog& parsed_log,
size_t index) {
const rtclog::Event& event = parsed_log.stream_[index];
ASSERT_TRUE(IsValidBasicEvent(event));
EXPECT_EQ(rtclog::Event::LOG_END, event.type());
}
} // namespace webrtc
#endif // ENABLE_RTC_EVENT_LOG