//////////////////////////////////////////////////////////////////////////////// // 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 #include #include #include #include #include #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 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 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 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(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; }