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