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

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: fix mac tests 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
« no previous file with comments | « media/filters/audio_renderer_base.h ('k') | media/filters/audio_renderer_base_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 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
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
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
OLDNEW
« no previous file with comments | « media/filters/audio_renderer_base.h ('k') | media/filters/audio_renderer_base_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698