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

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

Issue 7157001: Implements AudioMessageFilter as member in RenderThread (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: Refactored major parts of the failing unit test Created 9 years, 5 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) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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_renderer_impl.h" 5 #include "content/renderer/media/audio_renderer_impl.h"
6 6
7 #include <math.h> 7 #include <math.h>
8 8
9 #include "content/common/child_process.h"
9 #include "content/common/media/audio_messages.h" 10 #include "content/common/media/audio_messages.h"
10 #include "content/renderer/render_thread.h" 11 #include "content/renderer/render_thread.h"
11 #include "content/renderer/render_view.h" 12 #include "content/renderer/render_view.h"
12 #include "media/base/filter_host.h" 13 #include "media/base/filter_host.h"
13 14
14 namespace { 15 namespace {
15 16
16 // We will try to fill 200 ms worth of audio samples in each packet. A round 17 // We will try to fill 200 ms worth of audio samples in each packet. A round
17 // trip latency for IPC messages are typically 10 ms, this should give us 18 // trip latency for IPC messages are typically 10 ms, this should give us
18 // plenty of time to avoid clicks. 19 // plenty of time to avoid clicks.
19 const int kMillisecondsPerPacket = 200; 20 const int kMillisecondsPerPacket = 200;
20 21
21 // We have at most 3 packets in browser, i.e. 600 ms. This is a reasonable 22 // We have at most 3 packets in browser, i.e. 600 ms. This is a reasonable
22 // amount to avoid clicks. 23 // amount to avoid clicks.
23 const int kPacketsInBuffer = 3; 24 const int kPacketsInBuffer = 3;
24 25
25 } // namespace 26 } // namespace
26 27
27 AudioRendererImpl::AudioRendererImpl(AudioMessageFilter* filter) 28 AudioRendererImpl::AudioRendererImpl()
28 : AudioRendererBase(), 29 : AudioRendererBase(),
29 bytes_per_second_(0), 30 bytes_per_second_(0),
30 filter_(filter),
31 stream_id_(0), 31 stream_id_(0),
32 shared_memory_(NULL), 32 shared_memory_(NULL),
33 shared_memory_size_(0), 33 shared_memory_size_(0),
34 io_loop_(filter->message_loop()),
35 stopped_(false), 34 stopped_(false),
36 pending_request_(false), 35 pending_request_(false),
37 prerolling_(false), 36 prerolling_(false),
38 preroll_bytes_(0) { 37 preroll_bytes_(0) {
39 DCHECK(io_loop_); 38 filter_ = RenderThread::current()->audio_message_filter();
40 } 39 }
41 40
42 AudioRendererImpl::~AudioRendererImpl() { 41 AudioRendererImpl::~AudioRendererImpl() {
43 } 42 }
44 43
45 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { 44 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) {
46 if (bytes_per_second_) { 45 if (bytes_per_second_) {
47 return base::TimeDelta::FromMicroseconds( 46 return base::TimeDelta::FromMicroseconds(
48 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_); 47 base::Time::kMicrosecondsPerSecond * bytes / bytes_per_second_);
49 } 48 }
50 return base::TimeDelta(); 49 return base::TimeDelta();
51 } 50 }
52 51
53 bool AudioRendererImpl::OnInitialize(const media::AudioDecoderConfig& config) { 52 bool AudioRendererImpl::OnInitialize(const media::AudioDecoderConfig& config) {
54 AudioParameters params(config); 53 AudioParameters params(config);
55 params.format = AudioParameters::AUDIO_PCM_LINEAR; 54 params.format = AudioParameters::AUDIO_PCM_LINEAR;
56 55
57 bytes_per_second_ = params.GetBytesPerSecond(); 56 bytes_per_second_ = params.GetBytesPerSecond();
58 57
59 io_loop_->PostTask(FROM_HERE, 58 ChildProcess::current()->io_message_loop()->PostTask(
59 FROM_HERE,
60 NewRunnableMethod(this, &AudioRendererImpl::CreateStreamTask, params)); 60 NewRunnableMethod(this, &AudioRendererImpl::CreateStreamTask, params));
61 return true; 61 return true;
62 } 62 }
63 63
64 void AudioRendererImpl::OnStop() { 64 void AudioRendererImpl::OnStop() {
65 base::AutoLock auto_lock(lock_); 65 base::AutoLock auto_lock(lock_);
66 if (stopped_) 66 if (stopped_)
67 return; 67 return;
68 stopped_ = true; 68 stopped_ = true;
69 69
70 // We should never touch |io_loop_| after being stopped, so post our final 70 ChildProcess::current()->io_message_loop()->PostTask(
71 // task to clean up. 71 FROM_HERE,
72 io_loop_->PostTask(FROM_HERE,
73 NewRunnableMethod(this, &AudioRendererImpl::DestroyTask)); 72 NewRunnableMethod(this, &AudioRendererImpl::DestroyTask));
74 } 73 }
75 74
76 void AudioRendererImpl::ConsumeAudioSamples( 75 void AudioRendererImpl::ConsumeAudioSamples(
77 scoped_refptr<media::Buffer> buffer_in) { 76 scoped_refptr<media::Buffer> buffer_in) {
78 base::AutoLock auto_lock(lock_); 77 base::AutoLock auto_lock(lock_);
79 if (stopped_) 78 if (stopped_)
80 return; 79 return;
81 80
82 // TODO(hclam): handle end of stream here. 81 // TODO(hclam): handle end of stream here.
83 82
84 // Use the base class to queue the buffer. 83 // Use the base class to queue the buffer.
85 AudioRendererBase::ConsumeAudioSamples(buffer_in); 84 AudioRendererBase::ConsumeAudioSamples(buffer_in);
86 85
87 // Post a task to render thread to notify a packet reception. 86 // Post a task to render thread to notify a packet reception.
88 io_loop_->PostTask(FROM_HERE, 87 ChildProcess::current()->io_message_loop()->PostTask(
88 FROM_HERE,
89 NewRunnableMethod(this, &AudioRendererImpl::NotifyPacketReadyTask)); 89 NewRunnableMethod(this, &AudioRendererImpl::NotifyPacketReadyTask));
90 } 90 }
91 91
92 void AudioRendererImpl::SetPlaybackRate(float rate) { 92 void AudioRendererImpl::SetPlaybackRate(float rate) {
93 DCHECK(rate >= 0.0f); 93 DCHECK(rate >= 0.0f);
94 94
95 base::AutoLock auto_lock(lock_); 95 base::AutoLock auto_lock(lock_);
96 // Handle the case where we stopped due to |io_loop_| dying. 96 // Handle the case where we stopped due to IO message loop dying.
97 if (stopped_) { 97 if (stopped_) {
98 AudioRendererBase::SetPlaybackRate(rate); 98 AudioRendererBase::SetPlaybackRate(rate);
99 return; 99 return;
100 } 100 }
101 101
102 // We have two cases here: 102 // We have two cases here:
103 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 103 // Play: GetPlaybackRate() == 0.0 && rate != 0.0
104 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 104 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0
105 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { 105 if (GetPlaybackRate() == 0.0f && rate != 0.0f) {
106 io_loop_->PostTask(FROM_HERE, 106 ChildProcess::current()->io_message_loop()->PostTask(
107 NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); 107 FROM_HERE,
108 NewRunnableMethod(this, &AudioRendererImpl::PlayTask));
108 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { 109 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) {
109 // Pause is easy, we can always pause. 110 // Pause is easy, we can always pause.
110 io_loop_->PostTask(FROM_HERE, 111 ChildProcess::current()->io_message_loop()->PostTask(
111 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 112 FROM_HERE,
113 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
112 } 114 }
113 AudioRendererBase::SetPlaybackRate(rate); 115 AudioRendererBase::SetPlaybackRate(rate);
114 116
115 // If we are playing, give a kick to try fulfilling the packet request as 117 // If we are playing, give a kick to try fulfilling the packet request as
116 // the previous packet request may be stalled by a pause. 118 // the previous packet request may be stalled by a pause.
117 if (rate > 0.0f) { 119 if (rate > 0.0f) {
118 io_loop_->PostTask( 120 ChildProcess::current()->io_message_loop()->PostTask(
119 FROM_HERE, 121 FROM_HERE,
120 NewRunnableMethod(this, &AudioRendererImpl::NotifyPacketReadyTask)); 122 NewRunnableMethod(this, &AudioRendererImpl::NotifyPacketReadyTask));
121 } 123 }
122 } 124 }
123 125
124 void AudioRendererImpl::Pause(media::FilterCallback* callback) { 126 void AudioRendererImpl::Pause(media::FilterCallback* callback) {
125 AudioRendererBase::Pause(callback); 127 AudioRendererBase::Pause(callback);
126 base::AutoLock auto_lock(lock_); 128 base::AutoLock auto_lock(lock_);
127 if (stopped_) 129 if (stopped_)
128 return; 130 return;
129 131
130 io_loop_->PostTask(FROM_HERE, 132 ChildProcess::current()->io_message_loop()->PostTask(
133 FROM_HERE,
131 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 134 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
132 } 135 }
133 136
134 void AudioRendererImpl::Seek(base::TimeDelta time, 137 void AudioRendererImpl::Seek(base::TimeDelta time,
135 const media::FilterStatusCB& cb) { 138 const media::FilterStatusCB& cb) {
136 AudioRendererBase::Seek(time, cb); 139 AudioRendererBase::Seek(time, cb);
137 base::AutoLock auto_lock(lock_); 140 base::AutoLock auto_lock(lock_);
138 if (stopped_) 141 if (stopped_)
139 return; 142 return;
140 143
141 io_loop_->PostTask(FROM_HERE, 144 ChildProcess::current()->io_message_loop()->PostTask(
145 FROM_HERE,
142 NewRunnableMethod(this, &AudioRendererImpl::SeekTask)); 146 NewRunnableMethod(this, &AudioRendererImpl::SeekTask));
143 } 147 }
144 148
145 149
146 void AudioRendererImpl::Play(media::FilterCallback* callback) { 150 void AudioRendererImpl::Play(media::FilterCallback* callback) {
147 AudioRendererBase::Play(callback); 151 AudioRendererBase::Play(callback);
148 base::AutoLock auto_lock(lock_); 152 base::AutoLock auto_lock(lock_);
149 if (stopped_) 153 if (stopped_)
150 return; 154 return;
151 155
152 if (GetPlaybackRate() != 0.0f) { 156 if (GetPlaybackRate() != 0.0f) {
153 io_loop_->PostTask(FROM_HERE, 157 ChildProcess::current()->io_message_loop()->PostTask(
154 NewRunnableMethod(this, &AudioRendererImpl::PlayTask)); 158 FROM_HERE,
159 NewRunnableMethod(this, &AudioRendererImpl::PlayTask));
155 } else { 160 } else {
156 io_loop_->PostTask(FROM_HERE, 161 ChildProcess::current()->io_message_loop()->PostTask(
157 NewRunnableMethod(this, &AudioRendererImpl::PauseTask)); 162 FROM_HERE,
163 NewRunnableMethod(this, &AudioRendererImpl::PauseTask));
158 } 164 }
159 } 165 }
160 166
161 void AudioRendererImpl::SetVolume(float volume) { 167 void AudioRendererImpl::SetVolume(float volume) {
162 base::AutoLock auto_lock(lock_); 168 base::AutoLock auto_lock(lock_);
163 if (stopped_) 169 if (stopped_)
164 return; 170 return;
165 io_loop_->PostTask(FROM_HERE, 171 ChildProcess::current()->io_message_loop()->PostTask(
166 NewRunnableMethod( 172 FROM_HERE,
167 this, &AudioRendererImpl::SetVolumeTask, volume)); 173 NewRunnableMethod(this, &AudioRendererImpl::SetVolumeTask, volume));
168 } 174 }
169 175
170 void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle, 176 void AudioRendererImpl::OnCreated(base::SharedMemoryHandle handle,
171 uint32 length) { 177 uint32 length) {
172 DCHECK(MessageLoop::current() == io_loop_); 178 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
173 179
174 base::AutoLock auto_lock(lock_); 180 base::AutoLock auto_lock(lock_);
175 if (stopped_) 181 if (stopped_)
176 return; 182 return;
177 183
178 shared_memory_.reset(new base::SharedMemory(handle, false)); 184 shared_memory_.reset(new base::SharedMemory(handle, false));
179 shared_memory_->Map(length); 185 shared_memory_->Map(length);
180 shared_memory_size_ = length; 186 shared_memory_size_ = length;
181 } 187 }
182 188
183 void AudioRendererImpl::OnLowLatencyCreated(base::SharedMemoryHandle, 189 void AudioRendererImpl::OnLowLatencyCreated(base::SharedMemoryHandle,
184 base::SyncSocket::Handle, uint32) { 190 base::SyncSocket::Handle, uint32) {
185 // AudioRenderer should not have a low-latency audio channel. 191 // AudioRenderer should not have a low-latency audio channel.
186 NOTREACHED(); 192 NOTREACHED();
187 } 193 }
188 194
189 void AudioRendererImpl::OnRequestPacket(AudioBuffersState buffers_state) { 195 void AudioRendererImpl::OnRequestPacket(AudioBuffersState buffers_state) {
190 DCHECK(MessageLoop::current() == io_loop_); 196 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
191 197
192 { 198 {
193 base::AutoLock auto_lock(lock_); 199 base::AutoLock auto_lock(lock_);
194 DCHECK(!pending_request_); 200 DCHECK(!pending_request_);
195 pending_request_ = true; 201 pending_request_ = true;
196 request_buffers_state_ = buffers_state; 202 request_buffers_state_ = buffers_state;
197 } 203 }
198 204
199 // Try to fill in the fulfill the packet request. 205 // Try to fill in the fulfill the packet request.
200 NotifyPacketReadyTask(); 206 NotifyPacketReadyTask();
201 } 207 }
202 208
203 void AudioRendererImpl::OnStateChanged(AudioStreamState state) { 209 void AudioRendererImpl::OnStateChanged(AudioStreamState state) {
204 DCHECK(MessageLoop::current() == io_loop_); 210 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
205 211
206 base::AutoLock auto_lock(lock_); 212 base::AutoLock auto_lock(lock_);
207 if (stopped_) 213 if (stopped_)
208 return; 214 return;
209 215
210 switch (state) { 216 switch (state) {
211 case kAudioStreamError: 217 case kAudioStreamError:
212 // We receive this error if we counter an hardware error on the browser 218 // We receive this error if we counter an hardware error on the browser
213 // side. We can proceed with ignoring the audio stream. 219 // side. We can proceed with ignoring the audio stream.
214 // TODO(hclam): We need more handling of these kind of error. For example 220 // TODO(hclam): We need more handling of these kind of error. For example
(...skipping 10 matching lines...) Expand all
225 break; 231 break;
226 } 232 }
227 } 233 }
228 234
229 void AudioRendererImpl::OnVolume(double volume) { 235 void AudioRendererImpl::OnVolume(double volume) {
230 // TODO(hclam): decide whether we need to report the current volume to 236 // TODO(hclam): decide whether we need to report the current volume to
231 // pipeline. 237 // pipeline.
232 } 238 }
233 239
234 void AudioRendererImpl::CreateStreamTask(const AudioParameters& audio_params) { 240 void AudioRendererImpl::CreateStreamTask(const AudioParameters& audio_params) {
235 DCHECK(MessageLoop::current() == io_loop_); 241 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
236 242
237 base::AutoLock auto_lock(lock_); 243 base::AutoLock auto_lock(lock_);
238 if (stopped_) 244 if (stopped_)
239 return; 245 return;
240 246
241 // Make sure we don't call create more than once. 247 // Make sure we don't call create more than once.
242 DCHECK_EQ(0, stream_id_); 248 DCHECK_EQ(0, stream_id_);
243 stream_id_ = filter_->AddDelegate(this); 249 stream_id_ = filter_->AddDelegate(this);
244 io_loop_->AddDestructionObserver(this); 250 ChildProcess::current()->io_message_loop()->AddDestructionObserver(this);
245 251
246 AudioParameters params_to_send(audio_params); 252 AudioParameters params_to_send(audio_params);
247 // Let the browser choose packet size. 253 // Let the browser choose packet size.
248 params_to_send.samples_per_packet = 0; 254 params_to_send.samples_per_packet = 0;
249 255
250 filter_->Send(new AudioHostMsg_CreateStream( 256 Send(new AudioHostMsg_CreateStream(stream_id_, params_to_send, false));
251 0, stream_id_, params_to_send, false));
252 } 257 }
253 258
254 void AudioRendererImpl::PlayTask() { 259 void AudioRendererImpl::PlayTask() {
255 DCHECK(MessageLoop::current() == io_loop_); 260 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
256 261
257 filter_->Send(new AudioHostMsg_PlayStream(0, stream_id_)); 262 Send(new AudioHostMsg_PlayStream(stream_id_));
258 } 263 }
259 264
260 void AudioRendererImpl::PauseTask() { 265 void AudioRendererImpl::PauseTask() {
261 DCHECK(MessageLoop::current() == io_loop_); 266 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
262 267
263 filter_->Send(new AudioHostMsg_PauseStream(0, stream_id_)); 268 Send(new AudioHostMsg_PauseStream(stream_id_));
264 } 269 }
265 270
266 void AudioRendererImpl::SeekTask() { 271 void AudioRendererImpl::SeekTask() {
267 DCHECK(MessageLoop::current() == io_loop_); 272 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
268 273
269 // We have to pause the audio stream before we can flush. 274 // We have to pause the audio stream before we can flush.
270 filter_->Send(new AudioHostMsg_PauseStream(0, stream_id_)); 275 Send(new AudioHostMsg_PauseStream(stream_id_));
271 filter_->Send(new AudioHostMsg_FlushStream(0, stream_id_)); 276 Send(new AudioHostMsg_FlushStream(stream_id_));
272 } 277 }
273 278
274 void AudioRendererImpl::DestroyTask() { 279 void AudioRendererImpl::DestroyTask() {
275 DCHECK(MessageLoop::current() == io_loop_); 280 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
276 281
277 // Make sure we don't call destroy more than once. 282 // Make sure we don't call destroy more than once.
278 DCHECK_NE(0, stream_id_); 283 DCHECK_NE(0, stream_id_);
279 filter_->RemoveDelegate(stream_id_); 284 filter_->RemoveDelegate(stream_id_);
280 filter_->Send(new AudioHostMsg_CloseStream(0, stream_id_)); 285 Send(new AudioHostMsg_CloseStream(stream_id_));
281 io_loop_->RemoveDestructionObserver(this); 286 ChildProcess::current()->io_message_loop()->RemoveDestructionObserver(this);
282 stream_id_ = 0; 287 stream_id_ = 0;
283 } 288 }
284 289
285 void AudioRendererImpl::SetVolumeTask(double volume) { 290 void AudioRendererImpl::SetVolumeTask(double volume) {
286 DCHECK(MessageLoop::current() == io_loop_); 291 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
287 292
288 base::AutoLock auto_lock(lock_); 293 base::AutoLock auto_lock(lock_);
289 if (stopped_) 294 if (stopped_)
290 return; 295 return;
291 filter_->Send(new AudioHostMsg_SetVolume(0, stream_id_, volume)); 296 Send(new AudioHostMsg_SetVolume(stream_id_, volume));
292 } 297 }
293 298
294 void AudioRendererImpl::NotifyPacketReadyTask() { 299 void AudioRendererImpl::NotifyPacketReadyTask() {
295 DCHECK(MessageLoop::current() == io_loop_); 300 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
296 301
297 base::AutoLock auto_lock(lock_); 302 base::AutoLock auto_lock(lock_);
298 if (stopped_) 303 if (stopped_)
299 return; 304 return;
300 if (pending_request_ && GetPlaybackRate() > 0.0f) { 305 if (pending_request_ && GetPlaybackRate() > 0.0f) {
301 DCHECK(shared_memory_.get()); 306 DCHECK(shared_memory_.get());
302 307
303 // Adjust the playback delay. 308 // Adjust the playback delay.
304 base::Time current_time = base::Time::Now(); 309 base::Time current_time = base::Time::Now();
305 310
(...skipping 18 matching lines...) Expand all
324 request_delay = base::TimeDelta::FromMicroseconds( 329 request_delay = base::TimeDelta::FromMicroseconds(
325 static_cast<int64>(ceil(request_delay.InMicroseconds() * 330 static_cast<int64>(ceil(request_delay.InMicroseconds() *
326 GetPlaybackRate()))); 331 GetPlaybackRate())));
327 } 332 }
328 333
329 uint32 filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()), 334 uint32 filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()),
330 shared_memory_size_, request_delay, 335 shared_memory_size_, request_delay,
331 request_buffers_state_.pending_bytes == 0); 336 request_buffers_state_.pending_bytes == 0);
332 pending_request_ = false; 337 pending_request_ = false;
333 // Then tell browser process we are done filling into the buffer. 338 // Then tell browser process we are done filling into the buffer.
334 filter_->Send(new AudioHostMsg_NotifyPacketReady(0, stream_id_, filled)); 339 Send(new AudioHostMsg_NotifyPacketReady(stream_id_, filled));
335 } 340 }
336 } 341 }
337 342
338 void AudioRendererImpl::WillDestroyCurrentMessageLoop() { 343 void AudioRendererImpl::WillDestroyCurrentMessageLoop() {
339 DCHECK(MessageLoop::current() == io_loop_); 344 DCHECK(MessageLoop::current() == ChildProcess::current()->io_message_loop());
340 345
341 // We treat the IO loop going away the same as stopping. 346 // We treat the IO loop going away the same as stopping.
342 base::AutoLock auto_lock(lock_); 347 base::AutoLock auto_lock(lock_);
343 if (stopped_) 348 if (stopped_)
344 return; 349 return;
345 350
346 stopped_ = true; 351 stopped_ = true;
347 DestroyTask(); 352 DestroyTask();
348 } 353 }
354
355 void AudioRendererImpl::Send(IPC::Message* message) {
356 filter_->Send(message);
357 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698