1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include "call/flexfec_receive_stream_impl.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <stddef.h>
14*d9f75844SAndroid Build Coastguard Worker
15*d9f75844SAndroid Build Coastguard Worker #include <cstdint>
16*d9f75844SAndroid Build Coastguard Worker #include <string>
17*d9f75844SAndroid Build Coastguard Worker #include <utility>
18*d9f75844SAndroid Build Coastguard Worker
19*d9f75844SAndroid Build Coastguard Worker #include "api/array_view.h"
20*d9f75844SAndroid Build Coastguard Worker #include "api/call/transport.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/rtp_parameters.h"
22*d9f75844SAndroid Build Coastguard Worker #include "call/rtp_stream_receiver_controller_interface.h"
23*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/include/flexfec_receiver.h"
24*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/include/receive_statistics.h"
25*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/rtp_packet_received.h"
26*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
27*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/strings/string_builder.h"
29*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/clock.h"
30*d9f75844SAndroid Build Coastguard Worker
31*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
32*d9f75844SAndroid Build Coastguard Worker
ToString() const33*d9f75844SAndroid Build Coastguard Worker std::string FlexfecReceiveStream::Config::ToString() const {
34*d9f75844SAndroid Build Coastguard Worker char buf[1024];
35*d9f75844SAndroid Build Coastguard Worker rtc::SimpleStringBuilder ss(buf);
36*d9f75844SAndroid Build Coastguard Worker ss << "{payload_type: " << payload_type;
37*d9f75844SAndroid Build Coastguard Worker ss << ", remote_ssrc: " << rtp.remote_ssrc;
38*d9f75844SAndroid Build Coastguard Worker ss << ", local_ssrc: " << rtp.local_ssrc;
39*d9f75844SAndroid Build Coastguard Worker ss << ", protected_media_ssrcs: [";
40*d9f75844SAndroid Build Coastguard Worker size_t i = 0;
41*d9f75844SAndroid Build Coastguard Worker for (; i + 1 < protected_media_ssrcs.size(); ++i)
42*d9f75844SAndroid Build Coastguard Worker ss << protected_media_ssrcs[i] << ", ";
43*d9f75844SAndroid Build Coastguard Worker if (!protected_media_ssrcs.empty())
44*d9f75844SAndroid Build Coastguard Worker ss << protected_media_ssrcs[i];
45*d9f75844SAndroid Build Coastguard Worker ss << "], transport_cc: " << (rtp.transport_cc ? "on" : "off");
46*d9f75844SAndroid Build Coastguard Worker ss << ", rtp.extensions: [";
47*d9f75844SAndroid Build Coastguard Worker i = 0;
48*d9f75844SAndroid Build Coastguard Worker for (; i + 1 < rtp.extensions.size(); ++i)
49*d9f75844SAndroid Build Coastguard Worker ss << rtp.extensions[i].ToString() << ", ";
50*d9f75844SAndroid Build Coastguard Worker if (!rtp.extensions.empty())
51*d9f75844SAndroid Build Coastguard Worker ss << rtp.extensions[i].ToString();
52*d9f75844SAndroid Build Coastguard Worker ss << "]}";
53*d9f75844SAndroid Build Coastguard Worker return ss.str();
54*d9f75844SAndroid Build Coastguard Worker }
55*d9f75844SAndroid Build Coastguard Worker
IsCompleteAndEnabled() const56*d9f75844SAndroid Build Coastguard Worker bool FlexfecReceiveStream::Config::IsCompleteAndEnabled() const {
57*d9f75844SAndroid Build Coastguard Worker // Check if FlexFEC is enabled.
58*d9f75844SAndroid Build Coastguard Worker if (payload_type < 0)
59*d9f75844SAndroid Build Coastguard Worker return false;
60*d9f75844SAndroid Build Coastguard Worker // Do we have the necessary SSRC information?
61*d9f75844SAndroid Build Coastguard Worker if (rtp.remote_ssrc == 0)
62*d9f75844SAndroid Build Coastguard Worker return false;
63*d9f75844SAndroid Build Coastguard Worker // TODO(brandtr): Update this check when we support multistream protection.
64*d9f75844SAndroid Build Coastguard Worker if (protected_media_ssrcs.size() != 1u)
65*d9f75844SAndroid Build Coastguard Worker return false;
66*d9f75844SAndroid Build Coastguard Worker return true;
67*d9f75844SAndroid Build Coastguard Worker }
68*d9f75844SAndroid Build Coastguard Worker
69*d9f75844SAndroid Build Coastguard Worker namespace {
70*d9f75844SAndroid Build Coastguard Worker
71*d9f75844SAndroid Build Coastguard Worker // TODO(brandtr): Update this function when we support multistream protection.
MaybeCreateFlexfecReceiver(Clock * clock,const FlexfecReceiveStream::Config & config,RecoveredPacketReceiver * recovered_packet_receiver)72*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<FlexfecReceiver> MaybeCreateFlexfecReceiver(
73*d9f75844SAndroid Build Coastguard Worker Clock* clock,
74*d9f75844SAndroid Build Coastguard Worker const FlexfecReceiveStream::Config& config,
75*d9f75844SAndroid Build Coastguard Worker RecoveredPacketReceiver* recovered_packet_receiver) {
76*d9f75844SAndroid Build Coastguard Worker if (config.payload_type < 0) {
77*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
78*d9f75844SAndroid Build Coastguard Worker << "Invalid FlexFEC payload type given. "
79*d9f75844SAndroid Build Coastguard Worker "This FlexfecReceiveStream will therefore be useless.";
80*d9f75844SAndroid Build Coastguard Worker return nullptr;
81*d9f75844SAndroid Build Coastguard Worker }
82*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(config.payload_type, 0);
83*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_LE(config.payload_type, 127);
84*d9f75844SAndroid Build Coastguard Worker if (config.rtp.remote_ssrc == 0) {
85*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
86*d9f75844SAndroid Build Coastguard Worker << "Invalid FlexFEC SSRC given. "
87*d9f75844SAndroid Build Coastguard Worker "This FlexfecReceiveStream will therefore be useless.";
88*d9f75844SAndroid Build Coastguard Worker return nullptr;
89*d9f75844SAndroid Build Coastguard Worker }
90*d9f75844SAndroid Build Coastguard Worker if (config.protected_media_ssrcs.empty()) {
91*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
92*d9f75844SAndroid Build Coastguard Worker << "No protected media SSRC supplied. "
93*d9f75844SAndroid Build Coastguard Worker "This FlexfecReceiveStream will therefore be useless.";
94*d9f75844SAndroid Build Coastguard Worker return nullptr;
95*d9f75844SAndroid Build Coastguard Worker }
96*d9f75844SAndroid Build Coastguard Worker
97*d9f75844SAndroid Build Coastguard Worker if (config.protected_media_ssrcs.size() > 1) {
98*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING)
99*d9f75844SAndroid Build Coastguard Worker << "The supplied FlexfecConfig contained multiple protected "
100*d9f75844SAndroid Build Coastguard Worker "media streams, but our implementation currently only "
101*d9f75844SAndroid Build Coastguard Worker "supports protecting a single media stream. "
102*d9f75844SAndroid Build Coastguard Worker "To avoid confusion, disabling FlexFEC completely.";
103*d9f75844SAndroid Build Coastguard Worker return nullptr;
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(1U, config.protected_media_ssrcs.size());
106*d9f75844SAndroid Build Coastguard Worker return std::unique_ptr<FlexfecReceiver>(new FlexfecReceiver(
107*d9f75844SAndroid Build Coastguard Worker clock, config.rtp.remote_ssrc, config.protected_media_ssrcs[0],
108*d9f75844SAndroid Build Coastguard Worker recovered_packet_receiver));
109*d9f75844SAndroid Build Coastguard Worker }
110*d9f75844SAndroid Build Coastguard Worker
CreateRtpRtcpModule(Clock * clock,ReceiveStatistics * receive_statistics,const FlexfecReceiveStreamImpl::Config & config,RtcpRttStats * rtt_stats)111*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<ModuleRtpRtcpImpl2> CreateRtpRtcpModule(
112*d9f75844SAndroid Build Coastguard Worker Clock* clock,
113*d9f75844SAndroid Build Coastguard Worker ReceiveStatistics* receive_statistics,
114*d9f75844SAndroid Build Coastguard Worker const FlexfecReceiveStreamImpl::Config& config,
115*d9f75844SAndroid Build Coastguard Worker RtcpRttStats* rtt_stats) {
116*d9f75844SAndroid Build Coastguard Worker RtpRtcpInterface::Configuration configuration;
117*d9f75844SAndroid Build Coastguard Worker configuration.audio = false;
118*d9f75844SAndroid Build Coastguard Worker configuration.receiver_only = true;
119*d9f75844SAndroid Build Coastguard Worker configuration.clock = clock;
120*d9f75844SAndroid Build Coastguard Worker configuration.receive_statistics = receive_statistics;
121*d9f75844SAndroid Build Coastguard Worker configuration.outgoing_transport = config.rtcp_send_transport;
122*d9f75844SAndroid Build Coastguard Worker configuration.rtt_stats = rtt_stats;
123*d9f75844SAndroid Build Coastguard Worker configuration.local_media_ssrc = config.rtp.local_ssrc;
124*d9f75844SAndroid Build Coastguard Worker return ModuleRtpRtcpImpl2::Create(configuration);
125*d9f75844SAndroid Build Coastguard Worker }
126*d9f75844SAndroid Build Coastguard Worker
127*d9f75844SAndroid Build Coastguard Worker } // namespace
128*d9f75844SAndroid Build Coastguard Worker
FlexfecReceiveStreamImpl(Clock * clock,Config config,RecoveredPacketReceiver * recovered_packet_receiver,RtcpRttStats * rtt_stats)129*d9f75844SAndroid Build Coastguard Worker FlexfecReceiveStreamImpl::FlexfecReceiveStreamImpl(
130*d9f75844SAndroid Build Coastguard Worker Clock* clock,
131*d9f75844SAndroid Build Coastguard Worker Config config,
132*d9f75844SAndroid Build Coastguard Worker RecoveredPacketReceiver* recovered_packet_receiver,
133*d9f75844SAndroid Build Coastguard Worker RtcpRttStats* rtt_stats)
134*d9f75844SAndroid Build Coastguard Worker : extension_map_(std::move(config.rtp.extensions)),
135*d9f75844SAndroid Build Coastguard Worker remote_ssrc_(config.rtp.remote_ssrc),
136*d9f75844SAndroid Build Coastguard Worker transport_cc_(config.rtp.transport_cc),
137*d9f75844SAndroid Build Coastguard Worker payload_type_(config.payload_type),
138*d9f75844SAndroid Build Coastguard Worker receiver_(
139*d9f75844SAndroid Build Coastguard Worker MaybeCreateFlexfecReceiver(clock, config, recovered_packet_receiver)),
140*d9f75844SAndroid Build Coastguard Worker rtp_receive_statistics_(ReceiveStatistics::Create(clock)),
141*d9f75844SAndroid Build Coastguard Worker rtp_rtcp_(CreateRtpRtcpModule(clock,
142*d9f75844SAndroid Build Coastguard Worker rtp_receive_statistics_.get(),
143*d9f75844SAndroid Build Coastguard Worker config,
144*d9f75844SAndroid Build Coastguard Worker rtt_stats)) {
145*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_INFO) << "FlexfecReceiveStreamImpl: " << config.ToString();
146*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(payload_type_, -1);
147*d9f75844SAndroid Build Coastguard Worker
148*d9f75844SAndroid Build Coastguard Worker packet_sequence_checker_.Detach();
149*d9f75844SAndroid Build Coastguard Worker
150*d9f75844SAndroid Build Coastguard Worker // RTCP reporting.
151*d9f75844SAndroid Build Coastguard Worker rtp_rtcp_->SetRTCPStatus(config.rtcp_mode);
152*d9f75844SAndroid Build Coastguard Worker }
153*d9f75844SAndroid Build Coastguard Worker
~FlexfecReceiveStreamImpl()154*d9f75844SAndroid Build Coastguard Worker FlexfecReceiveStreamImpl::~FlexfecReceiveStreamImpl() {
155*d9f75844SAndroid Build Coastguard Worker RTC_DLOG(LS_INFO) << "~FlexfecReceiveStreamImpl: ssrc: " << remote_ssrc_;
156*d9f75844SAndroid Build Coastguard Worker }
157*d9f75844SAndroid Build Coastguard Worker
RegisterWithTransport(RtpStreamReceiverControllerInterface * receiver_controller)158*d9f75844SAndroid Build Coastguard Worker void FlexfecReceiveStreamImpl::RegisterWithTransport(
159*d9f75844SAndroid Build Coastguard Worker RtpStreamReceiverControllerInterface* receiver_controller) {
160*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
161*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(!rtp_stream_receiver_);
162*d9f75844SAndroid Build Coastguard Worker
163*d9f75844SAndroid Build Coastguard Worker if (!receiver_)
164*d9f75844SAndroid Build Coastguard Worker return;
165*d9f75844SAndroid Build Coastguard Worker
166*d9f75844SAndroid Build Coastguard Worker // TODO(nisse): OnRtpPacket in this class delegates all real work to
167*d9f75844SAndroid Build Coastguard Worker // `receiver_`. So maybe we don't need to implement RtpPacketSinkInterface
168*d9f75844SAndroid Build Coastguard Worker // here at all, we'd then delete the OnRtpPacket method and instead register
169*d9f75844SAndroid Build Coastguard Worker // `receiver_` as the RtpPacketSinkInterface for this stream.
170*d9f75844SAndroid Build Coastguard Worker rtp_stream_receiver_ =
171*d9f75844SAndroid Build Coastguard Worker receiver_controller->CreateReceiver(remote_ssrc(), this);
172*d9f75844SAndroid Build Coastguard Worker }
173*d9f75844SAndroid Build Coastguard Worker
UnregisterFromTransport()174*d9f75844SAndroid Build Coastguard Worker void FlexfecReceiveStreamImpl::UnregisterFromTransport() {
175*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
176*d9f75844SAndroid Build Coastguard Worker rtp_stream_receiver_.reset();
177*d9f75844SAndroid Build Coastguard Worker }
178*d9f75844SAndroid Build Coastguard Worker
OnRtpPacket(const RtpPacketReceived & packet)179*d9f75844SAndroid Build Coastguard Worker void FlexfecReceiveStreamImpl::OnRtpPacket(const RtpPacketReceived& packet) {
180*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
181*d9f75844SAndroid Build Coastguard Worker if (!receiver_)
182*d9f75844SAndroid Build Coastguard Worker return;
183*d9f75844SAndroid Build Coastguard Worker
184*d9f75844SAndroid Build Coastguard Worker receiver_->OnRtpPacket(packet);
185*d9f75844SAndroid Build Coastguard Worker
186*d9f75844SAndroid Build Coastguard Worker // Do not report media packets in the RTCP RRs generated by `rtp_rtcp_`.
187*d9f75844SAndroid Build Coastguard Worker if (packet.Ssrc() == remote_ssrc()) {
188*d9f75844SAndroid Build Coastguard Worker rtp_receive_statistics_->OnRtpPacket(packet);
189*d9f75844SAndroid Build Coastguard Worker }
190*d9f75844SAndroid Build Coastguard Worker }
191*d9f75844SAndroid Build Coastguard Worker
SetPayloadType(int payload_type)192*d9f75844SAndroid Build Coastguard Worker void FlexfecReceiveStreamImpl::SetPayloadType(int payload_type) {
193*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
194*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_GE(payload_type, -1);
195*d9f75844SAndroid Build Coastguard Worker payload_type_ = payload_type;
196*d9f75844SAndroid Build Coastguard Worker }
197*d9f75844SAndroid Build Coastguard Worker
payload_type() const198*d9f75844SAndroid Build Coastguard Worker int FlexfecReceiveStreamImpl::payload_type() const {
199*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
200*d9f75844SAndroid Build Coastguard Worker return payload_type_;
201*d9f75844SAndroid Build Coastguard Worker }
202*d9f75844SAndroid Build Coastguard Worker
SetRtpExtensions(std::vector<RtpExtension> extensions)203*d9f75844SAndroid Build Coastguard Worker void FlexfecReceiveStreamImpl::SetRtpExtensions(
204*d9f75844SAndroid Build Coastguard Worker std::vector<RtpExtension> extensions) {
205*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
206*d9f75844SAndroid Build Coastguard Worker extension_map_.Reset(extensions);
207*d9f75844SAndroid Build Coastguard Worker }
208*d9f75844SAndroid Build Coastguard Worker
GetRtpExtensionMap() const209*d9f75844SAndroid Build Coastguard Worker RtpHeaderExtensionMap FlexfecReceiveStreamImpl::GetRtpExtensionMap() const {
210*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
211*d9f75844SAndroid Build Coastguard Worker return extension_map_;
212*d9f75844SAndroid Build Coastguard Worker }
213*d9f75844SAndroid Build Coastguard Worker
SetLocalSsrc(uint32_t local_ssrc)214*d9f75844SAndroid Build Coastguard Worker void FlexfecReceiveStreamImpl::SetLocalSsrc(uint32_t local_ssrc) {
215*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&packet_sequence_checker_);
216*d9f75844SAndroid Build Coastguard Worker if (local_ssrc == rtp_rtcp_->local_media_ssrc())
217*d9f75844SAndroid Build Coastguard Worker return;
218*d9f75844SAndroid Build Coastguard Worker
219*d9f75844SAndroid Build Coastguard Worker rtp_rtcp_->SetLocalSsrc(local_ssrc);
220*d9f75844SAndroid Build Coastguard Worker }
221*d9f75844SAndroid Build Coastguard Worker
222*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
223