summaryrefslogtreecommitdiffstats
path: root/core/jni/android_media_RemoteDisplay.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'core/jni/android_media_RemoteDisplay.cpp')
-rw-r--r--core/jni/android_media_RemoteDisplay.cpp182
1 files changed, 182 insertions, 0 deletions
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
new file mode 100644
index 0000000..5d24f61
--- /dev/null
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "RemoteDisplay"
+
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include "android_os_Parcel.h"
+#include "android_util_Binder.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/android_view_Surface.h>
+
+#include <binder/IServiceManager.h>
+
+#include <gui/ISurfaceTexture.h>
+
+#include <media/IMediaPlayerService.h>
+#include <media/IRemoteDisplay.h>
+#include <media/IRemoteDisplayClient.h>
+
+#include <utils/Log.h>
+
+#include <ScopedUtfChars.h>
+
+namespace android {
+
+static struct {
+ jmethodID notifyDisplayConnected;
+ jmethodID notifyDisplayDisconnected;
+ jmethodID notifyDisplayError;
+} gRemoteDisplayClassInfo;
+
+// ----------------------------------------------------------------------------
+
+class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
+public:
+ NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
+ mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
+ }
+
+protected:
+ ~NativeRemoteDisplayClient() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
+ }
+
+public:
+ virtual void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture,
+ uint32_t width, uint32_t height, uint32_t flags) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, surfaceTexture);
+ if (surfaceObj == NULL) {
+ ALOGE("Could not create Surface from surface texture %p provided by media server.",
+ surfaceTexture.get());
+ return;
+ }
+
+ env->CallVoidMethod(mRemoteDisplayObjGlobal,
+ gRemoteDisplayClassInfo.notifyDisplayConnected,
+ surfaceObj, width, height, flags);
+ env->DeleteLocalRef(surfaceObj);
+ checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
+ }
+
+ virtual void onDisplayDisconnected() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(mRemoteDisplayObjGlobal,
+ gRemoteDisplayClassInfo.notifyDisplayDisconnected);
+ checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
+ }
+
+ virtual void onDisplayError(int32_t error) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+
+ env->CallVoidMethod(mRemoteDisplayObjGlobal,
+ gRemoteDisplayClassInfo.notifyDisplayError, error);
+ checkAndClearExceptionFromCallback(env, "notifyDisplayError");
+ }
+
+private:
+ jobject mRemoteDisplayObjGlobal;
+
+ static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+ }
+};
+
+class NativeRemoteDisplay {
+public:
+ NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
+ const sp<NativeRemoteDisplayClient>& client) :
+ mDisplay(display), mClient(client) {
+ }
+
+ ~NativeRemoteDisplay() {
+ mDisplay->dispose();
+ }
+
+private:
+ sp<IRemoteDisplay> mDisplay;
+ sp<NativeRemoteDisplayClient> mClient;
+};
+
+
+// ----------------------------------------------------------------------------
+
+static jint nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
+ ScopedUtfChars iface(env, ifaceStr);
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
+ sm->getService(String16("media.player")));
+ if (service == NULL) {
+ ALOGE("Could not obtain IMediaPlayerService from service manager");
+ return 0;
+ }
+
+ sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
+ sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
+ client, String8(iface.c_str()));
+ if (display == NULL) {
+ ALOGE("Media player service rejected request to listen for remote display '%s'.",
+ iface.c_str());
+ return 0;
+ }
+
+ NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
+ return reinterpret_cast<jint>(wrapper);
+}
+
+static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
+ NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
+ delete wrapper;
+}
+
+// ----------------------------------------------------------------------------
+
+static JNINativeMethod gMethods[] = {
+ {"nativeListen", "(Ljava/lang/String;)I",
+ (void*)nativeListen },
+ {"nativeDispose", "(I)V",
+ (void*)nativeDispose },
+};
+
+int register_android_media_RemoteDisplay(JNIEnv* env)
+{
+ int err = AndroidRuntime::registerNativeMethods(env, "android/media/RemoteDisplay",
+ gMethods, NELEM(gMethods));
+
+ jclass clazz = env->FindClass("android/media/RemoteDisplay");
+ gRemoteDisplayClassInfo.notifyDisplayConnected =
+ env->GetMethodID(clazz, "notifyDisplayConnected",
+ "(Landroid/view/Surface;III)V");
+ gRemoteDisplayClassInfo.notifyDisplayDisconnected =
+ env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
+ gRemoteDisplayClassInfo.notifyDisplayError =
+ env->GetMethodID(clazz, "notifyDisplayError", "(I)V");
+ return err;
+}
+
+};