Bug 1306572 - Part1 - Implement GeckoMediaDrm API as a glue for native CDMProxy and java impl MediaDrmBridge. r=cpearce,jchen
authorJames Cheng <jacheng@mozilla.com>
Tue, 01 Nov 2016 14:39:01 +0800
changeset 321113 d85acf31e2166023ef33e353599b400bf8161fcc
parent 321112 9d1487ccc2e34cecc2ee040b81d5ea164b57e964
child 321114 f6e81941c5370ac75ce2ce2ff0b03d9e6cdde687
push id30919
push userphilringnalda@gmail.com
push dateSat, 05 Nov 2016 20:28:20 +0000
treeherdermozilla-central@572249b2ffb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, jchen
bugs1306572
milestone52.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 1306572 - Part1 - Implement GeckoMediaDrm API as a glue for native CDMProxy and java impl MediaDrmBridge. r=cpearce,jchen MozReview-Commit-ID: GUKqWvmaaFl
mobile/android/base/java/org/mozilla/gecko/media/MediaDrmProxy.java
widget/android/bindings/MediaCodec-classes.txt
widget/android/fennec/FennecJNINatives.h
widget/android/fennec/FennecJNIWrappers.cpp
widget/android/fennec/FennecJNIWrappers.h
--- a/mobile/android/base/java/org/mozilla/gecko/media/MediaDrmProxy.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/MediaDrmProxy.java
@@ -1,17 +1,19 @@
 /* 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/. */
 
 
 package org.mozilla.gecko.media;
 
+import java.util.ArrayList;
 import java.util.UUID;
 
+import org.mozilla.gecko.mozglue.JNIObject;
 import org.mozilla.gecko.annotation.WrapForJNI;
 import org.mozilla.gecko.AppConstants;
 
 import android.media.MediaCodecInfo;
 import android.media.MediaCodecList;
 import android.media.MediaCrypto;
 import android.media.MediaDrm;
 import android.util.Log;
@@ -32,16 +34,21 @@ public final class MediaDrmProxy {
     private static final String VORBIS = "audio/vorbis";
     @WrapForJNI
     private static final String VP8 = "video/x-vnd.on2.vp8";
     @WrapForJNI
     private static final String VP9 = "video/x-vnd.on2.vp9";
     @WrapForJNI
     private static final String OPUS = "audio/opus";
 
+    // A flag to avoid using the native object that has been destroyed.
+    private boolean mDestroyed;
+    private GeckoMediaDrm mImpl;
+    public static ArrayList<MediaDrmProxy> mProxyList = new ArrayList<MediaDrmProxy>();
+
     private static boolean isSystemSupported() {
         // Support versions >= LOLLIPOP
         if (AppConstants.Versions.preLollipop) {
             if (DEBUG) Log.d(LOGTAG, "System Not supported !!, current SDK version is " + Build.VERSION.SDK_INT);
             return false;
         }
         return true;
     }
@@ -83,9 +90,215 @@ public final class MediaDrmProxy {
                 if (m.equals(mimeType)) {
                   return true;
                 }
             }
         }
         if (DEBUG) Log.d(LOGTAG, "cannot decode mimetype = " + mimeType);
         return false;
     }
