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