Commit ad63d65d authored by Yuchen Liu's avatar Yuchen Liu Committed by Commit Bot

[Fuchsia][EME] Support LoadSession and RemoveSession

Implement LoadSession and RemoveSession for FuchsiaCdm:

LoadSession -> fuchsia CDM::LoadLicenseSession
RemoveSession -> fuchsia LicenseSession::GenerateLicenseRelease

Bug: internal b/162078899
Test: https://storage.googleapis.com/m3u8_lag/persistent_license/index.html
Change-Id: I151645ecaee800979690bd47936cc27584322acb
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2373403
Commit-Queue: Yuchen Liu <yucliu@chromium.org>
Reviewed-by: default avatarXiaohan Wang <xhwang@chromium.org>
Reviewed-by: default avatarSergey Ulanov <sergeyu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#828039}
parent 9394364f
...@@ -41,10 +41,10 @@ class PlayreadyKeySystemProperties : public ::media::KeySystemProperties { ...@@ -41,10 +41,10 @@ class PlayreadyKeySystemProperties : public ::media::KeySystemProperties {
public: public:
PlayreadyKeySystemProperties(const std::string& key_system_name, PlayreadyKeySystemProperties(const std::string& key_system_name,
media::SupportedCodecs supported_codecs, media::SupportedCodecs supported_codecs,
bool persistent_license_support) bool persistent_usage_record_support)
: key_system_name_(key_system_name), : key_system_name_(key_system_name),
supported_codecs_(supported_codecs), supported_codecs_(supported_codecs),
persistent_license_support_(persistent_license_support) {} persistent_usage_record_support_(persistent_usage_record_support) {}
std::string GetKeySystemName() const override { return key_system_name_; } std::string GetKeySystemName() const override { return key_system_name_; }
...@@ -72,16 +72,24 @@ class PlayreadyKeySystemProperties : public ::media::KeySystemProperties { ...@@ -72,16 +72,24 @@ class PlayreadyKeySystemProperties : public ::media::KeySystemProperties {
return media::EmeConfigRule::NOT_SUPPORTED; return media::EmeConfigRule::NOT_SUPPORTED;
} }
// For backward compatible, currently JS will create a persistent license
// session and inject a special init data as the persistent usage record
// session signal. In other words, the platform has to announce the support of
// persistent license session to allow JS use the persistent usage record
// session functions.
// TODO(internal b/142749428): Remove once the temporary solution is removed.
media::EmeSessionTypeSupport GetPersistentLicenseSessionSupport() media::EmeSessionTypeSupport GetPersistentLicenseSessionSupport()
const override { const override {
return persistent_license_support_ return persistent_usage_record_support_
? media::EmeSessionTypeSupport::SUPPORTED ? media::EmeSessionTypeSupport::SUPPORTED
: media::EmeSessionTypeSupport::NOT_SUPPORTED; : media::EmeSessionTypeSupport::NOT_SUPPORTED;
} }
media::EmeSessionTypeSupport GetPersistentUsageRecordSessionSupport() media::EmeSessionTypeSupport GetPersistentUsageRecordSessionSupport()
const override { const override {
return media::EmeSessionTypeSupport::NOT_SUPPORTED; return persistent_usage_record_support_
? media::EmeSessionTypeSupport::SUPPORTED
: media::EmeSessionTypeSupport::NOT_SUPPORTED;
} }
media::EmeFeatureSupport GetPersistentStateSupport() const override { media::EmeFeatureSupport GetPersistentStateSupport() const override {
...@@ -104,7 +112,7 @@ class PlayreadyKeySystemProperties : public ::media::KeySystemProperties { ...@@ -104,7 +112,7 @@ class PlayreadyKeySystemProperties : public ::media::KeySystemProperties {
private: private:
const std::string key_system_name_; const std::string key_system_name_;
const media::SupportedCodecs supported_codecs_; const media::SupportedCodecs supported_codecs_;
const bool persistent_license_support_; const bool persistent_usage_record_support_;
}; };
} // namespace } // namespace
...@@ -201,20 +209,20 @@ void WebEngineContentRendererClient::AddSupportedKeySystems( ...@@ -201,20 +209,20 @@ void WebEngineContentRendererClient::AddSupportedKeySystems(
cdm::WidevineKeySystemProperties::Robustness:: cdm::WidevineKeySystemProperties::Robustness::
HW_SECURE_CRYPTO, // max audio robustness HW_SECURE_CRYPTO, // max audio robustness
cdm::WidevineKeySystemProperties::Robustness:: cdm::WidevineKeySystemProperties::Robustness::
HW_SECURE_ALL, // max video robustness HW_SECURE_ALL, // max video robustness
media::EmeSessionTypeSupport::NOT_SUPPORTED, // persistent license media::EmeSessionTypeSupport::SUPPORTED, // persistent license
media::EmeSessionTypeSupport::NOT_SUPPORTED, // persistent usage record media::EmeSessionTypeSupport::SUPPORTED, // persistent usage record
media::EmeFeatureSupport::ALWAYS_ENABLED, // persistent state media::EmeFeatureSupport::ALWAYS_ENABLED, // persistent state
media::EmeFeatureSupport::ALWAYS_ENABLED)); // distinctive identifier media::EmeFeatureSupport::ALWAYS_ENABLED)); // distinctive identifier
} }
std::string playready_key_system = std::string playready_key_system =
base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII( base::CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kPlayreadyKeySystem); switches::kPlayreadyKeySystem);
if (!playready_key_system.empty()) { if (!playready_key_system.empty()) {
key_systems->emplace_back( key_systems->emplace_back(new PlayreadyKeySystemProperties(
new PlayreadyKeySystemProperties(playready_key_system, supported_codecs, playready_key_system, supported_codecs,
/*persistent_license_support=*/false)); /*persistent_usage_record_support=*/true));
} }
} }
......
...@@ -60,6 +60,18 @@ fuchsia::media::drm::LicenseServerMessage CreateLicenseServerMessage( ...@@ -60,6 +60,18 @@ fuchsia::media::drm::LicenseServerMessage CreateLicenseServerMessage(
return message; return message;
} }
fuchsia::media::drm::LicenseSessionType ToFuchsiaLicenseSessionType(
CdmSessionType session_type) {
switch (session_type) {
case CdmSessionType::kTemporary:
return fuchsia::media::drm::LicenseSessionType::TEMPORARY;
case CdmSessionType::kPersistentLicense:
return fuchsia::media::drm::LicenseSessionType::PERSISTENT_LICENSE;
case CdmSessionType::kPersistentUsageRecord:
return fuchsia::media::drm::LicenseSessionType::PERSISTENT_USAGE_RECORD;
}
}
CdmMessageType ToCdmMessageType(fuchsia::media::drm::LicenseMessageType type) { CdmMessageType ToCdmMessageType(fuchsia::media::drm::LicenseMessageType type) {
switch (type) { switch (type) {
case fuchsia::media::drm::LicenseMessageType::REQUEST: case fuchsia::media::drm::LicenseMessageType::REQUEST:
...@@ -119,6 +131,7 @@ class FuchsiaCdm::CdmSession { ...@@ -119,6 +131,7 @@ class FuchsiaCdm::CdmSession {
public: public:
using ResultCB = using ResultCB =
base::OnceCallback<void(base::Optional<CdmPromise::Exception>)>; base::OnceCallback<void(base::Optional<CdmPromise::Exception>)>;
using SessionReadyCB = base::OnceCallback<void(bool success)>;
CdmSession(const FuchsiaCdm::SessionCallbacks* callbacks, CdmSession(const FuchsiaCdm::SessionCallbacks* callbacks,
base::RepeatingClosure on_new_key) base::RepeatingClosure on_new_key)
...@@ -157,6 +170,15 @@ class FuchsiaCdm::CdmSession { ...@@ -157,6 +170,15 @@ class FuchsiaCdm::CdmSession {
result) { ProcessResult(result); }); result) { ProcessResult(result); });
} }
void GenerateLicenseRelease(ResultCB generate_license_release_cb) {
DCHECK(!result_cb_);
result_cb_ = std::move(generate_license_release_cb);
pending_release_ = true;
session_->GenerateLicenseRelease(
[this](fuchsia::media::drm::LicenseSession_GenerateLicenseRelease_Result
result) { ProcessResult(result); });
}
void ProcessLicenseResponse(const std::vector<uint8_t>& response, void ProcessLicenseResponse(const std::vector<uint8_t>& response,
ResultCB process_license_response_cb) { ResultCB process_license_response_cb) {
DCHECK(!result_cb_); DCHECK(!result_cb_);
...@@ -172,7 +194,20 @@ class FuchsiaCdm::CdmSession { ...@@ -172,7 +194,20 @@ class FuchsiaCdm::CdmSession {
} }
const std::string& session_id() const { return session_id_; } const std::string& session_id() const { return session_id_; }
void set_session_ready_cb(SessionReadyCB session_ready_cb) {
session_ready_cb_ = std::move(session_ready_cb);
session_.events().OnReady =
fit::bind_member(this, &CdmSession::OnSessionReady);
}
bool pending_release() const { return pending_release_; }
private: private:
void OnSessionReady() {
DCHECK(session_ready_cb_);
std::move(session_ready_cb_).Run(true);
}
void OnLicenseMessageGenerated(fuchsia::media::drm::LicenseMessage message) { void OnLicenseMessageGenerated(fuchsia::media::drm::LicenseMessage message) {
DCHECK(!session_id_.empty()); DCHECK(!session_id_.empty());
std::string session_msg; std::string session_msg;
...@@ -212,6 +247,10 @@ class FuchsiaCdm::CdmSession { ...@@ -212,6 +247,10 @@ class FuchsiaCdm::CdmSession {
void OnSessionError(zx_status_t status) { void OnSessionError(zx_status_t status) {
ZX_LOG(ERROR, status) << "Session error."; ZX_LOG(ERROR, status) << "Session error.";
if (session_ready_cb_)
std::move(session_ready_cb_).Run(false);
if (result_cb_) if (result_cb_)
std::move(result_cb_).Run(CdmPromise::Exception::TYPE_ERROR); std::move(result_cb_).Run(CdmPromise::Exception::TYPE_ERROR);
} }
...@@ -231,9 +270,16 @@ class FuchsiaCdm::CdmSession { ...@@ -231,9 +270,16 @@ class FuchsiaCdm::CdmSession {
fuchsia::media::drm::LicenseSessionPtr session_; fuchsia::media::drm::LicenseSessionPtr session_;
std::string session_id_; std::string session_id_;
// Callback for OnReady.
SessionReadyCB session_ready_cb_;
// Callback for license operation. // Callback for license operation.
ResultCB result_cb_; ResultCB result_cb_;
// `GenerateLicenseRelease` has been called and the session is waiting for
// license release response from server.
bool pending_release_ = false;
DISALLOW_COPY_AND_ASSIGN(CdmSession); DISALLOW_COPY_AND_ASSIGN(CdmSession);
}; };
...@@ -335,13 +381,6 @@ void FuchsiaCdm::CreateSessionAndGenerateRequest( ...@@ -335,13 +381,6 @@ void FuchsiaCdm::CreateSessionAndGenerateRequest(
EmeInitDataType init_data_type, EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data, const std::vector<uint8_t>& init_data,
std::unique_ptr<NewSessionCdmPromise> promise) { std::unique_ptr<NewSessionCdmPromise> promise) {
// TODO(crbug.com/1131114): Support persistent license.
if (session_type != CdmSessionType::kTemporary) {
promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
"session type is not supported.");
return;
}
if (init_data_type == EmeInitDataType::UNKNOWN) { if (init_data_type == EmeInitDataType::UNKNOWN) {
promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0, promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0,
"init data type is not supported."); "init data type is not supported.");
...@@ -358,8 +397,7 @@ void FuchsiaCdm::CreateSessionAndGenerateRequest( ...@@ -358,8 +397,7 @@ void FuchsiaCdm::CreateSessionAndGenerateRequest(
CdmSession* session_ptr = session.get(); CdmSession* session_ptr = session.get();
cdm_->CreateLicenseSession( cdm_->CreateLicenseSession(
fuchsia::media::drm::LicenseSessionType::TEMPORARY, ToFuchsiaLicenseSessionType(session_type), session_ptr->NewRequest(),
session_ptr->NewRequest(),
[this, promise_id, [this, promise_id,
session = std::move(session)](std::string session_id) mutable { session = std::move(session)](std::string session_id) mutable {
OnCreateSession(std::move(session), promise_id, session_id); OnCreateSession(std::move(session), promise_id, session_id);
...@@ -416,7 +454,46 @@ void FuchsiaCdm::OnGenerateLicenseRequestStatus( ...@@ -416,7 +454,46 @@ void FuchsiaCdm::OnGenerateLicenseRequestStatus(
void FuchsiaCdm::LoadSession(CdmSessionType session_type, void FuchsiaCdm::LoadSession(CdmSessionType session_type,
const std::string& session_id, const std::string& session_id,
std::unique_ptr<NewSessionCdmPromise> promise) { std::unique_ptr<NewSessionCdmPromise> promise) {
NOTIMPLEMENTED(); DCHECK_NE(session_type, CdmSessionType::kTemporary);
DCHECK(!session_id.empty());
REJECT_PROMISE_AND_RETURN_IF_BAD_CDM(promise, cdm_);
if (session_map_.contains(session_id)) {
promise->reject(CdmPromise::Exception::QUOTA_EXCEEDED_ERROR, 0,
"session already exists.");
return;
}
uint32_t promise_id = promises_.SavePromise(std::move(promise));
auto session = std::make_unique<CdmSession>(
&session_callbacks_,
base::BindRepeating(&FuchsiaCdm::OnNewKey, base::Unretained(this)));
CdmSession* session_ptr = session.get();
session_ptr->set_session_id(session_id);
session_ptr->set_session_ready_cb(
base::BindOnce(&FuchsiaCdm::OnSessionLoaded, base::Unretained(this),
std::move(session), promise_id));
cdm_->LoadLicenseSession(session_id, session_ptr->NewRequest());
}
void FuchsiaCdm::OnSessionLoaded(std::unique_ptr<CdmSession> session,
uint32_t promise_id,
bool loaded) {
if (!loaded) {
promises_.ResolvePromise(promise_id, std::string());
return;
}
std::string session_id = session->session_id();
DCHECK(session_map_.find(session_id) == session_map_.end())
<< "Duplicated session id " << session_id;
session_map_.emplace(session_id, std::move(session));
promises_.ResolvePromise(promise_id, session_id);
} }
void FuchsiaCdm::UpdateSession(const std::string& session_id, void FuchsiaCdm::UpdateSession(const std::string& session_id,
...@@ -441,10 +518,11 @@ void FuchsiaCdm::UpdateSession(const std::string& session_id, ...@@ -441,10 +518,11 @@ void FuchsiaCdm::UpdateSession(const std::string& session_id,
session->ProcessLicenseResponse( session->ProcessLicenseResponse(
response, base::BindOnce(&FuchsiaCdm::OnProcessLicenseServerMessageStatus, response, base::BindOnce(&FuchsiaCdm::OnProcessLicenseServerMessageStatus,
base::Unretained(this), promise_id)); base::Unretained(this), session_id, promise_id));
} }
void FuchsiaCdm::OnProcessLicenseServerMessageStatus( void FuchsiaCdm::OnProcessLicenseServerMessageStatus(
const std::string& session_id,
uint32_t promise_id, uint32_t promise_id,
base::Optional<CdmPromise::Exception> exception) { base::Optional<CdmPromise::Exception> exception) {
if (exception.has_value()) { if (exception.has_value()) {
...@@ -454,6 +532,19 @@ void FuchsiaCdm::OnProcessLicenseServerMessageStatus( ...@@ -454,6 +532,19 @@ void FuchsiaCdm::OnProcessLicenseServerMessageStatus(
} }
promises_.ResolvePromise(promise_id); promises_.ResolvePromise(promise_id);
auto it = session_map_.find(session_id);
if (it == session_map_.end())
return;
// Close the session if the session is waiting for license release ack.
CdmSession* session = it->second.get();
DCHECK(session);
if (!session->pending_release())
return;
session_map_.erase(it);
} }
void FuchsiaCdm::CloseSession(const std::string& session_id, void FuchsiaCdm::CloseSession(const std::string& session_id,
...@@ -470,9 +561,41 @@ void FuchsiaCdm::CloseSession(const std::string& session_id, ...@@ -470,9 +561,41 @@ void FuchsiaCdm::CloseSession(const std::string& session_id,
void FuchsiaCdm::RemoveSession(const std::string& session_id, void FuchsiaCdm::RemoveSession(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise> promise) { std::unique_ptr<SimpleCdmPromise> promise) {
NOTIMPLEMENTED(); auto it = session_map_.find(session_id);
promise->reject(CdmPromise::Exception::NOT_SUPPORTED_ERROR, 0, if (it == session_map_.end()) {
"not implemented"); promise->reject(CdmPromise::Exception::INVALID_STATE_ERROR, 0,
"session doesn't exist.");
return;
}
REJECT_PROMISE_AND_RETURN_IF_BAD_CDM(promise, cdm_);
uint32_t promise_id = promises_.SavePromise(std::move(promise));
CdmSession* session = it->second.get();
DCHECK(session);
// For temporary session, the API will remove the keys and close the session.
// For persistent license and persistent usage record, the API will invalidate
// the keys and generates a license release message.
session->GenerateLicenseRelease(
base::BindOnce(&FuchsiaCdm::OnGenerateLicenseReleaseStatus,
base::Unretained(this), session_id, promise_id));
}
void FuchsiaCdm::OnGenerateLicenseReleaseStatus(
const std::string& session_id,
uint32_t promise_id,
base::Optional<CdmPromise::Exception> exception) {
if (exception.has_value()) {
promises_.RejectPromise(promise_id, exception.value(), 0,
"Failed to release license.");
session_map_.erase(session_id);
return;
}
DCHECK(!session_id.empty());
promises_.ResolvePromise(promise_id);
} }
CdmContext* FuchsiaCdm::GetCdmContext() { CdmContext* FuchsiaCdm::GetCdmContext() {
......
...@@ -89,6 +89,15 @@ class FuchsiaCdm : public ContentDecryptionModule, ...@@ -89,6 +89,15 @@ class FuchsiaCdm : public ContentDecryptionModule,
uint32_t promise_id, uint32_t promise_id,
base::Optional<CdmPromise::Exception> exception); base::Optional<CdmPromise::Exception> exception);
void OnProcessLicenseServerMessageStatus( void OnProcessLicenseServerMessageStatus(
const std::string& session_id,
uint32_t promise_id,
base::Optional<CdmPromise::Exception> exception);
void OnSessionLoaded(std::unique_ptr<CdmSession> session,
uint32_t promise_id,
bool loaded);
void OnGenerateLicenseReleaseStatus(
const std::string& session_id,
uint32_t promise_id, uint32_t promise_id,
base::Optional<CdmPromise::Exception> exception); base::Optional<CdmPromise::Exception> exception);
......
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