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}
diff --git a/api/voip/BUILD.gn b/api/voip/BUILD.gn
index 369a82f..a62dd14 100644
--- a/api/voip/BUILD.gn
+++ b/api/voip/BUILD.gn
@@ -16,10 +16,12 @@
"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" ]
}
diff --git a/api/voip/voip_engine.h b/api/voip/voip_engine.h
index bff261f..5724b6b 100644
--- a/api/voip/voip_engine.h
+++ b/api/voip/voip_engine.h
@@ -17,6 +17,7 @@
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 @@
// 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
diff --git a/api/voip/voip_statistics.h b/api/voip/voip_statistics.h
new file mode 100644
index 0000000..5f4e174
--- /dev/null
+++ b/api/voip/voip_statistics.h
@@ -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_
diff --git a/audio/voip/audio_channel.cc b/audio/voip/audio_channel.cc
index 43d4d0f..28bd270 100644
--- a/audio/voip/audio_channel.cc
+++ b/audio/voip/audio_channel.cc
@@ -129,4 +129,29 @@
}
}
+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
diff --git a/audio/voip/audio_channel.h b/audio/voip/audio_channel.h
index 04fbfe3..9d0e707 100644
--- a/audio/voip/audio_channel.h
+++ b/audio/voip/audio_channel.h
@@ -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 @@
void SetReceiveCodecs(const std::map<int, SdpAudioFormat>& codecs) {
ingress_->SetReceiveCodecs(codecs);
}
+ NetEqLifetimeStatistics GetNetEqStatistics();
private:
// ChannelId that this audio channel belongs for logging purpose.
diff --git a/audio/voip/audio_ingress.h b/audio/voip/audio_ingress.h
index d09de60..beff6cd 100644
--- a/audio/voip/audio_ingress.h
+++ b/audio/voip/audio_ingress.h
@@ -82,12 +82,8 @@
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;
}
diff --git a/audio/voip/test/audio_channel_unittest.cc b/audio/voip/test/audio_channel_unittest.cc
index ce55782..601545b 100644
--- a/audio/voip/test/audio_channel_unittest.cc
+++ b/audio/voip/test/audio_channel_unittest.cc
@@ -139,5 +139,36 @@
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
diff --git a/audio/voip/voip_core.cc b/audio/voip/voip_core.cc
index 2d752ac..2c066e1 100644
--- a/audio/voip/voip_core.cc
+++ b/audio/voip/voip_core.cc
@@ -382,4 +382,12 @@
return false;
}
+absl::optional<NetEqLifetimeStatistics> VoipCore::GetNetEqStatistics(
+ ChannelId channel) {
+ if (auto audio_channel = GetChannel(channel)) {
+ return audio_channel->GetNetEqStatistics();
+ }
+ return absl::nullopt;
+}
+
} // namespace webrtc
diff --git a/audio/voip/voip_core.h b/audio/voip/voip_core.h
index 11ac616..1993fbe 100644
--- a/audio/voip/voip_core.h
+++ b/audio/voip/voip_core.h
@@ -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 @@
public VoipBase,
public VoipNetwork,
public VoipCodec,
- public VoipDtmf {
+ public VoipDtmf,
+ public VoipStatistics {
public:
~VoipCore() override = default;
@@ -70,6 +72,7 @@
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 @@
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.