• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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