Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(380)

Side by Side Diff: content/renderer/media/audio_input_device.cc

Issue 9121045: Switch AudioDevice classes from SyncSocket to CancelableSyncSocket. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Address comments, add temporary ScopedAllowIO for the audio thread cleanup+TODO for next cl. Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/time.h" 10 #include "base/time.h"
10 #include "content/common/child_process.h" 11 #include "content/common/child_process.h"
11 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
12 #include "content/common/view_messages.h" 13 #include "content/common/view_messages.h"
13 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
14 #include "media/audio/audio_manager_base.h" 15 #include "media/audio/audio_manager_base.h"
15 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
16 17
17 AudioInputDevice::AudioInputDevice(size_t buffer_size, 18 AudioInputDevice::AudioInputDevice(size_t buffer_size,
18 int channels, 19 int channels,
19 double sample_rate, 20 double sample_rate,
20 CaptureCallback* callback, 21 CaptureCallback* callback,
21 CaptureEventHandler* event_handler) 22 CaptureEventHandler* event_handler)
22 : callback_(callback), 23 : callback_(callback),
23 event_handler_(event_handler), 24 event_handler_(event_handler),
24 audio_delay_milliseconds_(0), 25 audio_delay_milliseconds_(0),
25 volume_(1.0), 26 volume_(1.0),
26 stream_id_(0), 27 stream_id_(0),
27 session_id_(0), 28 session_id_(0),
28 pending_device_ready_(false), 29 pending_device_ready_(false),
29 shared_memory_handle_(base::SharedMemory::NULLHandle()), 30 shared_memory_handle_(base::SharedMemory::NULLHandle()),
30 socket_handle_(base::SyncSocket::kInvalidHandle),
31 memory_length_(0) { 31 memory_length_(0) {
32 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 32 filter_ = RenderThreadImpl::current()->audio_input_message_filter();
33 audio_data_.reserve(channels); 33 audio_data_.reserve(channels);
34 #if defined(OS_MACOSX) 34 #if defined(OS_MACOSX)
35 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; 35 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X.";
36 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 36 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
37 #elif defined(OS_WIN) 37 #elif defined(OS_WIN)
38 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; 38 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows.";
39 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 39 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
40 #else 40 #else
(...skipping 29 matching lines...) Expand all
70 VLOG(1) << "SetDevice (session_id=" << session_id << ")"; 70 VLOG(1) << "SetDevice (session_id=" << session_id << ")";
71 ChildProcess::current()->io_message_loop()->PostTask( 71 ChildProcess::current()->io_message_loop()->PostTask(
72 FROM_HERE, 72 FROM_HERE,
73 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, 73 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this,
74 session_id)); 74 session_id));
75 } 75 }
76 76
77 void AudioInputDevice::Stop() { 77 void AudioInputDevice::Stop() {
78 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); 78 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop());
79 VLOG(1) << "Stop()"; 79 VLOG(1) << "Stop()";
80 // Max waiting time for Stop() to complete. If this time limit is passed,
81 // we will stop waiting and return false. It ensures that Stop() can't block
82 // the calling thread forever.
83 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000);
84 80
85 base::WaitableEvent completion(false, false); 81 base::WaitableEvent completion(false, false);
86
87 ChildProcess::current()->io_message_loop()->PostTask( 82 ChildProcess::current()->io_message_loop()->PostTask(
88 FROM_HERE, 83 FROM_HERE,
89 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this, 84 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this,
90 &completion)); 85 &completion));
91 86
92 // We wait here for the IO task to be completed to remove race conflicts 87 // We wait here for the IO task to be completed to remove race conflicts
93 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 88 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
94 // function call. 89 // function call.
95 if (!completion.TimedWait(kMaxTimeOut)) { 90 completion.Wait();
96 LOG(ERROR) << "Failed to shut down audio input on IO thread";
97 }
98
99 if (audio_thread_.get()) {
100 // Terminate the main thread function in the audio thread.
101 {
102 base::SyncSocket socket(socket_handle_);
103 }
104 // Wait for the audio thread to exit.
105 audio_thread_->Join();
106 // Ensures that we can call Stop() multiple times.
107 audio_thread_.reset(NULL);
108 }
109 } 91 }
110 92
111 bool AudioInputDevice::SetVolume(double volume) { 93 bool AudioInputDevice::SetVolume(double volume) {
112 NOTIMPLEMENTED(); 94 NOTIMPLEMENTED();
113 return false; 95 return false;
114 } 96 }
115 97
116 bool AudioInputDevice::GetVolume(double* volume) { 98 bool AudioInputDevice::GetVolume(double* volume) {
117 NOTIMPLEMENTED(); 99 NOTIMPLEMENTED();
118 return false; 100 return false;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 136 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
155 // Make sure we don't call shutdown more than once. 137 // Make sure we don't call shutdown more than once.
156 if (!stream_id_) { 138 if (!stream_id_) {
157 completion->Signal(); 139 completion->Signal();
158 return; 140 return;
159 } 141 }
160 142
161 filter_->RemoveDelegate(stream_id_); 143 filter_->RemoveDelegate(stream_id_);
162 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 144 Send(new AudioInputHostMsg_CloseStream(stream_id_));
163 145
146 ShutDownAudioThread();
147
164 stream_id_ = 0; 148 stream_id_ = 0;
165 session_id_ = 0; 149 session_id_ = 0;
166 pending_device_ready_ = false; 150 pending_device_ready_ = false;
167 151
168 completion->Signal(); 152 completion->Signal();
169 } 153 }
170 154
171 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 155 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
172 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 156 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
173 if (stream_id_) 157 if (stream_id_)
(...skipping 19 matching lines...) Expand all
193 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). 177 // Takes care of the case when Stop() is called before OnLowLatencyCreated().
194 if (!stream_id_) { 178 if (!stream_id_) {
195 base::SharedMemory::CloseHandle(handle); 179 base::SharedMemory::CloseHandle(handle);
196 // Close the socket handler. 180 // Close the socket handler.
197 base::SyncSocket socket(socket_handle); 181 base::SyncSocket socket(socket_handle);
198 return; 182 return;
199 } 183 }
200 184
201 shared_memory_handle_ = handle; 185 shared_memory_handle_ = handle;
202 memory_length_ = length; 186 memory_length_ = length;
203 187 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle));
204 socket_handle_ = socket_handle;
205 188
206 audio_thread_.reset( 189 audio_thread_.reset(
207 new base::DelegateSimpleThread(this, "RendererAudioInputThread")); 190 new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
208 audio_thread_->Start(); 191 audio_thread_->Start();
209 192
210 MessageLoop::current()->PostTask( 193 MessageLoop::current()->PostTask(
211 FROM_HERE, 194 FROM_HERE,
212 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 195 base::Bind(&AudioInputDevice::StartOnIOThread, this));
213 } 196 }
214 197
215 void AudioInputDevice::OnVolume(double volume) { 198 void AudioInputDevice::OnVolume(double volume) {
216 NOTIMPLEMENTED(); 199 NOTIMPLEMENTED();
217 } 200 }
218 201
219 void AudioInputDevice::OnStateChanged(AudioStreamState state) { 202 void AudioInputDevice::OnStateChanged(AudioStreamState state) {
220 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 203 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
221 switch (state) { 204 switch (state) {
222 case kAudioStreamPaused: 205 case kAudioStreamPaused:
206 // TODO(xians): Should we just call ShutDownOnIOThread here instead?
207
223 // Do nothing if the stream has been closed. 208 // Do nothing if the stream has been closed.
224 if (!stream_id_) 209 if (!stream_id_)
225 return; 210 return;
226 211
227 filter_->RemoveDelegate(stream_id_); 212 filter_->RemoveDelegate(stream_id_);
228 213
229 // Joining the audio thread will be quite soon, since the stream has 214 ShutDownAudioThread();
230 // been closed before.
231 if (audio_thread_.get()) {
232 {
233 base::SyncSocket socket(socket_handle_);
234 }
235 audio_thread_->Join();
236 audio_thread_.reset(NULL);
237 }
238 215
239 if (event_handler_) 216 if (event_handler_)
240 event_handler_->OnDeviceStopped(); 217 event_handler_->OnDeviceStopped();
241 218
242 stream_id_ = 0; 219 stream_id_ = 0;
243 pending_device_ready_ = false; 220 pending_device_ready_ = false;
244 break; 221 break;
245 case kAudioStreamPlaying: 222 case kAudioStreamPlaying:
246 NOTIMPLEMENTED(); 223 NOTIMPLEMENTED();
247 break; 224 break;
(...skipping 13 matching lines...) Expand all
261 // Takes care of the case when Stop() is called before OnDeviceReady(). 238 // Takes care of the case when Stop() is called before OnDeviceReady().
262 if (!pending_device_ready_) 239 if (!pending_device_ready_)
263 return; 240 return;
264 241
265 // If AudioInputDeviceManager returns an empty string, it means no device 242 // If AudioInputDeviceManager returns an empty string, it means no device
266 // is ready for start. 243 // is ready for start.
267 if (device_id.empty()) { 244 if (device_id.empty()) {
268 filter_->RemoveDelegate(stream_id_); 245 filter_->RemoveDelegate(stream_id_);
269 stream_id_ = 0; 246 stream_id_ = 0;
270 } else { 247 } else {
271 Send(new AudioInputHostMsg_CreateStream( 248 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_,
272 stream_id_, audio_parameters_, true, device_id)); 249 true, device_id));
273 } 250 }
274 251
275 pending_device_ready_ = false; 252 pending_device_ready_ = false;
276 // Notify the client that the device has been started. 253 // Notify the client that the device has been started.
277 if (event_handler_) 254 if (event_handler_)
278 event_handler_->OnDeviceStarted(device_id); 255 event_handler_->OnDeviceStarted(device_id);
279 } 256 }
280 257
281 void AudioInputDevice::Send(IPC::Message* message) { 258 void AudioInputDevice::Send(IPC::Message* message) {
282 filter_->Send(message); 259 filter_->Send(message);
283 } 260 }
284 261
285 // Our audio thread runs here. We receive captured audio samples on 262 // Our audio thread runs here. We receive captured audio samples on
286 // this thread. 263 // this thread.
287 void AudioInputDevice::Run() { 264 void AudioInputDevice::Run() {
288 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 265 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
289 266
290 base::SharedMemory shared_memory(shared_memory_handle_, false); 267 base::SharedMemory shared_memory(shared_memory_handle_, false);
291 shared_memory.Map(memory_length_); 268 shared_memory.Map(memory_length_);
292 269
293 base::SyncSocket socket(socket_handle_); 270 base::CancelableSyncSocket* socket = audio_socket_.get();
scherkus (not reviewing) 2012/01/30 19:10:57 nit: do we need this line of code?
tommi (sloooow) - chröme 2012/01/30 21:53:14 yup (different than before)
294 271
295 int pending_data;
296 const int samples_per_ms = 272 const int samples_per_ms =
297 static_cast<int>(audio_parameters_.sample_rate) / 1000; 273 static_cast<int>(audio_parameters_.sample_rate) / 1000;
298 const int bytes_per_ms = audio_parameters_.channels * 274 const int bytes_per_ms = audio_parameters_.channels *
299 (audio_parameters_.bits_per_sample / 8) * samples_per_ms; 275 (audio_parameters_.bits_per_sample / 8) * samples_per_ms;
300 276
301 while ((sizeof(pending_data) == socket.Receive(&pending_data, 277 while (true) {
302 sizeof(pending_data))) && 278 uint32 pending_data = 0;
303 (pending_data >= 0)) { 279 size_t received = socket->Receive(&pending_data, sizeof(pending_data));
280 if (received != sizeof(pending_data)) {
281 DCHECK(received == 0U);
282 break;
283 }
304 // TODO(henrika): investigate the provided |pending_data| value 284 // TODO(henrika): investigate the provided |pending_data| value
305 // and ensure that it is actually an accurate delay estimation. 285 // and ensure that it is actually an accurate delay estimation.
306 286
307 // Convert the number of pending bytes in the capture buffer 287 // Convert the number of pending bytes in the capture buffer
308 // into milliseconds. 288 // into milliseconds.
309 audio_delay_milliseconds_ = pending_data / bytes_per_ms; 289 audio_delay_milliseconds_ = pending_data / bytes_per_ms;
310 290
311 FireCaptureCallback(reinterpret_cast<int16*>(shared_memory.memory())); 291 FireCaptureCallback(reinterpret_cast<int16*>(shared_memory.memory()));
312 } 292 }
313 } 293 }
314 294
315 void AudioInputDevice::FireCaptureCallback(int16* input_audio) { 295 void AudioInputDevice::FireCaptureCallback(int16* input_audio) {
316 if (!callback_) 296 if (!callback_)
317 return; 297 return;
318 298
319 const size_t number_of_frames = audio_parameters_.samples_per_packet; 299 const size_t number_of_frames = audio_parameters_.samples_per_packet;
320 300
321 const int bytes_per_sample = sizeof(input_audio[0]); 301 const int bytes_per_sample = sizeof(input_audio[0]);
322 302
323 // Deinterleave each channel and convert to 32-bit floating-point 303 // Deinterleave each channel and convert to 32-bit floating-point
324 // with nominal range -1.0 -> +1.0. 304 // with nominal range -1.0 -> +1.0.
325 for (int channel_index = 0; channel_index < audio_parameters_.channels; 305 for (int channel_index = 0; channel_index < audio_parameters_.channels;
326 ++channel_index) { 306 ++channel_index) {
327 media::DeinterleaveAudioChannel(input_audio, 307 media::DeinterleaveAudioChannel(input_audio,
328 audio_data_[channel_index], 308 audio_data_[channel_index],
329 audio_parameters_.channels, 309 audio_parameters_.channels,
330 channel_index, 310 channel_index,
331 bytes_per_sample, 311 bytes_per_sample,
332 number_of_frames); 312 number_of_frames);
333 } 313 }
334 314
335 // Deliver captured data to the client in floating point format 315 // Deliver captured data to the client in floating point format
336 // and update the audio-delay measurement. 316 // and update the audio-delay measurement.
337 callback_->Capture(audio_data_, 317 callback_->Capture(audio_data_,
338 number_of_frames, 318 number_of_frames,
339 audio_delay_milliseconds_); 319 audio_delay_milliseconds_);
340 } 320 }
321
322 void AudioInputDevice::ShutDownAudioThread() {
323 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop());
324
325 // TODO(tommi): This is a copy/paste of the same method in AudioDevice.
326 // We could extract the worker thread+socket bits out to a separate
327 // class to avoid having to fix the same issues twice in these classes.
328
329 if (audio_thread_.get()) {
330 // Close the socket to terminate the main thread function in the
331 // audio thread.
332 audio_socket_->Shutdown(); // Stops blocking Receive calls.
333 // TODO(tommi): We must not do this from the IO thread. Fix.
334 base::ThreadRestrictions::ScopedAllowIO allow_wait;
335 audio_thread_->Join();
336 audio_thread_.reset(NULL);
337 audio_socket_.reset();
338 }
339 }
OLDNEW
« content/renderer/media/audio_device.cc ('K') | « content/renderer/media/audio_input_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698