From b287d968d9c6b7d1190b663cae207efc0497d75f Mon Sep 17 00:00:00 2001 From: "henrik.lundin@webrtc.org" Date: Mon, 7 Apr 2014 21:21:45 +0000 Subject: [PATCH] New NetEq test to verify correct timestamp propagation BUG=3154 R=turaj@webrtc.org Review URL: https://webrtc-codereview.appspot.com/11319004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@5860 4adac7df-926f-26a2-2b94-8c16560cd09d --- .../modules/audio_coding/neteq4/neteq_impl.cc | 5 + .../modules/audio_coding/neteq4/neteq_impl.h | 3 + .../neteq4/neteq_impl_unittest.cc | 95 +++++++++++++++++++ 3 files changed, 103 insertions(+) diff --git a/webrtc/modules/audio_coding/neteq4/neteq_impl.cc b/webrtc/modules/audio_coding/neteq4/neteq_impl.cc index aed1dbb41..97e1874ca 100644 --- a/webrtc/modules/audio_coding/neteq4/neteq_impl.cc +++ b/webrtc/modules/audio_coding/neteq4/neteq_impl.cc @@ -402,6 +402,11 @@ NetEqBackgroundNoiseMode NetEqImpl::BackgroundNoiseMode() const { return background_noise_->mode(); } +const SyncBuffer* NetEqImpl::sync_buffer_for_test() const { + CriticalSectionScoped lock(crit_sect_.get()); + return sync_buffer_.get(); +} + // Methods below this line are private. int NetEqImpl::InsertPacketInternal(const WebRtcRTPHeader& rtp_header, diff --git a/webrtc/modules/audio_coding/neteq4/neteq_impl.h b/webrtc/modules/audio_coding/neteq4/neteq_impl.h index 511452e95..dabf2d6cb 100644 --- a/webrtc/modules/audio_coding/neteq4/neteq_impl.h +++ b/webrtc/modules/audio_coding/neteq4/neteq_impl.h @@ -200,6 +200,9 @@ class NetEqImpl : public webrtc::NetEq { // Gets background noise mode. virtual NetEqBackgroundNoiseMode BackgroundNoiseMode() const; + // This accessor method is only intended for testing purposes. + virtual const SyncBuffer* sync_buffer_for_test() const; + private: static const int kOutputSizeMs = 10; static const int kMaxFrameSize = 2880; // 60 ms @ 48 kHz. diff --git a/webrtc/modules/audio_coding/neteq4/neteq_impl_unittest.cc b/webrtc/modules/audio_coding/neteq4/neteq_impl_unittest.cc index 295dc037f..58dff4839 100644 --- a/webrtc/modules/audio_coding/neteq4/neteq_impl_unittest.cc +++ b/webrtc/modules/audio_coding/neteq4/neteq_impl_unittest.cc @@ -25,6 +25,7 @@ #include "webrtc/modules/audio_coding/neteq4/mock/mock_packet_buffer.h" #include "webrtc/modules/audio_coding/neteq4/mock/mock_payload_splitter.h" #include "webrtc/modules/audio_coding/neteq4/preemptive_expand.h" +#include "webrtc/modules/audio_coding/neteq4/sync_buffer.h" #include "webrtc/modules/audio_coding/neteq4/timestamp_scaler.h" using ::testing::Return; @@ -396,4 +397,98 @@ TEST_F(NetEqImplTest, InsertPacketsUntilBufferIsFull) { EXPECT_EQ(rtp_header.header.sequenceNumber, test_header->sequenceNumber); } +// This test verifies that timestamps propagate from the incoming packets +// through to the sync buffer and to the playout timestamp. +TEST_F(NetEqImplTest, VerifyTimestampPropagation) { + UseNoMocks(); + CreateInstance(); + + const uint8_t kPayloadType = 17; // Just an arbitrary number. + const uint32_t kReceiveTime = 17; // Value doesn't matter for this test. + const int kSampleRateHz = 8000; + const int kPayloadLengthSamples = 10 * kSampleRateHz / 1000; // 10 ms. + const size_t kPayloadLengthBytes = kPayloadLengthSamples; + uint8_t payload[kPayloadLengthBytes] = {0}; + WebRtcRTPHeader rtp_header; + rtp_header.header.payloadType = kPayloadType; + rtp_header.header.sequenceNumber = 0x1234; + rtp_header.header.timestamp = 0x12345678; + rtp_header.header.ssrc = 0x87654321; + + // This is a dummy decoder that produces as many output samples as the input + // has bytes. The output is an increasing series, starting at 1 for the first + // sample, and then increasing by 1 for each sample. + class CountingSamplesDecoder : public AudioDecoder { + public: + explicit CountingSamplesDecoder(enum NetEqDecoder type) + : AudioDecoder(type), next_value_(1) {} + + // Produce as many samples as input bytes (|encoded_len|). + virtual int Decode(const uint8_t* encoded, + size_t encoded_len, + int16_t* decoded, + SpeechType* speech_type) { + for (size_t i = 0; i < encoded_len; ++i) { + decoded[i] = next_value_++; + } + *speech_type = kSpeech; + return encoded_len; + } + + virtual int Init() { + next_value_ = 1; + return 0; + } + + uint16_t next_value() const { return next_value_; } + + private: + int16_t next_value_; + } decoder_(kDecoderPCM16B); + + EXPECT_EQ(NetEq::kOK, + neteq_->RegisterExternalDecoder( + &decoder_, kDecoderPCM16B, 8000, kPayloadType)); + + // Insert one packet. + EXPECT_EQ(NetEq::kOK, + neteq_->InsertPacket( + rtp_header, payload, kPayloadLengthBytes, kReceiveTime)); + + // Pull audio once. + const int kMaxOutputSize = 10 * kSampleRateHz / 1000; + int16_t output[kMaxOutputSize]; + int samples_per_channel; + int num_channels; + NetEqOutputType type; + EXPECT_EQ( + NetEq::kOK, + neteq_->GetAudio( + kMaxOutputSize, output, &samples_per_channel, &num_channels, &type)); + ASSERT_EQ(kMaxOutputSize, samples_per_channel); + EXPECT_EQ(1, num_channels); + EXPECT_EQ(kOutputNormal, type); + + // Start with a simple check that the fake decoder is behaving as expected. + EXPECT_EQ(kPayloadLengthSamples, decoder_.next_value() - 1); + + // The value of the last of the output samples is the same as the number of + // samples played from the decoded packet. Thus, this number + the RTP + // timestamp should match the playout timestamp. + EXPECT_EQ(rtp_header.header.timestamp + output[samples_per_channel - 1], + neteq_->PlayoutTimestamp()); + + // Check the timestamp for the last value in the sync buffer. This should + // be one full frame length ahead of the RTP timestamp. + const SyncBuffer* sync_buffer = neteq_->sync_buffer_for_test(); + ASSERT_TRUE(sync_buffer != NULL); + EXPECT_EQ(rtp_header.header.timestamp + kPayloadLengthSamples, + sync_buffer->end_timestamp()); + + // Check that the number of samples still to play from the sync buffer add + // up with what was already played out. + EXPECT_EQ(kPayloadLengthSamples - output[samples_per_channel - 1], + static_cast(sync_buffer->FutureLength())); +} + } // namespace webrtc