// 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/test_rtcp_packet_builder.h" #include "base/logging.h" namespace media { namespace cast { TestRtcpPacketBuilder::TestRtcpPacketBuilder() : ptr_of_length_(NULL), big_endian_writer_(buffer_, kIpPacketSize) { } void TestRtcpPacketBuilder::AddSr(uint32 sender_ssrc, int number_of_report_blocks) { AddRtcpHeader(200, number_of_report_blocks); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(kNtpHigh); // NTP timestamp. big_endian_writer_.WriteU32(kNtpLow); big_endian_writer_.WriteU32(kRtpTimestamp); big_endian_writer_.WriteU32(kSendPacketCount); big_endian_writer_.WriteU32(kSendOctetCount); } void TestRtcpPacketBuilder::AddSrWithNtp(uint32 sender_ssrc, uint32 ntp_high, uint32 ntp_low, uint32 rtp_timestamp) { AddRtcpHeader(200, 0); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(ntp_high); big_endian_writer_.WriteU32(ntp_low); big_endian_writer_.WriteU32(rtp_timestamp); big_endian_writer_.WriteU32(kSendPacketCount); big_endian_writer_.WriteU32(kSendOctetCount); } void TestRtcpPacketBuilder::AddRr(uint32 sender_ssrc, int number_of_report_blocks) { AddRtcpHeader(201, number_of_report_blocks); big_endian_writer_.WriteU32(sender_ssrc); } void TestRtcpPacketBuilder::AddRb(uint32 rtp_ssrc) { big_endian_writer_.WriteU32(rtp_ssrc); big_endian_writer_.WriteU32(kLoss); big_endian_writer_.WriteU32(kExtendedMax); big_endian_writer_.WriteU32(kTestJitter); big_endian_writer_.WriteU32(kLastSr); big_endian_writer_.WriteU32(kDelayLastSr); } void TestRtcpPacketBuilder::AddSdesCname(uint32 sender_ssrc, const std::string& c_name) { AddRtcpHeader(202, 1); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU8(1); // c_name. DCHECK_LE(c_name.size(), 255u); big_endian_writer_.WriteU8( static_cast(c_name.size())); // c_name length in bytes. for (size_t i = 0; i < c_name.size(); ++i) { big_endian_writer_.WriteU8(c_name.c_str()[i]); } int padding; switch (c_name.size() % 4) { case 0: padding = 2; break; case 1: padding = 1; break; case 2: padding = 4; break; case 3: padding = 3; break; } for (int j = 0; j < padding; ++j) { big_endian_writer_.WriteU8(0); } } void TestRtcpPacketBuilder::AddXrHeader(uint32 sender_ssrc) { AddRtcpHeader(207, 0); big_endian_writer_.WriteU32(sender_ssrc); } void TestRtcpPacketBuilder::AddXrUnknownBlock() { big_endian_writer_.WriteU8(9); // Block type. big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(4); // Block length. // First receiver same as sender of this report. big_endian_writer_.WriteU32(0); big_endian_writer_.WriteU32(0); big_endian_writer_.WriteU32(0); big_endian_writer_.WriteU32(0); } void TestRtcpPacketBuilder::AddXrDlrrBlock(uint32 sender_ssrc) { big_endian_writer_.WriteU8(5); // Block type. big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(3); // Block length. // First receiver same as sender of this report. big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(kLastRr); big_endian_writer_.WriteU32(kDelayLastRr); } void TestRtcpPacketBuilder::AddXrExtendedDlrrBlock(uint32 sender_ssrc) { big_endian_writer_.WriteU8(5); // Block type. big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(9); // Block length. big_endian_writer_.WriteU32(0xaaaaaaaa); big_endian_writer_.WriteU32(0xaaaaaaaa); big_endian_writer_.WriteU32(0xaaaaaaaa); // First receiver same as sender of this report. big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(kLastRr); big_endian_writer_.WriteU32(kDelayLastRr); big_endian_writer_.WriteU32(0xbbbbbbbb); big_endian_writer_.WriteU32(0xbbbbbbbb); big_endian_writer_.WriteU32(0xbbbbbbbb); } void TestRtcpPacketBuilder::AddXrRrtrBlock() { big_endian_writer_.WriteU8(4); // Block type. big_endian_writer_.WriteU8(0); // Reserved. big_endian_writer_.WriteU16(2); // Block length. big_endian_writer_.WriteU32(kNtpHigh); big_endian_writer_.WriteU32(kNtpLow); } void TestRtcpPacketBuilder::AddNack(uint32 sender_ssrc, uint32 media_ssrc) { AddRtcpHeader(205, 1); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(media_ssrc); big_endian_writer_.WriteU16(kMissingPacket); big_endian_writer_.WriteU16(0); } void TestRtcpPacketBuilder::AddSendReportRequest(uint32 sender_ssrc, uint32 media_ssrc) { AddRtcpHeader(205, 5); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(media_ssrc); } void TestRtcpPacketBuilder::AddPli(uint32 sender_ssrc, uint32 media_ssrc) { AddRtcpHeader(206, 1); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(media_ssrc); } void TestRtcpPacketBuilder::AddRpsi(uint32 sender_ssrc, uint32 media_ssrc) { AddRtcpHeader(206, 3); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(media_ssrc); big_endian_writer_.WriteU8(0); // Padding bits. big_endian_writer_.WriteU8(kPayloadtype); uint64 picture_id = kPictureId; for (int i = 9; i > 0; i--) { big_endian_writer_.WriteU8( 0x80 | static_cast(picture_id >> (i * 7))); } // Add last byte of picture ID. big_endian_writer_.WriteU8(static_cast(picture_id & 0x7f)); } void TestRtcpPacketBuilder::AddRemb(uint32 sender_ssrc, uint32 media_ssrc) { AddRtcpHeader(206, 15); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(0); big_endian_writer_.WriteU8('R'); big_endian_writer_.WriteU8('E'); big_endian_writer_.WriteU8('M'); big_endian_writer_.WriteU8('B'); big_endian_writer_.WriteU8(1); // Number of SSRCs. big_endian_writer_.WriteU8(1); // BR Exp. // BR Mantissa. big_endian_writer_.WriteU16(static_cast(kTestRembBitrate / 2)); big_endian_writer_.WriteU32(media_ssrc); } void TestRtcpPacketBuilder::AddCast(uint32 sender_ssrc, uint32 media_ssrc) { AddRtcpHeader(206, 15); big_endian_writer_.WriteU32(sender_ssrc); big_endian_writer_.WriteU32(media_ssrc); big_endian_writer_.WriteU8('C'); big_endian_writer_.WriteU8('A'); big_endian_writer_.WriteU8('S'); big_endian_writer_.WriteU8('T'); big_endian_writer_.WriteU8(kAckFrameId); big_endian_writer_.WriteU8(3); // Loss fields. big_endian_writer_.WriteU16(0); // Reserved. big_endian_writer_.WriteU8(kLostFrameId); big_endian_writer_.WriteU16(kRtcpCastAllPacketsLost); big_endian_writer_.WriteU8(0); // Lost packet id mask. big_endian_writer_.WriteU8(kFrameIdWithLostPackets); big_endian_writer_.WriteU16(kLostPacketId1); big_endian_writer_.WriteU8(0x2); // Lost packet id mask. big_endian_writer_.WriteU8(kFrameIdWithLostPackets); big_endian_writer_.WriteU16(kLostPacketId3); big_endian_writer_.WriteU8(0); // Lost packet id mask. } const uint8* TestRtcpPacketBuilder::Packet() { PatchLengthField(); return buffer_; } void TestRtcpPacketBuilder::PatchLengthField() { if (ptr_of_length_) { // Back-patch the packet length. The client must have taken // care of proper padding to 32-bit words. int this_packet_length = (big_endian_writer_.ptr() - ptr_of_length_ - 2); DCHECK_EQ(0, this_packet_length % 4) << "Packets must be a multiple of 32 bits long"; *ptr_of_length_ = this_packet_length >> 10; *(ptr_of_length_ + 1) = (this_packet_length >> 2) & 0xFF; ptr_of_length_ = NULL; } } // Set the 5-bit value in the 1st byte of the header // and the payload type. Set aside room for the length field, // and make provision for back-patching it. void TestRtcpPacketBuilder::AddRtcpHeader(int payload, int format_or_count) { PatchLengthField(); big_endian_writer_.WriteU8(0x80 | (format_or_count & 0x1F)); big_endian_writer_.WriteU8(payload); ptr_of_length_ = big_endian_writer_.ptr(); // Initialize length to "clearly illegal". big_endian_writer_.WriteU16(0xDEAD); } } // namespace cast } // namespace media