/* * Copyright 2020 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_TAG "TunerClient" #include #include #include #include "TunerClient.h" using ::aidl::android::media::tv::tuner::TunerFrontendCapabilities; using ::aidl::android::media::tv::tuner::TunerFrontendDtmbCapabilities; using ::android::hardware::tv::tuner::V1_0::FrontendId; using ::android::hardware::tv::tuner::V1_0::FrontendStatusType; using ::android::hardware::tv::tuner::V1_0::FrontendType; namespace android { sp TunerClient::mTuner; sp<::android::hardware::tv::tuner::V1_1::ITuner> TunerClient::mTuner_1_1; shared_ptr TunerClient::mTunerService; int TunerClient::mTunerVersion; /////////////// TunerClient /////////////////////// TunerClient::TunerClient() { // Get HIDL Tuner in migration stage. getHidlTuner(); if (mTuner != NULL) { updateTunerResources(); } // Connect with Tuner Service. ::ndk::SpAIBinder binder(AServiceManager_getService("media.tuner")); mTunerService = ITunerService::fromBinder(binder); if (mTunerService == NULL) { ALOGE("Failed to get tuner service"); } else { mTunerService->getTunerHalVersion(&mTunerVersion); } } TunerClient::~TunerClient() { mTuner = NULL; mTuner_1_1 = NULL; mTunerVersion = 0; mTunerService = NULL; } vector TunerClient::getFrontendIds() { vector ids; if (mTunerService != NULL) { vector v; Status s = mTunerService->getFrontendIds(&v); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS || v.size() == 0) { ids.clear(); return ids; } for (int32_t id : v) { ids.push_back(static_cast(id)); } return ids; } if (mTuner != NULL) { Result res; mTuner->getFrontendIds([&](Result r, const hardware::hidl_vec& frontendIds) { res = r; ids = frontendIds; }); if (res != Result::SUCCESS || ids.size() == 0) { ALOGW("Frontend ids not available"); ids.clear(); return ids; } return ids; } return ids; } sp TunerClient::openFrontend(int frontendHandle) { if (mTunerService != NULL) { shared_ptr tunerFrontend; Status s = mTunerService->openFrontend(frontendHandle, &tunerFrontend); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS || tunerFrontend == NULL) { return NULL; } int id; s = tunerFrontend->getFrontendId(&id); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } TunerFrontendInfo aidlFrontendInfo; s = mTunerService->getFrontendInfo(id, &aidlFrontendInfo); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } return new FrontendClient(tunerFrontend, aidlFrontendInfo.type); } if (mTuner != NULL) { int id = getResourceIdFromHandle(frontendHandle, FRONTEND); sp hidlFrontend = openHidlFrontendById(id); if (hidlFrontend != NULL) { FrontendInfo hidlInfo; Result res = getHidlFrontendInfo(id, hidlInfo); if (res != Result::SUCCESS) { return NULL; } sp frontendClient = new FrontendClient( NULL, (int)hidlInfo.type); frontendClient->setHidlFrontend(hidlFrontend); frontendClient->setId(id); return frontendClient; } } return NULL; } shared_ptr TunerClient::getFrontendInfo(int id) { if (mTunerService != NULL) { TunerFrontendInfo aidlFrontendInfo; Status s = mTunerService->getFrontendInfo(id, &aidlFrontendInfo); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } return make_shared(frontendInfoAidlToHidl(aidlFrontendInfo)); } if (mTuner != NULL) { FrontendInfo hidlInfo; Result res = getHidlFrontendInfo(id, hidlInfo); if (res != Result::SUCCESS) { return NULL; } return make_shared(hidlInfo); } return NULL; } shared_ptr TunerClient::getFrontendDtmbCapabilities(int id) { if (mTunerService != NULL) { TunerFrontendDtmbCapabilities dtmbCaps; Status s = mTunerService->getFrontendDtmbCapabilities(id, &dtmbCaps); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } FrontendDtmbCapabilities hidlCaps{ .transmissionModeCap = static_cast(dtmbCaps.transmissionModeCap), .bandwidthCap = static_cast(dtmbCaps.bandwidthCap), .modulationCap = static_cast(dtmbCaps.modulationCap), .codeRateCap = static_cast(dtmbCaps.codeRateCap), .guardIntervalCap = static_cast(dtmbCaps.guardIntervalCap), .interleaveModeCap = static_cast(dtmbCaps.interleaveModeCap), }; return make_shared(hidlCaps); } if (mTuner_1_1 != NULL) { Result result; FrontendDtmbCapabilities dtmbCaps; mTuner_1_1->getFrontendDtmbCapabilities(id, [&](Result r, const FrontendDtmbCapabilities& caps) { dtmbCaps = caps; result = r; }); if (result == Result::SUCCESS) { return make_shared(dtmbCaps); } } return NULL; } sp TunerClient::openDemux(int demuxHandle) { if (mTunerService != NULL) { shared_ptr tunerDemux; Status s = mTunerService->openDemux(demuxHandle, &tunerDemux); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } return new DemuxClient(tunerDemux); } if (mTuner != NULL) { sp demuxClient = new DemuxClient(NULL); int demuxId; sp hidlDemux = openHidlDemux(demuxId); if (hidlDemux != NULL) { demuxClient->setHidlDemux(hidlDemux); demuxClient->setId(demuxId); return demuxClient; } } return NULL; } shared_ptr TunerClient::getDemuxCaps() { if (mTunerService != NULL) { TunerDemuxCapabilities aidlCaps; Status s = mTunerService->getDemuxCaps(&aidlCaps); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } return make_shared(getHidlDemuxCaps(aidlCaps)); } if (mTuner != NULL) { Result res; DemuxCapabilities caps; mTuner->getDemuxCaps([&](Result r, const DemuxCapabilities& demuxCaps) { caps = demuxCaps; res = r; }); if (res == Result::SUCCESS) { return make_shared(caps); } } return NULL; } sp TunerClient::openDescrambler(int descramblerHandle) { if (mTunerService != NULL) { shared_ptr tunerDescrambler; Status s = mTunerService->openDescrambler(descramblerHandle, &tunerDescrambler); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } return new DescramblerClient(tunerDescrambler); } if (mTuner != NULL) { sp descramblerClient = new DescramblerClient(NULL); sp hidlDescrambler = openHidlDescrambler(); if (hidlDescrambler != NULL) { descramblerClient->setHidlDescrambler(hidlDescrambler); return descramblerClient; } } return NULL; } sp TunerClient::openLnb(int lnbHandle) { if (mTunerService != NULL) { shared_ptr tunerLnb; Status s = mTunerService->openLnb(lnbHandle, &tunerLnb); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } return new LnbClient(tunerLnb); } if (mTuner != NULL) { int id = getResourceIdFromHandle(lnbHandle, LNB); sp lnbClient = new LnbClient(NULL); sp hidlLnb = openHidlLnbById(id); if (hidlLnb != NULL) { lnbClient->setHidlLnb(hidlLnb); lnbClient->setId(id); return lnbClient; } } return NULL; } sp TunerClient::openLnbByName(string lnbName) { if (mTunerService != NULL) { shared_ptr tunerLnb; Status s = mTunerService->openLnbByName(lnbName, &tunerLnb); if (ClientHelper::getServiceSpecificErrorCode(s) != Result::SUCCESS) { return NULL; } return new LnbClient(tunerLnb); } if (mTuner != NULL) { sp lnbClient = new LnbClient(NULL); LnbId id; sp hidlLnb = openHidlLnbByName(lnbName, id); if (hidlLnb != NULL) { lnbClient->setHidlLnb(hidlLnb); lnbClient->setId(id); return lnbClient; } } return NULL; } /////////////// TunerClient Helper Methods /////////////////////// void TunerClient::updateTunerResources() { if (mTuner == NULL) { return; } // Connect with Tuner Resource Manager. ::ndk::SpAIBinder binder(AServiceManager_getService("tv_tuner_resource_mgr")); mTunerResourceManager = ITunerResourceManager::fromBinder(binder); updateFrontendResources(); updateLnbResources(); // TODO: update Demux, Descrambler. } // TODO: remove after migration to Tuner Service is done. void TunerClient::updateFrontendResources() { vector ids = getFrontendIds(); if (ids.size() == 0) { return; } vector infos; for (int i = 0; i < ids.size(); i++) { shared_ptr frontendInfo = getFrontendInfo((int)ids[i]); if (frontendInfo == NULL) { continue; } TunerFrontendInfo tunerFrontendInfo{ .handle = getResourceHandleFromId((int)ids[i], FRONTEND), .type = static_cast(frontendInfo->type), .exclusiveGroupId = static_cast(frontendInfo->exclusiveGroupId), }; infos.push_back(tunerFrontendInfo); } mTunerResourceManager->setFrontendInfoList(infos); } void TunerClient::updateLnbResources() { vector handles = getLnbHandles(); if (handles.size() == 0) { return; } mTunerResourceManager->setLnbInfoList(handles); } sp TunerClient::getHidlTuner() { if (mTuner == NULL) { mTunerVersion = TUNER_HAL_VERSION_UNKNOWN; mTuner_1_1 = ::android::hardware::tv::tuner::V1_1::ITuner::getService(); if (mTuner_1_1 == NULL) { ALOGW("Failed to get tuner 1.1 service."); mTuner = ITuner::getService(); if (mTuner == NULL) { ALOGW("Failed to get tuner 1.0 service."); } else { mTunerVersion = TUNER_HAL_VERSION_1_0; } } else { mTuner = static_cast>(mTuner_1_1); mTunerVersion = TUNER_HAL_VERSION_1_1; } } return mTuner; } sp TunerClient::openHidlFrontendById(int id) { sp fe; Result res; mTuner->openFrontendById(id, [&](Result r, const sp& frontend) { fe = frontend; res = r; }); if (res != Result::SUCCESS || fe == nullptr) { ALOGE("Failed to open frontend"); return NULL; } return fe; } Result TunerClient::getHidlFrontendInfo(int id, FrontendInfo& feInfo) { Result res; mTuner->getFrontendInfo(id, [&](Result r, const FrontendInfo& info) { feInfo = info; res = r; }); return res; } sp TunerClient::openHidlDemux(int& demuxId) { sp demux; Result res; mTuner->openDemux([&](Result result, uint32_t id, const sp& demuxSp) { demux = demuxSp; demuxId = id; res = result; }); if (res != Result::SUCCESS || demux == nullptr) { ALOGE("Failed to open demux"); return NULL; } return demux; } sp TunerClient::openHidlLnbById(int id) { sp lnb; Result res; mTuner->openLnbById(id, [&](Result r, const sp& lnbSp) { res = r; lnb = lnbSp; }); if (res != Result::SUCCESS || lnb == nullptr) { ALOGE("Failed to open lnb by id"); return NULL; } return lnb; } sp TunerClient::openHidlLnbByName(string name, LnbId& lnbId) { sp lnb; Result res; mTuner->openLnbByName(name, [&](Result r, LnbId id, const sp& lnbSp) { res = r; lnb = lnbSp; lnbId = id; }); if (res != Result::SUCCESS || lnb == nullptr) { ALOGE("Failed to open lnb by name"); return NULL; } return lnb; } // TODO: remove after migration to Tuner Service is done. vector TunerClient::getLnbHandles() { vector lnbHandles; if (mTuner != NULL) { Result res; vector lnbIds; mTuner->getLnbIds([&](Result r, const hardware::hidl_vec& ids) { lnbIds = ids; res = r; }); if (res != Result::SUCCESS || lnbIds.size() == 0) { ALOGW("Lnb isn't available"); } else { for (int i = 0; i < lnbIds.size(); i++) { lnbHandles.push_back(getResourceHandleFromId((int)lnbIds[i], LNB)); } } } return lnbHandles; } sp TunerClient::openHidlDescrambler() { sp descrambler; Result res; mTuner->openDescrambler([&](Result r, const sp& descramblerSp) { res = r; descrambler = descramblerSp; }); if (res != Result::SUCCESS || descrambler == NULL) { return NULL; } return descrambler; } DemuxCapabilities TunerClient::getHidlDemuxCaps(TunerDemuxCapabilities& aidlCaps) { DemuxCapabilities caps{ .numDemux = (uint32_t)aidlCaps.numDemux, .numRecord = (uint32_t)aidlCaps.numRecord, .numPlayback = (uint32_t)aidlCaps.numPlayback, .numTsFilter = (uint32_t)aidlCaps.numTsFilter, .numSectionFilter = (uint32_t)aidlCaps.numSectionFilter, .numAudioFilter = (uint32_t)aidlCaps.numAudioFilter, .numVideoFilter = (uint32_t)aidlCaps.numVideoFilter, .numPesFilter = (uint32_t)aidlCaps.numPesFilter, .numPcrFilter = (uint32_t)aidlCaps.numPcrFilter, .numBytesInSectionFilter = (uint32_t)aidlCaps.numBytesInSectionFilter, .filterCaps = (uint32_t)aidlCaps.filterCaps, .bTimeFilter = aidlCaps.bTimeFilter, }; caps.linkCaps.resize(aidlCaps.linkCaps.size()); copy(aidlCaps.linkCaps.begin(), aidlCaps.linkCaps.end(), caps.linkCaps.begin()); return caps; } FrontendInfo TunerClient::frontendInfoAidlToHidl(TunerFrontendInfo aidlFrontendInfo) { FrontendInfo hidlFrontendInfo { .type = static_cast(aidlFrontendInfo.type), .minFrequency = static_cast(aidlFrontendInfo.minFrequency), .maxFrequency = static_cast(aidlFrontendInfo.maxFrequency), .minSymbolRate = static_cast(aidlFrontendInfo.minSymbolRate), .maxSymbolRate = static_cast(aidlFrontendInfo.maxSymbolRate), .acquireRange = static_cast(aidlFrontendInfo.acquireRange), .exclusiveGroupId = static_cast(aidlFrontendInfo.exclusiveGroupId), }; int size = aidlFrontendInfo.statusCaps.size(); hidlFrontendInfo.statusCaps.resize(size); for (int i = 0; i < size; i++) { hidlFrontendInfo.statusCaps[i] = static_cast(aidlFrontendInfo.statusCaps[i]); } switch (aidlFrontendInfo.caps.getTag()) { case TunerFrontendCapabilities::analogCaps: { auto analog = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.analogCaps({ .typeCap = static_cast(analog.typeCap), .sifStandardCap = static_cast(analog.sifStandardCap), }); break; } case TunerFrontendCapabilities::atscCaps: { auto atsc = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.atscCaps({ .modulationCap = static_cast(atsc.modulationCap), }); break; } case TunerFrontendCapabilities::atsc3Caps: { auto atsc3 = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.atsc3Caps({ .bandwidthCap = static_cast(atsc3.bandwidthCap), .modulationCap = static_cast(atsc3.modulationCap), .timeInterleaveModeCap = static_cast(atsc3.timeInterleaveModeCap), .codeRateCap = static_cast(atsc3.codeRateCap), .fecCap = static_cast(atsc3.fecCap), .demodOutputFormatCap = static_cast(atsc3.demodOutputFormatCap), }); break; } case TunerFrontendCapabilities::cableCaps: { auto cable = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.dvbcCaps({ .modulationCap = static_cast(cable.modulationCap), .fecCap = static_cast(cable.codeRateCap), .annexCap = static_cast(cable.annexCap), }); break; } case TunerFrontendCapabilities::dvbsCaps: { auto dvbs = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.dvbsCaps({ .modulationCap = static_cast(dvbs.modulationCap), .innerfecCap = static_cast(dvbs.codeRateCap), .standard = static_cast(dvbs.standard), }); break; } case TunerFrontendCapabilities::dvbtCaps: { auto dvbt = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.dvbtCaps({ .transmissionModeCap = static_cast(dvbt.transmissionModeCap), .bandwidthCap = static_cast(dvbt.bandwidthCap), .constellationCap = static_cast(dvbt.constellationCap), .coderateCap = static_cast(dvbt.codeRateCap), .hierarchyCap = static_cast(dvbt.hierarchyCap), .guardIntervalCap = static_cast(dvbt.guardIntervalCap), .isT2Supported = dvbt.isT2Supported, .isMisoSupported = dvbt.isMisoSupported, }); break; } case TunerFrontendCapabilities::isdbsCaps: { auto isdbs = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.isdbsCaps({ .modulationCap = static_cast(isdbs.modulationCap), .coderateCap = static_cast(isdbs.codeRateCap), }); break; } case TunerFrontendCapabilities::isdbs3Caps: { auto isdbs3 = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.isdbs3Caps({ .modulationCap = static_cast(isdbs3.modulationCap), .coderateCap = static_cast(isdbs3.codeRateCap), }); break; } case TunerFrontendCapabilities::isdbtCaps: { auto isdbt = aidlFrontendInfo.caps.get(); hidlFrontendInfo.frontendCaps.isdbtCaps({ .modeCap = static_cast(isdbt.modeCap), .bandwidthCap = static_cast(isdbt.bandwidthCap), .modulationCap = static_cast(isdbt.modulationCap), .coderateCap = static_cast(isdbt.codeRateCap), .guardIntervalCap = static_cast(isdbt.guardIntervalCap), }); break; } } return hidlFrontendInfo; } // TODO: remove after migration to Tuner Service is done. int TunerClient::getResourceIdFromHandle(int handle, int /*resourceType*/) { return (handle & 0x00ff0000) >> 16; } // TODO: remove after migration to Tuner Service is done. int TunerClient::getResourceHandleFromId(int id, int resourceType) { return (resourceType & 0x000000ff) << 24 | (id << 16) | (mResourceRequestCount++ & 0xffff); } } // namespace android