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