1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
// Copyright 2019 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 "cast/streaming/rtp_packetizer.h"
#include <algorithm>
#include <limits>
#include <random>
#include "cast/streaming/packet_util.h"
#include "platform/api/time.h"
#include "util/big_endian.h"
#include "util/integer_division.h"
#include "util/osp_logging.h"
namespace openscreen {
namespace cast {
namespace {
// Returns a random sequence number to start with. The reason for using a random
// number instead of zero is unclear, but this has existed both in several
// versions of the Cast Streaming spec and in other implementations for many
// years.
uint16_t GenerateRandomSequenceNumberStart() {
// Use a statically-allocated generator, instantiated upon first use, and
// seeded with the current time tick count. This generator was chosen because
// it is light-weight and does not need to produce unguessable (nor
// crypto-secure) values.
static std::minstd_rand generator(static_cast<std::minstd_rand::result_type>(
Clock::now().time_since_epoch().count()));
return std::uniform_int_distribution<uint16_t>()(generator);
}
} // namespace
RtpPacketizer::RtpPacketizer(RtpPayloadType payload_type,
Ssrc sender_ssrc,
int max_packet_size)
: payload_type_7bits_(static_cast<uint8_t>(payload_type)),
sender_ssrc_(sender_ssrc),
max_packet_size_(max_packet_size),
sequence_number_(GenerateRandomSequenceNumberStart()) {
OSP_DCHECK(IsRtpPayloadType(payload_type_7bits_));
OSP_DCHECK_GT(max_packet_size_, kMaxRtpHeaderSize);
}
RtpPacketizer::~RtpPacketizer() = default;
absl::Span<uint8_t> RtpPacketizer::GeneratePacket(const EncryptedFrame& frame,
FramePacketId packet_id,
absl::Span<uint8_t> buffer) {
OSP_CHECK_GE(static_cast<int>(buffer.size()), max_packet_size_);
const int num_packets = ComputeNumberOfPackets(frame);
OSP_DCHECK_GT(num_packets, 0);
OSP_DCHECK_LT(int{packet_id}, num_packets);
const bool is_last_packet = int{packet_id} == (num_packets - 1);
// Compute the size of this packet, which is the number of bytes of header
// plus the number of bytes of payload. Note that the optional Adaptive
// Latency information is only added to the first packet.
int packet_size = kBaseRtpHeaderSize;
const bool include_adaptive_latency_change =
(packet_id == 0 &&
frame.new_playout_delay > std::chrono::milliseconds(0));
if (include_adaptive_latency_change) {
OSP_DCHECK_LE(frame.new_playout_delay.count(),
int{std::numeric_limits<uint16_t>::max()});
packet_size += kAdaptiveLatencyHeaderSize;
}
int data_chunk_size = max_payload_size();
const int data_chunk_start = data_chunk_size * int{packet_id};
if (is_last_packet) {
data_chunk_size = static_cast<int>(frame.data.size()) - data_chunk_start;
}
packet_size += data_chunk_size;
OSP_DCHECK_LE(packet_size, max_packet_size_);
const absl::Span<uint8_t> packet(buffer.data(), packet_size);
// RTP Header.
AppendField<uint8_t>(kRtpRequiredFirstByte, &buffer);
AppendField<uint8_t>(
(is_last_packet ? kRtpMarkerBitMask : 0) | payload_type_7bits_, &buffer);
AppendField<uint16_t>(sequence_number_++, &buffer);
AppendField<uint32_t>(frame.rtp_timestamp.lower_32_bits(), &buffer);
AppendField<uint32_t>(sender_ssrc_, &buffer);
// Cast Header.
AppendField<uint8_t>(
((frame.dependency == EncodedFrame::KEY_FRAME) ? kRtpKeyFrameBitMask
: 0) |
kRtpHasReferenceFrameIdBitMask |
(include_adaptive_latency_change ? 1 : 0),
&buffer);
AppendField<uint8_t>(frame.frame_id.lower_8_bits(), &buffer);
AppendField<uint16_t>(packet_id, &buffer);
AppendField<uint16_t>(num_packets - 1, &buffer);
AppendField<uint8_t>(frame.referenced_frame_id.lower_8_bits(), &buffer);
// Extension of Cast Header for Adaptive Latency change.
if (include_adaptive_latency_change) {
AppendField<uint16_t>(
(kAdaptiveLatencyRtpExtensionType << kNumExtensionDataSizeFieldBits) |
sizeof(uint16_t),
&buffer);
AppendField<uint16_t>(frame.new_playout_delay.count(), &buffer);
}
// Sanity-check the pointer math, to ensure the packet is being entirely
// populated, with no underrun or overrun.
OSP_DCHECK_EQ(buffer.data() + data_chunk_size, packet.end());
// Copy the encrypted payload data into the packet.
memcpy(buffer.data(), frame.data.data() + data_chunk_start, data_chunk_size);
return packet;
}
int RtpPacketizer::ComputeNumberOfPackets(const EncryptedFrame& frame) const {
// The total number of packets is computed by assuming the payload will be
// split-up across as few packets as possible.
int num_packets = DividePositivesRoundingUp(
static_cast<int>(frame.data.size()), max_payload_size());
// Edge case: There must always be at least one packet, even when there are no
// payload bytes. Some audio codecs, for example, use zero bytes to represent
// a period of silence.
num_packets = std::max(1, num_packets);
// Ensure that the entire range of FramePacketIds can be represented.
return num_packets <= int{kMaxAllowedFramePacketId} ? num_packets : -1;
}
} // namespace cast
} // namespace openscreen
|