|  | /* | 
|  | *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | // This file contains unit tests for ACM's NetEQ wrapper (class ACMNetEQ). | 
|  |  | 
|  | #include "webrtc/modules/audio_coding/main/source/acm_neteq.h" | 
|  |  | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include "gtest/gtest.h" | 
|  | #include "webrtc/modules/audio_coding/codecs/pcm16b/include/pcm16b.h" | 
|  | #include "webrtc/modules/audio_coding/main/interface/audio_coding_module_typedefs.h" | 
|  | #include "webrtc/modules/audio_coding/main/source/acm_codec_database.h" | 
|  | #include "webrtc/modules/audio_coding/neteq/interface/webrtc_neteq_help_macros.h" | 
|  | #include "webrtc/modules/interface/module_common_types.h" | 
|  | #include "webrtc/typedefs.h" | 
|  |  | 
|  | namespace webrtc { | 
|  |  | 
|  | namespace acm1 { | 
|  |  | 
|  | class AcmNetEqTest : public ::testing::Test { | 
|  | protected: | 
|  | static const size_t kMaxPayloadLen = 5760;  // 60 ms, 48 kHz, 16 bit samples. | 
|  | static const int kPcm16WbPayloadType = 94; | 
|  | AcmNetEqTest() {} | 
|  | virtual void SetUp(); | 
|  | virtual void TearDown() {} | 
|  |  | 
|  | void InsertZeroPacket(uint16_t sequence_number, | 
|  | uint32_t timestamp, | 
|  | uint8_t payload_type, | 
|  | uint32_t ssrc, | 
|  | bool marker_bit, | 
|  | size_t len_payload_bytes); | 
|  | void PullData(int expected_num_samples); | 
|  |  | 
|  | ACMNetEQ neteq_; | 
|  | }; | 
|  |  | 
|  | void AcmNetEqTest::SetUp() { | 
|  | ASSERT_EQ(0, neteq_.Init()); | 
|  | ASSERT_EQ(0, neteq_.AllocatePacketBuffer(ACMCodecDB::NetEQDecoders(), | 
|  | ACMCodecDB::kNumCodecs)); | 
|  | WebRtcNetEQ_CodecDef codec_def; | 
|  | SET_CODEC_PAR(codec_def, kDecoderPCM16Bwb, kPcm16WbPayloadType, NULL, 16000); | 
|  | SET_PCM16B_WB_FUNCTIONS(codec_def); | 
|  | ASSERT_EQ(0, neteq_.AddCodec(&codec_def, true)); | 
|  | } | 
|  |  | 
|  | void AcmNetEqTest::InsertZeroPacket(uint16_t sequence_number, | 
|  | uint32_t timestamp, | 
|  | uint8_t payload_type, | 
|  | uint32_t ssrc, | 
|  | bool marker_bit, | 
|  | size_t len_payload_bytes) { | 
|  | ASSERT_TRUE(len_payload_bytes <= kMaxPayloadLen); | 
|  | uint16_t payload[kMaxPayloadLen] = {0}; | 
|  | WebRtcRTPHeader rtp_header; | 
|  | rtp_header.header.sequenceNumber = sequence_number; | 
|  | rtp_header.header.timestamp = timestamp; | 
|  | rtp_header.header.ssrc = ssrc; | 
|  | rtp_header.header.payloadType = payload_type; | 
|  | rtp_header.header.markerBit = marker_bit; | 
|  | rtp_header.type.Audio.channel = 1; | 
|  | // Receive timestamp can be set to send timestamp in this test. | 
|  | ASSERT_EQ(0, neteq_.RecIn(reinterpret_cast<uint8_t*>(payload), | 
|  | len_payload_bytes, rtp_header, timestamp)); | 
|  | } | 
|  |  | 
|  | void AcmNetEqTest::PullData(int expected_num_samples) { | 
|  | AudioFrame out_frame; | 
|  | ASSERT_EQ(0, neteq_.RecOut(out_frame)); | 
|  | ASSERT_EQ(expected_num_samples, out_frame.samples_per_channel_); | 
|  | } | 
|  |  | 
|  | TEST_F(AcmNetEqTest, NetworkStatistics) { | 
|  | // Use fax mode to avoid time-scaling. This is to simplify the testing of | 
|  | // packet waiting times in the packet buffer. | 
|  | neteq_.SetPlayoutMode(fax); | 
|  | // Insert 31 dummy packets at once. Each packet contains 10 ms 16 kHz audio. | 
|  | int num_frames = 30; | 
|  | const int kSamples = 10 * 16; | 
|  | const int kPayloadBytes = kSamples * 2; | 
|  | int i, j; | 
|  | for (i = 0; i < num_frames; ++i) { | 
|  | InsertZeroPacket(i, i * kSamples, kPcm16WbPayloadType, 0x1234, false, | 
|  | kPayloadBytes); | 
|  | } | 
|  | // Pull out data once. | 
|  | PullData(kSamples); | 
|  | // Insert one more packet (to produce different mean and median). | 
|  | i = num_frames; | 
|  | InsertZeroPacket(i, i * kSamples, kPcm16WbPayloadType, 0x1234, false, | 
|  | kPayloadBytes); | 
|  | // Pull out all data. | 
|  | for (j = 1; j < num_frames + 1; ++j) { | 
|  | PullData(kSamples); | 
|  | } | 
|  |  | 
|  | ACMNetworkStatistics stats; | 
|  | ASSERT_EQ(0, neteq_.NetworkStatistics(&stats)); | 
|  | EXPECT_EQ(0, stats.currentBufferSize); | 
|  | EXPECT_EQ(0, stats.preferredBufferSize); | 
|  | EXPECT_FALSE(stats.jitterPeaksFound); | 
|  | EXPECT_EQ(0, stats.currentPacketLossRate); | 
|  | EXPECT_EQ(0, stats.currentDiscardRate); | 
|  | EXPECT_EQ(0, stats.currentExpandRate); | 
|  | EXPECT_EQ(0, stats.currentPreemptiveRate); | 
|  | EXPECT_EQ(0, stats.currentAccelerateRate); | 
|  | EXPECT_EQ(-916, stats.clockDriftPPM);  // Initial value is slightly off. | 
|  | EXPECT_EQ(300, stats.maxWaitingTimeMs); | 
|  | EXPECT_EQ(10, stats.minWaitingTimeMs); | 
|  | EXPECT_EQ(159, stats.meanWaitingTimeMs); | 
|  | EXPECT_EQ(160, stats.medianWaitingTimeMs); | 
|  | } | 
|  |  | 
|  | TEST_F(AcmNetEqTest, TestZeroLengthWaitingTimesVector) { | 
|  | // Insert one packet. | 
|  | const int kSamples = 10 * 16; | 
|  | const int kPayloadBytes = kSamples * 2; | 
|  | int i = 0; | 
|  | InsertZeroPacket(i, i * kSamples, kPcm16WbPayloadType, 0x1234, false, | 
|  | kPayloadBytes); | 
|  | // Do not pull out any data. | 
|  |  | 
|  | ACMNetworkStatistics stats; | 
|  | ASSERT_EQ(0, neteq_.NetworkStatistics(&stats)); | 
|  | EXPECT_EQ(0, stats.currentBufferSize); | 
|  | EXPECT_EQ(0, stats.preferredBufferSize); | 
|  | EXPECT_FALSE(stats.jitterPeaksFound); | 
|  | EXPECT_EQ(0, stats.currentPacketLossRate); | 
|  | EXPECT_EQ(0, stats.currentDiscardRate); | 
|  | EXPECT_EQ(0, stats.currentExpandRate); | 
|  | EXPECT_EQ(0, stats.currentPreemptiveRate); | 
|  | EXPECT_EQ(0, stats.currentAccelerateRate); | 
|  | EXPECT_EQ(-916, stats.clockDriftPPM);  // Initial value is slightly off. | 
|  | EXPECT_EQ(-1, stats.minWaitingTimeMs); | 
|  | EXPECT_EQ(-1, stats.maxWaitingTimeMs); | 
|  | EXPECT_EQ(-1, stats.meanWaitingTimeMs); | 
|  | EXPECT_EQ(-1, stats.medianWaitingTimeMs); | 
|  | } | 
|  |  | 
|  | }  // namespace acm1 | 
|  |  | 
|  | }  // namespace webrtc |