summaryrefslogtreecommitdiff
path: root/chromium/media/mojo/services
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-24 12:15:48 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2018-08-28 13:30:04 +0000
commitb014812705fc80bff0a5c120dfcef88f349816dc (patch)
tree25a2e2d9fa285f1add86aa333389a839f81a39ae /chromium/media/mojo/services
parent9f4560b1027ae06fdb497023cdcaf91b8511fa74 (diff)
downloadqtwebengine-chromium-b014812705fc80bff0a5c120dfcef88f349816dc.tar.gz
BASELINE: Update Chromium to 68.0.3440.125
Change-Id: I23f19369e01f688e496f5bf179abb521ad73874f Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/media/mojo/services')
-rw-r--r--chromium/media/mojo/services/BUILD.gn11
-rw-r--r--chromium/media/mojo/services/OWNERS3
-rw-r--r--chromium/media/mojo/services/cdm_manifest.json2
-rw-r--r--chromium/media/mojo/services/cdm_service.cc43
-rw-r--r--chromium/media/mojo/services/cdm_service.h8
-rw-r--r--chromium/media/mojo/services/cdm_service_unittest.cc91
-rw-r--r--chromium/media/mojo/services/cdm_service_unittest_manifest.json2
-rw-r--r--chromium/media/mojo/services/gpu_mojo_media_client.cc26
-rw-r--r--chromium/media/mojo/services/gpu_mojo_media_client.h6
-rw-r--r--chromium/media/mojo/services/interface_factory_impl.cc128
-rw-r--r--chromium/media/mojo/services/interface_factory_impl.h21
-rw-r--r--chromium/media/mojo/services/media_manifest.json2
-rw-r--r--chromium/media/mojo/services/media_resource_shim.cc4
-rw-r--r--chromium/media/mojo/services/media_resource_shim.h1
-rw-r--r--chromium/media/mojo/services/media_service.h5
-rw-r--r--chromium/media/mojo/services/media_service_factory.cc5
-rw-r--r--chromium/media/mojo/services/media_service_factory.h2
-rw-r--r--chromium/media/mojo/services/media_service_unittest.cc319
-rw-r--r--chromium/media/mojo/services/mojo_audio_decoder_service.cc2
-rw-r--r--chromium/media/mojo/services/mojo_audio_input_stream.cc20
-rw-r--r--chromium/media/mojo/services/mojo_audio_input_stream.h4
-rw-r--r--chromium/media/mojo/services/mojo_audio_input_stream_observer.cc31
-rw-r--r--chromium/media/mojo/services/mojo_audio_input_stream_observer.h35
-rw-r--r--chromium/media/mojo/services/mojo_audio_input_stream_observer_unittest.cc64
-rw-r--r--chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc44
-rw-r--r--chromium/media/mojo/services/mojo_audio_output_stream.cc45
-rw-r--r--chromium/media/mojo/services/mojo_audio_output_stream.h23
-rw-r--r--chromium/media/mojo/services/mojo_audio_output_stream_provider.cc38
-rw-r--r--chromium/media/mojo/services/mojo_audio_output_stream_provider.h12
-rw-r--r--chromium/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc38
-rw-r--r--chromium/media/mojo/services/mojo_audio_output_stream_unittest.cc98
-rw-r--r--chromium/media/mojo/services/mojo_cdm_service.cc15
-rw-r--r--chromium/media/mojo/services/mojo_cdm_service.h2
-rw-r--r--chromium/media/mojo/services/mojo_cdm_service_context.cc11
-rw-r--r--chromium/media/mojo/services/mojo_decryptor_service.cc35
-rw-r--r--chromium/media/mojo/services/mojo_decryptor_service.h27
-rw-r--r--chromium/media/mojo/services/mojo_jpeg_decode_accelerator_service_unittest.cc2
-rw-r--r--chromium/media/mojo/services/mojo_jpeg_encode_accelerator_service.cc9
-rw-r--r--chromium/media/mojo/services/mojo_media_client.cc21
-rw-r--r--chromium/media/mojo/services/mojo_media_client.h32
-rw-r--r--chromium/media/mojo/services/mojo_media_log.cc5
-rw-r--r--chromium/media/mojo/services/mojo_media_log.h6
-rw-r--r--chromium/media/mojo/services/mojo_renderer_service.cc29
-rw-r--r--chromium/media/mojo/services/mojo_renderer_service.h27
-rw-r--r--chromium/media/mojo/services/mojo_video_decoder_service.cc67
-rw-r--r--chromium/media/mojo/services/mojo_video_decoder_service.h6
-rw-r--r--chromium/media/mojo/services/test_mojo_media_client.cc60
-rw-r--r--chromium/media/mojo/services/test_mojo_media_client.h25
-rw-r--r--chromium/media/mojo/services/watch_time_recorder.cc90
-rw-r--r--chromium/media/mojo/services/watch_time_recorder.h3
-rw-r--r--chromium/media/mojo/services/watch_time_recorder_unittest.cc67
51 files changed, 962 insertions, 710 deletions
diff --git a/chromium/media/mojo/services/BUILD.gn b/chromium/media/mojo/services/BUILD.gn
index 4d87502453f..938b4c6a003 100644
--- a/chromium/media/mojo/services/BUILD.gn
+++ b/chromium/media/mojo/services/BUILD.gn
@@ -32,8 +32,6 @@ component("services") {
"mojo_audio_decoder_service.h",
"mojo_audio_input_stream.cc",
"mojo_audio_input_stream.h",
- "mojo_audio_input_stream_observer.cc",
- "mojo_audio_input_stream_observer.h",
"mojo_audio_output_stream.cc",
"mojo_audio_output_stream.h",
"mojo_audio_output_stream_provider.cc",
@@ -103,7 +101,6 @@ component("services") {
"//media/gpu/ipc/service",
"//media/mojo/common",
"//media/mojo/common:mojo_shared_buffer_video_frame",
- "//mojo/common",
"//services/metrics/public/cpp:metrics_cpp",
"//services/metrics/public/cpp:ukm_builders",
"//services/service_manager/public/mojom",
@@ -133,7 +130,11 @@ component("services") {
"mojo_cdm_proxy_service.cc",
"mojo_cdm_proxy_service.h",
]
- deps += [ "//media/cdm:cdm_api" ]
+ deps += [
+ "//media/cdm:cdm_api",
+ "//media/cdm:cdm_paths",
+ "//media/cdm/library_cdm/clear_key_cdm:clear_key_cdm_proxy",
+ ]
# TODO(xhwang): Ideally media should not worry about sandbox. Find a way to
# remove this dependency.
@@ -161,7 +162,6 @@ source_set("unit_tests") {
sources = [
"deferred_destroy_strong_binding_set_unittest.cc",
"media_metrics_provider_unittest.cc",
- "mojo_audio_input_stream_observer_unittest.cc",
"mojo_audio_input_stream_unittest.cc",
"mojo_audio_output_stream_provider_unittest.cc",
"mojo_audio_output_stream_unittest.cc",
@@ -238,6 +238,7 @@ service_test("media_service_unittests") {
":services",
"//base",
"//media:test_support",
+ "//media/cdm:cdm_paths",
"//media/mojo/clients",
"//media/mojo/common",
"//media/mojo/interfaces",
diff --git a/chromium/media/mojo/services/OWNERS b/chromium/media/mojo/services/OWNERS
index fce6c7aef0b..da9d4b5c016 100644
--- a/chromium/media/mojo/services/OWNERS
+++ b/chromium/media/mojo/services/OWNERS
@@ -15,3 +15,6 @@ per-file test_manifest.json=file://ipc/SECURITY_OWNERS
per-file pipeline_apptest_manifest.json=set noparent
per-file pipeline_apptest_manifest.json=file://ipc/SECURITY_OWNERS
+
+per-file mojo_audio_output*=file://media/audio/OWNERS
+per-file mojo_audio_input*=file://media/audio/OWNERS
diff --git a/chromium/media/mojo/services/cdm_manifest.json b/chromium/media/mojo/services/cdm_manifest.json
index 96a06dd68f2..78ea3fccf42 100644
--- a/chromium/media/mojo/services/cdm_manifest.json
+++ b/chromium/media/mojo/services/cdm_manifest.json
@@ -5,7 +5,7 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "media:cdm": [ "media::mojom::CdmService" ]
+ "media:cdm": [ "media.mojom.CdmService" ]
},
"requires": {
"*": [ "app" ]
diff --git a/chromium/media/mojo/services/cdm_service.cc b/chromium/media/mojo/services/cdm_service.cc
index 678476e763b..1fdc540dd75 100644
--- a/chromium/media/mojo/services/cdm_service.cc
+++ b/chromium/media/mojo/services/cdm_service.cc
@@ -22,44 +22,49 @@ namespace media {
namespace {
+using service_manager::ServiceContextRef;
+
constexpr base::TimeDelta kServiceContextRefReleaseDelay =
base::TimeDelta::FromSeconds(5);
-void DeleteServiceContextRef(service_manager::ServiceContextRef* ref) {
+void DeleteServiceContextRef(ServiceContextRef* ref) {
delete ref;
}
// Starting a new process and loading the library CDM could be expensive. This
-// class helps delay the release of service_manager::ServiceContextRef by
+// class helps delay the release of ServiceContextRef by
// |kServiceContextRefReleaseDelay|, which will ultimately delay CdmService
// destruction by the same delay as well. This helps reduce the chance of
// destroying the CdmService and immediately creates it (in another process) in
// cases like navigation, which could cause long service connection delays.
-class DelayedReleaseServiceContextRef
- : public service_manager::ServiceContextRef {
+class DelayedReleaseServiceContextRef : public ServiceContextRef {
public:
- explicit DelayedReleaseServiceContextRef(
- std::unique_ptr<service_manager::ServiceContextRef> ref)
+ DelayedReleaseServiceContextRef(std::unique_ptr<ServiceContextRef> ref,
+ base::TimeDelta delay)
: ref_(std::move(ref)),
- task_runner_(base::ThreadTaskRunnerHandle::Get()) {}
+ delay_(delay),
+ task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ DCHECK_GT(delay_, base::TimeDelta());
+ }
~DelayedReleaseServiceContextRef() override {
service_manager::ServiceContextRef* ref_ptr = ref_.release();
if (!task_runner_->PostNonNestableDelayedTask(
FROM_HERE, base::BindOnce(&DeleteServiceContextRef, ref_ptr),
- kServiceContextRefReleaseDelay)) {
+ delay_)) {
DeleteServiceContextRef(ref_ptr);
}
}
- // service_manager::ServiceContextRef implementation.
+ // ServiceContextRef implementation.
std::unique_ptr<ServiceContextRef> Clone() override {
NOTIMPLEMENTED();
return nullptr;
}
private:
- std::unique_ptr<service_manager::ServiceContextRef> ref_;
+ std::unique_ptr<ServiceContextRef> ref_;
+ base::TimeDelta delay_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(DelayedReleaseServiceContextRef);
@@ -85,10 +90,9 @@ class DelayedReleaseServiceContextRef
// details.
class CdmFactoryImpl : public DeferredDestroy<mojom::CdmFactory> {
public:
- CdmFactoryImpl(
- CdmService::Client* client,
- service_manager::mojom::InterfaceProviderPtr interfaces,
- std::unique_ptr<service_manager::ServiceContextRef> service_context_ref)
+ CdmFactoryImpl(CdmService::Client* client,
+ service_manager::mojom::InterfaceProviderPtr interfaces,
+ std::unique_ptr<ServiceContextRef> service_context_ref)
: client_(client),
interfaces_(std::move(interfaces)),
service_context_ref_(std::move(service_context_ref)) {
@@ -147,7 +151,7 @@ class CdmFactoryImpl : public DeferredDestroy<mojom::CdmFactory> {
CdmService::Client* client_;
service_manager::mojom::InterfaceProviderPtr interfaces_;
mojo::StrongBindingSet<mojom::ContentDecryptionModule> cdm_bindings_;
- std::unique_ptr<service_manager::ServiceContextRef> service_context_ref_;
+ std::unique_ptr<ServiceContextRef> service_context_ref_;
std::unique_ptr<media::CdmFactory> cdm_factory_;
base::OnceClosure destroy_cb_;
@@ -157,7 +161,8 @@ class CdmFactoryImpl : public DeferredDestroy<mojom::CdmFactory> {
} // namespace
CdmService::CdmService(std::unique_ptr<Client> client)
- : client_(std::move(client)) {
+ : client_(std::move(client)),
+ service_release_delay_(kServiceContextRefReleaseDelay) {
DVLOG(1) << __func__;
DCHECK(client_);
registry_.AddInterface<mojom::CdmService>(
@@ -260,10 +265,10 @@ void CdmService::CreateCdmFactory(
if (!client_)
return;
- std::unique_ptr<service_manager::ServiceContextRef> service_context_ref =
- is_delayed_service_release_enabled
+ std::unique_ptr<ServiceContextRef> service_context_ref =
+ service_release_delay_ > base::TimeDelta()
? std::make_unique<DelayedReleaseServiceContextRef>(
- ref_factory_->CreateRef())
+ ref_factory_->CreateRef(), service_release_delay_)
: ref_factory_->CreateRef();
cdm_factory_bindings_.AddBinding(
diff --git a/chromium/media/mojo/services/cdm_service.h b/chromium/media/mojo/services/cdm_service.h
index 22f418c4bfe..67771567730 100644
--- a/chromium/media/mojo/services/cdm_service.h
+++ b/chromium/media/mojo/services/cdm_service.h
@@ -53,8 +53,10 @@ class MEDIA_MOJO_EXPORT CdmService : public service_manager::Service,
explicit CdmService(std::unique_ptr<Client> client);
~CdmService() final;
- void DisableDelayedServiceReleaseForTesting() {
- is_delayed_service_release_enabled = false;
+ // By default CdmService release is delayed. Overrides the delay with |delay|.
+ // If |delay| is 0, delayed service release will be disabled.
+ void SetServiceReleaseDelayForTesting(base::TimeDelta delay) {
+ service_release_delay_ = delay;
}
size_t BoundCdmFactorySizeForTesting() const {
@@ -92,7 +94,7 @@ class MEDIA_MOJO_EXPORT CdmService : public service_manager::Service,
DeferredDestroyStrongBindingSet<mojom::CdmFactory> cdm_factory_bindings_;
service_manager::BinderRegistry registry_;
mojo::BindingSet<mojom::CdmService> bindings_;
- bool is_delayed_service_release_enabled = true;
+ base::TimeDelta service_release_delay_;
};
} // namespace media
diff --git a/chromium/media/mojo/services/cdm_service_unittest.cc b/chromium/media/mojo/services/cdm_service_unittest.cc
index b0d39879bc4..90a9e99f5d2 100644
--- a/chromium/media/mojo/services/cdm_service_unittest.cc
+++ b/chromium/media/mojo/services/cdm_service_unittest.cc
@@ -25,13 +25,18 @@
#include "url/gurl.h"
#include "url/origin.h"
-using testing::Invoke;
-using testing::InvokeWithoutArgs;
-
namespace media {
namespace {
+using testing::_;
+using testing::Invoke;
+using testing::InvokeWithoutArgs;
+
+MATCHER_P(MatchesResult, success, "") {
+ return arg->success == success;
+}
+
const char kClearKeyKeySystem[] = "org.w3.clearkey";
const char kInvalidKeySystem[] = "invalid.key.system";
const char kSecurityOrigin[] = "https://foo.com";
@@ -87,12 +92,16 @@ class ServiceTestClient : public service_manager::test::ServiceTestClient,
std::make_unique<CdmService>(std::move(mock_cdm_service_client));
cdm_service_ = cdm_service.get();
- // Delayed service release involves a posted delayed task which will not
- // block *.RunUntilIdle() and hence cause a memory leak in the test.
- cdm_service_->DisableDelayedServiceReleaseForTesting();
+ cdm_service_->SetServiceReleaseDelayForTesting(service_release_delay_);
service_context_ = std::make_unique<service_manager::ServiceContext>(
std::move(cdm_service), std::move(request));
+ service_context_->SetQuitClosure(base::BindRepeating(
+ &ServiceTestClient::DestroyService, base::Unretained(this)));
+ }
+
+ void SetServiceReleaseDelay(base::TimeDelta delay) {
+ service_release_delay_ = delay;
}
void DestroyService() { service_context_.reset(); }
@@ -108,6 +117,11 @@ class ServiceTestClient : public service_manager::test::ServiceTestClient,
service_factory_bindings_.AddBinding(this, std::move(request));
}
+ // Delayed service release involves a posted delayed task which will not
+ // block *.RunUntilIdle() and hence cause a memory leak in the test. So by
+ // default use a zero value delay to disable the delay.
+ base::TimeDelta service_release_delay_;
+
service_manager::BinderRegistry registry_;
mojo::BindingSet<service_manager::mojom::ServiceFactory>
service_factory_bindings_;
@@ -116,22 +130,20 @@ class ServiceTestClient : public service_manager::test::ServiceTestClient,
MockCdmServiceClient* mock_cdm_service_client_ = nullptr;
};
-} // namespace
-
class CdmServiceTest : public service_manager::test::ServiceTest {
public:
CdmServiceTest() : ServiceTest("cdm_service_unittest") {}
~CdmServiceTest() override {}
+ MOCK_METHOD0(CdmServiceConnectionClosed, void());
MOCK_METHOD0(CdmFactoryConnectionClosed, void());
MOCK_METHOD0(CdmConnectionClosed, void());
- // service_manager::test::ServiceTest:
- void SetUp() override {
- ServiceTest::SetUp();
-
+ void Initialize() {
connector()->BindInterface(media::mojom::kCdmServiceName,
&cdm_service_ptr_);
+ cdm_service_ptr_.set_connection_error_handler(base::BindRepeating(
+ &CdmServiceTest::CdmServiceConnectionClosed, base::Unretained(this)));
service_manager::mojom::InterfaceProviderPtr interfaces;
auto provider = std::make_unique<MediaInterfaceProvider>(
@@ -146,21 +158,22 @@ class CdmServiceTest : public service_manager::test::ServiceTest {
&CdmServiceTest::CdmFactoryConnectionClosed, base::Unretained(this)));
}
- // MOCK_METHOD* doesn't support move-only types. Work around this by having
- // an extra method.
- MOCK_METHOD1(OnCdmInitializedInternal, void(bool result));
- void OnCdmInitialized(mojom::CdmPromiseResultPtr result,
- int cdm_id,
- mojom::DecryptorPtr decryptor) {
- OnCdmInitializedInternal(result->success);
+ void InitializeWithServiceReleaseDelay(base::TimeDelta delay) {
+ service_test_client_->SetServiceReleaseDelay(delay);
+ Initialize();
}
+ MOCK_METHOD3(OnCdmInitialized,
+ void(mojom::CdmPromiseResultPtr result,
+ int cdm_id,
+ mojom::DecryptorPtr decryptor));
+
void InitializeCdm(const std::string& key_system, bool expected_result) {
base::RunLoop run_loop;
cdm_factory_ptr_->CreateCdm(key_system, mojo::MakeRequest(&cdm_ptr_));
cdm_ptr_.set_connection_error_handler(base::BindRepeating(
&CdmServiceTest::CdmConnectionClosed, base::Unretained(this)));
- EXPECT_CALL(*this, OnCdmInitializedInternal(expected_result))
+ EXPECT_CALL(*this, OnCdmInitialized(MatchesResult(expected_result), _, _))
.WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
cdm_ptr_->Initialize(key_system, url::Origin::Create(GURL(kSecurityOrigin)),
CdmConfig(),
@@ -169,6 +182,7 @@ class CdmServiceTest : public service_manager::test::ServiceTest {
run_loop.Run();
}
+ // service_manager::test::ServiceTest implementation.
std::unique_ptr<service_manager::Service> CreateService() override {
auto service_test_client = std::make_unique<ServiceTestClient>(this);
service_test_client_ = service_test_client.get();
@@ -184,14 +198,17 @@ class CdmServiceTest : public service_manager::test::ServiceTest {
DISALLOW_COPY_AND_ASSIGN(CdmServiceTest);
};
+} // namespace
+
TEST_F(CdmServiceTest, LoadCdm) {
- base::FilePath cdm_path(FILE_PATH_LITERAL("dummy path"));
+ Initialize();
// Even with a dummy path where the CDM cannot be loaded, EnsureSandboxed()
// should still be called to ensure the process is sandboxed.
EXPECT_CALL(*service_test_client_->mock_cdm_service_client(),
EnsureSandboxed());
+ base::FilePath cdm_path(FILE_PATH_LITERAL("dummy path"));
#if defined(OS_MACOSX)
// Token provider will not be used since the path is a dummy path.
cdm_service_ptr_->LoadCdm(cdm_path, nullptr);
@@ -203,22 +220,26 @@ TEST_F(CdmServiceTest, LoadCdm) {
}
TEST_F(CdmServiceTest, InitializeCdm_Success) {
+ Initialize();
InitializeCdm(kClearKeyKeySystem, true);
}
TEST_F(CdmServiceTest, InitializeCdm_InvalidKeySystem) {
+ Initialize();
InitializeCdm(kInvalidKeySystem, false);
}
TEST_F(CdmServiceTest, DestroyAndRecreateCdm) {
+ Initialize();
InitializeCdm(kClearKeyKeySystem, true);
cdm_ptr_.reset();
InitializeCdm(kClearKeyKeySystem, true);
}
// CdmFactory connection error will NOT destroy CDMs. Instead, it will only be
-// destroyed after |cdm_| is reset.
+// destroyed after |cdm_ptr_| is reset.
TEST_F(CdmServiceTest, DestroyCdmFactory) {
+ Initialize();
auto* service = service_test_client_->cdm_service();
InitializeCdm(kClearKeyKeySystem, true);
@@ -236,13 +257,39 @@ TEST_F(CdmServiceTest, DestroyCdmFactory) {
EXPECT_EQ(service->UnboundCdmFactorySizeForTesting(), 0u);
}
+// Same as DestroyCdmFactory test, but do not disable delayed service release.
+// TODO(xhwang): Use ScopedTaskEnvironment::MainThreadType::MOCK_TIME and
+// ScopedTaskEnvironment::FastForwardBy() so we don't have to really wait for
+// the delay in the test. But currently FastForwardBy() doesn't support delayed
+// task yet.
+TEST_F(CdmServiceTest, DestroyCdmFactory_DelayedServiceRelease) {
+ constexpr base::TimeDelta kServiceContextRefReleaseDelay =
+ base::TimeDelta::FromSeconds(1);
+ InitializeWithServiceReleaseDelay(kServiceContextRefReleaseDelay);
+
+ InitializeCdm(kClearKeyKeySystem, true);
+ cdm_factory_ptr_.reset();
+ base::RunLoop().RunUntilIdle();
+
+ base::RunLoop run_loop;
+ auto start_time = base::Time::Now();
+ cdm_ptr_.reset();
+ EXPECT_CALL(*this, CdmServiceConnectionClosed())
+ .WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
+ run_loop.Run();
+ auto time_passed = base::Time::Now() - start_time;
+ EXPECT_GE(time_passed, kServiceContextRefReleaseDelay);
+}
+
// Destroy service will destroy the CdmFactory and all CDMs.
TEST_F(CdmServiceTest, DestroyCdmService) {
+ Initialize();
InitializeCdm(kClearKeyKeySystem, true);
base::RunLoop run_loop;
// Ideally we should not care about order, and should only quit the loop when
// both connections are closed.
+ EXPECT_CALL(*this, CdmServiceConnectionClosed());
EXPECT_CALL(*this, CdmFactoryConnectionClosed());
EXPECT_CALL(*this, CdmConnectionClosed())
.WillOnce(Invoke(&run_loop, &base::RunLoop::Quit));
diff --git a/chromium/media/mojo/services/cdm_service_unittest_manifest.json b/chromium/media/mojo/services/cdm_service_unittest_manifest.json
index 1d35efbb1a7..9440910d412 100644
--- a/chromium/media/mojo/services/cdm_service_unittest_manifest.json
+++ b/chromium/media/mojo/services/cdm_service_unittest_manifest.json
@@ -5,7 +5,7 @@
"service_manager:connector": {
"provides": {
"service_manager:service_factory": [
- "service_manager::mojom::ServiceFactory"
+ "service_manager.mojom.ServiceFactory"
]
},
"requires": {
diff --git a/chromium/media/mojo/services/gpu_mojo_media_client.cc b/chromium/media/mojo/services/gpu_mojo_media_client.cc
index fb112f24420..dd6d7ba0912 100644
--- a/chromium/media/mojo/services/gpu_mojo_media_client.cc
+++ b/chromium/media/mojo/services/gpu_mojo_media_client.cc
@@ -7,13 +7,16 @@
#include <utility>
#include "base/bind.h"
+#include "base/feature_list.h"
#include "build/build_config.h"
#include "gpu/ipc/service/gpu_channel.h"
#include "media/base/audio_decoder.h"
#include "media/base/cdm_factory.h"
+#include "media/base/media_switches.h"
#include "media/base/video_decoder.h"
#include "media/gpu/buildflags.h"
#include "media/gpu/ipc/service/media_gpu_channel_manager.h"
+#include "media/gpu/ipc/service/vda_video_decoder.h"
#if defined(OS_ANDROID)
#include "base/memory/ptr_util.h"
@@ -61,7 +64,7 @@ std::unique_ptr<MediaDrmStorage> CreateMediaDrmStorage(
}
#endif // defined(OS_ANDROID)
-#if defined(OS_ANDROID) || defined(OS_WIN)
+#if defined(OS_ANDROID) || defined(OS_MACOSX) || defined(OS_WIN)
gpu::CommandBufferStub* GetCommandBufferStub(
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
base::UnguessableToken channel_token,
@@ -82,11 +85,13 @@ gpu::CommandBufferStub* GetCommandBufferStub(
GpuMojoMediaClient::GpuMojoMediaClient(
const gpu::GpuPreferences& gpu_preferences,
+ const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
CdmProxyFactoryCB cdm_proxy_factory_cb)
: gpu_preferences_(gpu_preferences),
+ gpu_workarounds_(gpu_workarounds),
gpu_task_runner_(std::move(gpu_task_runner)),
media_gpu_channel_manager_(std::move(media_gpu_channel_manager)),
android_overlay_factory_cb_(std::move(android_overlay_factory_cb)),
@@ -109,7 +114,8 @@ std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
MediaLog* media_log,
mojom::CommandBufferIdPtr command_buffer_id,
- RequestOverlayInfoCB request_overlay_info_cb) {
+ RequestOverlayInfoCB request_overlay_info_cb,
+ const gfx::ColorSpace& target_color_space) {
// Both MCVD and D3D11 VideoDecoders need a command buffer.
if (!command_buffer_id)
return nullptr;
@@ -126,9 +132,19 @@ std::unique_ptr<VideoDecoder> GpuMojoMediaClient::CreateVideoDecoder(
android_overlay_factory_cb_, std::move(request_overlay_info_cb),
std::make_unique<VideoFrameFactoryImpl>(gpu_task_runner_,
std::move(get_stub_cb)));
-#elif defined(OS_WIN)
- return std::make_unique<D3D11VideoDecoder>(
- gpu_task_runner_,
+#elif defined(OS_MACOSX) || defined(OS_WIN)
+#if defined(OS_WIN)
+ if (base::FeatureList::IsEnabled(kD3D11VideoDecoder)) {
+ return D3D11VideoDecoder::Create(
+ gpu_task_runner_, gpu_preferences_, gpu_workarounds_,
+ base::BindRepeating(&GetCommandBufferStub, media_gpu_channel_manager_,
+ command_buffer_id->channel_token,
+ command_buffer_id->route_id));
+ }
+#endif // defined(OS_WIN)
+ return VdaVideoDecoder::Create(
+ task_runner, gpu_task_runner_, media_log, target_color_space,
+ gpu_preferences_, gpu_workarounds_,
base::BindRepeating(&GetCommandBufferStub, media_gpu_channel_manager_,
command_buffer_id->channel_token,
command_buffer_id->route_id));
diff --git a/chromium/media/mojo/services/gpu_mojo_media_client.h b/chromium/media/mojo/services/gpu_mojo_media_client.h
index eda075db512..37acd5ab568 100644
--- a/chromium/media/mojo/services/gpu_mojo_media_client.h
+++ b/chromium/media/mojo/services/gpu_mojo_media_client.h
@@ -12,6 +12,7 @@
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "media/base/android_overlay_mojo_factory.h"
#include "media/cdm/cdm_proxy.h"
#include "media/mojo/services/mojo_media_client.h"
@@ -28,6 +29,7 @@ class GpuMojoMediaClient : public MojoMediaClient {
// CdmProxy is not supported on the platform.
GpuMojoMediaClient(
const gpu::GpuPreferences& gpu_preferences,
+ const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
@@ -42,7 +44,8 @@ class GpuMojoMediaClient : public MojoMediaClient {
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
MediaLog* media_log,
mojom::CommandBufferIdPtr command_buffer_id,
- RequestOverlayInfoCB request_overlay_info_cb) final;
+ RequestOverlayInfoCB request_overlay_info_cb,
+ const gfx::ColorSpace& target_color_space) final;
std::unique_ptr<CdmFactory> CreateCdmFactory(
service_manager::mojom::InterfaceProvider* interface_provider) final;
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
@@ -51,6 +54,7 @@ class GpuMojoMediaClient : public MojoMediaClient {
private:
gpu::GpuPreferences gpu_preferences_;
+ gpu::GpuDriverBugWorkarounds gpu_workarounds_;
scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner_;
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager_;
AndroidOverlayMojoFactoryCB android_overlay_factory_cb_;
diff --git a/chromium/media/mojo/services/interface_factory_impl.cc b/chromium/media/mojo/services/interface_factory_impl.cc
index 760568207a6..14df0447a7d 100644
--- a/chromium/media/mojo/services/interface_factory_impl.cc
+++ b/chromium/media/mojo/services/interface_factory_impl.cc
@@ -11,6 +11,7 @@
#include "base/single_thread_task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "media/base/media_log.h"
+#include "media/mojo/services/mojo_decryptor_service.h"
#include "media/mojo/services/mojo_media_client.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
#include "services/service_manager/public/mojom/interface_provider.mojom.h"
@@ -25,9 +26,7 @@
#if BUILDFLAG(ENABLE_MOJO_RENDERER)
#include "base/bind_helpers.h"
-#include "media/base/audio_renderer_sink.h"
-#include "media/base/renderer_factory.h"
-#include "media/base/video_renderer_sink.h"
+#include "media/base/renderer.h"
#include "media/mojo/services/mojo_renderer_service.h"
#endif // BUILDFLAG(ENABLE_MOJO_RENDERER)
@@ -58,6 +57,8 @@ InterfaceFactoryImpl::InterfaceFactoryImpl(
mojo_media_client_(mojo_media_client) {
DVLOG(1) << __func__;
DCHECK(mojo_media_client_);
+
+ SetBindingConnectionErrorHandler();
}
InterfaceFactoryImpl::~InterfaceFactoryImpl() {
@@ -68,6 +69,7 @@ InterfaceFactoryImpl::~InterfaceFactoryImpl() {
void InterfaceFactoryImpl::CreateAudioDecoder(
mojo::InterfaceRequest<mojom::AudioDecoder> request) {
+ DVLOG(2) << __func__;
#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
scoped_refptr<base::SingleThreadTaskRunner> task_runner(
base::ThreadTaskRunnerHandle::Get());
@@ -88,6 +90,7 @@ void InterfaceFactoryImpl::CreateAudioDecoder(
void InterfaceFactoryImpl::CreateVideoDecoder(
mojom::VideoDecoderRequest request) {
+ DVLOG(2) << __func__;
#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
video_decoder_bindings_.AddBinding(
std::make_unique<MojoVideoDecoderService>(mojo_media_client_,
@@ -100,11 +103,8 @@ void InterfaceFactoryImpl::CreateRenderer(
media::mojom::HostedRendererType type,
const std::string& type_specific_id,
mojo::InterfaceRequest<mojom::Renderer> request) {
+ DVLOG(2) << __func__;
#if BUILDFLAG(ENABLE_MOJO_RENDERER)
- RendererFactory* renderer_factory = GetRendererFactory();
- if (!renderer_factory)
- return;
-
// Creation requests for non default renderers should have already been
// handled by now, in a different layer.
if (type != media::mojom::HostedRendererType::kDefault) {
@@ -112,17 +112,11 @@ void InterfaceFactoryImpl::CreateRenderer(
return;
}
- scoped_refptr<base::SingleThreadTaskRunner> task_runner(
- base::ThreadTaskRunnerHandle::Get());
- auto audio_sink =
- mojo_media_client_->CreateAudioRendererSink(type_specific_id);
-
- auto video_sink = mojo_media_client_->CreateVideoRendererSink(task_runner);
- // TODO(hubbe): Find out if gfx::ColorSpace() is correct for the
- // target_color_space.
- auto renderer = renderer_factory->CreateRenderer(
- task_runner, task_runner, audio_sink.get(), video_sink.get(),
- RequestOverlayInfoCB(), gfx::ColorSpace());
+ // For HostedRendererType::kDefault type, |type_specific_id| represents an
+ // audio device ID. See interface_factory.mojom.
+ const std::string& audio_device_id = type_specific_id;
+ auto renderer = mojo_media_client_->CreateRenderer(
+ base::ThreadTaskRunnerHandle::Get(), media_log_, audio_device_id);
if (!renderer) {
DLOG(ERROR) << "Renderer creation failed.";
return;
@@ -130,8 +124,8 @@ void InterfaceFactoryImpl::CreateRenderer(
std::unique_ptr<MojoRendererService> mojo_renderer_service =
std::make_unique<MojoRendererService>(
- &cdm_service_context_, std::move(audio_sink), std::move(video_sink),
- std::move(renderer), MojoRendererService::InitiateSurfaceRequestCB());
+ &cdm_service_context_, std::move(renderer),
+ MojoRendererService::InitiateSurfaceRequestCB());
MojoRendererService* mojo_renderer_service_ptr = mojo_renderer_service.get();
@@ -150,6 +144,7 @@ void InterfaceFactoryImpl::CreateRenderer(
void InterfaceFactoryImpl::CreateCdm(
const std::string& /* key_system */,
mojo::InterfaceRequest<mojom::ContentDecryptionModule> request) {
+ DVLOG(2) << __func__;
#if BUILDFLAG(ENABLE_MOJO_CDM)
CdmFactory* cdm_factory = GetCdmFactory();
if (!cdm_factory)
@@ -161,8 +156,23 @@ void InterfaceFactoryImpl::CreateCdm(
#endif // BUILDFLAG(ENABLE_MOJO_CDM)
}
+void InterfaceFactoryImpl::CreateDecryptor(int cdm_id,
+ mojom::DecryptorRequest request) {
+ DVLOG(2) << __func__;
+ auto mojo_decryptor_service =
+ MojoDecryptorService::Create(cdm_id, &cdm_service_context_);
+ if (!mojo_decryptor_service) {
+ DLOG(ERROR) << "MojoDecryptorService creation failed.";
+ return;
+ }
+
+ decryptor_bindings_.AddBinding(std::move(mojo_decryptor_service),
+ std::move(request));
+}
+
void InterfaceFactoryImpl::CreateCdmProxy(const std::string& cdm_guid,
mojom::CdmProxyRequest request) {
+ DVLOG(2) << __func__;
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
if (!base::IsValidGUID(cdm_guid)) {
DLOG(ERROR) << "Invalid CDM GUID: " << cdm_guid;
@@ -182,17 +192,83 @@ void InterfaceFactoryImpl::CreateCdmProxy(const std::string& cdm_guid,
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
}
+void InterfaceFactoryImpl::OnDestroyPending(base::OnceClosure destroy_cb) {
+ DVLOG(1) << __func__;
+ destroy_cb_ = std::move(destroy_cb);
+ if (IsEmpty())
+ std::move(destroy_cb_).Run();
+ // else the callback will be called when IsEmpty() becomes true.
+}
+
+bool InterfaceFactoryImpl::IsEmpty() {
+#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
+ if (!audio_decoder_bindings_.empty())
+ return false;
+#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
+
+#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
+ if (!video_decoder_bindings_.empty())
+ return false;
+#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
+
#if BUILDFLAG(ENABLE_MOJO_RENDERER)
-RendererFactory* InterfaceFactoryImpl::GetRendererFactory() {
- if (!renderer_factory_) {
- renderer_factory_ = mojo_media_client_->CreateRendererFactory(media_log_);
- LOG_IF(ERROR, !renderer_factory_) << "RendererFactory not available.";
- }
- return renderer_factory_.get();
+ if (!renderer_bindings_.empty())
+ return false;
+#endif // BUILDFLAG(ENABLE_MOJO_RENDERER)
+
+#if BUILDFLAG(ENABLE_MOJO_CDM)
+ if (!cdm_bindings_.empty())
+ return false;
+#endif // BUILDFLAG(ENABLE_MOJO_CDM)
+
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ if (!cdm_proxy_bindings_.empty())
+ return false;
+#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+
+ if (!decryptor_bindings_.empty())
+ return false;
+
+ return true;
}
+
+void InterfaceFactoryImpl::SetBindingConnectionErrorHandler() {
+ // base::Unretained is safe because all bindings are owned by |this|. If
+ // |this| is destructed, the bindings will be destructed as well and the
+ // connection error handler should never be called.
+ auto connection_error_cb = base::BindRepeating(
+ &InterfaceFactoryImpl::OnBindingConnectionError, base::Unretained(this));
+
+#if BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
+ audio_decoder_bindings_.set_connection_error_handler(connection_error_cb);
+#endif // BUILDFLAG(ENABLE_MOJO_AUDIO_DECODER)
+
+#if BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
+ video_decoder_bindings_.set_connection_error_handler(connection_error_cb);
+#endif // BUILDFLAG(ENABLE_MOJO_VIDEO_DECODER)
+
+#if BUILDFLAG(ENABLE_MOJO_RENDERER)
+ renderer_bindings_.set_connection_error_handler(connection_error_cb);
#endif // BUILDFLAG(ENABLE_MOJO_RENDERER)
#if BUILDFLAG(ENABLE_MOJO_CDM)
+ cdm_bindings_.set_connection_error_handler(connection_error_cb);
+#endif // BUILDFLAG(ENABLE_MOJO_CDM)
+
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ cdm_proxy_bindings_.set_connection_error_handler(connection_error_cb);
+#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+
+ decryptor_bindings_.set_connection_error_handler(connection_error_cb);
+}
+
+void InterfaceFactoryImpl::OnBindingConnectionError() {
+ DVLOG(2) << __func__;
+ if (destroy_cb_ && IsEmpty())
+ std::move(destroy_cb_).Run();
+}
+
+#if BUILDFLAG(ENABLE_MOJO_CDM)
CdmFactory* InterfaceFactoryImpl::GetCdmFactory() {
if (!cdm_factory_) {
cdm_factory_ = mojo_media_client_->CreateCdmFactory(interfaces_.get());
diff --git a/chromium/media/mojo/services/interface_factory_impl.h b/chromium/media/mojo/services/interface_factory_impl.h
index 7797ca1b415..486fdaea204 100644
--- a/chromium/media/mojo/services/interface_factory_impl.h
+++ b/chromium/media/mojo/services/interface_factory_impl.h
@@ -10,6 +10,7 @@
#include "base/macros.h"
#include "media/mojo/buildflags.h"
#include "media/mojo/interfaces/interface_factory.mojom.h"
+#include "media/mojo/services/deferred_destroy_strong_binding_set.h"
#include "media/mojo/services/mojo_cdm_service_context.h"
#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "services/service_manager/public/cpp/connector.h"
@@ -20,9 +21,8 @@ namespace media {
class CdmFactory;
class MediaLog;
class MojoMediaClient;
-class RendererFactory;
-class InterfaceFactoryImpl : public mojom::InterfaceFactory {
+class InterfaceFactoryImpl : public DeferredDestroy<mojom::InterfaceFactory> {
public:
InterfaceFactoryImpl(
service_manager::mojom::InterfaceProviderPtr interfaces,
@@ -39,13 +39,20 @@ class InterfaceFactoryImpl : public mojom::InterfaceFactory {
mojom::RendererRequest request) final;
void CreateCdm(const std::string& key_system,
mojom::ContentDecryptionModuleRequest request) final;
+ void CreateDecryptor(int cdm_id, mojom::DecryptorRequest request) final;
void CreateCdmProxy(const std::string& cdm_guid,
mojom::CdmProxyRequest request) final;
+ // DeferredDestroy<mojom::InterfaceFactory> implemenation.
+ void OnDestroyPending(base::OnceClosure destroy_cb) final;
+
private:
-#if BUILDFLAG(ENABLE_MOJO_RENDERER)
- RendererFactory* GetRendererFactory();
-#endif // BUILDFLAG(ENABLE_MOJO_RENDERER)
+ // Returns true when there is no media component (audio/video decoder,
+ // renderer, cdm and cdm proxy) bindings exist.
+ bool IsEmpty();
+
+ void SetBindingConnectionErrorHandler();
+ void OnBindingConnectionError();
#if BUILDFLAG(ENABLE_MOJO_CDM)
CdmFactory* GetCdmFactory();
@@ -66,7 +73,6 @@ class InterfaceFactoryImpl : public mojom::InterfaceFactory {
#if BUILDFLAG(ENABLE_MOJO_RENDERER)
MediaLog* media_log_;
- std::unique_ptr<RendererFactory> renderer_factory_;
mojo::StrongBindingSet<mojom::Renderer> renderer_bindings_;
#endif // BUILDFLAG(ENABLE_MOJO_RENDERER)
@@ -80,8 +86,11 @@ class InterfaceFactoryImpl : public mojom::InterfaceFactory {
mojo::StrongBindingSet<mojom::CdmProxy> cdm_proxy_bindings_;
#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ mojo::StrongBindingSet<mojom::Decryptor> decryptor_bindings_;
+
std::unique_ptr<service_manager::ServiceContextRef> connection_ref_;
MojoMediaClient* mojo_media_client_;
+ base::OnceClosure destroy_cb_;
DISALLOW_COPY_AND_ASSIGN(InterfaceFactoryImpl);
};
diff --git a/chromium/media/mojo/services/media_manifest.json b/chromium/media/mojo/services/media_manifest.json
index 64c6194d6bf..ca7971ecb25 100644
--- a/chromium/media/mojo/services/media_manifest.json
+++ b/chromium/media/mojo/services/media_manifest.json
@@ -4,7 +4,7 @@
"interface_provider_specs": {
"service_manager:connector": {
"provides": {
- "media:media": [ "media::mojom::MediaService" ]
+ "media:media": [ "media.mojom.MediaService" ]
},
"requires": {
"*": [ "app" ]
diff --git a/chromium/media/mojo/services/media_resource_shim.cc b/chromium/media/mojo/services/media_resource_shim.cc
index ace3f01b4ab..184f2a35022 100644
--- a/chromium/media/mojo/services/media_resource_shim.cc
+++ b/chromium/media/mojo/services/media_resource_shim.cc
@@ -39,10 +39,6 @@ std::vector<DemuxerStream*> MediaResourceShim::GetAllStreams() {
return result;
}
-void MediaResourceShim::SetStreamStatusChangeCB(
- const StreamStatusChangeCB& cb) {
-}
-
void MediaResourceShim::OnStreamReady() {
if (++streams_ready_ == streams_.size())
base::ResetAndReturn(&demuxer_ready_cb_).Run();
diff --git a/chromium/media/mojo/services/media_resource_shim.h b/chromium/media/mojo/services/media_resource_shim.h
index fe54ef7c648..fab9eecd5d5 100644
--- a/chromium/media/mojo/services/media_resource_shim.h
+++ b/chromium/media/mojo/services/media_resource_shim.h
@@ -27,7 +27,6 @@ class MediaResourceShim : public MediaResource {
// MediaResource interface.
std::vector<DemuxerStream*> GetAllStreams() override;
- void SetStreamStatusChangeCB(const StreamStatusChangeCB& cb) override;
private:
// Called as each mojom::DemuxerStream becomes ready. Once all streams
diff --git a/chromium/media/mojo/services/media_service.h b/chromium/media/mojo/services/media_service.h
index 5219eb2a56e..0e4dc375009 100644
--- a/chromium/media/mojo/services/media_service.h
+++ b/chromium/media/mojo/services/media_service.h
@@ -11,9 +11,9 @@
#include "media/base/media_log.h"
#include "media/mojo/interfaces/interface_factory.mojom.h"
#include "media/mojo/interfaces/media_service.mojom.h"
+#include "media/mojo/services/deferred_destroy_strong_binding_set.h"
#include "media/mojo/services/media_mojo_export.h"
#include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/public/cpp/bindings/strong_binding_set.h"
#include "services/service_manager/public/cpp/binder_registry.h"
#include "services/service_manager/public/cpp/service.h"
#include "services/service_manager/public/cpp/service_context.h"
@@ -56,7 +56,8 @@ class MEDIA_MOJO_EXPORT MediaService : public service_manager::Service,
// Note: Since |&media_log_| is passed to bindings, the bindings must be
// destructed first.
- mojo::StrongBindingSet<mojom::InterfaceFactory> interface_factory_bindings_;
+ DeferredDestroyStrongBindingSet<mojom::InterfaceFactory>
+ interface_factory_bindings_;
service_manager::BinderRegistry registry_;
mojo::BindingSet<mojom::MediaService> bindings_;
diff --git a/chromium/media/mojo/services/media_service_factory.cc b/chromium/media/mojo/services/media_service_factory.cc
index be65dd05d12..b789dfd4819 100644
--- a/chromium/media/mojo/services/media_service_factory.cc
+++ b/chromium/media/mojo/services/media_service_factory.cc
@@ -31,14 +31,15 @@ std::unique_ptr<service_manager::Service> CreateMediaService() {
std::unique_ptr<service_manager::Service> CreateGpuMediaService(
const gpu::GpuPreferences& gpu_preferences,
+ const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
CdmProxyFactoryCB cdm_proxy_factory_cb) {
return std::unique_ptr<service_manager::Service>(
new MediaService(std::make_unique<GpuMojoMediaClient>(
- gpu_preferences, task_runner, media_gpu_channel_manager,
- std::move(android_overlay_factory_cb),
+ gpu_preferences, gpu_workarounds, task_runner,
+ media_gpu_channel_manager, std::move(android_overlay_factory_cb),
std::move(cdm_proxy_factory_cb))));
}
diff --git a/chromium/media/mojo/services/media_service_factory.h b/chromium/media/mojo/services/media_service_factory.h
index 2c0e7ad644b..8dd062587e7 100644
--- a/chromium/media/mojo/services/media_service_factory.h
+++ b/chromium/media/mojo/services/media_service_factory.h
@@ -11,6 +11,7 @@
#include "base/memory/weak_ptr.h"
#include "base/single_thread_task_runner.h"
#include "gpu/command_buffer/service/gpu_preferences.h"
+#include "gpu/config/gpu_driver_bug_workarounds.h"
#include "media/base/android_overlay_mojo_factory.h"
#include "media/cdm/cdm_proxy.h"
#include "media/mojo/services/media_mojo_export.h"
@@ -34,6 +35,7 @@ CreateMediaService();
std::unique_ptr<service_manager::Service> MEDIA_MOJO_EXPORT
CreateGpuMediaService(
const gpu::GpuPreferences& gpu_preferences,
+ const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
base::WeakPtr<MediaGpuChannelManager> media_gpu_channel_manager,
AndroidOverlayMojoFactoryCB android_overlay_factory_cb,
diff --git a/chromium/media/mojo/services/media_service_unittest.cc b/chromium/media/mojo/services/media_service_unittest.cc
index 3685165b8c0..4897ac8790c 100644
--- a/chromium/media/mojo/services/media_service_unittest.cc
+++ b/chromium/media/mojo/services/media_service_unittest.cc
@@ -11,11 +11,13 @@
#include "base/callback.h"
#include "base/macros.h"
#include "base/run_loop.h"
+#include "base/task_scheduler/post_task.h"
#include "build/build_config.h"
#include "media/base/cdm_config.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/mojo/buildflags.h"
+#include "media/mojo/clients/mojo_decryptor.h"
#include "media/mojo/clients/mojo_demuxer_stream_impl.h"
#include "media/mojo/common/media_type_converters.h"
#include "media/mojo/interfaces/constants.mojom.h"
@@ -32,20 +34,54 @@
#include "url/gurl.h"
#include "url/origin.h"
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+#include "media/cdm/cdm_paths.h" // nogncheck
+#include "media/mojo/interfaces/cdm_proxy.mojom.h"
+#endif
+
+namespace media {
+
+namespace {
+
+using testing::_;
+using testing::DoAll;
using testing::Invoke;
using testing::InvokeWithoutArgs;
using testing::NiceMock;
+using testing::SaveArg;
using testing::StrictMock;
+using testing::WithArg;
-namespace media {
-namespace {
+MATCHER_P(MatchesResult, success, "") {
+ return arg->success == success;
+}
#if BUILDFLAG(ENABLE_MOJO_CDM) && !defined(OS_ANDROID)
const char kClearKeyKeySystem[] = "org.w3.clearkey";
const char kInvalidKeySystem[] = "invalid.key.system";
#endif
-const char kSecurityOrigin[] = "http://foo.com";
+const char kSecurityOrigin[] = "https://foo.com";
+
+// Returns a trivial encrypted DecoderBuffer.
+scoped_refptr<DecoderBuffer> CreateEncryptedBuffer() {
+ scoped_refptr<DecoderBuffer> encrypted_buffer(new DecoderBuffer(100));
+ encrypted_buffer->set_decrypt_config(
+ DecryptConfig::CreateCencConfig("dummy_key_id", "0123456789ABCDEF", {}));
+ return encrypted_buffer;
+}
+
+class MockCdmProxyClient : public mojom::CdmProxyClient {
+ public:
+ MockCdmProxyClient() = default;
+ ~MockCdmProxyClient() override = default;
+
+ // mojom::CdmProxyClient implementation.
+ MOCK_METHOD0(NotifyHardwareReset, void());
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MockCdmProxyClient);
+};
class MockRendererClient : public mojom::RendererClient {
public:
@@ -73,10 +109,20 @@ class MockRendererClient : public mojom::RendererClient {
DISALLOW_COPY_AND_ASSIGN(MockRendererClient);
};
+ACTION_P(QuitLoop, run_loop) {
+ base::PostTask(FROM_HERE, run_loop->QuitClosure());
+}
+
+// Tests MediaService built into a standalone mojo service binary (see
+// ServiceMain() in main.cc) where MediaService uses TestMojoMediaClient.
+// TestMojoMediaClient supports CDM creation using DefaultCdmFactory (only
+// supports Clear Key key system), and Renderer creation using
+// DefaultRendererFactory that always create media::RendererImpl.
class MediaServiceTest : public service_manager::test::ServiceTest {
public:
MediaServiceTest()
: ServiceTest("media_service_unittests"),
+ cdm_proxy_client_binding_(&cdm_proxy_client_),
renderer_client_binding_(&renderer_client_),
video_stream_(DemuxerStream::VIDEO) {}
~MediaServiceTest() override = default;
@@ -84,44 +130,100 @@ class MediaServiceTest : public service_manager::test::ServiceTest {
void SetUp() override {
ServiceTest::SetUp();
- media::mojom::MediaServicePtr media_service;
- connector()->BindInterface(media::mojom::kMediaServiceName, &media_service);
-
- service_manager::mojom::InterfaceProviderPtr interfaces;
+ service_manager::mojom::InterfaceProviderPtr host_interfaces;
auto provider = std::make_unique<MediaInterfaceProvider>(
- mojo::MakeRequest(&interfaces));
- media_service->CreateInterfaceFactory(
- mojo::MakeRequest(&interface_factory_), std::move(interfaces));
-
- run_loop_.reset(new base::RunLoop());
+ mojo::MakeRequest(&host_interfaces));
+
+ connector()->BindInterface(mojom::kMediaServiceName, &media_service_);
+ media_service_.set_connection_error_handler(
+ base::BindRepeating(&MediaServiceTest::MediaServiceConnectionClosed,
+ base::Unretained(this)));
+ media_service_->CreateInterfaceFactory(
+ mojo::MakeRequest(&interface_factory_), std::move(host_interfaces));
}
- // MOCK_METHOD* doesn't support move only types. Work around this by having
- // an extra method.
- MOCK_METHOD2(OnCdmInitializedInternal, void(bool result, int cdm_id));
- void OnCdmInitialized(mojom::CdmPromiseResultPtr result,
- int cdm_id,
- mojom::DecryptorPtr decryptor) {
- OnCdmInitializedInternal(result->success, cdm_id);
- }
+ MOCK_METHOD3(OnCdmInitialized,
+ void(mojom::CdmPromiseResultPtr result,
+ int cdm_id,
+ mojom::DecryptorPtr decryptor));
+ MOCK_METHOD0(OnCdmConnectionError, void());
- void InitializeCdm(const std::string& key_system,
- bool expected_result,
- int cdm_id) {
+ // Returns the CDM ID associated with the CDM.
+ int InitializeCdm(const std::string& key_system, bool expected_result) {
+ base::RunLoop run_loop;
interface_factory_->CreateCdm(key_system, mojo::MakeRequest(&cdm_));
+ cdm_.set_connection_error_handler(base::BindRepeating(
+ &MediaServiceTest::OnCdmConnectionError, base::Unretained(this)));
+
+ int cdm_id = CdmContext::kInvalidCdmId;
- EXPECT_CALL(*this, OnCdmInitializedInternal(expected_result, cdm_id))
- .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
+ // The last parameter mojom::DecryptorPtr is move-only and not supported by
+ // DoAll. Hence use WithArg to only extract the "int cdm_id" out and then
+ // call DoAll.
+ EXPECT_CALL(*this, OnCdmInitialized(MatchesResult(expected_result), _, _))
+ .WillOnce(WithArg<1>(DoAll(SaveArg<0>(&cdm_id), QuitLoop(&run_loop))));
cdm_->Initialize(key_system, url::Origin::Create(GURL(kSecurityOrigin)),
CdmConfig(),
- base::Bind(&MediaServiceTest::OnCdmInitialized,
- base::Unretained(this)));
+ base::BindOnce(&MediaServiceTest::OnCdmInitialized,
+ base::Unretained(this)));
+ run_loop.Run();
+ return cdm_id;
+ }
+
+ MOCK_METHOD4(OnCdmProxyInitialized,
+ void(CdmProxy::Status status,
+ CdmProxy::Protocol protocol,
+ uint32_t crypto_session_id,
+ int cdm_id));
+
+ // Returns the CDM ID associated with the CdmProxy.
+ int InitializeCdmProxy(const std::string& cdm_guid) {
+ base::RunLoop run_loop;
+ interface_factory_->CreateCdmProxy(cdm_guid,
+ mojo::MakeRequest(&cdm_proxy_));
+
+ mojom::CdmProxyClientAssociatedPtrInfo client_ptr_info;
+ cdm_proxy_client_binding_.Bind(mojo::MakeRequest(&client_ptr_info));
+ int cdm_id = CdmContext::kInvalidCdmId;
+
+ EXPECT_CALL(*this, OnCdmProxyInitialized(CdmProxy::Status::kOk, _, _, _))
+ .WillOnce(DoAll(SaveArg<3>(&cdm_id), QuitLoop(&run_loop)));
+ cdm_proxy_->Initialize(
+ std::move(client_ptr_info),
+ base::BindOnce(&MediaServiceTest::OnCdmProxyInitialized,
+ base::Unretained(this)));
+ run_loop.Run();
+ return cdm_id;
+ }
+
+ MOCK_METHOD2(OnDecrypted,
+ void(Decryptor::Status, scoped_refptr<DecoderBuffer>));
+
+ void CreateDecryptor(int cdm_id, bool expected_result) {
+ base::RunLoop run_loop;
+ mojom::DecryptorPtr decryptor_ptr;
+ interface_factory_->CreateDecryptor(cdm_id,
+ mojo::MakeRequest(&decryptor_ptr));
+ MojoDecryptor mojo_decryptor(std::move(decryptor_ptr));
+
+ // In the success case, there's no decryption key to decrypt the buffer so
+ // we would expect no-key.
+ auto expected_status =
+ expected_result ? Decryptor::kNoKey : Decryptor::kError;
+
+ EXPECT_CALL(*this, OnDecrypted(expected_status, _))
+ .WillOnce(QuitLoop(&run_loop));
+ mojo_decryptor.Decrypt(Decryptor::kVideo, CreateEncryptedBuffer(),
+ base::BindRepeating(&MediaServiceTest::OnDecrypted,
+ base::Unretained(this)));
+ run_loop.Run();
}
MOCK_METHOD1(OnRendererInitialized, void(bool));
void InitializeRenderer(const VideoDecoderConfig& video_config,
bool expected_result) {
+ base::RunLoop run_loop;
interface_factory_->CreateRenderer(
media::mojom::HostedRendererType::kDefault, std::string(),
mojo::MakeRequest(&renderer_));
@@ -135,25 +237,31 @@ class MediaServiceTest : public service_manager::test::ServiceTest {
mojom::RendererClientAssociatedPtrInfo client_ptr_info;
renderer_client_binding_.Bind(mojo::MakeRequest(&client_ptr_info));
- EXPECT_CALL(*this, OnRendererInitialized(expected_result))
- .WillOnce(InvokeWithoutArgs(run_loop_.get(), &base::RunLoop::Quit));
std::vector<mojom::DemuxerStreamPtrInfo> streams;
streams.push_back(std::move(video_stream_proxy_info));
- renderer_->Initialize(std::move(client_ptr_info), std::move(streams),
- base::nullopt, base::nullopt,
- base::Bind(&MediaServiceTest::OnRendererInitialized,
- base::Unretained(this)));
+
+ EXPECT_CALL(*this, OnRendererInitialized(expected_result))
+ .WillOnce(QuitLoop(&run_loop));
+ renderer_->Initialize(
+ std::move(client_ptr_info), std::move(streams), base::nullopt,
+ base::nullopt,
+ base::BindOnce(&MediaServiceTest::OnRendererInitialized,
+ base::Unretained(this)));
+ run_loop.Run();
}
- MOCK_METHOD0(ConnectionClosed, void());
+ MOCK_METHOD0(MediaServiceConnectionClosed, void());
protected:
- std::unique_ptr<base::RunLoop> run_loop_;
-
+ mojom::MediaServicePtr media_service_;
mojom::InterfaceFactoryPtr interface_factory_;
mojom::ContentDecryptionModulePtr cdm_;
+ mojom::CdmProxyPtr cdm_proxy_;
mojom::RendererPtr renderer_;
+ NiceMock<MockCdmProxyClient> cdm_proxy_client_;
+ mojo::AssociatedBinding<mojom::CdmProxyClient> cdm_proxy_client_binding_;
+
NiceMock<MockRendererClient> renderer_client_;
mojo::AssociatedBinding<mojom::RendererClient> renderer_client_binding_;
@@ -168,47 +276,148 @@ class MediaServiceTest : public service_manager::test::ServiceTest {
// Note: base::RunLoop::RunUntilIdle() does not work well in these tests because
// even when the loop is idle, we may still have pending events in the pipe.
+// - If you have an InterfacePtr hosted by the service in the service process,
+// you can use InterfacePtr::FlushForTesting(). Note that this doesn't drain
+// the task runner in the test process and doesn't cover all negative cases.
+// - If you expect a callback on an InterfacePtr call or connection error, use
+// base::RunLoop::Run() and QuitLoop().
// TODO(crbug.com/829233): Enable these tests on Android.
#if BUILDFLAG(ENABLE_MOJO_CDM) && !defined(OS_ANDROID)
TEST_F(MediaServiceTest, InitializeCdm_Success) {
- InitializeCdm(kClearKeyKeySystem, true, 1);
- run_loop_->Run();
+ InitializeCdm(kClearKeyKeySystem, true);
}
TEST_F(MediaServiceTest, InitializeCdm_InvalidKeySystem) {
- InitializeCdm(kInvalidKeySystem, false, 0);
- run_loop_->Run();
+ InitializeCdm(kInvalidKeySystem, false);
+}
+
+TEST_F(MediaServiceTest, Decryptor_WithCdm) {
+ int cdm_id = InitializeCdm(kClearKeyKeySystem, true);
+ CreateDecryptor(cdm_id, true);
}
#endif // BUILDFLAG(ENABLE_MOJO_CDM) && !defined(OS_ANDROID)
#if BUILDFLAG(ENABLE_MOJO_RENDERER)
TEST_F(MediaServiceTest, InitializeRenderer) {
InitializeRenderer(TestVideoConfig::Normal(), true);
- run_loop_->Run();
}
#endif // BUILDFLAG(ENABLE_MOJO_RENDERER)
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+TEST_F(MediaServiceTest, CdmProxy) {
+ InitializeCdmProxy(kClearKeyCdmGuid);
+}
+
+TEST_F(MediaServiceTest, Decryptor_WithCdmProxy) {
+ int cdm_id = InitializeCdmProxy(kClearKeyCdmGuid);
+ CreateDecryptor(cdm_id, true);
+}
+
+TEST_F(MediaServiceTest, Decryptor_WrongCdmId) {
+ int cdm_id = InitializeCdmProxy(kClearKeyCdmGuid);
+ CreateDecryptor(cdm_id + 1, false);
+}
+
+TEST_F(MediaServiceTest, DeferredDestruction_CdmProxy) {
+ InitializeCdmProxy(kClearKeyCdmGuid);
+
+ // Disconnecting InterfaceFactory should not terminate the MediaService since
+ // there is still a CdmProxy hosted.
+ interface_factory_.reset();
+ cdm_proxy_.FlushForTesting();
+
+ // Disconnecting CdmProxy will now terminate the MediaService.
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, MediaServiceConnectionClosed())
+ .WillOnce(QuitLoop(&run_loop));
+ cdm_proxy_.reset();
+ run_loop.Run();
+}
+#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+
+TEST_F(MediaServiceTest, Decryptor_WithoutCdmOrCdmProxy) {
+ // Creating decryptor without creating CDM or CdmProxy.
+ CreateDecryptor(1, false);
+}
+
+TEST_F(MediaServiceTest, Lifetime_DestroyMediaService) {
+ // Disconnecting |media_service_| doesn't terminate MediaService
+ // since |interface_factory_| is still alive. This is ensured here since
+ // MediaServiceConnectionClosed() is not called.
+ EXPECT_CALL(*this, MediaServiceConnectionClosed()).Times(0);
+ media_service_.reset();
+ interface_factory_.FlushForTesting();
+}
+
+TEST_F(MediaServiceTest, Lifetime_DestroyInterfaceFactory) {
+ // Disconnecting InterfaceFactory will now terminate the MediaService since
+ // there's no media components hosted.
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, MediaServiceConnectionClosed())
+ .WillOnce(QuitLoop(&run_loop));
+ interface_factory_.reset();
+ run_loop.Run();
+}
+
+#if (BUILDFLAG(ENABLE_MOJO_CDM) && !defined(OS_ANDROID)) || \
+ BUILDFLAG(ENABLE_MOJO_RENDERER)
+// MediaService stays alive as long as there are InterfaceFactory impls, which
+// are then deferred destroyed until no media components (e.g. CDM or Renderer)
+// are hosted.
TEST_F(MediaServiceTest, Lifetime) {
- // The lifetime of the media service is controlled by the number of
- // live InterfaceFactory impls, not MediaService impls, so this pipe should
- // be closed when the last InterfaceFactory is destroyed.
- media::mojom::MediaServicePtr media_service;
- connector()->BindInterface(media::mojom::kMediaServiceName, &media_service);
- media_service.set_connection_error_handler(
- base::Bind(&MediaServiceTest::ConnectionClosed, base::Unretained(this)));
-
- // Disconnecting CDM and Renderer services doesn't terminate the app.
+#if BUILDFLAG(ENABLE_MOJO_CDM) && !defined(OS_ANDROID)
+ InitializeCdm(kClearKeyKeySystem, true);
+#endif
+
+#if BUILDFLAG(ENABLE_MOJO_RENDERER)
+ InitializeRenderer(TestVideoConfig::Normal(), true);
+#endif
+
+ // Disconnecting CDM and Renderer services doesn't terminate MediaService
+ // since |interface_factory_| is still alive.
cdm_.reset();
renderer_.reset();
+ interface_factory_.FlushForTesting();
- // Disconnecting InterfaceFactory service should terminate the app, which will
- // close the connection.
- EXPECT_CALL(*this, ConnectionClosed())
- .WillOnce(Invoke(run_loop_.get(), &base::RunLoop::Quit));
+ // Disconnecting InterfaceFactory will now terminate the MediaService.
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, MediaServiceConnectionClosed())
+ .WillOnce(QuitLoop(&run_loop));
interface_factory_.reset();
+ run_loop.Run();
+}
+
+TEST_F(MediaServiceTest, DeferredDestruction) {
+#if BUILDFLAG(ENABLE_MOJO_CDM) && !defined(OS_ANDROID)
+ InitializeCdm(kClearKeyKeySystem, true);
+#endif
- run_loop_->Run();
+#if BUILDFLAG(ENABLE_MOJO_RENDERER)
+ InitializeRenderer(TestVideoConfig::Normal(), true);
+#endif
+
+ ASSERT_TRUE(cdm_ || renderer_);
+
+ // Disconnecting InterfaceFactory should not terminate the MediaService since
+ // there are still media components (CDM or Renderer) hosted.
+ interface_factory_.reset();
+ if (cdm_)
+ cdm_.FlushForTesting();
+ else if (renderer_)
+ renderer_.FlushForTesting();
+ else
+ NOTREACHED();
+
+ // Disconnecting CDM and Renderer will now terminate the MediaService.
+ base::RunLoop run_loop;
+ EXPECT_CALL(*this, MediaServiceConnectionClosed())
+ .WillOnce(QuitLoop(&run_loop));
+ cdm_.reset();
+ renderer_.reset();
+ run_loop.Run();
}
+#endif // (BUILDFLAG(ENABLE_MOJO_CDM) && !defined(OS_ANDROID)) ||
+ // BUILDFLAG(ENABLE_MOJO_RENDERER)
} // namespace media
diff --git a/chromium/media/mojo/services/mojo_audio_decoder_service.cc b/chromium/media/mojo/services/mojo_audio_decoder_service.cc
index 5f50351e72d..15cae7c515f 100644
--- a/chromium/media/mojo/services/mojo_audio_decoder_service.cc
+++ b/chromium/media/mojo/services/mojo_audio_decoder_service.cc
@@ -57,7 +57,7 @@ void MojoAudioDecoderService::Initialize(const AudioDecoderConfig& config,
base::Bind(&MojoAudioDecoderService::OnInitialized, weak_this_,
base::Passed(&callback)),
base::Bind(&MojoAudioDecoderService::OnAudioBufferReady, weak_this_),
- media::AudioDecoder::WaitingForDecryptionKeyCB());
+ base::NullCallback());
}
void MojoAudioDecoderService::SetDataSource(
diff --git a/chromium/media/mojo/services/mojo_audio_input_stream.cc b/chromium/media/mojo/services/mojo_audio_input_stream.cc
index 7592b7589f4..3762dbb608c 100644
--- a/chromium/media/mojo/services/mojo_audio_input_stream.cc
+++ b/chromium/media/mojo/services/mojo_audio_input_stream.cc
@@ -8,7 +8,7 @@
#include <utility>
#include "base/callback_helpers.h"
-#include "base/memory/shared_memory.h"
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/sync_socket.h"
#include "mojo/public/cpp/system/platform_handle.h"
@@ -49,6 +49,12 @@ MojoAudioInputStream::~MojoAudioInputStream() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
}
+void MojoAudioInputStream::SetOutputDeviceForAec(
+ const std::string& raw_output_device_id) {
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+ delegate_->OnSetOutputDeviceForAec(raw_output_device_id);
+}
+
void MojoAudioInputStream::Record() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
delegate_->OnRecordStream();
@@ -67,24 +73,20 @@ void MojoAudioInputStream::SetVolume(double volume) {
void MojoAudioInputStream::OnStreamCreated(
int stream_id,
- const base::SharedMemory* shared_memory,
+ base::ReadOnlySharedMemoryRegion shared_memory_region,
std::unique_ptr<base::CancelableSyncSocket> foreign_socket,
bool initially_muted) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(stream_created_callback_);
- DCHECK(shared_memory);
DCHECK(foreign_socket);
- base::SharedMemoryHandle foreign_memory_handle =
- shared_memory->GetReadOnlyHandle();
- if (!base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
+ if (!shared_memory_region.IsValid()) {
OnStreamError(/*not used*/ 0);
return;
}
- mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
- foreign_memory_handle, shared_memory->requested_size(),
- mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
+ mojo::ScopedSharedBufferHandle buffer_handle =
+ mojo::WrapReadOnlySharedMemoryRegion(std::move(shared_memory_region));
mojo::ScopedHandle socket_handle =
mojo::WrapPlatformFile(foreign_socket->Release());
diff --git a/chromium/media/mojo/services/mojo_audio_input_stream.h b/chromium/media/mojo/services/mojo_audio_input_stream.h
index d28f1e1c27e..26c4af1ef56 100644
--- a/chromium/media/mojo/services/mojo_audio_input_stream.h
+++ b/chromium/media/mojo/services/mojo_audio_input_stream.h
@@ -42,6 +42,8 @@ class MEDIA_MOJO_EXPORT MojoAudioInputStream
~MojoAudioInputStream() override;
+ void SetOutputDeviceForAec(const std::string& raw_output_device_id);
+
private:
// mojom::AudioInputStream implementation.
void Record() override;
@@ -50,7 +52,7 @@ class MEDIA_MOJO_EXPORT MojoAudioInputStream
// AudioInputDelegate::EventHandler implementation.
void OnStreamCreated(
int stream_id,
- const base::SharedMemory* shared_memory,
+ base::ReadOnlySharedMemoryRegion shared_memory_region,
std::unique_ptr<base::CancelableSyncSocket> foreign_socket,
bool initially_muted) override;
void OnMuted(int stream_id, bool is_muted) override;
diff --git a/chromium/media/mojo/services/mojo_audio_input_stream_observer.cc b/chromium/media/mojo/services/mojo_audio_input_stream_observer.cc
deleted file mode 100644
index 8f93afeadb4..00000000000
--- a/chromium/media/mojo/services/mojo_audio_input_stream_observer.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// Copyright 2018 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 "media/mojo/services/mojo_audio_input_stream_observer.h"
-
-#include <utility>
-
-namespace media {
-
-MojoAudioInputStreamObserver::MojoAudioInputStreamObserver(
- mojom::AudioInputStreamObserverRequest request,
- base::OnceClosure recording_started_callback,
- base::OnceClosure connection_error_callback)
- : binding_(this, std::move(request)),
- recording_started_callback_(std::move(recording_started_callback)) {
- DCHECK(recording_started_callback_);
- binding_.set_connection_error_handler(std::move(connection_error_callback));
-}
-
-MojoAudioInputStreamObserver::~MojoAudioInputStreamObserver() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
-}
-
-void MojoAudioInputStreamObserver::DidStartRecording() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(owning_sequence_);
- DCHECK(recording_started_callback_);
- std::move(recording_started_callback_).Run();
-}
-
-} // namespace media
diff --git a/chromium/media/mojo/services/mojo_audio_input_stream_observer.h b/chromium/media/mojo/services/mojo_audio_input_stream_observer.h
deleted file mode 100644
index c85f73df712..00000000000
--- a/chromium/media/mojo/services/mojo_audio_input_stream_observer.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef MEDIA_MOJO_SERVICES_MOJO_AUDIO_INPUT_STREAM_OBSERVER_H_
-#define MEDIA_MOJO_SERVICES_MOJO_AUDIO_INPUT_STREAM_OBSERVER_H_
-
-#include "media/mojo/interfaces/audio_input_stream.mojom.h"
-#include "media/mojo/services/media_mojo_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
-
-namespace media {
-
-class MEDIA_MOJO_EXPORT MojoAudioInputStreamObserver
- : public mojom::AudioInputStreamObserver {
- public:
- MojoAudioInputStreamObserver(mojom::AudioInputStreamObserverRequest request,
- base::OnceClosure recording_started_callback,
- base::OnceClosure connection_error_callback);
- ~MojoAudioInputStreamObserver() override;
-
- void DidStartRecording() override;
-
- private:
- mojo::Binding<AudioInputStreamObserver> binding_;
- base::OnceClosure recording_started_callback_;
-
- SEQUENCE_CHECKER(owning_sequence_);
-
- DISALLOW_COPY_AND_ASSIGN(MojoAudioInputStreamObserver);
-};
-
-} // namespace media
-
-#endif // MEDIA_MOJO_SERVICES_MOJO_AUDIO_INPUT_STREAM_OBSERVER_H_
diff --git a/chromium/media/mojo/services/mojo_audio_input_stream_observer_unittest.cc b/chromium/media/mojo/services/mojo_audio_input_stream_observer_unittest.cc
deleted file mode 100644
index 287eeb3e99a..00000000000
--- a/chromium/media/mojo/services/mojo_audio_input_stream_observer_unittest.cc
+++ /dev/null
@@ -1,64 +0,0 @@
-// Copyright 2018 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 "media/mojo/services/mojo_audio_input_stream_observer.h"
-
-#include <memory>
-#include <utility>
-
-#include "base/run_loop.h"
-#include "base/test/scoped_task_environment.h"
-#include "mojo/public/cpp/bindings/associated_binding.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace media {
-
-class MojoAudioInputStreamObserverTest : public testing::Test {
- public:
- MojoAudioInputStreamObserverTest() {}
- ~MojoAudioInputStreamObserverTest() {}
-
- std::unique_ptr<MojoAudioInputStreamObserver> CreateObserver(
- media::mojom::AudioInputStreamObserverRequest request) {
- return std::make_unique<MojoAudioInputStreamObserver>(
- std::move(request),
- base::BindOnce(
- &MojoAudioInputStreamObserverTest::RecordingStartedCallback,
- base::Unretained(this)),
- base::BindOnce(
- &MojoAudioInputStreamObserverTest::BindingConnectionError,
- base::Unretained(this)));
- }
-
- MOCK_METHOD0(RecordingStartedCallback, void());
- MOCK_METHOD0(BindingConnectionError, void());
-
- private:
- base::test::ScopedTaskEnvironment scoped_task_env_;
-
- DISALLOW_COPY_AND_ASSIGN(MojoAudioInputStreamObserverTest);
-};
-
-TEST_F(MojoAudioInputStreamObserverTest, DidStartRecording) {
- media::mojom::AudioInputStreamObserverPtr observer_ptr;
- std::unique_ptr<MojoAudioInputStreamObserver> observer =
- CreateObserver(mojo::MakeRequest(&observer_ptr));
-
- EXPECT_CALL(*this, RecordingStartedCallback());
- observer_ptr->DidStartRecording();
- base::RunLoop().RunUntilIdle();
-}
-
-TEST_F(MojoAudioInputStreamObserverTest, BindingConnectionError) {
- media::mojom::AudioInputStreamObserverPtr observer_ptr;
- std::unique_ptr<MojoAudioInputStreamObserver> observer =
- CreateObserver(mojo::MakeRequest(&observer_ptr));
-
- EXPECT_CALL(*this, BindingConnectionError());
- observer_ptr.reset();
- base::RunLoop().RunUntilIdle();
-}
-
-} // namespace media
diff --git a/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc b/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc
index 5271b9227e1..a193f4fc665 100644
--- a/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc
+++ b/chromium/media/mojo/services/mojo_audio_input_stream_unittest.cc
@@ -6,7 +6,7 @@
#include <utility>
-#include "base/memory/shared_memory.h"
+#include "base/memory/read_only_shared_memory_region.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/sync_socket.h"
@@ -59,11 +59,12 @@ class TestCancelableSyncSocket : public base::CancelableSyncSocket {
class MockDelegate : public AudioInputDelegate {
public:
MockDelegate() = default;
- ~MockDelegate() = default;
+ ~MockDelegate() override = default;
MOCK_METHOD0(GetStreamId, int());
MOCK_METHOD0(OnRecordStream, void());
MOCK_METHOD1(OnSetVolume, void(double));
+ MOCK_METHOD1(OnSetOutputDeviceForAec, void(const std::string&));
};
class MockDelegateFactory {
@@ -105,17 +106,9 @@ class MockClient : public mojom::AudioInputStreamClient {
socket_ = std::make_unique<base::CancelableSyncSocket>(fd);
EXPECT_NE(socket_->handle(), base::CancelableSyncSocket::kInvalidHandle);
- size_t memory_length;
- base::SharedMemoryHandle shmem_handle;
- mojo::UnwrappedSharedMemoryHandleProtection protection;
- EXPECT_EQ(mojo::UnwrapSharedMemoryHandle(
- std::move(data_pipe->shared_memory), &shmem_handle,
- &memory_length, &protection),
- MOJO_RESULT_OK);
- EXPECT_EQ(protection,
- mojo::UnwrappedSharedMemoryHandleProtection::kReadOnly);
- buffer_ = std::make_unique<base::SharedMemory>(shmem_handle,
- true /* read_only */);
+ region_ = mojo::UnwrapReadOnlySharedMemoryRegion(
+ std::move(data_pipe->shared_memory));
+ EXPECT_TRUE(region_.IsValid());
GotNotification(initially_muted);
}
@@ -127,7 +120,7 @@ class MockClient : public mojom::AudioInputStreamClient {
MOCK_METHOD0(OnError, void());
private:
- std::unique_ptr<base::SharedMemory> buffer_;
+ base::ReadOnlySharedMemoryRegion region_;
std::unique_ptr<base::CancelableSyncSocket> socket_;
DISALLOW_COPY_AND_ASSIGN(MockClient);
@@ -171,10 +164,8 @@ class MojoAudioInputStreamTest : public Test {
base::WrapUnique(delegate_));
EXPECT_TRUE(
base::CancelableSyncSocket::CreatePair(&local_, foreign_socket_.get()));
- base::SharedMemoryCreateOptions shmem_options;
- shmem_options.size = kShmemSize;
- shmem_options.share_read_only = true;
- EXPECT_TRUE(mem_.Create(shmem_options));
+ mem_ = base::ReadOnlySharedMemoryRegion::Create(kShmemSize).region;
+ EXPECT_TRUE(mem_.IsValid());
EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull()))
.WillOnce(SaveArg<0>(&delegate_event_handler_));
}
@@ -182,7 +173,7 @@ class MojoAudioInputStreamTest : public Test {
base::MessageLoop loop_;
base::CancelableSyncSocket local_;
std::unique_ptr<TestCancelableSyncSocket> foreign_socket_;
- base::SharedMemory mem_;
+ base::ReadOnlySharedMemoryRegion mem_;
StrictMock<MockDelegate>* delegate_ = nullptr;
AudioInputDelegate::EventHandler* delegate_event_handler_ = nullptr;
StrictMock<MockDelegateFactory> mock_delegate_factory_;
@@ -232,8 +223,9 @@ TEST_F(MojoAudioInputStreamTest, DestructWithCallPending_Safe) {
ASSERT_NE(nullptr, delegate_event_handler_);
foreign_socket_->ExpectOwnershipTransfer();
- delegate_event_handler_->OnStreamCreated(
- kStreamId, &mem_, std::move(foreign_socket_), kInitiallyNotMuted);
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_),
+ kInitiallyNotMuted);
audio_input_ptr->Record();
impl_.reset();
base::RunLoop().RunUntilIdle();
@@ -247,8 +239,9 @@ TEST_F(MojoAudioInputStreamTest, Created_NotifiesClient) {
ASSERT_NE(nullptr, delegate_event_handler_);
foreign_socket_->ExpectOwnershipTransfer();
- delegate_event_handler_->OnStreamCreated(
- kStreamId, &mem_, std::move(foreign_socket_), kInitiallyNotMuted);
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_),
+ kInitiallyNotMuted);
base::RunLoop().RunUntilIdle();
}
@@ -294,8 +287,9 @@ TEST_F(MojoAudioInputStreamTest, DelegateErrorAfterCreated_PropagatesError) {
ASSERT_NE(nullptr, delegate_event_handler_);
foreign_socket_->ExpectOwnershipTransfer();
- delegate_event_handler_->OnStreamCreated(
- kStreamId, &mem_, std::move(foreign_socket_), kInitiallyNotMuted);
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_),
+ kInitiallyNotMuted);
delegate_event_handler_->OnStreamError(kStreamId);
base::RunLoop().RunUntilIdle();
diff --git a/chromium/media/mojo/services/mojo_audio_output_stream.cc b/chromium/media/mojo/services/mojo_audio_output_stream.cc
index 79e52418c6a..5cdfb6ca5fd 100644
--- a/chromium/media/mojo/services/mojo_audio_output_stream.cc
+++ b/chromium/media/mojo/services/mojo_audio_output_stream.cc
@@ -15,29 +15,20 @@
namespace media {
MojoAudioOutputStream::MojoAudioOutputStream(
- mojom::AudioOutputStreamRequest request,
- mojom::AudioOutputStreamClientPtr client,
CreateDelegateCallback create_delegate_callback,
StreamCreatedCallback stream_created_callback,
- base::OnceClosure deleter_callback)
+ DeleterCallback deleter_callback)
: stream_created_callback_(std::move(stream_created_callback)),
deleter_callback_(std::move(deleter_callback)),
- binding_(this, std::move(request)),
- client_(std::move(client)),
+ binding_(this),
weak_factory_(this) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(stream_created_callback_);
DCHECK(deleter_callback_);
- // |this| owns |binding_|, so unretained is safe.
- binding_.set_connection_error_handler(
- base::BindOnce(&MojoAudioOutputStream::OnError, base::Unretained(this)));
- client_.set_connection_error_handler(
- base::BindOnce(&MojoAudioOutputStream::OnError, base::Unretained(this)));
delegate_ = std::move(create_delegate_callback).Run(this);
if (!delegate_) {
// Failed to initialize the stream. We cannot call |deleter_callback_| yet,
// since construction isn't done.
- binding_.Close();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(&MojoAudioOutputStream::OnStreamError,
@@ -72,44 +63,46 @@ void MojoAudioOutputStream::SetVolume(double volume) {
void MojoAudioOutputStream::OnStreamCreated(
int stream_id,
- const base::SharedMemory* shared_memory,
+ base::UnsafeSharedMemoryRegion shared_memory_region,
std::unique_ptr<base::CancelableSyncSocket> foreign_socket) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(stream_created_callback_);
- DCHECK(shared_memory);
DCHECK(foreign_socket);
- base::SharedMemoryHandle foreign_memory_handle =
- base::SharedMemory::DuplicateHandle(shared_memory->handle());
- if (!base::SharedMemory::IsHandleValid(foreign_memory_handle)) {
+ if (!shared_memory_region.IsValid()) {
OnStreamError(/*not used*/ 0);
return;
}
- mojo::ScopedSharedBufferHandle buffer_handle = mojo::WrapSharedMemoryHandle(
- foreign_memory_handle, shared_memory->requested_size(),
- mojo::UnwrappedSharedMemoryHandleProtection::kReadWrite);
+ mojo::ScopedSharedBufferHandle buffer_handle =
+ mojo::WrapUnsafeSharedMemoryRegion(std::move(shared_memory_region));
mojo::ScopedHandle socket_handle =
mojo::WrapPlatformFile(foreign_socket->Release());
DCHECK(buffer_handle.is_valid());
DCHECK(socket_handle.is_valid());
- base::ResetAndReturn(&stream_created_callback_)
- .Run(
- {base::in_place, std::move(buffer_handle), std::move(socket_handle)});
+ mojom::AudioOutputStreamPtr stream;
+ binding_.Bind(mojo::MakeRequest(&stream));
+ // |this| owns |binding_| so unretained is safe.
+ binding_.set_connection_error_handler(base::BindOnce(
+ &MojoAudioOutputStream::StreamConnectionLost, base::Unretained(this)));
+
+ std::move(stream_created_callback_)
+ .Run(std::move(stream), {base::in_place, std::move(buffer_handle),
+ std::move(socket_handle)});
}
void MojoAudioOutputStream::OnStreamError(int stream_id) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- client_->OnError();
- OnError();
+ DCHECK(deleter_callback_);
+ std::move(deleter_callback_).Run(/*had_error*/ true); // Deletes |this|.
}
-void MojoAudioOutputStream::OnError() {
+void MojoAudioOutputStream::StreamConnectionLost() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
DCHECK(deleter_callback_);
- std::move(deleter_callback_).Run(); // Deletes |this|.
+ std::move(deleter_callback_).Run(/*had_error*/ false); // Deletes |this|.
}
} // namespace media
diff --git a/chromium/media/mojo/services/mojo_audio_output_stream.h b/chromium/media/mojo/services/mojo_audio_output_stream.h
index 217052605cf..31c1fcf5eef 100644
--- a/chromium/media/mojo/services/mojo_audio_output_stream.h
+++ b/chromium/media/mojo/services/mojo_audio_output_stream.h
@@ -23,21 +23,22 @@ class MEDIA_MOJO_EXPORT MojoAudioOutputStream
public AudioOutputDelegate::EventHandler {
public:
using StreamCreatedCallback =
- mojom::AudioOutputStreamProvider::AcquireCallback;
+ base::OnceCallback<void(mojom::AudioOutputStreamPtr,
+ media::mojom::AudioDataPipePtr)>;
using CreateDelegateCallback =
base::OnceCallback<std::unique_ptr<AudioOutputDelegate>(
AudioOutputDelegate::EventHandler*)>;
+ using DeleterCallback = base::OnceCallback<void(bool)>;
// |create_delegate_callback| is used to obtain an AudioOutputDelegate for the
// stream in the constructor. |stream_created_callback| is called when the
// stream has been initialized. |deleter_callback| is called when this class
- // should be removed (stream ended/error). |deleter_callback| is required to
- // destroy |this| synchronously.
- MojoAudioOutputStream(mojom::AudioOutputStreamRequest request,
- mojom::AudioOutputStreamClientPtr client,
- CreateDelegateCallback create_delegate_callback,
+ // should be removed (stream ended/error). Its argument indicates if an error
+ // was encountered (false indicates that the remote end closed the stream).
+ // |deleter_callback| is required to destroy |this| synchronously.
+ MojoAudioOutputStream(CreateDelegateCallback create_delegate_callback,
StreamCreatedCallback stream_created_callback,
- base::OnceClosure deleter_callback);
+ DeleterCallback deleter_callback);
~MojoAudioOutputStream() override;
@@ -50,19 +51,17 @@ class MEDIA_MOJO_EXPORT MojoAudioOutputStream
// AudioOutputDelegate::EventHandler implementation.
void OnStreamCreated(
int stream_id,
- const base::SharedMemory* shared_memory,
+ base::UnsafeSharedMemoryRegion shared_memory_region,
std::unique_ptr<base::CancelableSyncSocket> foreign_socket) override;
void OnStreamError(int stream_id) override;
- // Closes connection to client and notifies owner.
- void OnError();
+ void StreamConnectionLost();
SEQUENCE_CHECKER(sequence_checker_);
StreamCreatedCallback stream_created_callback_;
- base::OnceClosure deleter_callback_;
+ DeleterCallback deleter_callback_;
mojo::Binding<AudioOutputStream> binding_;
- mojom::AudioOutputStreamClientPtr client_;
std::unique_ptr<AudioOutputDelegate> delegate_;
base::WeakPtrFactory<MojoAudioOutputStream> weak_factory_;
diff --git a/chromium/media/mojo/services/mojo_audio_output_stream_provider.cc b/chromium/media/mojo/services/mojo_audio_output_stream_provider.cc
index 32e7b7fc790..1a661e8099b 100644
--- a/chromium/media/mojo/services/mojo_audio_output_stream_provider.cc
+++ b/chromium/media/mojo/services/mojo_audio_output_stream_provider.cc
@@ -23,8 +23,9 @@ MojoAudioOutputStreamProvider::MojoAudioOutputStreamProvider(
observer_binding_(observer_.get()) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// Unretained is safe since |this| owns |binding_|.
- binding_.set_connection_error_handler(base::Bind(
- &MojoAudioOutputStreamProvider::OnError, base::Unretained(this)));
+ binding_.set_connection_error_handler(
+ base::BindOnce(&MojoAudioOutputStreamProvider::CleanUp,
+ base::Unretained(this), /*had_error*/ false));
DCHECK(create_delegate_callback_);
DCHECK(deleter_callback_);
}
@@ -34,10 +35,8 @@ MojoAudioOutputStreamProvider::~MojoAudioOutputStreamProvider() {
}
void MojoAudioOutputStreamProvider::Acquire(
- mojom::AudioOutputStreamRequest stream_request,
- mojom::AudioOutputStreamClientPtr client,
const AudioParameters& params,
- AcquireCallback callback) {
+ mojom::AudioOutputStreamProviderClientPtr provider_client) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
#if !defined(OS_ANDROID)
if (params.IsBitstreamFormat()) {
@@ -53,29 +52,32 @@ void MojoAudioOutputStreamProvider::Acquire(
return;
}
+ provider_client_ = std::move(provider_client);
+
mojom::AudioOutputStreamObserverPtr observer_ptr;
observer_binding_.Bind(mojo::MakeRequest(&observer_ptr));
// Unretained is safe since |this| owns |audio_output_|.
- audio_output_.emplace(std::move(stream_request), std::move(client),
- base::BindOnce(std::move(create_delegate_callback_),
- params, std::move(observer_ptr)),
- std::move(callback),
- base::BindOnce(&MojoAudioOutputStreamProvider::OnError,
- base::Unretained(this)));
+ audio_output_.emplace(
+ base::BindOnce(std::move(create_delegate_callback_), params,
+ std::move(observer_ptr)),
+ base::BindOnce(&mojom::AudioOutputStreamProviderClient::Created,
+ base::Unretained(provider_client_.get())),
+ base::BindOnce(&MojoAudioOutputStreamProvider::CleanUp,
+ base::Unretained(this)));
}
-void MojoAudioOutputStreamProvider::OnError() {
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
- // Deletes |this|:
+void MojoAudioOutputStreamProvider::CleanUp(bool had_error) {
+ if (had_error) {
+ provider_client_.ResetWithReason(
+ static_cast<uint32_t>(media::mojom::AudioOutputStreamObserver::
+ DisconnectReason::kPlatformError),
+ std::string());
+ }
std::move(deleter_callback_).Run(this);
}
void MojoAudioOutputStreamProvider::BadMessage(const std::string& error) {
mojo::ReportBadMessage(error);
- if (binding_.is_bound())
- binding_.Unbind();
- if (observer_binding_.is_bound())
- observer_binding_.Unbind();
std::move(deleter_callback_).Run(this); // deletes |this|.
}
diff --git a/chromium/media/mojo/services/mojo_audio_output_stream_provider.h b/chromium/media/mojo/services/mojo_audio_output_stream_provider.h
index f642571b1a0..0d580f31b98 100644
--- a/chromium/media/mojo/services/mojo_audio_output_stream_provider.h
+++ b/chromium/media/mojo/services/mojo_audio_output_stream_provider.h
@@ -42,25 +42,25 @@ class MEDIA_MOJO_EXPORT MojoAudioOutputStreamProvider
private:
// mojom::AudioOutputStreamProvider implementation.
- void Acquire(mojom::AudioOutputStreamRequest stream_request,
- mojom::AudioOutputStreamClientPtr client,
- const AudioParameters& params,
- AcquireCallback acquire_callback) override;
+ void Acquire(
+ const AudioParameters& params,
+ mojom::AudioOutputStreamProviderClientPtr provider_client) override;
// Called when |audio_output_| had an error.
- void OnError();
+ void CleanUp(bool had_error);
// Closes mojo connections, reports a bad message, and self-destructs.
void BadMessage(const std::string& error);
SEQUENCE_CHECKER(sequence_checker_);
- base::Optional<MojoAudioOutputStream> audio_output_;
mojo::Binding<AudioOutputStreamProvider> binding_;
CreateDelegateCallback create_delegate_callback_;
DeleterCallback deleter_callback_;
std::unique_ptr<mojom::AudioOutputStreamObserver> observer_;
mojo::Binding<mojom::AudioOutputStreamObserver> observer_binding_;
+ base::Optional<MojoAudioOutputStream> audio_output_;
+ mojom::AudioOutputStreamProviderClientPtr provider_client_;
DISALLOW_COPY_AND_ASSIGN(MojoAudioOutputStreamProvider);
};
diff --git a/chromium/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc b/chromium/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc
index 49edfa94372..e559976433e 100644
--- a/chromium/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc
+++ b/chromium/media/mojo/services/mojo_audio_output_stream_provider_unittest.cc
@@ -31,8 +31,6 @@ using testing::StrictMock;
using MockDeleter = base::MockCallback<
base::OnceCallback<void(mojom::AudioOutputStreamProvider*)>>;
-void FakeAcquireCallback(mojom::AudioDataPipePtr data_pipe) {}
-
class FakeObserver : public mojom::AudioOutputStreamObserver {
public:
FakeObserver() = default;
@@ -83,26 +81,22 @@ TEST(MojoAudioOutputStreamProviderTest, AcquireTwice_BadMessage) {
mojo::MakeRequest(&provider_ptr), base::BindOnce(&CreateFakeDelegate),
deleter.Get(), std::make_unique<FakeObserver>());
- mojom::AudioOutputStreamPtr stream_1;
- mojom::AudioOutputStreamClientPtr client_1;
- mojom::AudioOutputStreamClientRequest client_request_1 =
- mojo::MakeRequest(&client_1);
-
- mojom::AudioOutputStreamPtr stream_2;
- mojom::AudioOutputStreamClientPtr client_2;
- mojom::AudioOutputStreamClientRequest client_request_2 =
- mojo::MakeRequest(&client_2);
- provider_ptr->Acquire(mojo::MakeRequest(&stream_1), std::move(client_1),
- media::AudioParameters::UnavailableDeviceParams(),
- base::BindOnce(&FakeAcquireCallback));
- provider_ptr->Acquire(mojo::MakeRequest(&stream_2), std::move(client_2),
- media::AudioParameters::UnavailableDeviceParams(),
- base::BindOnce(&FakeAcquireCallback));
+ mojom::AudioOutputStreamProviderClientPtr client_1;
+ mojo::MakeRequest(&client_1);
+ provider_ptr->Acquire(media::AudioParameters::UnavailableDeviceParams(),
+ std::move(client_1));
+
+ mojom::AudioOutputStreamProviderClientPtr client_2;
+ mojo::MakeRequest(&client_2);
+ provider_ptr->Acquire(media::AudioParameters::UnavailableDeviceParams(),
+ std::move(client_2));
EXPECT_CALL(deleter, Run(provider)).WillOnce(DeleteArg<0>());
base::RunLoop().RunUntilIdle();
EXPECT_TRUE(got_bad_message);
Mock::VerifyAndClear(&deleter);
+
+ mojo::edk::SetDefaultProcessErrorCallback(mojo::edk::ProcessErrorCallback());
}
TEST(MojoAudioOutputStreamProviderTest,
@@ -124,12 +118,9 @@ TEST(MojoAudioOutputStreamProviderTest,
mojo::MakeRequest(&provider_ptr), base::BindOnce(&CreateFakeDelegate),
deleter.Get(), std::make_unique<FakeObserver>());
- mojom::AudioOutputStreamPtr stream;
- mojom::AudioOutputStreamClientPtr client;
- mojom::AudioOutputStreamClientRequest client_request =
- mojo::MakeRequest(&client);
- provider_ptr->Acquire(mojo::MakeRequest(&stream), std::move(client), params,
- base::BindOnce(&FakeAcquireCallback));
+ mojom::AudioOutputStreamProviderClientPtr client;
+ mojo::MakeRequest(&client);
+ provider_ptr->Acquire(params, std::move(client));
#if defined(OS_ANDROID)
base::RunLoop().RunUntilIdle();
@@ -144,6 +135,7 @@ TEST(MojoAudioOutputStreamProviderTest,
EXPECT_TRUE(got_bad_message);
Mock::VerifyAndClear(&deleter);
#endif
+ mojo::edk::SetDefaultProcessErrorCallback(mojo::edk::ProcessErrorCallback());
}
} // namespace media
diff --git a/chromium/media/mojo/services/mojo_audio_output_stream_unittest.cc b/chromium/media/mojo/services/mojo_audio_output_stream_unittest.cc
index efd161972c2..508e845d35f 100644
--- a/chromium/media/mojo/services/mojo_audio_output_stream_unittest.cc
+++ b/chromium/media/mojo/services/mojo_audio_output_stream_unittest.cc
@@ -11,6 +11,7 @@
#include "base/run_loop.h"
#include "base/sync_socket.h"
#include "media/audio/audio_output_controller.h"
+#include "mojo/public/cpp/system/message_pipe.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -57,7 +58,7 @@ class TestCancelableSyncSocket : public base::CancelableSyncSocket {
class MockDelegate : public AudioOutputDelegate {
public:
MockDelegate() = default;
- ~MockDelegate() = default;
+ ~MockDelegate() override = default;
MOCK_METHOD0(GetStreamId, int());
MOCK_METHOD0(OnPlayStream, void());
@@ -88,14 +89,14 @@ class MockDelegateFactory {
class MockDeleter {
public:
- MOCK_METHOD0(Finished, void());
+ MOCK_METHOD1(Finished, void(bool));
};
-class MockClient : public mojom::AudioOutputStreamClient {
+class MockClient {
public:
MockClient() = default;
- void Initialized(mojom::AudioDataPipePtr data_pipe) {
+ void Initialize(mojom::AudioDataPipePtr data_pipe) {
ASSERT_TRUE(data_pipe->shared_memory.is_valid());
ASSERT_TRUE(data_pipe->socket.is_valid());
@@ -121,8 +122,6 @@ class MockClient : public mojom::AudioOutputStreamClient {
MOCK_METHOD0(GotNotification, void());
- MOCK_METHOD0(OnError, void());
-
private:
std::unique_ptr<base::SharedMemory> buffer_;
std::unique_ptr<base::CancelableSyncSocket> socket_;
@@ -133,9 +132,9 @@ std::unique_ptr<AudioOutputDelegate> CreateNoDelegate(
return nullptr;
}
-void NotCalled(mojom::AudioDataPipePtr data_pipe) {
- EXPECT_TRUE(false) << "The StreamCreated callback was called despite the "
- "test expecting it not to.";
+void NotCalled(mojom::AudioOutputStreamPtr, mojom::AudioDataPipePtr) {
+ ADD_FAILURE() << "The StreamCreated callback was called despite the test "
+ "expecting it not to.";
}
} // namespace
@@ -143,30 +142,38 @@ void NotCalled(mojom::AudioDataPipePtr data_pipe) {
class MojoAudioOutputStreamTest : public Test {
public:
MojoAudioOutputStreamTest()
- : foreign_socket_(std::make_unique<TestCancelableSyncSocket>()),
- client_binding_(&client_, mojo::MakeRequest(&client_ptr_)) {}
+ : foreign_socket_(std::make_unique<TestCancelableSyncSocket>()) {}
AudioOutputStreamPtr CreateAudioOutput() {
- AudioOutputStreamPtr p;
+ mojom::AudioOutputStreamPtr p;
+ pending_stream_request_ = mojo::MakeRequest(&p);
ExpectDelegateCreation();
impl_ = std::make_unique<MojoAudioOutputStream>(
- mojo::MakeRequest(&p), std::move(client_ptr_),
base::BindOnce(&MockDelegateFactory::CreateDelegate,
base::Unretained(&mock_delegate_factory_)),
- base::BindOnce(&MockClient::Initialized, base::Unretained(&client_)),
+ base::BindOnce(&MojoAudioOutputStreamTest::CreatedStream,
+ base::Unretained(this)),
base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_)));
- EXPECT_TRUE(p.is_bound());
return p;
}
protected:
+ void CreatedStream(mojom::AudioOutputStreamPtr stream,
+ mojom::AudioDataPipePtr data_pipe) {
+ EXPECT_EQ(mojo::FuseMessagePipes(pending_stream_request_.PassMessagePipe(),
+ stream.PassInterface().PassHandle()),
+ MOJO_RESULT_OK);
+ client_.Initialize(std::move(data_pipe));
+ }
+
void ExpectDelegateCreation() {
delegate_ = new StrictMock<MockDelegate>();
mock_delegate_factory_.PrepareDelegateForCreation(
base::WrapUnique(delegate_));
EXPECT_TRUE(
base::CancelableSyncSocket::CreatePair(&local_, foreign_socket_.get()));
- EXPECT_TRUE(mem_.CreateAnonymous(kShmemSize));
+ mem_ = base::UnsafeSharedMemoryRegion::Create(kShmemSize);
+ EXPECT_TRUE(mem_.IsValid());
EXPECT_CALL(mock_delegate_factory_, MockCreateDelegate(NotNull()))
.WillOnce(SaveArg<0>(&delegate_event_handler_));
}
@@ -174,51 +181,57 @@ class MojoAudioOutputStreamTest : public Test {
base::MessageLoop loop_;
base::CancelableSyncSocket local_;
std::unique_ptr<TestCancelableSyncSocket> foreign_socket_;
- base::SharedMemory mem_;
+ base::UnsafeSharedMemoryRegion mem_;
StrictMock<MockDelegate>* delegate_ = nullptr;
AudioOutputDelegate::EventHandler* delegate_event_handler_ = nullptr;
StrictMock<MockDelegateFactory> mock_delegate_factory_;
StrictMock<MockDeleter> deleter_;
StrictMock<MockClient> client_;
- media::mojom::AudioOutputStreamClientPtr client_ptr_;
- mojo::Binding<media::mojom::AudioOutputStreamClient> client_binding_;
+ mojom::AudioOutputStreamRequest pending_stream_request_;
std::unique_ptr<MojoAudioOutputStream> impl_;
};
TEST_F(MojoAudioOutputStreamTest, NoDelegate_SignalsError) {
- bool deleter_called = false;
- EXPECT_CALL(client_, OnError()).Times(1);
mojom::AudioOutputStreamPtr stream_ptr;
MojoAudioOutputStream stream(
- mojo::MakeRequest(&stream_ptr), std::move(client_ptr_),
base::BindOnce(&CreateNoDelegate), base::BindOnce(&NotCalled),
- base::BindOnce([](bool* p) { *p = true; }, &deleter_called));
- EXPECT_FALSE(deleter_called)
- << "Stream shouldn't call the deleter from its constructor.";
+ base::BindOnce(&MockDeleter::Finished, base::Unretained(&deleter_)));
+ EXPECT_CALL(deleter_, Finished(true));
base::RunLoop().RunUntilIdle();
- EXPECT_TRUE(deleter_called);
}
TEST_F(MojoAudioOutputStreamTest, Play_Plays) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
+
+ EXPECT_CALL(client_, GotNotification());
EXPECT_CALL(*delegate_, OnPlayStream());
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_));
audio_output_ptr->Play();
base::RunLoop().RunUntilIdle();
}
TEST_F(MojoAudioOutputStreamTest, Pause_Pauses) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
+
+ EXPECT_CALL(client_, GotNotification());
EXPECT_CALL(*delegate_, OnPauseStream());
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_));
audio_output_ptr->Pause();
base::RunLoop().RunUntilIdle();
}
TEST_F(MojoAudioOutputStreamTest, SetVolume_SetsVolume) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
+
+ EXPECT_CALL(client_, GotNotification());
EXPECT_CALL(*delegate_, OnSetVolume(kNewVolume));
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_));
audio_output_ptr->SetVolume(kNewVolume);
base::RunLoop().RunUntilIdle();
}
@@ -230,7 +243,7 @@ TEST_F(MojoAudioOutputStreamTest, DestructWithCallPending_Safe) {
ASSERT_NE(nullptr, delegate_event_handler_);
foreign_socket_->ExpectOwnershipTransfer();
- delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
std::move(foreign_socket_));
audio_output_ptr->Play();
impl_.reset();
@@ -245,7 +258,7 @@ TEST_F(MojoAudioOutputStreamTest, Created_NotifiesClient) {
ASSERT_NE(nullptr, delegate_event_handler_);
foreign_socket_->ExpectOwnershipTransfer();
- delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
std::move(foreign_socket_));
base::RunLoop().RunUntilIdle();
@@ -253,9 +266,11 @@ TEST_F(MojoAudioOutputStreamTest, Created_NotifiesClient) {
TEST_F(MojoAudioOutputStreamTest, SetVolumeTooLarge_Error) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
- EXPECT_CALL(deleter_, Finished());
- EXPECT_CALL(client_, OnError()).Times(1);
+ EXPECT_CALL(deleter_, Finished(true));
+ EXPECT_CALL(client_, GotNotification());
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_));
audio_output_ptr->SetVolume(15);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClear(&deleter_);
@@ -263,9 +278,11 @@ TEST_F(MojoAudioOutputStreamTest, SetVolumeTooLarge_Error) {
TEST_F(MojoAudioOutputStreamTest, SetVolumeNegative_Error) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
- EXPECT_CALL(deleter_, Finished());
- EXPECT_CALL(client_, OnError()).Times(1);
+ EXPECT_CALL(deleter_, Finished(true));
+ EXPECT_CALL(client_, GotNotification());
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_));
audio_output_ptr->SetVolume(-0.5);
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClear(&deleter_);
@@ -273,8 +290,7 @@ TEST_F(MojoAudioOutputStreamTest, SetVolumeNegative_Error) {
TEST_F(MojoAudioOutputStreamTest, DelegateErrorBeforeCreated_PropagatesError) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
- EXPECT_CALL(deleter_, Finished());
- EXPECT_CALL(client_, OnError()).Times(1);
+ EXPECT_CALL(deleter_, Finished(true));
ASSERT_NE(nullptr, delegate_event_handler_);
delegate_event_handler_->OnStreamError(kStreamId);
@@ -286,13 +302,12 @@ TEST_F(MojoAudioOutputStreamTest, DelegateErrorBeforeCreated_PropagatesError) {
TEST_F(MojoAudioOutputStreamTest, DelegateErrorAfterCreated_PropagatesError) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
EXPECT_CALL(client_, GotNotification());
- EXPECT_CALL(deleter_, Finished());
- EXPECT_CALL(client_, OnError()).Times(1);
+ EXPECT_CALL(deleter_, Finished(true));
base::RunLoop().RunUntilIdle();
ASSERT_NE(nullptr, delegate_event_handler_);
foreign_socket_->ExpectOwnershipTransfer();
- delegate_event_handler_->OnStreamCreated(kStreamId, &mem_,
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
std::move(foreign_socket_));
delegate_event_handler_->OnStreamError(kStreamId);
@@ -300,9 +315,14 @@ TEST_F(MojoAudioOutputStreamTest, DelegateErrorAfterCreated_PropagatesError) {
Mock::VerifyAndClear(&deleter_);
}
-TEST_F(MojoAudioOutputStreamTest, RemoteEndGone_Error) {
+TEST_F(MojoAudioOutputStreamTest, RemoteEndGone_CallsDeleter) {
AudioOutputStreamPtr audio_output_ptr = CreateAudioOutput();
- EXPECT_CALL(deleter_, Finished());
+
+ EXPECT_CALL(client_, GotNotification());
+ EXPECT_CALL(deleter_, Finished(false));
+
+ delegate_event_handler_->OnStreamCreated(kStreamId, std::move(mem_),
+ std::move(foreign_socket_));
audio_output_ptr.reset();
base::RunLoop().RunUntilIdle();
Mock::VerifyAndClear(&deleter_);
diff --git a/chromium/media/mojo/services/mojo_cdm_service.cc b/chromium/media/mojo/services/mojo_cdm_service.cc
index 5c39b204fe2..31bb3e7fa5e 100644
--- a/chromium/media/mojo/services/mojo_cdm_service.cc
+++ b/chromium/media/mojo/services/mojo_cdm_service.cc
@@ -166,12 +166,17 @@ void MojoCdmService::OnCdmCreated(
// If |cdm| has a decryptor, create the MojoDecryptorService
// and pass the connection back to the client.
- mojom::DecryptorPtr decryptor_service;
+ mojom::DecryptorPtr decryptor_ptr;
CdmContext* const cdm_context = cdm_->GetCdmContext();
if (cdm_context && cdm_context->GetDecryptor()) {
- decryptor_.reset(new MojoDecryptorService(
- cdm_context->GetDecryptor(), MakeRequest(&decryptor_service),
- base::Bind(&MojoCdmService::OnDecryptorConnectionError, weak_this_)));
+ // Both |cdm_| and |decryptor_| are owned by |this|, so we don't need to
+ // pass in a CdmContextRef.
+ decryptor_.reset(
+ new MojoDecryptorService(cdm_context->GetDecryptor(), nullptr));
+ decryptor_binding_ = std::make_unique<mojo::Binding<mojom::Decryptor>>(
+ decryptor_.get(), MakeRequest(&decryptor_ptr));
+ decryptor_binding_->set_connection_error_handler(base::BindOnce(
+ &MojoCdmService::OnDecryptorConnectionError, weak_this_));
}
// If the |context_| is not null, we should support connecting the |cdm| with
@@ -184,7 +189,7 @@ void MojoCdmService::OnCdmCreated(
cdm_promise_result->success = true;
std::move(callback).Run(std::move(cdm_promise_result), cdm_id,
- std::move(decryptor_service));
+ std::move(decryptor_ptr));
}
void MojoCdmService::OnSessionMessage(const std::string& session_id,
diff --git a/chromium/media/mojo/services/mojo_cdm_service.h b/chromium/media/mojo/services/mojo_cdm_service.h
index 051d46dd18b..716620b9e6c 100644
--- a/chromium/media/mojo/services/mojo_cdm_service.h
+++ b/chromium/media/mojo/services/mojo_cdm_service.h
@@ -21,6 +21,7 @@
#include "media/mojo/services/mojo_cdm_promise.h"
#include "media/mojo/services/mojo_cdm_service_context.h"
#include "media/mojo/services/mojo_decryptor_service.h"
+#include "mojo/public/cpp/bindings/binding.h"
namespace media {
@@ -106,6 +107,7 @@ class MEDIA_MOJO_EXPORT MojoCdmService : public mojom::ContentDecryptionModule {
// MojoDecryptorService is passed the Decryptor from |cdm_|, so
// |decryptor_| must not outlive |cdm_|.
std::unique_ptr<MojoDecryptorService> decryptor_;
+ std::unique_ptr<mojo::Binding<mojom::Decryptor>> decryptor_binding_;
// Set to a valid CDM ID if the |cdm_| is successfully created.
int cdm_id_;
diff --git a/chromium/media/mojo/services/mojo_cdm_service_context.cc b/chromium/media/mojo/services/mojo_cdm_service_context.cc
index f7d62ccd6a0..49e71b5e111 100644
--- a/chromium/media/mojo/services/mojo_cdm_service_context.cc
+++ b/chromium/media/mojo/services/mojo_cdm_service_context.cc
@@ -38,13 +38,14 @@ class CdmProxyContextRef : public CdmContextRef, public CdmContext {
private:
// CdmContext implementation.
- CdmProxyContext* GetCdmProxyContext() final {
+ Decryptor* GetDecryptor() final {
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return cdm_context_ ? cdm_context_->GetDecryptor() : nullptr;
+ }
- if (!cdm_context_)
- return nullptr;
-
- return cdm_context_->GetCdmProxyContext();
+ CdmProxyContext* GetCdmProxyContext() final {
+ DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+ return cdm_context_ ? cdm_context_->GetCdmProxyContext() : nullptr;
}
base::WeakPtr<CdmContext> cdm_context_;
diff --git a/chromium/media/mojo/services/mojo_decryptor_service.cc b/chromium/media/mojo/services/mojo_decryptor_service.cc
index 99307ad60fb..8a08b90f305 100644
--- a/chromium/media/mojo/services/mojo_decryptor_service.cc
+++ b/chromium/media/mojo/services/mojo_decryptor_service.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/numerics/safe_conversions.h"
#include "media/base/audio_decoder_config.h"
+#include "media/base/cdm_context.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decryptor.h"
#include "media/base/video_decoder_config.h"
@@ -17,6 +18,7 @@
#include "media/mojo/common/mojo_decoder_buffer_converter.h"
#include "media/mojo/common/mojo_shared_buffer_video_frame.h"
#include "media/mojo/interfaces/demuxer_stream.mojom.h"
+#include "media/mojo/services/mojo_cdm_service_context.h"
#include "mojo/public/cpp/bindings/strong_binding.h"
namespace media {
@@ -45,17 +47,40 @@ class FrameResourceReleaserImpl final : public mojom::FrameResourceReleaser {
} // namespace
+// static
+std::unique_ptr<MojoDecryptorService> MojoDecryptorService::Create(
+ int cdm_id,
+ MojoCdmServiceContext* mojo_cdm_service_context) {
+ auto cdm_context_ref = mojo_cdm_service_context->GetCdmContextRef(cdm_id);
+ if (!cdm_context_ref) {
+ DVLOG(1) << "CdmContextRef not found for CDM ID: " << cdm_id;
+ return nullptr;
+ }
+
+ auto* cdm_context = cdm_context_ref->GetCdmContext();
+ DCHECK(cdm_context);
+
+ auto* decryptor = cdm_context->GetDecryptor();
+ if (!decryptor) {
+ DVLOG(1) << "CdmContext does not support Decryptor";
+ return nullptr;
+ }
+
+ return std::make_unique<MojoDecryptorService>(decryptor,
+ std::move(cdm_context_ref));
+}
+
MojoDecryptorService::MojoDecryptorService(
media::Decryptor* decryptor,
- mojo::InterfaceRequest<mojom::Decryptor> request,
- const base::Closure& error_handler)
- : binding_(this, std::move(request)),
- decryptor_(decryptor),
+ std::unique_ptr<CdmContextRef> cdm_context_ref)
+ : decryptor_(decryptor),
+ cdm_context_ref_(std::move(cdm_context_ref)),
weak_factory_(this) {
DVLOG(1) << __func__;
DCHECK(decryptor_);
+ // |cdm_context_ref_| could be null, in which case the owner of |this| will
+ // make sure |decryptor_| is always valid.
weak_this_ = weak_factory_.GetWeakPtr();
- binding_.set_connection_error_handler(error_handler);
}
MojoDecryptorService::~MojoDecryptorService() {
diff --git a/chromium/media/mojo/services/mojo_decryptor_service.h b/chromium/media/mojo/services/mojo_decryptor_service.h
index 879456b1f35..17e82580997 100644
--- a/chromium/media/mojo/services/mojo_decryptor_service.h
+++ b/chromium/media/mojo/services/mojo_decryptor_service.h
@@ -13,30 +13,34 @@
#include "base/macros.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "media/base/cdm_context.h"
#include "media/base/decryptor.h"
#include "media/mojo/interfaces/decryptor.mojom.h"
#include "media/mojo/services/media_mojo_export.h"
-#include "mojo/public/cpp/bindings/binding.h"
namespace media {
class DecoderBuffer;
+class MojoCdmServiceContext;
class MojoDecoderBufferReader;
class MojoDecoderBufferWriter;
-// A mojom::Decryptor implementation. This object is owned by the creator,
-// and uses a weak binding across the mojo interface.
+// A mojom::Decryptor implementation that proxies decryptor calls to a
+// media::Decryptor.
class MEDIA_MOJO_EXPORT MojoDecryptorService : public mojom::Decryptor {
public:
using StreamType = media::Decryptor::StreamType;
using Status = media::Decryptor::Status;
- // Constructs a MojoDecryptorService and binds it to the |request|.
- // |error_handler| will be called if a connection error occurs.
- // Caller must ensure that |decryptor| outlives |this|.
+ static std::unique_ptr<MojoDecryptorService> Create(
+ int cdm_id,
+ MojoCdmServiceContext* mojo_cdm_service_context);
+
+ // If |cdm_context_ref| is null, caller must ensure that |decryptor| outlives
+ // |this|. Otherwise, |decryptor| is guaranteed to be valid as long as
+ // |cdm_context_ref| is held.
MojoDecryptorService(media::Decryptor* decryptor,
- mojo::InterfaceRequest<mojom::Decryptor> request,
- const base::Closure& error_handler);
+ std::unique_ptr<CdmContextRef> cdm_context_ref);
~MojoDecryptorService() final;
@@ -93,9 +97,6 @@ class MEDIA_MOJO_EXPORT MojoDecryptorService : public mojom::Decryptor {
// Returns audio/video buffer reader according to the |stream_type|.
MojoDecoderBufferReader* GetBufferReader(StreamType stream_type) const;
- // A weak binding is used to connect to the MojoDecryptor.
- mojo::Binding<mojom::Decryptor> binding_;
-
// Helper classes to receive encrypted DecoderBuffer from the client.
std::unique_ptr<MojoDecoderBufferReader> audio_buffer_reader_;
std::unique_ptr<MojoDecoderBufferReader> video_buffer_reader_;
@@ -106,6 +107,10 @@ class MEDIA_MOJO_EXPORT MojoDecryptorService : public mojom::Decryptor {
media::Decryptor* decryptor_;
+ // Holds the CdmContextRef to keep the CdmContext alive for the lifetime of
+ // the |decryptor_|.
+ std::unique_ptr<CdmContextRef> cdm_context_ref_;
+
base::WeakPtr<MojoDecryptorService> weak_this_;
base::WeakPtrFactory<MojoDecryptorService> weak_factory_;
diff --git a/chromium/media/mojo/services/mojo_jpeg_decode_accelerator_service_unittest.cc b/chromium/media/mojo/services/mojo_jpeg_decode_accelerator_service_unittest.cc
index 4e7fc0d33f2..d12bf86edf3 100644
--- a/chromium/media/mojo/services/mojo_jpeg_decode_accelerator_service_unittest.cc
+++ b/chromium/media/mojo/services/mojo_jpeg_decode_accelerator_service_unittest.cc
@@ -78,7 +78,7 @@ TEST_F(MojoJpegDecodeAcceleratorServiceTest, InitializeAndDecode) {
kArbitraryBitstreamBufferId,
base::SharedMemory::DuplicateHandle(shm.handle()),
kInputBufferSizeInBytes);
- bitstream_buffer.SetDecryptConfig(DecryptConfig(kKeyId, kIv, subsamples));
+ bitstream_buffer.SetDecryptionSettings(kKeyId, kIv, subsamples);
jpeg_decoder->Decode(
bitstream_buffer, kDummyFrameCodedSize, std::move(output_frame_handle),
diff --git a/chromium/media/mojo/services/mojo_jpeg_encode_accelerator_service.cc b/chromium/media/mojo/services/mojo_jpeg_encode_accelerator_service.cc
index 25b67848d06..41ec4400eba 100644
--- a/chromium/media/mojo/services/mojo_jpeg_encode_accelerator_service.cc
+++ b/chromium/media/mojo/services/mojo_jpeg_encode_accelerator_service.cc
@@ -145,8 +145,11 @@ void MojoJpegEncodeAcceleratorService::EncodeWithFD(
media::BitstreamBuffer output_buffer(buffer_id, output_shm_handle,
output_buffer_size);
- media::BitstreamBuffer exif_buffer(buffer_id, exif_shm_handle,
- exif_buffer_size);
+ std::unique_ptr<media::BitstreamBuffer> exif_buffer;
+ if (exif_buffer_size > 0) {
+ exif_buffer = std::make_unique<media::BitstreamBuffer>(
+ buffer_id, exif_shm_handle, exif_buffer_size);
+ }
gfx::Size coded_size(coded_size_width, coded_size_height);
if (encode_cb_map_.find(buffer_id) != encode_cb_map_.end()) {
@@ -187,7 +190,7 @@ void MojoJpegEncodeAcceleratorService::EncodeWithFD(
base::Passed(&input_shm)));
DCHECK(accelerator_);
- accelerator_->Encode(frame, kJpegQuality, &exif_buffer, output_buffer);
+ accelerator_->Encode(frame, kJpegQuality, exif_buffer.get(), output_buffer);
#else
NOTREACHED();
#endif
diff --git a/chromium/media/mojo/services/mojo_media_client.cc b/chromium/media/mojo/services/mojo_media_client.cc
index 1bdf6e16971..83ef569ff33 100644
--- a/chromium/media/mojo/services/mojo_media_client.cc
+++ b/chromium/media/mojo/services/mojo_media_client.cc
@@ -6,12 +6,10 @@
#include "base/single_thread_task_runner.h"
#include "media/base/audio_decoder.h"
-#include "media/base/audio_renderer_sink.h"
#include "media/base/cdm_factory.h"
#include "media/base/media_log.h"
-#include "media/base/renderer_factory.h"
+#include "media/base/renderer.h"
#include "media/base/video_decoder.h"
-#include "media/base/video_renderer_sink.h"
#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
#include "media/cdm/cdm_proxy.h"
@@ -34,25 +32,18 @@ std::unique_ptr<VideoDecoder> MojoMediaClient::CreateVideoDecoder(
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
MediaLog* media_log,
mojom::CommandBufferIdPtr command_buffer_id,
- RequestOverlayInfoCB request_overlay_info_cb) {
+ RequestOverlayInfoCB request_overlay_info_cb,
+ const gfx::ColorSpace& target_color_space) {
return nullptr;
}
-scoped_refptr<AudioRendererSink> MojoMediaClient::CreateAudioRendererSink(
+std::unique_ptr<Renderer> MojoMediaClient::CreateRenderer(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ MediaLog* media_log,
const std::string& audio_device_id) {
return nullptr;
}
-std::unique_ptr<VideoRendererSink> MojoMediaClient::CreateVideoRendererSink(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
- return nullptr;
-}
-
-std::unique_ptr<RendererFactory> MojoMediaClient::CreateRendererFactory(
- MediaLog* media_log) {
- return nullptr;
-}
-
std::unique_ptr<CdmFactory> MojoMediaClient::CreateCdmFactory(
service_manager::mojom::InterfaceProvider* host_interfaces) {
return nullptr;
diff --git a/chromium/media/mojo/services/mojo_media_client.h b/chromium/media/mojo/services/mojo_media_client.h
index 9e84464a48d..47c8b9712d6 100644
--- a/chromium/media/mojo/services/mojo_media_client.h
+++ b/chromium/media/mojo/services/mojo_media_client.h
@@ -18,25 +18,27 @@
namespace base {
class SingleThreadTaskRunner;
-}
+} // namespace base
+
+namespace gfx {
+class ColorSpace;
+} // namespace gfx
namespace service_manager {
class Connector;
namespace mojom {
class InterfaceProvider;
-}
+} // namespace mojom
} // namespace service_manager
namespace media {
class AudioDecoder;
-class AudioRendererSink;
class CdmFactory;
class CdmProxy;
class MediaLog;
-class RendererFactory;
+class Renderer;
class VideoDecoder;
-class VideoRendererSink;
class MEDIA_MOJO_EXPORT MojoMediaClient {
public:
@@ -56,22 +58,16 @@ class MEDIA_MOJO_EXPORT MojoMediaClient {
scoped_refptr<base::SingleThreadTaskRunner> task_runner,
MediaLog* media_log,
mojom::CommandBufferIdPtr command_buffer_id,
- RequestOverlayInfoCB request_overlay_info_cb);
+ RequestOverlayInfoCB request_overlay_info_cb,
+ const gfx::ColorSpace& target_color_space);
- // Returns the output sink used for rendering audio on |audio_device_id|.
- // May be null if the RendererFactory doesn't need an audio sink.
- virtual scoped_refptr<AudioRendererSink> CreateAudioRendererSink(
+ // Returns the Renderer to be used by MojoRendererService.
+ // TODO(hubbe): Find out whether we should pass in |target_color_space| here.
+ virtual std::unique_ptr<Renderer> CreateRenderer(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ MediaLog* media_log,
const std::string& audio_device_id);
- // Returns the output sink used for rendering video.
- // May be null if the RendererFactory doesn't need a video sink.
- virtual std::unique_ptr<VideoRendererSink> CreateVideoRendererSink(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
-
- // Returns the RendererFactory to be used by MojoRendererService.
- virtual std::unique_ptr<RendererFactory> CreateRendererFactory(
- MediaLog* media_log);
-
// Returns the CdmFactory to be used by MojoCdmService. |host_interfaces| can
// be used to request interfaces provided remotely by the host. It may be a
// nullptr if the host chose not to bind the InterfacePtr.
diff --git a/chromium/media/mojo/services/mojo_media_log.cc b/chromium/media/mojo/services/mojo_media_log.cc
index f13f13ea963..30941d4bab8 100644
--- a/chromium/media/mojo/services/mojo_media_log.cc
+++ b/chromium/media/mojo/services/mojo_media_log.cc
@@ -8,9 +8,8 @@
namespace media {
-// TODO(sandersd): Do we need to respond to the channel closing?
MojoMediaLog::MojoMediaLog(
- mojo::AssociatedInterfacePtr<mojom::MediaLog> remote_media_log)
+ scoped_refptr<mojom::ThreadSafeMediaLogAssociatedPtr> remote_media_log)
: remote_media_log_(std::move(remote_media_log)) {
DVLOG(1) << __func__;
}
@@ -22,7 +21,7 @@ MojoMediaLog::~MojoMediaLog() {
void MojoMediaLog::AddEvent(std::unique_ptr<MediaLogEvent> event) {
DVLOG(1) << __func__;
DCHECK(event);
- remote_media_log_->AddEvent(*event);
+ (**remote_media_log_).AddEvent(*event);
}
} // namespace media
diff --git a/chromium/media/mojo/services/mojo_media_log.h b/chromium/media/mojo/services/mojo_media_log.h
index bf46c381486..78e526f359a 100644
--- a/chromium/media/mojo/services/mojo_media_log.h
+++ b/chromium/media/mojo/services/mojo_media_log.h
@@ -8,9 +8,9 @@
#include <memory>
#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
#include "media/base/media_log.h"
#include "media/mojo/interfaces/media_log.mojom.h"
-#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
namespace media {
@@ -18,14 +18,14 @@ class MojoMediaLog final : public MediaLog {
public:
// TODO(sandersd): Template on Ptr type to support non-associated.
explicit MojoMediaLog(
- mojo::AssociatedInterfacePtr<mojom::MediaLog> remote_media_log);
+ scoped_refptr<mojom::ThreadSafeMediaLogAssociatedPtr> remote_media_log);
~MojoMediaLog() final;
// MediaLog implementation.
void AddEvent(std::unique_ptr<MediaLogEvent> event) override;
private:
- mojo::AssociatedInterfacePtr<mojom::MediaLog> remote_media_log_;
+ scoped_refptr<mojom::ThreadSafeMediaLogAssociatedPtr> remote_media_log_;
DISALLOW_COPY_AND_ASSIGN(MojoMediaLog);
};
diff --git a/chromium/media/mojo/services/mojo_renderer_service.cc b/chromium/media/mojo/services/mojo_renderer_service.cc
index 7097a77d07a..f385149ccb6 100644
--- a/chromium/media/mojo/services/mojo_renderer_service.cc
+++ b/chromium/media/mojo/services/mojo_renderer_service.cc
@@ -9,11 +9,9 @@
#include "base/bind.h"
#include "base/memory/ptr_util.h"
#include "base/optional.h"
-#include "media/base/audio_renderer_sink.h"
#include "media/base/cdm_context.h"
#include "media/base/media_url_demuxer.h"
#include "media/base/renderer.h"
-#include "media/base/video_renderer_sink.h"
#include "media/mojo/common/media_type_converters.h"
#include "media/mojo/services/media_resource_shim.h"
#include "media/mojo/services/mojo_cdm_service_context.h"
@@ -36,14 +34,12 @@ const int kTimeUpdateIntervalMs = 50;
// static
mojo::StrongBindingPtr<mojom::Renderer> MojoRendererService::Create(
MojoCdmServiceContext* mojo_cdm_service_context,
- scoped_refptr<AudioRendererSink> audio_sink,
- std::unique_ptr<VideoRendererSink> video_sink,
std::unique_ptr<media::Renderer> renderer,
const InitiateSurfaceRequestCB& initiate_surface_request_cb,
mojo::InterfaceRequest<mojom::Renderer> request) {
- MojoRendererService* service = new MojoRendererService(
- mojo_cdm_service_context, std::move(audio_sink), std::move(video_sink),
- std::move(renderer), initiate_surface_request_cb);
+ MojoRendererService* service =
+ new MojoRendererService(mojo_cdm_service_context, std::move(renderer),
+ initiate_surface_request_cb);
mojo::StrongBindingPtr<mojom::Renderer> binding =
mojo::MakeStrongBinding<mojom::Renderer>(base::WrapUnique(service),
@@ -54,27 +50,13 @@ mojo::StrongBindingPtr<mojom::Renderer> MojoRendererService::Create(
return binding;
}
-// static
-mojo::StrongBindingPtr<mojom::Renderer> MojoRendererService::Create(
- std::unique_ptr<media::Renderer> renderer,
- const InitiateSurfaceRequestCB& initiate_surface_request_cb,
- mojo::InterfaceRequest<mojom::Renderer> request) {
- return MojoRendererService::Create(
- nullptr, nullptr, nullptr, std::move(renderer),
- initiate_surface_request_cb, std::move(request));
-}
-
MojoRendererService::MojoRendererService(
MojoCdmServiceContext* mojo_cdm_service_context,
- scoped_refptr<AudioRendererSink> audio_sink,
- std::unique_ptr<VideoRendererSink> video_sink,
std::unique_ptr<media::Renderer> renderer,
InitiateSurfaceRequestCB initiate_surface_request_cb)
: mojo_cdm_service_context_(mojo_cdm_service_context),
state_(STATE_UNINITIALIZED),
playback_rate_(0),
- audio_sink_(std::move(audio_sink)),
- video_sink_(std::move(video_sink)),
renderer_(std::move(renderer)),
initiate_surface_request_cb_(initiate_surface_request_cb),
weak_factory_(this) {
@@ -281,9 +263,8 @@ void MojoRendererService::OnFlushCompleted(FlushCallback callback) {
std::move(callback).Run();
}
-void MojoRendererService::OnCdmAttached(
- base::OnceCallback<void(bool)> callback,
- bool success) {
+void MojoRendererService::OnCdmAttached(base::OnceCallback<void(bool)> callback,
+ bool success) {
DVLOG(1) << __func__ << "(" << success << ")";
if (!success)
diff --git a/chromium/media/mojo/services/mojo_renderer_service.h b/chromium/media/mojo/services/mojo_renderer_service.h
index 8303d772c7b..49a192a55d3 100644
--- a/chromium/media/mojo/services/mojo_renderer_service.h
+++ b/chromium/media/mojo/services/mojo_renderer_service.h
@@ -25,12 +25,10 @@
namespace media {
-class AudioRendererSink;
class CdmContextRef;
class MediaResourceShim;
class MojoCdmServiceContext;
class Renderer;
-class VideoRendererSink;
// A mojom::Renderer implementation that use a media::Renderer to render
// media streams.
@@ -43,21 +41,6 @@ class MEDIA_MOJO_EXPORT MojoRendererService : public mojom::Renderer,
// which is safely accessible via the returned StrongBindingPtr.
static mojo::StrongBindingPtr<mojom::Renderer> Create(
MojoCdmServiceContext* mojo_cdm_service_context,
- scoped_refptr<AudioRendererSink> audio_sink,
- std::unique_ptr<VideoRendererSink> video_sink,
- std::unique_ptr<media::Renderer> renderer,
- const InitiateSurfaceRequestCB& initiate_surface_request_cb,
- mojo::InterfaceRequest<mojom::Renderer> request);
-
- // Helper function to bind MojoRendererService with a StrongBinding,
- // which is safely accessible via the returned StrongBindingPtr.
- // NOTE: Some media::Renderers don't need Audio/VideoRendererSinks, and don't
- // support encrypted content. For example, MediaPlayerRenderer instead uses a
- // StreamTextureWrapper, and FlingingRenderer does not need to render any
- // video on the local device. This function serves the same purpose as the one
- // above, but without forcing classes to define the forward declared
- // AudioRendererSink, VideoRendererSink and MojoCdmServiceContext.
- static mojo::StrongBindingPtr<mojom::Renderer> Create(
std::unique_ptr<media::Renderer> renderer,
const InitiateSurfaceRequestCB& initiate_surface_request_cb,
mojo::InterfaceRequest<mojom::Renderer> request);
@@ -65,8 +48,6 @@ class MEDIA_MOJO_EXPORT MojoRendererService : public mojom::Renderer,
// |mojo_cdm_service_context| can be used to find the CDM to support
// encrypted media. If null, encrypted media is not supported.
MojoRendererService(MojoCdmServiceContext* mojo_cdm_service_context,
- scoped_refptr<AudioRendererSink> audio_sink,
- std::unique_ptr<VideoRendererSink> video_sink,
std::unique_ptr<media::Renderer> renderer,
InitiateSurfaceRequestCB initiate_surface_request_cb);
@@ -150,14 +131,8 @@ class MEDIA_MOJO_EXPORT MojoRendererService : public mojom::Renderer,
// the |renderer_|.
std::unique_ptr<CdmContextRef> cdm_context_ref_;
- // Audio and Video sinks.
- // May be null if underlying |renderer_| does not use them.
- scoped_refptr<AudioRendererSink> audio_sink_;
- std::unique_ptr<VideoRendererSink> video_sink_;
-
// Note: Destroy |renderer_| first to avoid access violation into other
- // members, e.g. |media_resource_|, |cdm_|, |audio_sink_|, and
- // |video_sink_|.
+ // members, e.g. |media_resource_| and |cdm_|.
// Must use "media::" because "Renderer" is ambiguous.
std::unique_ptr<media::Renderer> renderer_;
diff --git a/chromium/media/mojo/services/mojo_video_decoder_service.cc b/chromium/media/mojo/services/mojo_video_decoder_service.cc
index a68e7701ffb..ccfd012bcbc 100644
--- a/chromium/media/mojo/services/mojo_video_decoder_service.cc
+++ b/chromium/media/mojo/services/mojo_video_decoder_service.cc
@@ -8,6 +8,7 @@
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "base/macros.h"
+#include "base/metrics/histogram_macros.h"
#include "base/optional.h"
#include "base/threading/thread_task_runner_handle.h"
#include "media/base/cdm_context.h"
@@ -29,6 +30,13 @@ namespace media {
namespace {
+// Number of active (Decode() was called at least once)
+// MojoVideoDecoderService instances that are alive.
+//
+// Since MojoVideoDecoderService is constructed only by the MediaFactory,
+// this will only ever be accessed from a single thread.
+static int32_t g_num_active_mvd_instances = 0;
+
class StaticSyncTokenClient : public VideoFrame::SyncTokenClient {
public:
explicit StaticSyncTokenClient(const gpu::SyncToken& sync_token)
@@ -66,7 +74,7 @@ class VideoFrameHandleReleaserImpl final
// VideoFrame.
base::UnguessableToken RegisterVideoFrame(scoped_refptr<VideoFrame> frame) {
base::UnguessableToken token = base::UnguessableToken::Create();
- DVLOG(2) << __func__ << " => " << token.ToString();
+ DVLOG(3) << __func__ << " => " << token.ToString();
video_frames_[token] = std::move(frame);
return token;
}
@@ -74,7 +82,7 @@ class VideoFrameHandleReleaserImpl final
// mojom::MojoVideoFrameHandleReleaser implementation
void ReleaseVideoFrame(const base::UnguessableToken& release_token,
const gpu::SyncToken& release_sync_token) final {
- DVLOG(2) << __func__ << "(" << release_token.ToString() << ")";
+ DVLOG(3) << __func__ << "(" << release_token.ToString() << ")";
auto it = video_frames_.find(release_token);
if (it == video_frames_.end()) {
mojo::ReportBadMessage("Unknown |release_token|.");
@@ -98,14 +106,17 @@ MojoVideoDecoderService::MojoVideoDecoderService(
: mojo_media_client_(mojo_media_client),
mojo_cdm_service_context_(mojo_cdm_service_context),
weak_factory_(this) {
- DVLOG(3) << __func__;
+ DVLOG(1) << __func__;
DCHECK(mojo_media_client_);
DCHECK(mojo_cdm_service_context_);
weak_this_ = weak_factory_.GetWeakPtr();
}
MojoVideoDecoderService::~MojoVideoDecoderService() {
- DVLOG(3) << __func__;
+ DVLOG(1) << __func__;
+
+ if (is_active_instance_)
+ g_num_active_mvd_instances--;
}
void MojoVideoDecoderService::Construct(
@@ -113,7 +124,8 @@ void MojoVideoDecoderService::Construct(
mojom::MediaLogAssociatedPtrInfo media_log,
mojom::VideoFrameHandleReleaserRequest video_frame_handle_releaser,
mojo::ScopedDataPipeConsumerHandle decoder_buffer_pipe,
- mojom::CommandBufferIdPtr command_buffer_id) {
+ mojom::CommandBufferIdPtr command_buffer_id,
+ const gfx::ColorSpace& target_color_space) {
DVLOG(1) << __func__;
if (decoder_) {
@@ -124,9 +136,9 @@ void MojoVideoDecoderService::Construct(
client_.Bind(std::move(client));
- mojom::MediaLogAssociatedPtr media_log_ptr;
- media_log_ptr.Bind(std::move(media_log));
- media_log_ = std::make_unique<MojoMediaLog>(std::move(media_log_ptr));
+ media_log_ = std::make_unique<MojoMediaLog>(
+ mojom::ThreadSafeMediaLogAssociatedPtr::Create(
+ std::move(media_log), base::ThreadTaskRunnerHandle::Get()));
video_frame_handle_releaser_ =
mojo::MakeStrongBinding(std::make_unique<VideoFrameHandleReleaserImpl>(),
@@ -139,14 +151,16 @@ void MojoVideoDecoderService::Construct(
base::ThreadTaskRunnerHandle::Get(), media_log_.get(),
std::move(command_buffer_id),
base::Bind(&MojoVideoDecoderService::OnDecoderRequestedOverlayInfo,
- weak_this_));
+ weak_this_),
+ target_color_space);
}
void MojoVideoDecoderService::Initialize(const VideoDecoderConfig& config,
bool low_delay,
int32_t cdm_id,
InitializeCallback callback) {
- DVLOG(1) << __func__;
+ DVLOG(1) << __func__ << " config = " << config.AsHumanReadableString()
+ << ", cdm_id = " << cdm_id;
if (!decoder_) {
std::move(callback).Run(false, false, 1);
@@ -155,7 +169,7 @@ void MojoVideoDecoderService::Initialize(const VideoDecoderConfig& config,
// Get CdmContext from cdm_id if the stream is encrypted.
CdmContext* cdm_context = nullptr;
- if (config.is_encrypted()) {
+ if (cdm_id != CdmContext::kInvalidCdmId) {
cdm_context_ref_ = mojo_cdm_service_context_->GetCdmContextRef(cdm_id);
if (!cdm_context_ref_) {
DVLOG(1) << "CdmContextRef not found for CDM id: " << cdm_id;
@@ -173,40 +187,46 @@ void MojoVideoDecoderService::Initialize(const VideoDecoderConfig& config,
base::Passed(&callback)),
base::BindRepeating(&MojoVideoDecoderService::OnDecoderOutput,
weak_this_),
- media::VideoDecoder::WaitingForDecryptionKeyCB());
+ base::NullCallback());
}
void MojoVideoDecoderService::Decode(mojom::DecoderBufferPtr buffer,
DecodeCallback callback) {
- DVLOG(2) << __func__ << " pts=" << buffer->timestamp.InMilliseconds();
+ DVLOG(3) << __func__ << " pts=" << buffer->timestamp.InMilliseconds();
if (!decoder_) {
std::move(callback).Run(DecodeStatus::DECODE_ERROR);
return;
}
+ if (!is_active_instance_) {
+ is_active_instance_ = true;
+ g_num_active_mvd_instances++;
+ UMA_HISTOGRAM_EXACT_LINEAR("Media.MojoVideoDecoder.ActiveInstances",
+ g_num_active_mvd_instances, 64);
+ }
+
mojo_decoder_buffer_reader_->ReadDecoderBuffer(
std::move(buffer), base::BindOnce(&MojoVideoDecoderService::OnReaderRead,
weak_this_, std::move(callback)));
}
void MojoVideoDecoderService::Reset(ResetCallback callback) {
- DVLOG(1) << __func__;
+ DVLOG(2) << __func__;
if (!decoder_) {
std::move(callback).Run();
return;
}
- // Flush the reader so that pending decodes will be dispatches first.
+ // Flush the reader so that pending decodes will be dispatched first.
mojo_decoder_buffer_reader_->Flush(
base::Bind(&MojoVideoDecoderService::OnReaderFlushed, weak_this_,
base::Passed(&callback)));
}
-void MojoVideoDecoderService::OnDecoderInitialized(
- InitializeCallback callback,
- bool success) {
+void MojoVideoDecoderService::OnDecoderInitialized(InitializeCallback callback,
+ bool success) {
DVLOG(1) << __func__;
DCHECK(decoder_);
@@ -239,21 +259,26 @@ void MojoVideoDecoderService::OnReaderFlushed(ResetCallback callback) {
void MojoVideoDecoderService::OnDecoderDecoded(DecodeCallback callback,
DecodeStatus status) {
- DVLOG(2) << __func__;
+ DVLOG(3) << __func__;
std::move(callback).Run(status);
}
void MojoVideoDecoderService::OnDecoderReset(ResetCallback callback) {
- DVLOG(1) << __func__;
+ DVLOG(2) << __func__;
std::move(callback).Run();
}
void MojoVideoDecoderService::OnDecoderOutput(
const scoped_refptr<VideoFrame>& frame) {
- DVLOG(2) << __func__;
+ DVLOG(3) << __func__;
DCHECK(client_);
DCHECK(decoder_);
+ // All MojoVideoDecoder-based decoders are hardware decoders. If you're the
+ // first to implement an out-of-process decoder that is not power efficent,
+ // you can remove this DCHECK.
+ DCHECK(frame->metadata()->IsTrue(VideoFrameMetadata::POWER_EFFICIENT));
+
base::Optional<base::UnguessableToken> release_token;
if (frame->HasReleaseMailboxCB() && video_frame_handle_releaser_) {
// |video_frame_handle_releaser_| is explicitly constructed with a
diff --git a/chromium/media/mojo/services/mojo_video_decoder_service.h b/chromium/media/mojo/services/mojo_video_decoder_service.h
index 739fff0b124..05aa82518f6 100644
--- a/chromium/media/mojo/services/mojo_video_decoder_service.h
+++ b/chromium/media/mojo/services/mojo_video_decoder_service.h
@@ -46,7 +46,8 @@ class MEDIA_MOJO_EXPORT MojoVideoDecoderService final
mojom::MediaLogAssociatedPtrInfo media_log,
mojom::VideoFrameHandleReleaserRequest video_frame_handle_releaser,
mojo::ScopedDataPipeConsumerHandle decoder_buffer_pipe,
- mojom::CommandBufferIdPtr command_buffer_id) final;
+ mojom::CommandBufferIdPtr command_buffer_id,
+ const gfx::ColorSpace& target_color_space) final;
void Initialize(const VideoDecoderConfig& config,
bool low_delay,
int32_t cdm_id,
@@ -75,6 +76,9 @@ class MEDIA_MOJO_EXPORT MojoVideoDecoderService final
bool restart_for_transitions,
const ProvideOverlayInfoCB& provide_overlay_info_cb);
+ // Whether this instance is active (Decode() was called at least once).
+ bool is_active_instance_ = false;
+
// Decoder factory.
MojoMediaClient* mojo_media_client_;
diff --git a/chromium/media/mojo/services/test_mojo_media_client.cc b/chromium/media/mojo/services/test_mojo_media_client.cc
index d5def90093f..6c3ce3d4427 100644
--- a/chromium/media/mojo/services/test_mojo_media_client.cc
+++ b/chromium/media/mojo/services/test_mojo_media_client.cc
@@ -6,7 +6,6 @@
#include <memory>
-#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
#include "base/threading/thread_task_runner_handle.h"
#include "media/audio/audio_device_description.h"
@@ -19,9 +18,16 @@
#include "media/base/null_video_sink.h"
#include "media/base/renderer_factory.h"
#include "media/cdm/default_cdm_factory.h"
+#include "media/renderers/default_decoder_factory.h"
#include "media/renderers/default_renderer_factory.h"
#include "media/video/gpu_video_accelerator_factories.h"
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+#include "media/cdm/cdm_paths.h" // nogncheck
+#include "media/cdm/cdm_proxy.h" // nogncheck
+#include "media/cdm/library_cdm/clear_key_cdm/clear_key_cdm_proxy.h" // nogncheck
+#endif
+
namespace media {
TestMojoMediaClient::TestMojoMediaClient() = default;
@@ -50,23 +56,40 @@ void TestMojoMediaClient::Initialize(
}
}
-scoped_refptr<AudioRendererSink> TestMojoMediaClient::CreateAudioRendererSink(
+std::unique_ptr<Renderer> TestMojoMediaClient::CreateRenderer(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ MediaLog* media_log,
const std::string& /* audio_device_id */) {
- return new AudioOutputStreamSink();
-}
+ // If called the first time, do one time initialization.
+ if (!decoder_factory_) {
+ decoder_factory_.reset(new media::DefaultDecoderFactory(nullptr));
+ }
-std::unique_ptr<VideoRendererSink> TestMojoMediaClient::CreateVideoRendererSink(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
- return std::make_unique<NullVideoSink>(
+ if (!renderer_factory_) {
+ renderer_factory_ = std::make_unique<DefaultRendererFactory>(
+ media_log, decoder_factory_.get(),
+ DefaultRendererFactory::GetGpuFactoriesCB());
+ }
+
+ // We cannot share AudioOutputStreamSink or NullVideoSink among different
+ // RendererImpls. Thus create one for each Renderer creation.
+ auto audio_sink = base::MakeRefCounted<AudioOutputStreamSink>();
+ auto video_sink = std::make_unique<NullVideoSink>(
false, base::TimeDelta::FromSecondsD(1.0 / 60),
NullVideoSink::NewFrameCB(), task_runner);
-}
+ auto* video_sink_ptr = video_sink.get();
-std::unique_ptr<RendererFactory> TestMojoMediaClient::CreateRendererFactory(
- MediaLog* media_log) {
- return std::make_unique<DefaultRendererFactory>(
- media_log, nullptr, DefaultRendererFactory::GetGpuFactoriesCB());
-}
+ // Hold created sinks since DefaultRendererFactory only takes raw pointers to
+ // the sinks. We are not cleaning up them even after a created Renderer is
+ // destroyed. But this is fine since this class is only used for tests.
+ audio_sinks_.push_back(audio_sink);
+ video_sinks_.push_back(std::move(video_sink));
+
+ return renderer_factory_->CreateRenderer(
+ task_runner, task_runner, audio_sink.get(), video_sink_ptr,
+ RequestOverlayInfoCB(), gfx::ColorSpace());
+
+} // namespace media
std::unique_ptr<CdmFactory> TestMojoMediaClient::CreateCdmFactory(
service_manager::mojom::InterfaceProvider* /* host_interfaces */) {
@@ -74,4 +97,15 @@ std::unique_ptr<CdmFactory> TestMojoMediaClient::CreateCdmFactory(
return std::make_unique<DefaultCdmFactory>();
}
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+std::unique_ptr<CdmProxy> TestMojoMediaClient::CreateCdmProxy(
+ const std::string& cdm_guid) {
+ DVLOG(1) << __func__ << ": cdm_guid = " << cdm_guid;
+ if (cdm_guid == kClearKeyCdmGuid)
+ return std::make_unique<ClearKeyCdmProxy>();
+
+ return nullptr;
+}
+#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
+
} // namespace media
diff --git a/chromium/media/mojo/services/test_mojo_media_client.h b/chromium/media/mojo/services/test_mojo_media_client.h
index f593ed8ded2..d5adbeb790e 100644
--- a/chromium/media/mojo/services/test_mojo_media_client.h
+++ b/chromium/media/mojo/services/test_mojo_media_client.h
@@ -6,24 +6,22 @@
#define MEDIA_MOJO_SERVICES_TEST_MOJO_MEDIA_CLIENT_H_
#include <memory>
+#include <vector>
#include "base/macros.h"
#include "base/memory/ref_counted.h"
+#include "media/media_buildflags.h"
#include "media/mojo/services/mojo_media_client.h"
-namespace base {
-class SingleThreadTaskRunner;
-}
-
namespace media {
class AudioManager;
class AudioRendererSink;
-class MediaLog;
+class DecoderFactory;
class RendererFactory;
class VideoRendererSink;
-// Default MojoMediaClient for MediaService.
+// Test MojoMediaClient for MediaService.
class TestMojoMediaClient : public MojoMediaClient {
public:
TestMojoMediaClient();
@@ -31,17 +29,22 @@ class TestMojoMediaClient : public MojoMediaClient {
// MojoMediaClient implementation.
void Initialize(service_manager::Connector* connector) final;
- scoped_refptr<AudioRendererSink> CreateAudioRendererSink(
+ std::unique_ptr<Renderer> CreateRenderer(
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner,
+ MediaLog* media_log,
const std::string& audio_device_id) final;
- std::unique_ptr<VideoRendererSink> CreateVideoRendererSink(
- const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) final;
- std::unique_ptr<RendererFactory> CreateRendererFactory(
- MediaLog* media_log) final;
std::unique_ptr<CdmFactory> CreateCdmFactory(
service_manager::mojom::InterfaceProvider* /* host_interfaces */) final;
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+ std::unique_ptr<CdmProxy> CreateCdmProxy(const std::string& cdm_guid) final;
+#endif // BUILDFLAG(ENABLE_LIBRARY_CDMS)
private:
std::unique_ptr<AudioManager> audio_manager_;
+ std::unique_ptr<DecoderFactory> decoder_factory_;
+ std::unique_ptr<RendererFactory> renderer_factory_;
+ std::vector<scoped_refptr<AudioRendererSink>> audio_sinks_;
+ std::vector<std::unique_ptr<VideoRendererSink>> video_sinks_;
DISALLOW_COPY_AND_ASSIGN(TestMojoMediaClient);
};
diff --git a/chromium/media/mojo/services/watch_time_recorder.cc b/chromium/media/mojo/services/watch_time_recorder.cc
index 80816bd8c15..e34b0e3aeb9 100644
--- a/chromium/media/mojo/services/watch_time_recorder.cc
+++ b/chromium/media/mojo/services/watch_time_recorder.cc
@@ -85,74 +85,6 @@ static VideoDecoderName ConvertVideoDecoderNameToEnum(const std::string& name) {
return VideoDecoderName::kUnknown;
}
-static bool ShouldReportToUma(WatchTimeKey key) {
- switch (key) {
- // These keys are not currently reported to UMA, but are used for UKM metric
- // calculations. To report them in the future just add the keys to report to
- // the lower list and add histograms.xml entries for them.
- case WatchTimeKey::kVideoAll:
- case WatchTimeKey::kVideoMse:
- case WatchTimeKey::kVideoEme:
- case WatchTimeKey::kVideoSrc:
- case WatchTimeKey::kVideoBattery:
- case WatchTimeKey::kVideoAc:
- case WatchTimeKey::kVideoDisplayFullscreen:
- case WatchTimeKey::kVideoDisplayInline:
- case WatchTimeKey::kVideoDisplayPictureInPicture:
- case WatchTimeKey::kVideoEmbeddedExperience:
- case WatchTimeKey::kVideoNativeControlsOn:
- case WatchTimeKey::kVideoNativeControlsOff:
- case WatchTimeKey::kVideoBackgroundAll:
- case WatchTimeKey::kVideoBackgroundMse:
- case WatchTimeKey::kVideoBackgroundEme:
- case WatchTimeKey::kVideoBackgroundSrc:
- case WatchTimeKey::kVideoBackgroundBattery:
- case WatchTimeKey::kVideoBackgroundAc:
- case WatchTimeKey::kVideoBackgroundEmbeddedExperience:
- return false;
-
- case WatchTimeKey::kAudioAll:
- case WatchTimeKey::kAudioMse:
- case WatchTimeKey::kAudioEme:
- case WatchTimeKey::kAudioSrc:
- case WatchTimeKey::kAudioBattery:
- case WatchTimeKey::kAudioAc:
- case WatchTimeKey::kAudioEmbeddedExperience:
- case WatchTimeKey::kAudioNativeControlsOn:
- case WatchTimeKey::kAudioNativeControlsOff:
- case WatchTimeKey::kAudioBackgroundAll:
- case WatchTimeKey::kAudioBackgroundMse:
- case WatchTimeKey::kAudioBackgroundEme:
- case WatchTimeKey::kAudioBackgroundSrc:
- case WatchTimeKey::kAudioBackgroundBattery:
- case WatchTimeKey::kAudioBackgroundAc:
- case WatchTimeKey::kAudioBackgroundEmbeddedExperience:
- case WatchTimeKey::kAudioVideoAll:
- case WatchTimeKey::kAudioVideoMse:
- case WatchTimeKey::kAudioVideoEme:
- case WatchTimeKey::kAudioVideoSrc:
- case WatchTimeKey::kAudioVideoBattery:
- case WatchTimeKey::kAudioVideoAc:
- case WatchTimeKey::kAudioVideoDisplayFullscreen:
- case WatchTimeKey::kAudioVideoDisplayInline:
- case WatchTimeKey::kAudioVideoDisplayPictureInPicture:
- case WatchTimeKey::kAudioVideoEmbeddedExperience:
- case WatchTimeKey::kAudioVideoNativeControlsOn:
- case WatchTimeKey::kAudioVideoNativeControlsOff:
- case WatchTimeKey::kAudioVideoBackgroundAll:
- case WatchTimeKey::kAudioVideoBackgroundMse:
- case WatchTimeKey::kAudioVideoBackgroundEme:
- case WatchTimeKey::kAudioVideoBackgroundSrc:
- case WatchTimeKey::kAudioVideoBackgroundBattery:
- case WatchTimeKey::kAudioVideoBackgroundAc:
- case WatchTimeKey::kAudioVideoBackgroundEmbeddedExperience:
- return true;
- }
-
- NOTREACHED();
- return false;
-}
-
static void RecordWatchTimeInternal(
base::StringPiece key,
base::TimeDelta value,
@@ -236,9 +168,10 @@ void WatchTimeRecorder::FinalizeWatchTime(
// Report only certain keys to UMA and only if they have at met the minimum
// watch time requirement. Otherwise, for SRC/MSE/EME keys, log them to the
// discard metric.
- if (ShouldReportToUma(kv.first)) {
+ base::StringPiece key_str = ConvertWatchTimeKeyToStringForUma(kv.first);
+ if (!key_str.empty()) {
if (kv.second >= kMinimumElapsedWatchTime) {
- RecordWatchTimeInternal(WatchTimeKeyToString(kv.first), kv.second);
+ RecordWatchTimeInternal(key_str, kv.second);
} else if (kv.second > base::TimeDelta()) {
auto it = std::find_if(extended_metrics_keys_.begin(),
extended_metrics_keys_.end(),
@@ -264,7 +197,7 @@ void WatchTimeRecorder::FinalizeWatchTime(
// Check for watch times entries that have corresponding MTBR entries and
// report the MTBR value using watch_time / |underflow_count|. Do this only
// for foreground reporters since we only have UMA keys for foreground.
- if (!properties_->is_background) {
+ if (!properties_->is_background && !properties_->is_muted) {
for (auto& mapping : extended_metrics_keys_) {
auto it = watch_time_info_.find(mapping.watch_time_key);
if (it == watch_time_info_.end() || it->second < kMinimumElapsedWatchTime)
@@ -308,11 +241,6 @@ void WatchTimeRecorder::UpdateUnderflowCount(int32_t count) {
underflow_count_ = count;
}
-// static
-bool WatchTimeRecorder::ShouldReportUmaForTesting(WatchTimeKey key) {
- return ShouldReportToUma(key);
-}
-
void WatchTimeRecorder::RecordUkmPlaybackData() {
// UKM may be unavailable in content_shell or other non-chrome/ builds; it
// may also be unavailable if browser shutdown has started; so this may be a
@@ -329,6 +257,7 @@ void WatchTimeRecorder::RecordUkmPlaybackData() {
builder.SetIsTopFrame(is_top_frame_);
builder.SetIsBackground(properties_->is_background);
+ builder.SetIsMuted(properties_->is_muted);
builder.SetPlayerID(player_id_);
bool recorded_all_metric = false;
@@ -336,6 +265,7 @@ void WatchTimeRecorder::RecordUkmPlaybackData() {
if (kv.first == WatchTimeKey::kAudioAll ||
kv.first == WatchTimeKey::kAudioBackgroundAll ||
kv.first == WatchTimeKey::kAudioVideoAll ||
+ kv.first == WatchTimeKey::kAudioVideoMutedAll ||
kv.first == WatchTimeKey::kAudioVideoBackgroundAll ||
kv.first == WatchTimeKey::kVideoAll ||
kv.first == WatchTimeKey::kVideoBackgroundAll) {
@@ -351,6 +281,7 @@ void WatchTimeRecorder::RecordUkmPlaybackData() {
} else if (kv.first == WatchTimeKey::kAudioAc ||
kv.first == WatchTimeKey::kAudioBackgroundAc ||
kv.first == WatchTimeKey::kAudioVideoAc ||
+ kv.first == WatchTimeKey::kAudioVideoMutedAc ||
kv.first == WatchTimeKey::kAudioVideoBackgroundAc ||
kv.first == WatchTimeKey::kVideoAc ||
kv.first == WatchTimeKey::kVideoBackgroundAc) {
@@ -358,25 +289,32 @@ void WatchTimeRecorder::RecordUkmPlaybackData() {
} else if (kv.first == WatchTimeKey::kAudioBattery ||
kv.first == WatchTimeKey::kAudioBackgroundBattery ||
kv.first == WatchTimeKey::kAudioVideoBattery ||
+ kv.first == WatchTimeKey::kAudioVideoMutedBattery ||
kv.first == WatchTimeKey::kAudioVideoBackgroundBattery ||
kv.first == WatchTimeKey::kVideoBattery ||
kv.first == WatchTimeKey::kVideoBackgroundBattery) {
builder.SetWatchTime_Battery(kv.second.InMilliseconds());
} else if (kv.first == WatchTimeKey::kAudioNativeControlsOn ||
kv.first == WatchTimeKey::kAudioVideoNativeControlsOn ||
+ kv.first == WatchTimeKey::kAudioVideoMutedNativeControlsOn ||
kv.first == WatchTimeKey::kVideoNativeControlsOn) {
builder.SetWatchTime_NativeControlsOn(kv.second.InMilliseconds());
} else if (kv.first == WatchTimeKey::kAudioNativeControlsOff ||
kv.first == WatchTimeKey::kAudioVideoNativeControlsOff ||
+ kv.first == WatchTimeKey::kAudioVideoMutedNativeControlsOff ||
kv.first == WatchTimeKey::kVideoNativeControlsOff) {
builder.SetWatchTime_NativeControlsOff(kv.second.InMilliseconds());
} else if (kv.first == WatchTimeKey::kAudioVideoDisplayFullscreen ||
+ kv.first == WatchTimeKey::kAudioVideoMutedDisplayFullscreen ||
kv.first == WatchTimeKey::kVideoDisplayFullscreen) {
builder.SetWatchTime_DisplayFullscreen(kv.second.InMilliseconds());
} else if (kv.first == WatchTimeKey::kAudioVideoDisplayInline ||
+ kv.first == WatchTimeKey::kAudioVideoMutedDisplayInline ||
kv.first == WatchTimeKey::kVideoDisplayInline) {
builder.SetWatchTime_DisplayInline(kv.second.InMilliseconds());
} else if (kv.first == WatchTimeKey::kAudioVideoDisplayPictureInPicture ||
+ kv.first ==
+ WatchTimeKey::kAudioVideoMutedDisplayPictureInPicture ||
kv.first == WatchTimeKey::kVideoDisplayPictureInPicture) {
builder.SetWatchTime_DisplayPictureInPicture(kv.second.InMilliseconds());
}
diff --git a/chromium/media/mojo/services/watch_time_recorder.h b/chromium/media/mojo/services/watch_time_recorder.h
index ccc4330299e..82a7b670594 100644
--- a/chromium/media/mojo/services/watch_time_recorder.h
+++ b/chromium/media/mojo/services/watch_time_recorder.h
@@ -40,9 +40,6 @@ class MEDIA_MOJO_EXPORT WatchTimeRecorder : public mojom::WatchTimeRecorder {
void UpdateUnderflowCount(int32_t count) override;
- // Test helper method for determining if keys are not reported to UMA.
- static bool ShouldReportUmaForTesting(WatchTimeKey key);
-
private:
// Records a UKM event based on |aggregate_watch_time_info_|; only recorded
// with a complete finalize (destruction or empty FinalizeWatchTime call).
diff --git a/chromium/media/mojo/services/watch_time_recorder_unittest.cc b/chromium/media/mojo/services/watch_time_recorder_unittest.cc
index def3bacb95e..a9e2e0a428f 100644
--- a/chromium/media/mojo/services/watch_time_recorder_unittest.cc
+++ b/chromium/media/mojo/services/watch_time_recorder_unittest.cc
@@ -11,6 +11,7 @@
#include "base/hash.h"
#include "base/message_loop/message_loop.h"
#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/test/histogram_tester.h"
#include "base/test/test_message_loop.h"
#include "base/threading/thread_task_runner_handle.h"
@@ -69,7 +70,7 @@ class WatchTimeRecorderTest : public testing::Test {
bool is_encrypted) {
Initialize(mojom::PlaybackProperties::New(
kUnknownAudioCodec, kUnknownVideoCodec, has_audio, has_video, false,
- is_mse, is_encrypted, false, gfx::Size(800, 600)));
+ false, is_mse, is_encrypted, false, gfx::Size(800, 600)));
}
void ExpectWatchTime(const std::vector<base::StringPiece>& keys,
@@ -77,7 +78,9 @@ class WatchTimeRecorderTest : public testing::Test {
for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax);
++i) {
const base::StringPiece test_key =
- WatchTimeKeyToString(static_cast<WatchTimeKey>(i));
+ ConvertWatchTimeKeyToStringForUma(static_cast<WatchTimeKey>(i));
+ if (test_key.empty())
+ continue;
auto it = std::find(keys.begin(), keys.end(), test_key);
if (it == keys.end()) {
histogram_tester_->ExpectTotalCount(test_key.as_string(), 0);
@@ -161,8 +164,13 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
for (int i = 0; i <= static_cast<int>(WatchTimeKey::kWatchTimeKeyMax); ++i) {
const WatchTimeKey key = static_cast<WatchTimeKey>(i);
- SCOPED_TRACE(WatchTimeKeyToString(key));
+ auto key_str = ConvertWatchTimeKeyToStringForUma(key);
+ SCOPED_TRACE(key_str.empty() ? base::NumberToString(i)
+ : key_str.as_string());
+
+ // Values for |is_background| and |is_muted| don't matter in this test since
+ // they don't prevent the muted or background keys from being recorded.
Initialize(true, false, true, true);
wtr_->RecordWatchTime(WatchTimeKey::kWatchTimeKeyMax, kWatchTime1);
wtr_->RecordWatchTime(key, kWatchTime1);
@@ -176,10 +184,8 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
wtr_->FinalizeWatchTime({key});
base::RunLoop().RunUntilIdle();
- if (WatchTimeRecorder::ShouldReportUmaForTesting(key)) {
- const base::StringPiece key_str = WatchTimeKeyToString(key);
+ if (!key_str.empty())
ExpectWatchTime({key_str}, kWatchTime2);
- }
// These keys are only reported for a full finalize.
ExpectMtbrTime({}, base::TimeDelta());
@@ -199,6 +205,7 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
case WatchTimeKey::kAudioBackgroundAll:
case WatchTimeKey::kAudioVideoAll:
case WatchTimeKey::kAudioVideoBackgroundAll:
+ case WatchTimeKey::kAudioVideoMutedAll:
case WatchTimeKey::kVideoAll:
case WatchTimeKey::kVideoBackgroundAll:
ExpectUkmWatchTime({UkmEntry::kWatchTimeName}, kWatchTime2);
@@ -217,6 +224,10 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
case WatchTimeKey::kAudioVideoEme:
case WatchTimeKey::kAudioVideoSrc:
case WatchTimeKey::kAudioVideoEmbeddedExperience:
+ case WatchTimeKey::kAudioVideoMutedMse:
+ case WatchTimeKey::kAudioVideoMutedEme:
+ case WatchTimeKey::kAudioVideoMutedSrc:
+ case WatchTimeKey::kAudioVideoMutedEmbeddedExperience:
case WatchTimeKey::kAudioVideoBackgroundMse:
case WatchTimeKey::kAudioVideoBackgroundEme:
case WatchTimeKey::kAudioVideoBackgroundSrc:
@@ -236,6 +247,7 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
case WatchTimeKey::kAudioBattery:
case WatchTimeKey::kAudioBackgroundBattery:
case WatchTimeKey::kAudioVideoBattery:
+ case WatchTimeKey::kAudioVideoMutedBattery:
case WatchTimeKey::kAudioVideoBackgroundBattery:
case WatchTimeKey::kVideoBattery:
case WatchTimeKey::kVideoBackgroundBattery:
@@ -247,24 +259,28 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
case WatchTimeKey::kAudioBackgroundAc:
case WatchTimeKey::kAudioVideoAc:
case WatchTimeKey::kAudioVideoBackgroundAc:
+ case WatchTimeKey::kAudioVideoMutedAc:
case WatchTimeKey::kVideoAc:
case WatchTimeKey::kVideoBackgroundAc:
ExpectUkmWatchTime({UkmEntry::kWatchTime_ACName}, kWatchTime2);
break;
case WatchTimeKey::kAudioVideoDisplayFullscreen:
+ case WatchTimeKey::kAudioVideoMutedDisplayFullscreen:
case WatchTimeKey::kVideoDisplayFullscreen:
ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayFullscreenName},
kWatchTime2);
break;
case WatchTimeKey::kAudioVideoDisplayInline:
+ case WatchTimeKey::kAudioVideoMutedDisplayInline:
case WatchTimeKey::kVideoDisplayInline:
ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayInlineName},
kWatchTime2);
break;
case WatchTimeKey::kAudioVideoDisplayPictureInPicture:
+ case WatchTimeKey::kAudioVideoMutedDisplayPictureInPicture:
case WatchTimeKey::kVideoDisplayPictureInPicture:
ExpectUkmWatchTime({UkmEntry::kWatchTime_DisplayPictureInPictureName},
kWatchTime2);
@@ -272,6 +288,7 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
case WatchTimeKey::kAudioNativeControlsOn:
case WatchTimeKey::kAudioVideoNativeControlsOn:
+ case WatchTimeKey::kAudioVideoMutedNativeControlsOn:
case WatchTimeKey::kVideoNativeControlsOn:
ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOnName},
kWatchTime2);
@@ -279,6 +296,7 @@ TEST_F(WatchTimeRecorderTest, TestBasicReporting) {
case WatchTimeKey::kAudioNativeControlsOff:
case WatchTimeKey::kAudioVideoNativeControlsOff:
+ case WatchTimeKey::kAudioVideoMutedNativeControlsOff:
case WatchTimeKey::kVideoNativeControlsOff:
ExpectUkmWatchTime({UkmEntry::kWatchTime_NativeControlsOffName},
kWatchTime2);
@@ -365,9 +383,9 @@ TEST_F(WatchTimeRecorderTest, TestDiscardMetrics) {
EXPECT_TRUE(test_recorder_->EntryHasMetric(entry, name));
TEST_F(WatchTimeRecorderTest, TestFinalizeNoDuplication) {
- mojom::PlaybackPropertiesPtr properties =
- mojom::PlaybackProperties::New(kCodecAAC, kCodecH264, true, true, false,
- false, false, false, gfx::Size(800, 600));
+ mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
+ kCodecAAC, kCodecH264, true, true, false, false, false, false, false,
+ gfx::Size(800, 600));
Initialize(properties.Clone());
// Verify that UKM is reported along with the watch time.
@@ -400,6 +418,7 @@ TEST_F(WatchTimeRecorderTest, TestFinalizeNoDuplication) {
test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
+ EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
@@ -430,9 +449,9 @@ TEST_F(WatchTimeRecorderTest, TestFinalizeNoDuplication) {
}
TEST_F(WatchTimeRecorderTest, FinalizeWithoutWatchTime) {
- mojom::PlaybackPropertiesPtr properties =
- mojom::PlaybackProperties::New(kCodecAAC, kCodecH264, true, true, false,
- false, false, false, gfx::Size(800, 600));
+ mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
+ kCodecAAC, kCodecH264, true, true, false, false, false, false, false,
+ gfx::Size(800, 600));
Initialize(properties.Clone());
// Finalize everything. UKM is only recorded at destruction, so this should do
@@ -462,6 +481,7 @@ TEST_F(WatchTimeRecorderTest, FinalizeWithoutWatchTime) {
test_recorder_->ExpectEntrySourceHasUrl(entry, GURL(kTestOrigin));
EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
+ EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
@@ -492,9 +512,9 @@ TEST_F(WatchTimeRecorderTest, FinalizeWithoutWatchTime) {
}
TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideo) {
- mojom::PlaybackPropertiesPtr properties =
- mojom::PlaybackProperties::New(kCodecAAC, kCodecH264, true, true, false,
- false, false, false, gfx::Size(800, 600));
+ mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
+ kCodecAAC, kCodecH264, true, true, false, false, false, false, false,
+ gfx::Size(800, 600));
Initialize(properties.Clone());
constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(4);
@@ -509,6 +529,7 @@ TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideo) {
EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
+ EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
@@ -538,9 +559,9 @@ TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideo) {
}
TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoWithExtras) {
- mojom::PlaybackPropertiesPtr properties =
- mojom::PlaybackProperties::New(kCodecOpus, kCodecVP9, true, true, false,
- true, true, false, gfx::Size(800, 600));
+ mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
+ kCodecOpus, kCodecVP9, true, true, false, false, true, true, false,
+ gfx::Size(800, 600));
Initialize(properties.Clone());
constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(54);
@@ -601,6 +622,7 @@ TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoWithExtras) {
EXPECT_UKM(UkmEntry::kVideoDecoderNameName, 5);
EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
+ EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);
@@ -617,10 +639,10 @@ TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoWithExtras) {
}
}
-TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoBackground) {
- mojom::PlaybackPropertiesPtr properties =
- mojom::PlaybackProperties::New(kCodecAAC, kCodecH264, true, true, true,
- false, false, false, gfx::Size(800, 600));
+TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoBackgroundMuted) {
+ mojom::PlaybackPropertiesPtr properties = mojom::PlaybackProperties::New(
+ kCodecAAC, kCodecH264, true, true, true, true, false, false, false,
+ gfx::Size(800, 600));
Initialize(properties.Clone());
constexpr base::TimeDelta kWatchTime = base::TimeDelta::FromSeconds(54);
@@ -635,6 +657,7 @@ TEST_F(WatchTimeRecorderTest, BasicUkmAudioVideoBackground) {
EXPECT_UKM(UkmEntry::kWatchTimeName, kWatchTime.InMilliseconds());
EXPECT_UKM(UkmEntry::kIsBackgroundName, properties->is_background);
+ EXPECT_UKM(UkmEntry::kIsMutedName, properties->is_muted);
EXPECT_UKM(UkmEntry::kAudioCodecName, properties->audio_codec);
EXPECT_UKM(UkmEntry::kVideoCodecName, properties->video_codec);
EXPECT_UKM(UkmEntry::kHasAudioName, properties->has_audio);