Entitlement rotation support

Updates also include:
- Add APIs to query current Simulcrypt channel & stream status;
- EMM format change (used only to carry fingerprinting and service
blocking info);
- Key fetcher example to use curl key fetcher.
This commit is contained in:
Widevine Buildbot
2021-06-29 22:07:00 +00:00
parent 8a07605f56
commit 8818d7d026
16 changed files with 142 additions and 66 deletions

View File

@@ -71,23 +71,24 @@ class SecurityProfileList {
// contain single record. For custom DSP, it may contain multiple records // contain single record. For custom DSP, it may contain multiple records
// since active dsp and inactive dsp could share the same dsp_name under the // since active dsp and inactive dsp could share the same dsp_name under the
// same owner. // same owner.
bool GetProfileByNameAndOwner( virtual bool GetProfileByNameAndOwner(
const std::string& name, const std::string& owner, const std::string& name, const std::string& owner,
std::vector<SecurityProfile>* security_profiles) const; std::vector<SecurityProfile>* security_profiles) const;
// Populates |security_profiles| owned by the content owner. // Populates |security_profiles| owned by the content owner.
int GetProfilesByOwner(const std::string& owner, virtual int GetProfilesByOwner(
const std::string& owner,
std::vector<SecurityProfile>* security_profiles) const; std::vector<SecurityProfile>* security_profiles) const;
// Populates |owner_list| for security profiles. |is_default_dsp| boolean // Populates |owner_list| for security profiles. |is_default_dsp| boolean
// indicates the owner_list for default dsp or custom dsp. // indicates the owner_list for default dsp or custom dsp.
int GetProfilesOwnerList(const bool is_default_dsp, virtual int GetProfilesOwnerList(const bool is_default_dsp,
std::vector<std::string>* owner_list) const; std::vector<std::string>* owner_list) const;
// Return the device security capabilities. |drm_info| is populated with // Return the device security capabilities. |drm_info| is populated with
// data from |client_id| and |device_info|. |drm_info| must not be null and // data from |client_id| and |device_info|. |drm_info| must not be null and
// is owned by the caller. // is owned by the caller.
bool GetDrmInfo(const ClientIdentification& client_id, virtual bool GetDrmInfo(const ClientIdentification& client_id,
const ProvisionedDeviceInfo& device_info, const ProvisionedDeviceInfo& device_info,
SecurityProfile::DrmInfo* drm_info) const; SecurityProfile::DrmInfo* drm_info) const;
@@ -110,6 +111,12 @@ class SecurityProfileList {
HashAlgorithm hash_algorithm, const std::string& signature, HashAlgorithm hash_algorithm, const std::string& signature,
int* added_profile_num); int* added_profile_num);
// Returns an instance of the Security profile list for default security
// profiles. Default security profiles are owned by Widevine.
// TODO (b/187073516): This singleton can be moved to the "Environment" class
// as a non-static API.
static SecurityProfileList* GetInstanceForDefaultSecurityProfiles();
protected: protected:
void ClearAllProfiles(); void ClearAllProfiles();

View File

