Chromium Code Reviews| Index: media/audio/audio_input_device.cc |
| diff --git a/media/audio/audio_input_device.cc b/media/audio/audio_input_device.cc |
| index 3b83deb10e3475b9aee2c1415b73a0e00e7f718a..bb92dadac227d2e3d2d641867c22a157f1f5707d 100644 |
| --- a/media/audio/audio_input_device.cc |
| +++ b/media/audio/audio_input_device.cc |
| @@ -8,21 +8,37 @@ |
| #include <utility> |
| #include "base/bind.h" |
| +#include "base/callback_forward.h" |
| #include "base/macros.h" |
| #include "base/strings/stringprintf.h" |
| #include "base/threading/thread_restrictions.h" |
| -#include "base/time/time.h" |
| #include "build/build_config.h" |
| #include "media/audio/audio_manager_base.h" |
| #include "media/base/audio_bus.h" |
| namespace media { |
| +namespace { |
| + |
| // The number of shared memory buffer segments indicated to browser process |
| // in order to avoid data overwriting. This number can be any positive number, |
| // dependent how fast the renderer process can pick up captured data from |
| // shared memory. |
| -static const int kRequestedSharedMemoryCount = 10; |
| +const int kRequestedSharedMemoryCount = 10; |
| + |
| +// The number of seconds with missing callbacks before we report an error. |
| +// The value is based on that the Mac audio implementations (see |
| +// media/audio/mac/audio_low_latency_input_mac.h/cc) has a restart mechanism |
| +// that triggers after 10 seconds of missing callbacks, and after that an 8 |
| +// seconds delay before detecting still missing callbacks. We don't want to stop |
| +// the source before that to allow logging and stats reporting to take place. |
| +// TODO(grunell): The delay in the Mac implementation could probably be shorter. |
| +const int kMissingCallbacksTimeBeforeErrorSeconds = 20; |
| + |
| +// The interval for checking missing callbacks. |
| +const int kCheckMissingCallbacksIntervalSeconds = 5; |
| + |
| +} // namespace |
| // Takes care of invoking the capture callback on the audio thread. |
| // An instance of this class is created for each capture stream in |
| @@ -30,11 +46,16 @@ static const int kRequestedSharedMemoryCount = 10; |
| class AudioInputDevice::AudioThreadCallback |
| : public AudioDeviceThread::Callback { |
| public: |
| - AudioThreadCallback(const AudioParameters& audio_parameters, |
| - base::SharedMemoryHandle memory, |
| - int memory_length, |
| - int total_segments, |
| - CaptureCallback* capture_callback); |
| + using DataCallbackNotificationCallback = |
| + base::RepeatingCallback<void(base::TimeTicks last_callback_time)>; |
| + |
| + AudioThreadCallback( |
| + const AudioParameters& audio_parameters, |
| + base::SharedMemoryHandle memory, |
| + int memory_length, |
| + int total_segments, |
| + CaptureCallback* capture_callback, |
| + DataCallbackNotificationCallback data_callback_notification_callback); |
| ~AudioThreadCallback() override; |
| void MapSharedMemory() override; |
| @@ -48,6 +69,7 @@ class AudioInputDevice::AudioThreadCallback |
| uint32_t last_buffer_id_; |
| std::vector<std::unique_ptr<media::AudioBus>> audio_buses_; |
| CaptureCallback* capture_callback_; |
| + DataCallbackNotificationCallback data_callback_notification_callback_; |
| DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); |
| }; |
| @@ -146,12 +168,21 @@ void AudioInputDevice::OnStreamCreated( |
| DCHECK(!audio_callback_); |
| DCHECK(!audio_thread_); |
| audio_callback_.reset(new AudioInputDevice::AudioThreadCallback( |
| - audio_parameters_, handle, length, total_segments, callback_)); |
| + audio_parameters_, handle, length, total_segments, callback_, |
| + base::BindRepeating(&AudioInputDevice::SetLastCallbackTime, this))); |
| audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(), |
| socket_handle, "AudioInputDevice")); |
| state_ = RECORDING; |
| ipc_->RecordStream(); |
| + |
| + // Start detecting missing callbacks. |
| + last_callback_time_ = base::TimeTicks::Now(); |
| + check_alive_timer_.Start( |
| + FROM_HERE, |
| + base::TimeDelta::FromSeconds(kCheckMissingCallbacksIntervalSeconds), this, |
| + &AudioInputDevice::CheckIfInputStreamIsAlive); |
| + DCHECK(check_alive_timer_.IsRunning()); |
| } |
| void AudioInputDevice::OnError() { |
| @@ -222,6 +253,9 @@ void AudioInputDevice::StartUpOnIOThread() { |
| void AudioInputDevice::ShutDownOnIOThread() { |
| DCHECK(task_runner()->BelongsToCurrentThread()); |
| + check_alive_timer_.Stop(); |
| + DCHECK(!check_alive_timer_.IsRunning()); |
| + |
| // Close the stream, if we haven't already. |
| if (state_ >= CREATING_STREAM) { |
| ipc_->CloseStream(); |
| @@ -268,13 +302,35 @@ void AudioInputDevice::WillDestroyCurrentMessageLoop() { |
| ShutDownOnIOThread(); |
| } |
| +void AudioInputDevice::CheckIfInputStreamIsAlive() { |
| + DCHECK(task_runner()->BelongsToCurrentThread()); |
| + base::TimeDelta time_since_last_callback = |
| + base::TimeTicks::Now() - last_callback_time_; |
| + if (time_since_last_callback > |
| + base::TimeDelta::FromSeconds(kMissingCallbacksTimeBeforeErrorSeconds)) |
|
tommi (sloooow) - chröme
2017/05/19 09:11:48
{}
Henrik Grunell
2017/05/19 09:17:41
Done.
|
| + callback_->OnCaptureError("Detected missing callbacks."); |
|
tommi (sloooow) - chröme
2017/05/19 09:11:48
what about something like "No audio received from
Henrik Grunell
2017/05/19 09:17:41
Oops, forgot to update this text. Thanks, your sug
|
| +} |
| + |
| +void AudioInputDevice::SetLastCallbackTime(base::TimeTicks last_callback_time) { |
| + task_runner()->PostTask( |
| + FROM_HERE, base::Bind(&AudioInputDevice::SetLastCallbackTimeOnIOThread, |
| + this, last_callback_time)); |
| +} |
| + |
| +void AudioInputDevice::SetLastCallbackTimeOnIOThread( |
| + base::TimeTicks last_callback_time) { |
| + DCHECK(task_runner()->BelongsToCurrentThread()); |
| + last_callback_time_ = last_callback_time; |
| +} |
| + |
| // AudioInputDevice::AudioThreadCallback |
| AudioInputDevice::AudioThreadCallback::AudioThreadCallback( |
| const AudioParameters& audio_parameters, |
| base::SharedMemoryHandle memory, |
| int memory_length, |
| int total_segments, |
| - CaptureCallback* capture_callback) |
| + CaptureCallback* capture_callback, |
| + DataCallbackNotificationCallback data_callback_notification_callback) |
| : AudioDeviceThread::Callback(audio_parameters, |
| memory, |
| memory_length, |
| @@ -283,7 +339,9 @@ AudioInputDevice::AudioThreadCallback::AudioThreadCallback( |
| base::Time::kMillisecondsPerSecond), |
| current_segment_id_(0), |
| last_buffer_id_(UINT32_MAX), |
| - capture_callback_(capture_callback) {} |
| + capture_callback_(capture_callback), |
| + data_callback_notification_callback_( |
| + std::move(data_callback_notification_callback)) {} |
| AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { |
| } |
| @@ -341,6 +399,9 @@ void AudioInputDevice::AudioThreadCallback::Process(uint32_t pending_data) { |
| // Use pre-allocated audio bus wrapping existing block of shared memory. |
| media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get(); |
| + // Inform that we have gotten a callback. |
| + data_callback_notification_callback_.Run(base::TimeTicks::Now()); |
| + |
| // Deliver captured data to the client in floating point format and update |
| // the audio delay measurement. |
| capture_callback_->Capture( |