OSDN Git Service

TIF: Let TvInputHal handle multiple streams
authorWonsik Kim <wonsik@google.com>
Thu, 3 Jul 2014 10:06:56 +0000 (19:06 +0900)
committerWonsik Kim <wonsik@google.com>
Mon, 7 Jul 2014 05:36:26 +0000 (14:36 +0900)
Bug: 15579918
Change-Id: Iad972c36d675fb99b5950bcecf5925e660272cb4

services/core/java/com/android/server/tv/TvInputHal.java
services/core/java/com/android/server/tv/TvInputHardwareManager.java
services/core/jni/com_android_server_tv_TvInputHal.cpp

index 23c0a4c..855e539 100644 (file)
@@ -57,8 +57,9 @@ final class TvInputHal implements Handler.Callback {
 
     private native long nativeOpen();
 
-    private static native int nativeSetSurface(long ptr, int deviceId, int streamId,
+    private static native int nativeAddStream(long ptr, int deviceId, int streamId,
             Surface surface);
+    private static native int nativeRemoveStream(long ptr, int deviceId, int streamId);
     private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId,
             int generation);
     private static native void nativeClose(long ptr);
@@ -81,7 +82,7 @@ final class TvInputHal implements Handler.Callback {
         mHandler.sendEmptyMessage(EVENT_OPEN);
     }
 
-    public int setSurface(int deviceId, Surface surface, TvStreamConfig streamConfig) {
+    public int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) {
         long ptr = mPtr;
         if (ptr == 0) {
             return ERROR_NO_INIT;
@@ -89,7 +90,22 @@ final class TvInputHal implements Handler.Callback {
         if (mStreamConfigGeneration != streamConfig.getGeneration()) {
             return ERROR_STALE_CONFIG;
         }
-        if (nativeSetSurface(ptr, deviceId, streamConfig.getStreamId(), surface) == 0) {
+        if (nativeAddStream(ptr, deviceId, streamConfig.getStreamId(), surface) == 0) {
+            return SUCCESS;
+        } else {
+            return ERROR_UNKNOWN;
+        }
+    }
+
+    public int removeStream(int deviceId, TvStreamConfig streamConfig) {
+        long ptr = mPtr;
+        if (ptr == 0) {
+            return ERROR_NO_INIT;
+        }
+        if (mStreamConfigGeneration != streamConfig.getGeneration()) {
+            return ERROR_STALE_CONFIG;
+        }
+        if (nativeRemoveStream(ptr, deviceId, streamConfig.getStreamId()) == 0) {
             return SUCCESS;
         } else {
             return ERROR_UNKNOWN;
index 1146f0f..efe543b 100644 (file)
@@ -269,6 +269,8 @@ class TvInputHardwareManager implements TvInputHal.Callback {
         private final AudioDevicePort mAudioSink;
         private AudioPatch mAudioPatch = null;
 
+        private TvStreamConfig mActiveConfig = null;
+
         public TvInputHardwareImpl(TvInputHardwareInfo info) {
             mInfo = info;
             AudioDevicePort audioSource = null;
@@ -311,6 +313,9 @@ class TvInputHardwareManager implements TvInputHal.Callback {
             }
         }
 
+        // A TvInputHardwareImpl object holds only one active session. Therefore, if a client
+        // attempts to call setSurface with different TvStreamConfig objects, the last call will
+        // prevail.
         @Override
         public boolean setSurface(Surface surface, TvStreamConfig config)
                 throws RemoteException {
@@ -318,6 +323,12 @@ class TvInputHardwareManager implements TvInputHal.Callback {
                 if (mReleased) {
                     throw new IllegalStateException("Device already released.");
                 }
+                if (surface != null && config == null) {
+                    return false;
+                }
+                if (surface == null && mActiveConfig == null) {
+                    return false;
+                }
                 if (mInfo.getType() == TvInputHal.TYPE_HDMI) {
                     if (surface != null) {
                         // Set "Active Source" for HDMI.
@@ -347,7 +358,24 @@ class TvInputHardwareManager implements TvInputHal.Callback {
                         mAudioPatch = null;
                     }
                 }
-                return mHal.setSurface(mInfo.getDeviceId(), surface, config) == TvInputHal.SUCCESS;
+                int result = TvInputHal.ERROR_UNKNOWN;
+                if (surface == null) {
+                    result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig);
+                    mActiveConfig = null;
+                } else {
+                    if (config != mActiveConfig && mActiveConfig != null) {
+                        result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig);
+                        if (result != TvInputHal.SUCCESS) {
+                            mActiveConfig = null;
+                            return false;
+                        }
+                    }
+                    result = mHal.addStream(mInfo.getDeviceId(), surface, config);
+                    if (result == TvInputHal.SUCCESS) {
+                        mActiveConfig = config;
+                    }
+                }
+                return result == TvInputHal.SUCCESS;
             }
         }
 
index 7b8e6fd..64d418a 100644 (file)
@@ -74,17 +74,17 @@ public:
 
     static JTvInputHal* createInstance(JNIEnv* env, jobject thiz);
 
-    int setSurface(int deviceId, int streamId, const sp<Surface>& surface);
+    int addStream(int deviceId, int streamId, const sp<Surface>& surface);
+    int removeStream(int deviceId, int streamId);
     const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs);
 
 private:
     class Connection {
     public:
-        Connection() : mStreamId(0) {}
+        Connection() {}
 
         sp<Surface> mSurface;
         sp<NativeHandle> mSourceHandle;
-        int mStreamId;
     };
 
     JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev);
@@ -100,7 +100,7 @@ private:
     tv_input_device_t* mDevice;
     tv_input_callback_ops_t mCallback;
 
-    KeyedVector<int, Connection> mConnections;
+    KeyedVector<int, KeyedVector<int, Connection> > mConnections;
 };
 
 JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device) {
@@ -143,31 +143,19 @@ JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) {
     return new JTvInputHal(env, thiz, device);
 }
 
-int JTvInputHal::setSurface(int deviceId, int streamId, const sp<Surface>& surface) {
-    Connection& connection = mConnections.editValueFor(deviceId);
-    if (connection.mStreamId == streamId && connection.mSurface == surface) {
+int JTvInputHal::addStream(int deviceId, int streamId, const sp<Surface>& surface) {
+    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+    if (connections.indexOfKey(streamId) < 0) {
+        connections.add(streamId, Connection());
+    }
+    Connection& connection = connections.editValueFor(streamId);
+    if (connection.mSurface == surface) {
         // Nothing to do
         return NO_ERROR;
     }
     if (Surface::isValid(connection.mSurface)) {
         connection.mSurface.clear();
     }
-    if (surface == NULL) {
-        if (connection.mSurface != NULL) {
-            connection.mSurface->setSidebandStream(NULL);
-            connection.mSurface.clear();
-        }
-        if (connection.mSourceHandle != NULL) {
-            // Need to reset streams
-            if (mDevice->close_stream(
-                    mDevice, deviceId, connection.mStreamId) != 0) {
-                ALOGE("Couldn't remove stream");
-                return BAD_VALUE;
-            }
-            connection.mSourceHandle.clear();
-        }
-        return NO_ERROR;
-    }
     connection.mSurface = surface;
     if (connection.mSourceHandle == NULL) {
         // Need to configure stream
@@ -204,12 +192,39 @@ int JTvInputHal::setSurface(int deviceId, int streamId, const sp<Surface>& surfa
         }
         connection.mSourceHandle = NativeHandle::create(
                 stream.sideband_stream_source_handle, false);
-        connection.mStreamId = stream.stream_id;
         connection.mSurface->setSidebandStream(connection.mSourceHandle);
     }
     return NO_ERROR;
 }
 
+int JTvInputHal::removeStream(int deviceId, int streamId) {
+    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+    if (connections.indexOfKey(streamId) < 0) {
+        return BAD_VALUE;
+    }
+    Connection& connection = connections.editValueFor(streamId);
+    if (connection.mSurface == NULL) {
+        // Nothing to do
+        return NO_ERROR;
+    }
+    if (Surface::isValid(connection.mSurface)) {
+        connection.mSurface.clear();
+    }
+    if (connection.mSurface != NULL) {
+        connection.mSurface->setSidebandStream(NULL);
+        connection.mSurface.clear();
+    }
+    if (connection.mSourceHandle != NULL) {
+        // Need to reset streams
+        if (mDevice->close_stream(mDevice, deviceId, streamId) != 0) {
+            ALOGE("Couldn't remove stream");
+            return BAD_VALUE;
+        }
+        connection.mSourceHandle.clear();
+    }
+    return NO_ERROR;
+}
+
 const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) {
     const tv_stream_config_t* configs = NULL;
     if (mDevice->get_stream_configurations(
@@ -241,7 +256,7 @@ void JTvInputHal::notify(
 
 void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    mConnections.add(info.device_id, Connection());
+    mConnections.add(info.device_id, KeyedVector<int, Connection>());
 
     jobject builder = env->NewObject(
             gTvInputHardwareInfoBuilderClassInfo.clazz,
@@ -276,6 +291,11 @@ void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) {
 
 void JTvInputHal::onDeviceUnavailable(int deviceId) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
+    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+    for (size_t i = 0; i < connections.size(); ++i) {
+        removeStream(deviceId, connections.keyAt(i));
+    }
+    connections.clear();
     mConnections.removeItem(deviceId);
     env->CallVoidMethod(
             mThiz,
@@ -285,7 +305,11 @@ void JTvInputHal::onDeviceUnavailable(int deviceId) {
 
 void JTvInputHal::onStreamConfigurationsChanged(int deviceId) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    mConnections.removeItem(deviceId);
+    KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
+    for (size_t i = 0; i < connections.size(); ++i) {
+        removeStream(deviceId, connections.keyAt(i));
+    }
+    connections.clear();
     env->CallVoidMethod(
             mThiz,
             gTvInputHalClassInfo.streamConfigsChanged,
@@ -298,14 +322,20 @@ static jlong nativeOpen(JNIEnv* env, jobject thiz) {
     return (jlong)JTvInputHal::createInstance(env, thiz);
 }
 
-static int nativeSetSurface(JNIEnv* env, jclass clazz,
+static int nativeAddStream(JNIEnv* env, jclass clazz,
         jlong ptr, jint deviceId, jint streamId, jobject jsurface) {
     JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
-    sp<Surface> surface(
-            jsurface
-            ? android_view_Surface_getSurface(env, jsurface)
-            : NULL);
-    return tvInputHal->setSurface(deviceId, streamId, surface);
+    if (!jsurface) {
+        return BAD_VALUE;
+    }
+    sp<Surface> surface(android_view_Surface_getSurface(env, jsurface));
+    return tvInputHal->addStream(deviceId, streamId, surface);
+}
+
+static int nativeRemoveStream(JNIEnv* env, jclass clazz,
+        jlong ptr, jint deviceId, jint streamId) {
+    JTvInputHal* tvInputHal = (JTvInputHal*)ptr;
+    return tvInputHal->removeStream(deviceId, streamId);
 }
 
 static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz,
@@ -349,8 +379,10 @@ static JNINativeMethod gTvInputHalMethods[] = {
     /* name, signature, funcPtr */
     { "nativeOpen", "()J",
             (void*) nativeOpen },
-    { "nativeSetSurface", "(JIILandroid/view/Surface;)I",
-            (void*) nativeSetSurface },
+    { "nativeAddStream", "(JIILandroid/view/Surface;)I",
+            (void*) nativeAddStream },
+    { "nativeRemoveStream", "(JII)I",
+            (void*) nativeRemoveStream },
     { "nativeGetStreamConfigs", "(JII)[Landroid/media/tv/TvStreamConfig;",
             (void*) nativeGetStreamConfigs },
     { "nativeClose", "(J)V",