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