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:
@ -653,6 +653,8 @@ const char* StatsReport::Value::display_name() const {
|
||||
return "googTypingNoiseState";
|
||||
case kStatsValueNameWritable:
|
||||
return "googWritable";
|
||||
case kStatsValueNameAudioDeviceUnderrunCounter:
|
||||
return "googAudioDeviceUnderrunCounter";
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
|
||||
@ -238,6 +238,7 @@ class StatsReport {
|
||||
kStatsValueNameTransportType,
|
||||
kStatsValueNameTypingNoiseState,
|
||||
kStatsValueNameWritable,
|
||||
kStatsValueNameAudioDeviceUnderrunCounter,
|
||||
};
|
||||
|
||||
class IdBase : public rtc::RefCountInterface {
|
||||
|
||||
@ -687,6 +687,7 @@ struct VoiceMediaInfo {
|
||||
std::vector<VoiceReceiverInfo> receivers;
|
||||
RtpCodecParametersMap send_codecs;
|
||||
RtpCodecParametersMap receive_codecs;
|
||||
int32_t device_underrun_count = 0;
|
||||
};
|
||||
|
||||
struct VideoMediaInfo {
|
||||
|
||||
@ -2267,6 +2267,7 @@ bool WebRtcVoiceMediaChannel::GetStats(VoiceMediaInfo* info) {
|
||||
info->receive_codecs.insert(
|
||||
std::make_pair(codec_params.payload_type, std::move(codec_params)));
|
||||
}
|
||||
info->device_underrun_count = engine_->adm()->GetPlayoutUnderrunCount();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2243,6 +2243,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
|
||||
|
||||
// Check stats for the added streams.
|
||||
{
|
||||
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
|
||||
cricket::VoiceMediaInfo info;
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
|
||||
@ -2262,6 +2263,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
|
||||
{
|
||||
cricket::VoiceMediaInfo info;
|
||||
EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcY));
|
||||
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size());
|
||||
EXPECT_EQ(0u, info.receivers.size());
|
||||
@ -2273,6 +2275,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStatsWithMultipleSendStreams) {
|
||||
cricket::VoiceMediaInfo info;
|
||||
DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
|
||||
SetAudioReceiveStreamStats();
|
||||
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
EXPECT_EQ(static_cast<size_t>(arraysize(kSsrcs4)), info.senders.size());
|
||||
EXPECT_EQ(1u, info.receivers.size());
|
||||
@ -2431,6 +2434,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
|
||||
|
||||
// Check stats for the added streams.
|
||||
{
|
||||
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
|
||||
cricket::VoiceMediaInfo info;
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
|
||||
@ -2446,6 +2450,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
|
||||
{
|
||||
cricket::VoiceMediaInfo info;
|
||||
SetSend(true);
|
||||
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
VerifyVoiceSenderInfo(info.senders[0], true);
|
||||
VerifyVoiceSendRecvCodecs(info);
|
||||
@ -2455,6 +2460,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
|
||||
{
|
||||
cricket::VoiceMediaInfo info;
|
||||
EXPECT_TRUE(channel_->RemoveRecvStream(kSsrcY));
|
||||
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
EXPECT_EQ(1u, info.senders.size());
|
||||
EXPECT_EQ(0u, info.receivers.size());
|
||||
@ -2466,6 +2472,7 @@ TEST_F(WebRtcVoiceEngineTestFake, GetStats) {
|
||||
cricket::VoiceMediaInfo info;
|
||||
DeliverPacket(kPcmuFrame, sizeof(kPcmuFrame));
|
||||
SetAudioReceiveStreamStats();
|
||||
EXPECT_CALL(adm_, GetPlayoutUnderrunCount()).WillOnce(Return(0));
|
||||
EXPECT_EQ(true, channel_->GetStats(&info));
|
||||
EXPECT_EQ(1u, info.senders.size());
|
||||
EXPECT_EQ(1u, info.receivers.size());
|
||||
|
||||
@ -261,6 +261,9 @@ class ADMWrapper : public AudioDeviceModule, public AudioTransport {
|
||||
int32_t EnableBuiltInNS(bool enable) override {
|
||||
return impl_->EnableBuiltInNS(enable);
|
||||
}
|
||||
int32_t GetPlayoutUnderrunCount() const override {
|
||||
return impl_->GetPlayoutUnderrunCount();
|
||||
}
|
||||
// Only supported on iOS.
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(AudioParameters* params) const override {
|
||||
|
||||
@ -44,6 +44,11 @@ int32_t AudioDeviceGeneric::EnableBuiltInNS(bool enable) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int32_t AudioDeviceGeneric::GetPlayoutUnderrunCount() const {
|
||||
RTC_LOG_F(LS_ERROR) << "Not supported on this platform";
|
||||
return -1;
|
||||
}
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
int AudioDeviceGeneric::GetPlayoutAudioParameters(
|
||||
AudioParameters* params) const {
|
||||
|
||||
@ -125,6 +125,9 @@ class AudioDeviceGeneric {
|
||||
virtual int32_t EnableBuiltInAGC(bool enable);
|
||||
virtual int32_t EnableBuiltInNS(bool enable);
|
||||
|
||||
// Play underrun count.
|
||||
virtual int32_t GetPlayoutUnderrunCount() const;
|
||||
|
||||
// iOS only.
|
||||
// TODO(henrika): add Android support.
|
||||
#if defined(WEBRTC_IOS)
|
||||
|
||||
@ -910,6 +910,14 @@ int32_t AudioDeviceModuleImpl::EnableBuiltInNS(bool enable) {
|
||||
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)
|
||||
int AudioDeviceModuleImpl::GetPlayoutAudioParameters(
|
||||
AudioParameters* params) const {
|
||||
|
||||
@ -137,6 +137,9 @@ class AudioDeviceModuleImpl : public AudioDeviceModuleForTest {
|
||||
bool BuiltInNSIsAvailable() const override;
|
||||
int32_t EnableBuiltInNS(bool enable) override;
|
||||
|
||||
// Play underrun count.
|
||||
int32_t GetPlayoutUnderrunCount() const override;
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(AudioParameters* params) const override;
|
||||
int GetRecordAudioParameters(AudioParameters* params) const override;
|
||||
|
||||
@ -146,6 +146,10 @@ class AudioDeviceModule : public rtc::RefCountInterface {
|
||||
virtual int32_t EnableBuiltInAGC(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.
|
||||
#if defined(WEBRTC_IOS)
|
||||
virtual int GetPlayoutAudioParameters(AudioParameters* params) const = 0;
|
||||
|
||||
@ -114,6 +114,8 @@ class AudioDeviceModuleDefault : public T {
|
||||
bool BuiltInNSIsAvailable() const override { return false; }
|
||||
int32_t EnableBuiltInNS(bool enable) override { return -1; }
|
||||
|
||||
int32_t GetPlayoutUnderrunCount() const override { return -1; }
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(AudioParameters* params) const override {
|
||||
return -1;
|
||||
|
||||
@ -91,6 +91,7 @@ class MockAudioDeviceModule : public AudioDeviceModule {
|
||||
MOCK_METHOD1(EnableBuiltInAEC, int32_t(bool enable));
|
||||
MOCK_METHOD1(EnableBuiltInAGC, int32_t(bool enable));
|
||||
MOCK_METHOD1(EnableBuiltInNS, int32_t(bool enable));
|
||||
MOCK_CONST_METHOD0(GetPlayoutUnderrunCount, int32_t());
|
||||
#if defined(WEBRTC_IOS)
|
||||
MOCK_CONST_METHOD1(GetPlayoutAudioParameters, int(AudioParameters* params));
|
||||
MOCK_CONST_METHOD1(GetRecordAudioParameters, int(AudioParameters* params));
|
||||
|
||||
@ -636,6 +636,14 @@ StatsReport* StatsCollector::PrepareReport(bool local,
|
||||
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) {
|
||||
return reports_.Find(StatsReport::NewTypedId(
|
||||
StatsReport::kStatsReportTypeTrack, track_id)) != nullptr;
|
||||
@ -956,6 +964,12 @@ class VoiceMediaChannelStatsGatherer final : public MediaChannelStatsGatherer {
|
||||
void ExtractStats(StatsCollector* collector) const override {
|
||||
ExtractSenderReceiverStats(collector, voice_media_info.receivers,
|
||||
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 {
|
||||
|
||||
@ -84,6 +84,8 @@ class StatsCollector {
|
||||
const StatsReport::Id& transport_id,
|
||||
StatsReport::Direction direction);
|
||||
|
||||
StatsReport* PrepareADMReport();
|
||||
|
||||
// A track is invalid if there is no report data for it.
|
||||
bool IsValidTrack(const std::string& track_id);
|
||||
|
||||
|
||||
@ -128,6 +128,8 @@ class FakeAudioCaptureModule : public webrtc::AudioDeviceModule,
|
||||
int32_t EnableBuiltInAGC(bool enable) override { return -1; }
|
||||
bool BuiltInNSIsAvailable() const override { return false; }
|
||||
int32_t EnableBuiltInNS(bool enable) override { return -1; }
|
||||
|
||||
int32_t GetPlayoutUnderrunCount() const override { return -1; }
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(
|
||||
webrtc::AudioParameters* params) const override {
|
||||
|
||||
@ -342,6 +342,19 @@ class WebRtcAudioTrack {
|
||||
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() {
|
||||
Logging.d(TAG,
|
||||
"AudioTrack: "
|
||||
|
||||
@ -584,6 +584,12 @@ class AndroidAudioDeviceModule : public AudioDeviceModule {
|
||||
return result;
|
||||
}
|
||||
|
||||
int32_t GetPlayoutUnderrunCount() const override {
|
||||
if (!initialized_)
|
||||
return -1;
|
||||
return output_->GetPlayoutUnderrunCount();
|
||||
}
|
||||
|
||||
int32_t AttachAudioBuffer() {
|
||||
RTC_LOG(INFO) << __FUNCTION__;
|
||||
output_->AttachAudioBuffer(audio_device_buffer_.get());
|
||||
|
||||
@ -65,6 +65,7 @@ class AudioOutput {
|
||||
virtual absl::optional<uint32_t> MaxSpeakerVolume() const = 0;
|
||||
virtual absl::optional<uint32_t> MinSpeakerVolume() const = 0;
|
||||
virtual void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) = 0;
|
||||
virtual int GetPlayoutUnderrunCount() = 0;
|
||||
};
|
||||
|
||||
// Extract an android.media.AudioManager from an android.content.Context.
|
||||
|
||||
@ -169,6 +169,10 @@ absl::optional<uint32_t> AudioTrackJni::SpeakerVolume() const {
|
||||
return volume;
|
||||
}
|
||||
|
||||
int AudioTrackJni::GetPlayoutUnderrunCount() {
|
||||
return Java_WebRtcAudioTrack_GetPlayoutUnderrunCount(env_, j_audio_track_);
|
||||
}
|
||||
|
||||
// TODO(henrika): possibly add stereo support.
|
||||
void AudioTrackJni::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
|
||||
RTC_LOG(INFO) << "AttachAudioBuffer";
|
||||
|
||||
@ -65,6 +65,7 @@ class AudioTrackJni : public AudioOutput {
|
||||
absl::optional<uint32_t> SpeakerVolume() const override;
|
||||
absl::optional<uint32_t> MaxSpeakerVolume() const override;
|
||||
absl::optional<uint32_t> MinSpeakerVolume() const override;
|
||||
int GetPlayoutUnderrunCount() override;
|
||||
|
||||
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
|
||||
|
||||
|
||||
@ -82,6 +82,8 @@ class OpenSLESPlayer : public AudioOutput {
|
||||
|
||||
void AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) override;
|
||||
|
||||
int GetPlayoutUnderrunCount() override { return -1; }
|
||||
|
||||
private:
|
||||
// These callback methods are called when data is required for playout.
|
||||
// They are both called from an internal "OpenSL ES thread" which is not
|
||||
|
||||
@ -125,6 +125,8 @@ class AudioDeviceModuleIOS : public AudioDeviceModule {
|
||||
bool BuiltInNSIsAvailable() const override;
|
||||
int32_t EnableBuiltInNS(bool enable) override;
|
||||
|
||||
int32_t GetPlayoutUnderrunCount() const override;
|
||||
|
||||
#if defined(WEBRTC_IOS)
|
||||
int GetPlayoutAudioParameters(AudioParameters* params) const override;
|
||||
int GetRecordAudioParameters(AudioParameters* params) const override;
|
||||
|
||||
@ -642,6 +642,14 @@ AudioDeviceModuleIOS::AudioDeviceModuleIOS()
|
||||
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)
|
||||
int AudioDeviceModuleIOS::GetPlayoutAudioParameters(
|
||||
AudioParameters* params) const {
|
||||
|
||||
Reference in New Issue
Block a user