+
+     // Interface for callback to native.
+    public interface Callbacks {
+        void onSessionCreated(int createSessionToken,
+                              int promiseId,
+                              byte[] sessionId,
+                              byte[] request);
+
+        void onSessionUpdated(int promiseId, byte[] sessionId);
+
+        void onSessionClosed(int promiseId, byte[] sessionId);
+
+        void onSessionMessage(byte[] sessionId,
+                              int sessionMessageType,
+                              byte[] request);
+
+       void onSessionError(byte[] sessionId,
+                           String message);
+
+        // MediaDrm.KeyStatus is available in API level 23(M)
+        // https://developer.android.com/reference/android/media/MediaDrm.KeyStatus.html
+        // For compatibility between L and M above, we'll unwrap the KeyStatus structure
+        // and store the keyid and status into SessionKeyInfo and pass to native(MediaDrmCDMProxy).
+        void onSessionBatchedKeyChanged(byte[] sessionId,
+                                        SessionKeyInfo[] keyInfos);
+
+        void onRejectPromise(int promiseId,
+                             String message);
+    } // Callbacks
+
+    public static class NativeMediaDrmProxyCallbacks extends JNIObject implements Callbacks {
+        @WrapForJNI(calledFrom = "gecko")
+        NativeMediaDrmProxyCallbacks() {}
+
+        @Override
+        @WrapForJNI(dispatchTo = "gecko")
+        public native void onSessionCreated(int createSessionToken,
+                                            int promiseId,
+                                            byte[] sessionId,
+                                            byte[] request);
+
+        @Override
+        @WrapForJNI(dispatchTo = "gecko")
+        public native void onSessionUpdated(int promiseId, byte[] sessionId);
+
+        @Override
+        @WrapForJNI(dispatchTo = "gecko")
+        public native void onSessionClosed(int promiseId, byte[] sessionId);
+
+        @Override
+        @WrapForJNI(dispatchTo = "gecko")
+        public native void onSessionMessage(byte[] sessionId,
+                                            int sessionMessageType,
+                                            byte[] request);
+
+        @Override
+        @WrapForJNI(dispatchTo = "gecko")
+        public native void onSessionError(byte[] sessionId,
+                                          String message);
+
+        @Override
+        @WrapForJNI(dispatchTo = "gecko")
+        public native void onSessionBatchedKeyChanged(byte[] sessionId,
+                                                      SessionKeyInfo[] keyInfos);
+
+        @Override
+        @WrapForJNI(dispatchTo = "gecko")
+        public native void onRejectPromise(int promiseId,
+                                           String message);
+
+        @Override // JNIObject
+        protected void disposeNative() {
+            throw new UnsupportedOperationException();
+        }
+    } // NativeMediaDrmProxyCallbacks
+
+    // A proxy to callback from LocalMediaDrmBridge to native instance.
+    public static class MediaDrmProxyCallbacks implements GeckoMediaDrm.Callbacks {
+        private final Callbacks mNativeCallbacks;
+        private final MediaDrmProxy mProxy;
+
+        public MediaDrmProxyCallbacks(MediaDrmProxy proxy, Callbacks callbacks) {
+            mNativeCallbacks = callbacks;
+            mProxy = proxy;
+        }
+
+        @Override
+        public void onSessionCreated(int createSessionToken,
+                                     int promiseId,
+                                     byte[] sessionId,
+                                     byte[] request) {
+            if (!mProxy.isDestroyed()) {
+                mNativeCallbacks.onSessionCreated(createSessionToken,
+                                                  promiseId,
+                                                  sessionId,
+                                                  request);
+            }
+        }
+
+        @Override
+        public void onSessionUpdated(int promiseId, byte[] sessionId) {
+            if (!mProxy.isDestroyed()) {
+                mNativeCallbacks.onSessionUpdated(promiseId, sessionId);
+            }
+        }
+
+        @Override
+        public void onSessionClosed(int promiseId, byte[] sessionId) {
+            if (!mProxy.isDestroyed()) {
+                mNativeCallbacks.onSessionClosed(promiseId, sessionId);
+            }
+        }
+
+        @Override
+        public void onSessionMessage(byte[] sessionId,
+                                     int sessionMessageType,
+                                     byte[] request) {
+            if (!mProxy.isDestroyed()) {
+                mNativeCallbacks.onSessionMessage(sessionId, sessionMessageType, request);
+            }
+        }
+
+        @Override
+        public void onSessionError(byte[] sessionId,
+                                   String message) {
+            if (!mProxy.isDestroyed()) {
+                mNativeCallbacks.onSessionError(sessionId, message);
+            }
+        }
+
+        @Override
+        public void onSessionBatchedKeyChanged(byte[] sessionId,
+                                               SessionKeyInfo[] keyInfos) {
+            if (!mProxy.isDestroyed()) {
+                mNativeCallbacks.onSessionBatchedKeyChanged(sessionId, keyInfos);
+            }
+        }
+
+        @Override
+        public void onRejectPromise(int promiseId,
+                                    String message) {
+            if (!mProxy.isDestroyed()) {
+                mNativeCallbacks.onRejectPromise(promiseId, message);
+            }
+        }
+    } // MediaDrmProxyCallbacks
+
+    public boolean isDestroyed() {
+        return mDestroyed;
+    }
+
+    @WrapForJNI(calledFrom = "gecko")
+    public static MediaDrmProxy create(String keySystem,
+                                       Callbacks nativeCallbacks) {
+        MediaDrmProxy proxy = new MediaDrmProxy(keySystem, nativeCallbacks);
+        return proxy;
+    }
+
+    MediaDrmProxy(String keySystem, Callbacks nativeCallbacks) {
+        if (DEBUG) Log.d(LOGTAG, "Constructing MediaDrmProxy");
+        // TODO: Bug 1306185 will implement the LocalMediaDrmBridge as an impl
+        // of GeckoMediaDrm for in-process decoding mode.
+        //mImpl = new LocalMediaDrmBridge(keySystem);
+        mImpl.setCallbacks(new MediaDrmProxyCallbacks(this, nativeCallbacks));
+        mProxyList.add(this);
+    }
+
+    @WrapForJNI
+    private void createSession(int createSessionToken,
+                               int promiseId,
+                               String initDataType,
+                               byte[] initData) {
+        if (DEBUG) Log.d(LOGTAG, "createSession, promiseId = " + promiseId);
+        mImpl.createSession(createSessionToken,
+                            promiseId,
+                            initDataType,
+                            initData);
+    }
+
+    @WrapForJNI
+    private void updateSession(int promiseId, String sessionId, byte[] response) {
+        if (DEBUG) Log.d(LOGTAG, "updateSession, primiseId(" + promiseId  + "sessionId(" + sessionId + ")");
+        mImpl.updateSession(promiseId, sessionId, response);
+    }
+
+    @WrapForJNI
+    private void closeSession(int promiseId, String sessionId) {
+        if (DEBUG) Log.d(LOGTAG, "closeSession, primiseId(" + promiseId  + "sessionId(" + sessionId + ")");
+        mImpl.closeSession(promiseId, sessionId);
+    }
+
+    @WrapForJNI // Called when natvie object is destroyed.
+    private void destroy() {
+        if (DEBUG) Log.d(LOGTAG, "destroy!! Native object is destroyed.");
+        if (mDestroyed) {
+            return;
+        }
+        mDestroyed = true;
+        release();
+    }
+
+    private void release() {
+        if (DEBUG) Log.d(LOGTAG, "release");
+        mProxyList.remove(this);
+        mImpl.release();
+    }
 }
