Bug 1121332. Part 1 - add media key status to gmp-api. r=cpearce.

This commit is contained in:
JW Wang 2015-01-31 13:22:12 +13:00
Родитель 9a7d224e66
Коммит c1dd9140a5
16 изменённых файлов: 114 добавлений и 154 удалений

Просмотреть файл

@ -267,35 +267,18 @@ CDMCallbackProxy::SessionError(const nsCString& aSessionId,
}
void
CDMCallbackProxy::KeyIdUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId)
CDMCallbackProxy::KeyStatusChanged(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId,
GMPMediaKeyStatus aStatus)
{
MOZ_ASSERT(mProxy->IsOnGMPThread());
bool keysChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
keysChange = caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
}
if (keysChange) {
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
&CDMProxy::OnKeysChange,
NS_ConvertUTF8toUTF16(aSessionId));
NS_DispatchToMainThread(task);
}
}
void
CDMCallbackProxy::KeyIdNotUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId)
{
MOZ_ASSERT(mProxy->IsOnGMPThread());
bool keysChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
keysChange = caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
keysChange = caps.SetKeyStatus(aKeyId,
NS_ConvertUTF8toUTF16(aSessionId),
aStatus);
}
if (keysChange) {
nsRefPtr<nsIRunnable> task;

Просмотреть файл

@ -43,11 +43,9 @@ public:
uint32_t aSystemCode,
const nsCString& aMessage) MOZ_OVERRIDE;
virtual void KeyIdUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE;
virtual void KeyIdNotUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE;
virtual void KeyStatusChanged(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId,
GMPMediaKeyStatus aStatus) MOZ_OVERRIDE;
virtual void SetCaps(uint64_t aCaps) MOZ_OVERRIDE;

Просмотреть файл

