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

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

Issue 8659040: There is a racing between SyncSocket::Receive in audio_thread_ and SyncSocket::Close in renderer ... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: new proposal from timmi Created 9 years 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/time.h" 9 #include "base/time.h"
10 #include "content/common/child_process.h" 10 #include "content/common/child_process.h"
11 #include "content/common/media/audio_messages.h" 11 #include "content/common/media/audio_messages.h"
12 #include "content/common/view_messages.h" 12 #include "content/common/view_messages.h"
13 #include "content/renderer/render_thread_impl.h" 13 #include "content/renderer/render_thread_impl.h"
14 #include "media/audio/audio_manager_base.h" 14 #include "media/audio/audio_manager_base.h"
15 #include "media/audio/audio_util.h" 15 #include "media/audio/audio_util.h"
16 16
17 AudioInputDevice::AudioInputDevice(size_t buffer_size, 17 AudioInputDevice::AudioInputDevice(size_t buffer_size,
18 int channels, 18 int channels,
19 double sample_rate, 19 double sample_rate,
20 CaptureCallback* callback, 20 CaptureCallback* callback,
21 CaptureEventHandler* event_handler) 21 CaptureEventHandler* event_handler)
22 : callback_(callback), 22 : callback_(callback),
23 event_handler_(event_handler), 23 event_handler_(event_handler),
24 audio_delay_milliseconds_(0), 24 audio_delay_milliseconds_(0),
25 volume_(1.0), 25 volume_(1.0),
26 stream_id_(0), 26 stream_id_(0),
27 session_id_(0), 27 session_id_(0),
28 pending_device_ready_(false) { 28 pending_device_ready_(false),
29 memory_length_(0) {
29 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 30 filter_ = RenderThreadImpl::current()->audio_input_message_filter();
30 audio_data_.reserve(channels); 31 audio_data_.reserve(channels);
31 #if defined(OS_MACOSX) 32 #if defined(OS_MACOSX)
32 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; 33 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X.";
33 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 34 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
34 #elif defined(OS_WIN) 35 #elif defined(OS_WIN)
35 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; 36 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows.";
36 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 37 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
37 #else 38 #else
38 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well. 39 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well.
(...skipping 26 matching lines...) Expand all
65 66
66 void AudioInputDevice::SetDevice(int session_id) { 67 void AudioInputDevice::SetDevice(int session_id) {
67 VLOG(1) << "SetDevice (session_id=" << session_id << ")"; 68 VLOG(1) << "SetDevice (session_id=" << session_id << ")";
68 ChildProcess::current()->io_message_loop()->PostTask( 69 ChildProcess::current()->io_message_loop()->PostTask(
69 FROM_HERE, 70 FROM_HERE,
70 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, 71 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this,
71 session_id)); 72 session_id));
72 } 73 }
73 74
74 bool AudioInputDevice::Stop() { 75 bool AudioInputDevice::Stop() {
76 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop());
75 VLOG(1) << "Stop()"; 77 VLOG(1) << "Stop()";
76 // Max waiting time for Stop() to complete. If this time limit is passed, 78 // Max waiting time for Stop() to complete. If this time limit is passed,
77 // we will stop waiting and return false. It ensures that Stop() can't block 79 // we will stop waiting and return false. It ensures that Stop() can't block
78 // the calling thread forever. 80 // the calling thread forever.
79 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000); 81 const base::TimeDelta kMaxTimeOut = base::TimeDelta::FromMilliseconds(1000);
80 82
81 base::WaitableEvent completion(false, false); 83 base::WaitableEvent completion(false, false);
82 84
83 ChildProcess::current()->io_message_loop()->PostTask( 85 ChildProcess::current()->io_message_loop()->PostTask(
84 FROM_HERE, 86 FROM_HERE,
85 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this, 87 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this,
86 &completion)); 88 &completion));
87 89
88 // We wait here for the IO task to be completed to remove race conflicts 90 // We wait here for the IO task to be completed to remove race conflicts
89 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 91 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
90 // function call. 92 // function call.
91 if (completion.TimedWait(kMaxTimeOut)) { 93 if (!completion.TimedWait(kMaxTimeOut)) {
92 if (audio_thread_.get()) { 94 LOG(WARNING) << "Failed to shut down audio input on IO thread";
93 // Terminate the main thread function in the audio thread. 95 }
94 socket_->Close(); 96
95 // Wait for the audio thread to exit. 97 if (audio_thread_.get()) {
96 audio_thread_->Join(); 98 // Terminate the main thread function in the audio thread.
97 // Ensures that we can call Stop() multiple times. 99 {
98 audio_thread_.reset(NULL); 100 base::SyncSocket socket(socket_handle_);
99 } 101 }
100 } else { 102 // Wait for the audio thread to exit.
101 LOG(ERROR) << "Failed to shut down audio input on IO thread"; 103 audio_thread_->Join();
102 return false; 104 // Ensures that we can call Stop() multiple times.
105 audio_thread_.reset(NULL);
103 } 106 }
104 107
105 return true; 108 return true;
106 } 109 }
107 110
108 bool AudioInputDevice::SetVolume(double volume) { 111 bool AudioInputDevice::SetVolume(double volume) {
109 NOTIMPLEMENTED(); 112 NOTIMPLEMENTED();
110 return false; 113 return false;
111 } 114 }
112 115
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
187 190
188 VLOG(1) << "OnLowLatencyCreated (stream_id=" << stream_id_ << ")"; 191 VLOG(1) << "OnLowLatencyCreated (stream_id=" << stream_id_ << ")";
189 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). 192 // Takes care of the case when Stop() is called before OnLowLatencyCreated().
190 if (!stream_id_) { 193 if (!stream_id_) {
191 base::SharedMemory::CloseHandle(handle); 194 base::SharedMemory::CloseHandle(handle);
192 // Close the socket handler. 195 // Close the socket handler.
193 base::SyncSocket socket(socket_handle); 196 base::SyncSocket socket(socket_handle);
194 return; 197 return;
195 } 198 }
196 199
197 shared_memory_.reset(new base::SharedMemory(handle, false)); 200 shared_memory_handle_ = handle;
198 shared_memory_->Map(length); 201 memory_length_ = length;
199 202
200 socket_.reset(new base::SyncSocket(socket_handle)); 203 socket_handle_ = socket_handle;
201 204
202 audio_thread_.reset( 205 audio_thread_.reset(
203 new base::DelegateSimpleThread(this, "RendererAudioInputThread")); 206 new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
204 audio_thread_->Start(); 207 audio_thread_->Start();
205 208
206 MessageLoop::current()->PostTask( 209 MessageLoop::current()->PostTask(
207 FROM_HERE, 210 FROM_HERE,
208 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 211 base::Bind(&AudioInputDevice::StartOnIOThread, this));
209 } 212 }
210 213
211 void AudioInputDevice::OnVolume(double volume) { 214 void AudioInputDevice::OnVolume(double volume) {
212 NOTIMPLEMENTED(); 215 NOTIMPLEMENTED();
213 } 216 }
214 217
215 void AudioInputDevice::OnStateChanged(AudioStreamState state) { 218 void AudioInputDevice::OnStateChanged(AudioStreamState state) {
216 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 219 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
217 switch (state) { 220 switch (state) {
218 case kAudioStreamPaused: 221 case kAudioStreamPaused:
219 // Do nothing if the stream has been closed. 222 // Do nothing if the stream has been closed.
220 if (!stream_id_) 223 if (!stream_id_)
221 return; 224 return;
222 225
223 filter_->RemoveDelegate(stream_id_); 226 filter_->RemoveDelegate(stream_id_);
224 227
225 // Joining the audio thread will be quite soon, since the stream has 228 // Joining the audio thread will be quite soon, since the stream has
226 // been closed before. 229 // been closed before.
227 if (audio_thread_.get()) { 230 if (audio_thread_.get()) {
228 socket_->Close(); 231 {
232 base::SyncSocket socket(socket_handle_);
233 }
229 audio_thread_->Join(); 234 audio_thread_->Join();
230 audio_thread_.reset(NULL); 235 audio_thread_.reset(NULL);
231 } 236 }
232 237
233 if (event_handler_) 238 if (event_handler_)
234 event_handler_->OnDeviceStopped(); 239 event_handler_->OnDeviceStopped();
235 240
236 stream_id_ = 0; 241 stream_id_ = 0;
237 pending_device_ready_ = false; 242 pending_device_ready_ = false;
238 break; 243 break;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
274 279
275 void AudioInputDevice::Send(IPC::Message* message) { 280 void AudioInputDevice::Send(IPC::Message* message) {
276 filter_->Send(message); 281 filter_->Send(message);
277 } 282 }
278 283
279 // Our audio thread runs here. We receive captured audio samples on 284 // Our audio thread runs here. We receive captured audio samples on
280 // this thread. 285 // this thread.
281 void AudioInputDevice::Run() { 286 void AudioInputDevice::Run() {
282 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 287 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
283 288
289 base::SharedMemory shared_memory(shared_memory_handle_, false);
290 shared_memory.Map(memory_length_);
291
292 base::SyncSocket socket(socket_handle_);
293
284 int pending_data; 294 int pending_data;
285 const int samples_per_ms = 295 const int samples_per_ms =
286 static_cast<int>(audio_parameters_.sample_rate) / 1000; 296 static_cast<int>(audio_parameters_.sample_rate) / 1000;
287 const int bytes_per_ms = audio_parameters_.channels * 297 const int bytes_per_ms = audio_parameters_.channels *
288 (audio_parameters_.bits_per_sample / 8) * samples_per_ms; 298 (audio_parameters_.bits_per_sample / 8) * samples_per_ms;
289 299
290 while (sizeof(pending_data) == socket_->Receive(&pending_data, 300 while ((sizeof(pending_data) == socket.Receive(&pending_data,
291 sizeof(pending_data)) && 301 sizeof(pending_data))) &&
292 pending_data >= 0) { 302 (pending_data >= 0)) {
293 // TODO(henrika): investigate the provided |pending_data| value 303 // TODO(henrika): investigate the provided |pending_data| value
294 // and ensure that it is actually an accurate delay estimation. 304 // and ensure that it is actually an accurate delay estimation.
295 305
296 // Convert the number of pending bytes in the capture buffer 306 // Convert the number of pending bytes in the capture buffer
297 // into milliseconds. 307 // into milliseconds.
298 audio_delay_milliseconds_ = pending_data / bytes_per_ms; 308 audio_delay_milliseconds_ = pending_data / bytes_per_ms;
299 309
300 FireCaptureCallback(); 310 FireCaptureCallback(static_cast<int16*>(shared_memory.memory()));
tommi (sloooow) - chröme 2011/12/01 14:40:45 reinterpret_cast
301 } 311 }
302 } 312 }
303 313
304 void AudioInputDevice::FireCaptureCallback() { 314 void AudioInputDevice::FireCaptureCallback(int16* input_audio) {
305 if (!callback_) 315 if (!callback_)
306 return; 316 return;
307 317
308 const size_t number_of_frames = audio_parameters_.samples_per_packet; 318 const size_t number_of_frames = audio_parameters_.samples_per_packet;
309 319
310 // Read 16-bit samples from shared memory (browser writes to it).
311 int16* input_audio = static_cast<int16*>(shared_memory_data());
312 const int bytes_per_sample = sizeof(input_audio[0]); 320 const int bytes_per_sample = sizeof(input_audio[0]);
313 321
314 // Deinterleave each channel and convert to 32-bit floating-point 322 // Deinterleave each channel and convert to 32-bit floating-point
315 // with nominal range -1.0 -> +1.0. 323 // with nominal range -1.0 -> +1.0.
316 for (int channel_index = 0; channel_index < audio_parameters_.channels; 324 for (int channel_index = 0; channel_index < audio_parameters_.channels;
317 ++channel_index) { 325 ++channel_index) {
318 media::DeinterleaveAudioChannel(input_audio, 326 media::DeinterleaveAudioChannel(input_audio,
319 audio_data_[channel_index], 327 audio_data_[channel_index],
320 audio_parameters_.channels, 328 audio_parameters_.channels,
321 channel_index, 329 channel_index,
322 bytes_per_sample, 330 bytes_per_sample,
323 number_of_frames); 331 number_of_frames);
324 } 332 }
325 333
326 // Deliver captured data to the client in floating point format 334 // Deliver captured data to the client in floating point format
327 // and update the audio-delay measurement. 335 // and update the audio-delay measurement.
328 callback_->Capture(audio_data_, 336 callback_->Capture(audio_data_,
329 number_of_frames, 337 number_of_frames,
330 audio_delay_milliseconds_); 338 audio_delay_milliseconds_);
331 } 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