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