com_android_server_tv_TvInputHal.cpp revision a617074c531dfa317e5051fa70ec6b6c21d14386
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_os_MessageQueue.h" 22#include "android_runtime/AndroidRuntime.h" 23#include "android_runtime/android_view_Surface.h" 24#include "JNIHelp.h" 25#include "jni.h" 26 27#include <gui/Surface.h> 28#include <utils/Errors.h> 29#include <utils/KeyedVector.h> 30#include <utils/Log.h> 31#include <utils/Looper.h> 32#include <utils/NativeHandle.h> 33#include <hardware/tv_input.h> 34 35namespace android { 36 37static struct { 38 jmethodID deviceAvailable; 39 jmethodID deviceUnavailable; 40 jmethodID streamConfigsChanged; 41 jmethodID firstFrameCaptured; 42} gTvInputHalClassInfo; 43 44static struct { 45 jclass clazz; 46} gTvStreamConfigClassInfo; 47 48static struct { 49 jclass clazz; 50 51 jmethodID constructor; 52 jmethodID streamId; 53 jmethodID type; 54 jmethodID maxWidth; 55 jmethodID maxHeight; 56 jmethodID generation; 57 jmethodID build; 58} gTvStreamConfigBuilderClassInfo; 59 60static struct { 61 jclass clazz; 62 63 jmethodID constructor; 64 jmethodID deviceId; 65 jmethodID type; 66 jmethodID hdmiPortId; 67 jmethodID audioType; 68 jmethodID audioAddress; 69 jmethodID build; 70} gTvInputHardwareInfoBuilderClassInfo; 71 72//////////////////////////////////////////////////////////////////////////////// 73 74class BufferProducerThread : public Thread { 75public: 76 BufferProducerThread(tv_input_device_t* device, int deviceId, const tv_stream_t* stream); 77 78 virtual status_t readyToRun(); 79 80 void setSurface(const sp<Surface>& surface); 81 void onCaptured(uint32_t seq, bool succeeded); 82 void shutdown(); 83 84private: 85 Mutex mLock; 86 Condition mCondition; 87 sp<Surface> mSurface; 88 tv_input_device_t* mDevice; 89 int mDeviceId; 90 tv_stream_t mStream; 91 sp<ANativeWindowBuffer_t> mBuffer; 92 enum { 93 CAPTURING, 94 CAPTURED, 95 RELEASED, 96 } mBufferState; 97 uint32_t mSeq; 98 bool mShutdown; 99 100 virtual bool threadLoop(); 101 102 void setSurfaceLocked(const sp<Surface>& surface); 103}; 104 105BufferProducerThread::BufferProducerThread( 106 tv_input_device_t* device, int deviceId, const tv_stream_t* stream) 107 : Thread(false), 108 mDevice(device), 109 mDeviceId(deviceId), 110 mBuffer(NULL), 111 mBufferState(RELEASED), 112 mSeq(0u), 113 mShutdown(false) { 114 memcpy(&mStream, stream, sizeof(mStream)); 115} 116 117status_t BufferProducerThread::readyToRun() { 118 sp<ANativeWindow> anw(mSurface); 119 status_t err = native_window_set_usage(anw.get(), mStream.buffer_producer.usage); 120 if (err != NO_ERROR) { 121 return err; 122 } 123 err = native_window_set_buffers_dimensions( 124 anw.get(), mStream.buffer_producer.width, mStream.buffer_producer.height); 125 if (err != NO_ERROR) { 126 return err; 127 } 128 err = native_window_set_buffers_format(anw.get(), mStream.buffer_producer.format); 129 if (err != NO_ERROR) { 130 return err; 131 } 132 return NO_ERROR; 133} 134 135void BufferProducerThread::setSurface(const sp<Surface>& surface) { 136 Mutex::Autolock autoLock(&mLock); 137 setSurfaceLocked(surface); 138} 139 140void BufferProducerThread::setSurfaceLocked(const sp<Surface>& surface) { 141 if (surface == mSurface) { 142 return; 143 } 144 145 if (mBufferState == CAPTURING) { 146 mDevice->cancel_capture(mDevice, mDeviceId, mStream.stream_id, mSeq); 147 } 148 while (mBufferState == CAPTURING) { 149 status_t err = mCondition.waitRelative(mLock, s2ns(1)); 150 if (err != NO_ERROR) { 151 ALOGE("error %d while wating for buffer state to change.", err); 152 break; 153 } 154 } 155 mBuffer.clear(); 156 mBufferState = RELEASED; 157 158 mSurface = surface; 159 mCondition.broadcast(); 160} 161 162void BufferProducerThread::onCaptured(uint32_t seq, bool succeeded) { 163 Mutex::Autolock autoLock(&mLock); 164 if (seq != mSeq) { 165 ALOGW("Incorrect sequence value: expected %u actual %u", mSeq, seq); 166 } 167 if (mBufferState != CAPTURING) { 168 ALOGW("mBufferState != CAPTURING : instead %d", mBufferState); 169 } 170 if (succeeded) { 171 mBufferState = CAPTURED; 172 } else { 173 mBuffer.clear(); 174 mBufferState = RELEASED; 175 } 176 mCondition.broadcast(); 177} 178 179void BufferProducerThread::shutdown() { 180 Mutex::Autolock autoLock(&mLock); 181 mShutdown = true; 182 setSurfaceLocked(NULL); 183 requestExitAndWait(); 184} 185 186bool BufferProducerThread::threadLoop() { 187 Mutex::Autolock autoLock(&mLock); 188 189 status_t err = NO_ERROR; 190 if (mSurface == NULL) { 191 err = mCondition.waitRelative(mLock, s2ns(1)); 192 // It's OK to time out here. 193 if (err != NO_ERROR && err != TIMED_OUT) { 194 ALOGE("error %d while wating for non-null surface to be set", err); 195 return false; 196 } 197 return true; 198 } 199 sp<ANativeWindow> anw(mSurface); 200 while (mBufferState == CAPTURING) { 201 err = mCondition.waitRelative(mLock, s2ns(1)); 202 if (err != NO_ERROR) { 203 ALOGE("error %d while wating for buffer state to change.", err); 204 return false; 205 } 206 } 207 if (mBufferState == CAPTURED && anw != NULL) { 208 err = anw->queueBuffer(anw.get(), mBuffer.get(), -1); 209 if (err != NO_ERROR) { 210 ALOGE("error %d while queueing buffer to surface", err); 211 return false; 212 } 213 mBuffer.clear(); 214 mBufferState = RELEASED; 215 } 216 if (mBuffer == NULL && !mShutdown && anw != NULL) { 217 ANativeWindowBuffer_t* buffer = NULL; 218 err = native_window_dequeue_buffer_and_wait(anw.get(), &buffer); 219 if (err != NO_ERROR) { 220 ALOGE("error %d while dequeueing buffer to surface", err); 221 return false; 222 } 223 mBuffer = buffer; 224 mBufferState = CAPTURING; 225 mDevice->request_capture(mDevice, mDeviceId, mStream.stream_id, 226 buffer->handle, ++mSeq); 227 } 228 229 return true; 230} 231 232//////////////////////////////////////////////////////////////////////////////// 233 234class JTvInputHal { 235public: 236 ~JTvInputHal(); 237 238 static JTvInputHal* createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper); 239 240 int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface); 241 int removeStream(int deviceId, int streamId); 242 const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs); 243 244 void onDeviceAvailable(const tv_input_device_info_t& info); 245 void onDeviceUnavailable(int deviceId); 246 void onStreamConfigurationsChanged(int deviceId); 247 void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded); 248 249private: 250 // Connection between a surface and a stream. 251 class Connection { 252 public: 253 Connection() {} 254 255 sp<Surface> mSurface; 256 tv_stream_type_t mStreamType; 257 258 // Only valid when mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE 259 sp<NativeHandle> mSourceHandle; 260 // Only valid when mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER 261 sp<BufferProducerThread> mThread; 262 }; 263 264 class NotifyHandler : public MessageHandler { 265 public: 266 NotifyHandler(JTvInputHal* hal, const tv_input_event_t* event); 267 268 virtual void handleMessage(const Message& message); 269 270 private: 271 tv_input_event_t mEvent; 272 JTvInputHal* mHal; 273 }; 274 275 JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* dev, const sp<Looper>& looper); 276 277 static void notify( 278 tv_input_device_t* dev, tv_input_event_t* event, void* data); 279 280 Mutex mLock; 281 jweak mThiz; 282 tv_input_device_t* mDevice; 283 tv_input_callback_ops_t mCallback; 284 sp<Looper> mLooper; 285 286 KeyedVector<int, KeyedVector<int, Connection> > mConnections; 287}; 288 289JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, tv_input_device_t* device, 290 const sp<Looper>& looper) { 291 mThiz = env->NewWeakGlobalRef(thiz); 292 mDevice = device; 293 mCallback.notify = &JTvInputHal::notify; 294 mLooper = looper; 295 296 mDevice->initialize(mDevice, &mCallback, this); 297} 298 299JTvInputHal::~JTvInputHal() { 300 mDevice->common.close((hw_device_t*)mDevice); 301 302 JNIEnv* env = AndroidRuntime::getJNIEnv(); 303 env->DeleteWeakGlobalRef(mThiz); 304 mThiz = NULL; 305} 306 307JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) { 308 tv_input_module_t* module = NULL; 309 status_t err = hw_get_module(TV_INPUT_HARDWARE_MODULE_ID, 310 (hw_module_t const**)&module); 311 if (err) { 312 ALOGE("Couldn't load %s module (%s)", 313 TV_INPUT_HARDWARE_MODULE_ID, strerror(-err)); 314 return 0; 315 } 316 317 tv_input_device_t* device = NULL; 318 err = module->common.methods->open( 319 (hw_module_t*)module, 320 TV_INPUT_DEFAULT_DEVICE, 321 (hw_device_t**)&device); 322 if (err) { 323 ALOGE("Couldn't open %s device (%s)", 324 TV_INPUT_DEFAULT_DEVICE, strerror(-err)); 325 return 0; 326 } 327 328 return new JTvInputHal(env, thiz, device, looper); 329} 330 331int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) { 332 KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); 333 if (connections.indexOfKey(streamId) < 0) { 334 connections.add(streamId, Connection()); 335 } 336 Connection& connection = connections.editValueFor(streamId); 337 if (connection.mSurface == surface) { 338 // Nothing to do 339 return NO_ERROR; 340 } 341 // Clear the surface in the connection. 342 if (connection.mSurface != NULL) { 343 if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) { 344 if (Surface::isValid(connection.mSurface)) { 345 connection.mSurface->setSidebandStream(NULL); 346 } 347 } 348 connection.mSurface.clear(); 349 } 350 if (connection.mSourceHandle == NULL && connection.mThread == NULL) { 351 // Need to configure stream 352 int numConfigs = 0; 353 const tv_stream_config_t* configs = NULL; 354 if (mDevice->get_stream_configurations( 355 mDevice, deviceId, &numConfigs, &configs) != 0) { 356 ALOGE("Couldn't get stream configs"); 357 return UNKNOWN_ERROR; 358 } 359 int configIndex = -1; 360 for (int i = 0; i < numConfigs; ++i) { 361 if (configs[i].stream_id == streamId) { 362 configIndex = i; 363 break; 364 } 365 } 366 if (configIndex == -1) { 367 ALOGE("Cannot find a config with given stream ID: %d", streamId); 368 return BAD_VALUE; 369 } 370 connection.mStreamType = configs[configIndex].type; 371 372 tv_stream_t stream; 373 stream.stream_id = configs[configIndex].stream_id; 374 if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) { 375 stream.buffer_producer.width = configs[configIndex].max_video_width; 376 stream.buffer_producer.height = configs[configIndex].max_video_height; 377 } 378 if (mDevice->open_stream(mDevice, deviceId, &stream) != 0) { 379 ALOGE("Couldn't add stream"); 380 return UNKNOWN_ERROR; 381 } 382 if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) { 383 connection.mSourceHandle = NativeHandle::create( 384 stream.sideband_stream_source_handle, false); 385 } else if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) { 386 if (connection.mThread != NULL) { 387 connection.mThread->shutdown(); 388 } 389 connection.mThread = new BufferProducerThread(mDevice, deviceId, &stream); 390 connection.mThread->run(); 391 } 392 } 393 connection.mSurface = surface; 394 if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) { 395 connection.mSurface->setSidebandStream(connection.mSourceHandle); 396 } else if (connection.mStreamType == TV_STREAM_TYPE_BUFFER_PRODUCER) { 397 connection.mThread->setSurface(surface); 398 } 399 return NO_ERROR; 400} 401 402int JTvInputHal::removeStream(int deviceId, int streamId) { 403 KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); 404 if (connections.indexOfKey(streamId) < 0) { 405 return BAD_VALUE; 406 } 407 Connection& connection = connections.editValueFor(streamId); 408 if (connection.mSurface == NULL) { 409 // Nothing to do 410 return NO_ERROR; 411 } 412 if (Surface::isValid(connection.mSurface)) { 413 connection.mSurface.clear(); 414 } 415 if (connection.mSurface != NULL) { 416 connection.mSurface->setSidebandStream(NULL); 417 connection.mSurface.clear(); 418 } 419 if (connection.mThread != NULL) { 420 connection.mThread->shutdown(); 421 connection.mThread.clear(); 422 } 423 if (mDevice->close_stream(mDevice, deviceId, streamId) != 0) { 424 ALOGE("Couldn't remove stream"); 425 return BAD_VALUE; 426 } 427 if (connection.mSourceHandle != NULL) { 428 connection.mSourceHandle.clear(); 429 } 430 return NO_ERROR; 431} 432 433const tv_stream_config_t* JTvInputHal::getStreamConfigs(int deviceId, int* numConfigs) { 434 const tv_stream_config_t* configs = NULL; 435 if (mDevice->get_stream_configurations( 436 mDevice, deviceId, numConfigs, &configs) != 0) { 437 ALOGE("Couldn't get stream configs"); 438 return NULL; 439 } 440 return configs; 441} 442 443// static 444void JTvInputHal::notify( 445 tv_input_device_t* dev, tv_input_event_t* event, void* data) { 446 JTvInputHal* thiz = (JTvInputHal*)data; 447 thiz->mLooper->sendMessage(new NotifyHandler(thiz, event), event->type); 448} 449 450void JTvInputHal::onDeviceAvailable(const tv_input_device_info_t& info) { 451 { 452 Mutex::Autolock autoLock(&mLock); 453 mConnections.add(info.device_id, KeyedVector<int, Connection>()); 454 } 455 JNIEnv* env = AndroidRuntime::getJNIEnv(); 456 457 jobject builder = env->NewObject( 458 gTvInputHardwareInfoBuilderClassInfo.clazz, 459 gTvInputHardwareInfoBuilderClassInfo.constructor); 460 env->CallObjectMethod( 461 builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.device_id); 462 env->CallObjectMethod( 463 builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type); 464 if (info.type == TV_INPUT_TYPE_HDMI) { 465 env->CallObjectMethod( 466 builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId, info.hdmi.port_id); 467 } 468 env->CallObjectMethod( 469 builder, gTvInputHardwareInfoBuilderClassInfo.audioType, info.audio_type); 470 if (info.audio_type != AUDIO_DEVICE_NONE) { 471 jstring audioAddress = env->NewStringUTF(info.audio_address); 472 env->CallObjectMethod( 473 builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress, audioAddress); 474 env->DeleteLocalRef(audioAddress); 475 } 476 477 jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build); 478 479 env->CallVoidMethod( 480 mThiz, 481 gTvInputHalClassInfo.deviceAvailable, 482 infoObject); 483 484 env->DeleteLocalRef(builder); 485 env->DeleteLocalRef(infoObject); 486} 487 488void JTvInputHal::onDeviceUnavailable(int deviceId) { 489 { 490 Mutex::Autolock autoLock(&mLock); 491 KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); 492 for (size_t i = 0; i < connections.size(); ++i) { 493 removeStream(deviceId, connections.keyAt(i)); 494 } 495 connections.clear(); 496 mConnections.removeItem(deviceId); 497 } 498 JNIEnv* env = AndroidRuntime::getJNIEnv(); 499 env->CallVoidMethod( 500 mThiz, 501 gTvInputHalClassInfo.deviceUnavailable, 502 deviceId); 503} 504 505void JTvInputHal::onStreamConfigurationsChanged(int deviceId) { 506 { 507 Mutex::Autolock autoLock(&mLock); 508 KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); 509 for (size_t i = 0; i < connections.size(); ++i) { 510 removeStream(deviceId, connections.keyAt(i)); 511 } 512 connections.clear(); 513 } 514 JNIEnv* env = AndroidRuntime::getJNIEnv(); 515 env->CallVoidMethod( 516 mThiz, 517 gTvInputHalClassInfo.streamConfigsChanged, 518 deviceId); 519} 520 521void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) { 522 sp<BufferProducerThread> thread; 523 { 524 Mutex::Autolock autoLock(&mLock); 525 KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); 526 Connection& connection = connections.editValueFor(streamId); 527 if (connection.mThread == NULL) { 528 ALOGE("capture thread not existing."); 529 return; 530 } 531 thread = connection.mThread; 532 } 533 thread->onCaptured(seq, succeeded); 534 if (seq == 0) { 535 JNIEnv* env = AndroidRuntime::getJNIEnv(); 536 env->CallVoidMethod( 537 mThiz, 538 gTvInputHalClassInfo.firstFrameCaptured, 539 deviceId, 540 streamId); 541 } 542} 543 544JTvInputHal::NotifyHandler::NotifyHandler(JTvInputHal* hal, const tv_input_event_t* event) { 545 mHal = hal; 546 memcpy(&mEvent, event, sizeof(mEvent)); 547} 548 549void JTvInputHal::NotifyHandler::handleMessage(const Message& message) { 550 switch (mEvent.type) { 551 case TV_INPUT_EVENT_DEVICE_AVAILABLE: { 552 mHal->onDeviceAvailable(mEvent.device_info); 553 } break; 554 case TV_INPUT_EVENT_DEVICE_UNAVAILABLE: { 555 mHal->onDeviceUnavailable(mEvent.device_info.device_id); 556 } break; 557 case TV_INPUT_EVENT_STREAM_CONFIGURATIONS_CHANGED: { 558 mHal->onStreamConfigurationsChanged(mEvent.device_info.device_id); 559 } break; 560 case TV_INPUT_EVENT_CAPTURE_SUCCEEDED: { 561 mHal->onCaptured(mEvent.capture_result.device_id, 562 mEvent.capture_result.stream_id, 563 mEvent.capture_result.seq, 564 true /* succeeded */); 565 } break; 566 case TV_INPUT_EVENT_CAPTURE_FAILED: { 567 mHal->onCaptured(mEvent.capture_result.device_id, 568 mEvent.capture_result.stream_id, 569 mEvent.capture_result.seq, 570 false /* succeeded */); 571 } break; 572 default: 573 ALOGE("Unrecognizable event"); 574 } 575} 576 577//////////////////////////////////////////////////////////////////////////////// 578 579static jlong nativeOpen(JNIEnv* env, jobject thiz, jobject messageQueueObj) { 580 sp<MessageQueue> messageQueue = 581 android_os_MessageQueue_getMessageQueue(env, messageQueueObj); 582 return (jlong)JTvInputHal::createInstance(env, thiz, messageQueue->getLooper()); 583} 584 585static int nativeAddOrUpdateStream(JNIEnv* env, jclass clazz, 586 jlong ptr, jint deviceId, jint streamId, jobject jsurface) { 587 JTvInputHal* tvInputHal = (JTvInputHal*)ptr; 588 if (!jsurface) { 589 return BAD_VALUE; 590 } 591 sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); 592 return tvInputHal->addOrUpdateStream(deviceId, streamId, surface); 593} 594 595static int nativeRemoveStream(JNIEnv* env, jclass clazz, 596 jlong ptr, jint deviceId, jint streamId) { 597 JTvInputHal* tvInputHal = (JTvInputHal*)ptr; 598 return tvInputHal->removeStream(deviceId, streamId); 599} 600 601static jobjectArray nativeGetStreamConfigs(JNIEnv* env, jclass clazz, 602 jlong ptr, jint deviceId, jint generation) { 603 JTvInputHal* tvInputHal = (JTvInputHal*)ptr; 604 int numConfigs = 0; 605 const tv_stream_config_t* configs = tvInputHal->getStreamConfigs(deviceId, &numConfigs); 606 607 jobjectArray result = env->NewObjectArray(numConfigs, gTvStreamConfigClassInfo.clazz, NULL); 608 for (int i = 0; i < numConfigs; ++i) { 609 jobject builder = env->NewObject( 610 gTvStreamConfigBuilderClassInfo.clazz, 611 gTvStreamConfigBuilderClassInfo.constructor); 612 env->CallObjectMethod( 613 builder, gTvStreamConfigBuilderClassInfo.streamId, configs[i].stream_id); 614 env->CallObjectMethod( 615 builder, gTvStreamConfigBuilderClassInfo.type, configs[i].type); 616 env->CallObjectMethod( 617 builder, gTvStreamConfigBuilderClassInfo.maxWidth, configs[i].max_video_width); 618 env->CallObjectMethod( 619 builder, gTvStreamConfigBuilderClassInfo.maxHeight, configs[i].max_video_height); 620 env->CallObjectMethod( 621 builder, gTvStreamConfigBuilderClassInfo.generation, generation); 622 623 jobject config = env->CallObjectMethod(builder, gTvStreamConfigBuilderClassInfo.build); 624 625 env->SetObjectArrayElement(result, i, config); 626 627 env->DeleteLocalRef(config); 628 env->DeleteLocalRef(builder); 629 } 630 return result; 631} 632 633static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) { 634 JTvInputHal* tvInputHal = (JTvInputHal*)ptr; 635 delete tvInputHal; 636} 637 638static JNINativeMethod gTvInputHalMethods[] = { 639 /* name, signature, funcPtr */ 640 { "nativeOpen", "(Landroid/os/MessageQueue;)J", 641 (void*) nativeOpen }, 642 { "nativeAddOrUpdateStream", "(JIILandroid/view/Surface;)I", 643 (void*) nativeAddOrUpdateStream }, 644 { "nativeRemoveStream", "(JII)I", 645 (void*) nativeRemoveStream }, 646 { "nativeGetStreamConfigs", "(JII)[Landroid/media/tv/TvStreamConfig;", 647 (void*) nativeGetStreamConfigs }, 648 { "nativeClose", "(J)V", 649 (void*) nativeClose }, 650}; 651 652#define FIND_CLASS(var, className) \ 653 var = env->FindClass(className); \ 654 LOG_FATAL_IF(! var, "Unable to find class " className) 655 656#define GET_METHOD_ID(var, clazz, methodName, fieldDescriptor) \ 657 var = env->GetMethodID(clazz, methodName, fieldDescriptor); \ 658 LOG_FATAL_IF(! var, "Unable to find method" methodName) 659 660int register_android_server_tv_TvInputHal(JNIEnv* env) { 661 int res = jniRegisterNativeMethods(env, "com/android/server/tv/TvInputHal", 662 gTvInputHalMethods, NELEM(gTvInputHalMethods)); 663 LOG_FATAL_IF(res < 0, "Unable to register native methods."); 664 665 jclass clazz; 666 FIND_CLASS(clazz, "com/android/server/tv/TvInputHal"); 667 668 GET_METHOD_ID( 669 gTvInputHalClassInfo.deviceAvailable, clazz, 670 "deviceAvailableFromNative", "(Landroid/media/tv/TvInputHardwareInfo;)V"); 671 GET_METHOD_ID( 672 gTvInputHalClassInfo.deviceUnavailable, clazz, "deviceUnavailableFromNative", "(I)V"); 673 GET_METHOD_ID( 674 gTvInputHalClassInfo.streamConfigsChanged, clazz, 675 "streamConfigsChangedFromNative", "(I)V"); 676 GET_METHOD_ID( 677 gTvInputHalClassInfo.firstFrameCaptured, clazz, 678 "firstFrameCapturedFromNative", "(II)V"); 679 680 FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/media/tv/TvStreamConfig"); 681 gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz)); 682 683 FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/media/tv/TvStreamConfig$Builder"); 684 gTvStreamConfigBuilderClassInfo.clazz = 685 jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz)); 686 687 GET_METHOD_ID( 688 gTvStreamConfigBuilderClassInfo.constructor, 689 gTvStreamConfigBuilderClassInfo.clazz, 690 "<init>", "()V"); 691 GET_METHOD_ID( 692 gTvStreamConfigBuilderClassInfo.streamId, 693 gTvStreamConfigBuilderClassInfo.clazz, 694 "streamId", "(I)Landroid/media/tv/TvStreamConfig$Builder;"); 695 GET_METHOD_ID( 696 gTvStreamConfigBuilderClassInfo.type, 697 gTvStreamConfigBuilderClassInfo.clazz, 698 "type", "(I)Landroid/media/tv/TvStreamConfig$Builder;"); 699 GET_METHOD_ID( 700 gTvStreamConfigBuilderClassInfo.maxWidth, 701 gTvStreamConfigBuilderClassInfo.clazz, 702 "maxWidth", "(I)Landroid/media/tv/TvStreamConfig$Builder;"); 703 GET_METHOD_ID( 704 gTvStreamConfigBuilderClassInfo.maxHeight, 705 gTvStreamConfigBuilderClassInfo.clazz, 706 "maxHeight", "(I)Landroid/media/tv/TvStreamConfig$Builder;"); 707 GET_METHOD_ID( 708 gTvStreamConfigBuilderClassInfo.generation, 709 gTvStreamConfigBuilderClassInfo.clazz, 710 "generation", "(I)Landroid/media/tv/TvStreamConfig$Builder;"); 711 GET_METHOD_ID( 712 gTvStreamConfigBuilderClassInfo.build, 713 gTvStreamConfigBuilderClassInfo.clazz, 714 "build", "()Landroid/media/tv/TvStreamConfig;"); 715 716 FIND_CLASS(gTvInputHardwareInfoBuilderClassInfo.clazz, 717 "android/media/tv/TvInputHardwareInfo$Builder"); 718 gTvInputHardwareInfoBuilderClassInfo.clazz = 719 jclass(env->NewGlobalRef(gTvInputHardwareInfoBuilderClassInfo.clazz)); 720 721 GET_METHOD_ID( 722 gTvInputHardwareInfoBuilderClassInfo.constructor, 723 gTvInputHardwareInfoBuilderClassInfo.clazz, 724 "<init>", "()V"); 725 GET_METHOD_ID( 726 gTvInputHardwareInfoBuilderClassInfo.deviceId, 727 gTvInputHardwareInfoBuilderClassInfo.clazz, 728 "deviceId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); 729 GET_METHOD_ID( 730 gTvInputHardwareInfoBuilderClassInfo.type, 731 gTvInputHardwareInfoBuilderClassInfo.clazz, 732 "type", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); 733 GET_METHOD_ID( 734 gTvInputHardwareInfoBuilderClassInfo.hdmiPortId, 735 gTvInputHardwareInfoBuilderClassInfo.clazz, 736 "hdmiPortId", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); 737 GET_METHOD_ID( 738 gTvInputHardwareInfoBuilderClassInfo.audioType, 739 gTvInputHardwareInfoBuilderClassInfo.clazz, 740 "audioType", "(I)Landroid/media/tv/TvInputHardwareInfo$Builder;"); 741 GET_METHOD_ID( 742 gTvInputHardwareInfoBuilderClassInfo.audioAddress, 743 gTvInputHardwareInfoBuilderClassInfo.clazz, 744 "audioAddress", "(Ljava/lang/String;)Landroid/media/tv/TvInputHardwareInfo$Builder;"); 745 GET_METHOD_ID( 746 gTvInputHardwareInfoBuilderClassInfo.build, 747 gTvInputHardwareInfoBuilderClassInfo.clazz, 748 "build", "()Landroid/media/tv/TvInputHardwareInfo;"); 749 750 return 0; 751} 752 753} /* namespace android */ 754