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

Side by Side Diff: media/filters/audio_renderer_base.cc

Issue 8763010: Replace AudioDecoder::ProduceAudioSamples/ConsumeAudioSamples with read callbacks. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: comments Created 9 years 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 "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
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
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698