| Index: media/filters/renderer_impl_unittest.cc
|
| diff --git a/media/filters/renderer_impl_unittest.cc b/media/filters/renderer_impl_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7e0b1cba10adac1cc4357dbec62a5a03a76ac166
|
| --- /dev/null
|
| +++ b/media/filters/renderer_impl_unittest.cc
|
| @@ -0,0 +1,554 @@
|
| +// Copyright 2014 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/message_loop/message_loop.h"
|
| +#include "base/run_loop.h"
|
| +#include "base/test/simple_test_tick_clock.h"
|
| +#include "media/base/gmock_callback_support.h"
|
| +#include "media/base/mock_filters.h"
|
| +#include "media/base/test_helpers.h"
|
| +#include "media/base/time_delta_interpolator.h"
|
| +#include "media/filters/renderer_impl.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using ::testing::_;
|
| +using ::testing::DoAll;
|
| +using ::testing::InSequence;
|
| +using ::testing::Mock;
|
| +using ::testing::Return;
|
| +using ::testing::SaveArg;
|
| +using ::testing::StrictMock;
|
| +
|
| +namespace media {
|
| +
|
| +const int64 kStartPlayingTimeInMs = 100;
|
| +const int64 kDurationInMs = 3000;
|
| +const int64 kAudioUpdateTimeMs = 150;
|
| +const int64 kAudioUpdateMaxTimeMs = 1000;
|
| +
|
| +ACTION_P2(SetBufferingState, cb, buffering_state) {
|
| + cb->Run(buffering_state);
|
| +}
|
| +
|
| +ACTION_P3(UpdateAudioTime, cb, time, max_time) {
|
| + cb->Run(base::TimeDelta::FromMilliseconds(time),
|
| + base::TimeDelta::FromMilliseconds(max_time));
|
| +}
|
| +
|
| +ACTION_P2(AudioError, cb, error) {
|
| + cb->Run(error);
|
| +}
|
| +
|
| +static base::TimeDelta GetDuration() {
|
| + return base::TimeDelta::FromMilliseconds(kDurationInMs);
|
| +}
|
| +
|
| +class RendererImplTest : public ::testing::Test {
|
| + public:
|
| + // Used for setting expectations on pipeline callbacks. Using a StrictMock
|
| + // also lets us test for missing callbacks.
|
| + class CallbackHelper {
|
| + public:
|
| + CallbackHelper() {}
|
| + virtual ~CallbackHelper() {}
|
| +
|
| + MOCK_METHOD1(OnInitialize, void(PipelineStatus));
|
| + MOCK_METHOD0(OnFlushed, void());
|
| + MOCK_METHOD0(OnEnded, void());
|
| + MOCK_METHOD1(OnError, void(PipelineStatus));
|
| + MOCK_METHOD1(OnUpdateStatistics, void(const PipelineStatistics&));
|
| + MOCK_METHOD1(OnBufferingStateChange, void(BufferingState));
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(CallbackHelper);
|
| + };
|
| +
|
| + RendererImplTest()
|
| + : demuxer_(new StrictMock<MockDemuxer>()),
|
| + video_renderer_(new StrictMock<MockVideoRenderer>()),
|
| + audio_renderer_(new StrictMock<MockAudioRenderer>()),
|
| + renderer_impl_(
|
| + new RendererImpl(message_loop_.message_loop_proxy(),
|
| + demuxer_.get(),
|
| + scoped_ptr<AudioRenderer>(audio_renderer_),
|
| + scoped_ptr<VideoRenderer>(video_renderer_))) {
|
| + // SetDemuxerExpectations() adds overriding expectations for expected
|
| + // non-NULL streams.
|
| + DemuxerStream* null_pointer = NULL;
|
| + EXPECT_CALL(*demuxer_, GetStream(_))
|
| + .WillRepeatedly(Return(null_pointer));
|
| + EXPECT_CALL(*demuxer_, GetLiveness())
|
| + .WillRepeatedly(Return(Demuxer::LIVENESS_UNKNOWN));
|
| + }
|
| +
|
| + virtual ~RendererImplTest() {
|
| + renderer_impl_.reset();
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + protected:
|
| + typedef std::vector<MockDemuxerStream*> MockDemuxerStreamVector;
|
| +
|
| + scoped_ptr<StrictMock<MockDemuxerStream> > CreateStream(
|
| + DemuxerStream::Type type) {
|
| + scoped_ptr<StrictMock<MockDemuxerStream> > stream(
|
| + new StrictMock<MockDemuxerStream>(type));
|
| + return stream.Pass();
|
| + }
|
| +
|
| + // Sets up expectations to allow the audio renderer to initialize.
|
| + void SetAudioRendererInitializeExpectations(PipelineStatus status) {
|
| + EXPECT_CALL(*audio_renderer_,
|
| + Initialize(audio_stream_.get(), _, _, _, _, _, _))
|
| + .WillOnce(DoAll(SaveArg<3>(&audio_time_cb_),
|
| + SaveArg<4>(&audio_buffering_state_cb_),
|
| + SaveArg<5>(&audio_ended_cb_),
|
| + SaveArg<6>(&audio_error_cb_),
|
| + RunCallback<1>(status)));
|
| + if (status == PIPELINE_OK) {
|
| + EXPECT_CALL(*audio_renderer_, GetTimeSource())
|
| + .WillOnce(Return(&time_source_));
|
| + }
|
| + }
|
| +
|
| + // Sets up expectations to allow the video renderer to initialize.
|
| + void SetVideoRendererInitializeExpectations(PipelineStatus status) {
|
| + EXPECT_CALL(*video_renderer_,
|
| + Initialize(video_stream_.get(), _, _, _, _, _, _, _, _, _))
|
| + .WillOnce(DoAll(SaveArg<5>(&video_buffering_state_cb_),
|
| + SaveArg<6>(&video_ended_cb_),
|
| + RunCallback<2>(status)));
|
| + }
|
| +
|
| + void InitializeAndExpect(PipelineStatus start_status) {
|
| + EXPECT_CALL(callbacks_, OnInitialize(start_status));
|
| +
|
| + renderer_impl_->Initialize(
|
| + base::Bind(&CallbackHelper::OnInitialize,
|
| + base::Unretained(&callbacks_)),
|
| + base::Bind(&CallbackHelper::OnUpdateStatistics,
|
| + base::Unretained(&callbacks_)),
|
| + base::Bind(&CallbackHelper::OnEnded, base::Unretained(&callbacks_)),
|
| + base::Bind(&CallbackHelper::OnError, base::Unretained(&callbacks_)),
|
| + base::Bind(&CallbackHelper::OnBufferingStateChange,
|
| + base::Unretained(&callbacks_)),
|
| + base::Bind(&GetDuration));
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + void CreateAudioStream() {
|
| + audio_stream_ = CreateStream(DemuxerStream::AUDIO);
|
| + streams_.push_back(audio_stream_.get());
|
| + EXPECT_CALL(*demuxer_, GetStream(DemuxerStream::AUDIO))
|
| + .WillRepeatedly(Return(audio_stream_.get()));
|
| + }
|
| +
|
| + void CreateVideoStream() {
|
| + video_stream_ = CreateStream(DemuxerStream::VIDEO);
|
| + video_stream_->set_video_decoder_config(video_decoder_config_);
|
| + streams_.push_back(video_stream_.get());
|
| + EXPECT_CALL(*demuxer_, GetStream(DemuxerStream::VIDEO))
|
| + .WillRepeatedly(Return(video_stream_.get()));
|
| + }
|
| +
|
| + void CreateAudioAndVideoStream() {
|
| + CreateAudioStream();
|
| + CreateVideoStream();
|
| + }
|
| +
|
| + void InitializeWithAudio() {
|
| + CreateAudioStream();
|
| + SetAudioRendererInitializeExpectations(PIPELINE_OK);
|
| + InitializeAndExpect(PIPELINE_OK);
|
| + }
|
| +
|
| + void InitializeWithVideo() {
|
| + CreateVideoStream();
|
| + SetVideoRendererInitializeExpectations(PIPELINE_OK);
|
| + InitializeAndExpect(PIPELINE_OK);
|
| + }
|
| +
|
| + void InitializeWithAudioAndVideo() {
|
| + CreateAudioAndVideoStream();
|
| + SetAudioRendererInitializeExpectations(PIPELINE_OK);
|
| + SetVideoRendererInitializeExpectations(PIPELINE_OK);
|
| + InitializeAndExpect(PIPELINE_OK);
|
| + }
|
| +
|
| + void Play() {
|
| + DCHECK(audio_stream_ || video_stream_);
|
| + EXPECT_CALL(callbacks_, OnBufferingStateChange(BUFFERING_HAVE_ENOUGH));
|
| +
|
| + if (audio_stream_) {
|
| + EXPECT_CALL(time_source_,
|
| + SetMediaTime(base::TimeDelta::FromMilliseconds(
|
| + kStartPlayingTimeInMs)));
|
| + EXPECT_CALL(time_source_, StartTicking());
|
| + EXPECT_CALL(*audio_renderer_, StartPlaying())
|
| + .WillOnce(SetBufferingState(&audio_buffering_state_cb_,
|
| + BUFFERING_HAVE_ENOUGH));
|
| + }
|
| +
|
| + if (video_stream_) {
|
| + EXPECT_CALL(*video_renderer_, StartPlaying())
|
| + .WillOnce(SetBufferingState(&video_buffering_state_cb_,
|
| + BUFFERING_HAVE_ENOUGH));
|
| + }
|
| +
|
| + renderer_impl_->StartPlayingFrom(
|
| + base::TimeDelta::FromMilliseconds(kStartPlayingTimeInMs));
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + void Flush(bool underflowed) {
|
| + if (audio_stream_) {
|
| + if (!underflowed)
|
| + EXPECT_CALL(time_source_, StopTicking());
|
| + EXPECT_CALL(*audio_renderer_, Flush(_))
|
| + .WillOnce(DoAll(SetBufferingState(&audio_buffering_state_cb_,
|
| + BUFFERING_HAVE_NOTHING),
|
| + RunClosure<0>()));
|
| + }
|
| +
|
| + if (video_stream_) {
|
| + EXPECT_CALL(*video_renderer_, Flush(_))
|
| + .WillOnce(DoAll(SetBufferingState(&video_buffering_state_cb_,
|
| + BUFFERING_HAVE_NOTHING),
|
| + RunClosure<0>()));
|
| + }
|
| +
|
| + EXPECT_CALL(callbacks_, OnFlushed());
|
| +
|
| + renderer_impl_->Flush(
|
| + base::Bind(&CallbackHelper::OnFlushed, base::Unretained(&callbacks_)));
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + void SetPlaybackRate(float playback_rate) {
|
| + EXPECT_CALL(time_source_, SetPlaybackRate(playback_rate));
|
| + renderer_impl_->SetPlaybackRate(playback_rate);
|
| + base::RunLoop().RunUntilIdle();
|
| + }
|
| +
|
| + int64 GetMediaTimeMs() {
|
| + return renderer_impl_->GetMediaTime().InMilliseconds();
|
| + }
|
| +
|
| + bool IsMediaTimeAdvancing(float playback_rate) {
|
| + int64 start_time_ms = GetMediaTimeMs();
|
| + const int64 time_to_advance_ms = 100;
|
| +
|
| + test_tick_clock_.Advance(
|
| + base::TimeDelta::FromMilliseconds(time_to_advance_ms));
|
| +
|
| + if (GetMediaTimeMs() == start_time_ms + time_to_advance_ms * playback_rate)
|
| + return true;
|
| +
|
| + DCHECK_EQ(start_time_ms, GetMediaTimeMs());
|
| + return false;
|
| + }
|
| +
|
| + bool IsMediaTimeAdvancing() {
|
| + return IsMediaTimeAdvancing(1.0f);
|
| + }
|
| +
|
| + // Fixture members.
|
| + base::MessageLoop message_loop_;
|
| + StrictMock<CallbackHelper> callbacks_;
|
| + base::SimpleTestTickClock test_tick_clock_;
|
| +
|
| + scoped_ptr<StrictMock<MockDemuxer> > demuxer_;
|
| + StrictMock<MockVideoRenderer>* video_renderer_;
|
| + StrictMock<MockAudioRenderer>* audio_renderer_;
|
| + scoped_ptr<RendererImpl> renderer_impl_;
|
| +
|
| + StrictMock<MockTimeSource> time_source_;
|
| + scoped_ptr<StrictMock<MockDemuxerStream> > audio_stream_;
|
| + scoped_ptr<StrictMock<MockDemuxerStream> > video_stream_;
|
| + MockDemuxerStreamVector streams_;
|
| + AudioRenderer::TimeCB audio_time_cb_;
|
| + BufferingStateCB audio_buffering_state_cb_;
|
| + BufferingStateCB video_buffering_state_cb_;
|
| + base::Closure audio_ended_cb_;
|
| + base::Closure video_ended_cb_;
|
| + PipelineStatusCB audio_error_cb_;
|
| + VideoDecoderConfig video_decoder_config_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(RendererImplTest);
|
| +};
|
| +
|
| +TEST_F(RendererImplTest, DestroyBeforeInitialize) {
|
| + // |renderer_impl_| will be destroyed in the dtor.
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, InitializeWithAudio) {
|
| + InitializeWithAudio();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, InitializeWithVideo) {
|
| + InitializeWithVideo();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, InitializeWithAudioVideo) {
|
| + InitializeWithAudioAndVideo();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, InitializeWithAudio_Failed) {
|
| + CreateAudioStream();
|
| + SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, InitializeWithVideo_Failed) {
|
| + CreateVideoStream();
|
| + SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, InitializeWithAudioVideo_AudioRendererFailed) {
|
| + CreateAudioAndVideoStream();
|
| + SetAudioRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| + // VideoRenderer::Initialize() should not be called.
|
| + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, InitializeWithAudioVideo_VideoRendererFailed) {
|
| + CreateAudioAndVideoStream();
|
| + SetAudioRendererInitializeExpectations(PIPELINE_OK);
|
| + SetVideoRendererInitializeExpectations(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| + InitializeAndExpect(PIPELINE_ERROR_INITIALIZATION_FAILED);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, StartPlayingFrom) {
|
| + InitializeWithAudioAndVideo();
|
| + Play();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, FlushAfterInitialization) {
|
| + InitializeWithAudioAndVideo();
|
| + Flush(true);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, FlushAfterPlay) {
|
| + InitializeWithAudioAndVideo();
|
| + Play();
|
| + Flush(false);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, FlushAfterUnderflow) {
|
| + InitializeWithAudioAndVideo();
|
| + Play();
|
| +
|
| + // Simulate underflow.
|
| + EXPECT_CALL(time_source_, StopTicking());
|
| + audio_buffering_state_cb_.Run(BUFFERING_HAVE_NOTHING);
|
| +
|
| + // Flush while underflowed. We shouldn't call StopTicking() again.
|
| + Flush(true);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, SetPlaybackRate) {
|
| + InitializeWithAudioAndVideo();
|
| + SetPlaybackRate(1.0f);
|
| + SetPlaybackRate(2.0f);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, SetVolume) {
|
| + InitializeWithAudioAndVideo();
|
| + EXPECT_CALL(*audio_renderer_, SetVolume(2.0f));
|
| + renderer_impl_->SetVolume(2.0f);
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, GetMediaTime) {
|
| + // Replace what's used for interpolating to simulate wall clock time.
|
| + renderer_impl_->SetTimeDeltaInterpolatorForTesting(
|
| + new TimeDeltaInterpolator(&test_tick_clock_));
|
| +
|
| + InitializeWithAudioAndVideo();
|
| + Play();
|
| +
|
| + EXPECT_EQ(kStartPlayingTimeInMs, GetMediaTimeMs());
|
| +
|
| + // Verify that the clock doesn't advance since it hasn't been started by
|
| + // a time update from the audio stream.
|
| + EXPECT_FALSE(IsMediaTimeAdvancing());
|
| +
|
| + // Provide an initial time update so that the pipeline transitions out of the
|
| + // "waiting for time update" state.
|
| + audio_time_cb_.Run(base::TimeDelta::FromMilliseconds(kAudioUpdateTimeMs),
|
| + base::TimeDelta::FromMilliseconds(kAudioUpdateMaxTimeMs));
|
| + EXPECT_EQ(kAudioUpdateTimeMs, GetMediaTimeMs());
|
| +
|
| + // Advance the clock so that GetMediaTime() also advances. This also verifies
|
| + // that the default playback rate is 1.
|
| + EXPECT_TRUE(IsMediaTimeAdvancing());
|
| +
|
| + // Verify that playback rate affects the rate GetMediaTime() advances.
|
| + SetPlaybackRate(2.0f);
|
| + EXPECT_TRUE(IsMediaTimeAdvancing(2.0f));
|
| +
|
| + // Verify that GetMediaTime() is bounded by audio max time.
|
| + DCHECK_GT(GetMediaTimeMs() + 2000, kAudioUpdateMaxTimeMs);
|
| + test_tick_clock_.Advance(base::TimeDelta::FromMilliseconds(2000));
|
| + EXPECT_EQ(kAudioUpdateMaxTimeMs, GetMediaTimeMs());
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, AudioStreamShorterThanVideo) {
|
| + // Replace what's used for interpolating to simulate wall clock time.
|
| + renderer_impl_->SetTimeDeltaInterpolatorForTesting(
|
| + new TimeDeltaInterpolator(&test_tick_clock_));
|
| +
|
| + InitializeWithAudioAndVideo();
|
| + Play();
|
| +
|
| + EXPECT_EQ(kStartPlayingTimeInMs, GetMediaTimeMs());
|
| +
|
| + // Verify that the clock doesn't advance since it hasn't been started by
|
| + // a time update from the audio stream.
|
| + EXPECT_FALSE(IsMediaTimeAdvancing());
|
| +
|
| + // Signal end of audio stream.
|
| + audio_ended_cb_.Run();
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + // Verify that the clock advances.
|
| + EXPECT_TRUE(IsMediaTimeAdvancing());
|
| +
|
| + // Signal end of video stream and make sure OnEnded() callback occurs.
|
| + EXPECT_CALL(time_source_, StopTicking());
|
| + EXPECT_CALL(callbacks_, OnEnded());
|
| + video_ended_cb_.Run();
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, AudioTimeUpdateDuringFlush) {
|
| + // Replace what's used for interpolating to simulate wall clock time.
|
| + renderer_impl_->SetTimeDeltaInterpolatorForTesting(
|
| + new TimeDeltaInterpolator(&test_tick_clock_));
|
| +
|
| + InitializeWithAudio();
|
| + Play();
|
| +
|
| + // Provide an initial time update so that the pipeline transitions out of the
|
| + // "waiting for time update" state.
|
| + audio_time_cb_.Run(base::TimeDelta::FromMilliseconds(kAudioUpdateTimeMs),
|
| + base::TimeDelta::FromMilliseconds(kAudioUpdateMaxTimeMs));
|
| + EXPECT_EQ(kAudioUpdateTimeMs, GetMediaTimeMs());
|
| +
|
| + int64 start_time = GetMediaTimeMs();
|
| +
|
| + EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(DoAll(
|
| + UpdateAudioTime(
|
| + &audio_time_cb_, kAudioUpdateTimeMs + 100, kAudioUpdateMaxTimeMs),
|
| + SetBufferingState(&audio_buffering_state_cb_, BUFFERING_HAVE_NOTHING),
|
| + RunClosure<0>()));
|
| + EXPECT_CALL(time_source_, StopTicking());
|
| + EXPECT_CALL(callbacks_, OnFlushed());
|
| + renderer_impl_->Flush(
|
| + base::Bind(&CallbackHelper::OnFlushed, base::Unretained(&callbacks_)));
|
| +
|
| + // Audio time update during Flush() has no effect.
|
| + EXPECT_EQ(start_time, GetMediaTimeMs());
|
| +
|
| + // Verify that the clock doesn't advance since it hasn't been started by
|
| + // a time update from the audio stream.
|
| + EXPECT_FALSE(IsMediaTimeAdvancing());
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, PostTimeUpdateDuringDestroy) {
|
| + InitializeWithAudioAndVideo();
|
| +
|
| + // Simulate the case where TimeCB is posted during ~AudioRenderer(), which is
|
| + // triggered in ~Renderer().
|
| + base::TimeDelta time = base::TimeDelta::FromMilliseconds(100);
|
| + message_loop_.PostTask(FROM_HERE, base::Bind(audio_time_cb_, time, time));
|
| +
|
| + renderer_impl_.reset();
|
| + message_loop_.RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, AudioStreamEnded) {
|
| + InitializeWithAudio();
|
| + Play();
|
| +
|
| + EXPECT_CALL(time_source_, StopTicking());
|
| + EXPECT_CALL(callbacks_, OnEnded());
|
| +
|
| + audio_ended_cb_.Run();
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, VideoStreamEnded) {
|
| + InitializeWithVideo();
|
| + Play();
|
| +
|
| + // Video ended won't affect |time_source_|.
|
| + EXPECT_CALL(callbacks_, OnEnded());
|
| +
|
| + video_ended_cb_.Run();
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, AudioVideoStreamsEnded) {
|
| + InitializeWithAudioAndVideo();
|
| + Play();
|
| +
|
| + // OnEnded() is called only when all streams have finished.
|
| + audio_ended_cb_.Run();
|
| + base::RunLoop().RunUntilIdle();
|
| +
|
| + EXPECT_CALL(time_source_, StopTicking());
|
| + EXPECT_CALL(callbacks_, OnEnded());
|
| +
|
| + video_ended_cb_.Run();
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, ErrorAfterInitialize) {
|
| + InitializeWithAudio();
|
| + EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_DECODE));
|
| + audio_error_cb_.Run(PIPELINE_ERROR_DECODE);
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, ErrorDuringPlaying) {
|
| + InitializeWithAudio();
|
| + Play();
|
| +
|
| + EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_DECODE));
|
| + audio_error_cb_.Run(PIPELINE_ERROR_DECODE);
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, ErrorDuringFlush) {
|
| + InitializeWithAudio();
|
| + Play();
|
| +
|
| + InSequence s;
|
| + EXPECT_CALL(time_source_, StopTicking());
|
| + EXPECT_CALL(*audio_renderer_, Flush(_)).WillOnce(DoAll(
|
| + AudioError(&audio_error_cb_, PIPELINE_ERROR_DECODE),
|
| + RunClosure<0>()));
|
| + EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_DECODE));
|
| + EXPECT_CALL(callbacks_, OnFlushed());
|
| + renderer_impl_->Flush(
|
| + base::Bind(&CallbackHelper::OnFlushed, base::Unretained(&callbacks_)));
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +TEST_F(RendererImplTest, ErrorAfterFlush) {
|
| + InitializeWithAudio();
|
| + Play();
|
| + Flush(false);
|
| +
|
| + EXPECT_CALL(callbacks_, OnError(PIPELINE_ERROR_DECODE));
|
| + audio_error_cb_.Run(PIPELINE_ERROR_DECODE);
|
| + base::RunLoop().RunUntilIdle();
|
| +}
|
| +
|
| +} // namespace media
|
|
|