Bug 1081755 - Implement MediaKeySession keyschange event. r=edwin,bz

This commit is contained in:
Chris Pearce 2014-10-15 21:33:18 +13:00
parent ae49c5abce
commit 67088a0aad
11 changed files with 131 additions and 9 deletions

View File

@ -496,6 +496,7 @@ GK_ATOM(keepcurrentinview, "keepcurrentinview")
GK_ATOM(keepobjectsalive, "keepobjectsalive")
GK_ATOM(key, "key")
GK_ATOM(keycode, "keycode")
GK_ATOM(keyschange, "keyschange")
GK_ATOM(keydown, "keydown")
GK_ATOM(keygen, "keygen")
GK_ATOM(keypress, "keypress")

View File

@ -272,8 +272,18 @@ CDMCallbackProxy::KeyIdUsable(const nsCString& aSessionId,
{
MOZ_ASSERT(mProxy->IsOnGMPThread());
CDMCaps::AutoLock caps(mProxy->Capabilites());
caps.SetKeyUsable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
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
@ -282,8 +292,18 @@ CDMCallbackProxy::KeyIdNotUsable(const nsCString& aSessionId,
{
MOZ_ASSERT(mProxy->IsOnGMPThread());
CDMCaps::AutoLock caps(mProxy->Capabilites());
caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
bool keysChange = false;
{
CDMCaps::AutoLock caps(mProxy->Capabilites());
keysChange = caps.SetKeyUnusable(aKeyId, NS_ConvertUTF8toUTF16(aSessionId));
}
if (keysChange) {
nsRefPtr<nsIRunnable> task;
task = NS_NewRunnableMethodWithArg<nsString>(mProxy,
&CDMProxy::OnKeysChange,
NS_ConvertUTF8toUTF16(aSessionId));
NS_DispatchToMainThread(task);
}
}
void

View File

@ -88,12 +88,16 @@ CDMCaps::AutoLock::IsKeyUsable(const CencKeyId& aKeyId)
return false;
}
void
bool
CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
const nsString& aSessionId)
{
mData.mMonitor.AssertCurrentThreadOwns();
mData.mUsableKeyIds.AppendElement(UsableKey(aKeyId, aSessionId));
UsableKey key(aKeyId, aSessionId);
if (mData.mUsableKeyIds.Contains(key)) {
return false;
}
mData.mUsableKeyIds.AppendElement(key);
auto& waiters = mData.mWaitForKeys;
size_t i = 0;
while (i < waiters.Length()) {
@ -110,13 +114,18 @@ CDMCaps::AutoLock::SetKeyUsable(const CencKeyId& aKeyId,
i++;
}
}
return true;
}
void
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 &&
@ -125,6 +134,7 @@ CDMCaps::AutoLock::SetKeyUnusable(const CencKeyId& aKeyId,
break;
}
}
return true;
}
void

View File

@ -38,8 +38,13 @@ public:
bool IsKeyUsable(const CencKeyId& aKeyId);
void SetKeyUsable(const CencKeyId& aKeyId, const nsString& aSessionId);
void SetKeyUnusable(const CencKeyId& aKeyId, const nsString& aSessionId);
// 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);
void DropKeysForSession(const nsAString& aSessionId);
void GetUsableKeysForSession(const nsAString& aSessionId,
@ -99,6 +104,11 @@ private:
: mId(aOther.mId)
, mSessionId(aOther.mSessionId)
{}
bool operator==(const UsableKey& aOther) const {
return mId == aOther.mId &&
mSessionId == aOther.mSessionId;
};
CencKeyId mId;
nsString mSessionId;
};

View File

@ -425,6 +425,19 @@ CDMProxy::OnSessionMessage(const nsAString& aSessionId,
}
}
void
CDMProxy::OnKeysChange(const nsAString& aSessionId)
{
MOZ_ASSERT(NS_IsMainThread());
if (mKeys.IsNull()) {
return;
}
nsRefPtr<dom::MediaKeySession> session(mKeys->GetSession(aSessionId));
if (session) {
session->DispatchKeysChange();
}
}
void
CDMProxy::OnExpirationChange(const nsAString& aSessionId,
GMPTimestamp aExpiryTime)

View File

@ -162,6 +162,9 @@ public:
CDMCaps& Capabilites();
// Main thread only.
void OnKeysChange(const nsAString& aSessionId);
#ifdef DEBUG
bool IsOnGMPThread();
#endif

