Bug 1121332. Part 4 - implement MediaKeySession.keyStatuses and remove MediaKeySession.getUsableKeyIds. r=bz.
authorJW Wang <jwwang@mozilla.com>
Sat, 31 Jan 2015 13:23:07 +1300
changeset 226869 455407ddfe431d116391bcd15f97d573de82c5e4
parent 226868 b3db757e1445f1df425addb0e04ef1fe55ed2882
child 226870 cc87f9a19451965e69d562d9252ba61835bf0c33
push id28207
push userphilringnalda@gmail.com
push dateSat, 31 Jan 2015 16:54:13 +0000
treeherdermozilla-central@6f9b69780bf4 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs1121332
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1121332. Part 4 - implement MediaKeySession.keyStatuses and remove MediaKeySession.getUsableKeyIds. r=bz.
dom/bindings/Bindings.conf
dom/media/eme/MediaKeySession.cpp
dom/media/eme/MediaKeySession.h
dom/media/eme/MediaKeyStatusMap.cpp
dom/media/eme/MediaKeyStatusMap.h
dom/media/eme/moz.build
dom/webidl/MediaKeySession.webidl
dom/webidl/MediaKeyStatusMap.webidl
dom/webidl/moz.build
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -628,16 +628,20 @@ DOMInterfaces = {
     'nativeType': 'nsLocation',
 },
 
 'MediaList': {
     'nativeType': 'nsMediaList',
     'headerFile': 'nsIMediaList.h',
 },
 
+'MediaKeyStatusMap' : {
+    'implicitJSContext': [ 'size', 'get', 'has' ]
+},
+
 'MediaStream': {
     'headerFile': 'DOMMediaStream.h',
     'nativeType': 'mozilla::DOMMediaStream'
 },
 
 'MediaStreamAudioDestinationNode': {
     'binaryNames': { 'stream': 'DOMStream' }
 },
--- a/dom/media/eme/MediaKeySession.cpp
+++ b/dom/media/eme/MediaKeySession.cpp
@@ -4,29 +4,31 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/dom/HTMLMediaElement.h"
 #include "mozilla/dom/MediaKeySession.h"
 #include "mozilla/dom/MediaKeyError.h"
 #include "mozilla/dom/MediaKeyMessageEvent.h"
 #include "mozilla/dom/MediaEncryptedEvent.h"
