blob: e5bae204c6729df7b28b1e66e184ecb93705a769 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/player/crypto/proxy_decryptor.h"
// WebMediaPlayer.h needs uint8_t defined
// See: https://bugs.webkit.org/show_bug.cgi?id=92031
#include <stdint.h>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/logging.h"
#if defined(_DEBUG)
#include "base/string_number_conversions.h"
#endif
#include "media/base/audio_decoder_config.h"
#include "media/base/decoder_buffer.h"
#include "media/base/decryptor_client.h"
#include "media/base/shell_buffer_factory.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_frame.h"
#include "media/crypto/shell_decryptor_factory.h"
#include "media/player/crypto/key_systems.h"
namespace media {
ProxyDecryptor::ProxyDecryptor(DecryptorClient* decryptor_client)
: client_(decryptor_client), destroy_soon_(false) {}
ProxyDecryptor::~ProxyDecryptor() {}
// TODO(xhwang): Support multiple decryptor notification request (e.g. from
// video and audio decoders). The current implementation is okay for the current
// media pipeline since we initialize audio and video decoders in sequence.
// But ProxyDecryptor should not depend on media pipeline's implementation
// detail.
void ProxyDecryptor::SetDecryptorReadyCB(
const DecryptorReadyCB& decryptor_ready_cb) {
base::AutoLock auto_lock(lock_);
if (destroy_soon_) {
decryptor_ready_cb.Run(NULL);
return;
}
// Cancels the previous decryptor request.
if (decryptor_ready_cb.is_null()) {
if (!decryptor_ready_cb_.is_null())
base::ResetAndReturn(&decryptor_ready_cb_).Run(NULL);
return;
}
// Normal decryptor request.
DCHECK(decryptor_ready_cb_.is_null());
if (decryptor_) {
decryptor_ready_cb.Run(decryptor_.get());
return;
}
decryptor_ready_cb_ = decryptor_ready_cb;
}
void ProxyDecryptor::DestroySoon() {
base::AutoLock auto_lock(lock_);
destroy_soon_ = true;
if (!decryptor_ready_cb_.is_null()) {
base::ResetAndReturn(&decryptor_ready_cb_).Run(NULL);
}
}
bool ProxyDecryptor::GenerateKeyRequest(const std::string& key_system,
const std::string& type,
const uint8* init_data,
int init_data_length) {
// We do not support run-time switching of decryptors. GenerateKeyRequest()
// only creates a new decryptor when |decryptor_| is not initialized.
DVLOG(1) << "GenerateKeyRequest: key_system = " << key_system;
base::AutoLock auto_lock(lock_);
if (!decryptor_) {
decryptor_ = CreateDecryptor(key_system);
if (!decryptor_) {
client_->KeyError(key_system, "", Decryptor::kUnknownError, 0);
return false;
}
}
if (!decryptor_->GenerateKeyRequest(key_system, type, init_data,
init_data_length)) {
decryptor_.reset();
return false;
}
if (!decryptor_ready_cb_.is_null())
base::ResetAndReturn(&decryptor_ready_cb_).Run(decryptor_.get());
return true;
}
void ProxyDecryptor::AddKey(const std::string& key_system,
const uint8* key,
int key_length,
const uint8* init_data,
int init_data_length,
const std::string& session_id) {
DVLOG(1) << "AddKey()";
#if defined(_DEBUG)
std::string hex = base::HexEncode(key, key_length);
DLOG(INFO) << "DRM Key Response: " << hex;
#endif
// WebMediaPlayerImpl ensures GenerateKeyRequest() has been called.
decryptor_->AddKey(key_system, key, key_length, init_data, init_data_length,
session_id);
}
void ProxyDecryptor::CancelKeyRequest(const std::string& key_system,
const std::string& session_id) {
DVLOG(1) << "CancelKeyRequest()";
// WebMediaPlayerImpl ensures GenerateKeyRequest() has been called.
decryptor_->CancelKeyRequest(key_system, session_id);
}
void ProxyDecryptor::RegisterKeyAddedCB(StreamType stream_type,
const KeyAddedCB& key_added_cb) {
NOTREACHED() << "KeyAddedCB should not be registered with ProxyDecryptor.";
}
void ProxyDecryptor::Decrypt(StreamType stream_type,
const scoped_refptr<DecoderBuffer>& encrypted,
const DecryptCB& decrypt_cb) {
NOTREACHED() << "ProxyDecryptor does not support decryption";
}
void ProxyDecryptor::CancelDecrypt(StreamType stream_type) {
base::AutoLock auto_lock(lock_);
if (decryptor_)
decryptor_->CancelDecrypt(stream_type);
}
void ProxyDecryptor::InitializeAudioDecoder(
scoped_ptr<AudioDecoderConfig> config,
const DecoderInitCB& init_cb) {
NOTREACHED() << "ProxyDecryptor does not support audio decoding";
}
void ProxyDecryptor::InitializeVideoDecoder(
scoped_ptr<VideoDecoderConfig> config,
const DecoderInitCB& init_cb) {
NOTREACHED() << "ProxyDecryptor does not support video decoding";
}
void ProxyDecryptor::DecryptAndDecodeAudio(
const scoped_refptr<DecoderBuffer>& encrypted,
const AudioDecodeCB& audio_decode_cb) {
NOTREACHED() << "ProxyDecryptor does not support audio decoding";
}
void ProxyDecryptor::DecryptAndDecodeVideo(
const scoped_refptr<DecoderBuffer>& encrypted,
const VideoDecodeCB& video_decode_cb) {
NOTREACHED() << "ProxyDecryptor does not support video decoding";
}
void ProxyDecryptor::ResetDecoder(StreamType stream_type) {
NOTREACHED() << "ProxyDecryptor does not support audio/video decoding";
}
void ProxyDecryptor::DeinitializeDecoder(StreamType stream_type) {
NOTREACHED() << "ProxyDecryptor does not support audio/video decoding";
}
scoped_ptr<Decryptor> ProxyDecryptor::CreateDecryptor(
const std::string& key_system) {
DCHECK(client_);
// lb_shell doesn't support ppapi or AesDecryptor, so we have our own
// decryptor factory to handle cdm support.
return scoped_ptr<Decryptor>(
ShellDecryptorFactory::Create(key_system, client_));
}
} // namespace media