1 /*
2  * Copyright (C) 2019 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 "android.hardware.tv.tuner@1.0-Demux"
18 
19 #include "Demux.h"
20 #include <utils/Log.h>
21 
22 namespace android {
23 namespace hardware {
24 namespace tv {
25 namespace tuner {
26 namespace V1_0 {
27 namespace implementation {
28 
29 #define WAIT_TIMEOUT 3000000000
30 
Demux(uint32_t demuxId,sp<Tuner> tuner)31 Demux::Demux(uint32_t demuxId, sp<Tuner> tuner) {
32     mDemuxId = demuxId;
33     mTunerService = tuner;
34 }
35 
~Demux()36 Demux::~Demux() {}
37 
setFrontendDataSource(uint32_t frontendId)38 Return<Result> Demux::setFrontendDataSource(uint32_t frontendId) {
39     ALOGV("%s", __FUNCTION__);
40 
41     if (mTunerService == nullptr) {
42         return Result::NOT_INITIALIZED;
43     }
44 
45     mFrontend = mTunerService->getFrontendById(frontendId);
46 
47     if (mFrontend == nullptr) {
48         return Result::INVALID_STATE;
49     }
50 
51     mFrontendSourceFile = mFrontend->getSourceFile();
52 
53     mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
54 
55     return startFrontendInputLoop();
56 }
57 
openFilter(const DemuxFilterType & type,uint32_t bufferSize,const sp<IFilterCallback> & cb,openFilter_cb _hidl_cb)58 Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
59                                const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) {
60     ALOGV("%s", __FUNCTION__);
61 
62     uint32_t filterId;
63 
64     if (!mUnusedFilterIds.empty()) {
65         filterId = *mUnusedFilterIds.begin();
66 
67         mUnusedFilterIds.erase(filterId);
68     } else {
69         filterId = ++mLastUsedFilterId;
70     }
71 
72     mUsedFilterIds.insert(filterId);
73 
74     if (cb == nullptr) {
75         ALOGW("callback can't be null");
76         _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
77         return Void();
78     }
79 
80     sp<Filter> filter = new Filter(type, filterId, bufferSize, cb, this);
81 
82     if (!filter->createFilterMQ()) {
83         _hidl_cb(Result::UNKNOWN_ERROR, filter);
84         return Void();
85     }
86 
87     mFilters[filterId] = filter;
88 
89     _hidl_cb(Result::SUCCESS, filter);
90     return Void();
91 }
92 
openTimeFilter(openTimeFilter_cb _hidl_cb)93 Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
94     ALOGV("%s", __FUNCTION__);
95 
96     sp<TimeFilter> timeFilter = new TimeFilter(this);
97 
98     _hidl_cb(Result::SUCCESS, timeFilter);
99     return Void();
100 }
101 
getAvSyncHwId(const sp<IFilter> &,getAvSyncHwId_cb _hidl_cb)102 Return<void> Demux::getAvSyncHwId(const sp<IFilter>& /* filter */, getAvSyncHwId_cb _hidl_cb) {
103     ALOGV("%s", __FUNCTION__);
104 
105     AvSyncHwId avSyncHwId = 0;
106 
107     _hidl_cb(Result::SUCCESS, avSyncHwId);
108     return Void();
109 }
110 
getAvSyncTime(AvSyncHwId,getAvSyncTime_cb _hidl_cb)111 Return<void> Demux::getAvSyncTime(AvSyncHwId /* avSyncHwId */, getAvSyncTime_cb _hidl_cb) {
112     ALOGV("%s", __FUNCTION__);
113 
114     uint64_t avSyncTime = 0;
115 
116     _hidl_cb(Result::SUCCESS, avSyncTime);
117     return Void();
118 }
119 
close()120 Return<Result> Demux::close() {
121     ALOGV("%s", __FUNCTION__);
122 
123     mUnusedFilterIds.clear();
124     mUsedFilterIds.clear();
125     mLastUsedFilterId = -1;
126 
127     return Result::SUCCESS;
128 }
129 
openDvr(DvrType type,uint32_t bufferSize,const sp<IDvrCallback> & cb,openDvr_cb _hidl_cb)130 Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
131                             openDvr_cb _hidl_cb) {
132     ALOGV("%s", __FUNCTION__);
133 
134     if (cb == nullptr) {
135         ALOGW("DVR callback can't be null");
136         _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
137         return Void();
138     }
139 
140     mDvr = new Dvr(type, bufferSize, cb, this);
141 
142     if (!mDvr->createDvrMQ()) {
143         _hidl_cb(Result::UNKNOWN_ERROR, mDvr);
144         return Void();
145     }
146 
147     _hidl_cb(Result::SUCCESS, mDvr);
148     return Void();
149 }
150 
connectCiCam(uint32_t ciCamId)151 Return<Result> Demux::connectCiCam(uint32_t ciCamId) {
152     ALOGV("%s", __FUNCTION__);
153 
154     mCiCamId = ciCamId;
155 
156     return Result::SUCCESS;
157 }
158 
disconnectCiCam()159 Return<Result> Demux::disconnectCiCam() {
160     ALOGV("%s", __FUNCTION__);
161 
162     return Result::SUCCESS;
163 }
164 
removeFilter(uint32_t filterId)165 Result Demux::removeFilter(uint32_t filterId) {
166     ALOGV("%s", __FUNCTION__);
167 
168     // resetFilterRecords(filterId);
169     mUsedFilterIds.erase(filterId);
170     mRecordFilterIds.erase(filterId);
171     mUnusedFilterIds.insert(filterId);
172     mFilters.erase(filterId);
173 
174     return Result::SUCCESS;
175 }
176 
startBroadcastTsFilter(vector<uint8_t> data)177 void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
178     set<uint32_t>::iterator it;
179     for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
180         uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
181         if (DEBUG_FILTER) {
182             ALOGW("start ts filter pid: %d", pid);
183         }
184         if (pid == mFilters[*it]->getTpid()) {
185             mFilters[*it]->updateFilterOutput(data);
186         }
187     }
188 }
189 
sendFrontendInputToRecord(vector<uint8_t> data)190 void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
191     set<uint32_t>::iterator it;
192     for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
193         if (DEBUG_FILTER) {
194             ALOGW("update record filter output");
195         }
196         mFilters[*it]->updateRecordOutput(data);
197     }
198 }
199 
startBroadcastFilterDispatcher()200 bool Demux::startBroadcastFilterDispatcher() {
201     set<uint32_t>::iterator it;
202 
203     // Handle the output data per filter type
204     for (it = mUsedFilterIds.begin(); it != mUsedFilterIds.end(); it++) {
205         if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
206             return false;
207         }
208     }
209 
210     return true;
211 }
212 
startRecordFilterDispatcher()213 bool Demux::startRecordFilterDispatcher() {
214     set<uint32_t>::iterator it;
215 
216     for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
217         if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
218             return false;
219         }
220     }
221 
222     return true;
223 }
224 
startFilterHandler(uint32_t filterId)225 Result Demux::startFilterHandler(uint32_t filterId) {
226     return mFilters[filterId]->startFilterHandler();
227 }
228 
updateFilterOutput(uint16_t filterId,vector<uint8_t> data)229 void Demux::updateFilterOutput(uint16_t filterId, vector<uint8_t> data) {
230     mFilters[filterId]->updateFilterOutput(data);
231 }
232 
getFilterTpid(uint32_t filterId)233 uint16_t Demux::getFilterTpid(uint32_t filterId) {
234     return mFilters[filterId]->getTpid();
235 }
236 
startFrontendInputLoop()237 Result Demux::startFrontendInputLoop() {
238     pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
239     pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
240 
241     return Result::SUCCESS;
242 }
243 
__threadLoopFrontend(void * user)244 void* Demux::__threadLoopFrontend(void* user) {
245     Demux* const self = static_cast<Demux*>(user);
246     self->frontendInputThreadLoop();
247     return 0;
248 }
249 
frontendInputThreadLoop()250 void Demux::frontendInputThreadLoop() {
251     std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
252     mFrontendInputThreadRunning = true;
253     mKeepFetchingDataFromFrontend = true;
254 
255     // open the stream and get its length
256     std::ifstream inputData(mFrontendSourceFile, std::ifstream::binary);
257     // TODO take the packet size from the frontend setting
258     int packetSize = 188;
259     int writePacketAmount = 6;
260     char* buffer = new char[packetSize];
261     ALOGW("[Demux] Frontend input thread loop start %s", mFrontendSourceFile.c_str());
262     if (!inputData.is_open()) {
263         mFrontendInputThreadRunning = false;
264         ALOGW("[Demux] Error %s", strerror(errno));
265     }
266 
267     while (mFrontendInputThreadRunning) {
268         // move the stream pointer for packet size * 6 every read until the end
269         while (mKeepFetchingDataFromFrontend) {
270             for (int i = 0; i < writePacketAmount; i++) {
271                 inputData.read(buffer, packetSize);
272                 if (!inputData) {
273                     mKeepFetchingDataFromFrontend = false;
274                     mFrontendInputThreadRunning = false;
275                     break;
276                 }
277                 // filter and dispatch filter output
278                 vector<uint8_t> byteBuffer;
279                 byteBuffer.resize(packetSize);
280                 for (int index = 0; index < byteBuffer.size(); index++) {
281                     byteBuffer[index] = static_cast<uint8_t>(buffer[index]);
282                 }
283                 if (mIsRecording) {
284                     // Feed the data into the Dvr recording input
285                     sendFrontendInputToRecord(byteBuffer);
286                 } else {
287                     // Feed the data into the broadcast demux filter
288                     startBroadcastTsFilter(byteBuffer);
289                 }
290             }
291             if (mIsRecording) {
292                 // Dispatch the data into the broadcasting filters.
293                 startRecordFilterDispatcher();
294             } else {
295                 // Dispatch the data into the broadcasting filters.
296                 startBroadcastFilterDispatcher();
297             }
298             usleep(100);
299         }
300     }
301 
302     ALOGW("[Demux] Frontend Input thread end.");
303     delete[] buffer;
304     inputData.close();
305 }
306 
stopFrontendInput()307 void Demux::stopFrontendInput() {
308     ALOGD("[Demux] stop frontend on demux");
309     mKeepFetchingDataFromFrontend = false;
310     mFrontendInputThreadRunning = false;
311     std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
312 }
313 
setIsRecording(bool isRecording)314 void Demux::setIsRecording(bool isRecording) {
315     mIsRecording = isRecording;
316 }
317 
attachRecordFilter(int filterId)318 bool Demux::attachRecordFilter(int filterId) {
319     if (mFilters[filterId] == nullptr || mDvr == nullptr) {
320         return false;
321     }
322 
323     mRecordFilterIds.insert(filterId);
324     mFilters[filterId]->attachFilterToRecord(mDvr);
325 
326     return true;
327 }
328 
detachRecordFilter(int filterId)329 bool Demux::detachRecordFilter(int filterId) {
330     if (mFilters[filterId] == nullptr || mDvr == nullptr) {
331         return false;
332     }
333 
334     mRecordFilterIds.erase(filterId);
335     mFilters[filterId]->detachFilterFromRecord();
336 
337     return true;
338 }
339 
340 }  // namespace implementation
341 }  // namespace V1_0
342 }  // namespace tuner
343 }  // namespace tv
344 }  // namespace hardware
345 }  // namespace android
346