blob: ba09db9e1cd883400aabeca21f3300fc200789b5 [file] [log] [blame]
brandtra8b38552016-10-10 16:44:57 -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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/rtp_rtcp/include/flexfec_receiver.h"
brandtra8b38552016-10-10 16:44:57 -070012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <string.h>
14
15#include "api/array_view.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010016#include "api/scoped_refptr.h"
Rasmus Brandt13a8f202017-10-31 16:44:23 +010017#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020018#include "rtc_base/logging.h"
brandtra8b38552016-10-10 16:44:57 -070019
20namespace webrtc {
21
22namespace {
23
brandtra8b38552016-10-10 16:44:57 -070024// Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet.
25constexpr size_t kMinFlexfecHeaderSize = 20;
26
27// How often to log the recovered packets to the text log.
28constexpr int kPacketLogIntervalMs = 10000;
29
30} // namespace
31
brandtrb29e6522016-12-21 06:37:18 -080032FlexfecReceiver::FlexfecReceiver(
33 uint32_t ssrc,
34 uint32_t protected_media_ssrc,
35 RecoveredPacketReceiver* recovered_packet_receiver)
Sebastian Jansson8026d602019-03-04 19:39:01 +010036 : FlexfecReceiver(Clock::GetRealTimeClock(),
37 ssrc,
38 protected_media_ssrc,
39 recovered_packet_receiver) {}
40
41FlexfecReceiver::FlexfecReceiver(
42 Clock* clock,
43 uint32_t ssrc,
44 uint32_t protected_media_ssrc,
45 RecoveredPacketReceiver* recovered_packet_receiver)
brandtr0a4c1612016-11-03 08:18:27 -070046 : ssrc_(ssrc),
brandtra8b38552016-10-10 16:44:57 -070047 protected_media_ssrc_(protected_media_ssrc),
brandtrd726a3f2017-06-29 02:45:35 -070048 erasure_code_(
49 ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)),
brandtrb29e6522016-12-21 06:37:18 -080050 recovered_packet_receiver_(recovered_packet_receiver),
Sebastian Jansson8026d602019-03-04 19:39:01 +010051 clock_(clock),
brandtra8b38552016-10-10 16:44:57 -070052 last_recovered_packet_ms_(-1) {
53 // It's OK to create this object on a different thread/task queue than
54 // the one used during main operation.
55 sequence_checker_.Detach();
56}
57
brandtr0a4c1612016-11-03 08:18:27 -070058FlexfecReceiver::~FlexfecReceiver() = default;
brandtra8b38552016-10-10 16:44:57 -070059
nisse5c29a7a2017-02-16 06:52:32 -080060void FlexfecReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020061 RTC_DCHECK_RUN_ON(&sequence_checker_);
Rasmus Brandta00137c2017-12-12 10:01:20 +010062
63 // If this packet was recovered, it might be originating from
64 // ProcessReceivedPacket in this object. To avoid lifetime issues with
65 // |recovered_packets_|, we therefore break the cycle here.
66 // This might reduce decoding efficiency a bit, since we can't disambiguate
67 // recovered packets by RTX from recovered packets by FlexFEC.
68 if (packet.recovered())
69 return;
70
Sebastian Jansson6019d432019-05-27 14:24:29 +020071 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet =
72 AddReceivedPacket(packet);
nissea5f043f2017-09-18 07:58:59 -070073 if (!received_packet)
nisse5c29a7a2017-02-16 06:52:32 -080074 return;
nissea5f043f2017-09-18 07:58:59 -070075
76 ProcessReceivedPacket(*received_packet);
brandtra8b38552016-10-10 16:44:57 -070077}
78
brandtr0a4c1612016-11-03 08:18:27 -070079FecPacketCounter FlexfecReceiver::GetPacketCounter() const {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020080 RTC_DCHECK_RUN_ON(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -070081 return packet_counter_;
82}
83
eladalonc0d481a2017-08-02 07:39:07 -070084// TODO(eladalon): Consider using packet.recovered() to avoid processing
85// recovered packets here.
Sebastian Jansson6019d432019-05-27 14:24:29 +020086std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
87FlexfecReceiver::AddReceivedPacket(const RtpPacketReceived& packet) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +020088 RTC_DCHECK_RUN_ON(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -070089
90 // RTP packets with a full base header (12 bytes), but without payload,
91 // could conceivably be useful in the decoding. Therefore we check
brandtrb29e6522016-12-21 06:37:18 -080092 // with a non-strict inequality here.
93 RTC_DCHECK_GE(packet.size(), kRtpHeaderSize);
brandtra8b38552016-10-10 16:44:57 -070094
95 // Demultiplex based on SSRC, and insert into erasure code decoder.
Sebastian Jansson6019d432019-05-27 14:24:29 +020096 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
97 new ForwardErrorCorrection::ReceivedPacket());
brandtrb29e6522016-12-21 06:37:18 -080098 received_packet->seq_num = packet.SequenceNumber();
99 received_packet->ssrc = packet.Ssrc();
brandtr0a4c1612016-11-03 08:18:27 -0700100 if (received_packet->ssrc == ssrc_) {
brandtrb29e6522016-12-21 06:37:18 -0800101 // This is a FlexFEC packet.
102 if (packet.payload_size() < kMinFlexfecHeaderSize) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100103 RTC_LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding.";
nissea5f043f2017-09-18 07:58:59 -0700104 return nullptr;
brandtra8b38552016-10-10 16:44:57 -0700105 }
106 received_packet->is_fec = true;
107 ++packet_counter_.num_fec_packets;
brandtrb29e6522016-12-21 06:37:18 -0800108
brandtra8b38552016-10-10 16:44:57 -0700109 // Insert packet payload into erasure code.
Sebastian Jansson6019d432019-05-27 14:24:29 +0200110 received_packet->pkt = rtc::scoped_refptr<ForwardErrorCorrection::Packet>(
111 new ForwardErrorCorrection::Packet());
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200112 // TODO(ilnik): after slice capability is added to COW, use it here instead
113 // of initializing COW buffer with ArrayView.
brandtrb29e6522016-12-21 06:37:18 -0800114 auto payload = packet.payload();
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200115 received_packet->pkt->data.SetData(payload.data(), payload.size());
brandtra8b38552016-10-10 16:44:57 -0700116 } else {
117 // This is a media packet, or a FlexFEC packet belonging to some
118 // other FlexFEC stream.
119 if (received_packet->ssrc != protected_media_ssrc_) {
nissea5f043f2017-09-18 07:58:59 -0700120 return nullptr;
brandtra8b38552016-10-10 16:44:57 -0700121 }
122 received_packet->is_fec = false;
brandtrb29e6522016-12-21 06:37:18 -0800123
brandtra8b38552016-10-10 16:44:57 -0700124 // Insert entire packet into erasure code.
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200125 // Create a copy and fill with zeros all mutable extensions.
Sebastian Jansson6019d432019-05-27 14:24:29 +0200126 received_packet->pkt = rtc::scoped_refptr<ForwardErrorCorrection::Packet>(
127 new ForwardErrorCorrection::Packet());
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200128 RtpPacketReceived packet_copy(packet);
129 packet_copy.ZeroMutableExtensions();
130 received_packet->pkt->data = packet_copy.Buffer();
brandtra8b38552016-10-10 16:44:57 -0700131 }
brandtrb29e6522016-12-21 06:37:18 -0800132
brandtra8b38552016-10-10 16:44:57 -0700133 ++packet_counter_.num_packets;
134
nissea5f043f2017-09-18 07:58:59 -0700135 return received_packet;
brandtra8b38552016-10-10 16:44:57 -0700136}
137
138// Note that the implementation of this member function and the implementation
brandtrd55c3f62016-10-31 04:51:33 -0700139// in UlpfecReceiver::ProcessReceivedFec() are slightly different.
brandtra8b38552016-10-10 16:44:57 -0700140// This implementation only returns _recovered_ media packets through the
brandtrd55c3f62016-10-31 04:51:33 -0700141// callback, whereas the implementation in UlpfecReceiver returns _all inserted_
brandtra8b38552016-10-10 16:44:57 -0700142// media packets through the callback. The latter behaviour makes sense
nisseb1f2ff92017-06-09 04:01:55 -0700143// for ULPFEC, since the ULPFEC receiver is owned by the RtpVideoStreamReceiver.
brandtra8b38552016-10-10 16:44:57 -0700144// Here, however, the received media pipeline is more decoupled from the
145// FlexFEC decoder, and we therefore do not interfere with the reception
146// of non-recovered media packets.
nissea5f043f2017-09-18 07:58:59 -0700147void FlexfecReceiver::ProcessReceivedPacket(
Sebastian Jansson6019d432019-05-27 14:24:29 +0200148 const ForwardErrorCorrection::ReceivedPacket& received_packet) {
Sebastian Janssonb55015e2019-04-09 13:44:04 +0200149 RTC_DCHECK_RUN_ON(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -0700150
151 // Decode.
nissea5f043f2017-09-18 07:58:59 -0700152 erasure_code_->DecodeFec(received_packet, &recovered_packets_);
153
brandtra8b38552016-10-10 16:44:57 -0700154 // Return recovered packets through callback.
155 for (const auto& recovered_packet : recovered_packets_) {
Rasmus Brandt13a8f202017-10-31 16:44:23 +0100156 RTC_CHECK(recovered_packet);
brandtra8b38552016-10-10 16:44:57 -0700157 if (recovered_packet->returned) {
158 continue;
159 }
160 ++packet_counter_.num_recovered_packets;
nissee4bcd6d2017-05-16 04:47:04 -0700161 // Set this flag first, since OnRecoveredPacket may end up here
162 // again, with the same packet.
163 recovered_packet->returned = true;
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200164 RTC_CHECK_GT(recovered_packet->pkt->data.size(), 0);
nissed2ef3142017-05-11 08:00:58 -0700165 recovered_packet_receiver_->OnRecoveredPacket(
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200166 recovered_packet->pkt->data.cdata(),
167 recovered_packet->pkt->data.size());
brandtra8b38552016-10-10 16:44:57 -0700168 // Periodically log the incoming packets.
169 int64_t now_ms = clock_->TimeInMilliseconds();
170 if (now_ms - last_recovered_packet_ms_ > kPacketLogIntervalMs) {
171 uint32_t media_ssrc =
Ilya Nikolaevskiya5d952f2019-09-03 11:07:37 +0200172 ForwardErrorCorrection::ParseSsrc(recovered_packet->pkt->data.data());
Mirko Bonadei675513b2017-11-09 11:09:25 +0100173 RTC_LOG(LS_VERBOSE) << "Recovered media packet with SSRC: " << media_ssrc
174 << " from FlexFEC stream with SSRC: " << ssrc_ << ".";
brandtra8b38552016-10-10 16:44:57 -0700175 last_recovered_packet_ms_ = now_ms;
176 }
177 }
brandtra8b38552016-10-10 16:44:57 -0700178}
179
180} // namespace webrtc