1) Change return type to WvCasStatus for functions in wv_cas_types.cc.
2) Add a binary wv_cas_types_example. 3) Surface wv_cas_key_fetcher *source code* to partner to serve as an example of how they would make a HTTP request to acquire an entitlement key from license server. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=229953562
This commit is contained in:
@@ -22,6 +22,8 @@ filegroup(
|
||||
name = "binary_release_files",
|
||||
srcs = glob(["*.h"]) + [
|
||||
":wv_ecmg",
|
||||
"wv_cas_key_fetcher.cc",
|
||||
"wv_cas_types.cc",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -127,7 +129,9 @@ cc_library(
|
||||
"@abseil_repo//absl/base:core_headers",
|
||||
"@abseil_repo//absl/strings",
|
||||
"@curl_repo//:curl",
|
||||
"//util:error_space",
|
||||
"//common:signature_util",
|
||||
"//common:status",
|
||||
"//media_cas_packager_sdk/internal:key_fetcher",
|
||||
"//protos/public:media_cas_encryption_proto",
|
||||
],
|
||||
@@ -181,3 +185,12 @@ cc_binary(
|
||||
"//media_cas_packager_sdk/internal:ecmg_client_handler",
|
||||
],
|
||||
)
|
||||
|
||||
cc_binary(
|
||||
name = "wv_emmg",
|
||||
srcs = ["wv_emmg.cc"],
|
||||
deps = [
|
||||
"//base",
|
||||
"//media_cas_packager_sdk/internal:emmg",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -103,8 +103,6 @@ Status WvCasKeyFetcher::RequestEntitlementKey(const std::string& request_string,
|
||||
}
|
||||
|
||||
// Processes signed response.
|
||||
// TODO(b/114741232): Seems we are getting CasEncryptionResponse back instead
|
||||
// of SignedCasEncryptionResponse.
|
||||
LOG(INFO) << "Json CasEncryptionResponse: " << http_response.response();
|
||||
CasEncryptionResponse response;
|
||||
if (!JsonStringToMessage(http_response.response(), &response).ok()) {
|
||||
|
||||
@@ -79,8 +79,8 @@ bool StringToCryptoMode(const std::string& str, CryptoMode* mode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Status CreateWvCasEncryptionRequestJson(const WvCasEncryptionRequest& request,
|
||||
std::string* request_json) {
|
||||
WvCasStatus CreateWvCasEncryptionRequestJson(
|
||||
const WvCasEncryptionRequest& request, std::string* request_json) {
|
||||
CHECK(request_json);
|
||||
|
||||
CasEncryptionRequest request_proto;
|
||||
@@ -100,23 +100,23 @@ Status CreateWvCasEncryptionRequestJson(const WvCasEncryptionRequest& request,
|
||||
// NOTE: MessageToJsonString will automatically converts 'bytes' type fields
|
||||
// to base64. For example content ID '21140844' becomes 'MjExNDA4NDQ='.
|
||||
if (!MessageToJsonString(request_proto, request_json, print_options).ok()) {
|
||||
return Status(error::INTERNAL,
|
||||
"Failed to convert request message to json.");
|
||||
LOG(ERROR) << "Failed to convert request message to json.";
|
||||
return INTERNAL;
|
||||
}
|
||||
|
||||
return OkStatus();
|
||||
return OK;
|
||||
}
|
||||
|
||||
Status ParseWvCasEncryptionResponseJson(const std::string& response_json,
|
||||
WvCasEncryptionResponse* response) {
|
||||
WvCasStatus ParseWvCasEncryptionResponseJson(
|
||||
const std::string& response_json, WvCasEncryptionResponse* response) {
|
||||
CHECK(response);
|
||||
|
||||
CasEncryptionResponse response_proto;
|
||||
// NOTE: JsonStringToMessage will automatically perform base64 decode for
|
||||
// 'bytes' type fields.
|
||||
if (!JsonStringToMessage(response_json, &response_proto).ok()) {
|
||||
return Status(error::INTERNAL,
|
||||
"Failed to convert response json to message.");
|
||||
LOG(ERROR) << "Failed to convert response json to message.";
|
||||
return INTERNAL;
|
||||
}
|
||||
|
||||
response->status =
|
||||
@@ -133,7 +133,7 @@ Status ParseWvCasEncryptionResponseJson(const std::string& response_json,
|
||||
response->entitlement_keys.push_back(key_info);
|
||||
}
|
||||
|
||||
return OkStatus();
|
||||
return OK;
|
||||
}
|
||||
|
||||
} // namespace cas
|
||||
|
||||
@@ -114,15 +114,15 @@ struct WvCasEncryptionResponse {
|
||||
// request JSON message.
|
||||
// And that signed JSON message can be sent to Widevine license server for
|
||||
// aquiring entitlement keys.
|
||||
Status CreateWvCasEncryptionRequestJson(const WvCasEncryptionRequest& request,
|
||||
std::string* request_json);
|
||||
WvCasStatus CreateWvCasEncryptionRequestJson(
|
||||
const WvCasEncryptionRequest& request, std::string* request_json);
|
||||
|
||||
// Parses a WvCasEncryptionResponse in JSON format, returns a
|
||||
// WvCasEncryptionResponse.
|
||||
// |response_json| is supposed to be the 'response' field in the signed
|
||||
// response from Widevine license server.
|
||||
Status ParseWvCasEncryptionResponseJson(const std::string& response_json,
|
||||
WvCasEncryptionResponse* response);
|
||||
WvCasStatus ParseWvCasEncryptionResponseJson(const std::string& response_json,
|
||||
WvCasEncryptionResponse* response);
|
||||
|
||||
} // namespace cas
|
||||
} // namespace widevine
|
||||
|
||||
@@ -56,7 +56,8 @@ TEST(WvCasTypesTest, CreateWvCasEncryptionRequestJson) {
|
||||
request.key_rotation = true;
|
||||
|
||||
std::string actual_request_json;
|
||||
EXPECT_OK(CreateWvCasEncryptionRequestJson(request, &actual_request_json));
|
||||
EXPECT_EQ(OK,
|
||||
CreateWvCasEncryptionRequestJson(request, &actual_request_json));
|
||||
|
||||
// Content_id has been base64 encoded.
|
||||
std::string expected_request_json =
|
||||
@@ -76,7 +77,8 @@ TEST(WvCasTypesTest, ParseWvCasEncryptionResponseJson) {
|
||||
"\"key_slot\":\"ODD\"}]}";
|
||||
|
||||
WvCasEncryptionResponse actual_response;
|
||||
EXPECT_OK(ParseWvCasEncryptionResponseJson(response_json, &actual_response));
|
||||
EXPECT_EQ(OK,
|
||||
ParseWvCasEncryptionResponseJson(response_json, &actual_response));
|
||||
|
||||
EXPECT_EQ(WvCasEncryptionResponse::Status::OK, actual_response.status);
|
||||
// 21140844 is base64 decode of "MjExNDA4NDQ=".
|
||||
|
||||
@@ -6,15 +6,17 @@
|
||||
// widevine-licensing@google.com.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Example server that listens on a port for Simulcrypt API messages.
|
||||
// Widevine MediaCAS ECMG server.
|
||||
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <cerrno>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "glog/logging.h"
|
||||
|
||||
92
media_cas_packager_sdk/public/wv_emmg.cc
Normal file
92
media_cas_packager_sdk/public/wv_emmg.cc
Normal file
@@ -0,0 +1,92 @@
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright 2019 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.
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Widevine MediaCAS EMMG server.
|
||||
|
||||
#include <netdb.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
|
||||
#include "gflags/gflags.h"
|
||||
#include "glog/logging.h"
|
||||
#include "media_cas_packager_sdk/internal/emmg.h"
|
||||
|
||||
DEFINE_string(mux_address, "", "Mux server address");
|
||||
DEFINE_int32(mux_port, 0, "Mux server port number");
|
||||
|
||||
// EMMG specfic configs.
|
||||
DEFINE_int32(client_id, 0, "EMMG client_id");
|
||||
DEFINE_int32(section_tspkt_flag, 1, "EMMG section_tspkt_flag");
|
||||
DEFINE_int32(data_channel_id, 0, "EMMG data_channel_id");
|
||||
DEFINE_int32(data_stream_id, 0, "EMMG data_stream_id");
|
||||
DEFINE_int32(data_id, 0, "EMMG data_id");
|
||||
// data_type: type of data carried in the datagram in the stream:
|
||||
// 0x00: EMM;
|
||||
// 0x01: private data;
|
||||
// 0x02: DVB reserved (ECM);
|
||||
// other values: DVB reserved.
|
||||
DEFINE_int32(data_type, 0, "EMMG data_type");
|
||||
|
||||
#define BUFFER_SIZE (1024)
|
||||
|
||||
void BuildEmmgConfig(widevine::cas::EmmgConfig *config) {
|
||||
CHECK(config);
|
||||
config->client_id = FLAGS_client_id;
|
||||
config->section_tspkt_flag = FLAGS_section_tspkt_flag;
|
||||
config->data_channel_id = FLAGS_data_channel_id;
|
||||
config->data_stream_id = FLAGS_data_stream_id;
|
||||
config->data_id = FLAGS_data_id;
|
||||
config->data_type = FLAGS_data_type;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
gflags::ParseCommandLineFlags(&argc, &argv, true);
|
||||
CHECK(!FLAGS_mux_address.empty()) << "flag --mux_address is required";
|
||||
CHECK(FLAGS_mux_port != 0) << "flag --mux_port is required";
|
||||
|
||||
// Create server address.
|
||||
struct hostent ret;
|
||||
struct hostent *server;
|
||||
char buffer[BUFFER_SIZE];
|
||||
int h_errnop = 0;
|
||||
int return_val = gethostbyname_r(FLAGS_mux_address.c_str(), &ret, buffer,
|
||||
sizeof(buffer), &server, &h_errnop);
|
||||
if (return_val != 0 || server == nullptr) {
|
||||
LOG(FATAL) << "gethostbyname_r failed for " << FLAGS_mux_address;
|
||||
}
|
||||
struct sockaddr_in server_address;
|
||||
bzero(reinterpret_cast<char *>(&server_address), sizeof(server_address));
|
||||
server_address.sin_family = AF_INET;
|
||||
bcopy(server->h_addr,
|
||||
reinterpret_cast<char *>(&server_address.sin_addr.s_addr),
|
||||
server->h_length);
|
||||
server_address.sin_port = htons(FLAGS_mux_port);
|
||||
|
||||
// Connect to server.
|
||||
int server_socket_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (server_socket_fd < 0) {
|
||||
LOG(FATAL) << "Failed to create socket.";
|
||||
}
|
||||
if (connect(server_socket_fd,
|
||||
reinterpret_cast<struct sockaddr *>(&server_address),
|
||||
sizeof(server_address)) < 0) {
|
||||
LOG(FATAL) << "Failed to connect to server.";
|
||||
}
|
||||
|
||||
// Send EMMG messages.
|
||||
widevine::cas::EmmgConfig emmg_config;
|
||||
BuildEmmgConfig(&emmg_config);
|
||||
widevine::cas::Emmg emmg(&emmg_config, server_socket_fd);
|
||||
emmg.Start();
|
||||
|
||||
close(server_socket_fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user