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

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

Powered by Google App Engine
This is Rietveld 408576698