blob: dfc4ff72e02d696070dd5d0513cc6cde23130894 [file] [log] [blame]
Avi Drissmand6cdf9b2022-09-15 19:52:531// Copyright 2018 The Chromium Authors
Yuwei Huang5c93d5cc2018-08-03 23:58:182// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <cstdint>
6#include <list>
7#include <memory>
8#include <string>
9
10#include "base/bind.h"
11#include "base/callback.h"
Keishi Hattori0e45c022021-11-27 09:25:5212#include "base/memory/raw_ptr.h"
Gabriel Charetted87f10f2022-03-31 00:44:2213#include "base/time/time.h"
Yuwei Huang5c93d5cc2018-08-03 23:58:1814#include "remoting/client/audio/audio_jitter_buffer.h"
Yuwei Huang40c532242018-08-09 05:42:2715#include "remoting/client/audio/audio_stream_format.h"
Yuwei Huang5c93d5cc2018-08-03 23:58:1816#include "testing/gtest/include/gtest/gtest.h"
17
18namespace remoting {
19
20namespace {
21
22constexpr AudioPacket::BytesPerSample kBytesPerSample =
23 AudioPacket::BYTES_PER_SAMPLE_2;
24constexpr AudioPacket::Channels kChannels = AudioPacket::CHANNELS_STEREO;
Peter Kasting0265c3d2022-05-06 21:10:0525constexpr uint32_t kAudioSampleBytes = uint32_t{kChannels} * kBytesPerSample;
Yuwei Huang5c93d5cc2018-08-03 23:58:1826
27constexpr uint32_t kNumConsumerBuffers = 3;
28constexpr uint32_t kConsumerBufferMaxByteSize = 5000 * kAudioSampleBytes;
29
30constexpr uint8_t kDefaultBufferData = 0x5A;
31constexpr uint8_t kDummyAudioData = 0x8B;
32
33std::unique_ptr<AudioPacket> CreateAudioPacketWithSamplingRate(
34 AudioPacket::SamplingRate rate,
35 size_t bytes) {
36 std::unique_ptr<AudioPacket> packet = std::make_unique<AudioPacket>();
37 packet->set_encoding(AudioPacket::ENCODING_RAW);
38 packet->set_sampling_rate(rate);
39 packet->set_bytes_per_sample(kBytesPerSample);
40 packet->set_channels(kChannels);
41
42 std::string data;
43 data.resize(bytes, kDummyAudioData);
44 packet->add_data(data);
45
46 return packet;
47}
48
49// Check that the first |bytes_written| bytes are filled with audio data and
50// the rest of the buffer is unchanged.
51void CheckDataBytes(const uint8_t* buffer, size_t bytes_written) {
52 uint32_t i = 0;
53 for (; i < bytes_written; i++) {
54 ASSERT_EQ(kDummyAudioData, *(buffer + i));
55 }
56 // Rest of audio frame must be unchanged.
57 for (; i < kConsumerBufferMaxByteSize; i++) {
58 ASSERT_EQ(kDefaultBufferData, *(buffer + i));
59 }
60}
61
62} // namespace
63
64class AudioJitterBufferTest : public ::testing::Test {
65 protected:
66 void SetUp() override;
67 void TearDown() override;
68
69 void SetSampleRate(AudioPacket::SamplingRate sample_rate);
70 std::unique_ptr<AudioPacket> CreatePacket(int time_ms);
71 void AsyncConsumeData(size_t duration);
72 void VerifyStreamFormat();
73 void VerifyBuffersNotLost();
74 size_t ByteFromTime(int time_ms) const;
75 size_t GetNumQueuedPackets() const;
76 int GetNumQueuedTime() const;
77 size_t GetNumQueuedRequests() const;
78
79 std::unique_ptr<AudioJitterBuffer> audio_;
80 std::list<std::unique_ptr<uint8_t[]>> consumer_buffers_;
81
82 private:
Yuwei Huang40c532242018-08-09 05:42:2783 class SimpleGetDataRequest;
Yuwei Huang5c93d5cc2018-08-03 23:58:1884
Yuwei Huang40c532242018-08-09 05:42:2785 void OnFormatChanged(const AudioStreamFormat& format);
Yuwei Huang5c93d5cc2018-08-03 23:58:1886
87 AudioPacket::SamplingRate sample_rate_;
Yuwei Huang40c532242018-08-09 05:42:2788 std::unique_ptr<AudioStreamFormat> stream_format_;
Yuwei Huang5c93d5cc2018-08-03 23:58:1889};
90
Yuwei Huang40c532242018-08-09 05:42:2791class AudioJitterBufferTest::SimpleGetDataRequest
Yuwei Huang5c93d5cc2018-08-03 23:58:1892 : public AsyncAudioDataSupplier::GetDataRequest {
93 public:
94 SimpleGetDataRequest(AudioJitterBufferTest* test, size_t bytes_to_write);
95 ~SimpleGetDataRequest() override;
96
97 void OnDataFilled() override;
98
99 private:
Keishi Hattori0e45c022021-11-27 09:25:52100 raw_ptr<AudioJitterBufferTest> test_;
Yuwei Huang5c93d5cc2018-08-03 23:58:18101 std::unique_ptr<uint8_t[]> buffer_;
102 size_t bytes_to_write_;
103};
104
105// Test fixture definitions
106
107void AudioJitterBufferTest::SetUp() {
108 audio_ = std::make_unique<AudioJitterBuffer>(base::BindRepeating(
109 &AudioJitterBufferTest::OnFormatChanged, base::Unretained(this)));
110 consumer_buffers_.clear();
111 for (uint32_t i = 0u; i < kNumConsumerBuffers; i++) {
112 consumer_buffers_.push_back(
113 std::make_unique<uint8_t[]>(kConsumerBufferMaxByteSize));
114 }
115 SetSampleRate(AudioPacket::SAMPLING_RATE_48000);
116}
117
118void AudioJitterBufferTest::TearDown() {
119 VerifyBuffersNotLost();
120 audio_.reset();
121 consumer_buffers_.clear();
122}
123
124void AudioJitterBufferTest::SetSampleRate(
125 AudioPacket::SamplingRate sample_rate) {
126 sample_rate_ = sample_rate;
127}
128
129std::unique_ptr<AudioPacket> AudioJitterBufferTest::CreatePacket(int time_ms) {
130 return CreateAudioPacketWithSamplingRate(sample_rate_, ByteFromTime(time_ms));
131}
132
133void AudioJitterBufferTest::AsyncConsumeData(size_t duration) {
134 size_t bytes_to_write = ByteFromTime(duration);
135 ASSERT_LE(bytes_to_write, kConsumerBufferMaxByteSize);
136 ASSERT_FALSE(consumer_buffers_.empty());
137 audio_->AsyncGetData(
138 std::make_unique<SimpleGetDataRequest>(this, bytes_to_write));
139}
140
141void AudioJitterBufferTest::VerifyStreamFormat() {
142 ASSERT_TRUE(stream_format_);
143 ASSERT_EQ(kBytesPerSample, stream_format_->bytes_per_sample);
144 ASSERT_EQ(kChannels, stream_format_->channels);
145 ASSERT_EQ(sample_rate_, stream_format_->sample_rate);
146}
147
148void AudioJitterBufferTest::VerifyBuffersNotLost() {
149 size_t queued_requests = GetNumQueuedRequests();
150 ASSERT_EQ(kNumConsumerBuffers, queued_requests + consumer_buffers_.size());
151}
152
153size_t AudioJitterBufferTest::ByteFromTime(int time_ms) const {
154 return time_ms * sample_rate_ * kAudioSampleBytes /
155 base::Time::kMillisecondsPerSecond;
156}
157
158size_t AudioJitterBufferTest::GetNumQueuedPackets() const {
159 return audio_->queued_packets_.size();
160}
161
162int AudioJitterBufferTest::GetNumQueuedTime() const {
163 return audio_->queued_bytes_ * base::Time::kMillisecondsPerSecond /
164 kAudioSampleBytes / sample_rate_;
165}
166
167size_t AudioJitterBufferTest::GetNumQueuedRequests() const {
168 return audio_->queued_requests_.size();
169}
Yuwei Huang40c532242018-08-09 05:42:27170void AudioJitterBufferTest::OnFormatChanged(const AudioStreamFormat& format) {
171 stream_format_ = std::make_unique<AudioStreamFormat>(format);
Yuwei Huang5c93d5cc2018-08-03 23:58:18172}
173
174// SimpleGetDataRequest definitions
175
176AudioJitterBufferTest::SimpleGetDataRequest::SimpleGetDataRequest(
177 AudioJitterBufferTest* test,
178 size_t bytes_to_write)
179 : GetDataRequest(test->consumer_buffers_.front().get(), bytes_to_write),
180 test_(test),
181 buffer_(std::move(test->consumer_buffers_.front())),
182 bytes_to_write_(bytes_to_write) {
183 test_->consumer_buffers_.pop_front();
184 memset(buffer_.get(), kDefaultBufferData, kConsumerBufferMaxByteSize);
185}
186
187AudioJitterBufferTest::SimpleGetDataRequest::~SimpleGetDataRequest() {
188 if (buffer_) {
189 test_->consumer_buffers_.push_back(std::move(buffer_));
190 }
191}
192
193void AudioJitterBufferTest::SimpleGetDataRequest::OnDataFilled() {
194 CheckDataBytes(buffer_.get(), bytes_to_write_);
195 test_->consumer_buffers_.push_back(std::move(buffer_));
196}
197
198// Test cases
199
200TEST_F(AudioJitterBufferTest, Init) {
201 ASSERT_EQ(0u, GetNumQueuedPackets());
202
203 audio_->AddAudioPacket(CreatePacket(20));
204 ASSERT_EQ(1u, GetNumQueuedPackets());
205 VerifyStreamFormat();
206}
207
208TEST_F(AudioJitterBufferTest, MultipleSamples) {
209 audio_->AddAudioPacket(CreatePacket(10));
210 ASSERT_EQ(10, GetNumQueuedTime());
211 ASSERT_EQ(1u, GetNumQueuedPackets());
212
213 audio_->AddAudioPacket(CreatePacket(20));
214 ASSERT_EQ(30, GetNumQueuedTime());
215 ASSERT_EQ(2u, GetNumQueuedPackets());
216}
217
218TEST_F(AudioJitterBufferTest, ExceedLatency) {
219 // Push about 4 seconds worth of samples.
220 for (uint32_t i = 0; i < 100; ++i) {
221 audio_->AddAudioPacket(CreatePacket(40));
222 }
223
224 // Verify that we don't have more than 0.5s.
225 ASSERT_LT(GetNumQueuedTime(), 500);
226}
227
228TEST_F(AudioJitterBufferTest, SingleAsyncRequest_UnderrunProtection) {
229 // Add samples that are enough to fulfill one request but still doesn't get
230 // passed the underrun protection.
231 audio_->AddAudioPacket(CreatePacket(10));
232
233 // Create an Audio Request.
234 AsyncConsumeData(10);
235
236 // The request is not fulfilled.
237 ASSERT_EQ(1u, GetNumQueuedPackets());
238 ASSERT_EQ(1u, GetNumQueuedRequests());
239}
240
241TEST_F(AudioJitterBufferTest, SingleAsyncRequest_Fulfilled) {
242 // Add samples that are enough to bypass underrun protection.
243 audio_->AddAudioPacket(CreatePacket(80));
244
245 // Create an Audio Request.
246 AsyncConsumeData(10);
247
248 // Request is fulfilled and buffer is returned.
249 ASSERT_EQ(1u, GetNumQueuedPackets());
250 ASSERT_EQ(0u, GetNumQueuedRequests());
251}
252
253TEST_F(AudioJitterBufferTest, TwoAsyncRequest_FulfillOneByOne) {
254 // Add just enough samples to fulfill one request.
255 audio_->AddAudioPacket(CreatePacket(80));
256 ASSERT_EQ(1u, GetNumQueuedPackets());
257
258 AsyncConsumeData(80);
259 // Request is immediately fulfilled.
260 ASSERT_EQ(0u, GetNumQueuedPackets());
261 ASSERT_EQ(0u, GetNumQueuedRequests());
262 VerifyBuffersNotLost();
263
264 // Add another request.
265 AsyncConsumeData(80);
266 ASSERT_EQ(0u, GetNumQueuedPackets());
267 ASSERT_EQ(1u, GetNumQueuedRequests());
268 VerifyBuffersNotLost();
269
270 // Add packet fulfill the request.
271 audio_->AddAudioPacket(CreatePacket(80));
272 ASSERT_EQ(0u, GetNumQueuedPackets());
273 ASSERT_EQ(0u, GetNumQueuedRequests());
274}
275
276TEST_F(AudioJitterBufferTest, TwoAsyncRequest_OnePacketFulfillsTwoRequests) {
277 // Add packet big enough to fulfill two requests.
278 audio_->AddAudioPacket(CreatePacket(100));
279 ASSERT_EQ(1u, GetNumQueuedPackets());
280
281 AsyncConsumeData(50);
282 // Request is immediately fulfilled.
283 ASSERT_EQ(1u, GetNumQueuedPackets());
284 ASSERT_EQ(0u, GetNumQueuedRequests());
285 VerifyBuffersNotLost();
286
287 // Add another request.
288 AsyncConsumeData(50);
289 ASSERT_EQ(0u, GetNumQueuedPackets());
290 ASSERT_EQ(0u, GetNumQueuedRequests());
291}
292
293TEST_F(AudioJitterBufferTest, TwoAsyncRequest_UnderrunProtectionKicksIn) {
294 audio_->AddAudioPacket(CreatePacket(80));
295 ASSERT_EQ(1u, GetNumQueuedPackets());
296
297 // Consumes all packets while still waiting for 20ms of more data.
298 AsyncConsumeData(100);
299 ASSERT_EQ(0u, GetNumQueuedPackets());
300 ASSERT_EQ(1u, GetNumQueuedRequests());
301 VerifyBuffersNotLost();
302
303 // The package does not get pass underrun protection.
304 audio_->AddAudioPacket(CreatePacket(20));
305 ASSERT_EQ(1u, GetNumQueuedPackets());
306 ASSERT_EQ(1u, GetNumQueuedRequests());
307
308 // Add a bigger packet, which bypasses underrun protection.
309 audio_->AddAudioPacket(CreatePacket(100));
310 ASSERT_EQ(1u, GetNumQueuedPackets());
311 ASSERT_EQ(0u, GetNumQueuedRequests());
312}
313
314TEST_F(AudioJitterBufferTest, TwoAsyncRequest_TwoPacketsFulfillTwoRequests) {
315 // Add sample that doesn't fulfill the first request.
316 audio_->AddAudioPacket(CreatePacket(70));
317
318 // Create two requests.
319 AsyncConsumeData(80);
320 AsyncConsumeData(80);
321
322 // The first packet has been used to fill the first request.
323 ASSERT_EQ(0u, GetNumQueuedPackets());
324 ASSERT_EQ(2u, GetNumQueuedRequests());
325 VerifyBuffersNotLost();
326
327 // Add the rest to fulfill both requests.
328 audio_->AddAudioPacket(CreatePacket(90));
329 ASSERT_EQ(0u, GetNumQueuedPackets());
330 ASSERT_EQ(0u, GetNumQueuedRequests());
331}
332
333TEST_F(AudioJitterBufferTest, ChangeSampleRate) {
334 ASSERT_EQ(0u, GetNumQueuedPackets());
335
336 audio_->AddAudioPacket(CreatePacket(20));
337 AsyncConsumeData(80);
338 ASSERT_EQ(1u, GetNumQueuedPackets());
339 ASSERT_EQ(1u, GetNumQueuedRequests());
340 VerifyBuffersNotLost();
341 VerifyStreamFormat();
342
343 SetSampleRate(AudioPacket::SAMPLING_RATE_44100);
344 audio_->AddAudioPacket(CreatePacket(20));
345 // Previous packet has been removed.
346 ASSERT_EQ(1u, GetNumQueuedPackets());
347
348 // Previous pending requests are cleared and callbacks has been run.
349 ASSERT_EQ(0u, GetNumQueuedRequests());
350 VerifyStreamFormat();
351}
352
353} // namespace remoting