blob: 40879f2041ad8f4cabbd4960471ed37ce27c25e3 [file] [log] [blame]
Amyb4b68012019-10-15 17:38:19 -07001/*
2 * Copyright (C) 2019 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.0-Dvr"
18
19#include "Dvr.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
30
31Dvr::Dvr() {}
32
33Dvr::Dvr(DvrType type, uint32_t bufferSize, const sp<IDvrCallback>& cb, sp<Demux> demux) {
34 mType = type;
35 mBufferSize = bufferSize;
36 mCallback = cb;
37 mDemux = demux;
38}
39
Patrick Rohr45eff322021-07-23 14:56:53 +020040Dvr::~Dvr() {
41 // make sure thread has joined
42 close();
43}
Amyb4b68012019-10-15 17:38:19 -070044
45Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
46 ALOGV("%s", __FUNCTION__);
47
48 _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
49 return Void();
50}
51
52Return<Result> Dvr::configure(const DvrSettings& settings) {
53 ALOGV("%s", __FUNCTION__);
54
55 mDvrSettings = settings;
56 mDvrConfigured = true;
57
58 return Result::SUCCESS;
59}
60
61Return<Result> Dvr::attachFilter(const sp<IFilter>& filter) {
62 ALOGV("%s", __FUNCTION__);
63
64 uint32_t filterId;
65 Result status;
66
67 filter->getId([&](Result result, uint32_t id) {
68 filterId = id;
69 status = result;
70 });
71
72 if (status != Result::SUCCESS) {
73 return status;
74 }
75
Amy Zhang6bda6392020-05-26 19:00:46 -070076 // TODO check if the attached filter is a record filter
Amy5ed13572019-12-11 15:33:51 -080077 if (!mDemux->attachRecordFilter(filterId)) {
78 return Result::INVALID_ARGUMENT;
79 }
Amyb4b68012019-10-15 17:38:19 -070080
81 return Result::SUCCESS;
82}
83
84Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) {
85 ALOGV("%s", __FUNCTION__);
86
87 uint32_t filterId;
88 Result status;
89
90 filter->getId([&](Result result, uint32_t id) {
91 filterId = id;
92 status = result;
93 });
94
95 if (status != Result::SUCCESS) {
96 return status;
97 }
98
Amy Zhang6bda6392020-05-26 19:00:46 -070099 if (!mDemux->detachRecordFilter(filterId)) {
100 return Result::INVALID_ARGUMENT;
Amyb4b68012019-10-15 17:38:19 -0700101 }
102
103 return Result::SUCCESS;
104}
105
106Return<Result> Dvr::start() {
107 ALOGV("%s", __FUNCTION__);
108
109 if (!mCallback) {
110 return Result::NOT_INITIALIZED;
111 }
112
113 if (!mDvrConfigured) {
114 return Result::INVALID_STATE;
115 }
116
117 if (mType == DvrType::PLAYBACK) {
Patrick Rohr45eff322021-07-23 14:56:53 +0200118 mDvrThread = std::thread(&Dvr::playbackThreadLoop, this);
Amyb4b68012019-10-15 17:38:19 -0700119 } else if (mType == DvrType::RECORD) {
Amy5ed13572019-12-11 15:33:51 -0800120 mRecordStatus = RecordStatus::DATA_READY;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700121 mDemux->setIsRecording(mType == DvrType::RECORD);
Amyb4b68012019-10-15 17:38:19 -0700122 }
123
124 // TODO start another thread to send filter status callback to the framework
125
126 return Result::SUCCESS;
127}
128
129Return<Result> Dvr::stop() {
130 ALOGV("%s", __FUNCTION__);
131
132 mDvrThreadRunning = false;
Patrick Rohr45eff322021-07-23 14:56:53 +0200133 if (mDvrThread.joinable()) {
134 mDvrThread.join();
135 }
136 // thread should always be joinable if it is running,
137 // so it should be safe to assume recording stopped.
Amy Zhang6e8163a2020-04-24 15:41:21 -0700138 mDemux->setIsRecording(false);
Amy5ed13572019-12-11 15:33:51 -0800139
Amyb4b68012019-10-15 17:38:19 -0700140 return Result::SUCCESS;
141}
142
143Return<Result> Dvr::flush() {
144 ALOGV("%s", __FUNCTION__);
145
Amy5ed13572019-12-11 15:33:51 -0800146 mRecordStatus = RecordStatus::DATA_READY;
147
Amyb4b68012019-10-15 17:38:19 -0700148 return Result::SUCCESS;
149}
150
151Return<Result> Dvr::close() {
152 ALOGV("%s", __FUNCTION__);
Patrick Rohr45eff322021-07-23 14:56:53 +0200153 stop();
Amyb4b68012019-10-15 17:38:19 -0700154 return Result::SUCCESS;
155}
156
157bool Dvr::createDvrMQ() {
158 ALOGV("%s", __FUNCTION__);
159
160 // Create a synchronized FMQ that supports blocking read/write
Amy Zhang85a9ab32020-06-19 16:44:52 -0700161 unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
Amyb4b68012019-10-15 17:38:19 -0700162 if (!tmpDvrMQ->isValid()) {
Amy Zhang6e8163a2020-04-24 15:41:21 -0700163 ALOGW("[Dvr] Failed to create FMQ of DVR");
Amyb4b68012019-10-15 17:38:19 -0700164 return false;
165 }
166
Amy Zhang85a9ab32020-06-19 16:44:52 -0700167 mDvrMQ = move(tmpDvrMQ);
Amyb4b68012019-10-15 17:38:19 -0700168
169 if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
170 return false;
171 }
172
173 return true;
174}
175
Amy Zhang6bda6392020-05-26 19:00:46 -0700176EventFlag* Dvr::getDvrEventFlag() {
177 return mDvrEventFlag;
178}
179
Amyb4b68012019-10-15 17:38:19 -0700180void Dvr::playbackThreadLoop() {
181 ALOGD("[Dvr] playback threadLoop start.");
Amyb4b68012019-10-15 17:38:19 -0700182 mDvrThreadRunning = true;
183
184 while (mDvrThreadRunning) {
185 uint32_t efState = 0;
186 status_t status =
187 mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
188 &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
189 if (status != OK) {
190 ALOGD("[Dvr] wait for data ready on the playback FMQ");
191 continue;
192 }
Amy Zhang85a9ab32020-06-19 16:44:52 -0700193
194 if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
195 if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
196 ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
197 break;
198 }
199 maySendPlaybackStatusCallback();
200 }
Amyb4b68012019-10-15 17:38:19 -0700201 // Our current implementation filter the data and write it into the filter FMQ immediately
202 // after the DATA_READY from the VTS/framework
Amy Zhang6bda6392020-05-26 19:00:46 -0700203 if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
204 !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
205 ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
Amyb4b68012019-10-15 17:38:19 -0700206 break;
207 }
208
209 maySendPlaybackStatusCallback();
210 }
211
212 mDvrThreadRunning = false;
213 ALOGD("[Dvr] playback thread ended.");
214}
215
216void Dvr::maySendPlaybackStatusCallback() {
Amy Zhang85a9ab32020-06-19 16:44:52 -0700217 lock_guard<mutex> lock(mPlaybackStatusLock);
Amyb4b68012019-10-15 17:38:19 -0700218 int availableToRead = mDvrMQ->availableToRead();
219 int availableToWrite = mDvrMQ->availableToWrite();
220
221 PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
222 mDvrSettings.playback().highThreshold,
223 mDvrSettings.playback().lowThreshold);
224 if (mPlaybackStatus != newStatus) {
225 mCallback->onPlaybackStatus(newStatus);
226 mPlaybackStatus = newStatus;
227 }
228}
229
230PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
231 uint32_t highThreshold, uint32_t lowThreshold) {
232 if (availableToWrite == 0) {
233 return PlaybackStatus::SPACE_FULL;
234 } else if (availableToRead > highThreshold) {
235 return PlaybackStatus::SPACE_ALMOST_FULL;
236 } else if (availableToRead < lowThreshold) {
237 return PlaybackStatus::SPACE_ALMOST_EMPTY;
238 } else if (availableToRead == 0) {
239 return PlaybackStatus::SPACE_EMPTY;
240 }
241 return mPlaybackStatus;
242}
243
Amy Zhang6bda6392020-05-26 19:00:46 -0700244bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
Amyb4b68012019-10-15 17:38:19 -0700245 // Read playback data from the input FMQ
246 int size = mDvrMQ->availableToRead();
247 int playbackPacketSize = mDvrSettings.playback().packetSize;
248 vector<uint8_t> dataOutputBuffer;
249 dataOutputBuffer.resize(playbackPacketSize);
Amyb4b68012019-10-15 17:38:19 -0700250 // Dispatch the packet to the PID matching filter output buffer
251 for (int i = 0; i < size / playbackPacketSize; i++) {
252 if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
253 return false;
254 }
Amy Zhang6bda6392020-05-26 19:00:46 -0700255 if (isVirtualFrontend) {
256 if (isRecording) {
257 mDemux->sendFrontendInputToRecord(dataOutputBuffer);
258 } else {
259 mDemux->startBroadcastTsFilter(dataOutputBuffer);
260 }
261 } else {
262 startTpidFilter(dataOutputBuffer);
263 }
Amyb4b68012019-10-15 17:38:19 -0700264 }
265
266 return true;
267}
268
Amy Zhang85a9ab32020-06-19 16:44:52 -0700269bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
270 // Read ES from the DVR FMQ
271 // Note that currently we only provides ES with metaData in a specific format to be parsed.
272 // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
273 int size = mDvrMQ->availableToRead();
274 vector<uint8_t> dataOutputBuffer;
275 dataOutputBuffer.resize(size);
276 if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
277 return false;
278 }
279
280 int metaDataSize = size;
281 int totalFrames = 0;
282 int videoEsDataSize = 0;
283 int audioEsDataSize = 0;
284 int audioPid = 0;
285 int videoPid = 0;
286
287 vector<MediaEsMetaData> esMeta;
288 int videoReadPointer = 0;
289 int audioReadPointer = 0;
290 int frameCount = 0;
291 // Get meta data from the es
292 for (int i = 0; i < metaDataSize; i++) {
293 switch (dataOutputBuffer[i]) {
294 case 'm':
295 metaDataSize = 0;
296 getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
297 videoReadPointer = metaDataSize;
298 continue;
299 case 'l':
300 getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
301 esMeta.resize(totalFrames);
302 continue;
303 case 'V':
304 getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
305 audioReadPointer = metaDataSize + videoEsDataSize;
306 continue;
307 case 'A':
308 getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
309 continue;
310 case 'p':
311 if (dataOutputBuffer[++i] == 'a') {
312 getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
313 } else if (dataOutputBuffer[i] == 'v') {
314 getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
315 }
316 continue;
317 case 'v':
318 case 'a':
319 if (dataOutputBuffer[i + 1] != ',') {
320 ALOGE("[Dvr] Invalid format meta data.");
321 return false;
322 }
323 esMeta[frameCount] = {
324 .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
325 };
326 i += 5; // Move to Len
327 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
328 if (esMeta[frameCount].isAudio) {
329 esMeta[frameCount].startIndex = audioReadPointer;
330 audioReadPointer += esMeta[frameCount].len;
331 } else {
332 esMeta[frameCount].startIndex = videoReadPointer;
333 videoReadPointer += esMeta[frameCount].len;
334 }
335 i += 4; // move to PTS
336 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
337 frameCount++;
338 continue;
339 default:
340 continue;
341 }
342 }
343
344 if (frameCount != totalFrames) {
345 ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
346 totalFrames);
347 return false;
348 }
349
350 if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
351 ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
352 metaDataSize, videoEsDataSize, audioEsDataSize, size);
353 return false;
354 }
355
356 // Read es raw data from the FMQ per meta data built previously
357 vector<uint8_t> frameData;
358 map<uint32_t, sp<IFilter>>::iterator it;
359 int pid = 0;
360 for (int i = 0; i < totalFrames; i++) {
361 frameData.resize(esMeta[i].len);
362 pid = esMeta[i].isAudio ? audioPid : videoPid;
shubang3e2de6c2020-07-20 19:26:36 -0700363 memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
Amy Zhang85a9ab32020-06-19 16:44:52 -0700364 // Send to the media filter
365 if (isVirtualFrontend && isRecording) {
366 // TODO validate record
367 mDemux->sendFrontendInputToRecord(frameData);
368 } else {
369 for (it = mFilters.begin(); it != mFilters.end(); it++) {
370 if (pid == mDemux->getFilterTpid(it->first)) {
371 mDemux->updateMediaFilterOutput(it->first, frameData,
372 static_cast<uint64_t>(esMeta[i].pts));
373 startFilterDispatcher(isVirtualFrontend, isRecording);
374 }
375 }
376 }
377 }
378
379 return true;
380}
381
382void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
383 index += 2; // Move the pointer across the ":" to the value
384 while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
385 value = ((dataOutputBuffer[index++] - 48) + value * 10);
386 }
387}
388
Amyb4b68012019-10-15 17:38:19 -0700389void Dvr::startTpidFilter(vector<uint8_t> data) {
Amy Zhang85a9ab32020-06-19 16:44:52 -0700390 map<uint32_t, sp<IFilter>>::iterator it;
Amyb4b68012019-10-15 17:38:19 -0700391 for (it = mFilters.begin(); it != mFilters.end(); it++) {
392 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
393 if (DEBUG_DVR) {
394 ALOGW("[Dvr] start ts filter pid: %d", pid);
395 }
396 if (pid == mDemux->getFilterTpid(it->first)) {
397 mDemux->updateFilterOutput(it->first, data);
398 }
399 }
400}
401
Amy Zhang6bda6392020-05-26 19:00:46 -0700402bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
403 if (isVirtualFrontend) {
404 if (isRecording) {
405 return mDemux->startRecordFilterDispatcher();
406 } else {
407 return mDemux->startBroadcastFilterDispatcher();
408 }
409 }
410
Amy Zhang85a9ab32020-06-19 16:44:52 -0700411 map<uint32_t, sp<IFilter>>::iterator it;
Amyb4b68012019-10-15 17:38:19 -0700412 // Handle the output data per filter type
413 for (it = mFilters.begin(); it != mFilters.end(); it++) {
414 if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
415 return false;
416 }
417 }
418
419 return true;
420}
421
Amy Zhang85a9ab32020-06-19 16:44:52 -0700422bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
423 lock_guard<mutex> lock(mWriteLock);
Amy Zhang6e8163a2020-04-24 15:41:21 -0700424 if (mRecordStatus == RecordStatus::OVERFLOW) {
425 ALOGW("[Dvr] stops writing and wait for the client side flushing.");
426 return true;
427 }
Amy5ed13572019-12-11 15:33:51 -0800428 if (mDvrMQ->write(data.data(), data.size())) {
429 mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
430 maySendRecordStatusCallback();
431 return true;
432 }
433
434 maySendRecordStatusCallback();
435 return false;
436}
437
438void Dvr::maySendRecordStatusCallback() {
Amy Zhang85a9ab32020-06-19 16:44:52 -0700439 lock_guard<mutex> lock(mRecordStatusLock);
Amy5ed13572019-12-11 15:33:51 -0800440 int availableToRead = mDvrMQ->availableToRead();
441 int availableToWrite = mDvrMQ->availableToWrite();
442
443 RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
444 mDvrSettings.record().highThreshold,
445 mDvrSettings.record().lowThreshold);
446 if (mRecordStatus != newStatus) {
447 mCallback->onRecordStatus(newStatus);
448 mRecordStatus = newStatus;
449 }
450}
451
452RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
453 uint32_t highThreshold, uint32_t lowThreshold) {
454 if (availableToWrite == 0) {
455 return DemuxFilterStatus::OVERFLOW;
456 } else if (availableToRead > highThreshold) {
457 return DemuxFilterStatus::HIGH_WATER;
458 } else if (availableToRead < lowThreshold) {
459 return DemuxFilterStatus::LOW_WATER;
460 }
461 return mRecordStatus;
462}
463
Amy Zhang6bda6392020-05-26 19:00:46 -0700464bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) {
Amy Zhang6e8163a2020-04-24 15:41:21 -0700465 mFilters[filterId] = filter;
466 return true;
467}
468
Amy Zhang6bda6392020-05-26 19:00:46 -0700469bool Dvr::removePlaybackFilter(uint32_t filterId) {
470 mFilters.erase(filterId);
471 return true;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700472}
Amyb4b68012019-10-15 17:38:19 -0700473} // namespace implementation
474} // namespace V1_0
475} // namespace tuner
476} // namespace tv
477} // namespace hardware
shubang3e2de6c2020-07-20 19:26:36 -0700478} // namespace android