blob: 836afb6d6413ca939bcbf91a455200f2c91cee76 [file] [log] [blame]
// 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.
#ifndef MEDIA_CDM_WIN_MEDIA_FOUNDATION_CDM_H_
#define MEDIA_CDM_WIN_MEDIA_FOUNDATION_CDM_H_
#include <mfcontentdecryptionmodule.h>
#include <wrl.h>
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "media/base/cdm_context.h"
#include "media/base/content_decryption_module.h"
#include "media/base/media_export.h"
namespace media {
// Key to the client token. The same value is also used in MediaFoundation CDMs.
// Do NOT change this value!
DEFINE_PROPERTYKEY(EME_CONTENTDECRYPTIONMODULE_CLIENT_TOKEN,
0xa4abc308,
0xd249,
0x4150,
0x90,
0x37,
0xc9,
0x97,
0xf8,
0xcf,
0x8d,
0x0f,
PID_FIRST_USABLE);
class MediaFoundationCdmSession;
// A CDM implementation based on Media Foundation IMFContentDecryptionModule on
// Windows.
class MEDIA_EXPORT MediaFoundationCdm final : public ContentDecryptionModule,
public CdmContext {
public:
// Checks whether MediaFoundationCdm is available based on OS version. Further
// checks need to be made to determine the usability and the capabilities.
static bool IsAvailable();
// Callback to create an IMFContentDecryptionModule. If failed,
// IMFContentDecryptionModule must be null.
using CreateMFCdmCB = base::RepeatingCallback<
void(HRESULT&, Microsoft::WRL::ComPtr<IMFContentDecryptionModule>&)>;
// Callback to MediaFoundationCDM to resolve the promise.
using IsTypeSupportedResultCB = base::OnceCallback<void(bool is_supported)>;
// Callback to IMFMediaFoundataionCdmFactory's IsTypeSupported.
using IsTypeSupportedCB =
base::RepeatingCallback<void(const std::string&,
IsTypeSupportedResultCB)>;
// Callback to MediaFoundationCdmFactory::StoreClientToken
using StoreClientTokenCB =
base::RepeatingCallback<void(const std::vector<uint8_t>&)>;
// Constructs `MediaFoundationCdm`. Note that `Initialize()` must be called
// before calling any other methods.
MediaFoundationCdm(
const CreateMFCdmCB& create_mf_cdm_cb,
const IsTypeSupportedCB& is_type_supported_cb,
const StoreClientTokenCB& store_client_token_cb,
const SessionMessageCB& session_message_cb,
const SessionClosedCB& session_closed_cb,
const SessionKeysChangeCB& session_keys_change_cb,
const SessionExpirationUpdateCB& session_expiration_update_cb);
MediaFoundationCdm(const MediaFoundationCdm&) = delete;
MediaFoundationCdm& operator=(const MediaFoundationCdm&) = delete;
// Initializes `this` and returns whether the initialization succeeds. Must
// be called before any other methods.
HRESULT Initialize();
// ContentDecryptionModule implementation.
void SetServerCertificate(const std::vector<uint8_t>& certificate,
std::unique_ptr<SimpleCdmPromise> promise) override;
void GetStatusForPolicy(
HdcpVersion min_hdcp_version,
std::unique_ptr<KeyStatusCdmPromise> promise) override;
void CreateSessionAndGenerateRequest(
CdmSessionType session_type,
EmeInitDataType init_data_type,
const std::vector<uint8_t>& init_data,
std::unique_ptr<NewSessionCdmPromise> promise) override;
void LoadSession(CdmSessionType session_type,
const std::string& session_id,
std::unique_ptr<NewSessionCdmPromise> promise) override;
void UpdateSession(const std::string& session_id,
const std::vector<uint8_t>& response,
std::unique_ptr<SimpleCdmPromise> promise) override;
void CloseSession(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise> promise) override;
void RemoveSession(const std::string& session_id,
std::unique_ptr<SimpleCdmPromise> promise) override;
CdmContext* GetCdmContext() override;
// CdmContext implementation.
bool RequiresMediaFoundationRenderer() override;
bool GetMediaFoundationCdmProxy(
GetMediaFoundationCdmProxyCB get_mf_cdm_proxy_cb) override;
private:
~MediaFoundationCdm() override;
// Returns whether the |session_id| is accepted by the |this|.
bool OnSessionId(int session_token,
std::unique_ptr<NewSessionCdmPromise> promise,
const std::string& session_id);
MediaFoundationCdmSession* GetSession(const std::string& session_id);
void CloseSessionInternal(const std::string& session_id,
CdmSessionClosedReason reason,
std::unique_ptr<SimpleCdmPromise> promise);
// Called when hardware context reset happens.
void OnHardwareContextReset();
// Called when IsTypeSupported() result is available.
void OnIsTypeSupportedResult(std::unique_ptr<KeyStatusCdmPromise> promise,
bool is_supported);
void StoreClientTokenIfNeeded();
// Callback to create `mf_cdm_`.
CreateMFCdmCB create_mf_cdm_cb_;
// Callback to MFCdmFactory's IsTypeSupported().
IsTypeSupportedCB is_type_supported_cb_;
// Callback to MFCdmFactory's StoreClientToken().
StoreClientTokenCB store_client_token_cb_;
// Callbacks for firing session events.
SessionMessageCB session_message_cb_;
SessionClosedCB session_closed_cb_;
SessionKeysChangeCB session_keys_change_cb_;
SessionExpirationUpdateCB session_expiration_update_cb_;
Microsoft::WRL::ComPtr<IMFContentDecryptionModule> mf_cdm_;
// Used to generate unique tokens for identifying pending sessions before
// session ID is available.
int next_session_token_ = 0;
// Session token to session map for sessions waiting for session ID.
std::map<int, std::unique_ptr<MediaFoundationCdmSession>> pending_sessions_;
// Session ID to session map.
std::map<std::string, std::unique_ptr<MediaFoundationCdmSession>> sessions_;
scoped_refptr<MediaFoundationCdmProxy> cdm_proxy_;
// Copy of the last client token we stored.
std::vector<uint8_t> cached_client_token_;
// This must be the last member.
base::WeakPtrFactory<MediaFoundationCdm> weak_factory_{this};
};
} // namespace media
#endif // MEDIA_CDM_WIN_MEDIA_FOUNDATION_CDM_H_