1 /*
2  * Copyright (C) 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 // Unit Test for MediaSampleQueue
18 
19 // #define LOG_NDEBUG 0
20 #define LOG_TAG "MediaSampleQueueTests"
21 
22 #include <android-base/logging.h>
23 #include <gtest/gtest.h>
24 #include <media/MediaSampleQueue.h>
25 
26 #include <thread>
27 
28 namespace android {
29 
30 /** Duration to use when delaying threads to order operations. */
31 static constexpr int64_t kThreadDelayDurationMs = 100;
32 
33 class MediaSampleQueueTests : public ::testing::Test {
34 public:
MediaSampleQueueTests()35     MediaSampleQueueTests() { LOG(DEBUG) << "MediaSampleQueueTests created"; }
~MediaSampleQueueTests()36     ~MediaSampleQueueTests() { LOG(DEBUG) << "MediaSampleQueueTests destroyed"; }
37 };
38 
newSample(uint32_t id)39 static std::shared_ptr<MediaSample> newSample(uint32_t id) {
40     return MediaSample::createWithReleaseCallback(nullptr /* buffer */, 0 /* offset */, id,
41                                                   nullptr /* callback */);
42 }
43 
TEST_F(MediaSampleQueueTests,TestSequentialDequeueOrder)44 TEST_F(MediaSampleQueueTests, TestSequentialDequeueOrder) {
45     LOG(DEBUG) << "TestSequentialDequeueOrder Starts";
46 
47     static constexpr int kNumSamples = 4;
48     MediaSampleQueue sampleQueue;
49     EXPECT_TRUE(sampleQueue.isEmpty());
50 
51     // Enqueue loop.
52     for (int i = 0; i < kNumSamples; ++i) {
53         sampleQueue.enqueue(newSample(i));
54         EXPECT_FALSE(sampleQueue.isEmpty());
55     }
56 
57     // Dequeue loop.
58     for (int i = 0; i < kNumSamples; ++i) {
59         std::shared_ptr<MediaSample> sample;
60         bool aborted = sampleQueue.dequeue(&sample);
61         EXPECT_NE(sample, nullptr);
62         EXPECT_EQ(sample->bufferId, i);
63         EXPECT_FALSE(aborted);
64     }
65     EXPECT_TRUE(sampleQueue.isEmpty());
66 }
67 
TEST_F(MediaSampleQueueTests,TestInterleavedDequeueOrder)68 TEST_F(MediaSampleQueueTests, TestInterleavedDequeueOrder) {
69     LOG(DEBUG) << "TestInterleavedDequeueOrder Starts";
70 
71     static constexpr int kNumSamples = 4;
72     MediaSampleQueue sampleQueue;
73 
74     // Enqueue and dequeue.
75     for (int i = 0; i < kNumSamples; ++i) {
76         sampleQueue.enqueue(newSample(i));
77         EXPECT_FALSE(sampleQueue.isEmpty());
78 
79         std::shared_ptr<MediaSample> sample;
80         bool aborted = sampleQueue.dequeue(&sample);
81         EXPECT_NE(sample, nullptr);
82         EXPECT_EQ(sample->bufferId, i);
83         EXPECT_FALSE(aborted);
84         EXPECT_TRUE(sampleQueue.isEmpty());
85     }
86 }
87 
TEST_F(MediaSampleQueueTests,TestBlockingDequeue)88 TEST_F(MediaSampleQueueTests, TestBlockingDequeue) {
89     LOG(DEBUG) << "TestBlockingDequeue Starts";
90 
91     MediaSampleQueue sampleQueue;
92 
93     std::thread enqueueThread([&sampleQueue] {
94         // Note: This implementation is a bit racy. Any amount of sleep will not guarantee that the
95         // main thread will be blocked on the sample queue by the time this thread calls enqueue.
96         // But we can say with high confidence that it will and the test will not fail regardless.
97         std::this_thread::sleep_for(std::chrono::milliseconds(kThreadDelayDurationMs));
98         sampleQueue.enqueue(newSample(1));
99     });
100 
101     std::shared_ptr<MediaSample> sample;
102     bool aborted = sampleQueue.dequeue(&sample);
103     EXPECT_NE(sample, nullptr);
104     EXPECT_EQ(sample->bufferId, 1);
105     EXPECT_FALSE(aborted);
106     EXPECT_TRUE(sampleQueue.isEmpty());
107 
108     enqueueThread.join();
109 }
110 
TEST_F(MediaSampleQueueTests,TestDequeueBufferRelease)111 TEST_F(MediaSampleQueueTests, TestDequeueBufferRelease) {
112     LOG(DEBUG) << "TestDequeueBufferRelease Starts";
113 
114     static constexpr int kNumSamples = 4;
115     std::vector<bool> bufferReleased(kNumSamples, false);
116 
117     MediaSample::OnSampleReleasedCallback callback = [&bufferReleased](MediaSample* sample) {
118         bufferReleased[sample->bufferId] = true;
119     };
120 
121     MediaSampleQueue sampleQueue;
122     for (int i = 0; i < kNumSamples; ++i) {
123         bool aborted = sampleQueue.enqueue(
124                 MediaSample::createWithReleaseCallback(nullptr, 0, i, callback));
125         EXPECT_FALSE(aborted);
126     }
127 
128     for (int i = 0; i < kNumSamples; ++i) {
129         EXPECT_FALSE(bufferReleased[i]);
130     }
131 
132     for (int i = 0; i < kNumSamples; ++i) {
133         {
134             std::shared_ptr<MediaSample> sample;
135             bool aborted = sampleQueue.dequeue(&sample);
136             EXPECT_NE(sample, nullptr);
137             EXPECT_EQ(sample->bufferId, i);
138             EXPECT_FALSE(bufferReleased[i]);
139             EXPECT_FALSE(aborted);
140         }
141 
142         for (int j = 0; j < kNumSamples; ++j) {
143             EXPECT_EQ(bufferReleased[j], j <= i);
144         }
145     }
146 }
147 
TEST_F(MediaSampleQueueTests,TestAbortBufferRelease)148 TEST_F(MediaSampleQueueTests, TestAbortBufferRelease) {
149     LOG(DEBUG) << "TestAbortBufferRelease Starts";
150 
151     static constexpr int kNumSamples = 4;
152     std::vector<bool> bufferReleased(kNumSamples, false);
153 
154     MediaSample::OnSampleReleasedCallback callback = [&bufferReleased](MediaSample* sample) {
155         bufferReleased[sample->bufferId] = true;
156     };
157 
158     MediaSampleQueue sampleQueue;
159     for (int i = 0; i < kNumSamples; ++i) {
160         bool aborted = sampleQueue.enqueue(
161                 MediaSample::createWithReleaseCallback(nullptr, 0, i, callback));
162         EXPECT_FALSE(aborted);
163     }
164 
165     for (int i = 0; i < kNumSamples; ++i) {
166         EXPECT_FALSE(bufferReleased[i]);
167     }
168 
169     EXPECT_FALSE(sampleQueue.isEmpty());
170     sampleQueue.abort();
171     EXPECT_TRUE(sampleQueue.isEmpty());
172 
173     for (int i = 0; i < kNumSamples; ++i) {
174         EXPECT_TRUE(bufferReleased[i]);
175     }
176 }
177 
TEST_F(MediaSampleQueueTests,TestNonEmptyAbort)178 TEST_F(MediaSampleQueueTests, TestNonEmptyAbort) {
179     LOG(DEBUG) << "TestNonEmptyAbort Starts";
180 
181     MediaSampleQueue sampleQueue;
182     bool aborted = sampleQueue.enqueue(newSample(1));
183     EXPECT_FALSE(aborted);
184 
185     sampleQueue.abort();
186 
187     std::shared_ptr<MediaSample> sample;
188     aborted = sampleQueue.dequeue(&sample);
189     EXPECT_TRUE(aborted);
190     EXPECT_EQ(sample, nullptr);
191 
192     aborted = sampleQueue.enqueue(sample);
193     EXPECT_TRUE(aborted);
194 }
195 
TEST_F(MediaSampleQueueTests,TestEmptyAbort)196 TEST_F(MediaSampleQueueTests, TestEmptyAbort) {
197     LOG(DEBUG) << "TestEmptyAbort Starts";
198 
199     MediaSampleQueue sampleQueue;
200     sampleQueue.abort();
201 
202     std::shared_ptr<MediaSample> sample;
203     bool aborted = sampleQueue.dequeue(&sample);
204     EXPECT_TRUE(aborted);
205     EXPECT_EQ(sample, nullptr);
206 
207     aborted = sampleQueue.enqueue(sample);
208     EXPECT_TRUE(aborted);
209 }
210 
TEST_F(MediaSampleQueueTests,TestBlockingAbort)211 TEST_F(MediaSampleQueueTests, TestBlockingAbort) {
212     LOG(DEBUG) << "TestBlockingAbort Starts";
213 
214     MediaSampleQueue sampleQueue;
215 
216     std::thread abortingThread([&sampleQueue] {
217         // Note: This implementation is a bit racy. Any amount of sleep will not guarantee that the
218         // main thread will be blocked on the sample queue by the time this thread calls abort.
219         // But we can say with high confidence that it will and the test will not fail regardless.
220         std::this_thread::sleep_for(std::chrono::milliseconds(kThreadDelayDurationMs));
221         sampleQueue.abort();
222     });
223 
224     std::shared_ptr<MediaSample> sample;
225     bool aborted = sampleQueue.dequeue(&sample);
226     EXPECT_TRUE(aborted);
227     EXPECT_EQ(sample, nullptr);
228 
229     abortingThread.join();
230 }
231 
232 }  // namespace android
233 
main(int argc,char ** argv)234 int main(int argc, char** argv) {
235     ::testing::InitGoogleTest(&argc, argv);
236     return RUN_ALL_TESTS();
237 }
238