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 = std::shared_ptr<TvInputCallbackWrapper>(new TvInputCallbackWrapper(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     if (!mTvInput->setTvMessageEnabled(deviceId, streamId,
151                                        static_cast<AidlTvMessageEventType>(type), enabled)
152                  .isOk()) {
153         ALOGE("Error in setTvMessageEnabled. device id:%d stream id:%d", deviceId, streamId);
154         return BAD_VALUE;
155     }
156     return NO_ERROR;
157 }
158 
getStreamConfigs(int deviceId)159 const std::vector<AidlTvStreamConfig> JTvInputHal::getStreamConfigs(int deviceId) {
160     std::vector<AidlTvStreamConfig> list;
161     ::ndk::ScopedAStatus status = mTvInput->getStreamConfigurations(deviceId, &list);
162     if (!status.isOk()) {
163         ALOGE("Couldn't get stream configs for device id:%d result:%d", deviceId,
164               status.getServiceSpecificError());
165         return std::vector<AidlTvStreamConfig>();
166     }
167     return list;
168 }
169 
170 static const std::map<std::pair<AidlAudioDeviceType, std::string>, audio_devices_t>
171         aidlToNativeAudioType = {
172     {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_ANALOG},
173         AUDIO_DEVICE_IN_LINE},
174     {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_HDMI},
175         AUDIO_DEVICE_IN_HDMI},
176     {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_HDMI_ARC},
177         AUDIO_DEVICE_IN_HDMI_ARC},
178     {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_HDMI_EARC},
179         AUDIO_DEVICE_IN_HDMI_EARC},
180     {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_IP_V4},
181         AUDIO_DEVICE_IN_IP},
182     {{AidlAudioDeviceType::IN_DEVICE, AidlAudioDeviceDescription::CONNECTION_SPDIF},
183         AUDIO_DEVICE_IN_SPDIF},
184     {{AidlAudioDeviceType::IN_LOOPBACK, ""}, AUDIO_DEVICE_IN_LOOPBACK},
185     {{AidlAudioDeviceType::IN_TV_TUNER, ""}, AUDIO_DEVICE_IN_TV_TUNER},
186 };
187 
onDeviceAvailable(const TvInputDeviceInfoWrapper & info)188 void JTvInputHal::onDeviceAvailable(const TvInputDeviceInfoWrapper& info) {
189     {
190         Mutex::Autolock autoLock(&mStreamLock);
191         mConnections.add(info.deviceId, KeyedVector<int, Connection>());
192     }
193     JNIEnv* env = AndroidRuntime::getJNIEnv();
194     jobject builder = env->NewObject(gTvInputHardwareInfoBuilderClassInfo.clazz,
195                                      gTvInputHardwareInfoBuilderClassInfo.constructor);
196     env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.deviceId, info.deviceId);
197     env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.type, info.type);
198     if (info.type == TvInputType::HDMI) {
199         env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.hdmiPortId,
200                               info.portId);
201     }
202     env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.cableConnectionStatus,
203                           info.cableConnectionStatus);
204     if (info.isHidl) {
205         hidlSetUpAudioInfo(env, builder, info);
206     } else {
207         auto it = aidlToNativeAudioType.find({info.aidlAudioDevice.type.type,
208                                     info.aidlAudioDevice.type.connection});
209         audio_devices_t nativeAudioType = AUDIO_DEVICE_NONE;
210         if (it != aidlToNativeAudioType.end()) {
211             nativeAudioType = it->second;
212         }
213         env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioType,
214             nativeAudioType);
215         if (info.aidlAudioDevice.type.type != AidlAudioDeviceType::NONE) {
216             std::stringstream ss;
217             switch (info.aidlAudioDevice.address.getTag()) {
218                 case AidlAudioDeviceAddress::id:
219                     ss << info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::id>();
220                     break;
221                 case AidlAudioDeviceAddress::mac: {
222                     std::vector<uint8_t> addrList =
223                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::mac>();
224                     for (int i = 0; i < addrList.size(); i++) {
225                         if (i != 0) {
226                             ss << ':';
227                         }
228                         ss << std::uppercase << std::setfill('0') << std::setw(2) << std::hex
229                            << static_cast<int32_t>(addrList[i]);
230                     }
231                 } break;
232                 case AidlAudioDeviceAddress::ipv4: {
233                     std::vector<uint8_t> addrList =
234                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::ipv4>();
235                     for (int i = 0; i < addrList.size(); i++) {
236                         if (i != 0) {
237                             ss << '.';
238                         }
239                         ss << static_cast<int32_t>(addrList[i]);
240                     }
241                 } break;
242                 case AidlAudioDeviceAddress::ipv6: {
243                     std::vector<int32_t> addrList =
244                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::ipv6>();
245                     for (int i = 0; i < addrList.size(); i++) {
246                         if (i != 0) {
247                             ss << ':';
248                         }
249                         ss << std::uppercase << std::setfill('0') << std::setw(4) << std::hex
250                            << addrList[i];
251                     }
252                 } break;
253                 case AidlAudioDeviceAddress::alsa: {
254                     std::vector<int32_t> addrList =
255                             info.aidlAudioDevice.address.get<AidlAudioDeviceAddress::alsa>();
256                     ss << "card=" << addrList[0] << ";device=" << addrList[1];
257                 } break;
258             }
259             std::string bufferStr = ss.str();
260             jstring audioAddress = env->NewStringUTF(bufferStr.c_str());
261             env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.audioAddress,
262                                   audioAddress);
263             env->DeleteLocalRef(audioAddress);
264         }
265     }
266 
267     jobject infoObject = env->CallObjectMethod(builder, gTvInputHardwareInfoBuilderClassInfo.build);
268 
269     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.deviceAvailable, infoObject);
270 
271     env->DeleteLocalRef(builder);
272     env->DeleteLocalRef(infoObject);
273 }
274 
onDeviceUnavailable(int deviceId)275 void JTvInputHal::onDeviceUnavailable(int deviceId) {
276     {
277         Mutex::Autolock autoLock(&mStreamLock);
278         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
279         for (size_t i = 0; i < connections.size(); ++i) {
280             removeStream(deviceId, connections.keyAt(i));
281         }
282         connections.clear();
283         mConnections.removeItem(deviceId);
284     }
285     JNIEnv* env = AndroidRuntime::getJNIEnv();
286     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.deviceUnavailable, deviceId);
287 }
288 
onStreamConfigurationsChanged(int deviceId,int cableConnectionStatus)289 void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus) {
290     {
291         Mutex::Autolock autoLock(&mStreamLock);
292         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
293         for (size_t i = 0; i < connections.size(); ++i) {
294             removeStream(deviceId, connections.keyAt(i));
295         }
296         connections.clear();
297     }
298     JNIEnv* env = AndroidRuntime::getJNIEnv();
299     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.streamConfigsChanged, deviceId,
300                         cableConnectionStatus);
301 }
302 
onTvMessage(int deviceId,int streamId,AidlTvMessageEventType type,AidlTvMessage & message,signed char data[],int dataLength)303 void JTvInputHal::onTvMessage(int deviceId, int streamId, AidlTvMessageEventType type,
304                               AidlTvMessage& message, signed char data[], int dataLength) {
305     JNIEnv* env = AndroidRuntime::getJNIEnv();
306     ScopedLocalRef<jobject> bundle(env,
307                                    env->NewObject(gBundleClassInfo.clazz,
308                                                   gBundleClassInfo.constructor));
309     ScopedLocalRef<jbyteArray> convertedData(env, env->NewByteArray(dataLength));
310     env->SetByteArrayRegion(convertedData.get(), 0, dataLength, reinterpret_cast<jbyte*>(data));
311     std::string key = "android.media.tv.TvInputManager.raw_data";
312     ScopedLocalRef<jstring> jkey(env, env->NewStringUTF(key.c_str()));
313     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putByteArray, jkey.get(),
314                         convertedData.get());
315     ScopedLocalRef<jstring> subtype(env, env->NewStringUTF(message.subType.c_str()));
316     key = "android.media.tv.TvInputManager.subtype";
317     jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
318     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putString, jkey.get(), subtype.get());
319     key = "android.media.tv.TvInputManager.group_id";
320     jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
321     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putInt, jkey.get(), message.groupId);
322     key = "android.media.tv.TvInputManager.stream_id";
323     jkey = ScopedLocalRef<jstring>(env, env->NewStringUTF(key.c_str()));
324     env->CallVoidMethod(bundle.get(), gBundleClassInfo.putInt, jkey.get(), streamId);
325     env->CallVoidMethod(mThiz, gTvInputHalClassInfo.tvMessageReceived, deviceId,
326                         static_cast<jint>(type), bundle.get());
327 }
328 
onCaptured(int deviceId,int streamId,uint32_t seq,bool succeeded)329 void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) {
330     sp<BufferProducerThread> thread;
331     {
332         Mutex::Autolock autoLock(&mStreamLock);
333         KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId);
334         Connection& connection = connections.editValueFor(streamId);
335         if (connection.mThread == NULL) {
336             ALOGE("capture thread not existing.");
337             return;
338         }
339         thread = connection.mThread;
340     }
341     thread->onCaptured(seq, succeeded);
342     if (seq == 0) {
343         JNIEnv* env = AndroidRuntime::getJNIEnv();
344         env->CallVoidMethod(mThiz, gTvInputHalClassInfo.firstFrameCaptured, deviceId, streamId);
345     }
346 }
347 
348 JTvInputHal::TvInputDeviceInfoWrapper
createDeviceInfoWrapper(const AidlTvInputDeviceInfo & aidlTvInputDeviceInfo)349 JTvInputHal::TvInputDeviceInfoWrapper::createDeviceInfoWrapper(
350         const AidlTvInputDeviceInfo& aidlTvInputDeviceInfo) {
351     TvInputDeviceInfoWrapper deviceInfo;
352     deviceInfo.isHidl = false;
353     deviceInfo.deviceId = aidlTvInputDeviceInfo.deviceId;
354     deviceInfo.type = aidlTvInputDeviceInfo.type;
355     deviceInfo.portId = aidlTvInputDeviceInfo.portId;
356     deviceInfo.cableConnectionStatus = aidlTvInputDeviceInfo.cableConnectionStatus;
357     deviceInfo.aidlAudioDevice = aidlTvInputDeviceInfo.audioDevice;
358     return deviceInfo;
359 }
360 
createEventWrapper(const AidlTvInputEvent & aidlTvInputEvent)361 JTvInputHal::TvInputEventWrapper JTvInputHal::TvInputEventWrapper::createEventWrapper(
362         const AidlTvInputEvent& aidlTvInputEvent) {
363     TvInputEventWrapper event;
364     event.type = aidlTvInputEvent.type;
365     event.deviceInfo =
366             TvInputDeviceInfoWrapper::createDeviceInfoWrapper(aidlTvInputEvent.deviceInfo);
367     return event;
368 }
369 
createEventWrapper(const AidlTvMessageEvent & aidlTvMessageEvent,bool isLegacyMessage)370 JTvInputHal::TvMessageEventWrapper JTvInputHal::TvMessageEventWrapper::createEventWrapper(
371         const AidlTvMessageEvent& aidlTvMessageEvent, bool isLegacyMessage) {
372     auto messageList = aidlTvMessageEvent.messages;
373     TvMessageEventWrapper event;
374     // Handle backwards compatibility for V1
375     if (isLegacyMessage) {
376         event.deviceId = messageList[0].groupId;
377         event.messages.insert(event.messages.begin(), std::begin(messageList) + 1,
378                               std::end(messageList));
379     } else {
380         event.deviceId = aidlTvMessageEvent.deviceId;
381         event.messages.insert(event.messages.begin(), std::begin(messageList),
382                               std::end(messageList));
383     }
384     event.streamId = aidlTvMessageEvent.streamId;
385     event.type = aidlTvMessageEvent.type;
386     return event;
387 }
388 
NotifyHandler(JTvInputHal * hal,const TvInputEventWrapper & event)389 JTvInputHal::NotifyHandler::NotifyHandler(JTvInputHal* hal, const TvInputEventWrapper& event) {
390     mHal = hal;
391     mEvent = event;
392 }
393 
handleMessage(const Message & message)394 void JTvInputHal::NotifyHandler::handleMessage(const Message& message) {
395     switch (mEvent.type) {
396         case TvInputEventType::DEVICE_AVAILABLE: {
397             mHal->onDeviceAvailable(mEvent.deviceInfo);
398         } break;
399         case TvInputEventType::DEVICE_UNAVAILABLE: {
400             mHal->onDeviceUnavailable(mEvent.deviceInfo.deviceId);
401         } break;
402         case TvInputEventType::STREAM_CONFIGURATIONS_CHANGED: {
403             int cableConnectionStatus = static_cast<int>(mEvent.deviceInfo.cableConnectionStatus);
404             mHal->onStreamConfigurationsChanged(mEvent.deviceInfo.deviceId, cableConnectionStatus);
405         } break;
406         default:
407             ALOGE("Unrecognizable event");
408     }
409 }
410 
NotifyTvMessageHandler(JTvInputHal * hal,const TvMessageEventWrapper & event)411 JTvInputHal::NotifyTvMessageHandler::NotifyTvMessageHandler(JTvInputHal* hal,
412                                                             const TvMessageEventWrapper& event) {
413     mHal = hal;
414     mEvent = event;
415 }
416 
handleMessage(const Message & message)417 void JTvInputHal::NotifyTvMessageHandler::handleMessage(const Message& message) {
418     std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> queue =
419             mHal->mQueueMap[mEvent.deviceId][mEvent.streamId];
420     for (AidlTvMessage item : mEvent.messages) {
421         if (queue == NULL || !queue->isValid() || queue->availableToRead() < item.dataLengthBytes) {
422             MQDescriptor<int8_t, SynchronizedReadWrite> queueDesc;
423             if (mHal->mTvInput->getTvMessageQueueDesc(&queueDesc, mEvent.deviceId, mEvent.streamId)
424                         .isOk()) {
425                 queue = std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(queueDesc,
426                                                                                           false);
427             }
428             if (queue == NULL || !queue->isValid() ||
429                 queue->availableToRead() < item.dataLengthBytes) {
430                 ALOGE("Incomplete TvMessageQueue data or missing queue");
431                 return;
432             }
433             mHal->mQueueMap[mEvent.deviceId][mEvent.streamId] = queue;
434         }
435         signed char* buffer = new signed char[item.dataLengthBytes];
436         if (queue->read(buffer, item.dataLengthBytes)) {
437             mHal->onTvMessage(mEvent.deviceId, mEvent.streamId, mEvent.type, item, buffer,
438                               item.dataLengthBytes);
439         } else {
440             ALOGE("Failed to read from TvMessageQueue");
441         }
442         delete[] buffer;
443     }
444 }
445 
TvInputCallbackWrapper(JTvInputHal * hal)446 JTvInputHal::TvInputCallbackWrapper::TvInputCallbackWrapper(JTvInputHal* hal) {
447     aidlTvInputCallback = ::ndk::SharedRefBase::make<AidlTvInputCallback>(hal);
448     hidlTvInputCallback = sp<HidlTvInputCallback>::make(hal);
449 }
450 
AidlTvInputCallback(JTvInputHal * hal)451 JTvInputHal::AidlTvInputCallback::AidlTvInputCallback(JTvInputHal* hal) {
452     mHal = hal;
453 }
454 
notify(const AidlTvInputEvent & event)455 ::ndk::ScopedAStatus JTvInputHal::AidlTvInputCallback::notify(const AidlTvInputEvent& event) {
456     mHal->mLooper->sendMessage(new NotifyHandler(mHal,
457                                                  TvInputEventWrapper::createEventWrapper(event)),
458                                static_cast<int>(event.type));
459     return ::ndk::ScopedAStatus::ok();
460 }
461 
notifyTvMessageEvent(const AidlTvMessageEvent & event)462 ::ndk::ScopedAStatus JTvInputHal::AidlTvInputCallback::notifyTvMessageEvent(
463         const AidlTvMessageEvent& event) {
464     const std::string DEVICE_ID_SUBTYPE = "device_id";
465     ::ndk::ScopedAStatus status = ::ndk::ScopedAStatus::ok();
466     int32_t aidlVersion = 0;
467     if (mHal->mTvInput->getAidlInterfaceVersion(&aidlVersion).isOk() && event.messages.size() > 0) {
468         bool validLegacyMessage = aidlVersion == 1 &&
469                 event.messages[0].subType == DEVICE_ID_SUBTYPE && event.messages.size() > 1;
470         bool validTvMessage = aidlVersion > 1 && event.messages.size() > 0;
471         if (validLegacyMessage || validTvMessage) {
472             mHal->mLooper->sendMessage(
473                     new NotifyTvMessageHandler(mHal,
474                                                TvMessageEventWrapper::
475                                                        createEventWrapper(event,
476                                                                           validLegacyMessage)),
477                     static_cast<int>(event.type));
478         } else {
479             status = ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
480             ALOGE("The TVMessage event was malformed for HAL version: %d", aidlVersion);
481         }
482     } else {
483         status = ::ndk::ScopedAStatus::fromExceptionCode(EX_ILLEGAL_ARGUMENT);
484         ALOGE("The TVMessage event was empty or the HAL version (version: %d) could not "
485               "be inferred.",
486               aidlVersion);
487     }
488     return status;
489 }
490 
ITvInputWrapper(std::shared_ptr<AidlITvInput> & aidlTvInput)491 JTvInputHal::ITvInputWrapper::ITvInputWrapper(std::shared_ptr<AidlITvInput>& aidlTvInput)
492       : mIsHidl(false), mAidlTvInput(aidlTvInput) {}
493 
setCallback(const std::shared_ptr<TvInputCallbackWrapper> & in_callback)494 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::setCallback(
495         const std::shared_ptr<TvInputCallbackWrapper>& in_callback) {
496     if (mIsHidl) {
497         if (in_callback == nullptr) {
498             return hidlSetCallback(nullptr);
499         }
500         else {
501             in_callback->aidlTvInputCallback = nullptr;
502             return hidlSetCallback(in_callback->hidlTvInputCallback);
503         }
504     } else {
505         if (in_callback == nullptr) {
506             return mAidlTvInput->setCallback(nullptr);
507         }
508         else {
509             in_callback->hidlTvInputCallback = nullptr;
510             return mAidlTvInput->setCallback(in_callback->aidlTvInputCallback);
511         }
512     }
513 }
514 
getStreamConfigurations(int32_t in_deviceId,std::vector<AidlTvStreamConfig> * _aidl_return)515 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::getStreamConfigurations(
516         int32_t in_deviceId, std::vector<AidlTvStreamConfig>* _aidl_return) {
517     if (mIsHidl) {
518         return hidlGetStreamConfigurations(in_deviceId, _aidl_return);
519     } else {
520         return mAidlTvInput->getStreamConfigurations(in_deviceId, _aidl_return);
521     }
522 }
523 
openStream(int32_t in_deviceId,int32_t in_streamId,AidlNativeHandle * _aidl_return)524 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::openStream(int32_t in_deviceId,
525                                                               int32_t in_streamId,
526                                                               AidlNativeHandle* _aidl_return) {
527     if (mIsHidl) {
528         return hidlOpenStream(in_deviceId, in_streamId, _aidl_return);
529     } else {
530         return mAidlTvInput->openStream(in_deviceId, in_streamId, _aidl_return);
531     }
532 }
533 
closeStream(int32_t in_deviceId,int32_t in_streamId)534 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::closeStream(int32_t in_deviceId,
535                                                                int32_t in_streamId) {
536     if (mIsHidl) {
537         return hidlCloseStream(in_deviceId, in_streamId);
538     } else {
539         return mAidlTvInput->closeStream(in_deviceId, in_streamId);
540     }
541 }
542 
setTvMessageEnabled(int32_t deviceId,int32_t streamId,TvMessageEventType in_type,bool enabled)543 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::setTvMessageEnabled(int32_t deviceId,
544                                                                        int32_t streamId,
545                                                                        TvMessageEventType in_type,
546                                                                        bool enabled) {
547     if (mIsHidl) {
548         return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
549     } else {
550         return mAidlTvInput->setTvMessageEnabled(deviceId, streamId, in_type, enabled);
551     }
552 }
553 
getTvMessageQueueDesc(MQDescriptor<int8_t,SynchronizedReadWrite> * out_queue,int32_t in_deviceId,int32_t in_streamId)554 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::getTvMessageQueueDesc(
555         MQDescriptor<int8_t, SynchronizedReadWrite>* out_queue, int32_t in_deviceId,
556         int32_t in_streamId) {
557     if (mIsHidl) {
558         return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
559     } else {
560         return mAidlTvInput->getTvMessageQueueDesc(out_queue, in_deviceId, in_streamId);
561     }
562 }
563 
getAidlInterfaceVersion(int32_t * _aidl_return)564 ::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::getAidlInterfaceVersion(int32_t* _aidl_return) {
565     if (mIsHidl) {
566         return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
567     } else {
568         return mAidlTvInput->getInterfaceVersion(_aidl_return);
569     }
570 }
571 
572 } // namespace android
573