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