Report errors from ChromiumEnv::GetChildren in Posix.
[chromium-blink-merge.git] / media / audio / audio_input_controller.cc
blobef94d1274d66d8ab843b26255b904b5f4960b32d
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
3 // found in the LICENSE file.
5 #include "media/audio/audio_input_controller.h"
7 #include "base/bind.h"
8 #include "base/threading/thread_restrictions.h"
9 #include "media/base/limits.h"
10 #include "media/base/scoped_histogram_timer.h"
11 #include "media/base/user_input_monitor.h"
13 namespace {
14 const int kMaxInputChannels = 2;
16 // TODO(henrika): remove usage of timers and add support for proper
17 // notification of when the input device is removed. This was originally added
18 // to resolve http://crbug.com/79936 for Windows platforms. This then caused
19 // breakage (very hard to repro bugs!) on other platforms: See
20 // http://crbug.com/226327 and http://crbug.com/230972.
21 const int kTimerResetIntervalSeconds = 1;
22 // We have received reports that the timer can be too trigger happy on some
23 // Mac devices and the initial timer interval has therefore been increased
24 // from 1 second to 5 seconds.
25 const int kTimerInitialIntervalSeconds = 5;
28 namespace media {
30 // static
31 AudioInputController::Factory* AudioInputController::factory_ = NULL;
33 AudioInputController::AudioInputController(EventHandler* handler,
34 SyncWriter* sync_writer,
35 UserInputMonitor* user_input_monitor)
36 : creator_loop_(base::MessageLoopProxy::current()),
37 handler_(handler),
38 stream_(NULL),
39 data_is_active_(false),
40 state_(kEmpty),
41 sync_writer_(sync_writer),
42 max_volume_(0.0),
43 user_input_monitor_(user_input_monitor),
44 prev_key_down_count_(0) {
45 DCHECK(creator_loop_.get());
48 AudioInputController::~AudioInputController() {
49 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_);
52 // static
53 scoped_refptr<AudioInputController> AudioInputController::Create(
54 AudioManager* audio_manager,
55 EventHandler* event_handler,
56 const AudioParameters& params,
57 const std::string& device_id,
58 UserInputMonitor* user_input_monitor) {
59 DCHECK(audio_manager);
61 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
62 return NULL;
64 if (factory_) {
65 return factory_->Create(
66 audio_manager, event_handler, params, user_input_monitor);
68 scoped_refptr<AudioInputController> controller(
69 new AudioInputController(event_handler, NULL, user_input_monitor));
71 controller->message_loop_ = audio_manager->GetMessageLoop();
73 // Create and open a new audio input stream from the existing
74 // audio-device thread.
75 if (!controller->message_loop_->PostTask(FROM_HERE,
76 base::Bind(&AudioInputController::DoCreate, controller,
77 base::Unretained(audio_manager), params, device_id))) {
78 controller = NULL;
81 return controller;
84 // static
85 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
86 AudioManager* audio_manager,
87 EventHandler* event_handler,
88 const AudioParameters& params,
89 const std::string& device_id,
90 SyncWriter* sync_writer,
91 UserInputMonitor* user_input_monitor) {
92 DCHECK(audio_manager);
93 DCHECK(sync_writer);
95 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
96 return NULL;
98 // Create the AudioInputController object and ensure that it runs on
99 // the audio-manager thread.
100 scoped_refptr<AudioInputController> controller(
101 new AudioInputController(event_handler, sync_writer, user_input_monitor));
102 controller->message_loop_ = audio_manager->GetMessageLoop();
104 // Create and open a new audio input stream from the existing
105 // audio-device thread. Use the provided audio-input device.
106 if (!controller->message_loop_->PostTask(FROM_HERE,
107 base::Bind(&AudioInputController::DoCreate, controller,
108 base::Unretained(audio_manager), params, device_id))) {
109 controller = NULL;
112 return controller;
115 // static
116 scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
117 const scoped_refptr<base::MessageLoopProxy>& message_loop,
118 EventHandler* event_handler,
119 AudioInputStream* stream,
120 SyncWriter* sync_writer,
121 UserInputMonitor* user_input_monitor) {
122 DCHECK(sync_writer);
123 DCHECK(stream);
125 // Create the AudioInputController object and ensure that it runs on
126 // the audio-manager thread.
127 scoped_refptr<AudioInputController> controller(
128 new AudioInputController(event_handler, sync_writer, user_input_monitor));
129 controller->message_loop_ = message_loop;
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
133 // implementation will reliably report error and close events). Note, of
134 // course, that we're assuming CreateForStream() has been called for the audio
135 // mirroring use case only.
136 if (!controller->message_loop_->PostTask(
137 FROM_HERE,
138 base::Bind(&AudioInputController::DoCreateForStream, controller,
139 stream, false))) {
140 controller = NULL;
143 return controller;
146 void AudioInputController::Record() {
147 message_loop_->PostTask(FROM_HERE, base::Bind(
148 &AudioInputController::DoRecord, this));
151 void AudioInputController::Close(const base::Closure& closed_task) {
152 DCHECK(!closed_task.is_null());
153 DCHECK(creator_loop_->BelongsToCurrentThread());
155 message_loop_->PostTaskAndReply(
156 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
159 void AudioInputController::SetVolume(double volume) {
160 message_loop_->PostTask(FROM_HERE, base::Bind(
161 &AudioInputController::DoSetVolume, this, volume));
164 void AudioInputController::SetAutomaticGainControl(bool enabled) {
165 message_loop_->PostTask(FROM_HERE, base::Bind(
166 &AudioInputController::DoSetAutomaticGainControl, this, enabled));
169 void AudioInputController::DoCreate(AudioManager* audio_manager,
170 const AudioParameters& params,
171 const std::string& device_id) {
172 DCHECK(message_loop_->BelongsToCurrentThread());
173 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
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
176 // errors. In reality, probably only Windows needs to be treated as
177 // unreliable here.
178 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
179 true);
182 void AudioInputController::DoCreateForStream(
183 AudioInputStream* stream_to_control, bool enable_nodata_timer) {
184 DCHECK(message_loop_->BelongsToCurrentThread());
186 DCHECK(!stream_);
187 stream_ = stream_to_control;
189 if (!stream_) {
190 handler_->OnError(this);
191 return;
194 if (stream_ && !stream_->Open()) {
195 stream_->Close();
196 stream_ = NULL;
197 handler_->OnError(this);
198 return;
201 DCHECK(!no_data_timer_.get());
202 if (enable_nodata_timer) {
203 // Create the data timer which will call DoCheckForNoData(). The timer
204 // is started in DoRecord() and restarted in each DoCheckForNoData()
205 // callback.
206 no_data_timer_.reset(new base::Timer(
207 FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds),
208 base::Bind(&AudioInputController::DoCheckForNoData,
209 base::Unretained(this)), false));
210 } else {
211 DVLOG(1) << "Disabled: timer check for no data.";
214 state_ = kCreated;
215 handler_->OnCreated(this);
217 if (user_input_monitor_) {
218 user_input_monitor_->EnableKeyPressMonitoring();
219 prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
223 void AudioInputController::DoRecord() {
224 DCHECK(message_loop_->BelongsToCurrentThread());
225 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
227 if (state_ != kCreated)
228 return;
231 base::AutoLock auto_lock(lock_);
232 state_ = kRecording;
235 if (no_data_timer_) {
236 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed,
237 // a callback to DoCheckForNoData() is made.
238 no_data_timer_->Reset();
241 stream_->Start(this);
242 handler_->OnRecording(this);
245 void AudioInputController::DoClose() {
246 DCHECK(message_loop_->BelongsToCurrentThread());
247 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
249 // Delete the timer on the same thread that created it.
250 no_data_timer_.reset();
252 if (state_ != kClosed) {
253 DoStopCloseAndClearStream(NULL);
254 SetDataIsActive(false);
256 if (LowLatencyMode()) {
257 sync_writer_->Close();
260 state_ = kClosed;
262 if (user_input_monitor_)
263 user_input_monitor_->DisableKeyPressMonitoring();
267 void AudioInputController::DoReportError() {
268 DCHECK(message_loop_->BelongsToCurrentThread());
269 handler_->OnError(this);
272 void AudioInputController::DoSetVolume(double volume) {
273 DCHECK(message_loop_->BelongsToCurrentThread());
274 DCHECK_GE(volume, 0);
275 DCHECK_LE(volume, 1.0);
277 if (state_ != kCreated && state_ != kRecording)
278 return;
280 // Only ask for the maximum volume at first call and use cached value
281 // for remaining function calls.
282 if (!max_volume_) {
283 max_volume_ = stream_->GetMaxVolume();
286 if (max_volume_ == 0.0) {
287 DLOG(WARNING) << "Failed to access input volume control";
288 return;
291 // Set the stream volume and scale to a range matched to the platform.
292 stream_->SetVolume(max_volume_ * volume);
295 void AudioInputController::DoSetAutomaticGainControl(bool enabled) {
296 DCHECK(message_loop_->BelongsToCurrentThread());
297 DCHECK_NE(state_, kRecording);
299 // Ensure that the AGC state only can be modified before streaming starts.
300 if (state_ != kCreated || state_ == kRecording)
301 return;
303 stream_->SetAutomaticGainControl(enabled);
306 void AudioInputController::DoCheckForNoData() {
307 DCHECK(message_loop_->BelongsToCurrentThread());
309 if (!GetDataIsActive()) {
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
312 // capture device has been removed or disabled.
313 handler_->OnError(this);
314 return;
317 // Mark data as non-active. The flag will be re-enabled in OnData() each
318 // time a data packet is received. Hence, under normal conditions, the
319 // flag will only be disabled during a very short period.
320 SetDataIsActive(false);
322 // Restart the timer to ensure that we check the flag again in
323 // |kTimerResetIntervalSeconds|.
324 no_data_timer_->Start(
325 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds),
326 base::Bind(&AudioInputController::DoCheckForNoData,
327 base::Unretained(this)));
330 void AudioInputController::OnData(AudioInputStream* stream,
331 const uint8* data,
332 uint32 size,
333 uint32 hardware_delay_bytes,
334 double volume) {
336 base::AutoLock auto_lock(lock_);
337 if (state_ != kRecording)
338 return;
341 bool key_pressed = false;
342 if (user_input_monitor_) {
343 size_t current_count = user_input_monitor_->GetKeyPressCount();
344 key_pressed = current_count != prev_key_down_count_;
345 prev_key_down_count_ = current_count;
346 DVLOG_IF(6, key_pressed) << "Detected keypress.";
349 // Mark data as active to ensure that the periodic calls to
350 // DoCheckForNoData() does not report an error to the event handler.
351 SetDataIsActive(true);
353 // Use SyncSocket if we are in a low-latency mode.
354 if (LowLatencyMode()) {
355 sync_writer_->Write(data, size, volume, key_pressed);
356 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
357 return;
360 handler_->OnData(this, data, size);
363 void AudioInputController::OnClose(AudioInputStream* stream) {
364 DVLOG(1) << "AudioInputController::OnClose()";
365 // TODO(satish): Sometimes the device driver closes the input stream without
366 // us asking for it (may be if the device was unplugged?). Check how to handle
367 // such cases here.
370 void AudioInputController::OnError(AudioInputStream* stream) {
371 // Handle error on the audio-manager thread.
372 message_loop_->PostTask(FROM_HERE, base::Bind(
373 &AudioInputController::DoReportError, this));
376 void AudioInputController::DoStopCloseAndClearStream(
377 base::WaitableEvent* done) {
378 DCHECK(message_loop_->BelongsToCurrentThread());
380 // Allow calling unconditionally and bail if we don't have a stream to close.
381 if (stream_ != NULL) {
382 stream_->Stop();
383 stream_->Close();
384 stream_ = NULL;
387 // Should be last in the method, do not touch "this" from here on.
388 if (done != NULL)
389 done->Signal();
392 void AudioInputController::SetDataIsActive(bool enabled) {
393 base::subtle::Release_Store(&data_is_active_, enabled);
396 bool AudioInputController::GetDataIsActive() {
397 return (base::subtle::Acquire_Load(&data_is_active_) != false);
400 } // namespace media