Commit 9f24ecb2 authored by pwestin@google.com's avatar pwestin@google.com

Cast: Add capabity to send Receiver and Sender log messages over RTCP.

This cl contains the generation of the RTCP packets containing the log
messages, no code (more than this unittest) trigger the send.
Additionally the receiver is not wired up either. If a receiver receives
a log message today it would be ignored.

Review URL: https://codereview.chromium.org/74613004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@238533 0039d316-1c4b-4281-b951-d872f2087c98
parent a9575487
......@@ -179,7 +179,7 @@ void Rtcp::IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length) {
}
void Rtcp::SendRtcpFromRtpReceiver(const RtcpCastMessage* cast_message,
const RtcpReceiverLogMessage* receiver_log) {
RtcpReceiverLogMessage* receiver_log) {
uint32 packet_type_flags = 0;
base::TimeTicks now = cast_environment_->Clock()->NowTicks();
......@@ -239,15 +239,15 @@ void Rtcp::SendRtcpFromRtpReceiver(const RtcpCastMessage* cast_message,
}
void Rtcp::SendRtcpFromRtpSender(
const RtcpSenderLogMessage* sender_log_message) {
RtcpSenderLogMessage* sender_log_message) {
uint32 packet_type_flags = RtcpSender::kRtcpSr;
base::TimeTicks now = cast_environment_->Clock()->NowTicks();
RtcpSenderInfo sender_info;
RtcpDlrrReportBlock dlrr;
if (sender_log_message) packet_type_flags |= RtcpSender::kRtcpSenderLog;
if (sender_log_message) {
packet_type_flags |= RtcpSender::kRtcpSenderLog;
}
RtcpSenderInfo sender_info;
if (rtp_sender_statistics_) {
rtp_sender_statistics_->GetStatistics(now, &sender_info);
} else {
......@@ -255,6 +255,7 @@ void Rtcp::SendRtcpFromRtpSender(
}
SaveLastSentNtpTime(now, sender_info.ntp_seconds, sender_info.ntp_fraction);
RtcpDlrrReportBlock dlrr;
if (!time_last_report_received_.is_null()) {
packet_type_flags |= RtcpSender::kRtcpDlrr;
dlrr.last_rr = last_report_received_;
......
......@@ -92,15 +92,20 @@ class Rtcp {
// |sender_log_message| is optional; without it no log messages will be
// attached to the RTCP report; instead a normal RTCP send report will be
// sent.
void SendRtcpFromRtpSender(const RtcpSenderLogMessage* sender_log_message);
// Additionally if all messages in |sender_log_message| does
// not fit in the packet the |sender_log_message| will contain the remaining
// unsent messages.
void SendRtcpFromRtpSender(RtcpSenderLogMessage* sender_log_message);
// |cast_message| and |receiver_log| is optional; if |cast_message| is
// provided the RTCP receiver report will append a Cast message containing
// Acks and Nacks; if |receiver_log| is provided the RTCP receiver report will
// append the log messages. If no argument is set a normal RTCP receiver
// report will be sent.
// report will be sent. Additionally if all messages in |receiver_log| does
// not fit in the packet the |receiver_log| will contain the remaining unsent
// messages.
void SendRtcpFromRtpReceiver(const RtcpCastMessage* cast_message,
const RtcpReceiverLogMessage* receiver_log);
RtcpReceiverLogMessage* receiver_log);
void IncomingRtcpPacket(const uint8* rtcp_buffer, size_t length);
bool Rtt(base::TimeDelta* rtt, base::TimeDelta* avg_rtt,
......
......@@ -13,6 +13,113 @@
#include "media/cast/rtcp/rtcp_utility.h"
#include "net/base/big_endian.h"
static const size_t kRtcpCastLogHeaderSize = 12;
static const size_t kRtcpSenderFrameLogSize = 4;
static const size_t kRtcpReceiverFrameLogSize = 8;
static const size_t kRtcpReceiverEventLogSize = 4;
namespace {
uint16 MergeEventTypeAndTimestampForWireFormat(
const media::cast::CastLoggingEvent& event,
const base::TimeDelta& time_delta) {
int64 time_delta_ms = time_delta.InMilliseconds();
// Max delta is 4096 milliseconds.
DCHECK_GE(GG_INT64_C(0xfff), time_delta_ms);
uint16 event_type_and_timestamp_delta =
static_cast<uint16>(time_delta_ms & 0xfff);
uint16 event_type = 0;
switch (event) {
case media::cast::kAckSent:
event_type = 1;
break;
case media::cast::kAudioPlayoutDelay:
event_type = 2;
break;
case media::cast::kAudioFrameDecoded:
event_type = 3;
break;
case media::cast::kVideoFrameDecoded:
event_type = 4;
break;
case media::cast::kVideoRenderDelay:
event_type = 5;
break;
case media::cast::kPacketReceived:
event_type = 6;
break;
default:
NOTREACHED();
}
DCHECK(!(event_type & 0xfff0));
return (event_type << 12) + event_type_and_timestamp_delta;
}
bool ScanRtcpReceiverLogMessage(
const media::cast::RtcpReceiverLogMessage& receiver_log_message,
size_t start_size,
size_t* number_of_frames,
size_t* total_number_of_messages_to_send,
size_t* rtcp_log_size) {
if (receiver_log_message.empty()) return false;
size_t remaining_space = media::cast::kIpPacketSize - start_size;
// We must have space for at least one message
DCHECK_GE(remaining_space, kRtcpCastLogHeaderSize +
kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize)
<< "Not enough buffer space";
if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize +
kRtcpReceiverEventLogSize) {
return false;
}
// Account for the RTCP header for an application-defined packet.
remaining_space -= kRtcpCastLogHeaderSize;
media::cast::RtcpReceiverLogMessage::const_iterator frame_it =
receiver_log_message.begin();
for (; frame_it != receiver_log_message.end(); ++frame_it) {
(*number_of_frames)++;
remaining_space -= kRtcpReceiverFrameLogSize;
size_t messages_in_frame = frame_it->event_log_messages_.size();
size_t remaining_space_in_messages =
remaining_space / kRtcpReceiverEventLogSize;
size_t messages_to_send = std::min(messages_in_frame,
remaining_space_in_messages);
if (messages_to_send > media::cast::kRtcpMaxReceiverLogMessages) {
// We can't send more than 256 messages.
remaining_space -= media::cast::kRtcpMaxReceiverLogMessages *
kRtcpReceiverEventLogSize;
*total_number_of_messages_to_send +=
media::cast::kRtcpMaxReceiverLogMessages;
break;
}
remaining_space -= messages_to_send * kRtcpReceiverEventLogSize;
*total_number_of_messages_to_send += messages_to_send;
if (remaining_space <
kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) {
// Make sure that we have room for at least one more message.
break;
}
}
*rtcp_log_size = kRtcpCastLogHeaderSize +
*number_of_frames * kRtcpReceiverFrameLogSize +
*total_number_of_messages_to_send * kRtcpReceiverEventLogSize;
DCHECK_GE(media::cast::kIpPacketSize,
start_size + *rtcp_log_size) << "Not enough buffer space";
VLOG(1) << "number of frames " << *number_of_frames;
VLOG(1) << "total messages to send " << *total_number_of_messages_to_send;
VLOG(1) << "rtcp log size " << *rtcp_log_size;
return true;
}
} // namespace
namespace media {
namespace cast {
......@@ -32,7 +139,7 @@ RtcpSender::~RtcpSender() {}
void RtcpSender::SendRtcpFromRtpSender(uint32 packet_type_flags,
const RtcpSenderInfo* sender_info,
const RtcpDlrrReportBlock* dlrr,
const RtcpSenderLogMessage* sender_log) {
RtcpSenderLogMessage* sender_log) {
if (packet_type_flags & kRtcpRr ||
packet_type_flags & kRtcpPli ||
packet_type_flags & kRtcpRrtr ||
......@@ -73,7 +180,7 @@ void RtcpSender::SendRtcpFromRtpReceiver(
const RtcpReportBlock* report_block,
const RtcpReceiverReferenceTimeReport* rrtr,
const RtcpCastMessage* cast_message,
const RtcpReceiverLogMessage* receiver_log) {
RtcpReceiverLogMessage* receiver_log) {
if (packet_type_flags & kRtcpSr ||
packet_type_flags & kRtcpDlrr ||
packet_type_flags & kRtcpSenderLog) {
......@@ -128,7 +235,7 @@ void RtcpSender::BuildSR(const RtcpSenderInfo& sender_info,
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 28);
big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0));
big_endian_writer.WriteU8(200);
big_endian_writer.WriteU8(kPacketTypeSenderReport);
big_endian_writer.WriteU16(number_of_rows);
big_endian_writer.WriteU32(ssrc_);
big_endian_writer.WriteU32(sender_info.ntp_seconds);
......@@ -153,7 +260,7 @@ void RtcpSender::BuildRR(const RtcpReportBlock* report_block,
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8);
big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0));
big_endian_writer.WriteU8(201);
big_endian_writer.WriteU8(kPacketTypeReceiverReport);
big_endian_writer.WriteU16(number_of_rows);
big_endian_writer.WriteU32(ssrc_);
......@@ -202,7 +309,7 @@ void RtcpSender::BuildSdec(std::vector<uint8>* packet) const {
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 10);
// We always need to add one SDES CNAME.
big_endian_writer.WriteU8(0x80 + 1);
big_endian_writer.WriteU8(202);
big_endian_writer.WriteU8(kPacketTypeSdes);
// Handle SDES length later on.
uint32 sdes_length_position = static_cast<uint32>(start_size) + 3;
......@@ -244,7 +351,7 @@ void RtcpSender::BuildPli(uint32 remote_ssrc,
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 12);
uint8 FMT = 1; // Picture loss indicator.
big_endian_writer.WriteU8(0x80 + FMT);
big_endian_writer.WriteU8(206);
big_endian_writer.WriteU8(kPacketTypePayloadSpecific);
big_endian_writer.WriteU16(2); // Used fixed length of 2.
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
big_endian_writer.WriteU32(remote_ssrc); // Add the remote SSRC.
......@@ -270,7 +377,7 @@ void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi,
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 24);
uint8 FMT = 3; // Reference Picture Selection Indication.
big_endian_writer.WriteU8(0x80 + FMT);
big_endian_writer.WriteU8(206);
big_endian_writer.WriteU8(kPacketTypePayloadSpecific);
// Calculate length.
uint32 bits_required = 7;
......@@ -327,7 +434,7 @@ void RtcpSender::BuildRemb(const RtcpRembMessage* remb,
// Add application layer feedback.
uint8 FMT = 15;
big_endian_writer.WriteU8(0x80 + FMT);
big_endian_writer.WriteU8(206);
big_endian_writer.WriteU8(kPacketTypePayloadSpecific);
big_endian_writer.WriteU8(0);
big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size() + 4));
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
......@@ -367,7 +474,7 @@ void RtcpSender::BuildNack(const RtcpNackMessage* nack,
uint8 FMT = 1;
big_endian_writer.WriteU8(0x80 + FMT);
big_endian_writer.WriteU8(205);
big_endian_writer.WriteU8(kPacketTypeGenericRtpFeedback);
big_endian_writer.WriteU8(0);
size_t nack_size_pos = start_size + 3;
big_endian_writer.WriteU8(3);
......@@ -419,7 +526,7 @@ void RtcpSender::BuildBye(std::vector<uint8>* packet) const {
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8);
big_endian_writer.WriteU8(0x80 + 1);
big_endian_writer.WriteU8(203);
big_endian_writer.WriteU8(kPacketTypeBye);
big_endian_writer.WriteU16(1); // Length.
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
}
......@@ -451,7 +558,7 @@ void RtcpSender::BuildDlrrRb(const RtcpDlrrReportBlock* dlrr,
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 24);
big_endian_writer.WriteU8(0x80);
big_endian_writer.WriteU8(207);
big_endian_writer.WriteU8(kPacketTypeXr);
big_endian_writer.WriteU16(5); // Length.
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
big_endian_writer.WriteU8(5); // Add block type.
......@@ -473,7 +580,7 @@ void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr,
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 20);
big_endian_writer.WriteU8(0x80);
big_endian_writer.WriteU8(207);
big_endian_writer.WriteU8(kPacketTypeXr);
big_endian_writer.WriteU16(4); // Length.
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
big_endian_writer.WriteU8(4); // Add block type.
......@@ -496,7 +603,7 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast,
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 20);
uint8 FMT = 15; // Application layer feedback.
big_endian_writer.WriteU8(0x80 + FMT);
big_endian_writer.WriteU8(206);
big_endian_writer.WriteU8(kPacketTypePayloadSpecific);
big_endian_writer.WriteU8(0);
size_t cast_size_pos = start_size + 3; // Save length position.
big_endian_writer.WriteU8(4);
......@@ -563,17 +670,129 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast,
(*packet)[cast_loss_field_pos] = static_cast<uint8>(number_of_loss_fields);
}
void RtcpSender::BuildSenderLog(const RtcpSenderLogMessage* sender_log_message,
void RtcpSender::BuildSenderLog(RtcpSenderLogMessage* sender_log_message,
std::vector<uint8>* packet) const {
// TODO(pwestin): Implement.
NOTIMPLEMENTED();
DCHECK(sender_log_message);
DCHECK(packet);
size_t start_size = packet->size();
size_t remaining_space = kIpPacketSize - start_size;
DCHECK_GE(remaining_space, kRtcpCastLogHeaderSize + kRtcpSenderFrameLogSize)
<< "Not enough buffer space";
if (remaining_space < kRtcpCastLogHeaderSize + kRtcpSenderFrameLogSize)
return;
size_t space_for_x_messages =
(remaining_space - kRtcpCastLogHeaderSize) / kRtcpSenderFrameLogSize;
size_t number_of_messages = std::min(space_for_x_messages,
sender_log_message->size());
size_t log_size = kRtcpCastLogHeaderSize +
number_of_messages * kRtcpSenderFrameLogSize;
packet->resize(start_size + log_size);
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), log_size);
big_endian_writer.WriteU8(0x80 + kSenderLogSubtype);
big_endian_writer.WriteU8(kPacketTypeApplicationDefined);
big_endian_writer.WriteU16(static_cast<uint16>(2 + number_of_messages));
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
big_endian_writer.WriteU32(kCast);
for (; number_of_messages > 0; --number_of_messages) {
DCHECK(!sender_log_message->empty());
const RtcpSenderFrameLogMessage& message = sender_log_message->front();
big_endian_writer.WriteU8(static_cast<uint8>(message.frame_status));
// We send the 24 east significant bits of the RTP timestamp.
big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp >> 16));
big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp >> 8));
big_endian_writer.WriteU8(static_cast<uint8>(message.rtp_timestamp));
sender_log_message->pop_front();
}
}
void RtcpSender::BuildReceiverLog(
const RtcpReceiverLogMessage* receiver_log_message,
std::vector<uint8>* packet) const {
// TODO(pwestin): Implement.
NOTIMPLEMENTED();
void RtcpSender::BuildReceiverLog(RtcpReceiverLogMessage* receiver_log_message,
std::vector<uint8>* packet) const {
DCHECK(receiver_log_message);
const size_t packet_start_size = packet->size();
size_t number_of_frames = 0;
size_t total_number_of_messages_to_send = 0;
size_t rtcp_log_size = 0;
if (!ScanRtcpReceiverLogMessage(*receiver_log_message,
packet_start_size,
&number_of_frames,
&total_number_of_messages_to_send,
&rtcp_log_size)) {
return;
}
packet->resize(packet_start_size + rtcp_log_size);
net::BigEndianWriter big_endian_writer(&((*packet)[packet_start_size]),
rtcp_log_size);
big_endian_writer.WriteU8(0x80 + kReceiverLogSubtype);
big_endian_writer.WriteU8(kPacketTypeApplicationDefined);
big_endian_writer.WriteU16(static_cast<uint16>(2 + 2 * number_of_frames +
total_number_of_messages_to_send));
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
big_endian_writer.WriteU32(kCast);
while (!receiver_log_message->empty() &&
total_number_of_messages_to_send > 0) {
RtcpReceiverFrameLogMessage& frame_log_messages =
receiver_log_message->front();
// Add our frame header.
big_endian_writer.WriteU32(frame_log_messages.rtp_timestamp_);
size_t messages_in_frame = frame_log_messages.event_log_messages_.size();
if (messages_in_frame > total_number_of_messages_to_send) {
// We are running out of space.
messages_in_frame = total_number_of_messages_to_send;
}
// Keep track of how many messages we have left to send.
total_number_of_messages_to_send -= messages_in_frame;
// On the wire format is number of messages - 1.
big_endian_writer.WriteU8(static_cast<uint8>(messages_in_frame - 1));
base::TimeTicks event_timestamp_base =
frame_log_messages.event_log_messages_.front().event_timestamp;
uint32 base_timestamp_ms =
(event_timestamp_base - base::TimeTicks()).InMilliseconds();
big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 16));
big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms >> 8));
big_endian_writer.WriteU8(static_cast<uint8>(base_timestamp_ms));
while (!frame_log_messages.event_log_messages_.empty() &&
messages_in_frame > 0) {
const RtcpReceiverEventLogMessage& event_message =
frame_log_messages.event_log_messages_.front();
uint16 event_type_and_timestamp_delta =
MergeEventTypeAndTimestampForWireFormat(event_message.type,
event_message.event_timestamp - event_timestamp_base);
switch (event_message.type) {
case kAckSent:
case kAudioPlayoutDelay:
case kAudioFrameDecoded:
case kVideoFrameDecoded:
case kVideoRenderDelay:
big_endian_writer.WriteU16(static_cast<uint16>(
event_message.delay_delta.InMilliseconds()));
big_endian_writer.WriteU16(event_type_and_timestamp_delta);
break;
case kPacketReceived:
big_endian_writer.WriteU16(event_message.packet_id);
big_endian_writer.WriteU16(event_type_and_timestamp_delta);
break;
default:
NOTREACHED();
}
messages_in_frame--;
frame_log_messages.event_log_messages_.pop_front();
}
if (frame_log_messages.event_log_messages_.empty()) {
// We sent all messages on this frame; pop the frame header.
receiver_log_message->pop_front();
}
}
DCHECK_EQ(total_number_of_messages_to_send, 0);
}
} // namespace cast
......
......@@ -28,13 +28,13 @@ class RtcpSender {
void SendRtcpFromRtpSender(uint32 packet_type_flags,
const RtcpSenderInfo* sender_info,
const RtcpDlrrReportBlock* dlrr,
const RtcpSenderLogMessage* sender_log);
RtcpSenderLogMessage* sender_log);
void SendRtcpFromRtpReceiver(uint32 packet_type_flags,
const RtcpReportBlock* report_block,
const RtcpReceiverReferenceTimeReport* rrtr,
const RtcpCastMessage* cast_message,
const RtcpReceiverLogMessage* receiver_log);
RtcpReceiverLogMessage* receiver_log);
enum RtcpPacketType {
kRtcpSr = 0x0002,
......@@ -89,10 +89,10 @@ class RtcpSender {
void BuildCast(const RtcpCastMessage* cast_message,
std::vector<uint8>* packet) const;
void BuildSenderLog(const RtcpSenderLogMessage* sender_log_message,
void BuildSenderLog(RtcpSenderLogMessage* sender_log_message,
std::vector<uint8>* packet) const;
void BuildReceiverLog(const RtcpReceiverLogMessage* receiver_log_message,
void BuildReceiverLog(RtcpReceiverLogMessage* receiver_log_message,
std::vector<uint8>* packet) const;
inline void BitrateToRembExponentBitrate(uint32 bitrate,
......
......@@ -8,6 +8,7 @@
#include "media/cast/cast_environment.h"
#include "media/cast/pacing/paced_sender.h"
#include "media/cast/rtcp/rtcp_sender.h"
#include "media/cast/rtcp/rtcp_utility.h"
#include "media/cast/rtcp/test_rtcp_packet_builder.h"
#include "media/cast/test/fake_task_runner.h"
#include "testing/gmock/include/gmock/gmock.h"
......@@ -163,6 +164,85 @@ TEST_F(RtcpSenderTest, RtcpSenderReportWithDlrr) {
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpSenderReportWithDlrrAndLog) {
RtcpSenderInfo sender_info;
sender_info.ntp_seconds = kNtpHigh;
sender_info.ntp_fraction = kNtpLow;
sender_info.rtp_timestamp = kRtpTimestamp;
sender_info.send_packet_count = kSendPacketCount;
sender_info.send_octet_count = kSendOctetCount;
// Sender report + c_name + dlrr + sender log.
TestRtcpPacketBuilder p;
p.AddSr(kSendingSsrc, 0);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddXrHeader(kSendingSsrc);
p.AddXrDlrrBlock(kSendingSsrc);
p.AddSenderLog(kSendingSsrc);
p.AddSenderFrameLog(kRtcpSenderFrameStatusSentToNetwork, kRtpTimestamp);
test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length());
RtcpDlrrReportBlock dlrr_rb;
dlrr_rb.last_rr = kLastRr;
dlrr_rb.delay_since_last_rr = kDelayLastRr;
RtcpSenderFrameLogMessage sender_frame_log;
sender_frame_log.frame_status = kRtcpSenderFrameStatusSentToNetwork;
sender_frame_log.rtp_timestamp = kRtpTimestamp;
RtcpSenderLogMessage sender_log;
sender_log.push_back(sender_frame_log);
rtcp_sender_->SendRtcpFromRtpSender(
RtcpSender::kRtcpSr | RtcpSender::kRtcpDlrr | RtcpSender::kRtcpSenderLog,
&sender_info,
&dlrr_rb,
&sender_log);
EXPECT_EQ(1, test_transport_.packet_count());
EXPECT_TRUE(sender_log.empty());
}
TEST_F(RtcpSenderTest, RtcpSenderReporWithTooManyLogFrames) {
RtcpSenderInfo sender_info;
sender_info.ntp_seconds = kNtpHigh;
sender_info.ntp_fraction = kNtpLow;
sender_info.rtp_timestamp = kRtpTimestamp;
sender_info.send_packet_count = kSendPacketCount;
sender_info.send_octet_count = kSendOctetCount;
// Sender report + c_name + sender log.
TestRtcpPacketBuilder p;
p.AddSr(kSendingSsrc, 0);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddSenderLog(kSendingSsrc);
for (int i = 0; i < 359; ++i) {
p.AddSenderFrameLog(kRtcpSenderFrameStatusSentToNetwork,
kRtpTimestamp + i * 90);
}
test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length());
RtcpSenderLogMessage sender_log;
for (int j = 0; j < 400; ++j) {
RtcpSenderFrameLogMessage sender_frame_log;
sender_frame_log.frame_status = kRtcpSenderFrameStatusSentToNetwork;
sender_frame_log.rtp_timestamp = kRtpTimestamp + j * 90;
sender_log.push_back(sender_frame_log);
}
rtcp_sender_->SendRtcpFromRtpSender(
RtcpSender::kRtcpSr | RtcpSender::kRtcpSenderLog,
&sender_info,
NULL,
&sender_log);
EXPECT_EQ(1, test_transport_.packet_count());
EXPECT_EQ(41u, sender_log.size());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtr) {
// Receiver report with report block + c_name.
TestRtcpPacketBuilder p;
......@@ -179,8 +259,7 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtr) {
report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender.
report_block.fraction_lost = kLoss >> 24;
report_block.cumulative_lost = kLoss; // 24 bits valid.
report_block.extended_high_sequence_number =
kExtendedMax;
report_block.extended_high_sequence_number = kExtendedMax;
report_block.jitter = kTestJitter;
report_block.last_sr = kLastSr;
report_block.delay_since_last_sr = kDelayLastSr;
......@@ -222,8 +301,7 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithCast) {
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id_ = kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets_[
kLostFrameId] = missing_packets;
cast_message.missing_frames_and_packets_[kLostFrameId] = missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
......@@ -241,5 +319,271 @@ TEST_F(RtcpSenderTest, RtcpReceiverReportWithCast) {
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtraAndCastMessage) {
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
p.AddCast(kSendingSsrc, kMediaSsrc);
test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length());
RtcpReportBlock report_block;
// Initialize remote_ssrc to a "clearly illegal" value.
report_block.remote_ssrc = 0xDEAD;
report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender.
report_block.fraction_lost = kLoss >> 24;
report_block.cumulative_lost = kLoss; // 24 bits valid.
report_block.extended_high_sequence_number = kExtendedMax;
report_block.jitter = kTestJitter;
report_block.last_sr = kLastSr;
report_block.delay_since_last_sr = kDelayLastSr;
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id_ = kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets_[kLostFrameId] = missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
missing_packets;
rtcp_sender_->SendRtcpFromRtpReceiver(
RtcpSender::kRtcpRr | RtcpSender::kRtcpRrtr | RtcpSender::kRtcpCast,
&report_block,
&rrtr,
&cast_message,
NULL);
EXPECT_EQ(1, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithRrtrCastMessageAndLog) {
static const uint32 kTimeBaseMs = 12345678;
static const uint32 kTimeDelayMs = 10;
static const uint32 kDelayDeltaMs = 123;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
p.AddXrHeader(kSendingSsrc);
p.AddXrRrtrBlock();
p.AddCast(kSendingSsrc, kMediaSsrc);
test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length());
RtcpReportBlock report_block;
// Initialize remote_ssrc to a "clearly illegal" value.
report_block.remote_ssrc = 0xDEAD;
report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender.
report_block.fraction_lost = kLoss >> 24;
report_block.cumulative_lost = kLoss; // 24 bits valid.
report_block.extended_high_sequence_number = kExtendedMax;
report_block.jitter = kTestJitter;
report_block.last_sr = kLastSr;
report_block.delay_since_last_sr = kDelayLastSr;
RtcpReceiverReferenceTimeReport rrtr;
rrtr.ntp_seconds = kNtpHigh;
rrtr.ntp_fraction = kNtpLow;
RtcpCastMessage cast_message(kMediaSsrc);
cast_message.ack_frame_id_ = kAckFrameId;
PacketIdSet missing_packets;
cast_message.missing_frames_and_packets_[kLostFrameId] = missing_packets;
missing_packets.insert(kLostPacketId1);
missing_packets.insert(kLostPacketId2);
missing_packets.insert(kLostPacketId3);
cast_message.missing_frames_and_packets_[kFrameIdWithLostPackets] =
missing_packets;
// Test empty Log message.
RtcpReceiverLogMessage receiver_log;
VLOG(0) << " Test empty Log " ;
rtcp_sender_->SendRtcpFromRtpReceiver(
RtcpSender::kRtcpRr | RtcpSender::kRtcpRrtr | RtcpSender::kRtcpCast |
RtcpSender::kRtcpReceiverLog,
&report_block,
&rrtr,
&cast_message,
&receiver_log);
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
p.AddReceiverFrameLog(kRtpTimestamp, 2, kTimeBaseMs);
p.AddReceiverEventLog(kDelayDeltaMs, 1, 0);
p.AddReceiverEventLog(kLostPacketId1, 6, kTimeDelayMs);
test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length());
RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp);
RtcpReceiverEventLogMessage event_log;
event_log.type = kAckSent;
event_log.event_timestamp = testing_clock.NowTicks();
event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
frame_log.event_log_messages_.push_back(event_log);
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
event_log.type = kPacketReceived;
event_log.event_timestamp = testing_clock.NowTicks();
event_log.packet_id = kLostPacketId1;
frame_log.event_log_messages_.push_back(event_log);
receiver_log.push_back(frame_log);
VLOG(0) << " Test Log " ;
rtcp_sender_->SendRtcpFromRtpReceiver(
RtcpSender::kRtcpRr | RtcpSender::kRtcpRrtr | RtcpSender::kRtcpCast |
RtcpSender::kRtcpReceiverLog,
&report_block,
&rrtr,
&cast_message,
&receiver_log);
EXPECT_TRUE(receiver_log.empty());
EXPECT_EQ(2, test_transport_.packet_count());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithOversizedFrameLog) {
static const uint32 kTimeBaseMs = 12345678;
static const uint32 kTimeDelayMs = 10;
static const uint32 kDelayDeltaMs = 123;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
RtcpReportBlock report_block;
// Initialize remote_ssrc to a "clearly illegal" value.
report_block.remote_ssrc = 0xDEAD;
report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender.
report_block.fraction_lost = kLoss >> 24;
report_block.cumulative_lost = kLoss; // 24 bits valid.
report_block.extended_high_sequence_number = kExtendedMax;
report_block.jitter = kTestJitter;
report_block.last_sr = kLastSr;
report_block.delay_since_last_sr = kDelayLastSr;
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs);
p.AddReceiverEventLog(kDelayDeltaMs, 1, 0);
p.AddReceiverFrameLog(kRtpTimestamp + 2345,
kRtcpMaxReceiverLogMessages, kTimeBaseMs);
for (size_t i = 0; i < kRtcpMaxReceiverLogMessages; ++i) {
p.AddReceiverEventLog(kLostPacketId1, 6, kTimeDelayMs * i);
}
test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length());
RtcpReceiverFrameLogMessage frame_1_log(kRtpTimestamp);
RtcpReceiverEventLogMessage event_log;
event_log.type = kAckSent;
event_log.event_timestamp = testing_clock.NowTicks();
event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
frame_1_log.event_log_messages_.push_back(event_log);
RtcpReceiverLogMessage receiver_log;
receiver_log.push_back(frame_1_log);
RtcpReceiverFrameLogMessage frame_2_log(kRtpTimestamp + 2345);
for (int j = 0; j < 300; ++j) {
event_log.type = kPacketReceived;
event_log.event_timestamp = testing_clock.NowTicks();
event_log.packet_id = kLostPacketId1;
frame_2_log.event_log_messages_.push_back(event_log);
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
}
receiver_log.push_back(frame_2_log);
rtcp_sender_->SendRtcpFromRtpReceiver(
RtcpSender::kRtcpRr | RtcpSender::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
&receiver_log);
EXPECT_EQ(1, test_transport_.packet_count());
EXPECT_EQ(1u, receiver_log.size());
EXPECT_EQ(300u - kRtcpMaxReceiverLogMessages,
receiver_log.front().event_log_messages_.size());
}
TEST_F(RtcpSenderTest, RtcpReceiverReportWithTooManyLogFrames) {
static const uint32 kTimeBaseMs = 12345678;
static const uint32 kTimeDelayMs = 10;
static const uint32 kDelayDeltaMs = 123;
TestRtcpPacketBuilder p;
p.AddRr(kSendingSsrc, 1);
p.AddRb(kMediaSsrc);
p.AddSdesCname(kSendingSsrc, kCName);
RtcpReportBlock report_block;
// Initialize remote_ssrc to a "clearly illegal" value.
report_block.remote_ssrc = 0xDEAD;
report_block.media_ssrc = kMediaSsrc; // SSRC of the RTP packet sender.
report_block.fraction_lost = kLoss >> 24;
report_block.cumulative_lost = kLoss; // 24 bits valid.
report_block.extended_high_sequence_number = kExtendedMax;
report_block.jitter = kTestJitter;
report_block.last_sr = kLastSr;
report_block.delay_since_last_sr = kDelayLastSr;
base::SimpleTestTickClock testing_clock;
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeBaseMs));
p.AddReceiverLog(kSendingSsrc);
for (int i = 0; i < 119; ++i) {
p.AddReceiverFrameLog(kRtpTimestamp, 1, kTimeBaseMs + i * kTimeDelayMs);
p.AddReceiverEventLog(kDelayDeltaMs, 1, 0);
}
test_transport_.SetExpectedRtcpPacket(p.Packet(), p.Length());
RtcpReceiverLogMessage receiver_log;
for (int j = 0; j < 200; ++j) {
RtcpReceiverFrameLogMessage frame_log(kRtpTimestamp);
RtcpReceiverEventLogMessage event_log;
event_log.type = kAckSent;
event_log.event_timestamp = testing_clock.NowTicks();
event_log.delay_delta = base::TimeDelta::FromMilliseconds(kDelayDeltaMs);
frame_log.event_log_messages_.push_back(event_log);
receiver_log.push_back(frame_log);
testing_clock.Advance(base::TimeDelta::FromMilliseconds(kTimeDelayMs));
}
rtcp_sender_->SendRtcpFromRtpReceiver(
RtcpSender::kRtcpRr | RtcpSender::kRtcpReceiverLog,
&report_block,
NULL,
NULL,
&receiver_log);
EXPECT_EQ(1, test_transport_.packet_count());
EXPECT_EQ(81u, receiver_log.size());
}
} // namespace cast
} // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment