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

Unified Diff: media/cast/rtcp/rtcp_sender.cc

Issue 74613004: Cast: Add capabity to send Receiver and Sender log messages over RTCP. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@rtcp_logging
Patch Set: Added missing static casts Created 7 years 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/cast/rtcp/rtcp_sender.h ('k') | media/cast/rtcp/rtcp_sender_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/cast/rtcp/rtcp_sender.cc
diff --git a/media/cast/rtcp/rtcp_sender.cc b/media/cast/rtcp/rtcp_sender.cc
index 76e81e06b6d7131021ca07cee579ddc2bf50eda2..473e1b4913a6caeca4689b1894b74205b8bf1a28 100644
--- a/media/cast/rtcp/rtcp_sender.cc
+++ b/media/cast/rtcp/rtcp_sender.cc
@@ -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
« no previous file with comments | « media/cast/rtcp/rtcp_sender.h ('k') | media/cast/rtcp/rtcp_sender_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698