1 /*
2 * Copyright (c) 2015 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 "modules/audio_coding/neteq/tools/rtc_event_log_source.h"
12
13 #include <string.h>
14
15 #include <iostream>
16 #include <limits>
17 #include <memory>
18 #include <set>
19 #include <utility>
20
21 #include "logging/rtc_event_log/rtc_event_processor.h"
22 #include "modules/audio_coding/neteq/tools/packet.h"
23 #include "rtc_base/checks.h"
24
25 namespace webrtc {
26 namespace test {
27
28 namespace {
ShouldSkipStream(ParsedRtcEventLog::MediaType media_type,uint32_t ssrc,absl::optional<uint32_t> ssrc_filter)29 bool ShouldSkipStream(ParsedRtcEventLog::MediaType media_type,
30 uint32_t ssrc,
31 absl::optional<uint32_t> ssrc_filter) {
32 if (media_type != ParsedRtcEventLog::MediaType::AUDIO)
33 return true;
34 if (ssrc_filter.has_value() && ssrc != *ssrc_filter)
35 return true;
36 return false;
37 }
38 } // namespace
39
CreateFromFile(const std::string & file_name,absl::optional<uint32_t> ssrc_filter)40 std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromFile(
41 const std::string& file_name,
42 absl::optional<uint32_t> ssrc_filter) {
43 auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
44 ParsedRtcEventLog parsed_log;
45 auto status = parsed_log.ParseFile(file_name);
46 if (!status.ok()) {
47 std::cerr << "Failed to parse event log: " << status.message() << std::endl;
48 std::cerr << "Skipping log." << std::endl;
49 return nullptr;
50 }
51 if (!source->Initialize(parsed_log, ssrc_filter)) {
52 std::cerr << "Failed to initialize source from event log, skipping."
53 << std::endl;
54 return nullptr;
55 }
56 return source;
57 }
58
CreateFromString(const std::string & file_contents,absl::optional<uint32_t> ssrc_filter)59 std::unique_ptr<RtcEventLogSource> RtcEventLogSource::CreateFromString(
60 const std::string& file_contents,
61 absl::optional<uint32_t> ssrc_filter) {
62 auto source = std::unique_ptr<RtcEventLogSource>(new RtcEventLogSource());
63 ParsedRtcEventLog parsed_log;
64 auto status = parsed_log.ParseString(file_contents);
65 if (!status.ok()) {
66 std::cerr << "Failed to parse event log: " << status.message() << std::endl;
67 std::cerr << "Skipping log." << std::endl;
68 return nullptr;
69 }
70 if (!source->Initialize(parsed_log, ssrc_filter)) {
71 std::cerr << "Failed to initialize source from event log, skipping."
72 << std::endl;
73 return nullptr;
74 }
75 return source;
76 }
77
~RtcEventLogSource()78 RtcEventLogSource::~RtcEventLogSource() {}
79
NextPacket()80 std::unique_ptr<Packet> RtcEventLogSource::NextPacket() {
81 if (rtp_packet_index_ >= rtp_packets_.size())
82 return nullptr;
83
84 std::unique_ptr<Packet> packet = std::move(rtp_packets_[rtp_packet_index_++]);
85 return packet;
86 }
87
NextAudioOutputEventMs()88 int64_t RtcEventLogSource::NextAudioOutputEventMs() {
89 if (audio_output_index_ >= audio_outputs_.size())
90 return std::numeric_limits<int64_t>::max();
91
92 int64_t output_time_ms = audio_outputs_[audio_output_index_++];
93 return output_time_ms;
94 }
95
RtcEventLogSource()96 RtcEventLogSource::RtcEventLogSource() : PacketSource() {}
97
Initialize(const ParsedRtcEventLog & parsed_log,absl::optional<uint32_t> ssrc_filter)98 bool RtcEventLogSource::Initialize(const ParsedRtcEventLog& parsed_log,
99 absl::optional<uint32_t> ssrc_filter) {
100 const auto first_log_end_time_us =
101 parsed_log.stop_log_events().empty()
102 ? std::numeric_limits<int64_t>::max()
103 : parsed_log.stop_log_events().front().log_time_us();
104
105 std::set<uint32_t> packet_ssrcs;
106 auto handle_rtp_packet =
107 [this, first_log_end_time_us,
108 &packet_ssrcs](const webrtc::LoggedRtpPacketIncoming& incoming) {
109 if (!filter_.test(incoming.rtp.header.payloadType) &&
110 incoming.log_time_us() < first_log_end_time_us) {
111 rtp_packets_.emplace_back(std::make_unique<Packet>(
112 incoming.rtp.header, incoming.rtp.total_length,
113 incoming.rtp.total_length - incoming.rtp.header_length,
114 static_cast<double>(incoming.log_time_ms())));
115 packet_ssrcs.insert(rtp_packets_.back()->header().ssrc);
116 }
117 };
118
119 std::set<uint32_t> ignored_ssrcs;
120 auto handle_audio_playout =
121 [this, first_log_end_time_us, &packet_ssrcs,
122 &ignored_ssrcs](const webrtc::LoggedAudioPlayoutEvent& audio_playout) {
123 if (audio_playout.log_time_us() < first_log_end_time_us) {
124 if (packet_ssrcs.count(audio_playout.ssrc) > 0) {
125 audio_outputs_.emplace_back(audio_playout.log_time_ms());
126 } else {
127 ignored_ssrcs.insert(audio_playout.ssrc);
128 }
129 }
130 };
131
132 // This wouldn't be needed if we knew that there was at most one audio stream.
133 webrtc::RtcEventProcessor event_processor;
134 for (const auto& rtp_packets : parsed_log.incoming_rtp_packets_by_ssrc()) {
135 ParsedRtcEventLog::MediaType media_type =
136 parsed_log.GetMediaType(rtp_packets.ssrc, webrtc::kIncomingPacket);
137 if (ShouldSkipStream(media_type, rtp_packets.ssrc, ssrc_filter)) {
138 continue;
139 }
140 event_processor.AddEvents(rtp_packets.incoming_packets, handle_rtp_packet);
141 }
142
143 for (const auto& audio_playouts : parsed_log.audio_playout_events()) {
144 if (ssrc_filter.has_value() && audio_playouts.first != *ssrc_filter)
145 continue;
146 event_processor.AddEvents(audio_playouts.second, handle_audio_playout);
147 }
148
149 // Fills in rtp_packets_ and audio_outputs_.
150 event_processor.ProcessEventsInOrder();
151
152 for (const auto& ssrc : ignored_ssrcs) {
153 std::cout << "Ignoring GetAudio events from SSRC 0x" << std::hex << ssrc
154 << " because no packets were found with a matching SSRC."
155 << std::endl;
156 }
157
158 return true;
159 }
160
161 } // namespace test
162 } // namespace webrtc
163