blob: 28c8b26834684a87ae0a9570d53e75f102fb9e89 [file] [log] [blame]
* 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_receiver.h"
#include <string.h>
#include "api/array_view.h"
#include "api/scoped_refptr.h"
#include "rtc_base/checks.h"
#include "rtc_base/logging.h"
namespace webrtc {
namespace {
// Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet.
constexpr size_t kMinFlexfecHeaderSize = 20;
// How often to log the recovered packets to the text log.
constexpr int kPacketLogIntervalMs = 10000;
} // namespace
uint32_t ssrc,
uint32_t protected_media_ssrc,
RecoveredPacketReceiver* recovered_packet_receiver)
: FlexfecReceiver(Clock::GetRealTimeClock(),
recovered_packet_receiver) {}
Clock* clock,
uint32_t ssrc,
uint32_t protected_media_ssrc,
RecoveredPacketReceiver* recovered_packet_receiver)
: ssrc_(ssrc),
ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)),
last_recovered_packet_ms_(-1) {
// It's OK to create this object on a different thread/task queue than
// the one used during main operation.
FlexfecReceiver::~FlexfecReceiver() = default;
void FlexfecReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
// If this packet was recovered, it might be originating from
// ProcessReceivedPacket in this object. To avoid lifetime issues with
// |recovered_packets_|, we therefore break the cycle here.
// This might reduce decoding efficiency a bit, since we can't disambiguate
// recovered packets by RTX from recovered packets by FlexFEC.
if (packet.recovered())
std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
if (!received_packet)
FecPacketCounter FlexfecReceiver::GetPacketCounter() const {
return packet_counter_;
// TODO(eladalon): Consider using packet.recovered() to avoid processing
// recovered packets here.
FlexfecReceiver::AddReceivedPacket(const RtpPacketReceived& packet) {
// RTP packets with a full base header (12 bytes), but without payload,
// could conceivably be useful in the decoding. Therefore we check
// with a non-strict inequality here.
RTC_DCHECK_GE(packet.size(), kRtpHeaderSize);
// Demultiplex based on SSRC, and insert into erasure code decoder.
std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
new ForwardErrorCorrection::ReceivedPacket());
received_packet->seq_num = packet.SequenceNumber();
received_packet->ssrc = packet.Ssrc();
if (received_packet->ssrc == ssrc_) {
// This is a FlexFEC packet.
if (packet.payload_size() < kMinFlexfecHeaderSize) {
RTC_LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding.";
return nullptr;
received_packet->is_fec = true;
// Insert packet payload into erasure code.
received_packet->pkt = rtc::scoped_refptr<ForwardErrorCorrection::Packet>(
new ForwardErrorCorrection::Packet());
received_packet->pkt->data =
packet.Buffer().Slice(packet.headers_size(), packet.payload_size());
} else {
// This is a media packet, or a FlexFEC packet belonging to some
// other FlexFEC stream.
if (received_packet->ssrc != protected_media_ssrc_) {
return nullptr;
received_packet->is_fec = false;
// Insert entire packet into erasure code.
// Create a copy and fill with zeros all mutable extensions.
received_packet->pkt = rtc::scoped_refptr<ForwardErrorCorrection::Packet>(
new ForwardErrorCorrection::Packet());
RtpPacketReceived packet_copy(packet);
received_packet->pkt->data = packet_copy.Buffer();
return received_packet;
// Note that the implementation of this member function and the implementation
// in UlpfecReceiver::ProcessReceivedFec() are slightly different.
// This implementation only returns _recovered_ media packets through the
// callback, whereas the implementation in UlpfecReceiver returns _all inserted_
// media packets through the callback. The latter behaviour makes sense
// for ULPFEC, since the ULPFEC receiver is owned by the RtpVideoStreamReceiver.
// Here, however, the received media pipeline is more decoupled from the
// FlexFEC decoder, and we therefore do not interfere with the reception
// of non-recovered media packets.
void FlexfecReceiver::ProcessReceivedPacket(
const ForwardErrorCorrection::ReceivedPacket& received_packet) {
// Decode.
erasure_code_->DecodeFec(received_packet, &recovered_packets_);
// Return recovered packets through callback.
for (const auto& recovered_packet : recovered_packets_) {
if (recovered_packet->returned) {
// Set this flag first, since OnRecoveredPacket may end up here
// again, with the same packet.
recovered_packet->returned = true;
RTC_CHECK_GT(recovered_packet->pkt->data.size(), 0);
// Periodically log the incoming packets.
int64_t now_ms = clock_->TimeInMilliseconds();
if (now_ms - last_recovered_packet_ms_ > kPacketLogIntervalMs) {
uint32_t media_ssrc =
RTC_LOG(LS_VERBOSE) << "Recovered media packet with SSRC: " << media_ssrc
<< " from FlexFEC stream with SSRC: " << ssrc_ << ".";
last_recovered_packet_ms_ = now_ms;
} // namespace webrtc