blob: 980e4084219e8fbb0b4498e8ac2d0d6f3220d017 [file] [log] [blame]
// Copyright 2017 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 "content/browser/media/key_system_support_impl.h"
#include <string>
#include "base/callback_helpers.h"
#include "base/containers/contains.h"
#include "base/logging.h"
#include "base/test/gmock_callback_support.h"
#include "base/test/mock_callback.h"
#include "base/token.h"
#include "content/public/test/browser_task_environment.h"
#include "media/base/video_codecs.h"
#include "media/cdm/cdm_capability.h"
#include "media/cdm/cdm_type.h"
#include "mojo/public/cpp/bindings/equals_traits.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace content {
using AudioCodec = media::AudioCodec;
using VideoCodec = media::VideoCodec;
using EncryptionScheme = media::EncryptionScheme;
using CdmSessionType = media::CdmSessionType;
using Robustness = CdmInfo::Robustness;
using base::test::RunOnceCallback;
using media::CdmCapability;
using media::mojom::KeySystemCapability;
using testing::_;
using testing::SaveArg;
const char kTestKeySystem[] = "com.example.somesystem";
// Ids to keep track of observers.
const int kObserver1 = 1;
const int kObserver2 = 2;
ACTION_TEMPLATE(PostOnceCallback,
HAS_1_TEMPLATE_PARAMS(int, k),
AND_1_VALUE_PARAMS(p0)) {
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::BindOnce(std::move(std::get<k>(args)), p0));
}
namespace {
using KeySystemSupportCB =
base::RepeatingCallback<void(KeySystemCapabilityPtrMap)>;
class KeySystemSupportObserverImpl
: public media::mojom::KeySystemSupportObserver {
public:
explicit KeySystemSupportObserverImpl(KeySystemSupportCB cb)
: key_system_support_cb_(std::move(cb)) {}
KeySystemSupportObserverImpl(const KeySystemSupportObserverImpl&) = delete;
KeySystemSupportObserverImpl& operator=(const KeySystemSupportObserverImpl&) =
delete;
~KeySystemSupportObserverImpl() override = default;
// media::mojom::KeySystemSupportObserver
void OnKeySystemSupportUpdated(KeySystemCapabilityPtrMap capabilities) final {
key_system_support_cb_.Run(std::move(capabilities));
}
private:
KeySystemSupportCB key_system_support_cb_;
};
CdmCapability TestCdmCapability() {
return CdmCapability(
{AudioCodec::kVorbis}, {{VideoCodec::kVP8, {}}, {VideoCodec::kVP9, {}}},
{EncryptionScheme::kCenc, EncryptionScheme::kCbcs},
{CdmSessionType::kTemporary, CdmSessionType::kPersistentLicense});
}
KeySystemCapabilities TestKeySystemCapabilities(
absl::optional<CdmCapability> sw_secure_capability,
absl::optional<CdmCapability> hw_secure_capability) {
KeySystemCapabilities key_system_capabilities;
key_system_capabilities[kTestKeySystem] = KeySystemCapability(
std::move(sw_secure_capability), std::move(hw_secure_capability));
return key_system_capabilities;
}
} // namespace
class KeySystemSupportImplTest : public testing::Test {
public:
KeySystemSupportImplTest() {
LOG(ERROR) << __func__;
key_system_support_impl_.SetGetKeySystemCapabilitiesUpdateCbForTesting(
get_support_cb_.Get());
key_system_support_impl_.Bind(
key_system_support_.BindNewPipeAndPassReceiver());
}
void OnKeySystemSupportUpdated(int observer_id,
base::OnceClosure done_cb,
KeySystemCapabilityPtrMap capabilities) {
results_[observer_id].push_back(std::move(capabilities));
std::move(done_cb).Run();
}
protected:
void GetKeySystemSupport() {
DVLOG(1) << __func__;
base::RunLoop run_loop;
mojo::PendingRemote<media::mojom::KeySystemSupportObserver> observer_remote;
mojo::MakeSelfOwnedReceiver(
std::make_unique<KeySystemSupportObserverImpl>(base::BindRepeating(
&KeySystemSupportImplTest::OnKeySystemSupportUpdated,
base::Unretained(this), kObserver1, run_loop.QuitClosure())),
observer_remote.InitWithNewPipeAndPassReceiver());
key_system_support_->AddObserver(std::move(observer_remote));
run_loop.Run();
}
BrowserTaskEnvironment task_environment_;
KeySystemSupportImpl key_system_support_impl_;
mojo::Remote<media::mojom::KeySystemSupport> key_system_support_;
base::MockCallback<KeySystemSupportImpl::GetKeySystemCapabilitiesUpdateCB>
get_support_cb_;
// KeySystemSupport update results. It's a map from the "observer ID" to the
// list of updates received by that observer.
std::map<int, std::vector<KeySystemCapabilityPtrMap>> results_;
};
TEST_F(KeySystemSupportImplTest, NoKeySystems) {
EXPECT_CALL(get_support_cb_, Run(_))
.WillOnce(RunOnceCallback<0>(KeySystemCapabilities()));
GetKeySystemSupport();
EXPECT_EQ(results_.size(), 1u); // One observer
EXPECT_TRUE(results_.count(kObserver1)); // Observer 1
EXPECT_EQ(results_[kObserver1].size(), 1u); // One update for observer 1
const auto& capabilities = results_[kObserver1][0];
EXPECT_TRUE(capabilities.empty()); // No capabilities
}
TEST_F(KeySystemSupportImplTest, OneObserver) {
EXPECT_CALL(get_support_cb_, Run(_))
.WillOnce(RunOnceCallback<0>(
TestKeySystemCapabilities(TestCdmCapability(), absl::nullopt)));
GetKeySystemSupport();
EXPECT_EQ(results_.size(), 1u); // One observer
EXPECT_TRUE(results_.count(kObserver1)); // Observer 1
EXPECT_EQ(results_[kObserver1].size(), 1u); // One update for observer 1
auto& capabilities = results_[kObserver1][0];
ASSERT_TRUE(capabilities.count(kTestKeySystem));
const auto& capability = capabilities[kTestKeySystem];
EXPECT_TRUE(capability->sw_secure_capability);
EXPECT_FALSE(capability->hw_secure_capability);
}
TEST_F(KeySystemSupportImplTest, TwoObservers) {
EXPECT_CALL(get_support_cb_, Run(_))
.WillOnce(RunOnceCallback<0>(
TestKeySystemCapabilities(TestCdmCapability(), absl::nullopt)));
base::RunLoop run_loop;
mojo::PendingRemote<media::mojom::KeySystemSupportObserver> observer_1_remote;
mojo::PendingRemote<media::mojom::KeySystemSupportObserver> observer_2_remote;
mojo::MakeSelfOwnedReceiver(
std::make_unique<KeySystemSupportObserverImpl>(base::BindRepeating(
&KeySystemSupportImplTest::OnKeySystemSupportUpdated,
base::Unretained(this), kObserver1, base::DoNothing())),
observer_1_remote.InitWithNewPipeAndPassReceiver());
mojo::MakeSelfOwnedReceiver(
std::make_unique<KeySystemSupportObserverImpl>(base::BindRepeating(
&KeySystemSupportImplTest::OnKeySystemSupportUpdated,
base::Unretained(this), kObserver2, run_loop.QuitClosure())),
observer_2_remote.InitWithNewPipeAndPassReceiver());
key_system_support_->AddObserver(std::move(observer_1_remote));
key_system_support_->AddObserver(std::move(observer_2_remote));
run_loop.Run();
EXPECT_EQ(results_.size(), 2u); // Two observers
EXPECT_TRUE(results_.count(kObserver1)); // Observer 1
EXPECT_EQ(results_[kObserver1].size(), 1u); // One update for observer 1
auto& capabilities = results_[kObserver1][0];
ASSERT_TRUE(capabilities.count(kTestKeySystem));
const auto& capability = capabilities[kTestKeySystem];
EXPECT_TRUE(capability->sw_secure_capability);
EXPECT_FALSE(capability->hw_secure_capability);
EXPECT_TRUE(results_.count(kObserver2)); // Observer 2
EXPECT_EQ(results_[kObserver2].size(), 1u); // One update for observer 1
EXPECT_TRUE(mojo::Equals(results_[kObserver1][0], results_[kObserver2][0]));
}
TEST_F(KeySystemSupportImplTest, TwoUpdates) {
KeySystemCapabilitiesUpdateCB callback;
EXPECT_CALL(get_support_cb_, Run(_)).WillOnce(SaveArg<0>(&callback));
base::RunLoop run_loop_1;
mojo::PendingRemote<media::mojom::KeySystemSupportObserver> observer_remote;
mojo::MakeSelfOwnedReceiver(
std::make_unique<KeySystemSupportObserverImpl>(base::BindRepeating(
&KeySystemSupportImplTest::OnKeySystemSupportUpdated,
base::Unretained(this), kObserver1, base::DoNothing())),
observer_remote.InitWithNewPipeAndPassReceiver());
key_system_support_->AddObserver(std::move(observer_remote));
run_loop_1.RunUntilIdle();
// Update twice, one with hardware capability, one without.
base::RunLoop run_loop_2;
callback.Run(TestKeySystemCapabilities(TestCdmCapability(), absl::nullopt));
callback.Run(
TestKeySystemCapabilities(TestCdmCapability(), TestCdmCapability()));
run_loop_2.RunUntilIdle();
EXPECT_EQ(results_.size(), 1u); // One observer
EXPECT_TRUE(results_.count(kObserver1)); // Observer 1
EXPECT_EQ(results_[kObserver1].size(), 2u); // Two updates for observer 1
auto& capabilities_1 = results_[kObserver1][0];
ASSERT_TRUE(capabilities_1.count(kTestKeySystem));
const auto& capability_1 = capabilities_1[kTestKeySystem];
EXPECT_TRUE(capability_1->sw_secure_capability);
EXPECT_FALSE(capability_1->hw_secure_capability);
auto& capabilities_2 = results_[kObserver1][1];
ASSERT_TRUE(capabilities_2.count(kTestKeySystem));
const auto& capability_2 = capabilities_2[kTestKeySystem];
EXPECT_TRUE(capability_2->sw_secure_capability);
EXPECT_TRUE(capability_2->hw_secure_capability);
}
} // namespace content