Add EMMG to carry fingerprinting and service blocking info
This commit is contained in:
@@ -67,3 +67,13 @@ cc_binary(
|
||||
srcs = ["wv_cas_types_example.cc"],
|
||||
deps = ["//media_cas_packager_sdk/public:wv_cas_types"],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "wv_cas_emm_example",
|
||||
srcs = ["wv_cas_emm_example.cc"],
|
||||
deps = [
|
||||
"//base",
|
||||
"//common:status",
|
||||
"//media_cas_packager_sdk/public:wv_cas_emm",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -52,7 +52,7 @@ const char kTestEmmgChannelSetup[] = {
|
||||
'\x01' // parameter_value
|
||||
};
|
||||
|
||||
const char kTestEmmgStreamSetup[] = {
|
||||
const char kTestEmmgStreamSetupForPrivateData[] = {
|
||||
'\x02', // protocol_version
|
||||
'\x01', '\x11', // message_type - Stream_setup
|
||||
'\x00', '\x1f', // message_length
|
||||
@@ -73,6 +73,27 @@ const char kTestEmmgStreamSetup[] = {
|
||||
'\x01' // parameter_value - private data
|
||||
};
|
||||
|
||||
const char kTestEmmgStreamSetupForEmm[] = {
|
||||
'\x02', // protocol_version
|
||||
'\x01', '\x11', // message_type - Stream_setup
|
||||
'\x00', '\x1f', // message_length
|
||||
'\x00', '\x01', // parameter_type - client_id
|
||||
'\x00', '\x04', // parameter_length
|
||||
'\x4a', '\xd4', '\x00', '\x00', // parameter_value
|
||||
'\x00', '\x03', // parameter_type - data_channel_id
|
||||
'\x00', '\x02', // parameter_length
|
||||
'\x00', '\x01', // parameter_value
|
||||
'\x00', '\x04', // parameter_type - data_stream_id
|
||||
'\x00', '\x02', // parameter_length
|
||||
'\x00', '\x01', // parameter_value
|
||||
'\x00', '\x08', // parameter_type - data_id
|
||||
'\x00', '\x02', // parameter_length
|
||||
'\x00', '\x01', // parameter_value
|
||||
'\x00', '\x07', // parameter_type - data_type
|
||||
'\x00', '\x01', // parameter_length
|
||||
'\x00' // parameter_value - emm
|
||||
};
|
||||
|
||||
const char kTestEmmgStreamBwRequest[] = {
|
||||
'\x02', // protocol_version
|
||||
'\x01', '\x17', // message_type - Stream_BW_request
|
||||
@@ -109,7 +130,7 @@ const char kTestEmmgStreamBwAllocation[] = {
|
||||
'\x00', '\x32' // parameter_value (50 kbps)
|
||||
};
|
||||
|
||||
const char kTestEmmgDataProvision[] = {
|
||||
const char kTestEmmgPrivateDataProvision[] = {
|
||||
'\x02', // protocol_version
|
||||
'\x02', '\x11', // message_type - Data_provision
|
||||
'\x00', '\xda', // message_length
|
||||
@@ -149,10 +170,10 @@ const char kTestEmmgDataProvision[] = {
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00',
|
||||
'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'};
|
||||
|
||||
const char kTestEmptyEmmgDataProvision[] = {
|
||||
const char kTestEmmgEmmDataProvision[] = {
|
||||
'\x02', // protocol_version
|
||||
'\x02', '\x11', // message_type - Data_provision
|
||||
'\x00', '\x00', // message_length
|
||||
'\x01', '\x96', // message_length
|
||||
'\x00', '\x01', // parameter_type - client_id
|
||||
'\x00', '\x04', // parameter_length
|
||||
'\x4a', '\xd4', '\x00', '\x00', // parameter_value
|
||||
@@ -165,9 +186,57 @@ const char kTestEmptyEmmgDataProvision[] = {
|
||||
'\x00', '\x08', // parameter_type - data_id
|
||||
'\x00', '\x02', // parameter_length
|
||||
'\x00', '\x01', // parameter_value
|
||||
'\x00', '\x00', // parameter_type - datagram
|
||||
'\x00', '\x00', // parameter_length
|
||||
};
|
||||
'\x00', '\x05', // parameter_type - datagram
|
||||
'\x01', '\x78', // parameter_length
|
||||
// Start of the first TS packet (188 bytes).
|
||||
'\x47', '\x40', '\x00', '\x10', // TS packet header (4 bytes).
|
||||
'\x00', // Pointer field (1 byte).
|
||||
'\x82', '\x70', '\xbe', // Secyion header (3 bytes).
|
||||
// Start of Widevine EMM.
|
||||
'\x01', '\x08', '\x00', '\x00', '\x00', '\x00', '\x5f', '\x3d', '\xc1',
|
||||
'\xfb', '\x00', '\x6b', '\x0a', '\x14', '\x0a', '\x03', '\x43', '\x48',
|
||||
'\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x08', '\x63',
|
||||
'\x6f', '\x6e', '\x74', '\x72', '\x6f', '\x6c', '\x73', '\x0a', '\x16',
|
||||
'\x0a', '\x03', '\x43', '\x48', '\x33', '\x12', '\x0f', '\x61', '\x6e',
|
||||
'\x6f', '\x74', '\x68', '\x65', '\x72', '\x20', '\x63', '\x6f', '\x6e',
|
||||
'\x74', '\x72', '\x6f', '\x6c', '\x12', '\x18', '\x0a', '\x03', '\x43',
|
||||
'\x48', '\x31', '\x0a', '\x03', '\x43', '\x48', '\x32', '\x12', '\x06',
|
||||
'\x47', '\x72', '\x6f', '\x75', '\x70', '\x31', '\x20', '\xd2', '\x85',
|
||||
'\xd8', '\xcc', '\x04', '\x12', '\x21', '\x0a', '\x03', '\x43', '\x48',
|
||||
'\x33', '\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x32',
|
||||
'\x12', '\x06', '\x47', '\x72', '\x6f', '\x75', '\x70', '\x33', '\x18',
|
||||
'\xd2', '\x85', '\xd8', '\xcc', '\x04', '\x20', '\xd3', '\x85', '\xd8',
|
||||
'\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',
|
||||
// Start of the second TS packet (188 bytes).
|
||||
'\x47', '\x00', '\x00', '\x11', // TS packet header (4 bytes).
|
||||
// Continued Widevine EMM.
|
||||
'\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78', '\x78',
|
||||
'\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',
|
||||
'\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', '\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'};
|
||||
|
||||
const char kTestEmmgStreamCloseRequest[] = {
|
||||
'\x02', // protocol_version
|
||||
|
||||
133
example/wv_cas_emm_example.cc
Normal file
133
example/wv_cas_emm_example.cc
Normal file
@@ -0,0 +1,133 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2020 Google LLC.
|
||||
//
|
||||
// This software is licensed under the terms defined in the Widevine Master
|
||||
// License Agreement. For a copy of this agreement, please contact
|
||||
// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Example of how to use the wv_cas_emm library.
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <cstdint>
|
||||
#include "common/status.h"
|
||||
#include "media_cas_packager_sdk/public/wv_cas_emm.h"
|
||||
|
||||
namespace {
|
||||
|
||||
using widevine::cas::WvCasEmm;
|
||||
using widevine::cas::WvCasFingerprintingInitParameters;
|
||||
using widevine::cas::WvCasServiceBlockingInitParameters;
|
||||
|
||||
// PID for the EMM packet.
|
||||
static constexpr int kEmmPid = 1;
|
||||
static constexpr size_t kTsPacketSize = 188;
|
||||
static constexpr size_t kMaxPossibleTsPacketsCount = 6;
|
||||
static constexpr size_t kMaxPossibleTsPacketsSizeBytes =
|
||||
kMaxPossibleTsPacketsCount * kTsPacketSize;
|
||||
static constexpr unsigned char kTestECPrivateKey2Secp256r1[] = {
|
||||
0x30, 0x77, 0x02, 0x01, 0x01, 0x04, 0x20, 0x34, 0x9a, 0xf2, 0x95,
|
||||
0x94, 0xd4, 0xca, 0xb9, 0xa0, 0x81, 0xe4, 0x1c, 0xf5, 0xde, 0x8d,
|
||||
0x23, 0xf6, 0x79, 0xba, 0x3c, 0x6e, 0xc9, 0x0b, 0x56, 0x0f, 0x07,
|
||||
0x5e, 0x9f, 0xe9, 0x38, 0x18, 0xfc, 0xa0, 0x0a, 0x06, 0x08, 0x2a,
|
||||
0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0xa1, 0x44, 0x03, 0x42,
|
||||
0x00, 0x04, 0x7b, 0x2a, 0x61, 0x59, 0xe5, 0x1b, 0xb6, 0x30, 0x7b,
|
||||
0x59, 0x98, 0x42, 0x59, 0x37, 0xfb, 0x46, 0xfe, 0x53, 0xfe, 0x32,
|
||||
0xa1, 0x5c, 0x93, 0x36, 0x11, 0xb0, 0x5a, 0xae, 0xa4, 0x48, 0xe3,
|
||||
0x20, 0x12, 0xce, 0x78, 0xa7, 0x7f, 0xfd, 0x73, 0x5e, 0x09, 0x77,
|
||||
0x53, 0x77, 0x8f, 0xd6, 0x1b, 0x26, 0xfa, 0xc4, 0x2c, 0xc4, 0x11,
|
||||
0xfa, 0x72, 0x6a, 0xbe, 0x94, 0x78, 0x4d, 0x74, 0x20, 0x27, 0x86};
|
||||
|
||||
std::vector<WvCasFingerprintingInitParameters> GetFingerprintingParams() {
|
||||
WvCasFingerprintingInitParameters fingerprinting_1;
|
||||
// Channels used in the fingerprinting and service blocking info. The channel
|
||||
// definition is opaque to Widevine.
|
||||
fingerprinting_1.channels = {"CH1", "CH2"};
|
||||
// Fingerprinting control information. The format is opaque to Widevine.
|
||||
fingerprinting_1.control = "controls";
|
||||
|
||||
WvCasFingerprintingInitParameters fingerprinting_2;
|
||||
fingerprinting_2.channels = {"CH3"};
|
||||
fingerprinting_2.control = "another control";
|
||||
|
||||
return {fingerprinting_1, fingerprinting_2};
|
||||
}
|
||||
|
||||
std::vector<WvCasServiceBlockingInitParameters> GetServiceBlockingParams() {
|
||||
WvCasServiceBlockingInitParameters service_blocking_1;
|
||||
service_blocking_1.channels = {"CH1"};
|
||||
// Device groups that should have service blocking. The group definition is
|
||||
// opaque to Widevine.
|
||||
service_blocking_1.device_groups = {"Group1", "Group2"};
|
||||
// Service blocking start and end time, Epoch time in seconds.
|
||||
service_blocking_1.start_time = 1598398260;
|
||||
service_blocking_1.end_time = 1598398261;
|
||||
|
||||
WvCasServiceBlockingInitParameters service_blocking_2;
|
||||
service_blocking_2.channels = {"CH2", "CH3"};
|
||||
service_blocking_2.device_groups = {"Group3"};
|
||||
service_blocking_2.start_time = 0; // start_time set to 0 means immediate.
|
||||
service_blocking_2.end_time = 1598398261;
|
||||
|
||||
return {service_blocking_1, service_blocking_2};
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
widevine::Status status;
|
||||
// Create EMM object with the ECC signing key.
|
||||
std::string ecc_signing_key(std::begin(kTestECPrivateKey2Secp256r1),
|
||||
std::end(kTestECPrivateKey2Secp256r1));
|
||||
std::unique_ptr<WvCasEmm> emm = WvCasEmm::Create(ecc_signing_key);
|
||||
if (emm == nullptr) {
|
||||
std::cerr << "Failed to create WvCasEmm object";
|
||||
return -1;
|
||||
}
|
||||
// Optionally set the fingerprinting info.
|
||||
status = emm->SetFingerprinting(GetFingerprintingParams());
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set fingerprinting info: " << status << std::endl;
|
||||
return -2;
|
||||
}
|
||||
// Optionally set the service blocking info.
|
||||
status = emm->SetServiceBlocking(GetServiceBlockingParams());
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to set service blocking info: " << status << std::endl;
|
||||
return -3;
|
||||
}
|
||||
|
||||
// Generate serialized EMM.
|
||||
std::string serialized_emm;
|
||||
status = emm->GenerateEmm(&serialized_emm);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to generate serialized EMM: " << status << std::endl;
|
||||
return -4;
|
||||
}
|
||||
std::cout << "Successfully generated EMM bytes: ";
|
||||
for (size_t i = 0; i < serialized_emm.size(); i++) {
|
||||
printf("'\\x%02x', ", static_cast<uint8_t>(serialized_emm[i]));
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
// Generate EMM wrapped in TS packet.
|
||||
// Notice that the signature of the EMM is expected to differ for each call.
|
||||
uint8_t packet[kMaxPossibleTsPacketsSizeBytes];
|
||||
ssize_t packet_size = kMaxPossibleTsPacketsSizeBytes;
|
||||
uint8_t continuity_counter = 0;
|
||||
status = emm->GenerateEmmTsPackets(kEmmPid, &continuity_counter, packet,
|
||||
&packet_size);
|
||||
if (!status.ok()) {
|
||||
std::cerr << "Failed to generate EMM TS packet: " << status << std::endl;
|
||||
return -5;
|
||||
}
|
||||
std::cout << "Successfully generated EMM TS packet bytes: ";
|
||||
for (size_t i = 0; i < packet_size; i++) {
|
||||
printf("'\\x%02x', ", packet[i]);
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user