OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2015 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <iostream> | 11 #include <iostream> |
12 #include <memory> | 12 #include <memory> |
13 #include <sstream> | 13 #include <sstream> |
14 #include <string> | 14 #include <string> |
15 | 15 |
16 #include "gflags/gflags.h" | 16 #include "gflags/gflags.h" |
17 #include "webrtc/base/checks.h" | 17 #include "webrtc/base/checks.h" |
18 #include "webrtc/call/call.h" | |
19 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" | 18 #include "webrtc/logging/rtc_event_log/rtc_event_log.h" |
20 #include "webrtc/logging/rtc_event_log/rtc_event_log_parser.h" | 19 #include "webrtc/logging/rtc_event_log/rtc_event_log_parser.h" |
21 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" | 20 #include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
21 #include "webrtc/modules/rtp_rtcp/source/rtp_utility.h" | |
22 #include "webrtc/test/rtp_file_writer.h" | 22 #include "webrtc/test/rtp_file_writer.h" |
23 | 23 |
24 namespace { | 24 namespace { |
25 | 25 |
26 DEFINE_bool(noaudio, | 26 DEFINE_bool(noaudio, |
27 false, | 27 false, |
28 "Excludes audio packets from the converted RTPdump file."); | 28 "Excludes audio packets from the converted RTPdump file."); |
29 DEFINE_bool(novideo, | 29 DEFINE_bool(novideo, |
30 false, | 30 false, |
31 "Excludes video packets from the converted RTPdump file."); | 31 "Excludes video packets from the converted RTPdump file."); |
32 DEFINE_bool(nodata, | 32 DEFINE_bool(nodata, |
33 false, | 33 false, |
34 "Excludes data packets from the converted RTPdump file."); | 34 "Excludes data packets from the converted RTPdump file."); |
35 DEFINE_bool(nortp, | 35 DEFINE_bool(nortp, |
36 false, | 36 false, |
37 "Excludes RTP packets from the converted RTPdump file."); | 37 "Excludes RTP packets from the converted RTPdump file."); |
38 DEFINE_bool(nortcp, | 38 DEFINE_bool(nortcp, |
39 false, | 39 false, |
40 "Excludes RTCP packets from the converted RTPdump file."); | 40 "Excludes RTCP packets from the converted RTPdump file."); |
41 DEFINE_string(ssrc, | 41 DEFINE_string(ssrc, |
42 "", | 42 "", |
43 "Store only packets with this SSRC (decimal or hex, the latter " | 43 "Store only packets with this SSRC (decimal or hex, the latter " |
44 "starting with 0x)."); | 44 "starting with 0x)."); |
45 | 45 |
46 enum class MediaType { ANY, AUDIO, VIDEO, DATA }; | |
47 | |
48 // Struct used for storing SSRCs used in a Stream. | |
49 struct Stream { | |
terelius
2017/05/23 11:57:58
If this struct is used by all/most tools, maybe th
perkj_webrtc
2017/05/24 12:32:21
Done.
| |
50 Stream(uint32_t ssrc, MediaType media_type, webrtc::PacketDirection direction) | |
51 : ssrc(ssrc), media_type(media_type), direction(direction) {} | |
52 uint32_t ssrc; | |
53 MediaType media_type; | |
54 webrtc::PacketDirection direction; | |
55 }; | |
56 | |
57 // All configured streams found in the event log. | |
58 std::vector<Stream> global_streams; | |
terelius
2017/05/23 11:57:58
Another alternative is to make this a part of the
perkj_webrtc
2017/05/24 12:32:21
Done.
| |
59 | |
60 // Returns the MediaType for registered SSRCs. Search from the end to use last | |
61 // registered types first. | |
62 MediaType GetMediaType(uint32_t ssrc, webrtc::PacketDirection direction) { | |
63 for (auto rit = global_streams.rbegin(); rit != global_streams.rend(); | |
64 ++rit) { | |
65 if (rit->ssrc == ssrc && rit->direction == direction) | |
66 return rit->media_type; | |
67 } | |
68 return MediaType::ANY; | |
69 } | |
70 | |
46 // Parses the input string for a valid SSRC. If a valid SSRC is found, it is | 71 // Parses the input string for a valid SSRC. If a valid SSRC is found, it is |
47 // written to the output variable |ssrc|, and true is returned. Otherwise, | 72 // written to the output variable |ssrc|, and true is returned. Otherwise, |
48 // false is returned. | 73 // false is returned. |
49 // The empty string must be validated as true, because it is the default value | 74 // The empty string must be validated as true, because it is the default value |
50 // of the command-line flag. In this case, no value is written to the output | 75 // of the command-line flag. In this case, no value is written to the output |
51 // variable. | 76 // variable. |
52 bool ParseSsrc(std::string str, uint32_t* ssrc) { | 77 bool ParseSsrc(std::string str, uint32_t* ssrc) { |
53 // If the input string starts with 0x or 0X it indicates a hexadecimal number. | 78 // If the input string starts with 0x or 0X it indicates a hexadecimal number. |
54 auto read_mode = std::dec; | 79 auto read_mode = std::dec; |
55 if (str.size() > 2 && | 80 if (str.size() > 2 && |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
103 std::cerr << "Error while opening output file: " << output_file | 128 std::cerr << "Error while opening output file: " << output_file |
104 << std::endl; | 129 << std::endl; |
105 return -1; | 130 return -1; |
106 } | 131 } |
107 | 132 |
108 std::cout << "Found " << parsed_stream.GetNumberOfEvents() | 133 std::cout << "Found " << parsed_stream.GetNumberOfEvents() |
109 << " events in the input file." << std::endl; | 134 << " events in the input file." << std::endl; |
110 int rtp_counter = 0, rtcp_counter = 0; | 135 int rtp_counter = 0, rtcp_counter = 0; |
111 bool header_only = false; | 136 bool header_only = false; |
112 for (size_t i = 0; i < parsed_stream.GetNumberOfEvents(); i++) { | 137 for (size_t i = 0; i < parsed_stream.GetNumberOfEvents(); i++) { |
138 if (parsed_stream.GetEventType(i) == | |
139 webrtc::ParsedRtcEventLog::VIDEO_RECEIVER_CONFIG_EVENT) { | |
140 webrtc::rtclog::StreamConfig config; | |
141 parsed_stream.GetVideoReceiveConfig(i, &config); | |
142 | |
143 global_streams.emplace_back(config.remote_ssrc, MediaType::VIDEO, | |
144 webrtc::kIncomingPacket); | |
145 global_streams.emplace_back(config.local_ssrc, MediaType::VIDEO, | |
146 webrtc::kOutgoingPacket); | |
147 } | |
148 if (parsed_stream.GetEventType(i) == | |
149 webrtc::ParsedRtcEventLog::VIDEO_SENDER_CONFIG_EVENT) { | |
150 webrtc::rtclog::StreamConfig config; | |
151 parsed_stream.GetVideoSendConfig(i, &config); | |
152 global_streams.emplace_back(config.local_ssrc, MediaType::VIDEO, | |
153 webrtc::kOutgoingPacket); | |
154 | |
155 global_streams.emplace_back(config.rtx_ssrc, MediaType::VIDEO, | |
156 webrtc::kOutgoingPacket); | |
157 } | |
158 if (parsed_stream.GetEventType(i) == | |
159 webrtc::ParsedRtcEventLog::AUDIO_RECEIVER_CONFIG_EVENT) { | |
160 webrtc::rtclog::StreamConfig config; | |
161 parsed_stream.GetAudioReceiveConfig(i, &config); | |
162 global_streams.emplace_back(config.remote_ssrc, MediaType::AUDIO, | |
163 webrtc::kIncomingPacket); | |
164 global_streams.emplace_back(config.local_ssrc, MediaType::AUDIO, | |
165 webrtc::kOutgoingPacket); | |
166 } | |
167 if (parsed_stream.GetEventType(i) == | |
168 webrtc::ParsedRtcEventLog::AUDIO_SENDER_CONFIG_EVENT) { | |
169 webrtc::rtclog::StreamConfig config; | |
170 parsed_stream.GetAudioSendConfig(i, &config); | |
171 global_streams.emplace_back(config.local_ssrc, MediaType::AUDIO, | |
172 webrtc::kOutgoingPacket); | |
173 } | |
174 | |
113 // The parsed_stream will assert if the protobuf event is missing | 175 // The parsed_stream will assert if the protobuf event is missing |
114 // some required fields and we attempt to access them. We could consider | 176 // some required fields and we attempt to access them. We could consider |
115 // a softer failure option, but it does not seem useful to generate | 177 // a softer failure option, but it does not seem useful to generate |
116 // RTP dumps based on broken event logs. | 178 // RTP dumps based on broken event logs. |
117 if (!FLAGS_nortp && | 179 if (!FLAGS_nortp && |
118 parsed_stream.GetEventType(i) == webrtc::ParsedRtcEventLog::RTP_EVENT) { | 180 parsed_stream.GetEventType(i) == webrtc::ParsedRtcEventLog::RTP_EVENT) { |
119 webrtc::test::RtpPacket packet; | 181 webrtc::test::RtpPacket packet; |
120 webrtc::PacketDirection direction; | 182 webrtc::PacketDirection direction; |
121 webrtc::MediaType media_type; | 183 parsed_stream.GetRtpHeader(i, &direction, packet.data, &packet.length, |
122 parsed_stream.GetRtpHeader(i, &direction, &media_type, packet.data, | 184 &packet.original_length); |
123 &packet.length, &packet.original_length); | |
124 if (packet.original_length > packet.length) | 185 if (packet.original_length > packet.length) |
125 header_only = true; | 186 header_only = true; |
126 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; | 187 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; |
127 | 188 |
189 webrtc::RtpUtility::RtpHeaderParser rtp_parser(packet.data, | |
190 packet.length); | |
191 | |
128 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? | 192 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? |
129 if (direction == webrtc::kOutgoingPacket) | 193 if (direction == webrtc::kOutgoingPacket) |
130 continue; | 194 continue; |
131 if (FLAGS_noaudio && media_type == webrtc::MediaType::AUDIO) | 195 |
196 webrtc::RTPHeader parsed_header; | |
197 rtp_parser.Parse(&parsed_header); | |
198 MediaType media_type = GetMediaType(parsed_header.ssrc, direction); | |
199 if (FLAGS_noaudio && media_type == MediaType::AUDIO) | |
132 continue; | 200 continue; |
133 if (FLAGS_novideo && media_type == webrtc::MediaType::VIDEO) | 201 if (FLAGS_novideo && media_type == MediaType::VIDEO) |
134 continue; | 202 continue; |
135 if (FLAGS_nodata && media_type == webrtc::MediaType::DATA) | 203 if (FLAGS_nodata && media_type == MediaType::DATA) |
136 continue; | 204 continue; |
137 if (!FLAGS_ssrc.empty()) { | 205 if (!FLAGS_ssrc.empty()) { |
138 const uint32_t packet_ssrc = | 206 const uint32_t packet_ssrc = |
139 webrtc::ByteReader<uint32_t>::ReadBigEndian( | 207 webrtc::ByteReader<uint32_t>::ReadBigEndian( |
140 reinterpret_cast<const uint8_t*>(packet.data + 8)); | 208 reinterpret_cast<const uint8_t*>(packet.data + 8)); |
141 if (packet_ssrc != ssrc_filter) | 209 if (packet_ssrc != ssrc_filter) |
142 continue; | 210 continue; |
143 } | 211 } |
144 | 212 |
145 rtp_writer->WritePacket(&packet); | 213 rtp_writer->WritePacket(&packet); |
146 rtp_counter++; | 214 rtp_counter++; |
147 } | 215 } |
148 if (!FLAGS_nortcp && | 216 if (!FLAGS_nortcp && |
149 parsed_stream.GetEventType(i) == | 217 parsed_stream.GetEventType(i) == |
150 webrtc::ParsedRtcEventLog::RTCP_EVENT) { | 218 webrtc::ParsedRtcEventLog::RTCP_EVENT) { |
151 webrtc::test::RtpPacket packet; | 219 webrtc::test::RtpPacket packet; |
152 webrtc::PacketDirection direction; | 220 webrtc::PacketDirection direction; |
153 webrtc::MediaType media_type; | 221 parsed_stream.GetRtcpPacket(i, &direction, packet.data, &packet.length); |
154 parsed_stream.GetRtcpPacket(i, &direction, &media_type, packet.data, | |
155 &packet.length); | |
156 // For RTCP packets the original_length should be set to 0 in the | 222 // For RTCP packets the original_length should be set to 0 in the |
157 // RTPdump format. | 223 // RTPdump format. |
158 packet.original_length = 0; | 224 packet.original_length = 0; |
159 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; | 225 packet.time_ms = parsed_stream.GetTimestamp(i) / 1000; |
160 | 226 |
161 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? | 227 // TODO(terelius): Maybe add a flag to dump outgoing traffic instead? |
162 if (direction == webrtc::kOutgoingPacket) | 228 if (direction == webrtc::kOutgoingPacket) |
163 continue; | 229 continue; |
164 if (FLAGS_noaudio && media_type == webrtc::MediaType::AUDIO) | 230 |
231 const uint32_t packet_ssrc = webrtc::ByteReader<uint32_t>::ReadBigEndian( | |
232 reinterpret_cast<const uint8_t*>(packet.data + 4)); | |
233 MediaType media_type = GetMediaType(packet_ssrc, direction); | |
terelius
2017/05/23 11:57:58
Please add a TODO or comment documenting that medi
| |
234 if (FLAGS_noaudio && media_type == MediaType::AUDIO) | |
165 continue; | 235 continue; |
166 if (FLAGS_novideo && media_type == webrtc::MediaType::VIDEO) | 236 if (FLAGS_novideo && media_type == MediaType::VIDEO) |
167 continue; | 237 continue; |
168 if (FLAGS_nodata && media_type == webrtc::MediaType::DATA) | 238 if (FLAGS_nodata && media_type == MediaType::DATA) |
169 continue; | 239 continue; |
170 if (!FLAGS_ssrc.empty()) { | 240 if (!FLAGS_ssrc.empty()) { |
171 const uint32_t packet_ssrc = | |
172 webrtc::ByteReader<uint32_t>::ReadBigEndian( | |
173 reinterpret_cast<const uint8_t*>(packet.data + 4)); | |
174 if (packet_ssrc != ssrc_filter) | 241 if (packet_ssrc != ssrc_filter) |
175 continue; | 242 continue; |
176 } | 243 } |
177 | 244 |
178 rtp_writer->WritePacket(&packet); | 245 rtp_writer->WritePacket(&packet); |
179 rtcp_counter++; | 246 rtcp_counter++; |
180 } | 247 } |
181 } | 248 } |
182 std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "") | 249 std::cout << "Wrote " << rtp_counter << (header_only ? " header-only" : "") |
183 << " RTP packets and " << rtcp_counter << " RTCP packets to the " | 250 << " RTP packets and " << rtcp_counter << " RTCP packets to the " |
184 << "output file." << std::endl; | 251 << "output file." << std::endl; |
185 return 0; | 252 return 0; |
186 } | 253 } |
OLD | NEW |