1 /*
2 * Copyright 2021 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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "android.hardware.tv.tuner-service.example-Tuner"
19
20 #include <aidl/android/hardware/tv/tuner/DemuxFilterMainType.h>
21 #include <aidl/android/hardware/tv/tuner/Result.h>
22 #include <utils/Log.h>
23
24 #include "Demux.h"
25 #include "Descrambler.h"
26 #include "Frontend.h"
27 #include "Lnb.h"
28 #include "Tuner.h"
29
30 namespace aidl {
31 namespace android {
32 namespace hardware {
33 namespace tv {
34 namespace tuner {
35
Tuner()36 Tuner::Tuner() {}
37
init()38 void Tuner::init() {
39 // Static Frontends array to maintain local frontends information
40 // Array index matches their FrontendId in the default impl
41 mFrontendSize = 11;
42 mFrontends[0] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS, 0);
43 mFrontends[1] = ndk::SharedRefBase::make<Frontend>(FrontendType::ATSC3, 1);
44 mFrontends[2] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBC, 2);
45 mFrontends[3] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBS, 3);
46 mFrontends[4] = ndk::SharedRefBase::make<Frontend>(FrontendType::DVBT, 4);
47 mFrontends[5] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBT, 5);
48 mFrontends[6] = ndk::SharedRefBase::make<Frontend>(FrontendType::ANALOG, 6);
49 mFrontends[7] = ndk::SharedRefBase::make<Frontend>(FrontendType::ATSC, 7);
50 mFrontends[8] = ndk::SharedRefBase::make<Frontend>(FrontendType::ISDBS3, 8);
51 mFrontends[9] = ndk::SharedRefBase::make<Frontend>(FrontendType::DTMB, 9);
52 mFrontends[10] = ndk::SharedRefBase::make<Frontend>(FrontendType::IPTV, 10);
53
54 mMaxUsableFrontends[FrontendType::ISDBS] = 1;
55 mMaxUsableFrontends[FrontendType::ATSC3] = 1;
56 mMaxUsableFrontends[FrontendType::DVBC] = 1;
57 mMaxUsableFrontends[FrontendType::DVBS] = 1;
58 mMaxUsableFrontends[FrontendType::DVBT] = 1;
59 mMaxUsableFrontends[FrontendType::ISDBT] = 1;
60 mMaxUsableFrontends[FrontendType::ANALOG] = 1;
61 mMaxUsableFrontends[FrontendType::ATSC] = 1;
62 mMaxUsableFrontends[FrontendType::ISDBS3] = 1;
63 mMaxUsableFrontends[FrontendType::DTMB] = 1;
64 mMaxUsableFrontends[FrontendType::IPTV] = 1;
65
66 mDemuxes[0] =
67 ndk::SharedRefBase::make<Demux>(0, (static_cast<int32_t>(DemuxFilterMainType::TS) |
68 static_cast<int32_t>(DemuxFilterMainType::MMTP) |
69 static_cast<int32_t>(DemuxFilterMainType::TLV)));
70 mDemuxes[1] =
71 ndk::SharedRefBase::make<Demux>(1, (static_cast<int32_t>(DemuxFilterMainType::MMTP) |
72 static_cast<int32_t>(DemuxFilterMainType::TLV)));
73 mDemuxes[2] = ndk::SharedRefBase::make<Demux>(2, static_cast<int32_t>(DemuxFilterMainType::IP));
74 mDemuxes[3] = ndk::SharedRefBase::make<Demux>(3, static_cast<int32_t>(DemuxFilterMainType::TS));
75
76 mLnbs.resize(2);
77 mLnbs[0] = ndk::SharedRefBase::make<Lnb>(0);
78 mLnbs[1] = ndk::SharedRefBase::make<Lnb>(1);
79 }
80
~Tuner()81 Tuner::~Tuner() {}
82
getFrontendIds(std::vector<int32_t> * _aidl_return)83 ::ndk::ScopedAStatus Tuner::getFrontendIds(std::vector<int32_t>* _aidl_return) {
84 ALOGV("%s", __FUNCTION__);
85
86 _aidl_return->resize(mFrontendSize);
87 for (int i = 0; i < mFrontendSize; i++) {
88 (*_aidl_return)[i] = mFrontends[i]->getFrontendId();
89 }
90
91 return ::ndk::ScopedAStatus::ok();
92 }
93
getDemuxInfo(int32_t in_demuxId,DemuxInfo * _aidl_return)94 ::ndk::ScopedAStatus Tuner::getDemuxInfo(int32_t in_demuxId, DemuxInfo* _aidl_return) {
95 if (mDemuxes.find(in_demuxId) == mDemuxes.end()) {
96 return ::ndk::ScopedAStatus::fromServiceSpecificError(
97 static_cast<int32_t>(Result::INVALID_ARGUMENT));
98 } else {
99 mDemuxes[in_demuxId]->getDemuxInfo(_aidl_return);
100 return ::ndk::ScopedAStatus::ok();
101 }
102 }
103
getDemuxIds(std::vector<int32_t> * _aidl_return)104 ::ndk::ScopedAStatus Tuner::getDemuxIds(std::vector<int32_t>* _aidl_return) {
105 ALOGV("%s", __FUNCTION__);
106
107 int numOfDemuxes = mDemuxes.size();
108 _aidl_return->resize(numOfDemuxes);
109 int i = 0;
110 for (auto e = mDemuxes.begin(); e != mDemuxes.end(); e++) {
111 (*_aidl_return)[i++] = e->first;
112 }
113 return ::ndk::ScopedAStatus::ok();
114 }
115
openFrontendById(int32_t in_frontendId,std::shared_ptr<IFrontend> * _aidl_return)116 ::ndk::ScopedAStatus Tuner::openFrontendById(int32_t in_frontendId,
117 std::shared_ptr<IFrontend>* _aidl_return) {
118 ALOGV("%s", __FUNCTION__);
119
120 if (in_frontendId >= mFrontendSize || in_frontendId < 0) {
121 ALOGW("[ WARN ] Frontend with id %d isn't available", in_frontendId);
122 *_aidl_return = nullptr;
123 return ::ndk::ScopedAStatus::fromServiceSpecificError(
124 static_cast<int32_t>(Result::INVALID_ARGUMENT));
125 }
126
127 mFrontends[in_frontendId]->setTunerService(this->ref<Tuner>());
128 *_aidl_return = mFrontends[in_frontendId];
129 return ::ndk::ScopedAStatus::ok();
130 }
131
openDemuxById(int32_t in_demuxId,std::shared_ptr<IDemux> * _aidl_return)132 ::ndk::ScopedAStatus Tuner::openDemuxById(int32_t in_demuxId,
133 std::shared_ptr<IDemux>* _aidl_return) {
134 ALOGV("%s", __FUNCTION__);
135
136 if (mDemuxes.find(in_demuxId) == mDemuxes.end()) {
137 ALOGW("[ WARN ] Demux with id %d isn't available", in_demuxId);
138 *_aidl_return = nullptr;
139 return ::ndk::ScopedAStatus::fromServiceSpecificError(
140 static_cast<int32_t>(Result::INVALID_ARGUMENT));
141 }
142
143 if (mDemuxes[in_demuxId]->isInUse()) {
144 return ::ndk::ScopedAStatus::fromServiceSpecificError(
145 static_cast<int32_t>(Result::UNAVAILABLE));
146 } else {
147 mDemuxes[in_demuxId]->setTunerService(this->ref<Tuner>());
148 mDemuxes[in_demuxId]->setInUse(true);
149
150 *_aidl_return = mDemuxes[in_demuxId];
151 return ::ndk::ScopedAStatus::ok();
152 }
153 }
154
openDemux(std::vector<int32_t> * out_demuxId,std::shared_ptr<IDemux> * _aidl_return)155 ::ndk::ScopedAStatus Tuner::openDemux(std::vector<int32_t>* out_demuxId,
156 std::shared_ptr<IDemux>* _aidl_return) {
157 ALOGV("%s", __FUNCTION__);
158
159 bool found = false;
160 int32_t demuxId = 0;
161 for (auto e = mDemuxes.begin(); e != mDemuxes.end(); e++) {
162 if (!e->second->isInUse()) {
163 found = true;
164 demuxId = e->second->getDemuxId();
165 }
166 }
167
168 if (found) {
169 out_demuxId->push_back(demuxId);
170 return openDemuxById(demuxId, _aidl_return);
171 } else {
172 return ::ndk::ScopedAStatus::fromServiceSpecificError(
173 static_cast<int32_t>(Result::UNAVAILABLE));
174 }
175 }
176
getDemuxCaps(DemuxCapabilities * _aidl_return)177 ::ndk::ScopedAStatus Tuner::getDemuxCaps(DemuxCapabilities* _aidl_return) {
178 ALOGV("%s", __FUNCTION__);
179
180 // IP filter can be an MMTP filter's data source.
181 _aidl_return->linkCaps = {0x00, 0x00, 0x02, 0x00, 0x00};
182 // Support time filter testing
183 _aidl_return->bTimeFilter = true;
184
185 // set filterCaps as the bitwize OR of all the demux' caps
186 std::vector<int32_t> demuxIds;
187 getDemuxIds(&demuxIds);
188 int32_t filterCaps = 0;
189
190 for (int i = 0; i < demuxIds.size(); i++) {
191 DemuxInfo demuxInfo;
192 getDemuxInfo(demuxIds[i], &demuxInfo);
193 filterCaps |= demuxInfo.filterTypes;
194 }
195 _aidl_return->filterCaps = filterCaps;
196
197 return ::ndk::ScopedAStatus::ok();
198 }
199
openDescrambler(std::shared_ptr<IDescrambler> * _aidl_return)200 ::ndk::ScopedAStatus Tuner::openDescrambler(std::shared_ptr<IDescrambler>* _aidl_return) {
201 ALOGV("%s", __FUNCTION__);
202
203 *_aidl_return = ndk::SharedRefBase::make<Descrambler>();
204
205 return ndk::ScopedAStatus::ok();
206 }
207
getFrontendInfo(int32_t in_frontendId,FrontendInfo * _aidl_return)208 ::ndk::ScopedAStatus Tuner::getFrontendInfo(int32_t in_frontendId, FrontendInfo* _aidl_return) {
209 ALOGV("%s", __FUNCTION__);
210
211 if (in_frontendId < 0 || in_frontendId >= mFrontendSize) {
212 return ::ndk::ScopedAStatus::fromServiceSpecificError(
213 static_cast<int32_t>(Result::INVALID_ARGUMENT));
214 }
215
216 mFrontends[in_frontendId]->getFrontendInfo(_aidl_return);
217 return ::ndk::ScopedAStatus::ok();
218 }
219
getLnbIds(std::vector<int32_t> * _aidl_return)220 ::ndk::ScopedAStatus Tuner::getLnbIds(std::vector<int32_t>* _aidl_return) {
221 ALOGV("%s", __FUNCTION__);
222
223 _aidl_return->resize(mLnbs.size());
224 for (int i = 0; i < mLnbs.size(); i++) {
225 (*_aidl_return)[i] = mLnbs[i]->getId();
226 }
227
228 return ::ndk::ScopedAStatus::ok();
229 }
230
openLnbById(int32_t in_lnbId,std::shared_ptr<ILnb> * _aidl_return)231 ::ndk::ScopedAStatus Tuner::openLnbById(int32_t in_lnbId, std::shared_ptr<ILnb>* _aidl_return) {
232 ALOGV("%s", __FUNCTION__);
233
234 if (in_lnbId >= mLnbs.size()) {
235 *_aidl_return = nullptr;
236 return ::ndk::ScopedAStatus::fromServiceSpecificError(
237 static_cast<int32_t>(Result::INVALID_ARGUMENT));
238 }
239
240 *_aidl_return = mLnbs[in_lnbId];
241 return ::ndk::ScopedAStatus::ok();
242 }
243
getFrontendById(int32_t frontendId)244 std::shared_ptr<Frontend> Tuner::getFrontendById(int32_t frontendId) {
245 ALOGV("%s", __FUNCTION__);
246
247 return mFrontends[frontendId];
248 }
249
openLnbByName(const std::string &,std::vector<int32_t> * out_lnbId,std::shared_ptr<ILnb> * _aidl_return)250 ::ndk::ScopedAStatus Tuner::openLnbByName(const std::string& /* in_lnbName */,
251 std::vector<int32_t>* out_lnbId,
252 std::shared_ptr<ILnb>* _aidl_return) {
253 ALOGV("%s", __FUNCTION__);
254
255 out_lnbId->push_back(1234);
256 *_aidl_return = ndk::SharedRefBase::make<Lnb>();
257
258 return ::ndk::ScopedAStatus::ok();
259 }
260
setLna(bool)261 ::ndk::ScopedAStatus Tuner::setLna(bool /* in_bEnable */) {
262 ALOGV("%s", __FUNCTION__);
263
264 return ::ndk::ScopedAStatus::ok();
265 }
266
setMaxNumberOfFrontends(FrontendType in_frontendType,int32_t in_maxNumber)267 ::ndk::ScopedAStatus Tuner::setMaxNumberOfFrontends(FrontendType in_frontendType,
268 int32_t in_maxNumber) {
269 ALOGV("%s", __FUNCTION__);
270
271 // In the default implementation, every type only has one frontend.
272 if (in_maxNumber < 0 || in_maxNumber > 1) {
273 return ::ndk::ScopedAStatus::fromServiceSpecificError(
274 static_cast<int32_t>(Result::INVALID_ARGUMENT));
275 }
276 mMaxUsableFrontends[in_frontendType] = in_maxNumber;
277 return ::ndk::ScopedAStatus::ok();
278 }
279
getMaxNumberOfFrontends(FrontendType in_frontendType,int32_t * _aidl_return)280 ::ndk::ScopedAStatus Tuner::getMaxNumberOfFrontends(FrontendType in_frontendType,
281 int32_t* _aidl_return) {
282 *_aidl_return = mMaxUsableFrontends[in_frontendType];
283 return ::ndk::ScopedAStatus::ok();
284 }
285
isLnaSupported(bool * _aidl_return)286 ::ndk::ScopedAStatus Tuner::isLnaSupported(bool* _aidl_return) {
287 ALOGV("%s", __FUNCTION__);
288
289 *_aidl_return = true;
290 return ::ndk::ScopedAStatus::ok();
291 }
292
dump(int fd,const char ** args,uint32_t numArgs)293 binder_status_t Tuner::dump(int fd, const char** args, uint32_t numArgs) {
294 ALOGV("%s", __FUNCTION__);
295 {
296 dprintf(fd, "Frontends:\n");
297 for (int i = 0; i < mFrontendSize; i++) {
298 mFrontends[i]->dump(fd, args, numArgs);
299 }
300 }
301 {
302 dprintf(fd, "Demuxs:\n");
303 map<int32_t, std::shared_ptr<Demux>>::iterator it;
304 for (it = mDemuxes.begin(); it != mDemuxes.end(); it++) {
305 it->second->dump(fd, args, numArgs);
306 }
307 }
308 {
309 dprintf(fd, "Lnbs:\n");
310 for (int i = 0; i < mLnbs.size(); i++) {
311 mLnbs[i]->dump(fd, args, numArgs);
312 }
313 }
314 return STATUS_OK;
315 }
316
setFrontendAsDemuxSource(int32_t frontendId,int32_t demuxId)317 void Tuner::setFrontendAsDemuxSource(int32_t frontendId, int32_t demuxId) {
318 mFrontendToDemux[frontendId] = demuxId;
319 if (mFrontends[frontendId] != nullptr && mFrontends[frontendId]->isLocked()) {
320 mDemuxes[demuxId]->startFrontendInputLoop();
321 }
322 }
323
removeDemux(int32_t demuxId)324 void Tuner::removeDemux(int32_t demuxId) {
325 map<int32_t, int32_t>::iterator it;
326 for (it = mFrontendToDemux.begin(); it != mFrontendToDemux.end(); it++) {
327 if (it->second == demuxId) {
328 it = mFrontendToDemux.erase(it);
329 break;
330 }
331 }
332 mDemuxes[demuxId]->setInUse(false);
333 }
334
removeFrontend(int32_t frontendId)335 void Tuner::removeFrontend(int32_t frontendId) {
336 map<int32_t, int32_t>::iterator it = mFrontendToDemux.find(frontendId);
337 if (it != mFrontendToDemux.end()) {
338 mDemuxes[it->second]->setInUse(false);
339 }
340 mFrontendToDemux.erase(frontendId);
341 }
342
frontendStopTune(int32_t frontendId)343 void Tuner::frontendStopTune(int32_t frontendId) {
344 map<int32_t, int32_t>::iterator it = mFrontendToDemux.find(frontendId);
345 int32_t demuxId;
346 if (it != mFrontendToDemux.end()) {
347 demuxId = it->second;
348 mDemuxes[demuxId]->stopFrontendInput();
349 }
350 }
351
frontendStartTune(int32_t frontendId)352 void Tuner::frontendStartTune(int32_t frontendId) {
353 map<int32_t, int32_t>::iterator it = mFrontendToDemux.find(frontendId);
354 int32_t demuxId;
355 if (it != mFrontendToDemux.end()) {
356 demuxId = it->second;
357 mDemuxes[demuxId]->startFrontendInputLoop();
358 }
359 }
360
361 } // namespace tuner
362 } // namespace tv
363 } // namespace hardware
364 } // namespace android
365 } // namespace aidl
366