1 // Copyright (c) 2012 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.
5 #include "remoting/client/audio_player.h"
7 #include "base/compiler_specific.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "testing/gtest/include/gtest/gtest.h"
13 const int kAudioSamplesPerFrame
= 25;
14 const int kAudioSampleBytes
= 4;
15 const int kAudioFrameBytes
= kAudioSamplesPerFrame
* kAudioSampleBytes
;
16 const int kPaddingBytes
= 16;
18 // TODO(garykac): Generate random audio data in the tests rather than having
19 // a single constant value.
20 const uint8 kDefaultBufferData
= 0x5A;
21 const uint8 kDummyAudioData
= 0x8B;
27 class FakeAudioPlayer
: public AudioPlayer
{
32 bool ResetAudioPlayer(AudioPacket::SamplingRate
) override
{ return true; }
34 uint32
GetSamplesPerFrame() override
{ return kAudioSamplesPerFrame
; }
37 class AudioPlayerTest
: public ::testing::Test
{
39 void SetUp() override
{
40 audio_
.reset(new FakeAudioPlayer());
41 buffer_
.reset(new char[kAudioFrameBytes
+ kPaddingBytes
]);
44 void TearDown() override
{}
46 void ConsumeAudioFrame() {
47 uint8
* buffer
= reinterpret_cast<uint8
*>(buffer_
.get());
48 memset(buffer
, kDefaultBufferData
, kAudioFrameBytes
+ kPaddingBytes
);
49 AudioPlayer::AudioPlayerCallback(reinterpret_cast<void*>(buffer_
.get()),
51 reinterpret_cast<void*>(audio_
.get()));
52 // Verify we haven't written beyond the end of the buffer.
53 for (int i
= 0; i
< kPaddingBytes
; i
++)
54 ASSERT_EQ(kDefaultBufferData
, *(buffer
+ kAudioFrameBytes
+ i
));
57 // Check that the first |num_bytes| bytes are filled with audio data and
58 // the rest of the buffer is zero-filled.
59 void CheckAudioFrameBytes(int num_bytes
) {
60 uint8
* buffer
= reinterpret_cast<uint8
*>(buffer_
.get());
62 for (; i
< num_bytes
; i
++) {
63 ASSERT_EQ(kDummyAudioData
, *(buffer
+ i
));
65 // Rest of audio frame must be filled with '0's.
66 for (; i
< kAudioFrameBytes
; i
++) {
67 ASSERT_EQ(0, *(buffer
+ i
));
71 int GetNumQueuedSamples() {
72 return audio_
->queued_bytes_
/ kAudioSampleBytes
;
75 int GetNumQueuedPackets() {
76 return static_cast<int>(audio_
->queued_packets_
.size());
79 int GetBytesConsumed() {
80 return static_cast<int>(audio_
->bytes_consumed_
);
83 scoped_ptr
<AudioPlayer
> audio_
;
84 scoped_ptr
<char[]> buffer_
;
87 scoped_ptr
<AudioPacket
> CreatePacketWithSamplingRate(
88 AudioPacket::SamplingRate rate
, int samples
) {
89 scoped_ptr
<AudioPacket
> packet(new AudioPacket());
90 packet
->set_encoding(AudioPacket::ENCODING_RAW
);
91 packet
->set_sampling_rate(rate
);
92 packet
->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2
);
93 packet
->set_channels(AudioPacket::CHANNELS_STEREO
);
95 // The data must be a multiple of 4 bytes (channels x bytes_per_sample).
97 data
.resize(samples
* kAudioSampleBytes
, kDummyAudioData
);
98 packet
->add_data(data
);
100 return packet
.Pass();
103 scoped_ptr
<AudioPacket
> CreatePacket44100Hz(int samples
) {
104 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_44100
,
108 scoped_ptr
<AudioPacket
> CreatePacket48000Hz(int samples
) {
109 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_48000
,
113 TEST_F(AudioPlayerTest
, Init
) {
114 ASSERT_EQ(0, GetNumQueuedPackets());
116 audio_
->ProcessAudioPacket(CreatePacket44100Hz(10));
117 ASSERT_EQ(1, GetNumQueuedPackets());
120 TEST_F(AudioPlayerTest
, MultipleSamples
) {
121 audio_
->ProcessAudioPacket(CreatePacket44100Hz(10));
122 ASSERT_EQ(10, GetNumQueuedSamples());
123 ASSERT_EQ(1, GetNumQueuedPackets());
125 audio_
->ProcessAudioPacket(CreatePacket44100Hz(20));
126 ASSERT_EQ(30, GetNumQueuedSamples());
127 ASSERT_EQ(2, GetNumQueuedPackets());
130 TEST_F(AudioPlayerTest
, ChangeSampleRate
) {
131 audio_
->ProcessAudioPacket(CreatePacket44100Hz(10));
132 ASSERT_EQ(10, GetNumQueuedSamples());
133 ASSERT_EQ(1, GetNumQueuedPackets());
135 // New packet with different sampling rate causes previous samples to
137 audio_
->ProcessAudioPacket(CreatePacket48000Hz(20));
138 ASSERT_EQ(20, GetNumQueuedSamples());
139 ASSERT_EQ(1, GetNumQueuedPackets());
142 TEST_F(AudioPlayerTest
, ExceedLatency
) {
143 // Push about 4 seconds worth of samples.
144 for (int i
= 0; i
< 100; ++i
) {
145 audio_
->ProcessAudioPacket(CreatePacket48000Hz(2000));
148 // Verify that we don't have more than 0.5s.
149 EXPECT_LT(GetNumQueuedSamples(), 24000);
152 // Incoming packets: 100
153 // Consume: 25 (w/ 75 remaining, offset 25 into packet)
154 TEST_F(AudioPlayerTest
, ConsumePartialPacket
) {
155 int total_samples
= 0;
156 int bytes_consumed
= 0;
158 // Process 100 samples.
159 int packet1_samples
= 100;
160 total_samples
+= packet1_samples
;
161 audio_
->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples
));
162 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
163 ASSERT_EQ(1, GetNumQueuedPackets());
164 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
166 // Consume one frame (=25) of samples.
168 total_samples
-= kAudioSamplesPerFrame
;
169 bytes_consumed
+= kAudioFrameBytes
;
170 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
171 ASSERT_EQ(1, GetNumQueuedPackets());
172 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
173 CheckAudioFrameBytes(kAudioFrameBytes
);
175 // Remaining samples.
176 ASSERT_EQ(75, total_samples
);
177 ASSERT_EQ(25 * kAudioSampleBytes
, bytes_consumed
);
180 // Incoming packets: 20, 70
181 // Consume: 25, 25 (w/ 40 remaining, offset 30 into packet)
182 TEST_F(AudioPlayerTest
, ConsumeAcrossPackets
) {
183 int total_samples
= 0;
184 int bytes_consumed
= 0;
187 int packet1_samples
= 20;
188 total_samples
+= packet1_samples
;
189 audio_
->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples
));
190 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
193 int packet2_samples
= 70;
194 total_samples
+= packet2_samples
;
195 audio_
->ProcessAudioPacket(CreatePacket44100Hz(packet2_samples
));
196 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
197 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
199 // Consume 1st frame of 25 samples.
200 // This will consume the entire 1st packet.
202 total_samples
-= kAudioSamplesPerFrame
;
203 bytes_consumed
+= kAudioFrameBytes
- (packet1_samples
* kAudioSampleBytes
);
204 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
205 ASSERT_EQ(1, GetNumQueuedPackets());
206 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
207 CheckAudioFrameBytes(kAudioFrameBytes
);
209 // Consume 2nd frame of 25 samples.
211 total_samples
-= kAudioSamplesPerFrame
;
212 bytes_consumed
+= kAudioFrameBytes
;
213 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
214 ASSERT_EQ(1, GetNumQueuedPackets());
215 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
216 CheckAudioFrameBytes(kAudioFrameBytes
);
218 // Remaining samples.
219 ASSERT_EQ(40, total_samples
);
220 ASSERT_EQ(30 * kAudioSampleBytes
, bytes_consumed
);
223 // Incoming packets: 50, 30
224 // Consume: 25, 25, 25 (w/ 5 remaining, offset 25 into packet)
225 TEST_F(AudioPlayerTest
, ConsumeEntirePacket
) {
226 int total_samples
= 0;
227 int bytes_consumed
= 0;
230 int packet1_samples
= 50;
231 total_samples
+= packet1_samples
;
232 audio_
->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples
));
233 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
234 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
237 int packet2_samples
= 30;
238 total_samples
+= packet2_samples
;
239 audio_
->ProcessAudioPacket(CreatePacket44100Hz(packet2_samples
));
240 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
241 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
243 // Consume 1st frame of 25 samples.
245 total_samples
-= kAudioSamplesPerFrame
;
246 bytes_consumed
+= kAudioFrameBytes
;
247 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
248 ASSERT_EQ(2, GetNumQueuedPackets());
249 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
250 CheckAudioFrameBytes(kAudioFrameBytes
);
252 // Consume 2nd frame of 25 samples.
253 // This will consume the entire first packet (exactly), but the entry for
254 // this packet will stick around (empty) until the next audio chunk is
257 total_samples
-= kAudioSamplesPerFrame
;
258 bytes_consumed
+= kAudioFrameBytes
;
259 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
260 ASSERT_EQ(2, GetNumQueuedPackets());
261 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
262 CheckAudioFrameBytes(kAudioFrameBytes
);
264 // Consume 3rd frame of 25 samples.
266 total_samples
-= kAudioSamplesPerFrame
;
267 bytes_consumed
+= kAudioFrameBytes
- (packet1_samples
* kAudioSampleBytes
);
268 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
269 ASSERT_EQ(1, GetNumQueuedPackets());
270 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
271 CheckAudioFrameBytes(kAudioFrameBytes
);
273 // Remaining samples.
274 ASSERT_EQ(5, total_samples
);
275 ASSERT_EQ(25 * kAudioSampleBytes
, bytes_consumed
);
278 // Incoming packets: <none>
280 TEST_F(AudioPlayerTest
, NoDataToConsume
) {
281 // Attempt to consume a frame of 25 samples.
283 ASSERT_EQ(0, GetNumQueuedSamples());
284 ASSERT_EQ(0, GetNumQueuedPackets());
285 ASSERT_EQ(0, GetBytesConsumed());
286 CheckAudioFrameBytes(0);
289 // Incoming packets: 10
291 TEST_F(AudioPlayerTest
, NotEnoughDataToConsume
) {
292 int total_samples
= 0;
293 int bytes_consumed
= 0;
296 int packet1_samples
= 10;
297 total_samples
+= packet1_samples
;
298 audio_
->ProcessAudioPacket(CreatePacket44100Hz(packet1_samples
));
299 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
300 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
302 // Attempt to consume a frame of 25 samples.
304 ASSERT_EQ(0, GetNumQueuedSamples());
305 ASSERT_EQ(0, GetNumQueuedPackets());
306 ASSERT_EQ(0, GetBytesConsumed());
307 CheckAudioFrameBytes(packet1_samples
* kAudioSampleBytes
);
310 } // namespace remoting