blob: adb263553eaf105b6dd1ed7a4b6563065583efd0 [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
Amy5ed13572019-12-11 15:33:51 -080073 // check if the attached filter is a record filter
Amyb4b68012019-10-15 17:38:19 -070074 mFilters[filterId] = filter;
Amy5ed13572019-12-11 15:33:51 -080075 if (!mDemux->attachRecordFilter(filterId)) {
76 return Result::INVALID_ARGUMENT;
77 }
Amyb4b68012019-10-15 17:38:19 -070078
79 return Result::SUCCESS;
80}
81
82Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) {
83 ALOGV("%s", __FUNCTION__);
84
85 uint32_t filterId;
86 Result status;
87
88 filter->getId([&](Result result, uint32_t id) {
89 filterId = id;
90 status = result;
91 });
92
93 if (status != Result::SUCCESS) {
94 return status;
95 }
96
97 std::map<uint32_t, sp<IFilter>>::iterator it;
98
99 it = mFilters.find(filterId);
100 if (it != mFilters.end()) {
101 mFilters.erase(filterId);
Amy5ed13572019-12-11 15:33:51 -0800102 if (!mDemux->detachRecordFilter(filterId)) {
103 return Result::INVALID_ARGUMENT;
104 }
105 }
106
107 // If all the filters are detached, record can't be started
108 if (mFilters.empty()) {
109 mIsRecordFilterAttached = false;
Amyb4b68012019-10-15 17:38:19 -0700110 }
111
112 return Result::SUCCESS;
113}
114
115Return<Result> Dvr::start() {
116 ALOGV("%s", __FUNCTION__);
117
118 if (!mCallback) {
119 return Result::NOT_INITIALIZED;
120 }
121
122 if (!mDvrConfigured) {
123 return Result::INVALID_STATE;
124 }
125
126 if (mType == DvrType::PLAYBACK) {
127 pthread_create(&mDvrThread, NULL, __threadLoopPlayback, this);
128 pthread_setname_np(mDvrThread, "playback_waiting_loop");
129 } else if (mType == DvrType::RECORD) {
Amy5ed13572019-12-11 15:33:51 -0800130 mRecordStatus = RecordStatus::DATA_READY;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700131 mDemux->setIsRecording(mType == DvrType::RECORD);
Amyb4b68012019-10-15 17:38:19 -0700132 }
133
134 // TODO start another thread to send filter status callback to the framework
135
136 return Result::SUCCESS;
137}
138
139Return<Result> Dvr::stop() {
140 ALOGV("%s", __FUNCTION__);
141
142 mDvrThreadRunning = false;
143
144 std::lock_guard<std::mutex> lock(mDvrThreadLock);
145
Amy5ed13572019-12-11 15:33:51 -0800146 mIsRecordStarted = false;
Amy Zhang6e8163a2020-04-24 15:41:21 -0700147 mDemux->setIsRecording(false);
Amy5ed13572019-12-11 15:33:51 -0800148
Amyb4b68012019-10-15 17:38:19 -0700149 return Result::SUCCESS;
150}
151
152Return<Result> Dvr::flush() {
153 ALOGV("%s", __FUNCTION__);
154
Amy5ed13572019-12-11 15:33:51 -0800155 mRecordStatus = RecordStatus::DATA_READY;
156
Amyb4b68012019-10-15 17:38:19 -0700157 return Result::SUCCESS;
158}
159
160Return<Result> Dvr::close() {
161 ALOGV("%s", __FUNCTION__);
162
163 return Result::SUCCESS;
164}
165
166bool Dvr::createDvrMQ() {
167 ALOGV("%s", __FUNCTION__);
168
169 // Create a synchronized FMQ that supports blocking read/write
170 std::unique_ptr<DvrMQ> tmpDvrMQ =
171 std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
172 if (!tmpDvrMQ->isValid()) {
Amy Zhang6e8163a2020-04-24 15:41:21 -0700173 ALOGW("[Dvr] Failed to create FMQ of DVR");
Amyb4b68012019-10-15 17:38:19 -0700174 return false;
175 }
176
177 mDvrMQ = std::move(tmpDvrMQ);
178
179 if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
180 return false;
181 }
182
183 return true;
184}
185
186void* Dvr::__threadLoopPlayback(void* user) {
187 Dvr* const self = static_cast<Dvr*>(user);
188 self->playbackThreadLoop();
189 return 0;
190}
191
192void Dvr::playbackThreadLoop() {
193 ALOGD("[Dvr] playback threadLoop start.");
194 std::lock_guard<std::mutex> lock(mDvrThreadLock);
195 mDvrThreadRunning = true;
196
197 while (mDvrThreadRunning) {
198 uint32_t efState = 0;
199 status_t status =
200 mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
201 &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
202 if (status != OK) {
203 ALOGD("[Dvr] wait for data ready on the playback FMQ");
204 continue;
205 }
206 // Our current implementation filter the data and write it into the filter FMQ immediately
207 // after the DATA_READY from the VTS/framework
208 if (!readPlaybackFMQ() || !startFilterDispatcher()) {
209 ALOGD("[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
220void Dvr::maySendPlaybackStatusCallback() {
221 std::lock_guard<std::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
234PlaybackStatus 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
248bool Dvr::readPlaybackFMQ() {
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);
Amyb4b68012019-10-15 17:38:19 -0700254 // 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 startTpidFilter(dataOutputBuffer);
260 }
261
262 return true;
263}
264
265void Dvr::startTpidFilter(vector<uint8_t> data) {
266 std::map<uint32_t, sp<IFilter>>::iterator it;
267 for (it = mFilters.begin(); it != mFilters.end(); it++) {
268 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
269 if (DEBUG_DVR) {
270 ALOGW("[Dvr] start ts filter pid: %d", pid);
271 }
272 if (pid == mDemux->getFilterTpid(it->first)) {
273 mDemux->updateFilterOutput(it->first, data);
274 }
275 }
276}
277
278bool Dvr::startFilterDispatcher() {
279 std::map<uint32_t, sp<IFilter>>::iterator it;
Amyb4b68012019-10-15 17:38:19 -0700280 // Handle the output data per filter type
281 for (it = mFilters.begin(); it != mFilters.end(); it++) {
282 if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
283 return false;
284 }
285 }
286
287 return true;
288}
289
Amy5ed13572019-12-11 15:33:51 -0800290bool Dvr::writeRecordFMQ(const std::vector<uint8_t>& data) {
291 std::lock_guard<std::mutex> lock(mWriteLock);
Amy Zhang6e8163a2020-04-24 15:41:21 -0700292 if (mRecordStatus == RecordStatus::OVERFLOW) {
293 ALOGW("[Dvr] stops writing and wait for the client side flushing.");
294 return true;
295 }
Amy5ed13572019-12-11 15:33:51 -0800296 if (mDvrMQ->write(data.data(), data.size())) {
297 mDvrEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
298 maySendRecordStatusCallback();
299 return true;
300 }
301
302 maySendRecordStatusCallback();
303 return false;
304}
305
306void Dvr::maySendRecordStatusCallback() {
307 std::lock_guard<std::mutex> lock(mRecordStatusLock);
308 int availableToRead = mDvrMQ->availableToRead();
309 int availableToWrite = mDvrMQ->availableToWrite();
310
311 RecordStatus newStatus = checkRecordStatusChange(availableToWrite, availableToRead,
312 mDvrSettings.record().highThreshold,
313 mDvrSettings.record().lowThreshold);
314 if (mRecordStatus != newStatus) {
315 mCallback->onRecordStatus(newStatus);
316 mRecordStatus = newStatus;
317 }
318}
319
320RecordStatus Dvr::checkRecordStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
321 uint32_t highThreshold, uint32_t lowThreshold) {
322 if (availableToWrite == 0) {
323 return DemuxFilterStatus::OVERFLOW;
324 } else if (availableToRead > highThreshold) {
325 return DemuxFilterStatus::HIGH_WATER;
326 } else if (availableToRead < lowThreshold) {
327 return DemuxFilterStatus::LOW_WATER;
328 }
329 return mRecordStatus;
330}
331
Amy Zhang6e8163a2020-04-24 15:41:21 -0700332bool Dvr::addPlaybackFilter(sp<IFilter> filter) {
333 uint32_t filterId;
334 Result status;
335
336 filter->getId([&](Result result, uint32_t id) {
337 filterId = id;
338 status = result;
339 });
340
341 if (status != Result::SUCCESS) {
342 return false;
343 }
344
345 mFilters[filterId] = filter;
346 return true;
347}
348
349DvrType Dvr::getType() {
350 return mType;
351}
352
Amyb4b68012019-10-15 17:38:19 -0700353} // namespace implementation
354} // namespace V1_0
355} // namespace tuner
356} // namespace tv
357} // namespace hardware
358} // namespace android