-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "media/filters/decrypting_audio_decoder.h"
+
#include <stdint.h>
#include <string>
#include "base/bind.h"
#include "base/callback_helpers.h"
-#include "base/macros.h"
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/test/gmock_callback_support.h"
+#include "base/test/gmock_move_support.h"
+#include "base/test/task_environment.h"
#include "media/base/audio_buffer.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
-#include "media/base/gmock_callback_support.h"
#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/base/timestamp_constants.h"
-#include "media/filters/decrypting_audio_decoder.h"
#include "testing/gmock/include/gmock/gmock.h"
+using ::base::test::RunOnceCallback;
using ::testing::_;
using ::testing::AtMost;
using ::testing::Return;
-using ::testing::SaveArg;
using ::testing::StrictMock;
namespace media {
scoped_refptr<DecoderBuffer> buffer(new DecoderBuffer(buffer_size));
buffer->set_decrypt_config(DecryptConfig::CreateCencConfig(
std::string(reinterpret_cast<const char*>(kFakeKeyId),
- arraysize(kFakeKeyId)),
- std::string(reinterpret_cast<const char*>(kFakeIv), arraysize(kFakeIv)),
+ std::size(kFakeKeyId)),
+ std::string(reinterpret_cast<const char*>(kFakeIv), std::size(kFakeIv)),
std::vector<SubsampleEntry>()));
return buffer;
}
class DecryptingAudioDecoderTest : public testing::Test {
public:
DecryptingAudioDecoderTest()
- : decoder_(new DecryptingAudioDecoder(message_loop_.task_runner(),
- &media_log_)),
+ : decoder_(new DecryptingAudioDecoder(
+ task_environment_.GetMainThreadTaskRunner(),
+ &media_log_)),
cdm_context_(new StrictMock<MockCdmContext>()),
decryptor_(new StrictMock<MockDecryptor>()),
num_decrypt_and_decode_calls_(0),
num_frames_in_decryptor_(0),
encrypted_buffer_(CreateFakeEncryptedBuffer()),
- decoded_frame_(NULL),
+ decoded_frame_(nullptr),
decoded_frame_list_() {}
+ DecryptingAudioDecoderTest(const DecryptingAudioDecoderTest&) = delete;
+ DecryptingAudioDecoderTest& operator=(const DecryptingAudioDecoderTest&) =
+ delete;
+
~DecryptingAudioDecoderTest() override { Destroy(); }
void InitializeAndExpectResult(const AudioDecoderConfig& config,
decoded_frame_list_.push_back(decoded_frame_);
decoder_->Initialize(
- config, cdm_context_.get(), NewExpectedBoolCB(success),
- base::Bind(&DecryptingAudioDecoderTest::FrameReady,
- base::Unretained(this)),
- base::Bind(&DecryptingAudioDecoderTest::OnWaitingForDecryptionKey,
- base::Unretained(this)));
+ config, cdm_context_.get(),
+ base::BindOnce(
+ [](bool success, DecoderStatus status) {
+ EXPECT_EQ(status.is_ok(), success);
+ },
+ success),
+ base::BindRepeating(&DecryptingAudioDecoderTest::FrameReady,
+ base::Unretained(this)),
+ base::BindRepeating(&DecryptingAudioDecoderTest::OnWaiting,
+ base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
SetCdmType(CDM_WITH_DECRYPTOR);
EXPECT_CALL(*decryptor_, InitializeAudioDecoder(_, _))
.Times(AtMost(1))
- .WillOnce(RunCallback<1>(true));
- EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
- .WillOnce(SaveArg<1>(&key_added_cb_));
+ .WillOnce(RunOnceCallback<1>(true));
+ EXPECT_CALL(*cdm_context_, RegisterEventCB(_)).WillOnce([&](auto cb) {
+ event_cb_ = cb;
+ return std::make_unique<CallbackRegistration>();
+ });
- config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32,
+ config_.Initialize(AudioCodec::kVorbis, kSampleFormatPlanarF32,
CHANNEL_LAYOUT_STEREO, kSampleRate, EmptyExtraData(),
- AesCtrEncryptionScheme(), base::TimeDelta(), 0);
+ EncryptionScheme::kCenc, base::TimeDelta(), 0);
InitializeAndExpectResult(config_, true);
}
void ReinitializeConfigChange(const AudioDecoderConfig& new_config) {
EXPECT_CALL(*decryptor_, DeinitializeDecoder(Decryptor::kAudio));
EXPECT_CALL(*decryptor_, InitializeAudioDecoder(_, _))
- .WillOnce(RunCallback<1>(true));
- EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
- .WillOnce(SaveArg<1>(&key_added_cb_));
+ .WillOnce(RunOnceCallback<1>(true));
decoder_->Initialize(
- new_config, cdm_context_.get(), NewExpectedBoolCB(true),
- base::Bind(&DecryptingAudioDecoderTest::FrameReady,
- base::Unretained(this)),
- base::Bind(&DecryptingAudioDecoderTest::OnWaitingForDecryptionKey,
- base::Unretained(this)));
+ new_config, cdm_context_.get(),
+ base::BindOnce(
+ [](DecoderStatus status) { EXPECT_TRUE(status.is_ok()); }),
+ base::BindRepeating(&DecryptingAudioDecoderTest::FrameReady,
+ base::Unretained(this)),
+ base::BindRepeating(&DecryptingAudioDecoderTest::OnWaiting,
+ base::Unretained(this)));
}
// Decode |buffer| and expect DecodeDone to get called with |status|.
void DecodeAndExpect(scoped_refptr<DecoderBuffer> buffer,
- DecodeStatus status) {
- EXPECT_CALL(*this, DecodeDone(status));
- decoder_->Decode(buffer, base::Bind(&DecryptingAudioDecoderTest::DecodeDone,
- base::Unretained(this)));
+ DecoderStatus status) {
+ EXPECT_CALL(*this, DecodeDone(HasStatusCode(status)));
+ decoder_->Decode(buffer,
+ base::BindOnce(&DecryptingAudioDecoderTest::DecodeDone,
+ base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
// Helper function to simulate the decrypting and decoding process in the
// |decryptor_| with a decoding delay of kDecodingDelay buffers.
void DecryptAndDecodeAudio(scoped_refptr<DecoderBuffer> encrypted,
- const Decryptor::AudioDecodeCB& audio_decode_cb) {
+ Decryptor::AudioDecodeCB audio_decode_cb) {
num_decrypt_and_decode_calls_++;
if (!encrypted->end_of_stream())
num_frames_in_decryptor_++;
if (num_decrypt_and_decode_calls_ <= kDecodingDelay ||
num_frames_in_decryptor_ == 0) {
- audio_decode_cb.Run(Decryptor::kNeedMoreData, Decryptor::AudioFrames());
+ std::move(audio_decode_cb)
+ .Run(Decryptor::kNeedMoreData, Decryptor::AudioFrames());
return;
}
num_frames_in_decryptor_--;
- audio_decode_cb.Run(Decryptor::kSuccess,
- Decryptor::AudioFrames(1, decoded_frame_));
+ std::move(audio_decode_cb)
+ .Run(Decryptor::kSuccess, Decryptor::AudioFrames(1, decoded_frame_));
}
// Sets up expectations and actions to put DecryptingAudioDecoder in an
Invoke(this, &DecryptingAudioDecoderTest::DecryptAndDecodeAudio));
EXPECT_CALL(*this, FrameReady(decoded_frame_));
for (int i = 0; i < kDecodingDelay + 1; ++i)
- DecodeAndExpect(encrypted_buffer_, DecodeStatus::OK);
+ DecodeAndExpect(encrypted_buffer_, DecoderStatus::Codes::kOk);
}
// Sets up expectations and actions to put DecryptingAudioDecoder in an end
void EnterEndOfStreamState() {
// The codec in the |decryptor_| will be flushed.
EXPECT_CALL(*this, FrameReady(decoded_frame_)).Times(kDecodingDelay);
- DecodeAndExpect(DecoderBuffer::CreateEOSBuffer(), DecodeStatus::OK);
+ DecodeAndExpect(DecoderBuffer::CreateEOSBuffer(),
+ DecoderStatus::Codes::kOk);
EXPECT_EQ(0, num_frames_in_decryptor_);
}
void EnterPendingDecodeState() {
EXPECT_TRUE(!pending_audio_decode_cb_);
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _))
- .WillOnce(SaveArg<1>(&pending_audio_decode_cb_));
+ .WillOnce(MoveArg<1>(&pending_audio_decode_cb_));
decoder_->Decode(encrypted_buffer_,
- base::Bind(&DecryptingAudioDecoderTest::DecodeDone,
- base::Unretained(this)));
+ base::BindOnce(&DecryptingAudioDecoderTest::DecodeDone,
+ base::Unretained(this)));
base::RunLoop().RunUntilIdle();
// Make sure the Decode() on the decoder triggers a DecryptAndDecode() on
// the decryptor.
void EnterWaitingForKeyState() {
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(encrypted_buffer_, _))
.WillRepeatedly(
- RunCallback<1>(Decryptor::kNoKey, Decryptor::AudioFrames()));
- EXPECT_CALL(*this, OnWaitingForDecryptionKey());
+ RunOnceCallback<1>(Decryptor::kNoKey, Decryptor::AudioFrames()));
+ EXPECT_CALL(*this, OnWaiting(WaitingReason::kNoDecryptionKey));
decoder_->Decode(encrypted_buffer_,
- base::Bind(&DecryptingAudioDecoderTest::DecodeDone,
- base::Unretained(this)));
+ base::BindOnce(&DecryptingAudioDecoderTest::DecodeDone,
+ base::Unretained(this)));
base::RunLoop().RunUntilIdle();
}
base::RunLoop().RunUntilIdle();
}
- MOCK_METHOD1(FrameReady, void(const scoped_refptr<AudioBuffer>&));
- MOCK_METHOD1(DecodeDone, void(DecodeStatus));
+ MOCK_METHOD1(FrameReady, void(scoped_refptr<AudioBuffer>));
+ MOCK_METHOD1(DecodeDone, void(DecoderStatus));
- MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
+ MOCK_METHOD1(OnWaiting, void(WaitingReason));
- base::MessageLoop message_loop_;
- MediaLog media_log_;
+ base::test::SingleThreadTaskEnvironment task_environment_;
+ NullMediaLog media_log_;
std::unique_ptr<DecryptingAudioDecoder> decoder_;
std::unique_ptr<StrictMock<MockCdmContext>> cdm_context_;
std::unique_ptr<StrictMock<MockDecryptor>> decryptor_;
int num_frames_in_decryptor_;
Decryptor::DecoderInitCB pending_init_cb_;
- Decryptor::NewKeyCB key_added_cb_;
+ CdmContext::EventCB event_cb_;
Decryptor::AudioDecodeCB pending_audio_decode_cb_;
// Constant buffer/frames, to be used/returned by |decoder_| and |decryptor_|.
scoped_refptr<DecoderBuffer> encrypted_buffer_;
scoped_refptr<AudioBuffer> decoded_frame_;
Decryptor::AudioFrames decoded_frame_list_;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(DecryptingAudioDecoderTest);
};
TEST_F(DecryptingAudioDecoderTest, Initialize_Normal) {
// Ensure decoder handles invalid audio configs without crashing.
TEST_F(DecryptingAudioDecoderTest, Initialize_InvalidAudioConfig) {
- AudioDecoderConfig config(kUnknownAudioCodec, kUnknownSampleFormat,
+ AudioDecoderConfig config(AudioCodec::kUnknown, kUnknownSampleFormat,
CHANNEL_LAYOUT_STEREO, 0, EmptyExtraData(),
- AesCtrEncryptionScheme());
+ EncryptionScheme::kCenc);
InitializeAndExpectResult(config, false);
}
// Ensure decoder handles unsupported audio configs without crashing.
TEST_F(DecryptingAudioDecoderTest, Initialize_UnsupportedAudioConfig) {
SetCdmType(CDM_WITH_DECRYPTOR);
+ EXPECT_CALL(*cdm_context_, RegisterEventCB(_)).WillOnce([&](auto cb) {
+ event_cb_ = cb;
+ return std::make_unique<CallbackRegistration>();
+ });
EXPECT_CALL(*decryptor_, InitializeAudioDecoder(_, _))
- .WillOnce(RunCallback<1>(false));
+ .WillOnce(RunOnceCallback<1>(false));
- AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
+ AudioDecoderConfig config(AudioCodec::kVorbis, kSampleFormatPlanarF32,
CHANNEL_LAYOUT_STEREO, kSampleRate,
- EmptyExtraData(), AesCtrEncryptionScheme());
+ EmptyExtraData(), EncryptionScheme::kCenc);
InitializeAndExpectResult(config, false);
}
TEST_F(DecryptingAudioDecoderTest, Initialize_CdmWithoutDecryptor) {
SetCdmType(CDM_WITHOUT_DECRYPTOR);
- AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
+ AudioDecoderConfig config(AudioCodec::kVorbis, kSampleFormatPlanarF32,
CHANNEL_LAYOUT_STEREO, kSampleRate,
- EmptyExtraData(), AesCtrEncryptionScheme());
+ EmptyExtraData(), EncryptionScheme::kCenc);
InitializeAndExpectResult(config, false);
}
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
.WillRepeatedly(
- RunCallback<1>(Decryptor::kError, Decryptor::AudioFrames()));
+ RunOnceCallback<1>(Decryptor::kError, Decryptor::AudioFrames()));
- DecodeAndExpect(encrypted_buffer_, DecodeStatus::DECODE_ERROR);
+ DecodeAndExpect(encrypted_buffer_, DecoderStatus::Codes::kFailed);
}
// Test the case where the decryptor returns multiple decoded frames.
decoded_frame_list_.push_back(frame_b);
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
- .WillOnce(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
+ .WillOnce(RunOnceCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
EXPECT_CALL(*this, FrameReady(decoded_frame_));
EXPECT_CALL(*this, FrameReady(frame_a));
EXPECT_CALL(*this, FrameReady(frame_b));
- DecodeAndExpect(encrypted_buffer_, DecodeStatus::OK);
+ DecodeAndExpect(encrypted_buffer_, DecoderStatus::Codes::kOk);
}
// Test the case where the decryptor receives end-of-stream buffer.
EXPECT_CALL(*decryptor_, InitializeAudioDecoder(_, _))
.Times(AtMost(1))
- .WillOnce(RunCallback<1>(true));
+ .WillOnce(RunOnceCallback<1>(true));
// The new config is different from the initial config in bits-per-channel,
// channel layout and samples_per_second.
- AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarS16,
+ AudioDecoderConfig new_config(AudioCodec::kVorbis, kSampleFormatPlanarS16,
CHANNEL_LAYOUT_5_1, 88200, EmptyExtraData(),
- AesCtrEncryptionScheme());
+ EncryptionScheme::kCenc);
EXPECT_NE(new_config.bits_per_channel(), config_.bits_per_channel());
EXPECT_NE(new_config.channel_layout(), config_.channel_layout());
EXPECT_NE(new_config.samples_per_second(), config_.samples_per_second());
EXPECT_CALL(*decryptor_, InitializeAudioDecoder(_, _))
.Times(AtMost(1))
- .WillOnce(RunCallback<1>(true));
+ .WillOnce(RunOnceCallback<1>(true));
// The new config is different from the initial config in bits-per-channel,
// channel layout and samples_per_second.
- AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarS16,
+ AudioDecoderConfig new_config(AudioCodec::kVorbis, kSampleFormatPlanarS16,
CHANNEL_LAYOUT_5_1, 88200, EmptyExtraData(),
- Unencrypted());
+ EncryptionScheme::kUnencrypted);
EXPECT_NE(new_config.bits_per_channel(), config_.bits_per_channel());
EXPECT_NE(new_config.channel_layout(), config_.channel_layout());
EXPECT_NE(new_config.samples_per_second(), config_.samples_per_second());
EnterWaitingForKeyState();
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
- .WillRepeatedly(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
+ .WillRepeatedly(
+ RunOnceCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
EXPECT_CALL(*this, FrameReady(decoded_frame_));
- EXPECT_CALL(*this, DecodeDone(DecodeStatus::OK));
- key_added_cb_.Run();
+ EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
+ event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
base::RunLoop().RunUntilIdle();
}
EnterPendingDecodeState();
EXPECT_CALL(*decryptor_, DecryptAndDecodeAudio(_, _))
- .WillRepeatedly(RunCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
+ .WillRepeatedly(
+ RunOnceCallback<1>(Decryptor::kSuccess, decoded_frame_list_));
EXPECT_CALL(*this, FrameReady(decoded_frame_));
- EXPECT_CALL(*this, DecodeDone(DecodeStatus::OK));
+ EXPECT_CALL(*this, DecodeDone(IsOkStatus()));
// The audio decode callback is returned after the correct decryption key is
// added.
- key_added_cb_.Run();
+ event_cb_.Run(CdmContext::Event::kHasAdditionalUsableKey);
std::move(pending_audio_decode_cb_)
.Run(Decryptor::kNoKey, Decryptor::AudioFrames());
base::RunLoop().RunUntilIdle();
Initialize();
EnterPendingDecodeState();
- EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+ EXPECT_CALL(*this, DecodeDone(HasStatusCode(DecoderStatus::Codes::kAborted)));
Reset();
}
Initialize();
EnterWaitingForKeyState();
- EXPECT_CALL(*this, DecodeDone(DecodeStatus::ABORTED));
+ EXPECT_CALL(*this, DecodeDone(HasStatusCode(DecoderStatus::Codes::kAborted)));
Reset();
}