OLD | NEW |
---|---|
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_device.h" | 5 #include "content/renderer/media/audio_device.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/debug/trace_event.h" | 8 #include "base/debug/trace_event.h" |
9 #include "base/message_loop.h" | 9 #include "base/message_loop.h" |
10 #include "base/time.h" | 10 #include "base/time.h" |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
99 params.bits_per_sample = bits_per_sample_; | 99 params.bits_per_sample = bits_per_sample_; |
100 params.samples_per_packet = buffer_size_; | 100 params.samples_per_packet = buffer_size_; |
101 | 101 |
102 ChildProcess::current()->io_message_loop()->PostTask( | 102 ChildProcess::current()->io_message_loop()->PostTask( |
103 FROM_HERE, | 103 FROM_HERE, |
104 base::Bind(&AudioDevice::InitializeOnIOThread, this, params)); | 104 base::Bind(&AudioDevice::InitializeOnIOThread, this, params)); |
105 } | 105 } |
106 | 106 |
107 void AudioDevice::Stop() { | 107 void AudioDevice::Stop() { |
108 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); | 108 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); |
109 base::WaitableEvent completion(false, false); | |
110 | 109 |
110 // Stop and shutdown the audio thread from the IO thread. | |
111 ChildProcess::current()->io_message_loop()->PostTask( | 111 ChildProcess::current()->io_message_loop()->PostTask( |
112 FROM_HERE, | 112 FROM_HERE, |
113 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &completion)); | 113 base::Bind(&AudioDevice::ShutDownOnIOThread, this)); |
114 | |
115 // We wait here for the IO task to be completed to remove race conflicts | |
116 // with OnLowLatencyCreated() and to ensure that Stop() acts as a synchronous | |
117 // function call. | |
118 completion.Wait(); | |
119 ShutDownAudioThread(); | |
120 } | 114 } |
121 | 115 |
122 void AudioDevice::Play() { | 116 void AudioDevice::Play() { |
123 ChildProcess::current()->io_message_loop()->PostTask( | 117 ChildProcess::current()->io_message_loop()->PostTask( |
124 FROM_HERE, | 118 FROM_HERE, |
125 base::Bind(&AudioDevice::PlayOnIOThread, this)); | 119 base::Bind(&AudioDevice::PlayOnIOThread, this)); |
126 } | 120 } |
127 | 121 |
128 void AudioDevice::Pause(bool flush) { | 122 void AudioDevice::Pause(bool flush) { |
129 ChildProcess::current()->io_message_loop()->PostTask( | 123 ChildProcess::current()->io_message_loop()->PostTask( |
(...skipping 13 matching lines...) Expand all Loading... | |
143 | 137 |
144 return true; | 138 return true; |
145 } | 139 } |
146 | 140 |
147 void AudioDevice::GetVolume(double* volume) { | 141 void AudioDevice::GetVolume(double* volume) { |
148 // Return a locally cached version of the current scaling factor. | 142 // Return a locally cached version of the current scaling factor. |
149 *volume = volume_; | 143 *volume = volume_; |
150 } | 144 } |
151 | 145 |
152 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) { | 146 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) { |
153 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); | 147 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
154 // Make sure we don't create the stream more than once. | 148 // Make sure we don't create the stream more than once. |
155 DCHECK_EQ(0, stream_id_); | 149 DCHECK_EQ(0, stream_id_); |
156 if (stream_id_) | 150 if (stream_id_) |
157 return; | 151 return; |
158 | 152 |
159 stream_id_ = filter_->AddDelegate(this); | 153 stream_id_ = filter_->AddDelegate(this); |
160 Send(new AudioHostMsg_CreateStream(stream_id_, params, true)); | 154 Send(new AudioHostMsg_CreateStream(stream_id_, params, true)); |
161 } | 155 } |
162 | 156 |
163 void AudioDevice::PlayOnIOThread() { | 157 void AudioDevice::PlayOnIOThread() { |
164 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); | 158 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
165 if (stream_id_ && is_started_) | 159 if (stream_id_ && is_started_) |
166 Send(new AudioHostMsg_PlayStream(stream_id_)); | 160 Send(new AudioHostMsg_PlayStream(stream_id_)); |
167 else | 161 else |
168 play_on_start_ = true; | 162 play_on_start_ = true; |
169 } | 163 } |
170 | 164 |
171 void AudioDevice::PauseOnIOThread(bool flush) { | 165 void AudioDevice::PauseOnIOThread(bool flush) { |
172 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); | 166 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
173 if (stream_id_ && is_started_) { | 167 if (stream_id_ && is_started_) { |
174 Send(new AudioHostMsg_PauseStream(stream_id_)); | 168 Send(new AudioHostMsg_PauseStream(stream_id_)); |
175 if (flush) | 169 if (flush) |
176 Send(new AudioHostMsg_FlushStream(stream_id_)); | 170 Send(new AudioHostMsg_FlushStream(stream_id_)); |
177 } else { | 171 } else { |
178 // Note that |flush| isn't relevant here since this is the case where | 172 // Note that |flush| isn't relevant here since this is the case where |
179 // the stream is first starting. | 173 // the stream is first starting. |
180 play_on_start_ = false; | 174 play_on_start_ = false; |
181 } | 175 } |
182 } | 176 } |
183 | 177 |
184 void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* completion) { | 178 void AudioDevice::ShutDownOnIOThread() { |
185 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); | 179 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
186 is_started_ = false; | |
187 | 180 |
188 // Make sure we don't call shutdown more than once. | 181 // Make sure we don't call shutdown more than once. |
189 if (!stream_id_) { | 182 if (!stream_id_) |
190 if (completion) | |
191 completion->Signal(); | |
192 return; | 183 return; |
193 } | 184 |
185 is_started_ = false; | |
194 | 186 |
195 filter_->RemoveDelegate(stream_id_); | 187 filter_->RemoveDelegate(stream_id_); |
196 Send(new AudioHostMsg_CloseStream(stream_id_)); | 188 Send(new AudioHostMsg_CloseStream(stream_id_)); |
197 stream_id_ = 0; | 189 stream_id_ = 0; |
198 | 190 |
199 if (completion) | 191 ShutDownAudioThread(); |
200 completion->Signal(); | |
201 } | 192 } |
202 | 193 |
203 void AudioDevice::SetVolumeOnIOThread(double volume) { | 194 void AudioDevice::SetVolumeOnIOThread(double volume) { |
204 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); | 195 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
205 if (stream_id_) | 196 if (stream_id_) |
206 Send(new AudioHostMsg_SetVolume(stream_id_, volume)); | 197 Send(new AudioHostMsg_SetVolume(stream_id_, volume)); |
207 } | 198 } |
208 | 199 |
209 void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) { | 200 void AudioDevice::OnRequestPacket(AudioBuffersState buffers_state) { |
210 // This method does not apply to the low-latency system. | 201 // This method does not apply to the low-latency system. |
211 } | 202 } |
212 | 203 |
213 void AudioDevice::OnStateChanged(AudioStreamState state) { | 204 void AudioDevice::OnStateChanged(AudioStreamState state) { |
214 if (state == kAudioStreamError) { | 205 if (state == kAudioStreamError) { |
215 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)"; | 206 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)"; |
216 } | 207 } |
217 } | 208 } |
218 | 209 |
219 void AudioDevice::OnCreated( | 210 void AudioDevice::OnCreated( |
220 base::SharedMemoryHandle handle, uint32 length) { | 211 base::SharedMemoryHandle handle, uint32 length) { |
221 // Not needed in this simple implementation. | 212 // Not needed in this simple implementation. |
222 } | 213 } |
223 | 214 |
224 void AudioDevice::OnLowLatencyCreated( | 215 void AudioDevice::OnLowLatencyCreated( |
225 base::SharedMemoryHandle handle, | 216 base::SharedMemoryHandle handle, |
226 base::SyncSocket::Handle socket_handle, | 217 base::SyncSocket::Handle socket_handle, |
227 uint32 length) { | 218 uint32 length) { |
228 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop()); | 219 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
220 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_); | |
229 #if defined(OS_WIN) | 221 #if defined(OS_WIN) |
230 DCHECK(handle); | 222 DCHECK(handle); |
231 DCHECK(socket_handle); | 223 DCHECK(socket_handle); |
232 #else | 224 #else |
233 DCHECK_GE(handle.fd, 0); | 225 DCHECK_GE(handle.fd, 0); |
234 DCHECK_GE(socket_handle, 0); | 226 DCHECK_GE(socket_handle, 0); |
235 #endif | 227 #endif |
236 DCHECK(length); | |
237 DCHECK(!audio_thread_.get()); | |
238 | 228 |
239 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). | 229 // Takes care of the case when Stop() is called before OnLowLatencyCreated(). |
240 if (!stream_id_) { | 230 if (!stream_id_) { |
241 base::SharedMemory::CloseHandle(handle); | 231 base::SharedMemory::CloseHandle(handle); |
242 // Close the socket handler. | 232 // Close the socket handler. |
243 base::SyncSocket socket(socket_handle); | 233 base::SyncSocket socket(socket_handle); |
244 return; | 234 return; |
245 } | 235 } |
246 | 236 |
237 // In case the audio thread is still shutting down from an async Stop(), | |
238 // we have to wait for it to be completely stopped. We must do this first | |
239 // before setting to the member variables below. | |
240 ShutDownAudioThread(); | |
enal1
2012/01/20 23:09:46
I don't fully understand the comment. Do you mean
tommi (sloooow) - chröme
2012/01/23 10:17:48
You're right, I don't need to do this and I should
| |
241 | |
247 shared_memory_handle_ = handle; | 242 shared_memory_handle_ = handle; |
248 memory_length_ = length; | 243 memory_length_ = length; |
244 audio_socket_ = new AudioSocket(socket_handle); | |
249 | 245 |
250 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_); | 246 audio_thread_.reset( |
251 | 247 new base::DelegateSimpleThread(this, "renderer_audio_thread")); |
252 audio_socket_ = new AudioSocket(socket_handle); | 248 audio_thread_->Start(); |
253 { | |
254 // Synchronize with ShutDownAudioThread(). | |
255 base::AutoLock auto_lock(lock_); | |
256 | |
257 DCHECK(!audio_thread_.get()); | |
258 audio_thread_.reset( | |
259 new base::DelegateSimpleThread(this, "renderer_audio_thread")); | |
260 audio_thread_->Start(); | |
261 } | |
262 | 249 |
263 // We handle the case where Play() and/or Pause() may have been called | 250 // We handle the case where Play() and/or Pause() may have been called |
264 // multiple times before OnLowLatencyCreated() gets called. | 251 // multiple times before OnLowLatencyCreated() gets called. |
265 is_started_ = true; | 252 is_started_ = true; |
266 if (play_on_start_) | 253 if (play_on_start_) |
267 PlayOnIOThread(); | 254 PlayOnIOThread(); |
268 } | 255 } |
269 | 256 |
270 void AudioDevice::OnVolume(double volume) { | 257 void AudioDevice::OnVolume(double volume) { |
271 NOTIMPLEMENTED(); | 258 NOTIMPLEMENTED(); |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
326 // to the browser process as float, so we don't lose precision for | 313 // to the browser process as float, so we don't lose precision for |
327 // audio hardware which has better than 16bit precision. | 314 // audio hardware which has better than 16bit precision. |
328 media::InterleaveFloatToInt16(audio_data_, | 315 media::InterleaveFloatToInt16(audio_data_, |
329 data, | 316 data, |
330 buffer_size_); | 317 buffer_size_); |
331 } | 318 } |
332 return num_frames; | 319 return num_frames; |
333 } | 320 } |
334 | 321 |
335 void AudioDevice::ShutDownAudioThread() { | 322 void AudioDevice::ShutDownAudioThread() { |
336 // Synchronize with OnLowLatencyCreated(). | 323 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); |
337 base::AutoLock auto_lock(lock_); | 324 |
338 if (audio_thread_.get()) { | 325 if (audio_thread_.get()) { |
339 // Close the socket to terminate the main thread function in the | 326 // Close the socket to terminate the main thread function in the |
340 // audio thread. | 327 // audio thread. |
341 audio_socket_->Close(); | 328 audio_socket_->Close(); |
329 audio_socket_ = NULL; | |
342 audio_thread_->Join(); | 330 audio_thread_->Join(); |
343 audio_thread_.reset(NULL); | 331 audio_thread_.reset(NULL); |
344 } | 332 } |
345 } | 333 } |
OLD | NEW |