VoipStatistics subAPI and implementation.

- Adding an interface that fetches lifetime NetEq statistics struct.

Bug: webrtc:11989
Change-Id: I871455bccdd53a33dd260f744e03ec81d29fbfd8
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/190200
Commit-Queue: Tim Na <natim@webrtc.org>
Reviewed-by: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Mirko Bonadei <mbonadei@webrtc.org>
Reviewed-by: Ivo Creusen <ivoc@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32516}
This commit is contained in:
Tim Na 2020-10-28 13:51:24 -07:00 committed by Commit Bot
parent e9bb49a09c
commit f4347f7bac
9 changed files with 117 additions and 7 deletions

View File

@ -16,10 +16,12 @@ rtc_source_set("voip_api") {
"voip_dtmf.h",
"voip_engine.h",
"voip_network.h",
"voip_statistics.h",
]
deps = [
"..:array_view",
"../audio_codecs:audio_codecs_api",
"../neteq:neteq_api",
]
absl_deps = [ "//third_party/abseil-cpp/absl/types:optional" ]
}

View File

@ -17,6 +17,7 @@ class VoipBase;
class VoipCodec;
class VoipNetwork;
class VoipDtmf;
class VoipStatistics;
// VoipEngine is the main interface serving as the entry point for all VoIP
// APIs. A single instance of VoipEngine should suffice the most of the need for
@ -84,6 +85,10 @@ class VoipEngine {
// VoipDtmf provides DTMF event APIs to register and send DTMF events.
virtual VoipDtmf& Dtmf() = 0;
// VoipStatistics provides performance metrics around audio decoding module
// and jitter buffer (NetEq).
virtual VoipStatistics& Statistics() = 0;
};
} // namespace webrtc

View File

@ -0,0 +1,34 @@
/*
* Copyright (c) 2020 The WebRTC project authors. All Rights Reserved.
*
* 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.
*/
#ifndef API_VOIP_VOIP_STATISTICS_H_
#define API_VOIP_VOIP_STATISTICS_H_
#include "api/neteq/neteq.h"
#include "api/voip/voip_base.h"
namespace webrtc {
// VoipStatistics interface provides the interfaces for querying metrics around
// the jitter buffer (NetEq) performance.
class VoipStatistics {
public:
// Gets the statistics from NetEq. Returns absl::nullopt when channel_id is
// invalid.
virtual absl::optional<NetEqLifetimeStatistics> GetNetEqStatistics(
ChannelId channel_id) = 0;
protected:
virtual ~VoipStatistics() = default;
};
} // namespace webrtc
#endif // API_VOIP_VOIP_STATISTICS_H_

View File

@ -129,4 +129,29 @@ void AudioChannel::StopPlay() {
}
}
NetEqLifetimeStatistics AudioChannel::GetNetEqStatistics() {
NetEqLifetimeStatistics neteq_stats;
NetworkStatistics stats = ingress_->GetNetworkStatistics();
neteq_stats.total_samples_received = stats.totalSamplesReceived;
neteq_stats.concealed_samples = stats.concealedSamples;
neteq_stats.concealment_events = stats.concealmentEvents;
neteq_stats.jitter_buffer_delay_ms = stats.jitterBufferDelayMs;
neteq_stats.jitter_buffer_emitted_count = stats.jitterBufferEmittedCount;
neteq_stats.jitter_buffer_target_delay_ms = stats.jitterBufferTargetDelayMs;
neteq_stats.inserted_samples_for_deceleration =
stats.insertedSamplesForDeceleration;
neteq_stats.removed_samples_for_acceleration =
stats.removedSamplesForAcceleration;
neteq_stats.silent_concealed_samples = stats.silentConcealedSamples;
neteq_stats.fec_packets_received = stats.fecPacketsReceived;
neteq_stats.fec_packets_discarded = stats.fecPacketsDiscarded;
neteq_stats.delayed_packet_outage_samples = stats.delayedPacketOutageSamples;
neteq_stats.relative_packet_arrival_delay_ms =
stats.relativePacketArrivalDelayMs;
neteq_stats.interruption_count = stats.interruptionCount;
neteq_stats.total_interruption_duration_ms =
stats.totalInterruptionDurationMs;
return neteq_stats;
}
} // namespace webrtc

View File

