blob: 56cb34cc80b5c3a918d69eae2194d64afcf798d3 [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
255 *_aidl_return = ::ndk::SharedRefBase::make<TunerFrontend>(mTuner, frontendHandle);
256 return Status::ok();
Amy Zhang70de35a2020-10-12 20:13:16 -0700257}
258
259TunerServiceFrontendInfo TunerService::convertToAidlFrontendInfo(int feId, FrontendInfo halInfo) {
260 TunerServiceFrontendInfo info{
261 .id = feId,
262 .type = (int)halInfo.type,
263 .minFrequency = (int)halInfo.minFrequency,
264 .maxFrequency = (int)halInfo.maxFrequency,
265 .minSymbolRate = (int)halInfo.minSymbolRate,
266 .maxSymbolRate = (int)halInfo.maxSymbolRate,
267 .acquireRange = (int)halInfo.acquireRange,
268 .exclusiveGroupId = (int)halInfo.exclusiveGroupId,
269 };
270 for (int i = 0; i < halInfo.statusCaps.size(); i++) {
271 info.statusCaps.push_back((int)halInfo.statusCaps[i]);
272 }
273
274 TunerFrontendCapabilities caps;
275 switch (halInfo.type) {
276 case FrontendType::ANALOG: {
277 TunerFrontendAnalogCapabilities analogCaps{
278 .typeCap = (int)halInfo.frontendCaps.analogCaps().typeCap,
279 .sifStandardCap = (int)halInfo.frontendCaps.analogCaps().sifStandardCap,
280 };
281 caps.set<TunerFrontendCapabilities::analogCaps>(analogCaps);
282 break;
283 }
284 case FrontendType::ATSC: {
285 TunerFrontendAtscCapabilities atscCaps{
286 .modulationCap = (int)halInfo.frontendCaps.atscCaps().modulationCap,
287 };
288 caps.set<TunerFrontendCapabilities::atscCaps>(atscCaps);
289 break;
290 }
291 case FrontendType::ATSC3: {
292 TunerFrontendAtsc3Capabilities atsc3Caps{
293 .bandwidthCap = (int)halInfo.frontendCaps.atsc3Caps().bandwidthCap,
294 .modulationCap = (int)halInfo.frontendCaps.atsc3Caps().modulationCap,
295 .timeInterleaveModeCap =
296 (int)halInfo.frontendCaps.atsc3Caps().timeInterleaveModeCap,
297 .codeRateCap = (int)halInfo.frontendCaps.atsc3Caps().codeRateCap,
298 .demodOutputFormatCap = (int)halInfo.frontendCaps.atsc3Caps().demodOutputFormatCap,
299 .fecCap = (int)halInfo.frontendCaps.atsc3Caps().fecCap,
300 };
301 caps.set<TunerFrontendCapabilities::atsc3Caps>(atsc3Caps);
302 break;
303 }
304 case FrontendType::DVBC: {
305 TunerFrontendCableCapabilities cableCaps{
306 .modulationCap = (int)halInfo.frontendCaps.dvbcCaps().modulationCap,
307 .codeRateCap = (int)halInfo.frontendCaps.dvbcCaps().fecCap,
308 .annexCap = (int)halInfo.frontendCaps.dvbcCaps().annexCap,
309 };
310 caps.set<TunerFrontendCapabilities::cableCaps>(cableCaps);
311 break;
312 }
313 case FrontendType::DVBS: {
314 TunerFrontendDvbsCapabilities dvbsCaps{
315 .modulationCap = (int)halInfo.frontendCaps.dvbsCaps().modulationCap,
316 .codeRateCap = (long)halInfo.frontendCaps.dvbsCaps().innerfecCap,
317 .standard = (int)halInfo.frontendCaps.dvbsCaps().standard,
318 };
319 caps.set<TunerFrontendCapabilities::dvbsCaps>(dvbsCaps);
320 break;
321 }
322 case FrontendType::DVBT: {
323 TunerFrontendDvbtCapabilities dvbtCaps{
324 .transmissionModeCap = (int)halInfo.frontendCaps.dvbtCaps().transmissionModeCap,
325 .bandwidthCap = (int)halInfo.frontendCaps.dvbtCaps().bandwidthCap,
326 .constellationCap = (int)halInfo.frontendCaps.dvbtCaps().constellationCap,
327 .codeRateCap = (int)halInfo.frontendCaps.dvbtCaps().coderateCap,
328 .hierarchyCap = (int)halInfo.frontendCaps.dvbtCaps().hierarchyCap,
329 .guardIntervalCap = (int)halInfo.frontendCaps.dvbtCaps().guardIntervalCap,
330 .isT2Supported = (bool)halInfo.frontendCaps.dvbtCaps().isT2Supported,
331 .isMisoSupported = (bool)halInfo.frontendCaps.dvbtCaps().isMisoSupported,
332 };
333 caps.set<TunerFrontendCapabilities::dvbtCaps>(dvbtCaps);
334 break;
335 }
336 case FrontendType::ISDBS: {
337 TunerFrontendIsdbsCapabilities isdbsCaps{
338 .modulationCap = (int)halInfo.frontendCaps.isdbsCaps().modulationCap,
339 .codeRateCap = (int)halInfo.frontendCaps.isdbsCaps().coderateCap,
340 };
341 caps.set<TunerFrontendCapabilities::isdbsCaps>(isdbsCaps);
342 break;
343 }
344 case FrontendType::ISDBS3: {
345 TunerFrontendIsdbs3Capabilities isdbs3Caps{
346 .modulationCap = (int)halInfo.frontendCaps.isdbs3Caps().modulationCap,
347 .codeRateCap = (int)halInfo.frontendCaps.isdbs3Caps().coderateCap,
348 };
349 caps.set<TunerFrontendCapabilities::isdbs3Caps>(isdbs3Caps);
350 break;
351 }
352 case FrontendType::ISDBT: {
353 TunerFrontendIsdbtCapabilities isdbtCaps{
354 .modeCap = (int)halInfo.frontendCaps.isdbtCaps().modeCap,
355 .bandwidthCap = (int)halInfo.frontendCaps.isdbtCaps().bandwidthCap,
356 .modulationCap = (int)halInfo.frontendCaps.isdbtCaps().modulationCap,
357 .codeRateCap = (int)halInfo.frontendCaps.isdbtCaps().coderateCap,
358 .guardIntervalCap = (int)halInfo.frontendCaps.isdbtCaps().guardIntervalCap,
359 };
360 caps.set<TunerFrontendCapabilities::isdbtCaps>(isdbtCaps);
361 break;
362 }
363 default:
364 break;
365 }
366
367 info.caps = caps;
368 return info;
369}
shubang6d266262020-10-09 00:15:04 -0700370
371Status TunerService::getFmqSyncReadWrite(
372 MQDescriptor<int8_t, SynchronizedReadWrite>* mqDesc, bool* _aidl_return) {
373 ALOGD("getFmqSyncReadWrite");
374 // TODO: put the following methods AIDL, and should be called from clients.
375 openDemux();
376 openFilter();
377 configFilter();
378 mFilter->start();
379 if (mqDesc == nullptr) {
380 ALOGD("getFmqSyncReadWrite null MQDescriptor.");
381 *_aidl_return = false;
382 } else {
383 ALOGD("getFmqSyncReadWrite true");
384 *_aidl_return = true;
385 *mqDesc = std::move(mAidlMQDesc);
386 }
387 return ndk::ScopedAStatus::ok();
388}
389
shubang23aa3ac2020-09-07 18:56:28 -0700390} // namespace android