blob: 5d24f619c896310126c18df64b665a747bb1ee49 [file] [log] [blame]
Jeff Browncbad9762012-09-04 21:57:59 -07001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "RemoteDisplay"
18
19#include "jni.h"
20#include "JNIHelp.h"
21
22#include "android_os_Parcel.h"
23#include "android_util_Binder.h"
24
25#include <android_runtime/AndroidRuntime.h>
26#include <android_runtime/android_view_Surface.h>
27
28#include <binder/IServiceManager.h>
29
30#include <gui/ISurfaceTexture.h>
31
32#include <media/IMediaPlayerService.h>
33#include <media/IRemoteDisplay.h>
34#include <media/IRemoteDisplayClient.h>
35
36#include <utils/Log.h>
37
38#include <ScopedUtfChars.h>
39
40namespace android {
41
42static struct {
43 jmethodID notifyDisplayConnected;
44 jmethodID notifyDisplayDisconnected;
45 jmethodID notifyDisplayError;
46} gRemoteDisplayClassInfo;
47
48// ----------------------------------------------------------------------------
49
50class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
51public:
52 NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
53 mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
54 }
55
56protected:
57 ~NativeRemoteDisplayClient() {
58 JNIEnv* env = AndroidRuntime::getJNIEnv();
59 env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
60 }
61
62public:
63 virtual void onDisplayConnected(const sp<ISurfaceTexture>& surfaceTexture,
64 uint32_t width, uint32_t height, uint32_t flags) {
65 JNIEnv* env = AndroidRuntime::getJNIEnv();
66
67 jobject surfaceObj = android_view_Surface_createFromISurfaceTexture(env, surfaceTexture);
68 if (surfaceObj == NULL) {
69 ALOGE("Could not create Surface from surface texture %p provided by media server.",
70 surfaceTexture.get());
71 return;
72 }
73
74 env->CallVoidMethod(mRemoteDisplayObjGlobal,
75 gRemoteDisplayClassInfo.notifyDisplayConnected,
76 surfaceObj, width, height, flags);
77 env->DeleteLocalRef(surfaceObj);
78 checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
79 }
80
81 virtual void onDisplayDisconnected() {
82 JNIEnv* env = AndroidRuntime::getJNIEnv();
83
84 env->CallVoidMethod(mRemoteDisplayObjGlobal,
85 gRemoteDisplayClassInfo.notifyDisplayDisconnected);
86 checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
87 }
88
89 virtual void onDisplayError(int32_t error) {
90 JNIEnv* env = AndroidRuntime::getJNIEnv();
91
92 env->CallVoidMethod(mRemoteDisplayObjGlobal,
93 gRemoteDisplayClassInfo.notifyDisplayError, error);
94 checkAndClearExceptionFromCallback(env, "notifyDisplayError");
95 }
96
97private:
98 jobject mRemoteDisplayObjGlobal;
99
100 static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
101 if (env->ExceptionCheck()) {
102 ALOGE("An exception was thrown by callback '%s'.", methodName);
103 LOGE_EX(env);
104 env->ExceptionClear();
105 }
106 }
107};
108
109class NativeRemoteDisplay {
110public:
111 NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
112 const sp<NativeRemoteDisplayClient>& client) :
113 mDisplay(display), mClient(client) {
114 }
115
116 ~NativeRemoteDisplay() {
117 mDisplay->dispose();
118 }
119
120private:
121 sp<IRemoteDisplay> mDisplay;
122 sp<NativeRemoteDisplayClient> mClient;
123};
124
125
126// ----------------------------------------------------------------------------
127
128static jint nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr) {
129 ScopedUtfChars iface(env, ifaceStr);
130
131 sp<IServiceManager> sm = defaultServiceManager();
132 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
133 sm->getService(String16("media.player")));
134 if (service == NULL) {
135 ALOGE("Could not obtain IMediaPlayerService from service manager");
136 return 0;
137 }
138
139 sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
140 sp<IRemoteDisplay> display = service->listenForRemoteDisplay(
141 client, String8(iface.c_str()));
142 if (display == NULL) {
143 ALOGE("Media player service rejected request to listen for remote display '%s'.",
144 iface.c_str());
145 return 0;
146 }
147
148 NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
149 return reinterpret_cast<jint>(wrapper);
150}
151
152static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
153 NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
154 delete wrapper;
155}
156
157// ----------------------------------------------------------------------------
158
159static JNINativeMethod gMethods[] = {
160 {"nativeListen", "(Ljava/lang/String;)I",
161 (void*)nativeListen },
162 {"nativeDispose", "(I)V",
163 (void*)nativeDispose },
164};
165
166int register_android_media_RemoteDisplay(JNIEnv* env)
167{
168 int err = AndroidRuntime::registerNativeMethods(env, "android/media/RemoteDisplay",
169 gMethods, NELEM(gMethods));
170
171 jclass clazz = env->FindClass("android/media/RemoteDisplay");
172 gRemoteDisplayClassInfo.notifyDisplayConnected =
173 env->GetMethodID(clazz, "notifyDisplayConnected",
174 "(Landroid/view/Surface;III)V");
175 gRemoteDisplayClassInfo.notifyDisplayDisconnected =
176 env->GetMethodID(clazz, "notifyDisplayDisconnected", "()V");
177 gRemoteDisplayClassInfo.notifyDisplayError =
178 env->GetMethodID(clazz, "notifyDisplayError", "(I)V");
179 return err;
180}
181
182};