Index: webrtc/modules/audio_device/audio_device_buffer.cc |
diff --git a/webrtc/modules/audio_device/audio_device_buffer.cc b/webrtc/modules/audio_device/audio_device_buffer.cc |
index d157c1cb1ae661483675e18411c0bd57d6a6d449..e3250d83f35a82b735f669e982be2b4997af4d34 100644 |
--- a/webrtc/modules/audio_device/audio_device_buffer.cc |
+++ b/webrtc/modules/audio_device/audio_device_buffer.cc |
@@ -18,7 +18,9 @@ |
#include "webrtc/base/logging.h" |
#include "webrtc/base/format_macros.h" |
#include "webrtc/base/timeutils.h" |
+#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h" |
#include "webrtc/modules/audio_device/audio_device_config.h" |
+#include "webrtc/system_wrappers/include/metrics.h" |
namespace webrtc { |
@@ -59,7 +61,10 @@ AudioDeviceBuffer::AudioDeviceBuffer() |
last_rec_samples_(0), |
play_samples_(0), |
last_play_samples_(0), |
- last_log_stat_time_(0) { |
+ last_log_stat_time_(0), |
+ max_rec_level_(0), |
+ max_play_level_(0), |
+ num_rec_level_is_zero_(0) { |
LOG(INFO) << "AudioDeviceBuffer::ctor"; |
} |
@@ -84,6 +89,16 @@ AudioDeviceBuffer::~AudioDeviceBuffer() { |
LOG(INFO) << "average: " |
<< static_cast<float>(total_diff_time) / num_measurements; |
} |
+ |
+ // Add UMA histogram to keep track of the case when only zeros have been |
+ // recorded. Ensure that recording callbacks have started and that at least |
+ // one timer event has been able to update |num_rec_level_is_zero_|. |
+ // I am avoiding use of the task queue here since we are under destruction |
+ // and reading these members on the creating thread feels safe. |
+ if (rec_callbacks_ > 0 && num_stat_reports_ > 0) { |
+ RTC_LOGGED_HISTOGRAM_BOOLEAN("WebRTC.Audio.RecordedOnlyZeros", |
+ static_cast<int>(num_stat_reports_ == num_rec_level_is_zero_)); |
+ } |
} |
int32_t AudioDeviceBuffer::RegisterAudioCallback( |
@@ -97,7 +112,7 @@ int32_t AudioDeviceBuffer::RegisterAudioCallback( |
int32_t AudioDeviceBuffer::InitPlayout() { |
LOG(INFO) << __FUNCTION__; |
RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
- last_playout_time_ = rtc::TimeMillis(); |
+ ResetPlayStats(); |
if (!timer_has_started_) { |
StartTimer(); |
timer_has_started_ = true; |
@@ -108,6 +123,7 @@ int32_t AudioDeviceBuffer::InitPlayout() { |
int32_t AudioDeviceBuffer::InitRecording() { |
LOG(INFO) << __FUNCTION__; |
RTC_DCHECK(thread_checker_.CalledOnValidThread()); |
+ ResetRecStats(); |
if (!timer_has_started_) { |
StartTimer(); |
timer_has_started_ = true; |
@@ -263,8 +279,8 @@ int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audio_buffer, |
// Update some stats but do it on the task queue to ensure that the members |
// are modified and read on the same thread. |
- task_queue_.PostTask( |
- rtc::Bind(&AudioDeviceBuffer::UpdateRecStats, this, num_samples)); |
+ task_queue_.PostTask(rtc::Bind(&AudioDeviceBuffer::UpdateRecStats, this, |
+ audio_buffer, num_samples)); |
return 0; |
} |
@@ -335,8 +351,8 @@ int32_t AudioDeviceBuffer::RequestPlayoutData(size_t num_samples) { |
// Update some stats but do it on the task queue to ensure that access of |
// members is serialized hence avoiding usage of locks. |
- task_queue_.PostTask( |
- rtc::Bind(&AudioDeviceBuffer::UpdatePlayStats, this, num_samples_out)); |
+ task_queue_.PostTask(rtc::Bind(&AudioDeviceBuffer::UpdatePlayStats, this, |
peah-webrtc
2016/09/09 09:06:27
Would it not be better to post the task once every
peah-webrtc
2016/09/09 09:06:27
How critical is the complexity here? Would it be o
henrika_webrtc
2016/09/09 11:55:01
Referring to off-line discussion.
henrika_webrtc
2016/09/09 11:55:01
Referring to off-line discussion.
|
+ &play_buffer_[0], num_samples_out)); |
return static_cast<int32_t>(num_samples_out); |
} |
@@ -379,6 +395,7 @@ void AudioDeviceBuffer::AllocateRecordingBufferIfNeeded() { |
} |
void AudioDeviceBuffer::StartTimer() { |
+ num_stat_reports_ = 0; |
last_log_stat_time_ = rtc::TimeMillis(); |
task_queue_.PostDelayedTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this), |
kTimerIntervalInMilliseconds); |
@@ -403,7 +420,8 @@ void AudioDeviceBuffer::LogStats() { |
<< "kHz] callbacks: " << rec_callbacks_ - last_rec_callbacks_ |
<< ", " |
<< "samples: " << diff_samples << ", " |
- << "rate: " << rate; |
+ << "rate: " << rate << ", " |
+ << "level: " << max_rec_level_; |
diff_samples = play_samples_ - last_play_samples_; |
rate = diff_samples / kTimerIntervalInSeconds; |
@@ -412,13 +430,22 @@ void AudioDeviceBuffer::LogStats() { |
<< "kHz] callbacks: " << play_callbacks_ - last_play_callbacks_ |
<< ", " |
<< "samples: " << diff_samples << ", " |
- << "rate: " << rate; |
+ << "rate: " << rate << ", " |
+ << "level: " << max_play_level_; |
+ } |
+ |
+ // Count number of times we detect "no audio" corresponding to a case where |
+ // all level measurements have been zero. |
+ if (max_rec_level_ == 0) { |
+ ++num_rec_level_is_zero_; |
} |
last_rec_callbacks_ = rec_callbacks_; |
last_play_callbacks_ = play_callbacks_; |
last_rec_samples_ = rec_samples_; |
last_play_samples_ = play_samples_; |
+ max_rec_level_ = 0; |
+ max_play_level_ = 0; |
int64_t time_to_wait_ms = next_callback_time - rtc::TimeMillis(); |
RTC_DCHECK_GT(time_to_wait_ms, 0) << "Invalid timer interval"; |
@@ -429,16 +456,58 @@ void AudioDeviceBuffer::LogStats() { |
time_to_wait_ms); |
} |
-void AudioDeviceBuffer::UpdateRecStats(size_t num_samples) { |
+void AudioDeviceBuffer::ResetRecStats() { |
+ rec_callbacks_ = 0; |
+ last_rec_callbacks_ = 0; |
+ rec_samples_ = 0; |
+ last_rec_samples_ = 0; |
+ max_rec_level_ = 0; |
+ num_rec_level_is_zero_ = 0; |
+} |
+ |
+void AudioDeviceBuffer::ResetPlayStats() { |
+ last_playout_time_ = rtc::TimeMillis(); |
+ play_callbacks_ = 0; |
+ last_play_callbacks_ = 0; |
+ play_samples_ = 0; |
+ last_play_samples_ = 0; |
+ max_play_level_ = 0; |
+} |
+ |
+void AudioDeviceBuffer::UpdateRecStats(const void* audio_buffer, |
+ size_t num_samples) { |
RTC_DCHECK(task_queue_.IsCurrent()); |
++rec_callbacks_; |
rec_samples_ += num_samples; |
+ |
+ // Find the max absolute value in an audio packet twice per second and update |
+ // |max_rec_level_| to track the largest value. |
+ if (rec_callbacks_ % 50 == 0) { |
+ int16_t max_abs = WebRtcSpl_MaxAbsValueW16( |
+ static_cast<int16_t*>(const_cast<void*>(audio_buffer)), |
peah-webrtc
2016/09/09 09:06:27
Do we know that these samples are always int16_t s
henrika_webrtc
2016/09/09 11:55:01
Yes. But I can add some more stuff around it.
|
+ num_samples * rec_channels_); |
+ if (max_abs > max_rec_level_) { |
+ max_rec_level_ = max_abs; |
+ } |
+ } |
} |
-void AudioDeviceBuffer::UpdatePlayStats(size_t num_samples) { |
+void AudioDeviceBuffer::UpdatePlayStats(const void* audio_buffer, |
+ size_t num_samples) { |
RTC_DCHECK(task_queue_.IsCurrent()); |
++play_callbacks_; |
play_samples_ += num_samples; |
+ |
+ // Find the max absolute value in an audio packet twice per second and update |
+ // |max_play_level_| to track the largest value. |
+ if (play_callbacks_ % 50 == 0) { |
+ int16_t max_abs = WebRtcSpl_MaxAbsValueW16( |
+ static_cast<int16_t*>(const_cast<void*>(audio_buffer)), |
peah-webrtc
2016/09/09 09:06:27
Do we know that these samples are always int16_t s
henrika_webrtc
2016/09/09 11:55:01
Yes.
|
+ num_samples * play_channels_); |
+ if (max_abs > max_play_level_) { |
+ max_play_level_ = max_abs; |
+ } |
+ } |
} |
} // namespace webrtc |