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

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

Issue 388663003: Cast: Reshuffle files under media/cast (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: missing includes Created 6 years, 5 months 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
deleted file mode 100644
index 4bed3773f65079964aee741ff3b593ee32a5068c..0000000000000000000000000000000000000000
--- a/media/cast/rtcp/rtcp_sender.cc
+++ /dev/null
@@ -1,827 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "media/cast/rtcp/rtcp_sender.h"
-
-#include <stdint.h>
-
-#include <algorithm>
-#include <vector>
-
-#include "base/big_endian.h"
-#include "base/logging.h"
-#include "media/cast/cast_environment.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"
-
-namespace media {
-namespace cast {
-namespace {
-
-// Max delta is 4095 milliseconds because we need to be able to encode it in
-// 12 bits.
-const int64 kMaxWireFormatTimeDeltaMs = INT64_C(0xfff);
-
-uint16 MergeEventTypeAndTimestampForWireFormat(
- const CastLoggingEvent& event,
- const base::TimeDelta& time_delta) {
- int64 time_delta_ms = time_delta.InMilliseconds();
-
- DCHECK_GE(time_delta_ms, 0);
- DCHECK_LE(time_delta_ms, kMaxWireFormatTimeDeltaMs);
-
- uint16 time_delta_12_bits =
- static_cast<uint16>(time_delta_ms & kMaxWireFormatTimeDeltaMs);
-
- uint16 event_type_4_bits = ConvertEventTypeToWireFormat(event);
- DCHECK(event_type_4_bits);
- DCHECK(~(event_type_4_bits & 0xfff0));
- return (event_type_4_bits << 12) | time_delta_12_bits;
-}
-
-bool EventTimestampLessThan(const RtcpReceiverEventLogMessage& lhs,
- const RtcpReceiverEventLogMessage& rhs) {
- return lhs.event_timestamp < rhs.event_timestamp;
-}
-
-void AddReceiverLog(
- const RtcpReceiverLogMessage& redundancy_receiver_log_message,
- RtcpReceiverLogMessage* receiver_log_message,
- size_t* remaining_space,
- size_t* number_of_frames,
- size_t* total_number_of_messages_to_send) {
- RtcpReceiverLogMessage::const_iterator it =
- redundancy_receiver_log_message.begin();
- while (it != redundancy_receiver_log_message.end() &&
- *remaining_space >=
- kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) {
- receiver_log_message->push_front(*it);
- size_t num_event_logs = (*remaining_space - kRtcpReceiverFrameLogSize) /
- kRtcpReceiverEventLogSize;
- RtcpReceiverEventLogMessages& event_log_messages =
- receiver_log_message->front().event_log_messages_;
- if (num_event_logs < event_log_messages.size())
- event_log_messages.resize(num_event_logs);
-
- *remaining_space -= kRtcpReceiverFrameLogSize +
- event_log_messages.size() * kRtcpReceiverEventLogSize;
- ++*number_of_frames;
- *total_number_of_messages_to_send += event_log_messages.size();
- ++it;
- }
-}
-
-// A class to build a string representing the NACK list in Cast message.
-//
-// The string will look like "23:3-6 25:1,5-6", meaning packets 3 to 6 in frame
-// 23 are being NACK'ed (i.e. they are missing from the receiver's point of
-// view) and packets 1, 5 and 6 are missing in frame 25. A frame that is
-// completely missing will show as "26:65535".
-class NackStringBuilder {
- public:
- NackStringBuilder()
- : frame_count_(0),
- packet_count_(0),
- last_frame_id_(-1),
- last_packet_id_(-1),
- contiguous_sequence_(false) {}
- ~NackStringBuilder() {}
-
- bool Empty() const { return frame_count_ == 0; }
-
- void PushFrame(int frame_id) {
- DCHECK_GE(frame_id, 0);
- if (frame_count_ > 0) {
- if (frame_id == last_frame_id_) {
- return;
- }
- if (contiguous_sequence_) {
- stream_ << "-" << last_packet_id_;
- }
- stream_ << ", ";
- }
- stream_ << frame_id;
- last_frame_id_ = frame_id;
- packet_count_ = 0;
- contiguous_sequence_ = false;
- ++frame_count_;
- }
-
- void PushPacket(int packet_id) {
- DCHECK_GE(last_frame_id_, 0);
- DCHECK_GE(packet_id, 0);
- if (packet_count_ == 0) {
- stream_ << ":" << packet_id;
- } else if (packet_id == last_packet_id_ + 1) {
- contiguous_sequence_ = true;
- } else {
- if (contiguous_sequence_) {
- stream_ << "-" << last_packet_id_;
- contiguous_sequence_ = false;
- }
- stream_ << "," << packet_id;
- }
- ++packet_count_;
- last_packet_id_ = packet_id;
- }
-
- std::string GetString() {
- if (contiguous_sequence_) {
- stream_ << "-" << last_packet_id_;
- contiguous_sequence_ = false;
- }
- return stream_.str();
- }
-
- private:
- std::ostringstream stream_;
- int frame_count_;
- int packet_count_;
- int last_frame_id_;
- int last_packet_id_;
- bool contiguous_sequence_;
-};
-} // namespace
-
-// 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) {
- DCHECK_LT(c_name_.length(), kRtcpCnameSize) << "Invalid config";
-}
-
-RtcpSender::~RtcpSender() {}
-
-void RtcpSender::SendRtcpFromRtpReceiver(
- uint32 packet_type_flags,
- const transport::RtcpReportBlock* report_block,
- const RtcpReceiverReferenceTimeReport* rrtr,
- const RtcpCastMessage* cast_message,
- const ReceiverRtcpEventSubscriber::RtcpEventMultiMap* rtcp_events,
- base::TimeDelta target_delay) {
- if (packet_type_flags & transport::kRtcpSr ||
- packet_type_flags & transport::kRtcpDlrr ||
- packet_type_flags & transport::kRtcpSenderLog) {
- NOTREACHED() << "Invalid argument";
- }
- if (packet_type_flags & transport::kRtcpPli ||
- packet_type_flags & transport::kRtcpRpsi ||
- packet_type_flags & transport::kRtcpRemb ||
- packet_type_flags & transport::kRtcpNack) {
- // Implement these for webrtc interop.
- NOTIMPLEMENTED();
- }
- transport::PacketRef packet(new base::RefCountedData<Packet>);
- packet->data.reserve(kMaxIpPacketSize);
-
- if (packet_type_flags & transport::kRtcpRr) {
- BuildRR(report_block, &packet->data);
- if (!c_name_.empty()) {
- BuildSdec(&packet->data);
- }
- }
- if (packet_type_flags & transport::kRtcpBye) {
- BuildBye(&packet->data);
- }
- if (packet_type_flags & transport::kRtcpRrtr) {
- DCHECK(rrtr) << "Invalid argument";
- BuildRrtr(rrtr, &packet->data);
- }
- if (packet_type_flags & transport::kRtcpCast) {
- DCHECK(cast_message) << "Invalid argument";
- BuildCast(cast_message, target_delay, &packet->data);
- }
- if (packet_type_flags & transport::kRtcpReceiverLog) {
- DCHECK(rtcp_events) << "Invalid argument";
- BuildReceiverLog(*rtcp_events, &packet->data);
- }
-
- if (packet->data.empty())
- return; // Sanity don't send empty packets.
-
- transport_->SendRtcpPacket(ssrc_, packet);
-}
-
-void RtcpSender::BuildRR(const transport::RtcpReportBlock* report_block,
- Packet* packet) const {
- size_t start_size = packet->size();
- DCHECK_LT(start_size + 32, kMaxIpPacketSize) << "Not enough buffer space";
- if (start_size + 32 > kMaxIpPacketSize)
- return;
-
- uint16 number_of_rows = (report_block) ? 7 : 1;
- packet->resize(start_size + 8);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 8);
- big_endian_writer.WriteU8(0x80 + (report_block ? 1 : 0));
- big_endian_writer.WriteU8(transport::kPacketTypeReceiverReport);
- big_endian_writer.WriteU16(number_of_rows);
- big_endian_writer.WriteU32(ssrc_);
-
- if (report_block) {
- AddReportBlocks(*report_block, packet); // Adds 24 bytes.
- }
-}
-
-void RtcpSender::AddReportBlocks(const transport::RtcpReportBlock& report_block,
- 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;
-
- packet->resize(start_size + 24);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 24);
- big_endian_writer.WriteU32(report_block.media_ssrc);
- big_endian_writer.WriteU8(report_block.fraction_lost);
- big_endian_writer.WriteU8(report_block.cumulative_lost >> 16);
- big_endian_writer.WriteU8(report_block.cumulative_lost >> 8);
- big_endian_writer.WriteU8(report_block.cumulative_lost);
-
- // Extended highest seq_no, contain the highest sequence number received.
- big_endian_writer.WriteU32(report_block.extended_high_sequence_number);
- big_endian_writer.WriteU32(report_block.jitter);
-
- // Last SR timestamp; our NTP time when we received the last report.
- // This is the value that we read from the send report packet not when we
- // received it.
- big_endian_writer.WriteU32(report_block.last_sr);
-
- // Delay since last received report, time since we received the report.
- big_endian_writer.WriteU32(report_block.delay_since_last_sr);
-}
-
-void RtcpSender::BuildSdec(Packet* packet) const {
- size_t start_size = packet->size();
- DCHECK_LT(start_size + 12 + c_name_.length(), kMaxIpPacketSize)
- << "Not enough buffer space";
- if (start_size + 12 > kMaxIpPacketSize)
- return;
-
- // SDES Source Description.
- packet->resize(start_size + 10);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 10);
- // We always need to add one SDES CNAME.
- big_endian_writer.WriteU8(0x80 + 1);
- big_endian_writer.WriteU8(transport::kPacketTypeSdes);
-
- // Handle SDES length later on.
- 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(static_cast<uint8>(c_name_.length()));
-
- size_t sdes_length = 10 + c_name_.length();
- packet->insert(
- packet->end(), c_name_.c_str(), c_name_.c_str() + c_name_.length());
-
- size_t padding = 0;
-
- // We must have a zero field even if we have an even multiple of 4 bytes.
- if ((packet->size() % 4) == 0) {
- padding++;
- packet->push_back(0);
- }
- while ((packet->size() % 4) != 0) {
- padding++;
- packet->push_back(0);
- }
- sdes_length += padding;
-
- // In 32-bit words minus one and we don't count the header.
- uint8 buffer_length = static_cast<uint8>((sdes_length / 4) - 1);
- (*packet)[sdes_length_position] = buffer_length;
-}
-
-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;
-
- packet->resize(start_size + 12);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 12);
- 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.WriteU32(remote_ssrc); // Add the remote SSRC.
-}
-
-/*
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | PB |0| Payload Type| Native Rpsi bit string |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | defined per codec ... | Padding (0) |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
-*/
-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;
-
- packet->resize(start_size + 24);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 24);
- uint8 FMT = 3; // Reference Picture Selection Indication.
- big_endian_writer.WriteU8(0x80 + FMT);
- big_endian_writer.WriteU8(transport::kPacketTypePayloadSpecific);
-
- // Calculate length.
- uint32 bits_required = 7;
- uint8 bytes_required = 1;
- while ((rpsi->picture_id >> bits_required) > 0) {
- bits_required += 7;
- bytes_required++;
- }
- uint8 size = 3;
- if (bytes_required > 6) {
- size = 5;
- } else if (bytes_required > 2) {
- size = 4;
- }
- big_endian_writer.WriteU8(0);
- big_endian_writer.WriteU8(size);
- big_endian_writer.WriteU32(ssrc_);
- big_endian_writer.WriteU32(rpsi->remote_ssrc);
-
- uint8 padding_bytes = 4 - ((2 + bytes_required) % 4);
- if (padding_bytes == 4) {
- padding_bytes = 0;
- }
- // Add padding length in bits, padding can be 0, 8, 16 or 24.
- big_endian_writer.WriteU8(padding_bytes * 8);
- big_endian_writer.WriteU8(rpsi->payload_type);
-
- // 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)));
- }
- // Add last byte of picture ID.
- big_endian_writer.WriteU8(static_cast<uint8>(rpsi->picture_id & 0x7f));
-
- // Add padding.
- for (int j = 0; j < padding_bytes; ++j) {
- big_endian_writer.WriteU8(0);
- }
-}
-
-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)
- << "Not enough buffer space";
- if (start_size + remb_size > kMaxIpPacketSize)
- return;
-
- packet->resize(start_size + remb_size);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), remb_size);
-
- // Add application layer feedback.
- uint8 FMT = 15;
- big_endian_writer.WriteU8(0x80 + FMT);
- big_endian_writer.WriteU8(transport::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.
- 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, &bitrate_mantissa);
-
- 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));
-
- std::list<uint32>::const_iterator it = remb->remb_ssrcs.begin();
- for (; it != remb->remb_ssrcs.end(); ++it) {
- big_endian_writer.WriteU32(*it);
- }
-}
-
-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;
-
- packet->resize(start_size + 16);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 16);
-
- uint8 FMT = 1;
- big_endian_writer.WriteU8(0x80 + FMT);
- big_endian_writer.WriteU8(transport::kPacketTypeGenericRtpFeedback);
- 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(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);
-
- std::list<uint16>::const_iterator it = nack->nack_list.begin();
- while (it != nack->nack_list.end() &&
- number_of_nack_fields < max_number_of_nack_fields) {
- uint16 nack_sequence_number = *it;
- uint16 bitmask = 0;
- ++it;
- while (it != nack->nack_list.end()) {
- int shift = static_cast<uint16>(*it - nack_sequence_number) - 1;
- if (shift >= 0 && shift <= 15) {
- bitmask |= (1 << shift);
- ++it;
- } else {
- break;
- }
- }
- // Write the sequence number and the bitmask to the packet.
- start_size = packet->size();
- DCHECK_LT(start_size + 4, kMaxIpPacketSize) << "Not enough buffer space";
- if (start_size + 4 > kMaxIpPacketSize)
- return;
-
- packet->resize(start_size + 4);
- base::BigEndianWriter big_endian_nack_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 4);
- big_endian_nack_writer.WriteU16(nack_sequence_number);
- big_endian_nack_writer.WriteU16(bitmask);
- number_of_nack_fields++;
- }
- DCHECK_GE(kRtcpMaxNackFields, number_of_nack_fields);
- (*packet)[nack_size_pos] = static_cast<uint8>(2 + number_of_nack_fields);
-}
-
-void RtcpSender::BuildBye(Packet* packet) const {
- size_t start_size = packet->size();
- DCHECK_LT(start_size + 8, kMaxIpPacketSize) << "Not enough buffer space";
- if (start_size + 8 > kMaxIpPacketSize)
- return;
-
- packet->resize(start_size + 8);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*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.WriteU32(ssrc_); // Add our own SSRC.
-}
-
-void RtcpSender::BuildRrtr(const RtcpReceiverReferenceTimeReport* rrtr,
- 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;
-
- packet->resize(start_size + 20);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 20);
-
- big_endian_writer.WriteU8(0x80);
- big_endian_writer.WriteU8(transport::kPacketTypeXr);
- 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.
-
- // 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,
- base::TimeDelta target_delay,
- 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;
-
- packet->resize(start_size + 20);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 20);
- uint8 FMT = 15; // Application layer feedback.
- 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.
- big_endian_writer.WriteU8(4);
- 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_));
- size_t cast_loss_field_pos = start_size + 17; // Save loss field position.
- big_endian_writer.WriteU8(0); // Overwritten with number_of_loss_fields.
- DCHECK_LE(target_delay.InMilliseconds(),
- std::numeric_limits<uint16_t>::max());
- big_endian_writer.WriteU16(target_delay.InMilliseconds());
-
- size_t number_of_loss_fields = 0;
- 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();
-
- NackStringBuilder nack_string_builder;
- for (; frame_it != cast->missing_frames_and_packets_.end() &&
- number_of_loss_fields < max_number_of_loss_fields;
- ++frame_it) {
- nack_string_builder.PushFrame(frame_it->first);
- // 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);
- base::BigEndianWriter big_endian_nack_writer(
- reinterpret_cast<char*>(&((*packet)[start_size])), 4);
- big_endian_nack_writer.WriteU8(static_cast<uint8>(frame_it->first));
- big_endian_nack_writer.WriteU16(kRtcpCastAllPacketsLost);
- big_endian_nack_writer.WriteU8(0);
- nack_string_builder.PushPacket(kRtcpCastAllPacketsLost);
- ++number_of_loss_fields;
- } else {
- PacketIdSet::const_iterator packet_it = frame_it->second.begin();
- while (packet_it != frame_it->second.end()) {
- uint16 packet_id = *packet_it;
-
- start_size = packet->size();
- packet->resize(start_size + 4);
- base::BigEndianWriter big_endian_nack_writer(
- reinterpret_cast<char*>(&((*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));
- big_endian_nack_writer.WriteU16(packet_id);
- nack_string_builder.PushPacket(packet_id);
-
- uint8 bitmask = 0;
- ++packet_it;
- while (packet_it != frame_it->second.end()) {
- int shift = static_cast<uint8>(*packet_it - packet_id) - 1;
- if (shift >= 0 && shift <= 7) {
- nack_string_builder.PushPacket(*packet_it);
- bitmask |= (1 << shift);
- ++packet_it;
- } else {
- break;
- }
- }
- big_endian_nack_writer.WriteU8(bitmask);
- ++number_of_loss_fields;
- }
- }
- }
- VLOG_IF(1, !nack_string_builder.Empty())
- << "SSRC: " << cast->media_ssrc_
- << ", ACK: " << cast->ack_frame_id_
- << ", NACK: " << nack_string_builder.GetString();
- DCHECK_LE(number_of_loss_fields, kRtcpMaxCastLossFields);
- (*packet)[cast_size_pos] = static_cast<uint8>(4 + number_of_loss_fields);
- (*packet)[cast_loss_field_pos] = static_cast<uint8>(number_of_loss_fields);
-}
-
-void RtcpSender::BuildReceiverLog(
- const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
- Packet* packet) {
- 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;
- RtcpReceiverLogMessage receiver_log_message;
-
- if (!BuildRtcpReceiverLogMessage(rtcp_events,
- packet_start_size,
- &receiver_log_message,
- &number_of_frames,
- &total_number_of_messages_to_send,
- &rtcp_log_size)) {
- return;
- }
- packet->resize(packet_start_size + rtcp_log_size);
-
- base::BigEndianWriter big_endian_writer(
- reinterpret_cast<char*>(&((*packet)[packet_start_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.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 FRAME_ACK_SENT:
- case FRAME_PLAYOUT:
- case FRAME_DECODED:
- big_endian_writer.WriteU16(
- static_cast<uint16>(event_message.delay_delta.InMilliseconds()));
- big_endian_writer.WriteU16(event_type_and_timestamp_delta);
- break;
- case PACKET_RECEIVED:
- 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, 0u);
-}
-
-bool RtcpSender::BuildRtcpReceiverLogMessage(
- const ReceiverRtcpEventSubscriber::RtcpEventMultiMap& rtcp_events,
- size_t start_size,
- RtcpReceiverLogMessage* receiver_log_message,
- size_t* number_of_frames,
- size_t* total_number_of_messages_to_send,
- size_t* rtcp_log_size) {
- size_t remaining_space =
- std::min(kMaxReceiverLogBytes, kMaxIpPacketSize - start_size);
- if (remaining_space < kRtcpCastLogHeaderSize + kRtcpReceiverFrameLogSize +
- kRtcpReceiverEventLogSize) {
- return false;
- }
-
- // We use this to do event timestamp sorting and truncating for events of
- // a single frame.
- std::vector<RtcpReceiverEventLogMessage> sorted_log_messages;
-
- // Account for the RTCP header for an application-defined packet.
- remaining_space -= kRtcpCastLogHeaderSize;
-
- ReceiverRtcpEventSubscriber::RtcpEventMultiMap::const_reverse_iterator rit =
- rtcp_events.rbegin();
-
- while (rit != rtcp_events.rend() &&
- remaining_space >=
- kRtcpReceiverFrameLogSize + kRtcpReceiverEventLogSize) {
- const RtpTimestamp rtp_timestamp = rit->first;
- RtcpReceiverFrameLogMessage frame_log(rtp_timestamp);
- remaining_space -= kRtcpReceiverFrameLogSize;
- ++*number_of_frames;
-
- // Get all events of a single frame.
- sorted_log_messages.clear();
- do {
- RtcpReceiverEventLogMessage event_log_message;
- event_log_message.type = rit->second.type;
- event_log_message.event_timestamp = rit->second.timestamp;
- event_log_message.delay_delta = rit->second.delay_delta;
- event_log_message.packet_id = rit->second.packet_id;
- sorted_log_messages.push_back(event_log_message);
- ++rit;
- } while (rit != rtcp_events.rend() && rit->first == rtp_timestamp);
-
- std::sort(sorted_log_messages.begin(),
- sorted_log_messages.end(),
- &EventTimestampLessThan);
-
- // From |sorted_log_messages|, only take events that are no greater than
- // |kMaxWireFormatTimeDeltaMs| seconds away from the latest event. Events
- // older than that cannot be encoded over the wire.
- std::vector<RtcpReceiverEventLogMessage>::reverse_iterator sorted_rit =
- sorted_log_messages.rbegin();
- base::TimeTicks first_event_timestamp = sorted_rit->event_timestamp;
- size_t events_in_frame = 0;
- while (sorted_rit != sorted_log_messages.rend() &&
- events_in_frame < kRtcpMaxReceiverLogMessages &&
- remaining_space >= kRtcpReceiverEventLogSize) {
- base::TimeDelta delta(first_event_timestamp -
- sorted_rit->event_timestamp);
- if (delta.InMilliseconds() > kMaxWireFormatTimeDeltaMs)
- break;
- frame_log.event_log_messages_.push_front(*sorted_rit);
- ++events_in_frame;
- ++*total_number_of_messages_to_send;
- remaining_space -= kRtcpReceiverEventLogSize;
- ++sorted_rit;
- }
-
- receiver_log_message->push_front(frame_log);
- }
-
- rtcp_events_history_.push_front(*receiver_log_message);
-
- // We don't try to match RTP timestamps of redundancy frame logs with those
- // from the newest set (which would save the space of an extra RTP timestamp
- // over the wire). Unless the redundancy frame logs are very recent, it's
- // unlikely there will be a match anyway.
- if (rtcp_events_history_.size() > kFirstRedundancyOffset) {
- // Add first redundnacy messages, if enough space remaining
- AddReceiverLog(rtcp_events_history_[kFirstRedundancyOffset],
- receiver_log_message,
- &remaining_space,
- number_of_frames,
- total_number_of_messages_to_send);
- }
-
- if (rtcp_events_history_.size() > kSecondRedundancyOffset) {
- // Add second redundancy messages, if enough space remaining
- AddReceiverLog(rtcp_events_history_[kSecondRedundancyOffset],
- receiver_log_message,
- &remaining_space,
- number_of_frames,
- total_number_of_messages_to_send);
- }
-
- if (rtcp_events_history_.size() > kReceiveLogMessageHistorySize) {
- rtcp_events_history_.pop_back();
- }
-
- DCHECK_LE(rtcp_events_history_.size(), kReceiveLogMessageHistorySize);
-
- *rtcp_log_size =
- kRtcpCastLogHeaderSize + *number_of_frames * kRtcpReceiverFrameLogSize +
- *total_number_of_messages_to_send * kRtcpReceiverEventLogSize;
- DCHECK_GE(kMaxIpPacketSize, start_size + *rtcp_log_size)
- << "Not enough buffer space.";
-
- VLOG(3) << "number of frames: " << *number_of_frames;
- VLOG(3) << "total messages to send: " << *total_number_of_messages_to_send;
- VLOG(3) << "rtcp log size: " << *rtcp_log_size;
- return *number_of_frames > 0;
-}
-
-} // namespace cast
-} // namespace media
« 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