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