blob: 99fc1723640d28618c6fdbd5ff2f50cb72825a60 [file] [log] [blame]
shubang23aa3ac2020-09-07 18:56:28 -07001/**
2 * Copyright (c) 2020, 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_TAG "TunerService"
18
19#include <android/binder_manager.h>
20#include <utils/Log.h>
Amy Zhang0f04c452020-10-30 13:36:44 -070021#include "TunerFrontend.h"
shubang23aa3ac2020-09-07 18:56:28 -070022#include "TunerService.h"
23
Amy Zhang70de35a2020-10-12 20:13:16 -070024using ::aidl::android::media::tv::tuner::TunerFrontendAnalogCapabilities;
25using ::aidl::android::media::tv::tuner::TunerFrontendAtsc3Capabilities;
26using ::aidl::android::media::tv::tuner::TunerFrontendAtscCapabilities;
27using ::aidl::android::media::tv::tuner::TunerFrontendCableCapabilities;
28using ::aidl::android::media::tv::tuner::TunerFrontendCapabilities;
29using ::aidl::android::media::tv::tuner::TunerFrontendDvbsCapabilities;
30using ::aidl::android::media::tv::tuner::TunerFrontendDvbtCapabilities;
31using ::aidl::android::media::tv::tuner::TunerFrontendIsdbs3Capabilities;
32using ::aidl::android::media::tv::tuner::TunerFrontendIsdbsCapabilities;
33using ::aidl::android::media::tv::tuner::TunerFrontendIsdbtCapabilities;
shubang23aa3ac2020-09-07 18:56:28 -070034using ::android::hardware::hidl_vec;
shubang6d266262020-10-09 00:15:04 -070035using ::android::hardware::tv::tuner::V1_0::DemuxFilterAvSettings;
36using ::android::hardware::tv::tuner::V1_0::DemuxFilterMainType;
37using ::android::hardware::tv::tuner::V1_0::DemuxFilterSettings;
38using ::android::hardware::tv::tuner::V1_0::DemuxFilterType;
39using ::android::hardware::tv::tuner::V1_0::DemuxTsFilterType;
shubang23aa3ac2020-09-07 18:56:28 -070040using ::android::hardware::tv::tuner::V1_0::FrontendId;
Amy Zhang70de35a2020-10-12 20:13:16 -070041using ::android::hardware::tv::tuner::V1_0::FrontendType;
shubang23aa3ac2020-09-07 18:56:28 -070042using ::android::hardware::tv::tuner::V1_0::Result;
43
44namespace android {
45
shubang23aa3ac2020-09-07 18:56:28 -070046TunerService::TunerService() {}
47TunerService::~TunerService() {}
48
49void TunerService::instantiate() {
50 std::shared_ptr<TunerService> service =
51 ::ndk::SharedRefBase::make<TunerService>();
52 AServiceManager_addService(service->asBinder().get(), getServiceName());
shubang6d266262020-10-09 00:15:04 -070053}
54
55template <typename HidlPayload, typename AidlPayload, typename AidlFlavor>
56bool TunerService::unsafeHidlToAidlMQDescriptor(
57 const hardware::MQDescriptor<HidlPayload, FlavorTypeToValue<AidlFlavor>::value>& hidlDesc,
58 MQDescriptor<AidlPayload, AidlFlavor>* aidlDesc) {
59 // TODO: use the builtin coversion method when it's merged.
60 ALOGD("unsafeHidlToAidlMQDescriptor");
61 static_assert(sizeof(HidlPayload) == sizeof(AidlPayload), "Payload types are incompatible");
62 static_assert(
63 has_typedef_fixed_size<AidlPayload>::value == true ||
64 std::is_fundamental<AidlPayload>::value ||
65 std::is_enum<AidlPayload>::value,
66 "Only fundamental types, enums, and AIDL parcelables annotated with @FixedSize "
67 "and built for the NDK backend are supported as AIDL payload types.");
68 aidlDesc->fileDescriptor = ndk::ScopedFileDescriptor(dup(hidlDesc.handle()->data[0]));
69 for (const auto& grantor : hidlDesc.grantors()) {
70 if (static_cast<int32_t>(grantor.offset) < 0 || static_cast<int64_t>(grantor.extent) < 0) {
71 ALOGD("Unsafe static_cast of grantor fields. offset=%d, extend=%ld",
72 static_cast<int32_t>(grantor.offset), static_cast<long>(grantor.extent));
73 logError(
74 "Unsafe static_cast of grantor fields. Either the hardware::MQDescriptor is "
75 "invalid, or the MessageQueue is too large to be described by AIDL.");
76 return false;
77 }
78 aidlDesc->grantors.push_back(
79 GrantorDescriptor {
80 .offset = static_cast<int32_t>(grantor.offset),
81 .extent = static_cast<int64_t>(grantor.extent)
82 });
83 }
84 if (static_cast<int32_t>(hidlDesc.getQuantum()) < 0 ||
85 static_cast<int32_t>(hidlDesc.getFlags()) < 0) {
86 ALOGD("Unsafe static_cast of quantum or flags. Quantum=%d, flags=%d",
87 static_cast<int32_t>(hidlDesc.getQuantum()),
88 static_cast<int32_t>(hidlDesc.getFlags()));
89 logError(
90 "Unsafe static_cast of quantum or flags. Either the hardware::MQDescriptor is "
91 "invalid, or the MessageQueue is too large to be described by AIDL.");
92 return false;
93 }
94 aidlDesc->quantum = static_cast<int32_t>(hidlDesc.getQuantum());
95 aidlDesc->flags = static_cast<int32_t>(hidlDesc.getFlags());
96 return true;
97}
98
99bool TunerService::getITuner() {
100 ALOGD("getITuner");
101 if (mTuner != nullptr) {
102 return true;
103 }
Amy Zhang0f04c452020-10-30 13:36:44 -0700104 mTuner = ITuner::getService();
105 if (mTuner == nullptr) {
shubang6d266262020-10-09 00:15:04 -0700106 ALOGE("Failed to get ITuner service");
107 return false;
Amy Zhang0f04c452020-10-30 13:36:44 -0700108 }
shubang6d266262020-10-09 00:15:04 -0700109 return true;
110}
111
112Result TunerService::openDemux() {
113 ALOGD("openDemux");
114 if (!getITuner()) {
115 return Result::NOT_INITIALIZED;
116 }
117 if (mDemux != nullptr) {
118 return Result::SUCCESS;
119 }
120 Result res;
121 uint32_t id;
122 sp<IDemux> demuxSp;
123 mTuner->openDemux([&](Result r, uint32_t demuxId, const sp<IDemux>& demux) {
124 demuxSp = demux;
125 id = demuxId;
126 res = r;
127 ALOGD("open demux, id = %d", demuxId);
128 });
129 if (res == Result::SUCCESS) {
130 mDemux = demuxSp;
131 } else {
132 ALOGD("open demux failed, res = %d", res);
133 }
134 return res;
135}
136
137Result TunerService::openFilter() {
138 ALOGD("openFilter");
139 if (!getITuner()) {
140 return Result::NOT_INITIALIZED;
141 }
142 DemuxFilterMainType mainType = DemuxFilterMainType::TS;
143 DemuxFilterType filterType {
144 .mainType = mainType,
145 };
146 filterType.subType.tsFilterType(DemuxTsFilterType::VIDEO);
147
148 sp<FilterCallback> callback = new FilterCallback();
149 Result res;
150 mDemux->openFilter(filterType, 16000000, callback,
151 [&](Result r, const sp<IFilter>& filter) {
152 mFilter = filter;
153 res = r;
154 });
155 if (res != Result::SUCCESS || mFilter == NULL) {
156 ALOGD("Failed to open filter, type = %d", filterType.mainType);
157 return res;
158 }
159
160 return Result::SUCCESS;
161}
162
163Result TunerService::configFilter() {
164 ALOGD("configFilter");
165 if (mFilter == NULL) {
166 ALOGD("Failed to configure filter: filter not found");
167 return Result::NOT_INITIALIZED;
168 }
169 DemuxFilterSettings filterSettings;
170 DemuxTsFilterSettings tsFilterSettings {
171 .tpid = 256,
172 };
173 DemuxFilterAvSettings filterAvSettings {
174 .isPassthrough = false,
175 };
176 tsFilterSettings.filterSettings.av(filterAvSettings);
177 filterSettings.ts(tsFilterSettings);
178 Result res = mFilter->configure(filterSettings);
179
180 if (res != Result::SUCCESS) {
181 ALOGD("config filter failed, res = %d", res);
182 return res;
183 }
184
185 Result getQueueDescResult = Result::UNKNOWN_ERROR;
186 mFilter->getQueueDesc(
187 [&](Result r, const MQDescriptorSync<uint8_t>& desc) {
188 mFilterMQDesc = desc;
189 getQueueDescResult = r;
190 ALOGD("getFilterQueueDesc");
191 });
192 if (getQueueDescResult == Result::SUCCESS) {
193 unsafeHidlToAidlMQDescriptor<uint8_t, int8_t, SynchronizedReadWrite>(
194 mFilterMQDesc, &mAidlMQDesc);
195 mAidlMq = new (std::nothrow) AidlMessageQueue(mAidlMQDesc);
196 EventFlag::createEventFlag(mAidlMq->getEventFlagWord(), &mEventFlag);
197 } else {
198 ALOGD("get MQDesc failed, res = %d", getQueueDescResult);
199 }
200 return getQueueDescResult;
shubang23aa3ac2020-09-07 18:56:28 -0700201}
202
203Status TunerService::getFrontendIds(std::vector<int32_t>* ids, int32_t* /* _aidl_return */) {
shubang6d266262020-10-09 00:15:04 -0700204 if (!getITuner()) {
Amy Zhang0f04c452020-10-30 13:36:44 -0700205 return ::ndk::ScopedAStatus::fromServiceSpecificError(
shubang6d266262020-10-09 00:15:04 -0700206 static_cast<int32_t>(Result::NOT_INITIALIZED));
shubang23aa3ac2020-09-07 18:56:28 -0700207 }
208 hidl_vec<FrontendId> feIds;
209 Result res;
210 mTuner->getFrontendIds([&](Result r, const hidl_vec<FrontendId>& frontendIds) {
211 feIds = frontendIds;
212 res = r;
213 });
214 if (res != Result::SUCCESS) {
215 return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
216 }
217 ids->resize(feIds.size());
218 std::copy(feIds.begin(), feIds.end(), ids->begin());
219
Amy Zhang0f04c452020-10-30 13:36:44 -0700220 return Status::ok();
shubang23aa3ac2020-09-07 18:56:28 -0700221}
222
Amy Zhang70de35a2020-10-12 20:13:16 -0700223Status TunerService::getFrontendInfo(
224 int32_t frontendHandle, TunerServiceFrontendInfo* _aidl_return) {
225 if (mTuner == nullptr) {
Amy Zhang0f04c452020-10-30 13:36:44 -0700226 ALOGE("ITuner service is not init.");
227 return ::ndk::ScopedAStatus::fromServiceSpecificError(
228 static_cast<int32_t>(Result::UNAVAILABLE));
Amy Zhang70de35a2020-10-12 20:13:16 -0700229 }
230
231 Result res;
232 FrontendInfo info;
233 int feId = getResourceIdFromHandle(frontendHandle);
234 mTuner->getFrontendInfo(feId, [&](Result r, const FrontendInfo& feInfo) {
235 info = feInfo;
236 res = r;
237 });
238 if (res != Result::SUCCESS) {
Amy Zhang0f04c452020-10-30 13:36:44 -0700239 return Status::fromServiceSpecificError(static_cast<int32_t>(res));
Amy Zhang70de35a2020-10-12 20:13:16 -0700240 }
241
242 TunerServiceFrontendInfo tunerInfo = convertToAidlFrontendInfo(feId, info);
243 *_aidl_return = tunerInfo;
Amy Zhang0f04c452020-10-30 13:36:44 -0700244 return Status::ok();
245}
246
247Status TunerService::openFrontend(
248 int32_t frontendHandle, std::shared_ptr<ITunerFrontend>* _aidl_return) {
249 if (mTuner == nullptr) {
250 ALOGE("ITuner service is not init.");
251 return ::ndk::ScopedAStatus::fromServiceSpecificError(
252 static_cast<int32_t>(Result::UNAVAILABLE));
253 }
254
Amy Zhangd61491e2021-01-12 16:27:29 -0800255 int id = getResourceIdFromHandle(frontendHandle);
256 *_aidl_return = ::ndk::SharedRefBase::make<TunerFrontend>(mTuner, id);
Amy Zhang0f04c452020-10-30 13:36:44 -0700257 return Status::ok();
Amy Zhang70de35a2020-10-12 20:13:16 -0700258}
259
260TunerServiceFrontendInfo TunerService::convertToAidlFrontendInfo(int feId, FrontendInfo halInfo) {
261 TunerServiceFrontendInfo info{
262 .id = feId,
263 .type = (int)halInfo.type,
264 .minFrequency = (int)halInfo.minFrequency,
265 .maxFrequency = (int)halInfo.maxFrequency,
266 .minSymbolRate = (int)halInfo.minSymbolRate,
267 .maxSymbolRate = (int)halInfo.maxSymbolRate,
268 .acquireRange = (int)halInfo.acquireRange,
269 .exclusiveGroupId = (int)halInfo.exclusiveGroupId,
270 };
271 for (int i = 0; i < halInfo.statusCaps.size(); i++) {
272 info.statusCaps.push_back((int)halInfo.statusCaps[i]);
273 }
274
275 TunerFrontendCapabilities caps;
276 switch (halInfo.type) {
277 case FrontendType::ANALOG: {
278 TunerFrontendAnalogCapabilities analogCaps{
279 .typeCap = (int)halInfo.frontendCaps.analogCaps().typeCap,
280 .sifStandardCap = (int)halInfo.frontendCaps.analogCaps().sifStandardCap,
281 };
282 caps.set<TunerFrontendCapabilities::analogCaps>(analogCaps);
283 break;
284 }
285 case FrontendType::ATSC: {
286 TunerFrontendAtscCapabilities atscCaps{
287 .modulationCap = (int)halInfo.frontendCaps.atscCaps().modulationCap,
288 };
289 caps.set<TunerFrontendCapabilities::atscCaps>(atscCaps);
290 break;
291 }
292 case FrontendType::ATSC3: {
293 TunerFrontendAtsc3Capabilities atsc3Caps{
294 .bandwidthCap = (int)halInfo.frontendCaps.atsc3Caps().bandwidthCap,
295 .modulationCap = (int)halInfo.frontendCaps.atsc3Caps().modulationCap,
296 .timeInterleaveModeCap =
297 (int)halInfo.frontendCaps.atsc3Caps().timeInterleaveModeCap,
298 .codeRateCap = (int)halInfo.frontendCaps.atsc3Caps().codeRateCap,
299 .demodOutputFormatCap = (int)halInfo.frontendCaps.atsc3Caps().demodOutputFormatCap,
300 .fecCap = (int)halInfo.frontendCaps.atsc3Caps().fecCap,
301 };
302 caps.set<TunerFrontendCapabilities::atsc3Caps>(atsc3Caps);
303 break;
304 }
305 case FrontendType::DVBC: {
306 TunerFrontendCableCapabilities cableCaps{
307 .modulationCap = (int)halInfo.frontendCaps.dvbcCaps().modulationCap,
308 .codeRateCap = (int)halInfo.frontendCaps.dvbcCaps().fecCap,
309 .annexCap = (int)halInfo.frontendCaps.dvbcCaps().annexCap,
310 };
311 caps.set<TunerFrontendCapabilities::cableCaps>(cableCaps);
312 break;
313 }
314 case FrontendType::DVBS: {
315 TunerFrontendDvbsCapabilities dvbsCaps{
316 .modulationCap = (int)halInfo.frontendCaps.dvbsCaps().modulationCap,
317 .codeRateCap = (long)halInfo.frontendCaps.dvbsCaps().innerfecCap,
318 .standard = (int)halInfo.frontendCaps.dvbsCaps().standard,
319 };
320 caps.set<TunerFrontendCapabilities::dvbsCaps>(dvbsCaps);
321 break;
322 }
323 case FrontendType::DVBT: {
324 TunerFrontendDvbtCapabilities dvbtCaps{
325 .transmissionModeCap = (int)halInfo.frontendCaps.dvbtCaps().transmissionModeCap,
326 .bandwidthCap = (int)halInfo.frontendCaps.dvbtCaps().bandwidthCap,
327 .constellationCap = (int)halInfo.frontendCaps.dvbtCaps().constellationCap,
328 .codeRateCap = (int)halInfo.frontendCaps.dvbtCaps().coderateCap,
329 .hierarchyCap = (int)halInfo.frontendCaps.dvbtCaps().hierarchyCap,
330 .guardIntervalCap = (int)halInfo.frontendCaps.dvbtCaps().guardIntervalCap,
331 .isT2Supported = (bool)halInfo.frontendCaps.dvbtCaps().isT2Supported,
332 .isMisoSupported = (bool)halInfo.frontendCaps.dvbtCaps().isMisoSupported,
333 };
334 caps.set<TunerFrontendCapabilities::dvbtCaps>(dvbtCaps);
335 break;
336 }
337 case FrontendType::ISDBS: {
338 TunerFrontendIsdbsCapabilities isdbsCaps{
339 .modulationCap = (int)halInfo.frontendCaps.isdbsCaps().modulationCap,
340 .codeRateCap = (int)halInfo.frontendCaps.isdbsCaps().coderateCap,
341 };
342 caps.set<TunerFrontendCapabilities::isdbsCaps>(isdbsCaps);
343 break;
344 }
345 case FrontendType::ISDBS3: {
346 TunerFrontendIsdbs3Capabilities isdbs3Caps{
347 .modulationCap = (int)halInfo.frontendCaps.isdbs3Caps().modulationCap,
348 .codeRateCap = (int)halInfo.frontendCaps.isdbs3Caps().coderateCap,
349 };
350 caps.set<TunerFrontendCapabilities::isdbs3Caps>(isdbs3Caps);
351 break;
352 }
353 case FrontendType::ISDBT: {
354 TunerFrontendIsdbtCapabilities isdbtCaps{
355 .modeCap = (int)halInfo.frontendCaps.isdbtCaps().modeCap,
356 .bandwidthCap = (int)halInfo.frontendCaps.isdbtCaps().bandwidthCap,
357 .modulationCap = (int)halInfo.frontendCaps.isdbtCaps().modulationCap,
358 .codeRateCap = (int)halInfo.frontendCaps.isdbtCaps().coderateCap,
359 .guardIntervalCap = (int)halInfo.frontendCaps.isdbtCaps().guardIntervalCap,
360 };
361 caps.set<TunerFrontendCapabilities::isdbtCaps>(isdbtCaps);
362 break;
363 }
364 default:
365 break;
366 }
367
368 info.caps = caps;
369 return info;
370}
shubang6d266262020-10-09 00:15:04 -0700371
372Status TunerService::getFmqSyncReadWrite(
373 MQDescriptor<int8_t, SynchronizedReadWrite>* mqDesc, bool* _aidl_return) {
374 ALOGD("getFmqSyncReadWrite");
375 // TODO: put the following methods AIDL, and should be called from clients.
376 openDemux();
377 openFilter();
378 configFilter();
379 mFilter->start();
380 if (mqDesc == nullptr) {
381 ALOGD("getFmqSyncReadWrite null MQDescriptor.");
382 *_aidl_return = false;
383 } else {
384 ALOGD("getFmqSyncReadWrite true");
385 *_aidl_return = true;
386 *mqDesc = std::move(mAidlMQDesc);
387 }
388 return ndk::ScopedAStatus::ok();
389}
390
shubang23aa3ac2020-09-07 18:56:28 -0700391} // namespace android