Bug 1121332. Part 4 - implement MediaKeySession.keyStatuses and remove MediaKeySession.getUsableKeyIds. r=bz. a=lmandel
authorJW Wang <jwwang@mozilla.com>
Sat, 31 Jan 2015 13:23:07 +1300
changeset 250186 3d9497f46338
parent 250185 e29d774c7215
child 250187 4bcb6239d04b
push id4521
push usercpearce@mozilla.com
push date2015-03-04 01:22 +0000
treeherdermozilla-beta@8abdbdecd2d6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, lmandel
bugs1121332
milestone37.0
Bug 1121332. Part 4 - implement MediaKeySession.keyStatuses and remove MediaKeySession.getUsableKeyIds. r=bz. a=lmandel
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
@@ -668,16 +668,20 @@ DOMInterfaces = {
 'MediaSource': [{
 },
 {
     'nativeType': 'JSObject',
     'workers': True,
     'skipGen': True
 }],
 
+'MediaKeyStatusMap' : {
+    'implicitJSContext': [ 'size', 'get', 'has' ]
+},
+
 'MediaStream': [{
     'headerFile': 'DOMMediaStream.h',
     'nativeType': 'mozilla::DOMMediaStream'
 },
 {
     'nativeType': 'JSObject',
     'workers': True,
     'skipGen': True
--- 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
@@ -797,10 +797,11 @@ 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',
     ]