• 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 #undef ANDROID_UTILS_REF_BASE_DISABLE_IMPLICIT_CONSTRUCTION // TODO:remove this and fix code
17 
18 #define LOG_TAG "RemoteDisplay"
19 
20 #include "jni.h"
21 #include <nativehelper/JNIHelp.h>
22 
23 #include "android_os_Parcel.h"
24 #include "android_util_Binder.h"
25 
26 #include "core_jni_helpers.h"
27 #include <android_runtime/android_view_Surface.h>
28 #include <android_runtime/Log.h>
29 
30 #include <binder/IServiceManager.h>
31 
32 #include <gui/IGraphicBufferProducer.h>
33 
34 #include <media/IMediaPlayerService.h>
35 #include <media/IRemoteDisplay.h>
36 #include <media/IRemoteDisplayClient.h>
37 
38 #include <utils/Log.h>
39 
40 #include <nativehelper/ScopedUtfChars.h>
41 
42 namespace android {
43 
44 static struct {
45     jmethodID notifyDisplayConnected;
46     jmethodID notifyDisplayDisconnected;
47     jmethodID notifyDisplayError;
48 } gRemoteDisplayClassInfo;
49 
50 // ----------------------------------------------------------------------------
51 
52 class NativeRemoteDisplayClient : public BnRemoteDisplayClient {
53 public:
NativeRemoteDisplayClient(JNIEnv * env,jobject remoteDisplayObj)54     NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
55             mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
56     }
57 
58 protected:
~NativeRemoteDisplayClient()59     ~NativeRemoteDisplayClient() {
60         JNIEnv* env = AndroidRuntime::getJNIEnv();
61         env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
62     }
63 
64 public:
onDisplayConnected(const sp<IGraphicBufferProducer> & bufferProducer,uint32_t width,uint32_t height,uint32_t flags,uint32_t session)65     virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
66             uint32_t width, uint32_t height, uint32_t flags, uint32_t session) {
67         JNIEnv* env = AndroidRuntime::getJNIEnv();
68 
69         jobject surfaceObj = android_view_Surface_createFromIGraphicBufferProducer(env, bufferProducer);
70         if (surfaceObj == NULL) {
71             ALOGE("Could not create Surface from surface texture %p provided by media server.",
72                   bufferProducer.get());
73             return;
74         }
75 
76         env->CallVoidMethod(mRemoteDisplayObjGlobal,
77                 gRemoteDisplayClassInfo.notifyDisplayConnected,
78                 surfaceObj, width, height, flags, session);
79         env->DeleteLocalRef(surfaceObj);
80         checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
81     }
82 
onDisplayDisconnected()83     virtual void onDisplayDisconnected() {
84         JNIEnv* env = AndroidRuntime::getJNIEnv();
85 
86         env->CallVoidMethod(mRemoteDisplayObjGlobal,
87                 gRemoteDisplayClassInfo.notifyDisplayDisconnected);
88         checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
89     }
90 
onDisplayError(int32_t error)91     virtual void onDisplayError(int32_t error) {
92         JNIEnv* env = AndroidRuntime::getJNIEnv();
93 
94         env->CallVoidMethod(mRemoteDisplayObjGlobal,
95                 gRemoteDisplayClassInfo.notifyDisplayError, error);
96         checkAndClearExceptionFromCallback(env, "notifyDisplayError");
97     }
98 
99 private:
100     jobject mRemoteDisplayObjGlobal;
101 
checkAndClearExceptionFromCallback(JNIEnv * env,const char * methodName)102     static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
103         if (env->ExceptionCheck()) {
104             ALOGE("An exception was thrown by callback '%s'.", methodName);
105             LOGE_EX(env);
106             env->ExceptionClear();
107         }
108     }
109 };
110 
111 class NativeRemoteDisplay {
112 public:
NativeRemoteDisplay(const sp<IRemoteDisplay> & display,const sp<NativeRemoteDisplayClient> & client)113     NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
114             const sp<NativeRemoteDisplayClient>& client) :
115             mDisplay(display), mClient(client) {
116     }
117 
~NativeRemoteDisplay()118     ~NativeRemoteDisplay() {
119         mDisplay->dispose();
120     }
121 
pause()122     void pause() {
123         mDisplay->pause();
124     }
125 
resume()126     void resume() {
127         mDisplay->resume();
128     }
129 
130 private:
131     sp<IRemoteDisplay> mDisplay;
132     sp<NativeRemoteDisplayClient> mClient;
133 };
134 
135 
136 // ----------------------------------------------------------------------------
137 
nativeListen(JNIEnv * env,jobject remoteDisplayObj,jstring ifaceStr,jstring opPackageNameStr)138 static jlong nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr,
139         jstring opPackageNameStr) {
140     ScopedUtfChars iface(env, ifaceStr);
141     ScopedUtfChars opPackageName(env, opPackageNameStr);
142 
143     sp<IServiceManager> sm = defaultServiceManager();
144     sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
145             sm->getService(String16("media.player")));
146     if (service == NULL) {
147         ALOGE("Could not obtain IMediaPlayerService from service manager");
148         return 0;
149     }
150 
151     sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
152     sp<IRemoteDisplay> display = service->listenForRemoteDisplay(String16(opPackageName.c_str()),
153             client, String8(iface.c_str()));
154     if (display == NULL) {
155         ALOGE("Media player service rejected request to listen for remote display '%s'.",
156                 iface.c_str());
157         return 0;
158     }
159 
160     NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
161     return reinterpret_cast<jlong>(wrapper);
162 }
163 
nativePause(JNIEnv * env,jobject remoteDisplayObj,jlong ptr)164 static void nativePause(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
165     NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
166     wrapper->pause();
167 }
168 
nativeResume(JNIEnv * env,jobject remoteDisplayObj,jlong ptr)169 static void nativeResume(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
170     NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
171     wrapper->resume();
172 }
173 
nativeDispose(JNIEnv * env,jobject remoteDisplayObj,jlong ptr)174 static void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
175     NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
176     delete wrapper;
177 }
178 
179 // ----------------------------------------------------------------------------
180 
181 static const JNINativeMethod gMethods[] = {
nativeListen(Ljava/lang/String;Ljava/lang/String;)182     {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J",
183             (void*)nativeListen },
nativeDispose(J)184     {"nativeDispose", "(J)V",
185             (void*)nativeDispose },
nativePause(J)186     {"nativePause", "(J)V",
187             (void*)nativePause },
nativeResume(J)188     {"nativeResume", "(J)V",
189             (void*)nativeResume },
190 };
191 
register_android_media_RemoteDisplay(JNIEnv * env)192 int register_android_media_RemoteDisplay(JNIEnv* env)
193 {
194     int err = RegisterMethodsOrDie(env, "android/media/RemoteDisplay", gMethods, NELEM(gMethods));
195 
196     jclass clazz = FindClassOrDie(env, "android/media/RemoteDisplay");
197     gRemoteDisplayClassInfo.notifyDisplayConnected = GetMethodIDOrDie(env,
198             clazz, "notifyDisplayConnected", "(Landroid/view/Surface;IIII)V");
199     gRemoteDisplayClassInfo.notifyDisplayDisconnected = GetMethodIDOrDie(env,
200             clazz, "notifyDisplayDisconnected", "()V");
201     gRemoteDisplayClassInfo.notifyDisplayError = GetMethodIDOrDie(env,
202             clazz, "notifyDisplayError", "(I)V");
203     return err;
204 }
205 
206 };
207