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