• 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/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