| 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 |