summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_tools/rtp_generator
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/rtc_tools/rtp_generator')
-rw-r--r--third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp8.json13
-rw-r--r--third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp9.json13
-rw-r--r--third_party/libwebrtc/rtc_tools/rtp_generator/main.cc48
-rw-r--r--third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.cc330
-rw-r--r--third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.h124
5 files changed, 528 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp8.json b/third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp8.json
new file mode 100644
index 0000000000..65402fb846
--- /dev/null
+++ b/third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp8.json
@@ -0,0 +1,13 @@
+{
+ "video_streams": [
+ {
+ "duration_ms": 10000,
+ "video_width": 640,
+ "video_height": 480,
+ "video_fps": 24,
+ "rtp" : {
+ "payload_name" : "VP8"
+ }
+ }
+ ]
+}
diff --git a/third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp9.json b/third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp9.json
new file mode 100644
index 0000000000..fd780d8151
--- /dev/null
+++ b/third_party/libwebrtc/rtc_tools/rtp_generator/configs/vp9.json
@@ -0,0 +1,13 @@
+{
+ "video_streams": [
+ {
+ "duration_ms": 10000,
+ "video_width": 640,
+ "video_height": 480,
+ "video_fps": 24,
+ "rtp" : {
+ "payload_name" : "VP9"
+ }
+ }
+ ]
+}
diff --git a/third_party/libwebrtc/rtc_tools/rtp_generator/main.cc b/third_party/libwebrtc/rtc_tools/rtp_generator/main.cc
new file mode 100644
index 0000000000..df49576f39
--- /dev/null
+++ b/third_party/libwebrtc/rtc_tools/rtp_generator/main.cc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include <stdlib.h>
+
+#include <string>
+
+#include "absl/flags/flag.h"
+#include "absl/flags/parse.h"
+#include "absl/flags/usage.h"
+#include "rtc_tools/rtp_generator/rtp_generator.h"
+
+ABSL_FLAG(std::string, input_config, "", "JSON file with config");
+ABSL_FLAG(std::string, output_rtpdump, "", "Where to store the rtpdump");
+
+int main(int argc, char* argv[]) {
+ absl::SetProgramUsageMessage(
+ "Generates custom configured rtpdumps for the purpose of testing.\n"
+ "Example Usage:\n"
+ "./rtp_generator --input_config=sender_config.json\n"
+ " --output_rtpdump=my.rtpdump\n");
+ absl::ParseCommandLine(argc, argv);
+
+ const std::string config_path = absl::GetFlag(FLAGS_input_config);
+ const std::string rtp_dump_path = absl::GetFlag(FLAGS_output_rtpdump);
+
+ if (rtp_dump_path.empty() || config_path.empty()) {
+ return EXIT_FAILURE;
+ }
+
+ absl::optional<webrtc::RtpGeneratorOptions> options =
+ webrtc::ParseRtpGeneratorOptionsFromFile(config_path);
+ if (!options.has_value()) {
+ return EXIT_FAILURE;
+ }
+
+ webrtc::RtpGenerator rtp_generator(*options);
+ rtp_generator.GenerateRtpDump(rtp_dump_path);
+
+ return EXIT_SUCCESS;
+}
diff --git a/third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.cc b/third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.cc
new file mode 100644
index 0000000000..e1a2cb30da
--- /dev/null
+++ b/third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.cc
@@ -0,0 +1,330 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "rtc_tools/rtp_generator/rtp_generator.h"
+
+#include <algorithm>
+#include <memory>
+#include <utility>
+
+#include "api/task_queue/default_task_queue_factory.h"
+#include "api/test/create_frame_generator.h"
+#include "api/video_codecs/builtin_video_decoder_factory.h"
+#include "api/video_codecs/builtin_video_encoder_factory.h"
+#include "api/video_codecs/video_encoder.h"
+#include "media/base/media_constants.h"
+#include "rtc_base/strings/json.h"
+#include "rtc_base/system/file_wrapper.h"
+#include "rtc_base/thread.h"
+#include "test/testsupport/file_utils.h"
+#include "video/config/encoder_stream_factory.h"
+#include "video/config/video_encoder_config.h"
+
+namespace webrtc {
+namespace {
+
+// Payload types.
+constexpr int kPayloadTypeVp8 = 125;
+constexpr int kPayloadTypeVp9 = 124;
+constexpr int kPayloadTypeH264 = 123;
+constexpr int kFakeVideoSendPayloadType = 122;
+
+// Defaults
+constexpr int kDefaultSsrc = 1337;
+constexpr int kMaxConfigBufferSize = 8192;
+
+// Utility function to validate a correct codec type has been passed in.
+bool IsValidCodecType(const std::string& codec_name) {
+ return cricket::kVp8CodecName == codec_name ||
+ cricket::kVp9CodecName == codec_name ||
+ cricket::kH264CodecName == codec_name;
+}
+
+// Utility function to return some base payload type for a codec_name.
+int GetDefaultTypeForPayloadName(const std::string& codec_name) {
+ if (cricket::kVp8CodecName == codec_name) {
+ return kPayloadTypeVp8;
+ }
+ if (cricket::kVp9CodecName == codec_name) {
+ return kPayloadTypeVp9;
+ }
+ if (cricket::kH264CodecName == codec_name) {
+ return kPayloadTypeH264;
+ }
+ return kFakeVideoSendPayloadType;
+}
+
+// Creates a single VideoSendStream configuration.
+absl::optional<RtpGeneratorOptions::VideoSendStreamConfig>
+ParseVideoSendStreamConfig(const Json::Value& json) {
+ RtpGeneratorOptions::VideoSendStreamConfig config;
+
+ // Parse video source settings.
+ if (!rtc::GetIntFromJsonObject(json, "duration_ms", &config.duration_ms)) {
+ RTC_LOG(LS_WARNING) << "duration_ms not specified using default: "
+ << config.duration_ms;
+ }
+ if (!rtc::GetIntFromJsonObject(json, "video_width", &config.video_width)) {
+ RTC_LOG(LS_WARNING) << "video_width not specified using default: "
+ << config.video_width;
+ }
+ if (!rtc::GetIntFromJsonObject(json, "video_height", &config.video_height)) {
+ RTC_LOG(LS_WARNING) << "video_height not specified using default: "
+ << config.video_height;
+ }
+ if (!rtc::GetIntFromJsonObject(json, "video_fps", &config.video_fps)) {
+ RTC_LOG(LS_WARNING) << "video_fps not specified using default: "
+ << config.video_fps;
+ }
+ if (!rtc::GetIntFromJsonObject(json, "num_squares", &config.num_squares)) {
+ RTC_LOG(LS_WARNING) << "num_squares not specified using default: "
+ << config.num_squares;
+ }
+
+ // Parse RTP settings for this configuration.
+ config.rtp.ssrcs.push_back(kDefaultSsrc);
+ Json::Value rtp_json;
+ if (!rtc::GetValueFromJsonObject(json, "rtp", &rtp_json)) {
+ RTC_LOG(LS_ERROR) << "video_streams must have an rtp section";
+ return absl::nullopt;
+ }
+ if (!rtc::GetStringFromJsonObject(rtp_json, "payload_name",
+ &config.rtp.payload_name)) {
+ RTC_LOG(LS_ERROR) << "rtp.payload_name must be specified";
+ return absl::nullopt;
+ }
+ if (!IsValidCodecType(config.rtp.payload_name)) {
+ RTC_LOG(LS_ERROR) << "rtp.payload_name must be VP8,VP9 or H264";
+ return absl::nullopt;
+ }
+
+ config.rtp.payload_type =
+ GetDefaultTypeForPayloadName(config.rtp.payload_name);
+ if (!rtc::GetIntFromJsonObject(rtp_json, "payload_type",
+ &config.rtp.payload_type)) {
+ RTC_LOG(LS_WARNING)
+ << "rtp.payload_type not specified using default for codec type"
+ << config.rtp.payload_type;
+ }
+
+ return config;
+}
+
+} // namespace
+
+absl::optional<RtpGeneratorOptions> ParseRtpGeneratorOptionsFromFile(
+ const std::string& options_file) {
+ if (!test::FileExists(options_file)) {
+ RTC_LOG(LS_ERROR) << " configuration file does not exist";
+ return absl::nullopt;
+ }
+
+ // Read the configuration file from disk.
+ FileWrapper config_file = FileWrapper::OpenReadOnly(options_file);
+ std::vector<char> raw_json_buffer(kMaxConfigBufferSize, 0);
+ size_t bytes_read =
+ config_file.Read(raw_json_buffer.data(), raw_json_buffer.size() - 1);
+ if (bytes_read == 0) {
+ RTC_LOG(LS_ERROR) << "Unable to read the configuration file.";
+ return absl::nullopt;
+ }
+
+ // Parse the file as JSON
+ Json::CharReaderBuilder builder;
+ Json::Value json;
+ std::string error_message;
+ std::unique_ptr<Json::CharReader> json_reader(builder.newCharReader());
+ if (!json_reader->parse(raw_json_buffer.data(),
+ raw_json_buffer.data() + raw_json_buffer.size(),
+ &json, &error_message)) {
+ RTC_LOG(LS_ERROR) << "Unable to parse the corpus config json file. Error:"
+ << error_message;
+ return absl::nullopt;
+ }
+
+ RtpGeneratorOptions gen_options;
+ for (const auto& video_stream_json : json["video_streams"]) {
+ absl::optional<RtpGeneratorOptions::VideoSendStreamConfig>
+ video_stream_config = ParseVideoSendStreamConfig(video_stream_json);
+ if (!video_stream_config.has_value()) {
+ RTC_LOG(LS_ERROR) << "Unable to parse the corpus config json file";
+ return absl::nullopt;
+ }
+ gen_options.video_streams.push_back(*video_stream_config);
+ }
+ return gen_options;
+}
+
+RtpGenerator::RtpGenerator(const RtpGeneratorOptions& options)
+ : options_(options),
+ video_encoder_factory_(CreateBuiltinVideoEncoderFactory()),
+ video_decoder_factory_(CreateBuiltinVideoDecoderFactory()),
+ video_bitrate_allocator_factory_(
+ CreateBuiltinVideoBitrateAllocatorFactory()),
+ event_log_(std::make_unique<RtcEventLogNull>()),
+ call_(Call::Create(CallConfig(event_log_.get()))),
+ task_queue_(CreateDefaultTaskQueueFactory()) {
+ constexpr int kMinBitrateBps = 30000; // 30 Kbps
+ constexpr int kMaxBitrateBps = 2500000; // 2.5 Mbps
+
+ int stream_count = 0;
+ webrtc::VideoEncoder::EncoderInfo encoder_info;
+ for (const auto& send_config : options.video_streams) {
+ webrtc::VideoSendStream::Config video_config(this);
+ video_config.encoder_settings.encoder_factory =
+ video_encoder_factory_.get();
+ video_config.encoder_settings.bitrate_allocator_factory =
+ video_bitrate_allocator_factory_.get();
+ video_config.rtp = send_config.rtp;
+ // Update some required to be unique values.
+ stream_count++;
+ video_config.rtp.mid = "mid-" + std::to_string(stream_count);
+
+ // Configure the video encoder configuration.
+ VideoEncoderConfig encoder_config;
+ encoder_config.content_type =
+ VideoEncoderConfig::ContentType::kRealtimeVideo;
+ encoder_config.codec_type =
+ PayloadStringToCodecType(video_config.rtp.payload_name);
+ if (video_config.rtp.payload_name == cricket::kVp8CodecName) {
+ VideoCodecVP8 settings = VideoEncoder::GetDefaultVp8Settings();
+ encoder_config.encoder_specific_settings =
+ rtc::make_ref_counted<VideoEncoderConfig::Vp8EncoderSpecificSettings>(
+ settings);
+ } else if (video_config.rtp.payload_name == cricket::kVp9CodecName) {
+ VideoCodecVP9 settings = VideoEncoder::GetDefaultVp9Settings();
+ encoder_config.encoder_specific_settings =
+ rtc::make_ref_counted<VideoEncoderConfig::Vp9EncoderSpecificSettings>(
+ settings);
+ } else if (video_config.rtp.payload_name == cricket::kH264CodecName) {
+ encoder_config.encoder_specific_settings = nullptr;
+ }
+ encoder_config.video_format.name = video_config.rtp.payload_name;
+ encoder_config.min_transmit_bitrate_bps = 0;
+ encoder_config.max_bitrate_bps = kMaxBitrateBps;
+ encoder_config.content_type =
+ VideoEncoderConfig::ContentType::kRealtimeVideo;
+
+ // Configure the simulcast layers.
+ encoder_config.number_of_streams = video_config.rtp.ssrcs.size();
+ encoder_config.bitrate_priority = 1.0;
+ encoder_config.simulcast_layers.resize(encoder_config.number_of_streams);
+ for (size_t i = 0; i < encoder_config.number_of_streams; ++i) {
+ encoder_config.simulcast_layers[i].active = true;
+ encoder_config.simulcast_layers[i].min_bitrate_bps = kMinBitrateBps;
+ encoder_config.simulcast_layers[i].max_bitrate_bps = kMaxBitrateBps;
+ encoder_config.simulcast_layers[i].max_framerate = send_config.video_fps;
+ }
+
+ encoder_config.video_stream_factory =
+ rtc::make_ref_counted<cricket::EncoderStreamFactory>(
+ video_config.rtp.payload_name, /*max qp*/ 56, /*screencast*/ false,
+ /*screenshare enabled*/ false, encoder_info);
+
+ // Setup the fake video stream for this.
+ std::unique_ptr<test::FrameGeneratorCapturer> frame_generator =
+ std::make_unique<test::FrameGeneratorCapturer>(
+ Clock::GetRealTimeClock(),
+ test::CreateSquareFrameGenerator(send_config.video_width,
+ send_config.video_height,
+ absl::nullopt, absl::nullopt),
+ send_config.video_fps, *task_queue_);
+ frame_generator->Init();
+
+ VideoSendStream* video_send_stream = call_->CreateVideoSendStream(
+ std::move(video_config), std::move(encoder_config));
+ video_send_stream->SetSource(
+ frame_generator.get(),
+ webrtc::DegradationPreference::MAINTAIN_FRAMERATE);
+ // Store these objects so we can destropy them at the end.
+ frame_generators_.push_back(std::move(frame_generator));
+ video_send_streams_.push_back(video_send_stream);
+ }
+}
+
+RtpGenerator::~RtpGenerator() {
+ for (VideoSendStream* send_stream : video_send_streams_) {
+ call_->DestroyVideoSendStream(send_stream);
+ }
+}
+
+void RtpGenerator::GenerateRtpDump(const std::string& rtp_dump_path) {
+ rtp_dump_writer_.reset(test::RtpFileWriter::Create(
+ test::RtpFileWriter::kRtpDump, rtp_dump_path));
+
+ call_->SignalChannelNetworkState(webrtc::MediaType::VIDEO,
+ webrtc::kNetworkUp);
+ for (VideoSendStream* send_stream : video_send_streams_) {
+ send_stream->Start();
+ }
+
+ // Spinlock until all the durations end.
+ WaitUntilAllVideoStreamsFinish();
+
+ call_->SignalChannelNetworkState(webrtc::MediaType::VIDEO,
+ webrtc::kNetworkDown);
+}
+
+bool RtpGenerator::SendRtp(const uint8_t* packet,
+ size_t length,
+ const webrtc::PacketOptions& options) {
+ test::RtpPacket rtp_packet = DataToRtpPacket(packet, length);
+ rtp_dump_writer_->WritePacket(&rtp_packet);
+ return true;
+}
+
+bool RtpGenerator::SendRtcp(const uint8_t* packet, size_t length) {
+ test::RtpPacket rtcp_packet = DataToRtpPacket(packet, length);
+ rtp_dump_writer_->WritePacket(&rtcp_packet);
+ return true;
+}
+
+int RtpGenerator::GetMaxDuration() const {
+ int max_end_ms = 0;
+ for (const auto& video_stream : options_.video_streams) {
+ max_end_ms = std::max(video_stream.duration_ms, max_end_ms);
+ }
+ return max_end_ms;
+}
+
+void RtpGenerator::WaitUntilAllVideoStreamsFinish() {
+ // Find the maximum duration required by the streams.
+ start_ms_ = Clock::GetRealTimeClock()->TimeInMilliseconds();
+ int64_t max_end_ms = start_ms_ + GetMaxDuration();
+
+ int64_t current_time = 0;
+ do {
+ int64_t min_wait_time = 0;
+ current_time = Clock::GetRealTimeClock()->TimeInMilliseconds();
+ // Stop any streams that are no longer active.
+ for (size_t i = 0; i < options_.video_streams.size(); ++i) {
+ const int64_t end_ms = start_ms_ + options_.video_streams[i].duration_ms;
+ if (current_time > end_ms) {
+ video_send_streams_[i]->Stop();
+ } else {
+ min_wait_time = std::min(min_wait_time, end_ms - current_time);
+ }
+ }
+ rtc::Thread::Current()->SleepMs(min_wait_time);
+ } while (current_time < max_end_ms);
+}
+
+test::RtpPacket RtpGenerator::DataToRtpPacket(const uint8_t* packet,
+ size_t packet_len) {
+ webrtc::test::RtpPacket rtp_packet;
+ memcpy(rtp_packet.data, packet, packet_len);
+ rtp_packet.length = packet_len;
+ rtp_packet.original_length = packet_len;
+ rtp_packet.time_ms =
+ webrtc::Clock::GetRealTimeClock()->TimeInMilliseconds() - start_ms_;
+ return rtp_packet;
+}
+
+} // namespace webrtc
diff --git a/third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.h b/third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.h
new file mode 100644
index 0000000000..9a56522c33
--- /dev/null
+++ b/third_party/libwebrtc/rtc_tools/rtp_generator/rtp_generator.h
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2019 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef RTC_TOOLS_RTP_GENERATOR_RTP_GENERATOR_H_
+#define RTC_TOOLS_RTP_GENERATOR_RTP_GENERATOR_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "api/call/transport.h"
+#include "api/media_types.h"
+#include "api/rtc_event_log/rtc_event_log.h"
+#include "api/task_queue/task_queue_factory.h"
+#include "api/video/builtin_video_bitrate_allocator_factory.h"
+#include "api/video_codecs/video_decoder_factory.h"
+#include "api/video_codecs/video_encoder_factory.h"
+#include "call/call.h"
+#include "call/rtp_config.h"
+#include "call/video_send_stream.h"
+#include "media/engine/webrtc_video_engine.h"
+#include "test/frame_generator_capturer.h"
+#include "test/rtp_file_reader.h"
+#include "test/rtp_file_writer.h"
+#include "video/config/video_encoder_config.h"
+
+namespace webrtc {
+
+// Specifies all the configurable options to pass to the corpus generator.
+// If modified please update the JSON parser as well as all.
+struct RtpGeneratorOptions {
+ struct VideoSendStreamConfig {
+ // The time to record the RtpDump for.
+ int duration_ms = 10000;
+ // The video resolution width.
+ int video_width = 640;
+ // The video resolution height.
+ int video_height = 480;
+ // The video fps.
+ int video_fps = 24;
+ // The number of squares to render.
+ int num_squares = 128;
+ // The individual RTP configuration.
+ RtpConfig rtp;
+ };
+ // Multiple senders can be active at once on an rtp channel.
+ std::vector<VideoSendStreamConfig> video_streams;
+};
+
+// Attempts to parse RtpGeneratorOptions from a JSON file. Any failures
+// will result in absl::nullopt.
+absl::optional<RtpGeneratorOptions> ParseRtpGeneratorOptionsFromFile(
+ const std::string& options_file);
+
+// The RtpGenerator allows generating of corpus material intended to be
+// used by fuzzers. It accepts a simple Json configuration file that allows the
+// user to configure the codec, extensions and error correction mechanisms. It
+// will then proceed to generate an rtpdump for the specified duration using
+// that configuration that can be replayed by the video_replayer. The receiver
+// configuration JSON will also be output and can be replayed as follows:
+// ./rtp_generator --config_file sender_config --output_rtpdump my.rtpdump
+// --output_config receiver_config.json
+// ./video_replay --config_file receiver_config.json --output_file my.rtpdump
+//
+// It achieves this by creating a VideoStreamSender, configuring it as requested
+// by the user and then intercepting all outgoing RTP packets and writing them
+// to a file instead of out of the network. It then uses this sender
+// configuration to generate a mirror receiver configuration that can be read by
+// the video_replay program.
+class RtpGenerator final : public webrtc::Transport {
+ public:
+ // Construct a new RtpGenerator using the specified options.
+ explicit RtpGenerator(const RtpGeneratorOptions& options);
+
+ RtpGenerator() = delete;
+ RtpGenerator(const RtpGenerator&) = delete;
+ RtpGenerator& operator=(const RtpGenerator&) = delete;
+
+ // Cleans up the VideoSendStream.
+ ~RtpGenerator() override;
+ // Generates an rtp_dump that is written out to
+ void GenerateRtpDump(const std::string& rtp_dump_path);
+
+ private:
+ // webrtc::Transport implementation
+ // Captured RTP packets are written to the RTPDump file instead of over the
+ // network.
+ bool SendRtp(const uint8_t* packet,
+ size_t length,
+ const webrtc::PacketOptions& options) override;
+ // RTCP packets are ignored for now.
+ bool SendRtcp(const uint8_t* packet, size_t length) override;
+ // Returns the maximum duration
+ int GetMaxDuration() const;
+ // Waits until all video streams have finished.
+ void WaitUntilAllVideoStreamsFinish();
+ // Converts packet data into an RtpPacket.
+ test::RtpPacket DataToRtpPacket(const uint8_t* packet, size_t packet_len);
+
+ const RtpGeneratorOptions options_;
+ std::unique_ptr<VideoEncoderFactory> video_encoder_factory_;
+ std::unique_ptr<VideoDecoderFactory> video_decoder_factory_;
+ std::unique_ptr<VideoBitrateAllocatorFactory>
+ video_bitrate_allocator_factory_;
+ std::unique_ptr<RtcEventLog> event_log_;
+ std::unique_ptr<Call> call_;
+ std::unique_ptr<test::RtpFileWriter> rtp_dump_writer_;
+ std::vector<std::unique_ptr<test::FrameGeneratorCapturer>> frame_generators_;
+ std::vector<VideoSendStream*> video_send_streams_;
+ std::vector<uint32_t> durations_ms_;
+ uint32_t start_ms_ = 0;
+ std::unique_ptr<TaskQueueFactory> task_queue_;
+};
+
+} // namespace webrtc
+
+#endif // RTC_TOOLS_RTP_GENERATOR_RTP_GENERATOR_H_