Home | History | Annotate | Download | only in source
      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 
     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 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 
     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 
    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