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