blob: a9c3b510635675ed5677f30400185616e3dfbee5 [file] [log] [blame]
Hongguang600a6ae2021-07-08 18:51:51 -07001/*
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
21void 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);
Hongguang901aa7b2021-08-26 12:20:56 -070027
28 mPlaybackThread = std::thread(&DvrCallback::playbackThreadLoop, this);
Hongguang600a6ae2021-07-08 18:51:51 -070029}
30
31void DvrCallback::stopPlaybackThread() {
32 mPlaybackThreadRunning = false;
33 mKeepWritingPlaybackFMQ = false;
34
Hongguang901aa7b2021-08-26 12:20:56 -070035 if (mPlaybackThread.joinable()) {
36 mPlaybackThread.join();
37 }
Hongguang600a6ae2021-07-08 18:51:51 -070038}
39
40void DvrCallback::playbackThreadLoop() {
Hongguang600a6ae2021-07-08 18:51:51 -070041 mPlaybackThreadRunning = true;
Hongguang901aa7b2021-08-26 12:20:56 -070042 mKeepWritingPlaybackFMQ = true;
Hongguang600a6ae2021-07-08 18:51:51 -070043
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
119void DvrCallback::testRecordOutput() {
Hongguang901aa7b2021-08-26 12:20:56 -0700120 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 }
Hongguang600a6ae2021-07-08 18:51:51 -0700129 }
130 }
131 stopRecordThread();
Hongguang901aa7b2021-08-26 12:20:56 -0700132 if (passed) ALOGW("[vts] record pass and stop");
Hongguang600a6ae2021-07-08 18:51:51 -0700133}
134
Hongguang901aa7b2021-08-26 12:20:56 -0700135void DvrCallback::startRecordOutputThread(RecordSettings /* recordSettings */,
Hongguang600a6ae2021-07-08 18:51:51 -0700136 MQDesc& recordMQDescriptor) {
137 mRecordMQ = std::make_unique<FilterMQ>(recordMQDescriptor, true /* resetPointers */);
138 EXPECT_TRUE(mRecordMQ);
Hongguang600a6ae2021-07-08 18:51:51 -0700139
Hongguang901aa7b2021-08-26 12:20:56 -0700140 mRecordThread = std::thread(&DvrCallback::recordThreadLoop, this);
Hongguang600a6ae2021-07-08 18:51:51 -0700141}
142
Hongguang901aa7b2021-08-26 12:20:56 -0700143void DvrCallback::recordThreadLoop() {
Hongguang600a6ae2021-07-08 18:51:51 -0700144 ALOGD("[vts] DvrCallback record threadLoop start.");
Hongguang600a6ae2021-07-08 18:51:51 -0700145 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) {
Hongguang901aa7b2021-08-26 12:20:56 -0700155 while (mKeepReadingRecordFMQ) {
Hongguang600a6ae2021-07-08 18:51:51 -0700156 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
178bool 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
190void DvrCallback::stopRecordThread() {
191 mKeepReadingRecordFMQ = false;
192 mRecordThreadRunning = false;
Hongguang901aa7b2021-08-26 12:20:56 -0700193
194 if (mRecordThread.joinable()) {
195 mRecordThread.join();
196 }
Hongguang600a6ae2021-07-08 18:51:51 -0700197}
198
199AssertionResult 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
223AssertionResult DvrTests::configDvrPlayback(DvrSettings setting) {
224 ndk::ScopedAStatus status = mDvrPlayback->configure(setting);
225
226 return AssertionResult(status.isOk());
227}
228
229AssertionResult DvrTests::configDvrRecord(DvrSettings setting) {
230 ndk::ScopedAStatus status = mDvrRecord->configure(setting);
231
232 return AssertionResult(status.isOk());
233}
234
235AssertionResult 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
245AssertionResult 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
255AssertionResult 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
265AssertionResult 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
275AssertionResult 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
285AssertionResult 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
295void DvrTests::closeDvrPlayback() {
296 ASSERT_TRUE(mDemux);
297 ASSERT_TRUE(mDvrPlayback);
298 ASSERT_TRUE(mDvrPlayback->close().isOk());
299}
300
301AssertionResult 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
311AssertionResult 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
321void DvrTests::closeDvrRecord() {
322 ASSERT_TRUE(mDemux);
323 ASSERT_TRUE(mDvrRecord);
324 ASSERT_TRUE(mDvrRecord->close().isOk());
325}