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

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

Issue 9317001: Revert 119769 - Switch AudioDevice classes from SyncSocket to CancelableSyncSocket. (Closed) Base URL: svn://svn.chromium.org/chrome/branches/1025/src/
Patch Set: 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
« no previous file with comments | « content/renderer/media/audio_input_device.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 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"
10 #include "base/time.h" 9 #include "base/time.h"
11 #include "content/common/child_process.h" 10 #include "content/common/child_process.h"
12 #include "content/common/media/audio_messages.h" 11 #include "content/common/media/audio_messages.h"
13 #include "content/common/view_messages.h" 12 #include "content/common/view_messages.h"
14 #include "content/renderer/render_thread_impl.h" 13 #include "content/renderer/render_thread_impl.h"
15 #include "media/audio/audio_manager_base.h" 14 #include "media/audio/audio_manager_base.h"
16 #include "media/audio/audio_util.h" 15 #include "media/audio/audio_util.h"
17 16
18 AudioInputDevice::AudioInputDevice(size_t buffer_size, 17 AudioInputDevice::AudioInputDevice(size_t buffer_size,
19 int channels, 18 int channels,
20 double sample_rate, 19 double sample_rate,
21 CaptureCallback* callback, 20 CaptureCallback* callback,
22 CaptureEventHandler* event_handler) 21 CaptureEventHandler* event_handler)
23 : callback_(callback), 22 : callback_(callback),
24 event_handler_(event_handler), 23 event_handler_(event_handler),
25 audio_delay_milliseconds_(0), 24 audio_delay_milliseconds_(0),
26 volume_(1.0), 25 volume_(1.0),
27 stream_id_(0), 26 stream_id_(0),
28 session_id_(0), 27 session_id_(0),
29 pending_device_ready_(false), 28 pending_device_ready_(false),
30 shared_memory_handle_(base::SharedMemory::NULLHandle()), 29 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);
80 84
81 base::WaitableEvent completion(false, false); 85 base::WaitableEvent completion(false, false);
86
82 ChildProcess::current()->io_message_loop()->PostTask( 87 ChildProcess::current()->io_message_loop()->PostTask(
83 FROM_HERE, 88 FROM_HERE,
84 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this, 89 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this,
85 &completion)); 90 &completion));
86 91
87 // We wait here for the IO task to be completed to remove race conflicts 92 // We wait here for the IO task to be completed to remove race conflicts
88 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 93 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
89 // function call. 94 // function call.
90 completion.Wait(); 95 if (!completion.TimedWait(kMaxTimeOut)) {
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 }
91 } 109 }
92 110
93 bool AudioInputDevice::SetVolume(double volume) { 111 bool AudioInputDevice::SetVolume(double volume) {
94 NOTIMPLEMENTED(); 112 NOTIMPLEMENTED();
95 return false; 113 return false;
96 } 114 }
97 115
98 bool AudioInputDevice::GetVolume(double* volume) { 116 bool AudioInputDevice::GetVolume(double* volume) {
99 NOTIMPLEMENTED(); 117 NOTIMPLEMENTED();
100 return false; 118 return false;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
136 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 154 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
137 // Make sure we don't call shutdown more than once. 155 // Make sure we don't call shutdown more than once.
138 if (!stream_id_) { 156 if (!stream_id_) {
139 completion->Signal(); 157 completion->Signal();
140 return; 158 return;
141 } 159 }
142 160
143 filter_->RemoveDelegate(stream_id_); 161 filter_->RemoveDelegate(stream_id_);
144 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 162 Send(new AudioInputHostMsg_CloseStream(stream_id_));
145 163
146 ShutDownAudioThread();
147
148 stream_id_ = 0; 164 stream_id_ = 0;
149 session_id_ = 0; 165 session_id_ = 0;
150 pending_device_ready_ = false; 166 pending_device_ready_ = false;
151 167
152 completion->Signal(); 168 completion->Signal();
153 } 169 }
154 170
155 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 171 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
156 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 172 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
157 if (stream_id_) 173 if (stream_id_)
(...skipping 19 matching lines...) Expand all
177 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). 193 // Takes care of the case when Stop() is called before OnLowLatencyCreated().
178 if (!stream_id_) { 194 if (!stream_id_) {
179 base::SharedMemory::CloseHandle(handle); 195 base::SharedMemory::CloseHandle(handle);
180 // Close the socket handler. 196 // Close the socket handler.
181 base::SyncSocket socket(socket_handle); 197 base::SyncSocket socket(socket_handle);
182 return; 198 return;
183 } 199 }
184 200
185 shared_memory_handle_ = handle; 201 shared_memory_handle_ = handle;
186 memory_length_ = length; 202 memory_length_ = length;
187 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle)); 203
204 socket_handle_ = socket_handle;
188 205
189 audio_thread_.reset( 206 audio_thread_.reset(
190 new base::DelegateSimpleThread(this, "RendererAudioInputThread")); 207 new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
191 audio_thread_->Start(); 208 audio_thread_->Start();
192 209
193 MessageLoop::current()->PostTask( 210 MessageLoop::current()->PostTask(
194 FROM_HERE, 211 FROM_HERE,
195 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 212 base::Bind(&AudioInputDevice::StartOnIOThread, this));
196 } 213 }
197 214
198 void AudioInputDevice::OnVolume(double volume) { 215 void AudioInputDevice::OnVolume(double volume) {
199 NOTIMPLEMENTED(); 216 NOTIMPLEMENTED();
200 } 217 }
201 218
202 void AudioInputDevice::OnStateChanged(AudioStreamState state) { 219 void AudioInputDevice::OnStateChanged(AudioStreamState state) {
203 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 220 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
204 switch (state) { 221 switch (state) {
205 case kAudioStreamPaused: 222 case kAudioStreamPaused:
206 // TODO(xians): Should we just call ShutDownOnIOThread here instead?
207
208 // Do nothing if the stream has been closed. 223 // Do nothing if the stream has been closed.
209 if (!stream_id_) 224 if (!stream_id_)
210 return; 225 return;
211 226
212 filter_->RemoveDelegate(stream_id_); 227 filter_->RemoveDelegate(stream_id_);
213 228
214 ShutDownAudioThread(); 229 // Joining the audio thread will be quite soon, since the stream has
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 }
215 238
216 if (event_handler_) 239 if (event_handler_)
217 event_handler_->OnDeviceStopped(); 240 event_handler_->OnDeviceStopped();
218 241
219 stream_id_ = 0; 242 stream_id_ = 0;
220 pending_device_ready_ = false; 243 pending_device_ready_ = false;
221 break; 244 break;
222 case kAudioStreamPlaying: 245 case kAudioStreamPlaying:
223 NOTIMPLEMENTED(); 246 NOTIMPLEMENTED();
224 break; 247 break;
(...skipping 13 matching lines...) Expand all
238 // Takes care of the case when Stop() is called before OnDeviceReady(). 261 // Takes care of the case when Stop() is called before OnDeviceReady().
239 if (!pending_device_ready_) 262 if (!pending_device_ready_)
240 return; 263 return;
241 264
242 // If AudioInputDeviceManager returns an empty string, it means no device 265 // If AudioInputDeviceManager returns an empty string, it means no device
243 // is ready for start. 266 // is ready for start.
244 if (device_id.empty()) { 267 if (device_id.empty()) {
245 filter_->RemoveDelegate(stream_id_); 268 filter_->RemoveDelegate(stream_id_);
246 stream_id_ = 0; 269 stream_id_ = 0;
247 } else { 270 } else {
248 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_, 271 Send(new AudioInputHostMsg_CreateStream(
249 true, device_id)); 272 stream_id_, audio_parameters_, true, device_id));
250 } 273 }
251 274
252 pending_device_ready_ = false; 275 pending_device_ready_ = false;
253 // Notify the client that the device has been started. 276 // Notify the client that the device has been started.
254 if (event_handler_) 277 if (event_handler_)
255 event_handler_->OnDeviceStarted(device_id); 278 event_handler_->OnDeviceStarted(device_id);
256 } 279 }
257 280
258 void AudioInputDevice::Send(IPC::Message* message) { 281 void AudioInputDevice::Send(IPC::Message* message) {
259 filter_->Send(message); 282 filter_->Send(message);
260 } 283 }
261 284
262 // Our audio thread runs here. We receive captured audio samples on 285 // Our audio thread runs here. We receive captured audio samples on
263 // this thread. 286 // this thread.
264 void AudioInputDevice::Run() { 287 void AudioInputDevice::Run() {
265 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 288 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
266 289
267 base::SharedMemory shared_memory(shared_memory_handle_, false); 290 base::SharedMemory shared_memory(shared_memory_handle_, false);
268 shared_memory.Map(memory_length_); 291 shared_memory.Map(memory_length_);
269 292
270 base::CancelableSyncSocket* socket = audio_socket_.get(); 293 base::SyncSocket socket(socket_handle_);
271 294
295 int pending_data;
272 const int samples_per_ms = 296 const int samples_per_ms =
273 static_cast<int>(audio_parameters_.sample_rate) / 1000; 297 static_cast<int>(audio_parameters_.sample_rate) / 1000;
274 const int bytes_per_ms = audio_parameters_.channels * 298 const int bytes_per_ms = audio_parameters_.channels *
275 (audio_parameters_.bits_per_sample / 8) * samples_per_ms; 299 (audio_parameters_.bits_per_sample / 8) * samples_per_ms;
276 300
277 while (true) { 301 while ((sizeof(pending_data) == socket.Receive(&pending_data,
278 uint32 pending_data = 0; 302 sizeof(pending_data))) &&
279 size_t received = socket->Receive(&pending_data, sizeof(pending_data)); 303 (pending_data >= 0)) {
280 if (received != sizeof(pending_data)) {
281 DCHECK(received == 0U);
282 break;
283 }
284 // TODO(henrika): investigate the provided |pending_data| value 304 // TODO(henrika): investigate the provided |pending_data| value
285 // and ensure that it is actually an accurate delay estimation. 305 // and ensure that it is actually an accurate delay estimation.
286 306
287 // Convert the number of pending bytes in the capture buffer 307 // Convert the number of pending bytes in the capture buffer
288 // into milliseconds. 308 // into milliseconds.
289 audio_delay_milliseconds_ = pending_data / bytes_per_ms; 309 audio_delay_milliseconds_ = pending_data / bytes_per_ms;
290 310
291 FireCaptureCallback(reinterpret_cast<int16*>(shared_memory.memory())); 311 FireCaptureCallback(reinterpret_cast<int16*>(shared_memory.memory()));
292 } 312 }
293 } 313 }
294 314
295 void AudioInputDevice::FireCaptureCallback(int16* input_audio) { 315 void AudioInputDevice::FireCaptureCallback(int16* input_audio) {
296 if (!callback_) 316 if (!callback_)
297 return; 317 return;
298 318
299 const size_t number_of_frames = audio_parameters_.samples_per_packet; 319 const size_t number_of_frames = audio_parameters_.samples_per_packet;
300 320
301 const int bytes_per_sample = sizeof(input_audio[0]); 321 const int bytes_per_sample = sizeof(input_audio[0]);
302 322
303 // Deinterleave each channel and convert to 32-bit floating-point 323 // Deinterleave each channel and convert to 32-bit floating-point
304 // with nominal range -1.0 -> +1.0. 324 // with nominal range -1.0 -> +1.0.
305 for (int channel_index = 0; channel_index < audio_parameters_.channels; 325 for (int channel_index = 0; channel_index < audio_parameters_.channels;
306 ++channel_index) { 326 ++channel_index) {
307 media::DeinterleaveAudioChannel(input_audio, 327 media::DeinterleaveAudioChannel(input_audio,
308 audio_data_[channel_index], 328 audio_data_[channel_index],
309 audio_parameters_.channels, 329 audio_parameters_.channels,
310 channel_index, 330 channel_index,
311 bytes_per_sample, 331 bytes_per_sample,
312 number_of_frames); 332 number_of_frames);
313 } 333 }
314 334
315 // Deliver captured data to the client in floating point format 335 // Deliver captured data to the client in floating point format
316 // and update the audio-delay measurement. 336 // and update the audio-delay measurement.
317 callback_->Capture(audio_data_, 337 callback_->Capture(audio_data_,
318 number_of_frames, 338 number_of_frames,
319 audio_delay_milliseconds_); 339 audio_delay_milliseconds_);
320 } 340 }
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
« no previous file with comments | « 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