1 /*
2 * Copyright 2021 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 #include "DvrTests.h"
18
19 #include <aidl/android/hardware/tv/tuner/DemuxQueueNotifyBits.h>
20
startPlaybackInputThread(string & dataInputFile,PlaybackSettings & settings,MQDesc & playbackMQDescriptor)21 void DvrCallback::startPlaybackInputThread(string& dataInputFile, PlaybackSettings& settings,
22 MQDesc& playbackMQDescriptor) {
23 mInputDataFile = dataInputFile;
24 mPlaybackSettings = settings;
25 mPlaybackMQ = std::make_unique<FilterMQ>(playbackMQDescriptor, true /* resetPointers */);
26 EXPECT_TRUE(mPlaybackMQ);
27
28 mPlaybackThread = std::thread(&DvrCallback::playbackThreadLoop, this);
29 }
30
stopPlaybackThread()31 void DvrCallback::stopPlaybackThread() {
32 mPlaybackThreadRunning = false;
33 mKeepWritingPlaybackFMQ = false;
34
35 if (mPlaybackThread.joinable()) {
36 mPlaybackThread.join();
37 }
38 }
39
playbackThreadLoop()40 void DvrCallback::playbackThreadLoop() {
41 mPlaybackThreadRunning = true;
42 mKeepWritingPlaybackFMQ = true;
43
44 // Create the EventFlag that is used to signal the HAL impl that data have been
45 // written into the Playback FMQ
46 EventFlag* playbackMQEventFlag;
47 EXPECT_TRUE(EventFlag::createEventFlag(mPlaybackMQ->getEventFlagWord(), &playbackMQEventFlag) ==
48 android::OK);
49
50 int fd = open(mInputDataFile.c_str(), O_RDONLY | O_LARGEFILE);
51 int readBytes;
52 uint32_t regionSize = 0;
53 int8_t* buffer;
54 ALOGW("[vts] playback thread loop start %s", mInputDataFile.c_str());
55 if (fd < 0) {
56 mPlaybackThreadRunning = false;
57 ALOGW("[vts] Error %s", strerror(errno));
58 }
59
60 while (mPlaybackThreadRunning) {
61 while (mKeepWritingPlaybackFMQ) {
62 int totalWrite = mPlaybackMQ->availableToWrite();
63 if (totalWrite * 4 < mPlaybackMQ->getQuantumCount()) {
64 // Wait for the HAL implementation to read more data then write.
65 continue;
66 }
67 AidlMessageQueue<int8_t, SynchronizedReadWrite>::MemTransaction memTx;
68 if (!mPlaybackMQ->beginWrite(totalWrite, &memTx)) {
69 ALOGW("[vts] Fail to write into Playback fmq.");
70 mPlaybackThreadRunning = false;
71 break;
72 }
73 auto first = memTx.getFirstRegion();
74 buffer = first.getAddress();
75 regionSize = first.getLength();
76
77 if (regionSize > 0) {
78 readBytes = read(fd, buffer, regionSize);
79 if (readBytes <= 0) {
80 if (readBytes < 0) {
81 ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
82 } else {
83 ALOGW("[vts] playback input EOF.");
84 }
85 mPlaybackThreadRunning = false;
86 break;
87 }
88 }
89 if (regionSize == 0 || (readBytes == regionSize && regionSize < totalWrite)) {
90 auto second = memTx.getSecondRegion();
91 buffer = second.getAddress();
92 regionSize = second.getLength();
93 int ret = read(fd, buffer, regionSize);
94 if (ret <= 0) {
95 if (ret < 0) {
96 ALOGW("[vts] Read from %s failed.", mInputDataFile.c_str());
97 } else {
98 ALOGW("[vts] playback input EOF.");
99 }
100 mPlaybackThreadRunning = false;
101 break;
102 }
103 readBytes += ret;
104 }
105 if (!mPlaybackMQ->commitWrite(readBytes)) {
106 ALOGW("[vts] Failed to commit write playback fmq.");
107 mPlaybackThreadRunning = false;
108 break;
109 }
110 playbackMQEventFlag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_READY));
111 }
112 }
113
114 mPlaybackThreadRunning = false;
115 ALOGW("[vts] Playback thread end.");
116 close(fd);
117 }
118
testRecordOutput()119 void DvrCallback::testRecordOutput() {
120 bool passed = true;
121 {
122 android::Mutex::Autolock autoLock(mMsgLock);
123 while (mDataOutputBuffer.empty()) {
124 if (-ETIMEDOUT == mMsgCondition.waitRelative(mMsgLock, WAIT_TIMEOUT)) {
125 EXPECT_TRUE(false) << "record output matching pid does not output within timeout";
126 passed = false;
127 break;
128 }
129 }
130 }
131 stopRecordThread();
132 if (passed) ALOGW("[vts] record pass and stop");
133 }
134
startRecordOutputThread(RecordSettings,MQDesc & recordMQDescriptor)135 void DvrCallback::startRecordOutputThread(RecordSettings /* recordSettings */,
136 MQDesc& recordMQDescriptor) {
137 mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
138 EXPECT_TRUE(mRecordMQ);
139
140 mRecordThread = std::thread(&DvrCallback::recordThreadLoop, this);
141 }
142
recordThreadLoop()143 void DvrCallback::recordThreadLoop() {
144 ALOGD("[vts] DvrCallback record threadLoop start.");
145 mRecordThreadRunning = true;
146 mKeepReadingRecordFMQ = true;
147
148 // Create the EventFlag that is used to signal the HAL impl that data have been
149 // read from the Record FMQ
150 EventFlag* recordMQEventFlag;
151 EXPECT_TRUE(EventFlag::createEventFlag(mRecordMQ->getEventFlagWord(), &recordMQEventFlag) ==
152 android::OK);
153
154 while (mRecordThreadRunning) {
155 while (mKeepReadingRecordFMQ) {
156 uint32_t efState = 0;
157 android::status_t status = recordMQEventFlag->wait(
158 static_cast<int32_t>(DemuxQueueNotifyBits::DATA_READY), &efState, WAIT_TIMEOUT,
159 true /* retry on spurious wake */);
160 if (status != android::OK) {
161 ALOGD("[vts] wait for data ready on the record FMQ");
162 continue;
163 }
164 // Our current implementation filter the data and write it into the filter FMQ
165 // immediately after the DATA_READY from the VTS/framework
166 if (!readRecordFMQ()) {
167 ALOGD("[vts] record data failed to be filtered. Ending thread");
168 mRecordThreadRunning = false;
169 break;
170 }
171 }
172 }
173
174 mRecordThreadRunning = false;
175 ALOGD("[vts] record thread ended.");
176 }
177
readRecordFMQ()178 bool DvrCallback::readRecordFMQ() {
179 android::Mutex::Autolock autoLock(mMsgLock);
180 bool result = false;
181 int readSize = mRecordMQ->availableToRead();
182 mDataOutputBuffer.clear();
183 mDataOutputBuffer.resize(readSize);
184 result = mRecordMQ->read(mDataOutputBuffer.data(), readSize);
185 EXPECT_TRUE(result) << "can't read from Record MQ";
186 mMsgCondition.signal();
187 return result;
188 }
189
stopRecordThread()190 void DvrCallback::stopRecordThread() {
191 mKeepReadingRecordFMQ = false;
192 mRecordThreadRunning = false;
193
194 if (mRecordThread.joinable()) {
195 mRecordThread.join();
196 }
197 }
198
openDvrInDemux(DvrType type,int32_t bufferSize)199 AssertionResult DvrTests::openDvrInDemux(DvrType type, int32_t bufferSize) {
200 ndk::ScopedAStatus status;
201 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
202
203 // Create dvr callback
204 if (type == DvrType::PLAYBACK) {
205 mDvrPlaybackCallback = ndk::SharedRefBase::make<DvrCallback>();
206 status = mDemux->openDvr(type, bufferSize, mDvrPlaybackCallback, &mDvrPlayback);
207 if (status.isOk()) {
208 mDvrPlaybackCallback->setDvr(mDvrPlayback);
209 }
210 }
211
212 if (type == DvrType::RECORD) {
213 mDvrRecordCallback = ndk::SharedRefBase::make<DvrCallback>();
214 status = mDemux->openDvr(type, bufferSize, mDvrRecordCallback, &mDvrRecord);
215 if (status.isOk()) {
216 mDvrRecordCallback->setDvr(mDvrRecord);
217 }
218 }
219
220 return AssertionResult(status.isOk());
221 }
222
configDvrPlayback(DvrSettings setting)223 AssertionResult DvrTests::configDvrPlayback(DvrSettings setting) {
224 ndk::ScopedAStatus status = mDvrPlayback->configure(setting);
225
226 return AssertionResult(status.isOk());
227 }
228
configDvrRecord(DvrSettings setting)229 AssertionResult DvrTests::configDvrRecord(DvrSettings setting) {
230 ndk::ScopedAStatus status = mDvrRecord->configure(setting);
231
232 return AssertionResult(status.isOk());
233 }
234
getDvrPlaybackMQDescriptor()235 AssertionResult DvrTests::getDvrPlaybackMQDescriptor() {
236 ndk::ScopedAStatus status;
237 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
238 EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
239
240 status = mDvrPlayback->getQueueDesc(&mDvrPlaybackMQDescriptor);
241
242 return AssertionResult(status.isOk());
243 }
244
getDvrRecordMQDescriptor()245 AssertionResult DvrTests::getDvrRecordMQDescriptor() {
246 ndk::ScopedAStatus status;
247 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
248 EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
249
250 status = mDvrRecord->getQueueDesc(&mDvrRecordMQDescriptor);
251
252 return AssertionResult(status.isOk());
253 }
254
attachFilterToDvr(std::shared_ptr<IFilter> filter)255 AssertionResult DvrTests::attachFilterToDvr(std::shared_ptr<IFilter> filter) {
256 ndk::ScopedAStatus status;
257 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
258 EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
259
260 status = mDvrRecord->attachFilter(filter);
261
262 return AssertionResult(status.isOk());
263 }
264
detachFilterToDvr(std::shared_ptr<IFilter> filter)265 AssertionResult DvrTests::detachFilterToDvr(std::shared_ptr<IFilter> filter) {
266 ndk::ScopedAStatus status;
267 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
268 EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
269
270 status = mDvrRecord->detachFilter(filter);
271
272 return AssertionResult(status.isOk());
273 }
274
startDvrPlayback()275 AssertionResult DvrTests::startDvrPlayback() {
276 ndk::ScopedAStatus status;
277 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
278 EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
279
280 status = mDvrPlayback->start();
281
282 return AssertionResult(status.isOk());
283 }
284
stopDvrPlayback()285 AssertionResult DvrTests::stopDvrPlayback() {
286 ndk::ScopedAStatus status;
287 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
288 EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
289
290 status = mDvrPlayback->stop();
291
292 return AssertionResult(status.isOk());
293 }
294
closeDvrPlayback()295 void DvrTests::closeDvrPlayback() {
296 ASSERT_TRUE(mDemux);
297 ASSERT_TRUE(mDvrPlayback);
298 ASSERT_TRUE(mDvrPlayback->close().isOk());
299 }
300
startDvrRecord()301 AssertionResult DvrTests::startDvrRecord() {
302 ndk::ScopedAStatus status;
303 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
304 EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
305
306 status = mDvrRecord->start();
307
308 return AssertionResult(status.isOk());
309 }
310
stopDvrRecord()311 AssertionResult DvrTests::stopDvrRecord() {
312 ndk::ScopedAStatus status;
313 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
314 EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
315
316 status = mDvrRecord->stop();
317
318 return AssertionResult(status.isOk());
319 }
320
closeDvrRecord()321 void DvrTests::closeDvrRecord() {
322 ASSERT_TRUE(mDemux);
323 ASSERT_TRUE(mDvrRecord);
324 ASSERT_TRUE(mDvrRecord->close().isOk());
325 }
326
setPlaybackStatusCheckIntervalHint(int64_t milliseconds)327 AssertionResult DvrTests::setPlaybackStatusCheckIntervalHint(int64_t milliseconds) {
328 ndk::ScopedAStatus status;
329 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
330 EXPECT_TRUE(mDvrPlayback) << "Test with openDvr first.";
331
332 status = mDvrPlayback->setStatusCheckIntervalHint(milliseconds);
333
334 if (getDvrPlaybackInterfaceVersion() < 2) {
335 return AssertionResult(status.getStatus() == STATUS_UNKNOWN_TRANSACTION);
336 }
337 return AssertionResult(status.isOk());
338 }
339
setRecordStatusCheckIntervalHint(int64_t milliseconds)340 AssertionResult DvrTests::setRecordStatusCheckIntervalHint(int64_t milliseconds) {
341 ndk::ScopedAStatus status;
342 EXPECT_TRUE(mDemux) << "Test with openDemux first.";
343 EXPECT_TRUE(mDvrRecord) << "Test with openDvr first.";
344
345 status = mDvrRecord->setStatusCheckIntervalHint(milliseconds);
346
347 if (getDvrRecordInterfaceVersion() < 2) {
348 return AssertionResult(status.getStatus() == STATUS_UNKNOWN_TRANSACTION);
349 }
350 return AssertionResult(status.isOk());
351 }
352
getDvrPlaybackInterfaceVersion()353 int32_t DvrTests::getDvrPlaybackInterfaceVersion() {
354 int32_t version;
355 mDvrPlayback->getInterfaceVersion(&version);
356 return version;
357 }
358
getDvrRecordInterfaceVersion()359 int32_t DvrTests::getDvrRecordInterfaceVersion() {
360 int32_t version;
361 mDvrRecord->getInterfaceVersion(&version);
362 return version;
363 }
364