blob: 15022ee9ac1c9886210a9f93f4a80871aaf5fb77 [file] [log] [blame]
Hongguang4092f2f2021-07-08 18:49:12 -07001/*
2 * Copyright 2021 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_NDEBUG 0
18#define LOG_TAG "android.hardware.tv.tuner-service.example-Demux"
19
20#include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
21
22#include <utils/Log.h>
23#include "Demux.h"
24
25namespace aidl {
26namespace android {
27namespace hardware {
28namespace tv {
29namespace tuner {
30
31#define WAIT_TIMEOUT 3000000000
32
33Demux::Demux(int32_t demuxId, std::shared_ptr<Tuner> tuner) {
34 mDemuxId = demuxId;
35 mTunerService = tuner;
36}
37
38Demux::~Demux() {
39 mFrontendInputThreadRunning = false;
40 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
41}
42
43::ndk::ScopedAStatus Demux::setFrontendDataSource(int32_t in_frontendId) {
44 ALOGV("%s", __FUNCTION__);
45
46 if (mTunerService == nullptr) {
47 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_NO_INIT);
48 }
49
50 mFrontend = mTunerService->getFrontendById(in_frontendId);
51
52 if (mFrontend == nullptr) {
53 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
54 }
55
56 mTunerService->setFrontendAsDemuxSource(in_frontendId, mDemuxId);
57
58 return ::ndk::ScopedAStatus::ok();
59}
60
61::ndk::ScopedAStatus Demux::openFilter(const DemuxFilterType& in_type, int32_t in_bufferSize,
62 const std::shared_ptr<IFilterCallback>& in_cb,
63 std::shared_ptr<IFilter>* _aidl_return) {
64 ALOGV("%s", __FUNCTION__);
65
66 int64_t filterId;
67 filterId = ++mLastUsedFilterId;
68
69 if (in_cb == nullptr) {
70 ALOGW("[Demux] callback can't be null");
71 *_aidl_return = nullptr;
72 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
73 }
74
75 std::shared_ptr<Filter> filter =
76 ndk::SharedRefBase::make<Filter>(in_type, filterId, in_bufferSize, in_cb, ref<Demux>());
77 if (!filter->createFilterMQ()) {
78 *_aidl_return = nullptr;
79 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_UNKNOWN_ERROR);
80 }
81
82 mFilters[filterId] = filter;
83 if (filter->isPcrFilter()) {
84 mPcrFilterIds.insert(filterId);
85 }
86 bool result = true;
87 if (!filter->isRecordFilter()) {
88 // Only save non-record filters for now. Record filters are saved when the
89 // IDvr.attacheFilter is called.
90 mPlaybackFilterIds.insert(filterId);
91 if (mDvrPlayback != nullptr) {
92 result = mDvrPlayback->addPlaybackFilter(filterId, filter);
93 }
94 }
95
96 if (!result) {
97 *_aidl_return = nullptr;
98 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
99 }
100
101 *_aidl_return = filter;
102 return ::ndk::ScopedAStatus::ok();
103}
104
105::ndk::ScopedAStatus Demux::openTimeFilter(std::shared_ptr<ITimeFilter>* _aidl_return) {
106 ALOGV("%s", __FUNCTION__);
107
108 mTimeFilter = ndk::SharedRefBase::make<TimeFilter>(ref<Demux>());
109
110 *_aidl_return = mTimeFilter;
111 return ::ndk::ScopedAStatus::ok();
112}
113
114::ndk::ScopedAStatus Demux::getAvSyncHwId(const std::shared_ptr<IFilter>& in_filter,
115 int32_t* _aidl_return) {
116 ALOGV("%s", __FUNCTION__);
117
118 int64_t id;
119 ::ndk::ScopedAStatus status;
120
121 status = in_filter->getId64Bit(&id);
122 if (!status.isOk()) {
123 ALOGE("[Demux] Can't get filter Id.");
124 *_aidl_return = -1;
125 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
126 }
127
128 if (!mFilters[id]->isMediaFilter()) {
129 ALOGE("[Demux] Given filter is not a media filter.");
130 *_aidl_return = -1;
131 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
132 }
133
134 if (!mPcrFilterIds.empty()) {
135 // Return the lowest pcr filter id in the default implementation as the av sync id
136 *_aidl_return = *mPcrFilterIds.begin();
137 return ::ndk::ScopedAStatus::ok();
138 }
139
140 ALOGE("[Demux] No PCR filter opened.");
141 *_aidl_return = -1;
142 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
143}
144
145::ndk::ScopedAStatus Demux::getAvSyncTime(int32_t in_avSyncHwId, int64_t* _aidl_return) {
146 ALOGV("%s", __FUNCTION__);
147
148 if (mPcrFilterIds.empty()) {
149 *_aidl_return = -1;
150 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
151 }
152 if (in_avSyncHwId != *mPcrFilterIds.begin()) {
153 *_aidl_return = -1;
154 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
155 }
156
157 *_aidl_return = -1;
158 return ::ndk::ScopedAStatus::ok();
159}
160
161::ndk::ScopedAStatus Demux::close() {
162 ALOGV("%s", __FUNCTION__);
163
164 set<int64_t>::iterator it;
165 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
166 mDvrPlayback->removePlaybackFilter(*it);
167 }
168 mPlaybackFilterIds.clear();
169 mRecordFilterIds.clear();
170 mFilters.clear();
171 mLastUsedFilterId = -1;
172 mTunerService->removeDemux(mDemuxId);
173 mFrontendInputThreadRunning = false;
174 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
175
176 return ::ndk::ScopedAStatus::ok();
177}
178
179::ndk::ScopedAStatus Demux::openDvr(DvrType in_type, int32_t in_bufferSize,
180 const std::shared_ptr<IDvrCallback>& in_cb,
181 std::shared_ptr<IDvr>* _aidl_return) {
182 ALOGV("%s", __FUNCTION__);
183
184 if (in_cb == nullptr) {
185 ALOGW("[Demux] DVR callback can't be null");
186 *_aidl_return = nullptr;
187 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
188 }
189
190 set<int64_t>::iterator it;
191 switch (in_type) {
192 case DvrType::PLAYBACK:
193 mDvrPlayback =
194 ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb, ref<Demux>());
195 if (!mDvrPlayback->createDvrMQ()) {
196 mDvrPlayback = nullptr;
197 *_aidl_return = mDvrPlayback;
198 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_UNKNOWN_ERROR);
199 }
200
201 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
202 if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
203 ALOGE("[Demux] Can't get filter info for DVR playback");
204 mDvrPlayback = nullptr;
205 *_aidl_return = mDvrPlayback;
206 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_UNKNOWN_ERROR);
207 }
208 }
209
210 *_aidl_return = mDvrPlayback;
211 return ::ndk::ScopedAStatus::ok();
212 case DvrType::RECORD:
213 mDvrRecord = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb, ref<Demux>());
214 if (!mDvrRecord->createDvrMQ()) {
215 mDvrRecord = nullptr;
216 *_aidl_return = mDvrRecord;
217 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_UNKNOWN_ERROR);
218 }
219
220 *_aidl_return = mDvrRecord;
221 return ::ndk::ScopedAStatus::ok();
222 default:
223 *_aidl_return = nullptr;
224 return ::ndk::ScopedAStatus::fromExceptionCode(STATUS_INVALID_OPERATION);
225 }
226}
227
228::ndk::ScopedAStatus Demux::connectCiCam(int32_t in_ciCamId) {
229 ALOGV("%s", __FUNCTION__);
230
231 mCiCamId = in_ciCamId;
232
233 return ::ndk::ScopedAStatus::ok();
234}
235
236::ndk::ScopedAStatus Demux::disconnectCiCam() {
237 ALOGV("%s", __FUNCTION__);
238
239 return ::ndk::ScopedAStatus::ok();
240}
241
242::ndk::ScopedAStatus Demux::removeFilter(int64_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 ::ndk::ScopedAStatus::ok();
253}
254
255void Demux::startBroadcastTsFilter(vector<int8_t> data) {
256 set<int64_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<int8_t> data) {
269 set<int64_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
278void Demux::sendFrontendInputToRecord(vector<int8_t> data, uint16_t pid, uint64_t pts) {
279 sendFrontendInputToRecord(data);
280 set<int64_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
288bool Demux::startBroadcastFilterDispatcher() {
289 set<int64_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().isOk()) {
294 return false;
295 }
296 }
297
298 return true;
299}
300
301bool Demux::startRecordFilterDispatcher() {
302 set<int64_t>::iterator it;
303
304 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
305 if (!mFilters[*it]->startRecordFilterHandler().isOk()) {
306 return false;
307 }
308 }
309
310 return true;
311}
312
313::ndk::ScopedAStatus Demux::startFilterHandler(int64_t filterId) {
314 return mFilters[filterId]->startFilterHandler();
315}
316
317void Demux::updateFilterOutput(int64_t filterId, vector<int8_t> data) {
318 mFilters[filterId]->updateFilterOutput(data);
319}
320
321void Demux::updateMediaFilterOutput(int64_t filterId, vector<int8_t> data, uint64_t pts) {
322 updateFilterOutput(filterId, data);
323 mFilters[filterId]->updatePts(pts);
324}
325
326uint16_t Demux::getFilterTpid(int64_t filterId) {
327 return mFilters[filterId]->getTpid();
328}
329
330void Demux::startFrontendInputLoop() {
331 mFrontendInputThreadRunning = true;
332 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 if (!mFrontendInputThreadRunning) {
344 return;
345 }
346
347 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
348 if (!mDvrPlayback) {
349 ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
350 mFrontendInputThreadRunning = false;
351 return;
352 }
353
354 while (mFrontendInputThreadRunning) {
355 uint32_t efState = 0;
356 ::android::status_t status = mDvrPlayback->getDvrEventFlag()->wait(
357 static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
358 true /* retry on spurious wake */);
359 if (status != ::android::OK) {
360 ALOGD("[Demux] wait for data ready on the playback FMQ");
361 continue;
362 }
363 if (mDvrPlayback->getSettings().get<DvrSettings::Tag::playback>().dataFormat ==
364 DataFormat::ES) {
365 if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
366 ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
367 break;
368 }
369 continue;
370 }
371 // Our current implementation filter the data and write it into the filter FMQ immediately
372 // after the DATA_READY from the VTS/framework
373 // This is for the non-ES data source, real playback use case handling.
374 if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
375 !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
376 ALOGE("[Demux] playback data failed to be filtered. Ending thread");
377 break;
378 }
379 }
380
381 mFrontendInputThreadRunning = false;
382 ALOGW("[Demux] Frontend Input thread end.");
383}
384
385void Demux::stopFrontendInput() {
386 ALOGD("[Demux] stop frontend on demux");
387 mKeepFetchingDataFromFrontend = false;
388 mFrontendInputThreadRunning = false;
389 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
390}
391
392void Demux::setIsRecording(bool isRecording) {
393 mIsRecording = isRecording;
394}
395
396bool Demux::isRecording() {
397 return mIsRecording;
398}
399
400bool Demux::attachRecordFilter(int64_t filterId) {
401 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
402 !mFilters[filterId]->isRecordFilter()) {
403 return false;
404 }
405
406 mRecordFilterIds.insert(filterId);
407 mFilters[filterId]->attachFilterToRecord(mDvrRecord);
408
409 return true;
410}
411
412bool Demux::detachRecordFilter(int64_t filterId) {
413 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
414 return false;
415 }
416
417 mRecordFilterIds.erase(filterId);
418 mFilters[filterId]->detachFilterFromRecord();
419
420 return true;
421}
422
423} // namespace tuner
424} // namespace tv
425} // namespace hardware
426} // namespace android
427} // namespace aidl