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