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 "[email protected]"
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     std::lock_guard<std::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     std::unique_ptr<DvrMQ> tmpDvrMQ =
159             std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
160     if (!tmpDvrMQ->isValid()) {
161         ALOGW("[Dvr] Failed to create FMQ of DVR");
162         return false;
163     }
164 
165     mDvrMQ = std::move(tmpDvrMQ);
166 
167     if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
168         return false;
169     }
170 
171     return true;
172 }
173 
getDvrEventFlag()174 EventFlag* Dvr::getDvrEventFlag() {
175     return mDvrEventFlag;
176 }
177 
__threadLoopPlayback(void * user)178 void* Dvr::__threadLoopPlayback(void* user) {
179     Dvr* const self = static_cast<Dvr*>(user);
180     self->playbackThreadLoop();
181     return 0;
182 }
183 
playbackThreadLoop()184 void Dvr::playbackThreadLoop() {
185     ALOGD("[Dvr] playback threadLoop start.");
186     std::lock_guard<std::mutex> lock(mDvrThreadLock);
187     mDvrThreadRunning = true;
188 
189     while (mDvrThreadRunning) {
190         uint32_t efState = 0;
191         status_t status =
192                 mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
193                                     &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
194         if (status != OK) {
195             ALOGD("[Dvr] wait for data ready on the playback FMQ");
196             continue;
197         }
198         // Our current implementation filter the data and write it into the filter FMQ immediately
199         // after the DATA_READY from the VTS/framework
200         if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
201             !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
202             ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
203             break;
204         }
205 
206         maySendPlaybackStatusCallback();
207     }
208 
209     mDvrThreadRunning = false;
210     ALOGD("[Dvr] playback thread ended.");
211 }
212 
maySendPlaybackStatusCallback()213 void Dvr::maySendPlaybackStatusCallback() {
214     std::lock_guard<std::mutex> lock(mPlaybackStatusLock);
215     int availableToRead = mDvrMQ->availableToRead();
216     int availableToWrite = mDvrMQ->availableToWrite();
217 
218     PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
219                                                          mDvrSettings.playback().highThreshold,
220                                                          mDvrSettings.playback().lowThreshold);
221     if (mPlaybackStatus != newStatus) {
222         mCallback->onPlaybackStatus(newStatus);
223         mPlaybackStatus = newStatus;
224     }
225 }
226 
checkPlaybackStatusChange(uint32_t availableToWrite,uint32_t availableToRead,uint32_t highThreshold,uint32_t lowThreshold)227 PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
228                                               uint32_t highThreshold, uint32_t lowThreshold) {
229     if (availableToWrite == 0) {
230         return PlaybackStatus::SPACE_FULL;
231     } else if (availableToRead > highThreshold) {
232         return PlaybackStatus::SPACE_ALMOST_FULL;
233     } else if (availableToRead < lowThreshold) {
234         return PlaybackStatus::SPACE_ALMOST_EMPTY;
235     } else if (availableToRead == 0) {
236         return PlaybackStatus::SPACE_EMPTY;
237     }
238     return mPlaybackStatus;
239 }
240 
readPlaybackFMQ(bool isVirtualFrontend,bool isRecording)241 bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
242     // Read playback data from the input FMQ
243     int size = mDvrMQ->availableToRead();
244     int playbackPacketSize = mDvrSettings.playback().packetSize;
245     vector<uint8_t> dataOutputBuffer;
246     dataOutputBuffer.resize(playbackPacketSize);
247     // Dispatch the packet to the PID matching filter output buffer
248     for (int i = 0; i < size / playbackPacketSize; i++) {
249         if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
250             return false;
251         }
252         if (isVirtualFrontend) {
253             if (isRecording) {
254                 mDemux->sendFrontendInputToRecord(dataOutputBuffer);
255             } else {
256                 mDemux->startBroadcastTsFilter(dataOutputBuffer);
257             }
258         } else {
259             startTpidFilter(dataOutputBuffer);
260         }
261     }
262 
263     return true;
264 }
265 
startTpidFilter(vector<uint8_t> data)266 void Dvr::startTpidFilter(vector<uint8_t> data) {
267     std::map<uint32_t, sp<IFilter>>::iterator it;
268     for (it = mFilters.begin(); it != mFilters.end(); it++) {
269         uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
270         if (DEBUG_DVR) {
271             ALOGW("[Dvr] start ts filter pid: %d", pid);
272         }
273         if (pid == mDemux->getFilterTpid(it->first)) {
274             mDemux->updateFilterOutput(it->first, data);
275         }
276     }
277 }
278 
startFilterDispatcher(bool isVirtualFrontend,bool isRecording)279 bool Dvr::startFilterDispatcher(bool isVirtualFrontend, bool isRecording) {
280     if (isVirtualFrontend) {
281         if (isRecording) {
282             return mDemux->startRecordFilterDispatcher();
283         } else {
284             return mDemux->startBroadcastFilterDispatcher();
285         }
286     }
287 
288     std::map<uint32_t, sp<IFilter>>::iterator it;
289     // Handle the output data per filter type
290     for (it = mFilters.begin(); it != mFilters.end(); it++) {
291         if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
292             return false;
293         }
294     }
295 
296     return true;
297 }
298 
writeRecordFMQ(const std::vector<uint8_t> & data)299 bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
300     std::lock_guard<std::mutex> lock(mWriteLock);
301     if (mRecordStatus == RecordStatus::OVERFLOW) {
302         ALOGW("[Dvr] stops writing and wait for the client side flushing.");
303         return true;
304     }
305     if (mDvrMQ->write(data.data(), data.size())) {
306         mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
307         maySendRecordStatusCallback();
308         return true;
309     }
310 
311     maySendRecordStatusCallback();
312     return false;
313 }
314 
maySendRecordStatusCallback()315 void Dvr::maySendRecordStatusCallback() {
316     std::lock_guard<std::mutex> lock(mRecordStatusLock);
317     int availableToRead = mDvrMQ->availableToRead();
318     int availableToWrite = mDvrMQ->availableToWrite();
319 
320     RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
321                                                      mDvrSettings.record().highThreshold,
322                                                      mDvrSettings.record().lowThreshold);
323     if (mRecordStatus != newStatus) {
324         mCallback->onRecordStatus(newStatus);
325         mRecordStatus = newStatus;
326     }
327 }
328 
checkRecordStatusChange(uint32_t availableToWrite,uint32_t availableToRead,uint32_t highThreshold,uint32_t lowThreshold)329 RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
330                                           uint32_t highThreshold, uint32_t lowThreshold) {
331     if (availableToWrite == 0) {
332         return DemuxFilterStatus::OVERFLOW;
333     } else if (availableToRead > highThreshold) {
334         return DemuxFilterStatus::HIGH_WATER;
335     } else if (availableToRead < lowThreshold) {
336         return DemuxFilterStatus::LOW_WATER;
337     }
338     return mRecordStatus;
339 }
340 
addPlaybackFilter(uint32_t filterId,sp<IFilter> filter)341 bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) {
342     mFilters[filterId] = filter;
343     return true;
344 }
345 
removePlaybackFilter(uint32_t filterId)346 bool Dvr::removePlaybackFilter(uint32_t filterId) {
347     mFilters.erase(filterId);
348     return true;
349 }
350 }  // namespace implementation
351 }  // namespace V1_0
352 }  // namespace tuner
353 }  // namespace tv
354 }  // namespace hardware
355 }  // namespace android