• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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