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