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