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 |