1 // Copyright (c) 2011 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"
12 const int kMaxInputChannels
= 2;
13 const int kTimerResetInterval
= 1; // One second.
19 AudioInputController::Factory
* AudioInputController::factory_
= NULL
;
21 AudioInputController::AudioInputController(AudioManager
* audio_manager
,
22 EventHandler
* handler
,
23 SyncWriter
* sync_writer
)
24 : audio_manager_(audio_manager
),
27 ALLOW_THIS_IN_INITIALIZER_LIST(no_data_timer_(FROM_HERE
,
28 base::TimeDelta::FromSeconds(kTimerResetInterval
),
30 &AudioInputController::DoReportNoDataError
)),
32 thread_("AudioInputControllerThread"),
33 sync_writer_(sync_writer
) {
34 DCHECK(audio_manager_
); // Fail early.
37 AudioInputController::~AudioInputController() {
38 DCHECK(kClosed
== state_
|| kCreated
== state_
|| kEmpty
== state_
);
42 scoped_refptr
<AudioInputController
> AudioInputController::Create(
43 AudioManager
* audio_manager
,
44 EventHandler
* event_handler
,
45 const AudioParameters
& params
) {
46 DCHECK(audio_manager
);
47 if (!params
.IsValid() || (params
.channels
> kMaxInputChannels
))
51 return factory_
->Create(audio_manager
, event_handler
, params
);
54 scoped_refptr
<AudioInputController
> controller(new AudioInputController(
55 audio_manager
, event_handler
, NULL
));
57 // Start the thread and post a task to create the audio input stream.
58 // Pass an empty string to indicate using default device.
59 std::string device_id
= AudioManagerBase::kDefaultDeviceId
;
60 controller
->thread_
.Start();
61 controller
->thread_
.message_loop()->PostTask(FROM_HERE
, base::Bind(
62 &AudioInputController::DoCreate
, controller
.get(),
68 scoped_refptr
<AudioInputController
> AudioInputController::CreateLowLatency(
69 AudioManager
* audio_manager
,
70 EventHandler
* event_handler
,
71 const AudioParameters
& params
,
72 const std::string
& device_id
,
73 SyncWriter
* sync_writer
) {
74 DCHECK(audio_manager
);
77 if (!params
.IsValid() || (params
.channels
> kMaxInputChannels
))
80 // Starts the audio controller thread.
81 scoped_refptr
<AudioInputController
> controller(new AudioInputController(
82 audio_manager
, event_handler
, sync_writer
));
84 // Start the thread and post a task to create the audio input stream.
85 controller
->thread_
.Start();
86 controller
->thread_
.message_loop()->PostTask(FROM_HERE
, base::Bind(
87 &AudioInputController::DoCreate
, controller
.get(), params
, device_id
));
91 void AudioInputController::Record() {
92 DCHECK(thread_
.IsRunning());
93 thread_
.message_loop()->PostTask(FROM_HERE
, base::Bind(
94 &AudioInputController::DoRecord
, this));
97 void AudioInputController::Close() {
98 if (!thread_
.IsRunning()) {
99 // If the thread is not running make sure we are stopped.
100 DCHECK_EQ(kClosed
, state_
);
104 // Wait for all tasks to complete on the audio thread.
105 thread_
.message_loop()->PostTask(FROM_HERE
, base::Bind(
106 &AudioInputController::DoClose
, this));
108 // A ScopedAllowIO object is required to join the thread when calling Stop.
109 // This is because as joining threads may be a long operation it's now
110 // not allowed in threads without IO access, which is the case of the IO
111 // thread (it is missnamed) being used here. This object overrides
112 // temporarily this restriction and should be used only in specific
113 // infrequent cases where joining is guaranteed to be fast.
114 // Bug: http://code.google.com/p/chromium/issues/detail?id=67806
115 base::ThreadRestrictions::ScopedAllowIO allow_io_for_thread_join
;
119 void AudioInputController::DoCreate(const AudioParameters
& params
,
120 const std::string
& device_id
) {
121 stream_
= audio_manager_
->MakeAudioInputStream(params
, device_id
);
124 // TODO(satish): Define error types.
125 handler_
->OnError(this, 0);
129 if (stream_
&& !stream_
->Open()) {
132 // TODO(satish): Define error types.
133 handler_
->OnError(this, 0);
137 thread_
.message_loop()->PostTask(FROM_HERE
, base::Bind(
138 &AudioInputController::DoResetNoDataTimer
, this));
140 handler_
->OnCreated(this);
143 void AudioInputController::DoRecord() {
144 DCHECK_EQ(thread_
.message_loop(), MessageLoop::current());
146 if (state_
!= kCreated
)
150 base::AutoLock
auto_lock(lock_
);
154 stream_
->Start(this);
155 handler_
->OnRecording(this);
158 void AudioInputController::DoClose() {
159 DCHECK_EQ(thread_
.message_loop(), MessageLoop::current());
160 DCHECK_NE(kClosed
, state_
);
162 // |stream_| can be null if creating the device failed in DoCreate().
166 // After stream is closed it is destroyed, so don't keep a reference to it.
170 if (LowLatencyMode()) {
171 sync_writer_
->Close();
174 // Since the stream is closed at this point there's no other threads reading
175 // |state_| so we don't need to lock.
179 void AudioInputController::DoReportError(int code
) {
180 DCHECK_EQ(thread_
.message_loop(), MessageLoop::current());
181 handler_
->OnError(this, code
);
184 void AudioInputController::DoReportNoDataError() {
185 DCHECK_EQ(thread_
.message_loop(), MessageLoop::current());
186 handler_
->OnError(this, 0);
189 void AudioInputController::DoResetNoDataTimer() {
190 DCHECK_EQ(thread_
.message_loop(), MessageLoop::current());
191 no_data_timer_
.Reset();
194 void AudioInputController::OnData(AudioInputStream
* stream
, const uint8
* data
,
195 uint32 size
, uint32 hardware_delay_bytes
) {
197 base::AutoLock
auto_lock(lock_
);
198 if (state_
!= kRecording
)
202 thread_
.message_loop()->PostTask(FROM_HERE
, base::Bind(
203 &AudioInputController::DoResetNoDataTimer
, this));
205 // Use SyncSocket if we are in a low-latency mode.
206 if (LowLatencyMode()) {
207 sync_writer_
->Write(data
, size
);
208 sync_writer_
->UpdateRecordedBytes(hardware_delay_bytes
);
212 handler_
->OnData(this, data
, size
);
215 void AudioInputController::OnClose(AudioInputStream
* stream
) {
216 // TODO(satish): Sometimes the device driver closes the input stream without
217 // us asking for it (may be if the device was unplugged?). Check how to handle
221 void AudioInputController::OnError(AudioInputStream
* stream
, int code
) {
222 // Handle error on the audio controller thread.
223 thread_
.message_loop()->PostTask(FROM_HERE
, base::Bind(
224 &AudioInputController::DoReportError
, this, code
));