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

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: Address CR comments and added VideoRendererBase & FFmpegVideoDecoder unit tests. 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
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 break;
Ami GONE FROM CHROMIUM 2012/01/29 22:12:38 s/break/return/ here and everywhere below, for uni
acolwell GONE FROM CHROMIUM 2012/01/30 00:14:14 Done.
158 161 case kPaused:
159 // Transition to kPlaying if we are currently handling an underflow since no 162 EnqueueBuffer(buffer);
160 // more data will be arriving. 163 DCHECK(!pending_read_);
161 if (state_ == kUnderflow || state_ == kRebuffering) 164 ResetAndRunCB(&pause_callback_);
Ami GONE FROM CHROMIUM 2012/01/29 22:12:38 Before your CL the code could handle receiving mul
acolwell GONE FROM CHROMIUM 2012/01/30 00:14:14 That was because algorithm->EnqueueBuffer() could
162 state_ = kPlaying; 165 break;
163 } else if (state_ == kSeeking && !buffer->IsEndOfStream() && 166 case kSeeking:
164 (buffer->GetTimestamp() + buffer->GetDuration()) < 167 if (IsBeforeSeekTime(buffer)) {
165 seek_timestamp_) { 168 ScheduleRead_Locked();
166 ScheduleRead_Locked(); 169 return;
167 } else { 170 }
168 // Note: Calling this may schedule more reads. 171 EnqueueBuffer(buffer);
169 algorithm_->EnqueueBuffer(buffer); 172 if (!buffer || buffer->IsEndOfStream() || algorithm_->IsQueueFull()) {
Ami GONE FROM CHROMIUM 2012/01/29 22:12:38 That the first two clauses repeat the test in Enqu
acolwell GONE FROM CHROMIUM 2012/01/30 00:14:14 Removed EB and just put the conditional checks in
170 } 173 state_ = kPaused;
171 174 ResetAndRunCB(&seek_cb_, PIPELINE_OK);
172 // Check for our preroll complete condition. 175 return;
173 if (state_ == kSeeking) { 176 }
174 DCHECK(!seek_cb_.is_null()); 177 break;
175 if (algorithm_->IsQueueFull() || recieved_end_of_stream_) { 178 case kPlaying:
176 // Transition into paused whether we have data in |algorithm_| or not. 179 case kUnderflow:
177 // FillBuffer() will play silence if there's nothing to fill. 180 case kRebuffering:
178 state_ = kPaused; 181 EnqueueBuffer(buffer);
179 ResetAndRunCB(&seek_cb_, PIPELINE_OK); 182 break;
180 } 183 case kStopped:
181 } else if (state_ == kPaused && !pending_read_) { 184 return;
182 // No more pending read! We're now officially "paused".
183 if (!pause_callback_.is_null()) {
184 pause_callback_.Run();
185 pause_callback_.Reset();
186 }
187 } 185 }
188 } 186 }
189 187
190 uint32 AudioRendererBase::FillBuffer(uint8* dest, 188 uint32 AudioRendererBase::FillBuffer(uint8* dest,
191 uint32 dest_len, 189 uint32 dest_len,
192 const base::TimeDelta& playback_delay, 190 const base::TimeDelta& playback_delay,
193 bool buffers_empty) { 191 bool buffers_empty) {
194 // The timestamp of the last buffer written during the last call to 192 // The timestamp of the last buffer written during the last call to
195 // FillBuffer(). 193 // FillBuffer().
196 base::TimeDelta last_fill_buffer_time; 194 base::TimeDelta last_fill_buffer_time;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
264 } 262 }
265 263
266 if (!underflow_cb.is_null()) 264 if (!underflow_cb.is_null())
267 underflow_cb.Run(); 265 underflow_cb.Run();
268 266
269 return dest_written; 267 return dest_written;
270 } 268 }
271 269
272 void AudioRendererBase::ScheduleRead_Locked() { 270 void AudioRendererBase::ScheduleRead_Locked() {
273 lock_.AssertAcquired(); 271 lock_.AssertAcquired();
274 if (pending_read_) 272 if (pending_read_ || state_ == kPaused)
275 return; 273 return;
276 pending_read_ = true; 274 pending_read_ = true;
277 decoder_->Read(read_cb_); 275 decoder_->Read(read_cb_);
278 } 276 }
279 277
280 void AudioRendererBase::SetPlaybackRate(float playback_rate) { 278 void AudioRendererBase::SetPlaybackRate(float playback_rate) {
281 base::AutoLock auto_lock(lock_); 279 base::AutoLock auto_lock(lock_);
282 algorithm_->SetPlaybackRate(playback_rate); 280 algorithm_->SetPlaybackRate(playback_rate);
283 } 281 }
284 282
285 float AudioRendererBase::GetPlaybackRate() { 283 float AudioRendererBase::GetPlaybackRate() {
286 base::AutoLock auto_lock(lock_); 284 base::AutoLock auto_lock(lock_);
287 return algorithm_->playback_rate(); 285 return algorithm_->playback_rate();
288 } 286 }
289 287
288 bool AudioRendererBase::IsBeforeSeekTime(const scoped_refptr<Buffer>& buffer) {
289 return (state_ == kSeeking) && buffer && !buffer->IsEndOfStream() &&
290 (buffer->GetTimestamp() + buffer->GetDuration()) < seek_timestamp_;
291 }
292
293 void AudioRendererBase::EnqueueBuffer(const scoped_refptr<Buffer>& buffer) {
294 if (buffer && !buffer->IsEndOfStream())
295 algorithm_->EnqueueBuffer(buffer);
296 }
297
290 } // namespace media 298 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698