@@ -151,11 +151,11 @@ const char kTestEmmgPrivateDataProvision[] = {
'\x47', '\x40', '\x00', '\x10', '\x0a', '\x0d', '\x77', '\x69', '\x64', '\x47', '\x40', '\x00', '\x10', '\x0a', '\x0d', '\x77', '\x69', '\x64',
'\x65', '\x76', '\x69', '\x6e', '\x65', '\x5f', '\x74', '\x65', '\x73', '\x65', '\x76', '\x69', '\x6e', '\x65', '\x5f', '\x74', '\x65', '\x73',
'\x74', '\x12', '\x09', '\x43', '\x61', '\x73', '\x54', '\x73', '\x46', '\x74', '\x12', '\x09', '\x43', '\x61', '\x73', '\x54', '\x73', '\x46',
'\x61', '\x6b', '\x65', '\x1a', '\x10', '\x66', '\x61', '\x6b', '\x65', '\x61', '\x6b', '\x65', '\x22', '\x0a', '\x66', '\x61', '\x6b', '\x65',
'\x4b', '\x65', '\x79', '\x49', '\x64', '\x31', '\x4b', '\x65', '\x79', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x31', '\x22', '\x0c', '\x66',
'\x49', '\x64', '\x31', '\x1a', '\x10', '\x66', '\x61', '\x6b', '\x65', '\x61', '\x6b', '\x65', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x49',
'\x4b', '\x65', '\x79', '\x49', '\x64', '\x32', '\x4b', '\x65', '\x79', '\x64', '\x32', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x49', '\x64', '\x32', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
@@ -191,22 +191,22 @@ const char kTestEmmgEmmDataProvision[] = {
// Start of the first TS packet (188 bytes). // Start of the first TS packet (188 bytes).
'\x47', '\x40', '\x00', '\x10', // TS packet header (4 bytes). '\x47', '\x40', '\x00', '\x10', // TS packet header (4 bytes).
'\x00', // Pointer field (1 byte). '\x00', // Pointer field (1 byte).
'\x82', '\x70', '\xbe', // Secyion header (3 bytes). '\x82', '\x70', '\xbc', // Section header (3 bytes).
// Start of Widevine EMM. // Start of Widevine EMM.
'\x01', '\x08', '\x00', '\x00', '\x00', '\x00', '\x5f', '\x3d', '\xc1', '\x0a', '\x71', '\x0a', '\x14', '\x0a', '\x03', '\x43', '\x48', '\x31',
'\xfb', '\x00', '\x6b', '\x0a', '\x14', '\x0a', '\x03', '\x43', '\x48', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x08', '\x63', '\x6f',
'\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x08', '\x63', '\x6e', '\x74', '\x72', '\x6f', '\x6c', '\x73', '\x0a', '\x16', '\x0a',
'\x6f', '\x6e', '\x74', '\x72', '\x6f', '\x6c', '\x73', '\x0a', '\x16', '\x03', '\x43', '\x48', '\x33', '\x12', '\x0f', '\x61', '\x6e', '\x6f',
'\x0a', '\x03', '\x43', '\x48', '\x33', '\x12', '\x0f', '\x61', '\x6e', '\x74', '\x68', '\x65', '\x72', '\x20', '\x63', '\x6f', '\x6e', '\x74',
'\x6f', '\x74', '\x68', '\x65', '\x72', '\x20', '\x63', '\x6f', '\x6e', '\x72', '\x6f', '\x6c', '\x12', '\x18', '\x0a', '\x03', '\x43', '\x48',
'\x74', '\x72', '\x6f', '\x6c', '\x12', '\x18', '\x0a', '\x03', '\x43', '\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x06', '\x47',
'\x48', '\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x06', '\x72', '\x6f', '\x75', '\x70', '\x31', '\x20', '\xd2', '\x85', '\xd8',
'\x47', '\x72', '\x6f', '\x75', '\x70', '\x31', '\x20', '\xd2', '\x85', '\xcc', '\x04', '\x12', '\x21', '\x0a', '\x03', '\x43', '\x48', '\x33',
'\xd8', '\xcc', '\x04', '\x12', '\x21', '\x0a', '\x03', '\x43', '\x48', '\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x32', '\x12',
'\x33', '\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x32', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x33', '\x18', '\xd2',
'\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x33', '\x18', '\x85', '\xd8', '\xcc', '\x04', '\x20', '\xd3', '\x85', '\xd8', '\xcc',
'\xd2', '\x85', '\xd8', '\xcc', '\x04', '\x20', '\xd3', '\x85', '\xd8', '\x04', '\x18', '\xfb', '\x83', '\xf7', '\xf9', '\x05', '\x12', '\x47',
'\xcc', '\x04', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78',
'\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78',
'\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78',
'\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78',
@@ -216,8 +216,8 @@ const char kTestEmmgEmmDataProvision[] = {
// Start of the second TS packet (188 bytes). // Start of the second TS packet (188 bytes).
'\x47', '\x00', '\x00', '\x11', // TS packet header (4 bytes). '\x47', '\x00', '\x00', '\x11', // TS packet header (4 bytes).
// Continued Widevine EMM. // Continued Widevine EMM.
'\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\xff',
'\x78', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',
'\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff', '\xff',

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -12,8 +12,11 @@
#include <vector> #include <vector>
#include "common/status.h" #include "common/status.h"
#include "media_cas_packager_sdk/public/wv_cas_curl_key_fetcher.h"
#include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h" #include "media_cas_packager_sdk/public/wv_cas_key_fetcher.h"
const char kCasEncryptionServerUrl[] =
"https://license.uat.widevine.com/cas/getcontentkey/widevine_test";
const char kContentId[] = "21140844"; const char kContentId[] = "21140844";
const char kContentProvider[] = "widevine"; const char kContentProvider[] = "widevine";
const char kTrackType[] = "SD"; const char kTrackType[] = "SD";
@@ -22,36 +25,16 @@ const char kSigningProvider[] = "widevine_test";
const char kSingingKey[] = const char kSingingKey[] =
"1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9"; "1ae8ccd0e7985cc0b6203a55855a1034afc252980e970ca90e5202689f947ab9";
const char kSingingIv[] = "d58ce954203b7c9a9a9d467f59839249"; const char kSingingIv[] = "d58ce954203b7c9a9a9d467f59839249";
const char kHttpResponse[] =
"{\"response\":"
"\"eyJzdGF0dXMiOiJPSyIsImNvbnRlbnRfaWQiOiJNakV4TkRBNE5EUT0iLCJlbnRpdGxlbWVu"
"dF9rZXlzIjpbeyJrZXlfaWQiOiJNUGFndXhNb1hNNkUxUzhEOUF3RkNBPT0iLCJrZXkiOiJoZ1"
"JycmdqeUg4NjQycjY3VHd0OHJ1cU5MUGNMRmtKcWRVSUROdm5GZDBNPSIsInRyYWNrX3R5cGUi"
"OiJTRCIsImtleV9zbG90IjoiU0lOR0xFIn1dfQ==\"}";
using widevine::Status; using widevine::Status;
using widevine::cas::EntitlementKeyInfo; using widevine::cas::EntitlementKeyInfo;
using widevine::cas::EntitlementRequestParams; using widevine::cas::EntitlementRequestParams;
using widevine::cas::WvCasKeyFetcher; using widevine::cas::WvCasCurlKeyFetcher;
class ExampleKeyFetcher : public WvCasKeyFetcher {
public:
ExampleKeyFetcher(const std::string& signing_provider,
const std::string& signing_key,
const std::string& signing_iv)
: WvCasKeyFetcher(signing_provider, signing_key, signing_iv) {}
// An example that always returns the same response.
Status MakeHttpRequest(const std::string& signed_request_json,
std::string* http_response_json) const override {
*http_response_json = kHttpResponse;
return widevine::OkStatus();
}
};
int main(int argc, char** argv) { int main(int argc, char** argv) {
// Initialize key fetcher. // Initialize key fetcher with server url.
ExampleKeyFetcher key_fetcher(kSigningProvider, kSingingKey, kSingingIv); WvCasCurlKeyFetcher key_fetcher(kCasEncryptionServerUrl, kSigningProvider,
kSingingKey, kSingingIv);
// Create request string. // Create request string.
std::string request_str; std::string request_str;

Binary file not shown.

Binary file not shown.

View File

@@ -50,9 +50,7 @@ class WvCasCaDescriptor {
// |ca_pid| the 13-bit PID of the ECMs // |ca_pid| the 13-bit PID of the ECMs
// |provider| provider name, put in private data for client to construct pssh // |provider| provider name, put in private data for client to construct pssh
// |content_id| content ID, put in private data for client to construct pssh // |content_id| content ID, put in private data for client to construct pssh
// |entitlement_key_ids| entitlement key ids, put in private data for client // |group_ids| the groups ids this channel belongs to. Optional.
// to select entitlement keys from single fat license. This field is only used
// when client uses single fat license.
// |serialized_ca_desc| a std::string object to receive the encoded descriptor. // |serialized_ca_desc| a std::string object to receive the encoded descriptor.
// //
// Notes: // Notes:
@@ -60,10 +58,10 @@ class WvCasCaDescriptor {
// section (for an EMM stream) or into a TS Program Map Table section (for an // section (for an EMM stream) or into a TS Program Map Table section (for an
// ECM stream). The descriptor will be 6 bytes plus any bytes added as // ECM stream). The descriptor will be 6 bytes plus any bytes added as
// (user-defined) private data. // (user-defined) private data.
virtual Status GenerateCaDescriptor( virtual Status GenerateCaDescriptor(uint16_t ca_pid,
uint16_t ca_pid, const std::string& provider, const std::string& provider,
const std::string& content_id, const std::string& content_id,
const std::vector<std::string>& entitlement_key_ids, const std::vector<std::string>& group_ids,
std::string* serialized_ca_desc) const; std::string* serialized_ca_desc) const;
// Return the base size (before private data is added) of the CA // Return the base size (before private data is added) of the CA
@@ -74,7 +72,7 @@ class WvCasCaDescriptor {
// Return private data in the CA descriptor. // Return private data in the CA descriptor.
virtual std::string GeneratePrivateData( virtual std::string GeneratePrivateData(
const std::string& provider, const std::string& content_id, const std::string& provider, const std::string& content_id,
const std::vector<std::string>& entitlement_key_ids) const; const std::vector<std::string>& group_ids) const;
}; };
} // namespace cas } // namespace cas

View File

@@ -61,6 +61,7 @@ struct WvCasEcmParameters {
uint16_t cas_id = 0x4AD4; uint16_t cas_id = 0x4AD4;
EcmVersion ecm_version = EcmVersion::kV2; EcmVersion ecm_version = EcmVersion::kV2;
std::string ecc_private_signing_key; std::string ecc_private_signing_key;
EntitlementKeyRotationInfo entitlement_rotation;
}; };
// Class for generating Widevine CAS ECMs. // Class for generating Widevine CAS ECMs.
@@ -94,6 +95,20 @@ class WvCasEcm {
virtual void SetServiceBlocking( virtual void SetServiceBlocking(
const EcmServiceBlockingParams* service_blocking); const EcmServiceBlockingParams* service_blocking);
// Sets the current value of the entitlement key rotation window left to
// |entitlement_rotation_window_left|. The value will be used in
// GenerateEcm/GenerateSingleKeyEcm if entitlement rotation is enabled as
// specified at initializing, and is automatically decreased by 1 on each call
// to GenerateEcm/GenerateSingleKeyEcm, until it reaches 1.
virtual Status SetEntitlementRotationWindowLeft(
uint32_t entitlement_rotation_window_left);
// Gets the current value of the entitlement key rotation window left. The
// value is used in GenerateEcm/GenerateSingleKeyEcm, and is automatically
// decreased by 1 on each call to GenerateEcm/GenerateSingleKeyEcm, until it
// reaches 1.
virtual uint32_t GetEntitlementRotationWindowLeft() const;
// Constructs a Widevine ECM using the provided key info. // Constructs a Widevine ECM using the provided key info.
// Args: // Args:
// |even_key| information for even key to be encoded into ECM. // |even_key| information for even key to be encoded into ECM.
@@ -106,6 +121,9 @@ class WvCasEcm {
// consistent with the initialized settings. // consistent with the initialized settings.
// The even_key and odd_key will be wrapped using the appropriate // The even_key and odd_key will be wrapped using the appropriate
// entitlement key. // entitlement key.
// If entitlement rotation is enabled as specified at initializing, the
// entitlement key rotation window left value will be automatically decreased
// by 1, until it reaches 1.
virtual Status GenerateEcm(const WvCasContentKeyInfo& even_key, virtual Status GenerateEcm(const WvCasContentKeyInfo& even_key,
const WvCasContentKeyInfo& odd_key, const WvCasContentKeyInfo& odd_key,
const std::string& track_type, const std::string& track_type,
@@ -122,6 +140,9 @@ class WvCasEcm {
// |serialized_ecm| caller-supplied std::string pointer to receive the ECM. // |serialized_ecm| caller-supplied std::string pointer to receive the ECM.
// The |key| contents (specifically IV sizes) must be consistent // The |key| contents (specifically IV sizes) must be consistent
// with the initialized settings. // with the initialized settings.
// If entitlement rotation is enabled as specified at initializing, the
// entitlement key rotation window left value will be automatically decreased
// by 1, until it reaches 1.
virtual Status GenerateSingleKeyEcm(const WvCasContentKeyInfo& key, virtual Status GenerateSingleKeyEcm(const WvCasContentKeyInfo& key,
const std::string& track_type, const std::string& track_type,
const std::vector<std::string>& group_ids, const std::vector<std::string>& group_ids,

View File

@@ -74,6 +74,12 @@ class WvCasEcmgClientHandler {
size_t& response_length, size_t& response_length,
size_t& processed_request_length); size_t& processed_request_length);
// Retrieves the current channel status;
WvEcmgChannelStatus GetChannelStatus() const;
// Retrieves the status of all open streams;
std::vector<WvEcmgStreamStatus> GetStreamStatus() const;
protected: protected:
// For unit test only. // For unit test only.
explicit WvCasEcmgClientHandler( explicit WvCasEcmgClientHandler(

View File

@@ -29,12 +29,17 @@ namespace cas {
// |group_id| optional field indicates if this is a key used for a group of // |group_id| optional field indicates if this is a key used for a group of
// contents. If this field is not empty, entitlement key would be generated // contents. If this field is not empty, entitlement key would be generated
// for the group instead of the single content. // for the group instead of the single content.
// |entitlement_rotation_enabled| Whether entitlement rotation is enabled.
// |entitlement_period_index| The requested entitlement period index if
// entitlement rotation is enabled.
struct EntitlementRequestParams { struct EntitlementRequestParams {
std::string content_id; std::string content_id;
std::string content_provider; std::string content_provider;
std::vector<std::string> track_types; std::vector<std::string> track_types;
bool key_rotation; bool key_rotation;
std::string group_id; std::string group_id;
bool entitlement_rotation_enabled = false;
uint32_t entitlement_period_index;
}; };
// WV CAS KeyFetcher. Performs the communication with the Widevine License // WV CAS KeyFetcher. Performs the communication with the Widevine License

View File

@@ -86,6 +86,23 @@ struct EntitlementKeyInfo {
enum class EcmVersion : int { kV2 = 0, kV3 = 1 }; enum class EcmVersion : int { kV2 = 0, kV3 = 1 };
// Used for generating ECMs if entitlement key rotation is enabled.
struct EntitlementKeyRotationInfo {
// Indicates if entitlement key rotation feature is used. If enabled,
// |period_index| and |rotation_window_left| must also be specified and will
// be carried in generated ECMs.
bool rotation_enabled = false;
// The current entitlement key period index. Only used if |rotation_enabled|
// is set to true.
uint32_t period_index = 0;
// It tells the client how many crypto periods (unique ECMs) left (including
// this ECM) that a new license request must be made. Must be a positive
// value. Only used if |rotation_enabled| is set to true.
// The value will automatically decrease by 1 on each call to GenerateEcm or
// GenerateSingleKeyEcm, until the value reaches 1.
uint32_t rotation_window_left = 0;
};
// A struct that captures the Simulcrypt ECMG configurations. Most fields are // A struct that captures the Simulcrypt ECMG configurations. Most fields are
// Simulcrypt standard fields (See ETSI TS 103 197 V1.5.1 (2008-10) // Simulcrypt standard fields (See ETSI TS 103 197 V1.5.1 (2008-10)
// Section 5.3). // Section 5.3).
@@ -177,6 +194,8 @@ struct EcmgCustomParameters {
// when the ECM is received, and stops util the device is no longer in // when the ECM is received, and stops util the device is no longer in
// |device_groups|. // |device_groups|.
std::vector<std::string> service_blocking_groups; std::vector<std::string> service_blocking_groups;
// Used if entitlement key rotation is enabled.
EntitlementKeyRotationInfo entitlement_rotation;
}; };
// A custom access control processing function used by ECMG to get information // A custom access control processing function used by ECMG to get information
@@ -233,6 +252,33 @@ typedef std::function<EcmServiceBlockingParams(uint16_t channel_id,
uint16_t stream_id)> uint16_t stream_id)>
ServiceBlockingSettingFunc; ServiceBlockingSettingFunc;
struct WvEcmgChannelStatus {
// If the channel has been set up or not.
bool has_setup;
uint16_t channel_id;
uint16_t ca_system_id;
int num_of_open_streams;
EcmVersion ecm_version;
// Below are Simulcrypt parameters values (see ETSI TS 103 197 V1.5.1
// (2008-10) Section 5.3).
uint8_t section_tspkt_flag;
uint16_t delay_start;
uint16_t delay_stop;
uint16_t ecm_pep_period;
uint16_t max_streams;
uint16_t min_cp_duration;
uint8_t lead_cw;
uint8_t cw_per_message;
uint16_t max_comp_time;
};
struct WvEcmgStreamStatus {
uint16_t stream_id;
uint16_t ecm_id;
CryptoMode crypto_mode;
int age_restriction;
};
struct WvCasEncryptionRequest { struct WvCasEncryptionRequest {
std::string content_id; std::string content_id;
std::string provider; std::string provider;

View File

@@ -19,9 +19,8 @@ message CaDescriptorPrivateData {
// Content ID. // Content ID.
optional bytes content_id = 2; optional bytes content_id = 2;
// Entitlement key IDs for current content per track. Each track will allow up // Deprecated.
// to 2 entitlement key ids (odd and even entitlement keys). repeated bytes deprecated_entitlement_key_ids = 3;
repeated bytes entitlement_key_ids = 3;
// The groups ids this channel belongs to. // The groups ids this channel belongs to.
repeated bytes group_ids = 4; repeated bytes group_ids = 4;
@@ -78,6 +77,17 @@ message EcmMetaData {
// Optional. The minimum age required to watch the content. The value // Optional. The minimum age required to watch the content. The value
// represents actual age, with 0 means no restriction. // represents actual age, with 0 means no restriction.
optional uint32 age_restriction = 2 [default = 0]; optional uint32 age_restriction = 2 [default = 0];
// If specified, it means entitlement key rotation is enabled. The value will
// be included in the license request. The server is expected to return
// entitlement keys accordingly (e.g., keys for |entitlement_period_index| and
// |entitlement_period_index| + 1).
optional uint32 entitlement_period_index = 3;
// Used only if entitlement key rotation is enabled. This parameter controls
// the probability of requesting a new license by clients upon receiving this
// ECM. The purpose is to spread out requests to avoid request storms. A
// client will request a new license with possibility = 1 /
// |entitlement_rotation_window_left|.
optional uint32 entitlement_rotation_window_left = 4 [default = 1];
} }
message EcmKeyData { message EcmKeyData {