1 /*
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
22 namespace android {
23 namespace hardware {
24 namespace tv {
25 namespace tuner {
26 namespace V1_0 {
27 namespace implementation {
28
29 #define WAIT_TIMEOUT 3000000000
30
Dvr()31 Dvr::Dvr() {}
32
Dvr(DvrType type,uint32_t bufferSize,const sp<IDvrCallback> & cb,sp<Demux> demux)33 Dvr::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
~Dvr()40 Dvr::~Dvr() {}
41
getQueueDesc(getQueueDesc_cb _hidl_cb)42 Return<void> Dvr::getQueueDesc(getQueueDesc_cb _hidl_cb) {
43 ALOGV("%s", __FUNCTION__);
44
45 _hidl_cb(Result::SUCCESS, *mDvrMQ->getDesc());
46 return Void();
47 }
48
configure(const DvrSettings & settings)49 Return<Result> Dvr::configure(const DvrSettings& settings) {
50 ALOGV("%s", __FUNCTION__);
51
52 mDvrSettings = settings;
53 mDvrConfigured = true;
54
55 return Result::SUCCESS;
56 }
57
attachFilter(const sp<IFilter> & filter)58 Return<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
73 // TODO check if the attached filter is a record filter
74 if (!mDemux->attachRecordFilter(filterId)) {
75 return Result::INVALID_ARGUMENT;
76 }
77
78 return Result::SUCCESS;
79 }
80
detachFilter(const sp<IFilter> & filter)81 Return<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
96 if (!mDemux->detachRecordFilter(filterId)) {
97 return Result::INVALID_ARGUMENT;
98 }
99
100 return Result::SUCCESS;
101 }
102
start()103 Return<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) {
118 mRecordStatus = RecordStatus::DATA_READY;
119 mDemux->setIsRecording(mType == DvrType::RECORD);
120 }
121
122 // TODO start another thread to send filter status callback to the framework
123
124 return Result::SUCCESS;
125 }
126
stop()127 Return<Result> Dvr::stop() {
128 ALOGV("%s", __FUNCTION__);
129
130 mDvrThreadRunning = false;
131
132 lock_guard<mutex> lock(mDvrThreadLock);
133
134 mIsRecordStarted = false;
135 mDemux->setIsRecording(false);
136
137 return Result::SUCCESS;
138 }
139
flush()140 Return<Result> Dvr::flush() {
141 ALOGV("%s", __FUNCTION__);
142
143 mRecordStatus = RecordStatus::DATA_READY;
144
145 return Result::SUCCESS;
146 }
147
close()148 Return<Result> Dvr::close() {
149 ALOGV("%s", __FUNCTION__);
150
151 return Result::SUCCESS;
152 }
153
createDvrMQ()154 bool Dvr::createDvrMQ() {
155 ALOGV("%s", __FUNCTION__);
156
157 // Create a synchronized FMQ that supports blocking read/write
158 unique_ptr<DvrMQ> tmpDvrMQ = unique_ptr<DvrMQ>(new (nothrow) DvrMQ(mBufferSize, true));
159 if (!tmpDvrMQ->isValid()) {
160 ALOGW("[Dvr] Failed to create FMQ of DVR");
161 return false;
162 }
163
164 mDvrMQ = move(tmpDvrMQ);
165
166 if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
167 return false;
168 }
169
170 return true;
171 }
172
getDvrEventFlag()173 EventFlag* Dvr::getDvrEventFlag() {
174 return mDvrEventFlag;
175 }
176
__threadLoopPlayback(void * user)177 void* Dvr::__threadLoopPlayback(void* user) {
178 Dvr* const self = static_cast<Dvr*>(user);
179 self->playbackThreadLoop();
180 return 0;
181 }
182
playbackThreadLoop()183 void Dvr::playbackThreadLoop() {
184 ALOGD("[Dvr] playback threadLoop start.");
185 lock_guard<mutex> lock(mDvrThreadLock);
186 mDvrThreadRunning = true;
187
188 while (mDvrThreadRunning) {
189 uint32_t efState = 0;
190 status_t status =
191 mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
192 &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
193 if (status != OK) {
194 ALOGD("[Dvr] wait for data ready on the playback FMQ");
195 continue;
196 }
197
198 if (mDvrSettings.playback().dataFormat == DataFormat::ES) {
199 if (!processEsDataOnPlayback(false /*isVirtualFrontend*/, false /*isRecording*/)) {
200 ALOGE("[Dvr] playback es data failed to be filtered. Ending thread");
201 break;
202 }
203 maySendPlaybackStatusCallback();
204 }
205 // Our current implementation filter the data and write it into the filter FMQ immediately
206 // after the DATA_READY from the VTS/framework
207 if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
208 !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
209 ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
210 break;
211 }
212
213 maySendPlaybackStatusCallback();
214 }
215
216 mDvrThreadRunning = false;
217 ALOGD("[Dvr] playback thread ended.");
218 }
219
maySendPlaybackStatusCallback()220 void Dvr::maySendPlaybackStatusCallback() {
221 lock_guard<mutex> lock(mPlaybackStatusLock);
222 int availableToRead = mDvrMQ->availableToRead();
223 int availableToWrite = mDvrMQ->availableToWrite();
224
225 PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
226 mDvrSettings.playback().highThreshold,
227 mDvrSettings.playback().lowThreshold);
228 if (mPlaybackStatus != newStatus) {
229 mCallback->onPlaybackStatus(newStatus);
230 mPlaybackStatus = newStatus;
231 }
232 }
233
checkPlaybackStatusChange(uint32_t availableToWrite,uint32_t availableToRead,uint32_t highThreshold,uint32_t lowThreshold)234 PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
235 uint32_t highThreshold, uint32_t lowThreshold) {
236 if (availableToWrite == 0) {
237 return PlaybackStatus::SPACE_FULL;
238 } else if (availableToRead > highThreshold) {
239 return PlaybackStatus::SPACE_ALMOST_FULL;
240 } else if (availableToRead < lowThreshold) {
241 return PlaybackStatus::SPACE_ALMOST_EMPTY;
242 } else if (availableToRead == 0) {
243 return PlaybackStatus::SPACE_EMPTY;
244 }
245 return mPlaybackStatus;
246 }
247
readPlaybackFMQ(bool isVirtualFrontend,bool isRecording)248 bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
249 // Read playback data from the input FMQ
250 int size = mDvrMQ->availableToRead();
251 int playbackPacketSize = mDvrSettings.playback().packetSize;
252 vector<uint8_t> dataOutputBuffer;
253 dataOutputBuffer.resize(playbackPacketSize);
254 // Dispatch the packet to the PID matching filter output buffer
255 for (int i = 0; i < size / playbackPacketSize; i++) {
256 if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
257 return false;
258 }
259 if (isVirtualFrontend) {
260 if (isRecording) {
261 mDemux->sendFrontendInputToRecord(dataOutputBuffer);
262 } else {
263 mDemux->startBroadcastTsFilter(dataOutputBuffer);
264 }
265 } else {
266 startTpidFilter(dataOutputBuffer);
267 }
268 }
269
270 return true;
271 }
272
processEsDataOnPlayback(bool isVirtualFrontend,bool isRecording)273 bool Dvr::processEsDataOnPlayback(bool isVirtualFrontend, bool isRecording) {
274 // Read ES from the DVR FMQ
275 // Note that currently we only provides ES with metaData in a specific format to be parsed.
276 // The ES size should be smaller than the Playback FMQ size to avoid reading truncated data.
277 int size = mDvrMQ->availableToRead();
278 vector<uint8_t> dataOutputBuffer;
279 dataOutputBuffer.resize(size);
280 if (!mDvrMQ->read(dataOutputBuffer.data(), size)) {
281 return false;
282 }
283
284 int metaDataSize = size;
285 int totalFrames = 0;
286 int videoEsDataSize = 0;
287 int audioEsDataSize = 0;
288 int audioPid = 0;
289 int videoPid = 0;
290
291 vector<MediaEsMetaData> esMeta;
292 int videoReadPointer = 0;
293 int audioReadPointer = 0;
294 int frameCount = 0;
295 // Get meta data from the es
296 for (int i = 0; i < metaDataSize; i++) {
297 switch (dataOutputBuffer[i]) {
298 case 'm':
299 metaDataSize = 0;
300 getMetaDataValue(i, dataOutputBuffer.data(), metaDataSize);
301 videoReadPointer = metaDataSize;
302 continue;
303 case 'l':
304 getMetaDataValue(i, dataOutputBuffer.data(), totalFrames);
305 esMeta.resize(totalFrames);
306 continue;
307 case 'V':
308 getMetaDataValue(i, dataOutputBuffer.data(), videoEsDataSize);
309 audioReadPointer = metaDataSize + videoEsDataSize;
310 continue;
311 case 'A':
312 getMetaDataValue(i, dataOutputBuffer.data(), audioEsDataSize);
313 continue;
314 case 'p':
315 if (dataOutputBuffer[++i] == 'a') {
316 getMetaDataValue(i, dataOutputBuffer.data(), audioPid);
317 } else if (dataOutputBuffer[i] == 'v') {
318 getMetaDataValue(i, dataOutputBuffer.data(), videoPid);
319 }
320 continue;
321 case 'v':
322 case 'a':
323 if (dataOutputBuffer[i + 1] != ',') {
324 ALOGE("[Dvr] Invalid format meta data.");
325 return false;
326 }
327 esMeta[frameCount] = {
328 .isAudio = dataOutputBuffer[i] == 'a' ? true : false,
329 };
330 i += 5; // Move to Len
331 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].len);
332 if (esMeta[frameCount].isAudio) {
333 esMeta[frameCount].startIndex = audioReadPointer;
334 audioReadPointer += esMeta[frameCount].len;
335 } else {
336 esMeta[frameCount].startIndex = videoReadPointer;
337 videoReadPointer += esMeta[frameCount].len;
338 }
339 i += 4; // move to PTS
340 getMetaDataValue(i, dataOutputBuffer.data(), esMeta[frameCount].pts);
341 frameCount++;
342 continue;
343 default:
344 continue;
345 }
346 }
347
348 if (frameCount != totalFrames) {
349 ALOGE("[Dvr] Invalid meta data, frameCount=%d, totalFrames reported=%d", frameCount,
350 totalFrames);
351 return false;
352 }
353
354 if (metaDataSize + audioEsDataSize + videoEsDataSize != size) {
355 ALOGE("[Dvr] Invalid meta data, metaSize=%d, videoSize=%d, audioSize=%d, totolSize=%d",
356 metaDataSize, videoEsDataSize, audioEsDataSize, size);
357 return false;
358 }
359
360 // Read es raw data from the FMQ per meta data built previously
361 vector<uint8_t> frameData;
362 map<uint32_t, sp<IFilter>>::iterator it;
363 int pid = 0;
364 for (int i = 0; i < totalFrames; i++) {
365 frameData.resize(esMeta[i].len);
366 pid = esMeta[i].isAudio ? audioPid : videoPid;
367 memcpy(frameData.data(), dataOutputBuffer.data() + esMeta[i].startIndex, esMeta[i].len);
368 // Send to the media filter
369 if (isVirtualFrontend && isRecording) {
370 // TODO validate record
371 mDemux->sendFrontendInputToRecord(frameData);
372 } else {
373 for (it = mFilters.begin(); it != mFilters.end(); it++) {
374 if (pid == mDemux->getFilterTpid(it->first)) {
375 mDemux->updateMediaFilterOutput(it->first, frameData,
376 static_cast<uint64_t>(esMeta[i].pts));
377 startFilterDispatcher(isVirtualFrontend, isRecording);
378 }
379 }
380 }
381 }
382
383 return true;
384 }
385
getMetaDataValue(int & index,uint8_t * dataOutputBuffer,int & value)386 void Dvr::getMetaDataValue(int& index, uint8_t* dataOutputBuffer, int& value) {
387 index += 2; // Move the pointer across the ":" to the value
388 while (dataOutputBuffer[index] != ',' && dataOutputBuffer[index] != '\n') {
389 value = ((dataOutputBuffer[index++] - 48) + value * 10);
390 }
391 }
392
startTpidFilter(vector<uint8_t> data)393 void Dvr::startTpidFilter(vector<uint8_t> data) {
394 map<uint32_t, sp<IFilter>>::iterator it;
395 for (it = mFilters.begin(); it != mFilters.end(); it++) {
396 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
397 if (DEBUG_DVR) {
398 ALOGW("[Dvr] start ts filter pid: %d", pid);
399 }
400 if (pid == mDemux->getFilterTpid(it->first)) {
401 mDemux->updateFilterOutput(it->first, data);
402 }
403 }
404 }
405
startFilterDispatcher(bool isVirtualFrontend,bool isRecording)406 bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
407 if (isVirtualFrontend) {
408 if (isRecording) {
409 return mDemux->startRecordFilterDispatcher();
410 } else {
411 return mDemux->startBroadcastFilterDispatcher();
412 }
413 }
414
415 map<uint32_t, sp<IFilter>>::iterator it;
416 // Handle the output data per filter type
417 for (it = mFilters.begin(); it != mFilters.end(); it++) {
418 if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
419 return false;
420 }
421 }
422
423 return true;
424 }
425
writeRecordFMQ(const vector<uint8_t> & data)426 bool Dvr::writeRecordFMQ(const vector<uint8_t>& data) {
427 lock_guard<mutex> lock(mWriteLock);
428 if (mRecordStatus == RecordStatus::OVERFLOW) {
429 ALOGW("[Dvr] stops writing and wait for the client side flushing.");
430 return true;
431 }
432 if (mDvrMQ->write(data.data(), data.size())) {
433 mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
434 maySendRecordStatusCallback();
435 return true;
436 }
437
438 maySendRecordStatusCallback();
439 return false;
440 }
441
maySendRecordStatusCallback()442 void Dvr::maySendRecordStatusCallback() {
443 lock_guard<mutex> lock(mRecordStatusLock);
444 int availableToRead = mDvrMQ->availableToRead();
445 int availableToWrite = mDvrMQ->availableToWrite();
446
447 RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
448 mDvrSettings.record().highThreshold,
449 mDvrSettings.record().lowThreshold);
450 if (mRecordStatus != newStatus) {
451 mCallback->onRecordStatus(newStatus);
452 mRecordStatus = newStatus;
453 }
454 }
455
checkRecordStatusChange(uint32_t availableToWrite,uint32_t availableToRead,uint32_t highThreshold,uint32_t lowThreshold)456 RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
457 uint32_t highThreshold, uint32_t lowThreshold) {
458 if (availableToWrite == 0) {
459 return DemuxFilterStatus::OVERFLOW;
460 } else if (availableToRead > highThreshold) {
461 return DemuxFilterStatus::HIGH_WATER;
462 } else if (availableToRead < lowThreshold) {
463 return DemuxFilterStatus::LOW_WATER;
464 }
465 return mRecordStatus;
466 }
467
addPlaybackFilter(uint32_t filterId,sp<IFilter> filter)468 bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) {
469 mFilters[filterId] = filter;
470 return true;
471 }
472
removePlaybackFilter(uint32_t filterId)473 bool Dvr::removePlaybackFilter(uint32_t filterId) {
474 mFilters.erase(filterId);
475 return true;
476 }
477 } // namespace implementation
478 } // namespace V1_0
479 } // namespace tuner
480 } // namespace tv
481 } // namespace hardware
482 } // namespace android
483