blob: 369dd31ae103d42a5dd8a9ba4cfa2dca8a3e0f85 [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
brandtr0a4c1612016-11-03 08:18:27 -070011#include "webrtc/modules/rtp_rtcp/include/flexfec_receiver.h"
brandtra8b38552016-10-10 16:44:57 -070012
brandtr70e40532016-12-21 00:22:03 -080013#include <utility>
14
brandtra8b38552016-10-10 16:44:57 -070015#include "webrtc/base/logging.h"
16#include "webrtc/base/scoped_ref_ptr.h"
brandtr70e40532016-12-21 00:22:03 -080017#include "webrtc/modules/rtp_rtcp/source/rtp_packet_received.h"
brandtra8b38552016-10-10 16:44:57 -070018
19namespace webrtc {
20
21namespace {
22
23using Packet = ForwardErrorCorrection::Packet;
24using ReceivedPacket = ForwardErrorCorrection::ReceivedPacket;
25
26// Minimum header size (in bytes) of a well-formed non-singular FlexFEC packet.
27constexpr size_t kMinFlexfecHeaderSize = 20;
28
29// How often to log the recovered packets to the text log.
30constexpr int kPacketLogIntervalMs = 10000;
31
32} // namespace
33
brandtr70e40532016-12-21 00:22:03 -080034FlexfecReceiver::FlexfecReceiver(uint32_t ssrc,
35 uint32_t protected_media_ssrc,
36 RecoveredPacketReceiver* callback)
brandtr0a4c1612016-11-03 08:18:27 -070037 : ssrc_(ssrc),
brandtra8b38552016-10-10 16:44:57 -070038 protected_media_ssrc_(protected_media_ssrc),
39 erasure_code_(ForwardErrorCorrection::CreateFlexfec()),
brandtr70e40532016-12-21 00:22:03 -080040 callback_(callback),
brandtra8b38552016-10-10 16:44:57 -070041 clock_(Clock::GetRealTimeClock()),
42 last_recovered_packet_ms_(-1) {
43 // It's OK to create this object on a different thread/task queue than
44 // the one used during main operation.
45 sequence_checker_.Detach();
46}
47
brandtr0a4c1612016-11-03 08:18:27 -070048FlexfecReceiver::~FlexfecReceiver() = default;
brandtra8b38552016-10-10 16:44:57 -070049
brandtr70e40532016-12-21 00:22:03 -080050bool FlexfecReceiver::AddAndProcessReceivedPacket(const uint8_t* packet,
51 size_t packet_length) {
brandtr8b5c3452016-12-19 10:02:30 -080052 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtr70e40532016-12-21 00:22:03 -080053 if (!AddReceivedPacket(packet, packet_length)) {
brandtra8b38552016-10-10 16:44:57 -070054 return false;
55 }
56 return ProcessReceivedPackets();
57}
58
brandtr0a4c1612016-11-03 08:18:27 -070059FecPacketCounter FlexfecReceiver::GetPacketCounter() const {
brandtr8b5c3452016-12-19 10:02:30 -080060 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -070061 return packet_counter_;
62}
63
brandtr70e40532016-12-21 00:22:03 -080064bool FlexfecReceiver::AddReceivedPacket(const uint8_t* packet,
65 size_t packet_length) {
brandtr8b5c3452016-12-19 10:02:30 -080066 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -070067
68 // RTP packets with a full base header (12 bytes), but without payload,
69 // could conceivably be useful in the decoding. Therefore we check
brandtr70e40532016-12-21 00:22:03 -080070 // with a strict inequality here.
71 if (packet_length < kRtpHeaderSize) {
72 LOG(LS_WARNING) << "Truncated packet, discarding.";
73 return false;
74 }
75
76 // TODO(brandtr): Consider how to handle received FlexFEC packets and
77 // the bandwidth estimator.
78 RtpPacketReceived parsed_packet;
79 if (!parsed_packet.Parse(packet, packet_length)) {
80 return false;
81 }
brandtra8b38552016-10-10 16:44:57 -070082
83 // Demultiplex based on SSRC, and insert into erasure code decoder.
84 std::unique_ptr<ReceivedPacket> received_packet(new ReceivedPacket());
brandtr70e40532016-12-21 00:22:03 -080085 received_packet->seq_num = parsed_packet.SequenceNumber();
86 received_packet->ssrc = parsed_packet.Ssrc();
brandtr0a4c1612016-11-03 08:18:27 -070087 if (received_packet->ssrc == ssrc_) {
brandtr70e40532016-12-21 00:22:03 -080088 // This is a FEC packet belonging to this FlexFEC stream.
89 if (parsed_packet.payload_size() < kMinFlexfecHeaderSize) {
brandtra8b38552016-10-10 16:44:57 -070090 LOG(LS_WARNING) << "Truncated FlexFEC packet, discarding.";
91 return false;
92 }
93 received_packet->is_fec = true;
94 ++packet_counter_.num_fec_packets;
95 // Insert packet payload into erasure code.
96 // TODO(brandtr): Remove this memcpy when the FEC packet classes
97 // are using COW buffers internally.
98 received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
brandtr70e40532016-12-21 00:22:03 -080099 auto payload = parsed_packet.payload();
danilchap96c15872016-11-21 01:35:29 -0800100 memcpy(received_packet->pkt->data, payload.data(), payload.size());
101 received_packet->pkt->length = payload.size();
brandtra8b38552016-10-10 16:44:57 -0700102 } else {
103 // This is a media packet, or a FlexFEC packet belonging to some
104 // other FlexFEC stream.
105 if (received_packet->ssrc != protected_media_ssrc_) {
106 return false;
107 }
108 received_packet->is_fec = false;
109 // Insert entire packet into erasure code.
110 // TODO(brandtr): Remove this memcpy too.
111 received_packet->pkt = rtc::scoped_refptr<Packet>(new Packet());
brandtr70e40532016-12-21 00:22:03 -0800112 memcpy(received_packet->pkt->data, parsed_packet.data(),
113 parsed_packet.size());
114 received_packet->pkt->length = parsed_packet.size();
brandtra8b38552016-10-10 16:44:57 -0700115 }
116 received_packets_.push_back(std::move(received_packet));
117 ++packet_counter_.num_packets;
118
119 return true;
120}
121
122// Note that the implementation of this member function and the implementation
brandtrd55c3f62016-10-31 04:51:33 -0700123// in UlpfecReceiver::ProcessReceivedFec() are slightly different.
brandtra8b38552016-10-10 16:44:57 -0700124// This implementation only returns _recovered_ media packets through the
brandtrd55c3f62016-10-31 04:51:33 -0700125// callback, whereas the implementation in UlpfecReceiver returns _all inserted_
brandtra8b38552016-10-10 16:44:57 -0700126// media packets through the callback. The latter behaviour makes sense
127// for ULPFEC, since the ULPFEC receiver is owned by the RtpStreamReceiver.
128// Here, however, the received media pipeline is more decoupled from the
129// FlexFEC decoder, and we therefore do not interfere with the reception
130// of non-recovered media packets.
brandtr0a4c1612016-11-03 08:18:27 -0700131bool FlexfecReceiver::ProcessReceivedPackets() {
brandtr8b5c3452016-12-19 10:02:30 -0800132 RTC_DCHECK_CALLED_SEQUENTIALLY(&sequence_checker_);
brandtra8b38552016-10-10 16:44:57 -0700133
134 // Decode.
135 if (!received_packets_.empty()) {
136 if (erasure_code_->DecodeFec(&received_packets_, &recovered_packets_) !=
137 0) {
138 return false;
139 }
140 }
141 // Return recovered packets through callback.
142 for (const auto& recovered_packet : recovered_packets_) {
143 if (recovered_packet->returned) {
144 continue;
145 }
146 ++packet_counter_.num_recovered_packets;
brandtr70e40532016-12-21 00:22:03 -0800147 if (!callback_->OnRecoveredPacket(recovered_packet->pkt->data,
148 recovered_packet->pkt->length)) {
brandtra8b38552016-10-10 16:44:57 -0700149 return false;
150 }
151 recovered_packet->returned = true;
152 // Periodically log the incoming packets.
153 int64_t now_ms = clock_->TimeInMilliseconds();
154 if (now_ms - last_recovered_packet_ms_ > kPacketLogIntervalMs) {
155 uint32_t media_ssrc =
156 ForwardErrorCorrection::ParseSsrc(recovered_packet->pkt->data);
brandtr0a4c1612016-11-03 08:18:27 -0700157 LOG(LS_INFO) << "Recovered media packet with SSRC: " << media_ssrc
158 << " from FlexFEC stream with SSRC: " << ssrc_ << ".";
brandtra8b38552016-10-10 16:44:57 -0700159 last_recovered_packet_ms_ = now_ms;
160 }
161 }
162 return true;
163}
164
165} // namespace webrtc