cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / media / audio / audio_input_controller.cc
blobd701337b51db7d80bd4ff5bf18f3316485fac62e
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 #if defined(OS_IOS)
23 // The first callback on iOS is received after the current background
24 // audio has faded away.
25 const int kTimerInitialIntervalSeconds = 4;
26 #else
27 // We have received reports that the timer can be too trigger happy on some
28 // Mac devices and the initial timer interval has therefore been increased
29 // from 1 second to 5 seconds.
30 const int kTimerInitialIntervalSeconds = 5;
31 #endif // defined(OS_IOS)
34 namespace media {
36 // static
37 AudioInputController::Factory* AudioInputController::factory_ = NULL;
39 AudioInputController::AudioInputController(EventHandler* handler,
40 SyncWriter* sync_writer,
41 UserInputMonitor* user_input_monitor)
42 : creator_loop_(base::MessageLoopProxy::current()),
43 handler_(handler),
44 stream_(NULL),
45 data_is_active_(false),
46 state_(kEmpty),
47 sync_writer_(sync_writer),
48 max_volume_(0.0),
49 user_input_monitor_(user_input_monitor),
50 prev_key_down_count_(0) {
51 DCHECK(creator_loop_.get());
54 AudioInputController::~AudioInputController() {
55 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_);
58 // static
59 scoped_refptr<AudioInputController> AudioInputController::Create(
60 AudioManager* audio_manager,
61 EventHandler* event_handler,
62 const AudioParameters& params,
63 const std::string& device_id,
64 UserInputMonitor* user_input_monitor) {
65 DCHECK(audio_manager);
67 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
68 return NULL;
70 if (factory_) {
71 return factory_->Create(
72 audio_manager, event_handler, params, user_input_monitor);
74 scoped_refptr<AudioInputController> controller(
75 new AudioInputController(event_handler, NULL, user_input_monitor));
77 controller->message_loop_ = audio_manager->GetMessageLoop();
79 // Create and open a new audio input stream from the existing
80 // audio-device thread.
81 if (!controller->message_loop_->PostTask(FROM_HERE,
82 base::Bind(&AudioInputController::DoCreate, controller,
83 base::Unretained(audio_manager), params, device_id))) {
84 controller = NULL;
87 return controller;
90 // static
91 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
92 AudioManager* audio_manager,
93 EventHandler* event_handler,
94 const AudioParameters& params,
95 const std::string& device_id,
96 SyncWriter* sync_writer,
97 UserInputMonitor* user_input_monitor) {
98 DCHECK(audio_manager);
99 DCHECK(sync_writer);
101 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
102 return NULL;
104 // Create the AudioInputController object and ensure that it runs on
105 // the audio-manager thread.
106 scoped_refptr<AudioInputController> controller(
107 new AudioInputController(event_handler, sync_writer, user_input_monitor));
108 controller->message_loop_ = audio_manager->GetMessageLoop();
110 // Create and open a new audio input stream from the existing
111 // audio-device thread. Use the provided audio-input device.
112 if (!controller->message_loop_->PostTask(FROM_HERE,
113 base::Bind(&AudioInputController::DoCreate, controller,
114 base::Unretained(audio_manager), params, device_id))) {
115 controller = NULL;
118 return controller;
121 // static
122 scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
123 const scoped_refptr<base::MessageLoopProxy>& message_loop,
124 EventHandler* event_handler,
125 AudioInputStream* stream,
126 SyncWriter* sync_writer,
127 UserInputMonitor* user_input_monitor) {
128 DCHECK(sync_writer);
129 DCHECK(stream);
131 // Create the AudioInputController object and ensure that it runs on
132 // the audio-manager thread.
133 scoped_refptr<AudioInputController> controller(
134 new AudioInputController(event_handler, sync_writer, user_input_monitor));
135 controller->message_loop_ = message_loop;
137 // TODO(miu): See TODO at top of file. Until that's resolved, we need to
138 // disable the error auto-detection here (since the audio mirroring
139 // implementation will reliably report error and close events). Note, of
140 // course, that we're assuming CreateForStream() has been called for the audio
141 // mirroring use case only.
142 if (!controller->message_loop_->PostTask(
143 FROM_HERE,
144 base::Bind(&AudioInputController::DoCreateForStream, controller,
145 stream, false))) {
146 controller = NULL;
149 return controller;
152 void AudioInputController::Record() {
153 message_loop_->PostTask(FROM_HERE, base::Bind(
154 &AudioInputController::DoRecord, this));
157 void AudioInputController::Close(const base::Closure& closed_task) {
158 DCHECK(!closed_task.is_null());
159 DCHECK(creator_loop_->BelongsToCurrentThread());
161 message_loop_->PostTaskAndReply(
162 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
165 void AudioInputController::SetVolume(double volume) {
166 message_loop_->PostTask(FROM_HERE, base::Bind(
167 &AudioInputController::DoSetVolume, this, volume));
170 void AudioInputController::SetAutomaticGainControl(bool enabled) {
171 message_loop_->PostTask(FROM_HERE, base::Bind(
172 &AudioInputController::DoSetAutomaticGainControl, this, enabled));
175 void AudioInputController::DoCreate(AudioManager* audio_manager,
176 const AudioParameters& params,
177 const std::string& device_id) {
178 DCHECK(message_loop_->BelongsToCurrentThread());
179 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CreateTime");
180 // TODO(miu): See TODO at top of file. Until that's resolved, assume all
181 // platform audio input requires the |no_data_timer_| be used to auto-detect
182 // errors. In reality, probably only Windows and IOS need to be treated as
183 // unreliable here.
184 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id),
185 true);
188 void AudioInputController::DoCreateForStream(
189 AudioInputStream* stream_to_control, bool enable_nodata_timer) {
190 DCHECK(message_loop_->BelongsToCurrentThread());
192 DCHECK(!stream_);
193 stream_ = stream_to_control;
195 if (!stream_) {
196 handler_->OnError(this);
197 return;
200 if (stream_ && !stream_->Open()) {
201 stream_->Close();
202 stream_ = NULL;
203 handler_->OnError(this);
204 return;
207 DCHECK(!no_data_timer_.get());
208 if (enable_nodata_timer) {
209 // Create the data timer which will call DoCheckForNoData(). The timer
210 // is started in DoRecord() and restarted in each DoCheckForNoData()
211 // callback.
212 no_data_timer_.reset(new base::Timer(
213 FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds),
214 base::Bind(&AudioInputController::DoCheckForNoData,
215 base::Unretained(this)), false));
216 } else {
217 DVLOG(1) << "Disabled: timer check for no data.";
220 state_ = kCreated;
221 handler_->OnCreated(this);
223 if (user_input_monitor_) {
224 user_input_monitor_->EnableKeyPressMonitoring();
225 prev_key_down_count_ = user_input_monitor_->GetKeyPressCount();
229 void AudioInputController::DoRecord() {
230 DCHECK(message_loop_->BelongsToCurrentThread());
231 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.RecordTime");
233 if (state_ != kCreated)
234 return;
237 base::AutoLock auto_lock(lock_);
238 state_ = kRecording;
241 if (no_data_timer_) {
242 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed,
243 // a callback to DoCheckForNoData() is made.
244 no_data_timer_->Reset();
247 stream_->Start(this);
248 handler_->OnRecording(this);
251 void AudioInputController::DoClose() {
252 DCHECK(message_loop_->BelongsToCurrentThread());
253 SCOPED_UMA_HISTOGRAM_TIMER("Media.AudioInputController.CloseTime");
255 // Delete the timer on the same thread that created it.
256 no_data_timer_.reset();
258 if (state_ != kClosed) {
259 DoStopCloseAndClearStream(NULL);
260 SetDataIsActive(false);
262 if (LowLatencyMode()) {
263 sync_writer_->Close();
266 state_ = kClosed;
268 if (user_input_monitor_)
269 user_input_monitor_->DisableKeyPressMonitoring();
273 void AudioInputController::DoReportError() {
274 DCHECK(message_loop_->BelongsToCurrentThread());
275 handler_->OnError(this);
278 void AudioInputController::DoSetVolume(double volume) {
279 DCHECK(message_loop_->BelongsToCurrentThread());
280 DCHECK_GE(volume, 0);
281 DCHECK_LE(volume, 1.0);
283 if (state_ != kCreated && state_ != kRecording)
284 return;
286 // Only ask for the maximum volume at first call and use cached value
287 // for remaining function calls.
288 if (!max_volume_) {
289 max_volume_ = stream_->GetMaxVolume();
292 if (max_volume_ == 0.0) {
293 DLOG(WARNING) << "Failed to access input volume control";
294 return;
297 // Set the stream volume and scale to a range matched to the platform.
298 stream_->SetVolume(max_volume_ * volume);
301 void AudioInputController::DoSetAutomaticGainControl(bool enabled) {
302 DCHECK(message_loop_->BelongsToCurrentThread());
303 DCHECK_NE(state_, kRecording);
305 // Ensure that the AGC state only can be modified before streaming starts.
306 if (state_ != kCreated || state_ == kRecording)
307 return;
309 stream_->SetAutomaticGainControl(enabled);
312 void AudioInputController::DoCheckForNoData() {
313 DCHECK(message_loop_->BelongsToCurrentThread());
315 if (!GetDataIsActive()) {
316 // The data-is-active marker will be false only if it has been more than
317 // one second since a data packet was recorded. This can happen if a
318 // capture device has been removed or disabled.
319 handler_->OnError(this);
320 return;
323 // Mark data as non-active. The flag will be re-enabled in OnData() each
324 // time a data packet is received. Hence, under normal conditions, the
325 // flag will only be disabled during a very short period.
326 SetDataIsActive(false);
328 // Restart the timer to ensure that we check the flag again in
329 // |kTimerResetIntervalSeconds|.
330 no_data_timer_->Start(
331 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds),
332 base::Bind(&AudioInputController::DoCheckForNoData,
333 base::Unretained(this)));
336 void AudioInputController::OnData(AudioInputStream* stream,
337 const uint8* data,
338 uint32 size,
339 uint32 hardware_delay_bytes,
340 double volume) {
342 base::AutoLock auto_lock(lock_);
343 if (state_ != kRecording)
344 return;
347 bool key_pressed = false;
348 if (user_input_monitor_) {
349 size_t current_count = user_input_monitor_->GetKeyPressCount();
350 key_pressed = current_count != prev_key_down_count_;
351 prev_key_down_count_ = current_count;
352 DVLOG_IF(6, key_pressed) << "Detected keypress.";
355 // Mark data as active to ensure that the periodic calls to
356 // DoCheckForNoData() does not report an error to the event handler.
357 SetDataIsActive(true);
359 // Use SyncSocket if we are in a low-latency mode.
360 if (LowLatencyMode()) {
361 sync_writer_->Write(data, size, volume, key_pressed);
362 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
363 return;
366 handler_->OnData(this, data, size);
369 void AudioInputController::OnClose(AudioInputStream* stream) {
370 DVLOG(1) << "AudioInputController::OnClose()";
371 // TODO(satish): Sometimes the device driver closes the input stream without
372 // us asking for it (may be if the device was unplugged?). Check how to handle
373 // such cases here.
376 void AudioInputController::OnError(AudioInputStream* stream) {
377 // Handle error on the audio-manager thread.
378 message_loop_->PostTask(FROM_HERE, base::Bind(
379 &AudioInputController::DoReportError, this));
382 void AudioInputController::DoStopCloseAndClearStream(
383 base::WaitableEvent* done) {
384 DCHECK(message_loop_->BelongsToCurrentThread());
386 // Allow calling unconditionally and bail if we don't have a stream to close.
387 if (stream_ != NULL) {
388 stream_->Stop();
389 stream_->Close();
390 stream_ = NULL;
393 // Should be last in the method, do not touch "this" from here on.
394 if (done != NULL)
395 done->Signal();
398 void AudioInputController::SetDataIsActive(bool enabled) {
399 base::subtle::Release_Store(&data_is_active_, enabled);
402 bool AudioInputController::GetDataIsActive() {
403 return (base::subtle::Acquire_Load(&data_is_active_) != false);
406 } // namespace media