Chromium Code Reviews| 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::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 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::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 Loading... | |
| 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 |
| OLD | NEW |