OLD | NEW |
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_controller.h" | 5 #include "media/audio/audio_input_controller.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/threading/thread_restrictions.h" | 8 #include "base/threading/thread_restrictions.h" |
9 #include "media/base/limits.h" | 9 #include "media/base/limits.h" |
10 #include "media/base/scoped_histogram_timer.h" | 10 #include "media/base/scoped_histogram_timer.h" |
(...skipping 18 matching lines...) Expand all Loading... |
29 const int kTimerInitialIntervalSeconds = 5; | 29 const int kTimerInitialIntervalSeconds = 5; |
30 #endif // defined(OS_IOS) | 30 #endif // defined(OS_IOS) |
31 } | 31 } |
32 | 32 |
33 namespace media { | 33 namespace media { |
34 | 34 |
35 // static | 35 // static |
36 AudioInputController::Factory* AudioInputController::factory_ = NULL; | 36 AudioInputController::Factory* AudioInputController::factory_ = NULL; |
37 | 37 |
38 AudioInputController::AudioInputController(EventHandler* handler, | 38 AudioInputController::AudioInputController(EventHandler* handler, |
39 SyncWriter* sync_writer, | 39 SyncWriter* sync_writer) |
40 UserInputMonitor* user_input_monitor) | |
41 : creator_loop_(base::MessageLoopProxy::current()), | 40 : creator_loop_(base::MessageLoopProxy::current()), |
42 handler_(handler), | 41 handler_(handler), |
43 stream_(NULL), | 42 stream_(NULL), |
44 data_is_active_(false), | 43 data_is_active_(false), |
45 state_(kEmpty), | 44 state_(kEmpty), |
46 sync_writer_(sync_writer), | 45 sync_writer_(sync_writer), |
47 max_volume_(0.0), | 46 max_volume_(0.0) { |
48 user_input_monitor_(user_input_monitor), | |
49 key_pressed_(false) { | |
50 DCHECK(creator_loop_.get()); | 47 DCHECK(creator_loop_.get()); |
51 } | 48 } |
52 | 49 |
53 AudioInputController::~AudioInputController() { | 50 AudioInputController::~AudioInputController() { |
54 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); | 51 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); |
55 } | 52 } |
56 | 53 |
57 // static | 54 // static |
58 scoped_refptr<AudioInputController> AudioInputController::Create( | 55 scoped_refptr<AudioInputController> AudioInputController::Create( |
59 AudioManager* audio_manager, | 56 AudioManager* audio_manager, |
60 EventHandler* event_handler, | 57 EventHandler* event_handler, |
61 const AudioParameters& params, | 58 const AudioParameters& params, |
62 const std::string& device_id, | 59 const std::string& device_id) { |
63 UserInputMonitor* user_input_monitor) { | |
64 DCHECK(audio_manager); | 60 DCHECK(audio_manager); |
65 | 61 |
66 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 62 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
67 return NULL; | 63 return NULL; |
68 | 64 |
69 if (factory_) { | 65 if (factory_) |
70 return factory_->Create( | 66 return factory_->Create(audio_manager, event_handler, params); |
71 audio_manager, event_handler, params, user_input_monitor); | 67 |
72 } | 68 scoped_refptr<AudioInputController> controller(new AudioInputController( |
73 scoped_refptr<AudioInputController> controller( | 69 event_handler, NULL)); |
74 new AudioInputController(event_handler, NULL, user_input_monitor)); | |
75 | 70 |
76 controller->message_loop_ = audio_manager->GetMessageLoop(); | 71 controller->message_loop_ = audio_manager->GetMessageLoop(); |
77 | 72 |
78 // Create and open a new audio input stream from the existing | 73 // Create and open a new audio input stream from the existing |
79 // audio-device thread. | 74 // audio-device thread. |
80 if (!controller->message_loop_->PostTask(FROM_HERE, | 75 if (!controller->message_loop_->PostTask(FROM_HERE, |
81 base::Bind(&AudioInputController::DoCreate, controller, | 76 base::Bind(&AudioInputController::DoCreate, controller, |
82 base::Unretained(audio_manager), params, device_id))) { | 77 base::Unretained(audio_manager), params, device_id))) { |
83 controller = NULL; | 78 controller = NULL; |
84 } | 79 } |
85 | 80 |
86 return controller; | 81 return controller; |
87 } | 82 } |
88 | 83 |
89 // static | 84 // static |
90 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( | 85 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( |
91 AudioManager* audio_manager, | 86 AudioManager* audio_manager, |
92 EventHandler* event_handler, | 87 EventHandler* event_handler, |
93 const AudioParameters& params, | 88 const AudioParameters& params, |
94 const std::string& device_id, | 89 const std::string& device_id, |
95 SyncWriter* sync_writer, | 90 SyncWriter* sync_writer) { |
96 UserInputMonitor* user_input_monitor) { | |
97 DCHECK(audio_manager); | 91 DCHECK(audio_manager); |
98 DCHECK(sync_writer); | 92 DCHECK(sync_writer); |
99 | 93 |
100 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 94 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
101 return NULL; | 95 return NULL; |
102 | 96 |
103 // Create the AudioInputController object and ensure that it runs on | 97 // Create the AudioInputController object and ensure that it runs on |
104 // the audio-manager thread. | 98 // the audio-manager thread. |
105 scoped_refptr<AudioInputController> controller( | 99 scoped_refptr<AudioInputController> controller(new AudioInputController( |
106 new AudioInputController(event_handler, sync_writer, user_input_monitor)); | 100 event_handler, sync_writer)); |
107 controller->message_loop_ = audio_manager->GetMessageLoop(); | 101 controller->message_loop_ = audio_manager->GetMessageLoop(); |
108 | 102 |
109 // Create and open a new audio input stream from the existing | 103 // Create and open a new audio input stream from the existing |
110 // audio-device thread. Use the provided audio-input device. | 104 // audio-device thread. Use the provided audio-input device. |
111 if (!controller->message_loop_->PostTask(FROM_HERE, | 105 if (!controller->message_loop_->PostTask(FROM_HERE, |
112 base::Bind(&AudioInputController::DoCreate, controller, | 106 base::Bind(&AudioInputController::DoCreate, controller, |
113 base::Unretained(audio_manager), params, device_id))) { | 107 base::Unretained(audio_manager), params, device_id))) { |
114 controller = NULL; | 108 controller = NULL; |
115 } | 109 } |
116 | 110 |
117 return controller; | 111 return controller; |
118 } | 112 } |
119 | 113 |
120 // static | 114 // static |
121 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( | 115 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( |
122 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 116 const scoped_refptr<base::MessageLoopProxy>& message_loop, |
123 EventHandler* event_handler, | 117 EventHandler* event_handler, |
124 AudioInputStream* stream, | 118 AudioInputStream* stream, |
125 SyncWriter* sync_writer, | 119 SyncWriter* sync_writer) { |
126 UserInputMonitor* user_input_monitor) { | |
127 DCHECK(sync_writer); | 120 DCHECK(sync_writer); |
128 DCHECK(stream); | 121 DCHECK(stream); |
129 | 122 |
130 // Create the AudioInputController object and ensure that it runs on | 123 // Create the AudioInputController object and ensure that it runs on |
131 // the audio-manager thread. | 124 // the audio-manager thread. |
132 scoped_refptr<AudioInputController> controller( | 125 scoped_refptr<AudioInputController> controller(new AudioInputController( |
133 new AudioInputController(event_handler, sync_writer, user_input_monitor)); | 126 event_handler, sync_writer)); |
134 controller->message_loop_ = message_loop; | 127 controller->message_loop_ = message_loop; |
135 | 128 |
136 // TODO(miu): See TODO at top of file. Until that's resolved, we need to | 129 // TODO(miu): See TODO at top of file. Until that's resolved, we need to |
137 // disable the error auto-detection here (since the audio mirroring | 130 // disable the error auto-detection here (since the audio mirroring |
138 // implementation will reliably report error and close events). Note, of | 131 // implementation will reliably report error and close events). Note, of |
139 // course, that we're assuming CreateForStream() has been called for the audio | 132 // course, that we're assuming CreateForStream() has been called for the audio |
140 // mirroring use case only. | 133 // mirroring use case only. |
141 if (!controller->message_loop_->PostTask( | 134 if (!controller->message_loop_->PostTask( |
142 FROM_HERE, | 135 FROM_HERE, |
143 base::Bind(&AudioInputController::DoCreateForStream, controller, | 136 base::Bind(&AudioInputController::DoCreateForStream, controller, |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 } | 226 } |
234 | 227 |
235 if (no_data_timer_) { | 228 if (no_data_timer_) { |
236 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, | 229 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, |
237 // a callback to DoCheckForNoData() is made. | 230 // a callback to DoCheckForNoData() is made. |
238 no_data_timer_->Reset(); | 231 no_data_timer_->Reset(); |
239 } | 232 } |
240 | 233 |
241 stream_->Start(this); | 234 stream_->Start(this); |
242 handler_->OnRecording(this); | 235 handler_->OnRecording(this); |
243 | |
244 if (user_input_monitor_) | |
245 user_input_monitor_->AddKeyStrokeListener(this); | |
246 } | 236 } |
247 | 237 |
248 void AudioInputController::DoClose() { | 238 void AudioInputController::DoClose() { |
249 DCHECK(message_loop_->BelongsToCurrentThread()); | 239 DCHECK(message_loop_->BelongsToCurrentThread()); |
250 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); | 240 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); |
251 | 241 |
252 // Delete the timer on the same thread that created it. | 242 // Delete the timer on the same thread that created it. |
253 no_data_timer_.reset(); | 243 no_data_timer_.reset(); |
254 | 244 |
255 if (state_ != kClosed) { | 245 if (state_ != kClosed) { |
256 DoStopCloseAndClearStream(NULL); | 246 DoStopCloseAndClearStream(NULL); |
257 SetDataIsActive(false); | 247 SetDataIsActive(false); |
258 | 248 |
259 if (LowLatencyMode()) { | 249 if (LowLatencyMode()) { |
260 sync_writer_->Close(); | 250 sync_writer_->Close(); |
261 } | 251 } |
262 | 252 |
263 state_ = kClosed; | 253 state_ = kClosed; |
264 | |
265 if (user_input_monitor_) | |
266 user_input_monitor_->RemoveKeyStrokeListener(this); | |
267 } | 254 } |
268 } | 255 } |
269 | 256 |
270 void AudioInputController::DoReportError() { | 257 void AudioInputController::DoReportError() { |
271 DCHECK(message_loop_->BelongsToCurrentThread()); | 258 DCHECK(message_loop_->BelongsToCurrentThread()); |
272 handler_->OnError(this); | 259 handler_->OnError(this); |
273 } | 260 } |
274 | 261 |
275 void AudioInputController::DoSetVolume(double volume) { | 262 void AudioInputController::DoSetVolume(double volume) { |
276 DCHECK(message_loop_->BelongsToCurrentThread()); | 263 DCHECK(message_loop_->BelongsToCurrentThread()); |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
326 // |kTimerResetIntervalSeconds|. | 313 // |kTimerResetIntervalSeconds|. |
327 no_data_timer_->Start( | 314 no_data_timer_->Start( |
328 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds), | 315 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds), |
329 base::Bind(&AudioInputController::DoCheckForNoData, | 316 base::Bind(&AudioInputController::DoCheckForNoData, |
330 base::Unretained(this))); | 317 base::Unretained(this))); |
331 } | 318 } |
332 | 319 |
333 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, | 320 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, |
334 uint32 size, uint32 hardware_delay_bytes, | 321 uint32 size, uint32 hardware_delay_bytes, |
335 double volume) { | 322 double volume) { |
336 bool key_pressed = false; | |
337 { | 323 { |
338 base::AutoLock auto_lock(lock_); | 324 base::AutoLock auto_lock(lock_); |
339 if (state_ != kRecording) | 325 if (state_ != kRecording) |
340 return; | 326 return; |
341 | |
342 std::swap(key_pressed, key_pressed_); | |
343 } | 327 } |
344 | 328 |
345 // Mark data as active to ensure that the periodic calls to | 329 // Mark data as active to ensure that the periodic calls to |
346 // DoCheckForNoData() does not report an error to the event handler. | 330 // DoCheckForNoData() does not report an error to the event handler. |
347 SetDataIsActive(true); | 331 SetDataIsActive(true); |
348 | 332 |
349 // Use SyncSocket if we are in a low-latency mode. | 333 // Use SyncSocket if we are in a low-latency mode. |
350 if (LowLatencyMode()) { | 334 if (LowLatencyMode()) { |
351 sync_writer_->Write(data, size, volume, key_pressed); | 335 sync_writer_->Write(data, size, volume); |
352 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); | 336 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
353 return; | 337 return; |
354 } | 338 } |
355 | 339 |
356 handler_->OnData(this, data, size); | 340 handler_->OnData(this, data, size); |
357 } | 341 } |
358 | 342 |
359 void AudioInputController::OnClose(AudioInputStream* stream) { | 343 void AudioInputController::OnClose(AudioInputStream* stream) { |
360 DVLOG(1) << "AudioInputController::OnClose()"; | 344 DVLOG(1) << "AudioInputController::OnClose()"; |
361 // TODO(satish): Sometimes the device driver closes the input stream without | 345 // TODO(satish): Sometimes the device driver closes the input stream without |
362 // us asking for it (may be if the device was unplugged?). Check how to handle | 346 // us asking for it (may be if the device was unplugged?). Check how to handle |
363 // such cases here. | 347 // such cases here. |
364 } | 348 } |
365 | 349 |
366 void AudioInputController::OnError(AudioInputStream* stream) { | 350 void AudioInputController::OnError(AudioInputStream* stream) { |
367 // Handle error on the audio-manager thread. | 351 // Handle error on the audio-manager thread. |
368 message_loop_->PostTask(FROM_HERE, base::Bind( | 352 message_loop_->PostTask(FROM_HERE, base::Bind( |
369 &AudioInputController::DoReportError, this)); | 353 &AudioInputController::DoReportError, this)); |
370 } | 354 } |
371 | 355 |
372 void AudioInputController::OnKeyStroke() { | |
373 base::AutoLock auto_lock(lock_); | |
374 key_pressed_ = true; | |
375 } | |
376 | |
377 void AudioInputController::DoStopCloseAndClearStream( | 356 void AudioInputController::DoStopCloseAndClearStream( |
378 base::WaitableEvent* done) { | 357 base::WaitableEvent *done) { |
379 DCHECK(message_loop_->BelongsToCurrentThread()); | 358 DCHECK(message_loop_->BelongsToCurrentThread()); |
380 | 359 |
381 // Allow calling unconditionally and bail if we don't have a stream to close. | 360 // Allow calling unconditionally and bail if we don't have a stream to close. |
382 if (stream_ != NULL) { | 361 if (stream_ != NULL) { |
383 stream_->Stop(); | 362 stream_->Stop(); |
384 stream_->Close(); | 363 stream_->Close(); |
385 stream_ = NULL; | 364 stream_ = NULL; |
386 } | 365 } |
387 | 366 |
388 // Should be last in the method, do not touch "this" from here on. | 367 // Should be last in the method, do not touch "this" from here on. |
389 if (done != NULL) | 368 if (done != NULL) |
390 done->Signal(); | 369 done->Signal(); |
391 } | 370 } |
392 | 371 |
393 void AudioInputController::SetDataIsActive(bool enabled) { | 372 void AudioInputController::SetDataIsActive(bool enabled) { |
394 base::subtle::Release_Store(&data_is_active_, enabled); | 373 base::subtle::Release_Store(&data_is_active_, enabled); |
395 } | 374 } |
396 | 375 |
397 bool AudioInputController::GetDataIsActive() { | 376 bool AudioInputController::GetDataIsActive() { |
398 return (base::subtle::Acquire_Load(&data_is_active_) != false); | 377 return (base::subtle::Acquire_Load(&data_is_active_) != false); |
399 } | 378 } |
400 | 379 |
401 } // namespace media | 380 } // namespace media |
OLD | NEW |