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 27 matching lines...) Expand all Loading... | |
38 }; | 38 }; |
39 | 39 |
40 AudioInputDevice::AudioInputDevice(const media::AudioParameters& params, | 40 AudioInputDevice::AudioInputDevice(const media::AudioParameters& params, |
41 CaptureCallback* callback, | 41 CaptureCallback* callback, |
42 CaptureEventHandler* event_handler) | 42 CaptureEventHandler* event_handler) |
43 : ScopedLoopObserver( | 43 : ScopedLoopObserver( |
44 ChildProcess::current()->io_message_loop()->message_loop_proxy()), | 44 ChildProcess::current()->io_message_loop()->message_loop_proxy()), |
45 audio_parameters_(params), | 45 audio_parameters_(params), |
46 callback_(callback), | 46 callback_(callback), |
47 event_handler_(event_handler), | 47 event_handler_(event_handler), |
48 volume_(1.0), | |
49 stream_id_(0), | 48 stream_id_(0), |
50 session_id_(0), | 49 session_id_(0), |
51 pending_device_ready_(false), | 50 pending_device_ready_(false), |
52 agc_is_enabled_(false) { | 51 agc_is_enabled_(false) { |
53 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); | 52 // TODO(tommi): This needs to be updated to match AudioDevice. |
53 ipc_ = RenderThreadImpl::current()->audio_input_message_filter(); | |
54 } | 54 } |
55 | 55 |
56 void AudioInputDevice::SetDevice(int session_id) { | 56 void AudioInputDevice::SetDevice(int session_id) { |
57 DVLOG(1) << "SetDevice (session_id=" << session_id << ")"; | 57 DVLOG(1) << "SetDevice (session_id=" << session_id << ")"; |
58 message_loop()->PostTask(FROM_HERE, | 58 message_loop()->PostTask(FROM_HERE, |
59 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id)); | 59 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id)); |
60 } | 60 } |
61 | 61 |
62 void AudioInputDevice::Start() { | 62 void AudioInputDevice::Start() { |
63 DVLOG(1) << "Start()"; | 63 DVLOG(1) << "Start()"; |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
126 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); | 126 audio_thread_.Start(audio_callback_.get(), socket_handle, "AudioInputDevice"); |
127 | 127 |
128 MessageLoop::current()->PostTask(FROM_HERE, | 128 MessageLoop::current()->PostTask(FROM_HERE, |
129 base::Bind(&AudioInputDevice::StartOnIOThread, this)); | 129 base::Bind(&AudioInputDevice::StartOnIOThread, this)); |
130 } | 130 } |
131 | 131 |
132 void AudioInputDevice::OnVolume(double volume) { | 132 void AudioInputDevice::OnVolume(double volume) { |
133 NOTIMPLEMENTED(); | 133 NOTIMPLEMENTED(); |
134 } | 134 } |
135 | 135 |
136 void AudioInputDevice::OnStateChanged(AudioStreamState state) { | 136 void AudioInputDevice::OnStateChanged( |
137 media::AudioInputDeviceIPCDelegate::State state) { | |
137 DCHECK(message_loop()->BelongsToCurrentThread()); | 138 DCHECK(message_loop()->BelongsToCurrentThread()); |
138 | 139 |
139 // Do nothing if the stream has been closed. | 140 // Do nothing if the stream has been closed. |
140 if (!stream_id_) | 141 if (!stream_id_) |
141 return; | 142 return; |
142 | 143 |
143 switch (state) { | 144 switch (state) { |
144 // TODO(xians): This should really be kAudioStreamStopped since the stream | 145 case media::AudioInputDeviceIPCDelegate::kStopped: |
145 // has been closed at this point. | |
146 case kAudioStreamPaused: | |
147 // TODO(xians): Should we just call ShutDownOnIOThread here instead? | 146 // TODO(xians): Should we just call ShutDownOnIOThread here instead? |
148 filter_->RemoveDelegate(stream_id_); | 147 ipc_->RemoveDelegate(stream_id_); |
149 | 148 |
150 audio_thread_.Stop(MessageLoop::current()); | 149 audio_thread_.Stop(MessageLoop::current()); |
151 audio_callback_.reset(); | 150 audio_callback_.reset(); |
152 | 151 |
153 if (event_handler_) | 152 if (event_handler_) |
154 event_handler_->OnDeviceStopped(); | 153 event_handler_->OnDeviceStopped(); |
155 | 154 |
156 stream_id_ = 0; | 155 stream_id_ = 0; |
157 pending_device_ready_ = false; | 156 pending_device_ready_ = false; |
158 break; | 157 break; |
159 case kAudioStreamPlaying: | 158 case media::AudioInputDeviceIPCDelegate::kRecording: |
160 NOTIMPLEMENTED(); | 159 NOTIMPLEMENTED(); |
161 break; | 160 break; |
162 case kAudioStreamError: | 161 case media::AudioInputDeviceIPCDelegate::kError: |
163 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; | 162 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; |
164 // Don't dereference the callback object if the audio thread | 163 // Don't dereference the callback object if the audio thread |
165 // is stopped or stopping. That could mean that the callback | 164 // is stopped or stopping. That could mean that the callback |
166 // object has been deleted. | 165 // object has been deleted. |
167 // TODO(tommi): Add an explicit contract for clearing the callback | 166 // TODO(tommi): Add an explicit contract for clearing the callback |
168 // object. Possibly require calling Initialize again or provide | 167 // object. Possibly require calling Initialize again or provide |
169 // a callback object via Start() and clear it in Stop(). | 168 // a callback object via Start() and clear it in Stop(). |
170 if (!audio_thread_.IsStopped()) | 169 if (!audio_thread_.IsStopped()) |
171 callback_->OnCaptureError(); | 170 callback_->OnCaptureError(); |
172 break; | 171 break; |
173 default: | 172 default: |
174 NOTREACHED(); | 173 NOTREACHED(); |
175 break; | 174 break; |
176 } | 175 } |
177 } | 176 } |
178 | 177 |
179 void AudioInputDevice::OnDeviceReady(const std::string& device_id) { | 178 void AudioInputDevice::OnDeviceReady(const std::string& device_id) { |
180 DCHECK(message_loop()->BelongsToCurrentThread()); | 179 DCHECK(message_loop()->BelongsToCurrentThread()); |
181 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; | 180 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; |
182 | 181 |
183 // Takes care of the case when Stop() is called before OnDeviceReady(). | 182 // Takes care of the case when Stop() is called before OnDeviceReady(). |
184 if (!pending_device_ready_) | 183 if (!pending_device_ready_) |
185 return; | 184 return; |
186 | 185 |
187 // If AudioInputDeviceManager returns an empty string, it means no device | 186 // If AudioInputDeviceManager returns an empty string, it means no device |
188 // is ready for start. | 187 // is ready for start. |
189 if (device_id.empty()) { | 188 if (device_id.empty()) { |
190 filter_->RemoveDelegate(stream_id_); | 189 ipc_->RemoveDelegate(stream_id_); |
191 stream_id_ = 0; | 190 stream_id_ = 0; |
192 } else { | 191 } else { |
193 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, | 192 ipc_->CreateStream(stream_id_, audio_parameters_, device_id, |
194 device_id, agc_is_enabled_)); | 193 agc_is_enabled_); |
scherkus (not reviewing)
2012/07/24 17:57:48
indenting
tommi (sloooow) - chröme
2012/07/25 13:46:17
Done.
| |
195 } | 194 } |
196 | 195 |
197 pending_device_ready_ = false; | 196 pending_device_ready_ = false; |
198 // Notify the client that the device has been started. | 197 // Notify the client that the device has been started. |
199 if (event_handler_) | 198 if (event_handler_) |
200 event_handler_->OnDeviceStarted(device_id); | 199 event_handler_->OnDeviceStarted(device_id); |
201 } | 200 } |
202 | 201 |
202 void AudioInputDevice::OnIPCClosed() { | |
203 ipc_ = NULL; | |
scherkus (not reviewing)
2012/07/24 17:57:48
FYI we seem to guard against calling ipc_ with str
tommi (sloooow) - chröme
2012/07/25 13:46:17
The stream_id_ checks are not really meant to guar
| |
204 } | |
205 | |
203 AudioInputDevice::~AudioInputDevice() { | 206 AudioInputDevice::~AudioInputDevice() { |
204 // TODO(henrika): The current design requires that the user calls | 207 // TODO(henrika): The current design requires that the user calls |
205 // Stop before deleting this class. | 208 // Stop before deleting this class. |
206 CHECK_EQ(0, stream_id_); | 209 CHECK_EQ(0, stream_id_); |
207 } | 210 } |
208 | 211 |
209 void AudioInputDevice::InitializeOnIOThread() { | 212 void AudioInputDevice::InitializeOnIOThread() { |
210 DCHECK(message_loop()->BelongsToCurrentThread()); | 213 DCHECK(message_loop()->BelongsToCurrentThread()); |
211 // Make sure we don't call Start() more than once. | 214 // Make sure we don't call Start() more than once. |
212 DCHECK_EQ(0, stream_id_); | 215 DCHECK_EQ(0, stream_id_); |
213 if (stream_id_) | 216 if (stream_id_) |
214 return; | 217 return; |
215 | 218 |
216 stream_id_ = filter_->AddDelegate(this); | 219 stream_id_ = ipc_->AddDelegate(this); |
217 // If |session_id_| is not specified, it will directly create the stream; | 220 // If |session_id_| is not specified, it will directly create the stream; |
218 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser | 221 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser |
219 // and create the stream when getting a OnDeviceReady() callback. | 222 // and create the stream when getting a OnDeviceReady() callback. |
220 if (!session_id_) { | 223 if (!session_id_) { |
221 Send(new AudioInputHostMsg_CreateStream( | 224 ipc_->CreateStream(stream_id_, audio_parameters_, |
222 stream_id_, audio_parameters_, | 225 media::AudioManagerBase::kDefaultDeviceId, agc_is_enabled_); |
223 media::AudioManagerBase::kDefaultDeviceId, | |
224 agc_is_enabled_)); | |
225 } else { | 226 } else { |
226 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); | 227 ipc_->StartDevice(stream_id_, session_id_); |
227 pending_device_ready_ = true; | 228 pending_device_ready_ = true; |
228 } | 229 } |
229 } | 230 } |
230 | 231 |
231 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { | 232 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { |
232 DCHECK(message_loop()->BelongsToCurrentThread()); | 233 DCHECK(message_loop()->BelongsToCurrentThread()); |
233 session_id_ = session_id; | 234 session_id_ = session_id; |
234 } | 235 } |
235 | 236 |
236 void AudioInputDevice::StartOnIOThread() { | 237 void AudioInputDevice::StartOnIOThread() { |
237 DCHECK(message_loop()->BelongsToCurrentThread()); | 238 DCHECK(message_loop()->BelongsToCurrentThread()); |
238 if (stream_id_) | 239 if (stream_id_) |
239 Send(new AudioInputHostMsg_RecordStream(stream_id_)); | 240 ipc_->RecordStream(stream_id_); |
240 } | 241 } |
241 | 242 |
242 void AudioInputDevice::ShutDownOnIOThread() { | 243 void AudioInputDevice::ShutDownOnIOThread() { |
243 DCHECK(message_loop()->BelongsToCurrentThread()); | 244 DCHECK(message_loop()->BelongsToCurrentThread()); |
244 // NOTE: |completion| may be NULL. | 245 // NOTE: |completion| may be NULL. |
245 // Make sure we don't call shutdown more than once. | 246 // Make sure we don't call shutdown more than once. |
246 if (stream_id_) { | 247 if (stream_id_) { |
247 filter_->RemoveDelegate(stream_id_); | 248 ipc_->CloseStream(stream_id_); |
248 Send(new AudioInputHostMsg_CloseStream(stream_id_)); | 249 ipc_->RemoveDelegate(stream_id_); |
249 | 250 |
250 stream_id_ = 0; | 251 stream_id_ = 0; |
251 session_id_ = 0; | 252 session_id_ = 0; |
252 pending_device_ready_ = false; | 253 pending_device_ready_ = false; |
253 agc_is_enabled_ = false; | 254 agc_is_enabled_ = false; |
254 } | 255 } |
255 | 256 |
256 // We can run into an issue where ShutDownOnIOThread is called right after | 257 // We can run into an issue where ShutDownOnIOThread is called right after |
257 // OnStreamCreated is called in cases where Start/Stop are called before we | 258 // OnStreamCreated is called in cases where Start/Stop are called before we |
258 // get the OnStreamCreated callback. To handle that corner case, we call | 259 // get the OnStreamCreated callback. To handle that corner case, we call |
259 // Stop(). In most cases, the thread will already be stopped. | 260 // Stop(). In most cases, the thread will already be stopped. |
260 // Another situation is when the IO thread goes away before Stop() is called | 261 // Another situation is when the IO thread goes away before Stop() is called |
261 // in which case, we cannot use the message loop to close the thread handle | 262 // in which case, we cannot use the message loop to close the thread handle |
262 // and can't not rely on the main thread existing either. | 263 // and can't not rely on the main thread existing either. |
263 base::ThreadRestrictions::ScopedAllowIO allow_io; | 264 base::ThreadRestrictions::ScopedAllowIO allow_io; |
264 audio_thread_.Stop(NULL); | 265 audio_thread_.Stop(NULL); |
265 audio_callback_.reset(); | 266 audio_callback_.reset(); |
266 } | 267 } |
267 | 268 |
268 void AudioInputDevice::SetVolumeOnIOThread(double volume) { | 269 void AudioInputDevice::SetVolumeOnIOThread(double volume) { |
269 DCHECK(message_loop()->BelongsToCurrentThread()); | 270 DCHECK(message_loop()->BelongsToCurrentThread()); |
270 if (stream_id_) | 271 if (stream_id_) |
271 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); | 272 ipc_->SetVolume(stream_id_, volume); |
272 } | 273 } |
273 | 274 |
274 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { | 275 void AudioInputDevice::SetAutomaticGainControlOnIOThread(bool enabled) { |
275 DCHECK(message_loop()->BelongsToCurrentThread()); | 276 DCHECK(message_loop()->BelongsToCurrentThread()); |
276 DCHECK_EQ(0, stream_id_) << | 277 DCHECK_EQ(0, stream_id_) << |
277 "The AGC state can not be modified while capturing is active."; | 278 "The AGC state can not be modified while capturing is active."; |
278 if (stream_id_) | 279 if (stream_id_) |
279 return; | 280 return; |
280 | 281 |
281 // We simply store the new AGC setting here. This value will be used when | 282 // We simply store the new AGC setting here. This value will be used when |
282 // a new stream is initialized and by GetAutomaticGainControl(). | 283 // a new stream is initialized and by GetAutomaticGainControl(). |
283 agc_is_enabled_ = enabled; | 284 agc_is_enabled_ = enabled; |
284 } | 285 } |
285 | 286 |
286 void AudioInputDevice::Send(IPC::Message* message) { | |
287 filter_->Send(message); | |
288 } | |
289 | |
290 void AudioInputDevice::WillDestroyCurrentMessageLoop() { | 287 void AudioInputDevice::WillDestroyCurrentMessageLoop() { |
291 LOG(ERROR) << "IO loop going away before the input device has been stopped"; | 288 LOG(ERROR) << "IO loop going away before the input device has been stopped"; |
292 ShutDownOnIOThread(); | 289 ShutDownOnIOThread(); |
293 } | 290 } |
294 | 291 |
295 // AudioInputDevice::AudioThreadCallback | 292 // AudioInputDevice::AudioThreadCallback |
296 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( | 293 AudioInputDevice::AudioThreadCallback::AudioThreadCallback( |
297 const media::AudioParameters& audio_parameters, | 294 const media::AudioParameters& audio_parameters, |
298 base::SharedMemoryHandle memory, | 295 base::SharedMemoryHandle memory, |
299 int memory_length, | 296 int memory_length, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
334 channel_index, | 331 channel_index, |
335 bytes_per_sample, | 332 bytes_per_sample, |
336 number_of_frames); | 333 number_of_frames); |
337 } | 334 } |
338 | 335 |
339 // Deliver captured data to the client in floating point format | 336 // Deliver captured data to the client in floating point format |
340 // and update the audio-delay measurement. | 337 // and update the audio-delay measurement. |
341 capture_callback_->Capture(audio_data_, number_of_frames, | 338 capture_callback_->Capture(audio_data_, number_of_frames, |
342 audio_delay_milliseconds, volume); | 339 audio_delay_milliseconds, volume); |
343 } | 340 } |
OLD | NEW |