Home | History | Annotate | Download | only in receiver
      1 // Copyright 2014 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 "base/bind.h"
      6 #include "base/bind_helpers.h"
      7 #include "base/synchronization/condition_variable.h"
      8 #include "base/synchronization/lock.h"
      9 #include "base/sys_byteorder.h"
     10 #include "base/time/time.h"
     11 #include "media/cast/cast_config.h"
     12 #include "media/cast/receiver/audio_decoder.h"
     13 #include "media/cast/test/utility/audio_utility.h"
     14 #include "media/cast/test/utility/standalone_cast_environment.h"
     15 #include "testing/gtest/include/gtest/gtest.h"
     16 #include "third_party/opus/src/include/opus.h"
     17 
     18 namespace media {
     19 namespace cast {
     20 
     21 namespace {
     22 struct TestScenario {
     23   Codec codec;
     24   int num_channels;
     25   int sampling_rate;
     26 
     27   TestScenario(Codec c, int n, int s)
     28       : codec(c), num_channels(n), sampling_rate(s) {}
     29 };
     30 }  // namespace
     31 
     32 class AudioDecoderTest : public ::testing::TestWithParam<TestScenario> {
     33  public:
     34   AudioDecoderTest()
     35       : cast_environment_(new StandaloneCastEnvironment()),
     36         cond_(&lock_) {}
     37 
     38   virtual ~AudioDecoderTest() {
     39     // Make sure all threads have stopped before the environment goes away.
     40     cast_environment_->Shutdown();
     41   }
     42 
     43  protected:
     44   virtual void SetUp() OVERRIDE {
     45     audio_decoder_.reset(new AudioDecoder(cast_environment_,
     46                                           GetParam().num_channels,
     47                                           GetParam().sampling_rate,
     48                                           GetParam().codec));
     49     CHECK_EQ(STATUS_AUDIO_INITIALIZED, audio_decoder_->InitializationResult());
     50 
     51     audio_bus_factory_.reset(
     52         new TestAudioBusFactory(GetParam().num_channels,
     53                                 GetParam().sampling_rate,
     54                                 TestAudioBusFactory::kMiddleANoteFreq,
     55                                 0.5f));
     56     last_frame_id_ = 0;
     57     seen_a_decoded_frame_ = false;
     58 
     59     if (GetParam().codec == CODEC_AUDIO_OPUS) {
     60       opus_encoder_memory_.reset(
     61           new uint8[opus_encoder_get_size(GetParam().num_channels)]);
     62       OpusEncoder* const opus_encoder =
     63           reinterpret_cast<OpusEncoder*>(opus_encoder_memory_.get());
     64       CHECK_EQ(OPUS_OK, opus_encoder_init(opus_encoder,
     65                                           GetParam().sampling_rate,
     66                                           GetParam().num_channels,
     67                                           OPUS_APPLICATION_AUDIO));
     68       CHECK_EQ(OPUS_OK,
     69                opus_encoder_ctl(opus_encoder, OPUS_SET_BITRATE(OPUS_AUTO)));
     70     }
     71 
     72     total_audio_feed_in_ = base::TimeDelta();
     73     total_audio_decoded_ = base::TimeDelta();
     74   }
     75 
     76   // Called from the unit test thread to create another EncodedFrame and push it
     77   // into the decoding pipeline.
     78   void FeedMoreAudio(const base::TimeDelta& duration,
     79                      int num_dropped_frames) {
     80     // Prepare a simulated EncodedFrame to feed into the AudioDecoder.
     81     scoped_ptr<EncodedFrame> encoded_frame(
     82         new EncodedFrame());
     83     encoded_frame->dependency = EncodedFrame::KEY;
     84     encoded_frame->frame_id = last_frame_id_ + 1 + num_dropped_frames;
     85     encoded_frame->referenced_frame_id = encoded_frame->frame_id;
     86     last_frame_id_ = encoded_frame->frame_id;
     87 
     88     const scoped_ptr<AudioBus> audio_bus(
     89         audio_bus_factory_->NextAudioBus(duration).Pass());
     90 
     91     // Encode |audio_bus| into |encoded_frame->data|.
     92     const int num_elements = audio_bus->channels() * audio_bus->frames();
     93     std::vector<int16> interleaved(num_elements);
     94     audio_bus->ToInterleaved(
     95         audio_bus->frames(), sizeof(int16), &interleaved.front());
     96     if (GetParam().codec == CODEC_AUDIO_PCM16) {
     97       encoded_frame->data.resize(num_elements * sizeof(int16));
     98       int16* const pcm_data =
     99           reinterpret_cast<int16*>(encoded_frame->mutable_bytes());
    100       for (size_t i = 0; i < interleaved.size(); ++i)
    101         pcm_data[i] = static_cast<int16>(base::HostToNet16(interleaved[i]));
    102     } else if (GetParam().codec == CODEC_AUDIO_OPUS) {
    103       OpusEncoder* const opus_encoder =
    104           reinterpret_cast<OpusEncoder*>(opus_encoder_memory_.get());
    105       const int kOpusEncodeBufferSize = 4000;
    106       encoded_frame->data.resize(kOpusEncodeBufferSize);
    107       const int payload_size =
    108           opus_encode(opus_encoder,
    109                       &interleaved.front(),
    110                       audio_bus->frames(),
    111                       encoded_frame->mutable_bytes(),
    112                       encoded_frame->data.size());
    113       CHECK_GT(payload_size, 1);
    114       encoded_frame->data.resize(payload_size);
    115     } else {
    116       ASSERT_TRUE(false);  // Not reached.
    117     }
    118 
    119     {
    120       base::AutoLock auto_lock(lock_);
    121       total_audio_feed_in_ += duration;
    122     }
    123 
    124     cast_environment_->PostTask(
    125         CastEnvironment::MAIN,
    126         FROM_HERE,
    127         base::Bind(&AudioDecoder::DecodeFrame,
    128                    base::Unretained(audio_decoder_.get()),
    129                    base::Passed(&encoded_frame),
    130                    base::Bind(&AudioDecoderTest::OnDecodedFrame,
    131                               base::Unretained(this),
    132                               num_dropped_frames == 0)));
    133   }
    134 
    135   // Blocks the caller until all audio that has been feed in has been decoded.
    136   void WaitForAllAudioToBeDecoded() {
    137     DCHECK(!cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    138     base::AutoLock auto_lock(lock_);
    139     while (total_audio_decoded_ < total_audio_feed_in_)
    140       cond_.Wait();
    141     EXPECT_EQ(total_audio_feed_in_.InMicroseconds(),
    142               total_audio_decoded_.InMicroseconds());
    143   }
    144 
    145  private:
    146   // Called by |audio_decoder_| to deliver each frame of decoded audio.
    147   void OnDecodedFrame(bool should_be_continuous,
    148                       scoped_ptr<AudioBus> audio_bus,
    149                       bool is_continuous) {
    150     DCHECK(cast_environment_->CurrentlyOn(CastEnvironment::MAIN));
    151 
    152     // A NULL |audio_bus| indicates a decode error, which we don't expect.
    153     ASSERT_FALSE(!audio_bus);
    154 
    155     // Did the decoder detect whether frames were dropped?
    156     EXPECT_EQ(should_be_continuous, is_continuous);
    157 
    158     // Does the audio data seem to be intact?  For Opus, we have to ignore the
    159     // first frame seen at the start (and immediately after dropped packet
    160     // recovery) because it introduces a tiny, significant delay.
    161     bool examine_signal = true;
    162     if (GetParam().codec == CODEC_AUDIO_OPUS) {
    163       examine_signal = seen_a_decoded_frame_ && should_be_continuous;
    164       seen_a_decoded_frame_ = true;
    165     }
    166     if (examine_signal) {
    167       for (int ch = 0; ch < audio_bus->channels(); ++ch) {
    168         EXPECT_NEAR(
    169             TestAudioBusFactory::kMiddleANoteFreq * 2 * audio_bus->frames() /
    170                 GetParam().sampling_rate,
    171             CountZeroCrossings(audio_bus->channel(ch), audio_bus->frames()),
    172             1);
    173       }
    174     }
    175 
    176     // Signal the main test thread that more audio was decoded.
    177     base::AutoLock auto_lock(lock_);
    178     total_audio_decoded_ += base::TimeDelta::FromSeconds(1) *
    179         audio_bus->frames() / GetParam().sampling_rate;
    180     cond_.Signal();
    181   }
    182 
    183   const scoped_refptr<StandaloneCastEnvironment> cast_environment_;
    184   scoped_ptr<AudioDecoder> audio_decoder_;
    185   scoped_ptr<TestAudioBusFactory> audio_bus_factory_;
    186   uint32 last_frame_id_;
    187   bool seen_a_decoded_frame_;
    188   scoped_ptr<uint8[]> opus_encoder_memory_;
    189 
    190   base::Lock lock_;
    191   base::ConditionVariable cond_;
    192   base::TimeDelta total_audio_feed_in_;
    193   base::TimeDelta total_audio_decoded_;
    194 
    195   DISALLOW_COPY_AND_ASSIGN(AudioDecoderTest);
    196 };
    197 
    198 TEST_P(AudioDecoderTest, DecodesFramesWithSameDuration) {
    199   const base::TimeDelta kTenMilliseconds =
    200       base::TimeDelta::FromMilliseconds(10);
    201   const int kNumFrames = 10;
    202   for (int i = 0; i < kNumFrames; ++i)
    203     FeedMoreAudio(kTenMilliseconds, 0);
    204   WaitForAllAudioToBeDecoded();
    205 }
    206 
    207 TEST_P(AudioDecoderTest, DecodesFramesWithVaryingDuration) {
    208   // These are the set of frame durations supported by the Opus encoder.
    209   const int kFrameDurationMs[] = { 5, 10, 20, 40, 60 };
    210 
    211   const int kNumFrames = 10;
    212   for (size_t i = 0; i < arraysize(kFrameDurationMs); ++i)
    213     for (int j = 0; j < kNumFrames; ++j)
    214       FeedMoreAudio(base::TimeDelta::FromMilliseconds(kFrameDurationMs[i]), 0);
    215   WaitForAllAudioToBeDecoded();
    216 }
    217 
    218 TEST_P(AudioDecoderTest, RecoversFromDroppedFrames) {
    219   const base::TimeDelta kTenMilliseconds =
    220       base::TimeDelta::FromMilliseconds(10);
    221   const int kNumFrames = 100;
    222   int next_drop_at = 3;
    223   int next_num_dropped = 1;
    224   for (int i = 0; i < kNumFrames; ++i) {
    225     if (i == next_drop_at) {
    226       const int num_dropped = next_num_dropped++;
    227       next_drop_at *= 2;
    228       i += num_dropped;
    229       FeedMoreAudio(kTenMilliseconds, num_dropped);
    230     } else {
    231       FeedMoreAudio(kTenMilliseconds, 0);
    232     }
    233   }
    234   WaitForAllAudioToBeDecoded();
    235 }
    236 
    237 INSTANTIATE_TEST_CASE_P(
    238     AudioDecoderTestScenarios,
    239     AudioDecoderTest,
    240     ::testing::Values(
    241          TestScenario(CODEC_AUDIO_PCM16, 1, 8000),
    242          TestScenario(CODEC_AUDIO_PCM16, 2, 48000),
    243          TestScenario(CODEC_AUDIO_OPUS, 1, 8000),
    244          TestScenario(CODEC_AUDIO_OPUS, 2, 48000)));
    245 
    246 }  // namespace cast
    247 }  // namespace media
    248