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: 29 FakeAudioPlayer() { 30 } 31 32 virtual bool ResetAudioPlayer(AudioPacket::SamplingRate) OVERRIDE { 33 return true; 34 } 35 36 virtual uint32 GetSamplesPerFrame() OVERRIDE { 37 return kAudioSamplesPerFrame; 38 } 39 }; 40 41 class AudioPlayerTest : public ::testing::Test { 42 protected: 43 virtual void SetUp() { 44 audio_.reset(new FakeAudioPlayer()); 45 buffer_.reset(new char[kAudioFrameBytes + kPaddingBytes]); 46 } 47 48 virtual void TearDown() { 49 } 50 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. 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 76 int GetNumQueuedSamples() { 77 return audio_->queued_bytes_ / kAudioSampleBytes; 78 } 79 80 int GetNumQueuedPackets() { 81 return static_cast<int>(audio_->queued_packets_.size()); 82 } 83 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 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 108 scoped_ptr<AudioPacket> CreatePacket44100Hz(int samples) { 109 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_44100, 110 samples); 111 } 112 113 scoped_ptr<AudioPacket> CreatePacket48000Hz(int samples) { 114 return CreatePacketWithSamplingRate(AudioPacket::SAMPLING_RATE_48000, 115 samples); 116 } 117 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 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 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 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) 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) 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) 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 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 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