blob: 68e175c17d5b04acfd8f1c1d3d13de645351e4eb [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
132 std::lock_guard<std::mutex> lock(mDvrThreadLock);
133
Amy5ed13572019-12-11 15:33:51 -0800134 mIsRecordStarted = false;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700135 mDemux->setIsRecording(false);
Amy5ed13572019-12-11 15:33:51 -0800136
Amyb4b68012019-10-15 17:38:19 -0700137 return Result::SUCCESS;
138}
139
140Return<Result> Dvr::flush() {
141 ALOGV("%s", __FUNCTION__);
142
Amy5ed13572019-12-11 15:33:51 -0800143 mRecordStatus = RecordStatus::DATA_READY;
144
Amyb4b68012019-10-15 17:38:19 -0700145 return Result::SUCCESS;
146}
147
148Return<Result> Dvr::close() {
149 ALOGV("%s", __FUNCTION__);
150
151 return Result::SUCCESS;
152}
153
154bool 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()) {
Amy Zhang6e8163a2020-04-24 15:41:21 -0700161 ALOGW("[Dvr] Failed to create FMQ of DVR");
Amyb4b68012019-10-15 17:38:19 -0700162 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
Amy Zhang6bda6392020-05-26 19:00:46 -0700174EventFlag* Dvr::getDvrEventFlag() {
175 return mDvrEventFlag;
176}
177
Amyb4b68012019-10-15 17:38:19 -0700178void* Dvr::__threadLoopPlayback(void* user) {
179 Dvr* const self = static_cast<Dvr*>(user);
180 self->playbackThreadLoop();
181 return 0;
182}
183
184void 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
Amy Zhang6bda6392020-05-26 19:00:46 -0700200 if (!readPlaybackFMQ(false /*isVirtualFrontend*/, false /*isRecording*/) ||
201 !startFilterDispatcher(false /*isVirtualFrontend*/, false /*isRecording*/)) {
202 ALOGE("[Dvr] playback data failed to be filtered. Ending thread");
Amyb4b68012019-10-15 17:38:19 -0700203 break;
204 }
205
206 maySendPlaybackStatusCallback();
207 }
208
209 mDvrThreadRunning = false;
210 ALOGD("[Dvr] playback thread ended.");
211}
212
213void 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
227PlaybackStatus 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
Amy Zhang6bda6392020-05-26 19:00:46 -0700241bool Dvr::readPlaybackFMQ(bool isVirtualFrontend, bool isRecording) {
Amyb4b68012019-10-15 17:38:19 -0700242 // 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);
Amyb4b68012019-10-15 17:38:19 -0700247 // 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 }
Amy Zhang6bda6392020-05-26 19:00:46 -0700252 if (isVirtualFrontend) {
253 if (isRecording) {
254 mDemux->sendFrontendInputToRecord(dataOutputBuffer);
255 } else {
256 mDemux->startBroadcastTsFilter(dataOutputBuffer);
257 }
258 } else {
259 startTpidFilter(dataOutputBuffer);
260 }
Amyb4b68012019-10-15 17:38:19 -0700261 }
262
263 return true;
264}
265
266void 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
Amy Zhang6bda6392020-05-26 19:00:46 -0700279bool 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
Amyb4b68012019-10-15 17:38:19 -0700288 std::map<uint32_t, sp<IFilter>>::iterator it;
Amyb4b68012019-10-15 17:38:19 -0700289 // 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
Amy5ed13572019-12-11 15:33:51 -0800299bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
300 std::lock_guard<std::mutex> lock(mWriteLock);
Amy Zhang6e8163a2020-04-24 15:41:21 -0700301 if (mRecordStatus == RecordStatus::OVERFLOW) {
302 ALOGW("[Dvr] stops writing and wait for the client side flushing.");
303 return true;
304 }
Amy5ed13572019-12-11 15:33:51 -0800305 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
315void 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
329RecordStatus 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
Amy Zhang6bda6392020-05-26 19:00:46 -0700341bool Dvr::addPlaybackFilter(uint32_t filterId, sp<IFilter> filter) {
Amy Zhang6e8163a2020-04-24 15:41:21 -0700342 mFilters[filterId] = filter;
343 return true;
344}
345
Amy Zhang6bda6392020-05-26 19:00:46 -0700346bool Dvr::removePlaybackFilter(uint32_t filterId) {
347 mFilters.erase(filterId);
348 return true;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700349}
Amyb4b68012019-10-15 17:38:19 -0700350} // namespace implementation
351} // namespace V1_0
352} // namespace tuner
353} // namespace tv
354} // namespace hardware
355} // namespace android