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