/* * Copyright 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 "android.hardware.tv.tuner-service.example-Frontend" #include #include #include "Frontend.h" namespace aidl { namespace android { namespace hardware { namespace tv { namespace tuner { Frontend::Frontend(FrontendType type, int32_t id) { mType = type; mId = id; mTuner = nullptr; // Init callback to nullptr mCallback = nullptr; mIptvPluginInterface = nullptr; mIptvPluginStreamer = nullptr; switch (mType) { case FrontendType::ISDBS: { mFrontendCaps.set(FrontendIsdbsCapabilities()); mFrontendStatusCaps = { FrontendStatusType::DEMOD_LOCK, FrontendStatusType::SNR, FrontendStatusType::FEC, FrontendStatusType::MODULATION, FrontendStatusType::MODULATIONS, FrontendStatusType::ROLL_OFF, FrontendStatusType::STREAM_ID_LIST, }; break; } case FrontendType::ATSC3: { mFrontendCaps.set(FrontendAtsc3Capabilities()); mFrontendStatusCaps = { FrontendStatusType::BER, FrontendStatusType::PER, FrontendStatusType::ATSC3_PLP_INFO, FrontendStatusType::MODULATIONS, FrontendStatusType::BERS, FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH, FrontendStatusType::ATSC3_ALL_PLP_INFO, }; break; } case FrontendType::DVBC: { mFrontendCaps.set(FrontendDvbcCapabilities()); mFrontendStatusCaps = { FrontendStatusType::PRE_BER, FrontendStatusType::SIGNAL_QUALITY, FrontendStatusType::MODULATION, FrontendStatusType::SPECTRAL, FrontendStatusType::MODULATIONS, FrontendStatusType::CODERATES, FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH, }; break; } case FrontendType::DVBS: { mFrontendCaps.set(FrontendDvbsCapabilities()); mFrontendStatusCaps = { FrontendStatusType::SIGNAL_STRENGTH, FrontendStatusType::SYMBOL_RATE, FrontendStatusType::MODULATION, FrontendStatusType::MODULATIONS, FrontendStatusType::ROLL_OFF, FrontendStatusType::IS_MISO, }; break; } case FrontendType::DVBT: { mFrontendCaps.set(FrontendDvbtCapabilities()); mFrontendStatusCaps = { FrontendStatusType::EWBS, FrontendStatusType::PLP_ID, FrontendStatusType::HIERARCHY, FrontendStatusType::MODULATIONS, FrontendStatusType::BANDWIDTH, FrontendStatusType::GUARD_INTERVAL, FrontendStatusType::TRANSMISSION_MODE, FrontendStatusType::T2_SYSTEM_ID, FrontendStatusType::DVBT_CELL_IDS, }; break; } case FrontendType::ISDBT: { FrontendIsdbtCapabilities isdbtCaps{ .modeCap = (int)FrontendIsdbtMode::MODE_1 | (int)FrontendIsdbtMode::MODE_2, .bandwidthCap = (int)FrontendIsdbtBandwidth::BANDWIDTH_6MHZ, .modulationCap = (int)FrontendIsdbtModulation::MOD_16QAM, .coderateCap = (int)FrontendIsdbtCoderate::CODERATE_4_5 | (int)FrontendIsdbtCoderate::CODERATE_6_7, .guardIntervalCap = (int)FrontendIsdbtGuardInterval::INTERVAL_1_128, .timeInterleaveCap = (int)FrontendIsdbtTimeInterleaveMode::AUTO | (int)FrontendIsdbtTimeInterleaveMode::INTERLEAVE_1_0, .isSegmentAuto = true, .isFullSegment = true, }; mFrontendCaps.set(isdbtCaps); mFrontendStatusCaps = { FrontendStatusType::AGC, FrontendStatusType::LNA, FrontendStatusType::MODULATION, FrontendStatusType::MODULATIONS, FrontendStatusType::BANDWIDTH, FrontendStatusType::GUARD_INTERVAL, FrontendStatusType::TRANSMISSION_MODE, FrontendStatusType::ISDBT_SEGMENTS, FrontendStatusType::ISDBT_MODE, FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG, FrontendStatusType::INTERLEAVINGS, }; break; } case FrontendType::ANALOG: { mFrontendCaps.set(FrontendAnalogCapabilities()); mFrontendStatusCaps = { FrontendStatusType::LAYER_ERROR, FrontendStatusType::MER, FrontendStatusType::UEC, FrontendStatusType::TS_DATA_RATES, }; break; } case FrontendType::ATSC: { mFrontendCaps.set(FrontendAtscCapabilities()); mFrontendStatusCaps = { FrontendStatusType::FREQ_OFFSET, FrontendStatusType::RF_LOCK, FrontendStatusType::MODULATIONS, FrontendStatusType::IS_LINEAR, }; break; } case FrontendType::ISDBS3: { mFrontendCaps.set(FrontendIsdbs3Capabilities()); mFrontendStatusCaps = { FrontendStatusType::DEMOD_LOCK, FrontendStatusType::MODULATION, FrontendStatusType::MODULATIONS, FrontendStatusType::ROLL_OFF, FrontendStatusType::IS_SHORT_FRAMES, FrontendStatusType::STREAM_ID_LIST, }; break; } case FrontendType::DTMB: { mFrontendCaps.set(FrontendDtmbCapabilities()); mFrontendStatusCaps = { FrontendStatusType::MODULATIONS, FrontendStatusType::INTERLEAVINGS, FrontendStatusType::BANDWIDTH, FrontendStatusType::GUARD_INTERVAL, FrontendStatusType::TRANSMISSION_MODE, }; break; } case FrontendType::IPTV: { mFrontendCaps.set(FrontendIptvCapabilities()); mFrontendStatusCaps = { FrontendStatusType::IPTV_CONTENT_URL, FrontendStatusType::IPTV_PACKETS_LOST, FrontendStatusType::IPTV_PACKETS_RECEIVED, FrontendStatusType::IPTV_AVERAGE_JITTER_MS, FrontendStatusType::IPTV_WORST_JITTER_MS, }; break; } default: { break; } } } Frontend::~Frontend() { ALOGV("%s", __FUNCTION__); mCallback = nullptr; mIsLocked = false; mTuner = nullptr; if (mTuneByteBuffer != nullptr) { free(mTuneByteBuffer); } } ::ndk::ScopedAStatus Frontend::close() { ALOGV("%s", __FUNCTION__); // Reset callback mCallback = nullptr; mIsLocked = false; if (mTuner != nullptr) { mTuner->removeFrontend(mId); } mTuner = nullptr; return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::setCallback(const std::shared_ptr& in_callback) { ALOGV("%s", __FUNCTION__); if (in_callback == nullptr) { ALOGW("[ WARN ] Set Frontend callback with nullptr"); return ::ndk::ScopedAStatus::fromServiceSpecificError( static_cast(Result::INVALID_ARGUMENT)); } mCallback = in_callback; return ::ndk::ScopedAStatus::ok(); } dtv_plugin* Frontend::createIptvPluginInterface() { const char* path = "/vendor/lib/iptv_udp_plugin.so"; DtvPlugin* plugin = new DtvPlugin(path); bool plugin_loaded = plugin->load(); if (!plugin_loaded) { ALOGE("Failed to load plugin"); return nullptr; } return plugin->interface(); } dtv_streamer* Frontend::createIptvPluginStreamer(dtv_plugin* interface, const char* transport_desc) { dtv_streamer* streamer = interface->create_streamer(); int open_fd = interface->open_stream(streamer, transport_desc); if (open_fd < 0) { return nullptr; } ALOGI("[ INFO ] open_stream successful, open_fd=%d", open_fd); return streamer; } void Frontend::readTuneByte(void* buf) { ssize_t bytes_read = mIptvPluginInterface->read_stream(mIptvPluginStreamer, buf, TUNE_BUFFER_SIZE, TUNE_BUFFER_TIMEOUT); if (bytes_read <= 0) { ALOGI("[ ERROR ] Tune byte couldn't be read."); return; } mCallback->onEvent(FrontendEventType::LOCKED); mIsLocked = true; mTuneByteBuffer = buf; } ::ndk::ScopedAStatus Frontend::tune(const FrontendSettings& in_settings) { if (mCallback == nullptr) { ALOGW("[ WARN ] Frontend callback is not set for tuning"); return ::ndk::ScopedAStatus::fromServiceSpecificError( static_cast(Result::INVALID_STATE)); } if (mType != FrontendType::IPTV) { mTuner->frontendStartTune(mId); mCallback->onEvent(FrontendEventType::LOCKED); mIsLocked = true; } else { // This is a reference implementation for IPTV. It uses an additional socket buffer. // Vendors can use hardware memory directly to make the implementation more performant. ALOGI("[ INFO ] Frontend type is set to IPTV, tag = %d id=%d", in_settings.getTag(), mId); mIptvPluginInterface = createIptvPluginInterface(); if (mIptvPluginInterface == nullptr) { ALOGE("[ INFO ] Failed to load plugin."); return ::ndk::ScopedAStatus::fromServiceSpecificError( static_cast(Result::INVALID_ARGUMENT)); } // validate content_url format std::string content_url = in_settings.get()->contentUrl; mIptvTransportDescription = "{ \"uri\": \"" + content_url + "\"}"; ALOGI("[ INFO ] transport_desc: %s", mIptvTransportDescription.c_str()); bool is_transport_desc_valid = mIptvPluginInterface->validate(mIptvTransportDescription.c_str()); if (!is_transport_desc_valid) { // not of format protocol://ip:port ALOGE("[ INFO ] transport_desc is not valid"); return ::ndk::ScopedAStatus::fromServiceSpecificError( static_cast(Result::INVALID_ARGUMENT)); } // create a streamer and open it for reading data mIptvPluginStreamer = createIptvPluginStreamer(mIptvPluginInterface, mIptvTransportDescription.c_str()); void* buf = malloc(sizeof(char) * TUNE_BUFFER_SIZE); if (buf == nullptr) { ALOGE("Failed to allocate 1 byte buffer for tuning."); return ::ndk::ScopedAStatus::fromServiceSpecificError( static_cast(Result::INVALID_STATE)); } mIptvFrontendTuneThread = std::thread(&Frontend::readTuneByte, this, buf); if (mIptvFrontendTuneThread.joinable()) { mIptvFrontendTuneThread.join(); } } return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::stopTune() { ALOGV("%s", __FUNCTION__); mTuner->frontendStopTune(mId); mIsLocked = false; return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::scan(const FrontendSettings& in_settings, FrontendScanType in_type) { ALOGV("%s", __FUNCTION__); // If it's in middle of scanning, stop it first. if (mScanThread.joinable()) { mScanThread.join(); } mFrontendSettings = in_settings; mFrontendScanType = in_type; mScanThread = std::thread(&Frontend::scanThreadLoop, this); return ::ndk::ScopedAStatus::ok(); } void Frontend::setTunerService(std::shared_ptr tuner) { mTuner = tuner; } void Frontend::scanThreadLoop() { if (mIsLocked) { FrontendScanMessage msg; msg.set(true); mCallback->onScanMessage(FrontendScanMessageType::END, msg); return; } int64_t frequency = 0; switch (mFrontendSettings.getTag()) { case FrontendSettings::Tag::analog: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::atsc: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::atsc3: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::dvbs: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::dvbc: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::dvbt: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::isdbs: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::isdbs3: frequency = mFrontendSettings.get().frequency; break; case FrontendSettings::Tag::isdbt: frequency = mFrontendSettings.get().frequency; break; default: break; } if (mFrontendScanType == FrontendScanType::SCAN_BLIND) { frequency += 100 * 1000; } { FrontendScanMessage msg; vector frequencies = {frequency}; msg.set(frequencies); mCallback->onScanMessage(FrontendScanMessageType::FREQUENCY, msg); } { FrontendScanMessage msg; msg.set(20); mCallback->onScanMessage(FrontendScanMessageType::PROGRESS_PERCENT, msg); } { FrontendScanMessage msg; vector symbolRates = {30}; msg.set(symbolRates); mCallback->onScanMessage(FrontendScanMessageType::SYMBOL_RATE, msg); } if (mType == FrontendType::DVBT) { FrontendScanMessage msg; msg.set(FrontendDvbtHierarchy::HIERARCHY_NON_NATIVE); mCallback->onScanMessage(FrontendScanMessageType::HIERARCHY, msg); } if (mType == FrontendType::ANALOG) { FrontendScanMessage msg; msg.set(FrontendAnalogType::PAL); mCallback->onScanMessage(FrontendScanMessageType::ANALOG_TYPE, msg); } { FrontendScanMessage msg; vector plpIds = {2}; msg.set(plpIds); mCallback->onScanMessage(FrontendScanMessageType::PLP_IDS, msg); } { FrontendScanMessage msg; vector groupIds = {3}; msg.set(groupIds); mCallback->onScanMessage(FrontendScanMessageType::GROUP_IDS, msg); } { FrontendScanMessage msg; vector inputStreamIds = {1}; msg.set(inputStreamIds); mCallback->onScanMessage(FrontendScanMessageType::INPUT_STREAM_IDS, msg); } switch (mType) { case FrontendType::DVBT: { FrontendScanMessage msg; FrontendScanMessageStandard std; std.set(FrontendDvbtStandard::AUTO); msg.set(std); mCallback->onScanMessage(FrontendScanMessageType::STANDARD, msg); break; } case FrontendType::DVBS: { FrontendScanMessage msg; FrontendScanMessageStandard std; std.set(FrontendDvbsStandard::AUTO); msg.set(std); mCallback->onScanMessage(FrontendScanMessageType::STANDARD, msg); break; } case FrontendType::ANALOG: { FrontendScanMessage msg; FrontendScanMessageStandard std; std.set(FrontendAnalogSifStandard::AUTO); msg.set(std); mCallback->onScanMessage(FrontendScanMessageType::STANDARD, msg); break; } default: break; } { FrontendScanMessage msg; FrontendScanAtsc3PlpInfo info; info.plpId = 1; info.bLlsFlag = false; vector atsc3PlpInfos = {info}; msg.set(atsc3PlpInfos); mCallback->onScanMessage(FrontendScanMessageType::ATSC3_PLP_INFO, msg); } { FrontendScanMessage msg; FrontendModulation modulation; modulation.set(FrontendDvbcModulation::MOD_16QAM); msg.set(modulation); mCallback->onScanMessage(FrontendScanMessageType::MODULATION, msg); } { FrontendScanMessage msg; msg.set(true); mCallback->onScanMessage(FrontendScanMessageType::HIGH_PRIORITY, msg); } if (mType == FrontendType::DVBT) { FrontendScanMessage msg; vector dvbtCellIds = {0, 1}; msg.set(dvbtCellIds); mCallback->onScanMessage(FrontendScanMessageType::DVBT_CELL_IDS, msg); } { FrontendScanMessage msg; msg.set(false); mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg); mIsLocked = false; } { FrontendScanMessage msg; msg.set(true); mCallback->onScanMessage(FrontendScanMessageType::LOCKED, msg); mIsLocked = true; } } ::ndk::ScopedAStatus Frontend::stopScan() { ALOGV("%s", __FUNCTION__); if (mScanThread.joinable()) { mScanThread.join(); } mIsLocked = false; return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::getStatus(const std::vector& in_statusTypes, std::vector* _aidl_return) { ALOGV("%s", __FUNCTION__); for (int i = 0; i < in_statusTypes.size(); i++) { FrontendStatusType type = in_statusTypes[i]; FrontendStatus status; // assign randomly selected values for testing. switch (type) { case FrontendStatusType::DEMOD_LOCK: { status.set(true); break; } case FrontendStatusType::SNR: { status.set(221); break; } case FrontendStatusType::BER: { status.set(1); break; } case FrontendStatusType::PER: { status.set(2); break; } case FrontendStatusType::PRE_BER: { status.set(3); break; } case FrontendStatusType::SIGNAL_QUALITY: { status.set(4); break; } case FrontendStatusType::SIGNAL_STRENGTH: { status.set(5); break; } case FrontendStatusType::SYMBOL_RATE: { status.set(6); break; } case FrontendStatusType::FEC: { status.set(FrontendInnerFec::FEC_2_9); // value = 1 << 7 break; } case FrontendStatusType::MODULATION: { switch (mType) { case FrontendType::ISDBS: { FrontendModulationStatus modulationStatus; modulationStatus.set( FrontendIsdbsModulation::MOD_BPSK); // value = 1 << 1 status.set(modulationStatus); break; } case FrontendType::DVBC: { FrontendModulationStatus modulationStatus; modulationStatus.set( FrontendDvbcModulation::MOD_16QAM); // value = 1 << 1 status.set(modulationStatus); break; } case FrontendType::DVBS: { FrontendModulationStatus modulationStatus; modulationStatus.set( FrontendDvbsModulation::MOD_QPSK); // value = 1 << 1 status.set(modulationStatus); break; } case FrontendType::ISDBS3: { FrontendModulationStatus modulationStatus; modulationStatus.set( FrontendIsdbs3Modulation::MOD_BPSK); // value = 1 << 1 status.set(modulationStatus); break; } case FrontendType::ISDBT: { FrontendModulationStatus modulationStatus; modulationStatus.set( FrontendIsdbtModulation::MOD_DQPSK); // value = 1 << 1 status.set(modulationStatus); break; } default: break; } break; } case FrontendStatusType::SPECTRAL: { status.set(FrontendSpectralInversion::NORMAL); break; } case FrontendStatusType::LNB_VOLTAGE: { status.set(LnbVoltage::VOLTAGE_5V); break; } case FrontendStatusType::PLP_ID: { status.set(101); break; } case FrontendStatusType::EWBS: { status.set(false); break; } case FrontendStatusType::AGC: { status.set(7); break; } case FrontendStatusType::LNA: { status.set(false); break; } case FrontendStatusType::LAYER_ERROR: { vector v = {false, true, true}; status.set(v); break; } case FrontendStatusType::MER: { status.set(8); break; } case FrontendStatusType::FREQ_OFFSET: { status.set(9); break; } case FrontendStatusType::HIERARCHY: { status.set(FrontendDvbtHierarchy::HIERARCHY_1_NATIVE); break; } case FrontendStatusType::RF_LOCK: { status.set(false); break; } case FrontendStatusType::ATSC3_PLP_INFO: { FrontendStatusAtsc3PlpInfo info1; info1.plpId = 3; info1.isLocked = false; info1.uec = 313; FrontendStatusAtsc3PlpInfo info2; info2.plpId = 5; info2.isLocked = true; info2.uec = 515; vector infos = {info1, info2}; status.set(infos); break; } case FrontendStatusType::MODULATIONS: { FrontendModulation modulation; vector modulations; switch (mType) { case FrontendType::ISDBS: { modulation.set( FrontendIsdbsModulation::MOD_BPSK); // value = 1 << 1 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::DVBC: { modulation.set( FrontendDvbcModulation::MOD_16QAM); // value = 1 << 1 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::DVBS: { modulation.set( FrontendDvbsModulation::MOD_QPSK); // value = 1 << 1 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::DVBT: { modulation.set( FrontendDvbtConstellation::CONSTELLATION_16QAM_R); // value = 1 << // 16 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::ISDBS3: { modulation.set( FrontendIsdbs3Modulation::MOD_BPSK); // value = 1 << 1 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::ISDBT: { modulation.set( FrontendIsdbtModulation::MOD_DQPSK); // value = 1 << 1 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::ATSC: { modulation.set( FrontendAtscModulation::MOD_8VSB); // value = 1 << 2 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::ATSC3: { modulation.set( FrontendAtsc3Modulation::MOD_QPSK); // value = 1 << 1 modulations.push_back(modulation); status.set(modulations); break; } case FrontendType::DTMB: { modulation.set( FrontendDtmbModulation::CONSTELLATION_4QAM); // value = 1 << 1 modulations.push_back(modulation); status.set(modulations); break; } default: break; } break; } case FrontendStatusType::BERS: { vector bers = {1}; status.set(bers); break; } case FrontendStatusType::CODERATES: { vector rates; rates.push_back(FrontendInnerFec::FEC_6_15); // value = 1 << 39 status.set(rates); break; } case FrontendStatusType::BANDWIDTH: { FrontendBandwidth bandwidth; switch (mType) { case FrontendType::DVBC: { bandwidth.set( FrontendDvbcBandwidth::BANDWIDTH_6MHZ); // value = 1 << 1 status.set(bandwidth); break; } case FrontendType::DVBT: { bandwidth.set( FrontendDvbtBandwidth::BANDWIDTH_8MHZ); // value = 1 << 1 status.set(bandwidth); break; } case FrontendType::ISDBT: { bandwidth.set( FrontendIsdbtBandwidth::BANDWIDTH_8MHZ); // value = 1 << 1 status.set(bandwidth); break; } case FrontendType::ATSC3: { bandwidth.set( FrontendAtsc3Bandwidth::BANDWIDTH_6MHZ); // value = 1 << 1 status.set(bandwidth); break; } case FrontendType::DTMB: { bandwidth.set( FrontendDtmbBandwidth::BANDWIDTH_8MHZ); // value = 1 << 1 status.set(bandwidth); break; } default: break; } break; } case FrontendStatusType::GUARD_INTERVAL: { FrontendGuardInterval interval; switch (mType) { case FrontendType::DVBT: { interval.set( FrontendDvbtGuardInterval::INTERVAL_1_32); // value = 1 << 1 status.set(interval); break; } case FrontendType::ISDBT: { interval.set( FrontendIsdbtGuardInterval::INTERVAL_1_32); // value = 1 << 1 status.set(interval); break; } case FrontendType::DTMB: { interval.set( FrontendDtmbGuardInterval::PN_420_VARIOUS); // value = 1 << 1 status.set(interval); break; } default: break; } break; } case FrontendStatusType::TRANSMISSION_MODE: { FrontendTransmissionMode transMode; switch (mType) { case FrontendType::DVBT: { transMode.set( FrontendDvbtTransmissionMode::MODE_16K_E); // value = 1 << 8 status.set(transMode); break; } case FrontendType::ISDBT: { transMode.set( FrontendIsdbtMode::MODE_1); // value = 1 << 1 status.set(transMode); break; } case FrontendType::DTMB: { transMode.set( FrontendDtmbTransmissionMode::C1); // value = 1 << 1 status.set(transMode); break; } default: break; } break; } case FrontendStatusType::UEC: { status.set(4); break; } case FrontendStatusType::T2_SYSTEM_ID: { status.set(5); break; } case FrontendStatusType::INTERLEAVINGS: { FrontendInterleaveMode interleave; vector interleaves; switch (mType) { case FrontendType::DVBC: { // value = 1 << 1 interleave.set( FrontendCableTimeInterleaveMode::INTERLEAVING_128_1_0); interleaves.push_back(interleave); status.set(interleaves); break; } case FrontendType::ATSC3: { interleave.set( FrontendAtsc3TimeInterleaveMode::CTI); // value = 1 << 1 interleaves.push_back(interleave); status.set(interleaves); break; } case FrontendType::DTMB: { interleave.set( FrontendDtmbTimeInterleaveMode::TIMER_INT_240); // value = 1 << 1 interleaves.push_back(interleave); status.set(interleaves); break; } case FrontendType::ISDBT: { interleave.set( FrontendIsdbtTimeInterleaveMode::INTERLEAVE_1_0); // value = 1 << 1 interleaves.push_back(interleave); status.set(interleaves); break; } default: break; } break; } case FrontendStatusType::ISDBT_SEGMENTS: { vector segments = {2, 3}; status.set(segments); break; } case FrontendStatusType::TS_DATA_RATES: { vector dataRates = {4, 5}; status.set(dataRates); break; } case FrontendStatusType::ROLL_OFF: { FrontendRollOff rollOff; switch (mType) { case FrontendType::DVBS: { rollOff.set( FrontendDvbsRolloff::ROLLOFF_0_35); // value = 1 status.set(rollOff); break; } case FrontendType::ISDBS: { rollOff.set( FrontendIsdbsRolloff::ROLLOFF_0_35); // value = 1 status.set(rollOff); break; } case FrontendType::ISDBS3: { rollOff.set( FrontendIsdbs3Rolloff::ROLLOFF_0_03); // value = 1 status.set(rollOff); break; } default: break; } break; } case FrontendStatusType::IS_MISO: { status.set(true); break; } case FrontendStatusType::IS_LINEAR: { status.set(true); break; } case FrontendStatusType::IS_SHORT_FRAMES: { status.set(true); break; } case FrontendStatusType::ISDBT_MODE: { status.set(FrontendIsdbtMode::AUTO); break; } case FrontendStatusType::ISDBT_PARTIAL_RECEPTION_FLAG: { status.set( FrontendIsdbtPartialReceptionFlag::AUTO); break; } case FrontendStatusType::STREAM_ID_LIST: { vector streamIds = {0, 1}; status.set(streamIds); break; } case FrontendStatusType::DVBT_CELL_IDS: { vector dvbtCellIds = {0, 1}; status.set(dvbtCellIds); break; } case FrontendStatusType::ATSC3_ALL_PLP_INFO: { FrontendScanAtsc3PlpInfo info1; info1.plpId = 1; info1.bLlsFlag = false; FrontendScanAtsc3PlpInfo info2; info2.plpId = 2; info2.bLlsFlag = true; FrontendScanAtsc3PlpInfo info3; info3.plpId = 3; info3.bLlsFlag = false; vector infos = {info1, info2, info3}; status.set(infos); break; } case FrontendStatusType::IPTV_CONTENT_URL: { status.set(""); break; } case FrontendStatusType::IPTV_PACKETS_LOST: { status.set(5); break; } case FrontendStatusType::IPTV_PACKETS_RECEIVED: { status.set(5); break; } case FrontendStatusType::IPTV_WORST_JITTER_MS: { status.set(5); break; } case FrontendStatusType::IPTV_AVERAGE_JITTER_MS: { status.set(5); break; } default: { continue; } } _aidl_return->push_back(status); } return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::setLnb(int32_t /* in_lnbId */) { ALOGV("%s", __FUNCTION__); if (!supportsSatellite()) { return ::ndk::ScopedAStatus::fromServiceSpecificError( static_cast(Result::INVALID_STATE)); } return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::linkCiCam(int32_t in_ciCamId, int32_t* _aidl_return) { ALOGV("%s", __FUNCTION__); mCiCamId = in_ciCamId; *_aidl_return = 0; return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::unlinkCiCam(int32_t /* in_ciCamId */) { ALOGV("%s", __FUNCTION__); mCiCamId = -1; return ::ndk::ScopedAStatus::ok(); } binder_status_t Frontend::dump(int fd, const char** /* args */, uint32_t /* numArgs */) { dprintf(fd, " Frontend %d\n", mId); dprintf(fd, " mType: %d\n", mType); dprintf(fd, " mIsLocked: %d\n", mIsLocked); dprintf(fd, " mCiCamId: %d\n", mCiCamId); dprintf(fd, " mFrontendStatusCaps:"); for (int i = 0; i < mFrontendStatusCaps.size(); i++) { dprintf(fd, " %d\n", mFrontendStatusCaps[i]); } return STATUS_OK; } ::ndk::ScopedAStatus Frontend::getHardwareInfo(std::string* _aidl_return) { ALOGV("%s", __FUNCTION__); *_aidl_return = "Sample Frontend"; return ::ndk::ScopedAStatus::ok(); } ::ndk::ScopedAStatus Frontend::removeOutputPid(int32_t /* in_pid */) { ALOGV("%s", __FUNCTION__); return ::ndk::ScopedAStatus::fromServiceSpecificError( static_cast(Result::UNAVAILABLE)); } ::ndk::ScopedAStatus Frontend::getFrontendStatusReadiness( const std::vector& in_statusTypes, std::vector* _aidl_return) { ALOGV("%s", __FUNCTION__); _aidl_return->resize(in_statusTypes.size()); for (int i = 0; i < in_statusTypes.size(); i++) { int j = 0; while (j < mFrontendStatusCaps.size()) { if (in_statusTypes[i] == mFrontendStatusCaps[j]) { (*_aidl_return)[i] = FrontendStatusReadiness::STABLE; break; } j++; } if (j >= mFrontendStatusCaps.size()) { (*_aidl_return)[i] = FrontendStatusReadiness::UNSUPPORTED; } } return ::ndk::ScopedAStatus::ok(); } FrontendType Frontend::getFrontendType() { return mType; } int32_t Frontend::getFrontendId() { return mId; } dtv_plugin* Frontend::getIptvPluginInterface() { return mIptvPluginInterface; } string Frontend::getIptvTransportDescription() { return mIptvTransportDescription; } dtv_streamer* Frontend::getIptvPluginStreamer() { return mIptvPluginStreamer; } bool Frontend::supportsSatellite() { return mType == FrontendType::DVBS || mType == FrontendType::ISDBS || mType == FrontendType::ISDBS3; } bool Frontend::isLocked() { return mIsLocked; } void Frontend::getFrontendInfo(FrontendInfo* _aidl_return) { // assign randomly selected values for testing. *_aidl_return = { .type = mType, .minFrequency = 139000000, .maxFrequency = 1139000000, .minSymbolRate = 45, .maxSymbolRate = 1145, .acquireRange = 30, .exclusiveGroupId = 57, .statusCaps = mFrontendStatusCaps, .frontendCaps = mFrontendCaps, }; } } // namespace tuner } // namespace tv } // namespace hardware } // namespace android } // namespace aidl