blob: c62b8788919c6fe67bade8aaf6b1786ce0ded7a3 [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
40Dvr::~Dvr() {}
41
42Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
43 ALOGV("%s", __FUNCTION__);
44
45 _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
46 return Void();
47}
48
49Return<Result> Dvr::configure(const DvrSettings& settings) {
50 ALOGV("%s", __FUNCTION__);
51
52 mDvrSettings = settings;
53 mDvrConfigured = true;
54
55 return Result::SUCCESS;
56}
57
58Return<Result> Dvr::attachFilter(const sp<IFilter>& filter) {
59 ALOGV("%s", __FUNCTION__);
60
61 uint32_t filterId;
62 Result status;
63
64 filter->getId([&](Result result, uint32_t id) {
65 filterId = id;
66 status = result;
67 });
68
69 if (status != Result::SUCCESS) {
70 return status;
71 }
72
Amy Zhang6bda6392020-05-26 19:00:46 -070073 // TODO check if the attached filter is a record filter
Amy5ed13572019-12-11 15:33:51 -080074 if (!mDemux->attachRecordFilter(filterId)) {
75 return Result::INVALID_ARGUMENT;
76 }
Amyb4b68012019-10-15 17:38:19 -070077
78 return Result::SUCCESS;
79}
80
81Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) {
82 ALOGV("%s", __FUNCTION__);
83
84 uint32_t filterId;
85 Result status;
86
87 filter->getId([&](Result result, uint32_t id) {
88 filterId = id;
89 status = result;
90 });
91
92 if (status != Result::SUCCESS) {
93 return status;
94 }
95
Amy Zhang6bda6392020-05-26 19:00:46 -070096 if (!mDemux->detachRecordFilter(filterId)) {
97 return Result::INVALID_ARGUMENT;
Amyb4b68012019-10-15 17:38:19 -070098 }
99
100 return Result::SUCCESS;
101}
102
103Return<Result> Dvr::start() {
104 ALOGV("%s", __FUNCTION__);
105
106 if (!mCallback) {
107 return Result::NOT_INITIALIZED;
108 }
109
110 if (!mDvrConfigured) {
111 return Result::INVALID_STATE;
112 }
113
114 if (mType == DvrType::PLAYBACK) {
115 pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
116 pthread_setname_np(mDvrThread, "playback_waiting_loop");
117 } else if (mType == DvrType::RECORD) {
Amy5ed13572019-12-11 15:33:51 -0800118 mRecordStatus = RecordStatus::DATA_READY;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700119 mDemux->setIsRecording(mType == DvrType::RECORD);
Amyb4b68012019-10-15 17:38:19 -0700120 }
121
122 // TODO start another thread to send filter status callback to the framework
123
124 return Result::SUCCESS;
125}
126
127Return<Result> Dvr::stop() {
128 ALOGV("%s", __FUNCTION__);
129
130 mDvrThreadRunning = false;
131
Amy Zhang85a9ab32020-06-19 16:44:52 -0700132 lock_guard<mutex> lock(mDvrThreadLock);
Amyb4b68012019-10-15 17:38:19 -0700133
Amy Zhang6e8163a2020-04-24 15:41:21 -0700134 mDemux->setIsRecording(false);
Amy5ed13572019-12-11 15:33:51 -0800135
Amyb4b68012019-10-15 17:38:19 -0700136 return Result::SUCCESS;
137}
138
139Return<Result> Dvr::flush() {
140 ALOGV("%s", __FUNCTION__);
141
Amy5ed13572019-12-11 15:33:51 -0800142 mRecordStatus = RecordStatus::DATA_READY;
143
Amyb4b68012019-10-15 17:38:19 -0700144 return Result::SUCCESS;
145}
146
147Return<Result> Dvr::close() {
148 ALOGV("%s", __FUNCTION__);
149
150 return Result::SUCCESS;
151}
152
153bool Dvr::createDvrMQ() {
154 ALOGV("%s", __FUNCTION__);
155
156 // Create a synchronized FMQ that supports blocking read/write
Amy Zhang85a9ab32020-06-19 16:44:52 -0700157 unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
Amyb4b68012019-10-15 17:38:19 -0700158 if (!tmpDvrMQ->isValid()) {
Amy Zhang6e8163a2020-04-24 15:41:21 -0700159 ALOGW("[Dvr] Failed to create FMQ of DVR");
Amyb4b68012019-10-15 17:38:19 -0700160 return false;
161 }
162
Amy Zhang85a9ab32020-06-19 16:44:52 -0700163 mDvrMQ = move(tmpDvrMQ);
Amyb4b68012019-10-15 17:38:19 -0700164
165 if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
166 return false;
167 }
168
169 return true;
170}
171
Amy Zhang6bda6392020-05-26 19:00:46 -0700172EventFlag* Dvr::getDvrEventFlag() {
173 return mDvrEventFlag;
174}
175
Amyb4b68012019-10-15 17:38:19 -0700176void* Dvr::__threadLoopPlayback(void* user) {
177 Dvr* const self = static_cast<Dvr*>(user);
178 self->playbackThreadLoop();
179 return 0;
180}
181
182void Dvr::playbackThreadLoop() {
183 ALOGD("[Dvr] playback threadLoop start.");
Amy Zhang85a9ab32020-06-19 16:44:52 -0700184 lock_guard<mutex> lock(mDvrThreadLock);
Amyb4b68012019-10-15 17:38:19 -0700185 mDvrThreadRunning = true;
186
187 while (mDvrThreadRunning) {
188 uint32_t efState = 0;
189 status_t status =
190 mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
191 &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
192 if (status != OK) {
193 ALOGD("[Dvr] wait for data ready on the playback FMQ");
194 continue;
195 }
Amy Zhang85a9ab32020-06-19 16:44:52 -0700196
197 if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
198 if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
199 ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
200 break;
201 }
202 maySendPlaybackStatusCallback();
203 }
Amyb4b68012019-10-15 17:38:19 -0700204 // Our current implementation filter the data and write it into the filter FMQ immediately
205 // after the DATA_READY from the VTS/framework
Amy Zhang6bda6392020-05-26 19:00:46 -0700206 if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
207 !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
208 ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
Amyb4b68012019-10-15 17:38:19 -0700209 break;
210 }
211
212 maySendPlaybackStatusCallback();
213 }
214
215 mDvrThreadRunning = false;
216 ALOGD("[Dvr] playback thread ended.");
217}
218
219void Dvr::maySendPlaybackStatusCallback() {
Amy Zhang85a9ab32020-06-19 16:44:52 -0700220 lock_guard<mutex> lock(mPlaybackStatusLock);
Amyb4b68012019-10-15 17:38:19 -0700221 int availableToRead = mDvrMQ->availableToRead();
222 int availableToWrite = mDvrMQ->availableToWrite();
223
224 PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
225 mDvrSettings.playback().highThreshold,
226 mDvrSettings.playback().lowThreshold);
227 if (mPlaybackStatus != newStatus) {
228 mCallback->onPlaybackStatus(newStatus);
229 mPlaybackStatus = newStatus;
230 }
231}
232
233PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
234 uint32_t highThreshold, uint32_t lowThreshold) {
235 if (availableToWrite == 0) {
236 return PlaybackStatus::SPACE_FULL;
237 } else if (availableToRead > highThreshold) {
238 return PlaybackStatus::SPACE_ALMOST_FULL;
239 } else if (availableToRead < lowThreshold) {
240 return PlaybackStatus::SPACE_ALMOST_EMPTY;
241 } else if (availableToRead == 0) {
242 return PlaybackStatus::SPACE_EMPTY;
243 }
244 return mPlaybackStatus;
245}
246
Amy Zhang6bda6392020-05-26 19:00:46 -0700247bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
Amyb4b68012019-10-15 17:38:19 -0700248 // Read playback data from the input FMQ
249 int size = mDvrMQ->availableToRead();
250 int playbackPacketSize = mDvrSettings.playback().packetSize;
251 vector<uint8_t> dataOutputBuffer;
252 dataOutputBuffer.resize(playbackPacketSize);
Amyb4b68012019-10-15 17:38:19 -0700253 // Dispatch the packet to the PID matching filter output buffer
254 for (int i = 0; i < size / playbackPacketSize; i++) {
255 if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
256 return false;
257 }
Amy Zhang6bda6392020-05-26 19:00:46 -0700258 if (isVirtualFrontend) {
259 if (isRecording) {
260 mDemux->sendFrontendInputToRecord(dataOutputBuffer);
261 } else {
262 mDemux->startBroadcastTsFilter(dataOutputBuffer);
263 }
264 } else {
265 startTpidFilter(dataOutputBuffer);
266 }
Amyb4b68012019-10-15 17:38:19 -0700267 }
268
269 return true;
270}
271
Amy Zhang85a9ab32020-06-19 16:44:52 -0700272bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
273 // Read ES from the DVR FMQ
274 // Note that currently we only provides ES with metaData in a specific format to be parsed.
275 // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
276 int size = mDvrMQ->availableToRead();
277 vector<uint8_t> dataOutputBuffer;
278 dataOutputBuffer.resize(size);
279 if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
280 return false;
281 }
282
283 int metaDataSize = size;
284 int totalFrames = 0;
285 int videoEsDataSize = 0;
286 int audioEsDataSize = 0;
287 int audioPid = 0;
288 int videoPid = 0;
289
290 vector<MediaEsMetaData> esMeta;
291 int videoReadPointer = 0;
292 int audioReadPointer = 0;
293 int frameCount = 0;
294 // Get meta data from the es
295 for (int i = 0; i < metaDataSize; i++) {
296 switch (dataOutputBuffer[i]) {
297 case 'm':
298 metaDataSize = 0;
299 getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
300 videoReadPointer = metaDataSize;
301 continue;
302 case 'l':
303 getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
304 esMeta.resize(totalFrames);
305 continue;
306 case 'V':
307 getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
308 audioReadPointer = metaDataSize + videoEsDataSize;
309 continue;
310 case 'A':
311 getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
312 continue;
313 case 'p':
314 if (dataOutputBuffer[++i] == 'a') {
315 getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
316 } else if (dataOutputBuffer[i] == 'v') {
317 getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
318 }
319 continue;
320 case 'v':
321 case 'a':
322 if (dataOutputBuffer[i + 1] != ',') {
323 ALOGE("[Dvr] Invalid format meta data.");
324 return false;
325 }
326 esMeta[frameCount] = {
327 .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
328 };
329 i += 5; // Move to Len
330 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
331 if (esMeta[frameCount].isAudio) {
332 esMeta[frameCount].startIndex = audioReadPointer;
333 audioReadPointer += esMeta[frameCount].len;
334 } else {
335 esMeta[frameCount].startIndex = videoReadPointer;
336 videoReadPointer += esMeta[frameCount].len;
337 }
338 i += 4; // move to PTS
339 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
340 frameCount++;
341 continue;
342 default:
343 continue;
344 }
345 }
346
347 if (frameCount != totalFrames) {
348 ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
349 totalFrames);
350 return false;
351 }
352
353 if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
354 ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
355 metaDataSize, videoEsDataSize, audioEsDataSize, size);
356 return false;
357 }
358
359 // Read es raw data from the FMQ per meta data built previously
360 vector<uint8_t> frameData;
361 map<uint32_t, sp<IFilter>>::iterator it;
362 int pid = 0;
363 for (int i = 0; i < totalFrames; i++) {
364 frameData.resize(esMeta[i].len);
365 pid = esMeta[i].isAudio ? audioPid : videoPid;
shubang3e2de6c2020-07-20 19:26:36 -0700366 memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
Amy Zhang85a9ab32020-06-19 16:44:52 -0700367 // Send to the media filter
368 if (isVirtualFrontend && isRecording) {
369 // TODO validate record
370 mDemux->sendFrontendInputToRecord(frameData);
371 } else {
372 for (it = mFilters.begin(); it != mFilters.end(); it++) {
373 if (pid == mDemux->getFilterTpid(it->first)) {
374 mDemux->updateMediaFilterOutput(it->first, frameData,
375 static_cast<uint64_t>(esMeta[i].pts));
376 startFilterDispatcher(isVirtualFrontend, isRecording);
377 }
378 }
379 }
380 }
381
382 return true;
383}
384
385void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
386 index += 2; // Move the pointer across the ":" to the value
387 while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
388 value = ((dataOutputBuffer[index++] - 48) + value * 10);
389 }
390}
391
Amyb4b68012019-10-15 17:38:19 -0700392void Dvr::startTpidFilter(vector<uint8_t> data) {
Amy Zhang85a9ab32020-06-19 16:44:52 -0700393 map<uint32_t, sp<IFilter>>::iterator it;
Amyb4b68012019-10-15 17:38:19 -0700394 for (it = mFilters.begin(); it != mFilters.end(); it++) {
395 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
396 if (DEBUG_DVR) {
397 ALOGW("[Dvr] start ts filter pid: %d", pid);
398 }
399 if (pid == mDemux->getFilterTpid(it->first)) {
400 mDemux->updateFilterOutput(it->first, data);
401 }
402 }
403}
404
Amy Zhang6bda6392020-05-26 19:00:46 -0700405bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
406 if (isVirtualFrontend) {
407 if (isRecording) {
408 return mDemux->startRecordFilterDispatcher();
409 } else {
410 return mDemux->startBroadcastFilterDispatcher();
411 }
412 }
413
Amy Zhang85a9ab32020-06-19 16:44:52 -0700414 map<uint32_t, sp<IFilter>>::iterator it;
Amyb4b68012019-10-15 17:38:19 -0700415 // Handle the output data per filter type
416 for (it = mFilters.begin(); it != mFilters.end(); it++) {
417 if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
418 return false;
419 }
420 }
421
422 return true;
423}
424
Amy Zhang85a9ab32020-06-19 16:44:52 -0700425bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
426 lock_guard<mutex> lock(mWriteLock);
Amy Zhang6e8163a2020-04-24 15:41:21 -0700427 if (mRecordStatus == RecordStatus::OVERFLOW) {
428 ALOGW("[Dvr] stops writing and wait for the client side flushing.");
429 return true;
430 }
Amy5ed13572019-12-11 15:33:51 -0800431 if (mDvrMQ->write(data.data(), data.size())) {
432 mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
433 maySendRecordStatusCallback();
434 return true;
435 }
436
437 maySendRecordStatusCallback();
438 return false;
439}
440
441void Dvr::maySendRecordStatusCallback() {
Amy Zhang85a9ab32020-06-19 16:44:52 -0700442 lock_guard<mutex> lock(mRecordStatusLock);
Amy5ed13572019-12-11 15:33:51 -0800443 int availableToRead = mDvrMQ->availableToRead();
444 int availableToWrite = mDvrMQ->availableToWrite();
445
446 RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
447 mDvrSettings.record().highThreshold,
448 mDvrSettings.record().lowThreshold);
449 if (mRecordStatus != newStatus) {
450 mCallback->onRecordStatus(newStatus);
451 mRecordStatus = newStatus;
452 }
453}
454
455RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
456 uint32_t highThreshold, uint32_t lowThreshold) {
457 if (availableToWrite == 0) {
458 return DemuxFilterStatus::OVERFLOW;
459 } else if (availableToRead > highThreshold) {
460 return DemuxFilterStatus::HIGH_WATER;
461 } else if (availableToRead < lowThreshold) {
462 return DemuxFilterStatus::LOW_WATER;
463 }
464 return mRecordStatus;
465}
466
Amy Zhang6bda6392020-05-26 19:00:46 -0700467bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) {
Amy Zhang6e8163a2020-04-24 15:41:21 -0700468 mFilters[filterId] = filter;
469 return true;
470}
471
Amy Zhang6bda6392020-05-26 19:00:46 -0700472bool Dvr::removePlaybackFilter(uint32_t filterId) {
473 mFilters.erase(filterId);
474 return true;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700475}
Amyb4b68012019-10-15 17:38:19 -0700476} // namespace implementation
477} // namespace V1_0
478} // namespace tuner
479} // namespace tv
480} // namespace hardware
shubang3e2de6c2020-07-20 19:26:36 -0700481} // namespace android