| /* | |
| * Copyright (c) 2018 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 "modules/audio_coding/neteq/tools/neteq_event_log_input.h" | |
| #include <algorithm> | |
| #include <cstddef> | |
| #include <cstdint> | |
| #include <memory> | |
| #include <optional> | |
| #include <utility> | |
| #include <vector> | |
| #include "api/array_view.h" | |
| #include "api/rtp_headers.h" | |
| #include "logging/rtc_event_log/events/logged_rtp_rtcp.h" | |
| #include "logging/rtc_event_log/events/rtc_event_audio_playout.h" | |
| #include "logging/rtc_event_log/events/rtc_event_neteq_set_minimum_delay.h" | |
| #include "logging/rtc_event_log/rtc_event_log_parser.h" | |
| #include "modules/audio_coding/neteq/tools/neteq_input.h" | |
| #include "modules/rtp_rtcp/source/rtp_packet_received.h" | |
| namespace webrtc { | |
| namespace test { | |
| namespace { | |
| class NetEqEventLogInput : public NetEqInput { | |
| public: | |
| NetEqEventLogInput(const std::vector<LoggedRtpPacketIncoming>& packet_stream, | |
| const std::vector<LoggedAudioPlayoutEvent>& output_events, | |
| const std::vector<LoggedNetEqSetMinimumDelayEvent>& | |
| neteq_set_minimum_delay_events, | |
| std::optional<int64_t> end_time_ms) | |
| : packet_stream_(packet_stream), | |
| packet_stream_it_(packet_stream_.begin()), | |
| output_events_(output_events), | |
| output_events_it_(output_events_.begin()), | |
| neteq_set_minimum_delay_events_(neteq_set_minimum_delay_events), | |
| neteq_set_minimum_delay_events_it_( | |
| neteq_set_minimum_delay_events_.begin()), | |
| end_time_ms_(end_time_ms) { | |
| next_packet_ = CreateNextPacket(); | |
| // Ignore all output events before the first packet. | |
| while (output_events_it_ != output_events_.end() && | |
| output_events_it_->log_time_ms() < | |
| packet_stream_it_->log_time_ms()) { | |
| ++output_events_it_; | |
| } | |
| } | |
| std::optional<int64_t> NextPacketTime() const override { | |
| if (packet_stream_it_ == packet_stream_.end()) { | |
| return std::nullopt; | |
| } | |
| if (end_time_ms_ && packet_stream_it_->rtp.log_time_ms() > *end_time_ms_) { | |
| return std::nullopt; | |
| } | |
| return packet_stream_it_->rtp.log_time_ms(); | |
| } | |
| std::optional<int64_t> NextOutputEventTime() const override { | |
| if (output_events_it_ == output_events_.end()) { | |
| return std::nullopt; | |
| } | |
| if (end_time_ms_ && output_events_it_->log_time_ms() > *end_time_ms_) { | |
| return std::nullopt; | |
| } | |
| return output_events_it_->log_time_ms(); | |
| } | |
| std::optional<SetMinimumDelayInfo> NextSetMinimumDelayInfo() const override { | |
| if (neteq_set_minimum_delay_events_it_ == | |
| neteq_set_minimum_delay_events_.end()) { | |
| return std::nullopt; | |
| } | |
| if (end_time_ms_ && | |
| neteq_set_minimum_delay_events_it_->log_time_ms() > *end_time_ms_) { | |
| return std::nullopt; | |
| } | |
| return SetMinimumDelayInfo( | |
| neteq_set_minimum_delay_events_it_->log_time_ms(), | |
| neteq_set_minimum_delay_events_it_->minimum_delay_ms); | |
| } | |
| std::unique_ptr<RtpPacketReceived> PopPacket() override { | |
| if (packet_stream_it_ == packet_stream_.end()) { | |
| return nullptr; | |
| } | |
| ++packet_stream_it_; | |
| return std::exchange(next_packet_, CreateNextPacket()); | |
| } | |
| void AdvanceOutputEvent() override { | |
| if (output_events_it_ != output_events_.end()) { | |
| ++output_events_it_; | |
| } | |
| } | |
| void AdvanceSetMinimumDelay() override { | |
| if (neteq_set_minimum_delay_events_it_ != | |
| neteq_set_minimum_delay_events_.end()) { | |
| ++neteq_set_minimum_delay_events_it_; | |
| } | |
| } | |
| bool ended() const override { return !NextEventTime(); } | |
| const RtpPacketReceived* NextPacket() const override { | |
| return next_packet_.get(); | |
| } | |
| private: | |
| std::unique_ptr<RtpPacketReceived> CreateNextPacket() { | |
| if (packet_stream_it_ == packet_stream_.end()) { | |
| return nullptr; | |
| } | |
| const LoggedRtpPacket& logged = packet_stream_it_->rtp; | |
| auto packet_data = std::make_unique<RtpPacketReceived>(); | |
| packet_data->SetPayloadType(logged.header.payloadType); | |
| packet_data->SetMarker(logged.header.markerBit); | |
| packet_data->SetSequenceNumber(logged.header.sequenceNumber); | |
| packet_data->SetTimestamp(logged.header.timestamp); | |
| packet_data->SetSsrc(logged.header.ssrc); | |
| packet_data->SetCsrcs( | |
| MakeArrayView(logged.header.arrOfCSRCs, logged.header.numCSRCs)); | |
| packet_data->set_arrival_time(logged.log_time()); | |
| // This is a header-only "dummy" packet. Set the payload to all zeros, with | |
| // length according to the virtual length. | |
| size_t payload_size = logged.total_length - logged.header_length; | |
| std::fill_n(packet_data->AllocatePayload(payload_size), payload_size, 0); | |
| return packet_data; | |
| } | |
| const std::vector<LoggedRtpPacketIncoming> packet_stream_; | |
| std::vector<LoggedRtpPacketIncoming>::const_iterator packet_stream_it_; | |
| std::unique_ptr<RtpPacketReceived> next_packet_; | |
| const std::vector<LoggedAudioPlayoutEvent> output_events_; | |
| std::vector<LoggedAudioPlayoutEvent>::const_iterator output_events_it_; | |
| const std::vector<LoggedNetEqSetMinimumDelayEvent> | |
| neteq_set_minimum_delay_events_; | |
| std::vector<LoggedNetEqSetMinimumDelayEvent>::const_iterator | |
| neteq_set_minimum_delay_events_it_; | |
| const std::optional<int64_t> end_time_ms_; | |
| }; | |
| } // namespace | |
| std::unique_ptr<NetEqInput> CreateNetEqEventLogInput( | |
| const ParsedRtcEventLog& parsed_log, | |
| std::optional<uint32_t> ssrc) { | |
| if (parsed_log.incoming_audio_ssrcs().empty()) { | |
| return nullptr; | |
| } | |
| // Pick the first SSRC if none was provided. | |
| ssrc = ssrc.value_or(*parsed_log.incoming_audio_ssrcs().begin()); | |
| auto streams = parsed_log.incoming_rtp_packets_by_ssrc(); | |
| auto stream = | |
| std::find_if(streams.begin(), streams.end(), | |
| [ssrc](auto stream) { return stream.ssrc == ssrc; }); | |
| if (stream == streams.end()) { | |
| return nullptr; | |
| } | |
| auto output_events_it = parsed_log.audio_playout_events().find(*ssrc); | |
| if (output_events_it == parsed_log.audio_playout_events().end()) { | |
| return nullptr; | |
| } | |
| std::vector<LoggedNetEqSetMinimumDelayEvent> neteq_set_minimum_delay_events; | |
| auto neteq_set_minimum_delay_events_it = | |
| parsed_log.neteq_set_minimum_delay_events().find(*ssrc); | |
| if (neteq_set_minimum_delay_events_it != | |
| parsed_log.neteq_set_minimum_delay_events().end()) { | |
| neteq_set_minimum_delay_events = neteq_set_minimum_delay_events_it->second; | |
| } | |
| int64_t end_time_ms = parsed_log.first_log_segment().stop_time_ms(); | |
| return std::make_unique<NetEqEventLogInput>( | |
| stream->incoming_packets, output_events_it->second, | |
| neteq_set_minimum_delay_events, end_time_ms); | |
| } | |
| } // namespace test | |
| } // namespace webrtc |