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 30 matching lines...) Expand all Loading... | |
41 int channels, | 41 int channels, |
42 double sample_rate, | 42 double sample_rate, |
43 CaptureCallback* callback, | 43 CaptureCallback* callback, |
44 CaptureEventHandler* event_handler) | 44 CaptureEventHandler* event_handler) |
45 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()), | 45 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()), |
46 callback_(callback), | 46 callback_(callback), |
47 event_handler_(event_handler), | 47 event_handler_(event_handler), |
48 volume_(1.0), | 48 volume_(1.0), |
49 stream_id_(0), | 49 stream_id_(0), |
50 session_id_(0), | 50 session_id_(0), |
51 pending_device_ready_(false) { | 51 pending_device_ready_(false), |
52 agc_is_enabled_(false) { | |
tommi (sloooow) - chröme
2012/03/26 15:26:38
indent
| |
52 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); | 53 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); |
53 #if defined(OS_MACOSX) | 54 #if defined(OS_MACOSX) |
54 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; | 55 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; |
55 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; | 56 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; |
56 #elif defined(OS_WIN) | 57 #elif defined(OS_WIN) |
57 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; | 58 DVLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; |
58 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; | 59 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; |
59 #else | 60 #else |
60 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well. | 61 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well. |
61 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR; | 62 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR; |
(...skipping 28 matching lines...) Expand all Loading... | |
90 { | 91 { |
91 base::AutoLock auto_lock(audio_thread_lock_); | 92 base::AutoLock auto_lock(audio_thread_lock_); |
92 audio_thread_.Stop(MessageLoop::current()); | 93 audio_thread_.Stop(MessageLoop::current()); |
93 } | 94 } |
94 | 95 |
95 message_loop()->PostTask(FROM_HERE, | 96 message_loop()->PostTask(FROM_HERE, |
96 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); | 97 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this)); |
97 } | 98 } |
98 | 99 |
99 bool AudioInputDevice::SetVolume(double volume) { | 100 bool AudioInputDevice::SetVolume(double volume) { |
100 NOTIMPLEMENTED(); | 101 if (volume < 0 || volume > 1.0) |
102 return false; | |
tommi (sloooow) - chröme
2012/03/26 15:26:38
NOTREACHED?
| |
103 | |
104 message_loop()->PostTask(FROM_HERE, | |
105 base::Bind(&AudioInputDevice::SetVolumeOnIOThread, this, volume)); | |
106 | |
107 return true; | |
108 } | |
109 | |
110 bool AudioInputDevice::GetVolume(double* volume) { | |
111 NOTREACHED(); | |
101 return false; | 112 return false; |
102 } | 113 } |
103 | 114 |
104 bool AudioInputDevice::GetVolume(double* volume) { | 115 void AudioInputDevice::SetAutomaticGainControl(bool enabled) { |
105 NOTIMPLEMENTED(); | 116 DVLOG(1) << "SetAutomaticGainControl(enabled=" << enabled << ")"; |
106 return false; | 117 message_loop()->PostTask(FROM_HERE, |
118 base::Bind(&AudioInputDevice::SetAutomaticGainControlOnIOThread, | |
119 this, enabled)); | |
107 } | 120 } |
108 | 121 |
109 void AudioInputDevice::InitializeOnIOThread() { | 122 void AudioInputDevice::InitializeOnIOThread() { |
110 DCHECK(message_loop()->BelongsToCurrentThread()); | 123 DCHECK(message_loop()->BelongsToCurrentThread()); |
111 // Make sure we don't call Start() more than once. | 124 // Make sure we don't call Start() more than once. |
112 DCHECK_EQ(0, stream_id_); | 125 DCHECK_EQ(0, stream_id_); |
113 if (stream_id_) | 126 if (stream_id_) |
114 return; | 127 return; |
115 | 128 |
116 stream_id_ = filter_->AddDelegate(this); | 129 stream_id_ = filter_->AddDelegate(this); |
117 // If |session_id_| is not specified, it will directly create the stream; | 130 // If |session_id_| is not specified, it will directly create the stream; |
118 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser | 131 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser |
119 // and create the stream when getting a OnDeviceReady() callback. | 132 // and create the stream when getting a OnDeviceReady() callback. |
120 if (!session_id_) { | 133 if (!session_id_) { |
121 Send(new AudioInputHostMsg_CreateStream( | 134 Send(new AudioInputHostMsg_CreateStream( |
122 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId)); | 135 stream_id_, audio_parameters_, AudioManagerBase::kDefaultDeviceId, |
136 agc_is_enabled_)); | |
123 } else { | 137 } else { |
124 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); | 138 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); |
125 pending_device_ready_ = true; | 139 pending_device_ready_ = true; |
126 } | 140 } |
127 } | 141 } |
128 | 142 |
129 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { | 143 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { |
130 DCHECK(message_loop()->BelongsToCurrentThread()); | 144 DCHECK(message_loop()->BelongsToCurrentThread()); |
131 session_id_ = session_id; | 145 session_id_ = session_id; |
132 } | 146 } |
133 | 147 |
134 void AudioInputDevice::StartOnIOThread() { | 148 void AudioInputDevice::StartOnIOThread() { |
135 DCHECK(message_loop()->BelongsToCurrentThread()); | 149 DCHECK(message_loop()->BelongsToCurrentThread()); |
136 if (stream_id_) | 150 if (stream_id_) |
137 Send(new AudioInputHostMsg_RecordStream(stream_id_)); | 151 Send(new AudioInputHostMsg_RecordStream(stream_id_)); |
138 } | 152 } |
139 | 153 |
140 void AudioInputDevice::ShutDownOnIOThread() { | 154 void AudioInputDevice::ShutDownOnIOThread() { |
141 DCHECK(message_loop()->BelongsToCurrentThread()); | 155 DCHECK(message_loop()->BelongsToCurrentThread()); |
142 // NOTE: |completion| may be NULL. | 156 // NOTE: |completion| may be NULL. |
143 // Make sure we don't call shutdown more than once. | 157 // Make sure we don't call shutdown more than once. |
144 if (stream_id_) { | 158 if (stream_id_) { |
145 filter_->RemoveDelegate(stream_id_); | 159 filter_->RemoveDelegate(stream_id_); |
146 Send(new AudioInputHostMsg_CloseStream(stream_id_)); | 160 Send(new AudioInputHostMsg_CloseStream(stream_id_)); |
147 | 161 |
148 stream_id_ = 0; | 162 stream_id_ = 0; |
149 session_id_ = 0; | 163 session_id_ = 0; |
150 pending_device_ready_ = false; | 164 pending_device_ready_ = false; |
165 agc_is_enabled_ = false; | |
151 } | 166 } |
152 | 167 |
153 // We can run into an issue where ShutDownOnIOThread is called right after | 168 // We can run into an issue where ShutDownOnIOThread is called right after |
154 // OnStreamCreated is called in cases where Start/Stop are called before we | 169 // OnStreamCreated is called in cases where Start/Stop are called before we |
155 // get the OnStreamCreated callback. To handle that corner case, we call | 170 // get the OnStreamCreated callback. To handle that corner case, we call |
156 // Stop(). In most cases, the thread will already be stopped. | 171 // Stop(). In most cases, the thread will already be stopped. |
157 // Another situation is when the IO thread goes away before Stop() is called | 172 // Another situation is when the IO thread goes away before Stop() is called |
158 // in which case, we cannot use the message loop to close the thread handle | 173 // in which case, we cannot use the message loop to close the thread handle |
159 // and can't not rely on the main thread existing either. | 174 // and can't not rely on the main thread existing either. |
160 base::ThreadRestrictions::ScopedAllowIO allow_io; | 175 base::ThreadRestrictions::ScopedAllowIO allow_io; |
161 audio_thread_.Stop(NULL); | 176 audio_thread_.Stop(NULL); |
162 audio_callback_.reset(); | 177 audio_callback_.reset(); |
163 } | 178 } |
164 | 179 |
165 void AudioInputDevice::SetVolumeOnIOThread(double volume) { | 180 void AudioInputDevice::SetVolumeOnIOThread(double volume) { |
166 DCHECK(message_loop()->BelongsToCurrentThread()); | 181 DCHECK(message_loop()->BelongsToCurrentThread()); |
167 if (stream_id_) | 182 if (stream_id_) |
168 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); | 183 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); |
169 } | 184 } |
170 | 185 |
186 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { | |
187 DCHECK(message_loop()->BelongsToCurrentThread()); | |
188 // The state of the AGC can not be modified while capturing is active. | |
189 DCHECK_EQ(0, stream_id_); | |
190 if (stream_id_) | |
191 return; | |
192 | |
193 // We simply store the new AGC setting here. This value will be used when | |
194 // a new stream is initialized and by GetAutomaticGainControl(). | |
195 agc_is_enabled_ = enabled; | |
196 } | |
197 | |
171 void AudioInputDevice::OnStreamCreated( | 198 void AudioInputDevice::OnStreamCreated( |
172 base::SharedMemoryHandle handle, | 199 base::SharedMemoryHandle handle, |
173 base::SyncSocket::Handle socket_handle, | 200 base::SyncSocket::Handle socket_handle, |
174 uint32 length) { | 201 uint32 length) { |
175 DCHECK(message_loop()->BelongsToCurrentThread()); | 202 DCHECK(message_loop()->BelongsToCurrentThread()); |
176 #if defined(OS_WIN) | 203 #if defined(OS_WIN) |
177 DCHECK(handle); | 204 DCHECK(handle); |
178 DCHECK(socket_handle); | 205 DCHECK(socket_handle); |
179 #else | 206 #else |
180 DCHECK_GE(handle.fd, 0); | 207 DCHECK_GE(handle.fd, 0); |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
258 if (!pending_device_ready_) | 285 if (!pending_device_ready_) |
259 return; | 286 return; |
260 | 287 |
261 // If AudioInputDeviceManager returns an empty string, it means no device | 288 // If AudioInputDeviceManager returns an empty string, it means no device |
262 // is ready for start. | 289 // is ready for start. |
263 if (device_id.empty()) { | 290 if (device_id.empty()) { |
264 filter_->RemoveDelegate(stream_id_); | 291 filter_->RemoveDelegate(stream_id_); |
265 stream_id_ = 0; | 292 stream_id_ = 0; |
266 } else { | 293 } else { |
267 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, | 294 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, |
268 device_id)); | 295 device_id, agc_is_enabled_)); |
269 } | 296 } |
270 | 297 |
271 pending_device_ready_ = false; | 298 pending_device_ready_ = false; |
272 // Notify the client that the device has been started. | 299 // Notify the client that the device has been started. |
273 if (event_handler_) | 300 if (event_handler_) |
274 event_handler_->OnDeviceStarted(device_id); | 301 event_handler_->OnDeviceStarted(device_id); |
275 } | 302 } |
276 | 303 |
277 void AudioInputDevice::Send(IPC::Message* message) { | 304 void AudioInputDevice::Send(IPC::Message* message) { |
278 filter_->Send(message); | 305 filter_->Send(message); |
(...skipping 15 matching lines...) Expand all Loading... | |
294 } | 321 } |
295 | 322 |
296 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { | 323 AudioInputDevice::AudioThreadCallback::~AudioThreadCallback() { |
297 } | 324 } |
298 | 325 |
299 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { | 326 void AudioInputDevice::AudioThreadCallback::MapSharedMemory() { |
300 shared_memory_.Map(memory_length_); | 327 shared_memory_.Map(memory_length_); |
301 } | 328 } |
302 | 329 |
303 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { | 330 void AudioInputDevice::AudioThreadCallback::Process(int pending_data) { |
331 | |
tommi (sloooow) - chröme
2012/03/26 15:26:38
remove empty line
| |
332 // The shared memory represents parameters, size of the data buffer and the | |
333 // actual data buffer containing audio data. Map the memory into this | |
334 // structure and parse out parameters and data area. | |
335 AudioInputBuffer* buffer = | |
336 reinterpret_cast<AudioInputBuffer*>(shared_memory_.memory()); | |
337 uint32 size = buffer->params.size; | |
338 DCHECK_EQ(size, memory_length_ - sizeof(AudioInputBufferParameters)); | |
339 double volume = buffer->params.volume; | |
340 | |
304 int audio_delay_milliseconds = pending_data / bytes_per_ms_; | 341 int audio_delay_milliseconds = pending_data / bytes_per_ms_; |
305 int16* memory = reinterpret_cast<int16*>(shared_memory_.memory()); | 342 int16* memory = reinterpret_cast<int16*>(&buffer->audio[0]); |
306 const size_t number_of_frames = audio_parameters_.samples_per_packet; | 343 const size_t number_of_frames = audio_parameters_.samples_per_packet; |
307 const int bytes_per_sample = sizeof(memory[0]); | 344 const int bytes_per_sample = sizeof(memory[0]); |
308 | 345 |
309 // Deinterleave each channel and convert to 32-bit floating-point | 346 // Deinterleave each channel and convert to 32-bit floating-point |
310 // with nominal range -1.0 -> +1.0. | 347 // with nominal range -1.0 -> +1.0. |
311 for (int channel_index = 0; channel_index < audio_parameters_.channels; | 348 for (int channel_index = 0; channel_index < audio_parameters_.channels; |
312 ++channel_index) { | 349 ++channel_index) { |
313 media::DeinterleaveAudioChannel(memory, | 350 media::DeinterleaveAudioChannel(memory, |
314 audio_data_[channel_index], | 351 audio_data_[channel_index], |
315 audio_parameters_.channels, | 352 audio_parameters_.channels, |
316 channel_index, | 353 channel_index, |
317 bytes_per_sample, | 354 bytes_per_sample, |
318 number_of_frames); | 355 number_of_frames); |
319 } | 356 } |
320 | 357 |
321 // Deliver captured data to the client in floating point format | 358 // Deliver captured data to the client in floating point format |
322 // and update the audio-delay measurement. | 359 // and update the audio-delay measurement. |
323 capture_callback_->Capture(audio_data_, number_of_frames, | 360 capture_callback_->Capture(audio_data_, number_of_frames, |
324 audio_delay_milliseconds); | 361 audio_delay_milliseconds, volume); |
325 } | 362 } |
OLD | NEW |