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 <cmath>
12 #include <memory>
13 #include <vector>
14
15 #include "api/array_view.h"
16 #include "api/audio_codecs/builtin_audio_decoder_factory.h"
17 #include "modules/audio_coding/codecs/pcm16b/audio_encoder_pcm16b.h"
18 #include "modules/audio_coding/neteq/tools/audio_checksum.h"
19 #include "modules/audio_coding/neteq/tools/encode_neteq_input.h"
20 #include "modules/audio_coding/neteq/tools/neteq_test.h"
21 #include "modules/rtp_rtcp/source/byte_io.h"
22
23 namespace webrtc {
24 namespace test {
25 namespace {
26 constexpr int kPayloadType = 95;
27
28 class SineGenerator : public EncodeNetEqInput::Generator {
29 public:
SineGenerator(int sample_rate_hz)30 explicit SineGenerator(int sample_rate_hz)
31 : sample_rate_hz_(sample_rate_hz) {}
32
Generate(size_t num_samples)33 rtc::ArrayView<const int16_t> Generate(size_t num_samples) override {
34 if (samples_.size() < num_samples) {
35 samples_.resize(num_samples);
36 }
37
38 rtc::ArrayView<int16_t> output(samples_.data(), num_samples);
39 for (auto& x : output) {
40 x = static_cast<int16_t>(2000.0 * std::sin(phase_));
41 phase_ += 2 * kPi * kFreqHz / sample_rate_hz_;
42 }
43 return output;
44 }
45
46 private:
47 static constexpr int kFreqHz = 300; // The sinewave frequency.
48 const int sample_rate_hz_;
49 const double kPi = std::acos(-1);
50 std::vector<int16_t> samples_;
51 double phase_ = 0.0;
52 };
53
54 class FuzzRtpInput : public NetEqInput {
55 public:
FuzzRtpInput(rtc::ArrayView<const uint8_t> data)56 explicit FuzzRtpInput(rtc::ArrayView<const uint8_t> data) : data_(data) {
57 AudioEncoderPcm16B::Config config;
58 config.payload_type = kPayloadType;
59 config.sample_rate_hz = 32000;
60 std::unique_ptr<AudioEncoder> encoder(new AudioEncoderPcm16B(config));
61 std::unique_ptr<EncodeNetEqInput::Generator> generator(
62 new SineGenerator(config.sample_rate_hz));
63 input_.reset(new EncodeNetEqInput(std::move(generator), std::move(encoder),
64 std::numeric_limits<int64_t>::max()));
65 packet_ = input_->PopPacket();
66 FuzzHeader();
67 }
68
NextPacketTime() const69 absl::optional<int64_t> NextPacketTime() const override {
70 return packet_->time_ms;
71 }
72
NextOutputEventTime() const73 absl::optional<int64_t> NextOutputEventTime() const override {
74 return input_->NextOutputEventTime();
75 }
76
PopPacket()77 std::unique_ptr<PacketData> PopPacket() override {
78 RTC_DCHECK(packet_);
79 std::unique_ptr<PacketData> packet_to_return = std::move(packet_);
80 packet_ = input_->PopPacket();
81 FuzzHeader();
82 return packet_to_return;
83 }
84
AdvanceOutputEvent()85 void AdvanceOutputEvent() override { return input_->AdvanceOutputEvent(); }
86
ended() const87 bool ended() const override { return ended_; }
88
NextHeader() const89 absl::optional<RTPHeader> NextHeader() const override {
90 RTC_DCHECK(packet_);
91 return packet_->header;
92 }
93
94 private:
FuzzHeader()95 void FuzzHeader() {
96 constexpr size_t kNumBytesToFuzz = 11;
97 if (data_ix_ + kNumBytesToFuzz > data_.size()) {
98 ended_ = true;
99 return;
100 }
101 RTC_DCHECK(packet_);
102 const size_t start_ix = data_ix_;
103 packet_->header.payloadType =
104 ByteReader<uint8_t>::ReadLittleEndian(&data_[data_ix_]);
105 packet_->header.payloadType &= 0x7F;
106 data_ix_ += sizeof(uint8_t);
107 packet_->header.sequenceNumber =
108 ByteReader<uint16_t>::ReadLittleEndian(&data_[data_ix_]);
109 data_ix_ += sizeof(uint16_t);
110 packet_->header.timestamp =
111 ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
112 data_ix_ += sizeof(uint32_t);
113 packet_->header.ssrc =
114 ByteReader<uint32_t>::ReadLittleEndian(&data_[data_ix_]);
115 data_ix_ += sizeof(uint32_t);
116 RTC_CHECK_EQ(data_ix_ - start_ix, kNumBytesToFuzz);
117 }
118
119 bool ended_ = false;
120 rtc::ArrayView<const uint8_t> data_;
121 size_t data_ix_ = 0;
122 std::unique_ptr<EncodeNetEqInput> input_;
123 std::unique_ptr<PacketData> packet_;
124 };
125 } // namespace
126
FuzzOneInputTest(const uint8_t * data,size_t size)127 void FuzzOneInputTest(const uint8_t* data, size_t size) {
128 std::unique_ptr<FuzzRtpInput> input(
129 new FuzzRtpInput(rtc::ArrayView<const uint8_t>(data, size)));
130 std::unique_ptr<AudioChecksum> output(new AudioChecksum);
131 NetEqTest::Callbacks callbacks;
132 NetEq::Config config;
133 auto codecs = NetEqTest::StandardDecoderMap();
134 // kPayloadType is the payload type that will be used for encoding. Verify
135 // that it is included in the standard decoder map, and that it points to the
136 // expected decoder type.
137 const auto it = codecs.find(kPayloadType);
138 RTC_CHECK(it != codecs.end());
139 RTC_CHECK(it->second == SdpAudioFormat("L16", 32000, 1));
140
141 NetEqTest test(config, CreateBuiltinAudioDecoderFactory(), codecs,
142 /*text_log=*/nullptr, /*neteq_factory=*/nullptr,
143 std::move(input), std::move(output), callbacks);
144 test.Run();
145 }
146
147 } // namespace test
148
FuzzOneInput(const uint8_t * data,size_t size)149 void FuzzOneInput(const uint8_t* data, size_t size) {
150 if (size > 70000) {
151 return;
152 }
153 test::FuzzOneInputTest(data, size);
154 }
155
156 } // namespace webrtc
157