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

Side by Side Diff: media/audio/audio_input_device.cc

Issue 2888383002: Stop source and fire MediaStreamTrack ended event if missing audio input callbacks are detected. (Closed)
Patch Set: Added WebRTC logging in LocalMediaStreamAudioSource::OnCaptureError(). 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') | no next file » | 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"
12 #include "base/strings/stringprintf.h" 13 #include "base/strings/stringprintf.h"
13 #include "base/threading/thread_restrictions.h" 14 #include "base/threading/thread_restrictions.h"
14 #include "base/time/time.h"
15 #include "build/build_config.h" 15 #include "build/build_config.h"
16 #include "media/audio/audio_manager_base.h" 16 #include "media/audio/audio_manager_base.h"
17 #include "media/base/audio_bus.h" 17 #include "media/base/audio_bus.h"
18 18
19 namespace media { 19 namespace media {
20 20
21 namespace {
22
21 // The number of shared memory buffer segments indicated to browser process 23 // 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, 24 // 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 25 // dependent how fast the renderer process can pick up captured data from
24 // shared memory. 26 // shared memory.
25 static const int kRequestedSharedMemoryCount = 10; 27 const int kRequestedSharedMemoryCount = 10;
28
29 // The number of seconds with missing callbacks before we report an error.
30 // The value is based on that the Mac audio implementations (see
31 // media/audio/mac/audio_low_latency_input_mac.h/cc) has a restart mechanism
32 // that triggers after 10 seconds of missing callbacks, and after that an 8
33 // seconds delay before detecting still missing callbacks. We don't want to stop
34 // the source before that to allow logging and stats reporting to take place.
35 // TODO(grunell): The delay in the Mac implementation could probably be shorter.
36 const int kMissingCallbacksTimeBeforeErrorSeconds = 20;
tommi (sloooow) - chröme 2017/05/19 11:00:37 20 seems pretty long. In the comment, can you poi
Henrik Grunell 2017/05/20 08:40:51 Hmm, first of all the 10 seconds is really 10-15 s
37
38 // The interval for checking missing callbacks.
39 const int kCheckMissingCallbacksIntervalSeconds = 5;
40
41 } // namespace
26 42
27 // Takes care of invoking the capture callback on the audio thread. 43 // Takes care of invoking the capture callback on the audio thread.
28 // An instance of this class is created for each capture stream in 44 // An instance of this class is created for each capture stream in
29 // OnLowLatencyCreated(). 45 // OnLowLatencyCreated().
30 class AudioInputDevice::AudioThreadCallback 46 class AudioInputDevice::AudioThreadCallback
31 : public AudioDeviceThread::Callback { 47 : public AudioDeviceThread::Callback {
32 public: 48 public:
33 AudioThreadCallback(const AudioParameters& audio_parameters, 49 using DataCallbackNotificationCallback =
34 base::SharedMemoryHandle memory, 50 base::RepeatingCallback<void(base::TimeTicks last_callback_time)>;
35 int memory_length, 51
36 int total_segments, 52 AudioThreadCallback(
37 CaptureCallback* capture_callback); 53 const AudioParameters& audio_parameters,
54 base::SharedMemoryHandle memory,
55 int memory_length,
56 int total_segments,
57 CaptureCallback* capture_callback,
58 DataCallbackNotificationCallback data_callback_notification_callback);
tommi (sloooow) - chröme 2017/05/19 11:00:37 yo dawg, I heard you like callbacks, so...
ossu-chromium 2017/05/19 11:26:48 Yeah, this name... could it be made a bit clearer?
Henrik Grunell 2017/05/20 08:40:51 Haha, yep it's a callback to notify about a callba
ossu-chromium 2017/05/22 11:27:35 Alright, but this seems very wasteful. IIUC, with
Max Morin 2017/05/22 11:44:59 Another idea is to not use TimeTicks and have an a
Henrik Grunell 2017/05/22 15:04:54 That's a nice idea. However, it seems dangerous si
Henrik Grunell 2017/05/22 15:04:54 Agree.
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_;
72 DataCallbackNotificationCallback data_callback_notification_callback_;
51 73
52 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 74 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
53 }; 75 };
54 76
55 AudioInputDevice::AudioInputDevice( 77 AudioInputDevice::AudioInputDevice(
56 std::unique_ptr<AudioInputIPC> ipc, 78 std::unique_ptr<AudioInputIPC> ipc,
57 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) 79 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
58 : ScopedTaskRunnerObserver(io_task_runner), 80 : ScopedTaskRunnerObserver(io_task_runner),
59 callback_(NULL), 81 callback_(NULL),
60 ipc_(std::move(ipc)), 82 ipc_(std::move(ipc)),
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
139 base::AutoLock auto_lock(audio_thread_lock_); 161 base::AutoLock auto_lock(audio_thread_lock_);
140 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice. 162 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice.
141 // Interface changes need to be made; likely, after AudioInputDevice is merged 163 // Interface changes need to be made; likely, after AudioInputDevice is merged
142 // into AudioOutputDevice (http://crbug.com/179597). 164 // into AudioOutputDevice (http://crbug.com/179597).
143 if (stopping_hack_) 165 if (stopping_hack_)
144 return; 166 return;
145 167
146 DCHECK(!audio_callback_); 168 DCHECK(!audio_callback_);
147 DCHECK(!audio_thread_); 169 DCHECK(!audio_thread_);
148 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback( 170 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback(
149 audio_parameters_, handle, length, total_segments, callback_)); 171 audio_parameters_, handle, length, total_segments, callback_,
172 base::BindRepeating(&AudioInputDevice::SetLastCallbackTime, this)));
150 audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(), 173 audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(),
151 socket_handle, "AudioInputDevice")); 174 socket_handle, "AudioInputDevice"));
152 175
153 state_ = RECORDING; 176 state_ = RECORDING;
154 ipc_->RecordStream(); 177 ipc_->RecordStream();
178
179 // Start detecting missing callbacks.
180 last_callback_time_ = base::TimeTicks::Now();
181 check_alive_timer_.Start(
182 FROM_HERE,
183 base::TimeDelta::FromSeconds(kCheckMissingCallbacksIntervalSeconds), this,
184 &AudioInputDevice::CheckIfInputStreamIsAlive);
185 DCHECK(check_alive_timer_.IsRunning());
155 } 186 }
156 187
157 void AudioInputDevice::OnError() { 188 void AudioInputDevice::OnError() {
158 DCHECK(task_runner()->BelongsToCurrentThread()); 189 DCHECK(task_runner()->BelongsToCurrentThread());
159 190
160 // Do nothing if the stream has been closed. 191 // Do nothing if the stream has been closed.
161 if (state_ < CREATING_STREAM) 192 if (state_ < CREATING_STREAM)
162 return; 193 return;
163 194
164 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)"; 195 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)";
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 } 246 }
216 247
217 state_ = CREATING_STREAM; 248 state_ = CREATING_STREAM;
218 ipc_->CreateStream(this, session_id_, audio_parameters_, 249 ipc_->CreateStream(this, session_id_, audio_parameters_,
219 agc_is_enabled_, kRequestedSharedMemoryCount); 250 agc_is_enabled_, kRequestedSharedMemoryCount);
220 } 251 }
221 252
222 void AudioInputDevice::ShutDownOnIOThread() { 253 void AudioInputDevice::ShutDownOnIOThread() {
223 DCHECK(task_runner()->BelongsToCurrentThread()); 254 DCHECK(task_runner()->BelongsToCurrentThread());
224 255
256 check_alive_timer_.Stop();
257 DCHECK(!check_alive_timer_.IsRunning());
258
225 // Close the stream, if we haven't already. 259 // Close the stream, if we haven't already.
226 if (state_ >= CREATING_STREAM) { 260 if (state_ >= CREATING_STREAM) {
227 ipc_->CloseStream(); 261 ipc_->CloseStream();
228 state_ = IDLE; 262 state_ = IDLE;
229 agc_is_enabled_ = false; 263 agc_is_enabled_ = false;
230 } 264 }
231 265
232 // We can run into an issue where ShutDownOnIOThread is called right after 266 // 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 267 // OnStreamCreated is called in cases where Start/Stop are called before we
234 // get the OnStreamCreated callback. To handle that corner case, we call 268 // 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 295 // We simply store the new AGC setting here. This value will be used when
262 // a new stream is initialized and by GetAutomaticGainControl(). 296 // a new stream is initialized and by GetAutomaticGainControl().
263 agc_is_enabled_ = enabled; 297 agc_is_enabled_ = enabled;
264 } 298 }
265 299
266 void AudioInputDevice::WillDestroyCurrentMessageLoop() { 300 void AudioInputDevice::WillDestroyCurrentMessageLoop() {
267 LOG(ERROR) << "IO loop going away before the input device has been stopped"; 301 LOG(ERROR) << "IO loop going away before the input device has been stopped";
268 ShutDownOnIOThread(); 302 ShutDownOnIOThread();
269 } 303 }
270 304
305 void AudioInputDevice::CheckIfInputStreamIsAlive() {
306 DCHECK(task_runner()->BelongsToCurrentThread());
307 base::TimeDelta time_since_last_callback =
308 base::TimeTicks::Now() - last_callback_time_;
309 if (time_since_last_callback >
310 base::TimeDelta::FromSeconds(kMissingCallbacksTimeBeforeErrorSeconds)) {
311 callback_->OnCaptureError("No audio received from audio capture device.");
ossu-chromium 2017/05/19 11:26:48 Should we also tie this to a UMA stat, like we do
Henrik Grunell 2017/05/20 08:40:51 Thanks for reminding. Yes, we should have that. We
312 }
313 }
314
315 void AudioInputDevice::SetLastCallbackTime(base::TimeTicks last_callback_time) {
316 task_runner()->PostTask(
317 FROM_HERE, base::Bind(&AudioInputDevice::SetLastCallbackTimeOnIOThread,
318 this, last_callback_time));
319 }
320
321 void AudioInputDevice::SetLastCallbackTimeOnIOThread(
322 base::TimeTicks last_callback_time) {
323 DCHECK(task_runner()->BelongsToCurrentThread());
324 last_callback_time_ = last_callback_time;
325 }
326
271 // AudioInputDevice::AudioThreadCallback 327 // AudioInputDevice::AudioThreadCallback
272 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( 328 AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
273 const AudioParameters& audio_parameters, 329 const AudioParameters& audio_parameters,
274 base::SharedMemoryHandle memory, 330 base::SharedMemoryHandle memory,
275 int memory_length, 331 int memory_length,
276 int total_segments, 332 int total_segments,
277 CaptureCallback* capture_callback) 333 CaptureCallback* capture_callback,
334 DataCallbackNotificationCallback data_callback_notification_callback)
278 : AudioDeviceThread::Callback(audio_parameters, 335 : AudioDeviceThread::Callback(audio_parameters,
279 memory, 336 memory,
280 memory_length, 337 memory_length,
281 total_segments), 338 total_segments),
282 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) / 339 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) /
283 base::Time::kMillisecondsPerSecond), 340 base::Time::kMillisecondsPerSecond),
284 current_segment_id_(0), 341 current_segment_id_(0),
285 last_buffer_id_(UINT32_MAX), 342 last_buffer_id_(UINT32_MAX),
286 capture_callback_(capture_callback) {} 343 capture_callback_(capture_callback),
344 data_callback_notification_callback_(
345 std::move(data_callback_notification_callback)) {}
287 346
288 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 347 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
289 } 348 }
290 349
291 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 350 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
292 shared_memory_.Map(memory_length_); 351 shared_memory_.Map(memory_length_);
293 352
294 // Create vector of audio buses by wrapping existing blocks of memory. 353 // Create vector of audio buses by wrapping existing blocks of memory.
295 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory()); 354 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory());
296 for (int i = 0; i < total_segments_; ++i) { 355 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.", 393 "Segment id not matching. Remote = %u. Local = %d.",
335 pending_data, current_segment_id_); 394 pending_data, current_segment_id_);
336 LOG(ERROR) << message; 395 LOG(ERROR) << message;
337 capture_callback_->OnCaptureError(message); 396 capture_callback_->OnCaptureError(message);
338 } 397 }
339 last_buffer_id_ = buffer->params.id; 398 last_buffer_id_ = buffer->params.id;
340 399
341 // Use pre-allocated audio bus wrapping existing block of shared memory. 400 // Use pre-allocated audio bus wrapping existing block of shared memory.
342 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get(); 401 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get();
343 402
403 // Inform that we have gotten a callback.
404 data_callback_notification_callback_.Run(base::TimeTicks::Now());
405
344 // Deliver captured data to the client in floating point format and update 406 // Deliver captured data to the client in floating point format and update
345 // the audio delay measurement. 407 // the audio delay measurement.
346 capture_callback_->Capture( 408 capture_callback_->Capture(
347 audio_bus, 409 audio_bus,
348 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms 410 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms
349 buffer->params.volume, buffer->params.key_pressed); 411 buffer->params.volume, buffer->params.key_pressed);
350 412
351 if (++current_segment_id_ >= total_segments_) 413 if (++current_segment_id_ >= total_segments_)
352 current_segment_id_ = 0; 414 current_segment_id_ = 0;
353 } 415 }
354 416
355 } // namespace media 417 } // namespace media
OLDNEW
« no previous file with comments | « media/audio/audio_input_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698