fec_receiver_impl.cc revision 98f53510b222f71fdd8b799b2f33737ceeb28c61
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
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
44FecPacketCounter 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
77int32_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
221int32_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