diff --git a/webrtc/modules/audio_device/audio_device_buffer.cc b/webrtc/modules/audio_device/audio_device_buffer.cc index 8b49a3ffd0..e7a5da731a 100644 --- a/webrtc/modules/audio_device/audio_device_buffer.cc +++ b/webrtc/modules/audio_device/audio_device_buffer.cc @@ -53,10 +53,21 @@ AudioDeviceBuffer::AudioDeviceBuffer() rec_delay_ms_(0), clock_drift_(0), num_stat_reports_(0), + rec_callbacks_(0), + last_rec_callbacks_(0), + play_callbacks_(0), + last_play_callbacks_(0), + rec_samples_(0), + last_rec_samples_(0), + play_samples_(0), + last_play_samples_(0), + max_rec_level_(0), + max_play_level_(0), last_timer_task_time_(0), rec_stat_count_(0), play_stat_count_(0), play_start_time_(0), + rec_start_time_(0), only_silence_recorded_(true), log_stats_(false) { LOG(INFO) << "AudioDeviceBuffer::ctor"; @@ -315,9 +326,13 @@ int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audio_buffer, only_silence_recorded_ = false; } } - // Update recording stats which is used as base for periodic logging of the - // audio input state. - UpdateRecStats(max_abs, samples_per_channel); + // Update some stats but do it on the task queue to ensure that the members + // are modified and read on the same thread. Note that |max_abs| will be + // zero in most calls and then have no effect of the stats. It is only updated + // approximately two times per second and can then change the stats. + task_queue_.PostTask([this, max_abs, samples_per_channel] { + UpdateRecStats(max_abs, samples_per_channel); + }); return 0; } @@ -382,9 +397,13 @@ int32_t AudioDeviceBuffer::RequestPlayoutData(size_t samples_per_channel) { WebRtcSpl_MaxAbsValueW16(play_buffer_.data(), play_buffer_.size()); play_stat_count_ = 0; } - // Update playout stats which is used as base for periodic logging of the - // audio output state. - UpdatePlayStats(max_abs, num_samples_out); + // Update some stats but do it on the task queue to ensure that the members + // are modified and read on the same thread. Note that |max_abs| will be + // zero in most calls and then have no effect of the stats. It is only updated + // approximately two times per second and can then change the stats. + task_queue_.PostTask([this, max_abs, num_samples_out] { + UpdatePlayStats(max_abs, num_samples_out); + }); return static_cast(num_samples_out); } @@ -434,37 +453,37 @@ void AudioDeviceBuffer::LogStats(LogState state) { int64_t time_since_last = rtc::TimeDiff(now_time, last_timer_task_time_); last_timer_task_time_ = now_time; - Stats stats; - { - rtc::CritScope cs(&lock_); - stats = stats_; - stats_.max_rec_level = 0; - stats_.max_play_level = 0; - } - // Log the latest statistics but skip the first round just after state was // set to LOG_START. Hence, first printed log will be after ~10 seconds. if (++num_stat_reports_ > 1 && time_since_last > 0) { - uint32_t diff_samples = stats.rec_samples - last_stats_.rec_samples; + uint32_t diff_samples = rec_samples_ - last_rec_samples_; float rate = diff_samples / (static_cast(time_since_last) / 1000.0); LOG(INFO) << "[REC : " << time_since_last << "msec, " - << rec_sample_rate_ / 1000 << "kHz] callbacks: " - << stats.rec_callbacks - last_stats_.rec_callbacks << ", " + << rec_sample_rate_ / 1000 + << "kHz] callbacks: " << rec_callbacks_ - last_rec_callbacks_ + << ", " << "samples: " << diff_samples << ", " << "rate: " << static_cast(rate + 0.5) << ", " - << "level: " << stats.max_rec_level; + << "level: " << max_rec_level_; - diff_samples = stats.play_samples - last_stats_.play_samples; + diff_samples = play_samples_ - last_play_samples_; rate = diff_samples / (static_cast(time_since_last) / 1000.0); LOG(INFO) << "[PLAY: " << time_since_last << "msec, " - << play_sample_rate_ / 1000 << "kHz] callbacks: " - << stats.play_callbacks - last_stats_.play_callbacks << ", " + << play_sample_rate_ / 1000 + << "kHz] callbacks: " << play_callbacks_ - last_play_callbacks_ + << ", " << "samples: " << diff_samples << ", " << "rate: " << static_cast(rate + 0.5) << ", " - << "level: " << stats.max_play_level; - last_stats_ = stats; + << "level: " << max_play_level_; } + 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"; @@ -476,37 +495,39 @@ void AudioDeviceBuffer::LogStats(LogState state) { void AudioDeviceBuffer::ResetRecStats() { RTC_DCHECK_RUN_ON(&task_queue_); - last_stats_.ResetRecStats(); - rtc::CritScope cs(&lock_); - stats_.ResetRecStats(); + rec_callbacks_ = 0; + last_rec_callbacks_ = 0; + rec_samples_ = 0; + last_rec_samples_ = 0; + max_rec_level_ = 0; } void AudioDeviceBuffer::ResetPlayStats() { RTC_DCHECK_RUN_ON(&task_queue_); - last_stats_.ResetPlayStats(); - rtc::CritScope cs(&lock_); - stats_.ResetPlayStats(); + play_callbacks_ = 0; + last_play_callbacks_ = 0; + play_samples_ = 0; + last_play_samples_ = 0; + max_play_level_ = 0; } void AudioDeviceBuffer::UpdateRecStats(int16_t max_abs, size_t samples_per_channel) { - RTC_DCHECK_RUN_ON(&recording_thread_checker_); - rtc::CritScope cs(&lock_); - ++stats_.rec_callbacks; - stats_.rec_samples += samples_per_channel; - if (max_abs > stats_.max_rec_level) { - stats_.max_rec_level = max_abs; + RTC_DCHECK_RUN_ON(&task_queue_); + ++rec_callbacks_; + rec_samples_ += samples_per_channel; + if (max_abs > max_rec_level_) { + max_rec_level_ = max_abs; } } void AudioDeviceBuffer::UpdatePlayStats(int16_t max_abs, size_t samples_per_channel) { - RTC_DCHECK_RUN_ON(&playout_thread_checker_); - rtc::CritScope cs(&lock_); - ++stats_.play_callbacks; - stats_.play_samples += samples_per_channel; - if (max_abs > stats_.max_play_level) { - stats_.max_play_level = max_abs; + RTC_DCHECK_RUN_ON(&task_queue_); + ++play_callbacks_; + play_samples_ += samples_per_channel; + if (max_abs > max_play_level_) { + max_play_level_ = max_abs; } } diff --git a/webrtc/modules/audio_device/audio_device_buffer.h b/webrtc/modules/audio_device/audio_device_buffer.h index 1466e6934b..e2c6f2871a 100644 --- a/webrtc/modules/audio_device/audio_device_buffer.h +++ b/webrtc/modules/audio_device/audio_device_buffer.h @@ -12,7 +12,6 @@ #define WEBRTC_MODULES_AUDIO_DEVICE_AUDIO_DEVICE_BUFFER_H_ #include "webrtc/base/buffer.h" -#include "webrtc/base/criticalsection.h" #include "webrtc/base/task_queue.h" #include "webrtc/base/thread_annotations.h" #include "webrtc/base/thread_checker.h" @@ -37,43 +36,6 @@ class AudioDeviceBuffer { LOG_ACTIVE, }; - struct Stats { - void ResetRecStats() { - rec_callbacks = 0; - rec_samples = 0; - max_rec_level = 0; - } - - void ResetPlayStats() { - play_callbacks = 0; - play_samples = 0; - max_play_level = 0; - } - - // Total number of recording callbacks where the source provides 10ms audio - // data each time. - uint64_t rec_callbacks = 0; - - // Total number of playback callbacks where the sink asks for 10ms audio - // data each time. - uint64_t play_callbacks = 0; - - // Total number of recorded audio samples. - uint64_t rec_samples = 0; - - // Total number of played audio samples. - uint64_t play_samples = 0; - - // Contains max level (max(abs(x))) of recorded audio packets over the last - // 10 seconds where a new measurement is done twice per second. The level - // is reset to zero at each call to LogStats(). - int16_t max_rec_level = 0; - - // Contains max level of recorded audio packets over the last 10 seconds - // where a new measurement is done twice per second. - int16_t max_play_level = 0; - }; - AudioDeviceBuffer(); virtual ~AudioDeviceBuffer(); @@ -130,8 +92,9 @@ class AudioDeviceBuffer { // state = LOG_ACTIVE => logs are printed and the timer is kept alive. void LogStats(LogState state); - // Updates counters in each play/record callback. These counters are later - // (periodically) read by LogStats() using a lock. + // Updates counters in each play/record callback but does it on the task + // queue to ensure that they can be read by LogStats() without any locks since + // each task is serialized by the task queue. void UpdateRecStats(int16_t max_abs, size_t samples_per_channel); void UpdatePlayStats(int16_t max_abs, size_t samples_per_channel); @@ -157,8 +120,6 @@ class AudioDeviceBuffer { // Native (platform specific) audio thread driving the recording side. rtc::ThreadChecker recording_thread_checker_; - rtc::CriticalSection lock_; - // Task queue used to invoke LogStats() periodically. Tasks are executed on a // worker thread but it does not necessarily have to be the same thread for // each task. @@ -223,6 +184,41 @@ class AudioDeviceBuffer { // Counts number of times LogStats() has been called. size_t num_stat_reports_ ACCESS_ON(task_queue_); + // Total number of recording callbacks where the source provides 10ms audio + // data each time. + uint64_t rec_callbacks_ ACCESS_ON(task_queue_); + + // Total number of recording callbacks stored at the last timer task. + uint64_t last_rec_callbacks_ ACCESS_ON(task_queue_); + + // Total number of playback callbacks where the sink asks for 10ms audio + // data each time. + uint64_t play_callbacks_ ACCESS_ON(task_queue_); + + // Total number of playout callbacks stored at the last timer task. + uint64_t last_play_callbacks_ ACCESS_ON(task_queue_); + + // Total number of recorded audio samples. + uint64_t rec_samples_ ACCESS_ON(task_queue_); + + // Total number of recorded samples stored at the previous timer task. + uint64_t last_rec_samples_ ACCESS_ON(task_queue_); + + // Total number of played audio samples. + uint64_t play_samples_ ACCESS_ON(task_queue_); + + // Total number of played samples stored at the previous timer task. + uint64_t last_play_samples_ ACCESS_ON(task_queue_); + + // Contains max level (max(abs(x))) of recorded audio packets over the last + // 10 seconds where a new measurement is done twice per second. The level + // is reset to zero at each call to LogStats(). + int16_t max_rec_level_ ACCESS_ON(task_queue_); + + // Contains max level of recorded audio packets over the last 10 seconds + // where a new measurement is done twice per second. + int16_t max_play_level_ ACCESS_ON(task_queue_); + // Time stamp of last timer task (drives logging). int64_t last_timer_task_time_ ACCESS_ON(task_queue_); @@ -235,13 +231,6 @@ class AudioDeviceBuffer { int64_t play_start_time_ ACCESS_ON(main_thread_checker_); int64_t rec_start_time_ ACCESS_ON(main_thread_checker_); - // Contains counters for playout and recording statistics. - Stats stats_ GUARDED_BY(lock_); - - // Stores current stats at each timer task. Used to calculate differences - // between two successive timer events. - Stats last_stats_ ACCESS_ON(task_queue_); - // Set to true at construction and modified to false as soon as one audio- // level estimate larger than zero is detected. bool only_silence_recorded_;