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