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 15 matching lines...) Expand all Loading... |
26 } | 26 } |
27 | 27 |
28 namespace media { | 28 namespace media { |
29 | 29 |
30 // static | 30 // static |
31 AudioInputController::Factory* AudioInputController::factory_ = NULL; | 31 AudioInputController::Factory* AudioInputController::factory_ = NULL; |
32 | 32 |
33 AudioInputController::AudioInputController(EventHandler* handler, | 33 AudioInputController::AudioInputController(EventHandler* handler, |
34 SyncWriter* sync_writer, | 34 SyncWriter* sync_writer, |
35 UserInputMonitor* user_input_monitor) | 35 UserInputMonitor* user_input_monitor) |
36 : creator_loop_(base::MessageLoopProxy::current()), | 36 : creator_task_runner_(base::MessageLoopProxy::current()), |
37 handler_(handler), | 37 handler_(handler), |
38 stream_(NULL), | 38 stream_(NULL), |
39 data_is_active_(false), | 39 data_is_active_(false), |
40 state_(kEmpty), | 40 state_(kEmpty), |
41 sync_writer_(sync_writer), | 41 sync_writer_(sync_writer), |
42 max_volume_(0.0), | 42 max_volume_(0.0), |
43 user_input_monitor_(user_input_monitor), | 43 user_input_monitor_(user_input_monitor), |
44 prev_key_down_count_(0) { | 44 prev_key_down_count_(0) { |
45 DCHECK(creator_loop_.get()); | 45 DCHECK(creator_task_runner_.get()); |
46 } | 46 } |
47 | 47 |
48 AudioInputController::~AudioInputController() { | 48 AudioInputController::~AudioInputController() { |
49 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); | 49 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); |
50 } | 50 } |
51 | 51 |
52 // static | 52 // static |
53 scoped_refptr<AudioInputController> AudioInputController::Create( | 53 scoped_refptr<AudioInputController> AudioInputController::Create( |
54 AudioManager* audio_manager, | 54 AudioManager* audio_manager, |
55 EventHandler* event_handler, | 55 EventHandler* event_handler, |
56 const AudioParameters& params, | 56 const AudioParameters& params, |
57 const std::string& device_id, | 57 const std::string& device_id, |
58 UserInputMonitor* user_input_monitor) { | 58 UserInputMonitor* user_input_monitor) { |
59 DCHECK(audio_manager); | 59 DCHECK(audio_manager); |
60 | 60 |
61 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 61 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
62 return NULL; | 62 return NULL; |
63 | 63 |
64 if (factory_) { | 64 if (factory_) { |
65 return factory_->Create( | 65 return factory_->Create( |
66 audio_manager, event_handler, params, user_input_monitor); | 66 audio_manager, event_handler, params, user_input_monitor); |
67 } | 67 } |
68 scoped_refptr<AudioInputController> controller( | 68 scoped_refptr<AudioInputController> controller( |
69 new AudioInputController(event_handler, NULL, user_input_monitor)); | 69 new AudioInputController(event_handler, NULL, user_input_monitor)); |
70 | 70 |
71 controller->message_loop_ = audio_manager->GetMessageLoop(); | 71 controller->task_runner_ = audio_manager->GetTaskRunner(); |
72 | 72 |
73 // Create and open a new audio input stream from the existing | 73 // Create and open a new audio input stream from the existing |
74 // audio-device thread. | 74 // audio-device thread. |
75 if (!controller->message_loop_->PostTask(FROM_HERE, | 75 if (!controller->task_runner_->PostTask(FROM_HERE, |
76 base::Bind(&AudioInputController::DoCreate, controller, | 76 base::Bind(&AudioInputController::DoCreate, controller, |
77 base::Unretained(audio_manager), params, device_id))) { | 77 base::Unretained(audio_manager), params, device_id))) { |
78 controller = NULL; | 78 controller = NULL; |
79 } | 79 } |
80 | 80 |
81 return controller; | 81 return controller; |
82 } | 82 } |
83 | 83 |
84 // static | 84 // static |
85 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( | 85 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency( |
86 AudioManager* audio_manager, | 86 AudioManager* audio_manager, |
87 EventHandler* event_handler, | 87 EventHandler* event_handler, |
88 const AudioParameters& params, | 88 const AudioParameters& params, |
89 const std::string& device_id, | 89 const std::string& device_id, |
90 SyncWriter* sync_writer, | 90 SyncWriter* sync_writer, |
91 UserInputMonitor* user_input_monitor) { | 91 UserInputMonitor* user_input_monitor) { |
92 DCHECK(audio_manager); | 92 DCHECK(audio_manager); |
93 DCHECK(sync_writer); | 93 DCHECK(sync_writer); |
94 | 94 |
95 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) | 95 if (!params.IsValid() || (params.channels() > kMaxInputChannels)) |
96 return NULL; | 96 return NULL; |
97 | 97 |
98 // Create the AudioInputController object and ensure that it runs on | 98 // Create the AudioInputController object and ensure that it runs on |
99 // the audio-manager thread. | 99 // the audio-manager thread. |
100 scoped_refptr<AudioInputController> controller( | 100 scoped_refptr<AudioInputController> controller( |
101 new AudioInputController(event_handler, sync_writer, user_input_monitor)); | 101 new AudioInputController(event_handler, sync_writer, user_input_monitor)); |
102 controller->message_loop_ = audio_manager->GetMessageLoop(); | 102 controller->task_runner_ = audio_manager->GetTaskRunner(); |
103 | 103 |
104 // Create and open a new audio input stream from the existing | 104 // Create and open a new audio input stream from the existing |
105 // audio-device thread. Use the provided audio-input device. | 105 // audio-device thread. Use the provided audio-input device. |
106 if (!controller->message_loop_->PostTask(FROM_HERE, | 106 if (!controller->task_runner_->PostTask(FROM_HERE, |
107 base::Bind(&AudioInputController::DoCreate, controller, | 107 base::Bind(&AudioInputController::DoCreate, controller, |
108 base::Unretained(audio_manager), params, device_id))) { | 108 base::Unretained(audio_manager), params, device_id))) { |
109 controller = NULL; | 109 controller = NULL; |
110 } | 110 } |
111 | 111 |
112 return controller; | 112 return controller; |
113 } | 113 } |
114 | 114 |
115 // static | 115 // static |
116 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( | 116 scoped_refptr<AudioInputController> AudioInputController::CreateForStream( |
117 const scoped_refptr<base::MessageLoopProxy>& message_loop, | 117 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
118 EventHandler* event_handler, | 118 EventHandler* event_handler, |
119 AudioInputStream* stream, | 119 AudioInputStream* stream, |
120 SyncWriter* sync_writer, | 120 SyncWriter* sync_writer, |
121 UserInputMonitor* user_input_monitor) { | 121 UserInputMonitor* user_input_monitor) { |
122 DCHECK(sync_writer); | 122 DCHECK(sync_writer); |
123 DCHECK(stream); | 123 DCHECK(stream); |
124 | 124 |
125 // Create the AudioInputController object and ensure that it runs on | 125 // Create the AudioInputController object and ensure that it runs on |
126 // the audio-manager thread. | 126 // the audio-manager thread. |
127 scoped_refptr<AudioInputController> controller( | 127 scoped_refptr<AudioInputController> controller( |
128 new AudioInputController(event_handler, sync_writer, user_input_monitor)); | 128 new AudioInputController(event_handler, sync_writer, user_input_monitor)); |
129 controller->message_loop_ = message_loop; | 129 controller->task_runner_ = task_runner; |
130 | 130 |
131 // TODO(miu): See TODO at top of file. Until that's resolved, we need to | 131 // TODO(miu): See TODO at top of file. Until that's resolved, we need to |
132 // disable the error auto-detection here (since the audio mirroring | 132 // disable the error auto-detection here (since the audio mirroring |
133 // implementation will reliably report error and close events). Note, of | 133 // implementation will reliably report error and close events). Note, of |
134 // course, that we're assuming CreateForStream() has been called for the audio | 134 // course, that we're assuming CreateForStream() has been called for the audio |
135 // mirroring use case only. | 135 // mirroring use case only. |
136 if (!controller->message_loop_->PostTask( | 136 if (!controller->task_runner_->PostTask( |
137 FROM_HERE, | 137 FROM_HERE, |
138 base::Bind(&AudioInputController::DoCreateForStream, controller, | 138 base::Bind(&AudioInputController::DoCreateForStream, controller, |
139 stream, false))) { | 139 stream, false))) { |
140 controller = NULL; | 140 controller = NULL; |
141 } | 141 } |
142 | 142 |
143 return controller; | 143 return controller; |
144 } | 144 } |
145 | 145 |
146 void AudioInputController::Record() { | 146 void AudioInputController::Record() { |
147 message_loop_->PostTask(FROM_HERE, base::Bind( | 147 task_runner_->PostTask(FROM_HERE, base::Bind( |
148 &AudioInputController::DoRecord, this)); | 148 &AudioInputController::DoRecord, this)); |
149 } | 149 } |
150 | 150 |
151 void AudioInputController::Close(const base::Closure& closed_task) { | 151 void AudioInputController::Close(const base::Closure& closed_task) { |
152 DCHECK(!closed_task.is_null()); | 152 DCHECK(!closed_task.is_null()); |
153 DCHECK(creator_loop_->BelongsToCurrentThread()); | 153 DCHECK(creator_task_runner_->BelongsToCurrentThread()); |
154 | 154 |
155 message_loop_->PostTaskAndReply( | 155 task_runner_->PostTaskAndReply( |
156 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task); | 156 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task); |
157 } | 157 } |
158 | 158 |
159 void AudioInputController::SetVolume(double volume) { | 159 void AudioInputController::SetVolume(double volume) { |
160 message_loop_->PostTask(FROM_HERE, base::Bind( | 160 task_runner_->PostTask(FROM_HERE, base::Bind( |
161 &AudioInputController::DoSetVolume, this, volume)); | 161 &AudioInputController::DoSetVolume, this, volume)); |
162 } | 162 } |
163 | 163 |
164 void AudioInputController::SetAutomaticGainControl(bool enabled) { | 164 void AudioInputController::SetAutomaticGainControl(bool enabled) { |
165 message_loop_->PostTask(FROM_HERE, base::Bind( | 165 task_runner_->PostTask(FROM_HERE, base::Bind( |
166 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); | 166 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); |
167 } | 167 } |
168 | 168 |
169 void AudioInputController::DoCreate(AudioManager* audio_manager, | 169 void AudioInputController::DoCreate(AudioManager* audio_manager, |
170 const AudioParameters& params, | 170 const AudioParameters& params, |
171 const std::string& device_id) { | 171 const std::string& device_id) { |
172 DCHECK(message_loop_->BelongsToCurrentThread()); | 172 DCHECK(task_runner_->BelongsToCurrentThread()); |
173 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); | 173 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime"); |
174 // TODO(miu): See TODO at top of file. Until that's resolved, assume all | 174 // TODO(miu): See TODO at top of file. Until that's resolved, assume all |
175 // platform audio input requires the |no_data_timer_| be used to auto-detect | 175 // platform audio input requires the |no_data_timer_| be used to auto-detect |
176 // errors. In reality, probably only Windows needs to be treated as | 176 // errors. In reality, probably only Windows needs to be treated as |
177 // unreliable here. | 177 // unreliable here. |
178 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), | 178 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id), |
179 true); | 179 true); |
180 } | 180 } |
181 | 181 |
182 void AudioInputController::DoCreateForStream( | 182 void AudioInputController::DoCreateForStream( |
183 AudioInputStream* stream_to_control, bool enable_nodata_timer) { | 183 AudioInputStream* stream_to_control, bool enable_nodata_timer) { |
184 DCHECK(message_loop_->BelongsToCurrentThread()); | 184 DCHECK(task_runner_->BelongsToCurrentThread()); |
185 | 185 |
186 DCHECK(!stream_); | 186 DCHECK(!stream_); |
187 stream_ = stream_to_control; | 187 stream_ = stream_to_control; |
188 | 188 |
189 if (!stream_) { | 189 if (!stream_) { |
190 handler_->OnError(this); | 190 handler_->OnError(this); |
191 return; | 191 return; |
192 } | 192 } |
193 | 193 |
194 if (stream_ && !stream_->Open()) { | 194 if (stream_ && !stream_->Open()) { |
(...skipping 19 matching lines...) Expand all Loading... |
214 state_ = kCreated; | 214 state_ = kCreated; |
215 handler_->OnCreated(this); | 215 handler_->OnCreated(this); |
216 | 216 |
217 if (user_input_monitor_) { | 217 if (user_input_monitor_) { |
218 user_input_monitor_->EnableKeyPressMonitoring(); | 218 user_input_monitor_->EnableKeyPressMonitoring(); |
219 prev_key_down_count_ = user_input_monitor_->GetKeyPressCount(); | 219 prev_key_down_count_ = user_input_monitor_->GetKeyPressCount(); |
220 } | 220 } |
221 } | 221 } |
222 | 222 |
223 void AudioInputController::DoRecord() { | 223 void AudioInputController::DoRecord() { |
224 DCHECK(message_loop_->BelongsToCurrentThread()); | 224 DCHECK(task_runner_->BelongsToCurrentThread()); |
225 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); | 225 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime"); |
226 | 226 |
227 if (state_ != kCreated) | 227 if (state_ != kCreated) |
228 return; | 228 return; |
229 | 229 |
230 { | 230 { |
231 base::AutoLock auto_lock(lock_); | 231 base::AutoLock auto_lock(lock_); |
232 state_ = kRecording; | 232 state_ = kRecording; |
233 } | 233 } |
234 | 234 |
235 if (no_data_timer_) { | 235 if (no_data_timer_) { |
236 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, | 236 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed, |
237 // a callback to DoCheckForNoData() is made. | 237 // a callback to DoCheckForNoData() is made. |
238 no_data_timer_->Reset(); | 238 no_data_timer_->Reset(); |
239 } | 239 } |
240 | 240 |
241 stream_->Start(this); | 241 stream_->Start(this); |
242 handler_->OnRecording(this); | 242 handler_->OnRecording(this); |
243 } | 243 } |
244 | 244 |
245 void AudioInputController::DoClose() { | 245 void AudioInputController::DoClose() { |
246 DCHECK(message_loop_->BelongsToCurrentThread()); | 246 DCHECK(task_runner_->BelongsToCurrentThread()); |
247 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); | 247 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime"); |
248 | 248 |
249 // Delete the timer on the same thread that created it. | 249 // Delete the timer on the same thread that created it. |
250 no_data_timer_.reset(); | 250 no_data_timer_.reset(); |
251 | 251 |
252 if (state_ != kClosed) { | 252 if (state_ != kClosed) { |
253 DoStopCloseAndClearStream(NULL); | 253 DoStopCloseAndClearStream(NULL); |
254 SetDataIsActive(false); | 254 SetDataIsActive(false); |
255 | 255 |
256 if (LowLatencyMode()) { | 256 if (LowLatencyMode()) { |
257 sync_writer_->Close(); | 257 sync_writer_->Close(); |
258 } | 258 } |
259 | 259 |
260 state_ = kClosed; | 260 state_ = kClosed; |
261 | 261 |
262 if (user_input_monitor_) | 262 if (user_input_monitor_) |
263 user_input_monitor_->DisableKeyPressMonitoring(); | 263 user_input_monitor_->DisableKeyPressMonitoring(); |
264 } | 264 } |
265 } | 265 } |
266 | 266 |
267 void AudioInputController::DoReportError() { | 267 void AudioInputController::DoReportError() { |
268 DCHECK(message_loop_->BelongsToCurrentThread()); | 268 DCHECK(task_runner_->BelongsToCurrentThread()); |
269 handler_->OnError(this); | 269 handler_->OnError(this); |
270 } | 270 } |
271 | 271 |
272 void AudioInputController::DoSetVolume(double volume) { | 272 void AudioInputController::DoSetVolume(double volume) { |
273 DCHECK(message_loop_->BelongsToCurrentThread()); | 273 DCHECK(task_runner_->BelongsToCurrentThread()); |
274 DCHECK_GE(volume, 0); | 274 DCHECK_GE(volume, 0); |
275 DCHECK_LE(volume, 1.0); | 275 DCHECK_LE(volume, 1.0); |
276 | 276 |
277 if (state_ != kCreated && state_ != kRecording) | 277 if (state_ != kCreated && state_ != kRecording) |
278 return; | 278 return; |
279 | 279 |
280 // Only ask for the maximum volume at first call and use cached value | 280 // Only ask for the maximum volume at first call and use cached value |
281 // for remaining function calls. | 281 // for remaining function calls. |
282 if (!max_volume_) { | 282 if (!max_volume_) { |
283 max_volume_ = stream_->GetMaxVolume(); | 283 max_volume_ = stream_->GetMaxVolume(); |
284 } | 284 } |
285 | 285 |
286 if (max_volume_ == 0.0) { | 286 if (max_volume_ == 0.0) { |
287 DLOG(WARNING) << "Failed to access input volume control"; | 287 DLOG(WARNING) << "Failed to access input volume control"; |
288 return; | 288 return; |
289 } | 289 } |
290 | 290 |
291 // Set the stream volume and scale to a range matched to the platform. | 291 // Set the stream volume and scale to a range matched to the platform. |
292 stream_->SetVolume(max_volume_ * volume); | 292 stream_->SetVolume(max_volume_ * volume); |
293 } | 293 } |
294 | 294 |
295 void AudioInputController::DoSetAutomaticGainControl(bool enabled) { | 295 void AudioInputController::DoSetAutomaticGainControl(bool enabled) { |
296 DCHECK(message_loop_->BelongsToCurrentThread()); | 296 DCHECK(task_runner_->BelongsToCurrentThread()); |
297 DCHECK_NE(state_, kRecording); | 297 DCHECK_NE(state_, kRecording); |
298 | 298 |
299 // Ensure that the AGC state only can be modified before streaming starts. | 299 // Ensure that the AGC state only can be modified before streaming starts. |
300 if (state_ != kCreated || state_ == kRecording) | 300 if (state_ != kCreated || state_ == kRecording) |
301 return; | 301 return; |
302 | 302 |
303 stream_->SetAutomaticGainControl(enabled); | 303 stream_->SetAutomaticGainControl(enabled); |
304 } | 304 } |
305 | 305 |
306 void AudioInputController::DoCheckForNoData() { | 306 void AudioInputController::DoCheckForNoData() { |
307 DCHECK(message_loop_->BelongsToCurrentThread()); | 307 DCHECK(task_runner_->BelongsToCurrentThread()); |
308 | 308 |
309 if (!GetDataIsActive()) { | 309 if (!GetDataIsActive()) { |
310 // The data-is-active marker will be false only if it has been more than | 310 // The data-is-active marker will be false only if it has been more than |
311 // one second since a data packet was recorded. This can happen if a | 311 // one second since a data packet was recorded. This can happen if a |
312 // capture device has been removed or disabled. | 312 // capture device has been removed or disabled. |
313 handler_->OnError(this); | 313 handler_->OnError(this); |
314 return; | 314 return; |
315 } | 315 } |
316 | 316 |
317 // Mark data as non-active. The flag will be re-enabled in OnData() each | 317 // Mark data as non-active. The flag will be re-enabled in OnData() each |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
355 sync_writer_->Write(data, size, volume, key_pressed); | 355 sync_writer_->Write(data, size, volume, key_pressed); |
356 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); | 356 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
357 return; | 357 return; |
358 } | 358 } |
359 | 359 |
360 handler_->OnData(this, data, size); | 360 handler_->OnData(this, data, size); |
361 } | 361 } |
362 | 362 |
363 void AudioInputController::OnError(AudioInputStream* stream) { | 363 void AudioInputController::OnError(AudioInputStream* stream) { |
364 // Handle error on the audio-manager thread. | 364 // Handle error on the audio-manager thread. |
365 message_loop_->PostTask(FROM_HERE, base::Bind( | 365 task_runner_->PostTask(FROM_HERE, base::Bind( |
366 &AudioInputController::DoReportError, this)); | 366 &AudioInputController::DoReportError, this)); |
367 } | 367 } |
368 | 368 |
369 void AudioInputController::DoStopCloseAndClearStream( | 369 void AudioInputController::DoStopCloseAndClearStream( |
370 base::WaitableEvent* done) { | 370 base::WaitableEvent* done) { |
371 DCHECK(message_loop_->BelongsToCurrentThread()); | 371 DCHECK(task_runner_->BelongsToCurrentThread()); |
372 | 372 |
373 // Allow calling unconditionally and bail if we don't have a stream to close. | 373 // Allow calling unconditionally and bail if we don't have a stream to close. |
374 if (stream_ != NULL) { | 374 if (stream_ != NULL) { |
375 stream_->Stop(); | 375 stream_->Stop(); |
376 stream_->Close(); | 376 stream_->Close(); |
377 stream_ = NULL; | 377 stream_ = NULL; |
378 } | 378 } |
379 | 379 |
380 // Should be last in the method, do not touch "this" from here on. | 380 // Should be last in the method, do not touch "this" from here on. |
381 if (done != NULL) | 381 if (done != NULL) |
382 done->Signal(); | 382 done->Signal(); |
383 } | 383 } |
384 | 384 |
385 void AudioInputController::SetDataIsActive(bool enabled) { | 385 void AudioInputController::SetDataIsActive(bool enabled) { |
386 base::subtle::Release_Store(&data_is_active_, enabled); | 386 base::subtle::Release_Store(&data_is_active_, enabled); |
387 } | 387 } |
388 | 388 |
389 bool AudioInputController::GetDataIsActive() { | 389 bool AudioInputController::GetDataIsActive() { |
390 return (base::subtle::Acquire_Load(&data_is_active_) != false); | 390 return (base::subtle::Acquire_Load(&data_is_active_) != false); |
391 } | 391 } |
392 | 392 |
393 } // namespace media | 393 } // namespace media |
OLD | NEW |