Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 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 "HdmiCecControllerJni" |
| 18 | |
| 19 | #define LOG_NDEBUG 1 |
| 20 | |
Jinsuk Kim | 8c688ad | 2014-07-24 14:48:34 +0900 | [diff] [blame] | 21 | #include <JNIHelp.h> |
| 22 | #include <ScopedPrimitiveArray.h> |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 23 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 24 | #include <cstring> |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 25 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 26 | #include <android_os_MessageQueue.h> |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 27 | #include <android_runtime/AndroidRuntime.h> |
| 28 | #include <android_runtime/Log.h> |
| 29 | #include <hardware/hdmi_cec.h> |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 30 | #include <sys/param.h> |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 31 | #include <utils/Looper.h> |
| 32 | #include <utils/RefBase.h> |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 33 | |
| 34 | namespace android { |
| 35 | |
| 36 | static struct { |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 37 | jmethodID handleIncomingCecCommand; |
| 38 | jmethodID handleHotplug; |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 39 | } gHdmiCecControllerClassInfo; |
| 40 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 41 | class HdmiCecController { |
| 42 | public: |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 43 | HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj, |
| 44 | const sp<Looper>& looper); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 45 | |
| 46 | void init(); |
| 47 | |
| 48 | // Send message to other device. Note that it runs in IO thread. |
| 49 | int sendMessage(const cec_message_t& message); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 50 | // Add a logical address to device. |
| 51 | int addLogicalAddress(cec_logical_address_t address); |
| 52 | // Clear all logical address registered to the device. |
| 53 | void clearLogicaladdress(); |
| 54 | // Get physical address of device. |
| 55 | int getPhysicalAddress(); |
| 56 | // Get CEC version from driver. |
| 57 | int getVersion(); |
| 58 | // Get vendor id used for vendor command. |
| 59 | uint32_t getVendorId(); |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 60 | // Get Port information on all the HDMI ports. |
| 61 | jobjectArray getPortInfos(); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 62 | // Set a flag and its value. |
| 63 | void setOption(int flag, int value); |
| 64 | // Set audio return channel status. |
Jinsuk Kim | 1481a42 | 2014-12-17 16:15:05 +0900 | [diff] [blame] | 65 | void setAudioReturnChannel(int port, bool flag); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 66 | // Whether to hdmi device is connected to the given port. |
| 67 | bool isConnected(int port); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 68 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 69 | jobject getCallbacksObj() const { |
| 70 | return mCallbacksObj; |
| 71 | } |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 72 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 73 | private: |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 74 | static const int INVALID_PHYSICAL_ADDRESS = 0xFFFF; |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 75 | static void onReceived(const hdmi_event_t* event, void* arg); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 76 | |
| 77 | hdmi_cec_device_t* mDevice; |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 78 | jobject mCallbacksObj; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 79 | sp<Looper> mLooper; |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 80 | }; |
| 81 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 82 | // RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL |
| 83 | // may keep its own lifetime, we need to copy it in order to delegate |
| 84 | // it to service thread. |
| 85 | class CecEventWrapper : public LightRefBase<CecEventWrapper> { |
| 86 | public: |
Chih-Hung Hsieh | c6baf56 | 2016-04-27 11:29:23 -0700 | [diff] [blame] | 87 | explicit CecEventWrapper(const hdmi_event_t& event) { |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 88 | // Copy message. |
| 89 | switch (event.type) { |
| 90 | case HDMI_EVENT_CEC_MESSAGE: |
| 91 | mEvent.cec.initiator = event.cec.initiator; |
| 92 | mEvent.cec.destination = event.cec.destination; |
| 93 | mEvent.cec.length = event.cec.length; |
| 94 | std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length); |
| 95 | break; |
| 96 | case HDMI_EVENT_HOT_PLUG: |
| 97 | mEvent.hotplug.connected = event.hotplug.connected; |
Jinsuk Kim | 284c31b | 2014-07-11 07:26:45 +0900 | [diff] [blame] | 98 | mEvent.hotplug.port_id = event.hotplug.port_id; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 99 | break; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 100 | default: |
| 101 | // TODO: add more type whenever new type is introduced. |
| 102 | break; |
| 103 | } |
| 104 | } |
| 105 | |
| 106 | const cec_message_t& cec() const { |
| 107 | return mEvent.cec; |
| 108 | } |
| 109 | |
| 110 | const hotplug_event_t& hotplug() const { |
| 111 | return mEvent.hotplug; |
| 112 | } |
| 113 | |
| 114 | virtual ~CecEventWrapper() {} |
| 115 | |
| 116 | private: |
| 117 | hdmi_event_t mEvent; |
| 118 | }; |
| 119 | |
| 120 | // Handler class to delegate incoming message to service thread. |
| 121 | class HdmiCecEventHandler : public MessageHandler { |
| 122 | public: |
| 123 | HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event) |
| 124 | : mController(controller), |
| 125 | mEventWrapper(event) { |
| 126 | } |
| 127 | |
| 128 | virtual ~HdmiCecEventHandler() {} |
| 129 | |
| 130 | void handleMessage(const Message& message) { |
| 131 | switch (message.what) { |
| 132 | case HDMI_EVENT_CEC_MESSAGE: |
| 133 | propagateCecCommand(mEventWrapper->cec()); |
| 134 | break; |
| 135 | case HDMI_EVENT_HOT_PLUG: |
| 136 | propagateHotplugEvent(mEventWrapper->hotplug()); |
| 137 | break; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 138 | default: |
| 139 | // TODO: add more type whenever new type is introduced. |
| 140 | break; |
| 141 | } |
| 142 | } |
| 143 | |
| 144 | private: |
| 145 | // Propagate the message up to Java layer. |
| 146 | void propagateCecCommand(const cec_message_t& message) { |
| 147 | jint srcAddr = message.initiator; |
| 148 | jint dstAddr = message.destination; |
| 149 | JNIEnv* env = AndroidRuntime::getJNIEnv(); |
| 150 | jbyteArray body = env->NewByteArray(message.length); |
| 151 | const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body); |
| 152 | env->SetByteArrayRegion(body, 0, message.length, bodyPtr); |
| 153 | |
| 154 | env->CallVoidMethod(mController->getCallbacksObj(), |
| 155 | gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr, |
| 156 | dstAddr, body); |
| 157 | env->DeleteLocalRef(body); |
| 158 | |
| 159 | checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| 160 | } |
| 161 | |
| 162 | void propagateHotplugEvent(const hotplug_event_t& event) { |
| 163 | // Note that this method should be called in service thread. |
| 164 | JNIEnv* env = AndroidRuntime::getJNIEnv(); |
Jinsuk Kim | 284c31b | 2014-07-11 07:26:45 +0900 | [diff] [blame] | 165 | jint port = event.port_id; |
Jungshik Jang | 4223072 | 2014-07-07 17:40:25 +0900 | [diff] [blame] | 166 | jboolean connected = (jboolean) event.connected; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 167 | env->CallVoidMethod(mController->getCallbacksObj(), |
Jungshik Jang | 4223072 | 2014-07-07 17:40:25 +0900 | [diff] [blame] | 168 | gHdmiCecControllerClassInfo.handleHotplug, port, connected); |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 169 | |
| 170 | checkAndClearExceptionFromCallback(env, __FUNCTION__); |
| 171 | } |
| 172 | |
| 173 | // static |
| 174 | static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { |
| 175 | if (env->ExceptionCheck()) { |
| 176 | ALOGE("An exception was thrown by callback '%s'.", methodName); |
| 177 | LOGE_EX(env); |
| 178 | env->ExceptionClear(); |
| 179 | } |
| 180 | } |
| 181 | |
| 182 | HdmiCecController* mController; |
| 183 | sp<CecEventWrapper> mEventWrapper; |
| 184 | }; |
| 185 | |
| 186 | HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, |
| 187 | jobject callbacksObj, const sp<Looper>& looper) : |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 188 | mDevice(device), |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 189 | mCallbacksObj(callbacksObj), |
| 190 | mLooper(looper) { |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 191 | } |
| 192 | |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 193 | void HdmiCecController::init() { |
| 194 | mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this); |
| 195 | } |
| 196 | |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 197 | int HdmiCecController::sendMessage(const cec_message_t& message) { |
| 198 | // TODO: propagate send_message's return value. |
| 199 | return mDevice->send_message(mDevice, &message); |
| 200 | } |
| 201 | |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 202 | int HdmiCecController::addLogicalAddress(cec_logical_address_t address) { |
| 203 | return mDevice->add_logical_address(mDevice, address); |
| 204 | } |
| 205 | |
| 206 | void HdmiCecController::clearLogicaladdress() { |
| 207 | mDevice->clear_logical_address(mDevice); |
| 208 | } |
| 209 | |
| 210 | int HdmiCecController::getPhysicalAddress() { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 211 | uint16_t addr; |
| 212 | if (!mDevice->get_physical_address(mDevice, &addr)) { |
| 213 | return addr; |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 214 | } |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 215 | return INVALID_PHYSICAL_ADDRESS; |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 216 | } |
| 217 | |
| 218 | int HdmiCecController::getVersion() { |
| 219 | int version = 0; |
| 220 | mDevice->get_version(mDevice, &version); |
| 221 | return version; |
| 222 | } |
| 223 | |
| 224 | uint32_t HdmiCecController::getVendorId() { |
| 225 | uint32_t vendorId = 0; |
| 226 | mDevice->get_vendor_id(mDevice, &vendorId); |
| 227 | return vendorId; |
| 228 | } |
| 229 | |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 230 | jobjectArray HdmiCecController::getPortInfos() { |
| 231 | JNIEnv* env = AndroidRuntime::getJNIEnv(); |
Jinsuk Kim | 63dd3bb | 2014-06-13 14:46:17 +0900 | [diff] [blame] | 232 | jclass hdmiPortInfo = env->FindClass("android/hardware/hdmi/HdmiPortInfo"); |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 233 | if (hdmiPortInfo == NULL) { |
| 234 | return NULL; |
| 235 | } |
| 236 | jmethodID ctor = env->GetMethodID(hdmiPortInfo, "<init>", "(IIIZZZ)V"); |
| 237 | if (ctor == NULL) { |
| 238 | return NULL; |
| 239 | } |
| 240 | hdmi_port_info* ports; |
| 241 | int numPorts; |
| 242 | mDevice->get_port_info(mDevice, &ports, &numPorts); |
| 243 | jobjectArray res = env->NewObjectArray(numPorts, hdmiPortInfo, NULL); |
| 244 | |
| 245 | // MHL support field will be obtained from MHL HAL. Leave it to false. |
| 246 | jboolean mhlSupported = (jboolean) 0; |
| 247 | for (int i = 0; i < numPorts; ++i) { |
| 248 | hdmi_port_info* info = &ports[i]; |
| 249 | jboolean cecSupported = (jboolean) info->cec_supported; |
| 250 | jboolean arcSupported = (jboolean) info->arc_supported; |
Jinsuk Kim | 284c31b | 2014-07-11 07:26:45 +0900 | [diff] [blame] | 251 | jobject infoObj = env->NewObject(hdmiPortInfo, ctor, info->port_id, info->type, |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 252 | info->physical_address, cecSupported, mhlSupported, arcSupported); |
| 253 | env->SetObjectArrayElement(res, i, infoObj); |
| 254 | } |
| 255 | return res; |
| 256 | } |
| 257 | |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 258 | void HdmiCecController::setOption(int flag, int value) { |
| 259 | mDevice->set_option(mDevice, flag, value); |
| 260 | } |
| 261 | |
| 262 | // Set audio return channel status. |
Jinsuk Kim | 1481a42 | 2014-12-17 16:15:05 +0900 | [diff] [blame] | 263 | void HdmiCecController::setAudioReturnChannel(int port, bool enabled) { |
| 264 | mDevice->set_audio_return_channel(mDevice, port, enabled ? 1 : 0); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 265 | } |
| 266 | |
| 267 | // Whether to hdmi device is connected to the given port. |
| 268 | bool HdmiCecController::isConnected(int port) { |
| 269 | return mDevice->is_connected(mDevice, port) == HDMI_CONNECTED; |
| 270 | } |
| 271 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 272 | // static |
| 273 | void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) { |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 274 | HdmiCecController* controller = static_cast<HdmiCecController*>(arg); |
| 275 | if (controller == NULL) { |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 276 | return; |
| 277 | } |
| 278 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 279 | sp<CecEventWrapper> spEvent(new CecEventWrapper(*event)); |
| 280 | sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent)); |
| 281 | controller->mLooper->sendMessage(handler, event->type); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 282 | } |
| 283 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 284 | //------------------------------------------------------------------------------ |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 285 | #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ |
| 286 | var = env->GetMethodID(clazz, methodName, methodDescriptor); \ |
| 287 | LOG_FATAL_IF(! var, "Unable to find method " methodName); |
| 288 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 289 | static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj, |
| 290 | jobject messageQueueObj) { |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 291 | int err; |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 292 | hw_module_t* module; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 293 | err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 294 | const_cast<const hw_module_t **>(&module)); |
| 295 | if (err != 0) { |
| 296 | ALOGE("Error acquiring hardware module: %d", err); |
| 297 | return 0; |
| 298 | } |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 299 | |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 300 | hw_device_t* device; |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 301 | err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 302 | if (err != 0) { |
| 303 | ALOGE("Error opening hardware module: %d", err); |
| 304 | return 0; |
| 305 | } |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 306 | |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 307 | sp<MessageQueue> messageQueue = |
| 308 | android_os_MessageQueue_getMessageQueue(env, messageQueueObj); |
| 309 | |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 310 | HdmiCecController* controller = new HdmiCecController( |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 311 | reinterpret_cast<hdmi_cec_device*>(device), |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 312 | env->NewGlobalRef(callbacksObj), |
| 313 | messageQueue->getLooper()); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 314 | controller->init(); |
| 315 | |
| 316 | GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz, |
| 317 | "handleIncomingCecCommand", "(II[B)V"); |
| 318 | GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz, |
Jungshik Jang | 4223072 | 2014-07-07 17:40:25 +0900 | [diff] [blame] | 319 | "handleHotplug", "(IZ)V"); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 320 | |
| 321 | return reinterpret_cast<jlong>(controller); |
| 322 | } |
| 323 | |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 324 | static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr, |
| 325 | jint srcAddr, jint dstAddr, jbyteArray body) { |
| 326 | cec_message_t message; |
| 327 | message.initiator = static_cast<cec_logical_address_t>(srcAddr); |
| 328 | message.destination = static_cast<cec_logical_address_t>(dstAddr); |
| 329 | |
| 330 | jsize len = env->GetArrayLength(body); |
| 331 | message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH); |
| 332 | ScopedByteArrayRO bodyPtr(env, body); |
Jae Seo | d0efcbb | 2016-02-12 00:12:36 -0800 | [diff] [blame] | 333 | std::memcpy(message.body, bodyPtr.get(), message.length); |
Jungshik Jang | e9c77c8 | 2014-04-24 20:30:09 +0900 | [diff] [blame] | 334 | |
| 335 | HdmiCecController* controller = |
| 336 | reinterpret_cast<HdmiCecController*>(controllerPtr); |
| 337 | return controller->sendMessage(message); |
| 338 | } |
| 339 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 340 | static jint nativeAddLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr, |
| 341 | jint logicalAddress) { |
| 342 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
| 343 | return controller->addLogicalAddress(static_cast<cec_logical_address_t>(logicalAddress)); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 344 | } |
| 345 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 346 | static void nativeClearLogicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 347 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 348 | controller->clearLogicaladdress(); |
| 349 | } |
| 350 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 351 | static jint nativeGetPhysicalAddress(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 352 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 353 | return controller->getPhysicalAddress(); |
| 354 | } |
| 355 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 356 | static jint nativeGetVersion(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 357 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 358 | return controller->getVersion(); |
| 359 | } |
| 360 | |
| 361 | static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 362 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 363 | return controller->getVendorId(); |
| 364 | } |
| 365 | |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 366 | static jobjectArray nativeGetPortInfos(JNIEnv* env, jclass clazz, jlong controllerPtr) { |
| 367 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
| 368 | return controller->getPortInfos(); |
| 369 | } |
| 370 | |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 371 | static void nativeSetOption(JNIEnv* env, jclass clazz, jlong controllerPtr, jint flag, jint value) { |
| 372 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 373 | controller->setOption(flag, value); |
| 374 | } |
| 375 | |
| 376 | static void nativeSetAudioReturnChannel(JNIEnv* env, jclass clazz, jlong controllerPtr, |
Jinsuk Kim | 1481a42 | 2014-12-17 16:15:05 +0900 | [diff] [blame] | 377 | jint port, jboolean enabled) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 378 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jinsuk Kim | 1481a42 | 2014-12-17 16:15:05 +0900 | [diff] [blame] | 379 | controller->setAudioReturnChannel(port, enabled == JNI_TRUE); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 380 | } |
| 381 | |
| 382 | static jboolean nativeIsConnected(JNIEnv* env, jclass clazz, jlong controllerPtr, jint port) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 383 | HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 384 | return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ; |
| 385 | } |
| 386 | |
Daniel Micay | 76f6a86 | 2015-09-19 17:31:01 -0400 | [diff] [blame] | 387 | static const JNINativeMethod sMethods[] = { |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 388 | /* name, signature, funcPtr */ |
Jungshik Jang | 4085d0e | 2014-05-27 19:52:39 +0900 | [diff] [blame] | 389 | { "nativeInit", |
| 390 | "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J", |
| 391 | (void *) nativeInit }, |
Jungshik Jang | a9095ba | 2014-05-02 13:06:22 +0900 | [diff] [blame] | 392 | { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand }, |
| 393 | { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress }, |
| 394 | { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress }, |
| 395 | { "nativeGetPhysicalAddress", "(J)I", (void *) nativeGetPhysicalAddress }, |
| 396 | { "nativeGetVersion", "(J)I", (void *) nativeGetVersion }, |
| 397 | { "nativeGetVendorId", "(J)I", (void *) nativeGetVendorId }, |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 398 | { "nativeGetPortInfos", |
Jinsuk Kim | 63dd3bb | 2014-06-13 14:46:17 +0900 | [diff] [blame] | 399 | "(J)[Landroid/hardware/hdmi/HdmiPortInfo;", |
Jinsuk Kim | 0340bbc | 2014-06-05 11:07:47 +0900 | [diff] [blame] | 400 | (void *) nativeGetPortInfos }, |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 401 | { "nativeSetOption", "(JII)V", (void *) nativeSetOption }, |
Jinsuk Kim | 1481a42 | 2014-12-17 16:15:05 +0900 | [diff] [blame] | 402 | { "nativeSetAudioReturnChannel", "(JIZ)V", (void *) nativeSetAudioReturnChannel }, |
Jungshik Jang | 092b445 | 2014-06-11 15:19:17 +0900 | [diff] [blame] | 403 | { "nativeIsConnected", "(JI)Z", (void *) nativeIsConnected }, |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 404 | }; |
| 405 | |
| 406 | #define CLASS_PATH "com/android/server/hdmi/HdmiCecController" |
| 407 | |
| 408 | int register_android_server_hdmi_HdmiCecController(JNIEnv* env) { |
Jinsuk Kim | a6ce770 | 2014-05-11 06:54:49 +0900 | [diff] [blame] | 409 | int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods)); |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 410 | LOG_FATAL_IF(res < 0, "Unable to register native methods."); |
Bernhard Rosenkränzer | 4048a4b | 2014-11-23 22:24:32 +0100 | [diff] [blame] | 411 | (void)res; // Don't scream about unused variable in the LOG_NDEBUG case |
Jungshik Jang | 0792d37 | 2014-04-23 17:57:26 +0900 | [diff] [blame] | 412 | return 0; |
| 413 | } |
| 414 | |
| 415 | } /* namespace android */ |