OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
68 } // namespace | 68 } // namespace |
69 | 69 |
70 | 70 |
71 const int SendStatisticsProxy::kStatsTimeoutMs = 5000; | 71 const int SendStatisticsProxy::kStatsTimeoutMs = 5000; |
72 | 72 |
73 SendStatisticsProxy::SendStatisticsProxy( | 73 SendStatisticsProxy::SendStatisticsProxy( |
74 Clock* clock, | 74 Clock* clock, |
75 const VideoSendStream::Config& config, | 75 const VideoSendStream::Config& config, |
76 VideoEncoderConfig::ContentType content_type) | 76 VideoEncoderConfig::ContentType content_type) |
77 : clock_(clock), | 77 : clock_(clock), |
78 config_(config), | 78 rtp_config_(config.rtp), |
79 content_type_(content_type), | 79 content_type_(content_type), |
80 last_sent_frame_timestamp_(0), | 80 last_sent_frame_timestamp_(0), |
81 encode_time_(kEncodeTimeWeigthFactor), | 81 encode_time_(kEncodeTimeWeigthFactor), |
82 uma_container_( | 82 uma_container_( |
83 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) { | 83 new UmaSamplesContainer(GetUmaPrefix(content_type_), stats_, clock)) { |
84 UpdateCodecTypeHistogram(config_.encoder_settings.payload_name); | 84 UpdateCodecTypeHistogram(config.encoder_settings.payload_name); |
85 } | 85 } |
86 | 86 |
87 SendStatisticsProxy::~SendStatisticsProxy() { | 87 SendStatisticsProxy::~SendStatisticsProxy() { |
88 rtc::CritScope lock(&crit_); | 88 rtc::CritScope lock(&crit_); |
89 uma_container_->UpdateHistograms(config_, stats_); | 89 uma_container_->UpdateHistograms(rtp_config_, stats_); |
90 } | 90 } |
91 | 91 |
92 SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( | 92 SendStatisticsProxy::UmaSamplesContainer::UmaSamplesContainer( |
93 const char* prefix, | 93 const char* prefix, |
94 const VideoSendStream::Stats& stats, | 94 const VideoSendStream::Stats& stats, |
95 Clock* const clock) | 95 Clock* const clock) |
96 : uma_prefix_(prefix), | 96 : uma_prefix_(prefix), |
97 clock_(clock), | 97 clock_(clock), |
98 max_sent_width_per_timestamp_(0), | 98 max_sent_width_per_timestamp_(0), |
99 max_sent_height_per_timestamp_(0), | 99 max_sent_height_per_timestamp_(0), |
100 input_frame_rate_tracker_(100, 10u), | 100 input_frame_rate_tracker_(100, 10u), |
101 sent_frame_rate_tracker_(100, 10u), | 101 sent_frame_rate_tracker_(100, 10u), |
102 first_rtcp_stats_time_ms_(-1), | 102 first_rtcp_stats_time_ms_(-1), |
103 first_rtp_stats_time_ms_(-1), | 103 first_rtp_stats_time_ms_(-1), |
104 start_stats_(stats) {} | 104 start_stats_(stats) {} |
105 | 105 |
106 SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {} | 106 SendStatisticsProxy::UmaSamplesContainer::~UmaSamplesContainer() {} |
107 | 107 |
108 void AccumulateRtpStats(const VideoSendStream::Stats& stats, | 108 void AccumulateRtpStats(const VideoSendStream::Stats& stats, |
109 const VideoSendStream::Config& config, | 109 const VideoSendStream::Config::Rtp& rtp_config, |
stefan-webrtc
2016/07/08 15:56:41
Should this be changed to "const std::vector<uint3
perkj_webrtc
2016/07/11 11:41:07
Done.
| |
110 StreamDataCounters* total_rtp_stats, | 110 StreamDataCounters* total_rtp_stats, |
111 StreamDataCounters* rtx_stats) { | 111 StreamDataCounters* rtx_stats) { |
112 const std::vector<uint32_t>& rtx_ssrcs = rtp_config.rtx.ssrcs; | |
112 for (auto it : stats.substreams) { | 113 for (auto it : stats.substreams) { |
113 const std::vector<uint32_t> rtx_ssrcs = config.rtp.rtx.ssrcs; | |
114 if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) != | 114 if (std::find(rtx_ssrcs.begin(), rtx_ssrcs.end(), it.first) != |
115 rtx_ssrcs.end()) { | 115 rtx_ssrcs.end()) { |
116 rtx_stats->Add(it.second.rtp_stats); | 116 rtx_stats->Add(it.second.rtp_stats); |
117 } else { | 117 } else { |
118 total_rtp_stats->Add(it.second.rtp_stats); | 118 total_rtp_stats->Add(it.second.rtp_stats); |
119 } | 119 } |
120 } | 120 } |
121 } | 121 } |
122 | 122 |
123 void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( | 123 void SendStatisticsProxy::UmaSamplesContainer::UpdateHistograms( |
124 const VideoSendStream::Config& config, | 124 const VideoSendStream::Config::Rtp& rtp_config, |
125 const VideoSendStream::Stats& current_stats) { | 125 const VideoSendStream::Stats& current_stats) { |
126 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix); | 126 RTC_DCHECK(uma_prefix_ == kRealtimePrefix || uma_prefix_ == kScreenPrefix); |
127 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0; | 127 const int kIndex = uma_prefix_ == kScreenPrefix ? 1 : 0; |
128 const int kMinRequiredSamples = 200; | 128 const int kMinRequiredSamples = 200; |
129 int in_width = input_width_counter_.Avg(kMinRequiredSamples); | 129 int in_width = input_width_counter_.Avg(kMinRequiredSamples); |
130 int in_height = input_height_counter_.Avg(kMinRequiredSamples); | 130 int in_height = input_height_counter_.Avg(kMinRequiredSamples); |
131 int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate()); | 131 int in_fps = round(input_frame_rate_tracker_.ComputeTotalRate()); |
132 if (in_width != -1) { | 132 if (in_width != -1) { |
133 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 133 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
134 kIndex, uma_prefix_ + "InputWidthInPixels", in_width); | 134 kIndex, uma_prefix_ + "InputWidthInPixels", in_width); |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
248 } | 248 } |
249 | 249 |
250 // The RTCP packet type counters, delivered via the | 250 // The RTCP packet type counters, delivered via the |
251 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire | 251 // RtcpPacketTypeCounterObserver interface, are aggregates over the entire |
252 // life of the send stream and are not reset when switching content type. | 252 // life of the send stream and are not reset when switching content type. |
253 // For the purpose of these statistics though, we want new counts when | 253 // For the purpose of these statistics though, we want new counts when |
254 // switching since we switch histogram name. On every reset of the | 254 // switching since we switch histogram name. On every reset of the |
255 // UmaSamplesContainer, we save the initial state of the counters, so that | 255 // UmaSamplesContainer, we save the initial state of the counters, so that |
256 // we can calculate the delta here and aggregate over all ssrcs. | 256 // we can calculate the delta here and aggregate over all ssrcs. |
257 RtcpPacketTypeCounter counters; | 257 RtcpPacketTypeCounter counters; |
258 for (uint32_t ssrc : config.rtp.ssrcs) { | 258 for (uint32_t ssrc : rtp_config.ssrcs) { |
259 auto kv = current_stats.substreams.find(ssrc); | 259 auto kv = current_stats.substreams.find(ssrc); |
260 if (kv == current_stats.substreams.end()) | 260 if (kv == current_stats.substreams.end()) |
261 continue; | 261 continue; |
262 | 262 |
263 RtcpPacketTypeCounter stream_counters = | 263 RtcpPacketTypeCounter stream_counters = |
264 kv->second.rtcp_packet_type_counts; | 264 kv->second.rtcp_packet_type_counts; |
265 kv = start_stats_.substreams.find(ssrc); | 265 kv = start_stats_.substreams.find(ssrc); |
266 if (kv != start_stats_.substreams.end()) | 266 if (kv != start_stats_.substreams.end()) |
267 stream_counters.Subtract(kv->second.rtcp_packet_type_counts); | 267 stream_counters.Subtract(kv->second.rtcp_packet_type_counts); |
268 | 268 |
(...skipping 15 matching lines...) Expand all Loading... | |
284 } | 284 } |
285 } | 285 } |
286 } | 286 } |
287 | 287 |
288 if (first_rtp_stats_time_ms_ != -1) { | 288 if (first_rtp_stats_time_ms_ != -1) { |
289 int64_t elapsed_sec = | 289 int64_t elapsed_sec = |
290 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000; | 290 (clock_->TimeInMilliseconds() - first_rtp_stats_time_ms_) / 1000; |
291 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { | 291 if (elapsed_sec >= metrics::kMinRunTimeInSeconds) { |
292 StreamDataCounters rtp; | 292 StreamDataCounters rtp; |
293 StreamDataCounters rtx; | 293 StreamDataCounters rtx; |
294 AccumulateRtpStats(current_stats, config, &rtp, &rtx); | 294 AccumulateRtpStats(current_stats, rtp_config, &rtp, &rtx); |
295 StreamDataCounters start_rtp; | 295 StreamDataCounters start_rtp; |
296 StreamDataCounters start_rtx; | 296 StreamDataCounters start_rtx; |
297 AccumulateRtpStats(start_stats_, config, &start_rtp, &start_rtx); | 297 AccumulateRtpStats(start_stats_, rtp_config, &start_rtp, &start_rtx); |
298 rtp.Subtract(start_rtp); | 298 rtp.Subtract(start_rtp); |
299 rtx.Subtract(start_rtx); | 299 rtx.Subtract(start_rtx); |
300 StreamDataCounters rtp_rtx = rtp; | 300 StreamDataCounters rtp_rtx = rtp; |
301 rtp_rtx.Add(rtx); | 301 rtp_rtx.Add(rtx); |
302 | 302 |
303 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 303 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
304 kIndex, uma_prefix_ + "BitrateSentInKbps", | 304 kIndex, uma_prefix_ + "BitrateSentInKbps", |
305 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / | 305 static_cast<int>(rtp_rtx.transmitted.TotalBytes() * 8 / elapsed_sec / |
306 1000)); | 306 1000)); |
307 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 307 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
308 kIndex, uma_prefix_ + "MediaBitrateSentInKbps", | 308 kIndex, uma_prefix_ + "MediaBitrateSentInKbps", |
309 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000)); | 309 static_cast<int>(rtp.MediaPayloadBytes() * 8 / elapsed_sec / 1000)); |
310 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 310 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
311 kIndex, uma_prefix_ + "PaddingBitrateSentInKbps", | 311 kIndex, uma_prefix_ + "PaddingBitrateSentInKbps", |
312 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / | 312 static_cast<int>(rtp_rtx.transmitted.padding_bytes * 8 / elapsed_sec / |
313 1000)); | 313 1000)); |
314 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 314 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
315 kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps", | 315 kIndex, uma_prefix_ + "RetransmittedBitrateSentInKbps", |
316 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / | 316 static_cast<int>(rtp_rtx.retransmitted.TotalBytes() * 8 / |
317 elapsed_sec / 1000)); | 317 elapsed_sec / 1000)); |
318 if (!config.rtp.rtx.ssrcs.empty()) { | 318 if (!rtp_config.rtx.ssrcs.empty()) { |
319 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 319 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
320 kIndex, uma_prefix_ + "RtxBitrateSentInKbps", | 320 kIndex, uma_prefix_ + "RtxBitrateSentInKbps", |
321 static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec / | 321 static_cast<int>(rtx.transmitted.TotalBytes() * 8 / elapsed_sec / |
322 1000)); | 322 1000)); |
323 } | 323 } |
324 if (config.rtp.fec.red_payload_type != -1) { | 324 if (rtp_config.fec.red_payload_type != -1) { |
325 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( | 325 RTC_LOGGED_HISTOGRAMS_COUNTS_10000( |
326 kIndex, uma_prefix_ + "FecBitrateSentInKbps", | 326 kIndex, uma_prefix_ + "FecBitrateSentInKbps", |
327 static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / | 327 static_cast<int>(rtp_rtx.fec.TotalBytes() * 8 / elapsed_sec / |
328 1000)); | 328 1000)); |
329 } | 329 } |
330 } | 330 } |
331 } | 331 } |
332 } | 332 } |
333 | 333 |
334 void SendStatisticsProxy::SetContentType( | 334 void SendStatisticsProxy::SetContentType( |
335 VideoEncoderConfig::ContentType content_type) { | 335 VideoEncoderConfig::ContentType content_type) { |
336 rtc::CritScope lock(&crit_); | 336 rtc::CritScope lock(&crit_); |
337 if (content_type_ != content_type) { | 337 if (content_type_ != content_type) { |
338 uma_container_->UpdateHistograms(config_, stats_); | 338 uma_container_->UpdateHistograms(rtp_config_, stats_); |
339 uma_container_.reset( | 339 uma_container_.reset( |
340 new UmaSamplesContainer(GetUmaPrefix(content_type), stats_, clock_)); | 340 new UmaSamplesContainer(GetUmaPrefix(content_type), stats_, clock_)); |
341 content_type_ = content_type; | 341 content_type_ = content_type; |
342 } | 342 } |
343 } | 343 } |
344 | 344 |
345 void SendStatisticsProxy::OnEncoderStatsUpdate( | 345 void SendStatisticsProxy::OnEncoderStatsUpdate( |
346 uint32_t framerate, | 346 uint32_t framerate, |
347 uint32_t bitrate, | 347 uint32_t bitrate, |
348 const std::string& encoder_name) { | 348 const std::string& encoder_name) { |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
388 } | 388 } |
389 } | 389 } |
390 | 390 |
391 VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry( | 391 VideoSendStream::StreamStats* SendStatisticsProxy::GetStatsEntry( |
392 uint32_t ssrc) { | 392 uint32_t ssrc) { |
393 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it = | 393 std::map<uint32_t, VideoSendStream::StreamStats>::iterator it = |
394 stats_.substreams.find(ssrc); | 394 stats_.substreams.find(ssrc); |
395 if (it != stats_.substreams.end()) | 395 if (it != stats_.substreams.end()) |
396 return &it->second; | 396 return &it->second; |
397 | 397 |
398 if (std::find(config_.rtp.ssrcs.begin(), config_.rtp.ssrcs.end(), ssrc) == | 398 if (std::find(rtp_config_.ssrcs.begin(), rtp_config_.ssrcs.end(), ssrc) == |
399 config_.rtp.ssrcs.end() && | 399 rtp_config_.ssrcs.end() && |
400 std::find(config_.rtp.rtx.ssrcs.begin(), | 400 std::find(rtp_config_.rtx.ssrcs.begin(), rtp_config_.rtx.ssrcs.end(), |
401 config_.rtp.rtx.ssrcs.end(), | 401 ssrc) == rtp_config_.rtx.ssrcs.end()) { |
402 ssrc) == config_.rtp.rtx.ssrcs.end()) { | |
403 return nullptr; | 402 return nullptr; |
404 } | 403 } |
405 | 404 |
406 return &stats_.substreams[ssrc]; // Insert new entry and return ptr. | 405 return &stats_.substreams[ssrc]; // Insert new entry and return ptr. |
407 } | 406 } |
408 | 407 |
409 void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) { | 408 void SendStatisticsProxy::OnInactiveSsrc(uint32_t ssrc) { |
410 rtc::CritScope lock(&crit_); | 409 rtc::CritScope lock(&crit_); |
411 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc); | 410 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc); |
412 if (!stats) | 411 if (!stats) |
(...skipping 16 matching lines...) Expand all Loading... | |
429 size_t simulcast_idx = 0; | 428 size_t simulcast_idx = 0; |
430 | 429 |
431 if (codec_info) { | 430 if (codec_info) { |
432 if (codec_info->codecType == kVideoCodecVP8) { | 431 if (codec_info->codecType == kVideoCodecVP8) { |
433 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx; | 432 simulcast_idx = codec_info->codecSpecific.VP8.simulcastIdx; |
434 } else if (codec_info->codecType == kVideoCodecGeneric) { | 433 } else if (codec_info->codecType == kVideoCodecGeneric) { |
435 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx; | 434 simulcast_idx = codec_info->codecSpecific.generic.simulcast_idx; |
436 } | 435 } |
437 } | 436 } |
438 | 437 |
439 if (simulcast_idx >= config_.rtp.ssrcs.size()) { | 438 if (simulcast_idx >= rtp_config_.ssrcs.size()) { |
440 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx | 439 LOG(LS_ERROR) << "Encoded image outside simulcast range (" << simulcast_idx |
441 << " >= " << config_.rtp.ssrcs.size() << ")."; | 440 << " >= " << rtp_config_.ssrcs.size() << ")."; |
442 return; | 441 return; |
443 } | 442 } |
444 uint32_t ssrc = config_.rtp.ssrcs[simulcast_idx]; | 443 uint32_t ssrc = rtp_config_.ssrcs[simulcast_idx]; |
445 | 444 |
446 rtc::CritScope lock(&crit_); | 445 rtc::CritScope lock(&crit_); |
447 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc); | 446 VideoSendStream::StreamStats* stats = GetStatsEntry(ssrc); |
448 if (!stats) | 447 if (!stats) |
449 return; | 448 return; |
450 | 449 |
451 stats->width = encoded_image._encodedWidth; | 450 stats->width = encoded_image._encodedWidth; |
452 stats->height = encoded_image._encodedHeight; | 451 stats->height = encoded_image._encodedHeight; |
453 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds(); | 452 update_times_[ssrc].resolution_update_ms = clock_->TimeInMilliseconds(); |
454 | 453 |
(...skipping 17 matching lines...) Expand all Loading... | |
472 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0; | 471 bool bw_limited = encoded_image.adapt_reason_.bw_resolutions_disabled > 0; |
473 uma_container_->bw_limited_frame_counter_.Add(bw_limited); | 472 uma_container_->bw_limited_frame_counter_.Add(bw_limited); |
474 if (bw_limited) { | 473 if (bw_limited) { |
475 uma_container_->bw_resolutions_disabled_counter_.Add( | 474 uma_container_->bw_resolutions_disabled_counter_.Add( |
476 encoded_image.adapt_reason_.bw_resolutions_disabled); | 475 encoded_image.adapt_reason_.bw_resolutions_disabled); |
477 } | 476 } |
478 } | 477 } |
479 | 478 |
480 if (encoded_image.qp_ != -1 && codec_info) { | 479 if (encoded_image.qp_ != -1 && codec_info) { |
481 if (codec_info->codecType == kVideoCodecVP8) { | 480 if (codec_info->codecType == kVideoCodecVP8) { |
482 int spatial_idx = (config_.rtp.ssrcs.size() == 1) | 481 int spatial_idx = (rtp_config_.ssrcs.size() == 1) |
483 ? -1 | 482 ? -1 |
484 : static_cast<int>(simulcast_idx); | 483 : static_cast<int>(simulcast_idx); |
485 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_); | 484 uma_container_->qp_counters_[spatial_idx].vp8.Add(encoded_image.qp_); |
486 } else if (codec_info->codecType == kVideoCodecVP9) { | 485 } else if (codec_info->codecType == kVideoCodecVP9) { |
487 int spatial_idx = (codec_info->codecSpecific.VP9.num_spatial_layers == 1) | 486 int spatial_idx = (codec_info->codecSpecific.VP9.num_spatial_layers == 1) |
488 ? -1 | 487 ? -1 |
489 : codec_info->codecSpecific.VP9.spatial_idx; | 488 : codec_info->codecSpecific.VP9.spatial_idx; |
490 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_); | 489 uma_container_->qp_counters_[spatial_idx].vp9.Add(encoded_image.qp_); |
491 } | 490 } |
492 } | 491 } |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
627 return Fraction(min_required_samples, 1000.0f); | 626 return Fraction(min_required_samples, 1000.0f); |
628 } | 627 } |
629 | 628 |
630 int SendStatisticsProxy::BoolSampleCounter::Fraction( | 629 int SendStatisticsProxy::BoolSampleCounter::Fraction( |
631 int min_required_samples, float multiplier) const { | 630 int min_required_samples, float multiplier) const { |
632 if (num_samples < min_required_samples || num_samples == 0) | 631 if (num_samples < min_required_samples || num_samples == 0) |
633 return -1; | 632 return -1; |
634 return static_cast<int>((sum * multiplier / num_samples) + 0.5f); | 633 return static_cast<int>((sum * multiplier / num_samples) + 0.5f); |
635 } | 634 } |
636 } // namespace webrtc | 635 } // namespace webrtc |
OLD | NEW |