blob: 395408c53b23f32d6dec582464b55f71359880e8 [file] [log] [blame]
henrike@webrtc.org28e20752013-07-10 00:45:36 +00001/*
kjellander1afca732016-02-07 20:46:45 -08002 * Copyright (c) 2010 The WebRTC project authors. All Rights Reserved.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00003 *
kjellander1afca732016-02-07 20:46:45 -08004 * 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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +00009 */
10
kjellandera96e2d72016-02-04 23:52:28 -080011#ifndef WEBRTC_MEDIA_BASE_RTPDUMP_H_
12#define WEBRTC_MEDIA_BASE_RTPDUMP_H_
henrike@webrtc.org28e20752013-07-10 00:45:36 +000013
pbos@webrtc.org371243d2014-03-07 15:22:04 +000014#include <string.h>
15
henrike@webrtc.org28e20752013-07-10 00:45:36 +000016#include <string>
17#include <vector>
18
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000019#include "webrtc/base/basictypes.h"
20#include "webrtc/base/bytebuffer.h"
kwiberg4485ffb2016-04-26 08:14:39 -070021#include "webrtc/base/constructormagic.h"
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000022#include "webrtc/base/stream.h"
henrike@webrtc.org28e20752013-07-10 00:45:36 +000023
24namespace 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
33enum 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
42struct RtpDumpFileHeader {
Peter Boström0c4e06b2015-10-07 12:23:21 +020043 RtpDumpFileHeader(uint32_t start_ms, uint32_t s, uint16_t p);
jbauchf1f87202016-03-30 06:43:37 -070044 void WriteToByteBuffer(rtc::ByteBufferWriter* buf);
henrike@webrtc.org28e20752013-07-10 00:45:36 +000045
46 static const char kFirstLine[];
47 static const size_t kHeaderLength = 16;
Peter Boström0c4e06b2015-10-07 12:23:21 +020048 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.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000053};
54
55struct RtpDumpPacket {
56 RtpDumpPacket() {}
57
Peter Boström0c4e06b2015-10-07 12:23:21 +020058 RtpDumpPacket(const void* d, size_t s, uint32_t elapsed, bool rtcp)
59 : elapsed_time(elapsed), original_data_len((rtcp) ? 0 : s) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +000060 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;
Peter Boström0c4e06b2015-10-07 12:23:21 +020073 bool GetRtpTimestamp(uint32_t* ts) const;
74 bool GetRtpSsrc(uint32_t* ssrc) const;
henrike@webrtc.org28e20752013-07-10 00:45:36 +000075 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;
Peter Boström0c4e06b2015-10-07 12:23:21 +020081 uint32_t elapsed_time; // Milliseconds since the start of recording.
82 std::vector<uint8_t> data; // The actual RTP or RTCP packet.
henrike@webrtc.org28e20752013-07-10 00:45:36 +000083 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
88class RtpDumpReader {
89 public:
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +000090 explicit RtpDumpReader(rtc::StreamInterface* stream)
henrike@webrtc.org28e20752013-07-10 00:45:36 +000091 : 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.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200100 void SetSsrc(uint32_t ssrc);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000101 virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000102
103 protected:
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000104 rtc::StreamResult ReadFileHeader();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000105 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
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000113 rtc::StreamInterface* stream_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000114 bool file_header_read_;
115 size_t first_line_and_file_header_len_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200116 uint32_t start_time_ms_;
117 uint32_t ssrc_override_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000118
henrikg3c089d72015-09-16 05:37:44 -0700119 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpReader);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000120};
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.
127class RtpDumpLoopReader : public RtpDumpReader {
128 public:
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000129 explicit RtpDumpLoopReader(rtc::StreamInterface* stream);
130 virtual rtc::StreamResult ReadPacket(RtpDumpPacket* packet);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000131
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.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200150 uint32_t elapsed_time_increases_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000151 int rtp_seq_num_increase_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200152 uint32_t rtp_timestamp_increase_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000153 // 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.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200156 uint32_t packet_count_;
157 uint32_t frame_count_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000158 // The elapsed time, RTP sequence number, and RTP timestamp of the first and
159 // the previous dump packets in the input stream.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200160 uint32_t first_elapsed_time_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000161 int first_rtp_seq_num_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200162 uint32_t first_rtp_timestamp_;
163 uint32_t prev_elapsed_time_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000164 int prev_rtp_seq_num_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200165 uint32_t prev_rtp_timestamp_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000166
henrikg3c089d72015-09-16 05:37:44 -0700167 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpLoopReader);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000168};
169
170class RtpDumpWriter {
171 public:
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000172 explicit RtpDumpWriter(rtc::StreamInterface* stream);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000173
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.
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000178 rtc::StreamResult WriteRtpPacket(const void* data, size_t data_len) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000179 return WritePacket(data, data_len, GetElapsedTime(), false);
180 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000181 rtc::StreamResult WriteRtcpPacket(const void* data, size_t data_len) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000182 return WritePacket(data, data_len, GetElapsedTime(), true);
183 }
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000184 rtc::StreamResult WritePacket(const RtpDumpPacket& packet) {
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000185 return WritePacket(&packet.data[0], packet.data.size(), packet.elapsed_time,
186 packet.is_rtcp());
187 }
Peter Boström0c4e06b2015-10-07 12:23:21 +0200188 uint32_t GetElapsedTime() const;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000189
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:
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000197 rtc::StreamResult WriteFileHeader();
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000198
199 private:
Peter Boström0c4e06b2015-10-07 12:23:21 +0200200 rtc::StreamResult WritePacket(const void* data,
201 size_t data_len,
202 uint32_t elapsed,
203 bool rtcp);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000204 size_t FilterPacket(const void* data, size_t data_len, bool rtcp);
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000205 rtc::StreamResult WriteToStream(const void* data, size_t data_len);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000206
buildbot@webrtc.orgd4e598d2014-07-29 17:36:52 +0000207 rtc::StreamInterface* stream_;
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000208 int packet_filter_;
209 bool file_header_written_;
Peter Boström0c4e06b2015-10-07 12:23:21 +0200210 uint32_t start_time_ms_; // Time when the record starts.
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000211 // If writing to the stream takes longer than this many ms, log a warning.
Peter Boström0c4e06b2015-10-07 12:23:21 +0200212 uint32_t warn_slow_writes_delay_;
henrikg3c089d72015-09-16 05:37:44 -0700213 RTC_DISALLOW_COPY_AND_ASSIGN(RtpDumpWriter);
henrike@webrtc.org28e20752013-07-10 00:45:36 +0000214};
215
216} // namespace cricket
217
kjellandera96e2d72016-02-04 23:52:28 -0800218#endif // WEBRTC_MEDIA_BASE_RTPDUMP_H_