Separate Simple Backend creation from initialization.
[chromium-blink-merge.git] / media / audio / audio_input_controller.cc
blobe8fc6e7699711f2d6e51fecc6a9debd602e29483
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"
11 namespace {
12 const int kMaxInputChannels = 2;
13 const int kTimerResetIntervalSeconds = 1;
14 #if defined(OS_IOS)
15 // The first callback on iOS is received after the current background
16 // audio has faded away.
17 const int kTimerInitialIntervalSeconds = 4;
18 #else
19 // We have received reports that the timer can be too trigger happy on some
20 // Mac devices and the initial timer interval has therefore been increased
21 // from 1 second to 5 seconds.
22 // TODO(henrika): remove usage of timers and add support for proper
23 // notification of when the input device is removed.
24 // See http://crbug.com/226327 for details.
25 const int kTimerInitialIntervalSeconds = 5;
26 #endif // defined(OS_IOS)
29 namespace media {
31 // static
32 AudioInputController::Factory* AudioInputController::factory_ = NULL;
34 AudioInputController::AudioInputController(EventHandler* handler,
35 SyncWriter* sync_writer)
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 DCHECK(creator_loop_);
46 AudioInputController::~AudioInputController() {
47 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_);
50 // static
51 scoped_refptr<AudioInputController> AudioInputController::Create(
52 AudioManager* audio_manager,
53 EventHandler* event_handler,
54 const AudioParameters& params) {
55 DCHECK(audio_manager);
57 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
58 return NULL;
60 if (factory_)
61 return factory_->Create(audio_manager, event_handler, params);
63 scoped_refptr<AudioInputController> controller(new AudioInputController(
64 event_handler, NULL));
66 controller->message_loop_ = audio_manager->GetMessageLoop();
68 // Create and open a new audio input stream from the existing
69 // audio-device thread. Use the default audio-input device.
70 std::string device_id = AudioManagerBase::kDefaultDeviceId;
71 if (!controller->message_loop_->PostTask(FROM_HERE,
72 base::Bind(&AudioInputController::DoCreate, controller,
73 base::Unretained(audio_manager), params, device_id))) {
74 controller = NULL;
77 return controller;
80 // static
81 scoped_refptr<AudioInputController> AudioInputController::CreateLowLatency(
82 AudioManager* audio_manager,
83 EventHandler* event_handler,
84 const AudioParameters& params,
85 const std::string& device_id,
86 SyncWriter* sync_writer) {
87 DCHECK(audio_manager);
88 DCHECK(sync_writer);
90 if (!params.IsValid() || (params.channels() > kMaxInputChannels))
91 return NULL;
93 // Create the AudioInputController object and ensure that it runs on
94 // the audio-manager thread.
95 scoped_refptr<AudioInputController> controller(new AudioInputController(
96 event_handler, sync_writer));
97 controller->message_loop_ = audio_manager->GetMessageLoop();
99 // Create and open a new audio input stream from the existing
100 // audio-device thread. Use the provided audio-input device.
101 if (!controller->message_loop_->PostTask(FROM_HERE,
102 base::Bind(&AudioInputController::DoCreate, controller,
103 base::Unretained(audio_manager), params, device_id))) {
104 controller = NULL;
107 return controller;
110 // static
111 scoped_refptr<AudioInputController> AudioInputController::CreateForStream(
112 AudioManager* audio_manager,
113 EventHandler* event_handler,
114 AudioInputStream* stream,
115 SyncWriter* sync_writer) {
116 DCHECK(audio_manager);
117 DCHECK(sync_writer);
118 DCHECK(stream);
120 // Create the AudioInputController object and ensure that it runs on
121 // the audio-manager thread.
122 scoped_refptr<AudioInputController> controller(new AudioInputController(
123 event_handler, sync_writer));
124 controller->message_loop_ = audio_manager->GetMessageLoop();
126 if (!controller->message_loop_->PostTask(
127 FROM_HERE,
128 base::Bind(&AudioInputController::DoCreateForStream, controller,
129 stream))) {
130 controller = NULL;
133 return controller;
136 void AudioInputController::Record() {
137 message_loop_->PostTask(FROM_HERE, base::Bind(
138 &AudioInputController::DoRecord, this));
141 void AudioInputController::Close(const base::Closure& closed_task) {
142 DCHECK(!closed_task.is_null());
143 DCHECK(creator_loop_->BelongsToCurrentThread());
145 message_loop_->PostTaskAndReply(
146 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task);
149 void AudioInputController::SetVolume(double volume) {
150 message_loop_->PostTask(FROM_HERE, base::Bind(
151 &AudioInputController::DoSetVolume, this, volume));
154 void AudioInputController::SetAutomaticGainControl(bool enabled) {
155 message_loop_->PostTask(FROM_HERE, base::Bind(
156 &AudioInputController::DoSetAutomaticGainControl, this, enabled));
159 void AudioInputController::DoCreate(AudioManager* audio_manager,
160 const AudioParameters& params,
161 const std::string& device_id) {
162 DCHECK(message_loop_->BelongsToCurrentThread());
163 DoCreateForStream(audio_manager->MakeAudioInputStream(params, device_id));
166 void AudioInputController::DoCreateForStream(
167 AudioInputStream* stream_to_control) {
168 DCHECK(message_loop_->BelongsToCurrentThread());
170 DCHECK(!stream_);
171 stream_ = stream_to_control;
173 if (!stream_) {
174 handler_->OnError(this);
175 return;
178 if (stream_ && !stream_->Open()) {
179 stream_->Close();
180 stream_ = NULL;
181 handler_->OnError(this);
182 return;
185 DCHECK(!no_data_timer_.get());
186 // Create the data timer which will call DoCheckForNoData(). The timer
187 // is started in DoRecord() and restarted in each DoCheckForNoData() callback.
188 no_data_timer_.reset(new base::Timer(
189 FROM_HERE, base::TimeDelta::FromSeconds(kTimerInitialIntervalSeconds),
190 base::Bind(&AudioInputController::DoCheckForNoData,
191 base::Unretained(this)), false));
192 state_ = kCreated;
193 handler_->OnCreated(this);
196 void AudioInputController::DoRecord() {
197 DCHECK(message_loop_->BelongsToCurrentThread());
199 if (state_ != kCreated)
200 return;
203 base::AutoLock auto_lock(lock_);
204 state_ = kRecording;
207 // Start the data timer. Once |kTimerResetIntervalSeconds| have passed,
208 // a callback to DoCheckForNoData() is made.
209 no_data_timer_->Reset();
211 stream_->Start(this);
212 handler_->OnRecording(this);
215 void AudioInputController::DoClose() {
216 DCHECK(message_loop_->BelongsToCurrentThread());
218 // Delete the timer on the same thread that created it.
219 no_data_timer_.reset();
221 if (state_ != kClosed) {
222 DoStopCloseAndClearStream(NULL);
223 SetDataIsActive(false);
225 if (LowLatencyMode()) {
226 sync_writer_->Close();
229 state_ = kClosed;
233 void AudioInputController::DoReportError() {
234 DCHECK(message_loop_->BelongsToCurrentThread());
235 handler_->OnError(this);
238 void AudioInputController::DoSetVolume(double volume) {
239 DCHECK(message_loop_->BelongsToCurrentThread());
240 DCHECK_GE(volume, 0);
241 DCHECK_LE(volume, 1.0);
243 if (state_ != kCreated && state_ != kRecording)
244 return;
246 // Only ask for the maximum volume at first call and use cached value
247 // for remaining function calls.
248 if (!max_volume_) {
249 max_volume_ = stream_->GetMaxVolume();
252 if (max_volume_ == 0.0) {
253 DLOG(WARNING) << "Failed to access input volume control";
254 return;
257 // Set the stream volume and scale to a range matched to the platform.
258 stream_->SetVolume(max_volume_ * volume);
261 void AudioInputController::DoSetAutomaticGainControl(bool enabled) {
262 DCHECK(message_loop_->BelongsToCurrentThread());
263 DCHECK_NE(state_, kRecording);
265 // Ensure that the AGC state only can be modified before streaming starts.
266 if (state_ != kCreated || state_ == kRecording)
267 return;
269 stream_->SetAutomaticGainControl(enabled);
272 void AudioInputController::DoCheckForNoData() {
273 DCHECK(message_loop_->BelongsToCurrentThread());
275 if (!GetDataIsActive()) {
276 // The data-is-active marker will be false only if it has been more than
277 // one second since a data packet was recorded. This can happen if a
278 // capture device has been removed or disabled.
279 handler_->OnError(this);
280 return;
283 // Mark data as non-active. The flag will be re-enabled in OnData() each
284 // time a data packet is received. Hence, under normal conditions, the
285 // flag will only be disabled during a very short period.
286 SetDataIsActive(false);
288 // Restart the timer to ensure that we check the flag again in
289 // |kTimerResetIntervalSeconds|.
290 no_data_timer_->Start(
291 FROM_HERE, base::TimeDelta::FromSeconds(kTimerResetIntervalSeconds),
292 base::Bind(&AudioInputController::DoCheckForNoData,
293 base::Unretained(this)));
296 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data,
297 uint32 size, uint32 hardware_delay_bytes,
298 double volume) {
300 base::AutoLock auto_lock(lock_);
301 if (state_ != kRecording)
302 return;
305 // Mark data as active to ensure that the periodic calls to
306 // DoCheckForNoData() does not report an error to the event handler.
307 SetDataIsActive(true);
309 // Use SyncSocket if we are in a low-latency mode.
310 if (LowLatencyMode()) {
311 sync_writer_->Write(data, size, volume);
312 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes);
313 return;
316 handler_->OnData(this, data, size);
319 void AudioInputController::OnClose(AudioInputStream* stream) {
320 DVLOG(1) << "AudioInputController::OnClose()";
321 // TODO(satish): Sometimes the device driver closes the input stream without
322 // us asking for it (may be if the device was unplugged?). Check how to handle
323 // such cases here.
326 void AudioInputController::OnError(AudioInputStream* stream) {
327 // Handle error on the audio-manager thread.
328 message_loop_->PostTask(FROM_HERE, base::Bind(
329 &AudioInputController::DoReportError, this));
332 void AudioInputController::DoStopCloseAndClearStream(
333 base::WaitableEvent *done) {
334 DCHECK(message_loop_->BelongsToCurrentThread());
336 // Allow calling unconditionally and bail if we don't have a stream to close.
337 if (stream_ != NULL) {
338 stream_->Stop();
339 stream_->Close();
340 stream_ = NULL;
343 // Should be last in the method, do not touch "this" from here on.
344 if (done != NULL)
345 done->Signal();
348 void AudioInputController::SetDataIsActive(bool enabled) {
349 base::subtle::Release_Store(&data_is_active_, enabled);
352 bool AudioInputController::GetDataIsActive() {
353 return (base::subtle::Acquire_Load(&data_is_active_) != false);
356 } // namespace media