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

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: Created 8 years, 11 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) 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 shared_memory_handle_(base::SharedMemory::NULLHandle()), 29 shared_memory_handle_(base::SharedMemory::NULLHandle()),
30 socket_handle_(base::SyncSocket::kInvalidHandle),
31 memory_length_(0) { 30 memory_length_(0) {
32 filter_ = RenderThreadImpl::current()->audio_input_message_filter(); 31 filter_ = RenderThreadImpl::current()->audio_input_message_filter();
33 audio_data_.reserve(channels); 32 audio_data_.reserve(channels);
34 #if defined(OS_MACOSX) 33 #if defined(OS_MACOSX)
35 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X."; 34 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Mac OS X.";
36 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 35 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
37 #elif defined(OS_WIN) 36 #elif defined(OS_WIN)
38 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows."; 37 VLOG(1) << "Using AUDIO_PCM_LOW_LATENCY as input mode on Windows.";
39 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY; 38 audio_parameters_.format = AudioParameters::AUDIO_PCM_LOW_LATENCY;
40 #else 39 #else
(...skipping 29 matching lines...) Expand all
70 VLOG(1) << "SetDevice (session_id=" << session_id << ")"; 69 VLOG(1) << "SetDevice (session_id=" << session_id << ")";
71 ChildProcess::current()->io_message_loop()->PostTask( 70 ChildProcess::current()->io_message_loop()->PostTask(
72 FROM_HERE, 71 FROM_HERE,
73 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, 72 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this,
74 session_id)); 73 session_id));
75 } 74 }
76 75
77 void AudioInputDevice::Stop() { 76 void AudioInputDevice::Stop() {
78 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); 77 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop());
79 VLOG(1) << "Stop()"; 78 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 79
85 base::WaitableEvent completion(false, false); 80 base::WaitableEvent completion(false, false);
86
87 ChildProcess::current()->io_message_loop()->PostTask( 81 ChildProcess::current()->io_message_loop()->PostTask(
88 FROM_HERE, 82 FROM_HERE,
89 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this, 83 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this,
90 &completion)); 84 &completion));
91 85
92 // We wait here for the IO task to be completed to remove race conflicts 86 // 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 87 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous
94 // function call. 88 // function call.
95 if (!completion.TimedWait(kMaxTimeOut)) { 89 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 } 90 }
110 91
111 bool AudioInputDevice::SetVolume(double volume) { 92 bool AudioInputDevice::SetVolume(double volume) {
112 NOTIMPLEMENTED(); 93 NOTIMPLEMENTED();
113 return false; 94 return false;
114 } 95 }
115 96
116 bool AudioInputDevice::GetVolume(double* volume) { 97 bool AudioInputDevice::GetVolume(double* volume) {
117 NOTIMPLEMENTED(); 98 NOTIMPLEMENTED();
118 return false; 99 return false;
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
154 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 135 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
155 // Make sure we don't call shutdown more than once. 136 // Make sure we don't call shutdown more than once.
156 if (!stream_id_) { 137 if (!stream_id_) {
157 completion->Signal(); 138 completion->Signal();
158 return; 139 return;
159 } 140 }
160 141
161 filter_->RemoveDelegate(stream_id_); 142 filter_->RemoveDelegate(stream_id_);
162 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 143 Send(new AudioInputHostMsg_CloseStream(stream_id_));
163 144
145 ShutDownAudioThread();
146
164 stream_id_ = 0; 147 stream_id_ = 0;
165 session_id_ = 0; 148 session_id_ = 0;
166 pending_device_ready_ = false; 149 pending_device_ready_ = false;
167 150
168 completion->Signal(); 151 completion->Signal();
169 } 152 }
170 153
171 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 154 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
172 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 155 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
173 if (stream_id_) 156 if (stream_id_)
(...skipping 19 matching lines...) Expand all
193 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). 176 // Takes care of the case when Stop() is called before OnLowLatencyCreated().
194 if (!stream_id_) { 177 if (!stream_id_) {
195 base::SharedMemory::CloseHandle(handle); 178 base::SharedMemory::CloseHandle(handle);
196 // Close the socket handler. 179 // Close the socket handler.
197 base::SyncSocket socket(socket_handle); 180 base::SyncSocket socket(socket_handle);
198 return; 181 return;
199 } 182 }
200 183
201 shared_memory_handle_ = handle; 184 shared_memory_handle_ = handle;
202 memory_length_ = length; 185 memory_length_ = length;
203 186 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle));
204 socket_handle_ = socket_handle;
205 187
206 audio_thread_.reset( 188 audio_thread_.reset(
207 new base::DelegateSimpleThread(this, "RendererAudioInputThread")); 189 new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
208 audio_thread_->Start(); 190 audio_thread_->Start();
209 191
210 MessageLoop::current()->PostTask( 192 MessageLoop::current()->PostTask(
211 FROM_HERE, 193 FROM_HERE,
212 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 194 base::Bind(&AudioInputDevice::StartOnIOThread, this));
213 } 195 }
214 196
215 void AudioInputDevice::OnVolume(double volume) { 197 void AudioInputDevice::OnVolume(double volume) {
216 NOTIMPLEMENTED(); 198 NOTIMPLEMENTED();
217 } 199 }
218 200
219 void AudioInputDevice::OnStateChanged(AudioStreamState state) { 201 void AudioInputDevice::OnStateChanged(AudioStreamState state) {
220 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 202 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
221 switch (state) { 203 switch (state) {
222 case kAudioStreamPaused: 204 case kAudioStreamPaused:
205 // TODO(xians): Should we just call ShutDownOnIOThread here instead?
206
223 // Do nothing if the stream has been closed. 207 // Do nothing if the stream has been closed.
224 if (!stream_id_) 208 if (!stream_id_)
225 return; 209 return;
226 210
227 filter_->RemoveDelegate(stream_id_); 211 filter_->RemoveDelegate(stream_id_);
228 212
229 // Joining the audio thread will be quite soon, since the stream has 213 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 214
239 if (event_handler_) 215 if (event_handler_)
240 event_handler_->OnDeviceStopped(); 216 event_handler_->OnDeviceStopped();
241 217
242 stream_id_ = 0; 218 stream_id_ = 0;
243 pending_device_ready_ = false; 219 pending_device_ready_ = false;
244 break; 220 break;
245 case kAudioStreamPlaying: 221 case kAudioStreamPlaying:
246 NOTIMPLEMENTED(); 222 NOTIMPLEMENTED();
247 break; 223 break;
(...skipping 13 matching lines...) Expand all
261 // Takes care of the case when Stop() is called before OnDeviceReady(). 237 // Takes care of the case when Stop() is called before OnDeviceReady().
262 if (!pending_device_ready_) 238 if (!pending_device_ready_)
263 return; 239 return;
264 240
265 // If AudioInputDeviceManager returns an empty string, it means no device 241 // If AudioInputDeviceManager returns an empty string, it means no device
266 // is ready for start. 242 // is ready for start.
267 if (device_id.empty()) { 243 if (device_id.empty()) {
268 filter_->RemoveDelegate(stream_id_); 244 filter_->RemoveDelegate(stream_id_);
269 stream_id_ = 0; 245 stream_id_ = 0;
270 } else { 246 } else {
271 Send(new AudioInputHostMsg_CreateStream( 247 Send(new AudioInputHostMsg_CreateStream(stream_id_, audio_parameters_,
272 stream_id_, audio_parameters_, true, device_id)); 248 true, device_id));
273 } 249 }
274 250
275 pending_device_ready_ = false; 251 pending_device_ready_ = false;
276 // Notify the client that the device has been started. 252 // Notify the client that the device has been started.
277 if (event_handler_) 253 if (event_handler_)
278 event_handler_->OnDeviceStarted(device_id); 254 event_handler_->OnDeviceStarted(device_id);
279 } 255 }
280 256
281 void AudioInputDevice::Send(IPC::Message* message) { 257 void AudioInputDevice::Send(IPC::Message* message) {
282 filter_->Send(message); 258 filter_->Send(message);
283 } 259 }
284 260
285 // Our audio thread runs here. We receive captured audio samples on 261 // Our audio thread runs here. We receive captured audio samples on
286 // this thread. 262 // this thread.
287 void AudioInputDevice::Run() { 263 void AudioInputDevice::Run() {
288 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio); 264 audio_thread_->SetThreadPriority(base::kThreadPriority_RealtimeAudio);
289 265
290 base::SharedMemory shared_memory(shared_memory_handle_, false); 266 base::SharedMemory shared_memory(shared_memory_handle_, false);
291 shared_memory.Map(memory_length_); 267 shared_memory.Map(memory_length_);
292 268
293 base::SyncSocket socket(socket_handle_); 269 base::CancelableSyncSocket* socket = audio_socket_.get();
294 270
295 int pending_data;
296 const int samples_per_ms = 271 const int samples_per_ms =
297 static_cast<int>(audio_parameters_.sample_rate) / 1000; 272 static_cast<int>(audio_parameters_.sample_rate) / 1000;
298 const int bytes_per_ms = audio_parameters_.channels * 273 const int bytes_per_ms = audio_parameters_.channels *
299 (audio_parameters_.bits_per_sample / 8) * samples_per_ms; 274 (audio_parameters_.bits_per_sample / 8) * samples_per_ms;
300 275
301 while ((sizeof(pending_data) == socket.Receive(&pending_data, 276 size_t received = 0U;
302 sizeof(pending_data))) && 277 while (true) {
303 (pending_data >= 0)) { 278 int pending_data;
no longer working on chromium 2012/01/30 13:35:18 nit: what about initializing the value to 0?
tommi (sloooow) - chröme 2012/01/30 17:07:39 Done.
279 received = socket->Receive(&pending_data, sizeof(pending_data));
280 if (received != sizeof(pending_data) || pending_data < 0) {
no longer working on chromium 2012/01/30 13:35:18 nit: how is it possible for pending_data to be neg
tommi (sloooow) - chröme 2012/01/30 17:07:39 Changed the type to uint32 as discussed (to match
281 DCHECK(received == 0U || pending_data < 0);
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 audio_thread_->Join();
334 audio_thread_.reset(NULL);
335 audio_socket_.reset();
336 }
337 }
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