• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
40 namespace android {
41 
42 static struct {
43     jmethodID notifyDisplayConnected;
44     jmethodID notifyDisplayDisconnected;
45     jmethodID notifyDisplayError;
46 } gRemoteDisplayClassInfo;
47 
48 // ----------------------------------------------------------------------------
49 
50 class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
51 public:
NativeRemoteDisplayClient(JNIEnv * env,jobject remoteDisplayObj)52     NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
53             mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
54     }
55 
56 protected:
~NativeRemoteDisplayClient()57     ~NativeRemoteDisplayClient() {
58         JNIEnv* env = AndroidRuntime::getJNIEnv();
59         env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
60     }
61 
62 public:
onDisplayConnected(const sp<ISurfaceTexture> & surfaceTexture,uint32_t width,uint32_t height,uint32_t flags)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 
onDisplayDisconnected()81     virtual void onDisplayDisconnected() {
82         JNIEnv* env = AndroidRuntime::getJNIEnv();
83 
84         env->CallVoidMethod(mRemoteDisplayObjGlobal,
85                 gRemoteDisplayClassInfo.notifyDisplayDisconnected);
86         checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
87     }
88 
onDisplayError(int32_t error)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 
97 private:
98     jobject mRemoteDisplayObjGlobal;
99 
checkAndClearExceptionFromCallback(JNIEnv * env,const char * methodName)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 
109 class NativeRemoteDisplay {
110 public:
NativeRemoteDisplay(const sp<IRemoteDisplay> & display,const sp<NativeRemoteDisplayClient> & client)111     NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
112             const sp<NativeRemoteDisplayClient>& client) :
113             mDisplay(display), mClient(client) {
114     }
115 
~NativeRemoteDisplay()116     ~NativeRemoteDisplay() {
117         mDisplay->dispose();
118     }
119 
120 private:
121     sp<IRemoteDisplay> mDisplay;
122     sp<NativeRemoteDisplayClient> mClient;
123 };
124 
125 
126 // ----------------------------------------------------------------------------
127 
nativeListen(JNIEnv * env,jobject remoteDisplayObj,jstring ifaceStr)128 static 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 
nativeDispose(JNIEnv * env,jobject remoteDisplayObj,jint ptr)152 static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jint ptr) {
153     NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
154     delete wrapper;
155 }
156 
157 // ----------------------------------------------------------------------------
158 
159 static JNINativeMethod gMethods[] = {
160     {"nativeListen", "(Ljava/lang/String;)I",
161             (void*)nativeListen },
162     {"nativeDispose", "(I)V",
163             (void*)nativeDispose },
164 };
165 
register_android_media_RemoteDisplay(JNIEnv * env)166 int 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 };
183