@ -18,6 +18,7 @@
#include "api/task_queue/task_queue_factory.h"
#include "api/voip/voip_base.h"
#include "api/voip/voip_statistics.h"
#include "audio/voip/audio_egress.h"
#include "audio/voip/audio_ingress.h"
#include "modules/rtp_rtcp/source/rtp_rtcp_impl2.h"
@ -81,6 +82,7 @@ class AudioChannel : public rtc::RefCountInterface {
void SetReceiveCodecs(const std::map<int, SdpAudioFormat>& codecs) {
ingress_->SetReceiveCodecs(codecs);
}
NetEqLifetimeStatistics GetNetEqStatistics();
private:
// ChannelId that this audio channel belongs for logging purpose.

View File

@ -82,12 +82,8 @@ class AudioIngress : public AudioMixer::Source {
NetworkStatistics GetNetworkStatistics() const {
NetworkStatistics stats;
acm_receiver_.GetNetworkStatistics(&stats);
return stats;
}
AudioDecodingCallStats GetDecodingStatistics() const {
AudioDecodingCallStats stats;
acm_receiver_.GetDecodingCallStatistics(&stats);
acm_receiver_.GetNetworkStatistics(&stats,
/*get_and_clear_legacy_stats=*/false);
return stats;
}

View File

@ -139,5 +139,36 @@ TEST_F(AudioChannelTest, VerifyLocalSsrcAsAssigned) {
EXPECT_EQ(rtp.Ssrc(), kLocalSsrc);
}
// Check metrics after processing an RTP packet.
TEST_F(AudioChannelTest, TestAudioStatistics) {
rtc::Event event;
auto loop_rtp = [&](const uint8_t* packet, size_t length, Unused) {
audio_channel_->ReceivedRTPPacket(
rtc::ArrayView<const uint8_t>(packet, length));
event.Set();
return true;
};
EXPECT_CALL(transport_, SendRtp).WillOnce(Invoke(loop_rtp));
auto audio_sender = audio_channel_->GetAudioSender();
audio_sender->SendAudioData(GetAudioFrame(0));
audio_sender->SendAudioData(GetAudioFrame(1));
event.Wait(/*give_up_after_ms=*/1000);
AudioFrame audio_frame;
audio_mixer_->Mix(/*number_of_channels=*/1, &audio_frame);
// Check a few fields as we wouldn't have enough samples verify most of them
// here.
absl::optional<NetEqLifetimeStatistics> neteq_stats =
audio_channel_->GetNetEqStatistics();
EXPECT_TRUE(neteq_stats);
EXPECT_EQ(neteq_stats->total_samples_received, 80ULL);
EXPECT_EQ(neteq_stats->concealed_samples, 0ULL);
EXPECT_EQ(neteq_stats->jitter_buffer_delay_ms, 1600ULL);
EXPECT_EQ(neteq_stats->interruption_count, 0);
}
} // namespace
} // namespace webrtc

View File

@ -382,4 +382,12 @@ bool VoipCore::SendDtmfEvent(ChannelId channel,
return false;
}
absl::optional<NetEqLifetimeStatistics> VoipCore::GetNetEqStatistics(
ChannelId channel) {
if (auto audio_channel = GetChannel(channel)) {
return audio_channel->GetNetEqStatistics();
}
return absl::nullopt;
}
} // namespace webrtc

View File

@ -26,6 +26,7 @@
#include "api/voip/voip_dtmf.h"
#include "api/voip/voip_engine.h"
#include "api/voip/voip_network.h"
#include "api/voip/voip_statistics.h"
#include "audio/audio_transport_impl.h"
#include "audio/voip/audio_channel.h"
#include "modules/audio_device/include/audio_device.h"
@ -47,7 +48,8 @@ class VoipCore : public VoipEngine,
public VoipBase,
public VoipNetwork,
public VoipCodec,
public VoipDtmf {
public VoipDtmf,
public VoipStatistics {
public:
~VoipCore() override = default;
@ -70,6 +72,7 @@ class VoipCore : public VoipEngine,
VoipNetwork& Network() override { return *this; }
VoipCodec& Codec() override { return *this; }
VoipDtmf& Dtmf() override { return *this; }
VoipStatistics& Statistics() override { return *this; }
// Implements VoipBase interfaces.
absl::optional<ChannelId> CreateChannel(
@ -103,6 +106,10 @@ class VoipCore : public VoipEngine,
DtmfEvent dtmf_event,
int duration_ms) override;
// Implements VoipStatistics interfaces.
absl::optional<NetEqLifetimeStatistics> GetNetEqStatistics(
ChannelId channel) override;
private:
// Fetches the corresponding AudioChannel assigned with given |channel|.
// Returns nullptr if not found.