OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license |
| 5 * that can be found in the LICENSE file in the root of the source |
| 6 * tree. An additional intellectual property rights grant can be found |
| 7 * in the file PATENTS. All contributing project authors may |
| 8 * be found in the AUTHORS file in the root of the source tree. |
| 9 */ |
| 10 |
| 11 #include <algorithm> |
| 12 #include <tuple> |
| 13 #include <vector> |
| 14 |
| 15 #include "testing/gtest/include/gtest/gtest.h" |
| 16 #include "webrtc/modules/audio_processing/swap_queue.h" |
| 17 #include "webrtc/modules/interface/module_common_types.h" |
| 18 #include "webrtc/system_wrappers/interface/event_wrapper.h" |
| 19 #include "webrtc/system_wrappers/interface/sleep.h" |
| 20 #include "webrtc/system_wrappers/interface/thread_wrapper.h" |
| 21 |
| 22 namespace webrtc { |
| 23 |
| 24 namespace { |
| 25 |
| 26 // The type for a message. |
| 27 class SwapQueueTestMessage { |
| 28 public: |
| 29 SwapQueueTestMessage() { |
| 30 id_ = -1; |
| 31 info_ = -1; |
| 32 } |
| 33 |
| 34 SwapQueueTestMessage(const SwapQueueTestMessage& m) |
| 35 : id_(m.id_), info_(m.info_) {} |
| 36 |
| 37 explicit SwapQueueTestMessage(int id, int info) { |
| 38 id_ = id; |
| 39 info_ = info; |
| 40 } |
| 41 |
| 42 bool Compare(const SwapQueueTestMessage& m) { |
| 43 return ((id_ == m.id_) && (info_ == m.info_)); |
| 44 } |
| 45 |
| 46 void swap(SwapQueueTestMessage& m) { |
| 47 std::swap(id_, m.id_); |
| 48 std::swap(info_, m.info_); |
| 49 } |
| 50 |
| 51 private: |
| 52 int id_; |
| 53 int info_; |
| 54 }; |
| 55 |
| 56 // Sample data type enum. |
| 57 enum class DataType { Float, Int16 }; |
| 58 |
| 59 // Implements the tests for the sample queue. |
| 60 class SwapQueueMessageTest |
| 61 : public ::testing::TestWithParam<::testing::tuple<size_t, size_t>> { |
| 62 public: |
| 63 SwapQueueMessageTest() |
| 64 : test_complete_(EventWrapper::Create()), |
| 65 reader_thread_( |
| 66 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")), |
| 67 writer_thread_( |
| 68 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {} |
| 69 |
| 70 // Run the test with a timeout. |
| 71 EventTypeWrapper RunTest() { |
| 72 StartThreads(); |
| 73 return test_complete_->Wait(kTestTimeOutLimit); |
| 74 } |
| 75 |
| 76 virtual void SetUp() { |
| 77 // Read test parameter |
| 78 size_t queue_size = static_cast<size_t>(testing::get<0>(GetParam())); |
| 79 size_t messages_size = static_cast<size_t>(testing::get<1>(GetParam())); |
| 80 |
| 81 // Create queues. |
| 82 queue_.reset(new SwapQueue<SwapQueueTestMessage>(queue_size)); |
| 83 |
| 84 // Create and populate message vector. |
| 85 messages_ = std::vector<SwapQueueTestMessage>(); |
| 86 CreateTestData(messages_size); |
| 87 } |
| 88 |
| 89 virtual void TearDown() { |
| 90 reader_thread_->Stop(); |
| 91 writer_thread_->Stop(); |
| 92 } |
| 93 |
| 94 private: |
| 95 const int kTestTimeOutLimit = 10 * 1000; |
| 96 |
| 97 // Populates the data vectors with random values. |
| 98 void CreateTestData(int messages_size) { |
| 99 messages_.resize(messages_size); |
| 100 for (size_t k = 0; k < messages_.size(); k++) |
| 101 messages_[k] = SwapQueueTestMessage(rand_r(&writer_seed) % 10000, |
| 102 rand_r(&writer_seed) % 10000); |
| 103 } |
| 104 |
| 105 // Thread callback for the reader thread |
| 106 static bool CbReaderThread(void* context) { |
| 107 return reinterpret_cast<SwapQueueMessageTest*>(context)->CbReaderImpl(); |
| 108 } |
| 109 |
| 110 // Thread callback for the writer thread |
| 111 static bool CbWriterThread(void* context) { |
| 112 return reinterpret_cast<SwapQueueMessageTest*>(context)->CbWriterImpl(); |
| 113 } |
| 114 |
| 115 // Tests in a threadsafe manner whether all the samples have been |
| 116 // written and read. |
| 117 bool TestDone() { return (GetNumMessagesRead() == messages_.size()); } |
| 118 |
| 119 // Returns in a threadsafe manner the number of frames read from the queue. |
| 120 size_t GetNumMessagesRead() { |
| 121 rtc::CritScope cs(&crit_); |
| 122 return num_messages_read_; |
| 123 } |
| 124 |
| 125 // Increases in a threadsafe manner the number of messages |
| 126 // read from the queue. |
| 127 void IncreaseMessageReadCounter() { |
| 128 rtc::CritScope cs(&crit_); |
| 129 num_messages_read_++; |
| 130 } |
| 131 |
| 132 // Implements the callback functionality for the reader thread. |
| 133 bool CbReaderImpl() { |
| 134 SleepRandomTime(3, &reader_seed); |
| 135 |
| 136 // Read the message and verify bitexactness. |
| 137 size_t num_messages_read = GetNumMessagesRead(); |
| 138 SwapQueueTestMessage m; |
| 139 if (queue_->Remove(&m)) { |
| 140 EXPECT_TRUE(m.Compare(messages_[num_messages_read])); |
| 141 IncreaseMessageReadCounter(); |
| 142 } |
| 143 |
| 144 // End the test if the test is done or an assert has occurred. |
| 145 if (TestDone() || HasFatalFailure()) { |
| 146 test_complete_->Set(); |
| 147 } |
| 148 |
| 149 return true; |
| 150 } |
| 151 |
| 152 // Implements the callback functionality for the writer thread. |
| 153 bool CbWriterImpl() { |
| 154 SleepRandomTime(3, &writer_seed); |
| 155 |
| 156 if (num_messages_written_ < messages_.size()) { |
| 157 // Attempt to put the message in the queue. |
| 158 SwapQueueTestMessage m(messages_[num_messages_written_]); |
| 159 if (queue_->Insert(&m)) |
| 160 num_messages_written_++; |
| 161 } |
| 162 |
| 163 // End the test early if a fatal failure (ASSERT_*) has occurred. |
| 164 if (HasFatalFailure()) |
| 165 test_complete_->Set(); |
| 166 |
| 167 return true; |
| 168 } |
| 169 |
| 170 // Sleeps a random time. |
| 171 static void SleepRandomTime(int max_sleep, unsigned int* seed) { |
| 172 SleepMs(rand_r(seed) % (max_sleep + 1)); |
| 173 } |
| 174 |
| 175 // Start the threads used in the test. |
| 176 void StartThreads() { |
| 177 EXPECT_TRUE(reader_thread_->Start()); |
| 178 reader_thread_->SetPriority(kRealtimePriority); |
| 179 EXPECT_TRUE(writer_thread_->Start()); |
| 180 writer_thread_->SetPriority(kRealtimePriority); |
| 181 } |
| 182 |
| 183 // Test parameters. |
| 184 rtc::scoped_ptr<SwapQueue<SwapQueueTestMessage>> queue_; |
| 185 rtc::CriticalSection crit_; |
| 186 const rtc::scoped_ptr<EventWrapper> test_complete_; |
| 187 rtc::scoped_ptr<ThreadWrapper> reader_thread_; |
| 188 rtc::scoped_ptr<ThreadWrapper> writer_thread_; |
| 189 unsigned int reader_seed = 42; |
| 190 unsigned int writer_seed = 37; |
| 191 std::vector<SwapQueueTestMessage> messages_; |
| 192 std::vector<int16_t> buffer_writer_int16_; |
| 193 size_t num_messages_written_ = 0; |
| 194 size_t num_messages_read_ GUARDED_BY(crit_) = 0; |
| 195 }; |
| 196 |
| 197 // Implements the tests sample queue. |
| 198 class SwapQueueSampleTest |
| 199 : public ::testing::TestWithParam< |
| 200 ::testing::tuple<size_t, size_t, size_t, DataType>> { |
| 201 public: |
| 202 SwapQueueSampleTest() |
| 203 : test_complete_(EventWrapper::Create()), |
| 204 reader_thread_( |
| 205 ThreadWrapper::CreateThread(CbReaderThread, this, "reader")), |
| 206 writer_thread_( |
| 207 ThreadWrapper::CreateThread(CbWriterThread, this, "writer")) {} |
| 208 |
| 209 // Run the test with a timeout. |
| 210 EventTypeWrapper RunTest() { |
| 211 StartThreads(); |
| 212 return test_complete_->Wait(kTestTimeOutLimit); |
| 213 } |
| 214 |
| 215 virtual void SetUp() { |
| 216 // Read parameters. |
| 217 queue_size_ = static_cast<size_t>(testing::get<0>(GetParam())); |
| 218 max_frame_length_ = static_cast<size_t>(testing::get<1>(GetParam())); |
| 219 data_length_ = static_cast<size_t>(testing::get<2>(GetParam())); |
| 220 data_type_ = static_cast<DataType>(testing::get<3>(GetParam())); |
| 221 |
| 222 // llocate read and write buffers. |
| 223 buffer_reader_flt_ = std::vector<float>(max_frame_length_, 0.0f); |
| 224 buffer_writer_flt_ = std::vector<float>(max_frame_length_, 0.0f); |
| 225 buffer_reader_int16_ = std::vector<int16_t>(max_frame_length_, 0); |
| 226 buffer_writer_int16_ = std::vector<int16_t>(max_frame_length_, 0); |
| 227 |
| 228 // Create queues. |
| 229 sample_queue_flt_.reset( |
| 230 new SwapQueue<std::vector<float>>(queue_size_, buffer_reader_flt_)); |
| 231 sample_queue_int16_.reset( |
| 232 new SwapQueue<std::vector<int16_t>>(queue_size_, buffer_reader_int16_)); |
| 233 |
| 234 // Create and populate data vectors. |
| 235 CreateTestData(data_length_); |
| 236 } |
| 237 |
| 238 virtual void TearDown() { |
| 239 reader_thread_->Stop(); |
| 240 writer_thread_->Stop(); |
| 241 } |
| 242 |
| 243 private: |
| 244 const int kTestTimeOutLimit = 10 * 1000; |
| 245 |
| 246 // Populates the data vectors with random values. |
| 247 void CreateTestData(size_t data_length) { |
| 248 samples_int16_.resize(data_length); |
| 249 samples_float_.resize(data_length); |
| 250 for (size_t k = 0; k < data_length; k++) { |
| 251 samples_float_[k] = |
| 252 (static_cast<float>((rand_r(&writer_seed) % (32768 + 32768 + 1)) - |
| 253 32768) / |
| 254 32768.0f); |
| 255 samples_int16_[k] = ((rand_r(&writer_seed) % (32767 + 32768)) - 32768); |
| 256 } |
| 257 } |
| 258 |
| 259 // Thread callback for the reader thread |
| 260 static bool CbReaderThread(void* context) { |
| 261 return reinterpret_cast<SwapQueueSampleTest*>(context)->CbReaderImpl(); |
| 262 } |
| 263 |
| 264 // Thread callback for the writer thread |
| 265 static bool CbWriterThread(void* context) { |
| 266 return reinterpret_cast<SwapQueueSampleTest*>(context)->CbWriterImpl(); |
| 267 } |
| 268 |
| 269 // Tests in a threadsafe manner whether all the samples have been |
| 270 // written and read. |
| 271 bool TestDone() { return (GetNumSamplesRead() == data_length_); } |
| 272 |
| 273 // Returns in a threadsafe manner the number of frames read from the queue. |
| 274 size_t GetNumFramesRead() { |
| 275 rtc::CritScope cs(&crit_); |
| 276 return num_frames_read_; |
| 277 } |
| 278 |
| 279 // Returns in a threadsafe manner the number of samples read from the queue. |
| 280 size_t GetNumSamplesRead() { |
| 281 rtc::CritScope cs(&crit_); |
| 282 return num_samples_read_; |
| 283 } |
| 284 |
| 285 // Increases in a threadsafe manner the number of frames and samples |
| 286 // read from the queue. |
| 287 void IncreaseReadCounters(size_t num_samples_read) { |
| 288 rtc::CritScope cs(&crit_); |
| 289 num_frames_read_++; |
| 290 num_samples_read_ += num_samples_read; |
| 291 } |
| 292 |
| 293 // Implements the callback functionality for the reader thread. |
| 294 bool CbReaderImpl() { |
| 295 SleepRandomTime(3, &reader_seed); |
| 296 |
| 297 // Read the samples and verify bitexactness. |
| 298 size_t num_samples_read = GetNumSamplesRead(); |
| 299 if ((data_type_ == DataType::Float) && |
| 300 (sample_queue_flt_->Remove(&buffer_reader_flt_))) { |
| 301 for (size_t k = 0; k < buffer_reader_flt_.size(); k++) |
| 302 EXPECT_EQ(buffer_reader_flt_[k], samples_float_[num_samples_read + k]); |
| 303 |
| 304 IncreaseReadCounters(buffer_reader_flt_.size()); |
| 305 } else if ((data_type_ == DataType::Int16) && |
| 306 (sample_queue_int16_->Remove(&buffer_reader_int16_))) { |
| 307 for (size_t k = 0; k < buffer_reader_int16_.size(); k++) |
| 308 EXPECT_EQ(buffer_reader_int16_[k], |
| 309 samples_int16_[num_samples_read + k]); |
| 310 |
| 311 IncreaseReadCounters(buffer_reader_int16_.size()); |
| 312 } |
| 313 |
| 314 // End the test if the test is done or an assert has occurred. |
| 315 if (TestDone() || HasFatalFailure()) { |
| 316 test_complete_->Set(); |
| 317 } |
| 318 |
| 319 return true; |
| 320 } |
| 321 |
| 322 // Implements the callback functionality for the writer thread. |
| 323 bool CbWriterImpl() { |
| 324 SleepRandomTime(3, &writer_seed); |
| 325 |
| 326 // Choose number of samples to write. |
| 327 const size_t num_samples_to_write = |
| 328 std::min(rand_r(&writer_seed) % max_frame_length_, |
| 329 data_length_ - num_samples_written_); |
| 330 |
| 331 // Write the data. |
| 332 bool data_written = false; |
| 333 if (num_samples_to_write > 0) { |
| 334 if (data_type_ == DataType::Float) { |
| 335 if (buffer_writer_flt_.size() != num_samples_to_write) |
| 336 buffer_writer_flt_.resize(num_samples_to_write); |
| 337 memcpy(&buffer_writer_flt_[0], &samples_float_[num_samples_written_], |
| 338 num_samples_to_write * sizeof(samples_float_[0])); |
| 339 |
| 340 data_written = sample_queue_flt_->Insert(&buffer_writer_flt_); |
| 341 } else { |
| 342 if (buffer_writer_int16_.size() != num_samples_to_write) |
| 343 buffer_writer_int16_.resize(num_samples_to_write); |
| 344 |
| 345 memcpy(&buffer_writer_int16_[0], &samples_int16_[num_samples_written_], |
| 346 num_samples_to_write * sizeof(samples_int16_[0])); |
| 347 |
| 348 data_written = sample_queue_int16_->Insert(&buffer_writer_int16_); |
| 349 } |
| 350 } |
| 351 |
| 352 // Update the number of samples left to write |
| 353 if (data_written) { |
| 354 num_samples_written_ += num_samples_to_write; |
| 355 num_frames_written_++; |
| 356 } |
| 357 |
| 358 // End the test early if a fatal failure (ASSERT_*) has occurred. |
| 359 if (HasFatalFailure()) |
| 360 test_complete_->Set(); |
| 361 |
| 362 return true; |
| 363 } |
| 364 |
| 365 // Sleeps a random time. |
| 366 static void SleepRandomTime(int max_sleep, unsigned int* seed) { |
| 367 SleepMs(rand_r(seed) % (max_sleep + 1)); |
| 368 } |
| 369 |
| 370 // Start the threads used in the test. |
| 371 void StartThreads() { |
| 372 EXPECT_TRUE(reader_thread_->Start()); |
| 373 reader_thread_->SetPriority(kRealtimePriority); |
| 374 EXPECT_TRUE(writer_thread_->Start()); |
| 375 writer_thread_->SetPriority(kRealtimePriority); |
| 376 } |
| 377 |
| 378 // Test parameters. |
| 379 size_t queue_size_; |
| 380 size_t max_frame_length_; |
| 381 size_t data_length_; |
| 382 DataType data_type_; |
| 383 |
| 384 rtc::scoped_ptr<SwapQueue<std::vector<float>>> sample_queue_flt_; |
| 385 rtc::scoped_ptr<SwapQueue<std::vector<int16_t>>> sample_queue_int16_; |
| 386 rtc::CriticalSection crit_; |
| 387 const rtc::scoped_ptr<EventWrapper> test_complete_; |
| 388 rtc::scoped_ptr<ThreadWrapper> reader_thread_; |
| 389 rtc::scoped_ptr<ThreadWrapper> writer_thread_; |
| 390 std::vector<int16_t> samples_int16_; |
| 391 std::vector<float> samples_float_; |
| 392 size_t num_samples_read_ GUARDED_BY(crit_) = 0; |
| 393 size_t num_samples_written_ = 0; |
| 394 unsigned int reader_seed = 42; |
| 395 unsigned int writer_seed = 37; |
| 396 std::vector<float> buffer_reader_flt_; |
| 397 std::vector<float> buffer_writer_flt_; |
| 398 std::vector<int16_t> buffer_reader_int16_; |
| 399 std::vector<int16_t> buffer_writer_int16_; |
| 400 size_t num_frames_written_ = 0; |
| 401 size_t num_frames_read_ GUARDED_BY(crit_) = 0; |
| 402 }; |
| 403 |
| 404 } // anonymous namespace |
| 405 |
| 406 // Test parameters for the message queue tests. |
| 407 const size_t kMessageQueueSizes[] = {2, 7, 20}; |
| 408 const size_t kMessageQueueDataLengths[] = {100}; |
| 409 |
| 410 // Test parameters for the sample queue tests. |
| 411 const size_t kSampleQueueSizes[] = {2, 7, 100}; |
| 412 const size_t kMaxFrameLengths[] = {77, 160}; |
| 413 const size_t kSampleQueueDataLengths[] = {1000, 10000}; |
| 414 const DataType kDataTypes[] = {DataType::Float, DataType::Int16}; |
| 415 |
| 416 TEST_P(SwapQueueSampleTest, BitExactness) { |
| 417 // Run test and verify that it did not time out. |
| 418 EXPECT_EQ(kEventSignaled, RunTest()); |
| 419 } |
| 420 |
| 421 TEST_P(SwapQueueMessageTest, BitExactness) { |
| 422 // Run test and verify that it did not time out. |
| 423 EXPECT_EQ(kEventSignaled, RunTest()); |
| 424 } |
| 425 |
| 426 INSTANTIATE_TEST_CASE_P( |
| 427 SwapQueueMessageTestAllCombinations, |
| 428 SwapQueueMessageTest, |
| 429 testing::Combine(::testing::ValuesIn(kMessageQueueSizes), |
| 430 ::testing::ValuesIn(kMessageQueueDataLengths))); |
| 431 |
| 432 INSTANTIATE_TEST_CASE_P( |
| 433 SwapQueueSampleTestAllCombinations, |
| 434 SwapQueueSampleTest, |
| 435 testing::Combine(::testing::ValuesIn(kSampleQueueSizes), |
| 436 ::testing::ValuesIn(kMaxFrameLengths), |
| 437 ::testing::ValuesIn(kSampleQueueDataLengths), |
| 438 ::testing::ValuesIn(kDataTypes))); |
| 439 |
| 440 } // namespace webrtc |
OLD | NEW |