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 24 FecReceiver* FecReceiver::Create(RtpData* callback) { 25 return new FecReceiverImpl(callback); 26 } 27 28 FecReceiverImpl::FecReceiverImpl(RtpData* callback) 29 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()), 30 recovered_packet_callback_(callback), 31 fec_(new ForwardErrorCorrection()) {} 32 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 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 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 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