| Index: media/filters/decrypting_audio_decoder_unittest.cc
|
| diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..89d2a64ccae893abb6199b42d2c4957350469529
|
| --- /dev/null
|
| +++ b/media/filters/decrypting_audio_decoder_unittest.cc
|
| @@ -0,0 +1,507 @@
|
| +// Copyright (c) 2012 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 <string>
|
| +#include <vector>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/callback_helpers.h"
|
| +#include "base/message_loop.h"
|
| +#include "media/base/buffers.h"
|
| +#include "media/base/data_buffer.h"
|
| +#include "media/base/decoder_buffer.h"
|
| +#include "media/base/decrypt_config.h"
|
| +#include "media/base/mock_callback.h"
|
| +#include "media/base/mock_filters.h"
|
| +#include "media/filters/decrypting_audio_decoder.h"
|
| +#include "media/filters/ffmpeg_decoder_unittest.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +
|
| +using ::testing::_;
|
| +using ::testing::AtMost;
|
| +using ::testing::Invoke;
|
| +using ::testing::IsNull;
|
| +using ::testing::ReturnRef;
|
| +using ::testing::SaveArg;
|
| +using ::testing::StrictMock;
|
| +
|
| +namespace media {
|
| +
|
| +static const int kFakeAudioFrameSize = 16;
|
| +static const uint8 kFakeKeyId[] = { 0x4b, 0x65, 0x79, 0x20, 0x49, 0x44 };
|
| +static const uint8 kFakeIv[DecryptConfig::kDecryptionKeySize] = { 0 };
|
| +
|
| +// Create a fake non-empty encrypted buffer.
|
| +static scoped_refptr<DecoderBuffer> CreateFakeEncryptedBuffer() {
|
| + const int buffer_size = 16; // Need a non-empty buffer;
|
| + scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(buffer_size));
|
| + buffer->SetDecryptConfig(scoped_ptr<DecryptConfig>(new DecryptConfig(
|
| + std::string(reinterpret_cast<const char*>(kFakeKeyId),
|
| + arraysize(kFakeKeyId)),
|
| + std::string(reinterpret_cast<const char*>(kFakeIv), arraysize(kFakeIv)),
|
| + 0,
|
| + std::vector<SubsampleEntry>())));
|
| + return buffer;
|
| +}
|
| +
|
| +// Use anonymous namespace here to prevent the actions to be defined multiple
|
| +// times across multiple test files. Sadly we can't use static for them.
|
| +namespace {
|
| +
|
| +ACTION_P(ReturnBuffer, buffer) {
|
| + arg0.Run(buffer ? DemuxerStream::kOk : DemuxerStream::kAborted, buffer);
|
| +}
|
| +
|
| +ACTION(ReturnConfigChanged) {
|
| + arg0.Run(DemuxerStream::kConfigChanged, scoped_refptr<DecoderBuffer>(NULL));
|
| +}
|
| +
|
| +ACTION_P(RunCallback0, param) {
|
| + if (!arg0.is_null())
|
| + arg0.Run(param);
|
| +}
|
| +
|
| +ACTION_P(RunCallback1, param) {
|
| + arg1.Run(param);
|
| +}
|
| +
|
| +ACTION_P2(RunCallback2, param1, param2) {
|
| + arg1.Run(param1, param2);
|
| +}
|
| +
|
| +ACTION_P2(ResetAndRunCallback, callback, param) {
|
| + base::ResetAndReturn(callback).Run(param);
|
| +}
|
| +
|
| +MATCHER(IsNullCallback, "") {
|
| + return (arg.is_null());
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +class DecryptingAudioDecoderTest : public testing::Test {
|
| + public:
|
| + DecryptingAudioDecoderTest()
|
| + : decoder_(new StrictMock<DecryptingAudioDecoder>(
|
| + base::Bind(&Identity<scoped_refptr<base::MessageLoopProxy> >,
|
| + message_loop_.message_loop_proxy()),
|
| + base::Bind(
|
| + &DecryptingAudioDecoderTest::RequestDecryptorNotification,
|
| + base::Unretained(this)))),
|
| + decryptor_(new StrictMock<MockDecryptor>()),
|
| + demuxer_(new StrictMock<MockDemuxerStream>()),
|
| + encrypted_buffer_(CreateFakeEncryptedBuffer()),
|
| + decoded_frame_(new DataBuffer(kFakeAudioFrameSize)),
|
| + end_of_stream_frame_(new DataBuffer(0)),
|
| + decoded_frame_list_(1, decoded_frame_) {
|
| + }
|
| +
|
| + void InitializeAndExpectStatus(const AudioDecoderConfig& config,
|
| + PipelineStatus status) {
|
| + EXPECT_CALL(*demuxer_, audio_decoder_config())
|
| + .WillRepeatedly(ReturnRef(config));
|
| +
|
| + decoder_->Initialize(demuxer_, NewExpectedStatusCB(status),
|
| + base::Bind(&MockStatisticsCB::OnStatistics,
|
| + base::Unretained(&statistics_cb_)));
|
| + message_loop_.RunAllPending();
|
| + }
|
| +
|
| + void Initialize() {
|
| + EXPECT_CALL(*decryptor_, InitializeAudioDecoderMock(_, _, _))
|
| + .Times(AtMost(1))
|
| + .WillOnce(DoAll(RunCallback1(true), SaveArg<2>(&key_added_cb_)));
|
| + EXPECT_CALL(*this, RequestDecryptorNotification(_))
|
| + .WillOnce(RunCallback0(decryptor_.get()));
|
| +
|
| + config_.Initialize(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
|
| + NULL, 0, true, true);
|
| +
|
| + InitializeAndExpectStatus(config_, PIPELINE_OK);
|
| + EXPECT_EQ(16, decoder_->bits_per_channel());
|
| + EXPECT_EQ(CHANNEL_LAYOUT_STEREO, decoder_->channel_layout());
|
| + EXPECT_EQ(44100, decoder_->samples_per_second());
|
| + }
|
| +
|
| + void ReadAndExpectFrameReadyWith(
|
| + AudioDecoder::Status status,
|
| + const scoped_refptr<Buffer>& audio_frame) {
|
| + if (status != AudioDecoder::kOk)
|
| + EXPECT_CALL(*this, FrameReady(status, IsNull()));
|
| + else
|
| + EXPECT_CALL(*this, FrameReady(status, audio_frame));
|
| +
|
| + decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
|
| + base::Unretained(this)));
|
| + message_loop_.RunAllPending();
|
| + }
|
| +
|
| + // Sets up expectations and actions to put DecryptingAudioDecoder in an
|
| + // active normal decoding state.
|
| + void EnterNormalDecodingState() {
|
| + Decryptor::AudioBuffers end_of_stream_frames_(1, end_of_stream_frame_);
|
| +
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillOnce(ReturnBuffer(encrypted_buffer_))
|
| + .WillRepeatedly(ReturnBuffer(DecoderBuffer::CreateEOSBuffer()));
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillOnce(RunCallback2(Decryptor::kSuccess,
|
| + decoded_frame_list_))
|
| + .WillRepeatedly(RunCallback2(Decryptor::kSuccess,
|
| + end_of_stream_frames_));
|
| + EXPECT_CALL(statistics_cb_, OnStatistics(_));
|
| +
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
|
| + }
|
| +
|
| + // Sets up expectations and actions to put DecryptingAudioDecoder in an end
|
| + // of stream state. This function must be called after
|
| + // EnterNormalDecodingState() to work.
|
| + void EnterEndOfStreamState() {
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, end_of_stream_frame_);
|
| + }
|
| +
|
| + // Make the read callback pending by saving and not firing it.
|
| + void EnterPendingReadState() {
|
| + EXPECT_TRUE(pending_demuxer_read_cb_.is_null());
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillOnce(SaveArg<0>(&pending_demuxer_read_cb_));
|
| + decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
|
| + base::Unretained(this)));
|
| + message_loop_.RunAllPending();
|
| + // Make sure the Read() on the decoder triggers a Read() on the demuxer.
|
| + EXPECT_FALSE(pending_demuxer_read_cb_.is_null());
|
| + }
|
| +
|
| + // Make the audio decode callback pending by saving and not firing it.
|
| + void EnterPendingDecodeState() {
|
| + EXPECT_TRUE(pending_audio_decode_cb_.is_null());
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _))
|
| + .WillOnce(SaveArg<1>(&pending_audio_decode_cb_));
|
| +
|
| + decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
|
| + base::Unretained(this)));
|
| + message_loop_.RunAllPending();
|
| + // Make sure the Read() on the decoder triggers a DecryptAndDecode() on the
|
| + // decryptor.
|
| + EXPECT_FALSE(pending_audio_decode_cb_.is_null());
|
| + }
|
| +
|
| + void EnterWaitingForKeyState() {
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillRepeatedly(RunCallback2(Decryptor::kNoKey,
|
| + Decryptor::AudioBuffers()));
|
| + decoder_->Read(base::Bind(&DecryptingAudioDecoderTest::FrameReady,
|
| + base::Unretained(this)));
|
| + message_loop_.RunAllPending();
|
| + }
|
| +
|
| + void AbortPendingAudioDecodeCB() {
|
| + if (!pending_audio_decode_cb_.is_null()) {
|
| + base::ResetAndReturn(&pending_audio_decode_cb_).Run(
|
| + Decryptor::kSuccess, Decryptor::AudioBuffers());
|
| + }
|
| + }
|
| +
|
| + void Reset() {
|
| + EXPECT_CALL(*decryptor_, ResetDecoder(Decryptor::kAudio))
|
| + .WillRepeatedly(InvokeWithoutArgs(
|
| + this, &DecryptingAudioDecoderTest::AbortPendingAudioDecodeCB));
|
| +
|
| + decoder_->Reset(NewExpectedClosure());
|
| + message_loop_.RunAllPending();
|
| + }
|
| +
|
| + MOCK_METHOD1(RequestDecryptorNotification,
|
| + void(const DecryptingAudioDecoder::DecryptorNotificationCB&));
|
| +
|
| + MOCK_METHOD2(FrameReady, void(AudioDecoder::Status,
|
| + const scoped_refptr<Buffer>&));
|
| +
|
| + MessageLoop message_loop_;
|
| + scoped_refptr<StrictMock<DecryptingAudioDecoder> > decoder_;
|
| + scoped_ptr<StrictMock<MockDecryptor> > decryptor_;
|
| + scoped_refptr<StrictMock<MockDemuxerStream> > demuxer_;
|
| + MockStatisticsCB statistics_cb_;
|
| + AudioDecoderConfig config_;
|
| +
|
| + DemuxerStream::ReadCB pending_demuxer_read_cb_;
|
| + Decryptor::DecoderInitCB pending_init_cb_;
|
| + Decryptor::KeyAddedCB key_added_cb_;
|
| + Decryptor::AudioDecodeCB pending_audio_decode_cb_;
|
| +
|
| + // Constant buffer/frames to be returned by the |demuxer_| and |decryptor_|.
|
| + scoped_refptr<DecoderBuffer> encrypted_buffer_;
|
| + scoped_refptr<Buffer> decoded_frame_;
|
| + scoped_refptr<Buffer> end_of_stream_frame_;
|
| + Decryptor::AudioBuffers decoded_frame_list_;
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(DecryptingAudioDecoderTest);
|
| +};
|
| +
|
| +TEST_F(DecryptingAudioDecoderTest, Initialize_Normal) {
|
| + Initialize();
|
| +}
|
| +
|
| +// Ensure that DecryptingAudioDecoder only accepts encrypted audio.
|
| +TEST_F(DecryptingAudioDecoderTest, Initialize_UnencryptedAudioConfig) {
|
| + AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
|
| + NULL, 0, false);
|
| +
|
| + InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
|
| +}
|
| +
|
| +// Ensure decoder handles invalid audio configs without crashing.
|
| +TEST_F(DecryptingAudioDecoderTest, Initialize_InvalidAudioConfig) {
|
| + AudioDecoderConfig config(kUnknownAudioCodec, 0, CHANNEL_LAYOUT_STEREO, 0,
|
| + NULL, 0, true);
|
| +
|
| + InitializeAndExpectStatus(config, PIPELINE_ERROR_DECODE);
|
| +}
|
| +
|
| +// Ensure decoder handles unsupported audio configs without crashing.
|
| +TEST_F(DecryptingAudioDecoderTest, Initialize_UnsupportedAudioConfig) {
|
| + EXPECT_CALL(*decryptor_, InitializeAudioDecoderMock(_, _, _))
|
| + .WillOnce(RunCallback1(false));
|
| + EXPECT_CALL(*this, RequestDecryptorNotification(_))
|
| + .WillOnce(RunCallback0(decryptor_.get()));
|
| +
|
| + AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
|
| + NULL, 0, true);
|
| + InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
|
| +}
|
| +
|
| +// Test normal decrypt and decode case.
|
| +TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_Normal) {
|
| + Initialize();
|
| + EnterNormalDecodingState();
|
| +}
|
| +
|
| +// Test the case where the decryptor returns error when doing decrypt and
|
| +// decode.
|
| +TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_DecodeError) {
|
| + Initialize();
|
| +
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillRepeatedly(RunCallback2(Decryptor::kError,
|
| + Decryptor::AudioBuffers()));
|
| +
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kDecodeError, NULL);
|
| +}
|
| +
|
| +// Test the case where the decryptor returns kNeedMoreData to ask for more
|
| +// buffers before it can produce a frame.
|
| +TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_NeedMoreData) {
|
| + Initialize();
|
| +
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .Times(2)
|
| + .WillRepeatedly(ReturnBuffer(encrypted_buffer_));
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillOnce(RunCallback2(Decryptor::kNeedMoreData,
|
| + Decryptor::AudioBuffers()))
|
| + .WillRepeatedly(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
|
| + EXPECT_CALL(statistics_cb_, OnStatistics(_))
|
| + .Times(2);
|
| +
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
|
| +}
|
| +
|
| +// Test the case where the decryptor returns multiple decoded frames.
|
| +TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_MultipleFrames) {
|
| + Initialize();
|
| +
|
| + scoped_refptr<Buffer> decoded_frame_a(new DataBuffer(kFakeAudioFrameSize));
|
| + scoped_refptr<Buffer> decoded_frame_b(new DataBuffer(kFakeAudioFrameSize));
|
| + decoded_frame_list_.push_back(decoded_frame_a);
|
| + decoded_frame_list_.push_back(decoded_frame_b);
|
| +
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillOnce(ReturnBuffer(encrypted_buffer_));
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillOnce(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
|
| + EXPECT_CALL(statistics_cb_, OnStatistics(_));
|
| +
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_a);
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_b);
|
| +}
|
| +
|
| +// Test the case where the decryptor receives end-of-stream buffer.
|
| +TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_EndOfStream) {
|
| + Initialize();
|
| + EnterNormalDecodingState();
|
| + EnterEndOfStreamState();
|
| +}
|
| +
|
| +// Test the case where the decryptor returns multiple decoded frames, the last
|
| +// of which is end-of-stream frame.
|
| +TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_MultipleFramesWithEos) {
|
| + Initialize();
|
| +
|
| + scoped_refptr<Buffer> decoded_frame_a(new DataBuffer(kFakeAudioFrameSize));
|
| + scoped_refptr<Buffer> decoded_frame_b(new DataBuffer(kFakeAudioFrameSize));
|
| + Decryptor::AudioBuffers second_decoded_frame_list;
|
| + second_decoded_frame_list.push_back(decoded_frame_a);
|
| + second_decoded_frame_list.push_back(decoded_frame_b);
|
| + second_decoded_frame_list.push_back(end_of_stream_frame_);
|
| +
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillOnce(ReturnBuffer(encrypted_buffer_))
|
| + .WillOnce(ReturnBuffer(DecoderBuffer::CreateEOSBuffer()));
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillOnce(RunCallback2(Decryptor::kSuccess, decoded_frame_list_))
|
| + .WillOnce(RunCallback2(Decryptor::kSuccess, second_decoded_frame_list));
|
| + // Expect only one OnStatistics() here because EOS input buffer doesn't
|
| + // trigger statistics reporting.
|
| + EXPECT_CALL(statistics_cb_, OnStatistics(_));
|
| +
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_);
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_a);
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, decoded_frame_b);
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, end_of_stream_frame_);
|
| +}
|
| +
|
| +// Test the case where the a key is added when the decryptor is in
|
| +// kWaitingForKey state.
|
| +TEST_F(DecryptingAudioDecoderTest, KeyAdded_DuringWaitingForKey) {
|
| + Initialize();
|
| + EnterWaitingForKeyState();
|
| +
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillRepeatedly(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
|
| + EXPECT_CALL(statistics_cb_, OnStatistics(_));
|
| + EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, decoded_frame_));
|
| + key_added_cb_.Run();
|
| + message_loop_.RunAllPending();
|
| +}
|
| +
|
| +// Test the case where the a key is added when the decryptor is in
|
| +// kPendingDecode state.
|
| +TEST_F(DecryptingAudioDecoderTest, KeyAdded_DruingPendingDecode) {
|
| + Initialize();
|
| + EnterPendingDecodeState();
|
| +
|
| + EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
|
| + .WillRepeatedly(RunCallback2(Decryptor::kSuccess, decoded_frame_list_));
|
| + EXPECT_CALL(statistics_cb_, OnStatistics(_));
|
| + EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, decoded_frame_));
|
| + // The audio decode callback is returned after the correct decryption key is
|
| + // added.
|
| + key_added_cb_.Run();
|
| + base::ResetAndReturn(&pending_audio_decode_cb_).Run(
|
| + Decryptor::kNoKey, Decryptor::AudioBuffers());
|
| + message_loop_.RunAllPending();
|
| +}
|
| +
|
| +// Test resetting when the decoder is in kIdle state but has not decoded any
|
| +// frame.
|
| +TEST_F(DecryptingAudioDecoderTest, Reset_DuringIdleAfterInitialization) {
|
| + Initialize();
|
| + Reset();
|
| +}
|
| +
|
| +// Test resetting when the decoder is in kIdle state after it has decoded one
|
| +// frame.
|
| +TEST_F(DecryptingAudioDecoderTest, Reset_DuringIdleAfterDecodedOneFrame) {
|
| + Initialize();
|
| + EnterNormalDecodingState();
|
| + Reset();
|
| +}
|
| +
|
| +// Test resetting when the decoder is in kPendingDemuxerRead state.
|
| +TEST_F(DecryptingAudioDecoderTest, Reset_DuringPendingDemuxerRead) {
|
| + Initialize();
|
| + EnterPendingReadState();
|
| +
|
| + EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
|
| +
|
| + Reset();
|
| + base::ResetAndReturn(&pending_demuxer_read_cb_).Run(DemuxerStream::kOk,
|
| + encrypted_buffer_);
|
| + message_loop_.RunAllPending();
|
| +}
|
| +
|
| +// Test resetting when the decoder is in kPendingDecode state.
|
| +TEST_F(DecryptingAudioDecoderTest, Reset_DuringPendingDecode) {
|
| + Initialize();
|
| + EnterPendingDecodeState();
|
| +
|
| + EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
|
| +
|
| + Reset();
|
| +}
|
| +
|
| +// Test resetting when the decoder is in kWaitingForKey state.
|
| +TEST_F(DecryptingAudioDecoderTest, Reset_DuringWaitingForKey) {
|
| + Initialize();
|
| + EnterWaitingForKeyState();
|
| +
|
| + EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
|
| +
|
| + Reset();
|
| +}
|
| +
|
| +// Test resetting when the decoder has hit end of stream and is in
|
| +// kDecodeFinished state.
|
| +TEST_F(DecryptingAudioDecoderTest, Reset_AfterDecodeFinished) {
|
| + Initialize();
|
| + EnterNormalDecodingState();
|
| + EnterEndOfStreamState();
|
| + Reset();
|
| +}
|
| +
|
| +// Test resetting after the decoder has been reset.
|
| +TEST_F(DecryptingAudioDecoderTest, Reset_AfterReset) {
|
| + Initialize();
|
| + EnterNormalDecodingState();
|
| + Reset();
|
| + Reset();
|
| +}
|
| +
|
| +// Test aborted read on the demuxer stream.
|
| +TEST_F(DecryptingAudioDecoderTest, DemuxerRead_Aborted) {
|
| + Initialize();
|
| +
|
| + // ReturnBuffer() with NULL triggers aborted demuxer read.
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillOnce(ReturnBuffer(scoped_refptr<DecoderBuffer>()));
|
| +
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kOk, NULL);
|
| +}
|
| +
|
| +// Test aborted read on the demuxer stream when the decoder is being reset.
|
| +TEST_F(DecryptingAudioDecoderTest, DemuxerRead_AbortedDuringReset) {
|
| + Initialize();
|
| + EnterPendingReadState();
|
| +
|
| + // Make sure we get a NULL audio frame returned.
|
| + EXPECT_CALL(*this, FrameReady(AudioDecoder::kOk, IsNull()));
|
| +
|
| + Reset();
|
| + base::ResetAndReturn(&pending_demuxer_read_cb_).Run(DemuxerStream::kAborted,
|
| + NULL);
|
| + message_loop_.RunAllPending();
|
| +}
|
| +
|
| +// Test config change on the demuxer stream.
|
| +TEST_F(DecryptingAudioDecoderTest, DemuxerRead_ConfigChanged) {
|
| + Initialize();
|
| +
|
| + EXPECT_CALL(*demuxer_, Read(_))
|
| + .WillOnce(ReturnConfigChanged());
|
| +
|
| + // TODO(xhwang): Update this test when kConfigChanged is supported in
|
| + // DecryptingAudioDecoder.
|
| + ReadAndExpectFrameReadyWith(AudioDecoder::kDecodeError, NULL);
|
| +}
|
| +
|
| +} // namespace media
|
|
|