diff options
Diffstat (limited to 'webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc')
-rw-r--r-- | webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc b/webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc new file mode 100644 index 0000000000..24ecc694ff --- /dev/null +++ b/webrtc/modules/audio_coding/acm2/acm_receiver_unittest_oldapi.cc @@ -0,0 +1,398 @@ +/* + * Copyright (c) 2013 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. + */ + +#include "webrtc/modules/audio_coding/acm2/acm_receiver.h" + +#include <algorithm> // std::min + +#include "testing/gtest/include/gtest/gtest.h" +#include "webrtc/base/scoped_ptr.h" +#include "webrtc/modules/audio_coding/include/audio_coding_module.h" +#include "webrtc/modules/audio_coding/acm2/audio_coding_module_impl.h" +#include "webrtc/modules/audio_coding/neteq/tools/rtp_generator.h" +#include "webrtc/system_wrappers/include/clock.h" +#include "webrtc/test/test_suite.h" +#include "webrtc/test/testsupport/fileutils.h" + +namespace webrtc { + +namespace acm2 { +namespace { + +bool CodecsEqual(const CodecInst& codec_a, const CodecInst& codec_b) { + if (strcmp(codec_a.plname, codec_b.plname) != 0 || + codec_a.plfreq != codec_b.plfreq || + codec_a.pltype != codec_b.pltype || + codec_b.channels != codec_a.channels) + return false; + return true; +} + +struct CodecIdInst { + explicit CodecIdInst(RentACodec::CodecId codec_id) { + const auto codec_ix = RentACodec::CodecIndexFromId(codec_id); + EXPECT_TRUE(codec_ix); + id = *codec_ix; + const auto codec_inst = RentACodec::CodecInstById(codec_id); + EXPECT_TRUE(codec_inst); + inst = *codec_inst; + } + int id; + CodecInst inst; +}; + +} // namespace + +class AcmReceiverTestOldApi : public AudioPacketizationCallback, + public ::testing::Test { + protected: + AcmReceiverTestOldApi() + : timestamp_(0), + packet_sent_(false), + last_packet_send_timestamp_(timestamp_), + last_frame_type_(kEmptyFrame) { + AudioCodingModule::Config config; + acm_.reset(new AudioCodingModuleImpl(config)); + receiver_.reset(new AcmReceiver(config)); + } + + ~AcmReceiverTestOldApi() {} + + void SetUp() override { + ASSERT_TRUE(receiver_.get() != NULL); + ASSERT_TRUE(acm_.get() != NULL); + codecs_ = RentACodec::Database(); + + acm_->InitializeReceiver(); + acm_->RegisterTransportCallback(this); + + rtp_header_.header.sequenceNumber = 0; + rtp_header_.header.timestamp = 0; + rtp_header_.header.markerBit = false; + rtp_header_.header.ssrc = 0x12345678; // Arbitrary. + rtp_header_.header.numCSRCs = 0; + rtp_header_.header.payloadType = 0; + rtp_header_.frameType = kAudioFrameSpeech; + rtp_header_.type.Audio.isCNG = false; + } + + void TearDown() override {} + + void InsertOnePacketOfSilence(int codec_id) { + CodecInst codec = + *RentACodec::CodecInstById(*RentACodec::CodecIdFromIndex(codec_id)); + if (timestamp_ == 0) { // This is the first time inserting audio. + ASSERT_EQ(0, acm_->RegisterSendCodec(codec)); + } else { + auto current_codec = acm_->SendCodec(); + ASSERT_TRUE(current_codec); + if (!CodecsEqual(codec, *current_codec)) + ASSERT_EQ(0, acm_->RegisterSendCodec(codec)); + } + AudioFrame frame; + // Frame setup according to the codec. + frame.sample_rate_hz_ = codec.plfreq; + frame.samples_per_channel_ = codec.plfreq / 100; // 10 ms. + frame.num_channels_ = codec.channels; + memset(frame.data_, 0, frame.samples_per_channel_ * frame.num_channels_ * + sizeof(int16_t)); + packet_sent_ = false; + last_packet_send_timestamp_ = timestamp_; + while (!packet_sent_) { + frame.timestamp_ = timestamp_; + timestamp_ += frame.samples_per_channel_; + ASSERT_GE(acm_->Add10MsData(frame), 0); + } + } + + template <size_t N> + void AddSetOfCodecs(const RentACodec::CodecId(&ids)[N]) { + for (auto id : ids) { + const auto i = RentACodec::CodecIndexFromId(id); + ASSERT_TRUE(i); + ASSERT_EQ( + 0, receiver_->AddCodec(*i, codecs_[*i].pltype, codecs_[*i].channels, + codecs_[*i].plfreq, nullptr, "")); + } + } + + int SendData(FrameType frame_type, + uint8_t payload_type, + uint32_t timestamp, + const uint8_t* payload_data, + size_t payload_len_bytes, + const RTPFragmentationHeader* fragmentation) override { + if (frame_type == kEmptyFrame) + return 0; + + rtp_header_.header.payloadType = payload_type; + rtp_header_.frameType = frame_type; + if (frame_type == kAudioFrameSpeech) + rtp_header_.type.Audio.isCNG = false; + else + rtp_header_.type.Audio.isCNG = true; + rtp_header_.header.timestamp = timestamp; + + int ret_val = receiver_->InsertPacket( + rtp_header_, + rtc::ArrayView<const uint8_t>(payload_data, payload_len_bytes)); + if (ret_val < 0) { + assert(false); + return -1; + } + rtp_header_.header.sequenceNumber++; + packet_sent_ = true; + last_frame_type_ = frame_type; + return 0; + } + + rtc::scoped_ptr<AcmReceiver> receiver_; + rtc::ArrayView<const CodecInst> codecs_; + rtc::scoped_ptr<AudioCodingModule> acm_; + WebRtcRTPHeader rtp_header_; + uint32_t timestamp_; + bool packet_sent_; // Set when SendData is called reset when inserting audio. + uint32_t last_packet_send_timestamp_; + FrameType last_frame_type_; +}; + +#if defined(WEBRTC_ANDROID) +#define MAYBE_AddCodecGetCodec DISABLED_AddCodecGetCodec +#else +#define MAYBE_AddCodecGetCodec AddCodecGetCodec +#endif +TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecGetCodec) { + // Add codec. + for (size_t n = 0; n < codecs_.size(); ++n) { + if (n & 0x1) // Just add codecs with odd index. + EXPECT_EQ(0, + receiver_->AddCodec(n, codecs_[n].pltype, codecs_[n].channels, + codecs_[n].plfreq, NULL, "")); + } + // Get codec and compare. + for (size_t n = 0; n < codecs_.size(); ++n) { + CodecInst my_codec; + if (n & 0x1) { + // Codecs with odd index should match the reference. + EXPECT_EQ(0, receiver_->DecoderByPayloadType(codecs_[n].pltype, + &my_codec)); + EXPECT_TRUE(CodecsEqual(codecs_[n], my_codec)); + } else { + // Codecs with even index are not registered. + EXPECT_EQ(-1, receiver_->DecoderByPayloadType(codecs_[n].pltype, + &my_codec)); + } + } +} + +#if defined(WEBRTC_ANDROID) +#define MAYBE_AddCodecChangePayloadType DISABLED_AddCodecChangePayloadType +#else +#define MAYBE_AddCodecChangePayloadType AddCodecChangePayloadType +#endif +TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecChangePayloadType) { + const CodecIdInst codec1(RentACodec::CodecId::kPCMA); + CodecInst codec2 = codec1.inst; + ++codec2.pltype; + CodecInst test_codec; + + // Register the same codec with different payloads. + EXPECT_EQ(0, receiver_->AddCodec(codec1.id, codec1.inst.pltype, + codec1.inst.channels, codec1.inst.plfreq, + nullptr, "")); + EXPECT_EQ(0, receiver_->AddCodec(codec1.id, codec2.pltype, codec2.channels, + codec2.plfreq, NULL, "")); + + // Both payload types should exist. + EXPECT_EQ(0, + receiver_->DecoderByPayloadType(codec1.inst.pltype, &test_codec)); + EXPECT_EQ(true, CodecsEqual(codec1.inst, test_codec)); + EXPECT_EQ(0, receiver_->DecoderByPayloadType(codec2.pltype, &test_codec)); + EXPECT_EQ(true, CodecsEqual(codec2, test_codec)); +} + +#if defined(WEBRTC_ANDROID) +#define MAYBE_AddCodecChangeCodecId DISABLED_AddCodecChangeCodecId +#else +#define MAYBE_AddCodecChangeCodecId AddCodecChangeCodecId +#endif +TEST_F(AcmReceiverTestOldApi, AddCodecChangeCodecId) { + const CodecIdInst codec1(RentACodec::CodecId::kPCMU); + CodecIdInst codec2(RentACodec::CodecId::kPCMA); + codec2.inst.pltype = codec1.inst.pltype; + CodecInst test_codec; + + // Register the same payload type with different codec ID. + EXPECT_EQ(0, receiver_->AddCodec(codec1.id, codec1.inst.pltype, + codec1.inst.channels, codec1.inst.plfreq, + nullptr, "")); + EXPECT_EQ(0, receiver_->AddCodec(codec2.id, codec2.inst.pltype, + codec2.inst.channels, codec2.inst.plfreq, + nullptr, "")); + + // Make sure that the last codec is used. + EXPECT_EQ(0, + receiver_->DecoderByPayloadType(codec2.inst.pltype, &test_codec)); + EXPECT_EQ(true, CodecsEqual(codec2.inst, test_codec)); +} + +#if defined(WEBRTC_ANDROID) +#define MAYBE_AddCodecRemoveCodec DISABLED_AddCodecRemoveCodec +#else +#define MAYBE_AddCodecRemoveCodec AddCodecRemoveCodec +#endif +TEST_F(AcmReceiverTestOldApi, MAYBE_AddCodecRemoveCodec) { + const CodecIdInst codec(RentACodec::CodecId::kPCMA); + const int payload_type = codec.inst.pltype; + EXPECT_EQ( + 0, receiver_->AddCodec(codec.id, codec.inst.pltype, codec.inst.channels, + codec.inst.plfreq, nullptr, "")); + + // Remove non-existing codec should not fail. ACM1 legacy. + EXPECT_EQ(0, receiver_->RemoveCodec(payload_type + 1)); + + // Remove an existing codec. + EXPECT_EQ(0, receiver_->RemoveCodec(payload_type)); + + // Ask for the removed codec, must fail. + CodecInst ci; + EXPECT_EQ(-1, receiver_->DecoderByPayloadType(payload_type, &ci)); +} + +#if defined(WEBRTC_ANDROID) +#define MAYBE_SampleRate DISABLED_SampleRate +#else +#define MAYBE_SampleRate SampleRate +#endif +TEST_F(AcmReceiverTestOldApi, MAYBE_SampleRate) { + const RentACodec::CodecId kCodecId[] = {RentACodec::CodecId::kISAC, + RentACodec::CodecId::kISACSWB}; + AddSetOfCodecs(kCodecId); + + AudioFrame frame; + const int kOutSampleRateHz = 8000; // Different than codec sample rate. + for (const auto codec_id : kCodecId) { + const CodecIdInst codec(codec_id); + const int num_10ms_frames = codec.inst.pacsize / (codec.inst.plfreq / 100); + InsertOnePacketOfSilence(codec.id); + for (int k = 0; k < num_10ms_frames; ++k) { + EXPECT_EQ(0, receiver_->GetAudio(kOutSampleRateHz, &frame)); + } + EXPECT_EQ(codec.inst.plfreq, receiver_->last_output_sample_rate_hz()); + } +} + +#if defined(WEBRTC_ANDROID) +#define MAYBE_PostdecodingVad DISABLED_PostdecodingVad +#else +#define MAYBE_PostdecodingVad PostdecodingVad +#endif +TEST_F(AcmReceiverTestOldApi, MAYBE_PostdecodingVad) { + receiver_->EnableVad(); + EXPECT_TRUE(receiver_->vad_enabled()); + const CodecIdInst codec(RentACodec::CodecId::kPCM16Bwb); + ASSERT_EQ( + 0, receiver_->AddCodec(codec.id, codec.inst.pltype, codec.inst.channels, + codec.inst.plfreq, nullptr, "")); + const int kNumPackets = 5; + const int num_10ms_frames = codec.inst.pacsize / (codec.inst.plfreq / 100); + AudioFrame frame; + for (int n = 0; n < kNumPackets; ++n) { + InsertOnePacketOfSilence(codec.id); + for (int k = 0; k < num_10ms_frames; ++k) + ASSERT_EQ(0, receiver_->GetAudio(codec.inst.plfreq, &frame)); + } + EXPECT_EQ(AudioFrame::kVadPassive, frame.vad_activity_); + + receiver_->DisableVad(); + EXPECT_FALSE(receiver_->vad_enabled()); + + for (int n = 0; n < kNumPackets; ++n) { + InsertOnePacketOfSilence(codec.id); + for (int k = 0; k < num_10ms_frames; ++k) + ASSERT_EQ(0, receiver_->GetAudio(codec.inst.plfreq, &frame)); + } + EXPECT_EQ(AudioFrame::kVadUnknown, frame.vad_activity_); +} + +#if defined(WEBRTC_ANDROID) +#define MAYBE_LastAudioCodec DISABLED_LastAudioCodec +#else +#define MAYBE_LastAudioCodec LastAudioCodec +#endif +#if defined(WEBRTC_CODEC_ISAC) +TEST_F(AcmReceiverTestOldApi, MAYBE_LastAudioCodec) { + const RentACodec::CodecId kCodecId[] = { + RentACodec::CodecId::kISAC, RentACodec::CodecId::kPCMA, + RentACodec::CodecId::kISACSWB, RentACodec::CodecId::kPCM16Bswb32kHz}; + AddSetOfCodecs(kCodecId); + + const RentACodec::CodecId kCngId[] = { + // Not including full-band. + RentACodec::CodecId::kCNNB, RentACodec::CodecId::kCNWB, + RentACodec::CodecId::kCNSWB}; + AddSetOfCodecs(kCngId); + + // Register CNG at sender side. + for (auto id : kCngId) + ASSERT_EQ(0, acm_->RegisterSendCodec(CodecIdInst(id).inst)); + + CodecInst codec; + // No audio payload is received. + EXPECT_EQ(-1, receiver_->LastAudioCodec(&codec)); + + // Start with sending DTX. + ASSERT_EQ(0, acm_->SetVAD(true, true, VADVeryAggr)); + packet_sent_ = false; + InsertOnePacketOfSilence(CodecIdInst(kCodecId[0]).id); // Enough to test + // with one codec. + ASSERT_TRUE(packet_sent_); + EXPECT_EQ(kAudioFrameCN, last_frame_type_); + + // Has received, only, DTX. Last Audio codec is undefined. + EXPECT_EQ(-1, receiver_->LastAudioCodec(&codec)); + EXPECT_FALSE(receiver_->last_packet_sample_rate_hz()); + + for (auto id : kCodecId) { + const CodecIdInst c(id); + + // Set DTX off to send audio payload. + acm_->SetVAD(false, false, VADAggr); + packet_sent_ = false; + InsertOnePacketOfSilence(c.id); + + // Sanity check if Actually an audio payload received, and it should be + // of type "speech." + ASSERT_TRUE(packet_sent_); + ASSERT_EQ(kAudioFrameSpeech, last_frame_type_); + EXPECT_EQ(rtc::Optional<int>(c.inst.plfreq), + receiver_->last_packet_sample_rate_hz()); + + // Set VAD on to send DTX. Then check if the "Last Audio codec" returns + // the expected codec. + acm_->SetVAD(true, true, VADAggr); + + // Do as many encoding until a DTX is sent. + while (last_frame_type_ != kAudioFrameCN) { + packet_sent_ = false; + InsertOnePacketOfSilence(c.id); + ASSERT_TRUE(packet_sent_); + } + EXPECT_EQ(rtc::Optional<int>(c.inst.plfreq), + receiver_->last_packet_sample_rate_hz()); + EXPECT_EQ(0, receiver_->LastAudioCodec(&codec)); + EXPECT_TRUE(CodecsEqual(c.inst, codec)); + } +} +#endif + +} // namespace acm2 + +} // namespace webrtc |