--- a/widget/android/bindings/MediaCodec-classes.txt
+++ b/widget/android/bindings/MediaCodec-classes.txt
@@ -1,4 +1,5 @@
 android.media.MediaCodec
 android.media.MediaCodec$BufferInfo
 android.media.MediaCodec$CryptoInfo
+android.media.MediaDrm$KeyStatus
 android.media.MediaFormat
--- a/widget/android/fennec/FennecJNINatives.h
+++ b/widget/android/fennec/FennecJNINatives.h
@@ -195,11 +195,50 @@ const JNINativeMethod CodecProxy::Native
             mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnOutput_t, Impl>
             ::template Wrap<&Impl::OnOutput>),
 
     mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnOutputFormatChanged_t>(
             mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnOutputFormatChanged_t, Impl>
             ::template Wrap<&Impl::OnOutputFormatChanged>)
 };
 
+template<class Impl>
+class MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives : public mozilla::jni::NativeImpl<NativeMediaDrmProxyCallbacks, Impl>
+{
+public:
+    static const JNINativeMethod methods[7];
+};
+
+template<class Impl>
+const JNINativeMethod MediaDrmProxy::NativeMediaDrmProxyCallbacks::Natives<Impl>::methods[] = {
+
+    mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnRejectPromise_t>(
+            mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnRejectPromise_t, Impl>
+            ::template Wrap<&Impl::OnRejectPromise>),
+
+    mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionBatchedKeyChanged_t>(
+            mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionBatchedKeyChanged_t, Impl>
+            ::template Wrap<&Impl::OnSessionBatchedKeyChanged>),
+
+    mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionClosed_t>(
+            mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionClosed_t, Impl>
+            ::template Wrap<&Impl::OnSessionClosed>),
+
+    mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionCreated_t>(
+            mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionCreated_t, Impl>
+            ::template Wrap<&Impl::OnSessionCreated>),
+
+    mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionError_t>(
+            mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionError_t, Impl>
+            ::template Wrap<&Impl::OnSessionError>),
+
+    mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionMessage_t>(
+            mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionMessage_t, Impl>
+            ::template Wrap<&Impl::OnSessionMessage>),
+
+    mozilla::jni::MakeNativeMethod<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionUpdated_t>(
+            mozilla::jni::NativeStub<MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionUpdated_t, Impl>
+            ::template Wrap<&Impl::OnSessionUpdated>)
+};
+
 } /* java */
 } /* mozilla */
 #endif // FennecJNINatives_h
