Reporting audio device underrun counter

Bug: webrtc:10884
Change-Id: I35636fcbc1e2a19a89242379cdff6ec5c12fd21a
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/149200
Reviewed-by: Henrik Andreassson <henrika@webrtc.org>
Commit-Queue: Alex Narest <alexnarest@google.com>
Cr-Commit-Position: refs/heads/master@{#28874}
This commit is contained in:
Alex Narest
2019-08-16 11:49:04 +02:00
committed by Commit Bot
parent 9b29d69650
commit bbeb10925e
24 changed files with 96 additions and 0 deletions

View File

@ -653,6 +653,8 @@ const char* StatsReport::Value::display_name() const {
return "googTypingNoiseState"; return "googTypingNoiseState";
case kStatsValueNameWritable: case kStatsValueNameWritable:
return "googWritable"; return "googWritable";
case kStatsValueNameAudioDeviceUnderrunCounter:
return "googAudioDeviceUnderrunCounter";
} }
return nullptr; return nullptr;

View File

@ -238,6 +238,7 @@ class StatsReport {
kStatsValueNameTransportType, kStatsValueNameTransportType,
kStatsValueNameTypingNoiseState, kStatsValueNameTypingNoiseState,
kStatsValueNameWritable, kStatsValueNameWritable,
kStatsValueNameAudioDeviceUnderrunCounter,
}; };
class IdBase : public rtc::RefCountInterface { class IdBase : public rtc::RefCountInterface {

View File

@ -687,6 +687,7 @@ struct VoiceMediaInfo {
std::vector<VoiceReceiverInfo> receivers; std::vector<VoiceReceiverInfo> receivers;
RtpCodecParametersMap send_codecs; RtpCodecParametersMap send_codecs;
RtpCodecParametersMap receive_codecs; RtpCodecParametersMap receive_codecs;
int32_t device_underrun_count = 0;
}; };
struct VideoMediaInfo { struct VideoMediaInfo {

View File

@ -2267,6 +2267,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
info->receive_codecs.insert( info->receive_codecs.insert(
std::make_pair(codec_params.payload_type, std::move(codec_params))); std::make_pair(codec_params.payload_type, std::move(codec_params)));
} }
info->device_underrun_count = engine_->adm()->GetPlayoutUnderrunCount();
return true; return true;
} }

View File

@ -2243,6 +2243,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
// Check stats for the added streams. // Check stats for the added streams.
{ {
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
cricket::VoiceMediaInfo info; cricket::VoiceMediaInfo info;
EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(true, channel_->GetStats(&info));
@ -2262,6 +2263,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
{ {
cricket::VoiceMediaInfo info; cricket::VoiceMediaInfo info;
EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcY)); EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcY));
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(true, channel_->GetStats(&info));
EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size()); EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size());
EXPECT_EQ(0u, info.receivers.size()); EXPECT_EQ(0u, info.receivers.size());
@ -2273,6 +2275,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
cricket::VoiceMediaInfo info; cricket::VoiceMediaInfo info;
DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame)); DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
SetAudioReceiveStreamStats(); SetAudioReceiveStreamStats();
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(true, channel_->GetStats(&info));
EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size()); EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size());
EXPECT_EQ(1u, info.receivers.size()); EXPECT_EQ(1u, info.receivers.size());
@ -2431,6 +2434,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
// Check stats for the added streams. // Check stats for the added streams.
{ {
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
cricket::VoiceMediaInfo info; cricket::VoiceMediaInfo info;
EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(true, channel_->GetStats(&info));
@ -2446,6 +2450,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
{ {
cricket::VoiceMediaInfo info; cricket::VoiceMediaInfo info;
SetSend(true); SetSend(true);
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(true, channel_->GetStats(&info));
VerifyVoiceSenderInfo(info.senders[0], true); VerifyVoiceSenderInfo(info.senders[0], true);
VerifyVoiceSendRecvCodecs(info); VerifyVoiceSendRecvCodecs(info);
@ -2455,6 +2460,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
{ {
cricket::VoiceMediaInfo info; cricket::VoiceMediaInfo info;
EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcY)); EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcY));
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(true, channel_->GetStats(&info));
EXPECT_EQ(1u, info.senders.size()); EXPECT_EQ(1u, info.senders.size());
EXPECT_EQ(0u, info.receivers.size()); EXPECT_EQ(0u, info.receivers.size());
@ -2466,6 +2472,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
cricket::VoiceMediaInfo info; cricket::VoiceMediaInfo info;
DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame)); DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
SetAudioReceiveStreamStats(); SetAudioReceiveStreamStats();
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
EXPECT_EQ(true, channel_->GetStats(&info)); EXPECT_EQ(true, channel_->GetStats(&info));
EXPECT_EQ(1u, info.senders.size()); EXPECT_EQ(1u, info.senders.size());
EXPECT_EQ(1u, info.receivers.size()); EXPECT_EQ(1u, info.receivers.size());

