1 /*
2 * Copyright (c) 2014 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 <stdio.h>
12
13 #include <fstream>
14 #include <map>
15 #include <memory>
16
17 #include "absl/flags/flag.h"
18 #include "absl/flags/parse.h"
19 #include "api/field_trials.h"
20 #include "api/rtc_event_log/rtc_event_log.h"
21 #include "api/task_queue/default_task_queue_factory.h"
22 #include "api/test/video/function_video_decoder_factory.h"
23 #include "api/transport/field_trial_based_config.h"
24 #include "api/video/video_codec_type.h"
25 #include "api/video_codecs/video_decoder.h"
26 #include "call/call.h"
27 #include "common_video/libyuv/include/webrtc_libyuv.h"
28 #include "media/engine/internal_decoder_factory.h"
29 #include "modules/rtp_rtcp/source/rtp_packet.h"
30 #include "modules/rtp_rtcp/source/rtp_util.h"
31 #include "modules/video_coding/utility/ivf_file_writer.h"
32 #include "rtc_base/checks.h"
33 #include "rtc_base/string_to_number.h"
34 #include "rtc_base/strings/json.h"
35 #include "rtc_base/time_utils.h"
36 #include "system_wrappers/include/clock.h"
37 #include "system_wrappers/include/sleep.h"
38 #include "test/call_config_utils.h"
39 #include "test/call_test.h"
40 #include "test/encoder_settings.h"
41 #include "test/fake_decoder.h"
42 #include "test/gtest.h"
43 #include "test/null_transport.h"
44 #include "test/rtp_file_reader.h"
45 #include "test/run_loop.h"
46 #include "test/run_test.h"
47 #include "test/test_video_capturer.h"
48 #include "test/testsupport/frame_writer.h"
49 #include "test/time_controller/simulated_time_controller.h"
50 #include "test/video_renderer.h"
51
52 // Flag for payload type.
53 ABSL_FLAG(int,
54 media_payload_type,
55 webrtc::test::CallTest::kPayloadTypeVP8,
56 "Media payload type");
57
58 // Flag for RED payload type.
59 ABSL_FLAG(int,
60 red_payload_type,
61 webrtc::test::CallTest::kRedPayloadType,
62 "RED payload type");
63
64 // Flag for ULPFEC payload type.
65 ABSL_FLAG(int,
66 ulpfec_payload_type,
67 webrtc::test::CallTest::kUlpfecPayloadType,
68 "ULPFEC payload type");
69
70 // Flag for FLEXFEC payload type.
71 ABSL_FLAG(int,
72 flexfec_payload_type,
73 webrtc::test::CallTest::kFlexfecPayloadType,
74 "FLEXFEC payload type");
75
76 ABSL_FLAG(int,
77 media_payload_type_rtx,
78 webrtc::test::CallTest::kSendRtxPayloadType,
79 "Media over RTX payload type");
80
81 ABSL_FLAG(int,
82 red_payload_type_rtx,
83 webrtc::test::CallTest::kRtxRedPayloadType,
84 "RED over RTX payload type");
85
86 // Flag for SSRC and RTX SSRC.
87 ABSL_FLAG(uint32_t,
88 ssrc,
89 webrtc::test::CallTest::kVideoSendSsrcs[0],
90 "Incoming SSRC");
91 ABSL_FLAG(uint32_t,
92 ssrc_rtx,
93 webrtc::test::CallTest::kSendRtxSsrcs[0],
94 "Incoming RTX SSRC");
95
96 ABSL_FLAG(uint32_t,
97 ssrc_flexfec,
98 webrtc::test::CallTest::kFlexfecSendSsrc,
99 "Incoming FLEXFEC SSRC");
100
101 // Flag for abs-send-time id.
102 ABSL_FLAG(int, abs_send_time_id, -1, "RTP extension ID for abs-send-time");
103
104 // Flag for transmission-offset id.
105 ABSL_FLAG(int,
106 transmission_offset_id,
107 -1,
108 "RTP extension ID for transmission-offset");
109
110 // Flag for rtpdump input file.
111 ABSL_FLAG(std::string, input_file, "", "input file");
112
113 ABSL_FLAG(std::string, config_file, "", "config file");
114
115 // Flag for raw output files.
116 ABSL_FLAG(std::string,
117 out_base,
118 "",
119 "Basename (excluding .jpg) for raw output");
120
121 ABSL_FLAG(std::string,
122 decoder_bitstream_filename,
123 "",
124 "Decoder bitstream output file");
125
126 ABSL_FLAG(std::string, decoder_ivf_filename, "", "Decoder ivf output file");
127
128 // Flag for video codec.
129 ABSL_FLAG(std::string, codec, "VP8", "Video codec");
130
131 // Flags for rtp start and stop timestamp.
132 ABSL_FLAG(uint32_t,
133 start_timestamp,
134 0,
135 "RTP start timestamp, packets with smaller timestamp will be ignored "
136 "(no wraparound)");
137 ABSL_FLAG(uint32_t,
138 stop_timestamp,
139 4294967295,
140 "RTP stop timestamp, packets with larger timestamp will be ignored "
141 "(no wraparound)");
142
143 // Flags for render window width and height
144 ABSL_FLAG(uint32_t, render_width, 640, "Width of render window");
145 ABSL_FLAG(uint32_t, render_height, 480, "Height of render window");
146
147 ABSL_FLAG(
148 std::string,
149 force_fieldtrials,
150 "",
151 "Field trials control experimental feature code which can be forced. "
152 "E.g. running with --force_fieldtrials=WebRTC-FooFeature/Enabled/"
153 " will assign the group Enable to field trial WebRTC-FooFeature. Multiple "
154 "trials are separated by \"/\"");
155
156 ABSL_FLAG(bool, simulated_time, false, "Run in simulated time");
157
158 ABSL_FLAG(bool, disable_preview, false, "Disable decoded video preview.");
159
160 ABSL_FLAG(bool, disable_decoding, false, "Disable video decoding.");
161
162 ABSL_FLAG(int,
163 extend_run_time_duration,
164 0,
165 "Extends the run time of the receiving client after the last RTP "
166 "packet has been delivered. Typically useful to let the last few "
167 "frames be decoded and rendered. Duration given in seconds.");
168
169 namespace {
ValidatePayloadType(int32_t payload_type)170 bool ValidatePayloadType(int32_t payload_type) {
171 return payload_type > 0 && payload_type <= 127;
172 }
173
ValidateOptionalPayloadType(int32_t payload_type)174 bool ValidateOptionalPayloadType(int32_t payload_type) {
175 return payload_type == -1 || ValidatePayloadType(payload_type);
176 }
177
ValidateRtpHeaderExtensionId(int32_t extension_id)178 bool ValidateRtpHeaderExtensionId(int32_t extension_id) {
179 return extension_id >= -1 && extension_id < 15;
180 }
181
ValidateInputFilenameNotEmpty(const std::string & string)182 bool ValidateInputFilenameNotEmpty(const std::string& string) {
183 return !string.empty();
184 }
185 } // namespace
186
187 namespace webrtc {
188 namespace {
189
190 const uint32_t kReceiverLocalSsrc = 0x123456;
191
192 class NullRenderer : public rtc::VideoSinkInterface<VideoFrame> {
193 public:
OnFrame(const VideoFrame & frame)194 void OnFrame(const VideoFrame& frame) override {}
195 };
196
197 class FileRenderPassthrough : public rtc::VideoSinkInterface<VideoFrame> {
198 public:
FileRenderPassthrough(const std::string & basename,rtc::VideoSinkInterface<VideoFrame> * renderer)199 FileRenderPassthrough(const std::string& basename,
200 rtc::VideoSinkInterface<VideoFrame>* renderer)
201 : basename_(basename), renderer_(renderer), file_(nullptr), count_(0) {}
202
~FileRenderPassthrough()203 ~FileRenderPassthrough() override {
204 if (file_)
205 fclose(file_);
206 }
207
208 private:
OnFrame(const VideoFrame & video_frame)209 void OnFrame(const VideoFrame& video_frame) override {
210 if (renderer_)
211 renderer_->OnFrame(video_frame);
212
213 if (basename_.empty())
214 return;
215
216 std::stringstream filename;
217 filename << basename_ << count_++ << "_" << video_frame.timestamp()
218 << ".jpg";
219
220 test::JpegFrameWriter frame_writer(filename.str());
221 RTC_CHECK(frame_writer.WriteFrame(video_frame, 100));
222 }
223
224 const std::string basename_;
225 rtc::VideoSinkInterface<VideoFrame>* const renderer_;
226 FILE* file_;
227 size_t count_;
228 };
229
230 class DecoderBitstreamFileWriter : public test::FakeDecoder {
231 public:
DecoderBitstreamFileWriter(const char * filename)232 explicit DecoderBitstreamFileWriter(const char* filename)
233 : file_(fopen(filename, "wb")) {
234 RTC_DCHECK(file_);
235 }
~DecoderBitstreamFileWriter()236 ~DecoderBitstreamFileWriter() override { fclose(file_); }
237
Decode(const EncodedImage & encoded_frame,bool,int64_t)238 int32_t Decode(const EncodedImage& encoded_frame,
239 bool /* missing_frames */,
240 int64_t /* render_time_ms */) override {
241 if (fwrite(encoded_frame.data(), 1, encoded_frame.size(), file_) <
242 encoded_frame.size()) {
243 RTC_LOG_ERR(LS_ERROR) << "fwrite of encoded frame failed.";
244 return WEBRTC_VIDEO_CODEC_ERROR;
245 }
246 return WEBRTC_VIDEO_CODEC_OK;
247 }
248
249 private:
250 FILE* file_;
251 };
252
253 class DecoderIvfFileWriter : public test::FakeDecoder {
254 public:
DecoderIvfFileWriter(const char * filename,const std::string & codec)255 explicit DecoderIvfFileWriter(const char* filename, const std::string& codec)
256 : file_writer_(
257 IvfFileWriter::Wrap(FileWrapper::OpenWriteOnly(filename), 0)) {
258 RTC_DCHECK(file_writer_.get());
259 if (codec == "VP8") {
260 video_codec_type_ = VideoCodecType::kVideoCodecVP8;
261 } else if (codec == "VP9") {
262 video_codec_type_ = VideoCodecType::kVideoCodecVP9;
263 } else if (codec == "H264") {
264 video_codec_type_ = VideoCodecType::kVideoCodecH264;
265 } else if (codec == "AV1") {
266 video_codec_type_ = VideoCodecType::kVideoCodecAV1;
267 } else {
268 RTC_LOG(LS_ERROR) << "Unsupported video codec " << codec;
269 RTC_DCHECK_NOTREACHED();
270 }
271 }
~DecoderIvfFileWriter()272 ~DecoderIvfFileWriter() override { file_writer_->Close(); }
273
Decode(const EncodedImage & encoded_frame,bool,int64_t render_time_ms)274 int32_t Decode(const EncodedImage& encoded_frame,
275 bool /* missing_frames */,
276 int64_t render_time_ms) override {
277 if (!file_writer_->WriteFrame(encoded_frame, video_codec_type_)) {
278 return WEBRTC_VIDEO_CODEC_ERROR;
279 }
280 return WEBRTC_VIDEO_CODEC_OK;
281 }
282
283 private:
284 std::unique_ptr<IvfFileWriter> file_writer_;
285 VideoCodecType video_codec_type_;
286 };
287
288 // Holds all the shared memory structures required for a receive stream. This
289 // structure is used to prevent members being deallocated before the replay
290 // has been finished.
291 struct StreamState {
292 test::NullTransport transport;
293 std::vector<std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>>> sinks;
294 std::vector<VideoReceiveStreamInterface*> receive_streams;
295 std::vector<FlexfecReceiveStream*> flexfec_streams;
296 std::unique_ptr<VideoDecoderFactory> decoder_factory;
297 };
298
299 // Loads multiple configurations from the provided configuration file.
ConfigureFromFile(const std::string & config_path,Call * call)300 std::unique_ptr<StreamState> ConfigureFromFile(const std::string& config_path,
301 Call* call) {
302 auto stream_state = std::make_unique<StreamState>();
303 // Parse the configuration file.
304 std::ifstream config_file(config_path);
305 std::stringstream raw_json_buffer;
306 raw_json_buffer << config_file.rdbuf();
307 std::string raw_json = raw_json_buffer.str();
308 Json::CharReaderBuilder builder;
309 Json::Value json_configs;
310 std::string error_message;
311 std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
312 if (!json_reader->parse(raw_json.data(), raw_json.data() + raw_json.size(),
313 &json_configs, &error_message)) {
314 fprintf(stderr, "Error parsing JSON config\n");
315 fprintf(stderr, "%s\n", error_message.c_str());
316 return nullptr;
317 }
318
319 if (absl::GetFlag(FLAGS_disable_decoding)) {
320 stream_state->decoder_factory =
321 std::make_unique<test::FunctionVideoDecoderFactory>(
322 []() { return std::make_unique<test::FakeDecoder>(); });
323 } else {
324 stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
325 }
326 size_t config_count = 0;
327 for (const auto& json : json_configs) {
328 // Create the configuration and parse the JSON into the config.
329 auto receive_config =
330 ParseVideoReceiveStreamJsonConfig(&(stream_state->transport), json);
331 // Instantiate the underlying decoder.
332 for (auto& decoder : receive_config.decoders) {
333 decoder = test::CreateMatchingDecoder(decoder.payload_type,
334 decoder.video_format.name);
335 }
336 // Create a window for this config.
337 std::stringstream window_title;
338 window_title << "Playback Video (" << config_count++ << ")";
339 if (absl::GetFlag(FLAGS_disable_preview)) {
340 stream_state->sinks.emplace_back(std::make_unique<NullRenderer>());
341 } else {
342 stream_state->sinks.emplace_back(test::VideoRenderer::Create(
343 window_title.str().c_str(), absl::GetFlag(FLAGS_render_width),
344 absl::GetFlag(FLAGS_render_height)));
345 }
346 // Create a receive stream for this config.
347 receive_config.renderer = stream_state->sinks.back().get();
348 receive_config.decoder_factory = stream_state->decoder_factory.get();
349 stream_state->receive_streams.emplace_back(
350 call->CreateVideoReceiveStream(std::move(receive_config)));
351 }
352 return stream_state;
353 }
354
355 // Loads the base configuration from flags passed in on the commandline.
ConfigureFromFlags(const std::string & rtp_dump_path,Call * call)356 std::unique_ptr<StreamState> ConfigureFromFlags(
357 const std::string& rtp_dump_path,
358 Call* call) {
359 auto stream_state = std::make_unique<StreamState>();
360 // Create the video renderers. We must add both to the stream state to keep
361 // them from deallocating.
362 std::stringstream window_title;
363 window_title << "Playback Video (" << rtp_dump_path << ")";
364 std::unique_ptr<rtc::VideoSinkInterface<VideoFrame>> playback_video;
365 if (absl::GetFlag(FLAGS_disable_preview)) {
366 playback_video = std::make_unique<NullRenderer>();
367 } else {
368 playback_video.reset(test::VideoRenderer::Create(
369 window_title.str().c_str(), absl::GetFlag(FLAGS_render_width),
370 absl::GetFlag(FLAGS_render_height)));
371 }
372 auto file_passthrough = std::make_unique<FileRenderPassthrough>(
373 absl::GetFlag(FLAGS_out_base), playback_video.get());
374 stream_state->sinks.push_back(std::move(playback_video));
375 stream_state->sinks.push_back(std::move(file_passthrough));
376 // Setup the configuration from the flags.
377 VideoReceiveStreamInterface::Config receive_config(
378 &(stream_state->transport));
379 receive_config.rtp.remote_ssrc = absl::GetFlag(FLAGS_ssrc);
380 receive_config.rtp.local_ssrc = kReceiverLocalSsrc;
381 receive_config.rtp.rtx_ssrc = absl::GetFlag(FLAGS_ssrc_rtx);
382 receive_config.rtp.rtx_associated_payload_types[absl::GetFlag(
383 FLAGS_media_payload_type_rtx)] = absl::GetFlag(FLAGS_media_payload_type);
384 receive_config.rtp
385 .rtx_associated_payload_types[absl::GetFlag(FLAGS_red_payload_type_rtx)] =
386 absl::GetFlag(FLAGS_red_payload_type);
387 receive_config.rtp.ulpfec_payload_type =
388 absl::GetFlag(FLAGS_ulpfec_payload_type);
389 receive_config.rtp.red_payload_type = absl::GetFlag(FLAGS_red_payload_type);
390 receive_config.rtp.nack.rtp_history_ms = 1000;
391
392 if (absl::GetFlag(FLAGS_flexfec_payload_type) != -1) {
393 receive_config.rtp.protected_by_flexfec = true;
394 FlexfecReceiveStream::Config flexfec_config(&(stream_state->transport));
395 flexfec_config.payload_type = absl::GetFlag(FLAGS_flexfec_payload_type);
396 flexfec_config.protected_media_ssrcs.push_back(absl::GetFlag(FLAGS_ssrc));
397 flexfec_config.rtp.remote_ssrc = absl::GetFlag(FLAGS_ssrc_flexfec);
398 FlexfecReceiveStream* flexfec_stream =
399 call->CreateFlexfecReceiveStream(flexfec_config);
400 receive_config.rtp.packet_sink_ = flexfec_stream;
401 stream_state->flexfec_streams.push_back(flexfec_stream);
402 }
403
404 if (absl::GetFlag(FLAGS_transmission_offset_id) != -1) {
405 receive_config.rtp.extensions.push_back(
406 RtpExtension(RtpExtension::kTimestampOffsetUri,
407 absl::GetFlag(FLAGS_transmission_offset_id)));
408 }
409 if (absl::GetFlag(FLAGS_abs_send_time_id) != -1) {
410 receive_config.rtp.extensions.push_back(RtpExtension(
411 RtpExtension::kAbsSendTimeUri, absl::GetFlag(FLAGS_abs_send_time_id)));
412 }
413 receive_config.renderer = stream_state->sinks.back().get();
414
415 // Setup the receiving stream
416 VideoReceiveStreamInterface::Decoder decoder;
417 decoder = test::CreateMatchingDecoder(absl::GetFlag(FLAGS_media_payload_type),
418 absl::GetFlag(FLAGS_codec));
419 if (!absl::GetFlag(FLAGS_decoder_bitstream_filename).empty()) {
420 // Replace decoder with file writer if we're writing the bitstream to a
421 // file instead.
422 stream_state->decoder_factory =
423 std::make_unique<test::FunctionVideoDecoderFactory>([]() {
424 return std::make_unique<DecoderBitstreamFileWriter>(
425 absl::GetFlag(FLAGS_decoder_bitstream_filename).c_str());
426 });
427 } else if (!absl::GetFlag(FLAGS_decoder_ivf_filename).empty()) {
428 // Replace decoder with file writer if we're writing the ivf to a
429 // file instead.
430 stream_state->decoder_factory =
431 std::make_unique<test::FunctionVideoDecoderFactory>([]() {
432 return std::make_unique<DecoderIvfFileWriter>(
433 absl::GetFlag(FLAGS_decoder_ivf_filename).c_str(),
434 absl::GetFlag(FLAGS_codec));
435 });
436 } else if (absl::GetFlag(FLAGS_disable_decoding)) {
437 stream_state->decoder_factory =
438 std::make_unique<test::FunctionVideoDecoderFactory>(
439 []() { return std::make_unique<test::FakeDecoder>(); });
440 } else {
441 stream_state->decoder_factory = std::make_unique<InternalDecoderFactory>();
442 }
443 receive_config.decoder_factory = stream_state->decoder_factory.get();
444 receive_config.decoders.push_back(decoder);
445
446 stream_state->receive_streams.emplace_back(
447 call->CreateVideoReceiveStream(std::move(receive_config)));
448 return stream_state;
449 }
450
CreateRtpReader(const std::string & rtp_dump_path)451 std::unique_ptr<test::RtpFileReader> CreateRtpReader(
452 const std::string& rtp_dump_path) {
453 std::unique_ptr<test::RtpFileReader> rtp_reader(test::RtpFileReader::Create(
454 test::RtpFileReader::kRtpDump, rtp_dump_path));
455 if (!rtp_reader) {
456 rtp_reader.reset(
457 test::RtpFileReader::Create(test::RtpFileReader::kPcap, rtp_dump_path));
458 if (!rtp_reader) {
459 fprintf(stderr,
460 "Couldn't open input file as either a rtpdump or .pcap. Note "
461 "that .pcapng is not supported.\nTrying to interpret the file as "
462 "length/packet interleaved.\n");
463 rtp_reader.reset(test::RtpFileReader::Create(
464 test::RtpFileReader::kLengthPacketInterleaved, rtp_dump_path));
465 if (!rtp_reader) {
466 fprintf(stderr,
467 "Unable to open input file with any supported format\n");
468 return nullptr;
469 }
470 }
471 }
472 return rtp_reader;
473 }
474
475 // The RtpReplayer is responsible for parsing the configuration provided by
476 // the user, setting up the windows, receive streams and decoders and then
477 // replaying the provided RTP dump.
478 class RtpReplayer final {
479 public:
RtpReplayer(absl::string_view replay_config_path,absl::string_view rtp_dump_path,std::unique_ptr<FieldTrialsView> field_trials,bool simulated_time)480 RtpReplayer(absl::string_view replay_config_path,
481 absl::string_view rtp_dump_path,
482 std::unique_ptr<FieldTrialsView> field_trials,
483 bool simulated_time)
484 : replay_config_path_(replay_config_path),
485 rtp_dump_path_(rtp_dump_path),
486 field_trials_(std::move(field_trials)),
487 rtp_reader_(CreateRtpReader(rtp_dump_path_)) {
488 TaskQueueFactory* task_queue_factory;
489 if (simulated_time) {
490 time_sim_ = std::make_unique<GlobalSimulatedTimeController>(
491 Timestamp::Millis(1 << 30));
492 task_queue_factory = time_sim_->GetTaskQueueFactory();
493 } else {
494 task_queue_factory_ = CreateDefaultTaskQueueFactory(field_trials_.get()),
495 task_queue_factory = task_queue_factory_.get();
496 }
497 worker_thread_ =
498 std::make_unique<rtc::TaskQueue>(task_queue_factory->CreateTaskQueue(
499 "worker_thread", TaskQueueFactory::Priority::NORMAL));
500 rtc::Event event;
501 worker_thread_->PostTask([&]() {
502 Call::Config call_config(&event_log_);
503 call_config.trials = field_trials_.get();
504 call_config.task_queue_factory = task_queue_factory;
505 call_.reset(Call::Create(call_config));
506
507 // Creation of the streams must happen inside a task queue because it is
508 // resued as a worker thread.
509 if (replay_config_path_.empty()) {
510 stream_state_ = ConfigureFromFlags(rtp_dump_path_, call_.get());
511 } else {
512 stream_state_ = ConfigureFromFile(replay_config_path_, call_.get());
513 }
514 event.Set();
515 });
516 event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
517
518 RTC_CHECK(stream_state_);
519 RTC_CHECK(rtp_reader_);
520 }
521
~RtpReplayer()522 ~RtpReplayer() {
523 // Destruction of streams and the call must happen on the same thread as
524 // their creation.
525 rtc::Event event;
526 worker_thread_->PostTask([&]() {
527 for (const auto& receive_stream : stream_state_->receive_streams) {
528 call_->DestroyVideoReceiveStream(receive_stream);
529 }
530 for (const auto& flexfec_stream : stream_state_->flexfec_streams) {
531 call_->DestroyFlexfecReceiveStream(flexfec_stream);
532 }
533 call_.reset();
534 event.Set();
535 });
536 event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
537 }
538
Run()539 void Run() {
540 rtc::Event event;
541 worker_thread_->PostTask([&]() {
542 // Start replaying the provided stream now that it has been configured.
543 // VideoReceiveStreams must be started on the same thread as they were
544 // created on.
545 for (const auto& receive_stream : stream_state_->receive_streams) {
546 receive_stream->Start();
547 }
548 event.Set();
549 });
550 event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
551
552 ReplayPackets();
553 }
554
555 private:
ReplayPackets()556 void ReplayPackets() {
557 int64_t replay_start_ms = -1;
558 int num_packets = 0;
559 std::map<uint32_t, int> unknown_packets;
560 rtc::Event event(/*manual_reset=*/false, /*initially_signalled=*/false);
561 uint32_t start_timestamp = absl::GetFlag(FLAGS_start_timestamp);
562 uint32_t stop_timestamp = absl::GetFlag(FLAGS_stop_timestamp);
563 while (true) {
564 int64_t now_ms = CurrentTimeMs();
565 if (replay_start_ms == -1) {
566 replay_start_ms = now_ms;
567 }
568
569 test::RtpPacket packet;
570 if (!rtp_reader_->NextPacket(&packet)) {
571 break;
572 }
573 rtc::CopyOnWriteBuffer packet_buffer(packet.data, packet.length);
574 RtpPacket header;
575 header.Parse(packet_buffer);
576 if (header.Timestamp() < start_timestamp ||
577 header.Timestamp() > stop_timestamp) {
578 continue;
579 }
580
581 int64_t deliver_in_ms = replay_start_ms + packet.time_ms - now_ms;
582 SleepOrAdvanceTime(deliver_in_ms);
583
584 ++num_packets;
585 PacketReceiver::DeliveryStatus result = PacketReceiver::DELIVERY_OK;
586 worker_thread_->PostTask([&]() {
587 MediaType media_type =
588 IsRtcpPacket(packet_buffer) ? MediaType::ANY : MediaType::VIDEO;
589 result = call_->Receiver()->DeliverPacket(media_type,
590 std::move(packet_buffer),
591 /* packet_time_us */ -1);
592 event.Set();
593 });
594 event.Wait(/*give_up_after=*/TimeDelta::Seconds(10));
595
596 switch (result) {
597 case PacketReceiver::DELIVERY_OK:
598 break;
599 case PacketReceiver::DELIVERY_UNKNOWN_SSRC: {
600 if (unknown_packets[header.Ssrc()] == 0)
601 fprintf(stderr, "Unknown SSRC: %u!\n", header.Ssrc());
602 ++unknown_packets[header.Ssrc()];
603 break;
604 }
605 case PacketReceiver::DELIVERY_PACKET_ERROR: {
606 fprintf(stderr,
607 "Packet error, corrupt packets or incorrect setup?\n");
608 fprintf(stderr, "Packet len=%zu pt=%u seq=%u ts=%u ssrc=0x%8x\n",
609 packet.length, header.PayloadType(), header.SequenceNumber(),
610 header.Timestamp(), header.Ssrc());
611 break;
612 }
613 }
614 }
615 // Note that even when `extend_run_time_duration` is zero
616 // `SleepOrAdvanceTime` should still be called in order to process the last
617 // delivered packet when running in simulated time.
618 SleepOrAdvanceTime(absl::GetFlag(FLAGS_extend_run_time_duration) * 1000);
619
620 fprintf(stderr, "num_packets: %d\n", num_packets);
621
622 for (std::map<uint32_t, int>::const_iterator it = unknown_packets.begin();
623 it != unknown_packets.end(); ++it) {
624 fprintf(stderr, "Packets for unknown ssrc '%u': %d\n", it->first,
625 it->second);
626 }
627 }
628
CurrentTimeMs()629 int64_t CurrentTimeMs() {
630 return time_sim_ ? time_sim_->GetClock()->TimeInMilliseconds()
631 : rtc::TimeMillis();
632 }
633
SleepOrAdvanceTime(int64_t duration_ms)634 void SleepOrAdvanceTime(int64_t duration_ms) {
635 if (time_sim_) {
636 time_sim_->AdvanceTime(TimeDelta::Millis(duration_ms));
637 } else if (duration_ms > 0) {
638 SleepMs(duration_ms);
639 }
640 }
641
642 const std::string replay_config_path_;
643 const std::string rtp_dump_path_;
644 RtcEventLogNull event_log_;
645 std::unique_ptr<FieldTrialsView> field_trials_;
646 std::unique_ptr<GlobalSimulatedTimeController> time_sim_;
647 std::unique_ptr<TaskQueueFactory> task_queue_factory_;
648 std::unique_ptr<rtc::TaskQueue> worker_thread_;
649 std::unique_ptr<Call> call_;
650 std::unique_ptr<test::RtpFileReader> rtp_reader_;
651 std::unique_ptr<StreamState> stream_state_;
652 };
653
RtpReplay()654 void RtpReplay() {
655 RtpReplayer replayer(
656 absl::GetFlag(FLAGS_config_file), absl::GetFlag(FLAGS_input_file),
657 std::make_unique<FieldTrials>(absl::GetFlag(FLAGS_force_fieldtrials)),
658 absl::GetFlag(FLAGS_simulated_time));
659 replayer.Run();
660 }
661
662 } // namespace
663 } // namespace webrtc
664
main(int argc,char * argv[])665 int main(int argc, char* argv[]) {
666 ::testing::InitGoogleTest(&argc, argv);
667 absl::ParseCommandLine(argc, argv);
668
669 RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type)));
670 RTC_CHECK(ValidatePayloadType(absl::GetFlag(FLAGS_media_payload_type_rtx)));
671 RTC_CHECK(ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type)));
672 RTC_CHECK(
673 ValidateOptionalPayloadType(absl::GetFlag(FLAGS_red_payload_type_rtx)));
674 RTC_CHECK(
675 ValidateOptionalPayloadType(absl::GetFlag(FLAGS_ulpfec_payload_type)));
676 RTC_CHECK(
677 ValidateOptionalPayloadType(absl::GetFlag(FLAGS_flexfec_payload_type)));
678 RTC_CHECK(
679 ValidateRtpHeaderExtensionId(absl::GetFlag(FLAGS_abs_send_time_id)));
680 RTC_CHECK(ValidateRtpHeaderExtensionId(
681 absl::GetFlag(FLAGS_transmission_offset_id)));
682 RTC_CHECK(ValidateInputFilenameNotEmpty(absl::GetFlag(FLAGS_input_file)));
683 RTC_CHECK_GE(absl::GetFlag(FLAGS_extend_run_time_duration), 0);
684
685 rtc::ThreadManager::Instance()->WrapCurrentThread();
686 webrtc::test::RunTest(webrtc::RtpReplay);
687 return 0;
688 }
689