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