Chromium Code Reviews| 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 "content/renderer/media/audio_input_device.h" | 5 #include "content/renderer/media/audio_input_device.h" |
| 6 | 6 |
| 7 #include "base/bind.h" | 7 #include "base/bind.h" |
| 8 #include "base/message_loop.h" | 8 #include "base/message_loop.h" |
| 9 #include "base/threading/thread_restrictions.h" | 9 #include "base/threading/thread_restrictions.h" |
| 10 #include "base/time.h" | 10 #include "base/time.h" |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 40 AudioInputDevice::AudioInputDevice(const AudioParameters& params, | 40 AudioInputDevice::AudioInputDevice(const AudioParameters& params, |
| 41 CaptureCallback* callback, | 41 CaptureCallback* callback, |
| 42 CaptureEventHandler* event_handler) | 42 CaptureEventHandler* event_handler) |
| 43 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()), | 43 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()), |
| 44 audio_parameters_(params), | 44 audio_parameters_(params), |
| 45 callback_(callback), | 45 callback_(callback), |
| 46 event_handler_(event_handler), | 46 event_handler_(event_handler), |
| 47 volume_(1.0), | 47 volume_(1.0), |
| 48 stream_id_(0), | 48 stream_id_(0), |
| 49 session_id_(0), | 49 session_id_(0), |
| 50 pending_device_ready_(false) { | 50 pending_device_ready_(false), |
| 51 agc_is_enabled_(false) { | |
|
tommi (sloooow) - chröme
2012/03/26 15:26:40
indent is off.
henrika (OOO until Aug 14)
2012/03/27 09:20:38
Done.
| |
| 51 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); | 52 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); |
| 52 } | 53 } |
| 53 | 54 |
| 54 AudioInputDevice::~AudioInputDevice() { | 55 AudioInputDevice::~AudioInputDevice() { |
| 55 // TODO(henrika): The current design requires that the user calls | 56 // TODO(henrika): The current design requires that the user calls |
| 56 // Stop before deleting this class. | 57 // Stop before deleting this class. |
| 57 CHECK_EQ(0, stream_id_); | 58 CHECK_EQ(0, stream_id_); |
| 58 } | 59 } |
| 59 | 60 |
| 60 void AudioInputDevice::Start() { | 61 void AudioInputDevice::Start() { |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 75 { | 76 { |
| 76 base::AutoLock auto_lock(audio_thread_lock_); | 77 base::AutoLock auto_lock(audio_thread_lock_); |
| 77 audio_thread_.Stop(MessageLoop::current()); | 78 audio_thread_.Stop(MessageLoop::current()); |
| 78 } | 79 } |
| 79 | 80 |
| 80 message_loop()->PostTask(FROM_HERE, | 81 message_loop()->PostTask(FROM_HERE, |
| 81 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); | 82 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); |
| 82 } | 83 } |
| 83 | 84 |
| 84 bool AudioInputDevice::SetVolume(double volume) { | 85 bool AudioInputDevice::SetVolume(double volume) { |
| 85 NOTIMPLEMENTED(); | 86 if (volume < 0 || volume > 1.0) |
| 87 return false; | |
| 88 | |
| 89 message_loop()->PostTask(FROM_HERE, | |
| 90 base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume)); | |
| 91 | |
| 92 return true; | |
| 93 } | |
| 94 | |
| 95 bool AudioInputDevice::GetVolume(double* volume) { | |
| 96 NOTREACHED(); | |
| 86 return false; | 97 return false; |
| 87 } | 98 } |
| 88 | 99 |
| 89 bool AudioInputDevice::GetVolume(double* volume) { | 100 void AudioInputDevice::SetAutomaticGainControl(bool enabled) { |
| 90 NOTIMPLEMENTED(); | 101 DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")"; |
| 91 return false; | 102 message_loop()->PostTask(FROM_HERE, |
| 103 base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread, | |
| 104 this, enabled)); | |
| 92 } | 105 } |
| 93 | 106 |
| 94 void AudioInputDevice::InitializeOnIOThread() { | 107 void AudioInputDevice::InitializeOnIOThread() { |
| 95 DCHECK(message_loop()->BelongsToCurrentThread()); | 108 DCHECK(message_loop()->BelongsToCurrentThread()); |
| 96 // Make sure we don't call Start() more than once. | 109 // Make sure we don't call Start() more than once. |
| 97 DCHECK_EQ(0, stream_id_); | 110 DCHECK_EQ(0, stream_id_); |
| 98 if (stream_id_) | 111 if (stream_id_) |
| 99 return; | 112 return; |
| 100 | 113 |
| 101 stream_id_ = filter_->AddDelegate(this); | 114 stream_id_ = filter_->AddDelegate(this); |
| 102 // If |session_id_| is not specified, it will directly create the stream; | 115 // If |session_id_| is not specified, it will directly create the stream; |
| 103 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser | 116 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser |
| 104 // and create the stream when getting a OnDeviceReady() callback. | 117 // and create the stream when getting a OnDeviceReady() callback. |
| 105 if (!session_id_) { | 118 if (!session_id_) { |
| 106 Send(new AudioInputHostMsg_CreateStream( | 119 Send(new AudioInputHostMsg_CreateStream( |
| 107 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId)); | 120 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId, |
| 121 agc_is_enabled_)); | |
| 108 } else { | 122 } else { |
| 109 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); | 123 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); |
| 110 pending_device_ready_ = true; | 124 pending_device_ready_ = true; |
| 111 } | 125 } |
| 112 } | 126 } |
| 113 | 127 |
| 114 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { | 128 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { |
| 115 DCHECK(message_loop()->BelongsToCurrentThread()); | 129 DCHECK(message_loop()->BelongsToCurrentThread()); |
| 116 session_id_ = session_id; | 130 session_id_ = session_id; |
| 117 } | 131 } |
| 118 | 132 |
| 119 void AudioInputDevice::StartOnIOThread() { | 133 void AudioInputDevice::StartOnIOThread() { |
| 120 DCHECK(message_loop()->BelongsToCurrentThread()); | 134 DCHECK(message_loop()->BelongsToCurrentThread()); |
| 121 if (stream_id_) | 135 if (stream_id_) |
| 122 Send(new AudioInputHostMsg_RecordStream(stream_id_)); | 136 Send(new AudioInputHostMsg_RecordStream(stream_id_)); |
| 123 } | 137 } |
| 124 | 138 |
| 125 void AudioInputDevice::ShutDownOnIOThread() { | 139 void AudioInputDevice::ShutDownOnIOThread() { |
| 126 DCHECK(message_loop()->BelongsToCurrentThread()); | 140 DCHECK(message_loop()->BelongsToCurrentThread()); |
| 127 // NOTE: |completion| may be NULL. | 141 // NOTE: |completion| may be NULL. |
| 128 // Make sure we don't call shutdown more than once. | 142 // Make sure we don't call shutdown more than once. |
| 129 if (stream_id_) { | 143 if (stream_id_) { |
| 130 filter_->RemoveDelegate(stream_id_); | 144 filter_->RemoveDelegate(stream_id_); |
| 131 Send(new AudioInputHostMsg_CloseStream(stream_id_)); | 145 Send(new AudioInputHostMsg_CloseStream(stream_id_)); |
| 132 | 146 |
| 133 stream_id_ = 0; | 147 stream_id_ = 0; |
| 134 session_id_ = 0; | 148 session_id_ = 0; |
| 135 pending_device_ready_ = false; | 149 pending_device_ready_ = false; |
| 150 agc_is_enabled_ = false; | |
| 136 } | 151 } |
| 137 | 152 |
| 138 // We can run into an issue where ShutDownOnIOThread is called right after | 153 // We can run into an issue where ShutDownOnIOThread is called right after |
| 139 // OnStreamCreated is called in cases where Start/Stop are called before we | 154 // OnStreamCreated is called in cases where Start/Stop are called before we |
| 140 // get the OnStreamCreated callback. To handle that corner case, we call | 155 // get the OnStreamCreated callback. To handle that corner case, we call |
| 141 // Stop(). In most cases, the thread will already be stopped. | 156 // Stop(). In most cases, the thread will already be stopped. |
| 142 // Another situation is when the IO thread goes away before Stop() is called | 157 // Another situation is when the IO thread goes away before Stop() is called |
| 143 // in which case, we cannot use the message loop to close the thread handle | 158 // in which case, we cannot use the message loop to close the thread handle |
| 144 // and can't not rely on the main thread existing either. | 159 // and can't not rely on the main thread existing either. |
| 145 base::ThreadRestrictions::ScopedAllowIO allow_io; | 160 base::ThreadRestrictions::ScopedAllowIO allow_io; |
| 146 audio_thread_.Stop(NULL); | 161 audio_thread_.Stop(NULL); |
| 147 audio_callback_.reset(); | 162 audio_callback_.reset(); |
| 148 } | 163 } |
| 149 | 164 |
| 150 void AudioInputDevice::SetVolumeOnIOThread(double volume) { | 165 void AudioInputDevice::SetVolumeOnIOThread(double volume) { |
| 151 DCHECK(message_loop()->BelongsToCurrentThread()); | 166 DCHECK(message_loop()->BelongsToCurrentThread()); |
| 152 if (stream_id_) | 167 if (stream_id_) |
| 153 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); | 168 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); |
| 154 } | 169 } |
| 155 | 170 |
| 171 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { | |
| 172 DCHECK(message_loop()->BelongsToCurrentThread()); | |
| 173 // The state of the AGC can not be modified while capturing is active. | |
|
tommi (sloooow) - chröme
2012/03/26 15:26:40
Are the reasons for this still valid?
henrika (OOO until Aug 14)
2012/03/27 09:20:38
Yes, I have removed locks in on the media side und
| |
| 174 DCHECK_EQ(0, stream_id_); | |
|
scherkus (not reviewing)
2012/03/26 22:41:04
want to move that comment into a DCHECK() message?
henrika (OOO until Aug 14)
2012/03/27 09:20:38
Done.
| |
| 175 if (stream_id_) | |
| 176 return; | |
| 177 | |
| 178 // We simply store the new AGC setting here. This value will be used when | |
| 179 // a new stream is initialized and by GetAutomaticGainControl(). | |
| 180 agc_is_enabled_ = enabled; | |
| 181 } | |
| 182 | |
| 156 void AudioInputDevice::OnStreamCreated( | 183 void AudioInputDevice::OnStreamCreated( |
| 157 base::SharedMemoryHandle handle, | 184 base::SharedMemoryHandle handle, |
| 158 base::SyncSocket::Handle socket_handle, | 185 base::SyncSocket::Handle socket_handle, |
| 159 uint32 length) { | 186 uint32 length) { |
| 160 DCHECK(message_loop()->BelongsToCurrentThread()); | 187 DCHECK(message_loop()->BelongsToCurrentThread()); |
| 161 #if defined(OS_WIN) | 188 #if defined(OS_WIN) |
| 162 DCHECK(handle); | 189 DCHECK(handle); |
| 163 DCHECK(socket_handle); | 190 DCHECK(socket_handle); |
| 164 #else | 191 #else |
| 165 DCHECK_GE(handle.fd, 0); | 192 DCHECK_GE(handle.fd, 0); |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 243 if (!pending_device_ready_) | 270 if (!pending_device_ready_) |
| 244 return; | 271 return; |
| 245 | 272 |
| 246 // If AudioInputDeviceManager returns an empty string, it means no device | 273 // If AudioInputDeviceManager returns an empty string, it means no device |
| 247 // is ready for start. | 274 // is ready for start. |
| 248 if (device_id.empty()) { | 275 if (device_id.empty()) { |
| 249 filter_->RemoveDelegate(stream_id_); | 276 filter_->RemoveDelegate(stream_id_); |
| 250 stream_id_ = 0; | 277 stream_id_ = 0; |
| 251 } else { | 278 } else { |
| 252 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, | 279 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, |
| 253 device_id)); | 280 device_id, agc_is_enabled_)); |
| 254 } | 281 } |
| 255 | 282 |
| 256 pending_device_ready_ = false; | 283 pending_device_ready_ = false; |
| 257 // Notify the client that the device has been started. | 284 // Notify the client that the device has been started. |
| 258 if (event_handler_) | 285 if (event_handler_) |
| 259 event_handler_->OnDeviceStarted(device_id); | 286 event_handler_->OnDeviceStarted(device_id); |
| 260 } | 287 } |
| 261 | 288 |
| 262 void AudioInputDevice::Send(IPC::Message* message) { | 289 void AudioInputDevice::Send(IPC::Message* message) { |
| 263 filter_->Send(message); | 290 filter_->Send(message); |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 279 } | 306 } |
| 280 | 307 |
| 281 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { | 308 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { |
| 282 } | 309 } |
| 283 | 310 |
| 284 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { | 311 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { |
| 285 shared_memory_.Map(memory_length_); | 312 shared_memory_.Map(memory_length_); |
| 286 } | 313 } |
| 287 | 314 |
| 288 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { | 315 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { |
| 316 | |
|
tommi (sloooow) - chröme
2012/03/26 15:26:40
remove this empty line
henrika (OOO until Aug 14)
2012/03/27 09:20:38
Done.
| |
| 317 // The shared memory represents parameters, size of the data buffer and the | |
| 318 // actual data buffer containing audio data. Map the memory into this | |
| 319 // structure and parse out parameters and data area. | |
| 320 AudioInputBuffer* buffer = | |
| 321 reinterpret_cast<AudioInputBuffer*>(shared_memory_.memory()); | |
| 322 uint32 size = buffer->params.size; | |
| 323 DCHECK_EQ(size, memory_length_ - sizeof(AudioInputBufferParameters)); | |
| 324 double volume = buffer->params.volume; | |
| 325 | |
| 289 int audio_delay_milliseconds = pending_data / bytes_per_ms_; | 326 int audio_delay_milliseconds = pending_data / bytes_per_ms_; |
| 290 int16* memory = reinterpret_cast<int16*>(shared_memory_.memory()); | 327 int16* memory = reinterpret_cast<int16*>(buffer->audio); |
|
tommi (sloooow) - chröme
2012/03/26 15:26:40
nit: &buffer->audio[0]
henrika (OOO until Aug 14)
2012/03/27 09:20:38
Done.
| |
| 291 const size_t number_of_frames = audio_parameters_.frames_per_buffer(); | 328 const size_t number_of_frames = audio_parameters_.frames_per_buffer(); |
| 292 const int bytes_per_sample = sizeof(memory[0]); | 329 const int bytes_per_sample = sizeof(memory[0]); |
| 293 | 330 |
| 294 // Deinterleave each channel and convert to 32-bit floating-point | 331 // Deinterleave each channel and convert to 32-bit floating-point |
| 295 // with nominal range -1.0 -> +1.0. | 332 // with nominal range -1.0 -> +1.0. |
| 296 for (int channel_index = 0; channel_index < audio_parameters_.channels(); | 333 for (int channel_index = 0; channel_index < audio_parameters_.channels(); |
| 297 ++channel_index) { | 334 ++channel_index) { |
| 298 media::DeinterleaveAudioChannel(memory, | 335 media::DeinterleaveAudioChannel(memory, |
| 299 audio_data_[channel_index], | 336 audio_data_[channel_index], |
| 300 audio_parameters_.channels(), | 337 audio_parameters_.channels(), |
| 301 channel_index, | 338 channel_index, |
| 302 bytes_per_sample, | 339 bytes_per_sample, |
| 303 number_of_frames); | 340 number_of_frames); |
| 304 } | 341 } |
| 305 | 342 |
| 306 // Deliver captured data to the client in floating point format | 343 // Deliver captured data to the client in floating point format |
| 307 // and update the audio-delay measurement. | 344 // and update the audio-delay measurement. |
| 308 capture_callback_->Capture(audio_data_, number_of_frames, | 345 capture_callback_->Capture(audio_data_, number_of_frames, |
| 309 audio_delay_milliseconds); | 346 audio_delay_milliseconds, volume); |
| 310 } | 347 } |
| OLD | NEW |