@ -5,7 +5,6 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "CDMCaps.h"
#include "gmp-decryption.h"
#include "EMELog.h"
#include "nsThreadUtils.h"
#include "SamplesWaitingForKey.h"
@ -80,9 +79,9 @@ bool
CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
{
mData.mMonitor.AssertCurrentThreadOwns();
const auto& keys = mData.mUsableKeyIds;
const auto& keys = mData.mKeyStatuses;
for (size_t i = 0; i < keys.Length(); i++) {
if (keys[i].mId == aKeyId) {
if (keys[i].mId == aKeyId && keys[i].mStatus == kGMPUsable) {
return true;
}
}
@ -90,15 +89,32 @@ CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
}
bool
CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
const nsString& aSessionId)
CDMCaps::AutoLock::SetKeyStatus(const CencKeyId& aKeyId,
const nsString& aSessionId,
GMPMediaKeyStatus aStatus)
{
mData.mMonitor.AssertCurrentThreadOwns();
UsableKey key(aKeyId, aSessionId);
if (mData.mUsableKeyIds.Contains(key)) {
return false;
KeyStatus key(aKeyId, aSessionId, aStatus);
auto index = mData.mKeyStatuses.IndexOf(key);
if (aStatus == kGMPUnknown) {
// Return true if the element is found to notify key changes.
return mData.mKeyStatuses.RemoveElement(key);
}
mData.mUsableKeyIds.AppendElement(key);
if (index != mData.mKeyStatuses.NoIndex) {
if (mData.mKeyStatuses[index].mStatus == aStatus) {
return false;
}
mData.mKeyStatuses[index].mStatus = aStatus;
} else {
mData.mKeyStatuses.AppendElement(key);
}
if (aStatus != kGMPUsable) {
return true;
}
auto& waiters = mData.mWaitForKeys;
size_t i = 0;
while (i < waiters.Length()) {
@ -113,26 +129,6 @@ CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
return true;
}
bool
CDMCaps::AutoLock::SetKeyUnusable(const CencKeyId& aKeyId,
const nsString& aSessionId)
{
mData.mMonitor.AssertCurrentThreadOwns();
UsableKey key(aKeyId, aSessionId);
if (!mData.mUsableKeyIds.Contains(key)) {
return false;
}
auto& keys = mData.mUsableKeyIds;
for (size_t i = 0; i < keys.Length(); i++) {
if (keys[i].mId == aKeyId &&
keys[i].mSessionId == aSessionId) {
keys.RemoveElementAt(i);
break;
}
}
return true;
}
void
CDMCaps::AutoLock::NotifyWhenKeyIdUsable(const CencKeyId& aKey,
SamplesWaitingForKey* aListener)
@ -178,12 +174,12 @@ void
CDMCaps::AutoLock::GetUsableKeysForSession(const nsAString& aSessionId,
nsTArray<CencKeyId>& aOutKeyIds)
{
for (size_t i = 0; i < mData.mUsableKeyIds.Length(); i++) {
const auto& key = mData.mUsableKeyIds[i];
if (key.mSessionId.Equals(aSessionId)) {
for (size_t i = 0; i < mData.mKeyStatuses.Length(); i++) {
const auto& key = mData.mKeyStatuses[i];
if (key.mSessionId.Equals(aSessionId) && key.mStatus == kGMPUsable) {
aOutKeyIds.AppendElement(key.mId);
}
}
}
} // namespace mozilla
} // namespace mozilla

Просмотреть файл

@ -14,6 +14,7 @@
#include "nsTArray.h"
#include "mozilla/Attributes.h"
#include "SamplesWaitingForKey.h"
#include "gmp-decryption.h"
namespace mozilla {
@ -37,13 +38,9 @@ public:
bool IsKeyUsable(const CencKeyId& aKeyId);
// Returns true if setting this key usable results in the usable keys
// changing for this session, i.e. the key was not previously marked usable.
bool SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
// Returns true if setting this key unusable results in the usable keys
// changing for this session, i.e. the key was previously marked usable.
bool SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
// Returns true if key status changed,
// i.e. the key status changed from usable to expired.
bool SetKeyStatus(const CencKeyId& aKeyId, const nsString& aSessionId, GMPMediaKeyStatus aStatus);
void GetUsableKeysForSession(const nsAString& aSessionId,
nsTArray<CencKeyId>& aOutKeyIds);
@ -85,25 +82,29 @@ private:
Monitor mMonitor;
struct UsableKey {
UsableKey(const CencKeyId& aId,
const nsString& aSessionId)
struct KeyStatus {
KeyStatus(const CencKeyId& aId,
const nsString& aSessionId,
GMPMediaKeyStatus aStatus)
: mId(aId)
, mSessionId(aSessionId)
, mStatus(aStatus)
{}
UsableKey(const UsableKey& aOther)
KeyStatus(const KeyStatus& aOther)
: mId(aOther.mId)
, mSessionId(aOther.mSessionId)
, mStatus(aOther.mStatus)
{}
bool operator==(const UsableKey& aOther) const {
bool operator==(const KeyStatus& aOther) const {
return mId == aOther.mId &&
mSessionId == aOther.mSessionId;
};
CencKeyId mId;
nsString mSessionId;
GMPMediaKeyStatus mStatus;
};
nsTArray<UsableKey> mUsableKeyIds;
nsTArray<KeyStatus> mKeyStatuses;
nsTArray<WaitForKeys> mWaitForKeys;

Просмотреть файл

@ -1,5 +1,5 @@
Name: fake
Description: Fake GMP Plugin
Version: 1.0
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v4[fake]
APIs: encode-video[h264], decode-video[h264], eme-decrypt-v5[fake]
Libraries: dxva2.dll

Просмотреть файл

@ -126,27 +126,17 @@ GMPDecryptorChild::SessionError(const char* aSessionId,
}
void
GMPDecryptorChild::KeyIdUsable(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength)
GMPDecryptorChild::KeyStatusChanged(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength,
GMPMediaKeyStatus aStatus)
{
nsAutoTArray<uint8_t, 16> kid;
kid.AppendElements(aKeyId, aKeyIdLength);
CALL_ON_GMP_THREAD(SendKeyIdUsable,
nsAutoCString(aSessionId, aSessionIdLength), kid);
}
void
GMPDecryptorChild::KeyIdNotUsable(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength)
{
nsAutoTArray<uint8_t, 16> kid;
kid.AppendElements(aKeyId, aKeyIdLength);
CALL_ON_GMP_THREAD(SendKeyIdNotUsable,
nsAutoCString(aSessionId, aSessionIdLength), kid);
CALL_ON_GMP_THREAD(SendKeyStatusChanged,
nsAutoCString(aSessionId, aSessionIdLength), kid,
aStatus);
}
void

Просмотреть файл

@ -63,15 +63,11 @@ public:
const char* aMessage,
uint32_t aMessageLength) MOZ_OVERRIDE;
virtual void KeyIdUsable(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength) MOZ_OVERRIDE;
virtual void KeyIdNotUsable(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength) MOZ_OVERRIDE;
virtual void KeyStatusChanged(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength,
GMPMediaKeyStatus aStatus) MOZ_OVERRIDE;
virtual void SetCapabilities(uint64_t aCaps) MOZ_OVERRIDE;

Просмотреть файл

@ -265,26 +265,15 @@ GMPDecryptorParent::RecvSessionError(const nsCString& aSessionId,
}
bool
GMPDecryptorParent::RecvKeyIdUsable(const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aKeyId)
GMPDecryptorParent::RecvKeyStatusChanged(const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aKeyId,
const GMPMediaKeyStatus& aStatus)
{
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return false;
}
mCallback->KeyIdUsable(aSessionId, aKeyId);
return true;
}
bool
GMPDecryptorParent::RecvKeyIdNotUsable(const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aKeyId)
{
if (!mIsOpen) {
NS_WARNING("Trying to use a dead GMP decrypter!");
return false;
}
mCallback->KeyIdNotUsable(aSessionId, aKeyId);
mCallback->KeyStatusChanged(aSessionId, aKeyId, aStatus);
return true;
}

Просмотреть файл

@ -91,11 +91,9 @@ private:
const uint32_t& aSystemCode,
const nsCString& aMessage) MOZ_OVERRIDE;
virtual bool RecvKeyIdUsable(const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aKeyId) MOZ_OVERRIDE;
virtual bool RecvKeyIdNotUsable(const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aKeyId) MOZ_OVERRIDE;
virtual bool RecvKeyStatusChanged(const nsCString& aSessionId,
InfallibleTArray<uint8_t>&& aKeyId,
const GMPMediaKeyStatus& aStatus) MOZ_OVERRIDE;
virtual bool RecvDecrypted(const uint32_t& aId,
const GMPErr& aErr,

Просмотреть файл

@ -44,11 +44,9 @@ public:
uint32_t aSystemCode,
const nsCString& aMessage) = 0;
virtual void KeyIdUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId) = 0;
virtual void KeyIdNotUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId) = 0;
virtual void KeyStatusChanged(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId,
GMPMediaKeyStatus aStatus) = 0;
virtual void SetCaps(uint64_t aCaps) = 0;

