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