blob: a86e18bf239794b6122e41cb77bb80c66f50a5d7 [file] [log] [blame]
nissecae45d02017-04-24 05:53:20 -07001/*
2 * Copyright (c) 2017 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 */
Sebastian Jansson91bb6672018-02-21 13:02:51 +010010#include <utility>
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020011#include <vector>
nissecae45d02017-04-24 05:53:20 -070012
Karl Wiberg918f50c2018-07-05 11:40:33 +020013#include "absl/memory/memory.h"
Yves Gerey3e707812018-11-28 16:47:49 +010014#include "absl/types/optional.h"
15#include "api/transport/network_types.h"
16#include "api/units/data_rate.h"
17#include "api/units/time_delta.h"
18#include "api/units/timestamp.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "call/rtp_transport_controller_send.h"
Yves Gerey3e707812018-11-28 16:47:49 +010020#include "call/rtp_video_sender.h"
Sebastian Jansson10211e92018-02-28 16:48:26 +010021#include "modules/congestion_controller/include/send_side_congestion_controller.h"
Sebastian Jansson19bea512018-03-13 19:07:46 +010022#include "modules/congestion_controller/rtp/include/send_side_congestion_controller.h"
Yves Gerey3e707812018-11-28 16:47:49 +010023#include "rtc_base/checks.h"
Sebastian Janssonc33c0fc2018-02-22 11:10:18 +010024#include "rtc_base/location.h"
Sebastian Jansson97f61ea2018-02-21 13:01:55 +010025#include "rtc_base/logging.h"
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020026#include "rtc_base/rate_limiter.h"
Sebastian Jansson19bea512018-03-13 19:07:46 +010027#include "system_wrappers/include/field_trial.h"
nissecae45d02017-04-24 05:53:20 -070028
29namespace webrtc {
Sebastian Jansson19bea512018-03-13 19:07:46 +010030namespace {
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020031static const int64_t kRetransmitWindowSizeMs = 500;
Stefan Holmer64be7fa2018-10-04 15:21:55 +020032static const size_t kMaxOverheadBytes = 500;
Sebastian Jansson19bea512018-03-13 19:07:46 +010033const char kTaskQueueExperiment[] = "WebRTC-TaskQueueCongestionControl";
34using TaskQueueController = webrtc::webrtc_cc::SendSideCongestionController;
35
Sebastian Jansson19bea512018-03-13 19:07:46 +010036std::unique_ptr<SendSideCongestionControllerInterface> CreateController(
37 Clock* clock,
Sebastian Janssonbd9fe092018-05-07 16:33:50 +020038 rtc::TaskQueue* task_queue,
Sebastian Jansson19bea512018-03-13 19:07:46 +010039 webrtc::RtcEventLog* event_log,
40 PacedSender* pacer,
41 const BitrateConstraints& bitrate_config,
Sebastian Janssondfce03a2018-05-18 18:05:10 +020042 bool task_queue_controller,
43 NetworkControllerFactoryInterface* controller_factory) {
Sebastian Jansson19bea512018-03-13 19:07:46 +010044 if (task_queue_controller) {
Sebastian Jansson4e140da2018-04-13 13:25:19 +020045 RTC_LOG(LS_INFO) << "Using TaskQueue based SSCC";
Karl Wiberg918f50c2018-07-05 11:40:33 +020046 return absl::make_unique<webrtc::webrtc_cc::SendSideCongestionController>(
Sebastian Janssonbd9fe092018-05-07 16:33:50 +020047 clock, task_queue, event_log, pacer, bitrate_config.start_bitrate_bps,
Sebastian Janssondfce03a2018-05-18 18:05:10 +020048 bitrate_config.min_bitrate_bps, bitrate_config.max_bitrate_bps,
49 controller_factory);
Sebastian Jansson19bea512018-03-13 19:07:46 +010050 }
Sebastian Jansson4e140da2018-04-13 13:25:19 +020051 RTC_LOG(LS_INFO) << "Using Legacy SSCC";
Karl Wiberg918f50c2018-07-05 11:40:33 +020052 auto cc = absl::make_unique<webrtc::SendSideCongestionController>(
Sebastian Jansson19bea512018-03-13 19:07:46 +010053 clock, nullptr /* observer */, event_log, pacer);
54 cc->SignalNetworkState(kNetworkDown);
55 cc->SetBweBitrates(bitrate_config.min_bitrate_bps,
56 bitrate_config.start_bitrate_bps,
57 bitrate_config.max_bitrate_bps);
58 return std::move(cc);
59}
60} // namespace
nissecae45d02017-04-24 05:53:20 -070061
62RtpTransportControllerSend::RtpTransportControllerSend(
63 Clock* clock,
Sebastian Jansson97f61ea2018-02-21 13:01:55 +010064 webrtc::RtcEventLog* event_log,
Sebastian Janssondfce03a2018-05-18 18:05:10 +020065 NetworkControllerFactoryInterface* controller_factory,
Sebastian Jansson97f61ea2018-02-21 13:01:55 +010066 const BitrateConstraints& bitrate_config)
Sebastian Jansson19704ec2018-03-12 15:59:12 +010067 : clock_(clock),
68 pacer_(clock, &packet_router_, event_log),
Sebastian Jansson317a5222018-03-16 15:36:37 +010069 bitrate_configurator_(bitrate_config),
70 process_thread_(ProcessThread::Create("SendControllerThread")),
71 observer_(nullptr),
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020072 retransmission_rate_limiter_(clock, kRetransmitWindowSizeMs),
Sebastian Janssone6256052018-05-04 14:08:15 +020073 task_queue_("rtp_send_controller") {
Sebastian Janssonbd9fe092018-05-07 16:33:50 +020074 // Created after task_queue to be able to post to the task queue internally.
Sebastian Jansson4ff72142018-10-08 11:15:04 +020075 send_side_cc_ = CreateController(
76 clock, &task_queue_, event_log, &pacer_, bitrate_config,
77 !field_trial::IsDisabled(kTaskQueueExperiment), controller_factory);
Sebastian Janssonbd9fe092018-05-07 16:33:50 +020078
Sebastian Janssonc33c0fc2018-02-22 11:10:18 +010079 process_thread_->RegisterModule(&pacer_, RTC_FROM_HERE);
Sebastian Jansson10211e92018-02-28 16:48:26 +010080 process_thread_->RegisterModule(send_side_cc_.get(), RTC_FROM_HERE);
Sebastian Janssonc33c0fc2018-02-22 11:10:18 +010081 process_thread_->Start();
Sebastian Jansson97f61ea2018-02-21 13:01:55 +010082}
Sebastian Janssonc33c0fc2018-02-22 11:10:18 +010083
84RtpTransportControllerSend::~RtpTransportControllerSend() {
85 process_thread_->Stop();
Sebastian Jansson10211e92018-02-28 16:48:26 +010086 process_thread_->DeRegisterModule(send_side_cc_.get());
Sebastian Janssonc33c0fc2018-02-22 11:10:18 +010087 process_thread_->DeRegisterModule(&pacer_);
88}
nissecae45d02017-04-24 05:53:20 -070089
Stefan Holmer9416ef82018-07-19 10:34:38 +020090RtpVideoSenderInterface* RtpTransportControllerSend::CreateRtpVideoSender(
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020091 const std::vector<uint32_t>& ssrcs,
92 std::map<uint32_t, RtpState> suspended_ssrcs,
93 const std::map<uint32_t, RtpPayloadState>& states,
94 const RtpConfig& rtp_config,
Jiawei Ou55718122018-11-09 13:17:39 -080095 int rtcp_report_interval_ms,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +020096 Transport* send_transport,
97 const RtpSenderObservers& observers,
Stefan Holmer64be7fa2018-10-04 15:21:55 +020098 RtcEventLog* event_log,
Benjamin Wright192eeec2018-10-17 17:27:25 -070099 std::unique_ptr<FecController> fec_controller,
100 const RtpSenderFrameEncryptionConfig& frame_encryption_config) {
Stefan Holmer9416ef82018-07-19 10:34:38 +0200101 video_rtp_senders_.push_back(absl::make_unique<RtpVideoSender>(
Jiawei Ou55718122018-11-09 13:17:39 -0800102 ssrcs, suspended_ssrcs, states, rtp_config, rtcp_report_interval_ms,
103 send_transport, observers,
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200104 // TODO(holmer): Remove this circular dependency by injecting
105 // the parts of RtpTransportControllerSendInterface that are really used.
Benjamin Wright192eeec2018-10-17 17:27:25 -0700106 this, event_log, &retransmission_rate_limiter_, std::move(fec_controller),
107 frame_encryption_config.frame_encryptor,
108 frame_encryption_config.crypto_options));
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200109 return video_rtp_senders_.back().get();
110}
111
Stefan Holmer9416ef82018-07-19 10:34:38 +0200112void RtpTransportControllerSend::DestroyRtpVideoSender(
113 RtpVideoSenderInterface* rtp_video_sender) {
114 std::vector<std::unique_ptr<RtpVideoSenderInterface>>::iterator it =
Stefan Holmer5ed25af2018-07-18 15:17:14 +0200115 video_rtp_senders_.end();
116 for (it = video_rtp_senders_.begin(); it != video_rtp_senders_.end(); ++it) {
117 if (it->get() == rtp_video_sender) {
118 break;
119 }
120 }
121 RTC_DCHECK(it != video_rtp_senders_.end());
122 video_rtp_senders_.erase(it);
123}
124
Sebastian Jansson19704ec2018-03-12 15:59:12 +0100125void RtpTransportControllerSend::OnNetworkChanged(uint32_t bitrate_bps,
126 uint8_t fraction_loss,
127 int64_t rtt_ms,
128 int64_t probing_interval_ms) {
129 // TODO(srte): Skip this step when old SendSideCongestionController is
130 // deprecated.
131 TargetTransferRate msg;
132 msg.at_time = Timestamp::ms(clock_->TimeInMilliseconds());
133 msg.target_rate = DataRate::bps(bitrate_bps);
134 msg.network_estimate.at_time = msg.at_time;
135 msg.network_estimate.bwe_period = TimeDelta::ms(probing_interval_ms);
136 uint32_t bandwidth_bps;
Sebastian Janssonbd9fe092018-05-07 16:33:50 +0200137 if (send_side_cc_->AvailableBandwidth(&bandwidth_bps))
Sebastian Jansson19704ec2018-03-12 15:59:12 +0100138 msg.network_estimate.bandwidth = DataRate::bps(bandwidth_bps);
139 msg.network_estimate.loss_rate_ratio = fraction_loss / 255.0;
140 msg.network_estimate.round_trip_time = TimeDelta::ms(rtt_ms);
Sebastian Janssone6256052018-05-04 14:08:15 +0200141
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200142 retransmission_rate_limiter_.SetMaxRate(bandwidth_bps);
143
Sebastian Janssone6256052018-05-04 14:08:15 +0200144 if (!task_queue_.IsCurrent()) {
145 task_queue_.PostTask([this, msg] {
146 rtc::CritScope cs(&observer_crit_);
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200147 // We won't register as observer until we have an observers.
Sebastian Janssone6256052018-05-04 14:08:15 +0200148 RTC_DCHECK(observer_ != nullptr);
149 observer_->OnTargetTransferRate(msg);
150 });
151 } else {
152 rtc::CritScope cs(&observer_crit_);
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200153 // We won't register as observer until we have an observers.
Sebastian Janssone6256052018-05-04 14:08:15 +0200154 RTC_DCHECK(observer_ != nullptr);
155 observer_->OnTargetTransferRate(msg);
156 }
157}
158
159rtc::TaskQueue* RtpTransportControllerSend::GetWorkerQueue() {
160 return &task_queue_;
Sebastian Jansson19704ec2018-03-12 15:59:12 +0100161}
162
nisse76e62b02017-05-31 02:24:52 -0700163PacketRouter* RtpTransportControllerSend::packet_router() {
164 return &packet_router_;
165}
166
nisse76e62b02017-05-31 02:24:52 -0700167TransportFeedbackObserver*
168RtpTransportControllerSend::transport_feedback_observer() {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100169 return send_side_cc_.get();
nisse76e62b02017-05-31 02:24:52 -0700170}
171
172RtpPacketSender* RtpTransportControllerSend::packet_sender() {
Stefan Holmer5c8942a2017-08-22 16:16:44 +0200173 return &pacer_;
nisse76e62b02017-05-31 02:24:52 -0700174}
175
sprangdb2a9fc2017-08-09 06:42:32 -0700176const RtpKeepAliveConfig& RtpTransportControllerSend::keepalive_config() const {
177 return keepalive_;
178}
179
Stefan Holmer5c8942a2017-08-22 16:16:44 +0200180void RtpTransportControllerSend::SetAllocatedSendBitrateLimits(
181 int min_send_bitrate_bps,
philipel832b1c82018-02-28 17:04:18 +0100182 int max_padding_bitrate_bps,
philipeldb4fa4b2018-03-06 18:29:22 +0100183 int max_total_bitrate_bps) {
Sebastian Jansson68ee4652018-03-13 11:40:34 +0100184 send_side_cc_->SetAllocatedSendBitrateLimits(
185 min_send_bitrate_bps, max_padding_bitrate_bps, max_total_bitrate_bps);
Stefan Holmer5c8942a2017-08-22 16:16:44 +0200186}
187
sprangdb2a9fc2017-08-09 06:42:32 -0700188void RtpTransportControllerSend::SetKeepAliveConfig(
189 const RtpKeepAliveConfig& config) {
190 keepalive_ = config;
191}
Sebastian Jansson4c1ffb82018-02-15 16:51:58 +0100192void RtpTransportControllerSend::SetPacingFactor(float pacing_factor) {
Sebastian Jansson68ee4652018-03-13 11:40:34 +0100193 send_side_cc_->SetPacingFactor(pacing_factor);
Sebastian Jansson4c1ffb82018-02-15 16:51:58 +0100194}
195void RtpTransportControllerSend::SetQueueTimeLimit(int limit_ms) {
196 pacer_.SetQueueTimeLimit(limit_ms);
197}
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100198CallStatsObserver* RtpTransportControllerSend::GetCallStatsObserver() {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100199 return send_side_cc_.get();
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100200}
201void RtpTransportControllerSend::RegisterPacketFeedbackObserver(
202 PacketFeedbackObserver* observer) {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100203 send_side_cc_->RegisterPacketFeedbackObserver(observer);
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100204}
205void RtpTransportControllerSend::DeRegisterPacketFeedbackObserver(
206 PacketFeedbackObserver* observer) {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100207 send_side_cc_->DeRegisterPacketFeedbackObserver(observer);
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100208}
Sebastian Jansson19704ec2018-03-12 15:59:12 +0100209
210void RtpTransportControllerSend::RegisterTargetTransferRateObserver(
211 TargetTransferRateObserver* observer) {
212 {
213 rtc::CritScope cs(&observer_crit_);
214 RTC_DCHECK(observer_ == nullptr);
215 observer_ = observer;
216 }
217 send_side_cc_->RegisterNetworkObserver(this);
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100218}
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100219void RtpTransportControllerSend::OnNetworkRouteChanged(
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100220 const std::string& transport_name,
221 const rtc::NetworkRoute& network_route) {
Sebastian Jansson91bb6672018-02-21 13:02:51 +0100222 // Check if the network route is connected.
223 if (!network_route.connected) {
224 RTC_LOG(LS_INFO) << "Transport " << transport_name << " is disconnected";
225 // TODO(honghaiz): Perhaps handle this in SignalChannelNetworkState and
226 // consider merging these two methods.
227 return;
228 }
229
230 // Check whether the network route has changed on each transport.
231 auto result =
232 network_routes_.insert(std::make_pair(transport_name, network_route));
233 auto kv = result.first;
234 bool inserted = result.second;
235 if (inserted) {
236 // No need to reset BWE if this is the first time the network connects.
237 return;
238 }
239 if (kv->second != network_route) {
240 kv->second = network_route;
241 BitrateConstraints bitrate_config = bitrate_configurator_.GetConfig();
242 RTC_LOG(LS_INFO) << "Network route changed on transport " << transport_name
243 << ": new local network id "
244 << network_route.local_network_id
245 << " new remote network id "
246 << network_route.remote_network_id
247 << " Reset bitrates to min: "
248 << bitrate_config.min_bitrate_bps
249 << " bps, start: " << bitrate_config.start_bitrate_bps
250 << " bps, max: " << bitrate_config.max_bitrate_bps
251 << " bps.";
252 RTC_DCHECK_GT(bitrate_config.start_bitrate_bps, 0);
Sebastian Jansson10211e92018-02-28 16:48:26 +0100253 send_side_cc_->OnNetworkRouteChanged(
Sebastian Jansson91bb6672018-02-21 13:02:51 +0100254 network_route, bitrate_config.start_bitrate_bps,
255 bitrate_config.min_bitrate_bps, bitrate_config.max_bitrate_bps);
256 }
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100257}
258void RtpTransportControllerSend::OnNetworkAvailability(bool network_available) {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100259 send_side_cc_->SignalNetworkState(network_available ? kNetworkUp
260 : kNetworkDown);
Stefan Holmerdbdb3a02018-07-17 16:03:46 +0200261 for (auto& rtp_sender : video_rtp_senders_) {
262 rtp_sender->OnNetworkAvailability(network_available);
263 }
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100264}
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100265RtcpBandwidthObserver* RtpTransportControllerSend::GetBandwidthObserver() {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100266 return send_side_cc_->GetBandwidthObserver();
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100267}
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100268int64_t RtpTransportControllerSend::GetPacerQueuingDelayMs() const {
Sebastian Janssona06e9192018-03-07 18:49:55 +0100269 return pacer_.QueueInMs();
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100270}
271int64_t RtpTransportControllerSend::GetFirstPacketTimeMs() const {
Sebastian Janssona06e9192018-03-07 18:49:55 +0100272 return pacer_.FirstSentPacketTimeMs();
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100273}
Sebastian Jansson12130bb2018-03-21 12:48:43 +0100274void RtpTransportControllerSend::SetPerPacketFeedbackAvailable(bool available) {
275 send_side_cc_->SetPerPacketFeedbackAvailable(available);
276}
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100277void RtpTransportControllerSend::EnablePeriodicAlrProbing(bool enable) {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100278 send_side_cc_->EnablePeriodicAlrProbing(enable);
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100279}
280void RtpTransportControllerSend::OnSentPacket(
281 const rtc::SentPacket& sent_packet) {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100282 send_side_cc_->OnSentPacket(sent_packet);
Sebastian Janssone4be6da2018-02-15 16:51:41 +0100283}
sprangdb2a9fc2017-08-09 06:42:32 -0700284
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100285void RtpTransportControllerSend::SetSdpBitrateParameters(
286 const BitrateConstraints& constraints) {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200287 absl::optional<BitrateConstraints> updated =
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100288 bitrate_configurator_.UpdateWithSdpParameters(constraints);
289 if (updated.has_value()) {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100290 send_side_cc_->SetBweBitrates(updated->min_bitrate_bps,
291 updated->start_bitrate_bps,
292 updated->max_bitrate_bps);
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100293 } else {
294 RTC_LOG(LS_VERBOSE)
Sebastian Jansson8f83b422018-02-21 13:07:13 +0100295 << "WebRTC.RtpTransportControllerSend.SetSdpBitrateParameters: "
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100296 << "nothing to update";
297 }
298}
299
300void RtpTransportControllerSend::SetClientBitratePreferences(
Niels Möller0c4f7be2018-05-07 14:01:37 +0200301 const BitrateSettings& preferences) {
Danil Chapovalovb9b146c2018-06-15 12:28:07 +0200302 absl::optional<BitrateConstraints> updated =
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100303 bitrate_configurator_.UpdateWithClientPreferences(preferences);
304 if (updated.has_value()) {
Sebastian Jansson10211e92018-02-28 16:48:26 +0100305 send_side_cc_->SetBweBitrates(updated->min_bitrate_bps,
306 updated->start_bitrate_bps,
307 updated->max_bitrate_bps);
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100308 } else {
309 RTC_LOG(LS_VERBOSE)
Sebastian Jansson8f83b422018-02-21 13:07:13 +0100310 << "WebRTC.RtpTransportControllerSend.SetClientBitratePreferences: "
Sebastian Jansson97f61ea2018-02-21 13:01:55 +0100311 << "nothing to update";
312 }
313}
Alex Narestbcf91802018-06-25 16:08:36 +0200314
315void RtpTransportControllerSend::SetAllocatedBitrateWithoutFeedback(
316 uint32_t bitrate_bps) {
Sebastian Jansson35fa2802018-10-01 09:16:12 +0200317 // Audio transport feedback will not be reported in this mode, instead update
318 // acknowledged bitrate estimator with the bitrate allocated for audio.
319 if (field_trial::IsEnabled("WebRTC-Audio-ABWENoTWCC")) {
320 // TODO(srte): Make sure it's safe to always report this and remove the
321 // field trial check.
322 send_side_cc_->SetAllocatedBitrateWithoutFeedback(bitrate_bps);
323 }
Alex Narestbcf91802018-06-25 16:08:36 +0200324}
Stefan Holmer64be7fa2018-10-04 15:21:55 +0200325
326void RtpTransportControllerSend::OnTransportOverheadChanged(
327 size_t transport_overhead_bytes_per_packet) {
328 if (transport_overhead_bytes_per_packet >= kMaxOverheadBytes) {
329 RTC_LOG(LS_ERROR) << "Transport overhead exceeds " << kMaxOverheadBytes;
330 return;
331 }
332
333 // TODO(holmer): Call AudioRtpSenders when they have been moved to
334 // RtpTransportControllerSend.
335 for (auto& rtp_video_sender : video_rtp_senders_) {
336 rtp_video_sender->OnTransportOverheadChanged(
337 transport_overhead_bytes_per_packet);
338 }
339}
nissecae45d02017-04-24 05:53:20 -0700340} // namespace webrtc