--- a/widget/android/fennec/FennecJNIWrappers.cpp
+++ b/widget/android/fennec/FennecJNIWrappers.cpp
@@ -262,36 +262,108 @@ auto MediaDrmProxy::CanDecode(mozilla::j
 constexpr char MediaDrmProxy::IsCryptoSchemeSupported_t::name[];
 constexpr char MediaDrmProxy::IsCryptoSchemeSupported_t::signature[];
 
 auto MediaDrmProxy::IsCryptoSchemeSupported(mozilla::jni::String::Param a0, mozilla::jni::String::Param a1) -> bool
 {
     return mozilla::jni::Method<IsCryptoSchemeSupported_t>::Call(MediaDrmProxy::Context(), nullptr, a0, a1);
 }
 
+constexpr char MediaDrmProxy::CloseSession_t::name[];
+constexpr char MediaDrmProxy::CloseSession_t::signature[];
+
+auto MediaDrmProxy::CloseSession(int32_t a0, mozilla::jni::String::Param a1) const -> void
+{
+    return mozilla::jni::Method<CloseSession_t>::Call(MediaDrmProxy::mCtx, nullptr, a0, a1);
+}
+
+constexpr char MediaDrmProxy::Create_t::name[];
+constexpr char MediaDrmProxy::Create_t::signature[];
+
+auto MediaDrmProxy::Create(mozilla::jni::String::Param a0, mozilla::jni::Object::Param a1) -> MediaDrmProxy::LocalRef
+{
+    return mozilla::jni::Method<Create_t>::Call(MediaDrmProxy::Context(), nullptr, a0, a1);
+}
+
+constexpr char MediaDrmProxy::CreateSession_t::name[];
+constexpr char MediaDrmProxy::CreateSession_t::signature[];
+
+auto MediaDrmProxy::CreateSession(int32_t a0, int32_t a1, mozilla::jni::String::Param a2, mozilla::jni::ByteArray::Param a3) const -> void
+{
+    return mozilla::jni::Method<CreateSession_t>::Call(MediaDrmProxy::mCtx, nullptr, a0, a1, a2, a3);
+}
+
+constexpr char MediaDrmProxy::Destroy_t::name[];
+constexpr char MediaDrmProxy::Destroy_t::signature[];
+
+auto MediaDrmProxy::Destroy() const -> void
+{
+    return mozilla::jni::Method<Destroy_t>::Call(MediaDrmProxy::mCtx, nullptr);
+}
+
 constexpr char MediaDrmProxy::IsSchemeSupported_t::name[];
 constexpr char MediaDrmProxy::IsSchemeSupported_t::signature[];
 
 auto MediaDrmProxy::IsSchemeSupported(mozilla::jni::String::Param a0) -> bool
 {
     return mozilla::jni::Method<IsSchemeSupported_t>::Call(MediaDrmProxy::Context(), nullptr, a0);
 }
 
+constexpr char MediaDrmProxy::UpdateSession_t::name[];
+constexpr char MediaDrmProxy::UpdateSession_t::signature[];
+
+auto MediaDrmProxy::UpdateSession(int32_t a0, mozilla::jni::String::Param a1, mozilla::jni::ByteArray::Param a2) const -> void
+{
+    return mozilla::jni::Method<UpdateSession_t>::Call(MediaDrmProxy::mCtx, nullptr, a0, a1, a2);
+}
+
 const char16_t MediaDrmProxy::AAC[] = u"audio/mp4a-latm";
 
 const char16_t MediaDrmProxy::AVC[] = u"video/avc";
 
 const char16_t MediaDrmProxy::OPUS[] = u"audio/opus";
 
 const char16_t MediaDrmProxy::VORBIS[] = u"audio/vorbis";
 
 const char16_t MediaDrmProxy::VP8[] = u"video/x-vnd.on2.vp8";
 
 const char16_t MediaDrmProxy::VP9[] = u"video/x-vnd.on2.vp9";
 
+const char MediaDrmProxy::NativeMediaDrmProxyCallbacks::name[] =
+        "org/mozilla/gecko/media/MediaDrmProxy$NativeMediaDrmProxyCallbacks";
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::New_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::New_t::signature[];
+
+auto MediaDrmProxy::NativeMediaDrmProxyCallbacks::New() -> NativeMediaDrmProxyCallbacks::LocalRef
+{
+    return mozilla::jni::Constructor<New_t>::Call(NativeMediaDrmProxyCallbacks::Context(), nullptr);
+}
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnRejectPromise_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnRejectPromise_t::signature[];
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionBatchedKeyChanged_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionBatchedKeyChanged_t::signature[];
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionClosed_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionClosed_t::signature[];
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionCreated_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionCreated_t::signature[];
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionError_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionError_t::signature[];
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionMessage_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionMessage_t::signature[];
+
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionUpdated_t::name[];
+constexpr char MediaDrmProxy::NativeMediaDrmProxyCallbacks::OnSessionUpdated_t::signature[];
+
 const char Sample::name[] =
         "org/mozilla/gecko/media/Sample";
 
 constexpr char Sample::WriteToByteBuffer_t::name[];
 constexpr char Sample::WriteToByteBuffer_t::signature[];
 
 auto Sample::WriteToByteBuffer(mozilla::jni::ByteBuffer::Param a0) const -> void
 {
--- a/widget/android/fennec/FennecJNIWrappers.h
+++ b/widget/android/fennec/FennecJNIWrappers.h
@@ -924,16 +924,18 @@ public:
 
 class MediaDrmProxy : public mozilla::jni::ObjectBase<MediaDrmProxy>
 {
 public:
     static const char name[];
 
     explicit MediaDrmProxy(const Context& ctx) : ObjectBase<MediaDrmProxy>(ctx) {}
 
+    class NativeMediaDrmProxyCallbacks;
+
     struct CanDecode_t {
         typedef MediaDrmProxy Owner;
         typedef bool ReturnType;
         typedef bool SetterType;
         typedef mozilla::jni::Args<
                 mozilla::jni::String::Param> Args;
         static constexpr char name[] = "CanDecode";
         static constexpr char signature[] =
@@ -965,16 +967,100 @@ public:
         static const mozilla::jni::CallingThread callingThread =
                 mozilla::jni::CallingThread::ANY;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
     static auto IsCryptoSchemeSupported(mozilla::jni::String::Param, mozilla::jni::String::Param) -> bool;
 
+    struct CloseSession_t {
+        typedef MediaDrmProxy Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                mozilla::jni::String::Param> Args;
+        static constexpr char name[] = "closeSession";
+        static constexpr char signature[] =
+                "(ILjava/lang/String;)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    auto CloseSession(int32_t, mozilla::jni::String::Param) const -> void;
+
+    struct Create_t {
+        typedef MediaDrmProxy Owner;
+        typedef MediaDrmProxy::LocalRef ReturnType;
+        typedef MediaDrmProxy::Param SetterType;
+        typedef mozilla::jni::Args<
+                mozilla::jni::String::Param,
+                mozilla::jni::Object::Param> Args;
+        static constexpr char name[] = "create";
+        static constexpr char signature[] =
+                "(Ljava/lang/String;Lorg/mozilla/gecko/media/MediaDrmProxy$Callbacks;)Lorg/mozilla/gecko/media/MediaDrmProxy;";
+        static const bool isStatic = true;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::GECKO;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    static auto Create(mozilla::jni::String::Param, mozilla::jni::Object::Param) -> MediaDrmProxy::LocalRef;
+
+    struct CreateSession_t {
+        typedef MediaDrmProxy Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                int32_t,
+                mozilla::jni::String::Param,
+                mozilla::jni::ByteArray::Param> Args;
+        static constexpr char name[] = "createSession";
+        static constexpr char signature[] =
+                "(IILjava/lang/String;[B)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    auto CreateSession(int32_t, int32_t, mozilla::jni::String::Param, mozilla::jni::ByteArray::Param) const -> void;
+
+    struct Destroy_t {
+        typedef MediaDrmProxy Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "destroy";
+        static constexpr char signature[] =
+                "()V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    auto Destroy() const -> void;
+
     struct IsSchemeSupported_t {
         typedef MediaDrmProxy Owner;
         typedef bool ReturnType;
         typedef bool SetterType;
         typedef mozilla::jni::Args<
                 mozilla::jni::String::Param> Args;
         static constexpr char name[] = "isSchemeSupported";
         static constexpr char signature[] =
@@ -985,16 +1071,38 @@ public:
         static const mozilla::jni::CallingThread callingThread =
                 mozilla::jni::CallingThread::ANY;
         static const mozilla::jni::DispatchTarget dispatchTarget =
                 mozilla::jni::DispatchTarget::CURRENT;
     };
 
     static auto IsSchemeSupported(mozilla::jni::String::Param) -> bool;
 
+    struct UpdateSession_t {
+        typedef MediaDrmProxy Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                mozilla::jni::String::Param,
+                mozilla::jni::ByteArray::Param> Args;
+        static constexpr char name[] = "updateSession";
+        static constexpr char signature[] =
+                "(ILjava/lang/String;[B)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    auto UpdateSession(int32_t, mozilla::jni::String::Param, mozilla::jni::ByteArray::Param) const -> void;
+
     static const char16_t AAC[];
 
     static const char16_t AVC[];
 
     static const char16_t OPUS[];
 
     static const char16_t VORBIS[];
 
@@ -1002,16 +1110,184 @@ public:
 
     static const char16_t VP9[];
 
     static const mozilla::jni::CallingThread callingThread =
             mozilla::jni::CallingThread::ANY;
 
 };
 
+class MediaDrmProxy::NativeMediaDrmProxyCallbacks : public mozilla::jni::ObjectBase<NativeMediaDrmProxyCallbacks>
+{
+public:
+    static const char name[];
+
+    explicit NativeMediaDrmProxyCallbacks(const Context& ctx) : ObjectBase<NativeMediaDrmProxyCallbacks>(ctx) {}
+
+    struct New_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef NativeMediaDrmProxyCallbacks::LocalRef ReturnType;
+        typedef NativeMediaDrmProxyCallbacks::Param SetterType;
+        typedef mozilla::jni::Args<> Args;
+        static constexpr char name[] = "<init>";
+        static constexpr char signature[] =
+                "()V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::GECKO;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::CURRENT;
+    };
+
+    static auto New() -> NativeMediaDrmProxyCallbacks::LocalRef;
+
+    struct OnRejectPromise_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                mozilla::jni::String::Param> Args;
+        static constexpr char name[] = "onRejectPromise";
+        static constexpr char signature[] =
+                "(ILjava/lang/String;)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::GECKO;
+    };
+
+    struct OnSessionBatchedKeyChanged_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                mozilla::jni::ByteArray::Param,
+                mozilla::jni::ObjectArray::Param> Args;
+        static constexpr char name[] = "onSessionBatchedKeyChanged";
+        static constexpr char signature[] =
+                "([B[Lorg/mozilla/gecko/media/SessionKeyInfo;)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::GECKO;
+    };
+
+    struct OnSessionClosed_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                mozilla::jni::ByteArray::Param> Args;
+        static constexpr char name[] = "onSessionClosed";
+        static constexpr char signature[] =
+                "(I[B)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::GECKO;
+    };
+
+    struct OnSessionCreated_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                int32_t,
+                mozilla::jni::ByteArray::Param,
+                mozilla::jni::ByteArray::Param> Args;
+        static constexpr char name[] = "onSessionCreated";
+        static constexpr char signature[] =
+                "(II[B[B)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::GECKO;
+    };
+
+    struct OnSessionError_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                mozilla::jni::ByteArray::Param,
+                mozilla::jni::String::Param> Args;
+        static constexpr char name[] = "onSessionError";
+        static constexpr char signature[] =
+                "([BLjava/lang/String;)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::GECKO;
+    };
+
+    struct OnSessionMessage_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                mozilla::jni::ByteArray::Param,
+                int32_t,
+                mozilla::jni::ByteArray::Param> Args;
+        static constexpr char name[] = "onSessionMessage";
+        static constexpr char signature[] =
+                "([BI[B)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::GECKO;
+    };
+
+    struct OnSessionUpdated_t {
+        typedef NativeMediaDrmProxyCallbacks Owner;
+        typedef void ReturnType;
+        typedef void SetterType;
+        typedef mozilla::jni::Args<
+                int32_t,
+                mozilla::jni::ByteArray::Param> Args;
+        static constexpr char name[] = "onSessionUpdated";
+        static constexpr char signature[] =
+                "(I[B)V";
+        static const bool isStatic = false;
+        static const mozilla::jni::ExceptionMode exceptionMode =
+                mozilla::jni::ExceptionMode::ABORT;
+        static const mozilla::jni::CallingThread callingThread =
+                mozilla::jni::CallingThread::ANY;
+        static const mozilla::jni::DispatchTarget dispatchTarget =
+                mozilla::jni::DispatchTarget::GECKO;
+    };
+
+    static const mozilla::jni::CallingThread callingThread =
+            mozilla::jni::CallingThread::ANY;
+
+    template<class Impl> class Natives;
+};
+
 class Sample : public mozilla::jni::ObjectBase<Sample>
 {
 public:
     static const char name[];
 
     explicit Sample(const Context& ctx) : ObjectBase<Sample>(ctx) {}
 
     struct WriteToByteBuffer_t {