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-Demux"
19
20 #include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
21 #include <aidl/android/hardware/tv/tuner/Result.h>
22
23 #include <utils/Log.h>
24 #include "Demux.h"
25
26 namespace aidl {
27 namespace android {
28 namespace hardware {
29 namespace tv {
30 namespace tuner {
31
32 #define WAIT_TIMEOUT 3000000000
33
Demux(int32_t demuxId,uint32_t filterTypes)34 Demux::Demux(int32_t demuxId, uint32_t filterTypes) {
35 mDemuxId = demuxId;
36 mFilterTypes = filterTypes;
37 }
38
setTunerService(std::shared_ptr<Tuner> tuner)39 void Demux::setTunerService(std::shared_ptr<Tuner> tuner) {
40 mTuner = tuner;
41 }
42
~Demux()43 Demux::~Demux() {
44 ALOGV("%s", __FUNCTION__);
45 close();
46 }
47
setFrontendDataSource(int32_t in_frontendId)48 ::ndk::ScopedAStatus Demux::setFrontendDataSource(int32_t in_frontendId) {
49 ALOGV("%s", __FUNCTION__);
50
51 if (mTuner == nullptr) {
52 return ::ndk::ScopedAStatus::fromServiceSpecificError(
53 static_cast<int32_t>(Result::NOT_INITIALIZED));
54 }
55
56 mFrontend = mTuner->getFrontendById(in_frontendId);
57 if (mFrontend == nullptr) {
58 return ::ndk::ScopedAStatus::fromServiceSpecificError(
59 static_cast<int32_t>(Result::INVALID_STATE));
60 }
61
62 mTuner->setFrontendAsDemuxSource(in_frontendId, mDemuxId);
63
64 return ::ndk::ScopedAStatus::ok();
65 }
66
openFilter(const DemuxFilterType & in_type,int32_t in_bufferSize,const std::shared_ptr<IFilterCallback> & in_cb,std::shared_ptr<IFilter> * _aidl_return)67 ::ndk::ScopedAStatus Demux::openFilter(const DemuxFilterType& in_type, int32_t in_bufferSize,
68 const std::shared_ptr<IFilterCallback>& in_cb,
69 std::shared_ptr<IFilter>* _aidl_return) {
70 ALOGV("%s", __FUNCTION__);
71
72 int64_t filterId;
73 filterId = ++mLastUsedFilterId;
74
75 if (in_cb == nullptr) {
76 ALOGW("[Demux] callback can't be null");
77 *_aidl_return = nullptr;
78 return ::ndk::ScopedAStatus::fromServiceSpecificError(
79 static_cast<int32_t>(Result::INVALID_ARGUMENT));
80 }
81
82 std::shared_ptr<Filter> filter = ndk::SharedRefBase::make<Filter>(
83 in_type, filterId, in_bufferSize, in_cb, this->ref<Demux>());
84 if (!filter->createFilterMQ()) {
85 *_aidl_return = nullptr;
86 return ::ndk::ScopedAStatus::fromServiceSpecificError(
87 static_cast<int32_t>(Result::UNKNOWN_ERROR));
88 }
89
90 mFilters[filterId] = filter;
91 if (filter->isPcrFilter()) {
92 mPcrFilterIds.insert(filterId);
93 }
94 bool result = true;
95 if (!filter->isRecordFilter()) {
96 // Only save non-record filters for now. Record filters are saved when the
97 // IDvr.attacheFilter is called.
98 mPlaybackFilterIds.insert(filterId);
99 if (mDvrPlayback != nullptr) {
100 result = mDvrPlayback->addPlaybackFilter(filterId, filter);
101 }
102 }
103
104 if (!result) {
105 *_aidl_return = nullptr;
106 return ::ndk::ScopedAStatus::fromServiceSpecificError(
107 static_cast<int32_t>(Result::INVALID_ARGUMENT));
108 }
109
110 *_aidl_return = filter;
111 return ::ndk::ScopedAStatus::ok();
112 }
113
openTimeFilter(std::shared_ptr<ITimeFilter> * _aidl_return)114 ::ndk::ScopedAStatus Demux::openTimeFilter(std::shared_ptr<ITimeFilter>* _aidl_return) {
115 ALOGV("%s", __FUNCTION__);
116
117 mTimeFilter = ndk::SharedRefBase::make<TimeFilter>(this->ref<Demux>());
118
119 *_aidl_return = mTimeFilter;
120 return ::ndk::ScopedAStatus::ok();
121 }
122
getAvSyncHwId(const std::shared_ptr<IFilter> & in_filter,int32_t * _aidl_return)123 ::ndk::ScopedAStatus Demux::getAvSyncHwId(const std::shared_ptr<IFilter>& in_filter,
124 int32_t* _aidl_return) {
125 ALOGV("%s", __FUNCTION__);
126
127 int64_t id;
128 ::ndk::ScopedAStatus status;
129
130 status = in_filter->getId64Bit(&id);
131 if (!status.isOk()) {
132 ALOGE("[Demux] Can't get filter Id.");
133 *_aidl_return = -1;
134 return ::ndk::ScopedAStatus::fromServiceSpecificError(
135 static_cast<int32_t>(Result::INVALID_STATE));
136 }
137
138 if (!mFilters[id]->isMediaFilter()) {
139 ALOGE("[Demux] Given filter is not a media filter.");
140 *_aidl_return = -1;
141 return ::ndk::ScopedAStatus::fromServiceSpecificError(
142 static_cast<int32_t>(Result::INVALID_STATE));
143 }
144
145 if (!mPcrFilterIds.empty()) {
146 // Return the lowest pcr filter id in the default implementation as the av sync id
147 *_aidl_return = *mPcrFilterIds.begin();
148 return ::ndk::ScopedAStatus::ok();
149 }
150
151 ALOGE("[Demux] No PCR filter opened.");
152 *_aidl_return = -1;
153 return ::ndk::ScopedAStatus::fromServiceSpecificError(
154 static_cast<int32_t>(Result::INVALID_STATE));
155 }
156
getAvSyncTime(int32_t in_avSyncHwId,int64_t * _aidl_return)157 ::ndk::ScopedAStatus Demux::getAvSyncTime(int32_t in_avSyncHwId, int64_t* _aidl_return) {
158 ALOGV("%s", __FUNCTION__);
159
160 if (mPcrFilterIds.empty()) {
161 *_aidl_return = -1;
162 return ::ndk::ScopedAStatus::fromServiceSpecificError(
163 static_cast<int32_t>(Result::INVALID_STATE));
164 }
165 if (in_avSyncHwId != *mPcrFilterIds.begin()) {
166 *_aidl_return = -1;
167 return ::ndk::ScopedAStatus::fromServiceSpecificError(
168 static_cast<int32_t>(Result::INVALID_ARGUMENT));
169 }
170
171 *_aidl_return = -1;
172 return ::ndk::ScopedAStatus::ok();
173 }
174
close()175 ::ndk::ScopedAStatus Demux::close() {
176 ALOGV("%s", __FUNCTION__);
177
178 stopFrontendInput();
179
180 set<int64_t>::iterator it;
181 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
182 mDvrPlayback->removePlaybackFilter(*it);
183 }
184 mPlaybackFilterIds.clear();
185 mRecordFilterIds.clear();
186 mFilters.clear();
187 mLastUsedFilterId = -1;
188 if (mTuner != nullptr) {
189 mTuner->removeDemux(mDemuxId);
190 mTuner = nullptr;
191 }
192
193 return ::ndk::ScopedAStatus::ok();
194 }
195
openDvr(DvrType in_type,int32_t in_bufferSize,const std::shared_ptr<IDvrCallback> & in_cb,std::shared_ptr<IDvr> * _aidl_return)196 ::ndk::ScopedAStatus Demux::openDvr(DvrType in_type, int32_t in_bufferSize,
197 const std::shared_ptr<IDvrCallback>& in_cb,
198 std::shared_ptr<IDvr>* _aidl_return) {
199 ALOGV("%s", __FUNCTION__);
200
201 if (in_cb == nullptr) {
202 ALOGW("[Demux] DVR callback can't be null");
203 *_aidl_return = nullptr;
204 return ::ndk::ScopedAStatus::fromServiceSpecificError(
205 static_cast<int32_t>(Result::INVALID_ARGUMENT));
206 }
207
208 set<int64_t>::iterator it;
209 switch (in_type) {
210 case DvrType::PLAYBACK:
211 mDvrPlayback = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
212 this->ref<Demux>());
213 if (!mDvrPlayback->createDvrMQ()) {
214 mDvrPlayback = nullptr;
215 *_aidl_return = mDvrPlayback;
216 return ::ndk::ScopedAStatus::fromServiceSpecificError(
217 static_cast<int32_t>(Result::UNKNOWN_ERROR));
218 }
219
220 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
221 if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
222 ALOGE("[Demux] Can't get filter info for DVR playback");
223 mDvrPlayback = nullptr;
224 *_aidl_return = mDvrPlayback;
225 return ::ndk::ScopedAStatus::fromServiceSpecificError(
226 static_cast<int32_t>(Result::UNKNOWN_ERROR));
227 }
228 }
229
230 *_aidl_return = mDvrPlayback;
231 return ::ndk::ScopedAStatus::ok();
232 case DvrType::RECORD:
233 mDvrRecord = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
234 this->ref<Demux>());
235 if (!mDvrRecord->createDvrMQ()) {
236 mDvrRecord = nullptr;
237 *_aidl_return = mDvrRecord;
238 return ::ndk::ScopedAStatus::fromServiceSpecificError(
239 static_cast<int32_t>(Result::UNKNOWN_ERROR));
240 }
241
242 *_aidl_return = mDvrRecord;
243 return ::ndk::ScopedAStatus::ok();
244 default:
245 *_aidl_return = nullptr;
246 return ::ndk::ScopedAStatus::fromServiceSpecificError(
247 static_cast<int32_t>(Result::INVALID_ARGUMENT));
248 }
249 }
250
connectCiCam(int32_t in_ciCamId)251 ::ndk::ScopedAStatus Demux::connectCiCam(int32_t in_ciCamId) {
252 ALOGV("%s", __FUNCTION__);
253
254 mCiCamId = in_ciCamId;
255
256 return ::ndk::ScopedAStatus::ok();
257 }
258
disconnectCiCam()259 ::ndk::ScopedAStatus Demux::disconnectCiCam() {
260 ALOGV("%s", __FUNCTION__);
261
262 return ::ndk::ScopedAStatus::ok();
263 }
264
removeFilter(int64_t filterId)265 ::ndk::ScopedAStatus Demux::removeFilter(int64_t filterId) {
266 ALOGV("%s", __FUNCTION__);
267
268 if (mDvrPlayback != nullptr) {
269 mDvrPlayback->removePlaybackFilter(filterId);
270 }
271 mPlaybackFilterIds.erase(filterId);
272 mRecordFilterIds.erase(filterId);
273 mFilters.erase(filterId);
274
275 return ::ndk::ScopedAStatus::ok();
276 }
277
startBroadcastTsFilter(vector<int8_t> data)278 void Demux::startBroadcastTsFilter(vector<int8_t> data) {
279 set<int64_t>::iterator it;
280 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
281 if (DEBUG_DEMUX) {
282 ALOGW("[Demux] start ts filter pid: %d", pid);
283 }
284 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
285 if (pid == mFilters[*it]->getTpid()) {
286 mFilters[*it]->updateFilterOutput(data);
287 }
288 }
289 }
290
sendFrontendInputToRecord(vector<int8_t> data)291 void Demux::sendFrontendInputToRecord(vector<int8_t> data) {
292 set<int64_t>::iterator it;
293 if (DEBUG_DEMUX) {
294 ALOGW("[Demux] update record filter output");
295 }
296 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
297 mFilters[*it]->updateRecordOutput(data);
298 }
299 }
300
sendFrontendInputToRecord(vector<int8_t> data,uint16_t pid,uint64_t pts)301 void Demux::sendFrontendInputToRecord(vector<int8_t> data, uint16_t pid, uint64_t pts) {
302 sendFrontendInputToRecord(data);
303 set<int64_t>::iterator it;
304 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
305 if (pid == mFilters[*it]->getTpid()) {
306 mFilters[*it]->updatePts(pts);
307 }
308 }
309 }
310
startBroadcastFilterDispatcher()311 bool Demux::startBroadcastFilterDispatcher() {
312 set<int64_t>::iterator it;
313
314 // Handle the output data per filter type
315 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
316 if (!mFilters[*it]->startFilterHandler().isOk()) {
317 return false;
318 }
319 }
320
321 return true;
322 }
323
startRecordFilterDispatcher()324 bool Demux::startRecordFilterDispatcher() {
325 set<int64_t>::iterator it;
326
327 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
328 if (!mFilters[*it]->startRecordFilterHandler().isOk()) {
329 return false;
330 }
331 }
332
333 return true;
334 }
335
startFilterHandler(int64_t filterId)336 ::ndk::ScopedAStatus Demux::startFilterHandler(int64_t filterId) {
337 return mFilters[filterId]->startFilterHandler();
338 }
339
updateFilterOutput(int64_t filterId,vector<int8_t> data)340 void Demux::updateFilterOutput(int64_t filterId, vector<int8_t> data) {
341 mFilters[filterId]->updateFilterOutput(data);
342 }
343
updateMediaFilterOutput(int64_t filterId,vector<int8_t> data,uint64_t pts)344 void Demux::updateMediaFilterOutput(int64_t filterId, vector<int8_t> data, uint64_t pts) {
345 updateFilterOutput(filterId, data);
346 mFilters[filterId]->updatePts(pts);
347 }
348
getFilterTpid(int64_t filterId)349 uint16_t Demux::getFilterTpid(int64_t filterId) {
350 return mFilters[filterId]->getTpid();
351 }
352
getDemuxId()353 int32_t Demux::getDemuxId() {
354 return mDemuxId;
355 }
356
isInUse()357 bool Demux::isInUse() {
358 return mInUse;
359 }
360
setInUse(bool inUse)361 void Demux::setInUse(bool inUse) {
362 mInUse = inUse;
363 }
364
getDemuxInfo(DemuxInfo * demuxInfo)365 void Demux::getDemuxInfo(DemuxInfo* demuxInfo) {
366 *demuxInfo = {.filterTypes = mFilterTypes};
367 }
368
startFrontendInputLoop()369 void Demux::startFrontendInputLoop() {
370 ALOGD("[Demux] start frontend on demux");
371 // Stop current Frontend thread loop first, in case the user starts a new
372 // tuning before stopping current tuning.
373 stopFrontendInput();
374 mFrontendInputThreadRunning = true;
375 mFrontendInputThread = std::thread(&Demux::frontendInputThreadLoop, this);
376 }
377
frontendInputThreadLoop()378 void Demux::frontendInputThreadLoop() {
379 if (!mFrontendInputThreadRunning) {
380 return;
381 }
382
383 if (!mDvrPlayback) {
384 ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
385 mFrontendInputThreadRunning = false;
386 return;
387 }
388
389 while (mFrontendInputThreadRunning) {
390 uint32_t efState = 0;
391 ::android::status_t status = mDvrPlayback->getDvrEventFlag()->wait(
392 static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
393 true /* retry on spurious wake */);
394 if (status != ::android::OK) {
395 ALOGD("[Demux] wait for data ready on the playback FMQ");
396 continue;
397 }
398 if (mDvrPlayback->getSettings().get<DvrSettings::Tag::playback>().dataFormat ==
399 DataFormat::ES) {
400 if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
401 ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
402 break;
403 }
404 continue;
405 }
406 // Our current implementation filter the data and write it into the filter FMQ immediately
407 // after the DATA_READY from the VTS/framework
408 // This is for the non-ES data source, real playback use case handling.
409 if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
410 !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
411 ALOGE("[Demux] playback data failed to be filtered. Ending thread");
412 break;
413 }
414 }
415
416 mFrontendInputThreadRunning = false;
417 ALOGW("[Demux] Frontend Input thread end.");
418 }
419
stopFrontendInput()420 void Demux::stopFrontendInput() {
421 ALOGD("[Demux] stop frontend on demux");
422 mKeepFetchingDataFromFrontend = false;
423 mFrontendInputThreadRunning = false;
424 if (mFrontendInputThread.joinable()) {
425 mFrontendInputThread.join();
426 }
427 }
428
setIsRecording(bool isRecording)429 void Demux::setIsRecording(bool isRecording) {
430 mIsRecording = isRecording;
431 }
432
isRecording()433 bool Demux::isRecording() {
434 return mIsRecording;
435 }
436
dump(int fd,const char ** args,uint32_t numArgs)437 binder_status_t Demux::dump(int fd, const char** args, uint32_t numArgs) {
438 dprintf(fd, " Demux %d:\n", mDemuxId);
439 dprintf(fd, " mIsRecording %d\n", mIsRecording);
440 {
441 dprintf(fd, " Filters:\n");
442 map<int64_t, std::shared_ptr<Filter>>::iterator it;
443 for (it = mFilters.begin(); it != mFilters.end(); it++) {
444 it->second->dump(fd, args, numArgs);
445 }
446 }
447 {
448 dprintf(fd, " TimeFilter:\n");
449 if (mTimeFilter != nullptr) {
450 mTimeFilter->dump(fd, args, numArgs);
451 }
452 }
453 {
454 dprintf(fd, " DvrPlayback:\n");
455 if (mDvrPlayback != nullptr) {
456 mDvrPlayback->dump(fd, args, numArgs);
457 }
458 }
459 {
460 dprintf(fd, " DvrRecord:\n");
461 if (mDvrRecord != nullptr) {
462 mDvrRecord->dump(fd, args, numArgs);
463 }
464 }
465 return STATUS_OK;
466 }
467
attachRecordFilter(int64_t filterId)468 bool Demux::attachRecordFilter(int64_t filterId) {
469 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
470 !mFilters[filterId]->isRecordFilter()) {
471 return false;
472 }
473
474 mRecordFilterIds.insert(filterId);
475 mFilters[filterId]->attachFilterToRecord(mDvrRecord);
476
477 return true;
478 }
479
detachRecordFilter(int64_t filterId)480 bool Demux::detachRecordFilter(int64_t filterId) {
481 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
482 return false;
483 }
484
485 mRecordFilterIds.erase(filterId);
486 mFilters[filterId]->detachFilterFromRecord();
487
488 return true;
489 }
490
491 } // namespace tuner
492 } // namespace tv
493 } // namespace hardware
494 } // namespace android
495 } // namespace aidl
496