2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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.
11 #include "webrtc/modules/rtp_rtcp/source/fec_receiver_impl.h"
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"
24 FecReceiver* FecReceiver::Create(RtpData* callback) {
25 return new FecReceiverImpl(callback);
28 FecReceiverImpl::FecReceiverImpl(RtpData* callback)
29 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
30 recovered_packet_callback_(callback),
31 fec_(new ForwardErrorCorrection()) {}
33 FecReceiverImpl::~FecReceiverImpl() {
34 while (!received_packet_list_.empty()) {
35 delete received_packet_list_.front();
36 received_packet_list_.pop_front();
39 fec_->ResetState(&recovered_packet_list_);
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 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
51 // RFC 2198 RTP Payload for Redundant Audio Data September 1997
53 // The bits in the header are specified as follows:
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
58 // If 0 there is only 1 byte RED header
60 // block PT: 7 bits RTP payload type for this block.
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.
69 // block length: 10 bits Length in bytes of the corresponding data
70 // block excluding header.
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;
79 // Add to list without RED header, aka a virtual RTP packet
80 // we remove the RED header
82 ForwardErrorCorrection::ReceivedPacket* received_packet =
83 new ForwardErrorCorrection::ReceivedPacket;
84 received_packet->pkt = new ForwardErrorCorrection::Packet;
86 // get payload type from RED header
87 uint8_t payload_type =
88 incoming_rtp_packet[header.headerLength] & 0x7f;
90 received_packet->is_fec = payload_type == ulpfec_payload_type;
91 received_packet->seq_num = header.sequenceNumber;
93 uint16_t blockLength = 0;
94 if (incoming_rtp_packet[header.headerLength] & 0x80) {
95 // f bit set in RED header
97 uint16_t timestamp_offset =
98 (incoming_rtp_packet[header.headerLength + 1]) << 8;
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;
111 (0x03 & incoming_rtp_packet[header.headerLength + 2]) << 8;
112 blockLength += (incoming_rtp_packet[header.headerLength + 3]);
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;
121 if (blockLength > payload_data_length - REDHeaderLength) {
122 // block length longer than packet
123 delete received_packet;
129 ForwardErrorCorrection::ReceivedPacket* second_received_packet = NULL;
130 if (blockLength > 0) {
131 // handle block length, split into 2 packets
134 // copy the RTP header
135 memcpy(received_packet->pkt->data, incoming_rtp_packet,
136 header.headerLength);
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
143 // copy the payload data
145 received_packet->pkt->data + header.headerLength,
146 incoming_rtp_packet + header.headerLength + REDHeaderLength,
149 received_packet->pkt->length = blockLength;
151 second_received_packet = new ForwardErrorCorrection::ReceivedPacket;
152 second_received_packet->pkt = new ForwardErrorCorrection::Packet;
154 second_received_packet->is_fec = true;
155 second_received_packet->seq_num = header.sequenceNumber;
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);
163 second_received_packet->pkt->length =
164 payload_data_length - REDHeaderLength - blockLength;
166 } else if (received_packet->is_fec) {
167 // everything behind the RED header
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 ModuleRTPUtility::BufferToUWord32(&incoming_rtp_packet[8]);
177 // copy the RTP header
178 memcpy(received_packet->pkt->data, incoming_rtp_packet,
179 header.headerLength);
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
186 // copy the media payload data
188 received_packet->pkt->data + header.headerLength,
189 incoming_rtp_packet + header.headerLength + REDHeaderLength,
190 payload_data_length - REDHeaderLength);
192 received_packet->pkt->length =
193 header.headerLength + payload_data_length - REDHeaderLength;
196 if (received_packet->pkt->length == 0) {
197 delete second_received_packet;
198 delete received_packet;
202 received_packet_list_.push_back(received_packet);
203 if (second_received_packet) {
204 received_packet_list_.push_back(second_received_packet);
209 int32_t FecReceiverImpl::ProcessReceivedFec() {
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;
217 if (!recovered_packet_callback_->OnRecoveredPacket(packet->data,
223 if (fec_->DecodeFEC(&received_packet_list_, &recovered_packet_list_) != 0) {
227 assert(received_packet_list_.empty());
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.
235 ForwardErrorCorrection::Packet* packet = (*it)->pkt;
237 if (!recovered_packet_callback_->OnRecoveredPacket(packet->data,
242 (*it)->returned = true;
248 } // namespace webrtc