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

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