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

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

Issue 9104043: Monitor the IO message loop in the AudioDevice classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/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
OLDNEW
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 14 matching lines...) Expand all
25 audio_delay_milliseconds_(0), 25 audio_delay_milliseconds_(0),
26 volume_(1.0), 26 volume_(1.0),
27 stream_id_(0), 27 stream_id_(0),
28 session_id_(0), 28 session_id_(0),
29 pending_device_ready_(false), 29 pending_device_ready_(false),
30 shared_memory_handle_(base::SharedMemory::NULLHandle()), 30 shared_memory_handle_(base::SharedMemory::NULLHandle()),
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 DVLOG(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 DVLOG(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
41 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well. 41 // TODO(henrika): add support for AUDIO_PCM_LOW_LATENCY on Linux as well.
42 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR; 42 audio_parameters_.format = AudioParameters::AUDIO_PCM_LINEAR;
43 #endif 43 #endif
44 audio_parameters_.channels = channels; 44 audio_parameters_.channels = channels;
45 audio_parameters_.sample_rate = static_cast<int>(sample_rate); 45 audio_parameters_.sample_rate = static_cast<int>(sample_rate);
46 audio_parameters_.bits_per_sample = 16; 46 audio_parameters_.bits_per_sample = 16;
47 audio_parameters_.samples_per_packet = buffer_size; 47 audio_parameters_.samples_per_packet = buffer_size;
48 for (int i = 0; i < channels; ++i) { 48 for (int i = 0; i < channels; ++i) {
49 float* channel_data = new float[buffer_size]; 49 float* channel_data = new float[buffer_size];
50 audio_data_.push_back(channel_data); 50 audio_data_.push_back(channel_data);
51 } 51 }
52 } 52 }
53 53
54 AudioInputDevice::~AudioInputDevice() { 54 AudioInputDevice::~AudioInputDevice() {
55 // TODO(henrika): The current design requires that the user calls 55 // TODO(henrika): The current design requires that the user calls
56 // Stop before deleting this class. 56 // Stop before deleting this class.
57 CHECK_EQ(0, stream_id_); 57 CHECK_EQ(0, stream_id_);
58 for (int i = 0; i < audio_parameters_.channels; ++i) 58 for (int i = 0; i < audio_parameters_.channels; ++i)
59 delete [] audio_data_[i]; 59 delete [] audio_data_[i];
60 } 60 }
61 61
62 void AudioInputDevice::Start() { 62 void AudioInputDevice::Start() {
63 VLOG(1) << "Start()"; 63 DVLOG(1) << "Start()";
64 ChildProcess::current()->io_message_loop()->PostTask( 64 loop()->PostTask(FROM_HERE,
65 FROM_HERE,
66 base::Bind(&AudioInputDevice::InitializeOnIOThread, this)); 65 base::Bind(&AudioInputDevice::InitializeOnIOThread, this));
67 } 66 }
68 67
69 void AudioInputDevice::SetDevice(int session_id) { 68 void AudioInputDevice::SetDevice(int session_id) {
70 VLOG(1) << "SetDevice (session_id=" << session_id << ")"; 69 DVLOG(1) << "SetDevice (session_id=" << session_id << ")";
71 ChildProcess::current()->io_message_loop()->PostTask( 70 loop()->PostTask(FROM_HERE,
72 FROM_HERE, 71 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this, session_id));
73 base::Bind(&AudioInputDevice::SetSessionIdOnIOThread, this,
74 session_id));
75 } 72 }
76 73
77 void AudioInputDevice::Stop() { 74 void AudioInputDevice::Stop() {
78 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); 75 DCHECK(!loop()->BelongsToCurrentThread());
79 VLOG(1) << "Stop()"; 76 DVLOG(1) << "Stop()";
80 77
81 base::WaitableEvent completion(false, false); 78 base::WaitableEvent completion(false, false);
82 ChildProcess::current()->io_message_loop()->PostTask( 79 if (loop()->PostTask(FROM_HERE,
83 FROM_HERE, 80 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this,
84 base::Bind(&AudioInputDevice::ShutDownOnIOThread, this, 81 &completion))) {
85 &completion)); 82 // We wait here for the IO task to be completed to remove race conflicts
86 83 // with OnLowLatencyCreated() and to ensure that Stop() acts as a
87 // We wait here for the IO task to be completed to remove race conflicts 84 // synchronous function call.
88 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous 85 completion.Wait();
89 // function call. 86 }
90 completion.Wait();
91 } 87 }
92 88
93 bool AudioInputDevice::SetVolume(double volume) { 89 bool AudioInputDevice::SetVolume(double volume) {
94 NOTIMPLEMENTED(); 90 NOTIMPLEMENTED();
95 return false; 91 return false;
96 } 92 }
97 93
98 bool AudioInputDevice::GetVolume(double* volume) { 94 bool AudioInputDevice::GetVolume(double* volume) {
99 NOTIMPLEMENTED(); 95 NOTIMPLEMENTED();
100 return false; 96 return false;
101 } 97 }
102 98
103 void AudioInputDevice::InitializeOnIOThread() { 99 void AudioInputDevice::InitializeOnIOThread() {
104 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 100 DCHECK(loop()->BelongsToCurrentThread());
105 // Make sure we don't call Start() more than once. 101 // Make sure we don't call Start() more than once.
106 DCHECK_EQ(0, stream_id_); 102 DCHECK_EQ(0, stream_id_);
107 if (stream_id_) 103 if (stream_id_)
108 return; 104 return;
109 105
110 stream_id_ = filter_->AddDelegate(this); 106 stream_id_ = filter_->AddDelegate(this);
111 // If |session_id_| is not specified, it will directly create the stream; 107 // If |session_id_| is not specified, it will directly create the stream;
112 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser 108 // otherwise it will send a AudioInputHostMsg_StartDevice msg to the browser
113 // and create the stream when getting a OnDeviceReady() callback. 109 // and create the stream when getting a OnDeviceReady() callback.
114 if (!session_id_) { 110 if (!session_id_) {
115 Send(new AudioInputHostMsg_CreateStream( 111 Send(new AudioInputHostMsg_CreateStream(
116 stream_id_, audio_parameters_, true, 112 stream_id_, audio_parameters_, true,
117 AudioManagerBase::kDefaultDeviceId)); 113 AudioManagerBase::kDefaultDeviceId));
118 } else { 114 } else {
119 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_)); 115 Send(new AudioInputHostMsg_StartDevice(stream_id_, session_id_));
120 pending_device_ready_ = true; 116 pending_device_ready_ = true;
121 } 117 }
122 } 118 }
123 119
124 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) { 120 void AudioInputDevice::SetSessionIdOnIOThread(int session_id) {
125 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 121 DCHECK(loop()->BelongsToCurrentThread());
126 session_id_ = session_id; 122 session_id_ = session_id;
127 } 123 }
128 124
129 void AudioInputDevice::StartOnIOThread() { 125 void AudioInputDevice::StartOnIOThread() {
130 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 126 DCHECK(loop()->BelongsToCurrentThread());
131 if (stream_id_) 127 if (stream_id_)
132 Send(new AudioInputHostMsg_RecordStream(stream_id_)); 128 Send(new AudioInputHostMsg_RecordStream(stream_id_));
133 } 129 }
134 130
135 void AudioInputDevice::ShutDownOnIOThread(base::WaitableEvent* completion) { 131 void AudioInputDevice::ShutDownOnIOThread(base::WaitableEvent* completion) {
136 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 132 DCHECK(loop()->BelongsToCurrentThread());
137 // Make sure we don't call shutdown more than once. 133 // Make sure we don't call shutdown more than once.
138 if (!stream_id_) { 134 if (stream_id_) {
139 completion->Signal(); 135 filter_->RemoveDelegate(stream_id_);
140 return; 136 Send(new AudioInputHostMsg_CloseStream(stream_id_));
137
138 ShutDownAudioThread();
139
140 stream_id_ = 0;
141 session_id_ = 0;
142 pending_device_ready_ = false;
141 } 143 }
142 144
143 filter_->RemoveDelegate(stream_id_); 145 if (completion)
144 Send(new AudioInputHostMsg_CloseStream(stream_id_)); 146 completion->Signal();
145
146 ShutDownAudioThread();
147
148 stream_id_ = 0;
149 session_id_ = 0;
150 pending_device_ready_ = false;
151
152 completion->Signal();
153 } 147 }
154 148
155 void AudioInputDevice::SetVolumeOnIOThread(double volume) { 149 void AudioInputDevice::SetVolumeOnIOThread(double volume) {
156 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 150 DCHECK(loop()->BelongsToCurrentThread());
157 if (stream_id_) 151 if (stream_id_)
158 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume)); 152 Send(new AudioInputHostMsg_SetVolume(stream_id_, volume));
159 } 153 }
160 154
161 void AudioInputDevice::OnLowLatencyCreated( 155 void AudioInputDevice::OnLowLatencyCreated(
162 base::SharedMemoryHandle handle, 156 base::SharedMemoryHandle handle,
163 base::SyncSocket::Handle socket_handle, 157 base::SyncSocket::Handle socket_handle,
164 uint32 length) { 158 uint32 length) {
165 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 159 DCHECK(loop()->BelongsToCurrentThread());
166 #if defined(OS_WIN) 160 #if defined(OS_WIN)
167 DCHECK(handle); 161 DCHECK(handle);
168 DCHECK(socket_handle); 162 DCHECK(socket_handle);
169 #else 163 #else
170 DCHECK_GE(handle.fd, 0); 164 DCHECK_GE(handle.fd, 0);
171 DCHECK_GE(socket_handle, 0); 165 DCHECK_GE(socket_handle, 0);
172 #endif 166 #endif
173 DCHECK(length); 167 DCHECK(length);
174 DCHECK(!audio_thread_.get()); 168 DCHECK(!audio_thread_.get());
175 169
176 VLOG(1) << "OnLowLatencyCreated (stream_id=" << stream_id_ << ")"; 170 DVLOG(1) << "OnLowLatencyCreated (stream_id=" << stream_id_ << ")";
177 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). 171 // Takes care of the case when Stop() is called before OnLowLatencyCreated().
178 if (!stream_id_) { 172 if (!stream_id_) {
179 base::SharedMemory::CloseHandle(handle); 173 base::SharedMemory::CloseHandle(handle);
180 // Close the socket handler. 174 // Close the socket handler.
181 base::SyncSocket socket(socket_handle); 175 base::SyncSocket socket(socket_handle);
182 return; 176 return;
183 } 177 }
184 178
185 shared_memory_handle_ = handle; 179 shared_memory_handle_ = handle;
186 memory_length_ = length; 180 memory_length_ = length;
187 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle)); 181 audio_socket_.reset(new base::CancelableSyncSocket(socket_handle));
188 182
189 audio_thread_.reset( 183 audio_thread_.reset(
190 new base::DelegateSimpleThread(this, "RendererAudioInputThread")); 184 new base::DelegateSimpleThread(this, "RendererAudioInputThread"));
191 audio_thread_->Start(); 185 audio_thread_->Start();
192 186
193 MessageLoop::current()->PostTask( 187 MessageLoop::current()->PostTask(
194 FROM_HERE, 188 FROM_HERE,
195 base::Bind(&AudioInputDevice::StartOnIOThread, this)); 189 base::Bind(&AudioInputDevice::StartOnIOThread, this));
196 } 190 }
197 191
198 void AudioInputDevice::OnVolume(double volume) { 192 void AudioInputDevice::OnVolume(double volume) {
199 NOTIMPLEMENTED(); 193 NOTIMPLEMENTED();
200 } 194 }
201 195
202 void AudioInputDevice::OnStateChanged(AudioStreamState state) { 196 void AudioInputDevice::OnStateChanged(AudioStreamState state) {
203 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 197 DCHECK(loop()->BelongsToCurrentThread());
204 switch (state) { 198 switch (state) {
205 case kAudioStreamPaused: 199 case kAudioStreamPaused:
206 // TODO(xians): Should we just call ShutDownOnIOThread here instead? 200 // TODO(xians): Should we just call ShutDownOnIOThread here instead?
207 201
208 // Do nothing if the stream has been closed. 202 // Do nothing if the stream has been closed.
209 if (!stream_id_) 203 if (!stream_id_)
210 return; 204 return;
211 205
212 filter_->RemoveDelegate(stream_id_); 206 filter_->RemoveDelegate(stream_id_);
213 207
(...skipping 11 matching lines...) Expand all
225 case kAudioStreamError: 219 case kAudioStreamError:
226 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)"; 220 DLOG(WARNING) << "AudioInputDevice::OnStateChanged(kError)";
227 break; 221 break;
228 default: 222 default:
229 NOTREACHED(); 223 NOTREACHED();
230 break; 224 break;
231 } 225 }
232 } 226 }
233 227
234 void AudioInputDevice::OnDeviceReady(const std::string& device_id) { 228 void AudioInputDevice::OnDeviceReady(const std::string& device_id) {
235 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); 229 DCHECK(loop()->BelongsToCurrentThread());
236 VLOG(1) << "OnDeviceReady (device_id=" << device_id << ")"; 230 DVLOG(1) << "OnDeviceReady (device_id=" << device_id << ")";
237 231
238 // Takes care of the case when Stop() is called before OnDeviceReady(). 232 // Takes care of the case when Stop() is called before OnDeviceReady().
239 if (!pending_device_ready_) 233 if (!pending_device_ready_)
240 return; 234 return;
241 235
242 // If AudioInputDeviceManager returns an empty string, it means no device 236 // If AudioInputDeviceManager returns an empty string, it means no device
243 // is ready for start. 237 // is ready for start.
244 if (device_id.empty()) { 238 if (device_id.empty()) {
245 filter_->RemoveDelegate(stream_id_); 239 filter_->RemoveDelegate(stream_id_);
246 stream_id_ = 0; 240 stream_id_ = 0;
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after
330 // Close the socket to terminate the main thread function in the 324 // Close the socket to terminate the main thread function in the
331 // audio thread. 325 // audio thread.
332 audio_socket_->Shutdown(); // Stops blocking Receive calls. 326 audio_socket_->Shutdown(); // Stops blocking Receive calls.
333 // TODO(tommi): We must not do this from the IO thread. Fix. 327 // TODO(tommi): We must not do this from the IO thread. Fix.
334 base::ThreadRestrictions::ScopedAllowIO allow_wait; 328 base::ThreadRestrictions::ScopedAllowIO allow_wait;
335 audio_thread_->Join(); 329 audio_thread_->Join();
336 audio_thread_.reset(NULL); 330 audio_thread_.reset(NULL);
337 audio_socket_.reset(); 331 audio_socket_.reset();
338 } 332 }
339 } 333 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698