Line data Source code
1 : /*
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_receiver.h"
12 :
13 : #include "webrtc/base/logging.h"
14 : #include "webrtc/base/scoped_ref_ptr.h"
15 :
16 : namespace webrtc {
17 :
18 : namespace {
19 :
20 : using Packet = ForwardErrorCorrection::Packet;
21 : using ReceivedPacket = ForwardErrorCorrection::ReceivedPacket;
22 :
23 : // Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet.
24 : constexpr size_t kMinFlexfecHeaderSize = 20;
25 :
26 : // How often to log the recovered packets to the text log.
27 : constexpr int kPacketLogIntervalMs = 10000;
28 :
29 : } // namespace
30 :
31 0 : FlexfecReceiver::FlexfecReceiver(
32 : uint32_t ssrc,
33 : uint32_t protected_media_ssrc,
34 0 : RecoveredPacketReceiver* recovered_packet_receiver)
35 : : ssrc_(ssrc),
36 : protected_media_ssrc_(protected_media_ssrc),
37 : erasure_code_(ForwardErrorCorrection::CreateFlexfec()),
38 : recovered_packet_receiver_(recovered_packet_receiver),
39 0 : clock_(Clock::GetRealTimeClock()),
40 0 : last_recovered_packet_ms_(-1) {
41 : // It's OK to create this object on a different thread/task queue than
42 : // the one used during main operation.
43 0 : sequence_checker_.Detach();
44 0 : }
45 :
46 : FlexfecReceiver::~FlexfecReceiver() = default;
47 :
48 0 : bool FlexfecReceiver::AddAndProcessReceivedPacket(
49 : const RtpPacketReceived& packet) {
50 0 : RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
51 0 : if (!AddReceivedPacket(std::move(packet))) {
52 0 : return false;
53 : }
54 0 : return ProcessReceivedPackets();
55 : }
56 :
57 0 : FecPacketCounter FlexfecReceiver::GetPacketCounter() const {
58 0 : RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
59 0 : return packet_counter_;
60 : }
61 :
62 0 : bool FlexfecReceiver::AddReceivedPacket(const RtpPacketReceived& packet) {
63 0 : RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
64 :
65 : // RTP packets with a full base header (12 bytes), but without payload,
66 : // could conceivably be useful in the decoding. Therefore we check
67 : // with a non-strict inequality here.
68 0 : RTC_DCHECK_GE(packet.size(), kRtpHeaderSize);
69 :
70 : // Demultiplex based on SSRC, and insert into erasure code decoder.
71 0 : std::unique_ptr<ReceivedPacket> received_packet(new ReceivedPacket());
72 0 : received_packet->seq_num = packet.SequenceNumber();
73 0 : received_packet->ssrc = packet.Ssrc();
74 0 : if (received_packet->ssrc == ssrc_) {
75 : // This is a FlexFEC packet.
76 0 : if (packet.payload_size() < kMinFlexfecHeaderSize) {
77 0 : LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding.";
78 0 : return false;
79 : }
80 0 : received_packet->is_fec = true;
81 0 : ++packet_counter_.num_fec_packets;
82 :
83 : // Insert packet payload into erasure code.
84 : // TODO(brandtr): Remove this memcpy when the FEC packet classes
85 : // are using COW buffers internally.
86 0 : received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
87 0 : auto payload = packet.payload();
88 0 : memcpy(received_packet->pkt->data, payload.data(), payload.size());
89 0 : received_packet->pkt->length = payload.size();
90 : } else {
91 : // This is a media packet, or a FlexFEC packet belonging to some
92 : // other FlexFEC stream.
93 0 : if (received_packet->ssrc != protected_media_ssrc_) {
94 0 : return false;
95 : }
96 0 : received_packet->is_fec = false;
97 :
98 : // Insert entire packet into erasure code.
99 : // TODO(brandtr): Remove this memcpy too.
100 0 : received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
101 0 : memcpy(received_packet->pkt->data, packet.data(), packet.size());
102 0 : received_packet->pkt->length = packet.size();
103 : }
104 :
105 0 : received_packets_.push_back(std::move(received_packet));
106 0 : ++packet_counter_.num_packets;
107 :
108 0 : return true;
109 : }
110 :
111 : // Note that the implementation of this member function and the implementation
112 : // in UlpfecReceiver::ProcessReceivedFec() are slightly different.
113 : // This implementation only returns _recovered_ media packets through the
114 : // callback, whereas the implementation in UlpfecReceiver returns _all inserted_
115 : // media packets through the callback. The latter behaviour makes sense
116 : // for ULPFEC, since the ULPFEC receiver is owned by the RtpStreamReceiver.
117 : // Here, however, the received media pipeline is more decoupled from the
118 : // FlexFEC decoder, and we therefore do not interfere with the reception
119 : // of non-recovered media packets.
120 0 : bool FlexfecReceiver::ProcessReceivedPackets() {
121 0 : RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
122 :
123 : // Decode.
124 0 : if (!received_packets_.empty()) {
125 0 : if (erasure_code_->DecodeFec(&received_packets_, &recovered_packets_) !=
126 : 0) {
127 0 : return false;
128 : }
129 : }
130 : // Return recovered packets through callback.
131 0 : for (const auto& recovered_packet : recovered_packets_) {
132 0 : if (recovered_packet->returned) {
133 0 : continue;
134 : }
135 0 : ++packet_counter_.num_recovered_packets;
136 0 : if (!recovered_packet_receiver_->OnRecoveredPacket(
137 0 : recovered_packet->pkt->data, recovered_packet->pkt->length)) {
138 0 : return false;
139 : }
140 0 : recovered_packet->returned = true;
141 : // Periodically log the incoming packets.
142 0 : int64_t now_ms = clock_->TimeInMilliseconds();
143 0 : if (now_ms - last_recovered_packet_ms_ > kPacketLogIntervalMs) {
144 : uint32_t media_ssrc =
145 0 : ForwardErrorCorrection::ParseSsrc(recovered_packet->pkt->data);
146 0 : LOG(LS_VERBOSE) << "Recovered media packet with SSRC: " << media_ssrc
147 0 : << " from FlexFEC stream with SSRC: " << ssrc_ << ".";
148 0 : last_recovered_packet_ms_ = now_ms;
149 : }
150 : }
151 0 : return true;
152 : }
153 :
154 : } // namespace webrtc
|