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;
23 // The first callback on iOS is received after the current background
24 // audio has faded away.
25 const int kTimerInitialIntervalSeconds
= 4;
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)
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()),
45 data_is_active_(false),
47 sync_writer_(sync_writer
),
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_
);
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
))
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
))) {
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
);
101 if (!params
.IsValid() || (params
.channels() > kMaxInputChannels
))
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
))) {
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
) {
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(
144 base::Bind(&AudioInputController::DoCreateForStream
, 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
184 DoCreateForStream(audio_manager
->MakeAudioInputStream(params
, device_id
),
188 void AudioInputController::DoCreateForStream(
189 AudioInputStream
* stream_to_control
, bool enable_nodata_timer
) {
190 DCHECK(message_loop_
->BelongsToCurrentThread());
193 stream_
= stream_to_control
;
196 handler_
->OnError(this);
200 if (stream_
&& !stream_
->Open()) {
203 handler_
->OnError(this);
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()
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));
217 DVLOG(1) << "Disabled: timer check for no data.";
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
)
237 base::AutoLock
auto_lock(lock_
);
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();
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
)
286 // Only ask for the maximum volume at first call and use cached value
287 // for remaining function calls.
289 max_volume_
= stream_
->GetMaxVolume();
292 if (max_volume_
== 0.0) {
293 DLOG(WARNING
) << "Failed to access input volume control";
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
)
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);
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
,
339 uint32 hardware_delay_bytes
,
342 base::AutoLock
auto_lock(lock_
);
343 if (state_
!= kRecording
)
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
);
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
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
) {
393 // Should be last in the method, do not touch "this" from here on.
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);