Add stats totalSamplesReceived and concealedSamples
Adds two new stats to RTCMediaStreamTrackStats:
* totalSamplesReceived is the total number of samples received on
the audio channel and includes real and synthetic samples.
* concealedSamples is the total number of synthetic samples
received on the audio channel used to conceal packet loss.
Bug: webrtc:8076
Change-Id: I36e9828525ec341490cf3310a972b56a8b443667
Reviewed-on: https://chromium-review.googlesource.com/615902
Commit-Queue: Steve Anton <steveanton@webrtc.org>
Reviewed-by: Tommi <tommi@webrtc.org>
Reviewed-by: Taylor Brandstetter <deadbeef@webrtc.org>
Reviewed-by: Henrik Boström <hbos@webrtc.org>
Reviewed-by: Henrik Lundin <henrik.lundin@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#19506}
This commit is contained in:
@ -273,9 +273,11 @@ class RTCMediaStreamTrackStats final : public RTCStats {
|
||||
// Audio-only members
|
||||
RTCStatsMember<double> audio_level;
|
||||
RTCStatsMember<double> total_audio_energy;
|
||||
RTCStatsMember<double> total_samples_duration;
|
||||
RTCStatsMember<double> echo_return_loss;
|
||||
RTCStatsMember<double> echo_return_loss_enhancement;
|
||||
RTCStatsMember<uint64_t> total_samples_received;
|
||||
RTCStatsMember<double> total_samples_duration;
|
||||
RTCStatsMember<uint64_t> concealed_samples;
|
||||
};
|
||||
|
||||
// https://w3c.github.io/webrtc-stats/#pcstats-dict*
|
||||
|
||||
@ -371,6 +371,8 @@ const char* StatsReport::Value::display_name() const {
|
||||
return "audioInputLevel";
|
||||
case kStatsValueNameBytesSent:
|
||||
return "bytesSent";
|
||||
case kStatsValueNameConcealedSamples:
|
||||
return "concealedSamples";
|
||||
case kStatsValueNamePacketsSent:
|
||||
return "packetsSent";
|
||||
case kStatsValueNameBytesReceived:
|
||||
@ -383,6 +385,8 @@ const char* StatsReport::Value::display_name() const {
|
||||
return "packetsLost";
|
||||
case kStatsValueNameProtocol:
|
||||
return "protocol";
|
||||
case kStatsValueNameTotalSamplesReceived:
|
||||
return "totalSamplesReceived";
|
||||
case kStatsValueNameTransportId:
|
||||
return "transportId";
|
||||
case kStatsValueNameSelectedCandidatePairId:
|
||||
|
||||
@ -104,6 +104,7 @@ class StatsReport {
|
||||
kStatsValueNameBytesReceived,
|
||||
kStatsValueNameBytesSent,
|
||||
kStatsValueNameCodecImplementationName,
|
||||
kStatsValueNameConcealedSamples,
|
||||
kStatsValueNameDataChannelId,
|
||||
kStatsValueNameFramesDecoded,
|
||||
kStatsValueNameFramesEncoded,
|
||||
@ -120,6 +121,7 @@ class StatsReport {
|
||||
kStatsValueNameState,
|
||||
kStatsValueNameTotalAudioEnergy,
|
||||
kStatsValueNameTotalSamplesDuration,
|
||||
kStatsValueNameTotalSamplesReceived,
|
||||
kStatsValueNameTransportId,
|
||||
kStatsValueNameSentPingRequestsTotal,
|
||||
kStatsValueNameSentPingRequestsBeforeFirstResponse,
|
||||
|
||||
@ -194,6 +194,8 @@ webrtc::AudioReceiveStream::Stats AudioReceiveStream::GetStats() const {
|
||||
auto ns = channel_proxy_->GetNetworkStatistics();
|
||||
stats.jitter_buffer_ms = ns.currentBufferSize;
|
||||
stats.jitter_buffer_preferred_ms = ns.preferredBufferSize;
|
||||
stats.total_samples_received = ns.totalSamplesReceived;
|
||||
stats.concealed_samples = ns.concealedSamples;
|
||||
stats.expand_rate = Q14ToFloat(ns.currentExpandRate);
|
||||
stats.speech_expand_rate = Q14ToFloat(ns.currentSpeechExpandRate);
|
||||
stats.secondary_decoded_rate = Q14ToFloat(ns.currentSecondaryDecodedRate);
|
||||
|
||||
@ -64,8 +64,9 @@ const CallStatistics kCallStats = {
|
||||
345, 678, 901, 234, -12, 3456, 7890, 567, 890, 123};
|
||||
const CodecInst kCodecInst = {
|
||||
123, "codec_name_recv", 96000, -187, 0, -103};
|
||||
const NetworkStatistics kNetworkStats = {
|
||||
123, 456, false, 0, {}, 789, 12, 345, 678, 901, 0, -1, -1, -1, -1, -1, 0};
|
||||
const NetworkStatistics kNetworkStats = {123, 456, false, 789012, 3456, 0, {},
|
||||
789, 12, 345, 678, 901, 0, -1,
|
||||
-1, -1, -1, -1, 0};
|
||||
const AudioDecodingCallStats kAudioDecodeStats = MakeAudioDecodeStatsForTest();
|
||||
|
||||
struct ConfigHelper {
|
||||
@ -318,7 +319,9 @@ TEST(AudioReceiveStreamTest, GetStats) {
|
||||
stats.delay_estimate_ms);
|
||||
EXPECT_EQ(static_cast<int32_t>(kSpeechOutputLevel), stats.audio_level);
|
||||
EXPECT_EQ(kTotalOutputEnergy, stats.total_output_energy);
|
||||
EXPECT_EQ(kNetworkStats.totalSamplesReceived, stats.total_samples_received);
|
||||
EXPECT_EQ(kTotalOutputDuration, stats.total_output_duration);
|
||||
EXPECT_EQ(kNetworkStats.concealedSamples, stats.concealed_samples);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentExpandRate), stats.expand_rate);
|
||||
EXPECT_EQ(Q14ToFloat(kNetworkStats.currentSpeechExpandRate),
|
||||
stats.speech_expand_rate);
|
||||
|
||||
@ -52,7 +52,15 @@ class AudioReceiveStream {
|
||||
// See description of "totalAudioEnergy" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy
|
||||
double total_output_energy = 0.0;
|
||||
// See description of "totalSamplesReceived" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalsamplesreceived
|
||||
uint64_t total_samples_received = 0;
|
||||
// See description of "totalSamplesDuration" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalsamplesduration
|
||||
double total_output_duration = 0.0;
|
||||
// See description of "concealedSamples" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-concealedsamples
|
||||
uint64_t concealed_samples = 0;
|
||||
float expand_rate = 0.0f;
|
||||
float speech_expand_rate = 0.0f;
|
||||
float secondary_decoded_rate = 0.0f;
|
||||
|
||||
@ -367,6 +367,13 @@ struct NetworkStatistics {
|
||||
uint16_t preferredBufferSize;
|
||||
// adding extra delay due to "peaky jitter"
|
||||
bool jitterPeaksFound;
|
||||
// Total number of audio samples received, including synthesized samples.
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalsamplesreceived
|
||||
uint64_t totalSamplesReceived;
|
||||
// Total number of inbound audio samples that are based on synthesized data to
|
||||
// conceal packet loss.
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-concealedsamples
|
||||
uint64_t concealedSamples;
|
||||
// Loss rate (network + late); fraction between 0 and 1, scaled to Q14.
|
||||
uint16_t currentPacketLossRate;
|
||||
// Late loss rate; fraction between 0 and 1, scaled to Q14.
|
||||
|
||||
@ -652,7 +652,9 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
|
||||
delay_estimate_ms(0),
|
||||
audio_level(0),
|
||||
total_output_energy(0.0),
|
||||
total_samples_received(0),
|
||||
total_output_duration(0.0),
|
||||
concealed_samples(0),
|
||||
expand_rate(0),
|
||||
speech_expand_rate(0),
|
||||
secondary_decoded_rate(0),
|
||||
@ -676,7 +678,15 @@ struct VoiceReceiverInfo : public MediaReceiverInfo {
|
||||
// See description of "totalAudioEnergy" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalaudioenergy
|
||||
double total_output_energy;
|
||||
// See description of "totalSamplesReceived" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalsamplesreceived
|
||||
uint64_t total_samples_received;
|
||||
// See description of "totalSamplesDuration" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalsamplesduration
|
||||
double total_output_duration;
|
||||
// See description of "concealedSamples" in the WebRTC stats spec:
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-concealedsamples
|
||||
uint64_t concealed_samples;
|
||||
// fraction of synthesized audio inserted through expansion.
|
||||
float expand_rate;
|
||||
// fraction of synthesized speech inserted through expansion.
|
||||
|
||||
@ -2282,7 +2282,9 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
|
||||
rinfo.delay_estimate_ms = stats.delay_estimate_ms;
|
||||
rinfo.audio_level = stats.audio_level;
|
||||
rinfo.total_output_energy = stats.total_output_energy;
|
||||
rinfo.total_samples_received = stats.total_samples_received;
|
||||
rinfo.total_output_duration = stats.total_output_duration;
|
||||
rinfo.concealed_samples = stats.concealed_samples;
|
||||
rinfo.expand_rate = stats.expand_rate;
|
||||
rinfo.speech_expand_rate = stats.speech_expand_rate;
|
||||
rinfo.secondary_decoded_rate = stats.secondary_decoded_rate;
|
||||
|
||||
@ -596,6 +596,8 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
||||
stats.jitter_buffer_preferred_ms = 567;
|
||||
stats.delay_estimate_ms = 890;
|
||||
stats.audio_level = 1234;
|
||||
stats.total_samples_received = 5678901;
|
||||
stats.concealed_samples = 234;
|
||||
stats.expand_rate = 5.67f;
|
||||
stats.speech_expand_rate = 8.90f;
|
||||
stats.secondary_decoded_rate = 1.23f;
|
||||
@ -632,6 +634,8 @@ class WebRtcVoiceEngineTestFake : public testing::Test {
|
||||
stats.jitter_buffer_preferred_ms);
|
||||
EXPECT_EQ(info.delay_estimate_ms, stats.delay_estimate_ms);
|
||||
EXPECT_EQ(info.audio_level, stats.audio_level);
|
||||
EXPECT_EQ(info.total_samples_received, stats.total_samples_received);
|
||||
EXPECT_EQ(info.concealed_samples, stats.concealed_samples);
|
||||
EXPECT_EQ(info.expand_rate, stats.expand_rate);
|
||||
EXPECT_EQ(info.speech_expand_rate, stats.speech_expand_rate);
|
||||
EXPECT_EQ(info.secondary_decoded_rate, stats.secondary_decoded_rate);
|
||||
|
||||
@ -332,6 +332,10 @@ void AcmReceiver::GetNetworkStatistics(NetworkStatistics* acm_stat) {
|
||||
acm_stat->medianWaitingTimeMs = neteq_stat.median_waiting_time_ms;
|
||||
acm_stat->minWaitingTimeMs = neteq_stat.min_waiting_time_ms;
|
||||
acm_stat->maxWaitingTimeMs = neteq_stat.max_waiting_time_ms;
|
||||
|
||||
NetEqLifetimeStatistics neteq_lifetime_stat = neteq_->GetLifetimeStatistics();
|
||||
acm_stat->totalSamplesReceived = neteq_lifetime_stat.total_samples_received;
|
||||
acm_stat->concealedSamples = neteq_lifetime_stat.concealed_samples;
|
||||
}
|
||||
|
||||
int AcmReceiver::DecoderByPayloadType(uint8_t payload_type,
|
||||
|
||||
@ -58,6 +58,18 @@ struct NetEqNetworkStatistics {
|
||||
int max_waiting_time_ms;
|
||||
};
|
||||
|
||||
// NetEq statistics that persist over the lifetime of the class.
|
||||
// These metrics are never reset.
|
||||
struct NetEqLifetimeStatistics {
|
||||
// Total number of audio samples received, including synthesized samples.
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-totalsamplesreceived
|
||||
uint64_t total_samples_received = 0;
|
||||
// Total number of inbound audio samples that are based on synthesized data to
|
||||
// conceal packet loss.
|
||||
// https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamtrackstats-concealedsamples
|
||||
uint64_t concealed_samples = 0;
|
||||
};
|
||||
|
||||
enum NetEqPlayoutMode {
|
||||
kPlayoutOn,
|
||||
kPlayoutOff,
|
||||
@ -220,6 +232,10 @@ class NetEq {
|
||||
// after the call.
|
||||
virtual int NetworkStatistics(NetEqNetworkStatistics* stats) = 0;
|
||||
|
||||
// Returns a copy of this class's lifetime statistics. These statistics are
|
||||
// never reset.
|
||||
virtual NetEqLifetimeStatistics GetLifetimeStatistics() const = 0;
|
||||
|
||||
// Writes the current RTCP statistics to |stats|. The statistics are reset
|
||||
// and a new report period is started with the call.
|
||||
virtual void GetRtcpStatistics(RtcpStatistics* stats) = 0;
|
||||
|
||||
@ -380,6 +380,11 @@ int NetEqImpl::NetworkStatistics(NetEqNetworkStatistics* stats) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetEqLifetimeStatistics NetEqImpl::GetLifetimeStatistics() const {
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
return stats_.GetLifetimeStatistics();
|
||||
}
|
||||
|
||||
void NetEqImpl::GetRtcpStatistics(RtcpStatistics* stats) {
|
||||
rtc::CritScope lock(&crit_sect_);
|
||||
if (stats) {
|
||||
|
||||
@ -185,6 +185,8 @@ class NetEqImpl : public webrtc::NetEq {
|
||||
// and a new report period is started with the call.
|
||||
void GetRtcpStatistics(RtcpStatistics* stats) override;
|
||||
|
||||
NetEqLifetimeStatistics GetLifetimeStatistics() const override;
|
||||
|
||||
// Same as RtcpStatistics(), but does not reset anything.
|
||||
void GetRtcpStatisticsNoReset(RtcpStatistics* stats) override;
|
||||
|
||||
|
||||
@ -153,24 +153,29 @@ void StatisticsCalculator::ResetMcu() {
|
||||
|
||||
void StatisticsCalculator::ExpandedVoiceSamples(size_t num_samples) {
|
||||
expanded_speech_samples_ += num_samples;
|
||||
lifetime_stats_.concealed_samples += num_samples;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::ExpandedNoiseSamples(size_t num_samples) {
|
||||
expanded_noise_samples_ += num_samples;
|
||||
lifetime_stats_.concealed_samples += num_samples;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::ExpandedVoiceSamplesCorrection(int num_samples) {
|
||||
expanded_speech_samples_ =
|
||||
AddIntToSizeTWithLowerCap(num_samples, expanded_speech_samples_);
|
||||
lifetime_stats_.concealed_samples += num_samples;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::ExpandedNoiseSamplesCorrection(int num_samples) {
|
||||
expanded_noise_samples_ =
|
||||
AddIntToSizeTWithLowerCap(num_samples, expanded_noise_samples_);
|
||||
lifetime_stats_.concealed_samples += num_samples;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::PreemptiveExpandedSamples(size_t num_samples) {
|
||||
preemptive_samples_ += num_samples;
|
||||
lifetime_stats_.concealed_samples += num_samples;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::AcceleratedSamples(size_t num_samples) {
|
||||
@ -205,6 +210,7 @@ void StatisticsCalculator::IncreaseCounter(size_t num_samples, int fs_hz) {
|
||||
timestamps_since_last_report_ = 0;
|
||||
discarded_packets_ = 0;
|
||||
}
|
||||
lifetime_stats_.total_samples_received += num_samples;
|
||||
}
|
||||
|
||||
void StatisticsCalculator::SecondaryDecodedSamples(int num_samples) {
|
||||
@ -307,6 +313,10 @@ void StatisticsCalculator::GetNetworkStatistics(
|
||||
Reset();
|
||||
}
|
||||
|
||||
NetEqLifetimeStatistics StatisticsCalculator::GetLifetimeStatistics() const {
|
||||
return lifetime_stats_;
|
||||
}
|
||||
|
||||
uint16_t StatisticsCalculator::CalculateQ14Ratio(size_t numerator,
|
||||
uint32_t denominator) {
|
||||
if (numerator == 0) {
|
||||
|
||||
@ -99,6 +99,10 @@ class StatisticsCalculator {
|
||||
const DecisionLogic& decision_logic,
|
||||
NetEqNetworkStatistics *stats);
|
||||
|
||||
// Returns a copy of this class's lifetime statistics. These statistics are
|
||||
// never reset.
|
||||
NetEqLifetimeStatistics GetLifetimeStatistics() const;
|
||||
|
||||
private:
|
||||
static const int kMaxReportPeriod = 60; // Seconds before auto-reset.
|
||||
static const size_t kLenWaitingTimes = 100;
|
||||
@ -158,6 +162,8 @@ class StatisticsCalculator {
|
||||
// Calculates numerator / denominator, and returns the value in Q14.
|
||||
static uint16_t CalculateQ14Ratio(size_t numerator, uint32_t denominator);
|
||||
|
||||
// TODO(steveanton): Add unit tests for the lifetime stats.
|
||||
NetEqLifetimeStatistics lifetime_stats_;
|
||||
size_t preemptive_samples_;
|
||||
size_t accelerate_samples_;
|
||||
size_t added_zero_samples_;
|
||||
|
||||
@ -525,6 +525,18 @@ class RTCStatsReportVerifier {
|
||||
verifier.MarkMemberTested(
|
||||
media_stream_track.echo_return_loss_enhancement, true);
|
||||
}
|
||||
// totalSamplesReceived and concealedSamples are only present on inbound
|
||||
// audio tracks.
|
||||
if (*media_stream_track.kind == RTCMediaStreamTrackKind::kAudio &&
|
||||
*media_stream_track.remote_source) {
|
||||
verifier.TestMemberIsNonNegative<uint64_t>(
|
||||
media_stream_track.total_samples_received);
|
||||
verifier.TestMemberIsNonNegative<uint64_t>(
|
||||
media_stream_track.concealed_samples);
|
||||
} else {
|
||||
verifier.TestMemberIsUndefined(media_stream_track.total_samples_received);
|
||||
verifier.TestMemberIsUndefined(media_stream_track.concealed_samples);
|
||||
}
|
||||
return verifier.ExpectAllMembersSuccessfullyTested();
|
||||
}
|
||||
|
||||
|
||||
@ -424,8 +424,11 @@ ProduceMediaStreamTrackStatsFromVoiceReceiverInfo(
|
||||
}
|
||||
audio_track_stats->total_audio_energy =
|
||||
voice_receiver_info.total_output_energy;
|
||||
audio_track_stats->total_samples_received =
|
||||
voice_receiver_info.total_samples_received;
|
||||
audio_track_stats->total_samples_duration =
|
||||
voice_receiver_info.total_output_duration;
|
||||
audio_track_stats->concealed_samples = voice_receiver_info.concealed_samples;
|
||||
return audio_track_stats;
|
||||
}
|
||||
|
||||
|
||||
@ -1554,7 +1554,9 @@ TEST_F(RTCStatsCollectorTest,
|
||||
voice_receiver_info.local_stats[0].ssrc = 3;
|
||||
voice_receiver_info.audio_level = 16383;
|
||||
voice_receiver_info.total_output_energy = 0.125;
|
||||
voice_receiver_info.total_samples_received = 4567;
|
||||
voice_receiver_info.total_output_duration = 0.25;
|
||||
voice_receiver_info.concealed_samples = 123;
|
||||
|
||||
test_->CreateMockRtpSendersReceiversAndChannels(
|
||||
{ std::make_pair(local_audio_track.get(), voice_sender_info_ssrc1),
|
||||
@ -1628,7 +1630,9 @@ TEST_F(RTCStatsCollectorTest,
|
||||
expected_remote_audio_track.detached = false;
|
||||
expected_remote_audio_track.audio_level = 16383.0 / 32767.0;
|
||||
expected_remote_audio_track.total_audio_energy = 0.125;
|
||||
expected_remote_audio_track.total_samples_received = 4567;
|
||||
expected_remote_audio_track.total_samples_duration = 0.25;
|
||||
expected_remote_audio_track.concealed_samples = 123;
|
||||
ASSERT_TRUE(report->Get(expected_remote_audio_track.id()));
|
||||
EXPECT_EQ(expected_remote_audio_track,
|
||||
report->Get(expected_remote_audio_track.id())->cast_to<
|
||||
|
||||
@ -379,9 +379,11 @@ WEBRTC_RTCSTATS_IMPL(RTCMediaStreamTrackStats, RTCStats, "track",
|
||||
&full_frames_lost,
|
||||
&audio_level,
|
||||
&total_audio_energy,
|
||||
&total_samples_duration,
|
||||
&echo_return_loss,
|
||||
&echo_return_loss_enhancement);
|
||||
&echo_return_loss_enhancement,
|
||||
&total_samples_received,
|
||||
&total_samples_duration,
|
||||
&concealed_samples);
|
||||
// clang-format on
|
||||
|
||||
RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(
|
||||
@ -410,9 +412,11 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(std::string&& id,
|
||||
full_frames_lost("fullFramesLost"),
|
||||
audio_level("audioLevel"),
|
||||
total_audio_energy("totalAudioEnergy"),
|
||||
total_samples_duration("totalSamplesDuration"),
|
||||
echo_return_loss("echoReturnLoss"),
|
||||
echo_return_loss_enhancement("echoReturnLossEnhancement") {
|
||||
echo_return_loss_enhancement("echoReturnLossEnhancement"),
|
||||
total_samples_received("totalSamplesReceived"),
|
||||
total_samples_duration("totalSamplesDuration"),
|
||||
concealed_samples("concealedSamples") {
|
||||
RTC_DCHECK(kind == RTCMediaStreamTrackKind::kAudio ||
|
||||
kind == RTCMediaStreamTrackKind::kVideo);
|
||||
}
|
||||
@ -437,9 +441,11 @@ RTCMediaStreamTrackStats::RTCMediaStreamTrackStats(
|
||||
full_frames_lost(other.full_frames_lost),
|
||||
audio_level(other.audio_level),
|
||||
total_audio_energy(other.total_audio_energy),
|
||||
total_samples_duration(other.total_samples_duration),
|
||||
echo_return_loss(other.echo_return_loss),
|
||||
echo_return_loss_enhancement(other.echo_return_loss_enhancement) {}
|
||||
echo_return_loss_enhancement(other.echo_return_loss_enhancement),
|
||||
total_samples_received(other.total_samples_received),
|
||||
total_samples_duration(other.total_samples_duration),
|
||||
concealed_samples(other.concealed_samples) {}
|
||||
|
||||
RTCMediaStreamTrackStats::~RTCMediaStreamTrackStats() {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user