* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef DRM_ADAPTER_IMPL_H
#define DRM_ADAPTER_IMPL_H
#include <mutex>
#include <pthread.h>
#include <securec.h>
#include "drm_adapter.h"
#include "native_drm_common.h"
#include "native_drm_err.h"
#include "nweb_log.h"
namespace OHOS::NWeb {
const std::string SECURITY_LEVEL = "securityLevel";
const std::string SERVER_CERTIFICATE = "serviceCertificate";
const std::string ORIGIN = "origin";
const std::string PRIVACY_MODE = "privacyMode";
const std::string SESSION_SHARING = "sessionSharing";
const std::string ENABLE = "enable";
const std::string WIDEVINE_NAME = "com.widevine.alpha";
const std::string WISEPLAY_NAME = "com.wiseplay.drm";
constexpr int32_t SECURITY_LEVEL_1 = 1;
constexpr int32_t SECURITY_LEVEL_3 = 3;
constexpr int32_t SECURITY_LEVEL_UNKNOWN = 0;
constexpr int32_t INFO_SIZE = 8;
constexpr int32_t MAX_URL_LENGTH = 2048;
constexpr int32_t MAX_REQUEST_LENGTH = 12288;
constexpr int32_t HEX_OFFSET = 4;
constexpr int32_t MAX_KEY_SET_ID_LEN = 128;
constexpr uint64_t MILLISECOND_IN_SECOND = 1000;
constexpr int32_t MILLISECOND_DIGITS = 3;
constexpr int32_t EXPIRATION_INFO_MAX_LEN = 16;
constexpr int32_t EXPIRATION_INFO_BASE = 10;
enum class MediaKeyType : int32_t {
MEDIA_KEY_TYPE_OFFLINE = 0,
MEDIA_KEY_TYPE_ONLINE,
MEDIA_KEY_TYPE_RELEASE,
};
enum class ClearInfoType : int32_t {
KEY_RELEASE = 0,
LOAD_FAIL,
};
enum class KeyStatus : uint32_t {
KEY_STATUS_USABLE = 0,
KEY_STATUS_EXPIRED = 1,
KEY_STATUS_OUTPUT_NOT_ALLOWED = 2,
KEY_STATUS_PENDING = 3,
KEY_STATUS_INTERNAL_ERROR = 4,
KEY_STATUS_USABLE_IN_FUTURE = 5,
};
enum class DrmResult : int32_t {
DRM_RESULT_ERROR = -1,
DRM_RESULT_OK = 0,
};
enum class KeySystemType : int32_t {
NONE = 0,
WIDEVINE,
WISEPLAY
};
class SessionId {
public:
static std::shared_ptr<SessionId> CreateSessionId(const std::string& emeId)
{
return std::make_shared<SessionId>(emeId, nullptr, 0);
}
SessionId(std::string emeId, const uint8_t* keySetId, int32_t keySetIdLen)
: emeId_(emeId), keySetIdLen_(keySetIdLen)
{
(void)memset_s(keySetId_, sizeof(keySetId_), 0, sizeof(keySetId_));
if (keySetId != nullptr && keySetIdLen > 0 && keySetIdLen <= MAX_KEY_SET_ID_LEN) {
if (memcpy_s(keySetId_, sizeof(keySetId_), keySetId, keySetIdLen) != 0) {
WVLOG_E("memcpy_s failed!");
}
}
}
std::string EmeId()
{
return emeId_;
}
uint8_t* KeySetId()
{
return keySetId_;
}
int32_t KeySetIdLen()
{
return keySetIdLen_;
}
void SetKeySetId(uint8_t* keySetId, int32_t keySetIdLen)
{
if (keySetIdLen > MAX_KEY_SET_ID_LEN) {
WVLOG_E("keySetIdLen error!");
return;
}
if (keySetId == nullptr || keySetIdLen <= 0) {
(void)memset_s(keySetId_, sizeof(keySetId_), 0, sizeof(keySetId_));
} else {
if (memcpy_s(keySetId_, sizeof(keySetId_), keySetId, keySetIdLen) != 0) {
WVLOG_E("memcpy_s failed!");
}
}
keySetIdLen_ = keySetIdLen;
}
private:
std::string emeId_;
uint8_t keySetId_[MAX_KEY_SET_ID_LEN];
int32_t keySetIdLen_;
};
class SessionInfo {
public:
SessionInfo(std::shared_ptr<SessionId> sessionId, std::string mimeType, int32_t keyType)
: sessionId_(sessionId), mimeType_(mimeType), keyType_(keyType)
{}
std::string MimeType()
{
return mimeType_;
}
int32_t KeyType()
{
return keyType_;
}
bool IsRelease()
{
return (keyType_ == static_cast<int32_t>(MediaKeyType::MEDIA_KEY_TYPE_RELEASE));
}
void SetKeyType(int32_t keyType)
{
keyType_ = keyType;
}
std::shared_ptr<SessionId> GetSessionId()
{
return sessionId_;
}
private:
std::shared_ptr<SessionId> sessionId_;
std::string mimeType_;
int32_t keyType_;
};
class DrmCallbackImpl {
public:
DrmCallbackImpl(std::shared_ptr<DrmCallbackAdapter> callbackAdapter);
~DrmCallbackImpl() = default;
void OnSessionMessage(const std::string& sessionId, int32_t& type, const std::vector<uint8_t>& message);
void OnProvisionRequest(const std::string& defaultUrl, const std::string& requestData);
void OnProvisioningComplete(bool success);
void OnMediaKeySessionReady(void* session);
void OnPromiseRejected(uint32_t promiseId, const std::string& errorMessage);
void OnPromiseResolved(uint32_t promiseId);
void OnPromiseResolvedWithSession(uint32_t promiseId, const std::string& sessionId);
void OnSessionClosed(const std::string& sessionId);
void OnSessionKeysChange(const std::string& sessionId, const std::vector<std::string>& keyIdArray,
const std::vector<uint32_t>& statusArray, bool hasAdditionalUsableKey, bool isKeyRelease);
void OnSessionExpirationUpdate(const std::string& sessionId, uint64_t expirationTime);
void OnStorageProvisioned();
void OnStorageSaveInfo(const std::vector<uint8_t>& ketSetId, const std::string& mimeType,
const std::string& sessionId, int32_t keyType);
void OnStorageLoadInfo(const std::string& sessionId);
void OnStorageClearInfoForKeyRelease(const std::string& sessionId);
void OnStorageClearInfoForLoadFail(const std::string& sessionId);
void OnMediaLicenseReady(bool success);
void UpdateMediaKeySessionInfoMap(MediaKeySession* keySession, std::shared_ptr<SessionInfo> sessionInfo);
std::shared_ptr<SessionInfo> GetMediaKeySessionInfo(MediaKeySession* keySession);
void RemoveMediaKeySessionInfo(MediaKeySession* keySession);
void ClearMediaKeySessionInfo();
private:
std::shared_ptr<DrmCallbackAdapter> callbackAdapter_;
std::unordered_map<MediaKeySession*, std::shared_ptr<SessionInfo>> mediaKeySessionInfoMap_;
std::mutex mediaKeySessionInfoMutex_;
};
class DrmAdapterImpl : public DrmAdapter {
public:
DrmAdapterImpl() = default;
~DrmAdapterImpl() override;
static Drm_ErrCode SystemCallBackWithObj(
MediaKeySystem* mediaKeySystem, DRM_EventType eventType, uint8_t* info, int32_t infoLen, char* extra);
static Drm_ErrCode SessionEventCallBackWithObj(
MediaKeySession* mediaKeySession, DRM_EventType eventType, uint8_t* info, int32_t infoLen, char* extra);
static Drm_ErrCode SessionKeyChangeCallBackWithObj(
MediaKeySession* mediaKeySession, DRM_KeysInfo* keysInfo, bool newKeysAvailable);
bool IsSupported(const std::string& name) override;
bool IsSupported2(const std::string& name, const std::string& mimeType) override;
bool IsSupported3(const std::string& name, const std::string& mimeType, int32_t level) override;
std::vector<uint8_t> GetUUID(const std::string& name) override;
void StorageProvisionedResult(bool result) override;
void StorageSaveInfoResult(bool result, int32_t type) override;
void StorageLoadInfoResult(const std::string& sessionId, const std::vector<uint8_t>& keySetId,
const std::string& mimeType, uint32_t keyType) override;
void StorageClearInfoResult(bool result, int32_t type) override;
int32_t CreateKeySystem(const std::string& name, const std::string& origin, int32_t securityLevel) override;
int32_t ProcessKeySystemResponse(const std::string& response, bool isResponseReceived) override;
int32_t GenerateMediaKeyRequest(const std::string& sessionId, int32_t type, int32_t initDataLen,
const std::vector<uint8_t>& initData, const std::string& mimeType, uint32_t promiseId) override;
int32_t UpdateSession(uint32_t promiseId, const std::string& sessionId, std::vector<uint8_t> response) override;
int32_t CloseSession(uint32_t promiseId, const std::string& sessionId) override;
int32_t RemoveSession(uint32_t promiseId, const std::string& sessionId) override;
int32_t LoadSession(uint32_t promiseId, const std::string& sessionId) override;
int32_t ReleaseMediaKeySystem() override;
int32_t ReleaseMediaKeySession() override;
int32_t SetConfigurationString(const std::string& configName, const std::string& value) override;
int32_t GetConfigurationString(const std::string& configName, char* value, int32_t valueLen) override;
int32_t SetConfigurationByteArray(const std::string& configName, const uint8_t* value, int32_t valueLen) override;
int32_t GetConfigurationByteArray(const std::string& configName, uint8_t* value, int32_t* valueLen) override;
int32_t GetMaxContentProtectionLevel(int32_t& level) override;
int32_t GetCertificateStatus(int32_t& certStatus) override;
int32_t RegistDrmCallback(std::shared_ptr<DrmCallbackAdapter> callbackAdapter) override;
int32_t ClearMediaKeys() override;
int32_t GetSecurityLevel() override;
int32_t RequireSecureDecoderModule(const std::string& mimeType, bool& status) override;
private:
int32_t CreateMediaKeySession(std::string emeId = "");
int32_t ReleaseMediaKeySession(MediaKeySession* drmKeySession);
MediaKeySession* GetMediaKeySession(std::string emeId);
void PutSessionInfo(std::shared_ptr<SessionId> sessionId, const std::string& mimeType, int32_t type);
std::shared_ptr<SessionInfo> GetSessionInfo(std::shared_ptr<SessionId> sessionId);
void RemoveSessionInfo(std::shared_ptr<SessionId> sessionId);
void LoadSessionInfo(const std::string& emeId);
void LoadSessionWithLoadedStorage(std::shared_ptr<SessionId> sessionId, uint32_t promiseId);
void UpdateSessionResult(
bool isKeyRelease, std::shared_ptr<SessionId> sessionId, uint8_t* mediaKeyId, int32_t mediaKeyIdLen);
void SetKeyType(std::shared_ptr<SessionId> sessionId, int32_t keyType);
void SetKeySetId(std::shared_ptr<SessionId> sessionId, uint8_t* mediaKeyId, int32_t mediaKeyIdLen);
std::shared_ptr<SessionId> GetSessionIdByEmeId(const std::string& emeId);
void ClearPersistentSessionInfoFroKeyRelease(std::shared_ptr<SessionId> sessionId);
void ClearPersistentSessionInfoForLoadFail(std::shared_ptr<SessionId> sessionId);
void HandleKeyUpdatedCallback(uint32_t promiseId, bool result);
static void OnSessionExpirationUpdate(MediaKeySession* drmKeySession, uint8_t* info, int32_t infoLen);
static void GetKeyRequest(MediaKeySession* drmKeySession, uint8_t* info, int32_t infoLen);
private:
static std::unordered_map<MediaKeySystem*, std::shared_ptr<DrmCallbackImpl>> mediaKeySystemCallbackMap_;
static std::unordered_map<MediaKeySession*, std::shared_ptr<DrmCallbackImpl>> mediaKeySessionCallbackMap_;
static std::mutex mediaKeySystemCallbackMapMutex_;
static std::mutex mediaKeySessionCallbackMutex_;
MediaKeySystem* drmKeySystem_ = nullptr;
MediaKeySession* drmKeySession_ = nullptr;
DRM_ContentProtectionLevel contentProtectionLevel_ = CONTENT_PROTECTION_LEVEL_UNKNOWN;
std::shared_ptr<DrmCallbackImpl> callback_ = nullptr;
std::unordered_map<std::string, std::shared_ptr<SessionInfo>> emeSessionInfoMap_;
std::unordered_map<std::string, MediaKeySession*> emeMediaKeySessionMap_;
std::mutex mediaKeySessionMutex_;
uint32_t removeSessionPromiseId_ = 0;
uint32_t updateSessionPromiseId_ = 0;
uint32_t loadSessionPromiseId_ = 0;
std::string releaseEmeId_ = "";
KeySystemType keySystemType_ = KeySystemType::NONE;
};
}
#endif