henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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 | |
kjellander | a96e2d7 | 2016-02-04 23:52:28 -0800 | [diff] [blame] | 28 | #ifndef WEBRTC_MEDIA_BASE_RTPDUMP_H_ |
| 29 | #define WEBRTC_MEDIA_BASE_RTPDUMP_H_ |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 30 | |
pbos@webrtc.org | 371243d | 2014-03-07 15:22:04 +0000 | [diff] [blame] | 31 | #include <string.h> |
| 32 | |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 33 | #include <string> |
| 34 | #include <vector> |
| 35 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 36 | #include "webrtc/base/basictypes.h" |
| 37 | #include "webrtc/base/bytebuffer.h" |
| 38 | #include "webrtc/base/stream.h" |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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 { |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 59 | RtpDumpFileHeader(uint32_t start_ms, uint32_t s, uint16_t p); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 60 | void WriteToByteBuffer(rtc::ByteBuffer* buf); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 61 | |
| 62 | static const char kFirstLine[]; |
| 63 | static const size_t kHeaderLength = 16; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 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. |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 69 | }; |
| 70 | |
| 71 | struct RtpDumpPacket { |
| 72 | RtpDumpPacket() {} |
| 73 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 74 | RtpDumpPacket(const void* d, size_t s, uint32_t elapsed, bool rtcp) |
| 75 | : elapsed_time(elapsed), original_data_len((rtcp) ? 0 : s) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 89 | bool GetRtpTimestamp(uint32_t* ts) const; |
| 90 | bool GetRtpSsrc(uint32_t* ssrc) const; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 97 | uint32_t elapsed_time; // Milliseconds since the start of recording. |
| 98 | std::vector<uint8_t> data; // The actual RTP or RTCP packet. |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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: |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 106 | explicit RtpDumpReader(rtc::StreamInterface* stream) |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 116 | void SetSsrc(uint32_t ssrc); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 117 | virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 118 | |
| 119 | protected: |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 120 | rtc::StreamResult ReadFileHeader(); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 129 | rtc::StreamInterface* stream_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 130 | bool file_header_read_; |
| 131 | size_t first_line_and_file_header_len_; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 132 | uint32_t start_time_ms_; |
| 133 | uint32_t ssrc_override_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 134 | |
henrikg | 3c089d7 | 2015-09-16 05:37:44 -0700 | [diff] [blame] | 135 | RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpReader); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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: |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 145 | explicit RtpDumpLoopReader(rtc::StreamInterface* stream); |
| 146 | virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 166 | uint32_t elapsed_time_increases_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 167 | int rtp_seq_num_increase_; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 168 | uint32_t rtp_timestamp_increase_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 172 | uint32_t packet_count_; |
| 173 | uint32_t frame_count_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 174 | // The elapsed time, RTP sequence number, and RTP timestamp of the first and |
| 175 | // the previous dump packets in the input stream. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 176 | uint32_t first_elapsed_time_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 177 | int first_rtp_seq_num_; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 178 | uint32_t first_rtp_timestamp_; |
| 179 | uint32_t prev_elapsed_time_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 180 | int prev_rtp_seq_num_; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 181 | uint32_t prev_rtp_timestamp_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 182 | |
henrikg | 3c089d7 | 2015-09-16 05:37:44 -0700 | [diff] [blame] | 183 | RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpLoopReader); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 184 | }; |
| 185 | |
| 186 | class RtpDumpWriter { |
| 187 | public: |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 188 | explicit RtpDumpWriter(rtc::StreamInterface* stream); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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. |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 194 | rtc::StreamResult WriteRtpPacket(const void* data, size_t data_len) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 195 | return WritePacket(data, data_len, GetElapsedTime(), false); |
| 196 | } |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 197 | rtc::StreamResult WriteRtcpPacket(const void* data, size_t data_len) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 198 | return WritePacket(data, data_len, GetElapsedTime(), true); |
| 199 | } |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 200 | rtc::StreamResult WritePacket(const RtpDumpPacket& packet) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 201 | return WritePacket(&packet.data[0], packet.data.size(), packet.elapsed_time, |
| 202 | packet.is_rtcp()); |
| 203 | } |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 204 | uint32_t GetElapsedTime() const; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 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: |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 213 | rtc::StreamResult WriteFileHeader(); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 214 | |
| 215 | private: |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 216 | rtc::StreamResult WritePacket(const void* data, |
| 217 | size_t data_len, |
| 218 | uint32_t elapsed, |
| 219 | bool rtcp); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 220 | size_t FilterPacket(const void* data, size_t data_len, bool rtcp); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 221 | rtc::StreamResult WriteToStream(const void* data, size_t data_len); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 222 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 223 | rtc::StreamInterface* stream_; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 224 | int packet_filter_; |
| 225 | bool file_header_written_; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 226 | uint32_t start_time_ms_; // Time when the record starts. |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 227 | // If writing to the stream takes longer than this many ms, log a warning. |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 228 | uint32_t warn_slow_writes_delay_; |
henrikg | 3c089d7 | 2015-09-16 05:37:44 -0700 | [diff] [blame] | 229 | RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 230 | }; |
| 231 | |
| 232 | } // namespace cricket |
| 233 | |
kjellander | a96e2d7 | 2016-02-04 23:52:28 -0800 | [diff] [blame] | 234 | #endif // WEBRTC_MEDIA_BASE_RTPDUMP_H_ |