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 virtual bool ResetAudioPlayer(AudioPacket::SamplingRate
) OVERRIDE
{
36 virtual uint32
GetSamplesPerFrame() OVERRIDE
{
37 return kAudioSamplesPerFrame
;
41 class AudioPlayerTest
: public ::testing::Test
{
43 virtual void SetUp() {
44 audio_
.reset(new FakeAudioPlayer());
45 buffer_
.reset(new char[kAudioFrameBytes
+ kPaddingBytes
]);
48 virtual void TearDown() {
51 void ConsumeAudioFrame() {
52 uint8
* buffer
= reinterpret_cast<uint8
*>(buffer_
.get());
53 memset(buffer
, kDefaultBufferData
, kAudioFrameBytes
+ kPaddingBytes
);
54 AudioPlayer::AudioPlayerCallback(reinterpret_cast<void*>(buffer_
.get()),
56 reinterpret_cast<void*>(audio_
.get()));
57 // Verify we haven't written beyond the end of the buffer.
58 for (int i
= 0; i
< kPaddingBytes
; i
++)
59 ASSERT_EQ(kDefaultBufferData
, *(buffer
+ kAudioFrameBytes
+ i
));
62 // Check that the first |num_bytes| bytes are filled with audio data and
63 // the rest of the buffer is zero-filled.
64 void CheckAudioFrameBytes(int num_bytes
) {
65 uint8
* buffer
= reinterpret_cast<uint8
*>(buffer_
.get());
67 for (; i
< num_bytes
; i
++) {
68 ASSERT_EQ(kDummyAudioData
, *(buffer
+ i
));
70 // Rest of audio frame must be filled with '0's.
71 for (; i
< kAudioFrameBytes
; i
++) {
72 ASSERT_EQ(0, *(buffer
+ i
));
76 int GetNumQueuedSamples() {
77 return audio_
->queued_bytes_
/ kAudioSampleBytes
;
80 int GetNumQueuedPackets() {
81 return static_cast<int>(audio_
->queued_packets_
.size());
84 int GetBytesConsumed() {
85 return static_cast<int>(audio_
->bytes_consumed_
);
88 scoped_ptr
<AudioPlayer
> audio_
;
89 scoped_ptr
<char[]> buffer_
;
92 scoped_ptr
<AudioPacket
> CreatePacketWithSamplingRate(
93 AudioPacket::SamplingRate rate
, int samples
) {
94 scoped_ptr
<AudioPacket
> packet(new AudioPacket());
95 packet
->set_encoding(AudioPacket::ENCODING_RAW
);
96 packet
->set_sampling_rate(rate
);
97 packet
->set_bytes_per_sample(AudioPacket::BYTES_PER_SAMPLE_2
);
98 packet
->set_channels(AudioPacket::CHANNELS_STEREO
);
100 // The data must be a multiple of 4 bytes (channels x bytes_per_sample).
102 data
.resize(samples
* kAudioSampleBytes
, kDummyAudioData
);
103 packet
->add_data(data
);
105 return packet
.Pass();
108 scoped_ptr
<AudioPacket
> CreatePacket44100Hz(int samples
) {
109 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_44100
,
113 scoped_ptr
<AudioPacket
> CreatePacket48000Hz(int samples
) {
114 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_48000
,
118 TEST_F(AudioPlayerTest
, Init
) {
119 ASSERT_EQ(0, GetNumQueuedPackets());
121 scoped_ptr
<AudioPacket
> packet(CreatePacket44100Hz(10));
122 audio_
->ProcessAudioPacket(packet
.Pass());
123 ASSERT_EQ(1, GetNumQueuedPackets());
126 TEST_F(AudioPlayerTest
, MultipleSamples
) {
127 scoped_ptr
<AudioPacket
> packet1(CreatePacket44100Hz(10));
128 audio_
->ProcessAudioPacket(packet1
.Pass());
129 ASSERT_EQ(10, GetNumQueuedSamples());
130 ASSERT_EQ(1, GetNumQueuedPackets());
132 scoped_ptr
<AudioPacket
> packet2(CreatePacket44100Hz(20));
133 audio_
->ProcessAudioPacket(packet2
.Pass());
134 ASSERT_EQ(30, GetNumQueuedSamples());
135 ASSERT_EQ(2, GetNumQueuedPackets());
138 TEST_F(AudioPlayerTest
, ChangeSampleRate
) {
139 scoped_ptr
<AudioPacket
> packet1(CreatePacket44100Hz(10));
140 audio_
->ProcessAudioPacket(packet1
.Pass());
141 ASSERT_EQ(10, GetNumQueuedSamples());
142 ASSERT_EQ(1, GetNumQueuedPackets());
144 // New packet with different sampling rate causes previous samples to
146 scoped_ptr
<AudioPacket
> packet2(CreatePacket48000Hz(20));
147 audio_
->ProcessAudioPacket(packet2
.Pass());
148 ASSERT_EQ(20, GetNumQueuedSamples());
149 ASSERT_EQ(1, GetNumQueuedPackets());
152 TEST_F(AudioPlayerTest
, ExceedLatency
) {
153 // Push about 4 seconds worth of samples.
154 for (int i
= 0; i
< 100; ++i
) {
155 scoped_ptr
<AudioPacket
> packet1(CreatePacket48000Hz(2000));
156 audio_
->ProcessAudioPacket(packet1
.Pass());
159 // Verify that we don't have more than 0.5s.
160 EXPECT_LT(GetNumQueuedSamples(), 24000);
163 // Incoming packets: 100
164 // Consume: 25 (w/ 75 remaining, offset 25 into packet)
165 TEST_F(AudioPlayerTest
, ConsumePartialPacket
) {
166 int total_samples
= 0;
167 int bytes_consumed
= 0;
169 // Process 100 samples.
170 int packet1_samples
= 100;
171 scoped_ptr
<AudioPacket
> packet(CreatePacket44100Hz(packet1_samples
));
172 total_samples
+= packet1_samples
;
173 audio_
->ProcessAudioPacket(packet
.Pass());
174 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
175 ASSERT_EQ(1, GetNumQueuedPackets());
176 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
178 // Consume one frame (=25) of samples.
180 total_samples
-= kAudioSamplesPerFrame
;
181 bytes_consumed
+= kAudioFrameBytes
;
182 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
183 ASSERT_EQ(1, GetNumQueuedPackets());
184 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
185 CheckAudioFrameBytes(kAudioFrameBytes
);
187 // Remaining samples.
188 ASSERT_EQ(75, total_samples
);
189 ASSERT_EQ(25 * kAudioSampleBytes
, bytes_consumed
);
192 // Incoming packets: 20, 70
193 // Consume: 25, 25 (w/ 40 remaining, offset 30 into packet)
194 TEST_F(AudioPlayerTest
, ConsumeAcrossPackets
) {
195 int total_samples
= 0;
196 int bytes_consumed
= 0;
199 int packet1_samples
= 20;
200 scoped_ptr
<AudioPacket
> packet1(CreatePacket44100Hz(packet1_samples
));
201 total_samples
+= packet1_samples
;
202 audio_
->ProcessAudioPacket(packet1
.Pass());
203 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
206 int packet2_samples
= 70;
207 scoped_ptr
<AudioPacket
> packet2(CreatePacket44100Hz(packet2_samples
));
208 total_samples
+= packet2_samples
;
209 audio_
->ProcessAudioPacket(packet2
.Pass());
210 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
211 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
213 // Consume 1st frame of 25 samples.
214 // This will consume the entire 1st packet.
216 total_samples
-= kAudioSamplesPerFrame
;
217 bytes_consumed
+= kAudioFrameBytes
- (packet1_samples
* kAudioSampleBytes
);
218 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
219 ASSERT_EQ(1, GetNumQueuedPackets());
220 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
221 CheckAudioFrameBytes(kAudioFrameBytes
);
223 // Consume 2nd frame of 25 samples.
225 total_samples
-= kAudioSamplesPerFrame
;
226 bytes_consumed
+= kAudioFrameBytes
;
227 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
228 ASSERT_EQ(1, GetNumQueuedPackets());
229 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
230 CheckAudioFrameBytes(kAudioFrameBytes
);
232 // Remaining samples.
233 ASSERT_EQ(40, total_samples
);
234 ASSERT_EQ(30 * kAudioSampleBytes
, bytes_consumed
);
237 // Incoming packets: 50, 30
238 // Consume: 25, 25, 25 (w/ 5 remaining, offset 25 into packet)
239 TEST_F(AudioPlayerTest
, ConsumeEntirePacket
) {
240 int total_samples
= 0;
241 int bytes_consumed
= 0;
244 int packet1_samples
= 50;
245 scoped_ptr
<AudioPacket
> packet1(CreatePacket44100Hz(packet1_samples
));
246 total_samples
+= packet1_samples
;
247 audio_
->ProcessAudioPacket(packet1
.Pass());
248 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
249 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
252 int packet2_samples
= 30;
253 scoped_ptr
<AudioPacket
> packet2(CreatePacket44100Hz(packet2_samples
));
254 total_samples
+= packet2_samples
;
255 audio_
->ProcessAudioPacket(packet2
.Pass());
256 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
257 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
259 // Consume 1st frame of 25 samples.
261 total_samples
-= kAudioSamplesPerFrame
;
262 bytes_consumed
+= kAudioFrameBytes
;
263 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
264 ASSERT_EQ(2, GetNumQueuedPackets());
265 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
266 CheckAudioFrameBytes(kAudioFrameBytes
);
268 // Consume 2nd frame of 25 samples.
269 // This will consume the entire first packet (exactly), but the entry for
270 // this packet will stick around (empty) until the next audio chunk is
273 total_samples
-= kAudioSamplesPerFrame
;
274 bytes_consumed
+= kAudioFrameBytes
;
275 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
276 ASSERT_EQ(2, GetNumQueuedPackets());
277 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
278 CheckAudioFrameBytes(kAudioFrameBytes
);
280 // Consume 3rd frame of 25 samples.
282 total_samples
-= kAudioSamplesPerFrame
;
283 bytes_consumed
+= kAudioFrameBytes
- (packet1_samples
* kAudioSampleBytes
);
284 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
285 ASSERT_EQ(1, GetNumQueuedPackets());
286 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
287 CheckAudioFrameBytes(kAudioFrameBytes
);
289 // Remaining samples.
290 ASSERT_EQ(5, total_samples
);
291 ASSERT_EQ(25 * kAudioSampleBytes
, bytes_consumed
);
294 // Incoming packets: <none>
296 TEST_F(AudioPlayerTest
, NoDataToConsume
) {
297 // Attempt to consume a frame of 25 samples.
299 ASSERT_EQ(0, GetNumQueuedSamples());
300 ASSERT_EQ(0, GetNumQueuedPackets());
301 ASSERT_EQ(0, GetBytesConsumed());
302 CheckAudioFrameBytes(0);
305 // Incoming packets: 10
307 TEST_F(AudioPlayerTest
, NotEnoughDataToConsume
) {
308 int total_samples
= 0;
309 int bytes_consumed
= 0;
312 int packet1_samples
= 10;
313 scoped_ptr
<AudioPacket
> packet1(CreatePacket44100Hz(packet1_samples
));
314 total_samples
+= packet1_samples
;
315 audio_
->ProcessAudioPacket(packet1
.Pass());
316 ASSERT_EQ(total_samples
, GetNumQueuedSamples());
317 ASSERT_EQ(bytes_consumed
, GetBytesConsumed());
319 // Attempt to consume a frame of 25 samples.
321 ASSERT_EQ(0, GetNumQueuedSamples());
322 ASSERT_EQ(0, GetNumQueuedPackets());
323 ASSERT_EQ(0, GetBytesConsumed());
324 CheckAudioFrameBytes(packet1_samples
* kAudioSampleBytes
);
327 } // namespace remoting