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 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 // 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 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 ModuleRTPUtility::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 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