1 /*
2  * Copyright 2022 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 #include "JTvInputHal.h"
18 
19 #include <nativehelper/ScopedLocalRef.h>
20 
21 namespace android {
22 
JTvInputHal(JNIEnv * env,jobject thiz,std::shared_ptr<ITvInputWrapper> tvInput,const sp<Looper> & looper)23 JTvInputHal::JTvInputHal(JNIEnv* env, jobject thiz, std::shared_ptr<ITvInputWrapper> tvInput,
24                          const sp<Looper>& looper) {
25     mThiz = env->NewWeakGlobalRef(thiz);
26     mTvInput = tvInput;
27     mLooper = looper;
28     mTvInputCallback = ::ndk::SharedRefBase::make<TvInputCallback>(this);
29     mTvInput->setCallback(mTvInputCallback);
30 }
31 
~JTvInputHal()32 JTvInputHal::~JTvInputHal() {
33     mTvInput->setCallback(nullptr);
34     JNIEnv* env = AndroidRuntime::getJNIEnv();
35     env->DeleteWeakGlobalRef(mThiz);
36     mThiz = NULL;
37 }
38 
createInstance(JNIEnv * env,jobject thiz,const sp<Looper> & looper)39 JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz, const sp<Looper>& looper) {
40     sp<HidlITvInput> hidlITvInput = HidlITvInput::getService();
41     if (hidlITvInput != nullptr) {
42         ALOGD("tv.input service is HIDL.");
43         return new JTvInputHal(env, thiz,
44                                std::shared_ptr<ITvInputWrapper>(new ITvInputWrapper(hidlITvInput)),
45                                looper);
46     }
47     std::shared_ptr<AidlITvInput> aidlITvInput = nullptr;
48     if (AServiceManager_isDeclared(TV_INPUT_AIDL_SERVICE_NAME)) {
49         ::ndk::SpAIBinder binder(AServiceManager_waitForService(TV_INPUT_AIDL_SERVICE_NAME));
50         aidlITvInput = AidlITvInput::fromBinder(binder);
51     }
52     if (aidlITvInput == nullptr) {
53         ALOGE("Couldn't get tv.input service.");
54         return nullptr;
55     }
56     return new JTvInputHal(env, thiz,
57                            std::shared_ptr<ITvInputWrapper>(new ITvInputWrapper(aidlITvInput)),
58                            looper);
59 }
60 
addOrUpdateStream(int deviceId,int streamId,const sp<Surface> & surface)61 int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) {
62     Mutex::Autolock autoLock(&mStreamLock);
63     KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
64     if (connections.indexOfKey(streamId) < 0) {
65         connections.add(streamId, Connection());
66     }
67     Connection& connection = connections.editValueFor(streamId);
68     if (connection.mSurface == surface) {
69         // Nothing to do
70         return NO_ERROR;
71     }
72     // Clear the surface in the connection.
73     if (connection.mSurface != NULL) {
74         if (connection.mStreamType == TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE) {
75             if (Surface::isValid(connection.mSurface)) {
76                 connection.mSurface->setSidebandStream(NULL);
77             }
78         }
79         connection.mSurface.clear();
80     }
81     if (connection.mSourceHandle == NULL && connection.mThread == NULL) {
82         // Need to configure stream
83         ::ndk::ScopedAStatus status;
84         std::vector<AidlTvStreamConfig> list;
85         status = mTvInput->getStreamConfigurations(deviceId, &list);
86         if (!status.isOk()) {
87             ALOGE("Couldn't get stream configs for device id:%d result:%d", deviceId,
88                   status.getServiceSpecificError());
89             return UNKNOWN_ERROR;
90         }
91         int configIndex = -1;
92         for (size_t i = 0; i < list.size(); ++i) {
93             if (list[i].streamId == streamId) {
94                 configIndex = i;
95                 break;
96             }
97         }
98         if (configIndex == -1) {
99             ALOGE("Cannot find a config with given stream ID: %d", streamId);
100             return BAD_VALUE;
101         }
102         connection.mStreamType = TV_STREAM_TYPE_INDEPENDENT_VIDEO_SOURCE;
103 
104         AidlNativeHandle sidebandStream;
105         status = mTvInput->openStream(deviceId, streamId, &sidebandStream);
106         if (!status.isOk()) {
107             ALOGE("Couldn't open stream. device id:%d stream id:%d result:%d", deviceId, streamId,
108                   status.getServiceSpecificError());
109             return UNKNOWN_ERROR;
110         }
111         connection.mSourceHandle = NativeHandle::create(dupFromAidl(sidebandStream), true);
112     }
113     connection.mSurface = surface;
114     if (connection.mSurface != nullptr) {
115         connection.mSurface->setSidebandStream(connection.mSourceHandle);
116     }
117     return NO_ERROR;
118 }
119 
removeStream(int deviceId,int streamId)120 int JTvInputHal::removeStream(int deviceId, int streamId) {
121     Mutex::Autolock autoLock(&mStreamLock);
122     KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
123     if (connections.indexOfKey(streamId) < 0) {
124         return BAD_VALUE;
125     }
126     Connection& connection = connections.editValueFor(streamId);
127     if (connection.mSurface == NULL) {
128         // Nothing to do
129         return NO_ERROR;
130     }
131     if (Surface::isValid(connection.mSurface)) {
132         connection.mSurface->setSidebandStream(NULL);
133     }
134     connection.mSurface.clear();
135     if (connection.mThread != NULL) {
136         connection.mThread->shutdown();
137         connection.mThread.clear();
138     }
139     if (!mTvInput->closeStream(deviceId, streamId).isOk()) {
140         ALOGE("Couldn't close stream. device id:%d stream id:%d", deviceId, streamId);
141         return BAD_VALUE;
142     }
143     if (connection.mSourceHandle != NULL) {
144         connection.mSourceHandle.clear();
145     }
146     return NO_ERROR;
147 }
148 
setTvMessageEnabled(int deviceId,int streamId,int type,bool enabled)149 int JTvInputHal::setTvMessageEnabled(int deviceId, int streamId, int type, bool enabled) {
150     Mutex::Autolock autoLock(&mLock);
151     if (!mTvInput->setTvMessageEnabled(deviceId, streamId,
152                                        static_cast<AidlTvMessageEventType>(type), enabled)
153                  .isOk()) {
154         ALOGE("Error in setTvMessageEnabled. device id:%d stream id:%d", deviceId, streamId);
155         return BAD_VALUE;
156     }
157     return NO_ERROR;
158 }
159 
getStreamConfigs(int deviceId)160 const std::vector<AidlTvStreamConfig> JTvInputHal::getStreamConfigs(int deviceId) {
161     std::vector<AidlTvStreamConfig> list;
162     ::ndk::ScopedAStatus status = mTvInput->getStreamConfigurations(deviceId, &list);
163     if (!status.isOk()) {
164         ALOGE("Couldn't get stream configs for device id:%d result:%d", deviceId,
165               status.getServiceSpecificError());
166         return std::vector<AidlTvStreamConfig>();
167     }
168     return list;
169 }
170 
onDeviceAvailable(const TvInputDeviceInfoWrapper & info)171 void JTvInputHal::onDeviceAvailable(const TvInputDeviceInfoWrapper& info) {
172     {
173         Mutex::Autolock autoLock(&mLock);
174         mConnections.add(info.deviceId, KeyedVector<int, Connection>());
175     }
176     JNIEnv* env = AndroidRuntime::getJNIEnv();
177     jobject builder = env->NewObject(gTvInputHardwareInfoBuilderClassInfo.clazz,
178                                      gTvInputHardwareInfoBuilderClassInfo.constructor);
179     env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.deviceId);
180     env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type);
181     if (info.type == TvInputType::HDMI) {
182         env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId,
183                               info.portId);
184     }
185     env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.cableConnectionStatus,
186                           info.cableConnectionStatus);
187     if (info.isHidl) {
188         hidlSetUpAudioInfo(env, builder, info);
189     } else {
190         AidlAudioDeviceType audioType = info.aidlAudioDevice.type.type;
191         env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioType, audioType);
192         if (audioType != AidlAudioDeviceType::NONE) {
193             std::stringstream ss;
194             switch (info.aidlAudioDevice.address.getTag()) {
195                 case AidlAudioDeviceAddress::id:
196                     ss << info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::id>();
197                     break;
198                 case AidlAudioDeviceAddress::mac: {
199                     std::vector<uint8_t> addrList =
200                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::mac>();
201                     for (int i = 0; i < addrList.size(); i++) {
202                         if (i != 0) {
203                             ss << ':';
204                         }
205                         ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex
206                            << static_cast<int32_t>(addrList[i]);
207                     }
208                 } break;
209                 case AidlAudioDeviceAddress::ipv4: {
210                     std::vector<uint8_t> addrList =
211                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::ipv4>();
212                     for (int i = 0; i < addrList.size(); i++) {
213                         if (i != 0) {
214                             ss << '.';
215                         }
216                         ss << static_cast<int32_t>(addrList[i]);
217                     }
218                 } break;
219                 case AidlAudioDeviceAddress::ipv6: {
220                     std::vector<int32_t> addrList =
221                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::ipv6>();
222                     for (int i = 0; i < addrList.size(); i++) {
223                         if (i != 0) {
224                             ss << ':';
225                         }
226                         ss << std::uppercase << std::setfill('0') << std::setw(4) << std::hex
227                            << addrList[i];
228                     }
229                 } break;
230                 case AidlAudioDeviceAddress::alsa: {
231                     std::vector<int32_t> addrList =
232                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::alsa>();
233                     ss << "card=" << addrList[0] << ";device=" << addrList[1];
234                 } break;
235             }
236             std::string bufferStr = ss.str();
237             jstring audioAddress = env->NewStringUTF(bufferStr.c_str());
238             env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress,
239                                   audioAddress);
240             env->DeleteLocalRef(audioAddress);
241         }
242     }
243 
244     jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build);
245 
246     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.deviceAvailable, infoObject);
247 
248     env->DeleteLocalRef(builder);
249     env->DeleteLocalRef(infoObject);
250 }
251 
onDeviceUnavailable(int deviceId)252 void JTvInputHal::onDeviceUnavailable(int deviceId) {
253     {
254         Mutex::Autolock autoLock(&mLock);
255         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
256         for (size_t i = 0; i < connections.size(); ++i) {
257             removeStream(deviceId, connections.keyAt(i));
258         }
259         connections.clear();
260         mConnections.removeItem(deviceId);
261     }
262     JNIEnv* env = AndroidRuntime::getJNIEnv();
263     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.deviceUnavailable, deviceId);
264 }
265 
onStreamConfigurationsChanged(int deviceId,int cableConnectionStatus)266 void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
267     {
268         Mutex::Autolock autoLock(&mLock);
269         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
270         for (size_t i = 0; i < connections.size(); ++i) {
271             removeStream(deviceId, connections.keyAt(i));
272         }
273         connections.clear();
274     }
275     JNIEnv* env = AndroidRuntime::getJNIEnv();
276     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId,
277                         cableConnectionStatus);
278 }
279 
onTvMessage(int deviceId,int streamId,AidlTvMessageEventType type,AidlTvMessage & message,signed char data[],int dataLength)280 void JTvInputHal::onTvMessage(int deviceId, int streamId, AidlTvMessageEventType type,
281                               AidlTvMessage& message, signed char data[], int dataLength) {
282     JNIEnv* env = AndroidRuntime::getJNIEnv();
283     ScopedLocalRef<jobject> bundle(env,
284                                    env->NewObject(gBundleClassInfo.clazz,
285                                                   gBundleClassInfo.constructor));
286     ScopedLocalRef<jbyteArray> convertedData(env, env->NewByteArray(dataLength));
287     env->SetByteArrayRegion(convertedData.get(), 0, dataLength, reinterpret_cast<jbyte*>(data));
288     std::string key = "android.media.tv.TvInputManager.raw_data";
289     ScopedLocalRef<jstring> jkey(env, env->NewStringUTF(key.c_str()));
290     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putByteArray, jkey.get(),
291                         convertedData.get());
292     ScopedLocalRef<jstring> subtype(env, env->NewStringUTF(message.subType.c_str()));
293     key = "android.media.tv.TvInputManager.subtype";
294     jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
295     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putString, jkey.get(), subtype.get());
296     key = "android.media.tv.TvInputManager.group_id";
297     jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
298     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putInt, jkey.get(), message.groupId);
299     key = "android.media.tv.TvInputManager.stream_id";
300     jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
301     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putInt, jkey.get(), streamId);
302     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.tvMessageReceived, deviceId,
303                         static_cast<jint>(type), bundle.get());
304 }
305 
onCaptured(int deviceId,int streamId,uint32_t seq,bool succeeded)306 void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
307     sp<BufferProducerThread> thread;
308     {
309         Mutex::Autolock autoLock(&mLock);
310         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
311         Connection& connection = connections.editValueFor(streamId);
312         if (connection.mThread == NULL) {
313             ALOGE("capture thread not existing.");
314             return;
315         }
316         thread = connection.mThread;
317     }
318     thread->onCaptured(seq, succeeded);
319     if (seq == 0) {
320         JNIEnv* env = AndroidRuntime::getJNIEnv();
321         env->CallVoidMethod(mThiz, gTvInputHalClassInfo.firstFrameCaptured, deviceId, streamId);
322     }
323 }
324 
325 JTvInputHal::TvInputDeviceInfoWrapper
createDeviceInfoWrapper(const AidlTvInputDeviceInfo & aidlTvInputDeviceInfo)326 JTvInputHal::TvInputDeviceInfoWrapper::createDeviceInfoWrapper(
327         const AidlTvInputDeviceInfo& aidlTvInputDeviceInfo) {
328     TvInputDeviceInfoWrapper deviceInfo;
329     deviceInfo.isHidl = false;
330     deviceInfo.deviceId = aidlTvInputDeviceInfo.deviceId;
331     deviceInfo.type = aidlTvInputDeviceInfo.type;
332     deviceInfo.portId = aidlTvInputDeviceInfo.portId;
333     deviceInfo.cableConnectionStatus = aidlTvInputDeviceInfo.cableConnectionStatus;
334     deviceInfo.aidlAudioDevice = aidlTvInputDeviceInfo.audioDevice;
335     return deviceInfo;
336 }
337 
createEventWrapper(const AidlTvInputEvent & aidlTvInputEvent)338 JTvInputHal::TvInputEventWrapper JTvInputHal::TvInputEventWrapper::createEventWrapper(
339         const AidlTvInputEvent& aidlTvInputEvent) {
340     TvInputEventWrapper event;
341     event.type = aidlTvInputEvent.type;
342     event.deviceInfo =
343             TvInputDeviceInfoWrapper::createDeviceInfoWrapper(aidlTvInputEvent.deviceInfo);
344     return event;
345 }
346 
createEventWrapper(const AidlTvMessageEvent & aidlTvMessageEvent)347 JTvInputHal::TvMessageEventWrapper JTvInputHal::TvMessageEventWrapper::createEventWrapper(
348         const AidlTvMessageEvent& aidlTvMessageEvent) {
349     TvMessageEventWrapper event;
350     event.messages.insert(event.messages.begin(), std::begin(aidlTvMessageEvent.messages) + 1,
351                           std::end(aidlTvMessageEvent.messages));
352     event.streamId = aidlTvMessageEvent.streamId;
353     event.deviceId = aidlTvMessageEvent.messages[0].groupId;
354     event.type = aidlTvMessageEvent.type;
355     return event;
356 }
357 
NotifyHandler(JTvInputHal * hal,const TvInputEventWrapper & event)358 JTvInputHal::NotifyHandler::NotifyHandler(JTvInputHal* hal, const TvInputEventWrapper& event) {
359     mHal = hal;
360     mEvent = event;
361 }
362 
handleMessage(const Message & message)363 void JTvInputHal::NotifyHandler::handleMessage(const Message& message) {
364     switch (mEvent.type) {
365         case TvInputEventType::DEVICE_AVAILABLE: {
366             mHal->onDeviceAvailable(mEvent.deviceInfo);
367         } break;
368         case TvInputEventType::DEVICE_UNAVAILABLE: {
369             mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId);
370         } break;
371         case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: {
372             int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus);
373             mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus);
374         } break;
375         default:
376             ALOGE("Unrecognizable event");
377     }
378 }
379 
NotifyTvMessageHandler(JTvInputHal * hal,const TvMessageEventWrapper & event)380 JTvInputHal::NotifyTvMessageHandler::NotifyTvMessageHandler(JTvInputHal* hal,
381                                                             const TvMessageEventWrapper& event) {
382     mHal = hal;
383     mEvent = event;
384 }
385 
handleMessage(const Message & message)386 void JTvInputHal::NotifyTvMessageHandler::handleMessage(const Message& message) {
387     std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> queue =
388             mHal->mQueueMap[mEvent.deviceId][mEvent.streamId];
389     for (AidlTvMessage item : mEvent.messages) {
390         if (queue == NULL || !queue->isValid() || queue->availableToRead() < item.dataLengthBytes) {
391             MQDescriptor<int8_t, SynchronizedReadWrite> queueDesc;
392             if (mHal->mTvInput->getTvMessageQueueDesc(&queueDesc, mEvent.deviceId, mEvent.streamId)
393                         .isOk()) {
394                 queue = std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(queueDesc,
395                                                                                           false);
396             }
397             if (queue == NULL || !queue->isValid() ||
398                 queue->availableToRead() < item.dataLengthBytes) {
399                 ALOGE("Incomplete TvMessageQueue data or missing queue");
400                 return;
401             }
402             mHal->mQueueMap[mEvent.deviceId][mEvent.streamId] = queue;
403         }
404         signed char* buffer = new signed char[item.dataLengthBytes];
405         if (queue->read(buffer, item.dataLengthBytes)) {
406             mHal->onTvMessage(mEvent.deviceId, mEvent.streamId, mEvent.type, item, buffer,
407                               item.dataLengthBytes);
408         } else {
409             ALOGE("Failed to read from TvMessageQueue");
410         }
411         delete[] buffer;
412     }
413 }
414 
TvInputCallback(JTvInputHal * hal)415 JTvInputHal::TvInputCallback::TvInputCallback(JTvInputHal* hal) {
416     mHal = hal;
417 }
418 
notify(const AidlTvInputEvent & event)419 ::ndk::ScopedAStatus JTvInputHal::TvInputCallback::notify(const AidlTvInputEvent& event) {
420     mHal->mLooper->sendMessage(new NotifyHandler(mHal,
421                                                  TvInputEventWrapper::createEventWrapper(event)),
422                                static_cast<int>(event.type));
423     return ::ndk::ScopedAStatus::ok();
424 }
425 
notifyTvMessageEvent(const AidlTvMessageEvent & event)426 ::ndk::ScopedAStatus JTvInputHal::TvInputCallback::notifyTvMessageEvent(
427         const AidlTvMessageEvent& event) {
428     const std::string DEVICE_ID_SUBTYPE = "device_id";
429     if (event.messages.size() > 1 && event.messages[0].subType == DEVICE_ID_SUBTYPE) {
430         mHal->mLooper
431                 ->sendMessage(new NotifyTvMessageHandler(mHal,
432                                                          TvMessageEventWrapper::createEventWrapper(
433                                                                  event)),
434                               static_cast<int>(event.type));
435     }
436 
437     return ::ndk::ScopedAStatus::ok();
438 }
439 
ITvInputWrapper(std::shared_ptr<AidlITvInput> & aidlTvInput)440 JTvInputHal::ITvInputWrapper::ITvInputWrapper(std::shared_ptr<AidlITvInput>& aidlTvInput)
441       : mIsHidl(false), mAidlTvInput(aidlTvInput) {}
442 
setCallback(const std::shared_ptr<TvInputCallback> & in_callback)443 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::setCallback(
444         const std::shared_ptr<TvInputCallback>& in_callback) {
445     if (mIsHidl) {
446         return hidlSetCallback(in_callback);
447     } else {
448         return mAidlTvInput->setCallback(in_callback);
449     }
450 }
451 
getStreamConfigurations(int32_t in_deviceId,std::vector<AidlTvStreamConfig> * _aidl_return)452 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::getStreamConfigurations(
453         int32_t in_deviceId, std::vector<AidlTvStreamConfig>* _aidl_return) {
454     if (mIsHidl) {
455         return hidlGetStreamConfigurations(in_deviceId, _aidl_return);
456     } else {
457         return mAidlTvInput->getStreamConfigurations(in_deviceId, _aidl_return);
458     }
459 }
460 
openStream(int32_t in_deviceId,int32_t in_streamId,AidlNativeHandle * _aidl_return)461 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::openStream(int32_t in_deviceId,
462                                                               int32_t in_streamId,
463                                                               AidlNativeHandle* _aidl_return) {
464     if (mIsHidl) {
465         return hidlOpenStream(in_deviceId, in_streamId, _aidl_return);
466     } else {
467         return mAidlTvInput->openStream(in_deviceId, in_streamId, _aidl_return);
468     }
469 }
470 
closeStream(int32_t in_deviceId,int32_t in_streamId)471 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::closeStream(int32_t in_deviceId,
472                                                                int32_t in_streamId) {
473     if (mIsHidl) {
474         return hidlCloseStream(in_deviceId, in_streamId);
475     } else {
476         return mAidlTvInput->closeStream(in_deviceId, in_streamId);
477     }
478 }
479 
setTvMessageEnabled(int32_t deviceId,int32_t streamId,TvMessageEventType in_type,bool enabled)480 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::setTvMessageEnabled(int32_t deviceId,
481                                                                        int32_t streamId,
482                                                                        TvMessageEventType in_type,
483                                                                        bool enabled) {
484     if (mIsHidl) {
485         return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
486     } else {
487         return mAidlTvInput->setTvMessageEnabled(deviceId, streamId, in_type, enabled);
488     }
489 }
490 
getTvMessageQueueDesc(MQDescriptor<int8_t,SynchronizedReadWrite> * out_queue,int32_t in_deviceId,int32_t in_streamId)491 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::getTvMessageQueueDesc(
492         MQDescriptor<int8_t, SynchronizedReadWrite>* out_queue, int32_t in_deviceId,
493         int32_t in_streamId) {
494     if (mIsHidl) {
495         return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
496     } else {
497         return mAidlTvInput->getTvMessageQueueDesc(out_queue, in_deviceId, in_streamId);
498     }
499 }
500 
501 } // namespace android
502