1 /*
2  *  Copyright 2018 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 "pc/datagram_rtp_transport.h"
12 
13 #include <algorithm>
14 #include <memory>
15 #include <utility>
16 
17 #include "absl/memory/memory.h"
18 #include "absl/strings/string_view.h"
19 #include "absl/types/optional.h"
20 #include "api/array_view.h"
21 #include "api/rtc_error.h"
22 #include "media/base/rtp_utils.h"
23 #include "modules/rtp_rtcp/source/rtcp_packet/transport_feedback.h"
24 #include "modules/rtp_rtcp/source/rtp_packet.h"
25 #include "modules/rtp_rtcp/source/rtp_packet_received.h"
26 #include "p2p/base/dtls_transport_internal.h"
27 #include "p2p/base/packet_transport_internal.h"
28 #include "rtc_base/buffer.h"
29 #include "rtc_base/checks.h"
30 #include "rtc_base/dscp.h"
31 #include "rtc_base/logging.h"
32 #include "rtc_base/rtc_certificate.h"
33 #include "rtc_base/ssl_stream_adapter.h"
34 #include "rtc_base/stream.h"
35 #include "rtc_base/thread.h"
36 #include "system_wrappers/include/field_trial.h"
37 
38 namespace webrtc {
39 
40 namespace {
41 
42 // Field trials.
43 // Disable datagram to RTCP feedback translation and enable RTCP feedback loop
44 // on top of datagram feedback loop. Note that two
45 // feedback loops add unneccesary overhead, so it's preferable to use feedback
46 // loop provided by datagram transport and convert datagram ACKs to RTCP ACKs,
47 // but enabling RTCP feedback loop may be useful in tests and experiments.
48 const char kDisableDatagramToRtcpFeebackTranslationFieldTrial[] =
49     "WebRTC-kDisableDatagramToRtcpFeebackTranslation";
50 
51 }  // namespace
52 
53 // Maximum packet size of RTCP feedback packet for allocation. We re-create RTCP
54 // feedback packets when we get ACK notifications from datagram transport. Our
55 // rtcp feedback packets contain only 1 ACK, so they are much smaller than 1250.
56 constexpr size_t kMaxRtcpFeedbackPacketSize = 1250;
57 
DatagramRtpTransport(const std::vector<RtpExtension> & rtp_header_extensions,cricket::IceTransportInternal * ice_transport,DatagramTransportInterface * datagram_transport)58 DatagramRtpTransport::DatagramRtpTransport(
59     const std::vector<RtpExtension>& rtp_header_extensions,
60     cricket::IceTransportInternal* ice_transport,
61     DatagramTransportInterface* datagram_transport)
62     : ice_transport_(ice_transport),
63       datagram_transport_(datagram_transport),
64       disable_datagram_to_rtcp_feeback_translation_(field_trial::IsEnabled(
65           kDisableDatagramToRtcpFeebackTranslationFieldTrial)) {
66   // Save extension map for parsing RTP packets (we only need transport
67   // sequence numbers).
68   const RtpExtension* transport_sequence_number_extension =
69       RtpExtension::FindHeaderExtensionByUri(rtp_header_extensions,
70                                              TransportSequenceNumber::kUri);
71 
72   if (transport_sequence_number_extension != nullptr) {
73     rtp_header_extension_map_.Register<TransportSequenceNumber>(
74         transport_sequence_number_extension->id);
75   } else {
76     RTC_LOG(LS_ERROR) << "Transport sequence numbers are not supported in "
77                          "datagram transport connection";
78   }
79 
80   // TODO(sukhanov): Add CHECK to make sure that field trial
81   // WebRTC-ExcludeTransportSequenceNumberFromFecFieldTrial is enabled.
82   // If feedback loop is translation is enabled, FEC packets must exclude
83   // transport sequence numbers, otherwise recovered packets will be corrupt.
84 
85   RTC_DCHECK(ice_transport_);
86   RTC_DCHECK(datagram_transport_);
87 
88   ice_transport_->SignalNetworkRouteChanged.connect(
89       this, &DatagramRtpTransport::OnNetworkRouteChanged);
90   // Subscribe to DatagramTransport to read incoming packets.
91   datagram_transport_->SetDatagramSink(this);
92   datagram_transport_->SetTransportStateCallback(this);
93 }
94 
~DatagramRtpTransport()95 DatagramRtpTransport::~DatagramRtpTransport() {
96   // Unsubscribe from DatagramTransport sinks.
97   datagram_transport_->SetDatagramSink(nullptr);
98   datagram_transport_->SetTransportStateCallback(nullptr);
99 }
100 
SendRtpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)101 bool DatagramRtpTransport::SendRtpPacket(rtc::CopyOnWriteBuffer* packet,
102                                          const rtc::PacketOptions& options,
103                                          int flags) {
104   RTC_DCHECK_RUN_ON(&thread_checker_);
105 
106   // Assign and increment datagram_id.
107   const DatagramId datagram_id = current_datagram_id_++;
108 
109   // Send as is (without extracting transport sequence number) for
110   // RTP packets if we are not doing datagram => RTCP feedback translation.
111   if (disable_datagram_to_rtcp_feeback_translation_) {
112     // Even if we are not extracting transport sequence number we need to
113     // propagate "Sent" notification for both RTP and RTCP packets. For this
114     // reason we need save options.packet_id in packet map.
115     sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
116 
117     return SendDatagram(*packet, datagram_id);
118   }
119 
120   // Parse RTP packet.
121   RtpPacket rtp_packet(&rtp_header_extension_map_);
122   // TODO(mellem): Verify that this doesn't mangle something (it shouldn't).
123   if (!rtp_packet.Parse(*packet)) {
124     RTC_NOTREACHED() << "Failed to parse outgoing RtpPacket, len="
125                      << packet->size()
126                      << ", options.packet_id=" << options.packet_id;
127     return -1;
128   }
129 
130   // Try to get transport sequence number.
131   uint16_t transport_senquence_number;
132   if (!rtp_packet.GetExtension<TransportSequenceNumber>(
133           &transport_senquence_number)) {
134     // Save packet info without transport sequence number.
135     sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
136 
137     RTC_LOG(LS_VERBOSE)
138         << "Sending rtp packet without transport sequence number, packet="
139         << rtp_packet.ToString();
140 
141     return SendDatagram(*packet, datagram_id);
142   }
143 
144   // Save packet info with sequence number and ssrc so we could reconstruct
145   // RTCP feedback packet when we receive datagram ACK.
146   sent_rtp_packet_map_[datagram_id] = SentPacketInfo(
147       options.packet_id, rtp_packet.Ssrc(), transport_senquence_number);
148 
149   // Since datagram transport provides feedback and timestamps, we do not need
150   // to send transport sequence number, so we remove it from RTP packet. Later
151   // when we get Ack for sent datagram, we will re-create RTCP feedback packet.
152   if (!rtp_packet.RemoveExtension(TransportSequenceNumber::kId)) {
153     RTC_NOTREACHED() << "Failed to remove transport sequence number, packet="
154                      << rtp_packet.ToString();
155     return -1;
156   }
157 
158   RTC_LOG(LS_VERBOSE) << "Removed transport_senquence_number="
159                       << transport_senquence_number
160                       << " from packet=" << rtp_packet.ToString()
161                       << ", saved bytes=" << packet->size() - rtp_packet.size();
162 
163   return SendDatagram(
164       rtc::ArrayView<const uint8_t>(rtp_packet.data(), rtp_packet.size()),
165       datagram_id);
166 }
167 
SendRtcpPacket(rtc::CopyOnWriteBuffer * packet,const rtc::PacketOptions & options,int flags)168 bool DatagramRtpTransport::SendRtcpPacket(rtc::CopyOnWriteBuffer* packet,
169                                           const rtc::PacketOptions& options,
170                                           int flags) {
171   RTC_DCHECK_RUN_ON(&thread_checker_);
172 
173   // Assign and increment datagram_id.
174   const DatagramId datagram_id = current_datagram_id_++;
175 
176   // Even if we are not extracting transport sequence number we need to
177   // propagate "Sent" notification for both RTP and RTCP packets. For this
178   // reason we need save options.packet_id in packet map.
179   sent_rtp_packet_map_[datagram_id] = SentPacketInfo(options.packet_id);
180   return SendDatagram(*packet, datagram_id);
181 }
182 
SendDatagram(rtc::ArrayView<const uint8_t> data,DatagramId datagram_id)183 bool DatagramRtpTransport::SendDatagram(rtc::ArrayView<const uint8_t> data,
184                                         DatagramId datagram_id) {
185   return datagram_transport_->SendDatagram(data, datagram_id).ok();
186 }
187 
OnDatagramReceived(rtc::ArrayView<const uint8_t> data)188 void DatagramRtpTransport::OnDatagramReceived(
189     rtc::ArrayView<const uint8_t> data) {
190   RTC_DCHECK_RUN_ON(&thread_checker_);
191 
192   rtc::ArrayView<const char> cdata(reinterpret_cast<const char*>(data.data()),
193                                    data.size());
194   if (cricket::InferRtpPacketType(cdata) == cricket::RtpPacketType::kRtcp) {
195     rtc::CopyOnWriteBuffer buffer(data.data(), data.size());
196     SignalRtcpPacketReceived(&buffer, /*packet_time_us=*/-1);
197     return;
198   }
199 
200   // TODO(sukhanov): I am not filling out time, but on my video quality
201   // test in WebRTC the time was not set either and higher layers of the stack
202   // overwrite -1 with current current rtc time. Leaveing comment for now to
203   // make sure it works as expected.
204   RtpPacketReceived parsed_packet(&rtp_header_extension_map_);
205   if (!parsed_packet.Parse(data)) {
206     RTC_LOG(LS_ERROR) << "Failed to parse incoming RTP packet";
207     return;
208   }
209   if (!rtp_demuxer_.OnRtpPacket(parsed_packet)) {
210     RTC_LOG(LS_WARNING) << "Failed to demux RTP packet: "
211                         << RtpDemuxer::DescribePacket(parsed_packet);
212   }
213 }
214 
OnDatagramSent(DatagramId datagram_id)215 void DatagramRtpTransport::OnDatagramSent(DatagramId datagram_id) {
216   RTC_DCHECK_RUN_ON(&thread_checker_);
217 
218   // Find packet_id and propagate OnPacketSent notification.
219   const auto& it = sent_rtp_packet_map_.find(datagram_id);
220   if (it == sent_rtp_packet_map_.end()) {
221     RTC_NOTREACHED() << "Did not find sent packet info for sent datagram_id="
222                      << datagram_id;
223     return;
224   }
225 
226   // Also see how DatagramRtpTransport::OnSentPacket handles OnSentPacket
227   // notification from ICE in bypass mode.
228   rtc::SentPacket sent_packet(/*packet_id=*/it->second.packet_id,
229                               rtc::TimeMillis());
230 
231   SignalSentPacket(sent_packet);
232 }
233 
GetAndRemoveSentPacketInfo(DatagramId datagram_id,SentPacketInfo * sent_packet_info)234 bool DatagramRtpTransport::GetAndRemoveSentPacketInfo(
235     DatagramId datagram_id,
236     SentPacketInfo* sent_packet_info) {
237   RTC_CHECK(sent_packet_info != nullptr);
238 
239   const auto& it = sent_rtp_packet_map_.find(datagram_id);
240   if (it == sent_rtp_packet_map_.end()) {
241     return false;
242   }
243 
244   *sent_packet_info = it->second;
245   sent_rtp_packet_map_.erase(it);
246   return true;
247 }
248 
OnDatagramAcked(const DatagramAck & ack)249 void DatagramRtpTransport::OnDatagramAcked(const DatagramAck& ack) {
250   RTC_DCHECK_RUN_ON(&thread_checker_);
251 
252   SentPacketInfo sent_packet_info;
253   if (!GetAndRemoveSentPacketInfo(ack.datagram_id, &sent_packet_info)) {
254     // TODO(sukhanov): If OnDatagramAck() can come after OnDatagramLost(),
255     // datagram_id is already deleted and we may need to relax the CHECK below.
256     // It's probably OK to ignore such datagrams, because it's been a few RTTs
257     // anyway since they were sent.
258     RTC_NOTREACHED() << "Did not find sent packet info for datagram_id="
259                      << ack.datagram_id;
260     return;
261   }
262 
263   RTC_LOG(LS_VERBOSE) << "Datagram acked, ack.datagram_id=" << ack.datagram_id
264                       << ", sent_packet_info.packet_id="
265                       << sent_packet_info.packet_id
266                       << ", sent_packet_info.transport_sequence_number="
267                       << sent_packet_info.transport_sequence_number.value_or(-1)
268                       << ", sent_packet_info.ssrc="
269                       << sent_packet_info.ssrc.value_or(-1)
270                       << ", receive_timestamp_ms="
271                       << ack.receive_timestamp.ms();
272 
273   // If transport sequence number was not present in RTP packet, we do not need
274   // to propagate RTCP feedback.
275   if (!sent_packet_info.transport_sequence_number) {
276     return;
277   }
278 
279   // TODO(sukhanov): We noticed that datagram transport implementations can
280   // return zero timestamps in the middle of the call. This is workaround to
281   // avoid propagating zero timestamps, but we need to understand why we have
282   // them in the first place.
283   int64_t receive_timestamp_us = ack.receive_timestamp.us();
284 
285   if (receive_timestamp_us == 0) {
286     receive_timestamp_us = previous_nonzero_timestamp_us_;
287   } else {
288     previous_nonzero_timestamp_us_ = receive_timestamp_us;
289   }
290 
291   // Ssrc must be provided in packet info if transport sequence number is set,
292   // which is guaranteed by SentPacketInfo constructor.
293   RTC_CHECK(sent_packet_info.ssrc);
294 
295   // Recreate RTCP feedback packet.
296   rtcp::TransportFeedback feedback_packet;
297   feedback_packet.SetMediaSsrc(*sent_packet_info.ssrc);
298 
299   const uint16_t transport_sequence_number =
300       sent_packet_info.transport_sequence_number.value();
301 
302   feedback_packet.SetBase(transport_sequence_number, receive_timestamp_us);
303   feedback_packet.AddReceivedPacket(transport_sequence_number,
304                                     receive_timestamp_us);
305 
306   rtc::CopyOnWriteBuffer buffer(kMaxRtcpFeedbackPacketSize);
307   size_t index = 0;
308   if (!feedback_packet.Create(buffer.data(), &index, buffer.capacity(),
309                               nullptr)) {
310     RTC_NOTREACHED() << "Failed to create RTCP feedback packet";
311     return;
312   }
313 
314   RTC_CHECK_GT(index, 0);
315   RTC_CHECK_LE(index, kMaxRtcpFeedbackPacketSize);
316 
317   // Propagage created RTCP packet as normal incoming packet.
318   buffer.SetSize(index);
319   SignalRtcpPacketReceived(&buffer, /*packet_time_us=*/-1);
320 }
321 
OnDatagramLost(DatagramId datagram_id)322 void DatagramRtpTransport::OnDatagramLost(DatagramId datagram_id) {
323   RTC_DCHECK_RUN_ON(&thread_checker_);
324 
325   RTC_LOG(LS_INFO) << "Datagram lost, datagram_id=" << datagram_id;
326 
327   SentPacketInfo sent_packet_info;
328   if (!GetAndRemoveSentPacketInfo(datagram_id, &sent_packet_info)) {
329     RTC_NOTREACHED() << "Did not find sent packet info for lost datagram_id="
330                      << datagram_id;
331   }
332 }
333 
OnStateChanged(MediaTransportState state)334 void DatagramRtpTransport::OnStateChanged(MediaTransportState state) {
335   state_ = state;
336   SignalWritableState(state_ == MediaTransportState::kWritable);
337   if (state_ == MediaTransportState::kWritable) {
338     SignalReadyToSend(true);
339   }
340 }
341 
transport_name() const342 const std::string& DatagramRtpTransport::transport_name() const {
343   return ice_transport_->transport_name();
344 }
345 
SetRtpOption(rtc::Socket::Option opt,int value)346 int DatagramRtpTransport::SetRtpOption(rtc::Socket::Option opt, int value) {
347   return ice_transport_->SetOption(opt, value);
348 }
349 
SetRtcpOption(rtc::Socket::Option opt,int value)350 int DatagramRtpTransport::SetRtcpOption(rtc::Socket::Option opt, int value) {
351   return -1;
352 }
353 
IsReadyToSend() const354 bool DatagramRtpTransport::IsReadyToSend() const {
355   return state_ == MediaTransportState::kWritable;
356 }
357 
IsWritable(bool) const358 bool DatagramRtpTransport::IsWritable(bool /*rtcp*/) const {
359   return state_ == MediaTransportState::kWritable;
360 }
361 
UpdateRtpHeaderExtensionMap(const cricket::RtpHeaderExtensions & header_extensions)362 void DatagramRtpTransport::UpdateRtpHeaderExtensionMap(
363     const cricket::RtpHeaderExtensions& header_extensions) {
364   rtp_header_extension_map_ = RtpHeaderExtensionMap(header_extensions);
365 }
366 
RegisterRtpDemuxerSink(const RtpDemuxerCriteria & criteria,RtpPacketSinkInterface * sink)367 bool DatagramRtpTransport::RegisterRtpDemuxerSink(
368     const RtpDemuxerCriteria& criteria,
369     RtpPacketSinkInterface* sink) {
370   rtp_demuxer_.RemoveSink(sink);
371   return rtp_demuxer_.AddSink(criteria, sink);
372 }
373 
UnregisterRtpDemuxerSink(RtpPacketSinkInterface * sink)374 bool DatagramRtpTransport::UnregisterRtpDemuxerSink(
375     RtpPacketSinkInterface* sink) {
376   return rtp_demuxer_.RemoveSink(sink);
377 }
378 
OnNetworkRouteChanged(absl::optional<rtc::NetworkRoute> network_route)379 void DatagramRtpTransport::OnNetworkRouteChanged(
380     absl::optional<rtc::NetworkRoute> network_route) {
381   RTC_DCHECK_RUN_ON(&thread_checker_);
382   SignalNetworkRouteChanged(network_route);
383 }
384 
385 }  // namespace webrtc
386