Line data Source code
1 : /*
2 : * Copyright (c) 2012 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/source/ulpfec_receiver_impl.h"
12 :
13 : #include <memory>
14 : #include <utility>
15 :
16 : #include "webrtc/base/checks.h"
17 : #include "webrtc/base/logging.h"
18 : #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
19 : #include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
20 : #include "webrtc/system_wrappers/include/clock.h"
21 :
22 : namespace webrtc {
23 :
24 0 : UlpfecReceiver* UlpfecReceiver::Create(RtpData* callback) {
25 0 : return new UlpfecReceiverImpl(callback);
26 : }
27 :
28 0 : UlpfecReceiverImpl::UlpfecReceiverImpl(RtpData* callback)
29 : : recovered_packet_callback_(callback),
30 0 : fec_(ForwardErrorCorrection::CreateUlpfec()) {}
31 :
32 0 : UlpfecReceiverImpl::~UlpfecReceiverImpl() {
33 0 : received_packets_.clear();
34 0 : fec_->ResetState(&recovered_packets_);
35 0 : }
36 :
37 0 : FecPacketCounter UlpfecReceiverImpl::GetPacketCounter() const {
38 0 : rtc::CritScope cs(&crit_sect_);
39 0 : return packet_counter_;
40 : }
41 :
42 : // 0 1 2 3
43 : // 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
44 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
45 : // |F| block PT | timestamp offset | block length |
46 : // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
47 : //
48 : //
49 : // RFC 2198 RTP Payload for Redundant Audio Data September 1997
50 : //
51 : // The bits in the header are specified as follows:
52 : //
53 : // F: 1 bit First bit in header indicates whether another header block
54 : // follows. If 1 further header blocks follow, if 0 this is the
55 : // last header block.
56 : // If 0 there is only 1 byte RED header
57 : //
58 : // block PT: 7 bits RTP payload type for this block.
59 : //
60 : // timestamp offset: 14 bits Unsigned offset of timestamp of this block
61 : // relative to timestamp given in RTP header. The use of an unsigned
62 : // offset implies that redundant data must be sent after the primary
63 : // data, and is hence a time to be subtracted from the current
64 : // timestamp to determine the timestamp of the data for which this
65 : // block is the redundancy.
66 : //
67 : // block length: 10 bits Length in bytes of the corresponding data
68 : // block excluding header.
69 :
70 0 : int32_t UlpfecReceiverImpl::AddReceivedRedPacket(
71 : const RTPHeader& header,
72 : const uint8_t* incoming_rtp_packet,
73 : size_t packet_length,
74 : uint8_t ulpfec_payload_type) {
75 0 : rtc::CritScope cs(&crit_sect_);
76 :
77 0 : uint8_t red_header_length = 1;
78 0 : size_t payload_data_length = packet_length - header.headerLength;
79 :
80 0 : if (payload_data_length == 0) {
81 0 : LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
82 0 : return -1;
83 : }
84 :
85 : // Remove RED header of incoming packet and store as a virtual RTP packet.
86 : std::unique_ptr<ForwardErrorCorrection::ReceivedPacket> received_packet(
87 0 : new ForwardErrorCorrection::ReceivedPacket());
88 0 : received_packet->pkt = new ForwardErrorCorrection::Packet();
89 :
90 : // Get payload type from RED header and sequence number from RTP header.
91 0 : uint8_t payload_type = incoming_rtp_packet[header.headerLength] & 0x7f;
92 0 : received_packet->is_fec = payload_type == ulpfec_payload_type;
93 0 : received_packet->seq_num = header.sequenceNumber;
94 :
95 0 : uint16_t block_length = 0;
96 0 : if (incoming_rtp_packet[header.headerLength] & 0x80) {
97 : // f bit set in RED header, i.e. there are more than one RED header blocks.
98 0 : red_header_length = 4;
99 0 : if (payload_data_length < red_header_length + 1u) {
100 0 : LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
101 0 : return -1;
102 : }
103 :
104 0 : uint16_t timestamp_offset = incoming_rtp_packet[header.headerLength + 1]
105 0 : << 8;
106 0 : timestamp_offset += incoming_rtp_packet[header.headerLength + 2];
107 0 : timestamp_offset = timestamp_offset >> 2;
108 0 : if (timestamp_offset != 0) {
109 0 : LOG(LS_WARNING) << "Corrupt payload found.";
110 0 : return -1;
111 : }
112 :
113 0 : block_length = (0x3 & incoming_rtp_packet[header.headerLength + 2]) << 8;
114 0 : block_length += incoming_rtp_packet[header.headerLength + 3];
115 :
116 : // Check next RED header block.
117 0 : if (incoming_rtp_packet[header.headerLength + 4] & 0x80) {
118 0 : LOG(LS_WARNING) << "More than 2 blocks in packet not supported.";
119 0 : return -1;
120 : }
121 : // Check that the packet is long enough to contain data in the following
122 : // block.
123 0 : if (block_length > payload_data_length - (red_header_length + 1)) {
124 0 : LOG(LS_WARNING) << "Block length longer than packet.";
125 0 : return -1;
126 : }
127 : }
128 0 : ++packet_counter_.num_packets;
129 0 : if (packet_counter_.first_packet_time_ms == -1) {
130 0 : packet_counter_.first_packet_time_ms =
131 0 : Clock::GetRealTimeClock()->TimeInMilliseconds();
132 : }
133 :
134 : std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>
135 0 : second_received_packet;
136 0 : if (block_length > 0) {
137 : // Handle block length, split into two packets.
138 0 : red_header_length = 5;
139 :
140 : // Copy RTP header.
141 0 : memcpy(received_packet->pkt->data, incoming_rtp_packet,
142 0 : header.headerLength);
143 :
144 : // Set payload type.
145 0 : received_packet->pkt->data[1] &= 0x80; // Reset RED payload type.
146 0 : received_packet->pkt->data[1] += payload_type; // Set media payload type.
147 :
148 : // Copy payload data.
149 0 : memcpy(received_packet->pkt->data + header.headerLength,
150 0 : incoming_rtp_packet + header.headerLength + red_header_length,
151 0 : block_length);
152 0 : received_packet->pkt->length = block_length;
153 :
154 0 : second_received_packet.reset(new ForwardErrorCorrection::ReceivedPacket);
155 0 : second_received_packet->pkt = new ForwardErrorCorrection::Packet;
156 :
157 0 : second_received_packet->is_fec = true;
158 0 : second_received_packet->seq_num = header.sequenceNumber;
159 0 : ++packet_counter_.num_fec_packets;
160 :
161 : // Copy FEC payload data.
162 0 : memcpy(second_received_packet->pkt->data,
163 0 : incoming_rtp_packet + header.headerLength + red_header_length +
164 0 : block_length,
165 0 : payload_data_length - red_header_length - block_length);
166 :
167 0 : second_received_packet->pkt->length =
168 0 : payload_data_length - red_header_length - block_length;
169 :
170 0 : } else if (received_packet->is_fec) {
171 0 : ++packet_counter_.num_fec_packets;
172 : // everything behind the RED header
173 0 : memcpy(received_packet->pkt->data,
174 0 : incoming_rtp_packet + header.headerLength + red_header_length,
175 0 : payload_data_length - red_header_length);
176 0 : received_packet->pkt->length = payload_data_length - red_header_length;
177 0 : received_packet->ssrc =
178 0 : ByteReader<uint32_t>::ReadBigEndian(&incoming_rtp_packet[8]);
179 :
180 : } else {
181 : // Copy RTP header.
182 0 : memcpy(received_packet->pkt->data, incoming_rtp_packet,
183 0 : header.headerLength);
184 :
185 : // Set payload type.
186 0 : received_packet->pkt->data[1] &= 0x80; // Reset RED payload type.
187 0 : received_packet->pkt->data[1] += payload_type; // Set media payload type.
188 :
189 : // Copy payload data.
190 0 : memcpy(received_packet->pkt->data + header.headerLength,
191 0 : incoming_rtp_packet + header.headerLength + red_header_length,
192 0 : payload_data_length - red_header_length);
193 0 : received_packet->pkt->length =
194 0 : header.headerLength + payload_data_length - red_header_length;
195 : }
196 :
197 0 : if (received_packet->pkt->length == 0) {
198 0 : return 0;
199 : }
200 :
201 0 : received_packets_.push_back(std::move(received_packet));
202 0 : if (second_received_packet) {
203 0 : received_packets_.push_back(std::move(second_received_packet));
204 : }
205 0 : return 0;
206 : }
207 :
208 0 : int32_t UlpfecReceiverImpl::ProcessReceivedFec() {
209 0 : crit_sect_.Enter();
210 0 : if (!received_packets_.empty()) {
211 : // Send received media packet to VCM.
212 0 : if (!received_packets_.front()->is_fec) {
213 0 : ForwardErrorCorrection::Packet* packet = received_packets_.front()->pkt;
214 0 : crit_sect_.Leave();
215 0 : if (!recovered_packet_callback_->OnRecoveredPacket(packet->data,
216 0 : packet->length)) {
217 0 : return -1;
218 : }
219 0 : crit_sect_.Enter();
220 : }
221 0 : if (fec_->DecodeFec(&received_packets_, &recovered_packets_) != 0) {
222 0 : crit_sect_.Leave();
223 0 : return -1;
224 : }
225 0 : RTC_DCHECK(received_packets_.empty());
226 : }
227 : // Send any recovered media packets to VCM.
228 0 : for (const auto& recovered_packet : recovered_packets_) {
229 0 : if (recovered_packet->returned) {
230 : // Already sent to the VCM and the jitter buffer.
231 0 : continue;
232 : }
233 0 : ForwardErrorCorrection::Packet* packet = recovered_packet->pkt;
234 0 : ++packet_counter_.num_recovered_packets;
235 0 : crit_sect_.Leave();
236 0 : if (!recovered_packet_callback_->OnRecoveredPacket(packet->data,
237 0 : packet->length)) {
238 0 : return -1;
239 : }
240 0 : crit_sect_.Enter();
241 0 : recovered_packet->returned = true;
242 : }
243 0 : crit_sect_.Leave();
244 0 : return 0;
245 : }
246 :
247 : } // namespace webrtc
|