com_android_server_tv_TvInputHal.cpp revision 1f589759969f170fe58303d495b1a3e096c91780
1/* 2 * Copyright 2014 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 "TvInputHal" 18 19//#define LOG_NDEBUG 0 20 21#include "android_runtime/AndroidRuntime.h" 22#include "android_runtime/android_view_Surface.h" 23#include "JNIHelp.h" 24#include "jni.h" 25 26#include <gui/Surface.h> 27#include <utils/Errors.h> 28#include <utils/KeyedVector.h> 29#include <utils/Log.h> 30#include <utils/NativeHandle.h> 31#include <hardware/tv_input.h> 32 33namespace android { 34 35static struct { 36 jmethodID deviceAvailable; 37 jmethodID deviceUnavailable; 38 jmethodID streamConfigsChanged; 39} gTvInputHalClassInfo; 40 41static struct { 42 jclass clazz; 43} gTvStreamConfigClassInfo; 44 45static struct { 46 jclass clazz; 47 48 jmethodID constructor; 49 jmethodID streamId; 50 jmethodID type; 51 jmethodID maxWidth; 52 jmethodID maxHeight; 53 jmethodID generation; 54 jmethodID build; 55} gTvStreamConfigBuilderClassInfo; 56 57//////////////////////////////////////////////////////////////////////////////// 58 59class JTvInputHal { 60public: 61 ~JTvInputHal(); 62 63 static JTvInputHal* createInstance(JNIEnv* env, jobject thiz); 64 65 void setSurface(int deviceId, int streamId, const sp<Surface>& surface); 66 void getStreamConfigs(int deviceId, jobjectArray* array); 67 const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs); 68 69private: 70 class Connection { 71 public: 72 Connection() : mStreamId(0) {} 73 74 sp<Surface> mSurface; 75 sp<NativeHandle> mSourceHandle; 76 int mStreamId; 77 }; 78 79 JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev); 80 81 static void notify( 82 tv_input_device_t* dev,tv_input_event_t* event, void* data); 83 84 void onDeviceAvailable(const tv_input_device_info_t& info); 85 void onDeviceUnavailable(int deviceId); 86 void onStreamConfigurationsChanged(int deviceId); 87 88 jweak mThiz; 89 tv_input_device_t* mDevice; 90 tv_input_callback_ops_t mCallback; 91 92 KeyedVector<int, Connection> mConnections; 93}; 94 95JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device) { 96 mThiz = env->NewWeakGlobalRef(thiz); 97 mDevice = device; 98 mCallback.notify = &JTvInputHal::notify; 99 100 mDevice->initialize(mDevice, &mCallback, this); 101} 102 103JTvInputHal::~JTvInputHal() { 104 mDevice->common.close((hw_device_t*)mDevice); 105 106 JNIEnv* env = AndroidRuntime::getJNIEnv(); 107 env->DeleteWeakGlobalRef(mThiz); 108 mThiz = NULL; 109} 110 111JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) { 112 tv_input_module_t* module = NULL; 113 status_t err = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID, 114 (hw_module_t const**)&module); 115 if (err) { 116 ALOGE("Couldn't load %s module (%s)", 117 TV_INPUT_HARDWARE_MODULE_ID, strerror(-err)); 118 return 0; 119 } 120 121 tv_input_device_t* device = NULL; 122 err = module->common.methods->open( 123 (hw_module_t*)module, 124 TV_INPUT_DEFAULT_DEVICE, 125 (hw_device_t**)&device); 126 if (err) { 127 ALOGE("Couldn't open %s device (%s)", 128 TV_INPUT_DEFAULT_DEVICE, strerror(-err)); 129 return 0; 130 } 131 132 return new JTvInputHal(env, thiz, device); 133} 134 135void JTvInputHal::setSurface(int deviceId, int streamId, const sp<Surface>& surface) { 136 Connection& connection = mConnections.editValueFor(deviceId); 137 if (connection.mSurface == surface) { 138 // Nothing to do 139 return; 140 } 141 if (Surface::isValid(connection.mSurface)) { 142 connection.mSurface.clear(); 143 } 144 if (surface == NULL) { 145 if (connection.mSurface != NULL) { 146 connection.mSurface->setSidebandStream(NULL); 147 connection.mSurface.clear(); 148 } 149 if (connection.mSourceHandle != NULL) { 150 // Need to reset streams 151 if (mDevice->close_stream( 152 mDevice, deviceId, connection.mStreamId) != 0) { 153 ALOGE("Couldn't remove stream"); 154 return; 155 } 156 connection.mSourceHandle.clear(); 157 } 158 return; 159 } 160 connection.mSurface = surface; 161 if (connection.mSourceHandle == NULL) { 162 // Need to configure stream 163 int numConfigs = 0; 164 const tv_stream_config_t* configs = NULL; 165 if (mDevice->get_stream_configurations( 166 mDevice, deviceId, &numConfigs, &configs) != 0) { 167 ALOGE("Couldn't get stream configs"); 168 return; 169 } 170 int configIndex = -1; 171 for (int i = 0; i < numConfigs; ++i) { 172 if (configs[i].stream_id == streamId) { 173 configIndex = i; 174 break; 175 } 176 } 177 if (configIndex == -1) { 178 ALOGE("Cannot find a config with given stream ID: %d", streamId); 179 return; 180 } 181 // TODO: handle buffer producer profile. 182 if (configs[configIndex].type != 183 TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) { 184 ALOGE("Profiles other than independent video source is not yet " 185 "supported : type = %d", configs[configIndex].type); 186 return; 187 } 188 tv_stream_t stream; 189 stream.stream_id = configs[configIndex].stream_id; 190 if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) { 191 ALOGE("Couldn't add stream"); 192 return; 193 } 194 connection.mSourceHandle = NativeHandle::create( 195 stream.sideband_stream_source_handle, false); 196 connection.mStreamId = stream.stream_id; 197 connection.mSurface->setSidebandStream(connection.mSourceHandle); 198 } 199} 200 201const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) { 202 const tv_stream_config_t* configs = NULL; 203 if (mDevice->get_stream_configurations( 204 mDevice, deviceId, numConfigs, &configs) != 0) { 205 ALOGE("Couldn't get stream configs"); 206 return NULL; 207 } 208 return configs; 209} 210 211 212// static 213void JTvInputHal::notify( 214 tv_input_device_t* dev, tv_input_event_t* event, void* data) { 215 JTvInputHal* thiz = (JTvInputHal*)data; 216 switch (event->type) { 217 case TV_INPUT_EVENT_DEVICE_AVAILABLE: { 218 thiz->onDeviceAvailable(event->device_info); 219 } break; 220 case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: { 221 thiz->onDeviceUnavailable(event->device_info.device_id); 222 } break; 223 case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: { 224 thiz->onStreamConfigurationsChanged(event->device_info.device_id); 225 } break; 226 default: 227 ALOGE("Unrecognizable event"); 228 } 229} 230 231void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) { 232 JNIEnv* env = AndroidRuntime::getJNIEnv(); 233 mConnections.add(info.device_id, Connection()); 234 env->CallVoidMethod( 235 mThiz, 236 gTvInputHalClassInfo.deviceAvailable, 237 info.device_id, 238 info.type); 239} 240 241void JTvInputHal::onDeviceUnavailable(int deviceId) { 242 JNIEnv* env = AndroidRuntime::getJNIEnv(); 243 mConnections.removeItem(deviceId); 244 env->CallVoidMethod( 245 mThiz, 246 gTvInputHalClassInfo.deviceUnavailable, 247 deviceId); 248} 249 250void JTvInputHal::onStreamConfigurationsChanged(int deviceId) { 251 JNIEnv* env = AndroidRuntime::getJNIEnv(); 252 mConnections.removeItem(deviceId); 253 env->CallVoidMethod( 254 mThiz, 255 gTvInputHalClassInfo.streamConfigsChanged, 256 deviceId); 257} 258 259//////////////////////////////////////////////////////////////////////////////// 260 261static jlong nativeOpen(JNIEnv* env, jobject thiz) { 262 return (jlong)JTvInputHal::createInstance(env, thiz); 263} 264 265static void nativeSetSurface(JNIEnv* env, jclass clazz, 266 jlong ptr, jint deviceId, jint streamId, jobject jsurface) { 267 JTvInputHal* tvInputHal = (JTvInputHal*)ptr; 268 sp<Surface> surface( 269 jsurface 270 ? android_view_Surface_getSurface(env, jsurface) 271 : NULL); 272 tvInputHal->setSurface(deviceId, streamId, surface); 273} 274 275static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz, 276 jlong ptr, jint deviceId, jint generation) { 277 JTvInputHal* tvInputHal = (JTvInputHal*)ptr; 278 int numConfigs = 0; 279 const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs); 280 281 jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL); 282 for (int i = 0; i < numConfigs; ++i) { 283 jobject builder = env->NewObject( 284 gTvStreamConfigBuilderClassInfo.clazz, 285 gTvStreamConfigBuilderClassInfo.constructor); 286 env->CallObjectMethod( 287 builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id); 288 env->CallObjectMethod( 289 builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type); 290 env->CallObjectMethod( 291 builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width); 292 env->CallObjectMethod( 293 builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height); 294 env->CallObjectMethod( 295 builder, gTvStreamConfigBuilderClassInfo.generation, generation); 296 297 jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build); 298 299 env->SetObjectArrayElement(result, i, config); 300 301 env->DeleteLocalRef(config); 302 env->DeleteLocalRef(builder); 303 } 304 return result; 305} 306 307static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) { 308 JTvInputHal* tvInputHal = (JTvInputHal*)ptr; 309 delete tvInputHal; 310} 311 312static JNINativeMethod gTvInputHalMethods[] = { 313 /* name, signature, funcPtr */ 314 { "nativeOpen", "()J", 315 (void*) nativeOpen }, 316 { "nativeSetSurface", "(JIILandroid/view/Surface;)V", 317 (void*) nativeSetSurface }, 318 { "nativeGetStreamConfigs", "(JII)[Landroid/tv/TvStreamConfig;", 319 (void*) nativeSetSurface }, 320 { "nativeClose", "(J)V", 321 (void*) nativeClose }, 322}; 323 324#define FIND_CLASS(var, className) \ 325 var = env->FindClass(className); \ 326 LOG_FATAL_IF(! var, "Unable to find class " className) 327 328#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ 329 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ 330 LOG_FATAL_IF(! var, "Unable to find method" methodName) 331 332int register_android_server_tv_TvInputHal(JNIEnv* env) { 333 int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal", 334 gTvInputHalMethods, NELEM(gTvInputHalMethods)); 335 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 336 337 jclass clazz; 338 FIND_CLASS(clazz, "android/tv/TvInputHal"); 339 340 GET_METHOD_ID( 341 gTvInputHalClassInfo.deviceAvailable, clazz, "deviceAvailableFromNative", "(II)V"); 342 GET_METHOD_ID( 343 gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V"); 344 GET_METHOD_ID( 345 gTvInputHalClassInfo.streamConfigsChanged, clazz, 346 "streamConfigsChangedFromNative", "(I)V"); 347 348 FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/tv/TvStreamConfig"); 349 gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz)); 350 351 FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/tv/TvStreamConfig/Builder"); 352 gTvStreamConfigBuilderClassInfo.clazz = 353 jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz)); 354 355 GET_METHOD_ID( 356 gTvStreamConfigBuilderClassInfo.constructor, 357 gTvStreamConfigBuilderClassInfo.clazz, 358 "<init>", "()V"); 359 GET_METHOD_ID( 360 gTvStreamConfigBuilderClassInfo.streamId, 361 gTvStreamConfigBuilderClassInfo.clazz, 362 "streamId", "(I)Landroid/tv/TvStreamConfig/Builder;"); 363 GET_METHOD_ID( 364 gTvStreamConfigBuilderClassInfo.type, 365 gTvStreamConfigBuilderClassInfo.clazz, 366 "type", "(I)Landroid/tv/TvStreamConfig/Builder;"); 367 GET_METHOD_ID( 368 gTvStreamConfigBuilderClassInfo.maxWidth, 369 gTvStreamConfigBuilderClassInfo.clazz, 370 "maxWidth", "(I)Landroid/tv/TvStreamConfig/Builder;"); 371 GET_METHOD_ID( 372 gTvStreamConfigBuilderClassInfo.maxHeight, 373 gTvStreamConfigBuilderClassInfo.clazz, 374 "maxHeight", "(I)Landroid/tv/TvStreamConfig/Builder;"); 375 GET_METHOD_ID( 376 gTvStreamConfigBuilderClassInfo.generation, 377 gTvStreamConfigBuilderClassInfo.clazz, 378 "generation", "(I)Landroid/tv/TvStreamConfig/Builder;"); 379 GET_METHOD_ID( 380 gTvStreamConfigBuilderClassInfo.build, 381 gTvStreamConfigBuilderClassInfo.clazz, 382 "build", "()Landroid/tv/TvStreamConfig;"); 383 384 return 0; 385} 386 387} /* namespace android */ 388