• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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