blob: a5d6368df07562a51cbb8f5dc958358831c55f97 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
pwestin@webrtc.org5dad00b2012-01-30 13:05:29 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
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/source/ulpfec_receiver_impl.h"
andrew@webrtc.org7fe219f2012-02-01 02:40:37 +000012
Yves Gerey988cc082018-10-23 12:03:01 +020013#include <string.h>
Jonas Olssona4d87372019-07-05 19:08:33 +020014
kwiberg84be5112016-04-27 01:19:58 -070015#include <memory>
brandtr35c480c2016-08-09 01:23:23 -070016#include <utility>
kwiberg84be5112016-04-27 01:19:58 -070017
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020018#include "absl/memory/memory.h"
Mirko Bonadeid9708072019-01-25 20:26:48 +010019#include "api/scoped_refptr.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020020#include "modules/rtp_rtcp/source/byte_io.h"
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020021#include "modules/rtp_rtcp/source/rtp_packet_received.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020022#include "rtc_base/logging.h"
Niels Möllerb5997872019-01-23 08:45:57 +010023#include "rtc_base/time_utils.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000024
niklase@google.com470e71d2011-07-07 08:21:25 +000025namespace webrtc {
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000026
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020027std::unique_ptr<UlpfecReceiver> UlpfecReceiver::Create(
28 uint32_t ssrc,
29 RecoveredPacketReceiver* callback,
30 rtc::ArrayView<const RtpExtension> extensions) {
31 return absl::make_unique<UlpfecReceiverImpl>(ssrc, callback, extensions);
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +000032}
33
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020034UlpfecReceiverImpl::UlpfecReceiverImpl(
35 uint32_t ssrc,
36 RecoveredPacketReceiver* callback,
37 rtc::ArrayView<const RtpExtension> extensions)
brandtrd726a3f2017-06-29 02:45:35 -070038 : ssrc_(ssrc),
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +020039 extensions_(extensions),
brandtrd726a3f2017-06-29 02:45:35 -070040 recovered_packet_callback_(callback),
41 fec_(ForwardErrorCorrection::CreateUlpfec(ssrc_)) {}
niklase@google.com470e71d2011-07-07 08:21:25 +000042
brandtrd55c3f62016-10-31 04:51:33 -070043UlpfecReceiverImpl::~UlpfecReceiverImpl() {
brandtr74811e52016-08-10 00:51:50 -070044 received_packets_.clear();
Rasmus Brandt78db1582016-09-21 09:19:34 +020045 fec_->ResetState(&recovered_packets_);
niklase@google.com470e71d2011-07-07 08:21:25 +000046}
47
brandtrd55c3f62016-10-31 04:51:33 -070048FecPacketCounter UlpfecReceiverImpl::GetPacketCounter() const {
danilchap7c9426c2016-04-14 03:05:31 -070049 rtc::CritScope cs(&crit_sect_);
asapersson@webrtc.org0800db72015-01-15 07:40:20 +000050 return packet_counter_;
51}
52
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +000053// 0 1 2 3
54// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
55// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
56// |F| block PT | timestamp offset | block length |
57// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
58//
59//
60// RFC 2198 RTP Payload for Redundant Audio Data September 1997
61//
62// The bits in the header are specified as follows:
63//
64// F: 1 bit First bit in header indicates whether another header block
65// follows. If 1 further header blocks follow, if 0 this is the
66// last header block.
67// If 0 there is only 1 byte RED header
68//
69// block PT: 7 bits RTP payload type for this block.
70//
71// timestamp offset: 14 bits Unsigned offset of timestamp of this block
72// relative to timestamp given in RTP header. The use of an unsigned
73// offset implies that redundant data must be sent after the primary
74// data, and is hence a time to be subtracted from the current
75// timestamp to determine the timestamp of the data for which this
76// block is the redundancy.
77//
78// block length: 10 bits Length in bytes of the corresponding data
79// block excluding header.
niklase@google.com470e71d2011-07-07 08:21:25 +000080
brandtrd55c3f62016-10-31 04:51:33 -070081int32_t UlpfecReceiverImpl::AddReceivedRedPacket(
82 const RTPHeader& header,
83 const uint8_t* incoming_rtp_packet,
84 size_t packet_length,
85 uint8_t ulpfec_payload_type) {
brandtrd726a3f2017-06-29 02:45:35 -070086 if (header.ssrc != ssrc_) {
Mirko Bonadei675513b2017-11-09 11:09:25 +010087 RTC_LOG(LS_WARNING)
brandtrd726a3f2017-06-29 02:45:35 -070088 << "Received RED packet with different SSRC than expected; dropping.";
89 return -1;
90 }
Ying Wang7a84fcf2018-05-18 13:48:58 +020091 if (packet_length > IP_PACKET_SIZE) {
92 RTC_LOG(LS_WARNING) << "Received RED packet with length exceeds maximum IP "
93 "packet size; dropping.";
94 return -1;
95 }
danilchap7c9426c2016-04-14 03:05:31 -070096 rtc::CritScope cs(&crit_sect_);
brandtr74811e52016-08-10 00:51:50 -070097
98 uint8_t red_header_length = 1;
pkasting@chromium.org4591fbd2014-11-20 22:28:14 +000099 size_t payload_data_length = packet_length - header.headerLength;
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000100
pbos70d5c472015-06-29 07:22:04 -0700101 if (payload_data_length == 0) {
Mirko Bonadei675513b2017-11-09 11:09:25 +0100102 RTC_LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
pbos70d5c472015-06-29 07:22:04 -0700103 return -1;
104 }
105
brandtr74811e52016-08-10 00:51:50 -0700106 // Remove RED header of incoming packet and store as a virtual RTP packet.
kwiberg84be5112016-04-27 01:19:58 -0700107 std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200108 new ForwardErrorCorrection::ReceivedPacket());
109 received_packet->pkt = new ForwardErrorCorrection::Packet();
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000110
brandtr74811e52016-08-10 00:51:50 -0700111 // Get payload type from RED header and sequence number from RTP header.
112 uint8_t payload_type = incoming_rtp_packet[header.headerLength] & 0x7f;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000113 received_packet->is_fec = payload_type == ulpfec_payload_type;
brandtrd726a3f2017-06-29 02:45:35 -0700114 received_packet->ssrc = header.ssrc;
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000115 received_packet->seq_num = header.sequenceNumber;
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000116
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000117 if (incoming_rtp_packet[header.headerLength] & 0x80) {
brandtr74811e52016-08-10 00:51:50 -0700118 // f bit set in RED header, i.e. there are more than one RED header blocks.
Ilya Nikolaevskiy36c8ef62019-06-27 10:08:50 +0200119 // WebRTC never generates multiple blocks in a RED packet for FEC.
120 RTC_LOG(LS_WARNING) << "More than 1 block in RED packet is not supported.";
121 return -1;
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000122 }
Ilya Nikolaevskiy36c8ef62019-06-27 10:08:50 +0200123
asapersson@webrtc.org0800db72015-01-15 07:40:20 +0000124 ++packet_counter_.num_packets;
asapersson0c43f772016-11-30 01:42:26 -0800125 if (packet_counter_.first_packet_time_ms == -1) {
Niels Möllerb5997872019-01-23 08:45:57 +0100126 packet_counter_.first_packet_time_ms = rtc::TimeMillis();
asapersson0c43f772016-11-30 01:42:26 -0800127 }
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000128
Ilya Nikolaevskiy36c8ef62019-06-27 10:08:50 +0200129 if (received_packet->is_fec) {
asapersson@webrtc.org0800db72015-01-15 07:40:20 +0000130 ++packet_counter_.num_fec_packets;
Ying Wang7a84fcf2018-05-18 13:48:58 +0200131
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000132 // everything behind the RED header
brandtr74811e52016-08-10 00:51:50 -0700133 memcpy(received_packet->pkt->data,
134 incoming_rtp_packet + header.headerLength + red_header_length,
135 payload_data_length - red_header_length);
136 received_packet->pkt->length = payload_data_length - red_header_length;
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +0000137 received_packet->ssrc =
sprang@webrtc.org779c3d12015-03-17 16:42:49 +0000138 ByteReader<uint32_t>::ReadBigEndian(&incoming_rtp_packet[8]);
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000139
140 } else {
brandtr74811e52016-08-10 00:51:50 -0700141 // Copy RTP header.
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +0000142 memcpy(received_packet->pkt->data, incoming_rtp_packet,
stefan@webrtc.org7bb8f022013-09-06 13:40:11 +0000143 header.headerLength);
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000144
brandtr74811e52016-08-10 00:51:50 -0700145 // Set payload type.
146 received_packet->pkt->data[1] &= 0x80; // Reset RED payload type.
147 received_packet->pkt->data[1] += payload_type; // Set media payload type.
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000148
brandtr74811e52016-08-10 00:51:50 -0700149 // Copy payload data.
150 memcpy(received_packet->pkt->data + header.headerLength,
151 incoming_rtp_packet + header.headerLength + red_header_length,
152 payload_data_length - red_header_length);
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +0000153 received_packet->pkt->length =
brandtr74811e52016-08-10 00:51:50 -0700154 header.headerLength + payload_data_length - red_header_length;
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000155 }
156
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +0000157 if (received_packet->pkt->length == 0) {
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000158 return 0;
159 }
160
brandtr74811e52016-08-10 00:51:50 -0700161 received_packets_.push_back(std::move(received_packet));
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000162 return 0;
163}
niklase@google.com470e71d2011-07-07 08:21:25 +0000164
nissea5f043f2017-09-18 07:58:59 -0700165// TODO(nisse): Drop always-zero return value.
brandtrd55c3f62016-10-31 04:51:33 -0700166int32_t UlpfecReceiverImpl::ProcessReceivedFec() {
danilchap7c9426c2016-04-14 03:05:31 -0700167 crit_sect_.Enter();
philipeld8f6c162018-01-19 14:41:41 +0100168
169 // If we iterate over |received_packets_| and it contains a packet that cause
170 // us to recurse back to this function (for example a RED packet encapsulating
171 // a RED packet), then we will recurse forever. To avoid this we swap
172 // |received_packets_| with an empty vector so that the next recursive call
173 // wont iterate over the same packet again. This also solves the problem of
174 // not modifying the vector we are currently iterating over (packets are added
175 // in AddReceivedRedPacket).
176 std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>
Yves Gerey665174f2018-06-19 15:03:05 +0200177 received_packets;
philipeld8f6c162018-01-19 14:41:41 +0100178 received_packets.swap(received_packets_);
179
180 for (const auto& received_packet : received_packets) {
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000181 // Send received media packet to VCM.
nissea5f043f2017-09-18 07:58:59 -0700182 if (!received_packet->is_fec) {
183 ForwardErrorCorrection::Packet* packet = received_packet->pkt;
danilchap7c9426c2016-04-14 03:05:31 -0700184 crit_sect_.Leave();
nisse30e89312017-05-29 08:16:37 -0700185 recovered_packet_callback_->OnRecoveredPacket(packet->data,
186 packet->length);
danilchap7c9426c2016-04-14 03:05:31 -0700187 crit_sect_.Enter();
Ilya Nikolaevskiy2d821c32019-06-26 14:39:36 +0200188 RtpPacketReceived rtp_packet;
189 // TODO(ilnik): move extension nullifying out of RtpPacket, so there's no
190 // need to create one here, and avoid two memcpy calls below.
191 rtp_packet.Parse(packet->data, packet->length); // Does memcopy.
192 rtp_packet.IdentifyExtensions(extensions_);
193 rtp_packet.CopyAndZeroMutableExtensions( // Does memcopy.
194 rtc::MakeArrayView(packet->data, packet->length));
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000195 }
nissea5f043f2017-09-18 07:58:59 -0700196 fec_->DecodeFec(*received_packet, &recovered_packets_);
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000197 }
nissea5f043f2017-09-18 07:58:59 -0700198
marpan@webrtc.org3a6080d2012-03-30 16:16:21 +0000199 // Send any recovered media packets to VCM.
brandtr74811e52016-08-10 00:51:50 -0700200 for (const auto& recovered_packet : recovered_packets_) {
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200201 if (recovered_packet->returned) {
202 // Already sent to the VCM and the jitter buffer.
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000203 continue;
Rasmus Brandtae4f7672016-07-07 09:40:51 +0200204 }
205 ForwardErrorCorrection::Packet* packet = recovered_packet->pkt;
asapersson@webrtc.org0800db72015-01-15 07:40:20 +0000206 ++packet_counter_.num_recovered_packets;
nisse41476e02017-08-25 09:08:44 -0700207 // Set this flag first; in case the recovered packet carries a RED
208 // header, OnRecoveredPacket will recurse back here.
209 recovered_packet->returned = true;
danilchap7c9426c2016-04-14 03:05:31 -0700210 crit_sect_.Leave();
Yves Gerey665174f2018-06-19 15:03:05 +0200211 recovered_packet_callback_->OnRecoveredPacket(packet->data, packet->length);
danilchap7c9426c2016-04-14 03:05:31 -0700212 crit_sect_.Enter();
pwestin@webrtc.org95cf4792012-01-20 06:59:06 +0000213 }
philipeld8f6c162018-01-19 14:41:41 +0100214
danilchap7c9426c2016-04-14 03:05:31 -0700215 crit_sect_.Leave();
marpan@webrtc.org57353a32011-12-16 17:21:09 +0000216 return 0;
217}
stefan@webrtc.org7adab092012-02-09 12:34:52 +0000218
phoglund@webrtc.org9919ad52013-05-16 15:06:28 +0000219} // namespace webrtc