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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "media/audio/audio_input_device.h" 5 #include "media/audio/audio_input_device.h"
6 6
7 #include <stdint.h> 7 #include <stdint.h>
8 #include <utility> 8 #include <utility>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback_forward.h"
11 #include "base/macros.h" 12 #include "base/macros.h"
13 #include "base/memory/ptr_util.h"
14 #include "base/metrics/histogram_macros.h"
12 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
13 #include "base/threading/thread_restrictions.h" 16 #include "base/threading/thread_restrictions.h"
14 #include "base/time/time.h"
15 #include "build/build_config.h" 17 #include "build/build_config.h"
16 #include "media/audio/audio_manager_base.h" 18 #include "media/audio/audio_manager_base.h"
17 #include "media/base/audio_bus.h" 19 #include "media/base/audio_bus.h"
18 20
19 namespace media { 21 namespace media {
20 22
23 namespace {
24
21 // The number of shared memory buffer segments indicated to browser process 25 // The number of shared memory buffer segments indicated to browser process
22 // in order to avoid data overwriting. This number can be any positive number, 26 // in order to avoid data overwriting. This number can be any positive number,
23 // dependent how fast the renderer process can pick up captured data from 27 // dependent how fast the renderer process can pick up captured data from
24 // shared memory. 28 // shared memory.
25 static const int kRequestedSharedMemoryCount = 10; 29 const int kRequestedSharedMemoryCount = 10;
30
31 // The number of seconds with missing callbacks before we report a capture
32 // error. The value is based on that the Mac audio implementation can defer
33 // start for 5 seconds when resuming after standby, and has a startup success
34 // check 5 seconds after actually starting, where stats is logged. We must allow
35 // enough time for this. See AUAudioInputStream::CheckInputStartupSuccess().
36 const int kMissingCallbacksTimeBeforeErrorSeconds = 12;
37
38 // The interval for checking missing callbacks.
39 const int kCheckMissingCallbacksIntervalSeconds = 5;
40
41 // How often AudioInputDevice::AudioThreadCallback informs that it has gotten
42 // data from the source.
43 const int kGotDataCallbackIntervalSeconds = 1;
44
45 } // namespace
26 46
27 // Takes care of invoking the capture callback on the audio thread. 47 // Takes care of invoking the capture callback on the audio thread.
28 // An instance of this class is created for each capture stream in 48 // An instance of this class is created for each capture stream in
29 // OnLowLatencyCreated(). 49 // OnLowLatencyCreated().
30 class AudioInputDevice::AudioThreadCallback 50 class AudioInputDevice::AudioThreadCallback
31 : public AudioDeviceThread::Callback { 51 : public AudioDeviceThread::Callback {
32 public: 52 public:
33 AudioThreadCallback(const AudioParameters& audio_parameters, 53 AudioThreadCallback(const AudioParameters& audio_parameters,
34 base::SharedMemoryHandle memory, 54 base::SharedMemoryHandle memory,
35 int memory_length, 55 int memory_length,
36 int total_segments, 56 int total_segments,
37 CaptureCallback* capture_callback); 57 CaptureCallback* capture_callback,
58 base::RepeatingClosure got_data_callback);
38 ~AudioThreadCallback() override; 59 ~AudioThreadCallback() override;
39 60
40 void MapSharedMemory() override; 61 void MapSharedMemory() override;
41 62
42 // Called whenever we receive notifications about pending data. 63 // Called whenever we receive notifications about pending data.
43 void Process(uint32_t pending_data) override; 64 void Process(uint32_t pending_data) override;
44 65
45 private: 66 private:
46 const double bytes_per_ms_; 67 const double bytes_per_ms_;
47 int current_segment_id_; 68 int current_segment_id_;
48 uint32_t last_buffer_id_; 69 uint32_t last_buffer_id_;
49 std::vector<std::unique_ptr<media::AudioBus>> audio_buses_; 70 std::vector<std::unique_ptr<media::AudioBus>> audio_buses_;
50 CaptureCallback* capture_callback_; 71 CaptureCallback* capture_callback_;
51 72
73 // Used for informing AudioInputDevice that we have gotten data, i.e. the
74 // stream is alive. |got_data_callback_| is run every
75 // |got_data_callback_interval_in_frames_| frames, calculated from
76 // kGotDataCallbackIntervalSeconds.
77 const int got_data_callback_interval_in_frames_;
78 int frames_since_last_got_data_callback_;
79 base::RepeatingClosure got_data_callback_;
80
52 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 81 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
53 }; 82 };
54 83
55 AudioInputDevice::AudioInputDevice( 84 AudioInputDevice::AudioInputDevice(
56 std::unique_ptr<AudioInputIPC> ipc, 85 std::unique_ptr<AudioInputIPC> ipc,
57 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) 86 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
58 : ScopedTaskRunnerObserver(io_task_runner), 87 : ScopedTaskRunnerObserver(io_task_runner),
59 callback_(NULL), 88 callback_(NULL),
60 ipc_(std::move(ipc)), 89 ipc_(std::move(ipc)),
61 state_(IDLE), 90 state_(IDLE),
62 session_id_(0), 91 session_id_(0),
63 agc_is_enabled_(false), 92 agc_is_enabled_(false),
64 stopping_hack_(false) { 93 stopping_hack_(false),
94 missing_callbacks_detected_(false) {
65 CHECK(ipc_); 95 CHECK(ipc_);
66 96
67 // The correctness of the code depends on the relative values assigned in the 97 // The correctness of the code depends on the relative values assigned in the
68 // State enum. 98 // State enum.
69 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); 99 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0");
70 static_assert(IDLE < CREATING_STREAM, "invalid enum value assignment 1"); 100 static_assert(IDLE < CREATING_STREAM, "invalid enum value assignment 1");
71 static_assert(CREATING_STREAM < RECORDING, "invalid enum value assignment 2"); 101 static_assert(CREATING_STREAM < RECORDING, "invalid enum value assignment 2");
72 } 102 }
73 103
74 void AudioInputDevice::Initialize(const AudioParameters& params, 104 void AudioInputDevice::Initialize(const AudioParameters& params,
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 base::AutoLock auto_lock(audio_thread_lock_); 169 base::AutoLock auto_lock(audio_thread_lock_);
140 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice. 170 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice.
141 // Interface changes need to be made; likely, after AudioInputDevice is merged 171 // Interface changes need to be made; likely, after AudioInputDevice is merged
142 // into AudioOutputDevice (http://crbug.com/179597). 172 // into AudioOutputDevice (http://crbug.com/179597).
143 if (stopping_hack_) 173 if (stopping_hack_)
144 return; 174 return;
145 175
146 DCHECK(!audio_callback_); 176 DCHECK(!audio_callback_);
147 DCHECK(!audio_thread_); 177 DCHECK(!audio_thread_);
148 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback( 178 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback(
149 audio_parameters_, handle, length, total_segments, callback_)); 179 audio_parameters_, handle, length, total_segments, callback_,
180 base::BindRepeating(&AudioInputDevice::SetLastCallbackTimeToNow, this)));
150 audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(), 181 audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(),
151 socket_handle, "AudioInputDevice")); 182 socket_handle, "AudioInputDevice"));
152 183
153 state_ = RECORDING; 184 state_ = RECORDING;
154 ipc_->RecordStream(); 185 ipc_->RecordStream();
186
187 // Start detecting missing callbacks.
188 SetLastCallbackTimeToNowOnIOThread();
189 DCHECK(!check_alive_timer_);
190 check_alive_timer_ = base::MakeUnique<base::RepeatingTimer>();
191 check_alive_timer_->Start(
192 FROM_HERE,
193 base::TimeDelta::FromSeconds(kCheckMissingCallbacksIntervalSeconds), this,
194 &AudioInputDevice::CheckIfInputStreamIsAlive);
195 DCHECK(check_alive_timer_->IsRunning());
155 } 196 }
156 197
157 void AudioInputDevice::OnError() { 198 void AudioInputDevice::OnError() {
158 DCHECK(task_runner()->BelongsToCurrentThread()); 199 DCHECK(task_runner()->BelongsToCurrentThread());
159 200
160 // Do nothing if the stream has been closed. 201 // Do nothing if the stream has been closed.
161 if (state_ < CREATING_STREAM) 202 if (state_ < CREATING_STREAM)
162 return; 203 return;
163 204
164 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)"; 205 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)";
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 } 256 }
216 257
217 state_ = CREATING_STREAM; 258 state_ = CREATING_STREAM;
218 ipc_->CreateStream(this, session_id_, audio_parameters_, 259 ipc_->CreateStream(this, session_id_, audio_parameters_,
219 agc_is_enabled_, kRequestedSharedMemoryCount); 260 agc_is_enabled_, kRequestedSharedMemoryCount);
220 } 261 }
221 262
222 void AudioInputDevice::ShutDownOnIOThread() { 263 void AudioInputDevice::ShutDownOnIOThread() {
223 DCHECK(task_runner()->BelongsToCurrentThread()); 264 DCHECK(task_runner()->BelongsToCurrentThread());
224 265
266 if (check_alive_timer_) {
267 check_alive_timer_->Stop();
268 check_alive_timer_.reset();
269 }
270
271 UMA_HISTOGRAM_BOOLEAN("Media.Audio.Capture.DetectedMissingCallbacks",
272 missing_callbacks_detected_);
273 missing_callbacks_detected_ = false;
274
225 // Close the stream, if we haven't already. 275 // Close the stream, if we haven't already.
226 if (state_ >= CREATING_STREAM) { 276 if (state_ >= CREATING_STREAM) {
227 ipc_->CloseStream(); 277 ipc_->CloseStream();
228 state_ = IDLE; 278 state_ = IDLE;
229 agc_is_enabled_ = false; 279 agc_is_enabled_ = false;
230 } 280 }
231 281
232 // We can run into an issue where ShutDownOnIOThread is called right after 282 // We can run into an issue where ShutDownOnIOThread is called right after
233 // OnStreamCreated is called in cases where Start/Stop are called before we 283 // OnStreamCreated is called in cases where Start/Stop are called before we
234 // get the OnStreamCreated callback. To handle that corner case, we call 284 // get the OnStreamCreated callback. To handle that corner case, we call
(...skipping 26 matching lines...) Expand all
261 // We simply store the new AGC setting here. This value will be used when 311 // We simply store the new AGC setting here. This value will be used when
262 // a new stream is initialized and by GetAutomaticGainControl(). 312 // a new stream is initialized and by GetAutomaticGainControl().
263 agc_is_enabled_ = enabled; 313 agc_is_enabled_ = enabled;
264 } 314 }
265 315
266 void AudioInputDevice::WillDestroyCurrentMessageLoop() { 316 void AudioInputDevice::WillDestroyCurrentMessageLoop() {
267 LOG(ERROR) << "IO loop going away before the input device has been stopped"; 317 LOG(ERROR) << "IO loop going away before the input device has been stopped";
268 ShutDownOnIOThread(); 318 ShutDownOnIOThread();
269 } 319 }
270 320
321 void AudioInputDevice::CheckIfInputStreamIsAlive() {
322 DCHECK(task_runner()->BelongsToCurrentThread());
323 if (base::TimeTicks::Now() - last_callback_time_ >
324 base::TimeDelta::FromSeconds(kMissingCallbacksTimeBeforeErrorSeconds)) {
325 callback_->OnCaptureError("No audio received from audio capture device.");
326 missing_callbacks_detected_ = true;
327 }
328 }
329
330 void AudioInputDevice::SetLastCallbackTimeToNow() {
331 task_runner()->PostTask(
332 FROM_HERE,
333 base::Bind(&AudioInputDevice::SetLastCallbackTimeToNowOnIOThread, this));
334 }
335
336 void AudioInputDevice::SetLastCallbackTimeToNowOnIOThread() {
337 last_callback_time_ = base::TimeTicks::Now();
338 }
339
271 // AudioInputDevice::AudioThreadCallback 340 // AudioInputDevice::AudioThreadCallback
272 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( 341 AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
273 const AudioParameters& audio_parameters, 342 const AudioParameters& audio_parameters,
274 base::SharedMemoryHandle memory, 343 base::SharedMemoryHandle memory,
275 int memory_length, 344 int memory_length,
276 int total_segments, 345 int total_segments,
277 CaptureCallback* capture_callback) 346 CaptureCallback* capture_callback,
347 base::RepeatingClosure got_data_callback_)
278 : AudioDeviceThread::Callback(audio_parameters, 348 : AudioDeviceThread::Callback(audio_parameters,
279 memory, 349 memory,
280 memory_length, 350 memory_length,
281 total_segments), 351 total_segments),
282 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) / 352 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) /
283 base::Time::kMillisecondsPerSecond), 353 base::Time::kMillisecondsPerSecond),
284 current_segment_id_(0), 354 current_segment_id_(0),
285 last_buffer_id_(UINT32_MAX), 355 last_buffer_id_(UINT32_MAX),
286 capture_callback_(capture_callback) {} 356 capture_callback_(capture_callback),
357 got_data_callback_interval_in_frames_(kGotDataCallbackIntervalSeconds *
358 audio_parameters.sample_rate()),
359 frames_since_last_got_data_callback_(0),
360 got_data_callback_(std::move(got_data_callback_)) {}
287 361
288 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 362 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
289 } 363 }
290 364
291 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 365 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
292 shared_memory_.Map(memory_length_); 366 shared_memory_.Map(memory_length_);
293 367
294 // Create vector of audio buses by wrapping existing blocks of memory. 368 // Create vector of audio buses by wrapping existing blocks of memory.
295 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory()); 369 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory());
296 for (int i = 0; i < total_segments_; ++i) { 370 for (int i = 0; i < total_segments_; ++i) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
334 "Segment id not matching. Remote = %u. Local = %d.", 408 "Segment id not matching. Remote = %u. Local = %d.",
335 pending_data, current_segment_id_); 409 pending_data, current_segment_id_);
336 LOG(ERROR) << message; 410 LOG(ERROR) << message;
337 capture_callback_->OnCaptureError(message); 411 capture_callback_->OnCaptureError(message);
338 } 412 }
339 last_buffer_id_ = buffer->params.id; 413 last_buffer_id_ = buffer->params.id;
340 414
341 // Use pre-allocated audio bus wrapping existing block of shared memory. 415 // Use pre-allocated audio bus wrapping existing block of shared memory.
342 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get(); 416 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get();
343 417
418 // Regularly inform that we have gotten data.
419 frames_since_last_got_data_callback_ += audio_bus->frames();
420 if (frames_since_last_got_data_callback_ >=
421 got_data_callback_interval_in_frames_) {
422 got_data_callback_.Run();
423 frames_since_last_got_data_callback_ = 0;
424 }
425
344 // Deliver captured data to the client in floating point format and update 426 // Deliver captured data to the client in floating point format and update
345 // the audio delay measurement. 427 // the audio delay measurement.
346 capture_callback_->Capture( 428 capture_callback_->Capture(
347 audio_bus, 429 audio_bus,
348 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms 430 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms
349 buffer->params.volume, buffer->params.key_pressed); 431 buffer->params.volume, buffer->params.key_pressed);
350 432
351 if (++current_segment_id_ >= total_segments_) 433 if (++current_segment_id_ >= total_segments_)
352 current_segment_id_ = 0; 434 current_segment_id_ = 0;
353 } 435 }
354 436
355 } // namespace media 437 } // namespace media
OLDNEW
« 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