Home | History | Annotate | Download | only in client
      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