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);
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;
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;
private final AudioDevicePort mAudioSink;
private AudioPatch mAudioPatch = null;
+ private TvStreamConfig mActiveConfig = null;
+
public TvInputHardwareImpl(TvInputHardwareInfo info) {
mInfo = info;
AudioDevicePort audioSource = null;
}
}
+ // 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 {
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.
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;
}
}
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);
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) {
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
}
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(
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,
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,
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,
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,
/* 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",