blob: bb3053d94641b723db0db0c0c8e0298bd63567c3 [file] [log] [blame]
Avi Drissmand6cdf9b2022-09-15 19:52:531// Copyright 2012 The Chromium Authors
[email protected]95674a72012-10-10 02:37:472// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Scott Nicholsd2375a32017-08-23 22:47:145#include "remoting/client/audio/audio_player.h"
[email protected]95674a72012-10-10 02:37:476
Scott Nicholsfb754cc2017-09-08 15:53:357#include <cstdint>
dcheng0765c492016-04-06 22:41:538#include <memory>
9
sergeyu77b42df82016-10-04 02:08:3810#include "base/callback.h"
[email protected]f9e3dde2012-10-10 04:19:5011#include "base/compiler_specific.h"
[email protected]95674a72012-10-10 02:37:4712#include "testing/gtest/include/gtest/gtest.h"
13
14namespace {
15
16const int kAudioSamplesPerFrame = 25;
17const int kAudioSampleBytes = 4;
18const int kAudioFrameBytes = kAudioSamplesPerFrame * kAudioSampleBytes;
19const int kPaddingBytes = 16;
20
Scott Nicholsd2375a32017-08-23 22:47:1421// TODO(nicholss): Update legacy audio player to use new audio buffer code.
[email protected]95674a72012-10-10 02:37:4722// TODO(garykac): Generate random audio data in the tests rather than having
23// a single constant value.
avi5a080f012015-12-22 23:15:4324const uint8_t kDefaultBufferData = 0x5A;
25const uint8_t kDummyAudioData = 0x8B;
[email protected]95674a72012-10-10 02:37:4726
27} // namespace
28
29namespace remoting {
30
31class FakeAudioPlayer : public AudioPlayer {
32 public:
Chris Watkins6fe52aa2017-11-28 03:24:0533 FakeAudioPlayer() = default;
[email protected]95674a72012-10-10 02:37:4734
dcheng562aba52014-10-21 12:30:1435 bool ResetAudioPlayer(AudioPacket::SamplingRate) override { return true; }
[email protected]95674a72012-10-10 02:37:4736
avi5a080f012015-12-22 23:15:4337 uint32_t GetSamplesPerFrame() override { return kAudioSamplesPerFrame; }
[email protected]95674a72012-10-10 02:37:4738};
39
40class AudioPlayerTest : public ::testing::Test {
41 protected:
dcheng440d8e1c2014-10-28 01:23:1542 void SetUp() override {
Peter Boström42afa23f2021-04-02 22:10:4643 audio_ = std::make_unique<FakeAudioPlayer>();
[email protected]95674a72012-10-10 02:37:4744 buffer_.reset(new char[kAudioFrameBytes + kPaddingBytes]);
45 }
46
dcheng440d8e1c2014-10-28 01:23:1547 void TearDown() override {}
[email protected]95674a72012-10-10 02:37:4748
49 void ConsumeAudioFrame() {
avi5a080f012015-12-22 23:15:4350 uint8_t* buffer = reinterpret_cast<uint8_t*>(buffer_.get());
[email protected]95674a72012-10-10 02:37:4751 memset(buffer, kDefaultBufferData, kAudioFrameBytes + kPaddingBytes);
52 AudioPlayer::AudioPlayerCallback(reinterpret_cast<void*>(buffer_.get()),
53 kAudioFrameBytes,
54 reinterpret_cast<void*>(audio_.get()));
55 // Verify we haven't written beyond the end of the buffer.
56 for (int i = 0; i < kPaddingBytes; i++)
57 ASSERT_EQ(kDefaultBufferData, *(buffer + kAudioFrameBytes + i));
58 }
59
60 // Check that the first |num_bytes| bytes are filled with audio data and
61 // the rest of the buffer is zero-filled.
62 void CheckAudioFrameBytes(int num_bytes) {
avi5a080f012015-12-22 23:15:4363 uint8_t* buffer = reinterpret_cast<uint8_t*>(buffer_.get());
[email protected]95674a72012-10-10 02:37:4764 int i = 0;
65 for (; i < num_bytes; i++) {
66 ASSERT_EQ(kDummyAudioData, *(buffer + i));
67 }
68 // Rest of audio frame must be filled with '0's.
69 for (; i < kAudioFrameBytes; i++) {
70 ASSERT_EQ(0, *(buffer + i));
71 }
72 }
73
[email protected]95674a72012-10-10 02:37:4774 int GetNumQueuedSamples() {
[email protected]b5528a22012-12-29 00:53:2575 return audio_->queued_bytes_ / kAudioSampleBytes;
[email protected]95674a72012-10-10 02:37:4776 }
77
78 int GetNumQueuedPackets() {
79 return static_cast<int>(audio_->queued_packets_.size());
80 }
81
Scott Nicholsd2375a32017-08-23 22:47:1482 int GetBytesConsumed() { return static_cast<int>(audio_->bytes_consumed_); }
[email protected]95674a72012-10-10 02:37:4783
dcheng0765c492016-04-06 22:41:5384 std::unique_ptr<AudioPlayer> audio_;
85 std::unique_ptr<char[]> buffer_;
[email protected]95674a72012-10-10 02:37:4786};
87
dcheng0765c492016-04-06 22:41:5388std::unique_ptr<AudioPacket> CreatePacketWithSamplingRate(
89 AudioPacket::SamplingRate rate,
90 int samples) {
91 std::unique_ptr<AudioPacket> packet(new AudioPacket());
[email protected]95674a72012-10-10 02:37:4792 packet->set_encoding(AudioPacket::ENCODING_RAW);
93 packet->set_sampling_rate(rate);
94 packet->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2);
95 packet->set_channels(AudioPacket::CHANNELS_STEREO);
96
97 // The data must be a multiple of 4 bytes (channels x bytes_per_sample).
98 std::string data;
99 data.resize(samples * kAudioSampleBytes, kDummyAudioData);
100 packet->add_data(data);
101
sergeyu42ad7c02015-12-24 00:20:51102 return packet;
[email protected]95674a72012-10-10 02:37:47103}
104
dcheng0765c492016-04-06 22:41:53105std::unique_ptr<AudioPacket> CreatePacket44100Hz(int samples) {
[email protected]95674a72012-10-10 02:37:47106 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_44100,
107 samples);
108}
109
dcheng0765c492016-04-06 22:41:53110std::unique_ptr<AudioPacket> CreatePacket48000Hz(int samples) {
[email protected]95674a72012-10-10 02:37:47111 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_48000,
112 samples);
113}
114
115TEST_F(AudioPlayerTest, Init) {
116 ASSERT_EQ(0, GetNumQueuedPackets());
117
Evan Stadeb36ca0a52020-03-12 15:56:52118 audio_->ProcessAudioPacket(CreatePacket44100Hz(10), {});
[email protected]95674a72012-10-10 02:37:47119 ASSERT_EQ(1, GetNumQueuedPackets());
120}
121
122TEST_F(AudioPlayerTest, MultipleSamples) {
Evan Stadeb36ca0a52020-03-12 15:56:52123 audio_->ProcessAudioPacket(CreatePacket44100Hz(10), {});
[email protected]95674a72012-10-10 02:37:47124 ASSERT_EQ(10, GetNumQueuedSamples());
125 ASSERT_EQ(1, GetNumQueuedPackets());
126
Evan Stadeb36ca0a52020-03-12 15:56:52127 audio_->ProcessAudioPacket(CreatePacket44100Hz(20), {});
[email protected]95674a72012-10-10 02:37:47128 ASSERT_EQ(30, GetNumQueuedSamples());
129 ASSERT_EQ(2, GetNumQueuedPackets());
130}
131
132TEST_F(AudioPlayerTest, ChangeSampleRate) {
Evan Stadeb36ca0a52020-03-12 15:56:52133 audio_->ProcessAudioPacket(CreatePacket44100Hz(10), {});
[email protected]95674a72012-10-10 02:37:47134 ASSERT_EQ(10, GetNumQueuedSamples());
135 ASSERT_EQ(1, GetNumQueuedPackets());
136
137 // New packet with different sampling rate causes previous samples to
138 // be removed.
Evan Stadeb36ca0a52020-03-12 15:56:52139 audio_->ProcessAudioPacket(CreatePacket48000Hz(20), {});
[email protected]95674a72012-10-10 02:37:47140 ASSERT_EQ(20, GetNumQueuedSamples());
141 ASSERT_EQ(1, GetNumQueuedPackets());
142}
143
144TEST_F(AudioPlayerTest, ExceedLatency) {
[email protected]b5528a22012-12-29 00:53:25145 // Push about 4 seconds worth of samples.
146 for (int i = 0; i < 100; ++i) {
Evan Stadeb36ca0a52020-03-12 15:56:52147 audio_->ProcessAudioPacket(CreatePacket48000Hz(2000), {});
[email protected]b5528a22012-12-29 00:53:25148 }
[email protected]95674a72012-10-10 02:37:47149
[email protected]b5528a22012-12-29 00:53:25150 // Verify that we don't have more than 0.5s.
151 EXPECT_LT(GetNumQueuedSamples(), 24000);
[email protected]95674a72012-10-10 02:37:47152}
153
154// Incoming packets: 100
155// Consume: 25 (w/ 75 remaining, offset 25 into packet)
156TEST_F(AudioPlayerTest, ConsumePartialPacket) {
157 int total_samples = 0;
158 int bytes_consumed = 0;
159
160 // Process 100 samples.
161 int packet1_samples = 100;
[email protected]95674a72012-10-10 02:37:47162 total_samples += packet1_samples;
Evan Stadeb36ca0a52020-03-12 15:56:52163 audio_->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples), {});
[email protected]95674a72012-10-10 02:37:47164 ASSERT_EQ(total_samples, GetNumQueuedSamples());
165 ASSERT_EQ(1, GetNumQueuedPackets());
166 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
167
168 // Consume one frame (=25) of samples.
169 ConsumeAudioFrame();
170 total_samples -= kAudioSamplesPerFrame;
171 bytes_consumed += kAudioFrameBytes;
172 ASSERT_EQ(total_samples, GetNumQueuedSamples());
173 ASSERT_EQ(1, GetNumQueuedPackets());
174 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
175 CheckAudioFrameBytes(kAudioFrameBytes);
176
177 // Remaining samples.
178 ASSERT_EQ(75, total_samples);
179 ASSERT_EQ(25 * kAudioSampleBytes, bytes_consumed);
180}
181
182// Incoming packets: 20, 70
183// Consume: 25, 25 (w/ 40 remaining, offset 30 into packet)
184TEST_F(AudioPlayerTest, ConsumeAcrossPackets) {
185 int total_samples = 0;
186 int bytes_consumed = 0;
187
188 // Packet 1.
189 int packet1_samples = 20;
[email protected]95674a72012-10-10 02:37:47190 total_samples += packet1_samples;
Evan Stadeb36ca0a52020-03-12 15:56:52191 audio_->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples), {});
[email protected]95674a72012-10-10 02:37:47192 ASSERT_EQ(total_samples, GetNumQueuedSamples());
193
194 // Packet 2.
195 int packet2_samples = 70;
[email protected]95674a72012-10-10 02:37:47196 total_samples += packet2_samples;
Evan Stadeb36ca0a52020-03-12 15:56:52197 audio_->ProcessAudioPacket(CreatePacket44100Hz(packet2_samples), {});
[email protected]95674a72012-10-10 02:37:47198 ASSERT_EQ(total_samples, GetNumQueuedSamples());
199 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
200
201 // Consume 1st frame of 25 samples.
202 // This will consume the entire 1st packet.
203 ConsumeAudioFrame();
204 total_samples -= kAudioSamplesPerFrame;
205 bytes_consumed += kAudioFrameBytes - (packet1_samples * kAudioSampleBytes);
206 ASSERT_EQ(total_samples, GetNumQueuedSamples());
207 ASSERT_EQ(1, GetNumQueuedPackets());
208 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
209 CheckAudioFrameBytes(kAudioFrameBytes);
210
211 // Consume 2nd frame of 25 samples.
212 ConsumeAudioFrame();
213 total_samples -= kAudioSamplesPerFrame;
214 bytes_consumed += kAudioFrameBytes;
215 ASSERT_EQ(total_samples, GetNumQueuedSamples());
216 ASSERT_EQ(1, GetNumQueuedPackets());
217 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
218 CheckAudioFrameBytes(kAudioFrameBytes);
219
220 // Remaining samples.
221 ASSERT_EQ(40, total_samples);
222 ASSERT_EQ(30 * kAudioSampleBytes, bytes_consumed);
223}
224
225// Incoming packets: 50, 30
226// Consume: 25, 25, 25 (w/ 5 remaining, offset 25 into packet)
227TEST_F(AudioPlayerTest, ConsumeEntirePacket) {
228 int total_samples = 0;
229 int bytes_consumed = 0;
230
231 // Packet 1.
232 int packet1_samples = 50;
[email protected]95674a72012-10-10 02:37:47233 total_samples += packet1_samples;
Evan Stadeb36ca0a52020-03-12 15:56:52234 audio_->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples), {});
[email protected]95674a72012-10-10 02:37:47235 ASSERT_EQ(total_samples, GetNumQueuedSamples());
236 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
237
238 // Packet 2.
239 int packet2_samples = 30;
[email protected]95674a72012-10-10 02:37:47240 total_samples += packet2_samples;
Evan Stadeb36ca0a52020-03-12 15:56:52241 audio_->ProcessAudioPacket(CreatePacket44100Hz(packet2_samples), {});
[email protected]95674a72012-10-10 02:37:47242 ASSERT_EQ(total_samples, GetNumQueuedSamples());
243 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
244
245 // Consume 1st frame of 25 samples.
246 ConsumeAudioFrame();
247 total_samples -= kAudioSamplesPerFrame;
248 bytes_consumed += kAudioFrameBytes;
249 ASSERT_EQ(total_samples, GetNumQueuedSamples());
250 ASSERT_EQ(2, GetNumQueuedPackets());
251 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
252 CheckAudioFrameBytes(kAudioFrameBytes);
253
254 // Consume 2nd frame of 25 samples.
255 // This will consume the entire first packet (exactly), but the entry for
256 // this packet will stick around (empty) until the next audio chunk is
257 // consumed.
258 ConsumeAudioFrame();
259 total_samples -= kAudioSamplesPerFrame;
260 bytes_consumed += kAudioFrameBytes;
261 ASSERT_EQ(total_samples, GetNumQueuedSamples());
262 ASSERT_EQ(2, GetNumQueuedPackets());
263 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
264 CheckAudioFrameBytes(kAudioFrameBytes);
265
266 // Consume 3rd frame of 25 samples.
267 ConsumeAudioFrame();
268 total_samples -= kAudioSamplesPerFrame;
269 bytes_consumed += kAudioFrameBytes - (packet1_samples * kAudioSampleBytes);
270 ASSERT_EQ(total_samples, GetNumQueuedSamples());
271 ASSERT_EQ(1, GetNumQueuedPackets());
272 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
273 CheckAudioFrameBytes(kAudioFrameBytes);
274
275 // Remaining samples.
276 ASSERT_EQ(5, total_samples);
277 ASSERT_EQ(25 * kAudioSampleBytes, bytes_consumed);
278}
279
280// Incoming packets: <none>
281// Consume: 25
282TEST_F(AudioPlayerTest, NoDataToConsume) {
283 // Attempt to consume a frame of 25 samples.
284 ConsumeAudioFrame();
285 ASSERT_EQ(0, GetNumQueuedSamples());
286 ASSERT_EQ(0, GetNumQueuedPackets());
287 ASSERT_EQ(0, GetBytesConsumed());
288 CheckAudioFrameBytes(0);
289}
290
291// Incoming packets: 10
292// Consume: 25
293TEST_F(AudioPlayerTest, NotEnoughDataToConsume) {
294 int total_samples = 0;
295 int bytes_consumed = 0;
296
297 // Packet 1.
298 int packet1_samples = 10;
[email protected]95674a72012-10-10 02:37:47299 total_samples += packet1_samples;
Evan Stadeb36ca0a52020-03-12 15:56:52300 audio_->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples), {});
[email protected]95674a72012-10-10 02:37:47301 ASSERT_EQ(total_samples, GetNumQueuedSamples());
302 ASSERT_EQ(bytes_consumed, GetBytesConsumed());
303
304 // Attempt to consume a frame of 25 samples.
305 ConsumeAudioFrame();
306 ASSERT_EQ(0, GetNumQueuedSamples());
307 ASSERT_EQ(0, GetNumQueuedPackets());
308 ASSERT_EQ(0, GetBytesConsumed());
309 CheckAudioFrameBytes(packet1_samples * kAudioSampleBytes);
310}
311
312} // namespace remoting