1 /*
2 * Copyright (c) 2019 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 "test/fuzzers/utils/rtp_replayer.h"
12
13 #include <algorithm>
14 #include <memory>
15 #include <string>
16 #include <utility>
17
18 #include "absl/memory/memory.h"
19 #include "api/task_queue/default_task_queue_factory.h"
20 #include "api/transport/field_trial_based_config.h"
21 #include "modules/rtp_rtcp/source/rtp_packet.h"
22 #include "rtc_base/strings/json.h"
23 #include "system_wrappers/include/clock.h"
24 #include "test/call_config_utils.h"
25 #include "test/encoder_settings.h"
26 #include "test/fake_decoder.h"
27 #include "test/rtp_file_reader.h"
28 #include "test/run_loop.h"
29
30 namespace webrtc {
31 namespace test {
32
Replay(const std::string & replay_config_filepath,const uint8_t * rtp_dump_data,size_t rtp_dump_size)33 void RtpReplayer::Replay(const std::string& replay_config_filepath,
34 const uint8_t* rtp_dump_data,
35 size_t rtp_dump_size) {
36 auto stream_state = std::make_unique<StreamState>();
37 std::vector<VideoReceiveStreamInterface::Config> receive_stream_configs =
38 ReadConfigFromFile(replay_config_filepath, &(stream_state->transport));
39 return Replay(std::move(stream_state), std::move(receive_stream_configs),
40 rtp_dump_data, rtp_dump_size);
41 }
42
Replay(std::unique_ptr<StreamState> stream_state,std::vector<VideoReceiveStreamInterface::Config> receive_stream_configs,const uint8_t * rtp_dump_data,size_t rtp_dump_size)43 void RtpReplayer::Replay(
44 std::unique_ptr<StreamState> stream_state,
45 std::vector<VideoReceiveStreamInterface::Config> receive_stream_configs,
46 const uint8_t* rtp_dump_data,
47 size_t rtp_dump_size) {
48 RunLoop loop;
49 rtc::ScopedBaseFakeClock fake_clock;
50
51 // Work around: webrtc calls webrtc::Random(clock.TimeInMicroseconds())
52 // everywhere and Random expects non-zero seed. Let's set the clock non-zero
53 // to make them happy.
54 fake_clock.SetTime(webrtc::Timestamp::Millis(1));
55
56 // Attempt to create an RtpReader from the input file.
57 auto rtp_reader = CreateRtpReader(rtp_dump_data, rtp_dump_size);
58 if (rtp_reader == nullptr) {
59 RTC_LOG(LS_ERROR) << "Failed to create the rtp_reader";
60 return;
61 }
62
63 // Setup the video streams based on the configuration.
64 webrtc::RtcEventLogNull event_log;
65 std::unique_ptr<TaskQueueFactory> task_queue_factory =
66 CreateDefaultTaskQueueFactory();
67 Call::Config call_config(&event_log);
68 call_config.task_queue_factory = task_queue_factory.get();
69 FieldTrialBasedConfig field_trials;
70 call_config.trials = &field_trials;
71 std::unique_ptr<Call> call(Call::Create(call_config));
72 SetupVideoStreams(&receive_stream_configs, stream_state.get(), call.get());
73
74 // Start replaying the provided stream now that it has been configured.
75 for (const auto& receive_stream : stream_state->receive_streams) {
76 receive_stream->Start();
77 }
78
79 ReplayPackets(&fake_clock, call.get(), rtp_reader.get());
80
81 for (const auto& receive_stream : stream_state->receive_streams) {
82 call->DestroyVideoReceiveStream(receive_stream);
83 }
84 }
85
86 std::vector<VideoReceiveStreamInterface::Config>
ReadConfigFromFile(const std::string & replay_config,Transport * transport)87 RtpReplayer::ReadConfigFromFile(const std::string& replay_config,
88 Transport* transport) {
89 Json::CharReaderBuilder factory;
90 std::unique_ptr<Json::CharReader> json_reader =
91 absl::WrapUnique(factory.newCharReader());
92 Json::Value json_configs;
93 Json::String errors;
94 if (!json_reader->parse(replay_config.data(),
95 replay_config.data() + replay_config.length(),
96 &json_configs, &errors)) {
97 RTC_LOG(LS_ERROR)
98 << "Error parsing JSON replay configuration for the fuzzer: " << errors;
99 return {};
100 }
101
102 std::vector<VideoReceiveStreamInterface::Config> receive_stream_configs;
103 receive_stream_configs.reserve(json_configs.size());
104 for (const auto& json : json_configs) {
105 receive_stream_configs.push_back(
106 ParseVideoReceiveStreamJsonConfig(transport, json));
107 }
108 return receive_stream_configs;
109 }
110
SetupVideoStreams(std::vector<VideoReceiveStreamInterface::Config> * receive_stream_configs,StreamState * stream_state,Call * call)111 void RtpReplayer::SetupVideoStreams(
112 std::vector<VideoReceiveStreamInterface::Config>* receive_stream_configs,
113 StreamState* stream_state,
114 Call* call) {
115 stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
116 for (auto& receive_config : *receive_stream_configs) {
117 // Attach the decoder for the corresponding payload type in the config.
118 for (auto& decoder : receive_config.decoders) {
119 decoder = test::CreateMatchingDecoder(decoder.payload_type,
120 decoder.video_format.name);
121 }
122
123 // Create the window to display the rendered video.
124 stream_state->sinks.emplace_back(
125 test::VideoRenderer::Create("Fuzzing WebRTC Video Config", 640, 480));
126 // Create a receive stream for this config.
127 receive_config.renderer = stream_state->sinks.back().get();
128 receive_config.decoder_factory = stream_state->decoder_factory.get();
129 stream_state->receive_streams.emplace_back(
130 call->CreateVideoReceiveStream(std::move(receive_config)));
131 }
132 }
133
CreateRtpReader(const uint8_t * rtp_dump_data,size_t rtp_dump_size)134 std::unique_ptr<test::RtpFileReader> RtpReplayer::CreateRtpReader(
135 const uint8_t* rtp_dump_data,
136 size_t rtp_dump_size) {
137 std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
138 test::RtpFileReader::kRtpDump, rtp_dump_data, rtp_dump_size, {}));
139 if (!rtp_reader) {
140 RTC_LOG(LS_ERROR) << "Unable to open input file with any supported format";
141 return nullptr;
142 }
143 return rtp_reader;
144 }
145
ReplayPackets(rtc::FakeClock * clock,Call * call,test::RtpFileReader * rtp_reader)146 void RtpReplayer::ReplayPackets(rtc::FakeClock* clock,
147 Call* call,
148 test::RtpFileReader* rtp_reader) {
149 int64_t replay_start_ms = -1;
150 int num_packets = 0;
151 std::map<uint32_t, int> unknown_packets;
152
153 while (true) {
154 int64_t now_ms = rtc::TimeMillis();
155 if (replay_start_ms == -1) {
156 replay_start_ms = now_ms;
157 }
158
159 test::RtpPacket packet;
160 if (!rtp_reader->NextPacket(&packet)) {
161 break;
162 }
163
164 int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
165 if (deliver_in_ms > 0) {
166 // StatsCounter::ReportMetricToAggregatedCounter is O(elapsed time).
167 // Set an upper limit to prevent waste time.
168 clock->AdvanceTime(webrtc::TimeDelta::Millis(
169 std::min(deliver_in_ms, static_cast<int64_t>(100))));
170 }
171
172 rtc::CopyOnWriteBuffer packet_buffer(packet.data, packet.length);
173 ++num_packets;
174 switch (call->Receiver()->DeliverPacket(webrtc::MediaType::VIDEO,
175 packet_buffer,
176 /* packet_time_us */ -1)) {
177 case PacketReceiver::DELIVERY_OK:
178 break;
179 case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
180 webrtc::RtpPacket header;
181 header.Parse(packet_buffer);
182 if (unknown_packets[header.Ssrc()] == 0) {
183 RTC_LOG(LS_ERROR) << "Unknown SSRC: " << header.Ssrc();
184 }
185 ++unknown_packets[header.Ssrc()];
186 break;
187 }
188 case PacketReceiver::DELIVERY_PACKET_ERROR: {
189 RTC_LOG(LS_ERROR)
190 << "Packet error, corrupt packets or incorrect setup?";
191 webrtc::RtpPacket header;
192 header.Parse(packet_buffer);
193 RTC_LOG(LS_ERROR) << "Packet packet_length=" << packet.length
194 << " payload_type=" << header.PayloadType()
195 << " sequence_number=" << header.SequenceNumber()
196 << " time_stamp=" << header.Timestamp()
197 << " ssrc=" << header.Ssrc();
198 break;
199 }
200 }
201 }
202 RTC_LOG(LS_INFO) << "num_packets: " << num_packets;
203
204 for (const auto& unknown_packet : unknown_packets) {
205 RTC_LOG(LS_ERROR) << "Packets for unknown ssrc " << unknown_packet.first
206 << ":" << unknown_packet.second;
207 }
208 }
209
210 } // namespace test
211 } // namespace webrtc
212