View File

@ -13,6 +13,7 @@
#include "mozilla/CDMProxy.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/Move.h"
#include "nsContentUtils.h"
namespace mozilla {
namespace dom {
@ -284,5 +285,24 @@ MediaKeySession::DispatchKeyError(uint32_t aSystemCode)
asyncDispatcher->PostDOMEvent();
}
void
MediaKeySession::DispatchKeysChange()
{
if (IsClosed()) {
return;
}
DebugOnly<nsresult> rv =
nsContentUtils::DispatchTrustedEvent(mKeys->GetOwnerDoc(),
this,
NS_LITERAL_STRING("keyschange"),
false,
false);
#ifdef DEBUG
if (NS_FAILED(rv)) {
NS_WARNING("Failed to dispatch keyschange event");
}
#endif
}
} // namespace dom
} // namespace mozilla

View File

@ -84,6 +84,8 @@ public:
void DispatchKeyError(uint32_t system_code);
void DispatchKeysChange();
void OnClosed();
bool IsClosed() const;

View File

@ -591,5 +591,11 @@ CopyArrayBufferViewOrArrayBufferData(const ArrayBufferViewOrArrayBuffer& aBuffer
return true;
}
nsIDocument*
MediaKeys::GetOwnerDoc() const
{
return mElement ? mElement->OwnerDoc() : nullptr;
}
} // namespace dom
} // namespace mozilla

View File

@ -122,6 +122,10 @@ public:
// was created, failure otherwise.
nsresult CheckPrincipals();
// Returns a pointer to the bound media element's owner doc.
// If we're not bound, this returns null.
nsIDocument* GetOwnerDoc() const;
private:
static bool IsTypeSupported(const nsAString& aKeySystem,

View File

@ -153,6 +153,25 @@ function PlayTest(test, elem)
elem.play();
}
function KeysChangeFunc(session, keys) {
session.keyIdsReceived = [];
for (var keyid in keys) {
info("Set " + keyid + " to false in session.keyIdsReceived");
session.keyIdsReceived[keyid] = false;
}
return function(ev) {
var session = ev.target;
session.gotKeysChanged = true;
session.getUsableKeyIds().then(function(keyIds) {
for (var k = 0; k < keyIds.length; k++) {
var kid = Base64ToHex(window.btoa(ArrayBufferToString(keyIds[k])));
ok(kid in session.keyIdsReceived, "session.keyIdsReceived contained " + kid + " as expected.");
session.keyIdsReceived[kid] = true;
}
}, bail("Failed to get keyIds"));
}
}
function startTest(test, token)
{
manager.started(test._token);
@ -170,6 +189,7 @@ function startTest(test, token)
MediaKeys.create(KEYSYSTEM_TYPE).then(function(mediaKeys) {
info(token + " created MediaKeys object ok");
mediaKeys.sessions = [];
return v.setMediaKeys(mediaKeys);
}, bail("failed to create MediaKeys object")).then(function() {
info(token + " set MediaKeys on <video> element ok");
@ -178,6 +198,8 @@ function startTest(test, token)
"MediaKeys should still support keysystem after CDM created...");
var session = v.mediaKeys.createSession(test.sessionType);
v.mediaKeys.sessions.push(session);
session.addEventListener("keyschange", KeysChangeFunc(session, test.keys), false);
session.addEventListener("message", UpdateSessionFunc(test));
session.generateRequest(ev.initDataType, ev.initData).then(function() {
}, bail(token + " Failed to initialise MediaKeySession"));
@ -198,6 +220,17 @@ function startTest(test, token)
token + " Duration of video should be corrrect");
ok(Math.abs(test.duration - v.currentTime) < 0.1,
token + " Current time should be same as duration");
// Verify all sessions had all keys went sent the to the CDM usable, and thus
// that we received keyschange event(s).
var sessions = v.mediaKeys.sessions;
is(sessions.length, 1, "should have 1 session");
for (var i = 0; i < sessions.length; i++) {
var session = sessions[i];
ok(session.gotKeysChanged, "Should have received at least one keychange event");
for (var kid in session.keyIdsReceived) {
ok(session.keyIdsReceived[kid], "key with id " + kid + " was usable as expected");
}
}
});
v.addEventListener("error", bail(token + " got error event"));