• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
4 
5 #include "remoting/client/audio_player.h"
6 
7 #include "base/compiler_specific.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 
11 namespace {
12 
13 const int kAudioSamplesPerFrame = 25;
14 const int kAudioSampleBytes = 4;
15 const int kAudioFrameBytes = kAudioSamplesPerFrame * kAudioSampleBytes;
16 const int kPaddingBytes = 16;
17 
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;
22 
23 }  // namespace
24 
25 namespace remoting {
26 
27 class FakeAudioPlayer : public AudioPlayer {
28  public:
FakeAudioPlayer()29   FakeAudioPlayer() {
30   }
31 
ResetAudioPlayer(AudioPacket::SamplingRate)32   virtual bool ResetAudioPlayer(AudioPacket::SamplingRate) OVERRIDE {
33     return true;
34   }
35 
GetSamplesPerFrame()36   virtual uint32 GetSamplesPerFrame() OVERRIDE {
37     return kAudioSamplesPerFrame;
38   }
39 };
40 
41 class AudioPlayerTest : public ::testing::Test {
42  protected:
SetUp()43   virtual void SetUp() {
44     audio_.reset(new FakeAudioPlayer());
45     buffer_.reset(new char[kAudioFrameBytes + kPaddingBytes]);
46   }
47 
TearDown()48   virtual void TearDown() {
49   }
50 
ConsumeAudioFrame()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()),
55                                      kAudioFrameBytes,
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));
60   }
61 
62   // Check that the first |num_bytes| bytes are filled with audio data and
63   // the rest of the buffer is zero-filled.
CheckAudioFrameBytes(int num_bytes)64   void CheckAudioFrameBytes(int num_bytes) {
65     uint8* buffer = reinterpret_cast<uint8*>(buffer_.get());
66     int i = 0;
67     for (; i < num_bytes; i++) {
68       ASSERT_EQ(kDummyAudioData, *(buffer + i));
69     }
70     // Rest of audio frame must be filled with '0's.
71     for (; i < kAudioFrameBytes; i++) {
72       ASSERT_EQ(0, *(buffer + i));
73     }
74   }
75 
GetNumQueuedSamples()76   int GetNumQueuedSamples() {
77     return audio_->queued_bytes_ / kAudioSampleBytes;
78   }
79 
GetNumQueuedPackets()80   int GetNumQueuedPackets() {
81     return static_cast<int>(audio_->queued_packets_.size());
82   }
83 
GetBytesConsumed()84   int GetBytesConsumed() {
85     return static_cast<int>(audio_->bytes_consumed_);
86   }
87 
88   scoped_ptr<AudioPlayer> audio_;
89   scoped_ptr<char[]> buffer_;
90 };
91 
CreatePacketWithSamplingRate(AudioPacket::SamplingRate rate,int samples)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);
99 
100   // The data must be a multiple of 4 bytes (channels x bytes_per_sample).
101   std::string data;
102   data.resize(samples * kAudioSampleBytes, kDummyAudioData);
103   packet->add_data(data);
104 
105   return packet.Pass();
106 }
107 
CreatePacket44100Hz(int samples)108 scoped_ptr<AudioPacket> CreatePacket44100Hz(int samples) {
109   return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_44100,
110                                       samples);
111 }
112 
CreatePacket48000Hz(int samples)113 scoped_ptr<AudioPacket> CreatePacket48000Hz(int samples) {
114   return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_48000,
115                                       samples);
116 }
117 
TEST_F(AudioPlayerTest,Init)118 TEST_F(AudioPlayerTest, Init) {
119   ASSERT_EQ(0, GetNumQueuedPackets());
120 
121   scoped_ptr<AudioPacket> packet(CreatePacket44100Hz(10));
122   audio_->ProcessAudioPacket(packet.Pass());
123   ASSERT_EQ(1, GetNumQueuedPackets());
124 }
125 
TEST_F(AudioPlayerTest,MultipleSamples)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());
131 
132   scoped_ptr<AudioPacket> packet2(CreatePacket44100Hz(20));
133   audio_->ProcessAudioPacket(packet2.Pass());
134   ASSERT_EQ(30, GetNumQueuedSamples());
135   ASSERT_EQ(2, GetNumQueuedPackets());
136 }
137 
TEST_F(AudioPlayerTest,ChangeSampleRate)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());
143 
144   // New packet with different sampling rate causes previous samples to
145   // be removed.
146   scoped_ptr<AudioPacket> packet2(CreatePacket48000Hz(20));
147   audio_->ProcessAudioPacket(packet2.Pass());
148   ASSERT_EQ(20, GetNumQueuedSamples());
149   ASSERT_EQ(1, GetNumQueuedPackets());
150 }
151 
TEST_F(AudioPlayerTest,ExceedLatency)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());
157   }
158 
159   // Verify that we don't have more than 0.5s.
160   EXPECT_LT(GetNumQueuedSamples(), 24000);
161 }
162 
163 // Incoming packets: 100
164 // Consume: 25 (w/ 75 remaining, offset 25 into packet)
TEST_F(AudioPlayerTest,ConsumePartialPacket)165 TEST_F(AudioPlayerTest, ConsumePartialPacket) {
166   int total_samples = 0;
167   int bytes_consumed = 0;
168 
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());
177 
178   // Consume one frame (=25) of samples.
179   ConsumeAudioFrame();
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);
186 
187   // Remaining samples.
188   ASSERT_EQ(75, total_samples);
189   ASSERT_EQ(25 * kAudioSampleBytes, bytes_consumed);
190 }
191 
192 // Incoming packets: 20, 70
193 // Consume: 25, 25 (w/ 40 remaining, offset 30 into packet)
TEST_F(AudioPlayerTest,ConsumeAcrossPackets)194 TEST_F(AudioPlayerTest, ConsumeAcrossPackets) {
195   int total_samples = 0;
196   int bytes_consumed = 0;
197 
198   // Packet 1.
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());
204 
205   // Packet 2.
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());
212 
213   // Consume 1st frame of 25 samples.
214   // This will consume the entire 1st packet.
215   ConsumeAudioFrame();
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);
222 
223   // Consume 2nd frame of 25 samples.
224   ConsumeAudioFrame();
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);
231 
232   // Remaining samples.
233   ASSERT_EQ(40, total_samples);
234   ASSERT_EQ(30 * kAudioSampleBytes, bytes_consumed);
235 }
236 
237 // Incoming packets: 50, 30
238 // Consume: 25, 25, 25 (w/ 5 remaining, offset 25 into packet)
TEST_F(AudioPlayerTest,ConsumeEntirePacket)239 TEST_F(AudioPlayerTest, ConsumeEntirePacket) {
240   int total_samples = 0;
241   int bytes_consumed = 0;
242 
243   // Packet 1.
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());
250 
251   // Packet 2.
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());
258 
259   // Consume 1st frame of 25 samples.
260   ConsumeAudioFrame();
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);
267 
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
271   // consumed.
272   ConsumeAudioFrame();
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);
279 
280   // Consume 3rd frame of 25 samples.
281   ConsumeAudioFrame();
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);
288 
289   // Remaining samples.
290   ASSERT_EQ(5, total_samples);
291   ASSERT_EQ(25 * kAudioSampleBytes, bytes_consumed);
292 }
293 
294 // Incoming packets: <none>
295 // Consume: 25
TEST_F(AudioPlayerTest,NoDataToConsume)296 TEST_F(AudioPlayerTest, NoDataToConsume) {
297   // Attempt to consume a frame of 25 samples.
298   ConsumeAudioFrame();
299   ASSERT_EQ(0, GetNumQueuedSamples());
300   ASSERT_EQ(0, GetNumQueuedPackets());
301   ASSERT_EQ(0, GetBytesConsumed());
302   CheckAudioFrameBytes(0);
303 }
304 
305 // Incoming packets: 10
306 // Consume: 25
TEST_F(AudioPlayerTest,NotEnoughDataToConsume)307 TEST_F(AudioPlayerTest, NotEnoughDataToConsume) {
308   int total_samples = 0;
309   int bytes_consumed = 0;
310 
311   // Packet 1.
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());
318 
319   // Attempt to consume a frame of 25 samples.
320   ConsumeAudioFrame();
321   ASSERT_EQ(0, GetNumQueuedSamples());
322   ASSERT_EQ(0, GetNumQueuedPackets());
323   ASSERT_EQ(0, GetBytesConsumed());
324   CheckAudioFrameBytes(packet1_samples * kAudioSampleBytes);
325 }
326 
327 }  // namespace remoting
328