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

Side by Side Diff: content/renderer/media/audio_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: Address review comments 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_device.h" 5 #include "content/renderer/media/audio_device.h"
6 6
7 #include "base/bind.h"
8 #include "base/debug/trace_event.h" 7 #include "base/debug/trace_event.h"
9 #include "base/message_loop.h" 8 #include "base/message_loop.h"
10 #include "base/threading/thread_restrictions.h" 9 #include "base/threading/thread_restrictions.h"
11 #include "base/time.h" 10 #include "base/time.h"
12 #include "content/common/child_process.h" 11 #include "content/common/child_process.h"
13 #include "content/common/media/audio_messages.h" 12 #include "content/common/media/audio_messages.h"
14 #include "content/common/view_messages.h" 13 #include "content/common/view_messages.h"
15 #include "content/renderer/render_thread_impl.h" 14 #include "content/renderer/render_thread_impl.h"
16 #include "media/audio/audio_output_controller.h" 15 #include "media/audio/audio_output_controller.h"
17 #include "media/audio/audio_util.h" 16 #include "media/audio/audio_util.h"
18 17
19 AudioDevice::AudioDevice() 18 AudioDevice::AudioDevice()
20 : buffer_size_(0), 19 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()),
20 buffer_size_(0),
21 channels_(0), 21 channels_(0),
22 bits_per_sample_(16), 22 bits_per_sample_(16),
23 sample_rate_(0), 23 sample_rate_(0),
24 latency_format_(AudioParameters::AUDIO_PCM_LOW_LATENCY), 24 latency_format_(AudioParameters::AUDIO_PCM_LOW_LATENCY),
25 callback_(0), 25 callback_(0),
26 is_initialized_(false), 26 is_initialized_(false),
27 audio_delay_milliseconds_(0), 27 audio_delay_milliseconds_(0),
28 volume_(1.0), 28 volume_(1.0),
29 stream_id_(0), 29 stream_id_(0),
30 play_on_start_(true), 30 play_on_start_(true),
31 is_started_(false), 31 is_started_(false),
32 shared_memory_handle_(base::SharedMemory::NULLHandle()), 32 shared_memory_handle_(base::SharedMemory::NULLHandle()),
33 memory_length_(0) { 33 memory_length_(0) {
34 filter_ = RenderThreadImpl::current()->audio_message_filter(); 34 filter_ = RenderThreadImpl::current()->audio_message_filter();
35 } 35 }
36 36
37 AudioDevice::AudioDevice(size_t buffer_size, 37 AudioDevice::AudioDevice(size_t buffer_size,
38 int channels, 38 int channels,
39 double sample_rate, 39 double sample_rate,
40 RenderCallback* callback) 40 RenderCallback* callback)
41 : bits_per_sample_(16), 41 : ScopedLoopObserver(ChildProcess::current()->io_message_loop()),
42 bits_per_sample_(16),
42 is_initialized_(false), 43 is_initialized_(false),
43 audio_delay_milliseconds_(0), 44 audio_delay_milliseconds_(0),
44 volume_(1.0), 45 volume_(1.0),
45 stream_id_(0), 46 stream_id_(0),
46 play_on_start_(true), 47 play_on_start_(true),
47 is_started_(false), 48 is_started_(false),
48 shared_memory_handle_(base::SharedMemory::NULLHandle()), 49 shared_memory_handle_(base::SharedMemory::NULLHandle()),
49 memory_length_(0) { 50 memory_length_(0) {
50 filter_ = RenderThreadImpl::current()->audio_message_filter(); 51 filter_ = RenderThreadImpl::current()->audio_message_filter();
51 Initialize(buffer_size, 52 Initialize(buffer_size,
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
93 } 94 }
94 95
95 void AudioDevice::Start() { 96 void AudioDevice::Start() {
96 AudioParameters params; 97 AudioParameters params;
97 params.format = latency_format_; 98 params.format = latency_format_;
98 params.channels = channels_; 99 params.channels = channels_;
99 params.sample_rate = static_cast<int>(sample_rate_); 100 params.sample_rate = static_cast<int>(sample_rate_);
100 params.bits_per_sample = bits_per_sample_; 101 params.bits_per_sample = bits_per_sample_;
101 params.samples_per_packet = buffer_size_; 102 params.samples_per_packet = buffer_size_;
102 103
103 ChildProcess::current()->io_message_loop()->PostTask( 104 message_loop()->PostTask(FROM_HERE,
104 FROM_HERE,
105 base::Bind(&AudioDevice::InitializeOnIOThread, this, params)); 105 base::Bind(&AudioDevice::InitializeOnIOThread, this, params));
106 } 106 }
107 107
108 void AudioDevice::Stop() { 108 void AudioDevice::Stop() {
109 DCHECK(MessageLoop::current() != ChildProcess::current()->io_message_loop()); 109 DCHECK(!message_loop()->BelongsToCurrentThread());
110 110
111 // Stop and shutdown the audio thread from the IO thread. 111 // Stop and shutdown the audio thread from the IO thread.
112 // This operation must be synchronous for now since the |callback_| pointer 112 // This operation must be synchronous for now since the |callback_| pointer
113 // isn't ref counted and the object might go out of scope after Stop() 113 // isn't ref counted and the object might go out of scope after Stop()
114 // returns (and FireRenderCallback might dereference a bogus pointer). 114 // returns (and FireRenderCallback might dereference a bogus pointer).
115 // TODO(tommi): Add an Uninitialize() method to AudioRendererSink? 115 // TODO(tommi): Add an Uninitialize() method to AudioRendererSink?
116 base::WaitableEvent done(true, false); 116 base::WaitableEvent done(true, false);
117 ChildProcess::current()->io_message_loop()->PostTask( 117 if (message_loop()->PostTask(FROM_HERE,
118 FROM_HERE, 118 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &done))) {
119 base::Bind(&AudioDevice::ShutDownOnIOThread, this, &done)); 119 done.Wait();
120 done.Wait(); 120 }
121 } 121 }
122 122
123 void AudioDevice::Play() { 123 void AudioDevice::Play() {
124 ChildProcess::current()->io_message_loop()->PostTask( 124 message_loop()->PostTask(FROM_HERE,
125 FROM_HERE,
126 base::Bind(&AudioDevice::PlayOnIOThread, this)); 125 base::Bind(&AudioDevice::PlayOnIOThread, this));
127 } 126 }
128 127
129 void AudioDevice::Pause(bool flush) { 128 void AudioDevice::Pause(bool flush) {
130 ChildProcess::current()->io_message_loop()->PostTask( 129 message_loop()->PostTask(FROM_HERE,
131 FROM_HERE,
132 base::Bind(&AudioDevice::PauseOnIOThread, this, flush)); 130 base::Bind(&AudioDevice::PauseOnIOThread, this, flush));
133 } 131 }
134 132
135 bool AudioDevice::SetVolume(double volume) { 133 bool AudioDevice::SetVolume(double volume) {
136 if (volume < 0 || volume > 1.0) 134 if (volume < 0 || volume > 1.0)
137 return false; 135 return false;
138 136
139 ChildProcess::current()->io_message_loop()->PostTask( 137 if (!message_loop()->PostTask(FROM_HERE,
140 FROM_HERE, 138 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume))) {
141 base::Bind(&AudioDevice::SetVolumeOnIOThread, this, volume)); 139 return false;
140 }
142 141
143 volume_ = volume; 142 volume_ = volume;
144 143
145 return true; 144 return true;
146 } 145 }
147 146
148 void AudioDevice::GetVolume(double* volume) { 147 void AudioDevice::GetVolume(double* volume) {
149 // Return a locally cached version of the current scaling factor. 148 // Return a locally cached version of the current scaling factor.
150 *volume = volume_; 149 *volume = volume_;
151 } 150 }
152 151
153 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) { 152 void AudioDevice::InitializeOnIOThread(const AudioParameters& params) {
154 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 153 DCHECK(message_loop()->BelongsToCurrentThread());
155 // Make sure we don't create the stream more than once. 154 // Make sure we don't create the stream more than once.
156 DCHECK_EQ(0, stream_id_); 155 DCHECK_EQ(0, stream_id_);
157 if (stream_id_) 156 if (stream_id_)
158 return; 157 return;
159 158
160 stream_id_ = filter_->AddDelegate(this); 159 stream_id_ = filter_->AddDelegate(this);
161 Send(new AudioHostMsg_CreateStream(stream_id_, params)); 160 Send(new AudioHostMsg_CreateStream(stream_id_, params));
162 } 161 }
163 162
164 void AudioDevice::PlayOnIOThread() { 163 void AudioDevice::PlayOnIOThread() {
165 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 164 DCHECK(message_loop()->BelongsToCurrentThread());
166 if (stream_id_ && is_started_) 165 if (stream_id_ && is_started_)
167 Send(new AudioHostMsg_PlayStream(stream_id_)); 166 Send(new AudioHostMsg_PlayStream(stream_id_));
168 else 167 else
169 play_on_start_ = true; 168 play_on_start_ = true;
170 } 169 }
171 170
172 void AudioDevice::PauseOnIOThread(bool flush) { 171 void AudioDevice::PauseOnIOThread(bool flush) {
173 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 172 DCHECK(message_loop()->BelongsToCurrentThread());
174 if (stream_id_ && is_started_) { 173 if (stream_id_ && is_started_) {
175 Send(new AudioHostMsg_PauseStream(stream_id_)); 174 Send(new AudioHostMsg_PauseStream(stream_id_));
176 if (flush) 175 if (flush)
177 Send(new AudioHostMsg_FlushStream(stream_id_)); 176 Send(new AudioHostMsg_FlushStream(stream_id_));
178 } else { 177 } else {
179 // Note that |flush| isn't relevant here since this is the case where 178 // Note that |flush| isn't relevant here since this is the case where
180 // the stream is first starting. 179 // the stream is first starting.
181 play_on_start_ = false; 180 play_on_start_ = false;
182 } 181 }
183 } 182 }
184 183
185 void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* signal) { 184 void AudioDevice::ShutDownOnIOThread(base::WaitableEvent* signal) {
186 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 185 DCHECK(message_loop()->BelongsToCurrentThread());
186 // NOTE: |signal| may be NULL.
187 187
188 // Make sure we don't call shutdown more than once. 188 // Make sure we don't call shutdown more than once.
189 if (stream_id_) { 189 if (stream_id_) {
190 is_started_ = false; 190 is_started_ = false;
191 191
192 filter_->RemoveDelegate(stream_id_); 192 filter_->RemoveDelegate(stream_id_);
193 Send(new AudioHostMsg_CloseStream(stream_id_)); 193 Send(new AudioHostMsg_CloseStream(stream_id_));
194 stream_id_ = 0; 194 stream_id_ = 0;
195 195
196 ShutDownAudioThread(); 196 ShutDownAudioThread();
197 } 197 }
198 198
199 signal->Signal(); 199 if (signal)
200 signal->Signal();
200 } 201 }
201 202
202 void AudioDevice::SetVolumeOnIOThread(double volume) { 203 void AudioDevice::SetVolumeOnIOThread(double volume) {
203 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 204 DCHECK(message_loop()->BelongsToCurrentThread());
204 if (stream_id_) 205 if (stream_id_)
205 Send(new AudioHostMsg_SetVolume(stream_id_, volume)); 206 Send(new AudioHostMsg_SetVolume(stream_id_, volume));
206 } 207 }
207 208
208 void AudioDevice::OnStateChanged(AudioStreamState state) { 209 void AudioDevice::OnStateChanged(AudioStreamState state) {
209 if (state == kAudioStreamError) { 210 if (state == kAudioStreamError) {
210 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)"; 211 DLOG(WARNING) << "AudioDevice::OnStateChanged(kError)";
211 callback_->OnError(); 212 callback_->OnError();
212 } 213 }
213 } 214 }
214 215
215 void AudioDevice::OnStreamCreated( 216 void AudioDevice::OnStreamCreated(
216 base::SharedMemoryHandle handle, 217 base::SharedMemoryHandle handle,
217 base::SyncSocket::Handle socket_handle, 218 base::SyncSocket::Handle socket_handle,
218 uint32 length) { 219 uint32 length) {
219 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 220 DCHECK(message_loop()->BelongsToCurrentThread());
220 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_); 221 DCHECK_GE(length, buffer_size_ * sizeof(int16) * channels_);
221 #if defined(OS_WIN) 222 #if defined(OS_WIN)
222 DCHECK(handle); 223 DCHECK(handle);
223 DCHECK(socket_handle); 224 DCHECK(socket_handle);
224 #else 225 #else
225 DCHECK_GE(handle.fd, 0); 226 DCHECK_GE(handle.fd, 0);
226 DCHECK_GE(socket_handle, 0); 227 DCHECK_GE(socket_handle, 0);
227 #endif 228 #endif
228 229
229 // Takes care of the case when Stop() is called before OnStreamCreated(). 230 // Takes care of the case when Stop() is called before OnStreamCreated().
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
307 // to the browser process as float, so we don't lose precision for 308 // to the browser process as float, so we don't lose precision for
308 // audio hardware which has better than 16bit precision. 309 // audio hardware which has better than 16bit precision.
309 media::InterleaveFloatToInt16(audio_data_, 310 media::InterleaveFloatToInt16(audio_data_,
310 data, 311 data,
311 buffer_size_); 312 buffer_size_);
312 } 313 }
313 return num_frames; 314 return num_frames;
314 } 315 }
315 316
316 void AudioDevice::ShutDownAudioThread() { 317 void AudioDevice::ShutDownAudioThread() {
317 DCHECK_EQ(MessageLoop::current(), ChildProcess::current()->io_message_loop()); 318 DCHECK(message_loop()->BelongsToCurrentThread());
318 319
319 if (audio_thread_.get()) { 320 if (audio_thread_.get()) {
320 // Close the socket to terminate the main thread function in the 321 // Close the socket to terminate the main thread function in the
321 // audio thread. 322 // audio thread.
322 audio_socket_->Shutdown(); // Stops blocking Receive calls. 323 audio_socket_->Shutdown(); // Stops blocking Receive calls.
323 // TODO(tommi): We must not do this from the IO thread. Fix. 324 // TODO(tommi): We must not do this from the IO thread. Fix.
324 base::ThreadRestrictions::ScopedAllowIO allow_wait; 325 base::ThreadRestrictions::ScopedAllowIO allow_wait;
325 audio_thread_->Join(); 326 audio_thread_->Join();
326 audio_thread_.reset(NULL); 327 audio_thread_.reset(NULL);
327 audio_socket_.reset(); 328 audio_socket_.reset();
328 } 329 }
329 } 330 }
331
332 void AudioDevice::WillDestroyCurrentMessageLoop() {
333 ShutDownOnIOThread(NULL);
334 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698