blob: d4290f85e93d293430c2ab57ae6cc71885174e98 [file] [log] [blame]
// Copyright 2017 The Cobalt Authors. All Rights Reserved.
//
// 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 COBALT_MEDIA_BASE_DRM_SYSTEM_H_
#define COBALT_MEDIA_BASE_DRM_SYSTEM_H_
#include <memory>
#include <string>
#include <vector>
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop/message_loop.h"
#include "base/optional.h"
#include "starboard/drm.h"
namespace cobalt {
namespace media {
// A C++ wrapper around |SbDrmSystem|.
//
// Ensures that callbacks are always asynchronous and performed
// from the same thread where |DrmSystem| was instantiated.
class DrmSystem : public base::RefCounted<DrmSystem> {
public:
typedef base::Callback<void(SbDrmSessionRequestType type,
std::unique_ptr<uint8[]> message,
int message_size)>
SessionUpdateRequestGeneratedCallback;
typedef base::Callback<void(SbDrmStatus status,
const std::string& error_message)>
SessionUpdateRequestDidNotGenerateCallback;
typedef base::Callback<void()> SessionUpdatedCallback;
typedef base::Callback<void(SbDrmStatus status,
const std::string& error_message)>
SessionDidNotUpdateCallback;
typedef base::Callback<void(const std::vector<std::string>& key_ids,
const std::vector<SbDrmKeyStatus>& key_statuses)>
SessionUpdateKeyStatusesCallback;
#if SB_HAS(DRM_SESSION_CLOSED)
typedef base::Callback<void()> SessionClosedCallback;
#endif // SB_HAS(DRM_SESSION_CLOSED)
typedef base::Callback<void(SbDrmStatus status,
const std::string& error_message)>
ServerCertificateUpdatedCallback;
// Flyweight that provides RAII semantics for sessions.
// Most of logic is implemented by |DrmSystem| and thus sessions must be
// destroyed before |DrmSystem|.
class Session {
public:
~Session();
const base::Optional<std::string>& id() const { return id_; }
// Wraps |SbDrmGenerateSessionUpdateRequest|.
//
// |session_update_request_generated_callback| is called upon a successful
// request generation. IMPORTANT: It may be called multiple times after
// a single call to |CreateSessionAndGenerateUpdateRequest|, for example
// when the underlying DRM system needs to update a license.
//
// |session_update_request_did_not_generate_callback| is called upon a
// failure during request generation. Unlike its successful counterpart,
// never called spontaneously.
void GenerateUpdateRequest(
const std::string& type, const uint8* init_data, int init_data_length,
const SessionUpdateRequestGeneratedCallback&
session_update_request_generated_callback,
const SessionUpdateRequestDidNotGenerateCallback&
session_update_request_did_not_generate_callback);
// Wraps |SbDrmUpdateSession|.
//
// |session_updated_callback| is called upon a successful session update.
// |session_did_not_update_callback| is called upon a failure during session
// update.
void Update(
const uint8* key, int key_length,
const SessionUpdatedCallback& session_updated_callback,
const SessionDidNotUpdateCallback& session_did_not_update_callback);
// Wraps |SbDrmCloseSession|.
void Close();
bool is_closed() const { return closed_; }
private:
// Private API for |DrmSystem|.
Session(DrmSystem* drm_system
,
SessionUpdateKeyStatusesCallback update_key_statuses_callback
#if SB_HAS(DRM_SESSION_CLOSED)
,
SessionClosedCallback session_closed_callback
#endif // SB_HAS(SESSION_CLOSED)
); // NOLINT(whitespace/parens)
void set_id(const std::string& id) { id_ = id; }
const SessionUpdateRequestGeneratedCallback&
update_request_generated_callback() const {
return update_request_generated_callback_;
}
const SessionUpdateKeyStatusesCallback& update_key_statuses_callback()
const {
return update_key_statuses_callback_;
}
#if SB_HAS(DRM_SESSION_CLOSED)
const SessionClosedCallback& session_closed_callback() const {
return session_closed_callback_;
}
#endif // SB_HAS(DRM_SESSION_CLOSED)
DrmSystem* const drm_system_;
SessionUpdateKeyStatusesCallback update_key_statuses_callback_;
#if SB_HAS(DRM_SESSION_CLOSED)
SessionClosedCallback session_closed_callback_;
#endif // SB_HAS(DRM_SESSION_CLOSED)
bool closed_;
base::Optional<std::string> id_;
// Supports spontaneous invocations of |SbDrmSessionUpdateRequestFunc|.
SessionUpdateRequestGeneratedCallback update_request_generated_callback_;
friend class DrmSystem;
DISALLOW_COPY_AND_ASSIGN(Session);
};
explicit DrmSystem(const char* key_system);
~DrmSystem();
SbDrmSystem wrapped_drm_system() { return wrapped_drm_system_; }
bool is_valid() const { return SbDrmSystemIsValid(wrapped_drm_system_); }
std::unique_ptr<Session> CreateSession(
SessionUpdateKeyStatusesCallback session_update_key_statuses_callback
#if SB_HAS(DRM_SESSION_CLOSED)
,
SessionClosedCallback session_closed_callback
#endif // SB_HAS(DRM_SESSION_CLOSED)
); // NOLINT(whitespace/parens)
bool IsServerCertificateUpdatable();
void UpdateServerCertificate(
const uint8_t* certificate, int certificate_size,
ServerCertificateUpdatedCallback server_certificate_updated_callback);
private:
// Stores context of |GenerateSessionUpdateRequest|.
struct SessionUpdateRequest {
Session* session;
SessionUpdateRequestGeneratedCallback generated_callback;
SessionUpdateRequestDidNotGenerateCallback did_not_generate_callback;
};
typedef base::hash_map<int, SessionUpdateRequest>
TicketToSessionUpdateRequestMap;
typedef base::hash_map<std::string, Session*> IdToSessionMap;
typedef base::hash_map<int, ServerCertificateUpdatedCallback>
TicketToServerCertificateUpdatedMap;
// Stores context of |Session::Update|.
struct SessionUpdate {
SessionUpdatedCallback updated_callback;
SessionDidNotUpdateCallback did_not_update_callback;
};
typedef base::hash_map<int, SessionUpdate> TicketToSessionUpdateMap;
// Defined to work around the limitation on number of parameters of
// base::Bind().
struct SessionTicketAndOptionalId {
int ticket;
base::Optional<std::string> id;
};
// Private API for |Session|.
void GenerateSessionUpdateRequest(
Session* session, const std::string& type, const uint8_t* init_data,
int init_data_length,
const SessionUpdateRequestGeneratedCallback&
session_update_request_generated_callback,
const SessionUpdateRequestDidNotGenerateCallback&
session_update_request_did_not_generate_callback);
void UpdateSession(
const std::string& session_id, const uint8_t* key, int key_length,
const SessionUpdatedCallback& session_updated_callback,
const SessionDidNotUpdateCallback& session_did_not_update_callback);
void CloseSession(const std::string& session_id);
// Called on the constructor thread, parameters are copied and owned by these
// methods.
void OnSessionUpdateRequestGenerated(
SessionTicketAndOptionalId ticket_and_optional_id, SbDrmStatus status,
SbDrmSessionRequestType type, const std::string& error_message,
std::unique_ptr<uint8[]> message, int message_size);
void OnSessionUpdated(int ticket, SbDrmStatus status,
const std::string& error_message);
void OnSessionKeyStatusChanged(
const std::string& session_id, const std::vector<std::string>& key_ids,
const std::vector<SbDrmKeyStatus>& key_statuses);
#if SB_API_VERSION >= 10
void OnServerCertificateUpdated(int ticket, SbDrmStatus status,
const std::string& error_message);
#endif // SB_API_VERSION >= 10
#if SB_HAS(DRM_SESSION_CLOSED)
void OnSessionClosed(const std::string& session_id);
#endif // SB_HAS(DRM_SESSION_CLOSED)
// Called on any thread, parameters need to be copied immediately.
#if SB_API_VERSION >= 10
static void OnSessionUpdateRequestGeneratedFunc(
SbDrmSystem wrapped_drm_system, void* context, int ticket,
SbDrmStatus status, SbDrmSessionRequestType type,
const char* error_message, const void* session_id, int session_id_size,
const void* content, int content_size, const char* url);
static void OnSessionUpdatedFunc(SbDrmSystem wrapped_drm_system,
void* context, int ticket,
SbDrmStatus status,
const char* error_message,
const void* session_id,
int session_id_length);
#else // SB_API_VERSION >= 10
static void OnSessionUpdateRequestGeneratedFunc(
SbDrmSystem wrapped_drm_system, void* context, int ticket,
const void* session_id, int session_id_size, const void* content,
int content_size, const char* url);
static void OnSessionUpdatedFunc(SbDrmSystem wrapped_drm_system,
void* context, int ticket,
const void* session_id,
int session_id_length, bool succeeded);
#endif // SB_API_VERSION >= 10
static void OnSessionKeyStatusesChangedFunc(
SbDrmSystem wrapped_drm_system, void* context, const void* session_id,
int session_id_size, int number_of_keys, const SbDrmKeyId* key_ids,
const SbDrmKeyStatus* key_statuses);
#if SB_HAS(DRM_SESSION_CLOSED)
static void OnSessionClosedFunc(SbDrmSystem wrapped_drm_system, void* context,
const void* session_id, int session_id_size);
#endif // SB_HAS(DRM_SESSION_CLOSED)
#if SB_API_VERSION >= 10
static void OnServerCertificateUpdatedFunc(SbDrmSystem wrapped_drm_system,
void* context, int ticket,
SbDrmStatus status,
const char* error_message);
#endif // SB_API_VERSION >= 10
const SbDrmSystem wrapped_drm_system_;
scoped_refptr<base::SingleThreadTaskRunner> const message_loop_;
// Factory should only be used to create the initial weak pointer. All
// subsequent weak pointers are created by copying the initial one. This is
// required to keep weak pointers bound to the constructor thread.
base::WeakPtrFactory<DrmSystem> weak_ptr_factory_;
base::WeakPtr<DrmSystem> weak_this_;
int next_ticket_ = 0;
// Supports concurrent calls to |GenerateSessionUpdateRequest|.
TicketToSessionUpdateRequestMap ticket_to_session_update_request_map_;
// Supports spontaneous invocations of |SbDrmSessionUpdateRequestFunc|.
IdToSessionMap id_to_session_map_;
TicketToServerCertificateUpdatedMap ticket_to_server_certificate_updated_map_;
// Supports concurrent calls to |Session::Update|.
TicketToSessionUpdateMap ticket_to_session_update_map_;
DISALLOW_COPY_AND_ASSIGN(DrmSystem);
};
} // namespace media
} // namespace cobalt
#endif // COBALT_MEDIA_BASE_DRM_SYSTEM_H_