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

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

Issue 9295020: Fix ChunkDemuxer seek deadlock (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix copyright year. Created 8 years, 10 months 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) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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"
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
60 } 60 }
61 if (!callback.is_null()) { 61 if (!callback.is_null()) {
62 callback.Run(); 62 callback.Run();
63 } 63 }
64 } 64 }
65 65
66 void AudioRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) { 66 void AudioRendererBase::Seek(base::TimeDelta time, const FilterStatusCB& cb) {
67 base::AutoLock auto_lock(lock_); 67 base::AutoLock auto_lock(lock_);
68 DCHECK_EQ(kPaused, state_); 68 DCHECK_EQ(kPaused, state_);
69 DCHECK(!pending_read_) << "Pending read must complete before seeking"; 69 DCHECK(!pending_read_) << "Pending read must complete before seeking";
70 DCHECK(pause_callback_.is_null());
70 DCHECK(seek_cb_.is_null()); 71 DCHECK(seek_cb_.is_null());
71 state_ = kSeeking; 72 state_ = kSeeking;
72 seek_cb_ = cb; 73 seek_cb_ = cb;
73 seek_timestamp_ = time; 74 seek_timestamp_ = time;
74 75
75 // Throw away everything and schedule our reads. 76 // Throw away everything and schedule our reads.
76 last_fill_buffer_time_ = base::TimeDelta(); 77 last_fill_buffer_time_ = base::TimeDelta();
77 recieved_end_of_stream_ = false; 78 recieved_end_of_stream_ = false;
78 rendered_end_of_stream_ = false; 79 rendered_end_of_stream_ = false;
79 80
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
137 } 138 }
138 139
139 void AudioRendererBase::DecodedAudioReady(scoped_refptr<Buffer> buffer) { 140 void AudioRendererBase::DecodedAudioReady(scoped_refptr<Buffer> buffer) {
140 base::AutoLock auto_lock(lock_); 141 base::AutoLock auto_lock(lock_);
141 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying || 142 DCHECK(state_ == kPaused || state_ == kSeeking || state_ == kPlaying ||
142 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped); 143 state_ == kUnderflow || state_ == kRebuffering || state_ == kStopped);
143 144
144 CHECK(pending_read_); 145 CHECK(pending_read_);
145 pending_read_ = false; 146 pending_read_ = false;
146 147
147 // TODO(scherkus): this happens due to a race, primarily because Stop() is a 148 if (buffer && buffer->IsEndOfStream()) {
148 // synchronous call when it should be asynchronous and accept a callback. 149 recieved_end_of_stream_ = true;
149 // Refer to http://crbug.com/16059 150
150 if (state_ == kStopped) { 151 // Transition to kPlaying if we are currently handling an underflow since
151 return; 152 // no more data will be arriving.
153 if (state_ == kUnderflow || state_ == kRebuffering)
154 state_ = kPlaying;
152 } 155 }
153 156
154 // Don't enqueue an end-of-stream buffer because it has no data, otherwise 157 switch (state_) {
155 // discard decoded audio data until we reach our desired seek timestamp. 158 case kUninitialized:
156 if (buffer->IsEndOfStream()) { 159 NOTREACHED();
157 recieved_end_of_stream_ = true; 160 return;
158 161 case kPaused:
159 // Transition to kPlaying if we are currently handling an underflow since no 162 if (buffer && !buffer->IsEndOfStream())
160 // more data will be arriving. 163 algorithm_->EnqueueBuffer(buffer);
161 if (state_ == kUnderflow || state_ == kRebuffering) 164 DCHECK(!pending_read_);
162 state_ = kPlaying; 165 ResetAndRunCB(&pause_callback_);
163 } else if (state_ == kSeeking && !buffer->IsEndOfStream() && 166 return;
164 (buffer->GetTimestamp() + buffer->GetDuration()) < 167 case kSeeking:
165 seek_timestamp_) { 168 if (IsBeforeSeekTime(buffer)) {
166 ScheduleRead_Locked(); 169 ScheduleRead_Locked();
167 } else { 170 return;
168 // Note: Calling this may schedule more reads. 171 }
169 algorithm_->EnqueueBuffer(buffer); 172 if (buffer && !buffer->IsEndOfStream()) {
170 } 173 algorithm_->EnqueueBuffer(buffer);
171 174 if (!algorithm_->IsQueueFull())
172 // Check for our preroll complete condition. 175 return;
173 if (state_ == kSeeking) { 176 }
174 DCHECK(!seek_cb_.is_null());
175 if (algorithm_->IsQueueFull() || recieved_end_of_stream_) {
176 // Transition into paused whether we have data in |algorithm_| or not.
177 // FillBuffer() will play silence if there's nothing to fill.
178 state_ = kPaused; 177 state_ = kPaused;
179 ResetAndRunCB(&seek_cb_, PIPELINE_OK); 178 ResetAndRunCB(&seek_cb_, PIPELINE_OK);
180 } 179 return;
181 } else if (state_ == kPaused && !pending_read_) { 180 case kPlaying:
182 // No more pending read! We're now officially "paused". 181 case kUnderflow:
183 if (!pause_callback_.is_null()) { 182 case kRebuffering:
184 pause_callback_.Run(); 183 if (buffer && !buffer->IsEndOfStream())
185 pause_callback_.Reset(); 184 algorithm_->EnqueueBuffer(buffer);
186 } 185 return;
186 case kStopped:
187 return;
187 } 188 }
188 } 189 }
189 190
190 uint32 AudioRendererBase::FillBuffer(uint8* dest, 191 uint32 AudioRendererBase::FillBuffer(uint8* dest,
191 uint32 dest_len, 192 uint32 dest_len,
192 const base::TimeDelta& playback_delay) { 193 const base::TimeDelta& playback_delay) {
193 // 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
194 // FillBuffer(). 195 // FillBuffer().
195 base::TimeDelta last_fill_buffer_time; 196 base::TimeDelta last_fill_buffer_time;
196 size_t dest_written = 0; 197 size_t dest_written = 0;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
271 void AudioRendererBase::SignalEndOfStream() { 272 void AudioRendererBase::SignalEndOfStream() {
272 DCHECK(recieved_end_of_stream_); 273 DCHECK(recieved_end_of_stream_);
273 if (!rendered_end_of_stream_) { 274 if (!rendered_end_of_stream_) {
274 rendered_end_of_stream_ = true; 275 rendered_end_of_stream_ = true;
275 host()->NotifyEnded(); 276 host()->NotifyEnded();
276 } 277 }
277 } 278 }
278 279
279 void AudioRendererBase::ScheduleRead_Locked() { 280 void AudioRendererBase::ScheduleRead_Locked() {
280 lock_.AssertAcquired(); 281 lock_.AssertAcquired();
281 if (pending_read_) 282 if (pending_read_ || state_ == kPaused)
282 return; 283 return;
283 pending_read_ = true; 284 pending_read_ = true;
284 decoder_->Read(read_cb_); 285 decoder_->Read(read_cb_);
285 } 286 }
286 287
287 void AudioRendererBase::SetPlaybackRate(float playback_rate) { 288 void AudioRendererBase::SetPlaybackRate(float playback_rate) {
288 base::AutoLock auto_lock(lock_); 289 base::AutoLock auto_lock(lock_);
289 algorithm_->SetPlaybackRate(playback_rate); 290 algorithm_->SetPlaybackRate(playback_rate);
290 } 291 }
291 292
292 float AudioRendererBase::GetPlaybackRate() { 293 float AudioRendererBase::GetPlaybackRate() {
293 base::AutoLock auto_lock(lock_); 294 base::AutoLock auto_lock(lock_);
294 return algorithm_->playback_rate(); 295 return algorithm_->playback_rate();
295 } 296 }
296 297
298 bool AudioRendererBase::IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer) {
299 return (state_ == kSeeking) && buffer && !buffer->IsEndOfStream() &&
300 (buffer->GetTimestamp() + buffer->GetDuration()) < seek_timestamp_;
301 }
302
297 } // namespace media 303 } // 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