Просмотреть файл

@ -60,6 +60,13 @@ struct ParamTraits<GMPSessionMessageType>
kGMPMessageInvalid>
{};
template <>
struct ParamTraits<GMPMediaKeyStatus>
: public ContiguousEnumSerializer<GMPMediaKeyStatus,
kGMPUsable,
kGMPMediaKeyStatusInvalid>
{};
template <>
struct ParamTraits<GMPSessionType>
: public ContiguousEnumSerializer<GMPSessionType,

Просмотреть файл

@ -7,6 +7,7 @@ include protocol PGMP;
include GMPTypes;
using GMPSessionMessageType from "gmp-decryption.h";
using GMPMediaKeyStatus from "gmp-decryption.h";
using GMPSessionType from "gmp-decryption.h";
using GMPDOMException from "gmp-decryption.h";
using GMPErr from "gmp-errors.h";
@ -77,12 +78,11 @@ parent:
uint32_t aSystemCode,
nsCString aMessage);
KeyIdUsable(nsCString aSessionId, uint8_t[] aKey);
KeyStatusChanged(nsCString aSessionId, uint8_t[] aKey,
GMPMediaKeyStatus aStatus);
SetCaps(uint64_t aCaps);
KeyIdNotUsable(nsCString aSessionId,uint8_t[] aKey);
Decrypted(uint32_t aId, GMPErr aResult, uint8_t[] aBuffer);
};

Просмотреть файл

