|  | /** | 
|  | * Copyright (c) 2021, The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not use this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *     http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | //#define LOG_NDEBUG 0 | 
|  | #define LOG_TAG "TunerHidlService" | 
|  |  | 
|  | #include "TunerHidlService.h" | 
|  |  | 
|  | #include <aidl/android/hardware/tv/tuner/FrontendIsdbtTimeInterleaveMode.h> | 
|  | #include <aidl/android/hardware/tv/tuner/Result.h> | 
|  | #include <android/binder_manager.h> | 
|  | #include <binder/IPCThreadState.h> | 
|  | #include <binder/PermissionCache.h> | 
|  | #include <cutils/properties.h> | 
|  | #include <utils/Log.h> | 
|  |  | 
|  | #include "TunerHelper.h" | 
|  | #include "TunerHidlDemux.h" | 
|  | #include "TunerHidlDescrambler.h" | 
|  | #include "TunerHidlFrontend.h" | 
|  | #include "TunerHidlLnb.h" | 
|  |  | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendAnalogCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendAtsc3Capabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendAtscCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendDtmbCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendDvbcCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendDvbsCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendDvbtCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendIsdbs3Capabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendIsdbsCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendIsdbtCapabilities; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendIsdbtTimeInterleaveMode; | 
|  | using ::aidl::android::hardware::tv::tuner::FrontendType; | 
|  | using ::aidl::android::hardware::tv::tuner::Result; | 
|  | using ::android::IPCThreadState; | 
|  | using ::android::PermissionCache; | 
|  | using ::android::hardware::hidl_vec; | 
|  |  | 
|  | using HidlFrontendId = ::android::hardware::tv::tuner::V1_0::FrontendId; | 
|  | using HidlLnbId = ::android::hardware::tv::tuner::V1_0::LnbId; | 
|  | using HidlFrontendType = ::android::hardware::tv::tuner::V1_1::FrontendType; | 
|  |  | 
|  | using namespace std; | 
|  |  | 
|  | namespace aidl { | 
|  | namespace android { | 
|  | namespace media { | 
|  | namespace tv { | 
|  | namespace tuner { | 
|  |  | 
|  | TunerHidlService::TunerHidlService() { | 
|  | mTuner = HidlITuner::getService(); | 
|  | ALOGE_IF(mTuner == nullptr, "Failed to get ITuner service"); | 
|  | mTunerVersion = TUNER_HAL_VERSION_1_0; | 
|  |  | 
|  | mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::castFrom(mTuner); | 
|  | if (mTuner_1_1 != nullptr) { | 
|  | mTunerVersion = TUNER_HAL_VERSION_1_1; | 
|  | } else { | 
|  | ALOGD("Failed to get ITuner_1_1 service"); | 
|  | } | 
|  |  | 
|  | // Register tuner resources to TRM. | 
|  | updateTunerResources(); | 
|  | } | 
|  |  | 
|  | TunerHidlService::~TunerHidlService() { | 
|  | mOpenedFrontends.clear(); | 
|  | mLnaStatus = -1; | 
|  | mTuner = nullptr; | 
|  | mTuner_1_1 = nullptr; | 
|  | } | 
|  |  | 
|  | binder_status_t TunerHidlService::instantiate() { | 
|  | if (HidlITuner::getService() == nullptr) { | 
|  | ALOGD("Failed to get ITuner HIDL HAL"); | 
|  | return STATUS_NAME_NOT_FOUND; | 
|  | } | 
|  |  | 
|  | shared_ptr<TunerHidlService> tunerService = ::ndk::SharedRefBase::make<TunerHidlService>(); | 
|  | bool lazyHal = property_get_bool("ro.tuner.lazyhal", false); | 
|  | if (lazyHal) { | 
|  | return AServiceManager_registerLazyService(tunerService->asBinder().get(), | 
|  | getServiceName()); | 
|  | } | 
|  | return AServiceManager_addService(tunerService->asBinder().get(), getServiceName()); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::openDemux(int32_t /* in_demuxHandle */, | 
|  | shared_ptr<ITunerDemux>* _aidl_return) { | 
|  | ALOGV("openDemux"); | 
|  | HidlResult res; | 
|  | uint32_t id; | 
|  | sp<IDemux> demuxSp = nullptr; | 
|  | mTuner->openDemux([&](HidlResult r, uint32_t demuxId, const sp<IDemux>& demux) { | 
|  | demuxSp = demux; | 
|  | id = demuxId; | 
|  | res = r; | 
|  | ALOGD("open demux, id = %d", demuxId); | 
|  | }); | 
|  | if (res == HidlResult::SUCCESS) { | 
|  | *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlDemux>(demuxSp, id, | 
|  | this->ref<TunerHidlService>()); | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ALOGW("open demux failed, res = %d", res); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res)); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::getDemuxInfo(int32_t /* in_demuxHandle */, | 
|  | DemuxInfo* /* _aidl_return */) { | 
|  | ALOGE("getDemuxInfo is not supported"); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(HidlResult::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::getDemuxInfoList( | 
|  | vector<DemuxInfo>* /* _aidle_return */) { | 
|  | ALOGE("getDemuxInfoList is not supported"); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(HidlResult::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::getDemuxCaps(DemuxCapabilities* _aidl_return) { | 
|  | ALOGV("getDemuxCaps"); | 
|  | HidlResult res; | 
|  | HidlDemuxCapabilities caps; | 
|  | mTuner->getDemuxCaps([&](HidlResult r, const HidlDemuxCapabilities& demuxCaps) { | 
|  | caps = demuxCaps; | 
|  | res = r; | 
|  | }); | 
|  | if (res == HidlResult::SUCCESS) { | 
|  | *_aidl_return = getAidlDemuxCaps(caps); | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ALOGW("Get demux caps failed, res = %d", res); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res)); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::getFrontendIds(vector<int32_t>* ids) { | 
|  | hidl_vec<HidlFrontendId> feIds; | 
|  | HidlResult res = getHidlFrontendIds(feIds); | 
|  | if (res != HidlResult::SUCCESS) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res)); | 
|  | } | 
|  | ids->resize(feIds.size()); | 
|  | copy(feIds.begin(), feIds.end(), ids->begin()); | 
|  |  | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::getFrontendInfo(int32_t id, FrontendInfo* _aidl_return) { | 
|  | HidlFrontendInfo info; | 
|  | HidlResult res = getHidlFrontendInfo(id, info); | 
|  | if (res != HidlResult::SUCCESS) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res)); | 
|  | } | 
|  |  | 
|  | HidlFrontendDtmbCapabilities dtmbCaps; | 
|  | if (static_cast<HidlFrontendType>(info.type) == HidlFrontendType::DTMB) { | 
|  | if (mTuner_1_1 == nullptr) { | 
|  | ALOGE("ITuner_1_1 service is not init."); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | mTuner_1_1->getFrontendDtmbCapabilities( | 
|  | id, [&](HidlResult r, const HidlFrontendDtmbCapabilities& caps) { | 
|  | dtmbCaps = caps; | 
|  | res = r; | 
|  | }); | 
|  | if (res != HidlResult::SUCCESS) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res)); | 
|  | } | 
|  | } | 
|  |  | 
|  | *_aidl_return = getAidlFrontendInfo(info, dtmbCaps); | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::openFrontend(int32_t frontendHandle, | 
|  | shared_ptr<ITunerFrontend>* _aidl_return) { | 
|  | HidlResult status; | 
|  | sp<HidlIFrontend> frontend; | 
|  | int id = TunerHelper::getResourceIdFromHandle(frontendHandle, FRONTEND); | 
|  | mTuner->openFrontendById(id, [&](HidlResult result, const sp<HidlIFrontend>& fe) { | 
|  | frontend = fe; | 
|  | status = result; | 
|  | }); | 
|  | if (status != HidlResult::SUCCESS) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status)); | 
|  | } | 
|  |  | 
|  | shared_ptr<TunerHidlFrontend> tunerFrontend = ::ndk::SharedRefBase::make<TunerHidlFrontend>( | 
|  | frontend, id, this->ref<TunerHidlService>()); | 
|  | if (mLnaStatus != -1) { | 
|  | tunerFrontend->setLna(mLnaStatus == 1); | 
|  | } | 
|  | { | 
|  | Mutex::Autolock _l(mOpenedFrontendsLock); | 
|  | mOpenedFrontends.insert(tunerFrontend); | 
|  | } | 
|  | *_aidl_return = tunerFrontend; | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::openLnb(int lnbHandle, shared_ptr<ITunerLnb>* _aidl_return) { | 
|  | HidlResult status; | 
|  | sp<HidlILnb> lnb; | 
|  | int id = TunerHelper::getResourceIdFromHandle(lnbHandle, LNB); | 
|  | mTuner->openLnbById(id, [&](HidlResult result, const sp<HidlILnb>& lnbSp) { | 
|  | lnb = lnbSp; | 
|  | status = result; | 
|  | }); | 
|  | if (status != HidlResult::SUCCESS) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status)); | 
|  | } | 
|  |  | 
|  | *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlLnb>(lnb, id); | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::openLnbByName(const string& lnbName, | 
|  | shared_ptr<ITunerLnb>* _aidl_return) { | 
|  | int lnbId; | 
|  | HidlResult status; | 
|  | sp<HidlILnb> lnb; | 
|  | mTuner->openLnbByName(lnbName, [&](HidlResult r, HidlLnbId id, const sp<HidlILnb>& lnbSp) { | 
|  | status = r; | 
|  | lnb = lnbSp; | 
|  | lnbId = static_cast<int32_t>(id); | 
|  | }); | 
|  | if (status != HidlResult::SUCCESS) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status)); | 
|  | } | 
|  |  | 
|  | *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlLnb>(lnb, lnbId); | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::openDescrambler( | 
|  | int32_t /*descramblerHandle*/, shared_ptr<ITunerDescrambler>* _aidl_return) { | 
|  | HidlResult status; | 
|  | sp<HidlIDescrambler> descrambler; | 
|  | //int id = TunerHelper::getResourceIdFromHandle(descramblerHandle, DESCRAMBLER); | 
|  | mTuner->openDescrambler([&](HidlResult r, const sp<HidlIDescrambler>& descramblerSp) { | 
|  | status = r; | 
|  | descrambler = descramblerSp; | 
|  | }); | 
|  | if (status != HidlResult::SUCCESS) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(status)); | 
|  | } | 
|  |  | 
|  | *_aidl_return = ::ndk::SharedRefBase::make<TunerHidlDescrambler>(descrambler); | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::getTunerHalVersion(int* _aidl_return) { | 
|  | *_aidl_return = mTunerVersion; | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::openSharedFilter( | 
|  | const string& in_filterToken, const shared_ptr<ITunerFilterCallback>& in_cb, | 
|  | shared_ptr<ITunerFilter>* _aidl_return) { | 
|  | if (mTuner == nullptr) { | 
|  | ALOGE("get ITuner failed"); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | if (!PermissionCache::checkCallingPermission(sSharedFilterPermission)) { | 
|  | ALOGE("Request requires android.permission.ACCESS_TV_SHARED_FILTER"); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | Mutex::Autolock _l(mSharedFiltersLock); | 
|  | if (mSharedFilters.find(in_filterToken) == mSharedFilters.end()) { | 
|  | *_aidl_return = nullptr; | 
|  | ALOGD("fail to find %s", in_filterToken.c_str()); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::INVALID_STATE)); | 
|  | } | 
|  |  | 
|  | shared_ptr<TunerHidlFilter> filter = mSharedFilters.at(in_filterToken); | 
|  | IPCThreadState* ipc = IPCThreadState::self(); | 
|  | const int pid = ipc->getCallingPid(); | 
|  | if (!filter->isSharedFilterAllowed(pid)) { | 
|  | *_aidl_return = nullptr; | 
|  | ALOGD("shared filter %s is opened in the same process", in_filterToken.c_str()); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::INVALID_STATE)); | 
|  | } | 
|  |  | 
|  | filter->attachSharedFilterCallback(in_cb); | 
|  |  | 
|  | *_aidl_return = filter; | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::isLnaSupported(bool* /* _aidl_return */) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::setLna(bool bEnable) { | 
|  | if (mTuner == nullptr) { | 
|  | ALOGE("get ITuner failed"); | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | mLnaStatus = bEnable ? 1 : 0; | 
|  |  | 
|  | { | 
|  | Mutex::Autolock _l(mOpenedFrontendsLock); | 
|  | for (auto it = mOpenedFrontends.begin(); it != mOpenedFrontends.end(); ++it) { | 
|  | (*it)->setLna(mLnaStatus == 1); | 
|  | } | 
|  | } | 
|  |  | 
|  | return ::ndk::ScopedAStatus::ok(); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::setMaxNumberOfFrontends(FrontendType /* in_frontendType */, | 
|  | int32_t /* in_maxNumber */) { | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | ::ndk::ScopedAStatus TunerHidlService::getMaxNumberOfFrontends(FrontendType /* in_frontendType */, | 
|  | int32_t* _aidl_return) { | 
|  | *_aidl_return = -1; | 
|  | return ::ndk::ScopedAStatus::fromServiceSpecificError( | 
|  | static_cast<int32_t>(Result::UNAVAILABLE)); | 
|  | } | 
|  |  | 
|  | string TunerHidlService::addFilterToShared(const shared_ptr<TunerHidlFilter>& sharedFilter) { | 
|  | Mutex::Autolock _l(mSharedFiltersLock); | 
|  |  | 
|  | // Use sharedFilter address as token. | 
|  | string token = to_string(reinterpret_cast<std::uintptr_t>(sharedFilter.get())); | 
|  | mSharedFilters[token] = sharedFilter; | 
|  |  | 
|  | return token; | 
|  | } | 
|  |  | 
|  | void TunerHidlService::removeSharedFilter(const shared_ptr<TunerHidlFilter>& sharedFilter) { | 
|  | Mutex::Autolock _l(mSharedFiltersLock); | 
|  |  | 
|  | // Use sharedFilter address as token. | 
|  | mSharedFilters.erase(to_string(reinterpret_cast<std::uintptr_t>(sharedFilter.get()))); | 
|  | } | 
|  |  | 
|  | void TunerHidlService::removeFrontend(const shared_ptr<TunerHidlFrontend>& frontend) { | 
|  | Mutex::Autolock _l(mOpenedFrontendsLock); | 
|  | for (auto it = mOpenedFrontends.begin(); it != mOpenedFrontends.end(); ++it) { | 
|  | if (it->get() == frontend.get()) { | 
|  | mOpenedFrontends.erase(it); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void TunerHidlService::updateTunerResources() { | 
|  | TunerHelper::updateTunerResources(getTRMFrontendInfos(), getTRMLnbHandles()); | 
|  | } | 
|  |  | 
|  | vector<TunerFrontendInfo> TunerHidlService::getTRMFrontendInfos() { | 
|  | vector<TunerFrontendInfo> infos; | 
|  | hidl_vec<HidlFrontendId> ids; | 
|  | HidlResult res = getHidlFrontendIds(ids); | 
|  | if (res != HidlResult::SUCCESS) { | 
|  | return infos; | 
|  | } | 
|  |  | 
|  | for (int i = 0; i < ids.size(); i++) { | 
|  | HidlFrontendInfo frontendInfo; | 
|  | HidlResult res = getHidlFrontendInfo(static_cast<int32_t>(ids[i]), frontendInfo); | 
|  | if (res != HidlResult::SUCCESS) { | 
|  | continue; | 
|  | } | 
|  | TunerFrontendInfo tunerFrontendInfo{ | 
|  | .handle = TunerHelper::getResourceHandleFromId(static_cast<int32_t>(ids[i]), | 
|  | FRONTEND), | 
|  | .type = static_cast<int32_t>(frontendInfo.type), | 
|  | .exclusiveGroupId = static_cast<int32_t>(frontendInfo.exclusiveGroupId), | 
|  | }; | 
|  | infos.push_back(tunerFrontendInfo); | 
|  | } | 
|  |  | 
|  | return infos; | 
|  | } | 
|  |  | 
|  | vector<int32_t> TunerHidlService::getTRMLnbHandles() { | 
|  | vector<int32_t> lnbHandles; | 
|  | if (mTuner != nullptr) { | 
|  | HidlResult res; | 
|  | vector<HidlLnbId> lnbIds; | 
|  | mTuner->getLnbIds([&](HidlResult r, const hidl_vec<HidlLnbId>& ids) { | 
|  | lnbIds = ids; | 
|  | res = r; | 
|  | }); | 
|  | if (res == HidlResult::SUCCESS && lnbIds.size() > 0) { | 
|  | for (int i = 0; i < lnbIds.size(); i++) { | 
|  | lnbHandles.push_back( | 
|  | TunerHelper::getResourceHandleFromId(static_cast<int32_t>(lnbIds[i]), LNB)); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return lnbHandles; | 
|  | } | 
|  |  | 
|  | HidlResult TunerHidlService::getHidlFrontendIds(hidl_vec<HidlFrontendId>& ids) { | 
|  | if (mTuner == nullptr) { | 
|  | return HidlResult::NOT_INITIALIZED; | 
|  | } | 
|  | HidlResult res; | 
|  | mTuner->getFrontendIds([&](HidlResult r, const hidl_vec<HidlFrontendId>& frontendIds) { | 
|  | ids = frontendIds; | 
|  | res = r; | 
|  | }); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | HidlResult TunerHidlService::getHidlFrontendInfo(const int id, HidlFrontendInfo& info) { | 
|  | if (mTuner == nullptr) { | 
|  | return HidlResult::NOT_INITIALIZED; | 
|  | } | 
|  | HidlResult res; | 
|  | mTuner->getFrontendInfo(id, [&](HidlResult r, const HidlFrontendInfo& feInfo) { | 
|  | info = feInfo; | 
|  | res = r; | 
|  | }); | 
|  | return res; | 
|  | } | 
|  |  | 
|  | DemuxCapabilities TunerHidlService::getAidlDemuxCaps(const HidlDemuxCapabilities& caps) { | 
|  | DemuxCapabilities aidlCaps{ | 
|  | .numDemux = static_cast<int32_t>(caps.numDemux), | 
|  | .numRecord = static_cast<int32_t>(caps.numRecord), | 
|  | .numPlayback = static_cast<int32_t>(caps.numPlayback), | 
|  | .numTsFilter = static_cast<int32_t>(caps.numTsFilter), | 
|  | .numSectionFilter = static_cast<int32_t>(caps.numSectionFilter), | 
|  | .numAudioFilter = static_cast<int32_t>(caps.numAudioFilter), | 
|  | .numVideoFilter = static_cast<int32_t>(caps.numVideoFilter), | 
|  | .numPesFilter = static_cast<int32_t>(caps.numPesFilter), | 
|  | .numPcrFilter = static_cast<int32_t>(caps.numPcrFilter), | 
|  | .numBytesInSectionFilter = static_cast<int64_t>(caps.numBytesInSectionFilter), | 
|  | .filterCaps = static_cast<int32_t>(caps.filterCaps), | 
|  | .bTimeFilter = caps.bTimeFilter, | 
|  | }; | 
|  | aidlCaps.linkCaps.resize(caps.linkCaps.size()); | 
|  | copy(caps.linkCaps.begin(), caps.linkCaps.end(), aidlCaps.linkCaps.begin()); | 
|  | return aidlCaps; | 
|  | } | 
|  |  | 
|  | FrontendInfo TunerHidlService::getAidlFrontendInfo( | 
|  | const HidlFrontendInfo& halInfo, const HidlFrontendDtmbCapabilities& halDtmbCaps) { | 
|  | FrontendInfo info{ | 
|  | .type = static_cast<FrontendType>(halInfo.type), | 
|  | .minFrequency = static_cast<int64_t>(halInfo.minFrequency), | 
|  | .maxFrequency = static_cast<int64_t>(halInfo.maxFrequency), | 
|  | .minSymbolRate = static_cast<int32_t>(halInfo.minSymbolRate), | 
|  | .maxSymbolRate = static_cast<int32_t>(halInfo.maxSymbolRate), | 
|  | .acquireRange = static_cast<int64_t>(halInfo.acquireRange), | 
|  | .exclusiveGroupId = static_cast<int32_t>(halInfo.exclusiveGroupId), | 
|  | }; | 
|  | for (int i = 0; i < halInfo.statusCaps.size(); i++) { | 
|  | info.statusCaps.push_back(static_cast<FrontendStatusType>(halInfo.statusCaps[i])); | 
|  | } | 
|  |  | 
|  | FrontendCapabilities caps; | 
|  | switch (halInfo.type) { | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::ANALOG: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendAnalogCapabilities analogCaps{ | 
|  | .typeCap = static_cast<int32_t>(halInfo.frontendCaps.analogCaps().typeCap), | 
|  | .sifStandardCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.analogCaps().sifStandardCap), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::analogCaps>(analogCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::ATSC: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::atscCaps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendAtscCapabilities atscCaps{ | 
|  | .modulationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.atscCaps().modulationCap), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::atscCaps>(atscCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::ATSC3: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::atsc3Caps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendAtsc3Capabilities atsc3Caps{ | 
|  | .bandwidthCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().bandwidthCap), | 
|  | .modulationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().modulationCap), | 
|  | .timeInterleaveModeCap = static_cast<int32_t>( | 
|  | halInfo.frontendCaps.atsc3Caps().timeInterleaveModeCap), | 
|  | .codeRateCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().codeRateCap), | 
|  | .demodOutputFormatCap = static_cast<int8_t>( | 
|  | halInfo.frontendCaps.atsc3Caps().demodOutputFormatCap), | 
|  | .fecCap = static_cast<int32_t>(halInfo.frontendCaps.atsc3Caps().fecCap), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::atsc3Caps>(atsc3Caps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::DVBC: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::dvbcCaps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendDvbcCapabilities dvbcCaps{ | 
|  | .modulationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.dvbcCaps().modulationCap), | 
|  | .fecCap = static_cast<int64_t>(halInfo.frontendCaps.dvbcCaps().fecCap), | 
|  | .annexCap = static_cast<int8_t>(halInfo.frontendCaps.dvbcCaps().annexCap), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::dvbcCaps>(dvbcCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::DVBS: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::dvbsCaps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendDvbsCapabilities dvbsCaps{ | 
|  | .modulationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.dvbsCaps().modulationCap), | 
|  | .innerfecCap = | 
|  | static_cast<int64_t>(halInfo.frontendCaps.dvbsCaps().innerfecCap), | 
|  | .standard = static_cast<int8_t>(halInfo.frontendCaps.dvbsCaps().standard), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::dvbsCaps>(dvbsCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::DVBT: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::dvbtCaps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendDvbtCapabilities dvbtCaps{ | 
|  | .transmissionModeCap = static_cast<int32_t>( | 
|  | halInfo.frontendCaps.dvbtCaps().transmissionModeCap), | 
|  | .bandwidthCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().bandwidthCap), | 
|  | .constellationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().constellationCap), | 
|  | .coderateCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().coderateCap), | 
|  | .hierarchyCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().hierarchyCap), | 
|  | .guardIntervalCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.dvbtCaps().guardIntervalCap), | 
|  | .isT2Supported = halInfo.frontendCaps.dvbtCaps().isT2Supported, | 
|  | .isMisoSupported = halInfo.frontendCaps.dvbtCaps().isMisoSupported, | 
|  | }; | 
|  | caps.set<FrontendCapabilities::dvbtCaps>(dvbtCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::ISDBS: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::isdbsCaps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendIsdbsCapabilities isdbsCaps{ | 
|  | .modulationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbsCaps().modulationCap), | 
|  | .coderateCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbsCaps().coderateCap), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::isdbsCaps>(isdbsCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::ISDBS3: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::isdbs3Caps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendIsdbs3Capabilities isdbs3Caps{ | 
|  | .modulationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbs3Caps().modulationCap), | 
|  | .coderateCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbs3Caps().coderateCap), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::isdbs3Caps>(isdbs3Caps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | case ::android::hardware::tv::tuner::V1_0::FrontendType::ISDBT: { | 
|  | if (HidlFrontendInfo::FrontendCapabilities::hidl_discriminator::isdbtCaps == | 
|  | halInfo.frontendCaps.getDiscriminator()) { | 
|  | FrontendIsdbtCapabilities isdbtCaps{ | 
|  | .modeCap = static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().modeCap), | 
|  | .bandwidthCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().bandwidthCap), | 
|  | .modulationCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().modulationCap), | 
|  | .coderateCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().coderateCap), | 
|  | .guardIntervalCap = | 
|  | static_cast<int32_t>(halInfo.frontendCaps.isdbtCaps().guardIntervalCap), | 
|  | .timeInterleaveCap = | 
|  | static_cast<int32_t>(FrontendIsdbtTimeInterleaveMode::UNDEFINED), | 
|  | .isSegmentAuto = false, | 
|  | .isFullSegment = false, | 
|  | }; | 
|  | caps.set<FrontendCapabilities::isdbtCaps>(isdbtCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | default: { | 
|  | if (static_cast<HidlFrontendType>(info.type) == HidlFrontendType::DTMB) { | 
|  | FrontendDtmbCapabilities dtmbCaps{ | 
|  | .transmissionModeCap = static_cast<int32_t>(halDtmbCaps.transmissionModeCap), | 
|  | .bandwidthCap = static_cast<int32_t>(halDtmbCaps.bandwidthCap), | 
|  | .modulationCap = static_cast<int32_t>(halDtmbCaps.modulationCap), | 
|  | .codeRateCap = static_cast<int32_t>(halDtmbCaps.codeRateCap), | 
|  | .guardIntervalCap = static_cast<int32_t>(halDtmbCaps.guardIntervalCap), | 
|  | .interleaveModeCap = static_cast<int32_t>(halDtmbCaps.interleaveModeCap), | 
|  | }; | 
|  | caps.set<FrontendCapabilities::dtmbCaps>(dtmbCaps); | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | info.frontendCaps = caps; | 
|  | return info; | 
|  | } | 
|  |  | 
|  | }  // namespace tuner | 
|  | }  // namespace tv | 
|  | }  // namespace media | 
|  | }  // namespace android | 
|  | }  // namespace aidl |