processing_audio_fifo_unittest.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. // Copyright 2022 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "services/audio/processing_audio_fifo.h"
  5. #include <cstring>
  6. #include "base/bind.h"
  7. #include "base/callback_helpers.h"
  8. #include "base/run_loop.h"
  9. #include "base/test/bind.h"
  10. #include "media/audio/simple_sources.h"
  11. #include "testing/gtest/include/gtest/gtest.h"
  12. namespace audio {
  13. const int kSampleRate = 48000;
  14. const int kFramesPerBuffer = kSampleRate / 200; // 5ms, for testing.
  15. const int kTestToneFrequency = 440;
  16. const int kTestFifoSize = 4;
  17. const double kTestVolume = 0.567;
  18. struct TestCaptureData {
  19. TestCaptureData(std::unique_ptr<media::AudioBus> audio_bus,
  20. base::TimeTicks capture_time,
  21. double volume,
  22. bool key_pressed)
  23. : audio_bus(std::move(audio_bus)),
  24. capture_time(capture_time),
  25. volume(volume),
  26. key_pressed(key_pressed) {}
  27. TestCaptureData(const TestCaptureData&) = delete;
  28. TestCaptureData& operator=(const TestCaptureData&) = delete;
  29. TestCaptureData(TestCaptureData&&) = default;
  30. TestCaptureData& operator=(TestCaptureData&& other) = default;
  31. ~TestCaptureData() = default;
  32. std::unique_ptr<media::AudioBus> audio_bus;
  33. base::TimeTicks capture_time;
  34. double volume;
  35. bool key_pressed;
  36. };
  37. void VerifyAudioDataEqual(const media::AudioBus& first,
  38. const media::AudioBus& second) {
  39. DCHECK_EQ(first.channels(), second.channels());
  40. DCHECK_EQ(first.frames(), second.frames());
  41. for (int ch = 0; ch < first.channels(); ++ch) {
  42. EXPECT_EQ(0, memcmp(first.channel(ch), second.channel(ch),
  43. sizeof(float) * first.frames()));
  44. }
  45. }
  46. void VerifyProcessingData(const TestCaptureData& expected_data,
  47. const media::AudioBus& audio_bus,
  48. base::TimeTicks capture_time,
  49. double volume,
  50. bool key_pressed) {
  51. VerifyAudioDataEqual(*expected_data.audio_bus, audio_bus);
  52. EXPECT_EQ(expected_data.capture_time, capture_time);
  53. EXPECT_DOUBLE_EQ(expected_data.volume, volume);
  54. EXPECT_EQ(expected_data.key_pressed, key_pressed);
  55. }
  56. class ProcessingAudioFifoTest : public testing::Test {
  57. public:
  58. ProcessingAudioFifoTest()
  59. : params_(media::AudioParameters::Format::AUDIO_PCM_LINEAR,
  60. media::CHANNEL_LAYOUT_STEREO,
  61. kSampleRate,
  62. kFramesPerBuffer),
  63. audio_source_(params_.channels(),
  64. kTestToneFrequency,
  65. params_.sample_rate()) {}
  66. ProcessingAudioFifoTest(const ProcessingAudioFifoTest&) = delete;
  67. ProcessingAudioFifoTest& operator=(const ProcessingAudioFifoTest&) = delete;
  68. ~ProcessingAudioFifoTest() override {
  69. if (fifo_)
  70. TearDownFifo();
  71. }
  72. protected:
  73. const media::AudioParameters params_;
  74. ProcessingAudioFifo* fifo() { return fifo_.get(); }
  75. void SetupFifo(ProcessingAudioFifo::ProcessAudioCallback callback) {
  76. fifo_ = std::make_unique<ProcessingAudioFifo>(
  77. params_, kTestFifoSize, std::move(callback), base::DoNothing());
  78. fifo_->Start();
  79. }
  80. void SetupFifoWithFakeEvent(
  81. ProcessingAudioFifo::ProcessAudioCallback callback) {
  82. fifo_ = std::make_unique<ProcessingAudioFifo>(
  83. params_, kTestFifoSize, std::move(callback), base::DoNothing());
  84. using_fake_event_ = true;
  85. fifo_->StartForTesting(&fake_new_capture_event_);
  86. }
  87. void SetFifoStoppingFlag() { fifo_->fifo_stopping_.Set(); }
  88. void TearDownFifo() {
  89. DCHECK(fifo_);
  90. if (using_fake_event_) {
  91. // Manually set the FIFO stopping flag, and allow the processing thread to
  92. // exit, otherwise we will wait forever in StopProcessingLoop().
  93. SetFifoStoppingFlag();
  94. SignalFakeNewCaptureEvent();
  95. }
  96. fifo_.reset();
  97. }
  98. std::unique_ptr<media::AudioBus> CreateAudioData(
  99. base::TimeTicks timestamp = base::TimeTicks::Now()) {
  100. auto data = media::AudioBus::Create(params_);
  101. audio_source_.OnMoreData(base::TimeDelta(), timestamp, 0, data.get());
  102. return data;
  103. }
  104. void GenerateTestCaptureData(std::vector<TestCaptureData>* dest, int count) {
  105. double volume_step = 1.0 / count;
  106. base::TimeTicks capture_time = base::TimeTicks::Now();
  107. base::TimeTicks timestamp = base::TimeTicks();
  108. for (int i = 0; i < count; ++i) {
  109. dest->emplace_back(CreateAudioData(timestamp), capture_time,
  110. i * volume_step, i % 2);
  111. timestamp += params_.GetBufferDuration();
  112. capture_time += base::Milliseconds(5);
  113. }
  114. }
  115. void SignalFakeNewCaptureEvent() {
  116. DCHECK(using_fake_event_);
  117. fake_new_capture_event_.Signal();
  118. }
  119. private:
  120. std::unique_ptr<ProcessingAudioFifo> fifo_;
  121. bool using_fake_event_ = false;
  122. base::WaitableEvent fake_new_capture_event_{
  123. base::WaitableEvent::ResetPolicy::AUTOMATIC};
  124. // The audio source used to generate data.
  125. media::SineWaveAudioSource audio_source_;
  126. };
  127. TEST_F(ProcessingAudioFifoTest, ConstructDestroy) {
  128. auto fifo = std::make_unique<ProcessingAudioFifo>(
  129. params_, kTestFifoSize, base::DoNothing(), base::DoNothing());
  130. fifo.reset();
  131. }
  132. TEST_F(ProcessingAudioFifoTest, ConstructStartDestroy) {
  133. auto fifo = std::make_unique<ProcessingAudioFifo>(
  134. params_, kTestFifoSize, base::DoNothing(), base::DoNothing());
  135. fifo->Start();
  136. fifo.reset();
  137. }
  138. TEST_F(ProcessingAudioFifoTest, PushData_OneBuffer) {
  139. TestCaptureData test_data(CreateAudioData(), base::TimeTicks(), kTestVolume,
  140. true);
  141. base::WaitableEvent data_processed;
  142. auto verify_data = [&](const media::AudioBus& audio_bus,
  143. base::TimeTicks capture_time, double volume,
  144. bool key_pressed) {
  145. // The processing callback should receive the same data that was pushed into
  146. // the fifo.
  147. VerifyProcessingData(test_data, audio_bus, capture_time, volume,
  148. key_pressed);
  149. data_processed.Signal();
  150. };
  151. SetupFifo(base::BindLambdaForTesting(verify_data));
  152. fifo()->PushData(test_data.audio_bus.get(), test_data.capture_time,
  153. test_data.volume, test_data.key_pressed);
  154. data_processed.Wait();
  155. }
  156. TEST_F(ProcessingAudioFifoTest, PushData_MultipleBuffers_SingleBatch) {
  157. // Stay below the FIFO's size to avoid dropping buffers.
  158. const int kNumberOfBuffers = kTestFifoSize;
  159. std::vector<TestCaptureData> capture_buffers;
  160. GenerateTestCaptureData(&capture_buffers, kNumberOfBuffers);
  161. base::WaitableEvent all_data_processed;
  162. int buffer_number = 0;
  163. auto verify_sequential_data = [&](const media::AudioBus& process_data,
  164. base::TimeTicks capture_time, double volume,
  165. bool key_pressed) {
  166. // Callbacks should receive buffers from |capture_buffers| in the order in
  167. // which they are pushed.
  168. VerifyProcessingData(capture_buffers[buffer_number], process_data,
  169. capture_time, volume, key_pressed);
  170. if (++buffer_number == kNumberOfBuffers)
  171. all_data_processed.Signal();
  172. };
  173. SetupFifo(base::BindLambdaForTesting(verify_sequential_data));
  174. // Push all data at once.
  175. for (int i = 0; i < kNumberOfBuffers; ++i) {
  176. TestCaptureData& data = capture_buffers[i];
  177. fifo()->PushData(data.audio_bus.get(), data.capture_time, data.volume,
  178. data.key_pressed);
  179. }
  180. all_data_processed.Wait();
  181. EXPECT_EQ(buffer_number, kNumberOfBuffers);
  182. }
  183. TEST_F(ProcessingAudioFifoTest, PushData_MultipleBuffers_WaitBetweenBuffers) {
  184. // Make sure push enough buffers to overwrite old ones.
  185. const int kNumberOfBuffers = kTestFifoSize * 3;
  186. std::vector<TestCaptureData> capture_buffers;
  187. GenerateTestCaptureData(&capture_buffers, kNumberOfBuffers);
  188. base::WaitableEvent single_buffer_processed(
  189. base::WaitableEvent::ResetPolicy::AUTOMATIC);
  190. int buffer_number = 0;
  191. auto verify_sequential_data = [&](const media::AudioBus& process_data,
  192. base::TimeTicks capture_time, double volume,
  193. bool key_pressed) {
  194. // Callbacks should receive buffers from |capture_buffers| in the order in
  195. // which they are pushed.
  196. VerifyProcessingData(capture_buffers[buffer_number++], process_data,
  197. capture_time, volume, key_pressed);
  198. single_buffer_processed.Signal();
  199. };
  200. SetupFifo(base::BindLambdaForTesting(verify_sequential_data));
  201. // Wait for the previous buffer to be processed before pushing a new one.
  202. // This should guarantee we never drop buffers.
  203. for (int i = 0; i < kNumberOfBuffers; ++i) {
  204. TestCaptureData& data = capture_buffers[i];
  205. fifo()->PushData(data.audio_bus.get(), data.capture_time, data.volume,
  206. data.key_pressed);
  207. single_buffer_processed.Wait();
  208. }
  209. }
  210. TEST_F(ProcessingAudioFifoTest, ProcessesAllAvailableData) {
  211. // Stay below the FIFO's size to avoid dropping buffers.
  212. const int kNumberOfBuffers = kTestFifoSize;
  213. std::vector<TestCaptureData> capture_buffers;
  214. GenerateTestCaptureData(&capture_buffers, kNumberOfBuffers);
  215. base::WaitableEvent any_buffer_processed;
  216. base::WaitableEvent all_buffers_processed;
  217. int buffer_number = 0;
  218. auto verify_sequential_data = [&](const media::AudioBus& process_data,
  219. base::TimeTicks capture_time, double volume,
  220. bool key_pressed) {
  221. VerifyProcessingData(capture_buffers[buffer_number++], process_data,
  222. capture_time, volume, key_pressed);
  223. any_buffer_processed.Signal();
  224. if (buffer_number == kNumberOfBuffers)
  225. all_buffers_processed.Signal();
  226. };
  227. // The processing thread won't be woken up when new data is pushed.
  228. SetupFifoWithFakeEvent(base::BindLambdaForTesting(verify_sequential_data));
  229. // Push all data.
  230. for (int i = 0; i < kNumberOfBuffers; ++i) {
  231. TestCaptureData& data = capture_buffers[i];
  232. fifo()->PushData(data.audio_bus.get(), data.capture_time, data.volume,
  233. data.key_pressed);
  234. }
  235. // No data should have been processed by now.
  236. EXPECT_FALSE(any_buffer_processed.TimedWait(base::Milliseconds(10)));
  237. EXPECT_EQ(buffer_number, 0);
  238. // The processing thread should process all pending data at once.
  239. SignalFakeNewCaptureEvent();
  240. all_buffers_processed.Wait();
  241. }
  242. TEST_F(ProcessingAudioFifoTest, NoDataToProcess) {
  243. base::WaitableEvent processing_callback_called;
  244. SetupFifoWithFakeEvent(base::BindLambdaForTesting(
  245. [&](const media::AudioBus& process_data, base::TimeTicks capture_time,
  246. double volume, bool key_pressed) {
  247. ADD_FAILURE() << "Processing callback unexpectedly called";
  248. processing_callback_called.Signal();
  249. }));
  250. // Wake up the processing thread without any queued data. This might not
  251. // happen in practice, but the processing thread should be resilient to race
  252. // conditions nonetheless.
  253. SignalFakeNewCaptureEvent();
  254. EXPECT_FALSE(processing_callback_called.TimedWait(base::Milliseconds(10)));
  255. }
  256. TEST_F(ProcessingAudioFifoTest, DontProcessPendingDataDuringStop) {
  257. base::WaitableEvent processing_callback_called;
  258. SetupFifoWithFakeEvent(base::BindLambdaForTesting(
  259. [&](const media::AudioBus& process_data, base::TimeTicks capture_time,
  260. double volume, bool key_pressed) {
  261. ADD_FAILURE() << "Processing callback unexpectedly called";
  262. processing_callback_called.Signal();
  263. }));
  264. // Push data into the FIFO, without calling SignalFakeNewCaptureEvent().
  265. fifo()->PushData(CreateAudioData().get(), base::TimeTicks(), kTestVolume,
  266. true);
  267. // The pushed data should not be processed when we stop and destroy the FIFO.
  268. TearDownFifo();
  269. EXPECT_FALSE(processing_callback_called.TimedWait(base::Milliseconds(10)));
  270. }
  271. TEST_F(ProcessingAudioFifoTest, FifoFull_DroppedFrames) {
  272. // Make sure push enough buffers to overwrite old ones.
  273. const int kNumberOfBatches = 3;
  274. const int kBatchSize = kTestFifoSize;
  275. const int kNumberOfBuffers = kBatchSize * kNumberOfBatches;
  276. std::vector<TestCaptureData> capture_buffers;
  277. GenerateTestCaptureData(&capture_buffers, kNumberOfBuffers);
  278. // Get the buffer idx in |capture_buffers| from the batch and buffer number.
  279. auto get_idx = [](int buffer_number, int batch_number) {
  280. return buffer_number + batch_number * kBatchSize;
  281. };
  282. base::WaitableEvent buffer_batch_processed(
  283. base::WaitableEvent::ResetPolicy::AUTOMATIC);
  284. // This test pushes 3 batches of buffers of size kBatchSize into the FIFO.
  285. // The first batch will be queued, the second will be dropped; the third
  286. // batch will be queued, after the first batch is done processing.
  287. int buffer_number = 0;
  288. int batch_number = 0;
  289. auto verify_dropped_data = [&](const media::AudioBus& process_data,
  290. base::TimeTicks capture_time, double volume,
  291. bool key_pressed) {
  292. // Verify we don't get any buffers from the 2nd batch.
  293. VerifyProcessingData(capture_buffers[get_idx(buffer_number, batch_number)],
  294. process_data, capture_time, volume, key_pressed);
  295. if (++buffer_number == kBatchSize) {
  296. buffer_number = 0;
  297. batch_number = 2; // Skip from 1st to 3rd batch of buffers.
  298. buffer_batch_processed.Signal();
  299. }
  300. };
  301. SetupFifoWithFakeEvent(base::BindLambdaForTesting(verify_dropped_data));
  302. // Send 3 batches.
  303. for (int batch = 0; batch < kNumberOfBatches; ++batch) {
  304. // Queue a batch of buffers.
  305. for (int buffer = 0; buffer < kBatchSize; ++buffer) {
  306. TestCaptureData& data = capture_buffers[get_idx(buffer, batch)];
  307. fifo()->PushData(data.audio_bus.get(), data.capture_time, data.volume,
  308. data.key_pressed);
  309. }
  310. // Skip processing the first batch, ensuring the second batch will be
  311. // dropped.
  312. if (batch == 0)
  313. continue;
  314. // Process queued buffers.
  315. SignalFakeNewCaptureEvent();
  316. buffer_batch_processed.Wait();
  317. }
  318. }
  319. TEST_F(ProcessingAudioFifoTest, StopDuringBatchProcess) {
  320. const int kNumberOfBuffers = kTestFifoSize;
  321. std::vector<TestCaptureData> capture_buffers;
  322. GenerateTestCaptureData(&capture_buffers, kNumberOfBuffers);
  323. base::WaitableEvent any_buffer_processed(
  324. base::WaitableEvent::ResetPolicy::AUTOMATIC);
  325. base::WaitableEvent stop_flag_set;
  326. int number_of_calls = 0;
  327. auto verify_stopping = [&](const media::AudioBus& process_data,
  328. base::TimeTicks capture_time, double volume,
  329. bool key_pressed) {
  330. // We should only get one processing callback call, since calling
  331. // SetFifoStoppingFlag() should prevent further data from being processed.
  332. EXPECT_LE(++number_of_calls, 1);
  333. any_buffer_processed.Signal();
  334. stop_flag_set.Wait();
  335. };
  336. SetupFifoWithFakeEvent(base::BindLambdaForTesting(verify_stopping));
  337. // Queue data but don't process it.
  338. for (int i = 0; i < kNumberOfBuffers; ++i) {
  339. TestCaptureData& data = capture_buffers[i];
  340. fifo()->PushData(data.audio_bus.get(), data.capture_time, data.volume,
  341. data.key_pressed);
  342. }
  343. // Process a single buffer.
  344. SignalFakeNewCaptureEvent();
  345. any_buffer_processed.Wait();
  346. // Simulate StopProcessingLoop() being called (without stopping the processing
  347. // thread).
  348. SetFifoStoppingFlag();
  349. stop_flag_set.Signal();
  350. // The remaining buffers in the FIFO should not be processed.
  351. EXPECT_FALSE(any_buffer_processed.TimedWait(base::Milliseconds(10)));
  352. EXPECT_EQ(1, number_of_calls);
  353. // Explicitly destroy the FIFO, to avoid TSAN failures.
  354. TearDownFifo();
  355. }
  356. } // namespace audio