blob: ec8bbdcbe9cae9fb3e48f3beb730d3f8e7c335b8 [file] [log] [blame]
brandtrc295e002016-11-03 09:22:33 -07001/*
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "webrtc/modules/rtp_rtcp/include/flexfec_sender.h"
12
13#include <utility>
14
15#include "webrtc/base/logging.h"
16#include "webrtc/modules/rtp_rtcp/include/rtp_rtcp_defines.h"
17#include "webrtc/modules/rtp_rtcp/source/forward_error_correction.h"
18#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
19
20namespace webrtc {
21
22namespace {
23
24// Let first sequence number be in the first half of the interval.
25constexpr uint16_t kMaxInitRtpSeqNumber = 0x7fff;
26
27// See breakdown in flexfec_header_reader_writer.cc.
28constexpr size_t kFlexfecMaxHeaderSize = 32;
29
30// Since we will mainly use FlexFEC to protect video streams, we use a 90 kHz
31// clock for the RTP timestamps. (This is according to the RFC, which states
32// that it is RECOMMENDED to use the same clock frequency for FlexFEC as for
33// the protected media stream.)
34// The constant converts from clock millisecond timestamps to the 90 kHz
35// RTP timestamp.
36const int kMsToRtpTimestamp = kVideoPayloadTypeFrequency / 1000;
37
38// How often to log the generated FEC packets to the text log.
39constexpr int64_t kPacketLogIntervalMs = 10000;
40
brandtr131bc492016-11-10 05:01:11 -080041RtpHeaderExtensionMap RegisterBweExtensions(
42 const std::vector<RtpExtension>& rtp_header_extensions) {
43 RtpHeaderExtensionMap map;
44 for (const auto& extension : rtp_header_extensions) {
45 if (extension.uri == TransportSequenceNumber::kUri) {
46 map.Register<TransportSequenceNumber>(extension.id);
47 } else if (extension.uri == AbsoluteSendTime::kUri) {
48 map.Register<AbsoluteSendTime>(extension.id);
49 } else if (extension.uri == TransmissionOffset::kUri) {
50 map.Register<TransmissionOffset>(extension.id);
51 } else {
52 LOG(LS_INFO) << "FlexfecSender only supports RTP header extensions for "
53 << "BWE, so the extension " << extension.ToString()
54 << " will not be used.";
55 }
56 }
57 return map;
58}
59
brandtrc295e002016-11-03 09:22:33 -070060} // namespace
61
62FlexfecSender::FlexfecSender(
63 int payload_type,
64 uint32_t ssrc,
65 uint32_t protected_media_ssrc,
66 const std::vector<RtpExtension>& rtp_header_extensions,
67 Clock* clock)
68 : clock_(clock),
69 random_(clock_->TimeInMicroseconds()),
70 last_generated_packet_ms_(-1),
71 payload_type_(payload_type),
72 // Initialize the timestamp offset and RTP sequence numbers randomly.
73 // (This is not intended to be cryptographically strong.)
74 timestamp_offset_(random_.Rand<uint32_t>()),
75 ssrc_(ssrc),
76 protected_media_ssrc_(protected_media_ssrc),
77 seq_num_(random_.Rand(1, kMaxInitRtpSeqNumber)),
78 ulpfec_generator_(ForwardErrorCorrection::CreateFlexfec()),
brandtr131bc492016-11-10 05:01:11 -080079 rtp_header_extension_map_(RegisterBweExtensions(rtp_header_extensions)) {
brandtrc295e002016-11-03 09:22:33 -070080 // This object should not have been instantiated if FlexFEC is disabled.
81 RTC_DCHECK_GE(payload_type, 0);
82 RTC_DCHECK_LE(payload_type, 127);
83
84 // It's OK to create this object on a different thread/task queue than
85 // the one used during main operation.
86 sequence_checker_.Detach();
brandtrc295e002016-11-03 09:22:33 -070087}
88
89FlexfecSender::~FlexfecSender() = default;
90
91// We are reusing the implementation from UlpfecGenerator for SetFecParameters,
92// AddRtpPacketAndGenerateFec, and FecAvailable.
93void FlexfecSender::SetFecParameters(const FecProtectionParams& params) {
94 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtr1743a192016-11-07 03:36:05 -080095 ulpfec_generator_.SetFecParameters(params);
brandtrc295e002016-11-03 09:22:33 -070096}
97
98bool FlexfecSender::AddRtpPacketAndGenerateFec(
99 const RtpPacketToSend& packet) {
100 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
101 // TODO(brandtr): Generalize this SSRC check when we support multistream
102 // protection.
103 RTC_DCHECK_EQ(packet.Ssrc(), protected_media_ssrc_);
104 return ulpfec_generator_.AddRtpPacketAndGenerateFec(
105 packet.data(), packet.payload_size(), packet.headers_size()) == 0;
106}
107
108bool FlexfecSender::FecAvailable() const {
109 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
110 return ulpfec_generator_.FecAvailable();
111}
112
113std::vector<std::unique_ptr<RtpPacketToSend>>
114FlexfecSender::GetFecPackets() {
115 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
116
117 std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets_to_send;
118 fec_packets_to_send.reserve(ulpfec_generator_.generated_fec_packets_.size());
119 for (const auto& fec_packet : ulpfec_generator_.generated_fec_packets_) {
120 std::unique_ptr<RtpPacketToSend> fec_packet_to_send(
121 new RtpPacketToSend(&rtp_header_extension_map_));
122
123 // RTP header.
124 fec_packet_to_send->SetMarker(false);
125 fec_packet_to_send->SetPayloadType(payload_type_);
126 fec_packet_to_send->SetSequenceNumber(seq_num_++);
127 fec_packet_to_send->SetTimestamp(
128 timestamp_offset_ +
129 static_cast<uint32_t>(kMsToRtpTimestamp *
130 clock_->TimeInMilliseconds()));
131 // Set "capture time" so that the TransmissionOffset header extension
132 // can be set by the RTPSender.
133 fec_packet_to_send->set_capture_time_ms(clock_->TimeInMilliseconds());
134 fec_packet_to_send->SetSsrc(ssrc_);
135 // Reserve extensions, if registered. These will be set by the RTPSender.
136 fec_packet_to_send->ReserveExtension<AbsoluteSendTime>();
137 fec_packet_to_send->ReserveExtension<TransmissionOffset>();
138 fec_packet_to_send->ReserveExtension<TransportSequenceNumber>();
139
140 // RTP payload.
141 uint8_t* payload = fec_packet_to_send->AllocatePayload(fec_packet->length);
142 memcpy(payload, fec_packet->data, fec_packet->length);
143
144 fec_packets_to_send.push_back(std::move(fec_packet_to_send));
145 }
146 ulpfec_generator_.ResetState();
147
148 // TODO(brandtr): Remove this log output when the FlexFEC subsystem is
149 // properly wired up in a robust way.
150 int64_t now_ms = clock_->TimeInMilliseconds();
151 if (!fec_packets_to_send.empty() &&
152 now_ms - last_generated_packet_ms_ > kPacketLogIntervalMs) {
153 LOG(LS_INFO) << "Generated " << fec_packets_to_send.size()
154 << " FlexFEC packets with payload type: " << payload_type_
155 << " and SSRC: " << ssrc_ << ".";
156 last_generated_packet_ms_ = now_ms;
157 }
158
159 return fec_packets_to_send;
160}
161
brandtr131bc492016-11-10 05:01:11 -0800162// The overhead is BWE RTP header extensions and FlexFEC header.
brandtrc295e002016-11-03 09:22:33 -0700163size_t FlexfecSender::MaxPacketOverhead() const {
brandtr131bc492016-11-10 05:01:11 -0800164 return rtp_header_extension_map_.GetTotalLengthInBytes() +
165 kFlexfecMaxHeaderSize;
brandtrc295e002016-11-03 09:22:33 -0700166}
167
168} // namespace webrtc