OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2010 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 #ifndef WEBRTC_MEDIA_BASE_RTPDUMP_H_ | |
12 #define WEBRTC_MEDIA_BASE_RTPDUMP_H_ | |
13 | |
14 #include <string.h> | |
15 | |
16 #include <string> | |
17 #include <vector> | |
18 | |
19 #include "webrtc/base/basictypes.h" | |
20 #include "webrtc/base/bytebuffer.h" | |
21 #include "webrtc/base/constructormagic.h" | |
22 #include "webrtc/base/stream.h" | |
23 | |
24 namespace cricket { | |
25 | |
26 // We use the RTP dump file format compatible to the format used by rtptools | |
27 // (http://www.cs.columbia.edu/irt/software/rtptools/) and Wireshark | |
28 // (http://wiki.wireshark.org/rtpdump). In particular, the file starts with the | |
29 // first line "#!rtpplay1.0 address/port\n", followed by a 16 byte file header. | |
30 // For each packet, the file contains a 8 byte dump packet header, followed by | |
31 // the actual RTP or RTCP packet. | |
32 | |
33 enum RtpDumpPacketFilter { | |
34 PF_NONE = 0x0, | |
35 PF_RTPHEADER = 0x1, | |
36 PF_RTPPACKET = 0x3, // includes header | |
37 // PF_RTCPHEADER = 0x4, // TODO(juberti) | |
38 PF_RTCPPACKET = 0xC, // includes header | |
39 PF_ALL = 0xF | |
40 }; | |
41 | |
42 struct RtpDumpFileHeader { | |
43 RtpDumpFileHeader(int64_t start_ms, uint32_t s, uint16_t p); | |
44 void WriteToByteBuffer(rtc::ByteBufferWriter* buf); | |
45 | |
46 static const char kFirstLine[]; | |
47 static const size_t kHeaderLength = 16; | |
48 uint32_t start_sec; // start of recording, the seconds part. | |
49 uint32_t start_usec; // start of recording, the microseconds part. | |
50 uint32_t source; // network source (multicast address). | |
51 uint16_t port; // UDP port. | |
52 uint16_t padding; // 2 bytes padding. | |
53 }; | |
54 | |
55 struct RtpDumpPacket { | |
56 RtpDumpPacket() {} | |
57 | |
58 RtpDumpPacket(const void* d, size_t s, uint32_t elapsed, bool rtcp) | |
59 : elapsed_time(elapsed), original_data_len((rtcp) ? 0 : s) { | |
60 data.resize(s); | |
61 memcpy(&data[0], d, s); | |
62 } | |
63 | |
64 // In the rtpdump file format, RTCP packets have their data len set to zero, | |
65 // since RTCP has an internal length field. | |
66 bool is_rtcp() const { return original_data_len == 0; } | |
67 bool IsValidRtpPacket() const; | |
68 bool IsValidRtcpPacket() const; | |
69 // Get the payload type, sequence number, timestampe, and SSRC of the RTP | |
70 // packet. Return true and set the output parameter if successful. | |
71 bool GetRtpPayloadType(int* pt) const; | |
72 bool GetRtpSeqNum(int* seq_num) const; | |
73 bool GetRtpTimestamp(uint32_t* ts) const; | |
74 bool GetRtpSsrc(uint32_t* ssrc) const; | |
75 bool GetRtpHeaderLen(size_t* len) const; | |
76 // Get the type of the RTCP packet. Return true and set the output parameter | |
77 // if successful. | |
78 bool GetRtcpType(int* type) const; | |
79 | |
80 static const size_t kHeaderLength = 8; | |
81 uint32_t elapsed_time; // Milliseconds since the start of recording. | |
82 std::vector<uint8_t> data; // The actual RTP or RTCP packet. | |
83 size_t original_data_len; // The original length of the packet; may be | |
84 // greater than data.size() if only part of the | |
85 // packet was recorded. | |
86 }; | |
87 | |
88 class RtpDumpReader { | |
89 public: | |
90 explicit RtpDumpReader(rtc::StreamInterface* stream) | |
91 : stream_(stream), | |
92 file_header_read_(false), | |
93 first_line_and_file_header_len_(0), | |
94 start_time_ms_(0), | |
95 ssrc_override_(0) { | |
96 } | |
97 virtual ~RtpDumpReader() {} | |
98 | |
99 // Use the specified ssrc, rather than the ssrc from dump, for RTP packets. | |
100 void SetSsrc(uint32_t ssrc); | |
101 virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet); | |
102 | |
103 protected: | |
104 rtc::StreamResult ReadFileHeader(); | |
105 bool RewindToFirstDumpPacket() { | |
106 return stream_->SetPosition(first_line_and_file_header_len_); | |
107 } | |
108 | |
109 private: | |
110 // Check if its matches "#!rtpplay1.0 address/port\n". | |
111 bool CheckFirstLine(const std::string& first_line); | |
112 | |
113 rtc::StreamInterface* stream_; | |
114 bool file_header_read_; | |
115 size_t first_line_and_file_header_len_; | |
116 int64_t start_time_ms_; | |
117 uint32_t ssrc_override_; | |
118 | |
119 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpReader); | |
120 }; | |
121 | |
122 // RtpDumpLoopReader reads RTP dump packets from the input stream and rewinds | |
123 // the stream when it ends. RtpDumpLoopReader maintains the elapsed time, the | |
124 // RTP sequence number and the RTP timestamp properly. RtpDumpLoopReader can | |
125 // handle both RTP dump and RTCP dump. We assume that the dump does not mix | |
126 // RTP packets and RTCP packets. | |
127 class RtpDumpLoopReader : public RtpDumpReader { | |
128 public: | |
129 explicit RtpDumpLoopReader(rtc::StreamInterface* stream); | |
130 virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet); | |
131 | |
132 private: | |
133 // During the first loop, update the statistics, including packet count, frame | |
134 // count, timestamps, and sequence number, of the input stream. | |
135 void UpdateStreamStatistics(const RtpDumpPacket& packet); | |
136 | |
137 // At the end of first loop, calculate elapsed_time_increases_, | |
138 // rtp_seq_num_increase_, and rtp_timestamp_increase_. | |
139 void CalculateIncreases(); | |
140 | |
141 // During the second and later loops, update the elapsed time of the dump | |
142 // packet. If the dumped packet is a RTP packet, update its RTP sequence | |
143 // number and timestamp as well. | |
144 void UpdateDumpPacket(RtpDumpPacket* packet); | |
145 | |
146 int loop_count_; | |
147 // How much to increase the elapsed time, RTP sequence number, RTP timestampe | |
148 // for each loop. They are calcualted with the variables below during the | |
149 // first loop. | |
150 uint32_t elapsed_time_increases_; | |
151 int rtp_seq_num_increase_; | |
152 uint32_t rtp_timestamp_increase_; | |
153 // How many RTP packets and how many payload frames in the input stream. RTP | |
154 // packets belong to the same frame have the same RTP timestamp, different | |
155 // dump timestamp, and different RTP sequence number. | |
156 uint32_t packet_count_; | |
157 uint32_t frame_count_; | |
158 // The elapsed time, RTP sequence number, and RTP timestamp of the first and | |
159 // the previous dump packets in the input stream. | |
160 uint32_t first_elapsed_time_; | |
161 int first_rtp_seq_num_; | |
162 int64_t first_rtp_timestamp_; | |
163 uint32_t prev_elapsed_time_; | |
164 int prev_rtp_seq_num_; | |
165 int64_t prev_rtp_timestamp_; | |
166 | |
167 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpLoopReader); | |
168 }; | |
169 | |
170 class RtpDumpWriter { | |
171 public: | |
172 explicit RtpDumpWriter(rtc::StreamInterface* stream); | |
173 | |
174 // Filter to control what packets we actually record. | |
175 void set_packet_filter(int filter); | |
176 // Write a RTP or RTCP packet. The parameters data points to the packet and | |
177 // data_len is its length. | |
178 rtc::StreamResult WriteRtpPacket(const void* data, size_t data_len) { | |
179 return WritePacket(data, data_len, GetElapsedTime(), false); | |
180 } | |
181 rtc::StreamResult WriteRtcpPacket(const void* data, size_t data_len) { | |
182 return WritePacket(data, data_len, GetElapsedTime(), true); | |
183 } | |
184 rtc::StreamResult WritePacket(const RtpDumpPacket& packet) { | |
185 return WritePacket(&packet.data[0], packet.data.size(), packet.elapsed_time, | |
186 packet.is_rtcp()); | |
187 } | |
188 uint32_t GetElapsedTime() const; | |
189 | |
190 bool GetDumpSize(size_t* size) { | |
191 // Note that we use GetPosition(), rather than GetSize(), to avoid flush the | |
192 // stream per write. | |
193 return stream_ && size && stream_->GetPosition(size); | |
194 } | |
195 | |
196 protected: | |
197 rtc::StreamResult WriteFileHeader(); | |
198 | |
199 private: | |
200 rtc::StreamResult WritePacket(const void* data, | |
201 size_t data_len, | |
202 uint32_t elapsed, | |
203 bool rtcp); | |
204 size_t FilterPacket(const void* data, size_t data_len, bool rtcp); | |
205 rtc::StreamResult WriteToStream(const void* data, size_t data_len); | |
206 | |
207 rtc::StreamInterface* stream_; | |
208 int packet_filter_; | |
209 bool file_header_written_; | |
210 int64_t start_time_ms_; // Time when the record starts. | |
211 // If writing to the stream takes longer than this many ms, log a warning. | |
212 int64_t warn_slow_writes_delay_; | |
213 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter); | |
214 }; | |
215 | |
216 } // namespace cricket | |
217 | |
218 #endif // WEBRTC_MEDIA_BASE_RTPDUMP_H_ | |
OLD | NEW |