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

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

Issue 9264013: Simplify shutdown of AudioDevice's audio thread. (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_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) 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
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
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
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 }
OLDNEW
« no previous file with comments | « content/renderer/media/audio_device.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698