Media Galleries API Metadata: Enable GetMetadata call and fix bugs
[chromium-blink-merge.git] / media / filters / audio_renderer_impl.cc
bloba102b6e132920943dbb7901cc16130068b358dae
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.
5 #include "media/filters/audio_renderer_impl.h"
7 #include <math.h>
9 #include <algorithm>
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"
23 namespace media {
25 namespace {
27 enum AudioRendererEvent {
28 INITIALIZED,
29 RENDER_ERROR,
30 MAX_EVENTS
33 void HistogramRendererEvent(AudioRendererEvent event) {
34 UMA_HISTOGRAM_ENUMERATION("Media.AudioRendererEvents", event, MAX_EVENTS);
37 } // namespace
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) {
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());
67 void AudioRendererImpl::Play(const base::Closure& callback) {
68 DCHECK(task_runner_->BelongsToCurrentThread());
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();
76 if (algorithm_->playback_rate() != 0)
77 DoPlay_Locked();
78 else
79 DCHECK(!sink_playing_);
82 void AudioRendererImpl::DoPlay_Locked() {
83 DCHECK(task_runner_->BelongsToCurrentThread());
84 lock_.AssertAcquired();
85 earliest_end_time_ = now_cb_.Run();
87 if ((state_ == kPlaying || state_ == kRebuffering || state_ == kUnderflow) &&
88 !sink_playing_) {
90 base::AutoUnlock auto_unlock(lock_);
91 sink_->Play();
94 sink_playing_ = true;
98 void AudioRendererImpl::Pause(const base::Closure& callback) {
99 DCHECK(task_runner_->BelongsToCurrentThread());
101 base::AutoLock auto_lock(lock_);
102 DCHECK(state_ == kPlaying || state_ == kUnderflow ||
103 state_ == kRebuffering) << "state_ == " << state_;
104 ChangeState_Locked(kPaused);
106 DoPause_Locked();
108 callback.Run();
111 void AudioRendererImpl::DoPause_Locked() {
112 DCHECK(task_runner_->BelongsToCurrentThread());
113 lock_.AssertAcquired();
115 if (sink_playing_) {
117 base::AutoUnlock auto_unlock(lock_);
118 sink_->Pause();
120 sink_playing_ = false;
124 void AudioRendererImpl::Flush(const base::Closure& callback) {
125 DCHECK(task_runner_->BelongsToCurrentThread());
127 base::AutoLock auto_lock(lock_);
128 DCHECK_EQ(state_, kPaused);
129 DCHECK(flush_cb_.is_null());
131 flush_cb_ = callback;
133 if (pending_read_) {
134 ChangeState_Locked(kFlushing);
135 return;
138 DoFlush_Locked();
141 void AudioRendererImpl::DoFlush_Locked() {
142 DCHECK(task_runner_->BelongsToCurrentThread());
143 lock_.AssertAcquired();
145 DCHECK(!pending_read_);
146 DCHECK_EQ(state_, kPaused);
148 if (decrypting_demuxer_stream_) {
149 decrypting_demuxer_stream_->Reset(
150 base::Bind(&AudioRendererImpl::ResetDecoder, weak_this_));
151 return;
154 ResetDecoder();
157 void AudioRendererImpl::ResetDecoder() {
158 DCHECK(task_runner_->BelongsToCurrentThread());
159 decoder_->Reset(base::Bind(&AudioRendererImpl::ResetDecoderDone, weak_this_));
162 void AudioRendererImpl::ResetDecoderDone() {
163 DCHECK(task_runner_->BelongsToCurrentThread());
165 base::AutoLock auto_lock(lock_);
166 if (state_ == kStopped)
167 return;
169 DCHECK_EQ(state_, kPaused);
170 DCHECK(!flush_cb_.is_null());
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;
178 earliest_end_time_ = now_cb_.Run();
179 splicer_->Reset();
180 algorithm_->FlushBuffers();
182 base::ResetAndReturn(&flush_cb_).Run();
185 void AudioRendererImpl::Stop(const base::Closure& callback) {
186 DCHECK(task_runner_->BelongsToCurrentThread());
187 DCHECK(!callback.is_null());
188 DCHECK(stop_cb_.is_null());
190 stop_cb_ = callback;
192 // TODO(scherkus): Consider invalidating |weak_factory_| and replacing
193 // task-running guards that check |state_| with DCHECK().
196 base::AutoLock auto_lock(lock_);
197 if (state_ == kInitializing) {
198 decoder_selector_->Abort();
199 return;
202 if (state_ == kStopped) {
203 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
204 return;
207 ChangeState_Locked(kStopped);
208 algorithm_.reset();
209 underflow_cb_.Reset();
210 time_cb_.Reset();
211 flush_cb_.Reset();
214 if (sink_) {
215 sink_->Stop();
216 sink_ = NULL;
219 if (decrypting_demuxer_stream_) {
220 decrypting_demuxer_stream_->Stop(
221 base::Bind(&AudioRendererImpl::StopDecoder, weak_this_));
222 return;
225 StopDecoder();
228 void AudioRendererImpl::StopDecoder() {
229 DCHECK(task_runner_->BelongsToCurrentThread());
230 DCHECK(!stop_cb_.is_null());
232 if (decoder_) {
233 decoder_->Stop(base::ResetAndReturn(&stop_cb_));
234 return;
237 task_runner_->PostTask(FROM_HERE, base::ResetAndReturn(&stop_cb_));
240 void AudioRendererImpl::Preroll(base::TimeDelta time,
241 const PipelineStatusCB& cb) {
242 DCHECK(task_runner_->BelongsToCurrentThread());
244 base::AutoLock auto_lock(lock_);
245 DCHECK(!sink_playing_);
246 DCHECK_EQ(state_, kPaused);
247 DCHECK(!pending_read_) << "Pending read must complete before seeking";
248 DCHECK(preroll_cb_.is_null());
250 ChangeState_Locked(kPrerolling);
251 preroll_cb_ = cb;
252 preroll_timestamp_ = time;
254 AttemptRead_Locked();
257 void AudioRendererImpl::Initialize(DemuxerStream* stream,
258 const PipelineStatusCB& init_cb,
259 const StatisticsCB& statistics_cb,
260 const base::Closure& underflow_cb,
261 const TimeCB& time_cb,
262 const base::Closure& ended_cb,
263 const base::Closure& disabled_cb,
264 const PipelineStatusCB& error_cb) {
265 DCHECK(task_runner_->BelongsToCurrentThread());
266 DCHECK(stream);
267 DCHECK_EQ(stream->type(), DemuxerStream::AUDIO);
268 DCHECK(!init_cb.is_null());
269 DCHECK(!statistics_cb.is_null());
270 DCHECK(!underflow_cb.is_null());
271 DCHECK(!time_cb.is_null());
272 DCHECK(!ended_cb.is_null());
273 DCHECK(!disabled_cb.is_null());
274 DCHECK(!error_cb.is_null());
275 DCHECK_EQ(kUninitialized, state_);
276 DCHECK(sink_);
278 state_ = kInitializing;
280 weak_this_ = weak_factory_.GetWeakPtr();
281 init_cb_ = init_cb;
282 statistics_cb_ = statistics_cb;
283 underflow_cb_ = underflow_cb;
284 time_cb_ = time_cb;
285 ended_cb_ = ended_cb;
286 disabled_cb_ = disabled_cb;
287 error_cb_ = error_cb;
289 decoder_selector_->SelectDecoder(
290 stream,
291 statistics_cb,
292 base::Bind(&AudioRendererImpl::OnDecoderSelected, weak_this_));
295 void AudioRendererImpl::OnDecoderSelected(
296 scoped_ptr<AudioDecoder> decoder,
297 scoped_ptr<DecryptingDemuxerStream> decrypting_demuxer_stream) {
298 DCHECK(task_runner_->BelongsToCurrentThread());
300 scoped_ptr<AudioDecoderSelector> deleter(decoder_selector_.Pass());
301 decoder_ = decoder.Pass();
303 if (!decoder_ || !stop_cb_.is_null()) {
305 base::AutoLock auto_lock(lock_);
306 ChangeState_Locked(kUninitialized);
308 // Stop() called during initialization.
309 if (!stop_cb_.is_null()) {
310 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_ABORT);
311 Stop(base::ResetAndReturn(&stop_cb_));
312 } else {
313 base::ResetAndReturn(&init_cb_).Run(DECODER_ERROR_NOT_SUPPORTED);
315 return;
318 base::AutoLock auto_lock(lock_);
319 decrypting_demuxer_stream_ = decrypting_demuxer_stream.Pass();
321 int sample_rate = decoder_->samples_per_second();
323 // The actual buffer size is controlled via the size of the AudioBus
324 // provided to Render(), so just choose something reasonable here for looks.
325 int buffer_size = decoder_->samples_per_second() / 100;
326 audio_parameters_ = AudioParameters(
327 AudioParameters::AUDIO_PCM_LOW_LATENCY, decoder_->channel_layout(),
328 sample_rate, decoder_->bits_per_channel(), buffer_size);
329 if (!audio_parameters_.IsValid()) {
330 ChangeState_Locked(kUninitialized);
331 base::ResetAndReturn(&init_cb_).Run(PIPELINE_ERROR_INITIALIZATION_FAILED);
332 return;
335 splicer_.reset(new AudioSplicer(sample_rate));
337 // We're all good! Continue initializing the rest of the audio renderer
338 // based on the decoder format.
339 algorithm_.reset(new AudioRendererAlgorithm());
340 algorithm_->Initialize(0, audio_parameters_);
342 ChangeState_Locked(kPaused);
344 HistogramRendererEvent(INITIALIZED);
347 base::AutoUnlock auto_unlock(lock_);
348 sink_->Initialize(audio_parameters_, weak_this_.get());
349 sink_->Start();
351 // Some sinks play on start...
352 sink_->Pause();
355 DCHECK(!sink_playing_);
357 base::ResetAndReturn(&init_cb_).Run(PIPELINE_OK);
360 void AudioRendererImpl::ResumeAfterUnderflow() {
361 DCHECK(task_runner_->BelongsToCurrentThread());
362 base::AutoLock auto_lock(lock_);
363 if (state_ == kUnderflow) {
364 // The "!preroll_aborted_" is a hack. If preroll is aborted, then we
365 // shouldn't even reach the kUnderflow state to begin with. But for now
366 // we're just making sure that the audio buffer capacity (i.e. the
367 // number of bytes that need to be buffered for preroll to complete)
368 // does not increase due to an aborted preroll.
369 // TODO(vrk): Fix this bug correctly! (crbug.com/151352)
370 if (!preroll_aborted_)
371 algorithm_->IncreaseQueueCapacity();
373 ChangeState_Locked(kRebuffering);
377 void AudioRendererImpl::SetVolume(float volume) {
378 DCHECK(task_runner_->BelongsToCurrentThread());
379 DCHECK(sink_);
380 sink_->SetVolume(volume);
383 void AudioRendererImpl::DecodedAudioReady(
384 AudioDecoder::Status status,
385 const scoped_refptr<AudioBuffer>& buffer) {
386 DVLOG(1) << __FUNCTION__ << "(" << status << ")";
387 DCHECK(task_runner_->BelongsToCurrentThread());
389 base::AutoLock auto_lock(lock_);
390 DCHECK(state_ != kUninitialized);
392 CHECK(pending_read_);
393 pending_read_ = false;
395 if (status == AudioDecoder::kAborted) {
396 HandleAbortedReadOrDecodeError(false);
397 return;
400 if (status == AudioDecoder::kDecodeError) {
401 HandleAbortedReadOrDecodeError(true);
402 return;
405 DCHECK_EQ(status, AudioDecoder::kOk);
406 DCHECK(buffer.get());
408 if (state_ == kFlushing) {
409 ChangeState_Locked(kPaused);
410 DoFlush_Locked();
411 return;
414 if (!splicer_->AddInput(buffer)) {
415 HandleAbortedReadOrDecodeError(true);
416 return;
419 if (!splicer_->HasNextBuffer()) {
420 AttemptRead_Locked();
421 return;
424 bool need_another_buffer = false;
425 while (splicer_->HasNextBuffer())
426 need_another_buffer = HandleSplicerBuffer(splicer_->GetNextBuffer());
428 if (!need_another_buffer && !CanRead_Locked())
429 return;
431 AttemptRead_Locked();
434 bool AudioRendererImpl::HandleSplicerBuffer(
435 const scoped_refptr<AudioBuffer>& buffer) {
436 if (buffer->end_of_stream()) {
437 received_end_of_stream_ = true;
439 // Transition to kPlaying if we are currently handling an underflow since
440 // no more data will be arriving.
441 if (state_ == kUnderflow || state_ == kRebuffering)
442 ChangeState_Locked(kPlaying);
443 } else {
444 if (state_ == kPrerolling) {
445 if (IsBeforePrerollTime(buffer))
446 return true;
448 // Trim off any additional time before the preroll timestamp.
449 const base::TimeDelta trim_time =
450 preroll_timestamp_ - buffer->timestamp();
451 if (trim_time > base::TimeDelta()) {
452 buffer->TrimStart(buffer->frame_count() *
453 (static_cast<double>(trim_time.InMicroseconds()) /
454 buffer->duration().InMicroseconds()));
456 // If the entire buffer was trimmed, request a new one.
457 if (!buffer->frame_count())
458 return true;
461 if (state_ != kUninitialized && state_ != kStopped)
462 algorithm_->EnqueueBuffer(buffer);
465 switch (state_) {
466 case kUninitialized:
467 case kInitializing:
468 case kFlushing:
469 NOTREACHED();
470 return false;
472 case kPaused:
473 DCHECK(!pending_read_);
474 return false;
476 case kPrerolling:
477 if (!buffer->end_of_stream() && !algorithm_->IsQueueFull())
478 return true;
479 ChangeState_Locked(kPaused);
480 base::ResetAndReturn(&preroll_cb_).Run(PIPELINE_OK);
481 return false;
483 case kPlaying:
484 case kUnderflow:
485 return false;
487 case kRebuffering:
488 if (!algorithm_->IsQueueFull())
489 return true;
490 ChangeState_Locked(kPlaying);
491 return false;
493 case kStopped:
494 return false;
496 return false;
499 void AudioRendererImpl::AttemptRead() {
500 base::AutoLock auto_lock(lock_);
501 AttemptRead_Locked();
504 void AudioRendererImpl::AttemptRead_Locked() {
505 DCHECK(task_runner_->BelongsToCurrentThread());
506 lock_.AssertAcquired();
508 if (!CanRead_Locked())
509 return;
511 pending_read_ = true;
512 decoder_->Read(base::Bind(&AudioRendererImpl::DecodedAudioReady, weak_this_));
515 bool AudioRendererImpl::CanRead_Locked() {
516 lock_.AssertAcquired();
518 switch (state_) {
519 case kUninitialized:
520 case kInitializing:
521 case kPaused:
522 case kFlushing:
523 case kStopped:
524 return false;
526 case kPrerolling:
527 case kPlaying:
528 case kUnderflow:
529 case kRebuffering:
530 break;
533 return !pending_read_ && !received_end_of_stream_ &&
534 !algorithm_->IsQueueFull();
537 void AudioRendererImpl::SetPlaybackRate(float playback_rate) {
538 DVLOG(1) << __FUNCTION__ << "(" << playback_rate << ")";
539 DCHECK(task_runner_->BelongsToCurrentThread());
540 DCHECK_GE(playback_rate, 0);
541 DCHECK(sink_);
543 base::AutoLock auto_lock(lock_);
545 // We have two cases here:
546 // Play: current_playback_rate == 0 && playback_rate != 0
547 // Pause: current_playback_rate != 0 && playback_rate == 0
548 float current_playback_rate = algorithm_->playback_rate();
549 if (current_playback_rate == 0 && playback_rate != 0)
550 DoPlay_Locked();
551 else if (current_playback_rate != 0 && playback_rate == 0)
552 DoPause_Locked();
554 algorithm_->SetPlaybackRate(playback_rate);
557 bool AudioRendererImpl::IsBeforePrerollTime(
558 const scoped_refptr<AudioBuffer>& buffer) {
559 DCHECK_EQ(state_, kPrerolling);
560 return buffer && !buffer->end_of_stream() &&
561 (buffer->timestamp() + buffer->duration()) < preroll_timestamp_;
564 int AudioRendererImpl::Render(AudioBus* audio_bus,
565 int audio_delay_milliseconds) {
566 const int requested_frames = audio_bus->frames();
567 base::TimeDelta current_time = kNoTimestamp();
568 base::TimeDelta max_time = kNoTimestamp();
569 base::TimeDelta playback_delay = base::TimeDelta::FromMilliseconds(
570 audio_delay_milliseconds);
572 int frames_written = 0;
573 base::Closure underflow_cb;
575 base::AutoLock auto_lock(lock_);
577 // Ensure Stop() hasn't destroyed our |algorithm_| on the pipeline thread.
578 if (!algorithm_)
579 return 0;
581 float playback_rate = algorithm_->playback_rate();
582 if (playback_rate == 0)
583 return 0;
585 // Mute audio by returning 0 when not playing.
586 if (state_ != kPlaying)
587 return 0;
589 // We use the following conditions to determine end of playback:
590 // 1) Algorithm can not fill the audio callback buffer
591 // 2) We received an end of stream buffer
592 // 3) We haven't already signalled that we've ended
593 // 4) Our estimated earliest end time has expired
595 // TODO(enal): we should replace (4) with a check that the browser has no
596 // more audio data or at least use a delayed callback.
598 // We use the following conditions to determine underflow:
599 // 1) Algorithm can not fill the audio callback buffer
600 // 2) We have NOT received an end of stream buffer
601 // 3) We are in the kPlaying state
603 // Otherwise the buffer has data we can send to the device.
604 frames_written = algorithm_->FillBuffer(audio_bus, requested_frames);
605 if (frames_written == 0) {
606 const base::TimeTicks now = now_cb_.Run();
608 if (received_end_of_stream_ && !rendered_end_of_stream_ &&
609 now >= earliest_end_time_) {
610 rendered_end_of_stream_ = true;
611 ended_cb_.Run();
612 } else if (!received_end_of_stream_ && state_ == kPlaying &&
613 !underflow_disabled_) {
614 ChangeState_Locked(kUnderflow);
615 underflow_cb = underflow_cb_;
616 } else {
617 // We can't write any data this cycle. For example, we may have
618 // sent all available data to the audio device while not reaching
619 // |earliest_end_time_|.
623 if (CanRead_Locked()) {
624 task_runner_->PostTask(FROM_HERE, base::Bind(
625 &AudioRendererImpl::AttemptRead, weak_this_));
628 // The |audio_time_buffered_| is the ending timestamp of the last frame
629 // buffered at the audio device. |playback_delay| is the amount of time
630 // buffered at the audio device. The current time can be computed by their
631 // difference.
632 if (audio_time_buffered_ != kNoTimestamp()) {
633 // Adjust the delay according to playback rate.
634 base::TimeDelta adjusted_playback_delay =
635 base::TimeDelta::FromMicroseconds(ceil(
636 playback_delay.InMicroseconds() * playback_rate));
638 base::TimeDelta previous_time = current_time_;
639 current_time_ = audio_time_buffered_ - adjusted_playback_delay;
641 // Time can change in one of two ways:
642 // 1) The time of the audio data at the audio device changed, or
643 // 2) The playback delay value has changed
645 // We only want to set |current_time| (and thus execute |time_cb_|) if
646 // time has progressed and we haven't signaled end of stream yet.
648 // Why? The current latency of the system results in getting the last call
649 // to FillBuffer() later than we'd like, which delays firing the 'ended'
650 // event, which delays the looping/trigging performance of short sound
651 // effects.
653 // TODO(scherkus): revisit this and switch back to relying on playback
654 // delay after we've revamped our audio IPC subsystem.
655 if (current_time_ > previous_time && !rendered_end_of_stream_) {
656 current_time = current_time_;
660 // The call to FillBuffer() on |algorithm_| has increased the amount of
661 // buffered audio data. Update the new amount of time buffered.
662 max_time = algorithm_->GetTime();
663 audio_time_buffered_ = max_time;
665 if (frames_written > 0) {
666 UpdateEarliestEndTime_Locked(
667 frames_written, playback_delay, now_cb_.Run());
671 if (current_time != kNoTimestamp() && max_time != kNoTimestamp())
672 time_cb_.Run(current_time, max_time);
674 if (!underflow_cb.is_null())
675 underflow_cb.Run();
677 DCHECK_LE(frames_written, requested_frames);
678 return frames_written;
681 void AudioRendererImpl::UpdateEarliestEndTime_Locked(
682 int frames_filled, const base::TimeDelta& playback_delay,
683 const base::TimeTicks& time_now) {
684 DCHECK_GT(frames_filled, 0);
686 base::TimeDelta predicted_play_time = base::TimeDelta::FromMicroseconds(
687 static_cast<float>(frames_filled) * base::Time::kMicrosecondsPerSecond /
688 audio_parameters_.sample_rate());
690 lock_.AssertAcquired();
691 earliest_end_time_ = std::max(
692 earliest_end_time_, time_now + playback_delay + predicted_play_time);
695 void AudioRendererImpl::OnRenderError() {
696 HistogramRendererEvent(RENDER_ERROR);
697 disabled_cb_.Run();
700 void AudioRendererImpl::DisableUnderflowForTesting() {
701 underflow_disabled_ = true;
704 void AudioRendererImpl::HandleAbortedReadOrDecodeError(bool is_decode_error) {
705 lock_.AssertAcquired();
707 PipelineStatus status = is_decode_error ? PIPELINE_ERROR_DECODE : PIPELINE_OK;
708 switch (state_) {
709 case kUninitialized:
710 case kInitializing:
711 NOTREACHED();
712 return;
713 case kPaused:
714 if (status != PIPELINE_OK)
715 error_cb_.Run(status);
716 return;
717 case kFlushing:
718 ChangeState_Locked(kPaused);
720 if (status == PIPELINE_OK) {
721 DoFlush_Locked();
722 return;
725 error_cb_.Run(status);
726 base::ResetAndReturn(&flush_cb_).Run();
727 return;
728 case kPrerolling:
729 // This is a signal for abort if it's not an error.
730 preroll_aborted_ = !is_decode_error;
731 ChangeState_Locked(kPaused);
732 base::ResetAndReturn(&preroll_cb_).Run(status);
733 return;
734 case kPlaying:
735 case kUnderflow:
736 case kRebuffering:
737 case kStopped:
738 if (status != PIPELINE_OK)
739 error_cb_.Run(status);
740 return;
744 void AudioRendererImpl::ChangeState_Locked(State new_state) {
745 DVLOG(1) << __FUNCTION__ << " : " << state_ << " -> " << new_state;
746 lock_.AssertAcquired();
747 state_ = new_state;
750 } // namespace media