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