| Index: webkit/media/crypto/proxy_decryptor.cc
|
| diff --git a/webkit/media/crypto/proxy_decryptor.cc b/webkit/media/crypto/proxy_decryptor.cc
|
| index 0b786552b577ea199d042517195a2a20ffb05cb1..c71c6bdea93ad133f450585892b27626756984ca 100644
|
| --- a/webkit/media/crypto/proxy_decryptor.cc
|
| +++ b/webkit/media/crypto/proxy_decryptor.cc
|
| @@ -4,7 +4,12 @@
|
|
|
| #include "webkit/media/crypto/proxy_decryptor.h"
|
|
|
| +#include <algorithm>
|
| +
|
| +#include "base/bind.h"
|
| +#include "base/location.h"
|
| #include "base/logging.h"
|
| +#include "base/message_loop_proxy.h"
|
| #include "media/base/decoder_buffer.h"
|
| #include "media/base/decryptor_client.h"
|
| #include "media/crypto/aes_decryptor.h"
|
| @@ -41,13 +46,27 @@ static scoped_refptr<webkit::ppapi::PluginInstance> CreatePluginInstance(
|
| return ppapi_plugin->instance();
|
| }
|
|
|
| +// TODO(xhwang): Simplify this function. This is mostly caused by the fact that
|
| +// we need to copy a scoped_array<uint8>.
|
| +static void FireNeedKey(media::DecryptorClient* client,
|
| + const scoped_refptr<media::DecoderBuffer>& encrypted) {
|
| + DCHECK(client);
|
| + DCHECK(encrypted);
|
| + DCHECK(encrypted->GetDecryptConfig());
|
| + std::string key_id = encrypted->GetDecryptConfig()->key_id();
|
| + scoped_array<uint8> key_id_array(new uint8[key_id.size()]);
|
| + memcpy(key_id_array.get(), key_id.data(), key_id.size());
|
| + client->NeedKey("", "", key_id_array.Pass(), key_id.size());
|
| +}
|
| +
|
| ProxyDecryptor::ProxyDecryptor(
|
| media::DecryptorClient* decryptor_client,
|
| WebKit::WebMediaPlayerClient* web_media_player_client,
|
| WebKit::WebFrame* web_frame)
|
| : client_(decryptor_client),
|
| web_media_player_client_(web_media_player_client),
|
| - web_frame_(web_frame) {
|
| + web_frame_(web_frame),
|
| + stopped_(false) {
|
| }
|
|
|
| ProxyDecryptor::~ProxyDecryptor() {
|
| @@ -58,12 +77,12 @@ void ProxyDecryptor::GenerateKeyRequest(const std::string& key_system,
|
| 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;
|
| if (!decryptor_.get()) {
|
| base::AutoLock auto_lock(lock_);
|
| decryptor_ = CreateDecryptor(key_system);
|
| }
|
|
|
| - DCHECK(client_);
|
| if (!decryptor_.get()) {
|
| client_->KeyError(key_system, "", media::Decryptor::kUnknownError, 0);
|
| return;
|
| @@ -78,14 +97,32 @@ void ProxyDecryptor::AddKey(const std::string& key_system,
|
| const uint8* init_data,
|
| int init_data_length,
|
| const std::string& session_id) {
|
| + DVLOG(1) << "AddKey()";
|
| +
|
| // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called.
|
| DCHECK(decryptor_.get());
|
| decryptor_->AddKey(key_system, key, key_length, init_data, init_data_length,
|
| session_id);
|
| +
|
| + std::vector<base::Closure> closures_to_run;
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + std::swap(pending_decrypt_closures_, closures_to_run);
|
| + }
|
| +
|
| + // Fire all pending callbacks here because only the |decryptor_| knows if the
|
| + // pending buffers can be decrypted or not.
|
| + for (std::vector<base::Closure>::iterator iter = closures_to_run.begin();
|
| + iter != closures_to_run.end();
|
| + ++iter) {
|
| + iter->Run();
|
| + }
|
| }
|
|
|
| void ProxyDecryptor::CancelKeyRequest(const std::string& key_system,
|
| const std::string& session_id) {
|
| + DVLOG(1) << "CancelKeyRequest()";
|
| +
|
| // WebMediaPlayerImpl ensures GenerateKeyRequest() has been called.
|
| DCHECK(decryptor_.get());
|
| decryptor_->CancelKeyRequest(key_system, session_id);
|
| @@ -98,15 +135,49 @@ void ProxyDecryptor::Decrypt(
|
| media::Decryptor* decryptor = NULL;
|
| {
|
| base::AutoLock auto_lock(lock_);
|
| + if (stopped_) {
|
| + DVLOG(1) << "Decrypt(): fire decrypt callbacks with kError.";
|
| + decrypt_cb.Run(kError, NULL);
|
| + return;
|
| + }
|
| decryptor = decryptor_.get();
|
| + if (!decryptor) {
|
| + DVLOG(1) << "ProxyDecryptor::Decrypt(): decryptor not initialized.";
|
| + pending_decrypt_closures_.push_back(
|
| + base::Bind(&ProxyDecryptor::DecryptOnMessageLoop,
|
| + base::Unretained(this),
|
| + base::MessageLoopProxy::current(), encrypted,
|
| + decrypt_cb));
|
| + // TODO(xhwang): The same NeedKey may be fired here and multiple times in
|
| + // OnBufferDecrypted(). While the spec says only one NeedKey should be
|
| + // fired. Leave them as is since the spec about this may change.
|
| + FireNeedKey(client_, encrypted);
|
| + return;
|
| + }
|
| }
|
| - if (!decryptor) {
|
| - DVLOG(1) << "ProxyDecryptor::Decrypt(): decryptor not initialized.";
|
| - decrypt_cb.Run(kError, NULL);
|
| - return;
|
| +
|
| + decryptor->Decrypt(encrypted, base::Bind(
|
| + &ProxyDecryptor::OnBufferDecrypted, base::Unretained(this),
|
| + base::MessageLoopProxy::current(), encrypted, decrypt_cb));
|
| +}
|
| +
|
| +void ProxyDecryptor::Stop() {
|
| + DVLOG(1) << "AddKey()";
|
| +
|
| + std::vector<base::Closure> closures_to_run;
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + if (decryptor_.get())
|
| + decryptor_->Stop();
|
| + stopped_ = true;
|
| + std::swap(pending_decrypt_closures_, closures_to_run);
|
| }
|
|
|
| - decryptor->Decrypt(encrypted, decrypt_cb);
|
| + for (std::vector<base::Closure>::iterator iter = closures_to_run.begin();
|
| + iter != closures_to_run.end();
|
| + ++iter) {
|
| + iter->Run();
|
| + }
|
| }
|
|
|
| scoped_ptr<media::Decryptor> ProxyDecryptor::CreatePpapiDecryptor(
|
| @@ -141,4 +212,62 @@ scoped_ptr<media::Decryptor> ProxyDecryptor::CreateDecryptor(
|
| return CreatePpapiDecryptor(key_system);
|
| }
|
|
|
| +void ProxyDecryptor::DecryptOnMessageLoop(
|
| + const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
|
| + const scoped_refptr<media::DecoderBuffer>& encrypted,
|
| + const media::Decryptor::DecryptCB& decrypt_cb) {
|
| + DCHECK(decryptor_.get());
|
| +
|
| + if (!message_loop_proxy->BelongsToCurrentThread()) {
|
| + message_loop_proxy->PostTask(FROM_HERE, base::Bind(
|
| + &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this),
|
| + message_loop_proxy, encrypted, decrypt_cb));
|
| + return;
|
| + }
|
| +
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + if (stopped_) {
|
| + DVLOG(1) << "DecryptOnMessageLoop(): fire decrypt callbacks with kError.";
|
| + decrypt_cb.Run(kError, NULL);
|
| + return;
|
| + }
|
| + }
|
| +
|
| + decryptor_->Decrypt(encrypted, base::Bind(
|
| + &ProxyDecryptor::OnBufferDecrypted, base::Unretained(this),
|
| + message_loop_proxy, encrypted, decrypt_cb));
|
| +}
|
| +
|
| +void ProxyDecryptor::OnBufferDecrypted(
|
| + const scoped_refptr<base::MessageLoopProxy>& message_loop_proxy,
|
| + const scoped_refptr<media::DecoderBuffer>& encrypted,
|
| + const media::Decryptor::DecryptCB& decrypt_cb,
|
| + media::Decryptor::DecryptStatus status,
|
| + const scoped_refptr<media::DecoderBuffer>& decrypted) {
|
| + if (status == media::Decryptor::kSuccess ||
|
| + status == media::Decryptor::kError) {
|
| + decrypt_cb.Run(status, decrypted);
|
| + return;
|
| + }
|
| +
|
| + DCHECK_EQ(status, media::Decryptor::kNoKey);
|
| + DVLOG(1) << "OnBufferDecrypted(): kNoKey fired";
|
| + {
|
| + base::AutoLock auto_lock(lock_);
|
| + if (stopped_) {
|
| + DVLOG(1) << "OnBufferDecrypted(): fire decrypt callbacks with kError.";
|
| + decrypt_cb.Run(kError, NULL);
|
| + return;
|
| + }
|
| + pending_decrypt_closures_.push_back(base::Bind(
|
| + &ProxyDecryptor::DecryptOnMessageLoop, base::Unretained(this),
|
| + message_loop_proxy, encrypted, decrypt_cb));
|
| + }
|
| + // TODO(xhwang): The same NeedKey may be fired multiple times here and also
|
| + // in Decrypt(). While the spec says only one NeedKey should be fired. Leave
|
| + // them as is since the spec about this may change.
|
| + FireNeedKey(client_, encrypted);
|
| +}
|
| +
|
| } // namespace webkit_media
|
|
|