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