1cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown/*
2cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Copyright (C) 2012 The Android Open Source Project
3cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *
4cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * you may not use this file except in compliance with the License.
6cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * You may obtain a copy of the License at
7cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *
8cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown *
10cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * Unless required by applicable law or agreed to in writing, software
11cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * See the License for the specific language governing permissions and
14cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown * limitations under the License.
15cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown */
16cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
17cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#define LOG_TAG "RemoteDisplay"
18cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
19cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include "jni.h"
20cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include "JNIHelp.h"
21cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
22cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include "android_os_Parcel.h"
23cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include "android_util_Binder.h"
24cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
25ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe#include "core_jni_helpers.h"
26cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include <android_runtime/android_view_Surface.h>
2787eac99a21772ae56018cb81db6966557b459554Ruben Brunk#include <android_runtime/Log.h>
28cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
29cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include <binder/IServiceManager.h>
30cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
31d47f7d8b5fe3a3861d7cbdc5f912235407823c8eAndy McFadden#include <gui/IGraphicBufferProducer.h>
32cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
33cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include <media/IMediaPlayerService.h>
34cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include <media/IRemoteDisplay.h>
35cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include <media/IRemoteDisplayClient.h>
36cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
37cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include <utils/Log.h>
38cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
39cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown#include <ScopedUtfChars.h>
40cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
41cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownnamespace android {
42cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
43cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownstatic struct {
44cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    jmethodID notifyDisplayConnected;
45cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    jmethodID notifyDisplayDisconnected;
46cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    jmethodID notifyDisplayError;
47cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown} gRemoteDisplayClassInfo;
48cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
49cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown// ----------------------------------------------------------------------------
50cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
51cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownclass NativeRemoteDisplayClient : public BnRemoteDisplayClient {
52cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownpublic:
53cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    NativeRemoteDisplayClient(JNIEnv* env, jobject remoteDisplayObj) :
54cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mRemoteDisplayObjGlobal(env->NewGlobalRef(remoteDisplayObj)) {
55cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
56cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
57cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownprotected:
58cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    ~NativeRemoteDisplayClient() {
59cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        JNIEnv* env = AndroidRuntime::getJNIEnv();
60cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        env->DeleteGlobalRef(mRemoteDisplayObjGlobal);
61cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
62cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
63cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownpublic:
64d47f7d8b5fe3a3861d7cbdc5f912235407823c8eAndy McFadden    virtual void onDisplayConnected(const sp<IGraphicBufferProducer>& bufferProducer,
651f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            uint32_t width, uint32_t height, uint32_t flags, uint32_t session) {
66cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        JNIEnv* env = AndroidRuntime::getJNIEnv();
67cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
6829479ebe1007361222bf6ab4d5e2a27927d4b8e8Mathias Agopian        jobject surfaceObj = android_view_Surface_createFromIGraphicBufferProducer(env, bufferProducer);
69cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (surfaceObj == NULL) {
70cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ALOGE("Could not create Surface from surface texture %p provided by media server.",
71d47f7d8b5fe3a3861d7cbdc5f912235407823c8eAndy McFadden                  bufferProducer.get());
72cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            return;
73cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
74cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
75cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        env->CallVoidMethod(mRemoteDisplayObjGlobal,
76cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                gRemoteDisplayClassInfo.notifyDisplayConnected,
771f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang                surfaceObj, width, height, flags, session);
78cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        env->DeleteLocalRef(surfaceObj);
79cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        checkAndClearExceptionFromCallback(env, "notifyDisplayConnected");
80cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
81cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
82cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    virtual void onDisplayDisconnected() {
83cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        JNIEnv* env = AndroidRuntime::getJNIEnv();
84cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
85cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        env->CallVoidMethod(mRemoteDisplayObjGlobal,
86cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                gRemoteDisplayClassInfo.notifyDisplayDisconnected);
87cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        checkAndClearExceptionFromCallback(env, "notifyDisplayDisconnected");
88cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
89cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
90cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    virtual void onDisplayError(int32_t error) {
91cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        JNIEnv* env = AndroidRuntime::getJNIEnv();
92cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
93cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        env->CallVoidMethod(mRemoteDisplayObjGlobal,
94cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                gRemoteDisplayClassInfo.notifyDisplayError, error);
95cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        checkAndClearExceptionFromCallback(env, "notifyDisplayError");
96cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
97cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
98cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownprivate:
99cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    jobject mRemoteDisplayObjGlobal;
100cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
101cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
102cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        if (env->ExceptionCheck()) {
103cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            ALOGE("An exception was thrown by callback '%s'.", methodName);
104cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            LOGE_EX(env);
105cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            env->ExceptionClear();
106cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        }
107cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
108cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown};
109cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
110cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownclass NativeRemoteDisplay {
111cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownpublic:
112cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    NativeRemoteDisplay(const sp<IRemoteDisplay>& display,
113cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            const sp<NativeRemoteDisplayClient>& client) :
114cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            mDisplay(display), mClient(client) {
115cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
116cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
117cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    ~NativeRemoteDisplay() {
118cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        mDisplay->dispose();
119cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
120cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
1211f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    void pause() {
1221f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        mDisplay->pause();
1231f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
1241f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
1251f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    void resume() {
1261f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang        mDisplay->resume();
1271f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    }
1281f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
129cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownprivate:
130cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    sp<IRemoteDisplay> mDisplay;
131cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    sp<NativeRemoteDisplayClient> mClient;
132cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown};
133cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
134cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
135cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown// ----------------------------------------------------------------------------
136cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
137fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganovstatic jlong nativeListen(JNIEnv* env, jobject remoteDisplayObj, jstring ifaceStr,
138fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov        jstring opPackageNameStr) {
139cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    ScopedUtfChars iface(env, ifaceStr);
140fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov    ScopedUtfChars opPackageName(env, opPackageNameStr);
141cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
142cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    sp<IServiceManager> sm = defaultServiceManager();
143cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(
144cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            sm->getService(String16("media.player")));
145cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    if (service == NULL) {
146cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        ALOGE("Could not obtain IMediaPlayerService from service manager");
147cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return 0;
148cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
149cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
150cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    sp<NativeRemoteDisplayClient> client(new NativeRemoteDisplayClient(env, remoteDisplayObj));
151fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov    sp<IRemoteDisplay> display = service->listenForRemoteDisplay(String16(opPackageName.c_str()),
152cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            client, String8(iface.c_str()));
153cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    if (display == NULL) {
154cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        ALOGE("Media player service rejected request to listen for remote display '%s'.",
155cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown                iface.c_str());
156cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown        return 0;
157cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    }
158cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
159cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    NativeRemoteDisplay* wrapper = new NativeRemoteDisplay(display, client);
160075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    return reinterpret_cast<jlong>(wrapper);
161cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
162cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
163075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhatstatic void nativePause(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
1641f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
1651f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    wrapper->pause();
1661f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang}
1671f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
168075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhatstatic void nativeResume(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
1691f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
1701f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang    wrapper->resume();
1711f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang}
1721f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang
173075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhatstatic void nativeDispose(JNIEnv* env, jobject remoteDisplayObj, jlong ptr) {
174cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    NativeRemoteDisplay* wrapper = reinterpret_cast<NativeRemoteDisplay*>(ptr);
175cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    delete wrapper;
176cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
177cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
178cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown// ----------------------------------------------------------------------------
179cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
18076f6a86de25e1bf74717e047e55fd44b089673f3Daniel Micaystatic const JNINativeMethod gMethods[] = {
181fa5ecdc4ac6d7a8db2bb9e4a6a60a3189025df30Svet Ganov    {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J",
182cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            (void*)nativeListen },
183075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    {"nativeDispose", "(J)V",
184cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown            (void*)nativeDispose },
185075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    {"nativePause", "(J)V",
1861f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            (void*)nativePause },
187075e9a19ce645752f8282bc19c91b25978a7dc52Ashok Bhat    {"nativeResume", "(J)V",
1881f3ecaae6303d5ee6c5ca8499262c9962f036365Chong Zhang            (void*)nativeResume },
189cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown};
190cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
191cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brownint register_android_media_RemoteDisplay(JNIEnv* env)
192cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown{
193ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    int err = RegisterMethodsOrDie(env, "android/media/RemoteDisplay", gMethods, NELEM(gMethods));
194ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe
195ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    jclass clazz = FindClassOrDie(env, "android/media/RemoteDisplay");
196ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    gRemoteDisplayClassInfo.notifyDisplayConnected = GetMethodIDOrDie(env,
197ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            clazz, "notifyDisplayConnected", "(Landroid/view/Surface;IIII)V");
198ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    gRemoteDisplayClassInfo.notifyDisplayDisconnected = GetMethodIDOrDie(env,
199ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            clazz, "notifyDisplayDisconnected", "()V");
200ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe    gRemoteDisplayClassInfo.notifyDisplayError = GetMethodIDOrDie(env,
201ed6b9dff563c5e22f040ff37e12c0d771e0478aeAndreas Gampe            clazz, "notifyDisplayError", "(I)V");
202cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown    return err;
203cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown}
204cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown
205cbad976b2a36a0895ca94510d5208a86f66cf596Jeff Brown};
206