1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2017 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 <cmath>
12*d9f75844SAndroid Build Coastguard Worker #include <limits>
13*d9f75844SAndroid Build Coastguard Worker #include <memory>
14*d9f75844SAndroid Build Coastguard Worker #include <vector>
15*d9f75844SAndroid Build Coastguard Worker
16*d9f75844SAndroid Build Coastguard Worker #include "api/array_view.h"
17*d9f75844SAndroid Build Coastguard Worker #include "api/audio_codecs/builtin_audio_decoder_factory.h"
18*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
19*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/neteq/tools/audio_checksum.h"
20*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/neteq/tools/encode_neteq_input.h"
21*d9f75844SAndroid Build Coastguard Worker #include "modules/audio_coding/neteq/tools/neteq_test.h"
22*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/numerics/safe_conversions.h"
23*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/random.h"
24*d9f75844SAndroid Build Coastguard Worker #include "test/fuzzers/fuzz_data_helper.h"
25*d9f75844SAndroid Build Coastguard Worker
26*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
27*d9f75844SAndroid Build Coastguard Worker namespace test {
28*d9f75844SAndroid Build Coastguard Worker namespace {
29*d9f75844SAndroid Build Coastguard Worker // Generate a mixture of sine wave and gaussian noise.
30*d9f75844SAndroid Build Coastguard Worker class SineAndNoiseGenerator : public EncodeNetEqInput::Generator {
31*d9f75844SAndroid Build Coastguard Worker public:
32*d9f75844SAndroid Build Coastguard Worker // The noise generator is seeded with a value from the fuzzer data, but 0 is
33*d9f75844SAndroid Build Coastguard Worker // avoided (since it is not allowed by the Random class).
SineAndNoiseGenerator(int sample_rate_hz,FuzzDataHelper * fuzz_data)34*d9f75844SAndroid Build Coastguard Worker SineAndNoiseGenerator(int sample_rate_hz, FuzzDataHelper* fuzz_data)
35*d9f75844SAndroid Build Coastguard Worker : sample_rate_hz_(sample_rate_hz),
36*d9f75844SAndroid Build Coastguard Worker fuzz_data_(*fuzz_data),
37*d9f75844SAndroid Build Coastguard Worker noise_generator_(fuzz_data_.ReadOrDefaultValueNotZero<uint64_t>(1)) {}
38*d9f75844SAndroid Build Coastguard Worker
39*d9f75844SAndroid Build Coastguard Worker // Generates num_samples of the sine-gaussian mixture.
Generate(size_t num_samples)40*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<const int16_t> Generate(size_t num_samples) override {
41*d9f75844SAndroid Build Coastguard Worker if (samples_.size() < num_samples) {
42*d9f75844SAndroid Build Coastguard Worker samples_.resize(num_samples);
43*d9f75844SAndroid Build Coastguard Worker }
44*d9f75844SAndroid Build Coastguard Worker
45*d9f75844SAndroid Build Coastguard Worker rtc::ArrayView<int16_t> output(samples_.data(), num_samples);
46*d9f75844SAndroid Build Coastguard Worker // Randomize an amplitude between 0 and 32768; use 65000/2 if we are out of
47*d9f75844SAndroid Build Coastguard Worker // fuzzer data.
48*d9f75844SAndroid Build Coastguard Worker const float amplitude = fuzz_data_.ReadOrDefaultValue<uint16_t>(65000) / 2;
49*d9f75844SAndroid Build Coastguard Worker // Randomize a noise standard deviation between 0 and 1999.
50*d9f75844SAndroid Build Coastguard Worker const float noise_std = fuzz_data_.ReadOrDefaultValue<uint16_t>(0) % 2000;
51*d9f75844SAndroid Build Coastguard Worker for (auto& x : output) {
52*d9f75844SAndroid Build Coastguard Worker x = rtc::saturated_cast<int16_t>(amplitude * std::sin(phase_) +
53*d9f75844SAndroid Build Coastguard Worker noise_generator_.Gaussian(0, noise_std));
54*d9f75844SAndroid Build Coastguard Worker phase_ += 2 * kPi * kFreqHz / sample_rate_hz_;
55*d9f75844SAndroid Build Coastguard Worker }
56*d9f75844SAndroid Build Coastguard Worker return output;
57*d9f75844SAndroid Build Coastguard Worker }
58*d9f75844SAndroid Build Coastguard Worker
59*d9f75844SAndroid Build Coastguard Worker private:
60*d9f75844SAndroid Build Coastguard Worker static constexpr int kFreqHz = 300; // The sinewave frequency.
61*d9f75844SAndroid Build Coastguard Worker const int sample_rate_hz_;
62*d9f75844SAndroid Build Coastguard Worker const double kPi = std::acos(-1);
63*d9f75844SAndroid Build Coastguard Worker std::vector<int16_t> samples_;
64*d9f75844SAndroid Build Coastguard Worker double phase_ = 0.0;
65*d9f75844SAndroid Build Coastguard Worker FuzzDataHelper& fuzz_data_;
66*d9f75844SAndroid Build Coastguard Worker Random noise_generator_;
67*d9f75844SAndroid Build Coastguard Worker };
68*d9f75844SAndroid Build Coastguard Worker
69*d9f75844SAndroid Build Coastguard Worker class FuzzSignalInput : public NetEqInput {
70*d9f75844SAndroid Build Coastguard Worker public:
FuzzSignalInput(FuzzDataHelper * fuzz_data,int sample_rate,uint8_t payload_type)71*d9f75844SAndroid Build Coastguard Worker explicit FuzzSignalInput(FuzzDataHelper* fuzz_data,
72*d9f75844SAndroid Build Coastguard Worker int sample_rate,
73*d9f75844SAndroid Build Coastguard Worker uint8_t payload_type)
74*d9f75844SAndroid Build Coastguard Worker : fuzz_data_(*fuzz_data) {
75*d9f75844SAndroid Build Coastguard Worker AudioEncoderPcm16B::Config config;
76*d9f75844SAndroid Build Coastguard Worker config.payload_type = payload_type;
77*d9f75844SAndroid Build Coastguard Worker config.sample_rate_hz = sample_rate;
78*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<AudioEncoder> encoder(new AudioEncoderPcm16B(config));
79*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EncodeNetEqInput::Generator> generator(
80*d9f75844SAndroid Build Coastguard Worker new SineAndNoiseGenerator(config.sample_rate_hz, fuzz_data));
81*d9f75844SAndroid Build Coastguard Worker input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder),
82*d9f75844SAndroid Build Coastguard Worker std::numeric_limits<int64_t>::max()));
83*d9f75844SAndroid Build Coastguard Worker packet_ = input_->PopPacket();
84*d9f75844SAndroid Build Coastguard Worker
85*d9f75844SAndroid Build Coastguard Worker // Select an output event period. This is how long time we wait between each
86*d9f75844SAndroid Build Coastguard Worker // call to NetEq::GetAudio. 10 ms is nominal, 9 and 11 ms will both lead to
87*d9f75844SAndroid Build Coastguard Worker // clock drift (in different directions).
88*d9f75844SAndroid Build Coastguard Worker constexpr int output_event_periods[] = {9, 10, 11};
89*d9f75844SAndroid Build Coastguard Worker output_event_period_ms_ = fuzz_data_.SelectOneOf(output_event_periods);
90*d9f75844SAndroid Build Coastguard Worker }
91*d9f75844SAndroid Build Coastguard Worker
NextPacketTime() const92*d9f75844SAndroid Build Coastguard Worker absl::optional<int64_t> NextPacketTime() const override {
93*d9f75844SAndroid Build Coastguard Worker return packet_->time_ms;
94*d9f75844SAndroid Build Coastguard Worker }
95*d9f75844SAndroid Build Coastguard Worker
NextOutputEventTime() const96*d9f75844SAndroid Build Coastguard Worker absl::optional<int64_t> NextOutputEventTime() const override {
97*d9f75844SAndroid Build Coastguard Worker return next_output_event_ms_;
98*d9f75844SAndroid Build Coastguard Worker }
99*d9f75844SAndroid Build Coastguard Worker
PopPacket()100*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<PacketData> PopPacket() override {
101*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(packet_);
102*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<PacketData> packet_to_return = std::move(packet_);
103*d9f75844SAndroid Build Coastguard Worker do {
104*d9f75844SAndroid Build Coastguard Worker packet_ = input_->PopPacket();
105*d9f75844SAndroid Build Coastguard Worker // If the next value from the fuzzer input is 0, the packet is discarded
106*d9f75844SAndroid Build Coastguard Worker // and the next one is pulled from the source.
107*d9f75844SAndroid Build Coastguard Worker } while (fuzz_data_.CanReadBytes(1) && fuzz_data_.Read<uint8_t>() == 0);
108*d9f75844SAndroid Build Coastguard Worker if (fuzz_data_.CanReadBytes(1)) {
109*d9f75844SAndroid Build Coastguard Worker // Generate jitter by setting an offset for the arrival time.
110*d9f75844SAndroid Build Coastguard Worker const int8_t arrival_time_offset_ms = fuzz_data_.Read<int8_t>();
111*d9f75844SAndroid Build Coastguard Worker // The arrival time can not be before the previous packets.
112*d9f75844SAndroid Build Coastguard Worker packet_->time_ms = std::max(packet_to_return->time_ms,
113*d9f75844SAndroid Build Coastguard Worker packet_->time_ms + arrival_time_offset_ms);
114*d9f75844SAndroid Build Coastguard Worker } else {
115*d9f75844SAndroid Build Coastguard Worker // Mark that we are at the end of the test. However, the current packet is
116*d9f75844SAndroid Build Coastguard Worker // still valid (but it may not have been fuzzed as expected).
117*d9f75844SAndroid Build Coastguard Worker ended_ = true;
118*d9f75844SAndroid Build Coastguard Worker }
119*d9f75844SAndroid Build Coastguard Worker return packet_to_return;
120*d9f75844SAndroid Build Coastguard Worker }
121*d9f75844SAndroid Build Coastguard Worker
AdvanceOutputEvent()122*d9f75844SAndroid Build Coastguard Worker void AdvanceOutputEvent() override {
123*d9f75844SAndroid Build Coastguard Worker next_output_event_ms_ += output_event_period_ms_;
124*d9f75844SAndroid Build Coastguard Worker }
125*d9f75844SAndroid Build Coastguard Worker
ended() const126*d9f75844SAndroid Build Coastguard Worker bool ended() const override { return ended_; }
127*d9f75844SAndroid Build Coastguard Worker
NextHeader() const128*d9f75844SAndroid Build Coastguard Worker absl::optional<RTPHeader> NextHeader() const override {
129*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(packet_);
130*d9f75844SAndroid Build Coastguard Worker return packet_->header;
131*d9f75844SAndroid Build Coastguard Worker }
132*d9f75844SAndroid Build Coastguard Worker
133*d9f75844SAndroid Build Coastguard Worker private:
134*d9f75844SAndroid Build Coastguard Worker bool ended_ = false;
135*d9f75844SAndroid Build Coastguard Worker FuzzDataHelper& fuzz_data_;
136*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EncodeNetEqInput> input_;
137*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<PacketData> packet_;
138*d9f75844SAndroid Build Coastguard Worker int64_t next_output_event_ms_ = 0;
139*d9f75844SAndroid Build Coastguard Worker int64_t output_event_period_ms_ = 10;
140*d9f75844SAndroid Build Coastguard Worker };
141*d9f75844SAndroid Build Coastguard Worker
142*d9f75844SAndroid Build Coastguard Worker template <class T>
MapHas(const std::map<int,T> & m,int key,const T & value)143*d9f75844SAndroid Build Coastguard Worker bool MapHas(const std::map<int, T>& m, int key, const T& value) {
144*d9f75844SAndroid Build Coastguard Worker const auto it = m.find(key);
145*d9f75844SAndroid Build Coastguard Worker return (it != m.end() && it->second == value);
146*d9f75844SAndroid Build Coastguard Worker }
147*d9f75844SAndroid Build Coastguard Worker
148*d9f75844SAndroid Build Coastguard Worker } // namespace
149*d9f75844SAndroid Build Coastguard Worker
FuzzOneInputTest(const uint8_t * data,size_t size)150*d9f75844SAndroid Build Coastguard Worker void FuzzOneInputTest(const uint8_t* data, size_t size) {
151*d9f75844SAndroid Build Coastguard Worker if (size < 1 || size > 65000) {
152*d9f75844SAndroid Build Coastguard Worker return;
153*d9f75844SAndroid Build Coastguard Worker }
154*d9f75844SAndroid Build Coastguard Worker
155*d9f75844SAndroid Build Coastguard Worker FuzzDataHelper fuzz_data(rtc::ArrayView<const uint8_t>(data, size));
156*d9f75844SAndroid Build Coastguard Worker
157*d9f75844SAndroid Build Coastguard Worker // Allowed sample rates and payload types used in the test.
158*d9f75844SAndroid Build Coastguard Worker std::pair<int, uint8_t> rate_types[] = {
159*d9f75844SAndroid Build Coastguard Worker {8000, 93}, {16000, 94}, {32000, 95}, {48000, 96}};
160*d9f75844SAndroid Build Coastguard Worker const auto rate_type = fuzz_data.SelectOneOf(rate_types);
161*d9f75844SAndroid Build Coastguard Worker const int sample_rate = rate_type.first;
162*d9f75844SAndroid Build Coastguard Worker const uint8_t payload_type = rate_type.second;
163*d9f75844SAndroid Build Coastguard Worker
164*d9f75844SAndroid Build Coastguard Worker // Set up the input signal generator.
165*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<FuzzSignalInput> input(
166*d9f75844SAndroid Build Coastguard Worker new FuzzSignalInput(&fuzz_data, sample_rate, payload_type));
167*d9f75844SAndroid Build Coastguard Worker
168*d9f75844SAndroid Build Coastguard Worker // Output sink for the test.
169*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<AudioChecksum> output(new AudioChecksum);
170*d9f75844SAndroid Build Coastguard Worker
171*d9f75844SAndroid Build Coastguard Worker // Configure NetEq and the NetEqTest object.
172*d9f75844SAndroid Build Coastguard Worker NetEqTest::Callbacks callbacks;
173*d9f75844SAndroid Build Coastguard Worker NetEq::Config config;
174*d9f75844SAndroid Build Coastguard Worker config.enable_post_decode_vad = true;
175*d9f75844SAndroid Build Coastguard Worker config.enable_fast_accelerate = true;
176*d9f75844SAndroid Build Coastguard Worker auto codecs = NetEqTest::StandardDecoderMap();
177*d9f75844SAndroid Build Coastguard Worker // rate_types contains the payload types that will be used for encoding.
178*d9f75844SAndroid Build Coastguard Worker // Verify that they all are included in the standard decoder map, and that
179*d9f75844SAndroid Build Coastguard Worker // they point to the expected decoder types.
180*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(
181*d9f75844SAndroid Build Coastguard Worker MapHas(codecs, rate_types[0].second, SdpAudioFormat("l16", 8000, 1)));
182*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(
183*d9f75844SAndroid Build Coastguard Worker MapHas(codecs, rate_types[1].second, SdpAudioFormat("l16", 16000, 1)));
184*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(
185*d9f75844SAndroid Build Coastguard Worker MapHas(codecs, rate_types[2].second, SdpAudioFormat("l16", 32000, 1)));
186*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(
187*d9f75844SAndroid Build Coastguard Worker MapHas(codecs, rate_types[3].second, SdpAudioFormat("l16", 48000, 1)));
188*d9f75844SAndroid Build Coastguard Worker
189*d9f75844SAndroid Build Coastguard Worker NetEqTest test(config, CreateBuiltinAudioDecoderFactory(), codecs,
190*d9f75844SAndroid Build Coastguard Worker /*text_log=*/nullptr, /*neteq_factory=*/nullptr,
191*d9f75844SAndroid Build Coastguard Worker std::move(input), std::move(output), callbacks);
192*d9f75844SAndroid Build Coastguard Worker test.Run();
193*d9f75844SAndroid Build Coastguard Worker }
194*d9f75844SAndroid Build Coastguard Worker
195*d9f75844SAndroid Build Coastguard Worker } // namespace test
196*d9f75844SAndroid Build Coastguard Worker
FuzzOneInput(const uint8_t * data,size_t size)197*d9f75844SAndroid Build Coastguard Worker void FuzzOneInput(const uint8_t* data, size_t size) {
198*d9f75844SAndroid Build Coastguard Worker test::FuzzOneInputTest(data, size);
199*d9f75844SAndroid Build Coastguard Worker }
200*d9f75844SAndroid Build Coastguard Worker
201*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
202