OLD | NEW |
---|---|
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 "media/filters/audio_renderer_base.h" | 5 #include "media/filters/audio_renderer_base.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
11 #include "base/callback.h" | 11 #include "base/callback.h" |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "media/base/filter_host.h" | 13 #include "media/base/filter_host.h" |
14 #include "media/filters/audio_renderer_algorithm_ola.h" | 14 #include "media/filters/audio_renderer_algorithm_ola.h" |
15 | 15 |
16 namespace media { | 16 namespace media { |
17 | 17 |
18 // Upper bound on the number of pending AudioDecoder reads. | |
19 // TODO(acolwell): Experiment with reducing this to 1. | |
20 const size_t kMaxPendingReads = 4; | |
21 | |
22 AudioRendererBase::AudioRendererBase() | 18 AudioRendererBase::AudioRendererBase() |
23 : state_(kUninitialized), | 19 : state_(kUninitialized), |
20 pending_read_(false), | |
24 recieved_end_of_stream_(false), | 21 recieved_end_of_stream_(false), |
25 rendered_end_of_stream_(false), | 22 rendered_end_of_stream_(false), |
26 pending_reads_(0) { | 23 read_cb_(base::Bind(&AudioRendererBase::DecodedAudioReady, |
24 base::Unretained(this))) { | |
27 } | 25 } |
28 | 26 |
29 AudioRendererBase::~AudioRendererBase() { | 27 AudioRendererBase::~AudioRendererBase() { |
30 // Stop() should have been called and |algorithm_| should have been destroyed. | 28 // Stop() should have been called and |algorithm_| should have been destroyed. |
31 DCHECK(state_ == kUninitialized || state_ == kStopped); | 29 DCHECK(state_ == kUninitialized || state_ == kStopped); |
32 DCHECK(!algorithm_.get()); | 30 DCHECK(!algorithm_.get()); |
33 } | 31 } |
34 | 32 |
35 void AudioRendererBase::Play(const base::Closure& callback) { | 33 void AudioRendererBase::Play(const base::Closure& callback) { |
36 base::AutoLock auto_lock(lock_); | 34 base::AutoLock auto_lock(lock_); |
37 DCHECK_EQ(kPaused, state_); | 35 DCHECK_EQ(kPaused, state_); |
38 state_ = kPlaying; | 36 state_ = kPlaying; |
39 callback.Run(); | 37 callback.Run(); |
40 } | 38 } |
41 | 39 |
42 void AudioRendererBase::Pause(const base::Closure& callback) { | 40 void AudioRendererBase::Pause(const base::Closure& callback) { |
43 base::AutoLock auto_lock(lock_); | 41 base::AutoLock auto_lock(lock_); |
44 DCHECK(state_ == kPlaying || state_ == kUnderflow || state_ == kRebuffering); | 42 DCHECK(state_ == kPlaying || state_ == kUnderflow || state_ == kRebuffering); |
45 pause_callback_ = callback; | 43 pause_callback_ = callback; |
46 state_ = kPaused; | 44 state_ = kPaused; |
47 | 45 |
48 // We'll only pause when we've finished all pending reads. | 46 // Pause only when we've completed our pending read. |
49 if (pending_reads_ == 0) { | 47 if (!pending_read_) { |
50 pause_callback_.Run(); | 48 pause_callback_.Run(); |
51 pause_callback_.Reset(); | 49 pause_callback_.Reset(); |
52 } else { | 50 } else { |
53 state_ = kPaused; | 51 state_ = kPaused; |
54 } | 52 } |
55 } | 53 } |
56 | 54 |
57 void AudioRendererBase::Stop(const base::Closure& callback) { | 55 void AudioRendererBase::Stop(const base::Closure& callback) { |
58 OnStop(); | 56 OnStop(); |
59 { | 57 { |
60 base::AutoLock auto_lock(lock_); | 58 base::AutoLock auto_lock(lock_); |
61 state_ = kStopped; | 59 state_ = kStopped; |
62 algorithm_.reset(NULL); | 60 algorithm_.reset(NULL); |
63 } | 61 } |
64 if (!callback.is_null()) { | 62 if (!callback.is_null()) { |
65 callback.Run(); | 63 callback.Run(); |
66 } | 64 } |
67 } | 65 } |
68 | 66 |
69 void AudioRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) { | 67 void AudioRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) { |
70 base::AutoLock auto_lock(lock_); | 68 base::AutoLock auto_lock(lock_); |
71 DCHECK_EQ(kPaused, state_); | 69 DCHECK_EQ(kPaused, state_); |
72 DCHECK_EQ(0u, pending_reads_) << "Pending reads should have completed"; | 70 DCHECK(!pending_read_) << "Pending read must complete before seeking"; |
73 DCHECK(seek_cb_.is_null()); | 71 DCHECK(seek_cb_.is_null()); |
74 state_ = kSeeking; | 72 state_ = kSeeking; |
75 seek_cb_ = cb; | 73 seek_cb_ = cb; |
76 seek_timestamp_ = time; | 74 seek_timestamp_ = time; |
77 | 75 |
78 // Throw away everything and schedule our reads. | 76 // Throw away everything and schedule our reads. |
79 last_fill_buffer_time_ = base::TimeDelta(); | 77 last_fill_buffer_time_ = base::TimeDelta(); |
80 recieved_end_of_stream_ = false; | 78 recieved_end_of_stream_ = false; |
81 rendered_end_of_stream_ = false; | 79 rendered_end_of_stream_ = false; |
82 | 80 |
83 // |algorithm_| will request more reads. | 81 // |algorithm_| will request more reads. |
84 algorithm_->FlushBuffers(); | 82 algorithm_->FlushBuffers(); |
85 } | 83 } |
86 | 84 |
87 void AudioRendererBase::Initialize(AudioDecoder* decoder, | 85 void AudioRendererBase::Initialize(AudioDecoder* decoder, |
88 const base::Closure& init_callback, | 86 const base::Closure& init_callback, |
89 const base::Closure& underflow_callback) { | 87 const base::Closure& underflow_callback) { |
90 DCHECK(decoder); | 88 DCHECK(decoder); |
91 DCHECK(!init_callback.is_null()); | 89 DCHECK(!init_callback.is_null()); |
92 DCHECK(!underflow_callback.is_null()); | 90 DCHECK(!underflow_callback.is_null()); |
93 DCHECK_EQ(kUninitialized, state_); | 91 DCHECK_EQ(kUninitialized, state_); |
94 decoder_ = decoder; | 92 decoder_ = decoder; |
95 underflow_callback_ = underflow_callback; | 93 underflow_callback_ = underflow_callback; |
96 | 94 |
97 // Use base::Unretained() as the decoder doesn't need to ref us. | |
98 decoder_->set_consume_audio_samples_callback( | |
99 base::Bind(&AudioRendererBase::ConsumeAudioSamples, | |
100 base::Unretained(this))); | |
101 | |
102 // Create a callback so our algorithm can request more reads. | 95 // Create a callback so our algorithm can request more reads. |
103 base::Closure cb = base::Bind(&AudioRendererBase::ScheduleRead_Locked, this); | 96 base::Closure cb = base::Bind(&AudioRendererBase::ScheduleRead_Locked, this); |
104 | 97 |
105 // Construct the algorithm. | 98 // Construct the algorithm. |
106 algorithm_.reset(new AudioRendererAlgorithmOLA()); | 99 algorithm_.reset(new AudioRendererAlgorithmOLA()); |
107 | 100 |
108 // Initialize our algorithm with media properties, initial playback rate, | 101 // Initialize our algorithm with media properties, initial playback rate, |
109 // and a callback to request more reads from the data source. | 102 // and a callback to request more reads from the data source. |
110 ChannelLayout channel_layout = decoder_->channel_layout(); | 103 ChannelLayout channel_layout = decoder_->channel_layout(); |
111 int channels = ChannelLayoutToChannelCount(channel_layout); | 104 int channels = ChannelLayoutToChannelCount(channel_layout); |
(...skipping 25 matching lines...) Expand all Loading... | |
137 void AudioRendererBase::ResumeAfterUnderflow(bool buffer_more_audio) { | 130 void AudioRendererBase::ResumeAfterUnderflow(bool buffer_more_audio) { |
138 base::AutoLock auto_lock(lock_); | 131 base::AutoLock auto_lock(lock_); |
139 if (state_ == kUnderflow) { | 132 if (state_ == kUnderflow) { |
140 if (buffer_more_audio) | 133 if (buffer_more_audio) |
141 algorithm_->IncreaseQueueCapacity(); | 134 algorithm_->IncreaseQueueCapacity(); |
142 | 135 |
143 state_ = kRebuffering; | 136 state_ = kRebuffering; |
144 } | 137 } |
145 } | 138 } |
146 | 139 |
147 void AudioRendererBase::ConsumeAudioSamples(scoped_refptr<Buffer> buffer_in) { | 140 void AudioRendererBase::DecodedAudioReady(scoped_refptr<Buffer> buffer) { |
148 base::AutoLock auto_lock(lock_); | 141 base::AutoLock auto_lock(lock_); |
149 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || | 142 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || |
150 state_ == kUnderflow || state_ == kRebuffering || | 143 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); |
151 state_ == kStopped); | |
152 if (!pending_reads_) | |
scherkus (not reviewing)
2011/12/19 19:30:13
vrk: do you know if replacing this with a CHECK()
vrk (LEFT CHROMIUM)
2011/12/20 01:22:00
Bah, spent a long time looking through the code to
scherkus (not reviewing)
2011/12/20 15:27:57
Thanks for digging in!
Yes all read calls are sup
| |
153 return; | |
154 | 144 |
155 --pending_reads_; | 145 CHECK(pending_read_); |
146 pending_read_ = false; | |
156 | 147 |
157 // TODO(scherkus): this happens due to a race, primarily because Stop() is a | 148 // TODO(scherkus): this happens due to a race, primarily because Stop() is a |
158 // synchronous call when it should be asynchronous and accept a callback. | 149 // synchronous call when it should be asynchronous and accept a callback. |
159 // Refer to http://crbug.com/16059 | 150 // Refer to http://crbug.com/16059 |
160 if (state_ == kStopped) { | 151 if (state_ == kStopped) { |
161 return; | 152 return; |
162 } | 153 } |
163 | 154 |
164 // Don't enqueue an end-of-stream buffer because it has no data, otherwise | 155 // Don't enqueue an end-of-stream buffer because it has no data, otherwise |
165 // discard decoded audio data until we reach our desired seek timestamp. | 156 // discard decoded audio data until we reach our desired seek timestamp. |
166 if (buffer_in->IsEndOfStream()) { | 157 if (buffer->IsEndOfStream()) { |
167 recieved_end_of_stream_ = true; | 158 recieved_end_of_stream_ = true; |
168 | 159 |
169 // Transition to kPlaying if we are currently handling an underflow since no | 160 // Transition to kPlaying if we are currently handling an underflow since no |
170 // more data will be arriving. | 161 // more data will be arriving. |
171 if (state_ == kUnderflow || state_ == kRebuffering) | 162 if (state_ == kUnderflow || state_ == kRebuffering) |
172 state_ = kPlaying; | 163 state_ = kPlaying; |
173 } else if (state_ == kSeeking && !buffer_in->IsEndOfStream() && | 164 } else if (state_ == kSeeking && !buffer->IsEndOfStream() && |
174 (buffer_in->GetTimestamp() + buffer_in->GetDuration()) < | 165 (buffer->GetTimestamp() + buffer->GetDuration()) < |
175 seek_timestamp_) { | 166 seek_timestamp_) { |
176 ScheduleRead_Locked(); | 167 ScheduleRead_Locked(); |
177 } else { | 168 } else { |
178 // Note: Calling this may schedule more reads. | 169 // Note: Calling this may schedule more reads. |
179 algorithm_->EnqueueBuffer(buffer_in); | 170 algorithm_->EnqueueBuffer(buffer); |
180 } | 171 } |
181 | 172 |
182 // Check for our preroll complete condition. | 173 // Check for our preroll complete condition. |
183 if (state_ == kSeeking) { | 174 if (state_ == kSeeking) { |
184 DCHECK(!seek_cb_.is_null()); | 175 DCHECK(!seek_cb_.is_null()); |
185 if (algorithm_->IsQueueFull() || recieved_end_of_stream_) { | 176 if (algorithm_->IsQueueFull() || recieved_end_of_stream_) { |
186 // Transition into paused whether we have data in |algorithm_| or not. | 177 // Transition into paused whether we have data in |algorithm_| or not. |
187 // FillBuffer() will play silence if there's nothing to fill. | 178 // FillBuffer() will play silence if there's nothing to fill. |
188 state_ = kPaused; | 179 state_ = kPaused; |
189 ResetAndRunCB(&seek_cb_, PIPELINE_OK); | 180 ResetAndRunCB(&seek_cb_, PIPELINE_OK); |
190 } | 181 } |
191 } else if (state_ == kPaused && pending_reads_ == 0) { | 182 } else if (state_ == kPaused && !pending_read_) { |
192 // No more pending reads! We're now officially "paused". | 183 // No more pending read! We're now officially "paused". |
193 if (!pause_callback_.is_null()) { | 184 if (!pause_callback_.is_null()) { |
194 pause_callback_.Run(); | 185 pause_callback_.Run(); |
195 pause_callback_.Reset(); | 186 pause_callback_.Reset(); |
196 } | 187 } |
197 } | 188 } |
198 } | 189 } |
199 | 190 |
200 uint32 AudioRendererBase::FillBuffer(uint8* dest, | 191 uint32 AudioRendererBase::FillBuffer(uint8* dest, |
201 uint32 dest_len, | 192 uint32 dest_len, |
202 const base::TimeDelta& playback_delay, | 193 const base::TimeDelta& playback_delay, |
203 bool buffers_empty) { | 194 bool buffers_empty) { |
204 // The timestamp of the last buffer written during the last call to | 195 // The timestamp of the last buffer written during the last call to |
205 // FillBuffer(). | 196 // FillBuffer(). |
206 base::TimeDelta last_fill_buffer_time; | 197 base::TimeDelta last_fill_buffer_time; |
207 size_t dest_written = 0; | 198 size_t dest_written = 0; |
208 { | 199 { |
209 base::AutoLock auto_lock(lock_); | 200 base::AutoLock auto_lock(lock_); |
210 | 201 |
211 if (state_ == kRebuffering && algorithm_->IsQueueFull()) | 202 if (state_ == kRebuffering && algorithm_->IsQueueFull()) |
212 state_ = kPlaying; | 203 state_ = kPlaying; |
213 | 204 |
214 // Mute audio by returning 0 when not playing. | 205 // Mute audio by returning 0 when not playing. |
215 if (state_ != kPlaying) { | 206 if (state_ != kPlaying) { |
216 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of | 207 // TODO(scherkus): To keep the audio hardware busy we write at most 8k of |
217 // zeros. This gets around the tricky situation of pausing and resuming | 208 // zeros. This gets around the tricky situation of pausing and resuming |
218 // the audio IPC layer in Chrome. Ideally, we should return zero and then | 209 // the audio IPC layer in Chrome. Ideally, we should return zero and then |
219 // the subclass can restart the conversation. | 210 // the subclass can restart the conversation. |
211 // | |
212 // This should get handled by the subclass http://crbug.com/106600 | |
220 const uint32 kZeroLength = 8192; | 213 const uint32 kZeroLength = 8192; |
221 dest_written = std::min(kZeroLength, dest_len); | 214 dest_written = std::min(kZeroLength, dest_len); |
222 memset(dest, 0, dest_written); | 215 memset(dest, 0, dest_written); |
223 return dest_written; | 216 return dest_written; |
224 } | 217 } |
225 | 218 |
226 // Save a local copy of last fill buffer time and reset the member. | 219 // Save a local copy of last fill buffer time and reset the member. |
227 last_fill_buffer_time = last_fill_buffer_time_; | 220 last_fill_buffer_time = last_fill_buffer_time_; |
228 last_fill_buffer_time_ = base::TimeDelta(); | 221 last_fill_buffer_time_ = base::TimeDelta(); |
229 | 222 |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
268 // finer time update events. | 261 // finer time update events. |
269 last_fill_buffer_time -= playback_delay; | 262 last_fill_buffer_time -= playback_delay; |
270 host()->SetTime(last_fill_buffer_time); | 263 host()->SetTime(last_fill_buffer_time); |
271 } | 264 } |
272 | 265 |
273 return dest_written; | 266 return dest_written; |
274 } | 267 } |
275 | 268 |
276 void AudioRendererBase::ScheduleRead_Locked() { | 269 void AudioRendererBase::ScheduleRead_Locked() { |
277 lock_.AssertAcquired(); | 270 lock_.AssertAcquired(); |
278 if (pending_reads_ < kMaxPendingReads) { | 271 if (pending_read_) |
279 ++pending_reads_; | 272 return; |
280 // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to | 273 pending_read_ = true; |
281 // provide buffer pools. In the future, we may want to implement real | 274 decoder_->Read(read_cb_); |
282 // buffer pool to recycle buffers. | |
283 scoped_refptr<Buffer> buffer; | |
284 decoder_->ProduceAudioSamples(buffer); | |
285 } | |
286 } | 275 } |
287 | 276 |
288 void AudioRendererBase::SetPlaybackRate(float playback_rate) { | 277 void AudioRendererBase::SetPlaybackRate(float playback_rate) { |
289 algorithm_->set_playback_rate(playback_rate); | 278 algorithm_->set_playback_rate(playback_rate); |
290 } | 279 } |
291 | 280 |
292 float AudioRendererBase::GetPlaybackRate() { | 281 float AudioRendererBase::GetPlaybackRate() { |
293 return algorithm_->playback_rate(); | 282 return algorithm_->playback_rate(); |
294 } | 283 } |
295 | 284 |
296 } // namespace media | 285 } // namespace media |
OLD | NEW |