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

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: Code review (ossu@ and tommi@). 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
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/metrics/histogram_macros.h"
12 #include "base/strings/stringprintf.h" 14 #include "base/strings/stringprintf.h"
13 #include "base/threading/thread_restrictions.h" 15 #include "base/threading/thread_restrictions.h"
14 #include "base/time/time.h"
15 #include "build/build_config.h" 16 #include "build/build_config.h"
16 #include "media/audio/audio_manager_base.h" 17 #include "media/audio/audio_manager_base.h"
17 #include "media/base/audio_bus.h" 18 #include "media/base/audio_bus.h"
18 19
19 namespace media { 20 namespace media {
20 21
22 namespace {
23
21 // The number of shared memory buffer segments indicated to browser process 24 // 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, 25 // 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 26 // dependent how fast the renderer process can pick up captured data from
24 // shared memory. 27 // shared memory.
25 static const int kRequestedSharedMemoryCount = 10; 28 const int kRequestedSharedMemoryCount = 10;
29
30 // The number of seconds with missing callbacks before we report a capture
31 // error. The value is based on that the Mac audio implementation has a restart
32 // mechanism that triggers after 10-15 seconds of missing callbacks. We must
33 // allow enough time for that restart. See
34 // AUAudioInputStream::CheckIfInputStreamIsAlive().
35 const int kMissingCallbacksTimeBeforeErrorSeconds = 20;
36
37 // The interval for checking missing callbacks.
38 const int kCheckMissingCallbacksIntervalSeconds = 5;
39
40 } // namespace
26 41
27 // Takes care of invoking the capture callback on the audio thread. 42 // Takes care of invoking the capture callback on the audio thread.
28 // An instance of this class is created for each capture stream in 43 // An instance of this class is created for each capture stream in
29 // OnLowLatencyCreated(). 44 // OnLowLatencyCreated().
30 class AudioInputDevice::AudioThreadCallback 45 class AudioInputDevice::AudioThreadCallback
31 : public AudioDeviceThread::Callback { 46 : public AudioDeviceThread::Callback {
32 public: 47 public:
48 using GotDataCallback =
49 base::RepeatingCallback<void(base::TimeTicks got_data_time)>;
50
33 AudioThreadCallback(const AudioParameters& audio_parameters, 51 AudioThreadCallback(const AudioParameters& audio_parameters,
34 base::SharedMemoryHandle memory, 52 base::SharedMemoryHandle memory,
35 int memory_length, 53 int memory_length,
36 int total_segments, 54 int total_segments,
37 CaptureCallback* capture_callback); 55 CaptureCallback* capture_callback,
56 GotDataCallback got_data_callback);
38 ~AudioThreadCallback() override; 57 ~AudioThreadCallback() override;
39 58
40 void MapSharedMemory() override; 59 void MapSharedMemory() override;
41 60
42 // Called whenever we receive notifications about pending data. 61 // Called whenever we receive notifications about pending data.
43 void Process(uint32_t pending_data) override; 62 void Process(uint32_t pending_data) override;
44 63
45 private: 64 private:
46 const double bytes_per_ms_; 65 const double bytes_per_ms_;
47 int current_segment_id_; 66 int current_segment_id_;
48 uint32_t last_buffer_id_; 67 uint32_t last_buffer_id_;
49 std::vector<std::unique_ptr<media::AudioBus>> audio_buses_; 68 std::vector<std::unique_ptr<media::AudioBus>> audio_buses_;
50 CaptureCallback* capture_callback_; 69 CaptureCallback* capture_callback_;
70 GotDataCallback got_data_callback_;
51 71
52 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback); 72 DISALLOW_COPY_AND_ASSIGN(AudioThreadCallback);
53 }; 73 };
54 74
55 AudioInputDevice::AudioInputDevice( 75 AudioInputDevice::AudioInputDevice(
56 std::unique_ptr<AudioInputIPC> ipc, 76 std::unique_ptr<AudioInputIPC> ipc,
57 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner) 77 const scoped_refptr<base::SingleThreadTaskRunner>& io_task_runner)
58 : ScopedTaskRunnerObserver(io_task_runner), 78 : ScopedTaskRunnerObserver(io_task_runner),
59 callback_(NULL), 79 callback_(NULL),
60 ipc_(std::move(ipc)), 80 ipc_(std::move(ipc)),
61 state_(IDLE), 81 state_(IDLE),
62 session_id_(0), 82 session_id_(0),
63 agc_is_enabled_(false), 83 agc_is_enabled_(false),
64 stopping_hack_(false) { 84 stopping_hack_(false),
85 missing_callbacks_detected_(false) {
65 CHECK(ipc_); 86 CHECK(ipc_);
66 87
67 // The correctness of the code depends on the relative values assigned in the 88 // The correctness of the code depends on the relative values assigned in the
68 // State enum. 89 // State enum.
69 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0"); 90 static_assert(IPC_CLOSED < IDLE, "invalid enum value assignment 0");
70 static_assert(IDLE < CREATING_STREAM, "invalid enum value assignment 1"); 91 static_assert(IDLE < CREATING_STREAM, "invalid enum value assignment 1");
71 static_assert(CREATING_STREAM < RECORDING, "invalid enum value assignment 2"); 92 static_assert(CREATING_STREAM < RECORDING, "invalid enum value assignment 2");
72 } 93 }
73 94
74 void AudioInputDevice::Initialize(const AudioParameters& params, 95 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_); 160 base::AutoLock auto_lock(audio_thread_lock_);
140 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice. 161 // TODO(miu): See TODO in OnStreamCreated method for AudioOutputDevice.
141 // Interface changes need to be made; likely, after AudioInputDevice is merged 162 // Interface changes need to be made; likely, after AudioInputDevice is merged
142 // into AudioOutputDevice (http://crbug.com/179597). 163 // into AudioOutputDevice (http://crbug.com/179597).
143 if (stopping_hack_) 164 if (stopping_hack_)
144 return; 165 return;
145 166
146 DCHECK(!audio_callback_); 167 DCHECK(!audio_callback_);
147 DCHECK(!audio_thread_); 168 DCHECK(!audio_thread_);
148 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback( 169 audio_callback_.reset(new AudioInputDevice::AudioThreadCallback(
149 audio_parameters_, handle, length, total_segments, callback_)); 170 audio_parameters_, handle, length, total_segments, callback_,
171 base::BindRepeating(&AudioInputDevice::SetLastCallbackTime, this)));
150 audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(), 172 audio_thread_.reset(new AudioDeviceThread(audio_callback_.get(),
151 socket_handle, "AudioInputDevice")); 173 socket_handle, "AudioInputDevice"));
152 174
153 state_ = RECORDING; 175 state_ = RECORDING;
154 ipc_->RecordStream(); 176 ipc_->RecordStream();
177
178 // Start detecting missing callbacks.
179 last_callback_time_ = base::TimeTicks::Now();
180 check_alive_timer_.Start(
181 FROM_HERE,
182 base::TimeDelta::FromSeconds(kCheckMissingCallbacksIntervalSeconds), this,
183 &AudioInputDevice::CheckIfInputStreamIsAlive);
184 DCHECK(check_alive_timer_.IsRunning());
155 } 185 }
156 186
157 void AudioInputDevice::OnError() { 187 void AudioInputDevice::OnError() {
158 DCHECK(task_runner()->BelongsToCurrentThread()); 188 DCHECK(task_runner()->BelongsToCurrentThread());
159 189
160 // Do nothing if the stream has been closed. 190 // Do nothing if the stream has been closed.
161 if (state_ < CREATING_STREAM) 191 if (state_ < CREATING_STREAM)
162 return; 192 return;
163 193
164 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)"; 194 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(ERROR)";
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
215 } 245 }
216 246
217 state_ = CREATING_STREAM; 247 state_ = CREATING_STREAM;
218 ipc_->CreateStream(this, session_id_, audio_parameters_, 248 ipc_->CreateStream(this, session_id_, audio_parameters_,
219 agc_is_enabled_, kRequestedSharedMemoryCount); 249 agc_is_enabled_, kRequestedSharedMemoryCount);
220 } 250 }
221 251
222 void AudioInputDevice::ShutDownOnIOThread() { 252 void AudioInputDevice::ShutDownOnIOThread() {
223 DCHECK(task_runner()->BelongsToCurrentThread()); 253 DCHECK(task_runner()->BelongsToCurrentThread());
224 254
255 check_alive_timer_.Stop();
256
257 UMA_HISTOGRAM_BOOLEAN("Media.Audio.Capture.DetectedMissingCallbacks",
258 missing_callbacks_detected_);
259 missing_callbacks_detected_ = false;
260
225 // Close the stream, if we haven't already. 261 // Close the stream, if we haven't already.
226 if (state_ >= CREATING_STREAM) { 262 if (state_ >= CREATING_STREAM) {
227 ipc_->CloseStream(); 263 ipc_->CloseStream();
228 state_ = IDLE; 264 state_ = IDLE;
229 agc_is_enabled_ = false; 265 agc_is_enabled_ = false;
230 } 266 }
231 267
232 // We can run into an issue where ShutDownOnIOThread is called right after 268 // 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 269 // OnStreamCreated is called in cases where Start/Stop are called before we
234 // get the OnStreamCreated callback. To handle that corner case, we call 270 // 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 297 // We simply store the new AGC setting here. This value will be used when
262 // a new stream is initialized and by GetAutomaticGainControl(). 298 // a new stream is initialized and by GetAutomaticGainControl().
263 agc_is_enabled_ = enabled; 299 agc_is_enabled_ = enabled;
264 } 300 }
265 301
266 void AudioInputDevice::WillDestroyCurrentMessageLoop() { 302 void AudioInputDevice::WillDestroyCurrentMessageLoop() {
267 LOG(ERROR) << "IO loop going away before the input device has been stopped"; 303 LOG(ERROR) << "IO loop going away before the input device has been stopped";
268 ShutDownOnIOThread(); 304 ShutDownOnIOThread();
269 } 305 }
270 306
307 void AudioInputDevice::CheckIfInputStreamIsAlive() {
308 DCHECK(task_runner()->BelongsToCurrentThread());
309 base::TimeDelta time_since_last_callback =
310 base::TimeTicks::Now() - last_callback_time_;
311 if (time_since_last_callback >
312 base::TimeDelta::FromSeconds(kMissingCallbacksTimeBeforeErrorSeconds)) {
313 callback_->OnCaptureError("No audio received from audio capture device.");
314 missing_callbacks_detected_ = true;
315 }
316 }
317
318 void AudioInputDevice::SetLastCallbackTime(base::TimeTicks last_callback_time) {
319 task_runner()->PostTask(
320 FROM_HERE, base::Bind(&AudioInputDevice::SetLastCallbackTimeOnIOThread,
321 this, last_callback_time));
322 }
323
324 void AudioInputDevice::SetLastCallbackTimeOnIOThread(
325 base::TimeTicks last_callback_time) {
326 DCHECK(task_runner()->BelongsToCurrentThread());
327 last_callback_time_ = last_callback_time;
328 }
329
271 // AudioInputDevice::AudioThreadCallback 330 // AudioInputDevice::AudioThreadCallback
272 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( 331 AudioInputDevice::AudioThreadCallback::AudioThreadCallback(
273 const AudioParameters& audio_parameters, 332 const AudioParameters& audio_parameters,
274 base::SharedMemoryHandle memory, 333 base::SharedMemoryHandle memory,
275 int memory_length, 334 int memory_length,
276 int total_segments, 335 int total_segments,
277 CaptureCallback* capture_callback) 336 CaptureCallback* capture_callback,
337 GotDataCallback got_data_callback_)
278 : AudioDeviceThread::Callback(audio_parameters, 338 : AudioDeviceThread::Callback(audio_parameters,
279 memory, 339 memory,
280 memory_length, 340 memory_length,
281 total_segments), 341 total_segments),
282 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) / 342 bytes_per_ms_(static_cast<double>(audio_parameters.GetBytesPerSecond()) /
283 base::Time::kMillisecondsPerSecond), 343 base::Time::kMillisecondsPerSecond),
284 current_segment_id_(0), 344 current_segment_id_(0),
285 last_buffer_id_(UINT32_MAX), 345 last_buffer_id_(UINT32_MAX),
286 capture_callback_(capture_callback) {} 346 capture_callback_(capture_callback),
347 got_data_callback_(std::move(got_data_callback_)) {}
287 348
288 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { 349 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() {
289 } 350 }
290 351
291 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { 352 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() {
292 shared_memory_.Map(memory_length_); 353 shared_memory_.Map(memory_length_);
293 354
294 // Create vector of audio buses by wrapping existing blocks of memory. 355 // Create vector of audio buses by wrapping existing blocks of memory.
295 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory()); 356 uint8_t* ptr = static_cast<uint8_t*>(shared_memory_.memory());
296 for (int i = 0; i < total_segments_; ++i) { 357 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.", 395 "Segment id not matching. Remote = %u. Local = %d.",
335 pending_data, current_segment_id_); 396 pending_data, current_segment_id_);
336 LOG(ERROR) << message; 397 LOG(ERROR) << message;
337 capture_callback_->OnCaptureError(message); 398 capture_callback_->OnCaptureError(message);
338 } 399 }
339 last_buffer_id_ = buffer->params.id; 400 last_buffer_id_ = buffer->params.id;
340 401
341 // Use pre-allocated audio bus wrapping existing block of shared memory. 402 // Use pre-allocated audio bus wrapping existing block of shared memory.
342 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get(); 403 media::AudioBus* audio_bus = audio_buses_[current_segment_id_].get();
343 404
405 // Inform that we have gotten data.
406 got_data_callback_.Run(base::TimeTicks::Now());
407
344 // Deliver captured data to the client in floating point format and update 408 // Deliver captured data to the client in floating point format and update
345 // the audio delay measurement. 409 // the audio delay measurement.
346 capture_callback_->Capture( 410 capture_callback_->Capture(
347 audio_bus, 411 audio_bus,
348 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms 412 buffer->params.hardware_delay_bytes / bytes_per_ms_, // Delay in ms
349 buffer->params.volume, buffer->params.key_pressed); 413 buffer->params.volume, buffer->params.key_pressed);
350 414
351 if (++current_segment_id_ >= total_segments_) 415 if (++current_segment_id_ >= total_segments_)
352 current_segment_id_ = 0; 416 current_segment_id_ = 0;
353 } 417 }
354 418
355 } // namespace media 419 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698