Bug 1257777 - Part 4: Implement remote codec proxy. r=snorp
MozReview-Commit-ID: 3YEfXXkg2Xi
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/java/org/mozilla/gecko/media/CodecProxy.java
@@ -0,0 +1,350 @@
+/* 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 org.mozilla.gecko.annotation.WrapForJNI;
+import org.mozilla.gecko.GeckoAppShell;
+import org.mozilla.gecko.mozglue.JNIObject;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.MediaCodec;
+import android.media.MediaCodec.BufferInfo;
+import android.media.MediaFormat;
+import android.os.DeadObjectException;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.Surface;
+
+import java.nio.ByteBuffer;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.LinkedList;
+import java.util.List;
+
+// Proxy class of ICodec binder.
+public final class CodecProxy {
+ private static final String LOGTAG = "GeckoRemoteCodecProxy";
+ private static final boolean DEBUG = false;
+
+ private static final RemoteManager sRemoteManager = new RemoteManager();
+
+ private ICodec mRemote;
+ private FormatParam mFormat;
+ private Surface mOutputSurface;
+ private CallbacksForwarder mCallbacks;
+
+ public interface Callbacks {
+ void onInputExhausted();
+ void onOutputFormatChanged(MediaFormat format);
+ void onOutput(byte[] bytes, BufferInfo info);
+ void onError(boolean fatal);
+ }
+
+ @WrapForJNI
+ public static class NativeCallbacks extends JNIObject implements Callbacks {
+ public native void onInputExhausted();
+ public native void onOutputFormatChanged(MediaFormat format);
+ public native void onOutput(byte[] bytes, BufferInfo info);
+ public native void onError(boolean fatal);
+
+ @Override // JNIObject
+ protected native void disposeNative();
+ }
+
+ private static class CallbacksForwarder extends ICodecCallbacks.Stub {
+ private final Callbacks mCallbacks;
+ // // Store the latest frame in case we receive dummy sample.
+ private byte[] mPrevBytes;
+
+ CallbacksForwarder(Callbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public void onInputExhausted() throws RemoteException {
+ mCallbacks.onInputExhausted();
+ }
+
+ @Override
+ public void onOutputFormatChanged(FormatParam format) throws RemoteException {
+ mCallbacks.onOutputFormatChanged(format.asFormat());
+ }
+
+ @Override
+ public void onOutput(Sample sample) throws RemoteException {
+ byte[] bytes = null;
+ if (sample.isDummy()) { // Dummy sample.
+ bytes = mPrevBytes;
+ } else {
+ mPrevBytes = bytes = sample.getBytes();
+ }
+ mCallbacks.onOutput(bytes, sample.info);
+ }
+
+ @Override
+ public void onError(boolean fatal) throws RemoteException {
+ reportError(fatal);
+ }
+
+ public void reportError(boolean fatal) {
+ mCallbacks.onError(fatal);
+ }
+ }
+
+ private static final class RemoteManager implements IBinder.DeathRecipient {
+ private List<CodecProxy> mProxies = new LinkedList<CodecProxy>();
+ private ICodecManager mRemote;
+ private volatile CountDownLatch mConnectionLatch;
+ private final ServiceConnection mConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (DEBUG) Log.d(LOGTAG, "service connected");
+ try {
+ service.linkToDeath(RemoteManager.this, 0);
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ }
+ mRemote = ICodecManager.Stub.asInterface(service);
+ if (mConnectionLatch != null) {
+ mConnectionLatch.countDown();
+ }
+ }
+
+ /**
+ * Called when a connection to the Service has been lost. This typically
+ * happens when the process hosting the service has crashed or been killed.
+ * This does <em>not</em> remove the ServiceConnection itself -- this
+ * binding to the service will remain active, and you will receive a call
+ * to {@link #onServiceConnected} when the Service is next running.
+ *
+ * @param name The concrete component name of the service whose
+ * connection has been lost.
+ */
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ if (DEBUG) Log.d(LOGTAG, "service disconnected");
+ mRemote.asBinder().unlinkToDeath(RemoteManager.this, 0);
+ mRemote = null;
+ if (mConnectionLatch != null) {
+ mConnectionLatch.countDown();
+ }
+ }
+ };
+
+ public synchronized boolean init() {
+ if (mRemote != null) {
+ return true;
+ }
+
+ if (DEBUG) Log.d(LOGTAG, "init remote manager " + this);
+ Context appCtxt = GeckoAppShell.getApplicationContext();
+ if (DEBUG) Log.d(LOGTAG, "ctxt=" + appCtxt);
+ appCtxt.bindService(new Intent(appCtxt, CodecManager.class),
+ mConnection, Context.BIND_AUTO_CREATE);
+ if (!waitConnection()) {
+ appCtxt.unbindService(mConnection);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean waitConnection() {
+ boolean ok = false;
+
+ mConnectionLatch = new CountDownLatch(1);
+ try {
+ int retryCount = 0;
+ while (retryCount < 5) {
+ if (DEBUG) Log.d(LOGTAG, "waiting for connection latch:" + mConnectionLatch);
+ mConnectionLatch.await(1, TimeUnit.SECONDS);
+ if (mConnectionLatch.getCount() == 0) {
+ break;
+ }
+ Log.w(LOGTAG, "Creator not connected in 1s. Try again.");
+ retryCount++;
+ }
+ ok = true;
+ } catch (InterruptedException e) {
+ Log.e(LOGTAG, "service not connected in 5 seconds. Stop waiting.");
+ e.printStackTrace();
+ }
+ mConnectionLatch = null;
+
+ return ok;
+ }
+
+ public synchronized CodecProxy createCodec(MediaFormat format, Surface surface, Callbacks callbacks) {
+ try {
+ ICodec remote = mRemote.createCodec();
+ CodecProxy proxy = new CodecProxy(format, surface, callbacks);
+ if (proxy.init(remote)) {
+ mProxies.add(proxy);
+ return proxy;
+ } else {
+ return null;
+ }
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Override
+ public void binderDied() {
+ Log.e(LOGTAG, "remote codec is dead");
+ handleRemoteDeath();
+ }
+
+ private synchronized void handleRemoteDeath() {
+ // Wait for onServiceDisconnected()
+ if (!waitConnection()) {
+ notifyError(true);
+ return;
+ }
+ // Restart
+ if (init() && recoverRemoteCodec()) {
+ notifyError(false);
+ } else {
+ notifyError(true);
+ }
+ }
+
+ private synchronized void notifyError(boolean fatal) {
+ for (CodecProxy proxy : mProxies) {
+ proxy.mCallbacks.reportError(fatal);
+ }
+ }
+
+ private synchronized boolean recoverRemoteCodec() {
+ if (DEBUG) Log.d(LOGTAG, "recover codec");
+ boolean ok = true;
+ try {
+ for (CodecProxy proxy : mProxies) {
+ ok &= proxy.init(mRemote.createCodec());
+ }
+ return ok;
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ private void releaseCodec(CodecProxy proxy) throws DeadObjectException, RemoteException {
+ proxy.deinit();
+ synchronized (this) {
+ if (mProxies.remove(proxy) && mProxies.isEmpty()) {
+ release();
+ }
+ }
+ }
+
+ private void release() {
+ if (DEBUG) Log.d(LOGTAG, "release remote manager " + this);
+ Context appCtxt = GeckoAppShell.getApplicationContext();
+ mRemote.asBinder().unlinkToDeath(this, 0);
+ mRemote = null;
+ appCtxt.unbindService(mConnection);
+ }
+ }
+
+ @WrapForJNI
+ public static CodecProxy create(MediaFormat format, Surface surface, Callbacks callbacks) {
+ if (!sRemoteManager.init()) {
+ return null;
+ }
+ return sRemoteManager.createCodec(format, surface, callbacks);
+ }
+
+ private CodecProxy(MediaFormat format, Surface surface, Callbacks callbacks) {
+ mFormat = new FormatParam(format);
+ mOutputSurface = surface;
+ mCallbacks = new CallbacksForwarder(callbacks);
+ }
+
+ private boolean init(ICodec remote) {
+ try {
+ remote.setCallbacks(mCallbacks);
+ remote.configure(mFormat, mOutputSurface, 0);
+ remote.start();
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return false;
+ }
+
+ mRemote = remote;
+ return true;
+ }
+
+ private boolean deinit() {
+ try {
+ mRemote.stop();
+ mRemote.release();
+ mRemote = null;
+ return true;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ @WrapForJNI
+ public synchronized boolean input(byte[] bytes, BufferInfo info) {
+ if (mRemote == null) {
+ Log.e(LOGTAG, "cannot send input to an ended codec");
+ return false;
+ }
+ Sample sample = (info.flags == MediaCodec.BUFFER_FLAG_END_OF_STREAM) ?
+ Sample.EOS : new Sample(ByteBuffer.wrap(bytes), info);
+ try {
+ mRemote.queueInput(sample);
+ } catch (DeadObjectException e) {
+ return false;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ Log.e(LOGTAG, "fail to input sample:" + sample);
+ return false;
+ }
+ return true;
+ }
+
+ @WrapForJNI
+ public synchronized boolean flush() {
+ if (mRemote == null) {
+ Log.e(LOGTAG, "cannot flush an ended codec");
+ return false;
+ }
+ try {
+ if (DEBUG) Log.d(LOGTAG, "flush " + this);
+ mRemote.flush();
+ } catch (DeadObjectException e) {
+ return false;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+
+ @WrapForJNI
+ public synchronized boolean release() {
+ if (mRemote == null) {
+ Log.w(LOGTAG, "codec already ended");
+ return true;
+ }
+ if (DEBUG) Log.d(LOGTAG, "release " + this);
+ try {
+ sRemoteManager.releaseCodec(this);
+ } catch (DeadObjectException e) {
+ return false;
+ } catch (RemoteException e) {
+ e.printStackTrace();
+ return false;
+ }
+ return true;
+ }
+}
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -504,16 +504,17 @@ gbjar.sources += ['java/org/mozilla/geck
'lwt/LightweightTheme.java',
'lwt/LightweightThemeDrawable.java',
'mdns/MulticastDNSManager.java',
'media/AsyncCodec.java',
'media/AsyncCodecFactory.java',
'media/AudioFocusAgent.java',
'media/Codec.java',
'media/CodecManager.java',
+ 'media/CodecProxy.java',
'media/FormatParam.java',
'media/JellyBeanAsyncCodec.java',
'media/MediaControlService.java',
'media/Sample.java',
'MediaCastingBar.java',
'MemoryMonitor.java',
'menu/GeckoMenu.java',
'menu/GeckoMenuInflater.java',
--- a/widget/android/GeneratedJNINatives.h
+++ b/widget/android/GeneratedJNINatives.h
@@ -496,16 +496,47 @@ const JNINativeMethod NativePanZoomContr
::template Wrap<&Impl::AbortAnimation>),
mozilla::jni::MakeNativeMethod<NativePanZoomController::SetIsLongpressEnabled_t>(
mozilla::jni::NativeStub<NativePanZoomController::SetIsLongpressEnabled_t, Impl>
::template Wrap<&Impl::SetIsLongpressEnabled>)
};
template<class Impl>
+class CodecProxy::NativeCallbacks::Natives : public mozilla::jni::NativeImpl<NativeCallbacks, Impl>
+{
+public:
+ static const JNINativeMethod methods[5];
+};
+
+template<class Impl>
+const JNINativeMethod CodecProxy::NativeCallbacks::Natives<Impl>::methods[] = {
+
+ mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::DisposeNative_t>(
+ mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::DisposeNative_t, Impl>
+ ::template Wrap<&Impl::DisposeNative>),
+
+ mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnError_t>(
+ mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnError_t, Impl>
+ ::template Wrap<&Impl::OnError>),
+
+ mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnInputExhausted_t>(
+ mozilla::jni::NativeStub<CodecProxy::NativeCallbacks::OnInputExhausted_t, Impl>
+ ::template Wrap<&Impl::OnInputExhausted>),
+
+ mozilla::jni::MakeNativeMethod<CodecProxy::NativeCallbacks::OnOutput_t>(
+ 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 NativeJSContainer::Natives : public mozilla::jni::NativeImpl<NativeJSContainer, Impl>
{
public:
static const JNINativeMethod methods[2];
};
template<class Impl>
const JNINativeMethod NativeJSContainer::Natives<Impl>::methods[] = {
--- a/widget/android/GeneratedJNIWrappers.cpp
+++ b/widget/android/GeneratedJNIWrappers.cpp
@@ -2016,16 +2016,77 @@ auto AudioFocusAgent::NotifyStartedPlayi
constexpr char AudioFocusAgent::NotifyStoppedPlaying_t::name[];
constexpr char AudioFocusAgent::NotifyStoppedPlaying_t::signature[];
auto AudioFocusAgent::NotifyStoppedPlaying() -> void
{
return mozilla::jni::Method<NotifyStoppedPlaying_t>::Call(AudioFocusAgent::Context(), nullptr);
}
+const char CodecProxy::name[] =
+ "org/mozilla/gecko/media/CodecProxy";
+
+constexpr char CodecProxy::Create_t::name[];
+constexpr char CodecProxy::Create_t::signature[];
+
+auto CodecProxy::Create(mozilla::jni::Object::Param a0, mozilla::jni::Object::Param a1, mozilla::jni::Object::Param a2) -> CodecProxy::LocalRef
+{
+ return mozilla::jni::Method<Create_t>::Call(CodecProxy::Context(), nullptr, a0, a1, a2);
+}
+
+constexpr char CodecProxy::Flush_t::name[];
+constexpr char CodecProxy::Flush_t::signature[];
+
+auto CodecProxy::Flush() const -> bool
+{
+ return mozilla::jni::Method<Flush_t>::Call(CodecProxy::mCtx, nullptr);
+}
+
+constexpr char CodecProxy::Input_t::name[];
+constexpr char CodecProxy::Input_t::signature[];
+
+auto CodecProxy::Input(mozilla::jni::ByteArray::Param a0, mozilla::jni::Object::Param a1) const -> bool
+{
+ return mozilla::jni::Method<Input_t>::Call(CodecProxy::mCtx, nullptr, a0, a1);
+}
+
+constexpr char CodecProxy::Release_t::name[];
+constexpr char CodecProxy::Release_t::signature[];
+
+auto CodecProxy::Release() const -> bool
+{
+ return mozilla::jni::Method<Release_t>::Call(CodecProxy::mCtx, nullptr);
+}
+
+const char CodecProxy::NativeCallbacks::name[] =
+ "org/mozilla/gecko/media/CodecProxy$NativeCallbacks";
+
+constexpr char CodecProxy::NativeCallbacks::New_t::name[];
+constexpr char CodecProxy::NativeCallbacks::New_t::signature[];
+
+auto CodecProxy::NativeCallbacks::New() -> NativeCallbacks::LocalRef
+{
+ return mozilla::jni::Constructor<New_t>::Call(NativeCallbacks::Context(), nullptr);
+}
+
+constexpr char CodecProxy::NativeCallbacks::DisposeNative_t::name[];
+constexpr char CodecProxy::NativeCallbacks::DisposeNative_t::signature[];
+
+constexpr char CodecProxy::NativeCallbacks::OnError_t::name[];
+constexpr char CodecProxy::NativeCallbacks::OnError_t::signature[];
+
+constexpr char CodecProxy::NativeCallbacks::OnInputExhausted_t::name[];
+constexpr char CodecProxy::NativeCallbacks::OnInputExhausted_t::signature[];
+
+constexpr char CodecProxy::NativeCallbacks::OnOutput_t::name[];
+constexpr char CodecProxy::NativeCallbacks::OnOutput_t::signature[];
+
+constexpr char CodecProxy::NativeCallbacks::OnOutputFormatChanged_t::name[];
+constexpr char CodecProxy::NativeCallbacks::OnOutputFormatChanged_t::signature[];
+
const char Restrictions::name[] =
"org/mozilla/gecko/restrictions/Restrictions";
constexpr char Restrictions::IsAllowed_t::name[];
constexpr char Restrictions::IsAllowed_t::signature[];
auto Restrictions::IsAllowed(int32_t a0, mozilla::jni::String::Param a1) -> bool
{
--- a/widget/android/GeneratedJNIWrappers.h
+++ b/widget/android/GeneratedJNIWrappers.h
@@ -5878,16 +5878,232 @@ public:
static auto NotifyStoppedPlaying() -> void;
static const mozilla::jni::CallingThread callingThread =
mozilla::jni::CallingThread::GECKO;
};
+class CodecProxy : public mozilla::jni::ObjectBase<CodecProxy>
+{
+public:
+ static const char name[];
+
+ explicit CodecProxy(const Context& ctx) : ObjectBase<CodecProxy>(ctx) {}
+
+ class NativeCallbacks;
+
+ struct Create_t {
+ typedef CodecProxy Owner;
+ typedef CodecProxy::LocalRef ReturnType;
+ typedef CodecProxy::Param SetterType;
+ typedef mozilla::jni::Args<
+ mozilla::jni::Object::Param,
+ mozilla::jni::Object::Param,
+ mozilla::jni::Object::Param> Args;
+ static constexpr char name[] = "create";
+ static constexpr char signature[] =
+ "(Landroid/media/MediaFormat;Landroid/view/Surface;Lorg/mozilla/gecko/media/CodecProxy$Callbacks;)Lorg/mozilla/gecko/media/CodecProxy;";
+ static const bool isStatic = true;
+ 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;
+ };
+
+ static auto Create(mozilla::jni::Object::Param, mozilla::jni::Object::Param, mozilla::jni::Object::Param) -> CodecProxy::LocalRef;
+
+ struct Flush_t {
+ typedef CodecProxy Owner;
+ typedef bool ReturnType;
+ typedef bool SetterType;
+ typedef mozilla::jni::Args<> Args;
+ static constexpr char name[] = "flush";
+ static constexpr char signature[] =
+ "()Z";
+ 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 Flush() const -> bool;
+
+ struct Input_t {
+ typedef CodecProxy Owner;
+ typedef bool ReturnType;
+ typedef bool SetterType;
+ typedef mozilla::jni::Args<
+ mozilla::jni::ByteArray::Param,
+ mozilla::jni::Object::Param> Args;
+ static constexpr char name[] = "input";
+ static constexpr char signature[] =
+ "([BLandroid/media/MediaCodec$BufferInfo;)Z";
+ 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 Input(mozilla::jni::ByteArray::Param, mozilla::jni::Object::Param) const -> bool;
+
+ struct Release_t {
+ typedef CodecProxy Owner;
+ typedef bool ReturnType;
+ typedef bool SetterType;
+ typedef mozilla::jni::Args<> Args;
+ static constexpr char name[] = "release";
+ static constexpr char signature[] =
+ "()Z";
+ 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 Release() const -> bool;
+
+ static const mozilla::jni::CallingThread callingThread =
+ mozilla::jni::CallingThread::ANY;
+
+};
+
+class CodecProxy::NativeCallbacks : public mozilla::jni::ObjectBase<NativeCallbacks>
+{
+public:
+ static const char name[];
+
+ explicit NativeCallbacks(const Context& ctx) : ObjectBase<NativeCallbacks>(ctx) {}
+
+ struct New_t {
+ typedef NativeCallbacks Owner;
+ typedef NativeCallbacks::LocalRef ReturnType;
+ typedef NativeCallbacks::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::ANY;
+ static const mozilla::jni::DispatchTarget dispatchTarget =
+ mozilla::jni::DispatchTarget::CURRENT;
+ };
+
+ static auto New() -> NativeCallbacks::LocalRef;
+
+ struct DisposeNative_t {
+ typedef NativeCallbacks Owner;
+ typedef void ReturnType;
+ typedef void SetterType;
+ typedef mozilla::jni::Args<> Args;
+ static constexpr char name[] = "disposeNative";
+ 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;
+ };
+
+ struct OnError_t {
+ typedef NativeCallbacks Owner;
+ typedef void ReturnType;
+ typedef void SetterType;
+ typedef mozilla::jni::Args<
+ bool> Args;
+ static constexpr char name[] = "onError";
+ static constexpr char signature[] =
+ "(Z)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;
+ };
+
+ struct OnInputExhausted_t {
+ typedef NativeCallbacks Owner;
+ typedef void ReturnType;
+ typedef void SetterType;
+ typedef mozilla::jni::Args<> Args;
+ static constexpr char name[] = "onInputExhausted";
+ 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;
+ };
+
+ struct OnOutput_t {
+ typedef NativeCallbacks Owner;
+ typedef void ReturnType;
+ typedef void SetterType;
+ typedef mozilla::jni::Args<
+ mozilla::jni::ByteArray::Param,
+ mozilla::jni::Object::Param> Args;
+ static constexpr char name[] = "onOutput";
+ static constexpr char signature[] =
+ "([BLandroid/media/MediaCodec$BufferInfo;)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;
+ };
+
+ struct OnOutputFormatChanged_t {
+ typedef NativeCallbacks Owner;
+ typedef void ReturnType;
+ typedef void SetterType;
+ typedef mozilla::jni::Args<
+ mozilla::jni::Object::Param> Args;
+ static constexpr char name[] = "onOutputFormatChanged";
+ static constexpr char signature[] =
+ "(Landroid/media/MediaFormat;)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;
+ };
+
+ static const mozilla::jni::CallingThread callingThread =
+ mozilla::jni::CallingThread::ANY;
+
+ template<class Impl> class Natives;
+};
+
class Restrictions : public mozilla::jni::ObjectBase<Restrictions>
{
public:
static const char name[];
explicit Restrictions(const Context& ctx) : ObjectBase<Restrictions>(ctx) {}
struct IsAllowed_t {