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

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: 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::SamplesReady,
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 reads 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::SamplesReady(scoped_refptr<Buffer> samples) {
vrk (LEFT CHROMIUM) 2011/12/03 03:10:17 Not sure why SamplesReady/samples is plural? Looks
scherkus (not reviewing) 2011/12/07 05:25:12 Changed to DecodedAudioReady() which I hope will b
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);
151 DCHECK_GT(pending_reads_, 0u); 144 DCHECK(pending_read_);
152 --pending_reads_; 145 pending_read_ = false;
153 146
154 // 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
155 // synchronous call when it should be asynchronous and accept a callback. 148 // synchronous call when it should be asynchronous and accept a callback.
156 // Refer to http://crbug.com/16059 149 // Refer to http://crbug.com/16059
157 if (state_ == kStopped) { 150 if (state_ == kStopped) {
158 return; 151 return;
159 } 152 }
160 153
161 // 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
162 // discard decoded audio data until we reach our desired seek timestamp. 155 // discard decoded audio data until we reach our desired seek timestamp.
163 if (buffer_in->IsEndOfStream()) { 156 if (samples->IsEndOfStream()) {
164 recieved_end_of_stream_ = true; 157 recieved_end_of_stream_ = true;
165 158
166 // 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
167 // more data will be arriving. 160 // more data will be arriving.
168 if (state_ == kUnderflow || state_ == kRebuffering) 161 if (state_ == kUnderflow || state_ == kRebuffering)
169 state_ = kPlaying; 162 state_ = kPlaying;
170 } else if (state_ == kSeeking && !buffer_in->IsEndOfStream() && 163 } else if (state_ == kSeeking && !samples->IsEndOfStream() &&
171 (buffer_in->GetTimestamp() + buffer_in->GetDuration()) < 164 (samples->GetTimestamp() + samples->GetDuration()) <
172 seek_timestamp_) { 165 seek_timestamp_) {
173 ScheduleRead_Locked(); 166 ScheduleRead_Locked();
174 } else { 167 } else {
175 // Note: Calling this may schedule more reads. 168 // Note: Calling this may schedule more reads.
176 algorithm_->EnqueueBuffer(buffer_in); 169 algorithm_->EnqueueBuffer(samples);
177 } 170 }
178 171
179 // Check for our preroll complete condition. 172 // Check for our preroll complete condition.
180 if (state_ == kSeeking) { 173 if (state_ == kSeeking) {
181 DCHECK(!seek_cb_.is_null()); 174 DCHECK(!seek_cb_.is_null());
182 if (algorithm_->IsQueueFull() || recieved_end_of_stream_) { 175 if (algorithm_->IsQueueFull() || recieved_end_of_stream_) {
183 // Transition into paused whether we have data in |algorithm_| or not. 176 // Transition into paused whether we have data in |algorithm_| or not.
184 // FillBuffer() will play silence if there's nothing to fill. 177 // FillBuffer() will play silence if there's nothing to fill.
185 state_ = kPaused; 178 state_ = kPaused;
186 ResetAndRunCB(&seek_cb_, PIPELINE_OK); 179 ResetAndRunCB(&seek_cb_, PIPELINE_OK);
187 } 180 }
188 } else if (state_ == kPaused && pending_reads_ == 0) { 181 } else if (state_ == kPaused && !pending_read_) {
189 // No more pending reads! We're now officially "paused". 182 // No more pending reads! We're now officially "paused".
190 if (!pause_callback_.is_null()) { 183 if (!pause_callback_.is_null()) {
191 pause_callback_.Run(); 184 pause_callback_.Run();
192 pause_callback_.Reset(); 185 pause_callback_.Reset();
193 } 186 }
194 } 187 }
195 } 188 }
196 189
197 uint32 AudioRendererBase::FillBuffer(uint8* dest, 190 uint32 AudioRendererBase::FillBuffer(uint8* dest,
198 uint32 dest_len, 191 uint32 dest_len,
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
265 // finer time update events. 258 // finer time update events.
266 last_fill_buffer_time -= playback_delay; 259 last_fill_buffer_time -= playback_delay;
267 host()->SetTime(last_fill_buffer_time); 260 host()->SetTime(last_fill_buffer_time);
268 } 261 }
269 262
270 return dest_written; 263 return dest_written;
271 } 264 }
272 265
273 void AudioRendererBase::ScheduleRead_Locked() { 266 void AudioRendererBase::ScheduleRead_Locked() {
274 lock_.AssertAcquired(); 267 lock_.AssertAcquired();
275 if (pending_reads_ < kMaxPendingReads) { 268 DCHECK(!pending_read_);
276 ++pending_reads_; 269 pending_read_ = true;
277 // TODO(jiesun): We use dummy buffer to feed decoder to let decoder to 270 decoder_->Read(read_cb_);
vrk (LEFT CHROMIUM) 2011/12/03 03:10:17 nit: Looks like it's unnecessary to make |read_cb_
scherkus (not reviewing) 2011/12/07 05:25:12 somewhat of an optimization to avoid needlessly re
278 // provide buffer pools. In the future, we may want to implement real
279 // buffer pool to recycle buffers.
280 scoped_refptr<Buffer> buffer;
281 decoder_->ProduceAudioSamples(buffer);
282 }
283 } 271 }
284 272
285 void AudioRendererBase::SetPlaybackRate(float playback_rate) { 273 void AudioRendererBase::SetPlaybackRate(float playback_rate) {
286 algorithm_->set_playback_rate(playback_rate); 274 algorithm_->set_playback_rate(playback_rate);
287 } 275 }
288 276
289 float AudioRendererBase::GetPlaybackRate() { 277 float AudioRendererBase::GetPlaybackRate() {
290 return algorithm_->playback_rate(); 278 return algorithm_->playback_rate();
291 } 279 }
292 280
293 } // namespace media 281 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698