@ -76,6 +76,14 @@ enum GMPSessionMessageType {
kGMPMessageInvalid = 4 // Must always be last.
};
enum GMPMediaKeyStatus {
kGMPUsable = 0,
kGMPExpired = 1,
kGMPOutputNotAllowed = 2,
kGMPUnknown = 3,
kGMPMediaKeyStatusInvalid = 4 // Must always be last.
};
// Time in milliseconds, as offset from epoch, 1 Jan 1970.
typedef int64_t GMPTimestamp;
@ -173,20 +181,14 @@ public:
const char* aMessage,
uint32_t aMessageLength) = 0;
// Marks a key as usable. Gecko will not call into the CDM to decrypt
// Notifies the status of a key. Gecko will not call into the CDM to decrypt
// or decode content encrypted with a key unless the CDM has marked it
// usable first. So a CDM *MUST* mark its usable keys as usable!
virtual void KeyIdUsable(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength) = 0;
// Marks a key as no longer usable.
// Note: Keys are assumed to be not usable when a session is closed or removed.
virtual void KeyIdNotUsable(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength) = 0;
virtual void KeyStatusChanged(const char* aSessionId,
uint32_t aSessionIdLength,
const uint8_t* aKeyId,
uint32_t aKeyIdLength,
GMPMediaKeyStatus aStatus) = 0;
// The CDM must report its capabilites of this CDM. aCaps should be a
// logical OR of the GMP_EME_CAP_* flags. The CDM *MUST* call this
@ -220,7 +222,7 @@ enum GMPSessionType {
kGMPSessionInvalid = 2 // Must always be last.
};
#define GMP_API_DECRYPTOR "eme-decrypt-v4"
#define GMP_API_DECRYPTOR "eme-decrypt-v5"
// API exposed by plugin library to manage decryption sessions.
// When the Host requests this by calling GMPGetAPIFunc().

Просмотреть файл

@ -1116,10 +1116,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback
nsresult aException,
uint32_t aSystemCode,
const nsCString& aMessage) MOZ_OVERRIDE {}
virtual void KeyIdUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE { }
virtual void KeyIdNotUsable(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId) MOZ_OVERRIDE {}
virtual void KeyStatusChanged(const nsCString& aSessionId,
const nsTArray<uint8_t>& aKeyId,
GMPMediaKeyStatus aStatus) MOZ_OVERRIDE { }
virtual void SetCaps(uint64_t aCaps) MOZ_OVERRIDE {}
virtual void Decrypted(uint32_t aId,
GMPErr aResult,

Просмотреть файл

@ -167,8 +167,9 @@ ClearKeySessionManager::PersistentSessionDataLoaded(GMPErr aStatus,
mDecryptionManager->ExpectKeyId(keyId);
mDecryptionManager->InitKey(keyId, key);
mKeyIds.insert(key);
mCallback->KeyIdUsable(&aSessionId[0], aSessionId.size(),
&keyId[0], keyId.size());
mCallback->KeyStatusChanged(&aSessionId[0], aSessionId.size(),
&keyId[0], keyId.size(),
kGMPUsable);
}
mCallback->ResolveLoadSessionPromise(aPromiseId, true);
@ -203,8 +204,9 @@ ClearKeySessionManager::UpdateSession(uint32_t aPromiseId,
for (auto it = keyPairs.begin(); it != keyPairs.end(); it++) {
mDecryptionManager->InitKey(it->mKeyId, it->mKey);
mKeyIds.insert(it->mKeyId);
mCallback->KeyIdUsable(aSessionId, aSessionIdLength,
&it->mKeyId[0], it->mKeyId.size());
mCallback->KeyStatusChanged(aSessionId, aSessionIdLength,
&it->mKeyId[0], it->mKeyId.size(),
kGMPUsable);
}
if (session->Type() != kGMPPersistentSession) {
@ -279,8 +281,9 @@ ClearKeySessionManager::ClearInMemorySessionData(ClearKeySession* aSession)
mDecryptionManager->ReleaseKeyId(*it);
const string& sessionId = aSession->Id();
mCallback->KeyIdNotUsable(&sessionId[0], sessionId.size(),
&(*it)[0], it->size());
mCallback->KeyStatusChanged(&sessionId[0], sessionId.size(),
&(*it)[0], it->size(),
kGMPUnknown);
}
mSessions.erase(aSession->Id());

Просмотреть файл

@ -1,4 +1,4 @@
Name: clearkey
Description: ClearKey decrypt-only GMP plugin
Version: 0.1
APIs: eme-decrypt-v4[org.w3.clearkey]
APIs: eme-decrypt-v5[org.w3.clearkey]