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

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: Moved detection to AudioInputDevice. Cleaned up. 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;
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);
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))
tommi (sloooow) - chröme 2017/05/19 09:11:48 {}
Henrik Grunell 2017/05/19 09:17:41 Done.
311 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
312 }
313
314 void AudioInputDevice::SetLastCallbackTime(base::TimeTicks last_callback_time) {
315 task_runner()->PostTask(
316 FROM_HERE, base::Bind(&AudioInputDevice::SetLastCallbackTimeOnIOThread,
317 this, last_callback_time));
318 }
319
320 void AudioInputDevice::SetLastCallbackTimeOnIOThread(
321 base::TimeTicks last_callback_time) {
322 DCHECK(task_runner()->BelongsToCurrentThread());
323 last_callback_time_ = last_callback_time;
324 }
325
271 // AudioInputDevice::AudioThreadCallback 326 // AudioInputDevice::AudioThreadCallback
272 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( 327 AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
273 const AudioParameters& audio_parameters, 328 const AudioParameters& audio_parameters,
274 base::SharedMemoryHandle memory, 329 base::SharedMemoryHandle memory,
275 int memory_length, 330 int memory_length,
276 int total_segments, 331 int total_segments,
277 CaptureCallback* capture_callback) 332 CaptureCallback* capture_callback,
333 DataCallbackNotificationCallback data_callback_notification_callback)
278 : AudioDeviceThread::Callback(audio_parameters, 334 : AudioDeviceThread::Callback(audio_parameters,
279 memory, 335 memory,
280 memory_length, 336 memory_length,
281 total_segments), 337 total_segments),
282 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) / 338 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) /
283 base::Time::kMillisecondsPerSecond), 339 base::Time::kMillisecondsPerSecond),
284 current_segment_id_(0), 340 current_segment_id_(0),
285 last_buffer_id_(UINT32_MAX), 341 last_buffer_id_(UINT32_MAX),
286 capture_callback_(capture_callback) {} 342 capture_callback_(capture_callback),
343 data_callback_notification_callback_(
344 std::move(data_callback_notification_callback)) {}
287 345
288 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 346 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
289 } 347 }
290 348
291 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 349 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
292 shared_memory_.Map(memory_length_); 350 shared_memory_.Map(memory_length_);
293 351
294 // Create vector of audio buses by wrapping existing blocks of memory. 352 // Create vector of audio buses by wrapping existing blocks of memory.
295 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory()); 353 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory());
296 for (int i = 0; i < total_segments_; ++i) { 354 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.", 392 "Segment id not matching. Remote = %u. Local = %d.",
335 pending_data, current_segment_id_); 393 pending_data, current_segment_id_);
336 LOG(ERROR) << message; 394 LOG(ERROR) << message;
337 capture_callback_->OnCaptureError(message); 395 capture_callback_->OnCaptureError(message);
338 } 396 }
339 last_buffer_id_ = buffer->params.id; 397 last_buffer_id_ = buffer->params.id;
340 398
341 // Use pre-allocated audio bus wrapping existing block of shared memory. 399 // Use pre-allocated audio bus wrapping existing block of shared memory.
342 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get(); 400 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get();
343 401
402 // Inform that we have gotten a callback.
403 data_callback_notification_callback_.Run(base::TimeTicks::Now());
404
344 // Deliver captured data to the client in floating point format and update 405 // Deliver captured data to the client in floating point format and update
345 // the audio delay measurement. 406 // the audio delay measurement.
346 capture_callback_->Capture( 407 capture_callback_->Capture(
347 audio_bus, 408 audio_bus,
348 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms 409 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms
349 buffer->params.volume, buffer->params.key_pressed); 410 buffer->params.volume, buffer->params.key_pressed);
350 411
351 if (++current_segment_id_ >= total_segments_) 412 if (++current_segment_id_ >= total_segments_)
352 current_segment_id_ = 0; 413 current_segment_id_ = 0;
353 } 414 }
354 415
355 } // namespace media 416 } // 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