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.
6 #include "base/callback_helpers.h"
7 #include "base/run_loop.h"
8 #include "base/strings/stringprintf.h"
9 #include "media/base/audio_buffer_converter.h"
10 #include "media/base/audio_hardware_config.h"
11 #include "media/base/audio_splicer.h"
12 #include "media/base/fake_audio_renderer_sink.h"
13 #include "media/base/gmock_callback_support.h"
14 #include "media/base/mock_filters.h"
15 #include "media/base/test_helpers.h"
16 #include "media/filters/audio_renderer_impl.h"
17 #include "testing/gtest/include/gtest/gtest.h"
19 using ::base::TimeDelta;
21 using ::testing::Return;
22 using ::testing::SaveArg;
28 // Since AudioBufferConverter is used due to different input/output sample
29 // rates, define some helper types to differentiate between the two.
31 explicit InputFrames(int value) : value(value) {}
36 explicit OutputFrames(int value) : value(value) {}
42 // Constants to specify the type of audio data used.
43 static AudioCodec kCodec = kCodecVorbis;
44 static SampleFormat kSampleFormat = kSampleFormatPlanarF32;
45 static ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
46 static int kChannelCount = 2;
47 static int kChannels = ChannelLayoutToChannelCount(kChannelLayout);
49 // Use a different output sample rate so the AudioBufferConverter is invoked.
50 static int kInputSamplesPerSecond = 5000;
51 static int kOutputSamplesPerSecond = 10000;
53 ACTION_P(EnterPendingDecoderInitStateAction, test) {
54 test->EnterPendingDecoderInitState(arg1);
57 class AudioRendererImplTest : public ::testing::Test {
59 // Give the decoder some non-garbage media properties.
60 AudioRendererImplTest()
61 : hardware_config_(AudioParameters(), AudioParameters()),
62 demuxer_stream_(DemuxerStream::AUDIO),
63 decoder_(new MockAudioDecoder()),
64 last_time_update_(kNoTimestamp()),
65 last_max_time_(kNoTimestamp()),
67 AudioDecoderConfig audio_config(kCodec,
70 kInputSamplesPerSecond,
74 demuxer_stream_.set_audio_decoder_config(audio_config);
76 // Used to save callbacks and run them at a later time.
77 EXPECT_CALL(*decoder_, Decode(_, _))
78 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::DecodeDecoder));
79 EXPECT_CALL(*decoder_, Reset(_))
80 .WillRepeatedly(Invoke(this, &AudioRendererImplTest::ResetDecoder));
82 // Mock out demuxer reads.
83 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly(
84 RunCallback<0>(DemuxerStream::kOk,
85 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))));
86 EXPECT_CALL(demuxer_stream_, SupportsConfigChanges())
87 .WillRepeatedly(Return(true));
88 AudioParameters out_params(AudioParameters::AUDIO_PCM_LOW_LATENCY,
90 kOutputSamplesPerSecond,
91 SampleFormatToBytesPerChannel(kSampleFormat) * 8,
93 hardware_config_.UpdateOutputConfig(out_params);
94 ScopedVector<AudioDecoder> decoders;
95 decoders.push_back(decoder_);
96 sink_ = new FakeAudioRendererSink();
97 renderer_.reset(new AudioRendererImpl(message_loop_.message_loop_proxy(),
100 SetDecryptorReadyCB(),
104 virtual ~AudioRendererImplTest() {
105 SCOPED_TRACE("~AudioRendererImplTest()");
108 void ExpectUnsupportedAudioDecoder() {
109 EXPECT_CALL(*decoder_, Initialize(_, _, _))
110 .WillOnce(DoAll(SaveArg<2>(&output_cb_),
111 RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED)));
114 MOCK_METHOD1(OnStatistics, void(const PipelineStatistics&));
115 MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
116 MOCK_METHOD1(OnError, void(PipelineStatus));
118 void OnAudioTimeCallback(TimeDelta current_time, TimeDelta max_time) {
119 CHECK(current_time <= max_time);
120 last_time_update_ = current_time;
121 last_max_time_ = max_time;
124 void InitializeRenderer(const PipelineStatusCB& pipeline_status_cb) {
125 renderer_->Initialize(
128 base::Bind(&AudioRendererImplTest::OnStatistics,
129 base::Unretained(this)),
130 base::Bind(&AudioRendererImplTest::OnAudioTimeCallback,
131 base::Unretained(this)),
132 base::Bind(&AudioRendererImplTest::OnBufferingStateChange,
133 base::Unretained(this)),
134 base::Bind(&AudioRendererImplTest::OnEnded,
135 base::Unretained(this)),
136 base::Bind(&AudioRendererImplTest::OnError,
137 base::Unretained(this)));
141 EXPECT_CALL(*decoder_, Initialize(_, _, _))
142 .WillOnce(DoAll(SaveArg<2>(&output_cb_),
143 RunCallback<1>(PIPELINE_OK)));
144 InitializeWithStatus(PIPELINE_OK);
146 next_timestamp_.reset(new AudioTimestampHelper(kInputSamplesPerSecond));
149 void InitializeWithStatus(PipelineStatus expected) {
150 SCOPED_TRACE(base::StringPrintf("InitializeWithStatus(%d)", expected));
152 WaitableMessageLoopEvent event;
153 InitializeRenderer(event.GetPipelineStatusCB());
154 event.RunAndWaitForStatus(expected);
156 // We should have no reads.
157 EXPECT_TRUE(decode_cb_.is_null());
160 void InitializeAndDestroy() {
161 EXPECT_CALL(*decoder_, Initialize(_, _, _))
162 .WillOnce(RunCallback<1>(PIPELINE_OK));
164 WaitableMessageLoopEvent event;
165 InitializeRenderer(event.GetPipelineStatusCB());
167 // Destroy the |renderer_| before we let the MessageLoop run, this simulates
168 // an interleaving in which we end up destroying the |renderer_| while the
169 // OnDecoderSelected callback is in flight.
171 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT);
174 void InitializeAndDestroyDuringDecoderInit() {
175 EXPECT_CALL(*decoder_, Initialize(_, _, _))
176 .WillOnce(EnterPendingDecoderInitStateAction(this));
178 WaitableMessageLoopEvent event;
179 InitializeRenderer(event.GetPipelineStatusCB());
180 base::RunLoop().RunUntilIdle();
181 DCHECK(!init_decoder_cb_.is_null());
184 event.RunAndWaitForStatus(PIPELINE_ERROR_ABORT);
187 void EnterPendingDecoderInitState(PipelineStatusCB cb) {
188 init_decoder_cb_ = cb;
191 void FlushDuringPendingRead() {
192 SCOPED_TRACE("FlushDuringPendingRead()");
193 WaitableMessageLoopEvent flush_event;
194 renderer_->Flush(flush_event.GetClosure());
195 SatisfyPendingRead(InputFrames(256));
196 flush_event.RunAndWait();
198 EXPECT_FALSE(IsReadPending());
202 Preroll(0, PIPELINE_OK);
205 void Preroll(int timestamp_ms, PipelineStatus expected) {
206 SCOPED_TRACE(base::StringPrintf("Preroll(%d, %d)", timestamp_ms, expected));
208 TimeDelta timestamp = TimeDelta::FromMilliseconds(timestamp_ms);
209 next_timestamp_->SetBaseTimestamp(timestamp);
211 // Fill entire buffer to complete prerolling.
212 renderer_->SetMediaTime(timestamp);
213 renderer_->StartPlaying();
214 WaitForPendingRead();
215 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
216 DeliverRemainingAudio();
219 void StartTicking() {
220 renderer_->StartTicking();
221 renderer_->SetPlaybackRate(1.0f);
224 void StopTicking() { renderer_->StopTicking(); }
226 bool IsReadPending() const {
227 return !decode_cb_.is_null();
230 void WaitForPendingRead() {
231 SCOPED_TRACE("WaitForPendingRead()");
232 if (!decode_cb_.is_null())
235 DCHECK(wait_for_pending_decode_cb_.is_null());
237 WaitableMessageLoopEvent event;
238 wait_for_pending_decode_cb_ = event.GetClosure();
241 DCHECK(!decode_cb_.is_null());
242 DCHECK(wait_for_pending_decode_cb_.is_null());
245 // Delivers decoded frames to |renderer_|.
246 void SatisfyPendingRead(InputFrames frames) {
247 CHECK_GT(frames.value, 0);
248 CHECK(!decode_cb_.is_null());
250 scoped_refptr<AudioBuffer> buffer =
251 MakeAudioBuffer<float>(kSampleFormat,
254 kInputSamplesPerSecond,
258 next_timestamp_->GetTimestamp());
259 next_timestamp_->AddFrames(frames.value);
261 DeliverBuffer(AudioDecoder::kOk, buffer);
264 void DeliverEndOfStream() {
265 DCHECK(!decode_cb_.is_null());
267 // Return EOS buffer to trigger EOS frame.
268 EXPECT_CALL(demuxer_stream_, Read(_))
269 .WillOnce(RunCallback<0>(DemuxerStream::kOk,
270 DecoderBuffer::CreateEOSBuffer()));
272 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
273 message_loop_.PostTask(
275 base::Bind(base::ResetAndReturn(&decode_cb_), AudioDecoder::kOk));
277 WaitForPendingRead();
279 message_loop_.PostTask(
281 base::Bind(base::ResetAndReturn(&decode_cb_), AudioDecoder::kOk));
283 base::RunLoop().RunUntilIdle();
286 // Delivers frames until |renderer_|'s internal buffer is full and no longer
287 // has pending reads.
288 void DeliverRemainingAudio() {
289 while (frames_remaining_in_buffer().value > 0) {
290 SatisfyPendingRead(InputFrames(256));
294 // Attempts to consume |requested_frames| frames from |renderer_|'s internal
295 // buffer. Returns true if and only if all of |requested_frames| were able
297 bool ConsumeBufferedData(OutputFrames requested_frames) {
298 scoped_ptr<AudioBus> bus =
299 AudioBus::Create(kChannels, requested_frames.value);
301 EXPECT_TRUE(sink_->Render(bus.get(), 0, &frames_read));
302 return frames_read == requested_frames.value;
305 OutputFrames frames_buffered() {
306 return OutputFrames(renderer_->algorithm_->frames_buffered());
309 OutputFrames buffer_capacity() {
310 return OutputFrames(renderer_->algorithm_->QueueCapacity());
313 OutputFrames frames_remaining_in_buffer() {
314 // This can happen if too much data was delivered, in which case the buffer
315 // will accept the data but not increase capacity.
316 if (frames_buffered().value > buffer_capacity().value) {
317 return OutputFrames(0);
319 return OutputFrames(buffer_capacity().value - frames_buffered().value);
322 void force_config_change() {
323 renderer_->OnConfigChange();
326 InputFrames converter_input_frames_left() const {
328 renderer_->buffer_converter_->input_frames_left_for_testing());
331 bool splicer_has_next_buffer() const {
332 return renderer_->splicer_->HasNextBuffer();
335 base::TimeDelta last_time_update() const {
336 return last_time_update_;
339 base::TimeDelta last_max_time() const { return last_max_time_; }
341 bool ended() const { return ended_; }
344 base::MessageLoop message_loop_;
345 scoped_ptr<AudioRendererImpl> renderer_;
346 scoped_refptr<FakeAudioRendererSink> sink_;
347 AudioHardwareConfig hardware_config_;
350 void DecodeDecoder(const scoped_refptr<DecoderBuffer>& buffer,
351 const AudioDecoder::DecodeCB& decode_cb) {
352 // TODO(scherkus): Make this a DCHECK after threading semantics are fixed.
353 if (base::MessageLoop::current() != &message_loop_) {
354 message_loop_.PostTask(FROM_HERE, base::Bind(
355 &AudioRendererImplTest::DecodeDecoder,
356 base::Unretained(this), buffer, decode_cb));
360 CHECK(decode_cb_.is_null()) << "Overlapping decodes are not permitted";
361 decode_cb_ = decode_cb;
363 // Wake up WaitForPendingRead() if needed.
364 if (!wait_for_pending_decode_cb_.is_null())
365 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run();
368 void ResetDecoder(const base::Closure& reset_cb) {
369 if (!decode_cb_.is_null()) {
370 // |reset_cb| will be called in DeliverBuffer(), after the decoder is
372 reset_cb_ = reset_cb;
376 message_loop_.PostTask(FROM_HERE, reset_cb);
379 void DeliverBuffer(AudioDecoder::Status status,
380 const scoped_refptr<AudioBuffer>& buffer) {
381 CHECK(!decode_cb_.is_null());
382 if (buffer && !buffer->end_of_stream())
383 output_cb_.Run(buffer);
384 base::ResetAndReturn(&decode_cb_).Run(status);
386 if (!reset_cb_.is_null())
387 base::ResetAndReturn(&reset_cb_).Run();
389 base::RunLoop().RunUntilIdle();
397 MockDemuxerStream demuxer_stream_;
398 MockAudioDecoder* decoder_;
400 // Used for satisfying reads.
401 AudioDecoder::OutputCB output_cb_;
402 AudioDecoder::DecodeCB decode_cb_;
403 base::Closure reset_cb_;
404 scoped_ptr<AudioTimestampHelper> next_timestamp_;
406 // Run during DecodeDecoder() to unblock WaitForPendingRead().
407 base::Closure wait_for_pending_decode_cb_;
409 PipelineStatusCB init_decoder_cb_;
410 base::TimeDelta last_time_update_;
411 base::TimeDelta last_max_time_;
414 DISALLOW_COPY_AND_ASSIGN(AudioRendererImplTest);
417 TEST_F(AudioRendererImplTest, Initialize_Successful) {
421 TEST_F(AudioRendererImplTest, Initialize_DecoderInitFailure) {
422 ExpectUnsupportedAudioDecoder();
423 InitializeWithStatus(DECODER_ERROR_NOT_SUPPORTED);
426 TEST_F(AudioRendererImplTest, Preroll) {
431 TEST_F(AudioRendererImplTest, StartTicking) {
436 // Drain internal buffer, we should have a pending read.
437 EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
438 WaitForPendingRead();
441 TEST_F(AudioRendererImplTest, EndOfStream) {
446 // Drain internal buffer, we should have a pending read.
447 EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
448 WaitForPendingRead();
450 // Forcefully trigger underflow.
451 EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
452 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
454 // Fulfill the read with an end-of-stream buffer. Doing so should change our
455 // buffering state so playback resumes.
456 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
457 DeliverEndOfStream();
459 // Consume all remaining data. We shouldn't have signal ended yet.
460 EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
461 base::RunLoop().RunUntilIdle();
462 EXPECT_FALSE(ended());
464 // Ended should trigger on next render call.
465 EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
466 base::RunLoop().RunUntilIdle();
467 EXPECT_TRUE(ended());
470 TEST_F(AudioRendererImplTest, Underflow) {
475 // Drain internal buffer, we should have a pending read.
476 EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
477 WaitForPendingRead();
479 // Verify the next FillBuffer() call triggers a buffering state change
481 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
482 EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
484 // Verify we're still not getting audio data.
485 EXPECT_EQ(0, frames_buffered().value);
486 EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
488 // Deliver enough data to have enough for buffering.
489 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
490 DeliverRemainingAudio();
492 // Verify we're getting audio data.
493 EXPECT_TRUE(ConsumeBufferedData(OutputFrames(1)));
496 TEST_F(AudioRendererImplTest, Underflow_CapacityResetsAfterFlush) {
501 // Drain internal buffer, we should have a pending read.
502 EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
503 WaitForPendingRead();
505 // Verify the next FillBuffer() call triggers the underflow callback
506 // since the decoder hasn't delivered any data after it was drained.
507 OutputFrames initial_capacity = buffer_capacity();
508 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
509 EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
511 // Verify that the buffer capacity increased as a result of underflowing.
512 EXPECT_GT(buffer_capacity().value, initial_capacity.value);
514 // Verify that the buffer capacity is restored to the |initial_capacity|.
515 FlushDuringPendingRead();
516 EXPECT_EQ(buffer_capacity().value, initial_capacity.value);
519 TEST_F(AudioRendererImplTest, Underflow_Flush) {
525 EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
526 WaitForPendingRead();
527 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
528 EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
529 WaitForPendingRead();
532 // We shouldn't expect another buffering state change when flushing.
533 FlushDuringPendingRead();
536 TEST_F(AudioRendererImplTest, PendingRead_Flush) {
542 // Partially drain internal buffer so we get a pending read.
543 EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
544 WaitForPendingRead();
548 EXPECT_TRUE(IsReadPending());
550 // Flush and expect to be notified that we have nothing.
551 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
552 FlushDuringPendingRead();
554 // Preroll again to a different timestamp and verify it completed normally.
555 Preroll(1000, PIPELINE_OK);
558 TEST_F(AudioRendererImplTest, PendingRead_Destroy) {
564 // Partially drain internal buffer so we get a pending read.
565 EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
566 WaitForPendingRead();
570 EXPECT_TRUE(IsReadPending());
575 TEST_F(AudioRendererImplTest, PendingFlush_Destroy) {
581 // Partially drain internal buffer so we get a pending read.
582 EXPECT_TRUE(ConsumeBufferedData(OutputFrames(256)));
583 WaitForPendingRead();
587 EXPECT_TRUE(IsReadPending());
590 WaitableMessageLoopEvent flush_event;
591 renderer_->Flush(flush_event.GetClosure());
593 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_NOTHING));
594 SatisfyPendingRead(InputFrames(256));
599 TEST_F(AudioRendererImplTest, InitializeThenDestroy) {
600 InitializeAndDestroy();
603 TEST_F(AudioRendererImplTest, InitializeThenDestroyDuringDecoderInit) {
604 InitializeAndDestroyDuringDecoderInit();
607 TEST_F(AudioRendererImplTest, ConfigChangeDrainsConverter) {
612 // Drain internal buffer, we should have a pending read.
613 EXPECT_TRUE(ConsumeBufferedData(frames_buffered()));
614 WaitForPendingRead();
616 // Deliver a little bit of data. Use an odd data size to ensure there is data
617 // left in the AudioBufferConverter. Ensure no buffers are in the splicer.
618 SatisfyPendingRead(InputFrames(2053));
619 EXPECT_FALSE(splicer_has_next_buffer());
620 EXPECT_GT(converter_input_frames_left().value, 0);
622 // Force a config change and then ensure all buffered data has been put into
624 force_config_change();
625 EXPECT_TRUE(splicer_has_next_buffer());
626 EXPECT_EQ(0, converter_input_frames_left().value);
629 TEST_F(AudioRendererImplTest, TimeUpdatesOnFirstBuffer) {
634 AudioTimestampHelper timestamp_helper(kOutputSamplesPerSecond);
635 EXPECT_EQ(kNoTimestamp(), last_time_update());
636 EXPECT_EQ(kNoTimestamp(), last_max_time());
638 // Preroll() should be buffered some data, consume half of it now.
639 OutputFrames frames_to_consume(frames_buffered().value / 2);
640 EXPECT_TRUE(ConsumeBufferedData(frames_to_consume));
641 WaitForPendingRead();
642 base::RunLoop().RunUntilIdle();
644 // ConsumeBufferedData() uses an audio delay of zero, so ensure we received
645 // a time update that's equal to |kFramesToConsume| from above.
646 timestamp_helper.SetBaseTimestamp(base::TimeDelta());
647 timestamp_helper.AddFrames(frames_to_consume.value);
648 EXPECT_EQ(base::TimeDelta(), last_time_update());
649 EXPECT_EQ(timestamp_helper.GetTimestamp(), last_max_time());
651 // The next time update should match the remaining frames_buffered(), but only
652 // after running the message loop.
653 frames_to_consume = frames_buffered();
654 EXPECT_TRUE(ConsumeBufferedData(frames_to_consume));
655 EXPECT_EQ(base::TimeDelta(), last_time_update());
656 EXPECT_EQ(timestamp_helper.GetTimestamp(), last_max_time());
658 // Now the times should be updated.
659 base::RunLoop().RunUntilIdle();
660 EXPECT_EQ(timestamp_helper.GetTimestamp(), last_time_update());
661 timestamp_helper.AddFrames(frames_to_consume.value);
662 EXPECT_EQ(timestamp_helper.GetTimestamp(), last_max_time());
665 TEST_F(AudioRendererImplTest, ImmediateEndOfStream) {
668 SCOPED_TRACE("Preroll()");
669 renderer_->StartPlaying();
670 WaitForPendingRead();
671 EXPECT_CALL(*this, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
672 DeliverEndOfStream();
676 // Read a single frame. We shouldn't be able to satisfy it.
677 EXPECT_FALSE(ended());
678 EXPECT_FALSE(ConsumeBufferedData(OutputFrames(1)));
679 base::RunLoop().RunUntilIdle();
680 EXPECT_TRUE(ended());
683 TEST_F(AudioRendererImplTest, OnRenderErrorCausesDecodeError) {
688 EXPECT_CALL(*this, OnError(PIPELINE_ERROR_DECODE));
689 sink_->OnRenderError();
690 base::RunLoop().RunUntilIdle();
693 // Test for AudioRendererImpl calling Pause()/Play() on the sink when the
694 // playback rate is set to zero and non-zero.
695 TEST_F(AudioRendererImplTest, SetPlaybackRate) {
699 // Rendering hasn't started. Sink should always be paused.
700 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state());
701 renderer_->SetPlaybackRate(0.0f);
702 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state());
703 renderer_->SetPlaybackRate(1.0f);
704 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state());
706 // Rendering has started with non-zero rate. Rate changes will affect sink
708 renderer_->StartTicking();
709 EXPECT_EQ(FakeAudioRendererSink::kPlaying, sink_->state());
710 renderer_->SetPlaybackRate(0.0f);
711 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state());
712 renderer_->SetPlaybackRate(1.0f);
713 EXPECT_EQ(FakeAudioRendererSink::kPlaying, sink_->state());
715 // Rendering has stopped. Sink should be paused.
716 renderer_->StopTicking();
717 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state());
719 // Start rendering with zero playback rate. Sink should be paused until
720 // non-zero rate is set.
721 renderer_->SetPlaybackRate(0.0f);
722 renderer_->StartTicking();
723 EXPECT_EQ(FakeAudioRendererSink::kPaused, sink_->state());
724 renderer_->SetPlaybackRate(1.0f);
725 EXPECT_EQ(FakeAudioRendererSink::kPlaying, sink_->state());