LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/rtp_rtcp/source/rtcp_packet - nack.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 79 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 9 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2015 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/rtcp_packet/nack.h"
      12             : 
      13             : #include <algorithm>
      14             : 
      15             : #include "webrtc/base/checks.h"
      16             : #include "webrtc/base/logging.h"
      17             : #include "webrtc/modules/rtp_rtcp/source/byte_io.h"
      18             : #include "webrtc/modules/rtp_rtcp/source/rtcp_packet/common_header.h"
      19             : 
      20             : namespace webrtc {
      21             : namespace rtcp {
      22             : constexpr uint8_t Nack::kFeedbackMessageType;
      23             : constexpr size_t Nack::kNackItemLength;
      24             : // RFC 4585: Feedback format.
      25             : //
      26             : // Common packet format:
      27             : //
      28             : //    0                   1                   2                   3
      29             : //    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
      30             : //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      31             : //   |V=2|P|   FMT   |       PT      |          length               |
      32             : //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      33             : // 0 |                  SSRC of packet sender                        |
      34             : //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      35             : // 4 |                  SSRC of media source                         |
      36             : //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      37             : //   :            Feedback Control Information (FCI)                 :
      38             : //   :                                                               :
      39             : //
      40             : // Generic NACK (RFC 4585).
      41             : //
      42             : // FCI:
      43             : //    0                   1                   2                   3
      44             : //    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
      45             : //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      46             : //   |            PID                |             BLP               |
      47             : //   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
      48           0 : Nack::Nack() {}
      49           0 : Nack::~Nack() {}
      50             : 
      51           0 : bool Nack::Parse(const CommonHeader& packet) {
      52           0 :   RTC_DCHECK_EQ(packet.type(), kPacketType);
      53           0 :   RTC_DCHECK_EQ(packet.fmt(), kFeedbackMessageType);
      54             : 
      55           0 :   if (packet.payload_size_bytes() < kCommonFeedbackLength + kNackItemLength) {
      56           0 :     LOG(LS_WARNING) << "Payload length " << packet.payload_size_bytes()
      57           0 :                     << " is too small for a Nack.";
      58           0 :     return false;
      59             :   }
      60             :   size_t nack_items =
      61           0 :       (packet.payload_size_bytes() - kCommonFeedbackLength) / kNackItemLength;
      62             : 
      63           0 :   ParseCommonFeedback(packet.payload());
      64           0 :   const uint8_t* next_nack = packet.payload() + kCommonFeedbackLength;
      65             : 
      66           0 :   packet_ids_.clear();
      67           0 :   packed_.resize(nack_items);
      68           0 :   for (size_t index = 0; index < nack_items; ++index) {
      69           0 :     packed_[index].first_pid = ByteReader<uint16_t>::ReadBigEndian(next_nack);
      70           0 :     packed_[index].bitmask = ByteReader<uint16_t>::ReadBigEndian(next_nack + 2);
      71           0 :     next_nack += kNackItemLength;
      72             :   }
      73           0 :   Unpack();
      74             : 
      75           0 :   return true;
      76             : }
      77             : 
      78           0 : bool Nack::Create(uint8_t* packet,
      79             :                   size_t* index,
      80             :                   size_t max_length,
      81             :                   RtcpPacket::PacketReadyCallback* callback) const {
      82           0 :   RTC_DCHECK(!packed_.empty());
      83             :   // If nack list can't fit in packet, try to fragment.
      84           0 :   constexpr size_t kNackHeaderLength = kHeaderLength + kCommonFeedbackLength;
      85           0 :   for (size_t nack_index = 0; nack_index < packed_.size();) {
      86           0 :     size_t bytes_left_in_buffer = max_length - *index;
      87           0 :     if (bytes_left_in_buffer < kNackHeaderLength + kNackItemLength) {
      88           0 :       if (!OnBufferFull(packet, index, callback))
      89           0 :         return false;
      90           0 :       continue;
      91             :     }
      92             :     size_t num_nack_fields =
      93           0 :         std::min((bytes_left_in_buffer - kNackHeaderLength) / kNackItemLength,
      94           0 :                  packed_.size() - nack_index);
      95             : 
      96             :     size_t payload_size_bytes =
      97           0 :         kCommonFeedbackLength + (num_nack_fields * kNackItemLength);
      98             :     size_t payload_size_32bits =
      99           0 :         rtc::CheckedDivExact<size_t>(payload_size_bytes, 4);
     100             :     CreateHeader(kFeedbackMessageType, kPacketType, payload_size_32bits, packet,
     101           0 :                  index);
     102             : 
     103           0 :     CreateCommonFeedback(packet + *index);
     104           0 :     *index += kCommonFeedbackLength;
     105             : 
     106           0 :     size_t nack_end_index = nack_index + num_nack_fields;
     107           0 :     for (; nack_index < nack_end_index; ++nack_index) {
     108           0 :       const PackedNack& item = packed_[nack_index];
     109           0 :       ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 0, item.first_pid);
     110           0 :       ByteWriter<uint16_t>::WriteBigEndian(packet + *index + 2, item.bitmask);
     111           0 :       *index += kNackItemLength;
     112             :     }
     113           0 :     RTC_DCHECK_LE(*index, max_length);
     114             :   }
     115             : 
     116           0 :   return true;
     117             : }
     118             : 
     119           0 : size_t Nack::BlockLength() const {
     120             :   return kHeaderLength + kCommonFeedbackLength +
     121           0 :          packed_.size() * kNackItemLength;
     122             : }
     123             : 
     124           0 : void Nack::SetPacketIds(const uint16_t* nack_list, size_t length) {
     125           0 :   RTC_DCHECK(nack_list);
     126           0 :   RTC_DCHECK(packet_ids_.empty());
     127           0 :   RTC_DCHECK(packed_.empty());
     128           0 :   packet_ids_.assign(nack_list, nack_list + length);
     129           0 :   Pack();
     130           0 : }
     131             : 
     132           0 : void Nack::Pack() {
     133           0 :   RTC_DCHECK(!packet_ids_.empty());
     134           0 :   RTC_DCHECK(packed_.empty());
     135           0 :   auto it = packet_ids_.begin();
     136           0 :   const auto end = packet_ids_.end();
     137           0 :   while (it != end) {
     138             :     PackedNack item;
     139           0 :     item.first_pid = *it++;
     140             :     // Bitmask specifies losses in any of the 16 packets following the pid.
     141           0 :     item.bitmask = 0;
     142           0 :     while (it != end) {
     143           0 :       uint16_t shift = static_cast<uint16_t>(*it - item.first_pid - 1);
     144           0 :       if (shift <= 15) {
     145           0 :         item.bitmask |= (1 << shift);
     146           0 :         ++it;
     147             :       } else {
     148           0 :         break;
     149             :       }
     150             :     }
     151           0 :     packed_.push_back(item);
     152             :   }
     153           0 : }
     154             : 
     155           0 : void Nack::Unpack() {
     156           0 :   RTC_DCHECK(packet_ids_.empty());
     157           0 :   RTC_DCHECK(!packed_.empty());
     158           0 :   for (const PackedNack& item : packed_) {
     159           0 :     packet_ids_.push_back(item.first_pid);
     160           0 :     uint16_t pid = item.first_pid + 1;
     161           0 :     for (uint16_t bitmask = item.bitmask; bitmask != 0; bitmask >>= 1, ++pid) {
     162           0 :       if (bitmask & 1)
     163           0 :         packet_ids_.push_back(pid);
     164             :     }
     165             :   }
     166           0 : }
     167             : 
     168             : }  // namespace rtcp
     169             : }  // namespace webrtc

Generated by: LCOV version 1.13