2013-07-10 00:45:36 +00:00
|
|
|
/*
|
2016-02-10 07:54:43 -08:00
|
|
|
* Copyright 2012 The WebRTC project authors. All Rights Reserved.
|
2013-07-10 00:45:36 +00:00
|
|
|
*
|
2016-02-10 07:54:43 -08:00
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
2013-07-10 00:45:36 +00:00
|
|
|
*/
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "pc/statscollector.h"
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2016-04-26 03:13:22 -07:00
|
|
|
#include <memory>
|
2018-02-06 10:34:40 -08:00
|
|
|
#include <set>
|
2013-07-10 00:45:36 +00:00
|
|
|
#include <utility>
|
|
|
|
|
#include <vector>
|
|
|
|
|
|
2017-09-15 06:47:31 +02:00
|
|
|
#include "pc/channel.h"
|
|
|
|
|
#include "pc/peerconnection.h"
|
|
|
|
|
#include "rtc_base/checks.h"
|
2018-07-23 17:38:12 +02:00
|
|
|
#include "rtc_base/third_party/base64/base64.h"
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
|
|
|
|
namespace {
|
|
|
|
|
|
2014-12-16 23:01:31 +00:00
|
|
|
// The following is the enum RTCStatsIceCandidateType from
|
|
|
|
|
// http://w3c.github.io/webrtc-stats/#rtcstatsicecandidatetype-enum such that
|
|
|
|
|
// our stats report for ice candidate type could conform to that.
|
|
|
|
|
const char STATSREPORT_LOCAL_PORT_TYPE[] = "host";
|
|
|
|
|
const char STATSREPORT_STUN_PORT_TYPE[] = "serverreflexive";
|
|
|
|
|
const char STATSREPORT_PRFLX_PORT_TYPE[] = "peerreflexive";
|
|
|
|
|
const char STATSREPORT_RELAY_PORT_TYPE[] = "relayed";
|
|
|
|
|
|
|
|
|
|
// Strings used by the stats collector to report adapter types. This fits the
|
|
|
|
|
// general stype of http://w3c.github.io/webrtc-stats than what
|
|
|
|
|
// AdapterTypeToString does.
|
|
|
|
|
const char* STATSREPORT_ADAPTER_TYPE_ETHERNET = "lan";
|
|
|
|
|
const char* STATSREPORT_ADAPTER_TYPE_WIFI = "wlan";
|
|
|
|
|
const char* STATSREPORT_ADAPTER_TYPE_WWAN = "wwan";
|
|
|
|
|
const char* STATSREPORT_ADAPTER_TYPE_VPN = "vpn";
|
Makes libjingle_peerconnection_android_unittest run on networkless devices.
PeerConnectionTest.java currently works, but only on a device with
network interfaces up. This is not a problem for desktop, but it is a
problem when running on Android devices since the devices in the lab
generally don't have network (due to the chaotic radio environment in
the device labs, devices are simply kept in flight mode).
The test does work if one modifies this line in the file
webrtc/base/network.cc:
bool ignored = ((cursor->ifa_flags & IFF_LOOPBACK) ||
IsIgnoredNetwork(*network));
If we remove the IFF_LOOPBACK clause, the test starts working on
an Android device in flight mode. This is nice - we're running the
call and packets interact with the OS network stack, which is good
for this end-to-end test. We can't just remove the clause though since
having loopback is undesirable for everyone except the test (right)?
so we need to make this behavior configurable.
This CL takes a stab at a complete solution where we pass a boolean
all the way through the Java PeerConnectionFactory down to the
BasicNetworkManager. This comes as a heavy price in interface
changes though. It's pretty out of proportion, but fundamentally we
need some way of telling the network manager that it is on Android
and in test mode. Passing the boolean all the way through is one way.
Another way might be to put the loopback filter behind an ifdef and
link a custom libjingle_peerconnection.so with the test. That is hacky
but doesn't pollute the interfaces. Not sure how to solve that in GYP
but it could mean some duplication between the production and
test .so files.
It would have been perfect to use flags here, but then we need to
hook up gflags parsing to some main() somewhere to make sure the
flag gets parsed, and make sure to pass that flag in our tests.
I'm not sure how that can be done.
Making the loopback filtering conditional is exactly how we solved the
equivalent problem in content_browsertests in Chrome, and it worked
great.
That's all I could think of.
BUG=4181
R=perkj@webrtc.org, pthatcher@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/36769004
Cr-Commit-Position: refs/heads/master@{#8344}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8344 4adac7df-926f-26a2-2b94-8c16560cd09d
2015-02-12 09:23:59 +00:00
|
|
|
const char* STATSREPORT_ADAPTER_TYPE_LOOPBACK = "loopback";
|
2018-07-26 10:44:02 -07:00
|
|
|
const char* STATSREPORT_ADAPTER_TYPE_WILDCARD = "wildcard";
|
2014-12-16 23:01:31 +00:00
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
template <typename ValueType>
|
|
|
|
|
struct TypeForAdd {
|
2015-03-04 15:25:19 +00:00
|
|
|
const StatsReport::StatsValueName name;
|
2015-03-12 16:35:55 +00:00
|
|
|
const ValueType& value;
|
2015-03-04 15:25:19 +00:00
|
|
|
};
|
|
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
typedef TypeForAdd<bool> BoolForAdd;
|
|
|
|
|
typedef TypeForAdd<float> FloatForAdd;
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
typedef TypeForAdd<int64_t> Int64ForAdd;
|
2015-03-12 16:35:55 +00:00
|
|
|
typedef TypeForAdd<int> IntForAdd;
|
2014-07-15 19:22:37 +00:00
|
|
|
|
2015-06-22 15:06:43 -07:00
|
|
|
StatsReport* AddTrackReport(StatsCollection* reports,
|
|
|
|
|
const std::string& track_id) {
|
2014-07-09 07:38:38 +00:00
|
|
|
// Adds an empty track report.
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport::Id id(
|
2015-01-21 11:36:18 +00:00
|
|
|
StatsReport::NewTypedId(StatsReport::kStatsReportTypeTrack, track_id));
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport* report = reports->ReplaceOrAddNew(id);
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddString(StatsReport::kStatsValueNameTrackId, track_id);
|
2015-06-22 15:06:43 -07:00
|
|
|
return report;
|
2014-07-09 07:38:38 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-04 15:26:13 +01:00
|
|
|
template <class Track>
|
|
|
|
|
void CreateTrackReport(const Track* track,
|
|
|
|
|
StatsCollection* reports,
|
|
|
|
|
TrackIdMap* track_ids) {
|
|
|
|
|
const std::string& track_id = track->id();
|
|
|
|
|
StatsReport* report = AddTrackReport(reports, track_id);
|
|
|
|
|
RTC_DCHECK(report != nullptr);
|
|
|
|
|
(*track_ids)[track_id] = report;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
template <class TrackVector>
|
2017-10-30 09:57:42 -07:00
|
|
|
void CreateTrackReports(const TrackVector& tracks,
|
|
|
|
|
StatsCollection* reports,
|
|
|
|
|
TrackIdMap* track_ids) {
|
2015-06-22 15:06:43 -07:00
|
|
|
for (const auto& track : tracks) {
|
2018-01-04 15:26:13 +01:00
|
|
|
CreateTrackReport(track.get(), reports, track_ids);
|
2015-06-22 15:06:43 -07:00
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 15:25:19 +00:00
|
|
|
void ExtractCommonSendProperties(const cricket::MediaSenderInfo& info,
|
|
|
|
|
StatsReport* report) {
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameCodecName, info.codec_name);
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameBytesSent, info.bytes_sent);
|
2016-05-13 11:46:35 -07:00
|
|
|
if (info.rtt_ms >= 0) {
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameRtt, info.rtt_ms);
|
|
|
|
|
}
|
2015-03-04 15:25:19 +00:00
|
|
|
}
|
|
|
|
|
|
2015-08-28 07:35:32 -07:00
|
|
|
void ExtractCommonReceiveProperties(const cricket::MediaReceiverInfo& info,
|
|
|
|
|
StatsReport* report) {
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameCodecName, info.codec_name);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-24 17:29:59 +01:00
|
|
|
void SetAudioProcessingStats(StatsReport* report,
|
|
|
|
|
bool typing_noise_detected,
|
|
|
|
|
const AudioProcessingStats& apm_stats) {
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddBoolean(StatsReport::kStatsValueNameTypingNoiseState,
|
|
|
|
|
typing_noise_detected);
|
2017-11-24 17:29:59 +01:00
|
|
|
if (apm_stats.delay_median_ms) {
|
2017-11-20 13:07:16 +01:00
|
|
|
report->AddInt(StatsReport::kStatsValueNameEchoDelayMedian,
|
2017-11-24 17:29:59 +01:00
|
|
|
*apm_stats.delay_median_ms);
|
2017-11-20 13:07:16 +01:00
|
|
|
}
|
2017-11-24 17:29:59 +01:00
|
|
|
if (apm_stats.delay_standard_deviation_ms) {
|
2017-11-20 13:07:16 +01:00
|
|
|
report->AddInt(StatsReport::kStatsValueNameEchoDelayStdDev,
|
2017-11-24 17:29:59 +01:00
|
|
|
*apm_stats.delay_standard_deviation_ms);
|
2016-05-13 11:46:35 -07:00
|
|
|
}
|
2017-11-24 17:29:59 +01:00
|
|
|
if (apm_stats.echo_return_loss) {
|
2017-11-20 13:07:16 +01:00
|
|
|
report->AddInt(StatsReport::kStatsValueNameEchoReturnLoss,
|
2017-11-24 17:29:59 +01:00
|
|
|
*apm_stats.echo_return_loss);
|
2017-11-20 13:07:16 +01:00
|
|
|
}
|
2017-11-24 17:29:59 +01:00
|
|
|
if (apm_stats.echo_return_loss_enhancement) {
|
2017-11-20 13:07:16 +01:00
|
|
|
report->AddInt(StatsReport::kStatsValueNameEchoReturnLossEnhancement,
|
2017-11-24 17:29:59 +01:00
|
|
|
*apm_stats.echo_return_loss_enhancement);
|
2017-11-20 13:07:16 +01:00
|
|
|
}
|
2017-11-24 17:29:59 +01:00
|
|
|
if (apm_stats.residual_echo_likelihood) {
|
2016-10-21 04:10:03 -07:00
|
|
|
report->AddFloat(StatsReport::kStatsValueNameResidualEchoLikelihood,
|
2017-11-24 17:29:59 +01:00
|
|
|
static_cast<float>(*apm_stats.residual_echo_likelihood));
|
2017-01-16 23:53:59 -08:00
|
|
|
}
|
2017-11-24 17:29:59 +01:00
|
|
|
if (apm_stats.residual_echo_likelihood_recent_max) {
|
2017-01-15 08:29:46 -08:00
|
|
|
report->AddFloat(
|
|
|
|
|
StatsReport::kStatsValueNameResidualEchoLikelihoodRecentMax,
|
2017-11-24 17:29:59 +01:00
|
|
|
static_cast<float>(*apm_stats.residual_echo_likelihood_recent_max));
|
|
|
|
|
}
|
|
|
|
|
if (apm_stats.divergent_filter_fraction) {
|
|
|
|
|
report->AddFloat(StatsReport::kStatsValueNameAecDivergentFilterFraction,
|
|
|
|
|
static_cast<float>(*apm_stats.divergent_filter_fraction));
|
2016-10-21 04:10:03 -07:00
|
|
|
}
|
2015-03-04 15:25:19 +00:00
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
void ExtractStats(const cricket::VoiceReceiverInfo& info, StatsReport* report) {
|
2015-08-28 07:35:32 -07:00
|
|
|
ExtractCommonReceiveProperties(info, report);
|
2015-03-04 15:25:19 +00:00
|
|
|
const FloatForAdd floats[] = {
|
|
|
|
|
{StatsReport::kStatsValueNameExpandRate, info.expand_rate},
|
|
|
|
|
{StatsReport::kStatsValueNameSecondaryDecodedRate,
|
|
|
|
|
info.secondary_decoded_rate},
|
2017-08-28 13:51:27 +02:00
|
|
|
{StatsReport::kStatsValueNameSecondaryDiscardedRate,
|
|
|
|
|
info.secondary_discarded_rate},
|
2015-03-04 15:25:19 +00:00
|
|
|
{StatsReport::kStatsValueNameSpeechExpandRate, info.speech_expand_rate},
|
2015-06-02 09:24:52 +02:00
|
|
|
{StatsReport::kStatsValueNameAccelerateRate, info.accelerate_rate},
|
|
|
|
|
{StatsReport::kStatsValueNamePreemptiveExpandRate,
|
|
|
|
|
info.preemptive_expand_rate},
|
2017-07-14 12:17:49 -07:00
|
|
|
{StatsReport::kStatsValueNameTotalAudioEnergy, info.total_output_energy},
|
|
|
|
|
{StatsReport::kStatsValueNameTotalSamplesDuration,
|
|
|
|
|
info.total_output_duration}};
|
2015-03-04 15:25:19 +00:00
|
|
|
|
|
|
|
|
const IntForAdd ints[] = {
|
|
|
|
|
{StatsReport::kStatsValueNameCurrentDelayMs, info.delay_estimate_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameDecodingCNG, info.decoding_cng},
|
|
|
|
|
{StatsReport::kStatsValueNameDecodingCTN, info.decoding_calls_to_neteq},
|
|
|
|
|
{StatsReport::kStatsValueNameDecodingCTSG,
|
|
|
|
|
info.decoding_calls_to_silence_generator},
|
2016-09-20 01:47:12 -07:00
|
|
|
{StatsReport::kStatsValueNameDecodingMutedOutput,
|
|
|
|
|
info.decoding_muted_output},
|
2015-03-04 15:25:19 +00:00
|
|
|
{StatsReport::kStatsValueNameDecodingNormal, info.decoding_normal},
|
|
|
|
|
{StatsReport::kStatsValueNameDecodingPLC, info.decoding_plc},
|
|
|
|
|
{StatsReport::kStatsValueNameDecodingPLCCNG, info.decoding_plc_cng},
|
|
|
|
|
{StatsReport::kStatsValueNameJitterBufferMs, info.jitter_buffer_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameJitterReceived, info.jitter_ms},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsLost, info.packets_lost},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsReceived, info.packets_rcvd},
|
|
|
|
|
{StatsReport::kStatsValueNamePreferredJitterBufferMs,
|
|
|
|
|
info.jitter_buffer_preferred_ms},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const auto& f : floats)
|
|
|
|
|
report->AddFloat(f.name, f.value);
|
|
|
|
|
|
|
|
|
|
for (const auto& i : ints)
|
|
|
|
|
report->AddInt(i.name, i.value);
|
2016-05-13 11:46:35 -07:00
|
|
|
if (info.audio_level >= 0) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAudioOutputLevel,
|
|
|
|
|
info.audio_level);
|
|
|
|
|
}
|
2015-03-04 15:25:19 +00:00
|
|
|
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameBytesReceived, info.bytes_rcvd);
|
2016-05-13 11:46:35 -07:00
|
|
|
if (info.capture_start_ntp_time_ms >= 0) {
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
|
|
|
|
|
info.capture_start_ntp_time_ms);
|
|
|
|
|
}
|
2016-01-28 01:27:15 -08:00
|
|
|
report->AddString(StatsReport::kStatsValueNameMediaType, "audio");
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExtractStats(const cricket::VoiceSenderInfo& info, StatsReport* report) {
|
2015-03-04 15:25:19 +00:00
|
|
|
ExtractCommonSendProperties(info, report);
|
|
|
|
|
|
2017-11-24 17:29:59 +01:00
|
|
|
SetAudioProcessingStats(report, info.typing_noise_detected,
|
|
|
|
|
info.apm_statistics);
|
2015-03-04 15:25:19 +00:00
|
|
|
|
2017-07-14 12:17:49 -07:00
|
|
|
const FloatForAdd floats[] = {
|
|
|
|
|
{StatsReport::kStatsValueNameTotalAudioEnergy, info.total_input_energy},
|
|
|
|
|
{StatsReport::kStatsValueNameTotalSamplesDuration,
|
|
|
|
|
info.total_input_duration}};
|
|
|
|
|
|
2015-11-27 17:27:35 -08:00
|
|
|
RTC_DCHECK_GE(info.audio_level, 0);
|
2015-03-04 15:25:19 +00:00
|
|
|
const IntForAdd ints[] = {
|
2015-11-27 17:27:35 -08:00
|
|
|
{StatsReport::kStatsValueNameAudioInputLevel, info.audio_level},
|
2015-03-04 15:25:19 +00:00
|
|
|
{StatsReport::kStatsValueNameJitterReceived, info.jitter_ms},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsLost, info.packets_lost},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsSent, info.packets_sent},
|
|
|
|
|
};
|
|
|
|
|
|
2017-07-14 12:17:49 -07:00
|
|
|
for (const auto& f : floats) {
|
|
|
|
|
report->AddFloat(f.name, f.value);
|
|
|
|
|
}
|
|
|
|
|
|
2016-05-13 11:46:35 -07:00
|
|
|
for (const auto& i : ints) {
|
|
|
|
|
if (i.value >= 0) {
|
|
|
|
|
report->AddInt(i.name, i.value);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-01-28 01:27:15 -08:00
|
|
|
report->AddString(StatsReport::kStatsValueNameMediaType, "audio");
|
2017-09-08 08:13:19 -07:00
|
|
|
if (info.ana_statistics.bitrate_action_counter) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAnaBitrateActionCounter,
|
|
|
|
|
*info.ana_statistics.bitrate_action_counter);
|
|
|
|
|
}
|
|
|
|
|
if (info.ana_statistics.channel_action_counter) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAnaChannelActionCounter,
|
|
|
|
|
*info.ana_statistics.channel_action_counter);
|
|
|
|
|
}
|
|
|
|
|
if (info.ana_statistics.dtx_action_counter) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAnaDtxActionCounter,
|
|
|
|
|
*info.ana_statistics.dtx_action_counter);
|
|
|
|
|
}
|
|
|
|
|
if (info.ana_statistics.fec_action_counter) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAnaFecActionCounter,
|
|
|
|
|
*info.ana_statistics.fec_action_counter);
|
|
|
|
|
}
|
2017-09-08 13:24:21 -07:00
|
|
|
if (info.ana_statistics.frame_length_increase_counter) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAnaFrameLengthIncreaseCounter,
|
|
|
|
|
*info.ana_statistics.frame_length_increase_counter);
|
|
|
|
|
}
|
|
|
|
|
if (info.ana_statistics.frame_length_decrease_counter) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAnaFrameLengthDecreaseCounter,
|
|
|
|
|
*info.ana_statistics.frame_length_decrease_counter);
|
|
|
|
|
}
|
|
|
|
|
if (info.ana_statistics.uplink_packet_loss_fraction) {
|
|
|
|
|
report->AddFloat(StatsReport::kStatsValueNameAnaUplinkPacketLossFraction,
|
|
|
|
|
*info.ana_statistics.uplink_packet_loss_fraction);
|
2017-09-08 08:13:19 -07:00
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExtractStats(const cricket::VideoReceiverInfo& info, StatsReport* report) {
|
2015-08-28 07:35:32 -07:00
|
|
|
ExtractCommonReceiveProperties(info, report);
|
2015-12-18 16:01:11 +01:00
|
|
|
report->AddString(StatsReport::kStatsValueNameCodecImplementationName,
|
|
|
|
|
info.decoder_implementation_name);
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddInt64(StatsReport::kStatsValueNameBytesReceived, info.bytes_rcvd);
|
2016-05-13 11:46:35 -07:00
|
|
|
if (info.capture_start_ntp_time_ms >= 0) {
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameCaptureStartNtpTimeMs,
|
|
|
|
|
info.capture_start_ntp_time_ms);
|
|
|
|
|
}
|
Reland of Add QP sum stats for received streams. (patchset #2 id:300001 of https://codereview.webrtc.org/2680893002/ )
Reason for revert:
Fix the problem.
Original issue's description:
> Revert of Add QP sum stats for received streams. (patchset #10 id:180001 of https://codereview.webrtc.org/2649133005/ )
>
> Reason for revert:
> Breaks downstream build.
>
> Original issue's description:
> > Add QP sum stats for received streams.
> >
> > This is not implemented yet in any of the decoders.
> >
> > BUG=webrtc:6541
> >
> > Review-Url: https://codereview.webrtc.org/2649133005
> > Cr-Commit-Position: refs/heads/master@{#16475}
> > Committed: https://chromium.googlesource.com/external/webrtc/+/ff0e72fd165facac27f0313aa178648782e63bc4
>
> TBR=hta@webrtc.org,hbos@webrtc.org,sprang@webrtc.org,magjed@webrtc.org,stefan@webrtc.org,sakal@webrtc.org
> # Skipping CQ checks because original CL landed less than 1 days ago.
> NOPRESUBMIT=true
> NOTREECHECKS=true
> NOTRY=true
> BUG=webrtc:6541
>
> Review-Url: https://codereview.webrtc.org/2680893002 .
> Cr-Commit-Position: refs/heads/master@{#16480}
> Committed: https://chromium.googlesource.com/external/webrtc/+/69fb2cca4d54f3df7ceddcd1c3e9b0ad80fa849b
TBR=hta@webrtc.org,hbos@webrtc.org,sprang@webrtc.org,magjed@webrtc.org,stefan@webrtc.org,skvlad@webrtc.org
BUG=webrtc:6541
Review-Url: https://codereview.webrtc.org/2681663005
Cr-Commit-Position: refs/heads/master@{#16511}
2017-02-09 04:53:45 -08:00
|
|
|
if (info.qp_sum)
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameQpSum, *info.qp_sum);
|
|
|
|
|
|
2015-03-04 15:25:19 +00:00
|
|
|
const IntForAdd ints[] = {
|
|
|
|
|
{StatsReport::kStatsValueNameCurrentDelayMs, info.current_delay_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameDecodeMs, info.decode_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameFirsSent, info.firs_sent},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameHeightReceived, info.frame_height},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameRateDecoded, info.framerate_decoded},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameRateOutput, info.framerate_output},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameRateReceived, info.framerate_rcvd},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameWidthReceived, info.frame_width},
|
|
|
|
|
{StatsReport::kStatsValueNameJitterBufferMs, info.jitter_buffer_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameMaxDecodeMs, info.max_decode_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameMinPlayoutDelayMs,
|
|
|
|
|
info.min_playout_delay_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameNacksSent, info.nacks_sent},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsLost, info.packets_lost},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsReceived, info.packets_rcvd},
|
|
|
|
|
{StatsReport::kStatsValueNamePlisSent, info.plis_sent},
|
|
|
|
|
{StatsReport::kStatsValueNameRenderDelayMs, info.render_delay_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameTargetDelayMs, info.target_delay_ms},
|
2016-10-26 07:09:24 -07:00
|
|
|
{StatsReport::kStatsValueNameFramesDecoded, info.frames_decoded},
|
2018-07-27 14:52:57 +00:00
|
|
|
};
|
2015-03-04 15:25:19 +00:00
|
|
|
|
|
|
|
|
for (const auto& i : ints)
|
|
|
|
|
report->AddInt(i.name, i.value);
|
2016-01-28 01:27:15 -08:00
|
|
|
report->AddString(StatsReport::kStatsValueNameMediaType, "video");
|
2017-07-07 01:26:24 -07:00
|
|
|
|
2017-07-06 03:06:50 -07:00
|
|
|
if (info.timing_frame_info) {
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameTimingFrameInfo,
|
|
|
|
|
info.timing_frame_info->ToString());
|
|
|
|
|
}
|
2017-07-07 01:26:24 -07:00
|
|
|
|
2017-08-23 05:24:10 -07:00
|
|
|
report->AddInt64(StatsReport::kStatsValueNameInterframeDelayMaxMs,
|
|
|
|
|
info.interframe_delay_max_ms);
|
2017-09-04 07:57:17 -07:00
|
|
|
|
|
|
|
|
report->AddString(
|
|
|
|
|
StatsReport::kStatsValueNameContentType,
|
|
|
|
|
webrtc::videocontenttypehelpers::ToString(info.content_type));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExtractStats(const cricket::VideoSenderInfo& info, StatsReport* report) {
|
2015-03-04 15:25:19 +00:00
|
|
|
ExtractCommonSendProperties(info, report);
|
|
|
|
|
|
2015-12-18 16:01:11 +01:00
|
|
|
report->AddString(StatsReport::kStatsValueNameCodecImplementationName,
|
|
|
|
|
info.encoder_implementation_name);
|
2013-12-13 12:29:34 +00:00
|
|
|
report->AddBoolean(StatsReport::kStatsValueNameBandwidthLimitedResolution,
|
|
|
|
|
(info.adapt_reason & 0x2) > 0);
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddBoolean(StatsReport::kStatsValueNameCpuLimitedResolution,
|
|
|
|
|
(info.adapt_reason & 0x1) > 0);
|
2017-11-16 14:04:52 +01:00
|
|
|
report->AddBoolean(StatsReport::kStatsValueNameHasEnteredLowResolution,
|
|
|
|
|
info.has_entered_low_resolution);
|
|
|
|
|
|
2016-10-31 06:53:47 -07:00
|
|
|
if (info.qp_sum)
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameQpSum, *info.qp_sum);
|
2015-03-04 15:25:19 +00:00
|
|
|
|
|
|
|
|
const IntForAdd ints[] = {
|
2018-02-28 16:35:03 +01:00
|
|
|
{StatsReport::kStatsValueNameAdaptationChanges, info.adapt_changes},
|
|
|
|
|
{StatsReport::kStatsValueNameAvgEncodeMs, info.avg_encode_ms},
|
|
|
|
|
{StatsReport::kStatsValueNameEncodeUsagePercent,
|
|
|
|
|
info.encode_usage_percent},
|
|
|
|
|
{StatsReport::kStatsValueNameFirsReceived, info.firs_rcvd},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameHeightSent, info.send_frame_height},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameRateInput, info.framerate_input},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameRateSent, info.framerate_sent},
|
|
|
|
|
{StatsReport::kStatsValueNameFrameWidthSent, info.send_frame_width},
|
|
|
|
|
{StatsReport::kStatsValueNameNacksReceived, info.nacks_rcvd},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsLost, info.packets_lost},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsSent, info.packets_sent},
|
|
|
|
|
{StatsReport::kStatsValueNamePlisReceived, info.plis_rcvd},
|
|
|
|
|
{StatsReport::kStatsValueNameFramesEncoded, info.frames_encoded},
|
|
|
|
|
{StatsReport::kStatsValueNameHugeFramesSent, info.huge_frames_sent},
|
2015-03-04 15:25:19 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
for (const auto& i : ints)
|
|
|
|
|
report->AddInt(i.name, i.value);
|
2016-01-28 01:27:15 -08:00
|
|
|
report->AddString(StatsReport::kStatsValueNameMediaType, "video");
|
2017-09-06 12:32:35 -07:00
|
|
|
report->AddString(
|
|
|
|
|
StatsReport::kStatsValueNameContentType,
|
|
|
|
|
webrtc::videocontenttypehelpers::ToString(info.content_type));
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExtractStats(const cricket::BandwidthEstimationInfo& info,
|
|
|
|
|
double stats_gathering_started,
|
|
|
|
|
StatsReport* report) {
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(report->type() == StatsReport::kStatsReportTypeBwe);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
report->set_timestamp(stats_gathering_started);
|
|
|
|
|
const IntForAdd ints[] = {
|
|
|
|
|
{StatsReport::kStatsValueNameAvailableSendBandwidth,
|
|
|
|
|
info.available_send_bandwidth},
|
|
|
|
|
{StatsReport::kStatsValueNameAvailableReceiveBandwidth,
|
|
|
|
|
info.available_recv_bandwidth},
|
|
|
|
|
{StatsReport::kStatsValueNameTargetEncBitrate, info.target_enc_bitrate},
|
|
|
|
|
{StatsReport::kStatsValueNameActualEncBitrate, info.actual_enc_bitrate},
|
|
|
|
|
{StatsReport::kStatsValueNameRetransmitBitrate, info.retransmit_bitrate},
|
|
|
|
|
{StatsReport::kStatsValueNameTransmitBitrate, info.transmit_bitrate},
|
|
|
|
|
};
|
|
|
|
|
for (const auto& i : ints)
|
|
|
|
|
report->AddInt(i.name, i.value);
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameBucketDelay, info.bucket_delay);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2013-10-25 21:18:33 +00:00
|
|
|
void ExtractRemoteStats(const cricket::MediaSenderInfo& info,
|
|
|
|
|
StatsReport* report) {
|
2015-01-19 20:41:26 +00:00
|
|
|
report->set_timestamp(info.remote_stats[0].timestamp);
|
2013-10-25 21:18:33 +00:00
|
|
|
// TODO(hta): Extract some stats here.
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ExtractRemoteStats(const cricket::MediaReceiverInfo& info,
|
|
|
|
|
StatsReport* report) {
|
2015-01-19 20:41:26 +00:00
|
|
|
report->set_timestamp(info.remote_stats[0].timestamp);
|
2013-10-25 21:18:33 +00:00
|
|
|
// TODO(hta): Extract some stats here.
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Template to extract stats from a data vector.
|
2013-12-05 00:24:06 +00:00
|
|
|
// In order to use the template, the functions that are called from it,
|
|
|
|
|
// ExtractStats and ExtractRemoteStats, must be defined and overloaded
|
|
|
|
|
// for each type.
|
2013-07-10 00:45:36 +00:00
|
|
|
template <typename T>
|
|
|
|
|
void ExtractStatsFromList(const std::vector<T>& data,
|
2015-03-12 16:35:55 +00:00
|
|
|
const StatsReport::Id& transport_id,
|
2014-06-12 14:57:05 +00:00
|
|
|
StatsCollector* collector,
|
2015-01-21 11:36:18 +00:00
|
|
|
StatsReport::Direction direction) {
|
|
|
|
|
for (const auto& d : data) {
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
uint32_t ssrc = d.ssrc();
|
2014-06-12 14:57:05 +00:00
|
|
|
// Each track can have stats for both local and remote objects.
|
2013-10-25 21:18:33 +00:00
|
|
|
// TODO(hta): Handle the case of multiple SSRCs per object.
|
2015-01-21 11:36:18 +00:00
|
|
|
StatsReport* report =
|
|
|
|
|
collector->PrepareReport(true, ssrc, transport_id, direction);
|
2014-06-12 14:57:05 +00:00
|
|
|
if (report)
|
2015-01-21 11:36:18 +00:00
|
|
|
ExtractStats(d, report);
|
2014-06-12 14:57:05 +00:00
|
|
|
|
2015-01-21 11:36:18 +00:00
|
|
|
if (!d.remote_stats.empty()) {
|
|
|
|
|
report = collector->PrepareReport(false, ssrc, transport_id, direction);
|
|
|
|
|
if (report)
|
|
|
|
|
ExtractRemoteStats(d, report);
|
2013-10-25 21:18:33 +00:00
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
2014-02-13 23:18:49 +00:00
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2014-12-16 23:01:31 +00:00
|
|
|
const char* IceCandidateTypeToStatsType(const std::string& candidate_type) {
|
|
|
|
|
if (candidate_type == cricket::LOCAL_PORT_TYPE) {
|
|
|
|
|
return STATSREPORT_LOCAL_PORT_TYPE;
|
|
|
|
|
}
|
|
|
|
|
if (candidate_type == cricket::STUN_PORT_TYPE) {
|
|
|
|
|
return STATSREPORT_STUN_PORT_TYPE;
|
|
|
|
|
}
|
|
|
|
|
if (candidate_type == cricket::PRFLX_PORT_TYPE) {
|
|
|
|
|
return STATSREPORT_PRFLX_PORT_TYPE;
|
|
|
|
|
}
|
|
|
|
|
if (candidate_type == cricket::RELAY_PORT_TYPE) {
|
|
|
|
|
return STATSREPORT_RELAY_PORT_TYPE;
|
|
|
|
|
}
|
2017-01-12 02:24:27 -08:00
|
|
|
RTC_NOTREACHED();
|
2014-12-16 23:01:31 +00:00
|
|
|
return "unknown";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* AdapterTypeToStatsType(rtc::AdapterType type) {
|
|
|
|
|
switch (type) {
|
|
|
|
|
case rtc::ADAPTER_TYPE_UNKNOWN:
|
|
|
|
|
return "unknown";
|
|
|
|
|
case rtc::ADAPTER_TYPE_ETHERNET:
|
|
|
|
|
return STATSREPORT_ADAPTER_TYPE_ETHERNET;
|
|
|
|
|
case rtc::ADAPTER_TYPE_WIFI:
|
|
|
|
|
return STATSREPORT_ADAPTER_TYPE_WIFI;
|
|
|
|
|
case rtc::ADAPTER_TYPE_CELLULAR:
|
|
|
|
|
return STATSREPORT_ADAPTER_TYPE_WWAN;
|
|
|
|
|
case rtc::ADAPTER_TYPE_VPN:
|
|
|
|
|
return STATSREPORT_ADAPTER_TYPE_VPN;
|
Makes libjingle_peerconnection_android_unittest run on networkless devices.
PeerConnectionTest.java currently works, but only on a device with
network interfaces up. This is not a problem for desktop, but it is a
problem when running on Android devices since the devices in the lab
generally don't have network (due to the chaotic radio environment in
the device labs, devices are simply kept in flight mode).
The test does work if one modifies this line in the file
webrtc/base/network.cc:
bool ignored = ((cursor->ifa_flags & IFF_LOOPBACK) ||
IsIgnoredNetwork(*network));
If we remove the IFF_LOOPBACK clause, the test starts working on
an Android device in flight mode. This is nice - we're running the
call and packets interact with the OS network stack, which is good
for this end-to-end test. We can't just remove the clause though since
having loopback is undesirable for everyone except the test (right)?
so we need to make this behavior configurable.
This CL takes a stab at a complete solution where we pass a boolean
all the way through the Java PeerConnectionFactory down to the
BasicNetworkManager. This comes as a heavy price in interface
changes though. It's pretty out of proportion, but fundamentally we
need some way of telling the network manager that it is on Android
and in test mode. Passing the boolean all the way through is one way.
Another way might be to put the loopback filter behind an ifdef and
link a custom libjingle_peerconnection.so with the test. That is hacky
but doesn't pollute the interfaces. Not sure how to solve that in GYP
but it could mean some duplication between the production and
test .so files.
It would have been perfect to use flags here, but then we need to
hook up gflags parsing to some main() somewhere to make sure the
flag gets parsed, and make sure to pass that flag in our tests.
I'm not sure how that can be done.
Making the loopback filtering conditional is exactly how we solved the
equivalent problem in content_browsertests in Chrome, and it worked
great.
That's all I could think of.
BUG=4181
R=perkj@webrtc.org, pthatcher@webrtc.org
Review URL: https://webrtc-codereview.appspot.com/36769004
Cr-Commit-Position: refs/heads/master@{#8344}
git-svn-id: http://webrtc.googlecode.com/svn/trunk@8344 4adac7df-926f-26a2-2b94-8c16560cd09d
2015-02-12 09:23:59 +00:00
|
|
|
case rtc::ADAPTER_TYPE_LOOPBACK:
|
|
|
|
|
return STATSREPORT_ADAPTER_TYPE_LOOPBACK;
|
2018-07-26 10:44:02 -07:00
|
|
|
case rtc::ADAPTER_TYPE_ANY:
|
|
|
|
|
return STATSREPORT_ADAPTER_TYPE_WILDCARD;
|
2014-12-16 23:01:31 +00:00
|
|
|
default:
|
2017-01-12 02:24:27 -08:00
|
|
|
RTC_NOTREACHED();
|
2014-12-16 23:01:31 +00:00
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-01-23 16:38:46 -08:00
|
|
|
StatsCollector::StatsCollector(PeerConnectionInternal* pc)
|
2015-10-14 11:33:11 -07:00
|
|
|
: pc_(pc), stats_gathering_started_(0) {
|
|
|
|
|
RTC_DCHECK(pc_);
|
2014-07-14 20:15:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StatsCollector::~StatsCollector() {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-13 23:41:47 -07:00
|
|
|
// Wallclock time in ms.
|
2015-02-03 22:09:37 +00:00
|
|
|
double StatsCollector::GetTimeNow() {
|
2018-08-10 15:38:52 +02:00
|
|
|
return static_cast<double>(rtc::TimeUTCMillis());
|
2015-02-03 22:09:37 +00:00
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Adds a MediaStream with tracks that can be used as a |selector| in a call
|
|
|
|
|
// to GetStats.
|
|
|
|
|
void StatsCollector::AddStream(MediaStreamInterface* stream) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(stream != NULL);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2017-10-30 09:57:42 -07:00
|
|
|
CreateTrackReports<AudioTrackVector>(stream->GetAudioTracks(), &reports_,
|
|
|
|
|
&track_ids_);
|
|
|
|
|
CreateTrackReports<VideoTrackVector>(stream->GetVideoTracks(), &reports_,
|
|
|
|
|
&track_ids_);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2018-01-04 15:26:13 +01:00
|
|
|
void StatsCollector::AddTrack(MediaStreamTrackInterface* track) {
|
|
|
|
|
if (track->kind() == MediaStreamTrackInterface::kAudioKind) {
|
|
|
|
|
CreateTrackReport(static_cast<AudioTrackInterface*>(track), &reports_,
|
|
|
|
|
&track_ids_);
|
|
|
|
|
} else if (track->kind() == MediaStreamTrackInterface::kVideoKind) {
|
|
|
|
|
CreateTrackReport(static_cast<VideoTrackInterface*>(track), &reports_,
|
|
|
|
|
&track_ids_);
|
|
|
|
|
} else {
|
|
|
|
|
RTC_NOTREACHED() << "Illegal track kind";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-03 18:30:11 +00:00
|
|
|
void StatsCollector::AddLocalAudioTrack(AudioTrackInterface* audio_track,
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
uint32_t ssrc) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(audio_track != NULL);
|
2016-10-04 13:46:56 -07:00
|
|
|
#if RTC_DCHECK_IS_ON
|
2015-03-12 16:35:55 +00:00
|
|
|
for (const auto& track : local_audio_tracks_)
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(track.first != audio_track || track.second != ssrc);
|
2015-03-12 16:35:55 +00:00
|
|
|
#endif
|
2014-07-09 07:38:38 +00:00
|
|
|
|
2014-03-03 18:30:11 +00:00
|
|
|
local_audio_tracks_.push_back(std::make_pair(audio_track, ssrc));
|
2014-07-09 07:38:38 +00:00
|
|
|
|
|
|
|
|
// Create the kStatsReportTypeTrack report for the new track if there is no
|
|
|
|
|
// report yet.
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport::Id id(StatsReport::NewTypedId(StatsReport::kStatsReportTypeTrack,
|
|
|
|
|
audio_track->id()));
|
|
|
|
|
StatsReport* report = reports_.Find(id);
|
2015-01-21 11:36:18 +00:00
|
|
|
if (!report) {
|
2015-03-12 16:35:55 +00:00
|
|
|
report = reports_.InsertNew(id);
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddString(StatsReport::kStatsValueNameTrackId, audio_track->id());
|
2015-01-21 11:36:18 +00:00
|
|
|
}
|
2014-03-03 18:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StatsCollector::RemoveLocalAudioTrack(AudioTrackInterface* audio_track,
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
uint32_t ssrc) {
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(audio_track != NULL);
|
2017-06-16 20:19:08 -07:00
|
|
|
local_audio_tracks_.erase(
|
|
|
|
|
std::remove_if(
|
|
|
|
|
local_audio_tracks_.begin(), local_audio_tracks_.end(),
|
|
|
|
|
[audio_track, ssrc](const LocalAudioTrackVector::value_type& track) {
|
|
|
|
|
return track.first == audio_track && track.second == ssrc;
|
|
|
|
|
}),
|
|
|
|
|
local_audio_tracks_.end());
|
2014-03-03 18:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
2014-08-15 08:38:30 +00:00
|
|
|
void StatsCollector::GetStats(MediaStreamTrackInterface* track,
|
2013-07-10 00:45:36 +00:00
|
|
|
StatsReports* reports) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(reports != NULL);
|
|
|
|
|
RTC_DCHECK(reports->empty());
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
if (!track) {
|
2015-01-21 11:36:18 +00:00
|
|
|
reports->reserve(reports_.size());
|
|
|
|
|
for (auto* r : reports_)
|
|
|
|
|
reports->push_back(r);
|
2014-08-15 08:38:30 +00:00
|
|
|
return;
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-21 11:36:18 +00:00
|
|
|
StatsReport* report = reports_.Find(StatsReport::NewTypedId(
|
2017-09-29 12:15:02 -07:00
|
|
|
StatsReport::kStatsReportTypeSession, pc_->session_id()));
|
2014-08-15 08:38:30 +00:00
|
|
|
if (report)
|
|
|
|
|
reports->push_back(report);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2015-01-21 11:36:18 +00:00
|
|
|
report = reports_.Find(
|
|
|
|
|
StatsReport::NewTypedId(StatsReport::kStatsReportTypeTrack, track->id()));
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2014-08-15 08:38:30 +00:00
|
|
|
if (!report)
|
|
|
|
|
return;
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2014-08-15 08:38:30 +00:00
|
|
|
reports->push_back(report);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
|
|
|
|
std::string track_id;
|
2015-01-21 11:36:18 +00:00
|
|
|
for (const auto* r : reports_) {
|
|
|
|
|
if (r->type() != StatsReport::kStatsReportTypeSsrc)
|
2013-07-10 00:45:36 +00:00
|
|
|
continue;
|
2014-08-15 08:38:30 +00:00
|
|
|
|
2015-01-21 11:36:18 +00:00
|
|
|
const StatsReport::Value* v =
|
|
|
|
|
r->FindValue(StatsReport::kStatsValueNameTrackId);
|
2015-03-12 16:35:55 +00:00
|
|
|
if (v && v->string_val() == track->id())
|
2015-01-21 11:36:18 +00:00
|
|
|
reports->push_back(r);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-13 23:18:49 +00:00
|
|
|
void StatsCollector::UpdateStats(
|
|
|
|
|
PeerConnectionInterface::StatsOutputLevel level) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2013-07-10 00:45:36 +00:00
|
|
|
double time_now = GetTimeNow();
|
|
|
|
|
// Calls to UpdateStats() that occur less than kMinGatherStatsPeriod number of
|
|
|
|
|
// ms apart will be ignored.
|
|
|
|
|
const double kMinGatherStatsPeriod = 50;
|
2014-07-09 07:38:38 +00:00
|
|
|
if (stats_gathering_started_ != 0 &&
|
|
|
|
|
stats_gathering_started_ + kMinGatherStatsPeriod > time_now) {
|
2013-07-10 00:45:36 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
stats_gathering_started_ = time_now;
|
|
|
|
|
|
2017-11-06 10:37:17 -08:00
|
|
|
// TODO(tommi): All of these hop over to the worker thread to fetch
|
|
|
|
|
// information. We could use an AsyncInvoker to run all of these and post
|
|
|
|
|
// the information back to the signaling thread where we can create and
|
|
|
|
|
// update stats reports. That would also clean up the threading story a bit
|
|
|
|
|
// since we'd be creating/updating the stats report objects consistently on
|
|
|
|
|
// the same thread (this class has no locks right now).
|
|
|
|
|
ExtractSessionInfo();
|
|
|
|
|
ExtractBweInfo();
|
2018-02-13 10:07:54 -08:00
|
|
|
ExtractMediaInfo();
|
2017-11-06 10:37:17 -08:00
|
|
|
ExtractSenderInfo();
|
|
|
|
|
ExtractDataInfo();
|
|
|
|
|
UpdateTrackReports();
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-14 11:33:11 -07:00
|
|
|
StatsReport* StatsCollector::PrepareReport(bool local,
|
|
|
|
|
uint32_t ssrc,
|
|
|
|
|
const StatsReport::Id& transport_id,
|
|
|
|
|
StatsReport::Direction direction) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport::Id id(StatsReport::NewIdWithDirection(
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
local ? StatsReport::kStatsReportTypeSsrc
|
|
|
|
|
: StatsReport::kStatsReportTypeRemoteSsrc,
|
2018-07-05 11:59:48 +02:00
|
|
|
rtc::ToString(ssrc), direction));
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport* report = reports_.Find(id);
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2014-07-09 07:38:38 +00:00
|
|
|
// Use the ID of the track that is currently mapped to the SSRC, if any.
|
2013-07-10 00:45:36 +00:00
|
|
|
std::string track_id;
|
2014-07-09 07:38:38 +00:00
|
|
|
if (!GetTrackIdBySsrc(ssrc, &track_id, direction)) {
|
2018-06-19 09:44:26 -07:00
|
|
|
// The SSRC is not used by any existing track (or lookup failed since the
|
|
|
|
|
// SSRC wasn't signaled in SDP). Try copying the track ID from a previous
|
|
|
|
|
// report: if one exists.
|
|
|
|
|
if (report) {
|
|
|
|
|
const StatsReport::Value* v =
|
|
|
|
|
report->FindValue(StatsReport::kStatsValueNameTrackId);
|
|
|
|
|
if (v)
|
|
|
|
|
track_id = v->string_val();
|
2014-07-09 07:38:38 +00:00
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
if (!report)
|
|
|
|
|
report = reports_.InsertNew(id);
|
2013-10-25 21:18:33 +00:00
|
|
|
|
2015-01-21 11:36:18 +00:00
|
|
|
// FYI - for remote reports, the timestamp will be overwritten later.
|
|
|
|
|
report->set_timestamp(stats_gathering_started_);
|
2013-10-25 21:18:33 +00:00
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
report->AddInt64(StatsReport::kStatsValueNameSsrc, ssrc);
|
2018-06-19 09:44:26 -07:00
|
|
|
if (!track_id.empty()) {
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameTrackId, track_id);
|
|
|
|
|
}
|
2013-10-25 21:18:33 +00:00
|
|
|
// Add the mapping of SSRC to transport.
|
2015-03-12 16:35:55 +00:00
|
|
|
report->AddId(StatsReport::kStatsValueNameTransportId, transport_id);
|
2013-10-25 21:18:33 +00:00
|
|
|
return report;
|
|
|
|
|
}
|
|
|
|
|
|
2016-11-04 11:38:15 -07:00
|
|
|
bool StatsCollector::IsValidTrack(const std::string& track_id) {
|
|
|
|
|
return reports_.Find(StatsReport::NewTypedId(
|
|
|
|
|
StatsReport::kStatsReportTypeTrack, track_id)) != nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport* StatsCollector::AddCertificateReports(
|
2018-02-23 13:04:51 -08:00
|
|
|
std::unique_ptr<rtc::SSLCertificateStats> cert_stats) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2013-10-09 15:37:36 +00:00
|
|
|
|
2016-08-25 03:52:38 -07:00
|
|
|
StatsReport* first_report = nullptr;
|
|
|
|
|
StatsReport* prev_report = nullptr;
|
2018-02-23 13:04:51 -08:00
|
|
|
for (rtc::SSLCertificateStats* stats = cert_stats.get(); stats;
|
2016-08-25 03:52:38 -07:00
|
|
|
stats = stats->issuer.get()) {
|
|
|
|
|
StatsReport::Id id(StatsReport::NewTypedId(
|
|
|
|
|
StatsReport::kStatsReportTypeCertificate, stats->fingerprint));
|
|
|
|
|
|
|
|
|
|
StatsReport* report = reports_.ReplaceOrAddNew(id);
|
|
|
|
|
report->set_timestamp(stats_gathering_started_);
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameFingerprint,
|
|
|
|
|
stats->fingerprint);
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameFingerprintAlgorithm,
|
|
|
|
|
stats->fingerprint_algorithm);
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameDer,
|
|
|
|
|
stats->base64_certificate);
|
|
|
|
|
if (!first_report)
|
|
|
|
|
first_report = report;
|
|
|
|
|
else
|
|
|
|
|
prev_report->AddId(StatsReport::kStatsValueNameIssuerId, id);
|
|
|
|
|
prev_report = report;
|
2013-10-09 15:37:36 +00:00
|
|
|
}
|
2016-08-25 03:52:38 -07:00
|
|
|
return first_report;
|
2015-03-12 16:35:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StatsReport* StatsCollector::AddConnectionInfoReport(
|
|
|
|
|
const std::string& content_name,
|
|
|
|
|
int component,
|
|
|
|
|
int connection_id,
|
|
|
|
|
const StatsReport::Id& channel_report_id,
|
|
|
|
|
const cricket::ConnectionInfo& info) {
|
|
|
|
|
StatsReport::Id id(
|
|
|
|
|
StatsReport::NewCandidatePairId(content_name, component, connection_id));
|
|
|
|
|
StatsReport* report = reports_.ReplaceOrAddNew(id);
|
|
|
|
|
report->set_timestamp(stats_gathering_started_);
|
|
|
|
|
|
|
|
|
|
const BoolForAdd bools[] = {
|
2015-09-21 11:48:28 -07:00
|
|
|
{StatsReport::kStatsValueNameActiveConnection, info.best_connection},
|
|
|
|
|
{StatsReport::kStatsValueNameReceiving, info.receiving},
|
|
|
|
|
{StatsReport::kStatsValueNameWritable, info.writable},
|
2015-03-12 16:35:55 +00:00
|
|
|
};
|
|
|
|
|
for (const auto& b : bools)
|
|
|
|
|
report->AddBoolean(b.name, b.value);
|
|
|
|
|
|
|
|
|
|
report->AddId(StatsReport::kStatsValueNameChannelId, channel_report_id);
|
2018-02-20 16:03:18 -08:00
|
|
|
cricket::CandidateStats local_candidate_stats(info.local_candidate);
|
|
|
|
|
cricket::CandidateStats remote_candidate_stats(info.remote_candidate);
|
2015-03-12 16:35:55 +00:00
|
|
|
report->AddId(StatsReport::kStatsValueNameLocalCandidateId,
|
2018-02-20 16:03:18 -08:00
|
|
|
AddCandidateReport(local_candidate_stats, true)->id());
|
2015-03-12 16:35:55 +00:00
|
|
|
report->AddId(StatsReport::kStatsValueNameRemoteCandidateId,
|
2018-02-20 16:03:18 -08:00
|
|
|
AddCandidateReport(remote_candidate_stats, false)->id());
|
2015-03-12 16:35:55 +00:00
|
|
|
|
|
|
|
|
const Int64ForAdd int64s[] = {
|
2016-06-01 17:09:15 -07:00
|
|
|
{StatsReport::kStatsValueNameBytesReceived, info.recv_total_bytes},
|
|
|
|
|
{StatsReport::kStatsValueNameBytesSent, info.sent_total_bytes},
|
|
|
|
|
{StatsReport::kStatsValueNamePacketsSent, info.sent_total_packets},
|
|
|
|
|
{StatsReport::kStatsValueNameRtt, info.rtt},
|
|
|
|
|
{StatsReport::kStatsValueNameSendPacketsDiscarded,
|
|
|
|
|
info.sent_discarded_packets},
|
|
|
|
|
{StatsReport::kStatsValueNameSentPingRequestsTotal,
|
|
|
|
|
info.sent_ping_requests_total},
|
|
|
|
|
{StatsReport::kStatsValueNameSentPingRequestsBeforeFirstResponse,
|
|
|
|
|
info.sent_ping_requests_before_first_response},
|
|
|
|
|
{StatsReport::kStatsValueNameSentPingResponses, info.sent_ping_responses},
|
|
|
|
|
{StatsReport::kStatsValueNameRecvPingRequests, info.recv_ping_requests},
|
|
|
|
|
{StatsReport::kStatsValueNameRecvPingResponses, info.recv_ping_responses},
|
2015-03-12 16:35:55 +00:00
|
|
|
};
|
|
|
|
|
for (const auto& i : int64s)
|
|
|
|
|
report->AddInt64(i.name, i.value);
|
|
|
|
|
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameLocalAddress,
|
|
|
|
|
info.local_candidate.address().ToString());
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameLocalCandidateType,
|
|
|
|
|
info.local_candidate.type());
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameRemoteAddress,
|
|
|
|
|
info.remote_candidate.address().ToString());
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameRemoteCandidateType,
|
|
|
|
|
info.remote_candidate.type());
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameTransportType,
|
|
|
|
|
info.local_candidate.protocol());
|
|
|
|
|
|
|
|
|
|
return report;
|
2013-10-09 15:37:36 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport* StatsCollector::AddCandidateReport(
|
2018-02-20 16:03:18 -08:00
|
|
|
const cricket::CandidateStats& candidate_stats,
|
2015-01-21 11:36:18 +00:00
|
|
|
bool local) {
|
2018-02-20 16:03:18 -08:00
|
|
|
const auto& candidate = candidate_stats.candidate;
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport::Id id(StatsReport::NewCandidateId(local, candidate.id()));
|
|
|
|
|
StatsReport* report = reports_.Find(id);
|
2014-12-16 23:01:31 +00:00
|
|
|
if (!report) {
|
2015-03-12 16:35:55 +00:00
|
|
|
report = reports_.InsertNew(id);
|
2015-01-21 11:36:18 +00:00
|
|
|
report->set_timestamp(stats_gathering_started_);
|
|
|
|
|
if (local) {
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddString(StatsReport::kStatsValueNameCandidateNetworkType,
|
|
|
|
|
AdapterTypeToStatsType(candidate.network_type()));
|
2014-12-16 23:01:31 +00:00
|
|
|
}
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddString(StatsReport::kStatsValueNameCandidateIPAddress,
|
|
|
|
|
candidate.address().ipaddr().ToString());
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameCandidatePortNumber,
|
|
|
|
|
candidate.address().PortAsString());
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameCandidatePriority,
|
|
|
|
|
candidate.priority());
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameCandidateType,
|
|
|
|
|
IceCandidateTypeToStatsType(candidate.type()));
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameCandidateTransportType,
|
|
|
|
|
candidate.protocol());
|
2014-12-16 23:01:31 +00:00
|
|
|
}
|
|
|
|
|
|
2018-03-01 18:25:20 -08:00
|
|
|
if (local && candidate_stats.stun_stats.has_value()) {
|
|
|
|
|
const auto& stun_stats = candidate_stats.stun_stats.value();
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameSentStunKeepaliveRequests,
|
|
|
|
|
stun_stats.stun_binding_requests_sent);
|
|
|
|
|
report->AddInt64(StatsReport::kStatsValueNameRecvStunKeepaliveResponses,
|
|
|
|
|
stun_stats.stun_binding_responses_received);
|
|
|
|
|
report->AddFloat(StatsReport::kStatsValueNameStunKeepaliveRttTotal,
|
|
|
|
|
stun_stats.stun_binding_rtt_ms_total);
|
|
|
|
|
report->AddFloat(StatsReport::kStatsValueNameStunKeepaliveRttSquaredTotal,
|
|
|
|
|
stun_stats.stun_binding_rtt_ms_squared_total);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
return report;
|
2014-12-16 23:01:31 +00:00
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
void StatsCollector::ExtractSessionInfo() {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-03-12 16:35:55 +00:00
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
// Extract information from the base session.
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport::Id id(StatsReport::NewTypedId(
|
2017-09-29 12:15:02 -07:00
|
|
|
StatsReport::kStatsReportTypeSession, pc_->session_id()));
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport* report = reports_.ReplaceOrAddNew(id);
|
2015-01-19 20:41:26 +00:00
|
|
|
report->set_timestamp(stats_gathering_started_);
|
2014-08-15 08:38:30 +00:00
|
|
|
report->AddBoolean(StatsReport::kStatsValueNameInitiator,
|
2017-09-29 12:15:02 -07:00
|
|
|
pc_->initial_offerer());
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2018-02-20 16:03:18 -08:00
|
|
|
cricket::CandidateStatsList pooled_candidate_stats_list =
|
|
|
|
|
pc_->GetPooledCandidateStats();
|
|
|
|
|
|
|
|
|
|
for (const cricket::CandidateStats& stats : pooled_candidate_stats_list) {
|
|
|
|
|
AddCandidateReport(stats, true);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 10:34:40 -08:00
|
|
|
std::set<std::string> transport_names;
|
|
|
|
|
for (const auto& entry : pc_->GetTransportNamesByMid()) {
|
|
|
|
|
transport_names.insert(entry.second);
|
2015-03-16 19:31:40 +00:00
|
|
|
}
|
2014-07-24 20:41:20 +00:00
|
|
|
|
2018-02-06 10:34:40 -08:00
|
|
|
std::map<std::string, cricket::TransportStats> transport_stats_by_name =
|
|
|
|
|
pc_->GetTransportStatsByNames(transport_names);
|
|
|
|
|
|
|
|
|
|
for (const auto& entry : transport_stats_by_name) {
|
|
|
|
|
const std::string& transport_name = entry.first;
|
|
|
|
|
const cricket::TransportStats& transport_stats = entry.second;
|
|
|
|
|
|
2015-03-16 19:31:40 +00:00
|
|
|
// Attempt to get a copy of the certificates from the transport and
|
|
|
|
|
// expose them in stats reports. All channels in a transport share the
|
|
|
|
|
// same local and remote certificates.
|
|
|
|
|
//
|
|
|
|
|
StatsReport::Id local_cert_report_id, remote_cert_report_id;
|
2015-08-27 10:12:24 +02:00
|
|
|
rtc::scoped_refptr<rtc::RTCCertificate> certificate;
|
2018-02-06 10:34:40 -08:00
|
|
|
if (pc_->GetLocalCertificate(transport_name, &certificate)) {
|
2018-02-23 13:04:51 -08:00
|
|
|
StatsReport* r =
|
|
|
|
|
AddCertificateReports(certificate->ssl_cert_chain().GetStats());
|
2015-03-16 19:31:40 +00:00
|
|
|
if (r)
|
|
|
|
|
local_cert_report_id = r->id();
|
|
|
|
|
}
|
2014-07-24 20:41:20 +00:00
|
|
|
|
2018-02-23 13:04:51 -08:00
|
|
|
std::unique_ptr<rtc::SSLCertChain> remote_cert_chain =
|
|
|
|
|
pc_->GetRemoteSSLCertChain(transport_name);
|
|
|
|
|
if (remote_cert_chain) {
|
|
|
|
|
StatsReport* r = AddCertificateReports(remote_cert_chain->GetStats());
|
2015-03-16 19:31:40 +00:00
|
|
|
if (r)
|
|
|
|
|
remote_cert_report_id = r->id();
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-06 10:34:40 -08:00
|
|
|
for (const auto& channel_iter : transport_stats.channel_stats) {
|
|
|
|
|
StatsReport::Id id(
|
|
|
|
|
StatsReport::NewComponentId(transport_name, channel_iter.component));
|
2015-03-16 19:31:40 +00:00
|
|
|
StatsReport* channel_report = reports_.ReplaceOrAddNew(id);
|
|
|
|
|
channel_report->set_timestamp(stats_gathering_started_);
|
|
|
|
|
channel_report->AddInt(StatsReport::kStatsValueNameComponent,
|
|
|
|
|
channel_iter.component);
|
|
|
|
|
if (local_cert_report_id.get()) {
|
|
|
|
|
channel_report->AddId(StatsReport::kStatsValueNameLocalCertificateId,
|
|
|
|
|
local_cert_report_id);
|
|
|
|
|
}
|
|
|
|
|
if (remote_cert_report_id.get()) {
|
|
|
|
|
channel_report->AddId(StatsReport::kStatsValueNameRemoteCertificateId,
|
|
|
|
|
remote_cert_report_id);
|
|
|
|
|
}
|
2015-11-18 19:41:53 -08:00
|
|
|
int srtp_crypto_suite = channel_iter.srtp_crypto_suite;
|
|
|
|
|
if (srtp_crypto_suite != rtc::SRTP_INVALID_CRYPTO_SUITE &&
|
|
|
|
|
rtc::SrtpCryptoSuiteToName(srtp_crypto_suite).length()) {
|
|
|
|
|
channel_report->AddString(
|
|
|
|
|
StatsReport::kStatsValueNameSrtpCipher,
|
|
|
|
|
rtc::SrtpCryptoSuiteToName(srtp_crypto_suite));
|
2015-03-16 19:31:40 +00:00
|
|
|
}
|
2015-11-18 19:41:53 -08:00
|
|
|
int ssl_cipher_suite = channel_iter.ssl_cipher_suite;
|
|
|
|
|
if (ssl_cipher_suite != rtc::TLS_NULL_WITH_NULL_NULL &&
|
|
|
|
|
rtc::SSLStreamAdapter::SslCipherSuiteToName(ssl_cipher_suite)
|
|
|
|
|
.length()) {
|
2015-09-30 21:48:54 -07:00
|
|
|
channel_report->AddString(
|
|
|
|
|
StatsReport::kStatsValueNameDtlsCipher,
|
2015-11-18 19:41:53 -08:00
|
|
|
rtc::SSLStreamAdapter::SslCipherSuiteToName(ssl_cipher_suite));
|
2015-03-16 19:31:40 +00:00
|
|
|
}
|
2015-03-12 16:35:55 +00:00
|
|
|
|
2018-02-20 16:03:18 -08:00
|
|
|
// Collect stats for non-pooled candidates. Note that the reports
|
|
|
|
|
// generated here supersedes the candidate reports generated in
|
|
|
|
|
// AddConnectionInfoReport below, and they may report candidates that are
|
|
|
|
|
// not paired. Also, the candidate report generated in
|
|
|
|
|
// AddConnectionInfoReport do not report port stats like StunStats.
|
|
|
|
|
for (const cricket::CandidateStats& stats :
|
|
|
|
|
channel_iter.candidate_stats_list) {
|
|
|
|
|
AddCandidateReport(stats, true);
|
|
|
|
|
}
|
|
|
|
|
|
2015-03-16 19:31:40 +00:00
|
|
|
int connection_id = 0;
|
|
|
|
|
for (const cricket::ConnectionInfo& info :
|
|
|
|
|
channel_iter.connection_infos) {
|
|
|
|
|
StatsReport* connection_report = AddConnectionInfoReport(
|
2018-02-06 10:34:40 -08:00
|
|
|
transport_name, channel_iter.component, connection_id++,
|
2015-03-16 19:31:40 +00:00
|
|
|
channel_report->id(), info);
|
|
|
|
|
if (info.best_connection) {
|
|
|
|
|
channel_report->AddId(
|
|
|
|
|
StatsReport::kStatsValueNameSelectedCandidatePairId,
|
|
|
|
|
connection_report->id());
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-06-02 06:44:03 -07:00
|
|
|
void StatsCollector::ExtractBweInfo() {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2017-06-02 06:44:03 -07:00
|
|
|
|
2017-09-29 12:15:02 -07:00
|
|
|
if (pc_->signaling_state() == PeerConnectionInterface::kClosed)
|
2017-06-02 06:44:03 -07:00
|
|
|
return;
|
|
|
|
|
|
2017-09-29 12:15:02 -07:00
|
|
|
webrtc::Call::Stats call_stats = pc_->GetCallStats();
|
2017-06-02 06:44:03 -07:00
|
|
|
cricket::BandwidthEstimationInfo bwe_info;
|
|
|
|
|
bwe_info.available_send_bandwidth = call_stats.send_bandwidth_bps;
|
|
|
|
|
bwe_info.available_recv_bandwidth = call_stats.recv_bandwidth_bps;
|
|
|
|
|
bwe_info.bucket_delay = call_stats.pacer_delay_ms;
|
2018-02-20 11:35:37 -08:00
|
|
|
|
2017-06-02 06:44:03 -07:00
|
|
|
// Fill in target encoder bitrate, actual encoder bitrate, rtx bitrate, etc.
|
|
|
|
|
// TODO(holmer): Also fill this in for audio.
|
2018-02-20 11:35:37 -08:00
|
|
|
for (auto transceiver : pc_->GetTransceiversInternal()) {
|
|
|
|
|
if (transceiver->media_type() != cricket::MEDIA_TYPE_VIDEO) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
auto* video_channel =
|
|
|
|
|
static_cast<cricket::VideoChannel*>(transceiver->internal()->channel());
|
|
|
|
|
if (!video_channel) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
video_channel->FillBitrateInfo(&bwe_info);
|
2017-06-02 06:44:03 -07:00
|
|
|
}
|
2018-02-20 11:35:37 -08:00
|
|
|
|
2017-06-02 06:44:03 -07:00
|
|
|
StatsReport::Id report_id(StatsReport::NewBandwidthEstimationId());
|
|
|
|
|
StatsReport* report = reports_.FindOrAddNew(report_id);
|
|
|
|
|
ExtractStats(bwe_info, stats_gathering_started_, report);
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
namespace {
|
2015-03-12 16:35:55 +00:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
struct VoiceChannelStatsInfo {
|
|
|
|
|
std::string transport_name;
|
|
|
|
|
cricket::VoiceMediaChannel* voice_media_channel;
|
|
|
|
|
cricket::VoiceMediaInfo voice_media_info;
|
|
|
|
|
};
|
2015-03-12 16:35:55 +00:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
struct VideoChannelStatsInfo {
|
|
|
|
|
std::string transport_name;
|
|
|
|
|
cricket::VideoMediaChannel* video_media_channel;
|
|
|
|
|
cricket::VideoMediaInfo video_media_info;
|
|
|
|
|
};
|
2015-03-12 16:35:55 +00:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
} // namespace
|
2014-03-03 18:30:11 +00:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
void StatsCollector::ExtractMediaInfo() {
|
|
|
|
|
RTC_DCHECK_RUN_ON(pc_->signaling_thread());
|
2013-07-10 00:45:36 +00:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
std::vector<VoiceChannelStatsInfo> voice_channel_infos;
|
|
|
|
|
std::vector<VideoChannelStatsInfo> video_channel_infos;
|
2014-12-15 09:44:48 +00:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
{
|
|
|
|
|
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
|
|
|
|
for (auto transceiver : pc_->GetTransceiversInternal()) {
|
|
|
|
|
if (!transceiver->internal()->channel()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
cricket::MediaType media_type = transceiver->internal()->media_type();
|
|
|
|
|
if (media_type == cricket::MEDIA_TYPE_AUDIO) {
|
|
|
|
|
auto* voice_channel = static_cast<cricket::VoiceChannel*>(
|
|
|
|
|
transceiver->internal()->channel());
|
|
|
|
|
voice_channel_infos.emplace_back();
|
|
|
|
|
VoiceChannelStatsInfo& info = voice_channel_infos.back();
|
|
|
|
|
info.transport_name = voice_channel->transport_name();
|
|
|
|
|
info.voice_media_channel = voice_channel->media_channel();
|
|
|
|
|
} else {
|
|
|
|
|
RTC_DCHECK_EQ(media_type, cricket::MEDIA_TYPE_VIDEO);
|
|
|
|
|
auto* video_channel = static_cast<cricket::VideoChannel*>(
|
|
|
|
|
transceiver->internal()->channel());
|
|
|
|
|
video_channel_infos.emplace_back();
|
|
|
|
|
VideoChannelStatsInfo& info = video_channel_infos.back();
|
|
|
|
|
info.transport_name = video_channel->transport_name();
|
|
|
|
|
info.video_media_channel = video_channel->media_channel();
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
2015-03-12 16:35:55 +00:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
pc_->worker_thread()->Invoke<void>(RTC_FROM_HERE, [&] {
|
|
|
|
|
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
|
|
|
|
for (auto it = voice_channel_infos.begin(); it != voice_channel_infos.end();
|
|
|
|
|
/* incremented manually */) {
|
|
|
|
|
if (!it->voice_media_channel->GetStats(&it->voice_media_info)) {
|
|
|
|
|
RTC_LOG(LS_ERROR) << "Failed to get voice channel stats";
|
|
|
|
|
it = voice_channel_infos.erase(it);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
for (auto it = video_channel_infos.begin(); it != video_channel_infos.end();
|
|
|
|
|
/* incremented manually */) {
|
|
|
|
|
if (!it->video_media_channel->GetStats(&it->video_media_info)) {
|
|
|
|
|
RTC_LOG(LS_ERROR) << "Failed to get video channel stats";
|
|
|
|
|
it = video_channel_infos.erase(it);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
++it;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
|
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
bool has_remote_audio = false;
|
|
|
|
|
for (const auto& info : voice_channel_infos) {
|
|
|
|
|
StatsReport::Id transport_id = StatsReport::NewComponentId(
|
|
|
|
|
info.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
|
ExtractStatsFromList(info.voice_media_info.receivers, transport_id, this,
|
|
|
|
|
StatsReport::kReceive);
|
|
|
|
|
ExtractStatsFromList(info.voice_media_info.senders, transport_id, this,
|
|
|
|
|
StatsReport::kSend);
|
|
|
|
|
if (!info.voice_media_info.receivers.empty()) {
|
|
|
|
|
has_remote_audio = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (const auto& info : video_channel_infos) {
|
|
|
|
|
StatsReport::Id transport_id = StatsReport::NewComponentId(
|
|
|
|
|
info.transport_name, cricket::ICE_CANDIDATE_COMPONENT_RTP);
|
|
|
|
|
ExtractStatsFromList(info.video_media_info.receivers, transport_id, this,
|
|
|
|
|
StatsReport::kReceive);
|
|
|
|
|
ExtractStatsFromList(info.video_media_info.senders, transport_id, this,
|
|
|
|
|
StatsReport::kSend);
|
|
|
|
|
}
|
2017-12-18 11:00:14 -08:00
|
|
|
|
2018-02-13 10:07:54 -08:00
|
|
|
UpdateStatsFromExistingLocalAudioTracks(has_remote_audio);
|
2013-07-10 00:45:36 +00:00
|
|
|
}
|
|
|
|
|
|
2016-04-01 01:10:42 -07:00
|
|
|
void StatsCollector::ExtractSenderInfo() {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2016-04-01 01:10:42 -07:00
|
|
|
|
|
|
|
|
for (const auto& sender : pc_->GetSenders()) {
|
|
|
|
|
// TODO(nisse): SSRC == 0 currently means none. Delete check when
|
|
|
|
|
// that is fixed.
|
|
|
|
|
if (!sender->ssrc()) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const rtc::scoped_refptr<MediaStreamTrackInterface> track(sender->track());
|
|
|
|
|
if (!track || track->kind() != MediaStreamTrackInterface::kVideoKind) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// Safe, because kind() == kVideoKind implies a subclass of
|
|
|
|
|
// VideoTrackInterface; see mediastreaminterface.h.
|
|
|
|
|
VideoTrackSourceInterface* source =
|
|
|
|
|
static_cast<VideoTrackInterface*>(track.get())->GetSource();
|
|
|
|
|
|
|
|
|
|
VideoTrackSourceInterface::Stats stats;
|
|
|
|
|
if (!source->GetStats(&stats)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
const StatsReport::Id stats_id = StatsReport::NewIdWithDirection(
|
2018-07-05 11:59:48 +02:00
|
|
|
StatsReport::kStatsReportTypeSsrc, rtc::ToString(sender->ssrc()),
|
|
|
|
|
StatsReport::kSend);
|
2016-04-01 01:10:42 -07:00
|
|
|
StatsReport* report = reports_.FindOrAddNew(stats_id);
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameFrameWidthInput,
|
|
|
|
|
stats.input_width);
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameFrameHeightInput,
|
|
|
|
|
stats.input_height);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-15 22:55:07 +00:00
|
|
|
void StatsCollector::ExtractDataInfo() {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-01-15 22:55:07 +00:00
|
|
|
|
2015-03-12 16:35:55 +00:00
|
|
|
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
|
|
|
|
|
2015-10-14 11:33:11 -07:00
|
|
|
for (const auto& dc : pc_->sctp_data_channels()) {
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport::Id id(StatsReport::NewTypedIntId(
|
2015-02-03 22:09:37 +00:00
|
|
|
StatsReport::kStatsReportTypeDataChannel, dc->id()));
|
2015-03-12 16:35:55 +00:00
|
|
|
StatsReport* report = reports_.ReplaceOrAddNew(id);
|
2015-02-03 22:09:37 +00:00
|
|
|
report->set_timestamp(stats_gathering_started_);
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddString(StatsReport::kStatsValueNameLabel, dc->label());
|
2016-05-13 11:46:35 -07:00
|
|
|
// Filter out the initial id (-1).
|
|
|
|
|
if (dc->id() >= 0) {
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameDataChannelId, dc->id());
|
|
|
|
|
}
|
2015-03-04 15:25:19 +00:00
|
|
|
report->AddString(StatsReport::kStatsValueNameProtocol, dc->protocol());
|
|
|
|
|
report->AddString(StatsReport::kStatsValueNameState,
|
|
|
|
|
DataChannelInterface::DataStateString(dc->state()));
|
2015-01-15 22:55:07 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-21 11:36:18 +00:00
|
|
|
StatsReport* StatsCollector::GetReport(const StatsReport::StatsType& type,
|
2014-06-12 14:57:05 +00:00
|
|
|
const std::string& id,
|
2015-01-21 11:36:18 +00:00
|
|
|
StatsReport::Direction direction) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(type == StatsReport::kStatsReportTypeSsrc ||
|
|
|
|
|
type == StatsReport::kStatsReportTypeRemoteSsrc);
|
2015-01-21 11:36:18 +00:00
|
|
|
return reports_.Find(StatsReport::NewIdWithDirection(type, id, direction));
|
2014-03-03 18:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
2017-11-20 13:07:16 +01:00
|
|
|
void StatsCollector::UpdateStatsFromExistingLocalAudioTracks(
|
|
|
|
|
bool has_remote_tracks) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2014-03-03 18:30:11 +00:00
|
|
|
// Loop through the existing local audio tracks.
|
2015-03-12 16:35:55 +00:00
|
|
|
for (const auto& it : local_audio_tracks_) {
|
|
|
|
|
AudioTrackInterface* track = it.first;
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
uint32_t ssrc = it.second;
|
2018-07-05 11:59:48 +02:00
|
|
|
StatsReport* report = GetReport(StatsReport::kStatsReportTypeSsrc,
|
|
|
|
|
rtc::ToString(ssrc), StatsReport::kSend);
|
2014-03-10 20:41:22 +00:00
|
|
|
if (report == NULL) {
|
|
|
|
|
// This can happen if a local audio track is added to a stream on the
|
|
|
|
|
// fly and the report has not been set up yet. Do nothing in this case.
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_ERROR) << "Stats report does not exist for ssrc " << ssrc;
|
2014-03-10 20:41:22 +00:00
|
|
|
continue;
|
|
|
|
|
}
|
2014-03-03 18:30:11 +00:00
|
|
|
|
|
|
|
|
// The same ssrc can be used by both local and remote audio tracks.
|
2015-01-21 11:36:18 +00:00
|
|
|
const StatsReport::Value* v =
|
|
|
|
|
report->FindValue(StatsReport::kStatsValueNameTrackId);
|
2015-03-12 16:35:55 +00:00
|
|
|
if (!v || v->string_val() != track->id())
|
2014-03-03 18:30:11 +00:00
|
|
|
continue;
|
|
|
|
|
|
2015-06-22 15:06:43 -07:00
|
|
|
report->set_timestamp(stats_gathering_started_);
|
2017-11-20 13:07:16 +01:00
|
|
|
UpdateReportFromAudioTrack(track, report, has_remote_tracks);
|
2014-03-03 18:30:11 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void StatsCollector::UpdateReportFromAudioTrack(AudioTrackInterface* track,
|
2017-11-20 13:07:16 +01:00
|
|
|
StatsReport* report,
|
|
|
|
|
bool has_remote_tracks) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(track != NULL);
|
2014-03-03 18:30:11 +00:00
|
|
|
|
2015-11-27 17:27:35 -08:00
|
|
|
// Don't overwrite report values if they're not available.
|
|
|
|
|
int signal_level;
|
|
|
|
|
if (track->GetSignalLevel(&signal_level)) {
|
|
|
|
|
RTC_DCHECK_GE(signal_level, 0);
|
|
|
|
|
report->AddInt(StatsReport::kStatsValueNameAudioInputLevel, signal_level);
|
|
|
|
|
}
|
2014-03-03 18:30:11 +00:00
|
|
|
|
2015-11-27 17:27:35 -08:00
|
|
|
auto audio_processor(track->GetAudioProcessor());
|
2014-03-03 18:30:11 +00:00
|
|
|
|
2015-11-27 17:27:35 -08:00
|
|
|
if (audio_processor.get()) {
|
2017-11-20 13:07:16 +01:00
|
|
|
AudioProcessorInterface::AudioProcessorStatistics stats =
|
|
|
|
|
audio_processor->GetStats(has_remote_tracks);
|
2015-03-04 15:25:19 +00:00
|
|
|
|
2017-11-24 17:29:59 +01:00
|
|
|
SetAudioProcessingStats(report, stats.typing_noise_detected,
|
|
|
|
|
stats.apm_statistics);
|
2015-11-27 17:27:35 -08:00
|
|
|
}
|
2014-03-03 18:30:11 +00:00
|
|
|
}
|
|
|
|
|
|
Use suffixed {uint,int}{8,16,32,64}_t types.
Removes the use of uint8, etc. in favor of uint8_t.
BUG=webrtc:5024
R=henrik.lundin@webrtc.org, henrikg@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1362503003 .
Cr-Commit-Position: refs/heads/master@{#10196}
2015-10-07 12:23:21 +02:00
|
|
|
bool StatsCollector::GetTrackIdBySsrc(uint32_t ssrc,
|
|
|
|
|
std::string* track_id,
|
2015-01-21 11:36:18 +00:00
|
|
|
StatsReport::Direction direction) {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-01-21 11:36:18 +00:00
|
|
|
if (direction == StatsReport::kSend) {
|
2017-09-29 12:15:02 -07:00
|
|
|
if (!pc_->GetLocalTrackIdBySsrc(ssrc, track_id)) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_WARNING) << "The SSRC " << ssrc
|
|
|
|
|
<< " is not associated with a sending track";
|
2014-06-12 14:57:05 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(direction == StatsReport::kReceive);
|
2017-09-29 12:15:02 -07:00
|
|
|
if (!pc_->GetRemoteTrackIdBySsrc(ssrc, track_id)) {
|
2017-11-09 11:09:25 +01:00
|
|
|
RTC_LOG(LS_WARNING) << "The SSRC " << ssrc
|
|
|
|
|
<< " is not associated with a receiving track";
|
2014-06-12 14:57:05 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-22 15:06:43 -07:00
|
|
|
void StatsCollector::UpdateTrackReports() {
|
2017-09-29 12:15:02 -07:00
|
|
|
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
|
2015-06-22 15:06:43 -07:00
|
|
|
|
|
|
|
|
rtc::Thread::ScopedDisallowBlockingCalls no_blocking_calls;
|
|
|
|
|
|
|
|
|
|
for (const auto& entry : track_ids_) {
|
|
|
|
|
StatsReport* report = entry.second;
|
|
|
|
|
report->set_timestamp(stats_gathering_started_);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-15 09:44:48 +00:00
|
|
|
void StatsCollector::ClearUpdateStatsCacheForTest() {
|
2014-07-09 07:38:38 +00:00
|
|
|
stats_gathering_started_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2013-07-10 00:45:36 +00:00
|
|
|
} // namespace webrtc
|