+#include "mozilla/dom/MediaKeyStatusMap.h"
 #include "nsCycleCollectionParticipant.h"
 #include "mozilla/CDMProxy.h"
 #include "mozilla/AsyncEventDispatcher.h"
 #include "mozilla/Move.h"
 #include "nsContentUtils.h"
 
 namespace mozilla {
 namespace dom {
 
 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaKeySession,
                                    DOMEventTargetHelper,
                                    mMediaKeyError,
                                    mKeys,
+                                   mKeyStatusMap,
                                    mClosed)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaKeySession)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
 NS_IMPL_ADDREF_INHERITED(MediaKeySession, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(MediaKeySession, DOMEventTargetHelper)
 
@@ -41,16 +43,17 @@ MediaKeySession::MediaKeySession(nsPIDOM
                                  ErrorResult& aRv)
   : DOMEventTargetHelper(aParent)
   , mKeys(aKeys)
   , mKeySystem(aKeySystem)
   , mSessionType(aSessionType)
   , mToken(sMediaKeySessionNum++)
   , mIsClosed(false)
   , mUninitialized(true)
+  , mKeyStatusMap(new MediaKeyStatusMap(aParent))
 {
   MOZ_ASSERT(aParent);
   mClosed = mKeys->MakePromise(aRv);
 }
 
 void MediaKeySession::SetSessionId(const nsAString& aSessionId)
 {
   if (NS_WARN_IF(!mSessionId.IsEmpty())) {
@@ -101,16 +104,40 @@ MediaKeySession::Expiration() const
 }
 
 Promise*
 MediaKeySession::Closed() const
 {
   return mClosed;
 }
 
+
+void
+MediaKeySession::UpdateKeyStatusMap()
+{
+  MOZ_ASSERT(!IsClosed());
+  if (!mKeys->GetCDMProxy()) {
+    return;
+  }
+
+  nsTArray<CDMCaps::KeyStatus> keyStatuses;
+  {
+    CDMCaps::AutoLock caps(mKeys->GetCDMProxy()->Capabilites());
+    caps.GetKeyStatusesForSession(mSessionId, keyStatuses);
+  }
+
+  mKeyStatusMap->Update(keyStatuses);
+}
+
+MediaKeyStatusMap*
+MediaKeySession::KeyStatuses() const
+{
+  return mKeyStatusMap;
+}
+
 already_AddRefed<Promise>
 MediaKeySession::GenerateRequest(const nsAString& aInitDataType,
                                  const ArrayBufferViewOrArrayBuffer& aInitData,
                                  ErrorResult& aRv)
 {
   nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
   if (aRv.Failed()) {
     return nullptr;
@@ -243,44 +270,16 @@ MediaKeySession::Remove(ErrorResult& aRv
     promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
     // "The session is closed."
     return promise.forget();
   }
   mKeys->GetCDMProxy()->RemoveSession(mSessionId, mKeys->StorePromise(promise));
   return promise.forget();
 }
 
-already_AddRefed<Promise>
-MediaKeySession::GetUsableKeyIds(ErrorResult& aRv)
-{
-  nsRefPtr<Promise> promise(mKeys->MakePromise(aRv));
-  if (aRv.Failed()) {
-    return nullptr;
-  }
-
-  if (IsClosed() || !mKeys->GetCDMProxy()) {
-    promise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
-    return promise.forget();
-  }
-
-  nsTArray<CencKeyId> keyIds;
-  {
-    CDMCaps::AutoLock caps(mKeys->GetCDMProxy()->Capabilites());
-    caps.GetUsableKeysForSession(mSessionId, keyIds);
-  }
-
-  nsTArray<TypedArrayCreator<ArrayBuffer>> array;
-  for (size_t i = 0; i < keyIds.Length(); i++) {
-    array.AppendElement(keyIds[i]);
-  }
-  promise->MaybeResolve(array);
-
-  return promise.forget();
-}
-
 void
 MediaKeySession::DispatchKeyMessage(MediaKeyMessageType aMessageType,
                                     const nsTArray<uint8_t>& aMessage)
 {
   nsRefPtr<MediaKeyMessageEvent> event(
     MediaKeyMessageEvent::Constructor(this, aMessageType, aMessage));
   nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(this, event);
@@ -297,16 +296,19 @@ MediaKeySession::DispatchKeyError(uint32
 }
 
 void
 MediaKeySession::DispatchKeysChange()
 {
   if (IsClosed()) {
     return;
   }
+
+  UpdateKeyStatusMap();
+
   nsRefPtr<AsyncEventDispatcher> asyncDispatcher =
     new AsyncEventDispatcher(this, NS_LITERAL_STRING("keyschange"), false);
   asyncDispatcher->PostDOMEvent();
 }
 
 uint32_t
 MediaKeySession::Token() const
 {
--- a/dom/media/eme/MediaKeySession.h
+++ b/dom/media/eme/MediaKeySession.h
@@ -25,16 +25,17 @@ struct JSContext;
 namespace mozilla {
 
 class CDMProxy;
 
 namespace dom {
 
 class ArrayBufferViewOrArrayBuffer;
 class MediaKeyError;
+class MediaKeyStatusMap;
 
 class MediaKeySession MOZ_FINAL : public DOMEventTargetHelper
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(MediaKeySession,
                                            DOMEventTargetHelper)
 public:
@@ -46,16 +47,18 @@ public:
 
   void SetSessionId(const nsAString& aSessionId);
 
   virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
 
   // Mark this as resultNotAddRefed to return raw pointers
   MediaKeyError* GetError() const;
 
+  MediaKeyStatusMap* KeyStatuses() const;
+
   void GetKeySystem(nsString& aRetval) const;
 
   void GetSessionId(nsString& aRetval) const;
 
   const nsString& GetSessionId() const;
 
   // Number of ms since epoch at which expiration occurs, or NaN if unknown.
   // TODO: The type of this attribute is still under contention.
@@ -73,18 +76,16 @@ public:
 
   already_AddRefed<Promise> Update(const ArrayBufferViewOrArrayBuffer& response,
                                    ErrorResult& aRv);
 
   already_AddRefed<Promise> Close(ErrorResult& aRv);
 
   already_AddRefed<Promise> Remove(ErrorResult& aRv);
 
-  already_AddRefed<Promise> GetUsableKeyIds(ErrorResult& aRv);
-
   void DispatchKeyMessage(MediaKeyMessageType aMessageType,
                           const nsTArray<uint8_t>& aMessage);
 
   void DispatchKeyError(uint32_t system_code);
 
   void DispatchKeysChange();
 
   void OnClosed();
@@ -92,24 +93,27 @@ public:
   bool IsClosed() const;
 
   // Process-unique identifier.
   uint32_t Token() const;
 
 private:
   ~MediaKeySession();
 
+  void UpdateKeyStatusMap();
+
   nsRefPtr<Promise> mClosed;
 
   nsRefPtr<MediaKeyError> mMediaKeyError;
   nsRefPtr<MediaKeys> mKeys;
   const nsString mKeySystem;
   nsString mSessionId;
   const SessionType mSessionType;
   const uint32_t mToken;
   bool mIsClosed;
   bool mUninitialized;
+  nsRefPtr<MediaKeyStatusMap> mKeyStatusMap;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif
new file mode 100644
--- /dev/null
+++ b/dom/media/eme/MediaKeyStatusMap.cpp
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsPIDOMWindow.h"
+#include "mozilla/dom/MediaKeyStatusMap.h"
+#include "mozilla/dom/UnionTypes.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaKeyStatusMap)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaKeyStatusMap)
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaKeyStatusMap)
+  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
+  NS_INTERFACE_MAP_ENTRY(nsISupports)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(MediaKeyStatusMap)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(MediaKeyStatusMap)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParent)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
+  tmp->mMap = nullptr;
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(MediaKeyStatusMap)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(MediaKeyStatusMap)
+  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
+  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mMap)
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+MediaKeyStatusMap::MediaKeyStatusMap(nsPIDOMWindow* aParent)
+  : mParent(aParent)
+  , mUpdateError(NS_OK)
+{
+  AutoJSAPI jsapi;
+  if (NS_WARN_IF(!jsapi.Init(aParent))) {
+    mUpdateError = NS_ERROR_FAILURE;
+    return;
+  }
+
+  JSContext* cx = jsapi.cx();
+  mMap = JS::NewMapObject(cx);
+  if (NS_WARN_IF(!mMap)) {
+    mUpdateError = NS_ERROR_FAILURE;
+  }
+}
+
+MediaKeyStatusMap::~MediaKeyStatusMap()
+{
+}
+
+JSObject*
+MediaKeyStatusMap::WrapObject(JSContext* aCx)
+{
+  return MediaKeyStatusMapBinding::Wrap(aCx, this);
+}
+
+nsPIDOMWindow*
+MediaKeyStatusMap::GetParentObject() const
+{
+  return mParent;
+}
+
+MediaKeyStatus
+MediaKeyStatusMap::Get(JSContext* aCx,
+                       const ArrayBufferViewOrArrayBuffer& aKey,
+                       ErrorResult& aRv) const
+{
+  if (NS_FAILED(mUpdateError)) {
+    aRv.Throw(mUpdateError);
+    return MediaKeyStatus::Internal_error;
+  }
+
+  JS::Rooted<JSObject*> map(aCx, mMap);
+  JS::Rooted<JS::Value> key(aCx);
+  JS::Rooted<JS::Value> val(aCx);
+
+  if (!aKey.ToJSVal(aCx, map, &key) ||
+      !JS::MapGet(aCx, map, key, &val)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return MediaKeyStatus::Internal_error;
+  }
+
+  bool ok;
+  int index = FindEnumStringIndex<true>(
+      aCx, val, MediaKeyStatusValues::strings,
+      "MediaKeyStatus", "Invalid MediaKeyStatus value", &ok);
+
+  return ok ? static_cast<MediaKeyStatus>(index) :
+              MediaKeyStatus::Internal_error;
+}
+
+bool
+MediaKeyStatusMap::Has(JSContext* aCx,
+                       const ArrayBufferViewOrArrayBuffer& aKey,
+                       ErrorResult& aRv) const
+{
+  if (NS_FAILED(mUpdateError)) {
+    aRv.Throw(mUpdateError);
+    return false;
+  }
+
+  JS::Rooted<JSObject*> map(aCx, mMap);
+  JS::Rooted<JS::Value> key(aCx);
+  bool result = false;
+
+  if (!aKey.ToJSVal(aCx, map, &key) ||
+      !JS::MapHas(aCx, map, key, &result)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+  }
+
+  return result;
+}
+
+template<decltype(JS::MapKeys) Method>
+static void CallMapMethod(JSContext* aCx,
+                          const JS::Heap<JSObject*>& aMap,
+                          JS::MutableHandle<JSObject*> aResult,
+                          ErrorResult& aRv,
+                          nsresult aUpdateError)
+{
+  if (NS_FAILED(aUpdateError)) {
+    aRv.Throw(aUpdateError);
+    return;
+  }
+
+  JS::Rooted<JSObject*> map(aCx, aMap);
+  JS::Rooted<JS::Value> result(aCx);
+  if (!Method(aCx, map, &result)) {
+    aRv.Throw(NS_ERROR_FAILURE);
+    return;
+  }
+
+  aResult.set(&result.toObject());
+}
+
+void
+MediaKeyStatusMap::Keys(JSContext* aCx,
+                        JS::MutableHandle<JSObject*> aResult,
+                        ErrorResult& aRv) const
+{
+  CallMapMethod<JS::MapKeys>(aCx, mMap, aResult, aRv, mUpdateError);
+}
+
+void
+MediaKeyStatusMap::Values(JSContext* aCx,
+                          JS::MutableHandle<JSObject*> aResult,
+                          ErrorResult& aRv) const
+{
+  CallMapMethod<JS::MapValues>(aCx, mMap, aResult, aRv, mUpdateError);
+}
+void
+MediaKeyStatusMap::Entries(JSContext* aCx,
+                           JS::MutableHandle<JSObject*> aResult,
+                           ErrorResult& aRv) const
+{
+  CallMapMethod<JS::MapEntries>(aCx, mMap, aResult, aRv, mUpdateError);
+}
+
+uint32_t
+MediaKeyStatusMap::GetSize(JSContext* aCx, ErrorResult& aRv) const
+{
+  if (NS_FAILED(mUpdateError)) {
+    aRv.Throw(mUpdateError);
+    return 0;
+  }
+  JS::Rooted<JSObject*> map(aCx, mMap);
+  return JS::MapSize(aCx, map);
+}
+
+static MediaKeyStatus
+ToMediaKeyStatus(GMPMediaKeyStatus aStatus) {
+  switch (aStatus) {
+    case kGMPUsable: return MediaKeyStatus::Usable;
+    case kGMPExpired: return MediaKeyStatus::Expired;
+    case kGMPOutputNotAllowed: return MediaKeyStatus::Output_not_allowed;
+    default: return MediaKeyStatus::Internal_error;
+  }
+}
+
+static bool
+ToJSString(JSContext* aCx, GMPMediaKeyStatus aStatus,
+           JS::MutableHandle<JS::Value> aResult)
+{
+  auto val = uint32_t(ToMediaKeyStatus(aStatus));
+  MOZ_ASSERT(val < ArrayLength(MediaKeyStatusValues::strings));
+  JSString* str = JS_NewStringCopyN(aCx,
+      MediaKeyStatusValues::strings[val].value,
+      MediaKeyStatusValues::strings[val].length);
+  if (!str) {
+    return false;
+  }
+  aResult.setString(str);
+  return true;
+}
+
+nsresult
+MediaKeyStatusMap::UpdateInternal(const nsTArray<CDMCaps::KeyStatus>& keys)
+{
+  AutoJSAPI jsapi;
+  if (!mMap || NS_WARN_IF(!jsapi.Init(mParent))) {
+    return NS_ERROR_FAILURE;
+  }
+
+  jsapi.TakeOwnershipOfErrorReporting();
+  JSContext* cx = jsapi.cx();
+  JS::Rooted<JSObject*> map(cx, mMap);
+  if (!JS::MapClear(cx, map)) {
+    return NS_ERROR_FAILURE;
+  }
+
+  for (size_t i = 0; i < keys.Length(); i++) {
+    const auto& ks = keys[i];
+    JS::Rooted<JS::Value> key(cx);
+    JS::Rooted<JS::Value> val(cx);
+    if (!ToJSValue(cx, TypedArrayCreator<ArrayBuffer>(ks.mId), &key) ||
+        !ToJSString(cx, ks.mStatus, &val) ||
+        !JS::MapSet(cx, map, key, val)) {
+      return NS_ERROR_OUT_OF_MEMORY;
+    }
+  }
+
+  return NS_OK;
+}
+
+void
+MediaKeyStatusMap::Update(const nsTArray<CDMCaps::KeyStatus>& keys)
+{
+  // Since we can't leave the map in a partial update state, we need
+  // to remember the error and throw it next time the interface methods
+  // are called.
+  mUpdateError = UpdateInternal(keys);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/media/eme/MediaKeyStatusMap.h
@@ -0,0 +1,78 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_MediaKeyStatuses_h
+#define mozilla_dom_MediaKeyStatuses_h
+
+#include "mozilla/ErrorResult.h"
+#include "mozilla/Attributes.h"
+#include "nsCycleCollectionParticipant.h"
+#include "nsWrapperCache.h"
+
+#include "mozilla/dom/TypedArray.h"
+#include "mozilla/dom/MediaKeyStatusMapBinding.h"
+#include "mozilla/CDMCaps.h"
+
+class nsPIDOMWindow;
+class ArrayBufferViewOrArrayBuffer;
+
+namespace mozilla {
+namespace dom {
+
+class MediaKeyStatusMap MOZ_FINAL : public nsISupports,
+                                    public nsWrapperCache
+{
+public:
+  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(MediaKeyStatusMap)
+
+public:
+  explicit MediaKeyStatusMap(nsPIDOMWindow* aParent);
+
+protected:
+  ~MediaKeyStatusMap();
+
+public:
+  nsPIDOMWindow* GetParentObject() const;
+
+  virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
+
+  MediaKeyStatus Get(JSContext* aCx,
+                     const ArrayBufferViewOrArrayBuffer& aKey,
+                     ErrorResult& aRv) const;
+
+  bool Has(JSContext* aCx,
+           const ArrayBufferViewOrArrayBuffer& aKey,
+           ErrorResult& aRv) const;
+
+  void Keys(JSContext* aCx,
+            JS::MutableHandle<JSObject*> aResult,
+            ErrorResult& aRv) const;
+
+  void Values(JSContext* aCx,
+              JS::MutableHandle<JSObject*> aResult,
+              ErrorResult& aRv) const;
+
+  void Entries(JSContext* aCx,
+               JS::MutableHandle<JSObject*> aResult,
+               ErrorResult& aRv) const;
+
+  uint32_t GetSize(JSContext* aCx, ErrorResult& aRv) const;
+
+  void Update(const nsTArray<CDMCaps::KeyStatus>& keys);
+
+private:
+  nsresult UpdateInternal(const nsTArray<CDMCaps::KeyStatus>& keys);
+
+  nsCOMPtr<nsPIDOMWindow> mParent;
+  JS::Heap<JSObject*> mMap;
+  nsresult mUpdateError;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif
--- a/dom/media/eme/moz.build
+++ b/dom/media/eme/moz.build
@@ -5,16 +5,17 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 EXPORTS.mozilla.dom += [
     'MediaEncryptedEvent.h',
     'MediaKeyError.h',
     'MediaKeyMessageEvent.h',
     'MediaKeys.h',
     'MediaKeySession.h',
+    'MediaKeyStatusMap.h',
     'MediaKeySystemAccess.h',
 ]
 
 EXPORTS.mozilla += [
     'CDMCallbackProxy.h',
     'CDMCaps.h',
     'CDMProxy.h',
     'EMELog.h'
@@ -25,14 +26,15 @@ UNIFIED_SOURCES += [
     'CDMCaps.cpp',
     'CDMProxy.cpp',
     'EMELog.cpp',
     'MediaEncryptedEvent.cpp',
     'MediaKeyError.cpp',
     'MediaKeyMessageEvent.cpp',
     'MediaKeys.cpp',
     'MediaKeySession.cpp',
+    'MediaKeyStatusMap.cpp',
     'MediaKeySystemAccess.cpp',
 ]
 
 FINAL_LIBRARY = 'xul'
 
 FAIL_ON_WARNINGS = True
--- a/dom/webidl/MediaKeySession.webidl
+++ b/dom/webidl/MediaKeySession.webidl
@@ -18,27 +18,26 @@ interface MediaKeySession : EventTarget 
   // session properties
   readonly attribute DOMString keySystem;
   readonly attribute DOMString sessionId;
 
   readonly attribute unrestricted double expiration;
 
   readonly attribute Promise<void> closed;
 
+  readonly attribute MediaKeyStatusMap keyStatuses;
+
   [NewObject]
-  Promise<void> generateRequest(DOMString initDataType, (ArrayBufferView or ArrayBuffer) initData);
+  Promise<void> generateRequest(DOMString initDataType, BufferSource initData);
 
   [NewObject]
   Promise<boolean> load(DOMString sessionId);
 
   // session operations
   [NewObject]
-  Promise<void> update((ArrayBufferView or ArrayBuffer) response);
+  Promise<void> update(BufferSource response);
 
   [NewObject]
   Promise<void> close();
 
   [NewObject]
   Promise<void> remove();
-
-  [NewObject]
-  Promise<sequence<ArrayBuffer>> getUsableKeyIds();
 };
new file mode 100644
--- /dev/null
+++ b/dom/webidl/MediaKeyStatusMap.webidl
@@ -0,0 +1,36 @@
+/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * The origin of this IDL file is
+ * https://dvcs.w3.org/hg/html-media/raw-file/default/encrypted-media/encrypted-media.html
+ *
+ * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
+ * W3C liability, trademark and document use rules apply.
+ */
+
+enum MediaKeyStatus {
+  "usable",
+  "expired",
+  "output-downscaled",
+  "output-not-allowed",
+  "internal-error"
+};
+
+[Pref="media.eme.enabled"]
+interface MediaKeyStatusMap {
+  [Throws]
+  readonly attribute unsigned long size;
+
+  [Throws]
+  object keys();
+
+  [Throws]
+  object values();
+
+  [Throws]
+  object entries();
+
+  // XXX: forEach, @@iterator
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -802,15 +802,16 @@ if CONFIG['MOZ_BUILD_APP'] in ['browser'
 
 if CONFIG['MOZ_EME']:
     WEBIDL_FILES += [
         'MediaEncryptedEvent.webidl',
         'MediaKeyError.webidl',
         'MediaKeyMessageEvent.webidl',
         'MediaKeys.webidl',
         'MediaKeySession.webidl',
+        'MediaKeyStatusMap.webidl',
         'MediaKeySystemAccess.webidl',
     ]
 
 if CONFIG['MOZ_PAY']:
     WEBIDL_FILES += [
         'MozPaymentProvider.webidl'
     ]