View File

@ -261,6 +261,9 @@ class ADMWrapper : public AudioDeviceModule, public AudioTransport {
int32_t EnableBuiltInNS(bool enable) override { int32_t EnableBuiltInNS(bool enable) override {
return impl_->EnableBuiltInNS(enable); return impl_->EnableBuiltInNS(enable);
} }
int32_t GetPlayoutUnderrunCount() const override {
return impl_->GetPlayoutUnderrunCount();
}
// Only supported on iOS. // Only supported on iOS.
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int GetPlayoutAudioParameters(AudioParameters* params) const override { int GetPlayoutAudioParameters(AudioParameters* params) const override {

View File

@ -44,6 +44,11 @@ int32_t AudioDeviceGeneric::EnableBuiltInNS(bool enable) {
return -1; return -1;
} }
int32_t AudioDeviceGeneric::GetPlayoutUnderrunCount() const {
RTC_LOG_F(LS_ERROR) << "Not supported on this platform";
return -1;
}
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int AudioDeviceGeneric::GetPlayoutAudioParameters( int AudioDeviceGeneric::GetPlayoutAudioParameters(
AudioParameters* params) const { AudioParameters* params) const {

View File

@ -125,6 +125,9 @@ class AudioDeviceGeneric {
virtual int32_t EnableBuiltInAGC(bool enable); virtual int32_t EnableBuiltInAGC(bool enable);
virtual int32_t EnableBuiltInNS(bool enable); virtual int32_t EnableBuiltInNS(bool enable);
// Play underrun count.
virtual int32_t GetPlayoutUnderrunCount() const;
// iOS only. // iOS only.
// TODO(henrika): add Android support. // TODO(henrika): add Android support.
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)

View File

@ -910,6 +910,14 @@ int32_t AudioDeviceModuleImpl::EnableBuiltInNS(bool enable) {
return ok; return ok;
} }
int32_t AudioDeviceModuleImpl::GetPlayoutUnderrunCount() const {
RTC_LOG(INFO) << __FUNCTION__;
CHECKinitialized_();
int32_t underrunCount = audio_device_->GetPlayoutUnderrunCount();
RTC_LOG(INFO) << "output: " << underrunCount;
return underrunCount;
}
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int AudioDeviceModuleImpl::GetPlayoutAudioParameters( int AudioDeviceModuleImpl::GetPlayoutAudioParameters(
AudioParameters* params) const { AudioParameters* params) const {

View File

@ -137,6 +137,9 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
bool BuiltInNSIsAvailable() const override; bool BuiltInNSIsAvailable() const override;
int32_t EnableBuiltInNS(bool enable) override; int32_t EnableBuiltInNS(bool enable) override;
// Play underrun count.
int32_t GetPlayoutUnderrunCount() const override;
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int GetPlayoutAudioParameters(AudioParameters* params) const override; int GetPlayoutAudioParameters(AudioParameters* params) const override;
int GetRecordAudioParameters(AudioParameters* params) const override; int GetRecordAudioParameters(AudioParameters* params) const override;

View File

@ -146,6 +146,10 @@ class AudioDeviceModule : public rtc::RefCountInterface {
virtual int32_t EnableBuiltInAGC(bool enable) = 0; virtual int32_t EnableBuiltInAGC(bool enable) = 0;
virtual int32_t EnableBuiltInNS(bool enable) = 0; virtual int32_t EnableBuiltInNS(bool enable) = 0;
// Play underrun count. Only supported on Android.
// TODO(alexnarest): Make it abstract after upstream projects support it.
virtual int32_t GetPlayoutUnderrunCount() const { return -1; }
// Only supported on iOS. // Only supported on iOS.
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
virtual int GetPlayoutAudioParameters(AudioParameters* params) const = 0; virtual int GetPlayoutAudioParameters(AudioParameters* params) const = 0;

View File

@ -114,6 +114,8 @@ class AudioDeviceModuleDefault : public T {
bool BuiltInNSIsAvailable() const override { return false; } bool BuiltInNSIsAvailable() const override { return false; }
int32_t EnableBuiltInNS(bool enable) override { return -1; } int32_t EnableBuiltInNS(bool enable) override { return -1; }
int32_t GetPlayoutUnderrunCount() const override { return -1; }
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int GetPlayoutAudioParameters(AudioParameters* params) const override { int GetPlayoutAudioParameters(AudioParameters* params) const override {
return -1; return -1;

View File

@ -91,6 +91,7 @@ class MockAudioDeviceModule : public AudioDeviceModule {
MOCK_METHOD1(EnableBuiltInAEC, int32_t(bool enable)); MOCK_METHOD1(EnableBuiltInAEC, int32_t(bool enable));
MOCK_METHOD1(EnableBuiltInAGC, int32_t(bool enable)); MOCK_METHOD1(EnableBuiltInAGC, int32_t(bool enable));
MOCK_METHOD1(EnableBuiltInNS, int32_t(bool enable)); MOCK_METHOD1(EnableBuiltInNS, int32_t(bool enable));
MOCK_CONST_METHOD0(GetPlayoutUnderrunCount, int32_t());
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
MOCK_CONST_METHOD1(GetPlayoutAudioParameters, int(AudioParameters* params)); MOCK_CONST_METHOD1(GetPlayoutAudioParameters, int(AudioParameters* params));
MOCK_CONST_METHOD1(GetRecordAudioParameters, int(AudioParameters* params)); MOCK_CONST_METHOD1(GetRecordAudioParameters, int(AudioParameters* params));

View File

@ -636,6 +636,14 @@ StatsReport* StatsCollector::PrepareReport(bool local,
return report; return report;
} }
StatsReport* StatsCollector::PrepareADMReport() {
RTC_DCHECK(pc_->signaling_thread()->IsCurrent());
StatsReport::Id id(StatsReport::NewTypedId(
StatsReport::kStatsReportTypeSession, pc_->session_id()));
StatsReport* report = reports_.FindOrAddNew(id);
return report;
}
bool StatsCollector::IsValidTrack(const std::string& track_id) { bool StatsCollector::IsValidTrack(const std::string& track_id) {
return reports_.Find(StatsReport::NewTypedId( return reports_.Find(StatsReport::NewTypedId(
StatsReport::kStatsReportTypeTrack, track_id)) != nullptr; StatsReport::kStatsReportTypeTrack, track_id)) != nullptr;
@ -956,6 +964,12 @@ class VoiceMediaChannelStatsGatherer final : public MediaChannelStatsGatherer {
void ExtractStats(StatsCollector* collector) const override { void ExtractStats(StatsCollector* collector) const override {
ExtractSenderReceiverStats(collector, voice_media_info.receivers, ExtractSenderReceiverStats(collector, voice_media_info.receivers,
voice_media_info.senders); voice_media_info.senders);
if (voice_media_info.device_underrun_count == -2 ||
voice_media_info.device_underrun_count > 0) {
StatsReport* report = collector->PrepareADMReport();
report->AddInt(StatsReport::kStatsValueNameAudioDeviceUnderrunCounter,
voice_media_info.device_underrun_count);
}
} }
bool HasRemoteAudio() const override { bool HasRemoteAudio() const override {

View File

@ -84,6 +84,8 @@ class StatsCollector {
const StatsReport::Id& transport_id, const StatsReport::Id& transport_id,
StatsReport::Direction direction); StatsReport::Direction direction);
StatsReport* PrepareADMReport();
// A track is invalid if there is no report data for it. // A track is invalid if there is no report data for it.
bool IsValidTrack(const std::string& track_id); bool IsValidTrack(const std::string& track_id);

View File

@ -128,6 +128,8 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule,
int32_t EnableBuiltInAGC(bool enable) override { return -1; } int32_t EnableBuiltInAGC(bool enable) override { return -1; }
bool BuiltInNSIsAvailable() const override { return false; } bool BuiltInNSIsAvailable() const override { return false; }
int32_t EnableBuiltInNS(bool enable) override { return -1; } int32_t EnableBuiltInNS(bool enable) override { return -1; }
int32_t GetPlayoutUnderrunCount() const override { return -1; }
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int GetPlayoutAudioParameters( int GetPlayoutAudioParameters(
webrtc::AudioParameters* params) const override { webrtc::AudioParameters* params) const override {

View File

@ -342,6 +342,19 @@ class WebRtcAudioTrack {
return audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL); return audioManager.getStreamVolume(AudioManager.STREAM_VOICE_CALL);
} }
@CalledByNative
private int GetPlayoutUnderrunCount() {
if (Build.VERSION.SDK_INT >= 24) {
if (audioTrack != null) {
return audioTrack.getUnderrunCount();
} else {
return -1;
}
} else {
return -2;
}
}
private void logMainParameters() { private void logMainParameters() {
Logging.d(TAG, Logging.d(TAG,
"AudioTrack: " "AudioTrack: "

View File

@ -584,6 +584,12 @@ class AndroidAudioDeviceModule : public AudioDeviceModule {
return result; return result;
} }
int32_t GetPlayoutUnderrunCount() const override {
if (!initialized_)
return -1;
return output_->GetPlayoutUnderrunCount();
}
int32_t AttachAudioBuffer() { int32_t AttachAudioBuffer() {
RTC_LOG(INFO) << __FUNCTION__; RTC_LOG(INFO) << __FUNCTION__;
output_->AttachAudioBuffer(audio_device_buffer_.get()); output_->AttachAudioBuffer(audio_device_buffer_.get());

View File

@ -65,6 +65,7 @@ class AudioOutput {
virtual absl::optional<uint32_t> MaxSpeakerVolume() const = 0; virtual absl::optional<uint32_t> MaxSpeakerVolume() const = 0;
virtual absl::optional<uint32_t> MinSpeakerVolume() const = 0; virtual absl::optional<uint32_t> MinSpeakerVolume() const = 0;
virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0; virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0;
virtual int GetPlayoutUnderrunCount() = 0;
}; };
// Extract an android.media.AudioManager from an android.content.Context. // Extract an android.media.AudioManager from an android.content.Context.

View File

@ -169,6 +169,10 @@ absl::optional<uint32_t> AudioTrackJni::SpeakerVolume() const {
return volume; return volume;
} }
int AudioTrackJni::GetPlayoutUnderrunCount() {
return Java_WebRtcAudioTrack_GetPlayoutUnderrunCount(env_, j_audio_track_);
}
// TODO(henrika): possibly add stereo support. // TODO(henrika): possibly add stereo support.
void AudioTrackJni::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) { void AudioTrackJni::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
RTC_LOG(INFO) << "AttachAudioBuffer"; RTC_LOG(INFO) << "AttachAudioBuffer";

View File

@ -65,6 +65,7 @@ class AudioTrackJni : public AudioOutput {
absl::optional<uint32_t> SpeakerVolume() const override; absl::optional<uint32_t> SpeakerVolume() const override;
absl::optional<uint32_t> MaxSpeakerVolume() const override; absl::optional<uint32_t> MaxSpeakerVolume() const override;
absl::optional<uint32_t> MinSpeakerVolume() const override; absl::optional<uint32_t> MinSpeakerVolume() const override;
int GetPlayoutUnderrunCount() override;
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override; void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;

View File

@ -82,6 +82,8 @@ class OpenSLESPlayer : public AudioOutput {
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override; void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
int GetPlayoutUnderrunCount() override { return -1; }
private: private:
// These callback methods are called when data is required for playout. // These callback methods are called when data is required for playout.
// They are both called from an internal "OpenSL ES thread" which is not // They are both called from an internal "OpenSL ES thread" which is not

View File

@ -125,6 +125,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule {
bool BuiltInNSIsAvailable() const override; bool BuiltInNSIsAvailable() const override;
int32_t EnableBuiltInNS(bool enable) override; int32_t EnableBuiltInNS(bool enable) override;
int32_t GetPlayoutUnderrunCount() const override;
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int GetPlayoutAudioParameters(AudioParameters* params) const override; int GetPlayoutAudioParameters(AudioParameters* params) const override;
int GetRecordAudioParameters(AudioParameters* params) const override; int GetRecordAudioParameters(AudioParameters* params) const override;

View File

@ -642,6 +642,14 @@ AudioDeviceModuleIOS::AudioDeviceModuleIOS()
return ok; return ok;
} }
int32_t AudioDeviceModuleIOS::GetPlayoutUnderrunCount() const {
RTC_LOG(INFO) << __FUNCTION__;
CHECKinitialized_();
int32_t ok = audio_device_->GetPlayoutUnderrunCount();
RTC_LOG(INFO) << "output: " << ok;
return ok;
}
#if defined(WEBRTC_IOS) #if defined(WEBRTC_IOS)
int AudioDeviceModuleIOS::GetPlayoutAudioParameters( int AudioDeviceModuleIOS::GetPlayoutAudioParameters(
AudioParameters* params) const { AudioParameters* params) const {