OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this |
2 // source code is governed by a BSD-style license that can be found in the | 2 // source code is governed by a BSD-style license that can be found in the |
3 // LICENSE file. | 3 // LICENSE file. |
4 | 4 |
5 #include "chrome/common/render_messages.h" | 5 #include "chrome/common/render_messages.h" |
6 #include "chrome/renderer/audio_message_filter.h" | 6 #include "chrome/renderer/audio_message_filter.h" |
7 #include "chrome/renderer/media/audio_renderer_impl.h" | 7 #include "chrome/renderer/media/audio_renderer_impl.h" |
8 #include "chrome/renderer/render_view.h" | 8 #include "chrome/renderer/render_view.h" |
9 #include "chrome/renderer/render_thread.h" | 9 #include "chrome/renderer/render_thread.h" |
10 #include "media/base/filter_host.h" | 10 #include "media/base/filter_host.h" |
11 | 11 |
12 namespace { | 12 namespace { |
13 | 13 |
14 // We will try to fill 200 ms worth of audio samples in each packet. A round | 14 // We will try to fill 200 ms worth of audio samples in each packet. A round |
15 // trip latency for IPC messages are typically 10 ms, this should give us | 15 // trip latency for IPC messages are typically 10 ms, this should give us |
16 // plenty of time to avoid clicks. | 16 // plenty of time to avoid clicks. |
17 const int kMillisecondsPerPacket = 200; | 17 const int kMillisecondsPerPacket = 200; |
18 | 18 |
19 // We have at most 3 packets in browser, i.e. 600 ms. This is a reasonable | 19 // We have at most 3 packets in browser, i.e. 600 ms. This is a reasonable |
20 // amount to avoid clicks. | 20 // amount to avoid clicks. |
21 const int kPacketsInBuffer = 3; | 21 const int kPacketsInBuffer = 3; |
22 | 22 |
23 // We want to preroll 400 milliseconds before starting to play. Again, 400 ms | 23 // We want to preroll 400 milliseconds before starting to play. Again, 400 ms |
24 // of audio data should give us enough time to get more from the renderer. | 24 // of audio data should give us enough time to get more from the renderer. |
25 const int kMillisecondsPreroll = 400; | 25 const int kMillisecondsPreroll = 400; |
26 | 26 |
27 } // namespace | 27 } // namespace |
28 | 28 |
29 AudioRendererImpl::AudioRendererImpl(AudioMessageFilter* filter) | 29 AudioRendererImpl::AudioRendererImpl(AudioMessageFilter* filter) |
30 : AudioRendererBase(kDefaultMaxQueueSize), | 30 : AudioRendererBase(), |
31 channels_(0), | 31 channels_(0), |
32 sample_rate_(0), | 32 sample_rate_(0), |
33 sample_bits_(0), | 33 sample_bits_(0), |
34 bytes_per_second_(0), | 34 bytes_per_second_(0), |
35 filter_(filter), | 35 filter_(filter), |
36 stream_id_(0), | 36 stream_id_(0), |
37 shared_memory_(NULL), | 37 shared_memory_(NULL), |
38 shared_memory_size_(0), | 38 shared_memory_size_(0), |
39 io_loop_(filter->message_loop()), | 39 io_loop_(filter->message_loop()), |
40 stopped_(false), | 40 stopped_(false), |
41 playback_rate_(0.0f), | |
42 pending_request_(false), | 41 pending_request_(false), |
43 prerolling_(true), | 42 prerolling_(true), |
44 preroll_bytes_(0) { | 43 preroll_bytes_(0) { |
45 DCHECK(io_loop_); | 44 DCHECK(io_loop_); |
46 } | 45 } |
47 | 46 |
48 AudioRendererImpl::~AudioRendererImpl() { | 47 AudioRendererImpl::~AudioRendererImpl() { |
49 } | 48 } |
50 | 49 |
51 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { | 50 base::TimeDelta AudioRendererImpl::ConvertToDuration(int bytes) { |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
110 | 109 |
111 // Post a task to render thread to notify a packet reception. | 110 // Post a task to render thread to notify a packet reception. |
112 io_loop_->PostTask(FROM_HERE, | 111 io_loop_->PostTask(FROM_HERE, |
113 NewRunnableMethod(this, &AudioRendererImpl::OnNotifyPacketReady)); | 112 NewRunnableMethod(this, &AudioRendererImpl::OnNotifyPacketReady)); |
114 } | 113 } |
115 | 114 |
116 void AudioRendererImpl::SetPlaybackRate(float rate) { | 115 void AudioRendererImpl::SetPlaybackRate(float rate) { |
117 DCHECK(rate >= 0.0f); | 116 DCHECK(rate >= 0.0f); |
118 | 117 |
119 // We have two cases here: | 118 // We have two cases here: |
120 // Play: playback_rate_ == 0.0 && rate != 0.0 | 119 // Play: GetPlaybackRate() == 0.0 && rate != 0.0 |
121 // Pause: playback_rate_ != 0.0 && rate == 0.0 | 120 // Pause: GetPlaybackRate() != 0.0 && rate == 0.0 |
122 AutoLock auto_lock(lock_); | 121 AutoLock auto_lock(lock_); |
123 if (playback_rate_ == 0.0f && rate != 0.0f) { | 122 if (GetPlaybackRate() == 0.0f && rate != 0.0f) { |
124 // Play is a bit tricky, we can only play if we have done prerolling. | 123 // Play is a bit tricky, we can only play if we have done prerolling. |
125 // TODO(hclam): I should check for end of streams status here. | 124 // TODO(hclam): I should check for end of streams status here. |
126 if (!prerolling_) | 125 if (!prerolling_) |
127 io_loop_->PostTask(FROM_HERE, | 126 io_loop_->PostTask(FROM_HERE, |
128 NewRunnableMethod(this, &AudioRendererImpl::OnPlay)); | 127 NewRunnableMethod(this, &AudioRendererImpl::OnPlay)); |
129 } else if (playback_rate_ != 0.0f && rate == 0.0f) { | 128 } else if (GetPlaybackRate() != 0.0f && rate == 0.0f) { |
130 // Pause is easy, we can always pause. | 129 // Pause is easy, we can always pause. |
131 io_loop_->PostTask(FROM_HERE, | 130 io_loop_->PostTask(FROM_HERE, |
132 NewRunnableMethod(this, &AudioRendererImpl::OnPause)); | 131 NewRunnableMethod(this, &AudioRendererImpl::OnPause)); |
133 } | 132 } |
134 playback_rate_ = rate; | 133 AudioRendererBase::SetPlaybackRate(rate); |
135 | 134 |
136 // If we are playing, give a kick to try fulfilling the packet request as | 135 // If we are playing, give a kick to try fulfilling the packet request as |
137 // the previous packet request may be stalled by a pause. | 136 // the previous packet request may be stalled by a pause. |
138 if (rate > 0.0f) { | 137 if (rate > 0.0f) { |
139 io_loop_->PostTask( | 138 io_loop_->PostTask( |
140 FROM_HERE, | 139 FROM_HERE, |
141 NewRunnableMethod(this, &AudioRendererImpl::OnNotifyPacketReady)); | 140 NewRunnableMethod(this, &AudioRendererImpl::OnNotifyPacketReady)); |
142 } | 141 } |
143 } | 142 } |
144 | 143 |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
266 return; | 265 return; |
267 filter_->Send(new ViewHostMsg_SetAudioVolume(0, stream_id_, left, right)); | 266 filter_->Send(new ViewHostMsg_SetAudioVolume(0, stream_id_, left, right)); |
268 } | 267 } |
269 | 268 |
270 void AudioRendererImpl::OnNotifyPacketReady() { | 269 void AudioRendererImpl::OnNotifyPacketReady() { |
271 DCHECK(MessageLoop::current() == io_loop_); | 270 DCHECK(MessageLoop::current() == io_loop_); |
272 | 271 |
273 AutoLock auto_lock(lock_); | 272 AutoLock auto_lock(lock_); |
274 if (stopped_) | 273 if (stopped_) |
275 return; | 274 return; |
276 if (pending_request_ && playback_rate_ > 0.0f) { | 275 if (pending_request_ && GetPlaybackRate() > 0.0f) { |
277 DCHECK(shared_memory_.get()); | 276 DCHECK(shared_memory_.get()); |
278 | 277 |
279 // Adjust the playback delay. | 278 // Adjust the playback delay. |
280 base::Time current_time = base::Time::Now(); | 279 base::Time current_time = base::Time::Now(); |
281 | 280 |
282 // Save a local copy of the request delay. | 281 // Save a local copy of the request delay. |
283 base::TimeDelta request_delay = request_delay_; | 282 base::TimeDelta request_delay = request_delay_; |
284 if (current_time > request_timestamp_) { | 283 if (current_time > request_timestamp_) { |
285 base::TimeDelta receive_latency = current_time - request_timestamp_; | 284 base::TimeDelta receive_latency = current_time - request_timestamp_; |
286 | 285 |
287 // If the receive latency is too much it may offset all the delay. | 286 // If the receive latency is too much it may offset all the delay. |
288 if (receive_latency >= request_delay) { | 287 if (receive_latency >= request_delay) { |
289 request_delay = base::TimeDelta(); | 288 request_delay = base::TimeDelta(); |
290 } else { | 289 } else { |
291 request_delay -= receive_latency; | 290 request_delay -= receive_latency; |
292 } | 291 } |
293 } | 292 } |
294 | 293 |
295 size_t filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()), | 294 size_t filled = FillBuffer(static_cast<uint8*>(shared_memory_->memory()), |
296 shared_memory_size_, | 295 shared_memory_size_, |
297 playback_rate_, | |
298 request_delay); | 296 request_delay); |
299 // TODO(hclam): we should try to fill in the buffer as much as possible. | 297 // TODO(hclam): we should try to fill in the buffer as much as possible. |
300 if (filled > 0) { | 298 if (filled > 0) { |
301 pending_request_ = false; | 299 pending_request_ = false; |
302 request_delay_ = base::TimeDelta(); | 300 request_delay_ = base::TimeDelta(); |
303 request_timestamp_ = base::Time(); | 301 request_timestamp_ = base::Time(); |
304 // Then tell browser process we are done filling into the buffer. | 302 // Then tell browser process we are done filling into the buffer. |
305 filter_->Send( | 303 filter_->Send( |
306 new ViewHostMsg_NotifyAudioPacketReady(0, stream_id_, filled)); | 304 new ViewHostMsg_NotifyAudioPacketReady(0, stream_id_, filled)); |
307 | 305 |
308 if (prerolling_) { | 306 if (prerolling_) { |
309 // We have completed prerolling. | 307 // We have completed prerolling. |
310 if (filled > preroll_bytes_) { | 308 if (filled > preroll_bytes_) { |
311 prerolling_ = false; | 309 prerolling_ = false; |
312 preroll_bytes_ = 0; | 310 preroll_bytes_ = 0; |
313 filter_->Send(new ViewHostMsg_StartAudioStream(0, stream_id_)); | 311 filter_->Send(new ViewHostMsg_StartAudioStream(0, stream_id_)); |
314 } else { | 312 } else { |
315 preroll_bytes_ -= filled; | 313 preroll_bytes_ -= filled; |
316 } | 314 } |
317 } | 315 } |
318 } | 316 } |
319 } | 317 } |
320 } | 318 } |
OLD | NEW |