#include "base/logging.h"
#include "media/cast/cast_environment.h"
+#include "media/cast/rtcp/receiver_rtcp_event_subscriber.h"
+#include "media/cast/rtcp/rtcp_defines.h"
#include "media/cast/rtcp/rtcp_utility.h"
#include "media/cast/transport/cast_transport_defines.h"
#include "media/cast/transport/pacing/paced_sender.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 {
+using media::cast::kRtcpCastLogHeaderSize;
+using media::cast::kRtcpSenderFrameLogSize;
+using media::cast::kRtcpReceiverFrameLogSize;
+using media::cast::kRtcpReceiverEventLogSize;
+
// Converts a log event type to an integer value.
int ConvertEventTypeToWireFormat(const media::cast::CastLoggingEvent& event) {
switch (event) {
return 7;
case media::cast::kVideoPacketReceived:
return 8;
- case media::cast::kDuplicatePacketReceived:
+ case media::cast::kDuplicateAudioPacketReceived:
return 9;
+ case media::cast::kDuplicateVideoPacketReceived:
+ return 10;
default:
return 0; // Not an interesting event.
}
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) {
+ 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::kMaxIpPacketSize - start_size;
// We must have space for at least one message
DCHECK_GE(remaining_space, kRtcpCastLogHeaderSize +
- kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize)
+ kRtcpReceiverFrameLogSize +
+ kRtcpReceiverEventLogSize)
<< "Not enough buffer space";
if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize +
- kRtcpReceiverEventLogSize) {
+ kRtcpReceiverEventLogSize) {
return false;
}
// Account for the RTCP header for an application-defined packet.
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);
+ 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;
+ remaining_space -=
+ media::cast::kRtcpMaxReceiverLogMessages * kRtcpReceiverEventLogSize;
*total_number_of_messages_to_send +=
media::cast::kRtcpMaxReceiverLogMessages;
break;
break;
}
}
- *rtcp_log_size = kRtcpCastLogHeaderSize +
- *number_of_frames * kRtcpReceiverFrameLogSize +
+ *rtcp_log_size =
+ kRtcpCastLogHeaderSize + *number_of_frames * kRtcpReceiverFrameLogSize +
*total_number_of_messages_to_send * kRtcpReceiverEventLogSize;
- DCHECK_GE(media::cast::kMaxIpPacketSize,
- start_size + *rtcp_log_size) << "Not enough buffer space";
+ DCHECK_GE(media::cast::kMaxIpPacketSize, 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;
// TODO(mikhal): This is only used by the receiver. Consider renaming.
RtcpSender::RtcpSender(scoped_refptr<CastEnvironment> cast_environment,
transport::PacedPacketSender* outgoing_transport,
- uint32 sending_ssrc,
- const std::string& c_name)
- : ssrc_(sending_ssrc),
- c_name_(c_name),
- transport_(outgoing_transport),
- cast_environment_(cast_environment) {
+ uint32 sending_ssrc, const std::string& c_name)
+ : ssrc_(sending_ssrc),
+ c_name_(c_name),
+ transport_(outgoing_transport),
+ cast_environment_(cast_environment) {
DCHECK_LT(c_name_.length(), kRtcpCnameSize) << "Invalid config";
}
const transport::RtcpReportBlock* report_block,
const RtcpReceiverReferenceTimeReport* rrtr,
const RtcpCastMessage* cast_message,
- RtcpReceiverLogMessage* receiver_log) {
- if (packet_type_flags & kRtcpSr ||
- packet_type_flags & kRtcpDlrr ||
+ ReceiverRtcpEventSubscriber* event_subscriber) {
+ if (packet_type_flags & kRtcpSr || packet_type_flags & kRtcpDlrr ||
packet_type_flags & kRtcpSenderLog) {
NOTREACHED() << "Invalid argument";
}
- if (packet_type_flags & kRtcpPli ||
- packet_type_flags & kRtcpRpsi ||
- packet_type_flags & kRtcpRemb ||
- packet_type_flags & kRtcpNack) {
+ if (packet_type_flags & kRtcpPli || packet_type_flags & kRtcpRpsi ||
+ packet_type_flags & kRtcpRemb || packet_type_flags & kRtcpNack) {
// Implement these for webrtc interop.
NOTIMPLEMENTED();
}
BuildCast(cast_message, &packet);
}
if (packet_type_flags & kRtcpReceiverLog) {
- DCHECK(receiver_log) << "Invalid argument";
- BuildReceiverLog(receiver_log, &packet);
+ DCHECK(event_subscriber) << "Invalid argument";
+ RtcpReceiverLogMessage receiver_log;
+ event_subscriber->GetReceiverLogMessageAndReset(&receiver_log);
+ BuildReceiverLog(&receiver_log, &packet);
}
if (packet.empty()) return; // Sanity don't send empty packets.
void RtcpSender::BuildSdec(Packet* packet) const {
size_t start_size = packet->size();
- DCHECK_LT(start_size + 12 + c_name_.length(), kMaxIpPacketSize)
+ DCHECK_LT(start_size + 12 + c_name_.length(), kMaxIpPacketSize)
<< "Not enough buffer space";
if (start_size + 12 > kMaxIpPacketSize) return;
uint32 sdes_length_position = static_cast<uint32>(start_size) + 3;
big_endian_writer.WriteU16(0);
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
- big_endian_writer.WriteU8(1); // CNAME = 1
+ big_endian_writer.WriteU8(1); // CNAME = 1
big_endian_writer.WriteU8(static_cast<uint8>(c_name_.length()));
size_t sdes_length = 10 + c_name_.length();
(*packet)[sdes_length_position] = buffer_length;
}
-void RtcpSender::BuildPli(uint32 remote_ssrc,
- Packet* packet) const {
+void RtcpSender::BuildPli(uint32 remote_ssrc, Packet* packet) const {
size_t start_size = packet->size();
DCHECK_LT(start_size + 12, kMaxIpPacketSize) << "Not enough buffer space";
if (start_size + 12 > kMaxIpPacketSize) return;
uint8 FMT = 1; // Picture loss indicator.
big_endian_writer.WriteU8(0x80 + FMT);
big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific);
- big_endian_writer.WriteU16(2); // Used fixed length of 2.
- big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
+ 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.
}
| defined per codec ... | Padding (0) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
-void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi,
- Packet* packet) const {
+void RtcpSender::BuildRpsi(const RtcpRpsiMessage* rpsi, Packet* packet) const {
size_t start_size = packet->size();
DCHECK_LT(start_size + 24, kMaxIpPacketSize) << "Not enough buffer space";
if (start_size + 24 > kMaxIpPacketSize) return;
// Add picture ID.
for (int i = bytes_required - 1; i > 0; i--) {
- big_endian_writer.WriteU8(
- 0x80 | static_cast<uint8>(rpsi->picture_id >> (i * 7)));
+ big_endian_writer.WriteU8(0x80 |
+ static_cast<uint8>(rpsi->picture_id >> (i * 7)));
}
// Add last byte of picture ID.
big_endian_writer.WriteU8(static_cast<uint8>(rpsi->picture_id & 0x7f));
}
}
-void RtcpSender::BuildRemb(const RtcpRembMessage* remb,
- Packet* packet) const {
+void RtcpSender::BuildRemb(const RtcpRembMessage* remb, Packet* packet) const {
size_t start_size = packet->size();
size_t remb_size = 20 + 4 * remb->remb_ssrcs.size();
DCHECK_LT(start_size + remb_size, kMaxIpPacketSize)
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.
- big_endian_writer.WriteU32(0); // Remote SSRC must be 0.
+ big_endian_writer.WriteU32(0); // Remote SSRC must be 0.
big_endian_writer.WriteU32(kRemb);
big_endian_writer.WriteU8(static_cast<uint8>(remb->remb_ssrcs.size()));
// 6 bit exponent and a 18 bit mantissa.
uint8 bitrate_exponent;
uint32 bitrate_mantissa;
- BitrateToRembExponentBitrate(remb->remb_bitrate,
- &bitrate_exponent,
+ BitrateToRembExponentBitrate(remb->remb_bitrate, &bitrate_exponent,
&bitrate_mantissa);
- big_endian_writer.WriteU8(static_cast<uint8>((bitrate_exponent << 2) +
- ((bitrate_mantissa >> 16) & 0x03)));
+ big_endian_writer.WriteU8(static_cast<uint8>(
+ (bitrate_exponent << 2) + ((bitrate_mantissa >> 16) & 0x03)));
big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa >> 8));
big_endian_writer.WriteU8(static_cast<uint8>(bitrate_mantissa));
remb->remb_bitrate);
}
-void RtcpSender::BuildNack(const RtcpNackMessage* nack,
- Packet* packet) const {
+void RtcpSender::BuildNack(const RtcpNackMessage* nack, Packet* packet) const {
size_t start_size = packet->size();
DCHECK_LT(start_size + 16, kMaxIpPacketSize) << "Not enough buffer space";
if (start_size + 16 > kMaxIpPacketSize) return;
big_endian_writer.WriteU8(0);
size_t nack_size_pos = start_size + 3;
big_endian_writer.WriteU8(3);
- big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
+ big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
big_endian_writer.WriteU32(nack->remote_ssrc); // Add the remote SSRC.
// Build NACK bitmasks and write them to the Rtcp message.
// The nack list should be sorted and not contain duplicates.
size_t number_of_nack_fields = 0;
- size_t max_number_of_nack_fields = std::min<size_t>(kRtcpMaxNackFields,
- (kMaxIpPacketSize - packet->size()) / 4);
+ size_t max_number_of_nack_fields = std::min<size_t>(
+ kRtcpMaxNackFields, (kMaxIpPacketSize - packet->size()) / 4);
std::list<uint16>::const_iterator it = nack->nack_list.begin();
while (it != nack->nack_list.end() &&
net::BigEndianWriter big_endian_writer(&((*packet)[start_size]), 8);
big_endian_writer.WriteU8(0x80 + 1);
big_endian_writer.WriteU8(transport::kPacketTypeBye);
- big_endian_writer.WriteU16(1); // Length.
+ big_endian_writer.WriteU16(1); // Length.
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
}
big_endian_writer.WriteU8(0x80);
big_endian_writer.WriteU8(transport::kPacketTypeXr);
- big_endian_writer.WriteU16(4); // Length.
+ big_endian_writer.WriteU16(4); // Length.
big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
- big_endian_writer.WriteU8(4); // Add block type.
- big_endian_writer.WriteU8(0); // Add reserved.
- big_endian_writer.WriteU16(2); // Block length.
+ big_endian_writer.WriteU8(4); // Add block type.
+ big_endian_writer.WriteU8(0); // Add reserved.
+ big_endian_writer.WriteU16(2); // Block length.
// Add the media (received RTP) SSRC.
big_endian_writer.WriteU32(rrtr->ntp_seconds);
big_endian_writer.WriteU32(rrtr->ntp_fraction);
}
-void RtcpSender::BuildCast(const RtcpCastMessage* cast,
- Packet* packet) const {
+void RtcpSender::BuildCast(const RtcpCastMessage* cast, Packet* packet) const {
size_t start_size = packet->size();
DCHECK_LT(start_size + 20, kMaxIpPacketSize) << "Not enough buffer space";
if (start_size + 20 > kMaxIpPacketSize) return;
big_endian_writer.WriteU8(0x80 + FMT);
big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific);
big_endian_writer.WriteU8(0);
- size_t cast_size_pos = start_size + 3; // Save length position.
+ size_t cast_size_pos = start_size + 3; // Save length position.
big_endian_writer.WriteU8(4);
- big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
+ big_endian_writer.WriteU32(ssrc_); // Add our own SSRC.
big_endian_writer.WriteU32(cast->media_ssrc_); // Remote SSRC.
big_endian_writer.WriteU32(kCast);
big_endian_writer.WriteU8(static_cast<uint8>(cast->ack_frame_id_));
big_endian_writer.WriteU8(0); // Reserved.
size_t number_of_loss_fields = 0;
- size_t max_number_of_loss_fields = std::min<size_t>(kRtcpMaxCastLossFields,
- (kMaxIpPacketSize - packet->size()) / 4);
+ size_t max_number_of_loss_fields = std::min<size_t>(
+ kRtcpMaxCastLossFields, (kMaxIpPacketSize - packet->size()) / 4);
MissingFramesAndPacketsMap::const_iterator frame_it =
cast->missing_frames_and_packets_.begin();
for (; frame_it != cast->missing_frames_and_packets_.end() &&
- number_of_loss_fields < max_number_of_loss_fields; ++frame_it) {
+ number_of_loss_fields < max_number_of_loss_fields;
+ ++frame_it) {
// Iterate through all frames with missing packets.
if (frame_it->second.empty()) {
// Special case all packets in a frame is missing.
start_size = packet->size();
packet->resize(start_size + 4);
- net::BigEndianWriter big_endian_nack_writer(
- &((*packet)[start_size]), 4);
+ net::BigEndianWriter big_endian_nack_writer(&((*packet)[start_size]),
+ 4);
// Write frame and packet id to buffer before calculating bitmask.
big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first));
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)) {
+ 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);
rtcp_log_size);
big_endian_writer.WriteU8(0x80 + kReceiverLogSubtype);
big_endian_writer.WriteU8(transport::kPacketTypeApplicationDefined);
- big_endian_writer.WriteU16(static_cast<uint16>(2 + 2 * number_of_frames +
- total_number_of_messages_to_send));
+ 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();
+ 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();
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);
+ MergeEventTypeAndTimestampForWireFormat(
+ event_message.type,
+ event_message.event_timestamp - event_timestamp_base);
switch (event_message.type) {
case kAudioAckSent:
case kVideoAckSent:
case kAudioFrameDecoded:
case kVideoFrameDecoded:
case kVideoRenderDelay:
- big_endian_writer.WriteU16(static_cast<uint16>(
- event_message.delay_delta.InMilliseconds()));
+ big_endian_writer.WriteU16(
+ static_cast<uint16>(event_message.delay_delta.InMilliseconds()));
big_endian_writer.WriteU16(event_type_and_timestamp_delta);
break;
case kAudioPacketReceived:
case kVideoPacketReceived:
- case kDuplicatePacketReceived:
+ case kDuplicateAudioPacketReceived:
+ case kDuplicateVideoPacketReceived:
big_endian_writer.WriteU16(event_message.packet_id);
big_endian_writer.WriteU16(event_type_and_timestamp_delta);
break;