7 #include "packager/media/base/widevine_key_source.h" 9 #include "packager/base/base64.h" 10 #include "packager/base/bind.h" 11 #include "packager/base/strings/string_number_conversions.h" 12 #include "packager/media/base/http_key_fetcher.h" 13 #include "packager/media/base/network_util.h" 14 #include "packager/media/base/producer_consumer_queue.h" 15 #include "packager/media/base/protection_system_ids.h" 16 #include "packager/media/base/protection_system_specific_info.h" 17 #include "packager/media/base/proto_json_util.h" 18 #include "packager/media/base/pssh_generator_util.h" 19 #include "packager/media/base/rcheck.h" 20 #include "packager/media/base/request_signer.h" 21 #include "packager/media/base/widevine_common_encryption.pb.h" 27 const bool kEnableKeyRotation =
true;
31 const int kNumTransientErrorRetries = 5;
32 const int kFirstRetryDelayMilliseconds = 1000;
36 const int kDefaultCryptoPeriodCount = 10;
37 const int kGetKeyTimeoutInSeconds = 5 * 60;
38 const int kKeyFetchTimeoutInSeconds = 60;
40 CommonEncryptionRequest::ProtectionScheme ToCommonEncryptionProtectionScheme(
41 FourCC protection_scheme) {
42 switch (protection_scheme) {
44 return CommonEncryptionRequest::CENC;
46 case kAppleSampleAesProtectionScheme:
48 return CommonEncryptionRequest::CBCS;
50 return CommonEncryptionRequest::CBC1;
52 return CommonEncryptionRequest::CENS;
54 LOG(WARNING) <<
"Ignore unrecognized protection scheme " 55 << FourCCToString(protection_scheme);
56 return CommonEncryptionRequest::UNSPECIFIED;
60 ProtectionSystemSpecificInfo ProtectionSystemInfoFromPsshProto(
61 const CommonEncryptionResponse::Track::Pssh& pssh_proto) {
62 PsshBoxBuilder pssh_builder;
63 pssh_builder.set_system_id(kWidevineSystemId, arraysize(kWidevineSystemId));
65 if (pssh_proto.has_boxes()) {
66 return {pssh_builder.system_id(),
67 std::vector<uint8_t>(pssh_proto.boxes().begin(),
68 pssh_proto.boxes().end())};
70 pssh_builder.set_pssh_box_version(0);
71 const std::vector<uint8_t> pssh_data(pssh_proto.data().begin(),
72 pssh_proto.data().end());
73 pssh_builder.set_pssh_data(pssh_data);
74 return {pssh_builder.system_id(), pssh_builder.CreateBox()};
81 int protection_system_flags,
82 FourCC protection_scheme)
84 :
KeySource(protection_system_flags & ~WIDEVINE_PROTECTION_SYSTEM_FLAG,
86 generate_widevine_protection_system_(
89 protection_system_flags == NO_PROTECTION_SYSTEM_FLAG ||
90 protection_system_flags & WIDEVINE_PROTECTION_SYSTEM_FLAG),
91 key_production_thread_(
"KeyProductionThread",
93 base::Unretained(this))),
95 server_url_(server_url),
96 crypto_period_count_(kDefaultCryptoPeriodCount),
97 protection_scheme_(protection_scheme),
98 start_key_production_(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
99 base::WaitableEvent::InitialState::NOT_SIGNALED) {
100 key_production_thread_.Start();
103 WidevineKeySource::~WidevineKeySource() {
106 if (key_production_thread_.HasBeenStarted()) {
109 start_key_production_.Signal();
110 key_production_thread_.Join();
115 const std::string& policy) {
116 base::AutoLock scoped_lock(lock_);
117 common_encryption_request_.reset(
new CommonEncryptionRequest);
118 common_encryption_request_->set_content_id(content_id.data(),
120 common_encryption_request_->set_policy(policy);
121 common_encryption_request_->set_protection_scheme(
122 ToCommonEncryptionProtectionScheme(protection_scheme_));
123 if (enable_entitlement_license_)
124 common_encryption_request_->set_enable_entitlement_license(
true);
126 return FetchKeysInternal(!kEnableKeyRotation, 0,
false);
130 const std::vector<uint8_t>& init_data) {
131 std::vector<uint8_t> pssh_data;
132 uint32_t asset_id = 0;
133 switch (init_data_type) {
134 case EmeInitDataType::CENC: {
135 const std::vector<uint8_t> widevine_system_id(
136 kWidevineSystemId, kWidevineSystemId + arraysize(kWidevineSystemId));
137 std::vector<ProtectionSystemSpecificInfo> protection_systems_info;
139 init_data.data(), init_data.size(), &protection_systems_info)) {
140 return Status(error::PARSER_FAILURE,
"Error parsing the PSSH boxes.");
142 for (
const auto& info : protection_systems_info) {
143 std::unique_ptr<PsshBoxBuilder> pssh_builder =
146 return Status(error::PARSER_FAILURE,
"Error parsing the PSSH box.");
149 if (info.system_id == widevine_system_id) {
150 pssh_data = pssh_builder->pssh_data();
152 }
else if (pssh_data.empty() && !pssh_builder->key_ids().empty()) {
154 GenerateWidevinePsshDataFromKeyIds(pssh_builder->key_ids());
160 if (pssh_data.empty())
161 return Status(error::INVALID_ARGUMENT,
"No supported PSSHs found.");
164 case EmeInitDataType::WEBM: {
165 pssh_data = GenerateWidevinePsshDataFromKeyIds({init_data});
168 case EmeInitDataType::WIDEVINE_CLASSIC:
169 if (init_data.size() <
sizeof(asset_id))
170 return Status(error::INVALID_ARGUMENT,
"Invalid asset id.");
171 asset_id = ntohlFromBuffer(init_data.data());
174 LOG(ERROR) <<
"Init data type " <<
static_cast<int>(init_data_type)
175 <<
" not supported.";
176 return Status(error::INVALID_ARGUMENT,
"Unsupported init data type.");
178 const bool widevine_classic =
179 init_data_type == EmeInitDataType::WIDEVINE_CLASSIC;
180 base::AutoLock scoped_lock(lock_);
181 common_encryption_request_.reset(
new CommonEncryptionRequest);
182 if (widevine_classic) {
183 common_encryption_request_->set_asset_id(asset_id);
185 common_encryption_request_->set_pssh_data(pssh_data.data(),
188 return FetchKeysInternal(!kEnableKeyRotation, 0, widevine_classic);
194 if (encryption_key_map_.find(stream_label) == encryption_key_map_.end()) {
195 return Status(error::INTERNAL_ERROR,
196 "Cannot find key for '" + stream_label +
"'.");
198 *key = *encryption_key_map_[stream_label];
205 for (
const auto& pair : encryption_key_map_) {
206 if (pair.second->key_id == key_id) {
211 return Status(error::INTERNAL_ERROR,
212 "Cannot find key with specified key ID");
216 const std::string& stream_label,
218 DCHECK(key_production_thread_.HasBeenStarted());
221 base::AutoLock scoped_lock(lock_);
222 if (!key_production_started_) {
225 first_crypto_period_index_ =
226 crypto_period_index ? crypto_period_index - 1 : 0;
228 const size_t queue_size = crypto_period_count_ * 10;
231 start_key_production_.Signal();
232 key_production_started_ =
true;
235 return GetKeyInternal(crypto_period_index, stream_label, key);
239 signer_ = std::move(signer);
243 std::unique_ptr<KeyFetcher> key_fetcher) {
244 key_fetcher_ = std::move(key_fetcher);
247 Status WidevineKeySource::GetKeyInternal(uint32_t crypto_period_index,
248 const std::string& stream_label,
253 std::shared_ptr<EncryptionKeyMap> encryption_key_map;
254 Status status = key_pool_->Peek(crypto_period_index, &encryption_key_map,
255 kGetKeyTimeoutInSeconds * 1000);
257 if (status.error_code() == error::STOPPED) {
258 CHECK(!common_encryption_request_status_.ok());
259 return common_encryption_request_status_;
264 if (encryption_key_map->find(stream_label) == encryption_key_map->end()) {
265 return Status(error::INTERNAL_ERROR,
266 "Cannot find key for '" + stream_label +
"'.");
268 *key = *encryption_key_map->at(stream_label);
272 void WidevineKeySource::FetchKeysTask() {
274 start_key_production_.Wait();
275 if (!key_pool_ || key_pool_->Stopped())
278 Status status = FetchKeysInternal(kEnableKeyRotation,
279 first_crypto_period_index_,
281 while (status.ok()) {
282 first_crypto_period_index_ += crypto_period_count_;
283 status = FetchKeysInternal(kEnableKeyRotation,
284 first_crypto_period_index_,
287 common_encryption_request_status_ = status;
291 Status WidevineKeySource::FetchKeysInternal(
bool enable_key_rotation,
292 uint32_t first_crypto_period_index,
293 bool widevine_classic) {
294 CommonEncryptionRequest request;
295 FillRequest(enable_key_rotation, first_crypto_period_index, &request);
298 Status status = GenerateKeyMessage(request, &message);
301 VLOG(1) <<
"Message: " << message;
303 std::string raw_response;
304 int64_t sleep_duration = kFirstRetryDelayMilliseconds;
308 for (
int i = 0; i < kNumTransientErrorRetries; ++i) {
309 status = key_fetcher_->FetchKeys(server_url_, message, &raw_response);
311 VLOG(1) <<
"Retry [" << i <<
"] Response:" << raw_response;
313 bool transient_error =
false;
314 if (ExtractEncryptionKey(enable_key_rotation, widevine_classic,
315 raw_response, &transient_error))
318 if (!transient_error) {
321 "Failed to extract encryption key from '" + raw_response +
"'.");
323 }
else if (status.error_code() != error::TIME_OUT) {
328 if (i != kNumTransientErrorRetries - 1) {
329 base::PlatformThread::Sleep(
330 base::TimeDelta::FromMilliseconds(sleep_duration));
334 return Status(error::SERVER_ERROR,
335 "Failed to recover from server internal error.");
338 void WidevineKeySource::FillRequest(
bool enable_key_rotation,
339 uint32_t first_crypto_period_index,
340 CommonEncryptionRequest* request) {
341 DCHECK(common_encryption_request_);
343 *request = *common_encryption_request_;
345 request->add_tracks()->set_type(
"SD");
346 request->add_tracks()->set_type(
"HD");
347 request->add_tracks()->set_type(
"UHD1");
348 request->add_tracks()->set_type(
"UHD2");
349 request->add_tracks()->set_type(
"AUDIO");
351 request->add_drm_types(ModularDrmType::WIDEVINE);
353 if (enable_key_rotation) {
354 request->set_first_crypto_period_index(first_crypto_period_index);
355 request->set_crypto_period_count(crypto_period_count_);
358 if (!group_id_.empty())
359 request->set_group_id(group_id_.data(), group_id_.size());
362 Status WidevineKeySource::GenerateKeyMessage(
363 const CommonEncryptionRequest& request,
364 std::string* message) {
367 SignedModularDrmRequest signed_request;
368 signed_request.set_request(MessageToJsonString(request));
372 std::string signature;
373 if (!signer_->GenerateSignature(signed_request.request(), &signature))
374 return Status(error::INTERNAL_ERROR,
"Signature generation failed.");
376 signed_request.set_signature(signature);
377 signed_request.set_signer(signer_->signer_name());
380 *message = MessageToJsonString(signed_request);
384 bool WidevineKeySource::ExtractEncryptionKey(
385 bool enable_key_rotation,
386 bool widevine_classic,
387 const std::string& response,
388 bool* transient_error) {
389 DCHECK(transient_error);
390 *transient_error =
false;
392 SignedModularDrmResponse signed_response_proto;
393 if (!JsonStringToMessage(response, &signed_response_proto)) {
394 LOG(ERROR) <<
"Failed to convert JSON to proto: " << response;
398 CommonEncryptionResponse response_proto;
399 if (!JsonStringToMessage(signed_response_proto.response(), &response_proto)) {
400 LOG(ERROR) <<
"Failed to convert JSON to proto: " 401 << signed_response_proto.response();
405 if (response_proto.status() != CommonEncryptionResponse::OK) {
406 LOG(ERROR) <<
"Received non-OK license response: " << response;
410 (response_proto.status() == CommonEncryptionResponse::INTERNAL_ERROR);
414 RCHECK(enable_key_rotation
415 ? response_proto.tracks_size() >= crypto_period_count_
416 : response_proto.tracks_size() >= 1);
418 uint32_t current_crypto_period_index = first_crypto_period_index_;
420 EncryptionKeyMap encryption_key_map;
421 for (
const auto& track : response_proto.tracks()) {
422 VLOG(2) <<
"track " << track.ShortDebugString();
424 if (enable_key_rotation) {
425 if (track.crypto_period_index() != current_crypto_period_index) {
426 if (track.crypto_period_index() != current_crypto_period_index + 1) {
427 LOG(ERROR) <<
"Expecting crypto period index " 428 << current_crypto_period_index <<
" or " 429 << current_crypto_period_index + 1 <<
"; Seen " 430 << track.crypto_period_index();
433 if (!PushToKeyPool(&encryption_key_map))
435 ++current_crypto_period_index;
439 const std::string& stream_label = track.type();
440 RCHECK(encryption_key_map.find(stream_label) == encryption_key_map.end());
442 std::unique_ptr<EncryptionKey> encryption_key(
new EncryptionKey());
443 encryption_key->key.assign(track.key().begin(), track.key().end());
446 if (!widevine_classic) {
447 encryption_key->key_id.assign(track.key_id().begin(),
448 track.key_id().end());
450 if (generate_widevine_protection_system_) {
451 if (track.pssh_size() != 1) {
452 LOG(ERROR) <<
"Expecting one and only one pssh, seeing " 453 << track.pssh_size();
456 encryption_key->key_system_info.push_back(
457 ProtectionSystemInfoFromPsshProto(track.pssh(0)));
460 encryption_key_map[stream_label] = std::move(encryption_key);
463 if (!widevine_classic) {
469 DCHECK(!encryption_key_map.empty());
470 if (!enable_key_rotation) {
472 for (
auto& pair : encryption_key_map)
473 encryption_key_map_[pair.first] = std::move(pair.second);
476 return PushToKeyPool(&encryption_key_map);
479 bool WidevineKeySource::PushToKeyPool(
480 EncryptionKeyMap* encryption_key_map) {
482 DCHECK(encryption_key_map);
483 auto encryption_key_map_shared = std::make_shared<EncryptionKeyMap>();
484 encryption_key_map_shared->swap(*encryption_key_map);
485 Status status = key_pool_->Push(encryption_key_map_shared, kInfiniteTimeout);
487 DCHECK_EQ(error::STOPPED, status.error_code());
All the methods that are virtual are virtual for mocking.