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