OLD | NEW |
| (Empty) |
1 /* | |
2 * libjingle | |
3 * Copyright 2010 Google Inc. | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions are met: | |
7 * | |
8 * 1. Redistributions of source code must retain the above copyright notice, | |
9 * this list of conditions and the following disclaimer. | |
10 * 2. Redistributions in binary form must reproduce the above copyright notice, | |
11 * this list of conditions and the following disclaimer in the documentation | |
12 * and/or other materials provided with the distribution. | |
13 * 3. The name of the author may not be used to endorse or promote products | |
14 * derived from this software without specific prior written permission. | |
15 * | |
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED | |
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF | |
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO | |
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | |
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | |
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | |
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | |
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
26 */ | |
27 | |
28 #ifndef TALK_MEDIA_BASE_RTPDUMP_H_ | |
29 #define TALK_MEDIA_BASE_RTPDUMP_H_ | |
30 | |
31 #include <string.h> | |
32 | |
33 #include <string> | |
34 #include <vector> | |
35 | |
36 #include "webrtc/base/basictypes.h" | |
37 #include "webrtc/base/bytebuffer.h" | |
38 #include "webrtc/base/stream.h" | |
39 | |
40 namespace cricket { | |
41 | |
42 // We use the RTP dump file format compatible to the format used by rtptools | |
43 // (http://www.cs.columbia.edu/irt/software/rtptools/) and Wireshark | |
44 // (http://wiki.wireshark.org/rtpdump). In particular, the file starts with the | |
45 // first line "#!rtpplay1.0 address/port\n", followed by a 16 byte file header. | |
46 // For each packet, the file contains a 8 byte dump packet header, followed by | |
47 // the actual RTP or RTCP packet. | |
48 | |
49 enum RtpDumpPacketFilter { | |
50 PF_NONE = 0x0, | |
51 PF_RTPHEADER = 0x1, | |
52 PF_RTPPACKET = 0x3, // includes header | |
53 // PF_RTCPHEADER = 0x4, // TODO(juberti) | |
54 PF_RTCPPACKET = 0xC, // includes header | |
55 PF_ALL = 0xF | |
56 }; | |
57 | |
58 struct RtpDumpFileHeader { | |
59 RtpDumpFileHeader(uint32_t start_ms, uint32_t s, uint16_t p); | |
60 void WriteToByteBuffer(rtc::ByteBuffer* buf); | |
61 | |
62 static const char kFirstLine[]; | |
63 static const size_t kHeaderLength = 16; | |
64 uint32_t start_sec; // start of recording, the seconds part. | |
65 uint32_t start_usec; // start of recording, the microseconds part. | |
66 uint32_t source; // network source (multicast address). | |
67 uint16_t port; // UDP port. | |
68 uint16_t padding; // 2 bytes padding. | |
69 }; | |
70 | |
71 struct RtpDumpPacket { | |
72 RtpDumpPacket() {} | |
73 | |
74 RtpDumpPacket(const void* d, size_t s, uint32_t elapsed, bool rtcp) | |
75 : elapsed_time(elapsed), original_data_len((rtcp) ? 0 : s) { | |
76 data.resize(s); | |
77 memcpy(&data[0], d, s); | |
78 } | |
79 | |
80 // In the rtpdump file format, RTCP packets have their data len set to zero, | |
81 // since RTCP has an internal length field. | |
82 bool is_rtcp() const { return original_data_len == 0; } | |
83 bool IsValidRtpPacket() const; | |
84 bool IsValidRtcpPacket() const; | |
85 // Get the payload type, sequence number, timestampe, and SSRC of the RTP | |
86 // packet. Return true and set the output parameter if successful. | |
87 bool GetRtpPayloadType(int* pt) const; | |
88 bool GetRtpSeqNum(int* seq_num) const; | |
89 bool GetRtpTimestamp(uint32_t* ts) const; | |
90 bool GetRtpSsrc(uint32_t* ssrc) const; | |
91 bool GetRtpHeaderLen(size_t* len) const; | |
92 // Get the type of the RTCP packet. Return true and set the output parameter | |
93 // if successful. | |
94 bool GetRtcpType(int* type) const; | |
95 | |
96 static const size_t kHeaderLength = 8; | |
97 uint32_t elapsed_time; // Milliseconds since the start of recording. | |
98 std::vector<uint8_t> data; // The actual RTP or RTCP packet. | |
99 size_t original_data_len; // The original length of the packet; may be | |
100 // greater than data.size() if only part of the | |
101 // packet was recorded. | |
102 }; | |
103 | |
104 class RtpDumpReader { | |
105 public: | |
106 explicit RtpDumpReader(rtc::StreamInterface* stream) | |
107 : stream_(stream), | |
108 file_header_read_(false), | |
109 first_line_and_file_header_len_(0), | |
110 start_time_ms_(0), | |
111 ssrc_override_(0) { | |
112 } | |
113 virtual ~RtpDumpReader() {} | |
114 | |
115 // Use the specified ssrc, rather than the ssrc from dump, for RTP packets. | |
116 void SetSsrc(uint32_t ssrc); | |
117 virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet); | |
118 | |
119 protected: | |
120 rtc::StreamResult ReadFileHeader(); | |
121 bool RewindToFirstDumpPacket() { | |
122 return stream_->SetPosition(first_line_and_file_header_len_); | |
123 } | |
124 | |
125 private: | |
126 // Check if its matches "#!rtpplay1.0 address/port\n". | |
127 bool CheckFirstLine(const std::string& first_line); | |
128 | |
129 rtc::StreamInterface* stream_; | |
130 bool file_header_read_; | |
131 size_t first_line_and_file_header_len_; | |
132 uint32_t start_time_ms_; | |
133 uint32_t ssrc_override_; | |
134 | |
135 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpReader); | |
136 }; | |
137 | |
138 // RtpDumpLoopReader reads RTP dump packets from the input stream and rewinds | |
139 // the stream when it ends. RtpDumpLoopReader maintains the elapsed time, the | |
140 // RTP sequence number and the RTP timestamp properly. RtpDumpLoopReader can | |
141 // handle both RTP dump and RTCP dump. We assume that the dump does not mix | |
142 // RTP packets and RTCP packets. | |
143 class RtpDumpLoopReader : public RtpDumpReader { | |
144 public: | |
145 explicit RtpDumpLoopReader(rtc::StreamInterface* stream); | |
146 virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet); | |
147 | |
148 private: | |
149 // During the first loop, update the statistics, including packet count, frame | |
150 // count, timestamps, and sequence number, of the input stream. | |
151 void UpdateStreamStatistics(const RtpDumpPacket& packet); | |
152 | |
153 // At the end of first loop, calculate elapsed_time_increases_, | |
154 // rtp_seq_num_increase_, and rtp_timestamp_increase_. | |
155 void CalculateIncreases(); | |
156 | |
157 // During the second and later loops, update the elapsed time of the dump | |
158 // packet. If the dumped packet is a RTP packet, update its RTP sequence | |
159 // number and timestamp as well. | |
160 void UpdateDumpPacket(RtpDumpPacket* packet); | |
161 | |
162 int loop_count_; | |
163 // How much to increase the elapsed time, RTP sequence number, RTP timestampe | |
164 // for each loop. They are calcualted with the variables below during the | |
165 // first loop. | |
166 uint32_t elapsed_time_increases_; | |
167 int rtp_seq_num_increase_; | |
168 uint32_t rtp_timestamp_increase_; | |
169 // How many RTP packets and how many payload frames in the input stream. RTP | |
170 // packets belong to the same frame have the same RTP timestamp, different | |
171 // dump timestamp, and different RTP sequence number. | |
172 uint32_t packet_count_; | |
173 uint32_t frame_count_; | |
174 // The elapsed time, RTP sequence number, and RTP timestamp of the first and | |
175 // the previous dump packets in the input stream. | |
176 uint32_t first_elapsed_time_; | |
177 int first_rtp_seq_num_; | |
178 uint32_t first_rtp_timestamp_; | |
179 uint32_t prev_elapsed_time_; | |
180 int prev_rtp_seq_num_; | |
181 uint32_t prev_rtp_timestamp_; | |
182 | |
183 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpLoopReader); | |
184 }; | |
185 | |
186 class RtpDumpWriter { | |
187 public: | |
188 explicit RtpDumpWriter(rtc::StreamInterface* stream); | |
189 | |
190 // Filter to control what packets we actually record. | |
191 void set_packet_filter(int filter); | |
192 // Write a RTP or RTCP packet. The parameters data points to the packet and | |
193 // data_len is its length. | |
194 rtc::StreamResult WriteRtpPacket(const void* data, size_t data_len) { | |
195 return WritePacket(data, data_len, GetElapsedTime(), false); | |
196 } | |
197 rtc::StreamResult WriteRtcpPacket(const void* data, size_t data_len) { | |
198 return WritePacket(data, data_len, GetElapsedTime(), true); | |
199 } | |
200 rtc::StreamResult WritePacket(const RtpDumpPacket& packet) { | |
201 return WritePacket(&packet.data[0], packet.data.size(), packet.elapsed_time, | |
202 packet.is_rtcp()); | |
203 } | |
204 uint32_t GetElapsedTime() const; | |
205 | |
206 bool GetDumpSize(size_t* size) { | |
207 // Note that we use GetPosition(), rather than GetSize(), to avoid flush the | |
208 // stream per write. | |
209 return stream_ && size && stream_->GetPosition(size); | |
210 } | |
211 | |
212 protected: | |
213 rtc::StreamResult WriteFileHeader(); | |
214 | |
215 private: | |
216 rtc::StreamResult WritePacket(const void* data, | |
217 size_t data_len, | |
218 uint32_t elapsed, | |
219 bool rtcp); | |
220 size_t FilterPacket(const void* data, size_t data_len, bool rtcp); | |
221 rtc::StreamResult WriteToStream(const void* data, size_t data_len); | |
222 | |
223 rtc::StreamInterface* stream_; | |
224 int packet_filter_; | |
225 bool file_header_written_; | |
226 uint32_t start_time_ms_; // Time when the record starts. | |
227 // If writing to the stream takes longer than this many ms, log a warning. | |
228 uint32_t warn_slow_writes_delay_; | |
229 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter); | |
230 }; | |
231 | |
232 } // namespace cricket | |
233 | |
234 #endif // TALK_MEDIA_BASE_RTPDUMP_H_ | |
OLD | NEW |