f08ef83b418a5fb97808f973c9428ee899243817
[platform/framework/web/crosswalk.git] / src / media / filters / audio_renderer_impl.cc
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
3 // found in the LICENSE file.
4
5 #include "media/filters/audio_renderer_impl.h"
6
7 #include <math.h>
8
9 #include <algorithm>
10
11 #include "base/bind.h"
12 #include "base/callback.h"
13 #include "base/callback_helpers.h"
14 #include "base/logging.h"
15 #include "base/metrics/histogram.h"
16 #include "base/single_thread_task_runner.h"
17 #include "media/base/audio_buffer.h"
18 #include "media/base/audio_splicer.h"
19 #include "media/base/bind_to_current_loop.h"
20 #include "media/base/demuxer_stream.h"
21 #include "media/filters/decrypting_demuxer_stream.h"
22
23 namespace media {
24
25 namespace {
26
27 enum AudioRendererEvent {
28   INITIALIZED,
29   RENDER_ERROR,
30   MAX_EVENTS
31 };
32
33 void HistogramRendererEvent(AudioRendererEvent event) {
34   UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererEvents", event, MAX_EVENTS);
35 }
36
37 }  // namespace
38
39 AudioRendererImpl::AudioRendererImpl(
40     const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
41     media::AudioRendererSink* sink,
42     ScopedVector<AudioDecoder> decoders,
43     const SetDecryptorReadyCB& set_decryptor_ready_cb)
44     : task_runner_(task_runner),
45       weak_factory_(this),
46       sink_(sink),
47       decoder_selector_(new AudioDecoderSelector(
48           task_runner, decoders.Pass(), set_decryptor_ready_cb)),
49       now_cb_(base::Bind(&base::TimeTicks::Now)),
50       state_(kUninitialized),
51       sink_playing_(false),
52       pending_read_(false),
53       received_end_of_stream_(false),
54       rendered_end_of_stream_(false),
55       audio_time_buffered_(kNoTimestamp()),
56       current_time_(kNoTimestamp()),
57       underflow_disabled_(false),
58       preroll_aborted_(false) {
59 }
60
61 AudioRendererImpl::~AudioRendererImpl() {
62   // Stop() should have been called and |algorithm_| should have been destroyed.
63   DCHECK(state_ == kUninitialized || state_ == kStopped);
64   DCHECK(!algorithm_.get());
65 }
66
67 void AudioRendererImpl::Play(const base::Closure& callback) {
68   DCHECK(task_runner_->BelongsToCurrentThread());
69
70   base::AutoLock auto_lock(lock_);
71   DCHECK_EQ(state_, kPaused);
72   ChangeState_Locked(kPlaying);
73   callback.Run();
74   earliest_end_time_ = now_cb_.Run();
75
76   if (algorithm_->playback_rate() != 0)
77     DoPlay_Locked();
78   else
79     DCHECK(!sink_playing_);
80 }
81
82 void AudioRendererImpl::DoPlay_Locked() {
83   DCHECK(task_runner_->BelongsToCurrentThread());
84   lock_.AssertAcquired();
85   earliest_end_time_ = now_cb_.Run();
86
87   if ((state_ == kPlaying || state_ == kRebuffering || state_ == kUnderflow) &&
88       !sink_playing_) {
89     {
90       base::AutoUnlock auto_unlock(lock_);
91       sink_->Play();
92     }
93
94     sink_playing_ = true;
95   }
96 }
97
98 void AudioRendererImpl::Pause(const base::Closure& callback) {
99   DCHECK(task_runner_->BelongsToCurrentThread());
100
101   base::AutoLock auto_lock(lock_);
102   DCHECK(state_ == kPlaying || state_ == kUnderflow ||
103          state_ == kRebuffering) << "state_ == " << state_;
104   ChangeState_Locked(kPaused);
105
106   DoPause_Locked();
107
108   callback.Run();
109 }
110
111 void AudioRendererImpl::DoPause_Locked() {
112   DCHECK(task_runner_->BelongsToCurrentThread());
113   lock_.AssertAcquired();
114
115   if (sink_playing_) {
116     {
117       base::AutoUnlock auto_unlock(lock_);
118       sink_->Pause();
119     }
120     sink_playing_ = false;
121   }
122 }
123
124 void AudioRendererImpl::Flush(const base::Closure& callback) {
125   DCHECK(task_runner_->BelongsToCurrentThread());
126
127   base::AutoLock auto_lock(lock_);
128   DCHECK_EQ(state_, kPaused);
129   DCHECK(flush_cb_.is_null());
130
131   flush_cb_ = callback;
132
133   if (pending_read_) {
134     ChangeState_Locked(kFlushing);
135     return;
136   }
137
138   DoFlush_Locked();
139 }
140
141 void AudioRendererImpl::DoFlush_Locked() {
142   DCHECK(task_runner_->BelongsToCurrentThread());
143   lock_.AssertAcquired();
144
145   DCHECK(!pending_read_);
146   DCHECK_EQ(state_, kPaused);
147
148   if (decrypting_demuxer_stream_) {
149     decrypting_demuxer_stream_->Reset(
150         base::Bind(&AudioRendererImpl::ResetDecoder, weak_this_));
151     return;
152   }
153
154   ResetDecoder();
155 }
156
157 void AudioRendererImpl::ResetDecoder() {
158   DCHECK(task_runner_->BelongsToCurrentThread());
159   decoder_->Reset(base::Bind(&AudioRendererImpl::ResetDecoderDone, weak_this_));
160 }
161
162 void AudioRendererImpl::ResetDecoderDone() {
163   DCHECK(task_runner_->BelongsToCurrentThread());
164   {
165     base::AutoLock auto_lock(lock_);
166     if (state_ == kStopped)
167       return;
168
169     DCHECK_EQ(state_, kPaused);
170     DCHECK(!flush_cb_.is_null());
171
172     audio_time_buffered_ = kNoTimestamp();
173     current_time_ = kNoTimestamp();
174     received_end_of_stream_ = false;
175     rendered_end_of_stream_ = false;
176     preroll_aborted_ = false;
177
178     earliest_end_time_ = now_cb_.Run();
179     splicer_->Reset();
180     algorithm_->FlushBuffers();
181   }
182   base::ResetAndReturn(&flush_cb_).Run();
183 }
184
185 void AudioRendererImpl::Stop(const base::Closure& callback) {
186   DCHECK(task_runner_->BelongsToCurrentThread());
187   DCHECK(!callback.is_null());
188   DCHECK(stop_cb_.is_null());
189
190   stop_cb_ = callback;
191
192   // TODO(scherkus): Consider invalidating |weak_factory_| and replacing
193   // task-running guards that check |state_| with DCHECK().
194
195   {
196     base::AutoLock auto_lock(lock_);
197     if (state_ == kInitializing) {
198       decoder_selector_->Abort();
199       return;
200     }
201
202     if (state_ == kStopped) {
203       task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
204       return;
205     }
206
207     ChangeState_Locked(kStopped);
208     algorithm_.reset();
209     underflow_cb_.Reset();
210     time_cb_.Reset();
211     flush_cb_.Reset();
212   }
213
214   if (sink_) {
215     sink_->Stop();
216     sink_ = NULL;
217   }
218
219   if (decoder_) {
220     decoder_->Stop(base::ResetAndReturn(&stop_cb_));
221     return;
222   }
223
224   task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
225 }
226
227 void AudioRendererImpl::Preroll(base::TimeDelta time,
228                                 const PipelineStatusCB& cb) {
229   DCHECK(task_runner_->BelongsToCurrentThread());
230
231   base::AutoLock auto_lock(lock_);
232   DCHECK(!sink_playing_);
233   DCHECK_EQ(state_, kPaused);
234   DCHECK(!pending_read_) << "Pending read must complete before seeking";
235   DCHECK(preroll_cb_.is_null());
236
237   ChangeState_Locked(kPrerolling);
238   preroll_cb_ = cb;
239   preroll_timestamp_ = time;
240
241   AttemptRead_Locked();
242 }
243
244 void AudioRendererImpl::Initialize(DemuxerStream* stream,
245                                    const PipelineStatusCB& init_cb,
246                                    const StatisticsCB& statistics_cb,
247                                    const base::Closure& underflow_cb,
248                                    const TimeCB& time_cb,
249                                    const base::Closure& ended_cb,
250                                    const base::Closure& disabled_cb,
251                                    const PipelineStatusCB& error_cb) {
252   DCHECK(task_runner_->BelongsToCurrentThread());
253   DCHECK(stream);
254   DCHECK_EQ(stream->type(), DemuxerStream::AUDIO);
255   DCHECK(!init_cb.is_null());
256   DCHECK(!statistics_cb.is_null());
257   DCHECK(!underflow_cb.is_null());
258   DCHECK(!time_cb.is_null());
259   DCHECK(!ended_cb.is_null());
260   DCHECK(!disabled_cb.is_null());
261   DCHECK(!error_cb.is_null());
262   DCHECK_EQ(kUninitialized, state_);
263   DCHECK(sink_);
264
265   state_ = kInitializing;
266
267   weak_this_ = weak_factory_.GetWeakPtr();
268   init_cb_ = init_cb;
269   statistics_cb_ = statistics_cb;
270   underflow_cb_ = underflow_cb;
271   time_cb_ = time_cb;
272   ended_cb_ = ended_cb;
273   disabled_cb_ = disabled_cb;
274   error_cb_ = error_cb;
275
276   decoder_selector_->SelectDecoder(
277       stream,
278       statistics_cb,
279       base::Bind(&AudioRendererImpl::OnDecoderSelected, weak_this_));
280 }
281
282 void AudioRendererImpl::OnDecoderSelected(
283     scoped_ptr<AudioDecoder> decoder,
284     scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) {
285   DCHECK(task_runner_->BelongsToCurrentThread());
286
287   scoped_ptr<AudioDecoderSelector> deleter(decoder_selector_.Pass());
288
289   if (!decoder) {
290     {
291       base::AutoLock auto_lock(lock_);
292       ChangeState_Locked(kUninitialized);
293     }
294     // Stop() called during initialization.
295     if (!stop_cb_.is_null()) {
296       base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
297       Stop(base::ResetAndReturn(&stop_cb_));
298     } else {
299       base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
300     }
301     return;
302   }
303
304   base::AutoLock auto_lock(lock_);
305   decoder_ = decoder.Pass();
306   decrypting_demuxer_stream_ = decrypting_demuxer_stream.Pass();
307
308   int sample_rate = decoder_->samples_per_second();
309
310   // The actual buffer size is controlled via the size of the AudioBus
311   // provided to Render(), so just choose something reasonable here for looks.
312   int buffer_size = decoder_->samples_per_second() / 100;
313   audio_parameters_ = AudioParameters(
314       AudioParameters::AUDIO_PCM_LOW_LATENCY, decoder_->channel_layout(),
315       sample_rate, decoder_->bits_per_channel(), buffer_size);
316   if (!audio_parameters_.IsValid()) {
317     ChangeState_Locked(kUninitialized);
318     base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
319     return;
320   }
321
322   splicer_.reset(new AudioSplicer(sample_rate));
323
324   // We're all good! Continue initializing the rest of the audio renderer
325   // based on the decoder format.
326   algorithm_.reset(new AudioRendererAlgorithm());
327   algorithm_->Initialize(0, audio_parameters_);
328
329   ChangeState_Locked(kPaused);
330
331   HistogramRendererEvent(INITIALIZED);
332
333   {
334     base::AutoUnlock auto_unlock(lock_);
335     sink_->Initialize(audio_parameters_, weak_this_.get());
336     sink_->Start();
337
338     // Some sinks play on start...
339     sink_->Pause();
340   }
341
342   DCHECK(!sink_playing_);
343
344   base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
345 }
346
347 void AudioRendererImpl::ResumeAfterUnderflow() {
348   DCHECK(task_runner_->BelongsToCurrentThread());
349   base::AutoLock auto_lock(lock_);
350   if (state_ == kUnderflow) {
351     // The "!preroll_aborted_" is a hack. If preroll is aborted, then we
352     // shouldn't even reach the kUnderflow state to begin with. But for now
353     // we're just making sure that the audio buffer capacity (i.e. the
354     // number of bytes that need to be buffered for preroll to complete)
355     // does not increase due to an aborted preroll.
356     // TODO(vrk): Fix this bug correctly! (crbug.com/151352)
357     if (!preroll_aborted_)
358       algorithm_->IncreaseQueueCapacity();
359
360     ChangeState_Locked(kRebuffering);
361   }
362 }
363
364 void AudioRendererImpl::SetVolume(float volume) {
365   DCHECK(task_runner_->BelongsToCurrentThread());
366   DCHECK(sink_);
367   sink_->SetVolume(volume);
368 }
369
370 void AudioRendererImpl::DecodedAudioReady(
371     AudioDecoder::Status status,
372     const scoped_refptr<AudioBuffer>& buffer) {
373   DVLOG(1) << __FUNCTION__ << "(" << status << ")";
374   DCHECK(task_runner_->BelongsToCurrentThread());
375
376   base::AutoLock auto_lock(lock_);
377   DCHECK(state_ != kUninitialized);
378
379   CHECK(pending_read_);
380   pending_read_ = false;
381
382   if (status == AudioDecoder::kAborted) {
383     HandleAbortedReadOrDecodeError(false);
384     return;
385   }
386
387   if (status == AudioDecoder::kDecodeError) {
388     HandleAbortedReadOrDecodeError(true);
389     return;
390   }
391
392   DCHECK_EQ(status, AudioDecoder::kOk);
393   DCHECK(buffer.get());
394
395   if (state_ == kFlushing) {
396     ChangeState_Locked(kPaused);
397     DoFlush_Locked();
398     return;
399   }
400
401   if (!splicer_->AddInput(buffer)) {
402     HandleAbortedReadOrDecodeError(true);
403     return;
404   }
405
406   if (!splicer_->HasNextBuffer()) {
407     AttemptRead_Locked();
408     return;
409   }
410
411   bool need_another_buffer = false;
412   while (splicer_->HasNextBuffer())
413     need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer());
414
415   if (!need_another_buffer && !CanRead_Locked())
416     return;
417
418   AttemptRead_Locked();
419 }
420
421 bool AudioRendererImpl::HandleSplicerBuffer(
422     const scoped_refptr<AudioBuffer>& buffer) {
423   if (buffer->end_of_stream()) {
424     received_end_of_stream_ = true;
425
426     // Transition to kPlaying if we are currently handling an underflow since
427     // no more data will be arriving.
428     if (state_ == kUnderflow || state_ == kRebuffering)
429       ChangeState_Locked(kPlaying);
430   } else {
431     if (state_ == kPrerolling) {
432       if (IsBeforePrerollTime(buffer))
433         return true;
434
435       // Trim off any additional time before the preroll timestamp.
436       const base::TimeDelta trim_time =
437           preroll_timestamp_ - buffer->timestamp();
438       if (trim_time > base::TimeDelta()) {
439         buffer->TrimStart(buffer->frame_count() *
440                           (static_cast<double>(trim_time.InMicroseconds()) /
441                            buffer->duration().InMicroseconds()));
442       }
443       // If the entire buffer was trimmed, request a new one.
444       if (!buffer->frame_count())
445         return true;
446     }
447
448     if (state_ != kUninitialized && state_ != kStopped)
449       algorithm_->EnqueueBuffer(buffer);
450   }
451
452   switch (state_) {
453     case kUninitialized:
454     case kInitializing:
455     case kFlushing:
456       NOTREACHED();
457       return false;
458
459     case kPaused:
460       DCHECK(!pending_read_);
461       return false;
462
463     case kPrerolling:
464       if (!buffer->end_of_stream() && !algorithm_->IsQueueFull())
465         return true;
466       ChangeState_Locked(kPaused);
467       base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK);
468       return false;
469
470     case kPlaying:
471     case kUnderflow:
472       return false;
473
474     case kRebuffering:
475       if (!algorithm_->IsQueueFull())
476         return true;
477       ChangeState_Locked(kPlaying);
478       return false;
479
480     case kStopped:
481       return false;
482   }
483   return false;
484 }
485
486 void AudioRendererImpl::AttemptRead() {
487   base::AutoLock auto_lock(lock_);
488   AttemptRead_Locked();
489 }
490
491 void AudioRendererImpl::AttemptRead_Locked() {
492   DCHECK(task_runner_->BelongsToCurrentThread());
493   lock_.AssertAcquired();
494
495   if (!CanRead_Locked())
496     return;
497
498   pending_read_ = true;
499   decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, weak_this_));
500 }
501
502 bool AudioRendererImpl::CanRead_Locked() {
503   lock_.AssertAcquired();
504
505   switch (state_) {
506     case kUninitialized:
507     case kInitializing:
508     case kPaused:
509     case kFlushing:
510     case kStopped:
511       return false;
512
513     case kPrerolling:
514     case kPlaying:
515     case kUnderflow:
516     case kRebuffering:
517       break;
518   }
519
520   return !pending_read_ && !received_end_of_stream_ &&
521       !algorithm_->IsQueueFull();
522 }
523
524 void AudioRendererImpl::SetPlaybackRate(float playback_rate) {
525   DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")";
526   DCHECK(task_runner_->BelongsToCurrentThread());
527   DCHECK_GE(playback_rate, 0);
528   DCHECK(sink_);
529
530   base::AutoLock auto_lock(lock_);
531
532   // We have two cases here:
533   // Play: current_playback_rate == 0 && playback_rate != 0
534   // Pause: current_playback_rate != 0 && playback_rate == 0
535   float current_playback_rate = algorithm_->playback_rate();
536   if (current_playback_rate == 0 && playback_rate != 0)
537     DoPlay_Locked();
538   else if (current_playback_rate != 0 && playback_rate == 0)
539     DoPause_Locked();
540
541   algorithm_->SetPlaybackRate(playback_rate);
542 }
543
544 bool AudioRendererImpl::IsBeforePrerollTime(
545     const scoped_refptr<AudioBuffer>& buffer) {
546   DCHECK_EQ(state_, kPrerolling);
547   return buffer && !buffer->end_of_stream() &&
548          (buffer->timestamp() + buffer->duration()) < preroll_timestamp_;
549 }
550
551 int AudioRendererImpl::Render(AudioBus* audio_bus,
552                               int audio_delay_milliseconds) {
553   const int requested_frames = audio_bus->frames();
554   base::TimeDelta current_time = kNoTimestamp();
555   base::TimeDelta max_time = kNoTimestamp();
556   base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds(
557       audio_delay_milliseconds);
558
559   int frames_written = 0;
560   base::Closure underflow_cb;
561   {
562     base::AutoLock auto_lock(lock_);
563
564     // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
565     if (!algorithm_)
566       return 0;
567
568     float playback_rate = algorithm_->playback_rate();
569     if (playback_rate == 0)
570       return 0;
571
572     // Mute audio by returning 0 when not playing.
573     if (state_ != kPlaying)
574       return 0;
575
576     // We use the following conditions to determine end of playback:
577     //   1) Algorithm can not fill the audio callback buffer
578     //   2) We received an end of stream buffer
579     //   3) We haven't already signalled that we've ended
580     //   4) Our estimated earliest end time has expired
581     //
582     // TODO(enal): we should replace (4) with a check that the browser has no
583     // more audio data or at least use a delayed callback.
584     //
585     // We use the following conditions to determine underflow:
586     //   1) Algorithm can not fill the audio callback buffer
587     //   2) We have NOT received an end of stream buffer
588     //   3) We are in the kPlaying state
589     //
590     // Otherwise the buffer has data we can send to the device.
591     frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
592     if (frames_written == 0) {
593       const base::TimeTicks now = now_cb_.Run();
594
595       if (received_end_of_stream_ && !rendered_end_of_stream_ &&
596           now >= earliest_end_time_) {
597         rendered_end_of_stream_ = true;
598         ended_cb_.Run();
599       } else if (!received_end_of_stream_ && state_ == kPlaying &&
600                  !underflow_disabled_) {
601         ChangeState_Locked(kUnderflow);
602         underflow_cb = underflow_cb_;
603       } else {
604         // We can't write any data this cycle. For example, we may have
605         // sent all available data to the audio device while not reaching
606         // |earliest_end_time_|.
607       }
608     }
609
610     if (CanRead_Locked()) {
611       task_runner_->PostTask(FROM_HERE, base::Bind(
612           &AudioRendererImpl::AttemptRead, weak_this_));
613     }
614
615     // The |audio_time_buffered_| is the ending timestamp of the last frame
616     // buffered at the audio device. |playback_delay| is the amount of time
617     // buffered at the audio device. The current time can be computed by their
618     // difference.
619     if (audio_time_buffered_ != kNoTimestamp()) {
620       // Adjust the delay according to playback rate.
621       base::TimeDelta adjusted_playback_delay =
622           base::TimeDelta::FromMicroseconds(ceil(
623               playback_delay.InMicroseconds() * playback_rate));
624
625       base::TimeDelta previous_time = current_time_;
626       current_time_ = audio_time_buffered_ - adjusted_playback_delay;
627
628       // Time can change in one of two ways:
629       //   1) The time of the audio data at the audio device changed, or
630       //   2) The playback delay value has changed
631       //
632       // We only want to set |current_time| (and thus execute |time_cb_|) if
633       // time has progressed and we haven't signaled end of stream yet.
634       //
635       // Why? The current latency of the system results in getting the last call
636       // to FillBuffer() later than we'd like, which delays firing the 'ended'
637       // event, which delays the looping/trigging performance of short sound
638       // effects.
639       //
640       // TODO(scherkus): revisit this and switch back to relying on playback
641       // delay after we've revamped our audio IPC subsystem.
642       if (current_time_ > previous_time && !rendered_end_of_stream_) {
643         current_time = current_time_;
644       }
645     }
646
647     // The call to FillBuffer() on |algorithm_| has increased the amount of
648     // buffered audio data. Update the new amount of time buffered.
649     max_time = algorithm_->GetTime();
650     audio_time_buffered_ = max_time;
651
652     if (frames_written > 0) {
653       UpdateEarliestEndTime_Locked(
654           frames_written, playback_delay, now_cb_.Run());
655     }
656   }
657
658   if (current_time != kNoTimestamp() && max_time != kNoTimestamp())
659     time_cb_.Run(current_time, max_time);
660
661   if (!underflow_cb.is_null())
662     underflow_cb.Run();
663
664   DCHECK_LE(frames_written, requested_frames);
665   return frames_written;
666 }
667
668 void AudioRendererImpl::UpdateEarliestEndTime_Locked(
669     int frames_filled, const base::TimeDelta& playback_delay,
670     const base::TimeTicks& time_now) {
671   DCHECK_GT(frames_filled, 0);
672
673   base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds(
674       static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond /
675       audio_parameters_.sample_rate());
676
677   lock_.AssertAcquired();
678   earliest_end_time_ = std::max(
679       earliest_end_time_, time_now + playback_delay + predicted_play_time);
680 }
681
682 void AudioRendererImpl::OnRenderError() {
683   HistogramRendererEvent(RENDER_ERROR);
684   disabled_cb_.Run();
685 }
686
687 void AudioRendererImpl::DisableUnderflowForTesting() {
688   underflow_disabled_ = true;
689 }
690
691 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) {
692   lock_.AssertAcquired();
693
694   PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK;
695   switch (state_) {
696     case kUninitialized:
697     case kInitializing:
698       NOTREACHED();
699       return;
700     case kPaused:
701       if (status != PIPELINE_OK)
702         error_cb_.Run(status);
703       return;
704     case kFlushing:
705       ChangeState_Locked(kPaused);
706
707       if (status == PIPELINE_OK) {
708         DoFlush_Locked();
709         return;
710       }
711
712       error_cb_.Run(status);
713       base::ResetAndReturn(&flush_cb_).Run();
714       return;
715     case kPrerolling:
716       // This is a signal for abort if it's not an error.
717       preroll_aborted_ = !is_decode_error;
718       ChangeState_Locked(kPaused);
719       base::ResetAndReturn(&preroll_cb_).Run(status);
720       return;
721     case kPlaying:
722     case kUnderflow:
723     case kRebuffering:
724     case kStopped:
725       if (status != PIPELINE_OK)
726         error_cb_.Run(status);
727       return;
728   }
729 }
730
731 void AudioRendererImpl::ChangeState_Locked(State new_state) {
732   DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state;
733   lock_.AssertAcquired();
734   state_ = new_state;
735 }
736
737 }  // namespace media