OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/audio/audio_input_controller.h" | 5 #include "media/audio/audio_input_controller.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/threading/thread_restrictions.h" | 8 #include "base/threading/thread_restrictions.h" |
9 #include "media/base/limits.h" | 9 #include "media/base/limits.h" |
10 | 10 |
11 namespace { | 11 namespace { |
12 const int kMaxInputChannels = 2; | 12 const int kMaxInputChannels = 2; |
13 const int kTimerResetInterval = 1; // One second. | 13 const int kTimerResetInterval = 1; // One second. |
14 } | 14 } |
15 | 15 |
16 namespace media { | 16 namespace media { |
17 | 17 |
18 // static | 18 // static |
19 AudioInputController::Factory* AudioInputController::factory_ = NULL; | 19 AudioInputController::Factory* AudioInputController::factory_ = NULL; |
20 | 20 |
21 AudioInputController::AudioInputController(EventHandler* handler, | 21 AudioInputController::AudioInputController(EventHandler* handler, |
22 SyncWriter* sync_writer) | 22 SyncWriter* sync_writer) |
23 : creator_loop_(base::MessageLoopProxy::current()), | 23 : creator_loop_(base::MessageLoopProxy::current()), |
24 handler_(handler), | 24 handler_(handler), |
25 stream_(NULL), | 25 stream_(NULL), |
26 state_(kEmpty), | 26 state_(kEmpty), |
27 sync_writer_(sync_writer) { | 27 sync_writer_(sync_writer), |
| 28 max_volume_(0.0) { |
28 DCHECK(creator_loop_); | 29 DCHECK(creator_loop_); |
29 no_data_timer_.reset(new base::DelayTimer<AudioInputController>(FROM_HERE, | 30 no_data_timer_.reset(new base::DelayTimer<AudioInputController>(FROM_HERE, |
30 base::TimeDelta::FromSeconds(kTimerResetInterval), | 31 base::TimeDelta::FromSeconds(kTimerResetInterval), |
31 this, | 32 this, |
32 &AudioInputController::DoReportNoDataError)); | 33 &AudioInputController::DoReportNoDataError)); |
33 } | 34 } |
34 | 35 |
35 AudioInputController::~AudioInputController() { | 36 AudioInputController::~AudioInputController() { |
36 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); | 37 DCHECK(kClosed == state_ || kCreated == state_ || kEmpty == state_); |
37 } | 38 } |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
105 DCHECK(!closed_task.is_null()); | 106 DCHECK(!closed_task.is_null()); |
106 DCHECK(creator_loop_->BelongsToCurrentThread()); | 107 DCHECK(creator_loop_->BelongsToCurrentThread()); |
107 // See crbug.com/119783: Deleting the timer now to avoid disaster if | 108 // See crbug.com/119783: Deleting the timer now to avoid disaster if |
108 // AudioInputController is destructed on a thread other than the creator | 109 // AudioInputController is destructed on a thread other than the creator |
109 // thread. | 110 // thread. |
110 no_data_timer_.reset(); | 111 no_data_timer_.reset(); |
111 message_loop_->PostTaskAndReply( | 112 message_loop_->PostTaskAndReply( |
112 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task); | 113 FROM_HERE, base::Bind(&AudioInputController::DoClose, this), closed_task); |
113 } | 114 } |
114 | 115 |
| 116 void AudioInputController::SetVolume(double volume) { |
| 117 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 118 &AudioInputController::DoSetVolume, this, volume)); |
| 119 } |
| 120 |
| 121 void AudioInputController::SetAutomaticGainControl(bool enabled) { |
| 122 message_loop_->PostTask(FROM_HERE, base::Bind( |
| 123 &AudioInputController::DoSetAutomaticGainControl, this, enabled)); |
| 124 } |
| 125 |
115 void AudioInputController::DoCreate(AudioManager* audio_manager, | 126 void AudioInputController::DoCreate(AudioManager* audio_manager, |
116 const AudioParameters& params, | 127 const AudioParameters& params, |
117 const std::string& device_id) { | 128 const std::string& device_id) { |
118 DCHECK(message_loop_->BelongsToCurrentThread()); | 129 DCHECK(message_loop_->BelongsToCurrentThread()); |
119 | 130 |
120 stream_ = audio_manager->MakeAudioInputStream(params, device_id); | 131 stream_ = audio_manager->MakeAudioInputStream(params, device_id); |
121 | 132 |
122 if (!stream_) { | 133 if (!stream_) { |
123 // TODO(satish): Define error types. | 134 // TODO(satish): Define error types. |
124 handler_->OnError(this, 0); | 135 handler_->OnError(this, 0); |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 | 178 |
168 state_ = kClosed; | 179 state_ = kClosed; |
169 } | 180 } |
170 } | 181 } |
171 | 182 |
172 void AudioInputController::DoReportError(int code) { | 183 void AudioInputController::DoReportError(int code) { |
173 DCHECK(message_loop_->BelongsToCurrentThread()); | 184 DCHECK(message_loop_->BelongsToCurrentThread()); |
174 handler_->OnError(this, code); | 185 handler_->OnError(this, code); |
175 } | 186 } |
176 | 187 |
| 188 void AudioInputController::DoSetVolume(double volume) { |
| 189 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 190 DCHECK_GE(volume, 0); |
| 191 DCHECK_LE(volume, 1.0); |
| 192 |
| 193 if (state_ != kCreated && state_ != kRecording) |
| 194 return; |
| 195 |
| 196 // Only ask for the maximum volume at first call and use cached value |
| 197 // for remaining function calls. |
| 198 if (!max_volume_) { |
| 199 max_volume_ = stream_->GetMaxVolume(); |
| 200 } |
| 201 |
| 202 if (max_volume_ == 0.0) { |
| 203 DLOG(WARNING) << "Failed to access input volume control"; |
| 204 return; |
| 205 } |
| 206 |
| 207 // Set the stream volume and scale to a range matched to the platform. |
| 208 stream_->SetVolume(max_volume_ * volume); |
| 209 } |
| 210 |
| 211 void AudioInputController::DoSetAutomaticGainControl(bool enabled) { |
| 212 DCHECK(message_loop_->BelongsToCurrentThread()); |
| 213 DCHECK_NE(state_, kRecording); |
| 214 |
| 215 // Ensure that the AGC state only can be modified before streaming starts. |
| 216 if (state_ != kCreated || state_ == kRecording) |
| 217 return; |
| 218 |
| 219 stream_->SetAutomaticGainControl(enabled); |
| 220 } |
| 221 |
177 void AudioInputController::DoReportNoDataError() { | 222 void AudioInputController::DoReportNoDataError() { |
178 DCHECK(creator_loop_->BelongsToCurrentThread()); | 223 DCHECK(creator_loop_->BelongsToCurrentThread()); |
179 | 224 |
180 // Error notifications should be sent on the audio-manager thread. | 225 // Error notifications should be sent on the audio-manager thread. |
181 int code = 0; | 226 int code = 0; |
182 message_loop_->PostTask(FROM_HERE, base::Bind( | 227 message_loop_->PostTask(FROM_HERE, base::Bind( |
183 &AudioInputController::DoReportError, this, code)); | 228 &AudioInputController::DoReportError, this, code)); |
184 } | 229 } |
185 | 230 |
186 void AudioInputController::DoResetNoDataTimer() { | 231 void AudioInputController::DoResetNoDataTimer() { |
187 DCHECK(creator_loop_->BelongsToCurrentThread()); | 232 DCHECK(creator_loop_->BelongsToCurrentThread()); |
188 if (no_data_timer_.get()) | 233 if (no_data_timer_.get()) |
189 no_data_timer_->Reset(); | 234 no_data_timer_->Reset(); |
190 } | 235 } |
191 | 236 |
192 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, | 237 void AudioInputController::OnData(AudioInputStream* stream, const uint8* data, |
193 uint32 size, uint32 hardware_delay_bytes) { | 238 uint32 size, uint32 hardware_delay_bytes, |
| 239 double volume) { |
194 { | 240 { |
195 base::AutoLock auto_lock(lock_); | 241 base::AutoLock auto_lock(lock_); |
196 if (state_ != kRecording) | 242 if (state_ != kRecording) |
197 return; | 243 return; |
198 } | 244 } |
199 | 245 |
200 creator_loop_->PostTask(FROM_HERE, base::Bind( | 246 creator_loop_->PostTask(FROM_HERE, base::Bind( |
201 &AudioInputController::DoResetNoDataTimer, this)); | 247 &AudioInputController::DoResetNoDataTimer, this)); |
202 | 248 |
203 // Use SyncSocket if we are in a low-latency mode. | 249 // Use SyncSocket if we are in a low-latency mode. |
204 if (LowLatencyMode()) { | 250 if (LowLatencyMode()) { |
205 sync_writer_->Write(data, size); | 251 sync_writer_->Write(data, size, volume); |
206 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); | 252 sync_writer_->UpdateRecordedBytes(hardware_delay_bytes); |
207 return; | 253 return; |
208 } | 254 } |
209 | 255 |
210 handler_->OnData(this, data, size); | 256 handler_->OnData(this, data, size); |
211 } | 257 } |
212 | 258 |
213 void AudioInputController::OnClose(AudioInputStream* stream) { | 259 void AudioInputController::OnClose(AudioInputStream* stream) { |
214 DVLOG(1) << "AudioInputController::OnClose()"; | 260 DVLOG(1) << "AudioInputController::OnClose()"; |
215 // TODO(satish): Sometimes the device driver closes the input stream without | 261 // TODO(satish): Sometimes the device driver closes the input stream without |
(...skipping 17 matching lines...) Expand all Loading... |
233 stream_->Close(); | 279 stream_->Close(); |
234 stream_ = NULL; | 280 stream_ = NULL; |
235 } | 281 } |
236 | 282 |
237 // Should be last in the method, do not touch "this" from here on. | 283 // Should be last in the method, do not touch "this" from here on. |
238 if (done != NULL) | 284 if (done != NULL) |
239 done->Signal(); | 285 done->Signal(); |
240 } | 286 } |
241 | 287 |
242 } // namespace media | 288 } // namespace media |
OLD | NEW |