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 mTunerService->setFrontendAsDemuxSource(frontendId, mDemuxId);
52
53 return Result::SUCCESS;
54 }
55
openFilter(const DemuxFilterType & type,uint32_t bufferSize,const sp<IFilterCallback> & cb,openFilter_cb _hidl_cb)56 Return<void> Demux::openFilter(const DemuxFilterType& type, uint32_t bufferSize,
57 const sp<IFilterCallback>& cb, openFilter_cb _hidl_cb) {
58 ALOGV("%s", __FUNCTION__);
59
60 uint32_t filterId;
61 filterId = ++mLastUsedFilterId;
62
63 if (cb == nullptr) {
64 ALOGW("[Demux] callback can't be null");
65 _hidl_cb(Result::INVALID_ARGUMENT, new Filter());
66 return Void();
67 }
68
69 sp<Filter> filter = new Filter(type, filterId, bufferSize, cb, this);
70
71 if (!filter->createFilterMQ()) {
72 _hidl_cb(Result::UNKNOWN_ERROR, filter);
73 return Void();
74 }
75
76 mFilters[filterId] = filter;
77 if (filter->isPcrFilter()) {
78 mPcrFilterIds.insert(filterId);
79 }
80 bool result = true;
81 if (!filter->isRecordFilter()) {
82 // Only save non-record filters for now. Record filters are saved when the
83 // IDvr.attacheFilter is called.
84 mPlaybackFilterIds.insert(filterId);
85 if (mDvrPlayback != nullptr) {
86 result = mDvrPlayback->addPlaybackFilter(filterId, filter);
87 }
88 }
89
90 _hidl_cb(result ? Result::SUCCESS : Result::INVALID_ARGUMENT, filter);
91 return Void();
92 }
93
openTimeFilter(openTimeFilter_cb _hidl_cb)94 Return<void> Demux::openTimeFilter(openTimeFilter_cb _hidl_cb) {
95 ALOGV("%s", __FUNCTION__);
96
97 mTimeFilter = new TimeFilter(this);
98
99 _hidl_cb(Result::SUCCESS, mTimeFilter);
100 return Void();
101 }
102
getAvSyncHwId(const sp<IFilter> & filter,getAvSyncHwId_cb _hidl_cb)103 Return<void> Demux::getAvSyncHwId(const sp<IFilter>& filter, getAvSyncHwId_cb _hidl_cb) {
104 ALOGV("%s", __FUNCTION__);
105
106 uint32_t avSyncHwId = -1;
107 int id;
108 Result status;
109
110 filter->getId([&](Result result, uint32_t filterId) {
111 id = filterId;
112 status = result;
113 });
114
115 if (status != Result::SUCCESS) {
116 ALOGE("[Demux] Can't get filter Id.");
117 _hidl_cb(Result::INVALID_STATE, avSyncHwId);
118 return Void();
119 }
120
121 if (!mFilters[id]->isMediaFilter()) {
122 ALOGE("[Demux] Given filter is not a media filter.");
123 _hidl_cb(Result::INVALID_ARGUMENT, avSyncHwId);
124 return Void();
125 }
126
127 if (!mPcrFilterIds.empty()) {
128 // Return the lowest pcr filter id in the default implementation as the av sync id
129 _hidl_cb(Result::SUCCESS, *mPcrFilterIds.begin());
130 return Void();
131 }
132
133 ALOGE("[Demux] No PCR filter opened.");
134 _hidl_cb(Result::INVALID_STATE, avSyncHwId);
135 return Void();
136 }
137
getAvSyncTime(AvSyncHwId avSyncHwId,getAvSyncTime_cb _hidl_cb)138 Return<void> Demux::getAvSyncTime(AvSyncHwId avSyncHwId, getAvSyncTime_cb _hidl_cb) {
139 ALOGV("%s", __FUNCTION__);
140
141 uint64_t avSyncTime = -1;
142 if (mPcrFilterIds.empty()) {
143 _hidl_cb(Result::INVALID_STATE, avSyncTime);
144 return Void();
145 }
146 if (avSyncHwId != *mPcrFilterIds.begin()) {
147 _hidl_cb(Result::INVALID_ARGUMENT, avSyncTime);
148 return Void();
149 }
150
151 _hidl_cb(Result::SUCCESS, avSyncTime);
152 return Void();
153 }
154
close()155 Return<Result> Demux::close() {
156 ALOGV("%s", __FUNCTION__);
157
158 set<uint32_t>::iterator it;
159 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
160 mDvrPlayback->removePlaybackFilter(*it);
161 }
162 mPlaybackFilterIds.clear();
163 mRecordFilterIds.clear();
164 mFilters.clear();
165 mLastUsedFilterId = -1;
166 mTunerService->removeDemux(mDemuxId);
167
168 return Result::SUCCESS;
169 }
170
openDvr(DvrType type,uint32_t bufferSize,const sp<IDvrCallback> & cb,openDvr_cb _hidl_cb)171 Return<void> Demux::openDvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb,
172 openDvr_cb _hidl_cb) {
173 ALOGV("%s", __FUNCTION__);
174
175 if (cb == nullptr) {
176 ALOGW("[Demux] DVR callback can't be null");
177 _hidl_cb(Result::INVALID_ARGUMENT, new Dvr());
178 return Void();
179 }
180
181 set<uint32_t>::iterator it;
182 switch (type) {
183 case DvrType::PLAYBACK:
184 mDvrPlayback = new Dvr(type, bufferSize, cb, this);
185 if (!mDvrPlayback->createDvrMQ()) {
186 _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
187 return Void();
188 }
189
190 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
191 if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
192 ALOGE("[Demux] Can't get filter info for DVR playback");
193 _hidl_cb(Result::UNKNOWN_ERROR, mDvrPlayback);
194 return Void();
195 }
196 }
197
198 _hidl_cb(Result::SUCCESS, mDvrPlayback);
199 return Void();
200 case DvrType::RECORD:
201 mDvrRecord = new Dvr(type, bufferSize, cb, this);
202 if (!mDvrRecord->createDvrMQ()) {
203 _hidl_cb(Result::UNKNOWN_ERROR, mDvrRecord);
204 return Void();
205 }
206
207 _hidl_cb(Result::SUCCESS, mDvrRecord);
208 return Void();
209 default:
210 _hidl_cb(Result::INVALID_ARGUMENT, nullptr);
211 return Void();
212 }
213 }
214
connectCiCam(uint32_t ciCamId)215 Return<Result> Demux::connectCiCam(uint32_t ciCamId) {
216 ALOGV("%s", __FUNCTION__);
217
218 mCiCamId = ciCamId;
219
220 return Result::SUCCESS;
221 }
222
disconnectCiCam()223 Return<Result> Demux::disconnectCiCam() {
224 ALOGV("%s", __FUNCTION__);
225
226 return Result::SUCCESS;
227 }
228
removeFilter(uint32_t filterId)229 Result Demux::removeFilter(uint32_t filterId) {
230 ALOGV("%s", __FUNCTION__);
231
232 if (mDvrPlayback != nullptr) {
233 mDvrPlayback->removePlaybackFilter(filterId);
234 }
235 mPlaybackFilterIds.erase(filterId);
236 mRecordFilterIds.erase(filterId);
237 mFilters.erase(filterId);
238
239 return Result::SUCCESS;
240 }
241
startBroadcastTsFilter(vector<uint8_t> data)242 void Demux::startBroadcastTsFilter(vector<uint8_t> data) {
243 set<uint32_t>::iterator it;
244 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
245 if (DEBUG_DEMUX) {
246 ALOGW("[Demux] start ts filter pid: %d", pid);
247 }
248 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
249 if (pid == mFilters[*it]->getTpid()) {
250 mFilters[*it]->updateFilterOutput(data);
251 }
252 }
253 }
254
sendFrontendInputToRecord(vector<uint8_t> data)255 void Demux::sendFrontendInputToRecord(vector<uint8_t> data) {
256 set<uint32_t>::iterator it;
257 if (DEBUG_DEMUX) {
258 ALOGW("[Demux] update record filter output");
259 }
260 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
261 mFilters[*it]->updateRecordOutput(data);
262 }
263 }
264
startBroadcastFilterDispatcher()265 bool Demux::startBroadcastFilterDispatcher() {
266 set<uint32_t>::iterator it;
267
268 // Handle the output data per filter type
269 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
270 if (mFilters[*it]->startFilterHandler() != Result::SUCCESS) {
271 return false;
272 }
273 }
274
275 return true;
276 }
277
startRecordFilterDispatcher()278 bool Demux::startRecordFilterDispatcher() {
279 set<uint32_t>::iterator it;
280
281 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
282 if (mFilters[*it]->startRecordFilterHandler() != Result::SUCCESS) {
283 return false;
284 }
285 }
286
287 return true;
288 }
289
startFilterHandler(uint32_t filterId)290 Result Demux::startFilterHandler(uint32_t filterId) {
291 return mFilters[filterId]->startFilterHandler();
292 }
293
updateFilterOutput(uint16_t filterId,vector<uint8_t> data)294 void Demux::updateFilterOutput(uint16_t filterId, vector<uint8_t> data) {
295 mFilters[filterId]->updateFilterOutput(data);
296 }
297
updateMediaFilterOutput(uint16_t filterId,vector<uint8_t> data,uint64_t pts)298 void Demux::updateMediaFilterOutput(uint16_t filterId, vector<uint8_t> data, uint64_t pts) {
299 updateFilterOutput(filterId, data);
300 mFilters[filterId]->updatePts(pts);
301 }
302
getFilterTpid(uint32_t filterId)303 uint16_t Demux::getFilterTpid(uint32_t filterId) {
304 return mFilters[filterId]->getTpid();
305 }
306
startFrontendInputLoop()307 void Demux::startFrontendInputLoop() {
308 pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
309 pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
310 }
311
__threadLoopFrontend(void * user)312 void* Demux::__threadLoopFrontend(void* user) {
313 Demux* const self = static_cast<Demux*>(user);
314 self->frontendInputThreadLoop();
315 return 0;
316 }
317
frontendInputThreadLoop()318 void Demux::frontendInputThreadLoop() {
319 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
320 mFrontendInputThreadRunning = true;
321
322 if (!mDvrPlayback) {
323 ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
324 mFrontendInputThreadRunning = false;
325 return;
326 }
327
328 while (mFrontendInputThreadRunning) {
329 uint32_t efState = 0;
330 status_t status = mDvrPlayback->getDvrEventFlag()->wait(
331 static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
332 true /* retry on spurious wake */);
333 if (status != OK) {
334 ALOGD("[Demux] wait for data ready on the playback FMQ");
335 continue;
336 }
337 if (mDvrPlayback->getSettings().playback().dataFormat == DataFormat::ES) {
338 if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
339 ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
340 break;
341 }
342 }
343 // Our current implementation filter the data and write it into the filter FMQ immediately
344 // after the DATA_READY from the VTS/framework
345 if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
346 !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
347 ALOGE("[Demux] playback data failed to be filtered. Ending thread");
348 break;
349 }
350 }
351
352 mFrontendInputThreadRunning = false;
353 ALOGW("[Demux] Frontend Input thread end.");
354 }
355
stopFrontendInput()356 void Demux::stopFrontendInput() {
357 ALOGD("[Demux] stop frontend on demux");
358 mKeepFetchingDataFromFrontend = false;
359 mFrontendInputThreadRunning = false;
360 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
361 }
362
setIsRecording(bool isRecording)363 void Demux::setIsRecording(bool isRecording) {
364 mIsRecording = isRecording;
365 }
366
attachRecordFilter(int filterId)367 bool Demux::attachRecordFilter(int filterId) {
368 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
369 !mFilters[filterId]->isRecordFilter()) {
370 return false;
371 }
372
373 mRecordFilterIds.insert(filterId);
374 mFilters[filterId]->attachFilterToRecord(mDvrRecord);
375
376 return true;
377 }
378
detachRecordFilter(int filterId)379 bool Demux::detachRecordFilter(int filterId) {
380 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
381 return false;
382 }
383
384 mRecordFilterIds.erase(filterId);
385 mFilters[filterId]->detachFilterFromRecord();
386
387 return true;
388 }
389
390 } // namespace implementation
391 } // namespace V1_0
392 } // namespace tuner
393 } // namespace tv
394 } // namespace hardware
395 } // namespace android
396