Index: media/cast/rtcp/rtcp_sender.cc |
diff --git a/media/cast/rtcp/rtcp_sender.cc b/media/cast/rtcp/rtcp_sender.cc |
index 465e9c8c48b8771e491ab8fadab97ef7e79a9910..b5999331a7bbccb70426a82a245d29b055094be2 100644 |
--- a/media/cast/rtcp/rtcp_sender.cc |
+++ b/media/cast/rtcp/rtcp_sender.cc |
@@ -13,12 +13,102 @@ |
#include "media/cast/rtcp/rtcp_utility.h" |
#include "net/base/big_endian.h" |
+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(); |
mikhal
2013/11/21 16:43:20
The receiver also includes jitter and packet loss
pwestin
2013/11/22 18:50:47
The difference is that this is intended for timing
|
+ } |
+ 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, 16) << "Not enough buffer space"; |
+ if (remaining_space < 16) return false; |
+ |
+ // Account for the RTCP header for an application-defined packet. |
+ remaining_space -= 12; |
mikhal
2013/11/21 16:43:20
use consts, here and elsewhere.
pwestin
2013/11/22 18:50:47
Done.
|
+ |
+ 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 -= 8; |
+ |
+ size_t messages_in_frame = frame_it->event_log_messages.size(); |
+ size_t remaining_space_in_messages = remaining_space / 4; |
+ 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 * 4; |
+ *total_number_of_messages_to_send += |
+ media::cast::kRtcpMaxReceiverLogMessages; |
+ break; |
+ } |
+ remaining_space -= messages_to_send * 4; |
+ *total_number_of_messages_to_send += messages_to_send; |
+ |
+ if (remaining_space < 12) { |
+ // Make sure that we have room for at least one more message. |
+ break; |
+ } |
+ } |
+ *rtcp_log_size = 12 + *number_of_frames * 8 + |
+ *total_number_of_messages_to_send * 4; |
+ 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 { |
-static const size_t kRtcpMaxNackFields = 253; |
-static const size_t kRtcpMaxCastLossFields = 100; |
- |
RtcpSender::RtcpSender(PacedPacketSender* outgoing_transport, |
uint32 sending_ssrc, |
const std::string& c_name) |
@@ -33,7 +123,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 || |
@@ -74,7 +164,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) { |
@@ -129,7 +219,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); |
@@ -154,7 +244,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_); |
@@ -203,7 +293,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; |
@@ -245,7 +335,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. |
@@ -274,7 +364,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; |
@@ -331,7 +421,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. |
@@ -371,7 +461,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); |
@@ -425,7 +515,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. |
} |
@@ -457,7 +547,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. |
@@ -479,7 +569,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. |
@@ -502,7 +592,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); |
@@ -573,17 +663,126 @@ void RtcpSender::BuildCast(const RtcpCastMessage* cast, |
cast->missing_frames_and_packets_.size()); |
} |
-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); |
+ static const size_t kRtcpMinSendLogSize = 16; |
+ size_t start_size = packet->size(); |
+ size_t remaining_space = kIpPacketSize - start_size; |
+ DCHECK_GE(remaining_space, kRtcpMinSendLogSize) << "Not enough buffer space"; |
+ if (remaining_space < kRtcpMinSendLogSize) return; |
+ |
+ size_t space_for_x_messages = (remaining_space - 12) / 4; |
+ size_t number_of_messages = std::min(space_for_x_messages, |
+ sender_log_message->size()); |
+ |
+ size_t log_size = 12 + number_of_messages * 4; |
+ 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(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(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(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 |