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"
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"
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;
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()),
39 data_is_active_(false),
41 sync_writer_(sync_writer
),
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_
);
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
))
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
))) {
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
);
95 if (!params
.IsValid() || (params
.channels() > kMaxInputChannels
))
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
))) {
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
) {
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(
138 base::Bind(&AudioInputController::DoCreateForStream
, 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
178 DoCreateForStream(audio_manager
->MakeAudioInputStream(params
, device_id
),
182 void AudioInputController::DoCreateForStream(
183 AudioInputStream
* stream_to_control
, bool enable_nodata_timer
) {
184 DCHECK(message_loop_
->BelongsToCurrentThread());
187 stream_
= stream_to_control
;
190 handler_
->OnError(this);
194 if (stream_
&& !stream_
->Open()) {
197 handler_
->OnError(this);
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()
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));
211 DVLOG(1) << "Disabled: timer check for no data.";
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
)
231 base::AutoLock
auto_lock(lock_
);
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();
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
)
280 // Only ask for the maximum volume at first call and use cached value
281 // for remaining function calls.
283 max_volume_
= stream_
->GetMaxVolume();
286 if (max_volume_
== 0.0) {
287 DLOG(WARNING
) << "Failed to access input volume control";
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
)
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);
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
,
333 uint32 hardware_delay_bytes
,
336 base::AutoLock
auto_lock(lock_
);
337 if (state_
!= kRecording
)
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
);
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
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
) {
387 // Should be last in the method, do not touch "this" from here on.
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);