• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "modules/rtp_rtcp/source/ulpfec_receiver_impl.h"
12 
13 #include <memory>
14 #include <utility>
15 
16 #include "api/scoped_refptr.h"
17 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
18 #include "rtc_base/logging.h"
19 #include "rtc_base/time_utils.h"
20 
21 namespace webrtc {
22 
Create(uint32_t ssrc,RecoveredPacketReceiver * callback,rtc::ArrayView<const RtpExtension> extensions)23 std::unique_ptr<UlpfecReceiver> UlpfecReceiver::Create(
24     uint32_t ssrc,
25     RecoveredPacketReceiver* callback,
26     rtc::ArrayView<const RtpExtension> extensions) {
27   return std::make_unique<UlpfecReceiverImpl>(ssrc, callback, extensions);
28 }
29 
UlpfecReceiverImpl(uint32_t ssrc,RecoveredPacketReceiver * callback,rtc::ArrayView<const RtpExtension> extensions)30 UlpfecReceiverImpl::UlpfecReceiverImpl(
31     uint32_t ssrc,
32     RecoveredPacketReceiver* callback,
33     rtc::ArrayView<const RtpExtension> extensions)
34     : ssrc_(ssrc),
35       extensions_(extensions),
36       recovered_packet_callback_(callback),
37       fec_(ForwardErrorCorrection::CreateUlpfec(ssrc_)) {}
38 
~UlpfecReceiverImpl()39 UlpfecReceiverImpl::~UlpfecReceiverImpl() {
40   received_packets_.clear();
41   fec_->ResetState(&recovered_packets_);
42 }
43 
GetPacketCounter() const44 FecPacketCounter UlpfecReceiverImpl::GetPacketCounter() const {
45   MutexLock lock(&mutex_);
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 
AddReceivedRedPacket(const RtpPacketReceived & rtp_packet,uint8_t ulpfec_payload_type)77 bool UlpfecReceiverImpl::AddReceivedRedPacket(
78     const RtpPacketReceived& rtp_packet,
79     uint8_t ulpfec_payload_type) {
80   if (rtp_packet.Ssrc() != ssrc_) {
81     RTC_LOG(LS_WARNING)
82         << "Received RED packet with different SSRC than expected; dropping.";
83     return false;
84   }
85   if (rtp_packet.size() > IP_PACKET_SIZE) {
86     RTC_LOG(LS_WARNING) << "Received RED packet with length exceeds maximum IP "
87                            "packet size; dropping.";
88     return false;
89   }
90   MutexLock lock(&mutex_);
91 
92   static constexpr uint8_t kRedHeaderLength = 1;
93 
94   if (rtp_packet.payload_size() == 0) {
95     RTC_LOG(LS_WARNING) << "Corrupt/truncated FEC packet.";
96     return false;
97   }
98 
99   // Remove RED header of incoming packet and store as a virtual RTP packet.
100   auto received_packet =
101       std::make_unique<ForwardErrorCorrection::ReceivedPacket>();
102   received_packet->pkt = new ForwardErrorCorrection::Packet();
103 
104   // Get payload type from RED header and sequence number from RTP header.
105   uint8_t payload_type = rtp_packet.payload()[0] & 0x7f;
106   received_packet->is_fec = payload_type == ulpfec_payload_type;
107   received_packet->is_recovered = rtp_packet.recovered();
108   received_packet->ssrc = rtp_packet.Ssrc();
109   received_packet->seq_num = rtp_packet.SequenceNumber();
110 
111   if (rtp_packet.payload()[0] & 0x80) {
112     // f bit set in RED header, i.e. there are more than one RED header blocks.
113     // WebRTC never generates multiple blocks in a RED packet for FEC.
114     RTC_LOG(LS_WARNING) << "More than 1 block in RED packet is not supported.";
115     return false;
116   }
117 
118   ++packet_counter_.num_packets;
119   packet_counter_.num_bytes += rtp_packet.size();
120   if (packet_counter_.first_packet_time_ms == -1) {
121     packet_counter_.first_packet_time_ms = rtc::TimeMillis();
122   }
123 
124   if (received_packet->is_fec) {
125     ++packet_counter_.num_fec_packets;
126     // everything behind the RED header
127     received_packet->pkt->data =
128         rtp_packet.Buffer().Slice(rtp_packet.headers_size() + kRedHeaderLength,
129                                   rtp_packet.payload_size() - kRedHeaderLength);
130   } else {
131     auto red_payload = rtp_packet.payload().subview(kRedHeaderLength);
132     received_packet->pkt->data.EnsureCapacity(rtp_packet.headers_size() +
133                                               red_payload.size());
134     // Copy RTP header.
135     received_packet->pkt->data.SetData(rtp_packet.data(),
136                                        rtp_packet.headers_size());
137     // Set payload type.
138     received_packet->pkt->data[1] &= 0x80;          // Reset RED payload type.
139     received_packet->pkt->data[1] += payload_type;  // Set media payload type.
140     // Copy payload data.
141     received_packet->pkt->data.AppendData(red_payload.data(),
142                                           red_payload.size());
143   }
144 
145   if (received_packet->pkt->data.size() > 0) {
146     received_packets_.push_back(std::move(received_packet));
147   }
148   return true;
149 }
150 
151 // TODO(nisse): Drop always-zero return value.
ProcessReceivedFec()152 int32_t UlpfecReceiverImpl::ProcessReceivedFec() {
153   mutex_.Lock();
154 
155   // If we iterate over |received_packets_| and it contains a packet that cause
156   // us to recurse back to this function (for example a RED packet encapsulating
157   // a RED packet), then we will recurse forever. To avoid this we swap
158   // |received_packets_| with an empty vector so that the next recursive call
159   // wont iterate over the same packet again. This also solves the problem of
160   // not modifying the vector we are currently iterating over (packets are added
161   // in AddReceivedRedPacket).
162   std::vector<std::unique_ptr<ForwardErrorCorrection::ReceivedPacket>>
163       received_packets;
164   received_packets.swap(received_packets_);
165 
166   for (const auto& received_packet : received_packets) {
167     // Send received media packet to VCM.
168     if (!received_packet->is_fec) {
169       ForwardErrorCorrection::Packet* packet = received_packet->pkt;
170       mutex_.Unlock();
171       recovered_packet_callback_->OnRecoveredPacket(packet->data.data(),
172                                                     packet->data.size());
173       mutex_.Lock();
174       // Create a packet with the buffer to modify it.
175       RtpPacketReceived rtp_packet;
176       const uint8_t* const original_data = packet->data.cdata();
177       if (!rtp_packet.Parse(packet->data)) {
178         RTC_LOG(LS_WARNING) << "Corrupted media packet";
179       } else {
180         rtp_packet.IdentifyExtensions(extensions_);
181         // Reset buffer reference, so zeroing would work on a buffer with a
182         // single reference.
183         packet->data = rtc::CopyOnWriteBuffer(0);
184         rtp_packet.ZeroMutableExtensions();
185         packet->data = rtp_packet.Buffer();
186         // Ensure that zeroing of extensions was done in place.
187         RTC_DCHECK_EQ(packet->data.cdata(), original_data);
188       }
189     }
190     if (!received_packet->is_recovered) {
191       // Do not pass recovered packets to FEC. Recovered packet might have
192       // different set of the RTP header extensions and thus different byte
193       // representation than the original packet, That will corrupt
194       // FEC calculation.
195       fec_->DecodeFec(*received_packet, &recovered_packets_);
196     }
197   }
198 
199   // Send any recovered media packets to VCM.
200   for (const auto& recovered_packet : recovered_packets_) {
201     if (recovered_packet->returned) {
202       // Already sent to the VCM and the jitter buffer.
203       continue;
204     }
205     ForwardErrorCorrection::Packet* packet = recovered_packet->pkt;
206     ++packet_counter_.num_recovered_packets;
207     // Set this flag first; in case the recovered packet carries a RED
208     // header, OnRecoveredPacket will recurse back here.
209     recovered_packet->returned = true;
210     mutex_.Unlock();
211     recovered_packet_callback_->OnRecoveredPacket(packet->data.data(),
212                                                   packet->data.size());
213     mutex_.Lock();
214   }
215 
216   mutex_.Unlock();
217   return 0;
218 }
219 
220 }  // namespace webrtc
221