blob: eb38f9040efd35b1572776223a9f9687fb91e77c [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
73 mFilters[filterId] = filter;
74
75 return Result::SUCCESS;
76}
77
78Return<Result> Dvr::detachFilter(const sp<IFilter>& filter) {
79 ALOGV("%s", __FUNCTION__);
80
81 uint32_t filterId;
82 Result status;
83
84 filter->getId([&](Result result, uint32_t id) {
85 filterId = id;
86 status = result;
87 });
88
89 if (status != Result::SUCCESS) {
90 return status;
91 }
92
93 std::map<uint32_t, sp<IFilter>>::iterator it;
94
95 it = mFilters.find(filterId);
96 if (it != mFilters.end()) {
97 mFilters.erase(filterId);
98 }
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) {
118 /*pthread_create(&mInputThread, NULL, __threadLoopInput, this);
119 pthread_setname_np(mInputThread, "playback_waiting_loop");*/
120 }
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
134 return Result::SUCCESS;
135}
136
137Return<Result> Dvr::flush() {
138 ALOGV("%s", __FUNCTION__);
139
140 return Result::SUCCESS;
141}
142
143Return<Result> Dvr::close() {
144 ALOGV("%s", __FUNCTION__);
145
146 return Result::SUCCESS;
147}
148
149bool Dvr::createDvrMQ() {
150 ALOGV("%s", __FUNCTION__);
151
152 // Create a synchronized FMQ that supports blocking read/write
153 std::unique_ptr<DvrMQ> tmpDvrMQ =
154 std::unique_ptr<DvrMQ>(new (std::nothrow) DvrMQ(mBufferSize, true));
155 if (!tmpDvrMQ->isValid()) {
156 ALOGW("Failed to create FMQ of DVR");
157 return false;
158 }
159
160 mDvrMQ = std::move(tmpDvrMQ);
161
162 if (EventFlag::createEventFlag(mDvrMQ->getEventFlagWord(), &mDvrEventFlag) != OK) {
163 return false;
164 }
165
166 return true;
167}
168
169void* Dvr::__threadLoopPlayback(void* user) {
170 Dvr* const self = static_cast<Dvr*>(user);
171 self->playbackThreadLoop();
172 return 0;
173}
174
175void Dvr::playbackThreadLoop() {
176 ALOGD("[Dvr] playback threadLoop start.");
177 std::lock_guard<std::mutex> lock(mDvrThreadLock);
178 mDvrThreadRunning = true;
179
180 while (mDvrThreadRunning) {
181 uint32_t efState = 0;
182 status_t status =
183 mDvrEventFlag->wait(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY),
184 &efState, WAIT_TIMEOUT, true /* retry on spurious wake */);
185 if (status != OK) {
186 ALOGD("[Dvr] wait for data ready on the playback FMQ");
187 continue;
188 }
189 // Our current implementation filter the data and write it into the filter FMQ immediately
190 // after the DATA_READY from the VTS/framework
191 if (!readPlaybackFMQ() || !startFilterDispatcher()) {
192 ALOGD("[Dvr] playback data failed to be filtered. Ending thread");
193 break;
194 }
195
196 maySendPlaybackStatusCallback();
197 }
198
199 mDvrThreadRunning = false;
200 ALOGD("[Dvr] playback thread ended.");
201}
202
203void Dvr::maySendPlaybackStatusCallback() {
204 std::lock_guard<std::mutex> lock(mPlaybackStatusLock);
205 int availableToRead = mDvrMQ->availableToRead();
206 int availableToWrite = mDvrMQ->availableToWrite();
207
208 PlaybackStatus newStatus = checkPlaybackStatusChange(availableToWrite, availableToRead,
209 mDvrSettings.playback().highThreshold,
210 mDvrSettings.playback().lowThreshold);
211 if (mPlaybackStatus != newStatus) {
212 mCallback->onPlaybackStatus(newStatus);
213 mPlaybackStatus = newStatus;
214 }
215}
216
217PlaybackStatus Dvr::checkPlaybackStatusChange(uint32_t availableToWrite, uint32_t availableToRead,
218 uint32_t highThreshold, uint32_t lowThreshold) {
219 if (availableToWrite == 0) {
220 return PlaybackStatus::SPACE_FULL;
221 } else if (availableToRead > highThreshold) {
222 return PlaybackStatus::SPACE_ALMOST_FULL;
223 } else if (availableToRead < lowThreshold) {
224 return PlaybackStatus::SPACE_ALMOST_EMPTY;
225 } else if (availableToRead == 0) {
226 return PlaybackStatus::SPACE_EMPTY;
227 }
228 return mPlaybackStatus;
229}
230
231bool Dvr::readPlaybackFMQ() {
232 // Read playback data from the input FMQ
233 int size = mDvrMQ->availableToRead();
234 int playbackPacketSize = mDvrSettings.playback().packetSize;
235 vector<uint8_t> dataOutputBuffer;
236 dataOutputBuffer.resize(playbackPacketSize);
237
238 // Dispatch the packet to the PID matching filter output buffer
239 for (int i = 0; i < size / playbackPacketSize; i++) {
240 if (!mDvrMQ->read(dataOutputBuffer.data(), playbackPacketSize)) {
241 return false;
242 }
243 startTpidFilter(dataOutputBuffer);
244 }
245
246 return true;
247}
248
249void Dvr::startTpidFilter(vector<uint8_t> data) {
250 std::map<uint32_t, sp<IFilter>>::iterator it;
251 for (it = mFilters.begin(); it != mFilters.end(); it++) {
252 uint16_t pid = ((data[1] & 0x1f) << 8) | ((data[2] & 0xff));
253 if (DEBUG_DVR) {
254 ALOGW("[Dvr] start ts filter pid: %d", pid);
255 }
256 if (pid == mDemux->getFilterTpid(it->first)) {
257 mDemux->updateFilterOutput(it->first, data);
258 }
259 }
260}
261
262bool Dvr::startFilterDispatcher() {
263 std::map<uint32_t, sp<IFilter>>::iterator it;
264
265 // Handle the output data per filter type
266 for (it = mFilters.begin(); it != mFilters.end(); it++) {
267 if (mDemux->startFilterHandler(it->first) != Result::SUCCESS) {
268 return false;
269 }
270 }
271
272 return true;
273}
274
275} // namespace implementation
276} // namespace V1_0
277} // namespace tuner
278} // namespace tv
279} // namespace hardware
280} // namespace android