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