blob: 3937c6ab25a0a0fc3cecf3f31b5b87b17093f780 [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>
Hongguange423acd2021-07-27 16:56:47 -070021#include <aidl/android/hardware/tv/tuner/Result.h>
Hongguang4092f2f2021-07-08 18:49:12 -070022
23#include <utils/Log.h>
24#include "Demux.h"
25
26namespace aidl {
27namespace android {
28namespace hardware {
29namespace tv {
30namespace tuner {
31
32#define WAIT_TIMEOUT 3000000000
33
Hongguang Chenff2c6b02021-08-07 00:12:26 +000034Demux::Demux(int32_t demuxId, std::shared_ptr<Tuner> tuner) {
Hongguang4092f2f2021-07-08 18:49:12 -070035 mDemuxId = demuxId;
Hongguange423acd2021-07-27 16:56:47 -070036 mTuner = tuner;
Hongguang4092f2f2021-07-08 18:49:12 -070037}
38
39Demux::~Demux() {
40 mFrontendInputThreadRunning = false;
41 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
42}
43
44::ndk::ScopedAStatus Demux::setFrontendDataSource(int32_t in_frontendId) {
45 ALOGV("%s", __FUNCTION__);
46
Hongguange423acd2021-07-27 16:56:47 -070047 if (mTuner == nullptr) {
48 return ::ndk::ScopedAStatus::fromServiceSpecificError(
49 static_cast<int32_t>(Result::NOT_INITIALIZED));
Hongguang4092f2f2021-07-08 18:49:12 -070050 }
51
Hongguange423acd2021-07-27 16:56:47 -070052 mFrontend = mTuner->getFrontendById(in_frontendId);
Hongguang4092f2f2021-07-08 18:49:12 -070053 if (mFrontend == nullptr) {
Hongguange423acd2021-07-27 16:56:47 -070054 return ::ndk::ScopedAStatus::fromServiceSpecificError(
55 static_cast<int32_t>(Result::INVALID_STATE));
Hongguang4092f2f2021-07-08 18:49:12 -070056 }
57
Hongguange423acd2021-07-27 16:56:47 -070058 mTuner->setFrontendAsDemuxSource(in_frontendId, mDemuxId);
Hongguang4092f2f2021-07-08 18:49:12 -070059
60 return ::ndk::ScopedAStatus::ok();
61}
62
63::ndk::ScopedAStatus Demux::openFilter(const DemuxFilterType& in_type, int32_t in_bufferSize,
64 const std::shared_ptr<IFilterCallback>& in_cb,
65 std::shared_ptr<IFilter>* _aidl_return) {
66 ALOGV("%s", __FUNCTION__);
67
68 int64_t filterId;
69 filterId = ++mLastUsedFilterId;
70
71 if (in_cb == nullptr) {
72 ALOGW("[Demux] callback can't be null");
73 *_aidl_return = nullptr;
Hongguange423acd2021-07-27 16:56:47 -070074 return ::ndk::ScopedAStatus::fromServiceSpecificError(
75 static_cast<int32_t>(Result::INVALID_ARGUMENT));
Hongguang4092f2f2021-07-08 18:49:12 -070076 }
77
Hongguang Chenff2c6b02021-08-07 00:12:26 +000078 std::shared_ptr<Filter> filter = ndk::SharedRefBase::make<Filter>(
79 in_type, filterId, in_bufferSize, in_cb, this->ref<Demux>());
Hongguang4092f2f2021-07-08 18:49:12 -070080 if (!filter->createFilterMQ()) {
81 *_aidl_return = nullptr;
Hongguange423acd2021-07-27 16:56:47 -070082 return ::ndk::ScopedAStatus::fromServiceSpecificError(
83 static_cast<int32_t>(Result::UNKNOWN_ERROR));
Hongguang4092f2f2021-07-08 18:49:12 -070084 }
85
86 mFilters[filterId] = filter;
87 if (filter->isPcrFilter()) {
88 mPcrFilterIds.insert(filterId);
89 }
90 bool result = true;
91 if (!filter->isRecordFilter()) {
92 // Only save non-record filters for now. Record filters are saved when the
93 // IDvr.attacheFilter is called.
94 mPlaybackFilterIds.insert(filterId);
95 if (mDvrPlayback != nullptr) {
96 result = mDvrPlayback->addPlaybackFilter(filterId, filter);
97 }
98 }
99
100 if (!result) {
101 *_aidl_return = nullptr;
Hongguange423acd2021-07-27 16:56:47 -0700102 return ::ndk::ScopedAStatus::fromServiceSpecificError(
103 static_cast<int32_t>(Result::INVALID_ARGUMENT));
Hongguang4092f2f2021-07-08 18:49:12 -0700104 }
105
106 *_aidl_return = filter;
107 return ::ndk::ScopedAStatus::ok();
108}
109
110::ndk::ScopedAStatus Demux::openTimeFilter(std::shared_ptr<ITimeFilter>* _aidl_return) {
111 ALOGV("%s", __FUNCTION__);
112
Hongguang Chenff2c6b02021-08-07 00:12:26 +0000113 mTimeFilter = ndk::SharedRefBase::make<TimeFilter>(this->ref<Demux>());
Hongguang4092f2f2021-07-08 18:49:12 -0700114
115 *_aidl_return = mTimeFilter;
116 return ::ndk::ScopedAStatus::ok();
117}
118
119::ndk::ScopedAStatus Demux::getAvSyncHwId(const std::shared_ptr<IFilter>& in_filter,
120 int32_t* _aidl_return) {
121 ALOGV("%s", __FUNCTION__);
122
123 int64_t id;
124 ::ndk::ScopedAStatus status;
125
126 status = in_filter->getId64Bit(&id);
127 if (!status.isOk()) {
128 ALOGE("[Demux] Can't get filter Id.");
129 *_aidl_return = -1;
Hongguange423acd2021-07-27 16:56:47 -0700130 return ::ndk::ScopedAStatus::fromServiceSpecificError(
131 static_cast<int32_t>(Result::INVALID_STATE));
Hongguang4092f2f2021-07-08 18:49:12 -0700132 }
133
134 if (!mFilters[id]->isMediaFilter()) {
135 ALOGE("[Demux] Given filter is not a media filter.");
136 *_aidl_return = -1;
Hongguange423acd2021-07-27 16:56:47 -0700137 return ::ndk::ScopedAStatus::fromServiceSpecificError(
138 static_cast<int32_t>(Result::INVALID_STATE));
Hongguang4092f2f2021-07-08 18:49:12 -0700139 }
140
141 if (!mPcrFilterIds.empty()) {
142 // Return the lowest pcr filter id in the default implementation as the av sync id
143 *_aidl_return = *mPcrFilterIds.begin();
144 return ::ndk::ScopedAStatus::ok();
145 }
146
147 ALOGE("[Demux] No PCR filter opened.");
148 *_aidl_return = -1;
Hongguange423acd2021-07-27 16:56:47 -0700149 return ::ndk::ScopedAStatus::fromServiceSpecificError(
150 static_cast<int32_t>(Result::INVALID_STATE));
Hongguang4092f2f2021-07-08 18:49:12 -0700151}
152
153::ndk::ScopedAStatus Demux::getAvSyncTime(int32_t in_avSyncHwId, int64_t* _aidl_return) {
154 ALOGV("%s", __FUNCTION__);
155
156 if (mPcrFilterIds.empty()) {
157 *_aidl_return = -1;
Hongguange423acd2021-07-27 16:56:47 -0700158 return ::ndk::ScopedAStatus::fromServiceSpecificError(
159 static_cast<int32_t>(Result::INVALID_STATE));
Hongguang4092f2f2021-07-08 18:49:12 -0700160 }
161 if (in_avSyncHwId != *mPcrFilterIds.begin()) {
162 *_aidl_return = -1;
Hongguange423acd2021-07-27 16:56:47 -0700163 return ::ndk::ScopedAStatus::fromServiceSpecificError(
164 static_cast<int32_t>(Result::INVALID_ARGUMENT));
Hongguang4092f2f2021-07-08 18:49:12 -0700165 }
166
167 *_aidl_return = -1;
168 return ::ndk::ScopedAStatus::ok();
169}
170
171::ndk::ScopedAStatus Demux::close() {
172 ALOGV("%s", __FUNCTION__);
173
174 set<int64_t>::iterator it;
175 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
176 mDvrPlayback->removePlaybackFilter(*it);
177 }
178 mPlaybackFilterIds.clear();
179 mRecordFilterIds.clear();
180 mFilters.clear();
181 mLastUsedFilterId = -1;
Hongguange423acd2021-07-27 16:56:47 -0700182 mTuner->removeDemux(mDemuxId);
Hongguang4092f2f2021-07-08 18:49:12 -0700183 mFrontendInputThreadRunning = false;
184 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
185
186 return ::ndk::ScopedAStatus::ok();
187}
188
189::ndk::ScopedAStatus Demux::openDvr(DvrType in_type, int32_t in_bufferSize,
190 const std::shared_ptr<IDvrCallback>& in_cb,
191 std::shared_ptr<IDvr>* _aidl_return) {
192 ALOGV("%s", __FUNCTION__);
193
194 if (in_cb == nullptr) {
195 ALOGW("[Demux] DVR callback can't be null");
196 *_aidl_return = nullptr;
Hongguange423acd2021-07-27 16:56:47 -0700197 return ::ndk::ScopedAStatus::fromServiceSpecificError(
198 static_cast<int32_t>(Result::INVALID_ARGUMENT));
Hongguang4092f2f2021-07-08 18:49:12 -0700199 }
200
201 set<int64_t>::iterator it;
202 switch (in_type) {
203 case DvrType::PLAYBACK:
Hongguang Chenff2c6b02021-08-07 00:12:26 +0000204 mDvrPlayback = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
205 this->ref<Demux>());
Hongguang4092f2f2021-07-08 18:49:12 -0700206 if (!mDvrPlayback->createDvrMQ()) {
207 mDvrPlayback = nullptr;
208 *_aidl_return = mDvrPlayback;
Hongguange423acd2021-07-27 16:56:47 -0700209 return ::ndk::ScopedAStatus::fromServiceSpecificError(
210 static_cast<int32_t>(Result::UNKNOWN_ERROR));
Hongguang4092f2f2021-07-08 18:49:12 -0700211 }
212
213 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
214 if (!mDvrPlayback->addPlaybackFilter(*it, mFilters[*it])) {
215 ALOGE("[Demux] Can't get filter info for DVR playback");
216 mDvrPlayback = nullptr;
217 *_aidl_return = mDvrPlayback;
Hongguange423acd2021-07-27 16:56:47 -0700218 return ::ndk::ScopedAStatus::fromServiceSpecificError(
219 static_cast<int32_t>(Result::UNKNOWN_ERROR));
Hongguang4092f2f2021-07-08 18:49:12 -0700220 }
221 }
222
223 *_aidl_return = mDvrPlayback;
224 return ::ndk::ScopedAStatus::ok();
225 case DvrType::RECORD:
Hongguang Chenff2c6b02021-08-07 00:12:26 +0000226 mDvrRecord = ndk::SharedRefBase::make<Dvr>(in_type, in_bufferSize, in_cb,
227 this->ref<Demux>());
Hongguang4092f2f2021-07-08 18:49:12 -0700228 if (!mDvrRecord->createDvrMQ()) {
229 mDvrRecord = nullptr;
230 *_aidl_return = mDvrRecord;
Hongguange423acd2021-07-27 16:56:47 -0700231 return ::ndk::ScopedAStatus::fromServiceSpecificError(
232 static_cast<int32_t>(Result::UNKNOWN_ERROR));
Hongguang4092f2f2021-07-08 18:49:12 -0700233 }
234
235 *_aidl_return = mDvrRecord;
236 return ::ndk::ScopedAStatus::ok();
237 default:
238 *_aidl_return = nullptr;
Hongguange423acd2021-07-27 16:56:47 -0700239 return ::ndk::ScopedAStatus::fromServiceSpecificError(
240 static_cast<int32_t>(Result::INVALID_ARGUMENT));
Hongguang4092f2f2021-07-08 18:49:12 -0700241 }
242}
243
244::ndk::ScopedAStatus Demux::connectCiCam(int32_t in_ciCamId) {
245 ALOGV("%s", __FUNCTION__);
246
247 mCiCamId = in_ciCamId;
248
249 return ::ndk::ScopedAStatus::ok();
250}
251
252::ndk::ScopedAStatus Demux::disconnectCiCam() {
253 ALOGV("%s", __FUNCTION__);
254
255 return ::ndk::ScopedAStatus::ok();
256}
257
258::ndk::ScopedAStatus Demux::removeFilter(int64_t filterId) {
259 ALOGV("%s", __FUNCTION__);
260
261 if (mDvrPlayback != nullptr) {
262 mDvrPlayback->removePlaybackFilter(filterId);
263 }
264 mPlaybackFilterIds.erase(filterId);
265 mRecordFilterIds.erase(filterId);
266 mFilters.erase(filterId);
267
268 return ::ndk::ScopedAStatus::ok();
269}
270
271void Demux::startBroadcastTsFilter(vector<int8_t> data) {
272 set<int64_t>::iterator it;
273 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
274 if (DEBUG_DEMUX) {
275 ALOGW("[Demux] start ts filter pid: %d", pid);
276 }
277 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
278 if (pid == mFilters[*it]->getTpid()) {
279 mFilters[*it]->updateFilterOutput(data);
280 }
281 }
282}
283
284void Demux::sendFrontendInputToRecord(vector<int8_t> data) {
285 set<int64_t>::iterator it;
286 if (DEBUG_DEMUX) {
287 ALOGW("[Demux] update record filter output");
288 }
289 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
290 mFilters[*it]->updateRecordOutput(data);
291 }
292}
293
294void Demux::sendFrontendInputToRecord(vector<int8_t> data, uint16_t pid, uint64_t pts) {
295 sendFrontendInputToRecord(data);
296 set<int64_t>::iterator it;
297 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
298 if (pid == mFilters[*it]->getTpid()) {
299 mFilters[*it]->updatePts(pts);
300 }
301 }
302}
303
304bool Demux::startBroadcastFilterDispatcher() {
305 set<int64_t>::iterator it;
306
307 // Handle the output data per filter type
308 for (it = mPlaybackFilterIds.begin(); it != mPlaybackFilterIds.end(); it++) {
309 if (!mFilters[*it]->startFilterHandler().isOk()) {
310 return false;
311 }
312 }
313
314 return true;
315}
316
317bool Demux::startRecordFilterDispatcher() {
318 set<int64_t>::iterator it;
319
320 for (it = mRecordFilterIds.begin(); it != mRecordFilterIds.end(); it++) {
321 if (!mFilters[*it]->startRecordFilterHandler().isOk()) {
322 return false;
323 }
324 }
325
326 return true;
327}
328
329::ndk::ScopedAStatus Demux::startFilterHandler(int64_t filterId) {
330 return mFilters[filterId]->startFilterHandler();
331}
332
333void Demux::updateFilterOutput(int64_t filterId, vector<int8_t> data) {
334 mFilters[filterId]->updateFilterOutput(data);
335}
336
337void Demux::updateMediaFilterOutput(int64_t filterId, vector<int8_t> data, uint64_t pts) {
338 updateFilterOutput(filterId, data);
339 mFilters[filterId]->updatePts(pts);
340}
341
342uint16_t Demux::getFilterTpid(int64_t filterId) {
343 return mFilters[filterId]->getTpid();
344}
345
346void Demux::startFrontendInputLoop() {
347 mFrontendInputThreadRunning = true;
348 pthread_create(&mFrontendInputThread, NULL, __threadLoopFrontend, this);
349 pthread_setname_np(mFrontendInputThread, "frontend_input_thread");
350}
351
352void* Demux::__threadLoopFrontend(void* user) {
353 Demux* const self = static_cast<Demux*>(user);
354 self->frontendInputThreadLoop();
355 return 0;
356}
357
358void Demux::frontendInputThreadLoop() {
359 if (!mFrontendInputThreadRunning) {
360 return;
361 }
362
363 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
364 if (!mDvrPlayback) {
365 ALOGW("[Demux] No software Frontend input configured. Ending Frontend thread loop.");
366 mFrontendInputThreadRunning = false;
367 return;
368 }
369
370 while (mFrontendInputThreadRunning) {
371 uint32_t efState = 0;
372 ::android::status_t status = mDvrPlayback->getDvrEventFlag()->wait(
373 static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
374 true /* retry on spurious wake */);
375 if (status != ::android::OK) {
376 ALOGD("[Demux] wait for data ready on the playback FMQ");
377 continue;
378 }
379 if (mDvrPlayback->getSettings().get<DvrSettings::Tag::playback>().dataFormat ==
380 DataFormat::ES) {
381 if (!mDvrPlayback->processEsDataOnPlayback(true /*isVirtualFrontend*/, mIsRecording)) {
382 ALOGE("[Demux] playback es data failed to be filtered. Ending thread");
383 break;
384 }
385 continue;
386 }
387 // Our current implementation filter the data and write it into the filter FMQ immediately
388 // after the DATA_READY from the VTS/framework
389 // This is for the non-ES data source, real playback use case handling.
390 if (!mDvrPlayback->readPlaybackFMQ(true /*isVirtualFrontend*/, mIsRecording) ||
391 !mDvrPlayback->startFilterDispatcher(true /*isVirtualFrontend*/, mIsRecording)) {
392 ALOGE("[Demux] playback data failed to be filtered. Ending thread");
393 break;
394 }
395 }
396
397 mFrontendInputThreadRunning = false;
398 ALOGW("[Demux] Frontend Input thread end.");
399}
400
401void Demux::stopFrontendInput() {
402 ALOGD("[Demux] stop frontend on demux");
403 mKeepFetchingDataFromFrontend = false;
404 mFrontendInputThreadRunning = false;
405 std::lock_guard<std::mutex> lock(mFrontendInputThreadLock);
406}
407
408void Demux::setIsRecording(bool isRecording) {
409 mIsRecording = isRecording;
410}
411
412bool Demux::isRecording() {
413 return mIsRecording;
414}
415
416bool Demux::attachRecordFilter(int64_t filterId) {
417 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr ||
418 !mFilters[filterId]->isRecordFilter()) {
419 return false;
420 }
421
422 mRecordFilterIds.insert(filterId);
423 mFilters[filterId]->attachFilterToRecord(mDvrRecord);
424
425 return true;
426}
427
428bool Demux::detachRecordFilter(int64_t filterId) {
429 if (mFilters[filterId] == nullptr || mDvrRecord == nullptr) {
430 return false;
431 }
432
433 mRecordFilterIds.erase(filterId);
434 mFilters[filterId]->detachFilterFromRecord();
435
436 return true;
437}
438
439} // namespace tuner
440} // namespace tv
441} // namespace hardware
442} // namespace android
443} // namespace aidl