Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(974)

Unified Diff: media/audio/audio_input_device.cc

Issue 2899413004: RL: Stop source and fire MediaStreamTrack ended event if missing audio input callbacks are detected. (Closed)
Patch Set: Only stop timer if created. (We can Stop() without Start()ed.) Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/audio/audio_input_device.h ('k') | tools/metrics/histograms/enums.xml » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..66966381cdcc46ab9f264d3ac2db7ad854bf4d90 100644
--- a/media/audio/audio_input_device.cc
+++ b/media/audio/audio_input_device.cc
@@ -8,21 +8,41 @@
#include <utility>
#include "base/bind.h"
+#include "base/callback_forward.h"
#include "base/macros.h"
+#include "base/memory/ptr_util.h"
+#include "base/metrics/histogram_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 a capture
+// error. The value is based on that the Mac audio implementation can defer
+// start for 5 seconds when resuming after standby, and has a startup success
+// check 5 seconds after actually starting, where stats is logged. We must allow
+// enough time for this. See AUAudioInputStream::CheckInputStartupSuccess().
+const int kMissingCallbacksTimeBeforeErrorSeconds = 12;
+
+// The interval for checking missing callbacks.
+const int kCheckMissingCallbacksIntervalSeconds = 5;
+
+// How often AudioInputDevice::AudioThreadCallback informs that it has gotten
+// data from the source.
+const int kGotDataCallbackIntervalSeconds = 1;
+
+} // namespace
// Takes care of invoking the capture callback on the audio thread.
// An instance of this class is created for each capture stream in
@@ -34,7 +54,8 @@ class AudioInputDevice::AudioThreadCallback
base::SharedMemoryHandle memory,
int memory_length,
int total_segments,
- CaptureCallback* capture_callback);
+ CaptureCallback* capture_callback,
+ base::RepeatingClosure got_data_callback);
~AudioThreadCallback() override;
void MapSharedMemory() override;
@@ -49,6 +70,14 @@ class AudioInputDevice::AudioThreadCallback
std::vector<std::unique_ptr<media::AudioBus>> audio_buses_;
CaptureCallback* capture_callback_;
+ // Used for informing AudioInputDevice that we have gotten data, i.e. the
+ // stream is alive. |got_data_callback_| is run every
+ // |got_data_callback_interval_in_frames_| frames, calculated from
+ // kGotDataCallbackIntervalSeconds.
+ const int got_data_callback_interval_in_frames_;
+ int frames_since_last_got_data_callback_;
+ base::RepeatingClosure got_data_callback_;
+
DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
};
@@ -61,7 +90,8 @@ AudioInputDevice::AudioInputDevice(
state_(IDLE),
session_id_(0),
agc_is_enabled_(false),
- stopping_hack_(false) {
+ stopping_hack_(false),
+ missing_callbacks_detected_(false) {
CHECK(ipc_);
// The correctness of the code depends on the relative values assigned in the
@@ -146,12 +176,23 @@ 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::SetLastCallbackTimeToNow, this)));
audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(),
socket_handle, "AudioInputDevice"));
state_ = RECORDING;
ipc_->RecordStream();
+
+ // Start detecting missing callbacks.
+ SetLastCallbackTimeToNowOnIOThread();
+ DCHECK(!check_alive_timer_);
+ check_alive_timer_ = base::MakeUnique<base::RepeatingTimer>();
+ check_alive_timer_->Start(
+ FROM_HERE,
+ base::TimeDelta::FromSeconds(kCheckMissingCallbacksIntervalSeconds), this,
+ &AudioInputDevice::CheckIfInputStreamIsAlive);
+ DCHECK(check_alive_timer_->IsRunning());
}
void AudioInputDevice::OnError() {
@@ -222,6 +263,15 @@ void AudioInputDevice::StartUpOnIOThread() {
void AudioInputDevice::ShutDownOnIOThread() {
DCHECK(task_runner()->BelongsToCurrentThread());
+ if (check_alive_timer_) {
+ check_alive_timer_->Stop();
+ check_alive_timer_.reset();
+ }
+
+ UMA_HISTOGRAM_BOOLEAN("Media.Audio.Capture.DetectedMissingCallbacks",
+ missing_callbacks_detected_);
+ missing_callbacks_detected_ = false;
+
// Close the stream, if we haven't already.
if (state_ >= CREATING_STREAM) {
ipc_->CloseStream();
@@ -268,13 +318,33 @@ void AudioInputDevice::WillDestroyCurrentMessageLoop() {
ShutDownOnIOThread();
}
+void AudioInputDevice::CheckIfInputStreamIsAlive() {
+ DCHECK(task_runner()->BelongsToCurrentThread());
+ if (base::TimeTicks::Now() - last_callback_time_ >
+ base::TimeDelta::FromSeconds(kMissingCallbacksTimeBeforeErrorSeconds)) {
+ callback_->OnCaptureError("No audio received from audio capture device.");
+ missing_callbacks_detected_ = true;
+ }
+}
+
+void AudioInputDevice::SetLastCallbackTimeToNow() {
+ task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&AudioInputDevice::SetLastCallbackTimeToNowOnIOThread, this));
+}
+
+void AudioInputDevice::SetLastCallbackTimeToNowOnIOThread() {
+ last_callback_time_ = base::TimeTicks::Now();
+}
+
// AudioInputDevice::AudioThreadCallback
AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
const AudioParameters& audio_parameters,
base::SharedMemoryHandle memory,
int memory_length,
int total_segments,
- CaptureCallback* capture_callback)
+ CaptureCallback* capture_callback,
+ base::RepeatingClosure got_data_callback_)
: AudioDeviceThread::Callback(audio_parameters,
memory,
memory_length,
@@ -283,7 +353,11 @@ AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
base::Time::kMillisecondsPerSecond),
current_segment_id_(0),
last_buffer_id_(UINT32_MAX),
- capture_callback_(capture_callback) {}
+ capture_callback_(capture_callback),
+ got_data_callback_interval_in_frames_(kGotDataCallbackIntervalSeconds *
+ audio_parameters.sample_rate()),
+ frames_since_last_got_data_callback_(0),
+ got_data_callback_(std::move(got_data_callback_)) {}
AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
}
@@ -341,6 +415,14 @@ 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();
+ // Regularly inform that we have gotten data.
+ frames_since_last_got_data_callback_ += audio_bus->frames();
+ if (frames_since_last_got_data_callback_ >=
+ got_data_callback_interval_in_frames_) {
+ got_data_callback_.Run();
+ frames_since_last_got_data_callback_ = 0;
+ }
+
// Deliver captured data to the client in floating point format and update
// the audio delay measurement.
capture_callback_->Capture(
« no previous file with comments | « media/audio/audio_input_device.h ('k') | tools/metrics/histograms/enums.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698