Commit a98a8fa4 authored by Xiaohan Wang's avatar Xiaohan Wang Committed by Commit Bot

media: Trigger Infobar on Mac ARM on EME query failure

CDM on Mac ARM is not ready yet. When requestMediaKeySystemAccess()
fails on Mac ARM, we reject the promise with "Unsupported platform" and
trigger an infobar to notify user. The infobar will be triggered at most
once per render process.

Since the infobar can only be triggered in the browser process, a new
mojo service CdmInfobarService is added. Note that even though there
already exists KeySystemSupport service, which is also implemented in
the browser process, we cannot trigger the infobar there, because the
infobar requires a WebContents context, while the KeySystemSupport
service is bound to a render process instead of a render frame.

Change-Id: Ia85a1f2b097b0c2d26d12cc3e9363c34a25691a3
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2404716Reviewed-by: default avatarDaniel Cheng <dcheng@chromium.org>
Reviewed-by: default avatarElly Fong-Jones <ellyjones@chromium.org>
Reviewed-by: default avatarJohn Rummell <jrummell@chromium.org>
Commit-Queue: Xiaohan Wang <xhwang@chromium.org>
Cr-Commit-Position: refs/heads/master@{#807631}
parent 8c2b401e
......@@ -208,6 +208,14 @@
#include "extensions/common/api/mime_handler.mojom.h" // nogncheck
#endif
#if defined(OS_MAC) && defined(ARCH_CPU_ARM_FAMILY)
#include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/ui/startup/mac_system_infobar_delegate.h"
#include "content/public/browser/frame_service_base.h"
#include "media/mojo/mojom/cdm_infobar_service.mojom.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#endif
namespace chrome {
namespace internal {
......@@ -418,6 +426,39 @@ void BindCaptionContextHandler(
}
#endif
#if defined(OS_MAC) && defined(ARCH_CPU_ARM_FAMILY)
class CdmInfobarServiceImpl final
: public content::FrameServiceBase<media::mojom::CdmInfobarService> {
public:
CdmInfobarServiceImpl(
content::RenderFrameHost* frame_host,
mojo::PendingReceiver<media::mojom::CdmInfobarService> receiver)
: FrameServiceBase(frame_host, std::move(receiver)) {}
CdmInfobarServiceImpl(const CdmInfobarServiceImpl&) = delete;
CdmInfobarServiceImpl& operator=(const CdmInfobarServiceImpl&) = delete;
private:
void NotifyUnsupportedPlatform() final {
auto* web_contents =
content::WebContents::FromRenderFrameHost(render_frame_host());
if (!web_contents)
return;
MacSystemInfoBarDelegate::Create(
InfoBarService::FromWebContents(web_contents));
}
};
void BindCdmInfobarServiceReceiver(
content::RenderFrameHost* frame_host,
mojo::PendingReceiver<media::mojom::CdmInfobarService> receiver) {
// CdmInfobarServiceImpl owns itself. It will self-destruct when a mojo
// interface error occurs, the render frame host is deleted, or the render
// frame host navigates to a new document.
new CdmInfobarServiceImpl(frame_host, std::move(receiver));
}
#endif
void PopulateChromeFrameBinders(
mojo::BinderMapWithContext<content::RenderFrameHost*>* map) {
map->Add<image_annotation::mojom::Annotator>(
......@@ -517,6 +558,11 @@ void PopulateChromeFrameBinders(
map->Add<chrome::mojom::CaptionHost>(
base::BindRepeating(&BindCaptionContextHandler));
#endif
#if defined(OS_MAC) && defined(ARCH_CPU_ARM_FAMILY)
map->Add<media::mojom::CdmInfobarService>(
base::BindRepeating(&BindCdmInfobarServiceReceiver));
#endif
}
void PopulateChromeWebUIFrameBinders(
......
......@@ -56,15 +56,28 @@ const char kVideoMP4MimeType[] = "video/mp4";
// These are the expected titles set by checkKeySystemWithMediaMimeType()
// in test_key_system_instantiation.html. Other titles are possible, but
// they are unexpected and will be logged with the failure. kUnsupportedResult
// is the actual message generated by navigator.requestMediaKeySystemAccess(),
// and will need to be updated if that code is modified.
// and kUnsupportedPlatformResult are the actual messages generated by
// navigator.requestMediaKeySystemAccess(), and will need to be updated if that
// code is modified.
const char kSuccessResult[] = "success";
const char kUnsupportedResult[] =
"Unsupported keySystem or supportedConfigurations.";
const char kUnsupportedPlatformResult[] = "Unsupported platform.";
const char kUnexpectedResult[] = "unexpected result";
#define EXPECT_SUCCESS(test) EXPECT_EQ(kSuccessResult, test)
// TODO(crbug.com/1111381): Remove this when MacOS ARM64 CDM is checked in.
#if defined(OS_MAC) && defined(ARCH_CPU_ARM_FAMILY)
#define EXPECT_UNSUPPORTED(test) \
do { \
auto result = test; \
EXPECT_TRUE(result == kUnsupportedResult || \
result == kUnsupportedPlatformResult); \
} while (0)
#else
#define EXPECT_UNSUPPORTED(test) EXPECT_EQ(kUnsupportedResult, test)
#endif
// Any support is acceptable. This can be used around new CDM check-in time
// where test expectations can change based on the new CDM's capability.
......@@ -274,6 +287,8 @@ class EncryptedMediaSupportedTypesTest : public InProcessBrowserTest {
content::TitleWatcher title_watcher(contents,
base::ASCIIToUTF16(kSuccessResult));
title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16(kUnsupportedResult));
title_watcher.AlsoWaitForTitle(
base::ASCIIToUTF16(kUnsupportedPlatformResult));
title_watcher.AlsoWaitForTitle(base::ASCIIToUTF16(kUnexpectedResult));
EXPECT_TRUE(content::ExecuteScript(contents, command));
base::string16 result = title_watcher.WaitAndGetTitle();
......
......@@ -115,6 +115,10 @@ bool MediaPermissionDispatcher::IsEncryptedMediaEnabled() {
return render_frame_->GetRendererPreferences().enable_encrypted_media;
}
void MediaPermissionDispatcher::NotifyUnsupportedPlatform() {
GetCdmInfobarService()->NotifyUnsupportedPlatform();
}
uint32_t MediaPermissionDispatcher::RegisterCallback(
PermissionStatusCB permission_status_cb) {
DCHECK(task_runner_->RunsTasksInCurrentSequence());
......@@ -138,6 +142,16 @@ MediaPermissionDispatcher::GetPermissionService() {
return permission_service_.get();
}
media::mojom::CdmInfobarService*
MediaPermissionDispatcher::GetCdmInfobarService() {
if (!cdm_infobar_service_) {
render_frame_->GetBrowserInterfaceBroker()->GetInterface(
cdm_infobar_service_.BindNewPipeAndPassReceiver());
}
return cdm_infobar_service_.get();
}
void MediaPermissionDispatcher::OnPermissionStatus(
uint32_t request_id,
blink::mojom::PermissionStatus status) {
......
......@@ -16,6 +16,7 @@
#include "content/common/content_export.h"
#include "content/renderer/render_frame_impl.h"
#include "media/base/media_permission.h"
#include "media/mojo/mojom/cdm_infobar_service.mojom.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/permissions/permission.mojom.h"
......@@ -42,6 +43,7 @@ class CONTENT_EXPORT MediaPermissionDispatcher : public media::MediaPermission {
void RequestPermission(Type type,
PermissionStatusCB permission_status_cb) override;
bool IsEncryptedMediaEnabled() override;
void NotifyUnsupportedPlatform() override;
private:
// Map of request IDs and pending PermissionStatusCBs.
......@@ -54,6 +56,9 @@ class CONTENT_EXPORT MediaPermissionDispatcher : public media::MediaPermission {
// Ensure there is a connection to the permission service and return it.
blink::mojom::PermissionService* GetPermissionService();
// Ensure there is a connection to the CdmInfobarService and return it.
media::mojom::CdmInfobarService* GetCdmInfobarService();
// Callback for |permission_service_| calls.
void OnPermissionStatus(uint32_t request_id,
blink::mojom::PermissionStatus status);
......@@ -66,6 +71,8 @@ class CONTENT_EXPORT MediaPermissionDispatcher : public media::MediaPermission {
RequestMap requests_;
mojo::Remote<blink::mojom::PermissionService> permission_service_;
mojo::Remote<media::mojom::CdmInfobarService> cdm_infobar_service_;
// The |RenderFrameImpl| that owns this MediaPermissionDispatcher. It's okay
// to hold a raw pointer here because the lifetime of this object is bounded
// by the render frame's life (the latter holds a unique pointer to this).
......
......@@ -10,4 +10,6 @@ MediaPermission::MediaPermission() = default;
MediaPermission::~MediaPermission() = default;
void MediaPermission::NotifyUnsupportedPlatform() {}
} // namespace media
......@@ -41,6 +41,8 @@ class MEDIA_EXPORT MediaPermission {
// the spec.
virtual bool IsEncryptedMediaEnabled() = 0;
virtual void NotifyUnsupportedPlatform();
private:
DISALLOW_COPY_AND_ASSIGN(MediaPermission);
};
......
......@@ -12,6 +12,7 @@
#include "base/metrics/histogram_macros.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "build/build_config.h"
#include "media/base/cdm_config.h"
#include "media/base/key_system_names.h"
#include "media/base/key_systems.h"
......@@ -909,7 +910,18 @@ void KeySystemConfigSelector::SelectConfig(
std::string key_system_ascii = key_system.Ascii();
if (!key_systems_->IsSupportedKeySystem(key_system_ascii)) {
#if defined(OS_MAC) && defined(ARCH_CPU_ARM_FAMILY)
// CDM support on Mac ARM is known not ready yet. We only notify once per
// render process.
static bool s_has_notified_unsupported_platform = false;
if (!s_has_notified_unsupported_platform) {
s_has_notified_unsupported_platform = true;
media_permission_->NotifyUnsupportedPlatform();
}
std::move(cb).Run(Status::kUnsupportedPlatform, nullptr, nullptr);
#else
std::move(cb).Run(Status::kUnsupportedKeySystem, nullptr, nullptr);
#endif
return;
}
......
......@@ -17,6 +17,7 @@ mojom("mojom") {
"audio_logging.mojom",
"audio_output_stream.mojom",
"audio_parameters.mojom",
"cdm_infobar_service.mojom",
"cdm_service.mojom",
"cdm_storage.mojom",
"content_decryption_module.mojom",
......
// Copyright 2020 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.
module media.mojom;
// Service to trigger info bar for CDM related events.
interface CdmInfobarService {
// Notifies that the platform is not supported.
NotifyUnsupportedPlatform();
};
\ No newline at end of file
......@@ -5,7 +5,8 @@
// of the result.
function setResultInTitle(title) {
if (title == "" || title == "success" || title == "TypeError" ||
title == "Unsupported keySystem or supportedConfigurations.") {
title == "Unsupported keySystem or supportedConfigurations." ||
title == "Unsupported platform.") {
document.title = title;
} else {
console.log("Unexpected result: " + title);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment