LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/audio_device - audio_device_buffer.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 283 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 41 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
       3             :  *
       4             :  *  Use of this source code is governed by a BSD-style license
       5             :  *  that can be found in the LICENSE file in the root of the source
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include <algorithm>
      12             : 
      13             : #include "webrtc/modules/audio_device/audio_device_buffer.h"
      14             : 
      15             : #include "webrtc/base/arraysize.h"
      16             : #include "webrtc/base/bind.h"
      17             : #include "webrtc/base/checks.h"
      18             : #include "webrtc/base/logging.h"
      19             : #include "webrtc/base/format_macros.h"
      20             : #include "webrtc/base/timeutils.h"
      21             : #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
      22             : #include "webrtc/modules/audio_device/audio_device_config.h"
      23             : #include "webrtc/system_wrappers/include/metrics.h"
      24             : 
      25             : namespace webrtc {
      26             : 
      27             : static const char kTimerQueueName[] = "AudioDeviceBufferTimer";
      28             : 
      29             : // Time between two sucessive calls to LogStats().
      30             : static const size_t kTimerIntervalInSeconds = 10;
      31             : static const size_t kTimerIntervalInMilliseconds =
      32             :     kTimerIntervalInSeconds * rtc::kNumMillisecsPerSec;
      33             : // Min time required to qualify an audio session as a "call". If playout or
      34             : // recording has been active for less than this time we will not store any
      35             : // logs or UMA stats but instead consider the call as too short.
      36             : static const size_t kMinValidCallTimeTimeInSeconds = 10;
      37             : static const size_t kMinValidCallTimeTimeInMilliseconds =
      38             :     kMinValidCallTimeTimeInSeconds * rtc::kNumMillisecsPerSec;
      39             : 
      40           0 : AudioDeviceBuffer::AudioDeviceBuffer()
      41             :     : task_queue_(kTimerQueueName),
      42             :       audio_transport_cb_(nullptr),
      43             :       rec_sample_rate_(0),
      44             :       play_sample_rate_(0),
      45             :       rec_channels_(0),
      46             :       play_channels_(0),
      47             :       playing_(false),
      48             :       recording_(false),
      49             :       current_mic_level_(0),
      50             :       new_mic_level_(0),
      51             :       typing_status_(false),
      52             :       play_delay_ms_(0),
      53             :       rec_delay_ms_(0),
      54             :       clock_drift_(0),
      55             :       num_stat_reports_(0),
      56             :       rec_callbacks_(0),
      57             :       last_rec_callbacks_(0),
      58             :       play_callbacks_(0),
      59             :       last_play_callbacks_(0),
      60             :       rec_samples_(0),
      61             :       last_rec_samples_(0),
      62             :       play_samples_(0),
      63             :       last_play_samples_(0),
      64             :       max_rec_level_(0),
      65             :       max_play_level_(0),
      66             :       last_timer_task_time_(0),
      67             :       rec_stat_count_(0),
      68             :       play_stat_count_(0),
      69             :       play_start_time_(0),
      70             :       rec_start_time_(0),
      71             :       only_silence_recorded_(true),
      72           0 :       log_stats_(false) {
      73           0 :   LOG(INFO) << "AudioDeviceBuffer::ctor";
      74           0 :   playout_thread_checker_.DetachFromThread();
      75           0 :   recording_thread_checker_.DetachFromThread();
      76           0 : }
      77             : 
      78           0 : AudioDeviceBuffer::~AudioDeviceBuffer() {
      79           0 :   RTC_DCHECK_RUN_ON(&main_thread_checker_);
      80           0 :   RTC_DCHECK(!playing_);
      81           0 :   RTC_DCHECK(!recording_);
      82           0 :   LOG(INFO) << "AudioDeviceBuffer::~dtor";
      83           0 : }
      84             : 
      85           0 : int32_t AudioDeviceBuffer::RegisterAudioCallback(
      86             :     AudioTransport* audio_callback) {
      87           0 :   RTC_DCHECK_RUN_ON(&main_thread_checker_);
      88           0 :   LOG(INFO) << __FUNCTION__;
      89           0 :   if (playing_ || recording_) {
      90           0 :     LOG(LS_ERROR) << "Failed to set audio transport since media was active";
      91           0 :     return -1;
      92             :   }
      93           0 :   audio_transport_cb_ = audio_callback;
      94           0 :   return 0;
      95             : }
      96             : 
      97           0 : void AudioDeviceBuffer::StartPlayout() {
      98           0 :   RTC_DCHECK_RUN_ON(&main_thread_checker_);
      99             :   // TODO(henrika): allow for usage of DCHECK(!playing_) here instead. Today the
     100             :   // ADM allows calling Start(), Start() by ignoring the second call but it
     101             :   // makes more sense to only allow one call.
     102           0 :   if (playing_) {
     103           0 :     return;
     104             :   }
     105           0 :   LOG(INFO) << __FUNCTION__;
     106           0 :   playout_thread_checker_.DetachFromThread();
     107             :   // Clear members tracking playout stats and do it on the task queue.
     108           0 :   task_queue_.PostTask([this] { ResetPlayStats(); });
     109             :   // Start a periodic timer based on task queue if not already done by the
     110             :   // recording side.
     111           0 :   if (!recording_) {
     112           0 :     StartPeriodicLogging();
     113             :   }
     114           0 :   const int64_t now_time = rtc::TimeMillis();
     115             :   // Clear members that are only touched on the main (creating) thread.
     116           0 :   play_start_time_ = now_time;
     117           0 :   playing_ = true;
     118             : }
     119             : 
     120           0 : void AudioDeviceBuffer::StartRecording() {
     121           0 :   RTC_DCHECK_RUN_ON(&main_thread_checker_);
     122           0 :   if (recording_) {
     123           0 :     return;
     124             :   }
     125           0 :   LOG(INFO) << __FUNCTION__;
     126           0 :   recording_thread_checker_.DetachFromThread();
     127             :   // Clear members tracking recording stats and do it on the task queue.
     128           0 :   task_queue_.PostTask([this] { ResetRecStats(); });
     129             :   // Start a periodic timer based on task queue if not already done by the
     130             :   // playout side.
     131           0 :   if (!playing_) {
     132           0 :     StartPeriodicLogging();
     133             :   }
     134             :   // Clear members that will be touched on the main (creating) thread.
     135           0 :   rec_start_time_ = rtc::TimeMillis();
     136           0 :   recording_ = true;
     137             :   // And finally a member which can be modified on the native audio thread.
     138             :   // It is safe to do so since we know by design that the owning ADM has not
     139             :   // yet started the native audio recording.
     140           0 :   only_silence_recorded_ = true;
     141             : }
     142             : 
     143           0 : void AudioDeviceBuffer::StopPlayout() {
     144           0 :   RTC_DCHECK_RUN_ON(&main_thread_checker_);
     145           0 :   if (!playing_) {
     146           0 :     return;
     147             :   }
     148           0 :   LOG(INFO) << __FUNCTION__;
     149           0 :   playing_ = false;
     150             :   // Stop periodic logging if no more media is active.
     151           0 :   if (!recording_) {
     152           0 :     StopPeriodicLogging();
     153             :   }
     154           0 :   LOG(INFO) << "total playout time: " << rtc::TimeSince(play_start_time_);
     155             : }
     156             : 
     157           0 : void AudioDeviceBuffer::StopRecording() {
     158           0 :   RTC_DCHECK_RUN_ON(&main_thread_checker_);
     159           0 :   if (!recording_) {
     160           0 :     return;
     161             :   }
     162           0 :   LOG(INFO) << __FUNCTION__;
     163           0 :   recording_ = false;
     164             :   // Stop periodic logging if no more media is active.
     165           0 :   if (!playing_) {
     166           0 :     StopPeriodicLogging();
     167             :   }
     168             :   // Add UMA histogram to keep track of the case when only zeros have been
     169             :   // recorded. Measurements (max of absolute level) are taken twice per second,
     170             :   // which means that if e.g 10 seconds of audio has been recorded, a total of
     171             :   // 20 level estimates must all be identical to zero to trigger the histogram.
     172             :   // |only_silence_recorded_| can only be cleared on the native audio thread
     173             :   // that drives audio capture but we know by design that the audio has stopped
     174             :   // when this method is called, hence there should not be aby conflicts. Also,
     175             :   // the fact that |only_silence_recorded_| can be affected during the complete
     176             :   // call makes chances of conflicts with potentially one last callback very
     177             :   // small.
     178           0 :   const size_t time_since_start = rtc::TimeSince(rec_start_time_);
     179           0 :   if (time_since_start > kMinValidCallTimeTimeInMilliseconds) {
     180           0 :     const int only_zeros = static_cast<int>(only_silence_recorded_);
     181           0 :     RTC_HISTOGRAM_BOOLEAN("WebRTC.Audio.RecordedOnlyZeros", only_zeros);
     182           0 :     LOG(INFO) << "HISTOGRAM(WebRTC.Audio.RecordedOnlyZeros): " << only_zeros;
     183             :   }
     184           0 :   LOG(INFO) << "total recording time: " << time_since_start;
     185             : }
     186             : 
     187           0 : int32_t AudioDeviceBuffer::SetRecordingSampleRate(uint32_t fsHz) {
     188           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     189           0 :   LOG(INFO) << "SetRecordingSampleRate(" << fsHz << ")";
     190           0 :   rec_sample_rate_ = fsHz;
     191           0 :   return 0;
     192             : }
     193             : 
     194           0 : int32_t AudioDeviceBuffer::SetPlayoutSampleRate(uint32_t fsHz) {
     195           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     196           0 :   LOG(INFO) << "SetPlayoutSampleRate(" << fsHz << ")";
     197           0 :   play_sample_rate_ = fsHz;
     198           0 :   return 0;
     199             : }
     200             : 
     201           0 : int32_t AudioDeviceBuffer::RecordingSampleRate() const {
     202           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     203           0 :   return rec_sample_rate_;
     204             : }
     205             : 
     206           0 : int32_t AudioDeviceBuffer::PlayoutSampleRate() const {
     207           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     208           0 :   return play_sample_rate_;
     209             : }
     210             : 
     211           0 : int32_t AudioDeviceBuffer::SetRecordingChannels(size_t channels) {
     212           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     213           0 :   LOG(INFO) << "SetRecordingChannels(" << channels << ")";
     214           0 :   rec_channels_ = channels;
     215           0 :   return 0;
     216             : }
     217             : 
     218           0 : int32_t AudioDeviceBuffer::SetPlayoutChannels(size_t channels) {
     219           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     220           0 :   LOG(INFO) << "SetPlayoutChannels(" << channels << ")";
     221           0 :   play_channels_ = channels;
     222           0 :   return 0;
     223             : }
     224             : 
     225           0 : int32_t AudioDeviceBuffer::SetRecordingChannel(
     226             :     const AudioDeviceModule::ChannelType channel) {
     227           0 :   LOG(INFO) << "SetRecordingChannel(" << channel << ")";
     228           0 :   LOG(LS_WARNING) << "Not implemented";
     229             :   // Add DCHECK to ensure that user does not try to use this API with a non-
     230             :   // default parameter.
     231           0 :   RTC_DCHECK_EQ(channel, AudioDeviceModule::kChannelBoth);
     232           0 :   return -1;
     233             : }
     234             : 
     235           0 : int32_t AudioDeviceBuffer::RecordingChannel(
     236             :     AudioDeviceModule::ChannelType& channel) const {
     237           0 :   LOG(LS_WARNING) << "Not implemented";
     238           0 :   return -1;
     239             : }
     240             : 
     241           0 : size_t AudioDeviceBuffer::RecordingChannels() const {
     242           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     243           0 :   return rec_channels_;
     244             : }
     245             : 
     246           0 : size_t AudioDeviceBuffer::PlayoutChannels() const {
     247           0 :   RTC_DCHECK(main_thread_checker_.CalledOnValidThread());
     248           0 :   return play_channels_;
     249             : }
     250             : 
     251           0 : int32_t AudioDeviceBuffer::SetCurrentMicLevel(uint32_t level) {
     252             : #if !defined(WEBRTC_WIN)
     253             :   // Windows uses a dedicated thread for volume APIs.
     254           0 :   RTC_DCHECK_RUN_ON(&recording_thread_checker_);
     255             : #endif
     256           0 :   current_mic_level_ = level;
     257           0 :   return 0;
     258             : }
     259             : 
     260           0 : int32_t AudioDeviceBuffer::SetTypingStatus(bool typing_status) {
     261           0 :   RTC_DCHECK_RUN_ON(&recording_thread_checker_);
     262           0 :   typing_status_ = typing_status;
     263           0 :   return 0;
     264             : }
     265             : 
     266           0 : uint32_t AudioDeviceBuffer::NewMicLevel() const {
     267           0 :   RTC_DCHECK_RUN_ON(&recording_thread_checker_);
     268           0 :   return new_mic_level_;
     269             : }
     270             : 
     271           0 : void AudioDeviceBuffer::SetVQEData(int play_delay_ms,
     272             :                                    int rec_delay_ms,
     273             :                                    int clock_drift) {
     274           0 :   RTC_DCHECK_RUN_ON(&recording_thread_checker_);
     275           0 :   play_delay_ms_ = play_delay_ms;
     276           0 :   rec_delay_ms_ = rec_delay_ms;
     277           0 :   clock_drift_ = clock_drift;
     278           0 : }
     279             : 
     280           0 : int32_t AudioDeviceBuffer::StartInputFileRecording(
     281             :     const char fileName[kAdmMaxFileNameSize]) {
     282           0 :   LOG(LS_WARNING) << "Not implemented";
     283           0 :   return 0;
     284             : }
     285             : 
     286           0 : int32_t AudioDeviceBuffer::StopInputFileRecording() {
     287           0 :   LOG(LS_WARNING) << "Not implemented";
     288           0 :   return 0;
     289             : }
     290             : 
     291           0 : int32_t AudioDeviceBuffer::StartOutputFileRecording(
     292             :     const char fileName[kAdmMaxFileNameSize]) {
     293           0 :   LOG(LS_WARNING) << "Not implemented";
     294           0 :   return 0;
     295             : }
     296             : 
     297           0 : int32_t AudioDeviceBuffer::StopOutputFileRecording() {
     298           0 :   LOG(LS_WARNING) << "Not implemented";
     299           0 :   return 0;
     300             : }
     301             : 
     302           0 : int32_t AudioDeviceBuffer::SetRecordedBuffer(const void* audio_buffer,
     303             :                                              size_t samples_per_channel) {
     304           0 :   RTC_DCHECK_RUN_ON(&recording_thread_checker_);
     305             :   // Copy the complete input buffer to the local buffer.
     306           0 :   const size_t old_size = rec_buffer_.size();
     307           0 :   rec_buffer_.SetData(static_cast<const int16_t*>(audio_buffer),
     308           0 :                       rec_channels_ * samples_per_channel);
     309             :   // Keep track of the size of the recording buffer. Only updated when the
     310             :   // size changes, which is a rare event.
     311           0 :   if (old_size != rec_buffer_.size()) {
     312           0 :     LOG(LS_INFO) << "Size of recording buffer: " << rec_buffer_.size();
     313             :   }
     314             : 
     315             :   // Derive a new level value twice per second and check if it is non-zero.
     316           0 :   int16_t max_abs = 0;
     317           0 :   RTC_DCHECK_LT(rec_stat_count_, 50);
     318           0 :   if (++rec_stat_count_ >= 50) {
     319             :     // Returns the largest absolute value in a signed 16-bit vector.
     320           0 :     max_abs = WebRtcSpl_MaxAbsValueW16(rec_buffer_.data(), rec_buffer_.size());
     321           0 :     rec_stat_count_ = 0;
     322             :     // Set |only_silence_recorded_| to false as soon as at least one detection
     323             :     // of a non-zero audio packet is found. It can only be restored to true
     324             :     // again by restarting the call.
     325           0 :     if (max_abs > 0) {
     326           0 :       only_silence_recorded_ = false;
     327             :     }
     328             :   }
     329             :   // Update some stats but do it on the task queue to ensure that the members
     330             :   // are modified and read on the same thread. Note that |max_abs| will be
     331             :   // zero in most calls and then have no effect of the stats. It is only updated
     332             :   // approximately two times per second and can then change the stats.
     333           0 :   task_queue_.PostTask([this, max_abs, samples_per_channel] {
     334           0 :     UpdateRecStats(max_abs, samples_per_channel);
     335           0 :   });
     336           0 :   return 0;
     337             : }
     338             : 
     339           0 : int32_t AudioDeviceBuffer::DeliverRecordedData() {
     340           0 :   RTC_DCHECK_RUN_ON(&recording_thread_checker_);
     341           0 :   if (!audio_transport_cb_) {
     342           0 :     LOG(LS_WARNING) << "Invalid audio transport";
     343           0 :     return 0;
     344             :   }
     345           0 :   const size_t frames = rec_buffer_.size() / rec_channels_;
     346           0 :   const size_t bytes_per_frame = rec_channels_ * sizeof(int16_t);
     347           0 :   uint32_t new_mic_level(0);
     348           0 :   uint32_t total_delay_ms = play_delay_ms_ + rec_delay_ms_;
     349           0 :   int32_t res = audio_transport_cb_->RecordedDataIsAvailable(
     350           0 :       rec_buffer_.data(), frames, bytes_per_frame, rec_channels_,
     351             :       rec_sample_rate_, total_delay_ms, clock_drift_, current_mic_level_,
     352           0 :       typing_status_, new_mic_level);
     353           0 :   if (res != -1) {
     354           0 :     new_mic_level_ = new_mic_level;
     355             :   } else {
     356           0 :     LOG(LS_ERROR) << "RecordedDataIsAvailable() failed";
     357             :   }
     358           0 :   return 0;
     359             : }
     360             : 
     361           0 : int32_t AudioDeviceBuffer::RequestPlayoutData(size_t samples_per_channel) {
     362           0 :   RTC_DCHECK_RUN_ON(&playout_thread_checker_);
     363             :   // The consumer can change the requested size on the fly and we therefore
     364             :   // resize the buffer accordingly. Also takes place at the first call to this
     365             :   // method.
     366           0 :   const size_t total_samples = play_channels_ * samples_per_channel;
     367           0 :   if (play_buffer_.size() != total_samples) {
     368           0 :     play_buffer_.SetSize(total_samples);
     369           0 :     LOG(LS_INFO) << "Size of playout buffer: " << play_buffer_.size();
     370             :   }
     371             : 
     372           0 :   size_t num_samples_out(0);
     373             :   // It is currently supported to start playout without a valid audio
     374             :   // transport object. Leads to warning and silence.
     375           0 :   if (!audio_transport_cb_) {
     376           0 :     LOG(LS_WARNING) << "Invalid audio transport";
     377           0 :     return 0;
     378             :   }
     379             : 
     380             :   // Retrieve new 16-bit PCM audio data using the audio transport instance.
     381           0 :   int64_t elapsed_time_ms = -1;
     382           0 :   int64_t ntp_time_ms = -1;
     383           0 :   const size_t bytes_per_frame = play_channels_ * sizeof(int16_t);
     384           0 :   uint32_t res = audio_transport_cb_->NeedMorePlayData(
     385             :       samples_per_channel, bytes_per_frame, play_channels_, play_sample_rate_,
     386           0 :       play_buffer_.data(), num_samples_out, &elapsed_time_ms, &ntp_time_ms);
     387           0 :   if (res != 0) {
     388           0 :     LOG(LS_ERROR) << "NeedMorePlayData() failed";
     389             :   }
     390             : 
     391             :   // Derive a new level value twice per second.
     392           0 :   int16_t max_abs = 0;
     393           0 :   RTC_DCHECK_LT(play_stat_count_, 50);
     394           0 :   if (++play_stat_count_ >= 50) {
     395             :     // Returns the largest absolute value in a signed 16-bit vector.
     396             :     max_abs =
     397           0 :         WebRtcSpl_MaxAbsValueW16(play_buffer_.data(), play_buffer_.size());
     398           0 :     play_stat_count_ = 0;
     399             :   }
     400             :   // Update some stats but do it on the task queue to ensure that the members
     401             :   // are modified and read on the same thread. Note that |max_abs| will be
     402             :   // zero in most calls and then have no effect of the stats. It is only updated
     403             :   // approximately two times per second and can then change the stats.
     404           0 :   task_queue_.PostTask([this, max_abs, num_samples_out] {
     405           0 :     UpdatePlayStats(max_abs, num_samples_out);
     406           0 :   });
     407           0 :   return static_cast<int32_t>(num_samples_out);
     408             : }
     409             : 
     410           0 : int32_t AudioDeviceBuffer::GetPlayoutData(void* audio_buffer) {
     411           0 :   RTC_DCHECK_RUN_ON(&playout_thread_checker_);
     412           0 :   RTC_DCHECK_GT(play_buffer_.size(), 0);
     413           0 :   const size_t bytes_per_sample = sizeof(int16_t);
     414           0 :   memcpy(audio_buffer, play_buffer_.data(),
     415           0 :          play_buffer_.size() * bytes_per_sample);
     416             :   // Return samples per channel or number of frames.
     417           0 :   return static_cast<int32_t>(play_buffer_.size() / play_channels_);
     418             : }
     419             : 
     420           0 : void AudioDeviceBuffer::StartPeriodicLogging() {
     421           0 :   task_queue_.PostTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this,
     422           0 :                                  AudioDeviceBuffer::LOG_START));
     423           0 : }
     424             : 
     425           0 : void AudioDeviceBuffer::StopPeriodicLogging() {
     426           0 :   task_queue_.PostTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this,
     427           0 :                                  AudioDeviceBuffer::LOG_STOP));
     428           0 : }
     429             : 
     430           0 : void AudioDeviceBuffer::LogStats(LogState state) {
     431           0 :   RTC_DCHECK_RUN_ON(&task_queue_);
     432           0 :   int64_t now_time = rtc::TimeMillis();
     433             : 
     434           0 :   if (state == AudioDeviceBuffer::LOG_START) {
     435             :     // Reset counters at start. We will not add any logging in this state but
     436             :     // the timer will started by posting a new (delayed) task.
     437           0 :     num_stat_reports_ = 0;
     438           0 :     last_timer_task_time_ = now_time;
     439           0 :     log_stats_ = true;
     440           0 :   } else if (state == AudioDeviceBuffer::LOG_STOP) {
     441             :     // Stop logging and posting new tasks.
     442           0 :     log_stats_ = false;
     443             :   } else if (state == AudioDeviceBuffer::LOG_ACTIVE) {
     444             :     // Keep logging unless logging was disabled while task was posted.
     445             :   }
     446             : 
     447             :   // Avoid adding more logs since we are in STOP mode.
     448           0 :   if (!log_stats_) {
     449           0 :     return;
     450             :   }
     451             : 
     452           0 :   int64_t next_callback_time = now_time + kTimerIntervalInMilliseconds;
     453           0 :   int64_t time_since_last = rtc::TimeDiff(now_time, last_timer_task_time_);
     454           0 :   last_timer_task_time_ = now_time;
     455             : 
     456             :   // Log the latest statistics but skip the first round just after state was
     457             :   // set to LOG_START. Hence, first printed log will be after ~10 seconds.
     458           0 :   if (++num_stat_reports_ > 1 && time_since_last > 0) {
     459           0 :     uint32_t diff_samples = rec_samples_ - last_rec_samples_;
     460           0 :     float rate = diff_samples / (static_cast<float>(time_since_last) / 1000.0);
     461           0 :     LOG(INFO) << "[REC : " << time_since_last << "msec, "
     462           0 :               << rec_sample_rate_ / 1000
     463           0 :               << "kHz] callbacks: " << rec_callbacks_ - last_rec_callbacks_
     464             :               << ", "
     465           0 :               << "samples: " << diff_samples << ", "
     466           0 :               << "rate: " << static_cast<int>(rate + 0.5) << ", "
     467           0 :               << "level: " << max_rec_level_;
     468             : 
     469           0 :     diff_samples = play_samples_ - last_play_samples_;
     470           0 :     rate = diff_samples / (static_cast<float>(time_since_last) / 1000.0);
     471           0 :     LOG(INFO) << "[PLAY: " << time_since_last << "msec, "
     472           0 :               << play_sample_rate_ / 1000
     473           0 :               << "kHz] callbacks: " << play_callbacks_ - last_play_callbacks_
     474             :               << ", "
     475           0 :               << "samples: " << diff_samples << ", "
     476           0 :               << "rate: " << static_cast<int>(rate + 0.5) << ", "
     477           0 :               << "level: " << max_play_level_;
     478             :   }
     479             : 
     480           0 :   last_rec_callbacks_ = rec_callbacks_;
     481           0 :   last_play_callbacks_ = play_callbacks_;
     482           0 :   last_rec_samples_ = rec_samples_;
     483           0 :   last_play_samples_ = play_samples_;
     484           0 :   max_rec_level_ = 0;
     485           0 :   max_play_level_ = 0;
     486             : 
     487           0 :   int64_t time_to_wait_ms = next_callback_time - rtc::TimeMillis();
     488           0 :   RTC_DCHECK_GT(time_to_wait_ms, 0) << "Invalid timer interval";
     489             : 
     490             :   // Keep posting new (delayed) tasks until state is changed to kLogStop.
     491           0 :   task_queue_.PostDelayedTask(rtc::Bind(&AudioDeviceBuffer::LogStats, this,
     492           0 :                                         AudioDeviceBuffer::LOG_ACTIVE),
     493           0 :                               time_to_wait_ms);
     494             : }
     495             : 
     496           0 : void AudioDeviceBuffer::ResetRecStats() {
     497           0 :   RTC_DCHECK_RUN_ON(&task_queue_);
     498           0 :   rec_callbacks_ = 0;
     499           0 :   last_rec_callbacks_ = 0;
     500           0 :   rec_samples_ = 0;
     501           0 :   last_rec_samples_ = 0;
     502           0 :   max_rec_level_ = 0;
     503           0 : }
     504             : 
     505           0 : void AudioDeviceBuffer::ResetPlayStats() {
     506           0 :   RTC_DCHECK_RUN_ON(&task_queue_);
     507           0 :   play_callbacks_ = 0;
     508           0 :   last_play_callbacks_ = 0;
     509           0 :   play_samples_ = 0;
     510           0 :   last_play_samples_ = 0;
     511           0 :   max_play_level_ = 0;
     512           0 : }
     513             : 
     514           0 : void AudioDeviceBuffer::UpdateRecStats(int16_t max_abs,
     515             :                                        size_t samples_per_channel) {
     516           0 :   RTC_DCHECK_RUN_ON(&task_queue_);
     517           0 :   ++rec_callbacks_;
     518           0 :   rec_samples_ += samples_per_channel;
     519           0 :   if (max_abs > max_rec_level_) {
     520           0 :     max_rec_level_ = max_abs;
     521             :   }
     522           0 : }
     523             : 
     524           0 : void AudioDeviceBuffer::UpdatePlayStats(int16_t max_abs,
     525             :                                         size_t samples_per_channel) {
     526           0 :   RTC_DCHECK_RUN_ON(&task_queue_);
     527           0 :   ++play_callbacks_;
     528           0 :   play_samples_ += samples_per_channel;
     529           0 :   if (max_abs > max_play_level_) {
     530           0 :     max_play_level_ = max_abs;
     531             :   }
     532           0 : }
     533             : 
     534             : }  // namespace webrtc

Generated by: LCOV version 1.13