Bug 1306572 - Part1 - Implement GeckoMediaDrm API as a glue for native CDMProxy and java impl MediaDrmBridge. draft
authorJames Cheng <jacheng@mozilla.com>
Tue, 01 Nov 2016 14:39:01 +0800
changeset 433971 4a8af7db5ae2fe18545b7fb05e063e4af4f1ab45
parent 433942 9c6b3b3a119bc48f5d12e3161218e98adaa12627
child 433972 01f90920eec0cb7cd471fa1ae58f03c11e486bb3
push id34695
push userbmo:jacheng@mozilla.com
push dateFri, 04 Nov 2016 15:45:45 +0000
bugs1306572
milestone52.0a1
Bug 1306572 - Part1 - Implement GeckoMediaDrm API as a glue for native CDMProxy and java impl MediaDrmBridge. 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 {