blob: 1a62bced68a4d2f22fb1a6e230f728c512b4f010 [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"
Rasmus Brandt13a8f202017-10-31 16:44:23 +010016#include "rtc_base/checks.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020017#include "rtc_base/logging.h"
18#include "rtc_base/scoped_ref_ptr.h"
brandtra8b38552016-10-10 16:44:57 -070019
20namespace webrtc {
21
22namespace {
23
24using Packet = ForwardErrorCorrection::Packet;
25using ReceivedPacket = ForwardErrorCorrection::ReceivedPacket;
26
27// Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet.
28constexpr size_t kMinFlexfecHeaderSize = 20;
29
30// How often to log the recovered packets to the text log.
31constexpr int kPacketLogIntervalMs = 10000;
32
33} // namespace
34
brandtrb29e6522016-12-21 06:37:18 -080035FlexfecReceiver::FlexfecReceiver(
36 uint32_t ssrc,
37 uint32_t protected_media_ssrc,
38 RecoveredPacketReceiver* recovered_packet_receiver)
brandtr0a4c1612016-11-03 08:18:27 -070039 : ssrc_(ssrc),
brandtra8b38552016-10-10 16:44:57 -070040 protected_media_ssrc_(protected_media_ssrc),
brandtrd726a3f2017-06-29 02:45:35 -070041 erasure_code_(
42 ForwardErrorCorrection::CreateFlexfec(ssrc, protected_media_ssrc)),
brandtrb29e6522016-12-21 06:37:18 -080043 recovered_packet_receiver_(recovered_packet_receiver),
brandtra8b38552016-10-10 16:44:57 -070044 clock_(Clock::GetRealTimeClock()),
45 last_recovered_packet_ms_(-1) {
46 // It's OK to create this object on a different thread/task queue than
47 // the one used during main operation.
48 sequence_checker_.Detach();
49}
50
brandtr0a4c1612016-11-03 08:18:27 -070051FlexfecReceiver::~FlexfecReceiver() = default;
brandtra8b38552016-10-10 16:44:57 -070052
nisse5c29a7a2017-02-16 06:52:32 -080053void FlexfecReceiver::OnRtpPacket(const RtpPacketReceived& packet) {
brandtr8b5c3452016-12-19 10:02:30 -080054 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
Rasmus Brandta00137c2017-12-12 10:01:20 +010055
56 // If this packet was recovered, it might be originating from
57 // ProcessReceivedPacket in this object. To avoid lifetime issues with
58 // |recovered_packets_|, we therefore break the cycle here.
59 // This might reduce decoding efficiency a bit, since we can't disambiguate
60 // recovered packets by RTX from recovered packets by FlexFEC.
61 if (packet.recovered())
62 return;
63
nissea5f043f2017-09-18 07:58:59 -070064 std::unique_ptr<ReceivedPacket> received_packet = AddReceivedPacket(packet);
65 if (!received_packet)
nisse5c29a7a2017-02-16 06:52:32 -080066 return;
nissea5f043f2017-09-18 07:58:59 -070067
68 ProcessReceivedPacket(*received_packet);
brandtra8b38552016-10-10 16:44:57 -070069}
70
brandtr0a4c1612016-11-03 08:18:27 -070071FecPacketCounter FlexfecReceiver::GetPacketCounter() const {
brandtr8b5c3452016-12-19 10:02:30 -080072 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -070073 return packet_counter_;
74}
75
eladalonc0d481a2017-08-02 07:39:07 -070076// TODO(eladalon): Consider using packet.recovered() to avoid processing
77// recovered packets here.
nissea5f043f2017-09-18 07:58:59 -070078std::unique_ptr<ReceivedPacket> FlexfecReceiver::AddReceivedPacket(
79 const RtpPacketReceived& packet) {
brandtr8b5c3452016-12-19 10:02:30 -080080 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -070081
82 // RTP packets with a full base header (12 bytes), but without payload,
83 // could conceivably be useful in the decoding. Therefore we check
brandtrb29e6522016-12-21 06:37:18 -080084 // with a non-strict inequality here.
85 RTC_DCHECK_GE(packet.size(), kRtpHeaderSize);
brandtra8b38552016-10-10 16:44:57 -070086
87 // Demultiplex based on SSRC, and insert into erasure code decoder.
88 std::unique_ptr<ReceivedPacket> received_packet(new ReceivedPacket());
brandtrb29e6522016-12-21 06:37:18 -080089 received_packet->seq_num = packet.SequenceNumber();
90 received_packet->ssrc = packet.Ssrc();
brandtr0a4c1612016-11-03 08:18:27 -070091 if (received_packet->ssrc == ssrc_) {
brandtrb29e6522016-12-21 06:37:18 -080092 // This is a FlexFEC packet.
93 if (packet.payload_size() < kMinFlexfecHeaderSize) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010094 RTC_LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding.";
nissea5f043f2017-09-18 07:58:59 -070095 return nullptr;
brandtra8b38552016-10-10 16:44:57 -070096 }
97 received_packet->is_fec = true;
98 ++packet_counter_.num_fec_packets;
brandtrb29e6522016-12-21 06:37:18 -080099
brandtra8b38552016-10-10 16:44:57 -0700100 // Insert packet payload into erasure code.
101 // TODO(brandtr): Remove this memcpy when the FEC packet classes
102 // are using COW buffers internally.
103 received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
brandtrb29e6522016-12-21 06:37:18 -0800104 auto payload = packet.payload();
danilchap96c15872016-11-21 01:35:29 -0800105 memcpy(received_packet->pkt->data, payload.data(), payload.size());
106 received_packet->pkt->length = payload.size();
brandtra8b38552016-10-10 16:44:57 -0700107 } else {
108 // This is a media packet, or a FlexFEC packet belonging to some
109 // other FlexFEC stream.
110 if (received_packet->ssrc != protected_media_ssrc_) {
nissea5f043f2017-09-18 07:58:59 -0700111 return nullptr;
brandtra8b38552016-10-10 16:44:57 -0700112 }
113 received_packet->is_fec = false;
brandtrb29e6522016-12-21 06:37:18 -0800114
brandtra8b38552016-10-10 16:44:57 -0700115 // Insert entire packet into erasure code.
116 // TODO(brandtr): Remove this memcpy too.
117 received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
brandtrb29e6522016-12-21 06:37:18 -0800118 memcpy(received_packet->pkt->data, packet.data(), packet.size());
119 received_packet->pkt->length = packet.size();
brandtra8b38552016-10-10 16:44:57 -0700120 }
brandtrb29e6522016-12-21 06:37:18 -0800121
brandtra8b38552016-10-10 16:44:57 -0700122 ++packet_counter_.num_packets;
123
nissea5f043f2017-09-18 07:58:59 -0700124 return received_packet;
brandtra8b38552016-10-10 16:44:57 -0700125}
126
127// Note that the implementation of this member function and the implementation
brandtrd55c3f62016-10-31 04:51:33 -0700128// in UlpfecReceiver::ProcessReceivedFec() are slightly different.
brandtra8b38552016-10-10 16:44:57 -0700129// This implementation only returns _recovered_ media packets through the
brandtrd55c3f62016-10-31 04:51:33 -0700130// callback, whereas the implementation in UlpfecReceiver returns _all inserted_
brandtra8b38552016-10-10 16:44:57 -0700131// media packets through the callback. The latter behaviour makes sense
nisseb1f2ff92017-06-09 04:01:55 -0700132// for ULPFEC, since the ULPFEC receiver is owned by the RtpVideoStreamReceiver.
brandtra8b38552016-10-10 16:44:57 -0700133// Here, however, the received media pipeline is more decoupled from the
134// FlexFEC decoder, and we therefore do not interfere with the reception
135// of non-recovered media packets.
nissea5f043f2017-09-18 07:58:59 -0700136void FlexfecReceiver::ProcessReceivedPacket(
137 const ReceivedPacket& received_packet) {
brandtr8b5c3452016-12-19 10:02:30 -0800138 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -0700139
140 // Decode.
nissea5f043f2017-09-18 07:58:59 -0700141 erasure_code_->DecodeFec(received_packet, &recovered_packets_);
142
brandtra8b38552016-10-10 16:44:57 -0700143 // Return recovered packets through callback.
144 for (const auto& recovered_packet : recovered_packets_) {
Rasmus Brandt13a8f202017-10-31 16:44:23 +0100145 RTC_CHECK(recovered_packet);
brandtra8b38552016-10-10 16:44:57 -0700146 if (recovered_packet->returned) {
147 continue;
148 }
149 ++packet_counter_.num_recovered_packets;
nissee4bcd6d2017-05-16 04:47:04 -0700150 // Set this flag first, since OnRecoveredPacket may end up here
151 // again, with the same packet.
152 recovered_packet->returned = true;
Rasmus Brandt13a8f202017-10-31 16:44:23 +0100153 RTC_CHECK(recovered_packet->pkt);
nissed2ef3142017-05-11 08:00:58 -0700154 recovered_packet_receiver_->OnRecoveredPacket(
155 recovered_packet->pkt->data, recovered_packet->pkt->length);
brandtra8b38552016-10-10 16:44:57 -0700156 // Periodically log the incoming packets.
157 int64_t now_ms = clock_->TimeInMilliseconds();
158 if (now_ms - last_recovered_packet_ms_ > kPacketLogIntervalMs) {
159 uint32_t media_ssrc =
160 ForwardErrorCorrection::ParseSsrc(recovered_packet->pkt->data);
Mirko Bonadei675513b2017-11-09 11:09:25 +0100161 RTC_LOG(LS_VERBOSE) << "Recovered media packet with SSRC: " << media_ssrc
162 << " from FlexFEC stream with SSRC: " << ssrc_ << ".";
brandtra8b38552016-10-10 16:44:57 -0700163 last_recovered_packet_ms_ = now_ms;
164 }
165 }
brandtra8b38552016-10-10 16:44:57 -0700166}
167
168} // namespace webrtc