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