| /* | 
 |  *  Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "modules/rtp_rtcp/include/flexfec_sender.h" | 
 |  | 
 | #include <string.h> | 
 |  | 
 | #include <list> | 
 | #include <utility> | 
 |  | 
 | #include "absl/strings/string_view.h" | 
 | #include "api/environment/environment.h" | 
 | #include "api/units/time_delta.h" | 
 | #include "api/units/timestamp.h" | 
 | #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" | 
 | #include "modules/rtp_rtcp/source/forward_error_correction.h" | 
 | #include "modules/rtp_rtcp/source/rtp_header_extensions.h" | 
 | #include "modules/rtp_rtcp/source/rtp_packet_to_send.h" | 
 | #include "rtc_base/checks.h" | 
 | #include "rtc_base/logging.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | namespace { | 
 |  | 
 | // Let first sequence number be in the first half of the interval. | 
 | constexpr uint16_t kMaxInitRtpSeqNumber = 0x7fff; | 
 |  | 
 | // See breakdown in flexfec_header_reader_writer.cc. | 
 | constexpr size_t kFlexfecMaxHeaderSize = 32; | 
 |  | 
 | // Since we will mainly use FlexFEC to protect video streams, we use a 90 kHz | 
 | // clock for the RTP timestamps. (This is according to the RFC, which states | 
 | // that it is RECOMMENDED to use the same clock frequency for FlexFEC as for | 
 | // the protected media stream.) | 
 | // The constant converts from clock millisecond timestamps to the 90 kHz | 
 | // RTP timestamp. | 
 | const int kMsToRtpTimestamp = kVideoPayloadTypeFrequency / 1000; | 
 |  | 
 | // How often to log the generated FEC packets to the text log. | 
 | constexpr TimeDelta kPacketLogInterval = TimeDelta::Seconds(10); | 
 |  | 
 | RtpHeaderExtensionMap RegisterSupportedExtensions( | 
 |     const std::vector<RtpExtension>& rtp_header_extensions) { | 
 |   RtpHeaderExtensionMap map; | 
 |   for (const auto& extension : rtp_header_extensions) { | 
 |     if (extension.uri == TransportSequenceNumber::Uri()) { | 
 |       map.Register<TransportSequenceNumber>(extension.id); | 
 |     } else if (extension.uri == AbsoluteSendTime::Uri()) { | 
 |       map.Register<AbsoluteSendTime>(extension.id); | 
 |     } else if (extension.uri == TransmissionOffset::Uri()) { | 
 |       map.Register<TransmissionOffset>(extension.id); | 
 |     } else if (extension.uri == RtpMid::Uri()) { | 
 |       map.Register<RtpMid>(extension.id); | 
 |     } else { | 
 |       RTC_LOG(LS_INFO) | 
 |           << "FlexfecSender only supports RTP header extensions for " | 
 |              "BWE and MID, so the extension " | 
 |           << extension.ToString() << " will not be used."; | 
 |     } | 
 |   } | 
 |   return map; | 
 | } | 
 |  | 
 | }  // namespace | 
 |  | 
 | FlexfecSender::FlexfecSender( | 
 |     const Environment& env, | 
 |     int payload_type, | 
 |     uint32_t ssrc, | 
 |     uint32_t protected_media_ssrc, | 
 |     absl::string_view mid, | 
 |     const std::vector<RtpExtension>& rtp_header_extensions, | 
 |     rtc::ArrayView<const RtpExtensionSize> extension_sizes, | 
 |     const RtpState* rtp_state) | 
 |     : env_(env), | 
 |       random_(env_.clock().TimeInMicroseconds()), | 
 |       payload_type_(payload_type), | 
 |       // Reset RTP state if this is not the first time we are operating. | 
 |       // Otherwise, randomize the initial timestamp offset and RTP sequence | 
 |       // numbers. (This is not intended to be cryptographically strong.) | 
 |       timestamp_offset_(rtp_state ? rtp_state->start_timestamp | 
 |                                   : random_.Rand<uint32_t>()), | 
 |       ssrc_(ssrc), | 
 |       protected_media_ssrc_(protected_media_ssrc), | 
 |       mid_(mid), | 
 |       seq_num_(rtp_state ? rtp_state->sequence_number | 
 |                          : random_.Rand(1, kMaxInitRtpSeqNumber)), | 
 |       ulpfec_generator_( | 
 |           env_, | 
 |           ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)), | 
 |       rtp_header_extension_map_( | 
 |           RegisterSupportedExtensions(rtp_header_extensions)), | 
 |       header_extensions_size_( | 
 |           RtpHeaderExtensionSize(extension_sizes, rtp_header_extension_map_)), | 
 |       fec_bitrate_(/*max_window_size=*/TimeDelta::Seconds(1)) { | 
 |   // This object should not have been instantiated if FlexFEC is disabled. | 
 |   RTC_DCHECK_GE(payload_type, 0); | 
 |   RTC_DCHECK_LE(payload_type, 127); | 
 | } | 
 |  | 
 | FlexfecSender::~FlexfecSender() = default; | 
 |  | 
 | // We are reusing the implementation from UlpfecGenerator for SetFecParameters, | 
 | // AddRtpPacketAndGenerateFec, and FecAvailable. | 
 | void FlexfecSender::SetProtectionParameters( | 
 |     const FecProtectionParams& delta_params, | 
 |     const FecProtectionParams& key_params) { | 
 |   ulpfec_generator_.SetProtectionParameters(delta_params, key_params); | 
 | } | 
 |  | 
 | void FlexfecSender::AddPacketAndGenerateFec(const RtpPacketToSend& packet) { | 
 |   // TODO(brandtr): Generalize this SSRC check when we support multistream | 
 |   // protection. | 
 |   RTC_DCHECK_EQ(packet.Ssrc(), protected_media_ssrc_); | 
 |   ulpfec_generator_.AddPacketAndGenerateFec(packet); | 
 | } | 
 |  | 
 | std::vector<std::unique_ptr<RtpPacketToSend>> FlexfecSender::GetFecPackets() { | 
 |   RTC_CHECK_RUNS_SERIALIZED(&ulpfec_generator_.race_checker_); | 
 |   std::vector<std::unique_ptr<RtpPacketToSend>> fec_packets_to_send; | 
 |   fec_packets_to_send.reserve(ulpfec_generator_.generated_fec_packets_.size()); | 
 |   size_t total_fec_data_bytes = 0; | 
 |   for (const auto* fec_packet : ulpfec_generator_.generated_fec_packets_) { | 
 |     std::unique_ptr<RtpPacketToSend> fec_packet_to_send( | 
 |         new RtpPacketToSend(&rtp_header_extension_map_)); | 
 |     fec_packet_to_send->set_packet_type( | 
 |         RtpPacketMediaType::kForwardErrorCorrection); | 
 |     fec_packet_to_send->set_allow_retransmission(false); | 
 |  | 
 |     // RTP header. | 
 |     fec_packet_to_send->SetMarker(false); | 
 |     fec_packet_to_send->SetPayloadType(payload_type_); | 
 |     fec_packet_to_send->SetSequenceNumber(seq_num_++); | 
 |     fec_packet_to_send->SetTimestamp( | 
 |         timestamp_offset_ + | 
 |         static_cast<uint32_t>(kMsToRtpTimestamp * | 
 |                               env_.clock().TimeInMilliseconds())); | 
 |     // Set "capture time" so that the TransmissionOffset header extension | 
 |     // can be set by the RTPSender. | 
 |     fec_packet_to_send->set_capture_time(env_.clock().CurrentTime()); | 
 |     fec_packet_to_send->SetSsrc(ssrc_); | 
 |     // Reserve extensions, if registered. These will be set by the RTPSender. | 
 |     fec_packet_to_send->ReserveExtension<AbsoluteSendTime>(); | 
 |     fec_packet_to_send->ReserveExtension<TransmissionOffset>(); | 
 |     fec_packet_to_send->ReserveExtension<TransportSequenceNumber>(); | 
 |     // Possibly include the MID header extension. | 
 |     if (!mid_.empty()) { | 
 |       // This is a no-op if the MID header extension is not registered. | 
 |       fec_packet_to_send->SetExtension<RtpMid>(mid_); | 
 |     } | 
 |  | 
 |     // RTP payload. | 
 |     uint8_t* payload = | 
 |         fec_packet_to_send->AllocatePayload(fec_packet->data.size()); | 
 |     memcpy(payload, fec_packet->data.cdata(), fec_packet->data.size()); | 
 |  | 
 |     total_fec_data_bytes += fec_packet_to_send->size(); | 
 |     fec_packets_to_send.push_back(std::move(fec_packet_to_send)); | 
 |   } | 
 |  | 
 |   if (!fec_packets_to_send.empty()) { | 
 |     ulpfec_generator_.ResetState(); | 
 |   } | 
 |  | 
 |   Timestamp now = env_.clock().CurrentTime(); | 
 |   if (!fec_packets_to_send.empty() && | 
 |       now - last_generated_packet_ > kPacketLogInterval) { | 
 |     RTC_LOG(LS_VERBOSE) << "Generated " << fec_packets_to_send.size() | 
 |                         << " FlexFEC packets with payload type: " | 
 |                         << payload_type_ << " and SSRC: " << ssrc_ << "."; | 
 |     last_generated_packet_ = now; | 
 |   } | 
 |  | 
 |   MutexLock lock(&mutex_); | 
 |   fec_bitrate_.Update(total_fec_data_bytes, now); | 
 |  | 
 |   return fec_packets_to_send; | 
 | } | 
 |  | 
 | // The overhead is BWE RTP header extensions and FlexFEC header. | 
 | size_t FlexfecSender::MaxPacketOverhead() const { | 
 |   return header_extensions_size_ + kFlexfecMaxHeaderSize; | 
 | } | 
 |  | 
 | DataRate FlexfecSender::CurrentFecRate() const { | 
 |   MutexLock lock(&mutex_); | 
 |   return fec_bitrate_.Rate(env_.clock().CurrentTime()) | 
 |       .value_or(DataRate::Zero()); | 
 | } | 
 |  | 
 | std::optional<RtpState> FlexfecSender::GetRtpState() { | 
 |   RtpState rtp_state; | 
 |   rtp_state.sequence_number = seq_num_; | 
 |   rtp_state.start_timestamp = timestamp_offset_; | 
 |   return rtp_state; | 
 | } | 
 |  | 
 | }  // namespace webrtc |