diff --git a/modules/audio_coding/BUILD.gn b/modules/audio_coding/BUILD.gn index 5889018ec6..44f9a8b19b 100644 --- a/modules/audio_coding/BUILD.gn +++ b/modules/audio_coding/BUILD.gn @@ -1145,6 +1145,7 @@ rtc_source_set("neteq_test_tools") { "../../test:rtp_test_utils", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", + "//third_party/abseil-cpp/absl/types:optional", ] public_deps = [ @@ -1238,6 +1239,7 @@ if (rtc_enable_protobuf) { "../../rtc_base:rtc_base_approved", "../rtp_rtcp", "../rtp_rtcp:rtp_rtcp_format", + "//third_party/abseil-cpp/absl/types:optional", ] public_deps = [ "../../logging:rtc_event_log_proto", diff --git a/modules/audio_coding/neteq/neteq_unittest.cc b/modules/audio_coding/neteq/neteq_unittest.cc index 3ee0b5bf69..3c63aa736a 100644 --- a/modules/audio_coding/neteq/neteq_unittest.cc +++ b/modules/audio_coding/neteq/neteq_unittest.cc @@ -1740,7 +1740,7 @@ TEST(NetEqNoTimeStretchingMode, RunTest) { {8, kRtpExtensionVideoTiming}}; std::unique_ptr input(new NetEqRtpDumpInput( webrtc::test::ResourcePath("audio_coding/neteq_universal_new", "rtp"), - rtp_ext_map)); + rtp_ext_map, absl::nullopt /*No SSRC filter*/)); std::unique_ptr input_time_limit( new TimeLimitedNetEqInput(std::move(input), 20000)); std::unique_ptr output(new VoidAudioSink); diff --git a/modules/audio_coding/neteq/tools/neteq_event_log_input.cc b/modules/audio_coding/neteq/tools/neteq_event_log_input.cc index 21c5f9ef02..9107e5e5ef 100644 --- a/modules/audio_coding/neteq/tools/neteq_event_log_input.cc +++ b/modules/audio_coding/neteq/tools/neteq_event_log_input.cc @@ -19,11 +19,8 @@ namespace webrtc { namespace test { NetEqEventLogInput::NetEqEventLogInput(const std::string& file_name, - const RtpHeaderExtensionMap& hdr_ext_map) - : source_(RtcEventLogSource::Create(file_name)) { - for (const auto& ext_pair : hdr_ext_map) { - source_->RegisterRtpHeaderExtension(ext_pair.second, ext_pair.first); - } + absl::optional ssrc_filter) + : source_(RtcEventLogSource::Create(file_name, ssrc_filter)) { LoadNextPacket(); AdvanceOutputEvent(); } diff --git a/modules/audio_coding/neteq/tools/neteq_event_log_input.h b/modules/audio_coding/neteq/tools/neteq_event_log_input.h index 86cf9f2f02..e04df1684f 100644 --- a/modules/audio_coding/neteq/tools/neteq_event_log_input.h +++ b/modules/audio_coding/neteq/tools/neteq_event_log_input.h @@ -28,7 +28,7 @@ class RtcEventLogSource; class NetEqEventLogInput final : public NetEqPacketSourceInput { public: NetEqEventLogInput(const std::string& file_name, - const RtpHeaderExtensionMap& hdr_ext_map); + absl::optional ssrc_filter); absl::optional NextOutputEventTime() const override; void AdvanceOutputEvent() override; diff --git a/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc b/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc index a86cf6afa5..ee02288c86 100644 --- a/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc +++ b/modules/audio_coding/neteq/tools/neteq_packet_source_input.cc @@ -58,15 +58,10 @@ std::unique_ptr NetEqPacketSourceInput::PopPacket() { return packet_data; } -void NetEqPacketSourceInput::SelectSsrc(uint32_t ssrc) { - source()->SelectSsrc(ssrc); - if (packet_ && packet_->header().ssrc != ssrc) - LoadNextPacket(); -} - NetEqRtpDumpInput::NetEqRtpDumpInput(const std::string& file_name, - const RtpHeaderExtensionMap& hdr_ext_map) - : source_(RtpFileSource::Create(file_name)) { + const RtpHeaderExtensionMap& hdr_ext_map, + absl::optional ssrc_filter) + : source_(RtpFileSource::Create(file_name, ssrc_filter)) { for (const auto& ext_pair : hdr_ext_map) { source_->RegisterRtpHeaderExtension(ext_pair.second, ext_pair.first); } diff --git a/modules/audio_coding/neteq/tools/neteq_packet_source_input.h b/modules/audio_coding/neteq/tools/neteq_packet_source_input.h index b32c534085..8633d1f5dd 100644 --- a/modules/audio_coding/neteq/tools/neteq_packet_source_input.h +++ b/modules/audio_coding/neteq/tools/neteq_packet_source_input.h @@ -12,8 +12,10 @@ #define MODULES_AUDIO_CODING_NETEQ_TOOLS_NETEQ_PACKET_SOURCE_INPUT_H_ #include +#include #include +#include "absl/types/optional.h" #include "modules/audio_coding/neteq/tools/neteq_input.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" @@ -32,7 +34,6 @@ class NetEqPacketSourceInput : public NetEqInput { std::unique_ptr PopPacket() override; absl::optional NextHeader() const override; bool ended() const override { return !next_output_event_ms_; } - void SelectSsrc(uint32_t); protected: virtual PacketSource* source() = 0; @@ -48,7 +49,8 @@ class NetEqPacketSourceInput : public NetEqInput { class NetEqRtpDumpInput final : public NetEqPacketSourceInput { public: NetEqRtpDumpInput(const std::string& file_name, - const RtpHeaderExtensionMap& hdr_ext_map); + const RtpHeaderExtensionMap& hdr_ext_map, + absl::optional ssrc_filter); absl::optional NextOutputEventTime() const override; void AdvanceOutputEvent() override; diff --git a/modules/audio_coding/neteq/tools/neteq_test_factory.cc b/modules/audio_coding/neteq/tools/neteq_test_factory.cc index 51077bc6b8..9c447cc6c6 100644 --- a/modules/audio_coding/neteq/tools/neteq_test_factory.cc +++ b/modules/audio_coding/neteq/tools/neteq_test_factory.cc @@ -309,25 +309,27 @@ std::unique_ptr NetEqTestFactory::InitializeTest( {FLAG_video_content_type, kRtpExtensionVideoContentType}, {FLAG_video_timing, kRtpExtensionVideoTiming}}; + absl::optional ssrc_filter; + // Check if an SSRC value was provided. + if (strlen(FLAG_ssrc) > 0) { + uint32_t ssrc; + RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed."; + ssrc_filter = ssrc; + } + std::unique_ptr input; if (RtpFileSource::ValidRtpDump(input_file_name) || RtpFileSource::ValidPcap(input_file_name)) { - input.reset(new NetEqRtpDumpInput(input_file_name, rtp_ext_map)); + input.reset( + new NetEqRtpDumpInput(input_file_name, rtp_ext_map, ssrc_filter)); } else { - input.reset(new NetEqEventLogInput(input_file_name, rtp_ext_map)); + input.reset(new NetEqEventLogInput(input_file_name, ssrc_filter)); } std::cout << "Input file: " << input_file_name << std::endl; RTC_CHECK(input) << "Cannot open input file"; RTC_CHECK(!input->ended()) << "Input file is empty"; - // Check if an SSRC value was provided. - if (strlen(FLAG_ssrc) > 0) { - uint32_t ssrc; - RTC_CHECK(ParseSsrc(FLAG_ssrc, &ssrc)) << "Flag verification has failed."; - static_cast(input.get())->SelectSsrc(ssrc); - } - // Check the sample rate. absl::optional sample_rate_hz; std::set> discarded_pt_and_ssrc; diff --git a/modules/audio_coding/neteq/tools/packet.cc b/modules/audio_coding/neteq/tools/packet.cc index b1a9b64193..0e7951b6e3 100644 --- a/modules/audio_coding/neteq/tools/packet.cc +++ b/modules/audio_coding/neteq/tools/packet.cc @@ -49,6 +49,20 @@ Packet::Packet(uint8_t* packet_memory, valid_header_ = ParseHeader(parser); } +Packet::Packet(const RTPHeader& header, + size_t virtual_packet_length_bytes, + size_t virtual_payload_length_bytes, + double time_ms) + : header_(header), + payload_memory_(), + payload_(NULL), + packet_length_bytes_(0), + payload_length_bytes_(0), + virtual_packet_length_bytes_(virtual_packet_length_bytes), + virtual_payload_length_bytes_(virtual_payload_length_bytes), + time_ms_(time_ms), + valid_header_(true) {} + Packet::Packet(uint8_t* packet_memory, size_t allocated_bytes, double time_ms) : payload_memory_(packet_memory), payload_(NULL), diff --git a/modules/audio_coding/neteq/tools/packet.h b/modules/audio_coding/neteq/tools/packet.h index 623c5cb635..39137aae43 100644 --- a/modules/audio_coding/neteq/tools/packet.h +++ b/modules/audio_coding/neteq/tools/packet.h @@ -50,7 +50,17 @@ class Packet { double time_ms, const RtpHeaderParser& parser); - // The following two constructors are the same as above, but without a + // Same as above, but creates the packet from an already parsed RTPHeader. + // This is typically used when reading RTP dump files that only contain the + // RTP headers, and no payload. The |virtual_packet_length_bytes| tells what + // size the packet had on wire, including the now discarded payload, + // The |virtual_payload_length_bytes| tells the size of the payload. + Packet(const RTPHeader& header, + size_t virtual_packet_length_bytes, + size_t virtual_payload_length_bytes, + double time_ms); + + // The following constructors are the same as the first two, but without a // parser. Note that when the object is constructed using any of these // methods, the header will be parsed using a default RtpHeaderParser object. // In particular, RTP header extensions won't be parsed. diff --git a/modules/audio_coding/neteq/tools/packet_source.cc b/modules/audio_coding/neteq/tools/packet_source.cc index 30bf431835..598ae6edd4 100644 --- a/modules/audio_coding/neteq/tools/packet_source.cc +++ b/modules/audio_coding/neteq/tools/packet_source.cc @@ -13,7 +13,7 @@ namespace webrtc { namespace test { -PacketSource::PacketSource() : use_ssrc_filter_(false), ssrc_(0) {} +PacketSource::PacketSource() = default; PacketSource::~PacketSource() = default; @@ -21,10 +21,5 @@ void PacketSource::FilterOutPayloadType(uint8_t payload_type) { filter_.set(payload_type, true); } -void PacketSource::SelectSsrc(uint32_t ssrc) { - use_ssrc_filter_ = true; - ssrc_ = ssrc; -} - } // namespace test } // namespace webrtc diff --git a/modules/audio_coding/neteq/tools/packet_source.h b/modules/audio_coding/neteq/tools/packet_source.h index fb689e33d4..cb86a98999 100644 --- a/modules/audio_coding/neteq/tools/packet_source.h +++ b/modules/audio_coding/neteq/tools/packet_source.h @@ -32,13 +32,8 @@ class PacketSource { virtual void FilterOutPayloadType(uint8_t payload_type); - virtual void SelectSsrc(uint32_t ssrc); - protected: std::bitset<128> filter_; // Payload type is 7 bits in the RFC. - // If SSRC filtering discards all packet that do not match the SSRC. - bool use_ssrc_filter_; // True when SSRC filtering is active. - uint32_t ssrc_; // The selected SSRC. All other SSRCs will be discarded. private: RTC_DISALLOW_COPY_AND_ASSIGN(PacketSource); diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc index 9e435c7cf8..9ba788996d 100644 --- a/modules/audio_coding/neteq/tools/rtc_event_log_source.cc +++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.cc @@ -13,94 +13,105 @@ #include #include #include +#include +#include "logging/rtc_event_log/rtc_event_processor.h" #include "modules/audio_coding/neteq/tools/packet.h" -#include "modules/rtp_rtcp/include/rtp_header_parser.h" #include "rtc_base/checks.h" namespace webrtc { namespace test { -RtcEventLogSource* RtcEventLogSource::Create(const std::string& file_name) { +namespace { +bool ShouldSkipStream(ParsedRtcEventLogNew::MediaType media_type, + uint32_t ssrc, + absl::optional ssrc_filter) { + if (media_type != ParsedRtcEventLogNew::MediaType::AUDIO) + return true; + if (ssrc_filter.has_value() && ssrc != *ssrc_filter) + return true; + return false; +} +} // namespace + +RtcEventLogSource* RtcEventLogSource::Create( + const std::string& file_name, + absl::optional ssrc_filter) { RtcEventLogSource* source = new RtcEventLogSource(); - RTC_CHECK(source->OpenFile(file_name)); + RTC_CHECK(source->OpenFile(file_name, ssrc_filter)); return source; } RtcEventLogSource::~RtcEventLogSource() {} -bool RtcEventLogSource::RegisterRtpHeaderExtension(RTPExtensionType type, - uint8_t id) { - RTC_CHECK(parser_.get()); - return parser_->RegisterRtpHeaderExtension(type, id); -} - std::unique_ptr RtcEventLogSource::NextPacket() { - for (; rtp_packet_index_ < parsed_stream_.GetNumberOfEvents(); - rtp_packet_index_++) { - if (parsed_stream_.GetEventType(rtp_packet_index_) == - ParsedRtcEventLogNew::EventType::RTP_EVENT) { - PacketDirection direction; - size_t header_length; - size_t packet_length; - uint64_t timestamp_us = parsed_stream_.GetTimestamp(rtp_packet_index_); - parsed_stream_.GetRtpHeader(rtp_packet_index_, &direction, nullptr, - &header_length, &packet_length, nullptr); + if (rtp_packet_index_ >= rtp_packets_.size()) + return nullptr; - if (direction != kIncomingPacket) { - continue; - } - - uint8_t* packet_header = new uint8_t[header_length]; - parsed_stream_.GetRtpHeader(rtp_packet_index_, nullptr, packet_header, - nullptr, nullptr, nullptr); - std::unique_ptr packet( - new Packet(packet_header, header_length, packet_length, - static_cast(timestamp_us) / 1000, *parser_.get())); - - if (!packet->valid_header()) { - std::cout << "Warning: Packet with index " << rtp_packet_index_ - << " has an invalid header and will be ignored." << std::endl; - continue; - } - - if (parsed_stream_.GetMediaType(packet->header().ssrc, direction) != - ParsedRtcEventLogNew::MediaType::AUDIO) { - continue; - } - - // Check if the packet should not be filtered out. - if (!filter_.test(packet->header().payloadType) && - !(use_ssrc_filter_ && packet->header().ssrc != ssrc_)) { - ++rtp_packet_index_; - return packet; - } - } - } - return nullptr; + std::unique_ptr packet = std::move(rtp_packets_[rtp_packet_index_++]); + return packet; } int64_t RtcEventLogSource::NextAudioOutputEventMs() { - while (audio_output_index_ < parsed_stream_.GetNumberOfEvents()) { - if (parsed_stream_.GetEventType(audio_output_index_) == - ParsedRtcEventLogNew::EventType::AUDIO_PLAYOUT_EVENT) { - LoggedAudioPlayoutEvent playout_event = - parsed_stream_.GetAudioPlayout(audio_output_index_); - if (!(use_ssrc_filter_ && playout_event.ssrc != ssrc_)) { - audio_output_index_++; - return playout_event.timestamp_us / 1000; - } - } - audio_output_index_++; - } - return std::numeric_limits::max(); + if (audio_output_index_ >= audio_outputs_.size()) + return std::numeric_limits::max(); + + int64_t output_time_ms = audio_outputs_[audio_output_index_++]; + return output_time_ms; } -RtcEventLogSource::RtcEventLogSource() - : PacketSource(), parser_(RtpHeaderParser::Create()) {} +RtcEventLogSource::RtcEventLogSource() : PacketSource() {} -bool RtcEventLogSource::OpenFile(const std::string& file_name) { - return parsed_stream_.ParseFile(file_name); +bool RtcEventLogSource::OpenFile(const std::string& file_name, + absl::optional ssrc_filter) { + ParsedRtcEventLogNew parsed_log; + if (!parsed_log.ParseFile(file_name)) + return false; + + auto handle_rtp_packet = + [this](const webrtc::LoggedRtpPacketIncoming& incoming) { + if (!filter_.test(incoming.rtp.header.payloadType)) { + rtp_packets_.emplace_back(absl::make_unique( + incoming.rtp.header, incoming.rtp.total_length, + incoming.rtp.total_length - incoming.rtp.header_length, + static_cast(incoming.log_time_ms()))); + } + }; + + auto handle_audio_playout = + [this](const webrtc::LoggedAudioPlayoutEvent& audio_playout) { + audio_outputs_.emplace_back(audio_playout.log_time_ms()); + }; + + // This wouldn't be needed if we knew that there was at most one audio stream. + webrtc::RtcEventProcessor event_processor; + for (const auto& rtp_packets : parsed_log.incoming_rtp_packets_by_ssrc()) { + ParsedRtcEventLogNew::MediaType media_type = + parsed_log.GetMediaType(rtp_packets.ssrc, webrtc::kIncomingPacket); + if (ShouldSkipStream(media_type, rtp_packets.ssrc, ssrc_filter)) { + continue; + } + auto rtp_view = absl::make_unique< + webrtc::ProcessableEventList>( + rtp_packets.incoming_packets.begin(), + rtp_packets.incoming_packets.end(), handle_rtp_packet); + event_processor.AddEvents(std::move(rtp_view)); + } + + for (const auto& audio_playouts : parsed_log.audio_playout_events()) { + if (ssrc_filter.has_value() && audio_playouts.first != *ssrc_filter) + continue; + auto audio_view = absl::make_unique< + webrtc::ProcessableEventList>( + audio_playouts.second.begin(), audio_playouts.second.end(), + handle_audio_playout); + event_processor.AddEvents(std::move(audio_view)); + } + + // Fills in rtp_packets_ and audio_outputs_. + event_processor.ProcessEventsInOrder(); + + return true; } } // namespace test diff --git a/modules/audio_coding/neteq/tools/rtc_event_log_source.h b/modules/audio_coding/neteq/tools/rtc_event_log_source.h index db4eb19e11..6b761f7dbb 100644 --- a/modules/audio_coding/neteq/tools/rtc_event_log_source.h +++ b/modules/audio_coding/neteq/tools/rtc_event_log_source.h @@ -13,7 +13,9 @@ #include #include +#include +#include "absl/types/optional.h" #include "logging/rtc_event_log/rtc_event_log_parser_new.h" #include "modules/audio_coding/neteq/tools/packet_source.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" @@ -31,13 +33,11 @@ class RtcEventLogSource : public PacketSource { public: // Creates an RtcEventLogSource reading from |file_name|. If the file cannot // be opened, or has the wrong format, NULL will be returned. - static RtcEventLogSource* Create(const std::string& file_name); + static RtcEventLogSource* Create(const std::string& file_name, + absl::optional ssrc_filter); virtual ~RtcEventLogSource(); - // Registers an RTP header extension and binds it to |id|. - virtual bool RegisterRtpHeaderExtension(RTPExtensionType type, uint8_t id); - std::unique_ptr NextPacket() override; // Returns the timestamp of the next audio output event, in milliseconds. The @@ -48,14 +48,14 @@ class RtcEventLogSource : public PacketSource { private: RtcEventLogSource(); - bool OpenFile(const std::string& file_name); + bool OpenFile(const std::string& file_name, + absl::optional ssrc_filter); + std::vector> rtp_packets_; size_t rtp_packet_index_ = 0; + std::vector audio_outputs_; size_t audio_output_index_ = 0; - ParsedRtcEventLogNew parsed_stream_; - std::unique_ptr parser_; - RTC_DISALLOW_COPY_AND_ASSIGN(RtcEventLogSource); }; diff --git a/modules/audio_coding/neteq/tools/rtp_file_source.cc b/modules/audio_coding/neteq/tools/rtp_file_source.cc index 806bba7a9f..eda2b3e31f 100644 --- a/modules/audio_coding/neteq/tools/rtp_file_source.cc +++ b/modules/audio_coding/neteq/tools/rtp_file_source.cc @@ -26,8 +26,9 @@ namespace webrtc { namespace test { -RtpFileSource* RtpFileSource::Create(const std::string& file_name) { - RtpFileSource* source = new RtpFileSource(); +RtpFileSource* RtpFileSource::Create(const std::string& file_name, + absl::optional ssrc_filter) { + RtpFileSource* source = new RtpFileSource(ssrc_filter); RTC_CHECK(source->OpenFile(file_name)); return source; } @@ -72,7 +73,7 @@ std::unique_ptr RtpFileSource::NextPacket() { continue; } if (filter_.test(packet->header().payloadType) || - (use_ssrc_filter_ && packet->header().ssrc != ssrc_)) { + (ssrc_filter_ && packet->header().ssrc != *ssrc_filter_)) { // This payload type should be filtered out. Continue to the next packet. continue; } @@ -80,8 +81,10 @@ std::unique_ptr RtpFileSource::NextPacket() { } } -RtpFileSource::RtpFileSource() - : PacketSource(), parser_(RtpHeaderParser::Create()) {} +RtpFileSource::RtpFileSource(absl::optional ssrc_filter) + : PacketSource(), + parser_(RtpHeaderParser::Create()), + ssrc_filter_(ssrc_filter) {} bool RtpFileSource::OpenFile(const std::string& file_name) { rtp_reader_.reset(RtpFileReader::Create(RtpFileReader::kRtpDump, file_name)); diff --git a/modules/audio_coding/neteq/tools/rtp_file_source.h b/modules/audio_coding/neteq/tools/rtp_file_source.h index 013333b89a..02ab897566 100644 --- a/modules/audio_coding/neteq/tools/rtp_file_source.h +++ b/modules/audio_coding/neteq/tools/rtp_file_source.h @@ -16,6 +16,7 @@ #include #include +#include "absl/types/optional.h" #include "common_types.h" // NOLINT(build/include) #include "modules/audio_coding/neteq/tools/packet_source.h" #include "modules/rtp_rtcp/include/rtp_rtcp_defines.h" @@ -33,7 +34,9 @@ class RtpFileSource : public PacketSource { public: // Creates an RtpFileSource reading from |file_name|. If the file cannot be // opened, or has the wrong format, NULL will be returned. - static RtpFileSource* Create(const std::string& file_name); + static RtpFileSource* Create( + const std::string& file_name, + absl::optional ssrc_filter = absl::nullopt); // Checks whether a files is a valid RTP dump or PCAP (Wireshark) file. static bool ValidRtpDump(const std::string& file_name); @@ -51,12 +54,13 @@ class RtpFileSource : public PacketSource { static const int kRtpFileHeaderSize = 4 + 4 + 4 + 2 + 2; static const size_t kPacketHeaderSize = 8; - RtpFileSource(); + explicit RtpFileSource(absl::optional ssrc_filter); bool OpenFile(const std::string& file_name); std::unique_ptr rtp_reader_; std::unique_ptr parser_; + const absl::optional ssrc_filter_; RTC_DISALLOW_COPY_AND_ASSIGN(RtpFileSource); };