summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/modules/audio_coding/test
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/modules/audio_coding/test')
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/Channel.cc274
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/Channel.h117
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.cc269
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.h111
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/PCMFile.cc240
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/PCMFile.h77
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.cc167
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.h77
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/RTPFile.cc235
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/RTPFile.h133
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.cc412
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.h83
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestRedFec.cc200
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestRedFec.h56
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc599
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestStereo.h100
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.cc240
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.h115
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/Tester.cc102
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.cc191
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.h62
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/opus_test.cc402
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/opus_test.h59
-rw-r--r--third_party/libwebrtc/modules/audio_coding/test/target_delay_unittest.cc161
24 files changed, 4482 insertions, 0 deletions
diff --git a/third_party/libwebrtc/modules/audio_coding/test/Channel.cc b/third_party/libwebrtc/modules/audio_coding/test/Channel.cc
new file mode 100644
index 0000000000..35aa6cb6b4
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/Channel.cc
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+#include "modules/audio_coding/test/Channel.h"
+
+#include <iostream>
+
+#include "rtc_base/strings/string_builder.h"
+#include "rtc_base/time_utils.h"
+
+namespace webrtc {
+
+int32_t Channel::SendData(AudioFrameType frameType,
+ uint8_t payloadType,
+ uint32_t timeStamp,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ int64_t absolute_capture_timestamp_ms) {
+ RTPHeader rtp_header;
+ int32_t status;
+ size_t payloadDataSize = payloadSize;
+
+ rtp_header.markerBit = false;
+ rtp_header.ssrc = 0;
+ rtp_header.sequenceNumber =
+ (external_sequence_number_ < 0)
+ ? _seqNo++
+ : static_cast<uint16_t>(external_sequence_number_);
+ rtp_header.payloadType = payloadType;
+ rtp_header.timestamp = (external_send_timestamp_ < 0)
+ ? timeStamp
+ : static_cast<uint32_t>(external_send_timestamp_);
+
+ if (frameType == AudioFrameType::kEmptyFrame) {
+ // When frame is empty, we should not transmit it. The frame size of the
+ // next non-empty frame will be based on the previous frame size.
+ _useLastFrameSize = _lastFrameSizeSample > 0;
+ return 0;
+ }
+
+ memcpy(_payloadData, payloadData, payloadDataSize);
+ if (_isStereo) {
+ if (_leftChannel) {
+ _rtp_header = rtp_header;
+ _leftChannel = false;
+ } else {
+ rtp_header = _rtp_header;
+ _leftChannel = true;
+ }
+ }
+
+ _channelCritSect.Lock();
+ if (_saveBitStream) {
+ // fwrite(payloadData, sizeof(uint8_t), payloadSize, _bitStreamFile);
+ }
+
+ if (!_isStereo) {
+ CalcStatistics(rtp_header, payloadSize);
+ }
+ _useLastFrameSize = false;
+ _lastInTimestamp = timeStamp;
+ _totalBytes += payloadDataSize;
+ _channelCritSect.Unlock();
+
+ if (_useFECTestWithPacketLoss) {
+ _packetLoss += 1;
+ if (_packetLoss == 3) {
+ _packetLoss = 0;
+ return 0;
+ }
+ }
+
+ if (num_packets_to_drop_ > 0) {
+ num_packets_to_drop_--;
+ return 0;
+ }
+
+ status =
+ _receiverACM->IncomingPacket(_payloadData, payloadDataSize, rtp_header);
+
+ return status;
+}
+
+// TODO(turajs): rewite this method.
+void Channel::CalcStatistics(const RTPHeader& rtp_header, size_t payloadSize) {
+ int n;
+ if ((rtp_header.payloadType != _lastPayloadType) &&
+ (_lastPayloadType != -1)) {
+ // payload-type is changed.
+ // we have to terminate the calculations on the previous payload type
+ // we ignore the last packet in that payload type just to make things
+ // easier.
+ for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
+ if (_lastPayloadType == _payloadStats[n].payloadType) {
+ _payloadStats[n].newPacket = true;
+ break;
+ }
+ }
+ }
+ _lastPayloadType = rtp_header.payloadType;
+
+ bool newPayload = true;
+ ACMTestPayloadStats* currentPayloadStr = NULL;
+ for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
+ if (rtp_header.payloadType == _payloadStats[n].payloadType) {
+ newPayload = false;
+ currentPayloadStr = &_payloadStats[n];
+ break;
+ }
+ }
+
+ if (!newPayload) {
+ if (!currentPayloadStr->newPacket) {
+ if (!_useLastFrameSize) {
+ _lastFrameSizeSample =
+ (uint32_t)((uint32_t)rtp_header.timestamp -
+ (uint32_t)currentPayloadStr->lastTimestamp);
+ }
+ RTC_DCHECK_GT(_lastFrameSizeSample, 0);
+ int k = 0;
+ for (; k < MAX_NUM_FRAMESIZES; ++k) {
+ if ((currentPayloadStr->frameSizeStats[k].frameSizeSample ==
+ _lastFrameSizeSample) ||
+ (currentPayloadStr->frameSizeStats[k].frameSizeSample == 0)) {
+ break;
+ }
+ }
+ if (k == MAX_NUM_FRAMESIZES) {
+ // New frame size found but no space to count statistics on it. Skip it.
+ printf("No memory to store statistics for payload %d : frame size %d\n",
+ _lastPayloadType, _lastFrameSizeSample);
+ return;
+ }
+ ACMTestFrameSizeStats* currentFrameSizeStats =
+ &(currentPayloadStr->frameSizeStats[k]);
+ currentFrameSizeStats->frameSizeSample = (int16_t)_lastFrameSizeSample;
+
+ // increment the number of encoded samples.
+ currentFrameSizeStats->totalEncodedSamples += _lastFrameSizeSample;
+ // increment the number of recveived packets
+ currentFrameSizeStats->numPackets++;
+ // increment the total number of bytes (this is based on
+ // the previous payload we don't know the frame-size of
+ // the current payload.
+ currentFrameSizeStats->totalPayloadLenByte +=
+ currentPayloadStr->lastPayloadLenByte;
+ // store the maximum payload-size (this is based on
+ // the previous payload we don't know the frame-size of
+ // the current payload.
+ if (currentFrameSizeStats->maxPayloadLen <
+ currentPayloadStr->lastPayloadLenByte) {
+ currentFrameSizeStats->maxPayloadLen =
+ currentPayloadStr->lastPayloadLenByte;
+ }
+ // store the current values for the next time
+ currentPayloadStr->lastTimestamp = rtp_header.timestamp;
+ currentPayloadStr->lastPayloadLenByte = payloadSize;
+ } else {
+ currentPayloadStr->newPacket = false;
+ currentPayloadStr->lastPayloadLenByte = payloadSize;
+ currentPayloadStr->lastTimestamp = rtp_header.timestamp;
+ currentPayloadStr->payloadType = rtp_header.payloadType;
+ memset(currentPayloadStr->frameSizeStats, 0,
+ MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
+ }
+ } else {
+ n = 0;
+ while (_payloadStats[n].payloadType != -1) {
+ n++;
+ }
+ // first packet
+ _payloadStats[n].newPacket = false;
+ _payloadStats[n].lastPayloadLenByte = payloadSize;
+ _payloadStats[n].lastTimestamp = rtp_header.timestamp;
+ _payloadStats[n].payloadType = rtp_header.payloadType;
+ memset(_payloadStats[n].frameSizeStats, 0,
+ MAX_NUM_FRAMESIZES * sizeof(ACMTestFrameSizeStats));
+ }
+}
+
+Channel::Channel(int16_t chID)
+ : _receiverACM(NULL),
+ _seqNo(0),
+ _bitStreamFile(NULL),
+ _saveBitStream(false),
+ _lastPayloadType(-1),
+ _isStereo(false),
+ _leftChannel(true),
+ _lastInTimestamp(0),
+ _useLastFrameSize(false),
+ _lastFrameSizeSample(0),
+ _packetLoss(0),
+ _useFECTestWithPacketLoss(false),
+ _beginTime(rtc::TimeMillis()),
+ _totalBytes(0),
+ external_send_timestamp_(-1),
+ external_sequence_number_(-1),
+ num_packets_to_drop_(0) {
+ int n;
+ int k;
+ for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
+ _payloadStats[n].payloadType = -1;
+ _payloadStats[n].newPacket = true;
+ for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
+ _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
+ _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
+ _payloadStats[n].frameSizeStats[k].numPackets = 0;
+ _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
+ _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
+ }
+ }
+ if (chID >= 0) {
+ _saveBitStream = true;
+ rtc::StringBuilder ss;
+ ss.AppendFormat("bitStream_%d.dat", chID);
+ _bitStreamFile = fopen(ss.str().c_str(), "wb");
+ } else {
+ _saveBitStream = false;
+ }
+}
+
+Channel::~Channel() {}
+
+void Channel::RegisterReceiverACM(AudioCodingModule* acm) {
+ _receiverACM = acm;
+ return;
+}
+
+void Channel::ResetStats() {
+ int n;
+ int k;
+ _channelCritSect.Lock();
+ _lastPayloadType = -1;
+ for (n = 0; n < MAX_NUM_PAYLOADS; n++) {
+ _payloadStats[n].payloadType = -1;
+ _payloadStats[n].newPacket = true;
+ for (k = 0; k < MAX_NUM_FRAMESIZES; k++) {
+ _payloadStats[n].frameSizeStats[k].frameSizeSample = 0;
+ _payloadStats[n].frameSizeStats[k].maxPayloadLen = 0;
+ _payloadStats[n].frameSizeStats[k].numPackets = 0;
+ _payloadStats[n].frameSizeStats[k].totalPayloadLenByte = 0;
+ _payloadStats[n].frameSizeStats[k].totalEncodedSamples = 0;
+ }
+ }
+ _beginTime = rtc::TimeMillis();
+ _totalBytes = 0;
+ _channelCritSect.Unlock();
+}
+
+uint32_t Channel::LastInTimestamp() {
+ uint32_t timestamp;
+ _channelCritSect.Lock();
+ timestamp = _lastInTimestamp;
+ _channelCritSect.Unlock();
+ return timestamp;
+}
+
+double Channel::BitRate() {
+ double rate;
+ uint64_t currTime = rtc::TimeMillis();
+ _channelCritSect.Lock();
+ rate = ((double)_totalBytes * 8.0) / (double)(currTime - _beginTime);
+ _channelCritSect.Unlock();
+ return rate;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/Channel.h b/third_party/libwebrtc/modules/audio_coding/test/Channel.h
new file mode 100644
index 0000000000..7a8829e1d2
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/Channel.h
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_CHANNEL_H_
+#define MODULES_AUDIO_CODING_TEST_CHANNEL_H_
+
+#include <stdio.h>
+
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "modules/include/module_common_types.h"
+#include "rtc_base/synchronization/mutex.h"
+
+namespace webrtc {
+
+#define MAX_NUM_PAYLOADS 50
+#define MAX_NUM_FRAMESIZES 6
+
+// TODO(turajs): Write constructor for this structure.
+struct ACMTestFrameSizeStats {
+ uint16_t frameSizeSample;
+ size_t maxPayloadLen;
+ uint32_t numPackets;
+ uint64_t totalPayloadLenByte;
+ uint64_t totalEncodedSamples;
+ double rateBitPerSec;
+ double usageLenSec;
+};
+
+// TODO(turajs): Write constructor for this structure.
+struct ACMTestPayloadStats {
+ bool newPacket;
+ int16_t payloadType;
+ size_t lastPayloadLenByte;
+ uint32_t lastTimestamp;
+ ACMTestFrameSizeStats frameSizeStats[MAX_NUM_FRAMESIZES];
+};
+
+class Channel : public AudioPacketizationCallback {
+ public:
+ Channel(int16_t chID = -1);
+ ~Channel() override;
+
+ int32_t SendData(AudioFrameType frameType,
+ uint8_t payloadType,
+ uint32_t timeStamp,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ int64_t absolute_capture_timestamp_ms) override;
+
+ void RegisterReceiverACM(AudioCodingModule* acm);
+
+ void ResetStats();
+
+ void SetIsStereo(bool isStereo) { _isStereo = isStereo; }
+
+ uint32_t LastInTimestamp();
+
+ void SetFECTestWithPacketLoss(bool usePacketLoss) {
+ _useFECTestWithPacketLoss = usePacketLoss;
+ }
+
+ double BitRate();
+
+ void set_send_timestamp(uint32_t new_send_ts) {
+ external_send_timestamp_ = new_send_ts;
+ }
+
+ void set_sequence_number(uint16_t new_sequence_number) {
+ external_sequence_number_ = new_sequence_number;
+ }
+
+ void set_num_packets_to_drop(int new_num_packets_to_drop) {
+ num_packets_to_drop_ = new_num_packets_to_drop;
+ }
+
+ private:
+ void CalcStatistics(const RTPHeader& rtp_header, size_t payloadSize);
+
+ AudioCodingModule* _receiverACM;
+ uint16_t _seqNo;
+ // 60msec * 32 sample(max)/msec * 2 description (maybe) * 2 bytes/sample
+ uint8_t _payloadData[60 * 32 * 2 * 2];
+
+ Mutex _channelCritSect;
+ FILE* _bitStreamFile;
+ bool _saveBitStream;
+ int16_t _lastPayloadType;
+ ACMTestPayloadStats _payloadStats[MAX_NUM_PAYLOADS];
+ bool _isStereo;
+ RTPHeader _rtp_header;
+ bool _leftChannel;
+ uint32_t _lastInTimestamp;
+ bool _useLastFrameSize;
+ uint32_t _lastFrameSizeSample;
+ // FEC Test variables
+ int16_t _packetLoss;
+ bool _useFECTestWithPacketLoss;
+ uint64_t _beginTime;
+ uint64_t _totalBytes;
+
+ // External timing info, defaulted to -1. Only used if they are
+ // non-negative.
+ int64_t external_send_timestamp_;
+ int32_t external_sequence_number_;
+ int num_packets_to_drop_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_CHANNEL_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.cc b/third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.cc
new file mode 100644
index 0000000000..9f9c4aa74c
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.cc
@@ -0,0 +1,269 @@
+/*
+ * 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.
+ */
+
+#include "modules/audio_coding/test/EncodeDecodeTest.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+namespace {
+// Buffer size for stereo 48 kHz audio.
+constexpr size_t kWebRtc10MsPcmAudio = 960;
+
+} // namespace
+
+TestPacketization::TestPacketization(RTPStream* rtpStream, uint16_t frequency)
+ : _rtpStream(rtpStream), _frequency(frequency), _seqNo(0) {}
+
+TestPacketization::~TestPacketization() {}
+
+int32_t TestPacketization::SendData(const AudioFrameType /* frameType */,
+ const uint8_t payloadType,
+ const uint32_t timeStamp,
+ const uint8_t* payloadData,
+ const size_t payloadSize,
+ int64_t absolute_capture_timestamp_ms) {
+ _rtpStream->Write(payloadType, timeStamp, _seqNo++, payloadData, payloadSize,
+ _frequency);
+ return 1;
+}
+
+Sender::Sender()
+ : _acm(NULL), _pcmFile(), _audioFrame(), _packetization(NULL) {}
+
+void Sender::Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view in_file_name,
+ int in_sample_rate,
+ int payload_type,
+ SdpAudioFormat format) {
+ // Open input file
+ const std::string file_name = webrtc::test::ResourcePath(in_file_name, "pcm");
+ _pcmFile.Open(file_name, in_sample_rate, "rb");
+ if (format.num_channels == 2) {
+ _pcmFile.ReadStereo(true);
+ }
+ // Set test length to 500 ms (50 blocks of 10 ms each).
+ _pcmFile.SetNum10MsBlocksToRead(50);
+ // Fast-forward 1 second (100 blocks) since the file starts with silence.
+ _pcmFile.FastForward(100);
+
+ acm->SetEncoder(CreateBuiltinAudioEncoderFactory()->MakeAudioEncoder(
+ payload_type, format, absl::nullopt));
+ _packetization = new TestPacketization(rtpStream, format.clockrate_hz);
+ EXPECT_EQ(0, acm->RegisterTransportCallback(_packetization));
+
+ _acm = acm;
+}
+
+void Sender::Teardown() {
+ _pcmFile.Close();
+ delete _packetization;
+}
+
+bool Sender::Add10MsData() {
+ if (!_pcmFile.EndOfFile()) {
+ EXPECT_GT(_pcmFile.Read10MsData(_audioFrame), 0);
+ int32_t ok = _acm->Add10MsData(_audioFrame);
+ EXPECT_GE(ok, 0);
+ return ok >= 0 ? true : false;
+ }
+ return false;
+}
+
+void Sender::Run() {
+ while (true) {
+ if (!Add10MsData()) {
+ break;
+ }
+ }
+}
+
+Receiver::Receiver()
+ : _playoutLengthSmpls(kWebRtc10MsPcmAudio),
+ _payloadSizeBytes(MAX_INCOMING_PAYLOAD) {}
+
+void Receiver::Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view out_file_name,
+ size_t channels,
+ int file_num) {
+ EXPECT_EQ(0, acm->InitializeReceiver());
+
+ if (channels == 1) {
+ acm->SetReceiveCodecs({{107, {"L16", 8000, 1}},
+ {108, {"L16", 16000, 1}},
+ {109, {"L16", 32000, 1}},
+ {0, {"PCMU", 8000, 1}},
+ {8, {"PCMA", 8000, 1}},
+ {102, {"ILBC", 8000, 1}},
+ {9, {"G722", 8000, 1}},
+ {120, {"OPUS", 48000, 2}},
+ {13, {"CN", 8000, 1}},
+ {98, {"CN", 16000, 1}},
+ {99, {"CN", 32000, 1}}});
+ } else {
+ ASSERT_EQ(channels, 2u);
+ acm->SetReceiveCodecs({{111, {"L16", 8000, 2}},
+ {112, {"L16", 16000, 2}},
+ {113, {"L16", 32000, 2}},
+ {110, {"PCMU", 8000, 2}},
+ {118, {"PCMA", 8000, 2}},
+ {119, {"G722", 8000, 2}},
+ {120, {"OPUS", 48000, 2, {{"stereo", "1"}}}}});
+ }
+
+ int playSampFreq;
+ std::string file_name;
+ rtc::StringBuilder file_stream;
+ file_stream << webrtc::test::OutputPath() << out_file_name << file_num
+ << ".pcm";
+ file_name = file_stream.str();
+ _rtpStream = rtpStream;
+
+ playSampFreq = 32000;
+ _pcmFile.Open(file_name, 32000, "wb+");
+
+ _realPayloadSizeBytes = 0;
+ _playoutBuffer = new int16_t[kWebRtc10MsPcmAudio];
+ _frequency = playSampFreq;
+ _acm = acm;
+ _firstTime = true;
+}
+
+void Receiver::Teardown() {
+ delete[] _playoutBuffer;
+ _pcmFile.Close();
+}
+
+bool Receiver::IncomingPacket() {
+ if (!_rtpStream->EndOfFile()) {
+ if (_firstTime) {
+ _firstTime = false;
+ _realPayloadSizeBytes = _rtpStream->Read(&_rtpHeader, _incomingPayload,
+ _payloadSizeBytes, &_nextTime);
+ if (_realPayloadSizeBytes == 0) {
+ if (_rtpStream->EndOfFile()) {
+ _firstTime = true;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ EXPECT_EQ(0, _acm->IncomingPacket(_incomingPayload, _realPayloadSizeBytes,
+ _rtpHeader));
+ _realPayloadSizeBytes = _rtpStream->Read(&_rtpHeader, _incomingPayload,
+ _payloadSizeBytes, &_nextTime);
+ if (_realPayloadSizeBytes == 0 && _rtpStream->EndOfFile()) {
+ _firstTime = true;
+ }
+ }
+ return true;
+}
+
+bool Receiver::PlayoutData() {
+ AudioFrame audioFrame;
+ bool muted;
+ int32_t ok = _acm->PlayoutData10Ms(_frequency, &audioFrame, &muted);
+ if (muted) {
+ ADD_FAILURE();
+ return false;
+ }
+ EXPECT_EQ(0, ok);
+ if (ok < 0) {
+ return false;
+ }
+ if (_playoutLengthSmpls == 0) {
+ return false;
+ }
+ _pcmFile.Write10MsData(audioFrame.data(), audioFrame.samples_per_channel_ *
+ audioFrame.num_channels_);
+ return true;
+}
+
+void Receiver::Run() {
+ uint8_t counter500Ms = 50;
+ uint32_t clock = 0;
+
+ while (counter500Ms > 0) {
+ if (clock == 0 || clock >= _nextTime) {
+ EXPECT_TRUE(IncomingPacket());
+ if (clock == 0) {
+ clock = _nextTime;
+ }
+ }
+ if ((clock % 10) == 0) {
+ if (!PlayoutData()) {
+ clock++;
+ continue;
+ }
+ }
+ if (_rtpStream->EndOfFile()) {
+ counter500Ms--;
+ }
+ clock++;
+ }
+}
+
+EncodeDecodeTest::EncodeDecodeTest() = default;
+
+void EncodeDecodeTest::Perform() {
+ const std::map<int, SdpAudioFormat> send_codecs = {
+ {107, {"L16", 8000, 1}}, {108, {"L16", 16000, 1}},
+ {109, {"L16", 32000, 1}}, {0, {"PCMU", 8000, 1}},
+ {8, {"PCMA", 8000, 1}},
+#ifdef WEBRTC_CODEC_ILBC
+ {102, {"ILBC", 8000, 1}},
+#endif
+ {9, {"G722", 8000, 1}}};
+ int file_num = 0;
+ for (const auto& send_codec : send_codecs) {
+ RTPFile rtpFile;
+ std::unique_ptr<AudioCodingModule> acm(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory())));
+
+ std::string fileName = webrtc::test::TempFilename(
+ webrtc::test::OutputPath(), "encode_decode_rtp");
+ rtpFile.Open(fileName.c_str(), "wb+");
+ rtpFile.WriteHeader();
+ Sender sender;
+ sender.Setup(acm.get(), &rtpFile, "audio_coding/testfile32kHz", 32000,
+ send_codec.first, send_codec.second);
+ sender.Run();
+ sender.Teardown();
+ rtpFile.Close();
+
+ rtpFile.Open(fileName.c_str(), "rb");
+ rtpFile.ReadHeader();
+ Receiver receiver;
+ receiver.Setup(acm.get(), &rtpFile, "encodeDecode_out", 1, file_num);
+ receiver.Run();
+ receiver.Teardown();
+ rtpFile.Close();
+
+ file_num++;
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.h b/third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.h
new file mode 100644
index 0000000000..89b76440ef
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/EncodeDecodeTest.h
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
+#define MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
+
+#include <stdio.h>
+#include <string.h>
+
+#include "absl/strings/string_view.h"
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "modules/audio_coding/test/PCMFile.h"
+#include "modules/audio_coding/test/RTPFile.h"
+#include "modules/include/module_common_types.h"
+
+namespace webrtc {
+
+#define MAX_INCOMING_PAYLOAD 8096
+
+// TestPacketization callback which writes the encoded payloads to file
+class TestPacketization : public AudioPacketizationCallback {
+ public:
+ TestPacketization(RTPStream* rtpStream, uint16_t frequency);
+ ~TestPacketization();
+ int32_t SendData(AudioFrameType frameType,
+ uint8_t payloadType,
+ uint32_t timeStamp,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ int64_t absolute_capture_timestamp_ms) override;
+
+ private:
+ static void MakeRTPheader(uint8_t* rtpHeader,
+ uint8_t payloadType,
+ int16_t seqNo,
+ uint32_t timeStamp,
+ uint32_t ssrc);
+ RTPStream* _rtpStream;
+ int32_t _frequency;
+ int16_t _seqNo;
+};
+
+class Sender {
+ public:
+ Sender();
+ void Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view in_file_name,
+ int in_sample_rate,
+ int payload_type,
+ SdpAudioFormat format);
+ void Teardown();
+ void Run();
+ bool Add10MsData();
+
+ protected:
+ AudioCodingModule* _acm;
+
+ private:
+ PCMFile _pcmFile;
+ AudioFrame _audioFrame;
+ TestPacketization* _packetization;
+};
+
+class Receiver {
+ public:
+ Receiver();
+ virtual ~Receiver() {}
+ void Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view out_file_name,
+ size_t channels,
+ int file_num);
+ void Teardown();
+ void Run();
+ virtual bool IncomingPacket();
+ bool PlayoutData();
+
+ private:
+ PCMFile _pcmFile;
+ int16_t* _playoutBuffer;
+ uint16_t _playoutLengthSmpls;
+ int32_t _frequency;
+ bool _firstTime;
+
+ protected:
+ AudioCodingModule* _acm;
+ uint8_t _incomingPayload[MAX_INCOMING_PAYLOAD];
+ RTPStream* _rtpStream;
+ RTPHeader _rtpHeader;
+ size_t _realPayloadSizeBytes;
+ size_t _payloadSizeBytes;
+ uint32_t _nextTime;
+};
+
+class EncodeDecodeTest {
+ public:
+ EncodeDecodeTest();
+ void Perform();
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_ENCODEDECODETEST_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/PCMFile.cc b/third_party/libwebrtc/modules/audio_coding/test/PCMFile.cc
new file mode 100644
index 0000000000..e069a42de1
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/PCMFile.cc
@@ -0,0 +1,240 @@
+/*
+ * 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.
+ */
+
+#include "modules/audio_coding/test/PCMFile.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "absl/strings/string_view.h"
+#include "rtc_base/checks.h"
+#include "test/gtest.h"
+
+namespace webrtc {
+
+#define MAX_FILE_NAME_LENGTH_BYTE 500
+
+PCMFile::PCMFile()
+ : pcm_file_(NULL),
+ samples_10ms_(160),
+ frequency_(16000),
+ end_of_file_(false),
+ auto_rewind_(false),
+ rewinded_(false),
+ read_stereo_(false),
+ save_stereo_(false) {
+ timestamp_ =
+ (((uint32_t)rand() & 0x0000FFFF) << 16) | ((uint32_t)rand() & 0x0000FFFF);
+}
+
+PCMFile::PCMFile(uint32_t timestamp)
+ : pcm_file_(NULL),
+ samples_10ms_(160),
+ frequency_(16000),
+ end_of_file_(false),
+ auto_rewind_(false),
+ rewinded_(false),
+ read_stereo_(false),
+ save_stereo_(false) {
+ timestamp_ = timestamp;
+}
+
+PCMFile::~PCMFile() {
+ if (pcm_file_) {
+ fclose(pcm_file_);
+ }
+}
+
+int16_t PCMFile::ChooseFile(std::string* file_name,
+ int16_t max_len,
+ uint16_t* frequency_hz) {
+ char tmp_name[MAX_FILE_NAME_LENGTH_BYTE];
+
+ EXPECT_TRUE(fgets(tmp_name, MAX_FILE_NAME_LENGTH_BYTE, stdin) != NULL);
+ tmp_name[MAX_FILE_NAME_LENGTH_BYTE - 1] = '\0';
+ int16_t n = 0;
+
+ // Removing trailing spaces.
+ while ((isspace(static_cast<unsigned char>(tmp_name[n])) ||
+ iscntrl(static_cast<unsigned char>(tmp_name[n]))) &&
+ (static_cast<unsigned char>(tmp_name[n]) != 0) &&
+ (n < MAX_FILE_NAME_LENGTH_BYTE)) {
+ n++;
+ }
+ if (n > 0) {
+ memmove(tmp_name, &tmp_name[n], MAX_FILE_NAME_LENGTH_BYTE - n);
+ }
+
+ // Removing trailing spaces.
+ n = (int16_t)(strlen(tmp_name) - 1);
+ if (n >= 0) {
+ while ((isspace(static_cast<unsigned char>(tmp_name[n])) ||
+ iscntrl(static_cast<unsigned char>(tmp_name[n]))) &&
+ (n >= 0)) {
+ n--;
+ }
+ }
+ if (n >= 0) {
+ tmp_name[n + 1] = '\0';
+ }
+
+ int16_t len = (int16_t)strlen(tmp_name);
+ if (len > max_len) {
+ return -1;
+ }
+ if (len > 0) {
+ std::string tmp_string(tmp_name, len + 1);
+ *file_name = tmp_string;
+ }
+ printf("Enter the sampling frequency (in Hz) of the above file [%u]: ",
+ *frequency_hz);
+ EXPECT_TRUE(fgets(tmp_name, 10, stdin) != NULL);
+ uint16_t tmp_frequency = (uint16_t)atoi(tmp_name);
+ if (tmp_frequency > 0) {
+ *frequency_hz = tmp_frequency;
+ }
+ return 0;
+}
+
+void PCMFile::Open(absl::string_view file_name,
+ uint16_t frequency,
+ absl::string_view mode,
+ bool auto_rewind) {
+ if ((pcm_file_ = fopen(std::string(file_name).c_str(),
+ std::string(mode).c_str())) == NULL) {
+ printf("Cannot open file %s.\n", std::string(file_name).c_str());
+ ADD_FAILURE() << "Unable to read file";
+ }
+ frequency_ = frequency;
+ samples_10ms_ = (uint16_t)(frequency_ / 100);
+ auto_rewind_ = auto_rewind;
+ end_of_file_ = false;
+ rewinded_ = false;
+}
+
+int32_t PCMFile::SamplingFrequency() const {
+ return frequency_;
+}
+
+uint16_t PCMFile::PayloadLength10Ms() const {
+ return samples_10ms_;
+}
+
+int32_t PCMFile::Read10MsData(AudioFrame& audio_frame) {
+ uint16_t channels = 1;
+ if (read_stereo_) {
+ channels = 2;
+ }
+
+ int32_t payload_size =
+ (int32_t)fread(audio_frame.mutable_data(), sizeof(uint16_t),
+ samples_10ms_ * channels, pcm_file_);
+ if (payload_size < samples_10ms_ * channels) {
+ int16_t* frame_data = audio_frame.mutable_data();
+ for (int k = payload_size; k < samples_10ms_ * channels; k++) {
+ frame_data[k] = 0;
+ }
+ if (auto_rewind_) {
+ rewind(pcm_file_);
+ rewinded_ = true;
+ } else {
+ end_of_file_ = true;
+ }
+ }
+ audio_frame.samples_per_channel_ = samples_10ms_;
+ audio_frame.sample_rate_hz_ = frequency_;
+ audio_frame.num_channels_ = channels;
+ audio_frame.timestamp_ = timestamp_;
+ timestamp_ += samples_10ms_;
+ ++blocks_read_;
+ if (num_10ms_blocks_to_read_ && blocks_read_ >= *num_10ms_blocks_to_read_)
+ end_of_file_ = true;
+ return samples_10ms_;
+}
+
+void PCMFile::Write10MsData(const AudioFrame& audio_frame) {
+ if (audio_frame.num_channels_ == 1) {
+ if (!save_stereo_) {
+ if (fwrite(audio_frame.data(), sizeof(uint16_t),
+ audio_frame.samples_per_channel_, pcm_file_) !=
+ static_cast<size_t>(audio_frame.samples_per_channel_)) {
+ return;
+ }
+ } else {
+ const int16_t* frame_data = audio_frame.data();
+ int16_t* stereo_audio = new int16_t[2 * audio_frame.samples_per_channel_];
+ for (size_t k = 0; k < audio_frame.samples_per_channel_; k++) {
+ stereo_audio[k << 1] = frame_data[k];
+ stereo_audio[(k << 1) + 1] = frame_data[k];
+ }
+ if (fwrite(stereo_audio, sizeof(int16_t),
+ 2 * audio_frame.samples_per_channel_, pcm_file_) !=
+ static_cast<size_t>(2 * audio_frame.samples_per_channel_)) {
+ return;
+ }
+ delete[] stereo_audio;
+ }
+ } else {
+ if (fwrite(audio_frame.data(), sizeof(int16_t),
+ audio_frame.num_channels_ * audio_frame.samples_per_channel_,
+ pcm_file_) !=
+ static_cast<size_t>(audio_frame.num_channels_ *
+ audio_frame.samples_per_channel_)) {
+ return;
+ }
+ }
+}
+
+void PCMFile::Write10MsData(const int16_t* playout_buffer,
+ size_t length_smpls) {
+ if (fwrite(playout_buffer, sizeof(uint16_t), length_smpls, pcm_file_) !=
+ length_smpls) {
+ return;
+ }
+}
+
+void PCMFile::Close() {
+ fclose(pcm_file_);
+ pcm_file_ = NULL;
+ blocks_read_ = 0;
+}
+
+void PCMFile::FastForward(int num_10ms_blocks) {
+ const int channels = read_stereo_ ? 2 : 1;
+ long num_bytes_to_move =
+ num_10ms_blocks * sizeof(int16_t) * samples_10ms_ * channels;
+ int error = fseek(pcm_file_, num_bytes_to_move, SEEK_CUR);
+ RTC_DCHECK_EQ(error, 0);
+}
+
+void PCMFile::Rewind() {
+ rewind(pcm_file_);
+ end_of_file_ = false;
+ blocks_read_ = 0;
+}
+
+bool PCMFile::Rewinded() {
+ return rewinded_;
+}
+
+void PCMFile::SaveStereo(bool is_stereo) {
+ save_stereo_ = is_stereo;
+}
+
+void PCMFile::ReadStereo(bool is_stereo) {
+ read_stereo_ = is_stereo;
+}
+
+void PCMFile::SetNum10MsBlocksToRead(int value) {
+ num_10ms_blocks_to_read_ = value;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/PCMFile.h b/third_party/libwebrtc/modules/audio_coding/test/PCMFile.h
new file mode 100644
index 0000000000..5320aa63d0
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/PCMFile.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_PCMFILE_H_
+#define MODULES_AUDIO_CODING_TEST_PCMFILE_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "absl/types/optional.h"
+#include "api/audio/audio_frame.h"
+
+namespace webrtc {
+
+class PCMFile {
+ public:
+ PCMFile();
+ PCMFile(uint32_t timestamp);
+ ~PCMFile();
+
+ void Open(absl::string_view filename,
+ uint16_t frequency,
+ absl::string_view mode,
+ bool auto_rewind = false);
+
+ int32_t Read10MsData(AudioFrame& audio_frame);
+
+ void Write10MsData(const int16_t* playout_buffer, size_t length_smpls);
+ void Write10MsData(const AudioFrame& audio_frame);
+
+ uint16_t PayloadLength10Ms() const;
+ int32_t SamplingFrequency() const;
+ void Close();
+ bool EndOfFile() const { return end_of_file_; }
+ // Moves forward the specified number of 10 ms blocks. If a limit has been set
+ // with SetNum10MsBlocksToRead, fast-forwarding does not count towards this
+ // limit.
+ void FastForward(int num_10ms_blocks);
+ void Rewind();
+ static int16_t ChooseFile(std::string* file_name,
+ int16_t max_len,
+ uint16_t* frequency_hz);
+ bool Rewinded();
+ void SaveStereo(bool is_stereo = true);
+ void ReadStereo(bool is_stereo = true);
+ // If set, the reading will stop after the specified number of blocks have
+ // been read. When that has happened, EndOfFile() will return true. Calling
+ // Rewind() will reset the counter and start over.
+ void SetNum10MsBlocksToRead(int value);
+
+ private:
+ FILE* pcm_file_;
+ uint16_t samples_10ms_;
+ int32_t frequency_;
+ bool end_of_file_;
+ bool auto_rewind_;
+ bool rewinded_;
+ uint32_t timestamp_;
+ bool read_stereo_;
+ bool save_stereo_;
+ absl::optional<int> num_10ms_blocks_to_read_;
+ int blocks_read_ = 0;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_PCMFILE_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.cc b/third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.cc
new file mode 100644
index 0000000000..799e9c5b1f
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.cc
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2014 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 "modules/audio_coding/test/PacketLossTest.h"
+
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+ReceiverWithPacketLoss::ReceiverWithPacketLoss()
+ : loss_rate_(0),
+ burst_length_(1),
+ packet_counter_(0),
+ lost_packet_counter_(0),
+ burst_lost_counter_(burst_length_) {}
+
+void ReceiverWithPacketLoss::Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view out_file_name,
+ int channels,
+ int file_num,
+ int loss_rate,
+ int burst_length) {
+ loss_rate_ = loss_rate;
+ burst_length_ = burst_length;
+ burst_lost_counter_ = burst_length_; // To prevent first packet gets lost.
+ rtc::StringBuilder ss;
+ ss << out_file_name << "_" << loss_rate_ << "_" << burst_length_ << "_";
+ Receiver::Setup(acm, rtpStream, ss.str(), channels, file_num);
+}
+
+bool ReceiverWithPacketLoss::IncomingPacket() {
+ if (!_rtpStream->EndOfFile()) {
+ if (packet_counter_ == 0) {
+ _realPayloadSizeBytes = _rtpStream->Read(&_rtpHeader, _incomingPayload,
+ _payloadSizeBytes, &_nextTime);
+ if (_realPayloadSizeBytes == 0) {
+ if (_rtpStream->EndOfFile()) {
+ packet_counter_ = 0;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ if (!PacketLost()) {
+ _acm->IncomingPacket(_incomingPayload, _realPayloadSizeBytes, _rtpHeader);
+ }
+ packet_counter_++;
+ _realPayloadSizeBytes = _rtpStream->Read(&_rtpHeader, _incomingPayload,
+ _payloadSizeBytes, &_nextTime);
+ if (_realPayloadSizeBytes == 0 && _rtpStream->EndOfFile()) {
+ packet_counter_ = 0;
+ lost_packet_counter_ = 0;
+ }
+ }
+ return true;
+}
+
+bool ReceiverWithPacketLoss::PacketLost() {
+ if (burst_lost_counter_ < burst_length_) {
+ lost_packet_counter_++;
+ burst_lost_counter_++;
+ return true;
+ }
+
+ if (lost_packet_counter_ * 100 < loss_rate_ * packet_counter_) {
+ lost_packet_counter_++;
+ burst_lost_counter_ = 1;
+ return true;
+ }
+ return false;
+}
+
+SenderWithFEC::SenderWithFEC() : expected_loss_rate_(0) {}
+
+void SenderWithFEC::Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view in_file_name,
+ int payload_type,
+ SdpAudioFormat format,
+ int expected_loss_rate) {
+ Sender::Setup(acm, rtpStream, in_file_name, format.clockrate_hz, payload_type,
+ format);
+ EXPECT_TRUE(SetFEC(true));
+ EXPECT_TRUE(SetPacketLossRate(expected_loss_rate));
+}
+
+bool SenderWithFEC::SetFEC(bool enable_fec) {
+ bool success = false;
+ _acm->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
+ if (*enc && (*enc)->SetFec(enable_fec)) {
+ success = true;
+ }
+ });
+ return success;
+}
+
+bool SenderWithFEC::SetPacketLossRate(int expected_loss_rate) {
+ if (_acm->SetPacketLossRate(expected_loss_rate) == 0) {
+ expected_loss_rate_ = expected_loss_rate;
+ return true;
+ }
+ return false;
+}
+
+PacketLossTest::PacketLossTest(int channels,
+ int expected_loss_rate,
+ int actual_loss_rate,
+ int burst_length)
+ : channels_(channels),
+ in_file_name_(channels_ == 1 ? "audio_coding/testfile32kHz"
+ : "audio_coding/teststereo32kHz"),
+ sample_rate_hz_(32000),
+ expected_loss_rate_(expected_loss_rate),
+ actual_loss_rate_(actual_loss_rate),
+ burst_length_(burst_length) {}
+
+void PacketLossTest::Perform() {
+#ifndef WEBRTC_CODEC_OPUS
+ return;
+#else
+ RTPFile rtpFile;
+ std::unique_ptr<AudioCodingModule> acm(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory())));
+ SdpAudioFormat send_format = SdpAudioFormat("opus", 48000, 2);
+ if (channels_ == 2) {
+ send_format.parameters = {{"stereo", "1"}};
+ }
+
+ std::string fileName = webrtc::test::TempFilename(webrtc::test::OutputPath(),
+ "packet_loss_test");
+ rtpFile.Open(fileName.c_str(), "wb+");
+ rtpFile.WriteHeader();
+ SenderWithFEC sender;
+ sender.Setup(acm.get(), &rtpFile, in_file_name_, 120, send_format,
+ expected_loss_rate_);
+ sender.Run();
+ sender.Teardown();
+ rtpFile.Close();
+
+ rtpFile.Open(fileName.c_str(), "rb");
+ rtpFile.ReadHeader();
+ ReceiverWithPacketLoss receiver;
+ receiver.Setup(acm.get(), &rtpFile, "packetLoss_out", channels_, 15,
+ actual_loss_rate_, burst_length_);
+ receiver.Run();
+ receiver.Teardown();
+ rtpFile.Close();
+#endif
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.h b/third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.h
new file mode 100644
index 0000000000..d841d65a1b
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/PacketLossTest.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2014 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
+#define MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
+
+#include <string>
+
+#include "absl/strings/string_view.h"
+#include "modules/audio_coding/test/EncodeDecodeTest.h"
+
+namespace webrtc {
+
+class ReceiverWithPacketLoss : public Receiver {
+ public:
+ ReceiverWithPacketLoss();
+ void Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view out_file_name,
+ int channels,
+ int file_num,
+ int loss_rate,
+ int burst_length);
+ bool IncomingPacket() override;
+
+ protected:
+ bool PacketLost();
+ int loss_rate_;
+ int burst_length_;
+ int packet_counter_;
+ int lost_packet_counter_;
+ int burst_lost_counter_;
+};
+
+class SenderWithFEC : public Sender {
+ public:
+ SenderWithFEC();
+ void Setup(AudioCodingModule* acm,
+ RTPStream* rtpStream,
+ absl::string_view in_file_name,
+ int payload_type,
+ SdpAudioFormat format,
+ int expected_loss_rate);
+ bool SetPacketLossRate(int expected_loss_rate);
+ bool SetFEC(bool enable_fec);
+
+ protected:
+ int expected_loss_rate_;
+};
+
+class PacketLossTest {
+ public:
+ PacketLossTest(int channels,
+ int expected_loss_rate_,
+ int actual_loss_rate,
+ int burst_length);
+ void Perform();
+
+ protected:
+ int channels_;
+ std::string in_file_name_;
+ int sample_rate_hz_;
+ int expected_loss_rate_;
+ int actual_loss_rate_;
+ int burst_length_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_PACKETLOSSTEST_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/RTPFile.cc b/third_party/libwebrtc/modules/audio_coding/test/RTPFile.cc
new file mode 100644
index 0000000000..0c2ab3c443
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/RTPFile.cc
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+#include "RTPFile.h"
+
+#include <stdlib.h>
+
+#include <limits>
+
+#include "absl/strings/string_view.h"
+
+#ifdef WIN32
+#include <Winsock2.h>
+#else
+#include <arpa/inet.h>
+#endif
+
+// TODO(tlegrand): Consider removing usage of gtest.
+#include "test/gtest.h"
+
+namespace webrtc {
+
+void RTPStream::ParseRTPHeader(RTPHeader* rtp_header,
+ const uint8_t* rtpHeader) {
+ rtp_header->payloadType = rtpHeader[1];
+ rtp_header->sequenceNumber =
+ (static_cast<uint16_t>(rtpHeader[2]) << 8) | rtpHeader[3];
+ rtp_header->timestamp = (static_cast<uint32_t>(rtpHeader[4]) << 24) |
+ (static_cast<uint32_t>(rtpHeader[5]) << 16) |
+ (static_cast<uint32_t>(rtpHeader[6]) << 8) |
+ rtpHeader[7];
+ rtp_header->ssrc = (static_cast<uint32_t>(rtpHeader[8]) << 24) |
+ (static_cast<uint32_t>(rtpHeader[9]) << 16) |
+ (static_cast<uint32_t>(rtpHeader[10]) << 8) |
+ rtpHeader[11];
+}
+
+void RTPStream::MakeRTPheader(uint8_t* rtpHeader,
+ uint8_t payloadType,
+ int16_t seqNo,
+ uint32_t timeStamp,
+ uint32_t ssrc) {
+ rtpHeader[0] = 0x80;
+ rtpHeader[1] = payloadType;
+ rtpHeader[2] = (seqNo >> 8) & 0xFF;
+ rtpHeader[3] = seqNo & 0xFF;
+ rtpHeader[4] = timeStamp >> 24;
+ rtpHeader[5] = (timeStamp >> 16) & 0xFF;
+ rtpHeader[6] = (timeStamp >> 8) & 0xFF;
+ rtpHeader[7] = timeStamp & 0xFF;
+ rtpHeader[8] = ssrc >> 24;
+ rtpHeader[9] = (ssrc >> 16) & 0xFF;
+ rtpHeader[10] = (ssrc >> 8) & 0xFF;
+ rtpHeader[11] = ssrc & 0xFF;
+}
+
+RTPPacket::RTPPacket(uint8_t payloadType,
+ uint32_t timeStamp,
+ int16_t seqNo,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t frequency)
+ : payloadType(payloadType),
+ timeStamp(timeStamp),
+ seqNo(seqNo),
+ payloadSize(payloadSize),
+ frequency(frequency) {
+ if (payloadSize > 0) {
+ this->payloadData = new uint8_t[payloadSize];
+ memcpy(this->payloadData, payloadData, payloadSize);
+ }
+}
+
+RTPPacket::~RTPPacket() {
+ delete[] payloadData;
+}
+
+void RTPBuffer::Write(const uint8_t payloadType,
+ const uint32_t timeStamp,
+ const int16_t seqNo,
+ const uint8_t* payloadData,
+ const size_t payloadSize,
+ uint32_t frequency) {
+ RTPPacket* packet = new RTPPacket(payloadType, timeStamp, seqNo, payloadData,
+ payloadSize, frequency);
+ MutexLock lock(&mutex_);
+ _rtpQueue.push(packet);
+}
+
+size_t RTPBuffer::Read(RTPHeader* rtp_header,
+ uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t* offset) {
+ RTPPacket* packet;
+ {
+ MutexLock lock(&mutex_);
+ packet = _rtpQueue.front();
+ _rtpQueue.pop();
+ }
+ rtp_header->markerBit = 1;
+ rtp_header->payloadType = packet->payloadType;
+ rtp_header->sequenceNumber = packet->seqNo;
+ rtp_header->ssrc = 0;
+ rtp_header->timestamp = packet->timeStamp;
+ if (packet->payloadSize > 0 && payloadSize >= packet->payloadSize) {
+ memcpy(payloadData, packet->payloadData, packet->payloadSize);
+ } else {
+ return 0;
+ }
+ *offset = (packet->timeStamp / (packet->frequency / 1000));
+
+ return packet->payloadSize;
+}
+
+bool RTPBuffer::EndOfFile() const {
+ MutexLock lock(&mutex_);
+ return _rtpQueue.empty();
+}
+
+void RTPFile::Open(absl::string_view filename, absl::string_view mode) {
+ std::string filename_str = std::string(filename);
+ if ((_rtpFile = fopen(filename_str.c_str(), std::string(mode).c_str())) ==
+ NULL) {
+ printf("Cannot write file %s.\n", filename_str.c_str());
+ ADD_FAILURE() << "Unable to write file";
+ exit(1);
+ }
+}
+
+void RTPFile::Close() {
+ if (_rtpFile != NULL) {
+ fclose(_rtpFile);
+ _rtpFile = NULL;
+ }
+}
+
+void RTPFile::WriteHeader() {
+ // Write data in a format that NetEQ and RTP Play can parse
+ fprintf(_rtpFile, "#!RTPencode%s\n", "1.0");
+ uint32_t dummy_variable = 0;
+ // should be converted to network endian format, but does not matter when 0
+ EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
+ EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
+ EXPECT_EQ(1u, fwrite(&dummy_variable, 4, 1, _rtpFile));
+ EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
+ EXPECT_EQ(1u, fwrite(&dummy_variable, 2, 1, _rtpFile));
+ fflush(_rtpFile);
+}
+
+void RTPFile::ReadHeader() {
+ uint32_t start_sec, start_usec, source;
+ uint16_t port, padding;
+ char fileHeader[40];
+ EXPECT_TRUE(fgets(fileHeader, 40, _rtpFile) != 0);
+ EXPECT_EQ(1u, fread(&start_sec, 4, 1, _rtpFile));
+ start_sec = ntohl(start_sec);
+ EXPECT_EQ(1u, fread(&start_usec, 4, 1, _rtpFile));
+ start_usec = ntohl(start_usec);
+ EXPECT_EQ(1u, fread(&source, 4, 1, _rtpFile));
+ source = ntohl(source);
+ EXPECT_EQ(1u, fread(&port, 2, 1, _rtpFile));
+ port = ntohs(port);
+ EXPECT_EQ(1u, fread(&padding, 2, 1, _rtpFile));
+ padding = ntohs(padding);
+}
+
+void RTPFile::Write(const uint8_t payloadType,
+ const uint32_t timeStamp,
+ const int16_t seqNo,
+ const uint8_t* payloadData,
+ const size_t payloadSize,
+ uint32_t frequency) {
+ /* write RTP packet to file */
+ uint8_t rtpHeader[12];
+ MakeRTPheader(rtpHeader, payloadType, seqNo, timeStamp, 0);
+ ASSERT_LE(12 + payloadSize + 8, std::numeric_limits<u_short>::max());
+ uint16_t lengthBytes = htons(static_cast<u_short>(12 + payloadSize + 8));
+ uint16_t plen = htons(static_cast<u_short>(12 + payloadSize));
+ uint32_t offsetMs;
+
+ offsetMs = (timeStamp / (frequency / 1000));
+ offsetMs = htonl(offsetMs);
+ EXPECT_EQ(1u, fwrite(&lengthBytes, 2, 1, _rtpFile));
+ EXPECT_EQ(1u, fwrite(&plen, 2, 1, _rtpFile));
+ EXPECT_EQ(1u, fwrite(&offsetMs, 4, 1, _rtpFile));
+ EXPECT_EQ(1u, fwrite(&rtpHeader, 12, 1, _rtpFile));
+ EXPECT_EQ(payloadSize, fwrite(payloadData, 1, payloadSize, _rtpFile));
+}
+
+size_t RTPFile::Read(RTPHeader* rtp_header,
+ uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t* offset) {
+ uint16_t lengthBytes;
+ uint16_t plen;
+ uint8_t rtpHeader[12];
+ size_t read_len = fread(&lengthBytes, 2, 1, _rtpFile);
+ /* Check if we have reached end of file. */
+ if ((read_len == 0) && feof(_rtpFile)) {
+ _rtpEOF = true;
+ return 0;
+ }
+ EXPECT_EQ(1u, fread(&plen, 2, 1, _rtpFile));
+ EXPECT_EQ(1u, fread(offset, 4, 1, _rtpFile));
+ lengthBytes = ntohs(lengthBytes);
+ plen = ntohs(plen);
+ *offset = ntohl(*offset);
+ EXPECT_GT(plen, 11);
+
+ EXPECT_EQ(1u, fread(rtpHeader, 12, 1, _rtpFile));
+ ParseRTPHeader(rtp_header, rtpHeader);
+ EXPECT_EQ(lengthBytes, plen + 8);
+
+ if (plen == 0) {
+ return 0;
+ }
+ if (lengthBytes < 20) {
+ return 0;
+ }
+ if (payloadSize < static_cast<size_t>((lengthBytes - 20))) {
+ return 0;
+ }
+ lengthBytes -= 20;
+ EXPECT_EQ(lengthBytes, fread(payloadData, 1, lengthBytes, _rtpFile));
+ return lengthBytes;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/RTPFile.h b/third_party/libwebrtc/modules/audio_coding/test/RTPFile.h
new file mode 100644
index 0000000000..b796491da9
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/RTPFile.h
@@ -0,0 +1,133 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_RTPFILE_H_
+#define MODULES_AUDIO_CODING_TEST_RTPFILE_H_
+
+#include <stdio.h>
+
+#include <queue>
+
+#include "absl/strings/string_view.h"
+#include "api/rtp_headers.h"
+#include "rtc_base/synchronization/mutex.h"
+#include "rtc_base/thread_annotations.h"
+
+namespace webrtc {
+
+class RTPStream {
+ public:
+ virtual ~RTPStream() {}
+
+ virtual void Write(uint8_t payloadType,
+ uint32_t timeStamp,
+ int16_t seqNo,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t frequency) = 0;
+
+ // Returns the packet's payload size. Zero should be treated as an
+ // end-of-stream (in the case that EndOfFile() is true) or an error.
+ virtual size_t Read(RTPHeader* rtp_Header,
+ uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t* offset) = 0;
+ virtual bool EndOfFile() const = 0;
+
+ protected:
+ void MakeRTPheader(uint8_t* rtpHeader,
+ uint8_t payloadType,
+ int16_t seqNo,
+ uint32_t timeStamp,
+ uint32_t ssrc);
+
+ void ParseRTPHeader(RTPHeader* rtp_header, const uint8_t* rtpHeader);
+};
+
+class RTPPacket {
+ public:
+ RTPPacket(uint8_t payloadType,
+ uint32_t timeStamp,
+ int16_t seqNo,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t frequency);
+
+ ~RTPPacket();
+
+ uint8_t payloadType;
+ uint32_t timeStamp;
+ int16_t seqNo;
+ uint8_t* payloadData;
+ size_t payloadSize;
+ uint32_t frequency;
+};
+
+class RTPBuffer : public RTPStream {
+ public:
+ RTPBuffer() = default;
+
+ ~RTPBuffer() = default;
+
+ void Write(uint8_t payloadType,
+ uint32_t timeStamp,
+ int16_t seqNo,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t frequency) override;
+
+ size_t Read(RTPHeader* rtp_header,
+ uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t* offset) override;
+
+ bool EndOfFile() const override;
+
+ private:
+ mutable Mutex mutex_;
+ std::queue<RTPPacket*> _rtpQueue RTC_GUARDED_BY(&mutex_);
+};
+
+class RTPFile : public RTPStream {
+ public:
+ ~RTPFile() {}
+
+ RTPFile() : _rtpFile(NULL), _rtpEOF(false) {}
+
+ void Open(absl::string_view outFilename, absl::string_view mode);
+
+ void Close();
+
+ void WriteHeader();
+
+ void ReadHeader();
+
+ void Write(uint8_t payloadType,
+ uint32_t timeStamp,
+ int16_t seqNo,
+ const uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t frequency) override;
+
+ size_t Read(RTPHeader* rtp_header,
+ uint8_t* payloadData,
+ size_t payloadSize,
+ uint32_t* offset) override;
+
+ bool EndOfFile() const override { return _rtpEOF; }
+
+ private:
+ FILE* _rtpFile;
+ bool _rtpEOF;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_RTPFILE_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.cc b/third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.cc
new file mode 100644
index 0000000000..b44037d732
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.cc
@@ -0,0 +1,412 @@
+/*
+ * 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.
+ */
+
+#include "modules/audio_coding/test/TestAllCodecs.h"
+
+#include <cstdio>
+#include <limits>
+#include <string>
+
+#include "absl/strings/match.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
+#include "modules/include/module_common_types.h"
+#include "rtc_base/logging.h"
+#include "rtc_base/string_encode.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+// Description of the test:
+// In this test we set up a one-way communication channel from a participant
+// called "a" to a participant called "b".
+// a -> channel_a_to_b -> b
+//
+// The test loops through all available mono codecs, encode at "a" sends over
+// the channel, and decodes at "b".
+
+#define CHECK_ERROR(f) \
+ do { \
+ EXPECT_GE(f, 0) << "Error Calling API"; \
+ } while (0)
+
+namespace {
+const size_t kVariableSize = std::numeric_limits<size_t>::max();
+}
+
+namespace webrtc {
+
+// Class for simulating packet handling.
+TestPack::TestPack()
+ : receiver_acm_(NULL),
+ sequence_number_(0),
+ timestamp_diff_(0),
+ last_in_timestamp_(0),
+ total_bytes_(0),
+ payload_size_(0) {}
+
+TestPack::~TestPack() {}
+
+void TestPack::RegisterReceiverACM(AudioCodingModule* acm) {
+ receiver_acm_ = acm;
+ return;
+}
+
+int32_t TestPack::SendData(AudioFrameType frame_type,
+ uint8_t payload_type,
+ uint32_t timestamp,
+ const uint8_t* payload_data,
+ size_t payload_size,
+ int64_t absolute_capture_timestamp_ms) {
+ RTPHeader rtp_header;
+ int32_t status;
+
+ rtp_header.markerBit = false;
+ rtp_header.ssrc = 0;
+ rtp_header.sequenceNumber = sequence_number_++;
+ rtp_header.payloadType = payload_type;
+ rtp_header.timestamp = timestamp;
+
+ if (frame_type == AudioFrameType::kEmptyFrame) {
+ // Skip this frame.
+ return 0;
+ }
+
+ // Only run mono for all test cases.
+ memcpy(payload_data_, payload_data, payload_size);
+
+ status =
+ receiver_acm_->IncomingPacket(payload_data_, payload_size, rtp_header);
+
+ payload_size_ = payload_size;
+ timestamp_diff_ = timestamp - last_in_timestamp_;
+ last_in_timestamp_ = timestamp;
+ total_bytes_ += payload_size;
+ return status;
+}
+
+size_t TestPack::payload_size() {
+ return payload_size_;
+}
+
+uint32_t TestPack::timestamp_diff() {
+ return timestamp_diff_;
+}
+
+void TestPack::reset_payload_size() {
+ payload_size_ = 0;
+}
+
+TestAllCodecs::TestAllCodecs()
+ : acm_a_(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
+ acm_b_(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
+ channel_a_to_b_(NULL),
+ test_count_(0),
+ packet_size_samples_(0),
+ packet_size_bytes_(0) {}
+
+TestAllCodecs::~TestAllCodecs() {
+ if (channel_a_to_b_ != NULL) {
+ delete channel_a_to_b_;
+ channel_a_to_b_ = NULL;
+ }
+}
+
+void TestAllCodecs::Perform() {
+ const std::string file_name =
+ webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+ infile_a_.Open(file_name, 32000, "rb");
+
+ acm_a_->InitializeReceiver();
+ acm_b_->InitializeReceiver();
+
+ acm_b_->SetReceiveCodecs({{107, {"L16", 8000, 1}},
+ {108, {"L16", 16000, 1}},
+ {109, {"L16", 32000, 1}},
+ {111, {"L16", 8000, 2}},
+ {112, {"L16", 16000, 2}},
+ {113, {"L16", 32000, 2}},
+ {0, {"PCMU", 8000, 1}},
+ {110, {"PCMU", 8000, 2}},
+ {8, {"PCMA", 8000, 1}},
+ {118, {"PCMA", 8000, 2}},
+ {102, {"ILBC", 8000, 1}},
+ {9, {"G722", 8000, 1}},
+ {119, {"G722", 8000, 2}},
+ {120, {"OPUS", 48000, 2, {{"stereo", "1"}}}},
+ {13, {"CN", 8000, 1}},
+ {98, {"CN", 16000, 1}},
+ {99, {"CN", 32000, 1}}});
+
+ // Create and connect the channel
+ channel_a_to_b_ = new TestPack;
+ acm_a_->RegisterTransportCallback(channel_a_to_b_);
+ channel_a_to_b_->RegisterReceiverACM(acm_b_.get());
+
+ // All codecs are tested for all allowed sampling frequencies, rates and
+ // packet sizes.
+ test_count_++;
+ OpenOutFile(test_count_);
+ char codec_g722[] = "G722";
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 160, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 320, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 480, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 640, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 800, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 960, 0);
+ Run(channel_a_to_b_);
+ outfile_b_.Close();
+#ifdef WEBRTC_CODEC_ILBC
+ test_count_++;
+ OpenOutFile(test_count_);
+ char codec_ilbc[] = "ILBC";
+ RegisterSendCodec('A', codec_ilbc, 8000, 13300, 240, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_ilbc, 8000, 13300, 480, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_ilbc, 8000, 15200, 160, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_ilbc, 8000, 15200, 320, 0);
+ Run(channel_a_to_b_);
+ outfile_b_.Close();
+#endif
+ test_count_++;
+ OpenOutFile(test_count_);
+ char codec_l16[] = "L16";
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 80, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 160, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 240, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 320, 0);
+ Run(channel_a_to_b_);
+ outfile_b_.Close();
+
+ test_count_++;
+ OpenOutFile(test_count_);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 160, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 320, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 480, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 640, 0);
+ Run(channel_a_to_b_);
+ outfile_b_.Close();
+
+ test_count_++;
+ OpenOutFile(test_count_);
+ RegisterSendCodec('A', codec_l16, 32000, 512000, 320, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_l16, 32000, 512000, 640, 0);
+ Run(channel_a_to_b_);
+ outfile_b_.Close();
+
+ test_count_++;
+ OpenOutFile(test_count_);
+ char codec_pcma[] = "PCMA";
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 160, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 240, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 320, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 400, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 480, 0);
+ Run(channel_a_to_b_);
+
+ char codec_pcmu[] = "PCMU";
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 160, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 240, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 320, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 400, 0);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 480, 0);
+ Run(channel_a_to_b_);
+ outfile_b_.Close();
+#ifdef WEBRTC_CODEC_OPUS
+ test_count_++;
+ OpenOutFile(test_count_);
+ char codec_opus[] = "OPUS";
+ RegisterSendCodec('A', codec_opus, 48000, 6000, 480, kVariableSize);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_opus, 48000, 20000, 480 * 2, kVariableSize);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_opus, 48000, 32000, 480 * 4, kVariableSize);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_opus, 48000, 48000, 480, kVariableSize);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_opus, 48000, 64000, 480 * 4, kVariableSize);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_opus, 48000, 96000, 480 * 6, kVariableSize);
+ Run(channel_a_to_b_);
+ RegisterSendCodec('A', codec_opus, 48000, 500000, 480 * 2, kVariableSize);
+ Run(channel_a_to_b_);
+ outfile_b_.Close();
+#endif
+}
+
+// Register Codec to use in the test
+//
+// Input: side - which ACM to use, 'A' or 'B'
+// codec_name - name to use when register the codec
+// sampling_freq_hz - sampling frequency in Herz
+// rate - bitrate in bytes
+// packet_size - packet size in samples
+// extra_byte - if extra bytes needed compared to the bitrate
+// used when registering, can be an internal header
+// set to kVariableSize if the codec is a variable
+// rate codec
+void TestAllCodecs::RegisterSendCodec(char side,
+ char* codec_name,
+ int32_t sampling_freq_hz,
+ int rate,
+ int packet_size,
+ size_t extra_byte) {
+ // Store packet-size in samples, used to validate the received packet.
+ // If G.722, store half the size to compensate for the timestamp bug in the
+ // RFC for G.722.
+ int clockrate_hz = sampling_freq_hz;
+ size_t num_channels = 1;
+ if (absl::EqualsIgnoreCase(codec_name, "G722")) {
+ packet_size_samples_ = packet_size / 2;
+ clockrate_hz = sampling_freq_hz / 2;
+ } else if (absl::EqualsIgnoreCase(codec_name, "OPUS")) {
+ packet_size_samples_ = packet_size;
+ num_channels = 2;
+ } else {
+ packet_size_samples_ = packet_size;
+ }
+
+ // Store the expected packet size in bytes, used to validate the received
+ // packet. If variable rate codec (extra_byte == -1), set to -1.
+ if (extra_byte != kVariableSize) {
+ // Add 0.875 to always round up to a whole byte
+ packet_size_bytes_ =
+ static_cast<size_t>(static_cast<float>(packet_size * rate) /
+ static_cast<float>(sampling_freq_hz * 8) +
+ 0.875) +
+ extra_byte;
+ } else {
+ // Packets will have a variable size.
+ packet_size_bytes_ = kVariableSize;
+ }
+
+ // Set pointer to the ACM where to register the codec.
+ AudioCodingModule* my_acm = NULL;
+ switch (side) {
+ case 'A': {
+ my_acm = acm_a_.get();
+ break;
+ }
+ case 'B': {
+ my_acm = acm_b_.get();
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ ASSERT_TRUE(my_acm != NULL);
+
+ auto factory = CreateBuiltinAudioEncoderFactory();
+ constexpr int payload_type = 17;
+ SdpAudioFormat format = {codec_name, clockrate_hz, num_channels};
+ format.parameters["ptime"] = rtc::ToString(rtc::CheckedDivExact(
+ packet_size, rtc::CheckedDivExact(sampling_freq_hz, 1000)));
+ my_acm->SetEncoder(
+ factory->MakeAudioEncoder(payload_type, format, absl::nullopt));
+}
+
+void TestAllCodecs::Run(TestPack* channel) {
+ AudioFrame audio_frame;
+
+ int32_t out_freq_hz = outfile_b_.SamplingFrequency();
+ size_t receive_size;
+ uint32_t timestamp_diff;
+ channel->reset_payload_size();
+ int error_count = 0;
+ int counter = 0;
+ // Set test length to 500 ms (50 blocks of 10 ms each).
+ infile_a_.SetNum10MsBlocksToRead(50);
+ // Fast-forward 1 second (100 blocks) since the file starts with silence.
+ infile_a_.FastForward(100);
+
+ while (!infile_a_.EndOfFile()) {
+ // Add 10 msec to ACM.
+ infile_a_.Read10MsData(audio_frame);
+ CHECK_ERROR(acm_a_->Add10MsData(audio_frame));
+
+ // Verify that the received packet size matches the settings.
+ receive_size = channel->payload_size();
+ if (receive_size) {
+ if ((receive_size != packet_size_bytes_) &&
+ (packet_size_bytes_ != kVariableSize)) {
+ error_count++;
+ }
+
+ // Verify that the timestamp is updated with expected length. The counter
+ // is used to avoid problems when switching codec or frame size in the
+ // test.
+ timestamp_diff = channel->timestamp_diff();
+ if ((counter > 10) &&
+ (static_cast<int>(timestamp_diff) != packet_size_samples_) &&
+ (packet_size_samples_ > -1))
+ error_count++;
+ }
+
+ // Run received side of ACM.
+ bool muted;
+ CHECK_ERROR(acm_b_->PlayoutData10Ms(out_freq_hz, &audio_frame, &muted));
+ ASSERT_FALSE(muted);
+
+ // Write output speech to file.
+ outfile_b_.Write10MsData(audio_frame.data(),
+ audio_frame.samples_per_channel_);
+
+ // Update loop counter
+ counter++;
+ }
+
+ EXPECT_EQ(0, error_count);
+
+ if (infile_a_.EndOfFile()) {
+ infile_a_.Rewind();
+ }
+}
+
+void TestAllCodecs::OpenOutFile(int test_number) {
+ std::string filename = webrtc::test::OutputPath();
+ rtc::StringBuilder test_number_str;
+ test_number_str << test_number;
+ filename += "testallcodecs_out_";
+ filename += test_number_str.str();
+ filename += ".pcm";
+ outfile_b_.Open(filename, 32000, "wb");
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.h b/third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.h
new file mode 100644
index 0000000000..0c276414e4
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestAllCodecs.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
+#define MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
+
+#include <memory>
+
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "modules/audio_coding/test/PCMFile.h"
+
+namespace webrtc {
+
+class TestPack : public AudioPacketizationCallback {
+ public:
+ TestPack();
+ ~TestPack();
+
+ void RegisterReceiverACM(AudioCodingModule* acm);
+
+ int32_t SendData(AudioFrameType frame_type,
+ uint8_t payload_type,
+ uint32_t timestamp,
+ const uint8_t* payload_data,
+ size_t payload_size,
+ int64_t absolute_capture_timestamp_ms) override;
+
+ size_t payload_size();
+ uint32_t timestamp_diff();
+ void reset_payload_size();
+
+ private:
+ AudioCodingModule* receiver_acm_;
+ uint16_t sequence_number_;
+ uint8_t payload_data_[60 * 32 * 2 * 2];
+ uint32_t timestamp_diff_;
+ uint32_t last_in_timestamp_;
+ uint64_t total_bytes_;
+ size_t payload_size_;
+};
+
+class TestAllCodecs {
+ public:
+ TestAllCodecs();
+ ~TestAllCodecs();
+
+ void Perform();
+
+ private:
+ // The default value of '-1' indicates that the registration is based only on
+ // codec name, and a sampling frequency matching is not required.
+ // This is useful for codecs which support several sampling frequency.
+ // Note! Only mono mode is tested in this test.
+ void RegisterSendCodec(char side,
+ char* codec_name,
+ int32_t sampling_freq_hz,
+ int rate,
+ int packet_size,
+ size_t extra_byte);
+
+ void Run(TestPack* channel);
+ void OpenOutFile(int test_number);
+
+ std::unique_ptr<AudioCodingModule> acm_a_;
+ std::unique_ptr<AudioCodingModule> acm_b_;
+ TestPack* channel_a_to_b_;
+ PCMFile infile_a_;
+ PCMFile outfile_b_;
+ int test_count_;
+ int packet_size_samples_;
+ size_t packet_size_bytes_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_TESTALLCODECS_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestRedFec.cc b/third_party/libwebrtc/modules/audio_coding/test/TestRedFec.cc
new file mode 100644
index 0000000000..fff48b27bc
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestRedFec.cc
@@ -0,0 +1,200 @@
+/*
+ * 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.
+ */
+
+#include "modules/audio_coding/test/TestRedFec.h"
+
+#include <memory>
+#include <utility>
+
+#include "absl/strings/match.h"
+#include "api/audio_codecs/L16/audio_decoder_L16.h"
+#include "api/audio_codecs/L16/audio_encoder_L16.h"
+#include "api/audio_codecs/audio_decoder_factory_template.h"
+#include "api/audio_codecs/audio_encoder_factory_template.h"
+#include "api/audio_codecs/g711/audio_decoder_g711.h"
+#include "api/audio_codecs/g711/audio_encoder_g711.h"
+#include "api/audio_codecs/g722/audio_decoder_g722.h"
+#include "api/audio_codecs/g722/audio_encoder_g722.h"
+#include "api/audio_codecs/opus/audio_decoder_opus.h"
+#include "api/audio_codecs/opus/audio_encoder_opus.h"
+#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
+#include "modules/audio_coding/codecs/red/audio_encoder_copy_red.h"
+#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+TestRedFec::TestRedFec()
+ : encoder_factory_(CreateAudioEncoderFactory<AudioEncoderG711,
+ AudioEncoderG722,
+ AudioEncoderL16,
+ AudioEncoderOpus>()),
+ decoder_factory_(CreateAudioDecoderFactory<AudioDecoderG711,
+ AudioDecoderG722,
+ AudioDecoderL16,
+ AudioDecoderOpus>()),
+ _acmA(AudioCodingModule::Create(
+ AudioCodingModule::Config(decoder_factory_))),
+ _acmB(AudioCodingModule::Create(
+ AudioCodingModule::Config(decoder_factory_))),
+ _channelA2B(NULL),
+ _testCntr(0) {}
+
+TestRedFec::~TestRedFec() {
+ if (_channelA2B != NULL) {
+ delete _channelA2B;
+ _channelA2B = NULL;
+ }
+}
+
+void TestRedFec::Perform() {
+ const std::string file_name =
+ webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+ _inFileA.Open(file_name, 32000, "rb");
+
+ ASSERT_EQ(0, _acmA->InitializeReceiver());
+ ASSERT_EQ(0, _acmB->InitializeReceiver());
+
+ // Create and connect the channel
+ _channelA2B = new Channel;
+ _acmA->RegisterTransportCallback(_channelA2B);
+ _channelA2B->RegisterReceiverACM(_acmB.get());
+
+ RegisterSendCodec(_acmA, {"L16", 8000, 1}, Vad::kVadAggressive, true);
+
+ OpenOutFile(_testCntr);
+ Run();
+ _outFileB.Close();
+
+ // Switch to another 8 kHz codec; RED should remain switched on.
+ RegisterSendCodec(_acmA, {"PCMU", 8000, 1}, Vad::kVadAggressive, true);
+ OpenOutFile(_testCntr);
+ Run();
+ _outFileB.Close();
+
+ // Switch to a 16 kHz codec; RED should be switched off.
+ RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
+
+ OpenOutFile(_testCntr);
+ RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
+ Run();
+ RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
+ Run();
+ _outFileB.Close();
+
+ _channelA2B->SetFECTestWithPacketLoss(true);
+ // Following tests are under packet losses.
+
+ // Switch to a 16 kHz codec; RED should be switched off.
+ RegisterSendCodec(_acmA, {"G722", 8000, 1}, Vad::kVadAggressive, false);
+
+ OpenOutFile(_testCntr);
+ Run();
+ _outFileB.Close();
+
+ RegisterSendCodec(_acmA, {"opus", 48000, 2}, absl::nullopt, false);
+
+ // _channelA2B imposes 25% packet loss rate.
+ EXPECT_EQ(0, _acmA->SetPacketLossRate(25));
+
+ _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
+ EXPECT_EQ(true, (*enc)->SetFec(true));
+ });
+
+ OpenOutFile(_testCntr);
+ Run();
+
+ // Switch to L16 with RED.
+ RegisterSendCodec(_acmA, {"L16", 8000, 1}, absl::nullopt, true);
+ Run();
+
+ // Switch to Opus again.
+ RegisterSendCodec(_acmA, {"opus", 48000, 2}, absl::nullopt, false);
+ _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
+ EXPECT_EQ(true, (*enc)->SetFec(false));
+ });
+ Run();
+
+ _acmA->ModifyEncoder([&](std::unique_ptr<AudioEncoder>* enc) {
+ EXPECT_EQ(true, (*enc)->SetFec(true));
+ });
+ _outFileB.Close();
+}
+
+void TestRedFec::RegisterSendCodec(
+ const std::unique_ptr<AudioCodingModule>& acm,
+ const SdpAudioFormat& codec_format,
+ absl::optional<Vad::Aggressiveness> vad_mode,
+ bool use_red) {
+ constexpr int payload_type = 17, cn_payload_type = 27, red_payload_type = 37;
+ const auto& other_acm = &acm == &_acmA ? _acmB : _acmA;
+
+ auto encoder = encoder_factory_->MakeAudioEncoder(payload_type, codec_format,
+ absl::nullopt);
+ EXPECT_NE(encoder, nullptr);
+ std::map<int, SdpAudioFormat> receive_codecs = {{payload_type, codec_format}};
+ if (!absl::EqualsIgnoreCase(codec_format.name, "opus")) {
+ if (vad_mode.has_value()) {
+ AudioEncoderCngConfig config;
+ config.speech_encoder = std::move(encoder);
+ config.num_channels = 1;
+ config.payload_type = cn_payload_type;
+ config.vad_mode = vad_mode.value();
+ encoder = CreateComfortNoiseEncoder(std::move(config));
+ receive_codecs.emplace(std::make_pair(
+ cn_payload_type, SdpAudioFormat("CN", codec_format.clockrate_hz, 1)));
+ }
+ if (use_red) {
+ AudioEncoderCopyRed::Config config;
+ config.payload_type = red_payload_type;
+ config.speech_encoder = std::move(encoder);
+ encoder = std::make_unique<AudioEncoderCopyRed>(std::move(config),
+ field_trials_);
+ receive_codecs.emplace(
+ std::make_pair(red_payload_type,
+ SdpAudioFormat("red", codec_format.clockrate_hz, 1)));
+ }
+ }
+ acm->SetEncoder(std::move(encoder));
+ other_acm->SetReceiveCodecs(receive_codecs);
+}
+
+void TestRedFec::Run() {
+ AudioFrame audioFrame;
+ int32_t outFreqHzB = _outFileB.SamplingFrequency();
+ // Set test length to 500 ms (50 blocks of 10 ms each).
+ _inFileA.SetNum10MsBlocksToRead(50);
+ // Fast-forward 1 second (100 blocks) since the file starts with silence.
+ _inFileA.FastForward(100);
+
+ while (!_inFileA.EndOfFile()) {
+ EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
+ EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
+ bool muted;
+ EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame, &muted));
+ ASSERT_FALSE(muted);
+ _outFileB.Write10MsData(audioFrame.data(), audioFrame.samples_per_channel_);
+ }
+ _inFileA.Rewind();
+}
+
+void TestRedFec::OpenOutFile(int16_t test_number) {
+ std::string file_name;
+ rtc::StringBuilder file_stream;
+ file_stream << webrtc::test::OutputPath();
+ file_stream << "TestRedFec_outFile_";
+ file_stream << test_number << ".pcm";
+ file_name = file_stream.str();
+ _outFileB.Open(file_name, 16000, "wb");
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestRedFec.h b/third_party/libwebrtc/modules/audio_coding/test/TestRedFec.h
new file mode 100644
index 0000000000..dbadd88487
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestRedFec.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
+#define MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
+
+#include <memory>
+#include <string>
+
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
+#include "common_audio/vad/include/vad.h"
+#include "modules/audio_coding/test/Channel.h"
+#include "modules/audio_coding/test/PCMFile.h"
+#include "test/scoped_key_value_config.h"
+
+namespace webrtc {
+
+class TestRedFec {
+ public:
+ explicit TestRedFec();
+ ~TestRedFec();
+
+ void Perform();
+
+ private:
+ void RegisterSendCodec(const std::unique_ptr<AudioCodingModule>& acm,
+ const SdpAudioFormat& codec_format,
+ absl::optional<Vad::Aggressiveness> vad_mode,
+ bool use_red);
+ void Run();
+ void OpenOutFile(int16_t testNumber);
+
+ test::ScopedKeyValueConfig field_trials_;
+ const rtc::scoped_refptr<AudioEncoderFactory> encoder_factory_;
+ const rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
+ std::unique_ptr<AudioCodingModule> _acmA;
+ std::unique_ptr<AudioCodingModule> _acmB;
+
+ Channel* _channelA2B;
+
+ PCMFile _inFileA;
+ PCMFile _outFileB;
+ int16_t _testCntr;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_TESTREDFEC_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc b/third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc
new file mode 100644
index 0000000000..599fafb602
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestStereo.cc
@@ -0,0 +1,599 @@
+/*
+ * 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.
+ */
+
+#include "modules/audio_coding/test/TestStereo.h"
+
+#include <string>
+
+#include "absl/strings/match.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
+#include "modules/include/module_common_types.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+// Class for simulating packet handling
+TestPackStereo::TestPackStereo()
+ : receiver_acm_(NULL),
+ seq_no_(0),
+ timestamp_diff_(0),
+ last_in_timestamp_(0),
+ total_bytes_(0),
+ payload_size_(0),
+ lost_packet_(false) {}
+
+TestPackStereo::~TestPackStereo() {}
+
+void TestPackStereo::RegisterReceiverACM(AudioCodingModule* acm) {
+ receiver_acm_ = acm;
+ return;
+}
+
+int32_t TestPackStereo::SendData(const AudioFrameType frame_type,
+ const uint8_t payload_type,
+ const uint32_t timestamp,
+ const uint8_t* payload_data,
+ const size_t payload_size,
+ int64_t absolute_capture_timestamp_ms) {
+ RTPHeader rtp_header;
+ int32_t status = 0;
+
+ rtp_header.markerBit = false;
+ rtp_header.ssrc = 0;
+ rtp_header.sequenceNumber = seq_no_++;
+ rtp_header.payloadType = payload_type;
+ rtp_header.timestamp = timestamp;
+ if (frame_type == AudioFrameType::kEmptyFrame) {
+ // Skip this frame
+ return 0;
+ }
+
+ if (lost_packet_ == false) {
+ status =
+ receiver_acm_->IncomingPacket(payload_data, payload_size, rtp_header);
+
+ if (frame_type != AudioFrameType::kAudioFrameCN) {
+ payload_size_ = static_cast<int>(payload_size);
+ } else {
+ payload_size_ = -1;
+ }
+
+ timestamp_diff_ = timestamp - last_in_timestamp_;
+ last_in_timestamp_ = timestamp;
+ total_bytes_ += payload_size;
+ }
+ return status;
+}
+
+uint16_t TestPackStereo::payload_size() {
+ return static_cast<uint16_t>(payload_size_);
+}
+
+uint32_t TestPackStereo::timestamp_diff() {
+ return timestamp_diff_;
+}
+
+void TestPackStereo::reset_payload_size() {
+ payload_size_ = 0;
+}
+
+void TestPackStereo::set_codec_mode(enum StereoMonoMode mode) {
+ codec_mode_ = mode;
+}
+
+void TestPackStereo::set_lost_packet(bool lost) {
+ lost_packet_ = lost;
+}
+
+TestStereo::TestStereo()
+ : acm_a_(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
+ acm_b_(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
+ channel_a2b_(NULL),
+ test_cntr_(0),
+ pack_size_samp_(0),
+ pack_size_bytes_(0),
+ counter_(0) {}
+
+TestStereo::~TestStereo() {
+ if (channel_a2b_ != NULL) {
+ delete channel_a2b_;
+ channel_a2b_ = NULL;
+ }
+}
+
+void TestStereo::Perform() {
+ uint16_t frequency_hz;
+ int audio_channels;
+ int codec_channels;
+
+ // Open both mono and stereo test files in 32 kHz.
+ const std::string file_name_stereo =
+ webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm");
+ const std::string file_name_mono =
+ webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+ frequency_hz = 32000;
+ in_file_stereo_ = new PCMFile();
+ in_file_mono_ = new PCMFile();
+ in_file_stereo_->Open(file_name_stereo, frequency_hz, "rb");
+ in_file_stereo_->ReadStereo(true);
+ in_file_mono_->Open(file_name_mono, frequency_hz, "rb");
+ in_file_mono_->ReadStereo(false);
+
+ // Create and initialize two ACMs, one for each side of a one-to-one call.
+ ASSERT_TRUE((acm_a_.get() != NULL) && (acm_b_.get() != NULL));
+ EXPECT_EQ(0, acm_a_->InitializeReceiver());
+ EXPECT_EQ(0, acm_b_->InitializeReceiver());
+
+ acm_b_->SetReceiveCodecs({{103, {"ISAC", 16000, 1}},
+ {104, {"ISAC", 32000, 1}},
+ {107, {"L16", 8000, 1}},
+ {108, {"L16", 16000, 1}},
+ {109, {"L16", 32000, 1}},
+ {111, {"L16", 8000, 2}},
+ {112, {"L16", 16000, 2}},
+ {113, {"L16", 32000, 2}},
+ {0, {"PCMU", 8000, 1}},
+ {110, {"PCMU", 8000, 2}},
+ {8, {"PCMA", 8000, 1}},
+ {118, {"PCMA", 8000, 2}},
+ {102, {"ILBC", 8000, 1}},
+ {9, {"G722", 8000, 1}},
+ {119, {"G722", 8000, 2}},
+ {120, {"OPUS", 48000, 2, {{"stereo", "1"}}}},
+ {13, {"CN", 8000, 1}},
+ {98, {"CN", 16000, 1}},
+ {99, {"CN", 32000, 1}}});
+
+ // Create and connect the channel.
+ channel_a2b_ = new TestPackStereo;
+ EXPECT_EQ(0, acm_a_->RegisterTransportCallback(channel_a2b_));
+ channel_a2b_->RegisterReceiverACM(acm_b_.get());
+
+ char codec_pcma_temp[] = "PCMA";
+ RegisterSendCodec('A', codec_pcma_temp, 8000, 64000, 80, 2);
+
+ //
+ // Test Stereo-To-Stereo for all codecs.
+ //
+ audio_channels = 2;
+ codec_channels = 2;
+
+ // All codecs are tested for all allowed sampling frequencies, rates and
+ // packet sizes.
+ channel_a2b_->set_codec_mode(kStereo);
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ char codec_g722[] = "G722";
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 480, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 640, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 800, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 960, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ channel_a2b_->set_codec_mode(kStereo);
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ char codec_l16[] = "L16";
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 240, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 480, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 640, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_l16, 32000, 512000, 640, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#ifdef PCMA_AND_PCMU
+ channel_a2b_->set_codec_mode(kStereo);
+ audio_channels = 2;
+ codec_channels = 2;
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ char codec_pcma[] = "PCMA";
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 240, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 400, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 480, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ char codec_pcmu[] = "PCMU";
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 240, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 400, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 480, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#endif
+#ifdef WEBRTC_CODEC_OPUS
+ channel_a2b_->set_codec_mode(kStereo);
+ audio_channels = 2;
+ codec_channels = 2;
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+
+ char codec_opus[] = "opus";
+ // Run Opus with 10 ms frame size.
+ RegisterSendCodec('A', codec_opus, 48000, 64000, 480, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ // Run Opus with 20 ms frame size.
+ RegisterSendCodec('A', codec_opus, 48000, 64000, 480 * 2, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ // Run Opus with 40 ms frame size.
+ RegisterSendCodec('A', codec_opus, 48000, 64000, 480 * 4, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ // Run Opus with 60 ms frame size.
+ RegisterSendCodec('A', codec_opus, 48000, 64000, 480 * 6, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ // Run Opus with 20 ms frame size and different bitrates.
+ RegisterSendCodec('A', codec_opus, 48000, 40000, 960, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_opus, 48000, 510000, 960, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#endif
+ //
+ // Test Mono-To-Stereo for all codecs.
+ //
+ audio_channels = 1;
+ codec_channels = 2;
+
+ test_cntr_++;
+ channel_a2b_->set_codec_mode(kStereo);
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ channel_a2b_->set_codec_mode(kStereo);
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#ifdef PCMA_AND_PCMU
+ test_cntr_++;
+ channel_a2b_->set_codec_mode(kStereo);
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#endif
+#ifdef WEBRTC_CODEC_OPUS
+ // Keep encode and decode in stereo.
+ test_cntr_++;
+ channel_a2b_->set_codec_mode(kStereo);
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_opus, 48000, 64000, 960, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+
+ // Encode in mono, decode in stereo mode.
+ RegisterSendCodec('A', codec_opus, 48000, 64000, 960, 1);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#endif
+
+ //
+ // Test Stereo-To-Mono for all codecs.
+ //
+ audio_channels = 2;
+ codec_channels = 1;
+ channel_a2b_->set_codec_mode(kMono);
+
+ // Run stereo audio and mono codec.
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_g722, 16000, 64000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 8000, 128000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 16000, 256000, 160, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_l16, 32000, 512000, 320, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#ifdef PCMA_AND_PCMU
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ RegisterSendCodec('A', codec_pcmu, 8000, 64000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ RegisterSendCodec('A', codec_pcma, 8000, 64000, 80, codec_channels);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#endif
+#ifdef WEBRTC_CODEC_OPUS
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ // Encode and decode in mono.
+ RegisterSendCodec('A', codec_opus, 48000, 32000, 960, codec_channels);
+ acm_b_->SetReceiveCodecs({{120, {"OPUS", 48000, 2}}});
+ Run(channel_a2b_, audio_channels, codec_channels);
+
+ // Encode in stereo, decode in mono.
+ RegisterSendCodec('A', codec_opus, 48000, 32000, 960, 2);
+ Run(channel_a2b_, audio_channels, codec_channels);
+
+ out_file_.Close();
+
+ // Test switching between decoding mono and stereo for Opus.
+
+ // Decode in mono.
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+ // Decode in stereo.
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ acm_b_->SetReceiveCodecs({{120, {"OPUS", 48000, 2, {{"stereo", "1"}}}}});
+ Run(channel_a2b_, audio_channels, 2);
+ out_file_.Close();
+ // Decode in mono.
+ test_cntr_++;
+ OpenOutFile(test_cntr_);
+ acm_b_->SetReceiveCodecs({{120, {"OPUS", 48000, 2}}});
+ Run(channel_a2b_, audio_channels, codec_channels);
+ out_file_.Close();
+#endif
+
+ // Delete the file pointers.
+ delete in_file_stereo_;
+ delete in_file_mono_;
+}
+
+// Register Codec to use in the test
+//
+// Input: side - which ACM to use, 'A' or 'B'
+// codec_name - name to use when register the codec
+// sampling_freq_hz - sampling frequency in Herz
+// rate - bitrate in bytes
+// pack_size - packet size in samples
+// channels - number of channels; 1 for mono, 2 for stereo
+void TestStereo::RegisterSendCodec(char side,
+ char* codec_name,
+ int32_t sampling_freq_hz,
+ int rate,
+ int pack_size,
+ int channels) {
+ // Store packet size in samples, used to validate the received packet
+ pack_size_samp_ = pack_size;
+
+ // Store the expected packet size in bytes, used to validate the received
+ // packet. Add 0.875 to always round up to a whole byte.
+ pack_size_bytes_ = (uint16_t)(static_cast<float>(pack_size * rate) /
+ static_cast<float>(sampling_freq_hz * 8) +
+ 0.875);
+
+ // Set pointer to the ACM where to register the codec
+ AudioCodingModule* my_acm = NULL;
+ switch (side) {
+ case 'A': {
+ my_acm = acm_a_.get();
+ break;
+ }
+ case 'B': {
+ my_acm = acm_b_.get();
+ break;
+ }
+ default:
+ break;
+ }
+ ASSERT_TRUE(my_acm != NULL);
+
+ auto encoder_factory = CreateBuiltinAudioEncoderFactory();
+ const int clockrate_hz = absl::EqualsIgnoreCase(codec_name, "g722")
+ ? sampling_freq_hz / 2
+ : sampling_freq_hz;
+ const std::string ptime = rtc::ToString(rtc::CheckedDivExact(
+ pack_size, rtc::CheckedDivExact(sampling_freq_hz, 1000)));
+ SdpAudioFormat::Parameters params = {{"ptime", ptime}};
+ RTC_CHECK(channels == 1 || channels == 2);
+ if (absl::EqualsIgnoreCase(codec_name, "opus")) {
+ if (channels == 2) {
+ params["stereo"] = "1";
+ }
+ channels = 2;
+ params["maxaveragebitrate"] = rtc::ToString(rate);
+ }
+ constexpr int payload_type = 17;
+ auto encoder = encoder_factory->MakeAudioEncoder(
+ payload_type, SdpAudioFormat(codec_name, clockrate_hz, channels, params),
+ absl::nullopt);
+ EXPECT_NE(nullptr, encoder);
+ my_acm->SetEncoder(std::move(encoder));
+
+ send_codec_name_ = codec_name;
+}
+
+void TestStereo::Run(TestPackStereo* channel,
+ int in_channels,
+ int out_channels,
+ int percent_loss) {
+ AudioFrame audio_frame;
+
+ int32_t out_freq_hz_b = out_file_.SamplingFrequency();
+ uint16_t rec_size;
+ uint32_t time_stamp_diff;
+ channel->reset_payload_size();
+ int error_count = 0;
+ int variable_bytes = 0;
+ int variable_packets = 0;
+ // Set test length to 500 ms (50 blocks of 10 ms each).
+ in_file_mono_->SetNum10MsBlocksToRead(50);
+ in_file_stereo_->SetNum10MsBlocksToRead(50);
+ // Fast-forward 1 second (100 blocks) since the files start with silence.
+ in_file_stereo_->FastForward(100);
+ in_file_mono_->FastForward(100);
+
+ while (true) {
+ // Simulate packet loss by setting `packet_loss_` to "true" in
+ // `percent_loss` percent of the loops.
+ if (percent_loss > 0) {
+ if (counter_ == floor((100 / percent_loss) + 0.5)) {
+ counter_ = 0;
+ channel->set_lost_packet(true);
+ } else {
+ channel->set_lost_packet(false);
+ }
+ counter_++;
+ }
+
+ // Add 10 msec to ACM
+ if (in_channels == 1) {
+ if (in_file_mono_->EndOfFile()) {
+ break;
+ }
+ in_file_mono_->Read10MsData(audio_frame);
+ } else {
+ if (in_file_stereo_->EndOfFile()) {
+ break;
+ }
+ in_file_stereo_->Read10MsData(audio_frame);
+ }
+ EXPECT_GE(acm_a_->Add10MsData(audio_frame), 0);
+
+ // Verify that the received packet size matches the settings.
+ rec_size = channel->payload_size();
+ if ((0 < rec_size) & (rec_size < 65535)) {
+ if (strcmp(send_codec_name_, "opus") == 0) {
+ // Opus is a variable rate codec, hence calculate the average packet
+ // size, and later make sure the average is in the right range.
+ variable_bytes += rec_size;
+ variable_packets++;
+ } else {
+ // For fixed rate codecs, check that packet size is correct.
+ if ((rec_size != pack_size_bytes_ * out_channels) &&
+ (pack_size_bytes_ < 65535)) {
+ error_count++;
+ }
+ }
+ // Verify that the timestamp is updated with expected length
+ time_stamp_diff = channel->timestamp_diff();
+ if ((counter_ > 10) && (time_stamp_diff != pack_size_samp_)) {
+ error_count++;
+ }
+ }
+
+ // Run receive side of ACM
+ bool muted;
+ EXPECT_EQ(0, acm_b_->PlayoutData10Ms(out_freq_hz_b, &audio_frame, &muted));
+ ASSERT_FALSE(muted);
+
+ // Write output speech to file
+ out_file_.Write10MsData(
+ audio_frame.data(),
+ audio_frame.samples_per_channel_ * audio_frame.num_channels_);
+ }
+
+ EXPECT_EQ(0, error_count);
+
+ // Check that packet size is in the right range for variable rate codecs,
+ // such as Opus.
+ if (variable_packets > 0) {
+ variable_bytes /= variable_packets;
+ EXPECT_NEAR(variable_bytes, pack_size_bytes_, 18);
+ }
+
+ if (in_file_mono_->EndOfFile()) {
+ in_file_mono_->Rewind();
+ }
+ if (in_file_stereo_->EndOfFile()) {
+ in_file_stereo_->Rewind();
+ }
+ // Reset in case we ended with a lost packet
+ channel->set_lost_packet(false);
+}
+
+void TestStereo::OpenOutFile(int16_t test_number) {
+ std::string file_name;
+ rtc::StringBuilder file_stream;
+ file_stream << webrtc::test::OutputPath() << "teststereo_out_" << test_number
+ << ".pcm";
+ file_name = file_stream.str();
+ out_file_.Open(file_name, 32000, "wb");
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestStereo.h b/third_party/libwebrtc/modules/audio_coding/test/TestStereo.h
new file mode 100644
index 0000000000..4c50a4b555
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestStereo.h
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
+#define MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
+
+#include <math.h>
+
+#include <memory>
+
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "modules/audio_coding/test/PCMFile.h"
+
+#define PCMA_AND_PCMU
+
+namespace webrtc {
+
+enum StereoMonoMode { kNotSet, kMono, kStereo };
+
+class TestPackStereo : public AudioPacketizationCallback {
+ public:
+ TestPackStereo();
+ ~TestPackStereo();
+
+ void RegisterReceiverACM(AudioCodingModule* acm);
+
+ int32_t SendData(AudioFrameType frame_type,
+ uint8_t payload_type,
+ uint32_t timestamp,
+ const uint8_t* payload_data,
+ size_t payload_size,
+ int64_t absolute_capture_timestamp_ms) override;
+
+ uint16_t payload_size();
+ uint32_t timestamp_diff();
+ void reset_payload_size();
+ void set_codec_mode(StereoMonoMode mode);
+ void set_lost_packet(bool lost);
+
+ private:
+ AudioCodingModule* receiver_acm_;
+ int16_t seq_no_;
+ uint32_t timestamp_diff_;
+ uint32_t last_in_timestamp_;
+ uint64_t total_bytes_;
+ int payload_size_;
+ StereoMonoMode codec_mode_;
+ // Simulate packet losses
+ bool lost_packet_;
+};
+
+class TestStereo {
+ public:
+ TestStereo();
+ ~TestStereo();
+
+ void Perform();
+
+ private:
+ // The default value of '-1' indicates that the registration is based only on
+ // codec name and a sampling frequncy matching is not required. This is useful
+ // for codecs which support several sampling frequency.
+ void RegisterSendCodec(char side,
+ char* codec_name,
+ int32_t samp_freq_hz,
+ int rate,
+ int pack_size,
+ int channels);
+
+ void Run(TestPackStereo* channel,
+ int in_channels,
+ int out_channels,
+ int percent_loss = 0);
+ void OpenOutFile(int16_t test_number);
+
+ std::unique_ptr<AudioCodingModule> acm_a_;
+ std::unique_ptr<AudioCodingModule> acm_b_;
+
+ TestPackStereo* channel_a2b_;
+
+ PCMFile* in_file_stereo_;
+ PCMFile* in_file_mono_;
+ PCMFile out_file_;
+ int16_t test_cntr_;
+ uint16_t pack_size_samp_;
+ uint16_t pack_size_bytes_;
+ int counter_;
+ char* send_codec_name_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_TESTSTEREO_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.cc b/third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.cc
new file mode 100644
index 0000000000..de26cafb68
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.cc
@@ -0,0 +1,240 @@
+/*
+ * 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.
+ */
+
+#include "modules/audio_coding/test/TestVADDTX.h"
+
+#include <string>
+
+#include "absl/strings/match.h"
+#include "absl/strings/string_view.h"
+#include "api/audio_codecs/audio_decoder_factory_template.h"
+#include "api/audio_codecs/audio_encoder_factory_template.h"
+#include "api/audio_codecs/ilbc/audio_decoder_ilbc.h"
+#include "api/audio_codecs/ilbc/audio_encoder_ilbc.h"
+#include "api/audio_codecs/opus/audio_decoder_opus.h"
+#include "api/audio_codecs/opus/audio_encoder_opus.h"
+#include "modules/audio_coding/codecs/cng/audio_encoder_cng.h"
+#include "modules/audio_coding/test/PCMFile.h"
+#include "rtc_base/strings/string_builder.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+MonitoringAudioPacketizationCallback::MonitoringAudioPacketizationCallback(
+ AudioPacketizationCallback* next)
+ : next_(next) {
+ ResetStatistics();
+}
+
+int32_t MonitoringAudioPacketizationCallback::SendData(
+ AudioFrameType frame_type,
+ uint8_t payload_type,
+ uint32_t timestamp,
+ const uint8_t* payload_data,
+ size_t payload_len_bytes,
+ int64_t absolute_capture_timestamp_ms) {
+ counter_[static_cast<int>(frame_type)]++;
+ return next_->SendData(frame_type, payload_type, timestamp, payload_data,
+ payload_len_bytes, absolute_capture_timestamp_ms);
+}
+
+void MonitoringAudioPacketizationCallback::PrintStatistics() {
+ printf("\n");
+ printf("kEmptyFrame %u\n",
+ counter_[static_cast<int>(AudioFrameType::kEmptyFrame)]);
+ printf("kAudioFrameSpeech %u\n",
+ counter_[static_cast<int>(AudioFrameType::kAudioFrameSpeech)]);
+ printf("kAudioFrameCN %u\n",
+ counter_[static_cast<int>(AudioFrameType::kAudioFrameCN)]);
+ printf("\n\n");
+}
+
+void MonitoringAudioPacketizationCallback::ResetStatistics() {
+ memset(counter_, 0, sizeof(counter_));
+}
+
+void MonitoringAudioPacketizationCallback::GetStatistics(uint32_t* counter) {
+ memcpy(counter, counter_, sizeof(counter_));
+}
+
+TestVadDtx::TestVadDtx()
+ : encoder_factory_(
+ CreateAudioEncoderFactory<AudioEncoderIlbc, AudioEncoderOpus>()),
+ decoder_factory_(
+ CreateAudioDecoderFactory<AudioDecoderIlbc, AudioDecoderOpus>()),
+ acm_send_(AudioCodingModule::Create(
+ AudioCodingModule::Config(decoder_factory_))),
+ acm_receive_(AudioCodingModule::Create(
+ AudioCodingModule::Config(decoder_factory_))),
+ channel_(std::make_unique<Channel>()),
+ packetization_callback_(
+ std::make_unique<MonitoringAudioPacketizationCallback>(
+ channel_.get())) {
+ EXPECT_EQ(
+ 0, acm_send_->RegisterTransportCallback(packetization_callback_.get()));
+ channel_->RegisterReceiverACM(acm_receive_.get());
+}
+
+bool TestVadDtx::RegisterCodec(const SdpAudioFormat& codec_format,
+ absl::optional<Vad::Aggressiveness> vad_mode) {
+ constexpr int payload_type = 17, cn_payload_type = 117;
+ bool added_comfort_noise = false;
+
+ auto encoder = encoder_factory_->MakeAudioEncoder(payload_type, codec_format,
+ absl::nullopt);
+ if (vad_mode.has_value() &&
+ !absl::EqualsIgnoreCase(codec_format.name, "opus")) {
+ AudioEncoderCngConfig config;
+ config.speech_encoder = std::move(encoder);
+ config.num_channels = 1;
+ config.payload_type = cn_payload_type;
+ config.vad_mode = vad_mode.value();
+ encoder = CreateComfortNoiseEncoder(std::move(config));
+ added_comfort_noise = true;
+ }
+ channel_->SetIsStereo(encoder->NumChannels() > 1);
+ acm_send_->SetEncoder(std::move(encoder));
+
+ std::map<int, SdpAudioFormat> receive_codecs = {{payload_type, codec_format}};
+ acm_receive_->SetReceiveCodecs(receive_codecs);
+
+ return added_comfort_noise;
+}
+
+// Encoding a file and see if the numbers that various packets occur follow
+// the expectation.
+void TestVadDtx::Run(absl::string_view in_filename,
+ int frequency,
+ int channels,
+ absl::string_view out_filename,
+ bool append,
+ const int* expects) {
+ packetization_callback_->ResetStatistics();
+
+ PCMFile in_file;
+ in_file.Open(in_filename, frequency, "rb");
+ in_file.ReadStereo(channels > 1);
+ // Set test length to 1000 ms (100 blocks of 10 ms each).
+ in_file.SetNum10MsBlocksToRead(100);
+ // Fast-forward both files 500 ms (50 blocks). The first second of the file is
+ // silence, but we want to keep half of that to test silence periods.
+ in_file.FastForward(50);
+
+ PCMFile out_file;
+ if (append) {
+ out_file.Open(out_filename, kOutputFreqHz, "ab");
+ } else {
+ out_file.Open(out_filename, kOutputFreqHz, "wb");
+ }
+
+ uint16_t frame_size_samples = in_file.PayloadLength10Ms();
+ AudioFrame audio_frame;
+ while (!in_file.EndOfFile()) {
+ in_file.Read10MsData(audio_frame);
+ audio_frame.timestamp_ = time_stamp_;
+ time_stamp_ += frame_size_samples;
+ EXPECT_GE(acm_send_->Add10MsData(audio_frame), 0);
+ bool muted;
+ acm_receive_->PlayoutData10Ms(kOutputFreqHz, &audio_frame, &muted);
+ ASSERT_FALSE(muted);
+ out_file.Write10MsData(audio_frame);
+ }
+
+ in_file.Close();
+ out_file.Close();
+
+#ifdef PRINT_STAT
+ packetization_callback_->PrintStatistics();
+#endif
+
+ uint32_t stats[3];
+ packetization_callback_->GetStatistics(stats);
+ packetization_callback_->ResetStatistics();
+
+ for (const auto& st : stats) {
+ int i = &st - stats; // Calculate the current position in stats.
+ switch (expects[i]) {
+ case 0: {
+ EXPECT_EQ(0u, st) << "stats[" << i << "] error.";
+ break;
+ }
+ case 1: {
+ EXPECT_GT(st, 0u) << "stats[" << i << "] error.";
+ break;
+ }
+ }
+ }
+}
+
+// Following is the implementation of TestWebRtcVadDtx.
+TestWebRtcVadDtx::TestWebRtcVadDtx() : output_file_num_(0) {}
+
+void TestWebRtcVadDtx::Perform() {
+ RunTestCases({"ILBC", 8000, 1});
+ RunTestCases({"opus", 48000, 2});
+}
+
+// Test various configurations on VAD/DTX.
+void TestWebRtcVadDtx::RunTestCases(const SdpAudioFormat& codec_format) {
+ Test(/*new_outfile=*/true,
+ /*expect_dtx_enabled=*/RegisterCodec(codec_format, absl::nullopt));
+
+ Test(/*new_outfile=*/false,
+ /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadAggressive));
+
+ Test(/*new_outfile=*/false,
+ /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadLowBitrate));
+
+ Test(/*new_outfile=*/false, /*expect_dtx_enabled=*/RegisterCodec(
+ codec_format, Vad::kVadVeryAggressive));
+
+ Test(/*new_outfile=*/false,
+ /*expect_dtx_enabled=*/RegisterCodec(codec_format, Vad::kVadNormal));
+}
+
+// Set the expectation and run the test.
+void TestWebRtcVadDtx::Test(bool new_outfile, bool expect_dtx_enabled) {
+ int expects[] = {-1, 1, expect_dtx_enabled, 0, 0};
+ if (new_outfile) {
+ output_file_num_++;
+ }
+ rtc::StringBuilder out_filename;
+ out_filename << webrtc::test::OutputPath() << "testWebRtcVadDtx_outFile_"
+ << output_file_num_ << ".pcm";
+ Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
+ out_filename.str(), !new_outfile, expects);
+}
+
+// Following is the implementation of TestOpusDtx.
+void TestOpusDtx::Perform() {
+ int expects[] = {0, 1, 0, 0, 0};
+
+ // Register Opus as send codec
+ std::string out_filename =
+ webrtc::test::OutputPath() + "testOpusDtx_outFile_mono.pcm";
+ RegisterCodec({"opus", 48000, 2}, absl::nullopt);
+ acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
+ (*encoder_ptr)->SetDtx(false);
+ });
+
+ Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
+ out_filename, false, expects);
+
+ acm_send_->ModifyEncoder([](std::unique_ptr<AudioEncoder>* encoder_ptr) {
+ (*encoder_ptr)->SetDtx(true);
+ });
+ expects[static_cast<int>(AudioFrameType::kEmptyFrame)] = 1;
+ expects[static_cast<int>(AudioFrameType::kAudioFrameCN)] = 1;
+ Run(webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm"), 32000, 1,
+ out_filename, true, expects);
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.h b/third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.h
new file mode 100644
index 0000000000..d81ae28beb
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TestVADDTX.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2011 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
+#define MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
+
+#include <memory>
+
+#include "absl/strings/string_view.h"
+#include "api/audio_codecs/audio_decoder_factory.h"
+#include "api/audio_codecs/audio_encoder_factory.h"
+#include "common_audio/vad/include/vad.h"
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
+#include "modules/audio_coding/test/Channel.h"
+
+namespace webrtc {
+
+// This class records the frame type, and delegates actual sending to the
+// `next_` AudioPacketizationCallback.
+class MonitoringAudioPacketizationCallback : public AudioPacketizationCallback {
+ public:
+ explicit MonitoringAudioPacketizationCallback(
+ AudioPacketizationCallback* next);
+
+ int32_t SendData(AudioFrameType frame_type,
+ uint8_t payload_type,
+ uint32_t timestamp,
+ const uint8_t* payload_data,
+ size_t payload_len_bytes,
+ int64_t absolute_capture_timestamp_ms) override;
+
+ void PrintStatistics();
+ void ResetStatistics();
+ void GetStatistics(uint32_t* stats);
+
+ private:
+ // 0 - kEmptyFrame
+ // 1 - kAudioFrameSpeech
+ // 2 - kAudioFrameCN
+ uint32_t counter_[3];
+ AudioPacketizationCallback* const next_;
+};
+
+// TestVadDtx is to verify that VAD/DTX perform as they should. It runs through
+// an audio file and check if the occurrence of various packet types follows
+// expectation. TestVadDtx needs its derived class to implement the Perform()
+// to put the test together.
+class TestVadDtx {
+ public:
+ static const int kOutputFreqHz = 16000;
+
+ TestVadDtx();
+
+ protected:
+ // Returns true iff CN was added.
+ bool RegisterCodec(const SdpAudioFormat& codec_format,
+ absl::optional<Vad::Aggressiveness> vad_mode);
+
+ // Encoding a file and see if the numbers that various packets occur follow
+ // the expectation. Saves result to a file.
+ // expects[x] means
+ // -1 : do not care,
+ // 0 : there have been no packets of type `x`,
+ // 1 : there have been packets of type `x`,
+ // with `x` indicates the following packet types
+ // 0 - kEmptyFrame
+ // 1 - kAudioFrameSpeech
+ // 2 - kAudioFrameCN
+ void Run(absl::string_view in_filename,
+ int frequency,
+ int channels,
+ absl::string_view out_filename,
+ bool append,
+ const int* expects);
+
+ const rtc::scoped_refptr<AudioEncoderFactory> encoder_factory_;
+ const rtc::scoped_refptr<AudioDecoderFactory> decoder_factory_;
+ std::unique_ptr<AudioCodingModule> acm_send_;
+ std::unique_ptr<AudioCodingModule> acm_receive_;
+ std::unique_ptr<Channel> channel_;
+ std::unique_ptr<MonitoringAudioPacketizationCallback> packetization_callback_;
+ uint32_t time_stamp_ = 0x12345678;
+};
+
+// TestWebRtcVadDtx is to verify that the WebRTC VAD/DTX perform as they should.
+class TestWebRtcVadDtx final : public TestVadDtx {
+ public:
+ TestWebRtcVadDtx();
+
+ void Perform();
+
+ private:
+ void RunTestCases(const SdpAudioFormat& codec_format);
+ void Test(bool new_outfile, bool expect_dtx_enabled);
+
+ int output_file_num_;
+};
+
+// TestOpusDtx is to verify that the Opus DTX performs as it should.
+class TestOpusDtx final : public TestVadDtx {
+ public:
+ void Perform();
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_TESTVADDTX_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/Tester.cc b/third_party/libwebrtc/modules/audio_coding/test/Tester.cc
new file mode 100644
index 0000000000..7612aa43a3
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/Tester.cc
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+#include <stdio.h>
+
+#include <string>
+#include <vector>
+
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "modules/audio_coding/test/EncodeDecodeTest.h"
+#include "modules/audio_coding/test/PacketLossTest.h"
+#include "modules/audio_coding/test/TestAllCodecs.h"
+#include "modules/audio_coding/test/TestRedFec.h"
+#include "modules/audio_coding/test/TestStereo.h"
+#include "modules/audio_coding/test/TestVADDTX.h"
+#include "modules/audio_coding/test/TwoWayCommunication.h"
+#include "modules/audio_coding/test/opus_test.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+TEST(AudioCodingModuleTest, TestAllCodecs) {
+ webrtc::TestAllCodecs().Perform();
+}
+
+#if defined(WEBRTC_ANDROID)
+TEST(AudioCodingModuleTest, DISABLED_TestEncodeDecode) {
+#else
+TEST(AudioCodingModuleTest, TestEncodeDecode) {
+#endif
+ webrtc::EncodeDecodeTest().Perform();
+}
+
+TEST(AudioCodingModuleTest, TestRedFec) {
+ webrtc::TestRedFec().Perform();
+}
+
+// Disabled on ios as flaky, see https://crbug.com/webrtc/7057
+#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
+TEST(AudioCodingModuleTest, DISABLED_TestStereo) {
+#else
+TEST(AudioCodingModuleTest, TestStereo) {
+#endif
+ webrtc::TestStereo().Perform();
+}
+
+TEST(AudioCodingModuleTest, TestWebRtcVadDtx) {
+ webrtc::TestWebRtcVadDtx().Perform();
+}
+
+TEST(AudioCodingModuleTest, TestOpusDtx) {
+ webrtc::TestOpusDtx().Perform();
+}
+
+// Disabled on ios as flaky, see https://crbug.com/webrtc/7057
+#if defined(WEBRTC_IOS)
+TEST(AudioCodingModuleTest, DISABLED_TestOpus) {
+#else
+TEST(AudioCodingModuleTest, TestOpus) {
+#endif
+ webrtc::OpusTest().Perform();
+}
+
+TEST(AudioCodingModuleTest, TestPacketLoss) {
+ webrtc::PacketLossTest(1, 10, 10, 1).Perform();
+}
+
+TEST(AudioCodingModuleTest, TestPacketLossBurst) {
+ webrtc::PacketLossTest(1, 10, 10, 2).Perform();
+}
+
+// Disabled on ios as flake, see https://crbug.com/webrtc/7057
+#if defined(WEBRTC_IOS)
+TEST(AudioCodingModuleTest, DISABLED_TestPacketLossStereo) {
+#else
+TEST(AudioCodingModuleTest, TestPacketLossStereo) {
+#endif
+ webrtc::PacketLossTest(2, 10, 10, 1).Perform();
+}
+
+// Disabled on ios as flake, see https://crbug.com/webrtc/7057
+#if defined(WEBRTC_IOS)
+TEST(AudioCodingModuleTest, DISABLED_TestPacketLossStereoBurst) {
+#else
+TEST(AudioCodingModuleTest, TestPacketLossStereoBurst) {
+#endif
+ webrtc::PacketLossTest(2, 10, 10, 2).Perform();
+}
+
+// The full API test is too long to run automatically on bots, but can be used
+// for offline testing. User interaction is needed.
+#ifdef ACM_TEST_FULL_API
+TEST(AudioCodingModuleTest, TestAPI) {
+ webrtc::APITest().Perform();
+}
+#endif
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.cc b/third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.cc
new file mode 100644
index 0000000000..b42415a21a
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.cc
@@ -0,0 +1,191 @@
+/*
+ * 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.
+ */
+
+#include "TwoWayCommunication.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <memory>
+
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/audio_codecs/builtin_audio_encoder_factory.h"
+#include "modules/audio_coding/test/PCMFile.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+#define MAX_FILE_NAME_LENGTH_BYTE 500
+
+TwoWayCommunication::TwoWayCommunication()
+ : _acmA(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
+ _acmRefA(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))) {
+ AudioCodingModule::Config config;
+ // The clicks will be more obvious if time-stretching is not allowed.
+ // TODO(henrik.lundin) Really?
+ config.neteq_config.for_test_no_time_stretching = true;
+ config.decoder_factory = CreateBuiltinAudioDecoderFactory();
+ _acmB.reset(AudioCodingModule::Create(config));
+ _acmRefB.reset(AudioCodingModule::Create(config));
+}
+
+TwoWayCommunication::~TwoWayCommunication() {
+ delete _channel_A2B;
+ delete _channel_B2A;
+ delete _channelRef_A2B;
+ delete _channelRef_B2A;
+ _inFileA.Close();
+ _inFileB.Close();
+ _outFileA.Close();
+ _outFileB.Close();
+ _outFileRefA.Close();
+ _outFileRefB.Close();
+}
+
+void TwoWayCommunication::SetUpAutotest(
+ AudioEncoderFactory* const encoder_factory,
+ const SdpAudioFormat& format1,
+ const int payload_type1,
+ const SdpAudioFormat& format2,
+ const int payload_type2) {
+ //--- Set A codecs
+ _acmA->SetEncoder(
+ encoder_factory->MakeAudioEncoder(payload_type1, format1, absl::nullopt));
+ _acmA->SetReceiveCodecs({{payload_type2, format2}});
+
+ //--- Set ref-A codecs
+ _acmRefA->SetEncoder(
+ encoder_factory->MakeAudioEncoder(payload_type1, format1, absl::nullopt));
+ _acmRefA->SetReceiveCodecs({{payload_type2, format2}});
+
+ //--- Set B codecs
+ _acmB->SetEncoder(
+ encoder_factory->MakeAudioEncoder(payload_type2, format2, absl::nullopt));
+ _acmB->SetReceiveCodecs({{payload_type1, format1}});
+
+ //--- Set ref-B codecs
+ _acmRefB->SetEncoder(
+ encoder_factory->MakeAudioEncoder(payload_type2, format2, absl::nullopt));
+ _acmRefB->SetReceiveCodecs({{payload_type1, format1}});
+
+ uint16_t frequencyHz;
+
+ //--- Input A and B
+ std::string in_file_name =
+ webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+ frequencyHz = 16000;
+ _inFileA.Open(in_file_name, frequencyHz, "rb");
+ _inFileB.Open(in_file_name, frequencyHz, "rb");
+
+ //--- Output A
+ std::string output_file_a = webrtc::test::OutputPath() + "outAutotestA.pcm";
+ frequencyHz = 16000;
+ _outFileA.Open(output_file_a, frequencyHz, "wb");
+ std::string output_ref_file_a =
+ webrtc::test::OutputPath() + "ref_outAutotestA.pcm";
+ _outFileRefA.Open(output_ref_file_a, frequencyHz, "wb");
+
+ //--- Output B
+ std::string output_file_b = webrtc::test::OutputPath() + "outAutotestB.pcm";
+ frequencyHz = 16000;
+ _outFileB.Open(output_file_b, frequencyHz, "wb");
+ std::string output_ref_file_b =
+ webrtc::test::OutputPath() + "ref_outAutotestB.pcm";
+ _outFileRefB.Open(output_ref_file_b, frequencyHz, "wb");
+
+ //--- Set A-to-B channel
+ _channel_A2B = new Channel;
+ _acmA->RegisterTransportCallback(_channel_A2B);
+ _channel_A2B->RegisterReceiverACM(_acmB.get());
+ //--- Do the same for the reference
+ _channelRef_A2B = new Channel;
+ _acmRefA->RegisterTransportCallback(_channelRef_A2B);
+ _channelRef_A2B->RegisterReceiverACM(_acmRefB.get());
+
+ //--- Set B-to-A channel
+ _channel_B2A = new Channel;
+ _acmB->RegisterTransportCallback(_channel_B2A);
+ _channel_B2A->RegisterReceiverACM(_acmA.get());
+ //--- Do the same for reference
+ _channelRef_B2A = new Channel;
+ _acmRefB->RegisterTransportCallback(_channelRef_B2A);
+ _channelRef_B2A->RegisterReceiverACM(_acmRefA.get());
+}
+
+void TwoWayCommunication::Perform() {
+ const SdpAudioFormat format1("ISAC", 16000, 1);
+ const SdpAudioFormat format2("L16", 8000, 1);
+ constexpr int payload_type1 = 17, payload_type2 = 18;
+
+ auto encoder_factory = CreateBuiltinAudioEncoderFactory();
+
+ SetUpAutotest(encoder_factory.get(), format1, payload_type1, format2,
+ payload_type2);
+
+ unsigned int msecPassed = 0;
+ unsigned int secPassed = 0;
+
+ int32_t outFreqHzA = _outFileA.SamplingFrequency();
+ int32_t outFreqHzB = _outFileB.SamplingFrequency();
+
+ AudioFrame audioFrame;
+
+ // In the following loop we tests that the code can handle misuse of the APIs.
+ // In the middle of a session with data flowing between two sides, called A
+ // and B, APIs will be called, and the code should continue to run, and be
+ // able to recover.
+ while (!_inFileA.EndOfFile() && !_inFileB.EndOfFile()) {
+ msecPassed += 10;
+ EXPECT_GT(_inFileA.Read10MsData(audioFrame), 0);
+ EXPECT_GE(_acmA->Add10MsData(audioFrame), 0);
+ EXPECT_GE(_acmRefA->Add10MsData(audioFrame), 0);
+
+ EXPECT_GT(_inFileB.Read10MsData(audioFrame), 0);
+
+ EXPECT_GE(_acmB->Add10MsData(audioFrame), 0);
+ EXPECT_GE(_acmRefB->Add10MsData(audioFrame), 0);
+ bool muted;
+ EXPECT_EQ(0, _acmA->PlayoutData10Ms(outFreqHzA, &audioFrame, &muted));
+ ASSERT_FALSE(muted);
+ _outFileA.Write10MsData(audioFrame);
+ EXPECT_EQ(0, _acmRefA->PlayoutData10Ms(outFreqHzA, &audioFrame, &muted));
+ ASSERT_FALSE(muted);
+ _outFileRefA.Write10MsData(audioFrame);
+ EXPECT_EQ(0, _acmB->PlayoutData10Ms(outFreqHzB, &audioFrame, &muted));
+ ASSERT_FALSE(muted);
+ _outFileB.Write10MsData(audioFrame);
+ EXPECT_EQ(0, _acmRefB->PlayoutData10Ms(outFreqHzB, &audioFrame, &muted));
+ ASSERT_FALSE(muted);
+ _outFileRefB.Write10MsData(audioFrame);
+
+ // Update time counters each time a second of data has passed.
+ if (msecPassed >= 1000) {
+ msecPassed = 0;
+ secPassed++;
+ }
+ // Re-register send codec on side B.
+ if (((secPassed % 5) == 4) && (msecPassed >= 990)) {
+ _acmB->SetEncoder(encoder_factory->MakeAudioEncoder(
+ payload_type2, format2, absl::nullopt));
+ }
+ // Initialize receiver on side A.
+ if (((secPassed % 7) == 6) && (msecPassed == 0))
+ EXPECT_EQ(0, _acmA->InitializeReceiver());
+ // Re-register codec on side A.
+ if (((secPassed % 7) == 6) && (msecPassed >= 990)) {
+ _acmA->SetReceiveCodecs({{payload_type2, format2}});
+ }
+ }
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.h b/third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.h
new file mode 100644
index 0000000000..b7eb9e5583
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/TwoWayCommunication.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
+#define MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
+
+#include <memory>
+
+#include "api/audio_codecs/audio_encoder_factory.h"
+#include "api/audio_codecs/audio_format.h"
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "modules/audio_coding/test/Channel.h"
+#include "modules/audio_coding/test/PCMFile.h"
+
+namespace webrtc {
+
+class TwoWayCommunication {
+ public:
+ TwoWayCommunication();
+ ~TwoWayCommunication();
+
+ void Perform();
+
+ private:
+ void SetUpAutotest(AudioEncoderFactory* const encoder_factory,
+ const SdpAudioFormat& format1,
+ int payload_type1,
+ const SdpAudioFormat& format2,
+ int payload_type2);
+
+ std::unique_ptr<AudioCodingModule> _acmA;
+ std::unique_ptr<AudioCodingModule> _acmB;
+
+ std::unique_ptr<AudioCodingModule> _acmRefA;
+ std::unique_ptr<AudioCodingModule> _acmRefB;
+
+ Channel* _channel_A2B;
+ Channel* _channel_B2A;
+
+ Channel* _channelRef_A2B;
+ Channel* _channelRef_B2A;
+
+ PCMFile _inFileA;
+ PCMFile _inFileB;
+
+ PCMFile _outFileA;
+ PCMFile _outFileB;
+
+ PCMFile _outFileRefA;
+ PCMFile _outFileRefB;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_TWOWAYCOMMUNICATION_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/opus_test.cc b/third_party/libwebrtc/modules/audio_coding/test/opus_test.cc
new file mode 100644
index 0000000000..6822bc3d72
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/opus_test.cc
@@ -0,0 +1,402 @@
+/*
+ * 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 "modules/audio_coding/test/opus_test.h"
+
+#include <string>
+
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "modules/audio_coding/codecs/opus/opus_interface.h"
+#include "modules/audio_coding/include/audio_coding_module_typedefs.h"
+#include "modules/audio_coding/test/TestStereo.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+OpusTest::OpusTest()
+ : acm_receiver_(AudioCodingModule::Create(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory()))),
+ channel_a2b_(NULL),
+ counter_(0),
+ payload_type_(255),
+ rtp_timestamp_(0) {}
+
+OpusTest::~OpusTest() {
+ if (channel_a2b_ != NULL) {
+ delete channel_a2b_;
+ channel_a2b_ = NULL;
+ }
+ if (opus_mono_encoder_ != NULL) {
+ WebRtcOpus_EncoderFree(opus_mono_encoder_);
+ opus_mono_encoder_ = NULL;
+ }
+ if (opus_stereo_encoder_ != NULL) {
+ WebRtcOpus_EncoderFree(opus_stereo_encoder_);
+ opus_stereo_encoder_ = NULL;
+ }
+ if (opus_mono_decoder_ != NULL) {
+ WebRtcOpus_DecoderFree(opus_mono_decoder_);
+ opus_mono_decoder_ = NULL;
+ }
+ if (opus_stereo_decoder_ != NULL) {
+ WebRtcOpus_DecoderFree(opus_stereo_decoder_);
+ opus_stereo_decoder_ = NULL;
+ }
+}
+
+void OpusTest::Perform() {
+#ifndef WEBRTC_CODEC_OPUS
+ // Opus isn't defined, exit.
+ return;
+#else
+ uint16_t frequency_hz;
+ size_t audio_channels;
+ int16_t test_cntr = 0;
+
+ // Open both mono and stereo test files in 32 kHz.
+ const std::string file_name_stereo =
+ webrtc::test::ResourcePath("audio_coding/teststereo32kHz", "pcm");
+ const std::string file_name_mono =
+ webrtc::test::ResourcePath("audio_coding/testfile32kHz", "pcm");
+ frequency_hz = 32000;
+ in_file_stereo_.Open(file_name_stereo, frequency_hz, "rb");
+ in_file_stereo_.ReadStereo(true);
+ in_file_mono_.Open(file_name_mono, frequency_hz, "rb");
+ in_file_mono_.ReadStereo(false);
+
+ // Create Opus encoders for mono and stereo.
+ ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_mono_encoder_, 1, 0, 48000), -1);
+ ASSERT_GT(WebRtcOpus_EncoderCreate(&opus_stereo_encoder_, 2, 1, 48000), -1);
+
+ // Create Opus decoders for mono and stereo for stand-alone testing of Opus.
+ ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_mono_decoder_, 1, 48000), -1);
+ ASSERT_GT(WebRtcOpus_DecoderCreate(&opus_stereo_decoder_, 2, 48000), -1);
+ WebRtcOpus_DecoderInit(opus_mono_decoder_);
+ WebRtcOpus_DecoderInit(opus_stereo_decoder_);
+
+ ASSERT_TRUE(acm_receiver_.get() != NULL);
+ EXPECT_EQ(0, acm_receiver_->InitializeReceiver());
+
+ // Register Opus stereo as receiving codec.
+ constexpr int kOpusPayloadType = 120;
+ const SdpAudioFormat kOpusFormatStereo("opus", 48000, 2, {{"stereo", "1"}});
+ payload_type_ = kOpusPayloadType;
+ acm_receiver_->SetReceiveCodecs({{kOpusPayloadType, kOpusFormatStereo}});
+
+ // Create and connect the channel.
+ channel_a2b_ = new TestPackStereo;
+ channel_a2b_->RegisterReceiverACM(acm_receiver_.get());
+
+ //
+ // Test Stereo.
+ //
+
+ channel_a2b_->set_codec_mode(kStereo);
+ audio_channels = 2;
+ test_cntr++;
+ OpenOutFile(test_cntr);
+
+ // Run Opus with 2.5 ms frame size.
+ Run(channel_a2b_, audio_channels, 64000, 120);
+
+ // Run Opus with 5 ms frame size.
+ Run(channel_a2b_, audio_channels, 64000, 240);
+
+ // Run Opus with 10 ms frame size.
+ Run(channel_a2b_, audio_channels, 64000, 480);
+
+ // Run Opus with 20 ms frame size.
+ Run(channel_a2b_, audio_channels, 64000, 960);
+
+ // Run Opus with 40 ms frame size.
+ Run(channel_a2b_, audio_channels, 64000, 1920);
+
+ // Run Opus with 60 ms frame size.
+ Run(channel_a2b_, audio_channels, 64000, 2880);
+
+ out_file_.Close();
+ out_file_standalone_.Close();
+
+ //
+ // Test Opus stereo with packet-losses.
+ //
+
+ test_cntr++;
+ OpenOutFile(test_cntr);
+
+ // Run Opus with 20 ms frame size, 1% packet loss.
+ Run(channel_a2b_, audio_channels, 64000, 960, 1);
+
+ // Run Opus with 20 ms frame size, 5% packet loss.
+ Run(channel_a2b_, audio_channels, 64000, 960, 5);
+
+ // Run Opus with 20 ms frame size, 10% packet loss.
+ Run(channel_a2b_, audio_channels, 64000, 960, 10);
+
+ out_file_.Close();
+ out_file_standalone_.Close();
+
+ //
+ // Test Mono.
+ //
+ channel_a2b_->set_codec_mode(kMono);
+ audio_channels = 1;
+ test_cntr++;
+ OpenOutFile(test_cntr);
+
+ // Register Opus mono as receiving codec.
+ const SdpAudioFormat kOpusFormatMono("opus", 48000, 2);
+ acm_receiver_->SetReceiveCodecs({{kOpusPayloadType, kOpusFormatMono}});
+
+ // Run Opus with 2.5 ms frame size.
+ Run(channel_a2b_, audio_channels, 32000, 120);
+
+ // Run Opus with 5 ms frame size.
+ Run(channel_a2b_, audio_channels, 32000, 240);
+
+ // Run Opus with 10 ms frame size.
+ Run(channel_a2b_, audio_channels, 32000, 480);
+
+ // Run Opus with 20 ms frame size.
+ Run(channel_a2b_, audio_channels, 32000, 960);
+
+ // Run Opus with 40 ms frame size.
+ Run(channel_a2b_, audio_channels, 32000, 1920);
+
+ // Run Opus with 60 ms frame size.
+ Run(channel_a2b_, audio_channels, 32000, 2880);
+
+ out_file_.Close();
+ out_file_standalone_.Close();
+
+ //
+ // Test Opus mono with packet-losses.
+ //
+ test_cntr++;
+ OpenOutFile(test_cntr);
+
+ // Run Opus with 20 ms frame size, 1% packet loss.
+ Run(channel_a2b_, audio_channels, 64000, 960, 1);
+
+ // Run Opus with 20 ms frame size, 5% packet loss.
+ Run(channel_a2b_, audio_channels, 64000, 960, 5);
+
+ // Run Opus with 20 ms frame size, 10% packet loss.
+ Run(channel_a2b_, audio_channels, 64000, 960, 10);
+
+ // Close the files.
+ in_file_stereo_.Close();
+ in_file_mono_.Close();
+ out_file_.Close();
+ out_file_standalone_.Close();
+#endif
+}
+
+void OpusTest::Run(TestPackStereo* channel,
+ size_t channels,
+ int bitrate,
+ size_t frame_length,
+ int percent_loss) {
+ AudioFrame audio_frame;
+ int32_t out_freq_hz_b = out_file_.SamplingFrequency();
+ const size_t kBufferSizeSamples = 480 * 12 * 2; // 120 ms stereo audio.
+ int16_t audio[kBufferSizeSamples];
+ int16_t out_audio[kBufferSizeSamples];
+ int16_t audio_type;
+ size_t written_samples = 0;
+ size_t read_samples = 0;
+ size_t decoded_samples = 0;
+ bool first_packet = true;
+ uint32_t start_time_stamp = 0;
+
+ channel->reset_payload_size();
+ counter_ = 0;
+
+ // Set encoder rate.
+ EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_mono_encoder_, bitrate));
+ EXPECT_EQ(0, WebRtcOpus_SetBitRate(opus_stereo_encoder_, bitrate));
+
+#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS) || defined(WEBRTC_ARCH_ARM)
+ // If we are on Android, iOS and/or ARM, use a lower complexity setting as
+ // default.
+ const int kOpusComplexity5 = 5;
+ EXPECT_EQ(0, WebRtcOpus_SetComplexity(opus_mono_encoder_, kOpusComplexity5));
+ EXPECT_EQ(0,
+ WebRtcOpus_SetComplexity(opus_stereo_encoder_, kOpusComplexity5));
+#endif
+
+ // Fast-forward 1 second (100 blocks) since the files start with silence.
+ in_file_stereo_.FastForward(100);
+ in_file_mono_.FastForward(100);
+
+ // Limit the runtime to 1000 blocks of 10 ms each.
+ for (size_t audio_length = 0; audio_length < 1000; audio_length += 10) {
+ bool lost_packet = false;
+
+ // Get 10 msec of audio.
+ if (channels == 1) {
+ if (in_file_mono_.EndOfFile()) {
+ break;
+ }
+ in_file_mono_.Read10MsData(audio_frame);
+ } else {
+ if (in_file_stereo_.EndOfFile()) {
+ break;
+ }
+ in_file_stereo_.Read10MsData(audio_frame);
+ }
+
+ // If input audio is sampled at 32 kHz, resampling to 48 kHz is required.
+ EXPECT_EQ(480, resampler_.Resample10Msec(
+ audio_frame.data(), audio_frame.sample_rate_hz_, 48000,
+ channels, kBufferSizeSamples - written_samples,
+ &audio[written_samples]));
+ written_samples += 480 * channels;
+
+ // Sometimes we need to loop over the audio vector to produce the right
+ // number of packets.
+ size_t loop_encode =
+ (written_samples - read_samples) / (channels * frame_length);
+
+ if (loop_encode > 0) {
+ const size_t kMaxBytes = 1000; // Maximum number of bytes for one packet.
+ size_t bitstream_len_byte;
+ uint8_t bitstream[kMaxBytes];
+ for (size_t i = 0; i < loop_encode; i++) {
+ int bitstream_len_byte_int = WebRtcOpus_Encode(
+ (channels == 1) ? opus_mono_encoder_ : opus_stereo_encoder_,
+ &audio[read_samples], frame_length, kMaxBytes, bitstream);
+ ASSERT_GE(bitstream_len_byte_int, 0);
+ bitstream_len_byte = static_cast<size_t>(bitstream_len_byte_int);
+
+ // Simulate packet loss by setting `packet_loss_` to "true" in
+ // `percent_loss` percent of the loops.
+ // TODO(tlegrand): Move handling of loss simulation to TestPackStereo.
+ if (percent_loss > 0) {
+ if (counter_ == floor((100 / percent_loss) + 0.5)) {
+ counter_ = 0;
+ lost_packet = true;
+ channel->set_lost_packet(true);
+ } else {
+ lost_packet = false;
+ channel->set_lost_packet(false);
+ }
+ counter_++;
+ }
+
+ // Run stand-alone Opus decoder, or decode PLC.
+ if (channels == 1) {
+ if (!lost_packet) {
+ decoded_samples += WebRtcOpus_Decode(
+ opus_mono_decoder_, bitstream, bitstream_len_byte,
+ &out_audio[decoded_samples * channels], &audio_type);
+ } else {
+ // Call decoder PLC.
+ constexpr int kPlcDurationMs = 10;
+ constexpr int kPlcSamples = 48 * kPlcDurationMs;
+ size_t total_plc_samples = 0;
+ while (total_plc_samples < frame_length) {
+ int ret = WebRtcOpus_Decode(
+ opus_mono_decoder_, NULL, 0,
+ &out_audio[decoded_samples * channels], &audio_type);
+ EXPECT_EQ(ret, kPlcSamples);
+ decoded_samples += ret;
+ total_plc_samples += ret;
+ }
+ EXPECT_EQ(total_plc_samples, frame_length);
+ }
+ } else {
+ if (!lost_packet) {
+ decoded_samples += WebRtcOpus_Decode(
+ opus_stereo_decoder_, bitstream, bitstream_len_byte,
+ &out_audio[decoded_samples * channels], &audio_type);
+ } else {
+ // Call decoder PLC.
+ constexpr int kPlcDurationMs = 10;
+ constexpr int kPlcSamples = 48 * kPlcDurationMs;
+ size_t total_plc_samples = 0;
+ while (total_plc_samples < frame_length) {
+ int ret = WebRtcOpus_Decode(
+ opus_stereo_decoder_, NULL, 0,
+ &out_audio[decoded_samples * channels], &audio_type);
+ EXPECT_EQ(ret, kPlcSamples);
+ decoded_samples += ret;
+ total_plc_samples += ret;
+ }
+ EXPECT_EQ(total_plc_samples, frame_length);
+ }
+ }
+
+ // Send data to the channel. "channel" will handle the loss simulation.
+ channel->SendData(AudioFrameType::kAudioFrameSpeech, payload_type_,
+ rtp_timestamp_, bitstream, bitstream_len_byte, 0);
+ if (first_packet) {
+ first_packet = false;
+ start_time_stamp = rtp_timestamp_;
+ }
+ rtp_timestamp_ += static_cast<uint32_t>(frame_length);
+ read_samples += frame_length * channels;
+ }
+ if (read_samples == written_samples) {
+ read_samples = 0;
+ written_samples = 0;
+ }
+ }
+
+ // Run received side of ACM.
+ bool muted;
+ ASSERT_EQ(
+ 0, acm_receiver_->PlayoutData10Ms(out_freq_hz_b, &audio_frame, &muted));
+ ASSERT_FALSE(muted);
+
+ // Write output speech to file.
+ out_file_.Write10MsData(
+ audio_frame.data(),
+ audio_frame.samples_per_channel_ * audio_frame.num_channels_);
+
+ // Write stand-alone speech to file.
+ out_file_standalone_.Write10MsData(out_audio, decoded_samples * channels);
+
+ if (audio_frame.timestamp_ > start_time_stamp) {
+ // Number of channels should be the same for both stand-alone and
+ // ACM-decoding.
+ EXPECT_EQ(audio_frame.num_channels_, channels);
+ }
+
+ decoded_samples = 0;
+ }
+
+ if (in_file_mono_.EndOfFile()) {
+ in_file_mono_.Rewind();
+ }
+ if (in_file_stereo_.EndOfFile()) {
+ in_file_stereo_.Rewind();
+ }
+ // Reset in case we ended with a lost packet.
+ channel->set_lost_packet(false);
+}
+
+void OpusTest::OpenOutFile(int test_number) {
+ std::string file_name;
+ std::stringstream file_stream;
+ file_stream << webrtc::test::OutputPath() << "opustest_out_" << test_number
+ << ".pcm";
+ file_name = file_stream.str();
+ out_file_.Open(file_name, 48000, "wb");
+ file_stream.str("");
+ file_name = file_stream.str();
+ file_stream << webrtc::test::OutputPath() << "opusstandalone_out_"
+ << test_number << ".pcm";
+ file_name = file_stream.str();
+ out_file_standalone_.Open(file_name, 48000, "wb");
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/modules/audio_coding/test/opus_test.h b/third_party/libwebrtc/modules/audio_coding/test/opus_test.h
new file mode 100644
index 0000000000..c69f922adb
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/opus_test.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#ifndef MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
+#define MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
+
+#include <math.h>
+
+#include <memory>
+
+#include "modules/audio_coding/acm2/acm_resampler.h"
+#include "modules/audio_coding/codecs/opus/opus_interface.h"
+#include "modules/audio_coding/test/PCMFile.h"
+#include "modules/audio_coding/test/TestStereo.h"
+
+namespace webrtc {
+
+class OpusTest {
+ public:
+ OpusTest();
+ ~OpusTest();
+
+ void Perform();
+
+ private:
+ void Run(TestPackStereo* channel,
+ size_t channels,
+ int bitrate,
+ size_t frame_length,
+ int percent_loss = 0);
+
+ void OpenOutFile(int test_number);
+
+ std::unique_ptr<AudioCodingModule> acm_receiver_;
+ TestPackStereo* channel_a2b_;
+ PCMFile in_file_stereo_;
+ PCMFile in_file_mono_;
+ PCMFile out_file_;
+ PCMFile out_file_standalone_;
+ int counter_;
+ uint8_t payload_type_;
+ uint32_t rtp_timestamp_;
+ acm2::ACMResampler resampler_;
+ WebRtcOpusEncInst* opus_mono_encoder_;
+ WebRtcOpusEncInst* opus_stereo_encoder_;
+ WebRtcOpusDecInst* opus_mono_decoder_;
+ WebRtcOpusDecInst* opus_stereo_decoder_;
+};
+
+} // namespace webrtc
+
+#endif // MODULES_AUDIO_CODING_TEST_OPUS_TEST_H_
diff --git a/third_party/libwebrtc/modules/audio_coding/test/target_delay_unittest.cc b/third_party/libwebrtc/modules/audio_coding/test/target_delay_unittest.cc
new file mode 100644
index 0000000000..5eccdcf8eb
--- /dev/null
+++ b/third_party/libwebrtc/modules/audio_coding/test/target_delay_unittest.cc
@@ -0,0 +1,161 @@
+/*
+ * 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 <memory>
+
+#include "api/audio/audio_frame.h"
+#include "api/audio_codecs/builtin_audio_decoder_factory.h"
+#include "api/rtp_headers.h"
+#include "modules/audio_coding/acm2/acm_receiver.h"
+#include "modules/audio_coding/codecs/pcm16b/pcm16b.h"
+#include "modules/audio_coding/include/audio_coding_module.h"
+#include "test/gtest.h"
+#include "test/testsupport/file_utils.h"
+
+namespace webrtc {
+
+class TargetDelayTest : public ::testing::Test {
+ protected:
+ TargetDelayTest()
+ : receiver_(
+ AudioCodingModule::Config(CreateBuiltinAudioDecoderFactory())) {}
+
+ ~TargetDelayTest() {}
+
+ void SetUp() {
+ constexpr int pltype = 108;
+ std::map<int, SdpAudioFormat> receive_codecs = {
+ {pltype, {"L16", kSampleRateHz, 1}}};
+ receiver_.SetCodecs(receive_codecs);
+
+ rtp_header_.payloadType = pltype;
+ rtp_header_.timestamp = 0;
+ rtp_header_.ssrc = 0x12345678;
+ rtp_header_.markerBit = false;
+ rtp_header_.sequenceNumber = 0;
+
+ int16_t audio[kFrameSizeSamples];
+ const int kRange = 0x7FF; // 2047, easy for masking.
+ for (size_t n = 0; n < kFrameSizeSamples; ++n)
+ audio[n] = (rand() & kRange) - kRange / 2;
+ WebRtcPcm16b_Encode(audio, kFrameSizeSamples, payload_);
+ }
+
+ void OutOfRangeInput() {
+ EXPECT_EQ(-1, SetMinimumDelay(-1));
+ EXPECT_EQ(-1, SetMinimumDelay(10001));
+ }
+
+ void TargetDelayBufferMinMax() {
+ const int kTargetMinDelayMs = kNum10msPerFrame * 10;
+ ASSERT_EQ(0, SetMinimumDelay(kTargetMinDelayMs));
+ for (int m = 0; m < 30; ++m) // Run enough iterations to fill the buffer.
+ Run(true);
+ int clean_optimal_delay = GetCurrentOptimalDelayMs();
+ EXPECT_EQ(kTargetMinDelayMs, clean_optimal_delay);
+
+ const int kTargetMaxDelayMs = 2 * (kNum10msPerFrame * 10);
+ ASSERT_EQ(0, SetMaximumDelay(kTargetMaxDelayMs));
+ for (int n = 0; n < 30; ++n) // Run enough iterations to fill the buffer.
+ Run(false);
+
+ int capped_optimal_delay = GetCurrentOptimalDelayMs();
+ EXPECT_EQ(kTargetMaxDelayMs, capped_optimal_delay);
+ }
+
+ private:
+ static const int kSampleRateHz = 16000;
+ static const int kNum10msPerFrame = 2;
+ static const size_t kFrameSizeSamples = 320; // 20 ms @ 16 kHz.
+ // payload-len = frame-samples * 2 bytes/sample.
+ static const int kPayloadLenBytes = 320 * 2;
+ // Inter-arrival time in number of packets in a jittery channel. One is no
+ // jitter.
+ static const int kInterarrivalJitterPacket = 2;
+
+ void Push() {
+ rtp_header_.timestamp += kFrameSizeSamples;
+ rtp_header_.sequenceNumber++;
+ ASSERT_EQ(0, receiver_.InsertPacket(rtp_header_,
+ rtc::ArrayView<const uint8_t>(
+ payload_, kFrameSizeSamples * 2)));
+ }
+
+ // Pull audio equivalent to the amount of audio in one RTP packet.
+ void Pull() {
+ AudioFrame frame;
+ bool muted;
+ for (int k = 0; k < kNum10msPerFrame; ++k) { // Pull one frame.
+ ASSERT_EQ(0, receiver_.GetAudio(-1, &frame, &muted));
+ ASSERT_FALSE(muted);
+ // Had to use ASSERT_TRUE, ASSERT_EQ generated error.
+ ASSERT_TRUE(kSampleRateHz == frame.sample_rate_hz_);
+ ASSERT_EQ(1u, frame.num_channels_);
+ ASSERT_TRUE(kSampleRateHz / 100 == frame.samples_per_channel_);
+ }
+ }
+
+ void Run(bool clean) {
+ for (int n = 0; n < 10; ++n) {
+ for (int m = 0; m < 5; ++m) {
+ Push();
+ Pull();
+ }
+
+ if (!clean) {
+ for (int m = 0; m < 10; ++m) { // Long enough to trigger delay change.
+ Push();
+ for (int n = 0; n < kInterarrivalJitterPacket; ++n)
+ Pull();
+ }
+ }
+ }
+ }
+
+ int SetMinimumDelay(int delay_ms) {
+ return receiver_.SetMinimumDelay(delay_ms);
+ }
+
+ int SetMaximumDelay(int delay_ms) {
+ return receiver_.SetMaximumDelay(delay_ms);
+ }
+
+ int GetCurrentOptimalDelayMs() {
+ NetworkStatistics stats;
+ receiver_.GetNetworkStatistics(&stats);
+ return stats.preferredBufferSize;
+ }
+
+ acm2::AcmReceiver receiver_;
+ RTPHeader rtp_header_;
+ uint8_t payload_[kPayloadLenBytes];
+};
+
+// Flaky on iOS: webrtc:7057.
+#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
+#define MAYBE_OutOfRangeInput DISABLED_OutOfRangeInput
+#else
+#define MAYBE_OutOfRangeInput OutOfRangeInput
+#endif
+TEST_F(TargetDelayTest, MAYBE_OutOfRangeInput) {
+ OutOfRangeInput();
+}
+
+// Flaky on iOS: webrtc:7057.
+#if defined(WEBRTC_ANDROID) || defined(WEBRTC_IOS)
+#define MAYBE_TargetDelayBufferMinMax DISABLED_TargetDelayBufferMinMax
+#else
+#define MAYBE_TargetDelayBufferMinMax TargetDelayBufferMinMax
+#endif
+TEST_F(TargetDelayTest, MAYBE_TargetDelayBufferMinMax) {
+ TargetDelayBufferMinMax();
+}
+
+} // namespace webrtc