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 | #include "webrtc/media/base/rtpdump.h" |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 29 | |
| 30 | #include <ctype.h> |
| 31 | |
| 32 | #include <string> |
| 33 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 34 | #include "webrtc/base/byteorder.h" |
| 35 | #include "webrtc/base/logging.h" |
| 36 | #include "webrtc/base/timeutils.h" |
kjellander | a96e2d7 | 2016-02-04 23:52:28 -0800 | [diff] [blame^] | 37 | #include "webrtc/media/base/rtputils.h" |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 38 | |
| 39 | namespace { |
| 40 | static const int kRtpSsrcOffset = 8; |
| 41 | const int kWarnSlowWritesDelayMs = 50; |
| 42 | } // namespace |
| 43 | |
| 44 | namespace cricket { |
| 45 | |
| 46 | const char RtpDumpFileHeader::kFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n"; |
| 47 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 48 | RtpDumpFileHeader::RtpDumpFileHeader(uint32_t start_ms, uint32_t s, uint16_t p) |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 49 | : start_sec(start_ms / 1000), |
| 50 | start_usec(start_ms % 1000 * 1000), |
| 51 | source(s), |
| 52 | port(p), |
| 53 | padding(0) { |
| 54 | } |
| 55 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 56 | void RtpDumpFileHeader::WriteToByteBuffer(rtc::ByteBuffer* buf) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 57 | buf->WriteUInt32(start_sec); |
| 58 | buf->WriteUInt32(start_usec); |
| 59 | buf->WriteUInt32(source); |
| 60 | buf->WriteUInt16(port); |
| 61 | buf->WriteUInt16(padding); |
| 62 | } |
| 63 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 64 | static const uint32_t kDefaultTimeIncrease = 30; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 65 | |
| 66 | bool RtpDumpPacket::IsValidRtpPacket() const { |
| 67 | return original_data_len >= data.size() && |
| 68 | data.size() >= kMinRtpPacketLen; |
| 69 | } |
| 70 | |
| 71 | bool RtpDumpPacket::IsValidRtcpPacket() const { |
| 72 | return original_data_len == 0 && |
| 73 | data.size() >= kMinRtcpPacketLen; |
| 74 | } |
| 75 | |
| 76 | bool RtpDumpPacket::GetRtpPayloadType(int* pt) const { |
| 77 | return IsValidRtpPacket() && |
| 78 | cricket::GetRtpPayloadType(&data[0], data.size(), pt); |
| 79 | } |
| 80 | |
| 81 | bool RtpDumpPacket::GetRtpSeqNum(int* seq_num) const { |
| 82 | return IsValidRtpPacket() && |
| 83 | cricket::GetRtpSeqNum(&data[0], data.size(), seq_num); |
| 84 | } |
| 85 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 86 | bool RtpDumpPacket::GetRtpTimestamp(uint32_t* ts) const { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 87 | return IsValidRtpPacket() && |
| 88 | cricket::GetRtpTimestamp(&data[0], data.size(), ts); |
| 89 | } |
| 90 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 91 | bool RtpDumpPacket::GetRtpSsrc(uint32_t* ssrc) const { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 92 | return IsValidRtpPacket() && |
| 93 | cricket::GetRtpSsrc(&data[0], data.size(), ssrc); |
| 94 | } |
| 95 | |
| 96 | bool RtpDumpPacket::GetRtpHeaderLen(size_t* len) const { |
| 97 | return IsValidRtpPacket() && |
| 98 | cricket::GetRtpHeaderLen(&data[0], data.size(), len); |
| 99 | } |
| 100 | |
| 101 | bool RtpDumpPacket::GetRtcpType(int* type) const { |
| 102 | return IsValidRtcpPacket() && |
| 103 | cricket::GetRtcpType(&data[0], data.size(), type); |
| 104 | } |
| 105 | |
| 106 | /////////////////////////////////////////////////////////////////////////// |
| 107 | // Implementation of RtpDumpReader. |
| 108 | /////////////////////////////////////////////////////////////////////////// |
| 109 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 110 | void RtpDumpReader::SetSsrc(uint32_t ssrc) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 111 | ssrc_override_ = ssrc; |
| 112 | } |
| 113 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 114 | rtc::StreamResult RtpDumpReader::ReadPacket(RtpDumpPacket* packet) { |
| 115 | if (!packet) return rtc::SR_ERROR; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 116 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 117 | rtc::StreamResult res = rtc::SR_SUCCESS; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 118 | // Read the file header if it has not been read yet. |
| 119 | if (!file_header_read_) { |
| 120 | res = ReadFileHeader(); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 121 | if (res != rtc::SR_SUCCESS) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 122 | return res; |
| 123 | } |
| 124 | file_header_read_ = true; |
| 125 | } |
| 126 | |
| 127 | // Read the RTP dump packet header. |
| 128 | char header[RtpDumpPacket::kHeaderLength]; |
| 129 | res = stream_->ReadAll(header, sizeof(header), NULL, NULL); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 130 | if (res != rtc::SR_SUCCESS) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 131 | return res; |
| 132 | } |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 133 | rtc::ByteBuffer buf(header, sizeof(header)); |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 134 | uint16_t dump_packet_len; |
| 135 | uint16_t data_len; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 136 | // Read the full length of the rtpdump packet, including the rtpdump header. |
| 137 | buf.ReadUInt16(&dump_packet_len); |
| 138 | packet->data.resize(dump_packet_len - sizeof(header)); |
| 139 | // Read the size of the original packet, which may be larger than the size in |
| 140 | // the rtpdump file, in the event that only part of the packet (perhaps just |
| 141 | // the header) was recorded. Note that this field is set to zero for RTCP |
| 142 | // packets, which have their own internal length field. |
| 143 | buf.ReadUInt16(&data_len); |
| 144 | packet->original_data_len = data_len; |
| 145 | // Read the elapsed time for this packet (different than RTP timestamp). |
| 146 | buf.ReadUInt32(&packet->elapsed_time); |
| 147 | |
| 148 | // Read the actual RTP or RTCP packet. |
| 149 | res = stream_->ReadAll(&packet->data[0], packet->data.size(), NULL, NULL); |
| 150 | |
| 151 | // If the packet is RTP and we have specified a ssrc, replace the RTP ssrc |
| 152 | // with the specified ssrc. |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 153 | if (res == rtc::SR_SUCCESS && |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 154 | packet->IsValidRtpPacket() && |
| 155 | ssrc_override_ != 0) { |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 156 | rtc::SetBE32(&packet->data[kRtpSsrcOffset], ssrc_override_); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 157 | } |
| 158 | |
| 159 | return res; |
| 160 | } |
| 161 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 162 | rtc::StreamResult RtpDumpReader::ReadFileHeader() { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 163 | // Read the first line. |
| 164 | std::string first_line; |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 165 | rtc::StreamResult res = stream_->ReadLine(&first_line); |
| 166 | if (res != rtc::SR_SUCCESS) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 167 | return res; |
| 168 | } |
| 169 | if (!CheckFirstLine(first_line)) { |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 170 | return rtc::SR_ERROR; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 171 | } |
| 172 | |
| 173 | // Read the 16 byte file header. |
| 174 | char header[RtpDumpFileHeader::kHeaderLength]; |
| 175 | res = stream_->ReadAll(header, sizeof(header), NULL, NULL); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 176 | if (res == rtc::SR_SUCCESS) { |
| 177 | rtc::ByteBuffer buf(header, sizeof(header)); |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 178 | uint32_t start_sec; |
| 179 | uint32_t start_usec; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 180 | buf.ReadUInt32(&start_sec); |
| 181 | buf.ReadUInt32(&start_usec); |
| 182 | start_time_ms_ = start_sec * 1000 + start_usec / 1000; |
| 183 | // Increase the length by 1 since first_line does not contain the ending \n. |
| 184 | first_line_and_file_header_len_ = first_line.size() + 1 + sizeof(header); |
| 185 | } |
| 186 | return res; |
| 187 | } |
| 188 | |
| 189 | bool RtpDumpReader::CheckFirstLine(const std::string& first_line) { |
| 190 | // The first line is like "#!rtpplay1.0 address/port" |
| 191 | bool matched = (0 == first_line.find("#!rtpplay1.0 ")); |
| 192 | |
| 193 | // The address could be IP or hostname. We do not check it here. Instead, we |
| 194 | // check the port at the end. |
| 195 | size_t pos = first_line.find('/'); |
| 196 | matched &= (pos != std::string::npos && pos < first_line.size() - 1); |
| 197 | for (++pos; pos < first_line.size() && matched; ++pos) { |
| 198 | matched &= (0 != isdigit(first_line[pos])); |
| 199 | } |
| 200 | |
| 201 | return matched; |
| 202 | } |
| 203 | |
| 204 | /////////////////////////////////////////////////////////////////////////// |
| 205 | // Implementation of RtpDumpLoopReader. |
| 206 | /////////////////////////////////////////////////////////////////////////// |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 207 | RtpDumpLoopReader::RtpDumpLoopReader(rtc::StreamInterface* stream) |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 208 | : RtpDumpReader(stream), |
| 209 | loop_count_(0), |
| 210 | elapsed_time_increases_(0), |
| 211 | rtp_seq_num_increase_(0), |
| 212 | rtp_timestamp_increase_(0), |
| 213 | packet_count_(0), |
| 214 | frame_count_(0), |
| 215 | first_elapsed_time_(0), |
| 216 | first_rtp_seq_num_(0), |
| 217 | first_rtp_timestamp_(0), |
| 218 | prev_elapsed_time_(0), |
| 219 | prev_rtp_seq_num_(0), |
| 220 | prev_rtp_timestamp_(0) { |
| 221 | } |
| 222 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 223 | rtc::StreamResult RtpDumpLoopReader::ReadPacket(RtpDumpPacket* packet) { |
| 224 | if (!packet) return rtc::SR_ERROR; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 225 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 226 | rtc::StreamResult res = RtpDumpReader::ReadPacket(packet); |
| 227 | if (rtc::SR_SUCCESS == res) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 228 | if (0 == loop_count_) { |
| 229 | // During the first loop, we update the statistics of the input stream. |
| 230 | UpdateStreamStatistics(*packet); |
| 231 | } |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 232 | } else if (rtc::SR_EOS == res) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 233 | if (0 == loop_count_) { |
| 234 | // At the end of the first loop, calculate elapsed_time_increases_, |
| 235 | // rtp_seq_num_increase_, and rtp_timestamp_increase_, which will be |
| 236 | // used during the second and later loops. |
| 237 | CalculateIncreases(); |
| 238 | } |
| 239 | |
| 240 | // Rewind the input stream to the first dump packet and read again. |
| 241 | ++loop_count_; |
| 242 | if (RewindToFirstDumpPacket()) { |
| 243 | res = RtpDumpReader::ReadPacket(packet); |
| 244 | } |
| 245 | } |
| 246 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 247 | if (rtc::SR_SUCCESS == res && loop_count_ > 0) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 248 | // During the second and later loops, we update the elapsed time of the dump |
| 249 | // packet. If the dumped packet is a RTP packet, we also update its RTP |
| 250 | // sequence number and timestamp. |
| 251 | UpdateDumpPacket(packet); |
| 252 | } |
| 253 | |
| 254 | return res; |
| 255 | } |
| 256 | |
| 257 | void RtpDumpLoopReader::UpdateStreamStatistics(const RtpDumpPacket& packet) { |
| 258 | // Get the RTP sequence number and timestamp of the dump packet. |
| 259 | int rtp_seq_num = 0; |
| 260 | packet.GetRtpSeqNum(&rtp_seq_num); |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 261 | uint32_t rtp_timestamp = 0; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 262 | packet.GetRtpTimestamp(&rtp_timestamp); |
| 263 | |
| 264 | // Set the timestamps and sequence number for the first dump packet. |
| 265 | if (0 == packet_count_++) { |
| 266 | first_elapsed_time_ = packet.elapsed_time; |
| 267 | first_rtp_seq_num_ = rtp_seq_num; |
| 268 | first_rtp_timestamp_ = rtp_timestamp; |
| 269 | // The first packet belongs to a new payload frame. |
| 270 | ++frame_count_; |
| 271 | } else if (rtp_timestamp != prev_rtp_timestamp_) { |
| 272 | // The current and previous packets belong to different payload frames. |
| 273 | ++frame_count_; |
| 274 | } |
| 275 | |
| 276 | prev_elapsed_time_ = packet.elapsed_time; |
| 277 | prev_rtp_timestamp_ = rtp_timestamp; |
| 278 | prev_rtp_seq_num_ = rtp_seq_num; |
| 279 | } |
| 280 | |
| 281 | void RtpDumpLoopReader::CalculateIncreases() { |
| 282 | // At this time, prev_elapsed_time_, prev_rtp_seq_num_, and |
| 283 | // prev_rtp_timestamp_ are values of the last dump packet in the input stream. |
| 284 | rtp_seq_num_increase_ = prev_rtp_seq_num_ - first_rtp_seq_num_ + 1; |
| 285 | // If we have only one packet or frame, we use the default timestamp |
| 286 | // increase. Otherwise, we use the difference between the first and the last |
| 287 | // packets or frames. |
| 288 | elapsed_time_increases_ = packet_count_ <= 1 ? kDefaultTimeIncrease : |
| 289 | (prev_elapsed_time_ - first_elapsed_time_) * packet_count_ / |
| 290 | (packet_count_ - 1); |
| 291 | rtp_timestamp_increase_ = frame_count_ <= 1 ? kDefaultTimeIncrease : |
| 292 | (prev_rtp_timestamp_ - first_rtp_timestamp_) * frame_count_ / |
| 293 | (frame_count_ - 1); |
| 294 | } |
| 295 | |
| 296 | void RtpDumpLoopReader::UpdateDumpPacket(RtpDumpPacket* packet) { |
| 297 | // Increase the elapsed time of the dump packet. |
| 298 | packet->elapsed_time += loop_count_ * elapsed_time_increases_; |
| 299 | |
| 300 | if (packet->IsValidRtpPacket()) { |
| 301 | // Get the old RTP sequence number and timestamp. |
| 302 | int sequence = 0; |
| 303 | packet->GetRtpSeqNum(&sequence); |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 304 | uint32_t timestamp = 0; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 305 | packet->GetRtpTimestamp(×tamp); |
| 306 | // Increase the RTP sequence number and timestamp. |
| 307 | sequence += loop_count_ * rtp_seq_num_increase_; |
| 308 | timestamp += loop_count_ * rtp_timestamp_increase_; |
| 309 | // Write the updated sequence number and timestamp back to the RTP packet. |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 310 | rtc::ByteBuffer buffer; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 311 | buffer.WriteUInt16(sequence); |
| 312 | buffer.WriteUInt32(timestamp); |
| 313 | memcpy(&packet->data[2], buffer.Data(), buffer.Length()); |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | /////////////////////////////////////////////////////////////////////////// |
| 318 | // Implementation of RtpDumpWriter. |
| 319 | /////////////////////////////////////////////////////////////////////////// |
| 320 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 321 | RtpDumpWriter::RtpDumpWriter(rtc::StreamInterface* stream) |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 322 | : stream_(stream), |
| 323 | packet_filter_(PF_ALL), |
| 324 | file_header_written_(false), |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 325 | start_time_ms_(rtc::Time()), |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 326 | warn_slow_writes_delay_(kWarnSlowWritesDelayMs) { |
| 327 | } |
| 328 | |
| 329 | void RtpDumpWriter::set_packet_filter(int filter) { |
| 330 | packet_filter_ = filter; |
| 331 | LOG(LS_INFO) << "RtpDumpWriter set_packet_filter to " << packet_filter_; |
| 332 | } |
| 333 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 334 | uint32_t RtpDumpWriter::GetElapsedTime() const { |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 335 | return rtc::TimeSince(start_time_ms_); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 336 | } |
| 337 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 338 | rtc::StreamResult RtpDumpWriter::WriteFileHeader() { |
| 339 | rtc::StreamResult res = WriteToStream( |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 340 | RtpDumpFileHeader::kFirstLine, |
| 341 | strlen(RtpDumpFileHeader::kFirstLine)); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 342 | if (res != rtc::SR_SUCCESS) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 343 | return res; |
| 344 | } |
| 345 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 346 | rtc::ByteBuffer buf; |
| 347 | RtpDumpFileHeader file_header(rtc::Time(), 0, 0); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 348 | file_header.WriteToByteBuffer(&buf); |
| 349 | return WriteToStream(buf.Data(), buf.Length()); |
| 350 | } |
| 351 | |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 352 | rtc::StreamResult RtpDumpWriter::WritePacket(const void* data, |
| 353 | size_t data_len, |
| 354 | uint32_t elapsed, |
| 355 | bool rtcp) { |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 356 | if (!stream_ || !data || 0 == data_len) return rtc::SR_ERROR; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 357 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 358 | rtc::StreamResult res = rtc::SR_SUCCESS; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 359 | // Write the file header if it has not been written yet. |
| 360 | if (!file_header_written_) { |
| 361 | res = WriteFileHeader(); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 362 | if (res != rtc::SR_SUCCESS) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 363 | return res; |
| 364 | } |
| 365 | file_header_written_ = true; |
| 366 | } |
| 367 | |
| 368 | // Figure out what to write. |
| 369 | size_t write_len = FilterPacket(data, data_len, rtcp); |
| 370 | if (write_len == 0) { |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 371 | return rtc::SR_SUCCESS; |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 372 | } |
| 373 | |
| 374 | // Write the dump packet header. |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 375 | rtc::ByteBuffer buf; |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 376 | buf.WriteUInt16( |
| 377 | static_cast<uint16_t>(RtpDumpPacket::kHeaderLength + write_len)); |
| 378 | buf.WriteUInt16(static_cast<uint16_t>(rtcp ? 0 : data_len)); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 379 | buf.WriteUInt32(elapsed); |
| 380 | res = WriteToStream(buf.Data(), buf.Length()); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 381 | if (res != rtc::SR_SUCCESS) { |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 382 | return res; |
| 383 | } |
| 384 | |
| 385 | // Write the header or full packet as indicated by write_len. |
| 386 | return WriteToStream(data, write_len); |
| 387 | } |
| 388 | |
| 389 | size_t RtpDumpWriter::FilterPacket(const void* data, size_t data_len, |
| 390 | bool rtcp) { |
| 391 | size_t filtered_len = 0; |
| 392 | if (!rtcp) { |
| 393 | if ((packet_filter_ & PF_RTPPACKET) == PF_RTPPACKET) { |
| 394 | // RTP header + payload |
| 395 | filtered_len = data_len; |
| 396 | } else if ((packet_filter_ & PF_RTPHEADER) == PF_RTPHEADER) { |
| 397 | // RTP header only |
| 398 | size_t header_len; |
| 399 | if (GetRtpHeaderLen(data, data_len, &header_len)) { |
| 400 | filtered_len = header_len; |
| 401 | } |
| 402 | } |
| 403 | } else { |
| 404 | if ((packet_filter_ & PF_RTCPPACKET) == PF_RTCPPACKET) { |
| 405 | // RTCP header + payload |
| 406 | filtered_len = data_len; |
| 407 | } |
| 408 | } |
| 409 | |
| 410 | return filtered_len; |
| 411 | } |
| 412 | |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 413 | rtc::StreamResult RtpDumpWriter::WriteToStream( |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 414 | const void* data, size_t data_len) { |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 415 | uint32_t before = rtc::Time(); |
buildbot@webrtc.org | d4e598d | 2014-07-29 17:36:52 +0000 | [diff] [blame] | 416 | rtc::StreamResult result = |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 417 | stream_->WriteAll(data, data_len, NULL, NULL); |
Peter Boström | 0c4e06b | 2015-10-07 12:23:21 +0200 | [diff] [blame] | 418 | uint32_t delay = rtc::TimeSince(before); |
henrike@webrtc.org | 28e2075 | 2013-07-10 00:45:36 +0000 | [diff] [blame] | 419 | if (delay >= warn_slow_writes_delay_) { |
| 420 | LOG(LS_WARNING) << "Slow RtpDump: took " << delay << "ms to write " |
| 421 | << data_len << " bytes."; |
| 422 | } |
| 423 | return result; |
| 424 | } |
| 425 | |
| 426 | } // namespace cricket |