1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker *
4*d9f75844SAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker * that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker * tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker * in the file PATENTS. All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker * be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker */
10*d9f75844SAndroid Build Coastguard Worker
11*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
12*d9f75844SAndroid Build Coastguard Worker #include <cmath>
13*d9f75844SAndroid Build Coastguard Worker #include <cstring>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <vector>
16*d9f75844SAndroid Build Coastguard Worker
17*d9f75844SAndroid Build Coastguard Worker #include "api/array_view.h"
18*d9f75844SAndroid Build Coastguard Worker #include "api/audio_codecs/builtin_audio_decoder_factory.h"
19*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
20*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/neteq/tools/audio_checksum.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/neteq/tools/encode_neteq_input.h"
22*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/neteq/tools/neteq_test.h"
23*d9f75844SAndroid Build Coastguard Worker #include "modules/rtp_rtcp/source/byte_io.h"
24*d9f75844SAndroid Build Coastguard Worker
25*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
26*d9f75844SAndroid Build Coastguard Worker namespace test {
27*d9f75844SAndroid Build Coastguard Worker namespace {
28*d9f75844SAndroid Build Coastguard Worker constexpr int kPayloadType = 95;
29*d9f75844SAndroid Build Coastguard Worker
30*d9f75844SAndroid Build Coastguard Worker class SineGenerator : public EncodeNetEqInput::Generator {
31*d9f75844SAndroid Build Coastguard Worker public:
SineGenerator(int sample_rate_hz)32*d9f75844SAndroid Build Coastguard Worker explicit SineGenerator(int sample_rate_hz)
33*d9f75844SAndroid Build Coastguard Worker : sample_rate_hz_(sample_rate_hz) {}
34*d9f75844SAndroid Build Coastguard Worker
Generate(size_t num_samples)35*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const int16_t> Generate(size_t num_samples) override {
36*d9f75844SAndroid Build Coastguard Worker if (samples_.size() < num_samples) {
37*d9f75844SAndroid Build Coastguard Worker samples_.resize(num_samples);
38*d9f75844SAndroid Build Coastguard Worker }
39*d9f75844SAndroid Build Coastguard Worker
40*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<int16_t> output(samples_.data(), num_samples);
41*d9f75844SAndroid Build Coastguard Worker for (auto& x : output) {
42*d9f75844SAndroid Build Coastguard Worker x = static_cast<int16_t>(2000.0 * std::sin(phase_));
43*d9f75844SAndroid Build Coastguard Worker phase_ += 2 * kPi * kFreqHz / sample_rate_hz_;
44*d9f75844SAndroid Build Coastguard Worker }
45*d9f75844SAndroid Build Coastguard Worker return output;
46*d9f75844SAndroid Build Coastguard Worker }
47*d9f75844SAndroid Build Coastguard Worker
48*d9f75844SAndroid Build Coastguard Worker private:
49*d9f75844SAndroid Build Coastguard Worker static constexpr int kFreqHz = 300; // The sinewave frequency.
50*d9f75844SAndroid Build Coastguard Worker const int sample_rate_hz_;
51*d9f75844SAndroid Build Coastguard Worker const double kPi = std::acos(-1);
52*d9f75844SAndroid Build Coastguard Worker std::vector<int16_t> samples_;
53*d9f75844SAndroid Build Coastguard Worker double phase_ = 0.0;
54*d9f75844SAndroid Build Coastguard Worker };
55*d9f75844SAndroid Build Coastguard Worker
56*d9f75844SAndroid Build Coastguard Worker class FuzzRtpInput : public NetEqInput {
57*d9f75844SAndroid Build Coastguard Worker public:
FuzzRtpInput(rtc::ArrayView<const uint8_t> data)58*d9f75844SAndroid Build Coastguard Worker explicit FuzzRtpInput(rtc::ArrayView<const uint8_t> data) : data_(data) {
59*d9f75844SAndroid Build Coastguard Worker AudioEncoderPcm16B::Config config;
60*d9f75844SAndroid Build Coastguard Worker config.payload_type = kPayloadType;
61*d9f75844SAndroid Build Coastguard Worker config.sample_rate_hz = 32000;
62*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<AudioEncoder> encoder(new AudioEncoderPcm16B(config));
63*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EncodeNetEqInput::Generator> generator(
64*d9f75844SAndroid Build Coastguard Worker new SineGenerator(config.sample_rate_hz));
65*d9f75844SAndroid Build Coastguard Worker input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder),
66*d9f75844SAndroid Build Coastguard Worker std::numeric_limits<int64_t>::max()));
67*d9f75844SAndroid Build Coastguard Worker packet_ = input_->PopPacket();
68*d9f75844SAndroid Build Coastguard Worker FuzzHeader();
69*d9f75844SAndroid Build Coastguard Worker MaybeFuzzPayload();
70*d9f75844SAndroid Build Coastguard Worker }
71*d9f75844SAndroid Build Coastguard Worker
NextPacketTime() const72*d9f75844SAndroid Build Coastguard Worker absl::optional<int64_t> NextPacketTime() const override {
73*d9f75844SAndroid Build Coastguard Worker return packet_->time_ms;
74*d9f75844SAndroid Build Coastguard Worker }
75*d9f75844SAndroid Build Coastguard Worker
NextOutputEventTime() const76*d9f75844SAndroid Build Coastguard Worker absl::optional<int64_t> NextOutputEventTime() const override {
77*d9f75844SAndroid Build Coastguard Worker return input_->NextOutputEventTime();
78*d9f75844SAndroid Build Coastguard Worker }
79*d9f75844SAndroid Build Coastguard Worker
PopPacket()80*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<PacketData> PopPacket() override {
81*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(packet_);
82*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<PacketData> packet_to_return = std::move(packet_);
83*d9f75844SAndroid Build Coastguard Worker packet_ = input_->PopPacket();
84*d9f75844SAndroid Build Coastguard Worker FuzzHeader();
85*d9f75844SAndroid Build Coastguard Worker MaybeFuzzPayload();
86*d9f75844SAndroid Build Coastguard Worker return packet_to_return;
87*d9f75844SAndroid Build Coastguard Worker }
88*d9f75844SAndroid Build Coastguard Worker
AdvanceOutputEvent()89*d9f75844SAndroid Build Coastguard Worker void AdvanceOutputEvent() override { return input_->AdvanceOutputEvent(); }
90*d9f75844SAndroid Build Coastguard Worker
ended() const91*d9f75844SAndroid Build Coastguard Worker bool ended() const override { return ended_; }
92*d9f75844SAndroid Build Coastguard Worker
NextHeader() const93*d9f75844SAndroid Build Coastguard Worker absl::optional<RTPHeader> NextHeader() const override {
94*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(packet_);
95*d9f75844SAndroid Build Coastguard Worker return packet_->header;
96*d9f75844SAndroid Build Coastguard Worker }
97*d9f75844SAndroid Build Coastguard Worker
98*d9f75844SAndroid Build Coastguard Worker private:
FuzzHeader()99*d9f75844SAndroid Build Coastguard Worker void FuzzHeader() {
100*d9f75844SAndroid Build Coastguard Worker constexpr size_t kNumBytesToFuzz = 11;
101*d9f75844SAndroid Build Coastguard Worker if (data_ix_ + kNumBytesToFuzz > data_.size()) {
102*d9f75844SAndroid Build Coastguard Worker ended_ = true;
103*d9f75844SAndroid Build Coastguard Worker return;
104*d9f75844SAndroid Build Coastguard Worker }
105*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(packet_);
106*d9f75844SAndroid Build Coastguard Worker const size_t start_ix = data_ix_;
107*d9f75844SAndroid Build Coastguard Worker packet_->header.payloadType =
108*d9f75844SAndroid Build Coastguard Worker ByteReader<uint8_t>::ReadLittleEndian(&data_[data_ix_]);
109*d9f75844SAndroid Build Coastguard Worker packet_->header.payloadType &= 0x7F;
110*d9f75844SAndroid Build Coastguard Worker data_ix_ += sizeof(uint8_t);
111*d9f75844SAndroid Build Coastguard Worker packet_->header.sequenceNumber =
112*d9f75844SAndroid Build Coastguard Worker ByteReader<uint16_t>::ReadLittleEndian(&data_[data_ix_]);
113*d9f75844SAndroid Build Coastguard Worker data_ix_ += sizeof(uint16_t);
114*d9f75844SAndroid Build Coastguard Worker packet_->header.timestamp =
115*d9f75844SAndroid Build Coastguard Worker ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
116*d9f75844SAndroid Build Coastguard Worker data_ix_ += sizeof(uint32_t);
117*d9f75844SAndroid Build Coastguard Worker packet_->header.ssrc =
118*d9f75844SAndroid Build Coastguard Worker ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
119*d9f75844SAndroid Build Coastguard Worker data_ix_ += sizeof(uint32_t);
120*d9f75844SAndroid Build Coastguard Worker RTC_CHECK_EQ(data_ix_ - start_ix, kNumBytesToFuzz);
121*d9f75844SAndroid Build Coastguard Worker }
122*d9f75844SAndroid Build Coastguard Worker
MaybeFuzzPayload()123*d9f75844SAndroid Build Coastguard Worker void MaybeFuzzPayload() {
124*d9f75844SAndroid Build Coastguard Worker // Read one byte of fuzz data to determine how many payload bytes to fuzz.
125*d9f75844SAndroid Build Coastguard Worker if (data_ix_ + 1 > data_.size()) {
126*d9f75844SAndroid Build Coastguard Worker ended_ = true;
127*d9f75844SAndroid Build Coastguard Worker return;
128*d9f75844SAndroid Build Coastguard Worker }
129*d9f75844SAndroid Build Coastguard Worker size_t bytes_to_fuzz = data_[data_ix_++];
130*d9f75844SAndroid Build Coastguard Worker
131*d9f75844SAndroid Build Coastguard Worker // Restrict number of bytes to fuzz to 16; a reasonably low number enough to
132*d9f75844SAndroid Build Coastguard Worker // cover a few RED headers. Also don't write outside the payload length.
133*d9f75844SAndroid Build Coastguard Worker bytes_to_fuzz = std::min(bytes_to_fuzz % 16, packet_->payload.size());
134*d9f75844SAndroid Build Coastguard Worker
135*d9f75844SAndroid Build Coastguard Worker if (bytes_to_fuzz == 0)
136*d9f75844SAndroid Build Coastguard Worker return;
137*d9f75844SAndroid Build Coastguard Worker
138*d9f75844SAndroid Build Coastguard Worker if (data_ix_ + bytes_to_fuzz > data_.size()) {
139*d9f75844SAndroid Build Coastguard Worker ended_ = true;
140*d9f75844SAndroid Build Coastguard Worker return;
141*d9f75844SAndroid Build Coastguard Worker }
142*d9f75844SAndroid Build Coastguard Worker
143*d9f75844SAndroid Build Coastguard Worker std::memcpy(packet_->payload.data(), &data_[data_ix_], bytes_to_fuzz);
144*d9f75844SAndroid Build Coastguard Worker data_ix_ += bytes_to_fuzz;
145*d9f75844SAndroid Build Coastguard Worker }
146*d9f75844SAndroid Build Coastguard Worker
147*d9f75844SAndroid Build Coastguard Worker bool ended_ = false;
148*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const uint8_t> data_;
149*d9f75844SAndroid Build Coastguard Worker size_t data_ix_ = 0;
150*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EncodeNetEqInput> input_;
151*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<PacketData> packet_;
152*d9f75844SAndroid Build Coastguard Worker };
153*d9f75844SAndroid Build Coastguard Worker } // namespace
154*d9f75844SAndroid Build Coastguard Worker
FuzzOneInputTest(const uint8_t * data,size_t size)155*d9f75844SAndroid Build Coastguard Worker void FuzzOneInputTest(const uint8_t* data, size_t size) {
156*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<FuzzRtpInput> input(
157*d9f75844SAndroid Build Coastguard Worker new FuzzRtpInput(rtc::ArrayView<const uint8_t>(data, size)));
158*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<AudioChecksum> output(new AudioChecksum);
159*d9f75844SAndroid Build Coastguard Worker NetEqTest::Callbacks callbacks;
160*d9f75844SAndroid Build Coastguard Worker NetEq::Config config;
161*d9f75844SAndroid Build Coastguard Worker auto codecs = NetEqTest::StandardDecoderMap();
162*d9f75844SAndroid Build Coastguard Worker // kPayloadType is the payload type that will be used for encoding. Verify
163*d9f75844SAndroid Build Coastguard Worker // that it is included in the standard decoder map, and that it points to the
164*d9f75844SAndroid Build Coastguard Worker // expected decoder type.
165*d9f75844SAndroid Build Coastguard Worker const auto it = codecs.find(kPayloadType);
166*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(it != codecs.end());
167*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(it->second == SdpAudioFormat("L16", 32000, 1));
168*d9f75844SAndroid Build Coastguard Worker
169*d9f75844SAndroid Build Coastguard Worker NetEqTest test(config, CreateBuiltinAudioDecoderFactory(), codecs,
170*d9f75844SAndroid Build Coastguard Worker /*text_log=*/nullptr, /*neteq_factory=*/nullptr,
171*d9f75844SAndroid Build Coastguard Worker std::move(input), std::move(output), callbacks);
172*d9f75844SAndroid Build Coastguard Worker test.Run();
173*d9f75844SAndroid Build Coastguard Worker }
174*d9f75844SAndroid Build Coastguard Worker
175*d9f75844SAndroid Build Coastguard Worker } // namespace test
176*d9f75844SAndroid Build Coastguard Worker
FuzzOneInput(const uint8_t * data,size_t size)177*d9f75844SAndroid Build Coastguard Worker void FuzzOneInput(const uint8_t* data, size_t size) {
178*d9f75844SAndroid Build Coastguard Worker if (size > 70000) {
179*d9f75844SAndroid Build Coastguard Worker return;
180*d9f75844SAndroid Build Coastguard Worker }
181*d9f75844SAndroid Build Coastguard Worker test::FuzzOneInputTest(data, size);
182*d9f75844SAndroid Build Coastguard Worker }
183*d9f75844SAndroid Build Coastguard Worker
184*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
185