| OLD | NEW |
| 1 /* | 1 /* |
| 2 * libjingle | 2 * libjingle |
| 3 * Copyright 2010 Google Inc. | 3 * Copyright 2010 Google Inc. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions are met: | 6 * modification, are permitted provided that the following conditions are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright notice, | 8 * 1. Redistributions of source code must retain the above copyright notice, |
| 9 * this list of conditions and the following disclaimer. | 9 * this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright notice, | 10 * 2. Redistributions in binary form must reproduce the above copyright notice, |
| (...skipping 27 matching lines...) Expand all Loading... |
| 38 | 38 |
| 39 namespace { | 39 namespace { |
| 40 static const int kRtpSsrcOffset = 8; | 40 static const int kRtpSsrcOffset = 8; |
| 41 const int kWarnSlowWritesDelayMs = 50; | 41 const int kWarnSlowWritesDelayMs = 50; |
| 42 } // namespace | 42 } // namespace |
| 43 | 43 |
| 44 namespace cricket { | 44 namespace cricket { |
| 45 | 45 |
| 46 const char RtpDumpFileHeader::kFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n"; | 46 const char RtpDumpFileHeader::kFirstLine[] = "#!rtpplay1.0 0.0.0.0/0\n"; |
| 47 | 47 |
| 48 RtpDumpFileHeader::RtpDumpFileHeader(uint32 start_ms, uint32 s, uint16 p) | 48 RtpDumpFileHeader::RtpDumpFileHeader(uint32_t start_ms, uint32_t s, uint16_t p) |
| 49 : start_sec(start_ms / 1000), | 49 : start_sec(start_ms / 1000), |
| 50 start_usec(start_ms % 1000 * 1000), | 50 start_usec(start_ms % 1000 * 1000), |
| 51 source(s), | 51 source(s), |
| 52 port(p), | 52 port(p), |
| 53 padding(0) { | 53 padding(0) { |
| 54 } | 54 } |
| 55 | 55 |
| 56 void RtpDumpFileHeader::WriteToByteBuffer(rtc::ByteBuffer* buf) { | 56 void RtpDumpFileHeader::WriteToByteBuffer(rtc::ByteBuffer* buf) { |
| 57 buf->WriteUInt32(start_sec); | 57 buf->WriteUInt32(start_sec); |
| 58 buf->WriteUInt32(start_usec); | 58 buf->WriteUInt32(start_usec); |
| 59 buf->WriteUInt32(source); | 59 buf->WriteUInt32(source); |
| 60 buf->WriteUInt16(port); | 60 buf->WriteUInt16(port); |
| 61 buf->WriteUInt16(padding); | 61 buf->WriteUInt16(padding); |
| 62 } | 62 } |
| 63 | 63 |
| 64 static const uint32 kDefaultTimeIncrease = 30; | 64 static const uint32_t kDefaultTimeIncrease = 30; |
| 65 | 65 |
| 66 bool RtpDumpPacket::IsValidRtpPacket() const { | 66 bool RtpDumpPacket::IsValidRtpPacket() const { |
| 67 return original_data_len >= data.size() && | 67 return original_data_len >= data.size() && |
| 68 data.size() >= kMinRtpPacketLen; | 68 data.size() >= kMinRtpPacketLen; |
| 69 } | 69 } |
| 70 | 70 |
| 71 bool RtpDumpPacket::IsValidRtcpPacket() const { | 71 bool RtpDumpPacket::IsValidRtcpPacket() const { |
| 72 return original_data_len == 0 && | 72 return original_data_len == 0 && |
| 73 data.size() >= kMinRtcpPacketLen; | 73 data.size() >= kMinRtcpPacketLen; |
| 74 } | 74 } |
| 75 | 75 |
| 76 bool RtpDumpPacket::GetRtpPayloadType(int* pt) const { | 76 bool RtpDumpPacket::GetRtpPayloadType(int* pt) const { |
| 77 return IsValidRtpPacket() && | 77 return IsValidRtpPacket() && |
| 78 cricket::GetRtpPayloadType(&data[0], data.size(), pt); | 78 cricket::GetRtpPayloadType(&data[0], data.size(), pt); |
| 79 } | 79 } |
| 80 | 80 |
| 81 bool RtpDumpPacket::GetRtpSeqNum(int* seq_num) const { | 81 bool RtpDumpPacket::GetRtpSeqNum(int* seq_num) const { |
| 82 return IsValidRtpPacket() && | 82 return IsValidRtpPacket() && |
| 83 cricket::GetRtpSeqNum(&data[0], data.size(), seq_num); | 83 cricket::GetRtpSeqNum(&data[0], data.size(), seq_num); |
| 84 } | 84 } |
| 85 | 85 |
| 86 bool RtpDumpPacket::GetRtpTimestamp(uint32* ts) const { | 86 bool RtpDumpPacket::GetRtpTimestamp(uint32_t* ts) const { |
| 87 return IsValidRtpPacket() && | 87 return IsValidRtpPacket() && |
| 88 cricket::GetRtpTimestamp(&data[0], data.size(), ts); | 88 cricket::GetRtpTimestamp(&data[0], data.size(), ts); |
| 89 } | 89 } |
| 90 | 90 |
| 91 bool RtpDumpPacket::GetRtpSsrc(uint32* ssrc) const { | 91 bool RtpDumpPacket::GetRtpSsrc(uint32_t* ssrc) const { |
| 92 return IsValidRtpPacket() && | 92 return IsValidRtpPacket() && |
| 93 cricket::GetRtpSsrc(&data[0], data.size(), ssrc); | 93 cricket::GetRtpSsrc(&data[0], data.size(), ssrc); |
| 94 } | 94 } |
| 95 | 95 |
| 96 bool RtpDumpPacket::GetRtpHeaderLen(size_t* len) const { | 96 bool RtpDumpPacket::GetRtpHeaderLen(size_t* len) const { |
| 97 return IsValidRtpPacket() && | 97 return IsValidRtpPacket() && |
| 98 cricket::GetRtpHeaderLen(&data[0], data.size(), len); | 98 cricket::GetRtpHeaderLen(&data[0], data.size(), len); |
| 99 } | 99 } |
| 100 | 100 |
| 101 bool RtpDumpPacket::GetRtcpType(int* type) const { | 101 bool RtpDumpPacket::GetRtcpType(int* type) const { |
| 102 return IsValidRtcpPacket() && | 102 return IsValidRtcpPacket() && |
| 103 cricket::GetRtcpType(&data[0], data.size(), type); | 103 cricket::GetRtcpType(&data[0], data.size(), type); |
| 104 } | 104 } |
| 105 | 105 |
| 106 /////////////////////////////////////////////////////////////////////////// | 106 /////////////////////////////////////////////////////////////////////////// |
| 107 // Implementation of RtpDumpReader. | 107 // Implementation of RtpDumpReader. |
| 108 /////////////////////////////////////////////////////////////////////////// | 108 /////////////////////////////////////////////////////////////////////////// |
| 109 | 109 |
| 110 void RtpDumpReader::SetSsrc(uint32 ssrc) { | 110 void RtpDumpReader::SetSsrc(uint32_t ssrc) { |
| 111 ssrc_override_ = ssrc; | 111 ssrc_override_ = ssrc; |
| 112 } | 112 } |
| 113 | 113 |
| 114 rtc::StreamResult RtpDumpReader::ReadPacket(RtpDumpPacket* packet) { | 114 rtc::StreamResult RtpDumpReader::ReadPacket(RtpDumpPacket* packet) { |
| 115 if (!packet) return rtc::SR_ERROR; | 115 if (!packet) return rtc::SR_ERROR; |
| 116 | 116 |
| 117 rtc::StreamResult res = rtc::SR_SUCCESS; | 117 rtc::StreamResult res = rtc::SR_SUCCESS; |
| 118 // Read the file header if it has not been read yet. | 118 // Read the file header if it has not been read yet. |
| 119 if (!file_header_read_) { | 119 if (!file_header_read_) { |
| 120 res = ReadFileHeader(); | 120 res = ReadFileHeader(); |
| 121 if (res != rtc::SR_SUCCESS) { | 121 if (res != rtc::SR_SUCCESS) { |
| 122 return res; | 122 return res; |
| 123 } | 123 } |
| 124 file_header_read_ = true; | 124 file_header_read_ = true; |
| 125 } | 125 } |
| 126 | 126 |
| 127 // Read the RTP dump packet header. | 127 // Read the RTP dump packet header. |
| 128 char header[RtpDumpPacket::kHeaderLength]; | 128 char header[RtpDumpPacket::kHeaderLength]; |
| 129 res = stream_->ReadAll(header, sizeof(header), NULL, NULL); | 129 res = stream_->ReadAll(header, sizeof(header), NULL, NULL); |
| 130 if (res != rtc::SR_SUCCESS) { | 130 if (res != rtc::SR_SUCCESS) { |
| 131 return res; | 131 return res; |
| 132 } | 132 } |
| 133 rtc::ByteBuffer buf(header, sizeof(header)); | 133 rtc::ByteBuffer buf(header, sizeof(header)); |
| 134 uint16 dump_packet_len; | 134 uint16_t dump_packet_len; |
| 135 uint16 data_len; | 135 uint16_t data_len; |
| 136 // Read the full length of the rtpdump packet, including the rtpdump header. | 136 // Read the full length of the rtpdump packet, including the rtpdump header. |
| 137 buf.ReadUInt16(&dump_packet_len); | 137 buf.ReadUInt16(&dump_packet_len); |
| 138 packet->data.resize(dump_packet_len - sizeof(header)); | 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 | 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 | 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 | 141 // the header) was recorded. Note that this field is set to zero for RTCP |
| 142 // packets, which have their own internal length field. | 142 // packets, which have their own internal length field. |
| 143 buf.ReadUInt16(&data_len); | 143 buf.ReadUInt16(&data_len); |
| 144 packet->original_data_len = data_len; | 144 packet->original_data_len = data_len; |
| 145 // Read the elapsed time for this packet (different than RTP timestamp). | 145 // Read the elapsed time for this packet (different than RTP timestamp). |
| (...skipping 22 matching lines...) Expand all Loading... |
| 168 } | 168 } |
| 169 if (!CheckFirstLine(first_line)) { | 169 if (!CheckFirstLine(first_line)) { |
| 170 return rtc::SR_ERROR; | 170 return rtc::SR_ERROR; |
| 171 } | 171 } |
| 172 | 172 |
| 173 // Read the 16 byte file header. | 173 // Read the 16 byte file header. |
| 174 char header[RtpDumpFileHeader::kHeaderLength]; | 174 char header[RtpDumpFileHeader::kHeaderLength]; |
| 175 res = stream_->ReadAll(header, sizeof(header), NULL, NULL); | 175 res = stream_->ReadAll(header, sizeof(header), NULL, NULL); |
| 176 if (res == rtc::SR_SUCCESS) { | 176 if (res == rtc::SR_SUCCESS) { |
| 177 rtc::ByteBuffer buf(header, sizeof(header)); | 177 rtc::ByteBuffer buf(header, sizeof(header)); |
| 178 uint32 start_sec; | 178 uint32_t start_sec; |
| 179 uint32 start_usec; | 179 uint32_t start_usec; |
| 180 buf.ReadUInt32(&start_sec); | 180 buf.ReadUInt32(&start_sec); |
| 181 buf.ReadUInt32(&start_usec); | 181 buf.ReadUInt32(&start_usec); |
| 182 start_time_ms_ = start_sec * 1000 + start_usec / 1000; | 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. | 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); | 184 first_line_and_file_header_len_ = first_line.size() + 1 + sizeof(header); |
| 185 } | 185 } |
| 186 return res; | 186 return res; |
| 187 } | 187 } |
| 188 | 188 |
| 189 bool RtpDumpReader::CheckFirstLine(const std::string& first_line) { | 189 bool RtpDumpReader::CheckFirstLine(const std::string& first_line) { |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 251 UpdateDumpPacket(packet); | 251 UpdateDumpPacket(packet); |
| 252 } | 252 } |
| 253 | 253 |
| 254 return res; | 254 return res; |
| 255 } | 255 } |
| 256 | 256 |
| 257 void RtpDumpLoopReader::UpdateStreamStatistics(const RtpDumpPacket& packet) { | 257 void RtpDumpLoopReader::UpdateStreamStatistics(const RtpDumpPacket& packet) { |
| 258 // Get the RTP sequence number and timestamp of the dump packet. | 258 // Get the RTP sequence number and timestamp of the dump packet. |
| 259 int rtp_seq_num = 0; | 259 int rtp_seq_num = 0; |
| 260 packet.GetRtpSeqNum(&rtp_seq_num); | 260 packet.GetRtpSeqNum(&rtp_seq_num); |
| 261 uint32 rtp_timestamp = 0; | 261 uint32_t rtp_timestamp = 0; |
| 262 packet.GetRtpTimestamp(&rtp_timestamp); | 262 packet.GetRtpTimestamp(&rtp_timestamp); |
| 263 | 263 |
| 264 // Set the timestamps and sequence number for the first dump packet. | 264 // Set the timestamps and sequence number for the first dump packet. |
| 265 if (0 == packet_count_++) { | 265 if (0 == packet_count_++) { |
| 266 first_elapsed_time_ = packet.elapsed_time; | 266 first_elapsed_time_ = packet.elapsed_time; |
| 267 first_rtp_seq_num_ = rtp_seq_num; | 267 first_rtp_seq_num_ = rtp_seq_num; |
| 268 first_rtp_timestamp_ = rtp_timestamp; | 268 first_rtp_timestamp_ = rtp_timestamp; |
| 269 // The first packet belongs to a new payload frame. | 269 // The first packet belongs to a new payload frame. |
| 270 ++frame_count_; | 270 ++frame_count_; |
| 271 } else if (rtp_timestamp != prev_rtp_timestamp_) { | 271 } else if (rtp_timestamp != prev_rtp_timestamp_) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 294 } | 294 } |
| 295 | 295 |
| 296 void RtpDumpLoopReader::UpdateDumpPacket(RtpDumpPacket* packet) { | 296 void RtpDumpLoopReader::UpdateDumpPacket(RtpDumpPacket* packet) { |
| 297 // Increase the elapsed time of the dump packet. | 297 // Increase the elapsed time of the dump packet. |
| 298 packet->elapsed_time += loop_count_ * elapsed_time_increases_; | 298 packet->elapsed_time += loop_count_ * elapsed_time_increases_; |
| 299 | 299 |
| 300 if (packet->IsValidRtpPacket()) { | 300 if (packet->IsValidRtpPacket()) { |
| 301 // Get the old RTP sequence number and timestamp. | 301 // Get the old RTP sequence number and timestamp. |
| 302 int sequence = 0; | 302 int sequence = 0; |
| 303 packet->GetRtpSeqNum(&sequence); | 303 packet->GetRtpSeqNum(&sequence); |
| 304 uint32 timestamp = 0; | 304 uint32_t timestamp = 0; |
| 305 packet->GetRtpTimestamp(×tamp); | 305 packet->GetRtpTimestamp(×tamp); |
| 306 // Increase the RTP sequence number and timestamp. | 306 // Increase the RTP sequence number and timestamp. |
| 307 sequence += loop_count_ * rtp_seq_num_increase_; | 307 sequence += loop_count_ * rtp_seq_num_increase_; |
| 308 timestamp += loop_count_ * rtp_timestamp_increase_; | 308 timestamp += loop_count_ * rtp_timestamp_increase_; |
| 309 // Write the updated sequence number and timestamp back to the RTP packet. | 309 // Write the updated sequence number and timestamp back to the RTP packet. |
| 310 rtc::ByteBuffer buffer; | 310 rtc::ByteBuffer buffer; |
| 311 buffer.WriteUInt16(sequence); | 311 buffer.WriteUInt16(sequence); |
| 312 buffer.WriteUInt32(timestamp); | 312 buffer.WriteUInt32(timestamp); |
| 313 memcpy(&packet->data[2], buffer.Data(), buffer.Length()); | 313 memcpy(&packet->data[2], buffer.Data(), buffer.Length()); |
| 314 } | 314 } |
| 315 } | 315 } |
| 316 | 316 |
| 317 /////////////////////////////////////////////////////////////////////////// | 317 /////////////////////////////////////////////////////////////////////////// |
| 318 // Implementation of RtpDumpWriter. | 318 // Implementation of RtpDumpWriter. |
| 319 /////////////////////////////////////////////////////////////////////////// | 319 /////////////////////////////////////////////////////////////////////////// |
| 320 | 320 |
| 321 RtpDumpWriter::RtpDumpWriter(rtc::StreamInterface* stream) | 321 RtpDumpWriter::RtpDumpWriter(rtc::StreamInterface* stream) |
| 322 : stream_(stream), | 322 : stream_(stream), |
| 323 packet_filter_(PF_ALL), | 323 packet_filter_(PF_ALL), |
| 324 file_header_written_(false), | 324 file_header_written_(false), |
| 325 start_time_ms_(rtc::Time()), | 325 start_time_ms_(rtc::Time()), |
| 326 warn_slow_writes_delay_(kWarnSlowWritesDelayMs) { | 326 warn_slow_writes_delay_(kWarnSlowWritesDelayMs) { |
| 327 } | 327 } |
| 328 | 328 |
| 329 void RtpDumpWriter::set_packet_filter(int filter) { | 329 void RtpDumpWriter::set_packet_filter(int filter) { |
| 330 packet_filter_ = filter; | 330 packet_filter_ = filter; |
| 331 LOG(LS_INFO) << "RtpDumpWriter set_packet_filter to " << packet_filter_; | 331 LOG(LS_INFO) << "RtpDumpWriter set_packet_filter to " << packet_filter_; |
| 332 } | 332 } |
| 333 | 333 |
| 334 uint32 RtpDumpWriter::GetElapsedTime() const { | 334 uint32_t RtpDumpWriter::GetElapsedTime() const { |
| 335 return rtc::TimeSince(start_time_ms_); | 335 return rtc::TimeSince(start_time_ms_); |
| 336 } | 336 } |
| 337 | 337 |
| 338 rtc::StreamResult RtpDumpWriter::WriteFileHeader() { | 338 rtc::StreamResult RtpDumpWriter::WriteFileHeader() { |
| 339 rtc::StreamResult res = WriteToStream( | 339 rtc::StreamResult res = WriteToStream( |
| 340 RtpDumpFileHeader::kFirstLine, | 340 RtpDumpFileHeader::kFirstLine, |
| 341 strlen(RtpDumpFileHeader::kFirstLine)); | 341 strlen(RtpDumpFileHeader::kFirstLine)); |
| 342 if (res != rtc::SR_SUCCESS) { | 342 if (res != rtc::SR_SUCCESS) { |
| 343 return res; | 343 return res; |
| 344 } | 344 } |
| 345 | 345 |
| 346 rtc::ByteBuffer buf; | 346 rtc::ByteBuffer buf; |
| 347 RtpDumpFileHeader file_header(rtc::Time(), 0, 0); | 347 RtpDumpFileHeader file_header(rtc::Time(), 0, 0); |
| 348 file_header.WriteToByteBuffer(&buf); | 348 file_header.WriteToByteBuffer(&buf); |
| 349 return WriteToStream(buf.Data(), buf.Length()); | 349 return WriteToStream(buf.Data(), buf.Length()); |
| 350 } | 350 } |
| 351 | 351 |
| 352 rtc::StreamResult RtpDumpWriter::WritePacket( | 352 rtc::StreamResult RtpDumpWriter::WritePacket(const void* data, |
| 353 const void* data, size_t data_len, uint32 elapsed, bool rtcp) { | 353 size_t data_len, |
| 354 uint32_t elapsed, |
| 355 bool rtcp) { |
| 354 if (!stream_ || !data || 0 == data_len) return rtc::SR_ERROR; | 356 if (!stream_ || !data || 0 == data_len) return rtc::SR_ERROR; |
| 355 | 357 |
| 356 rtc::StreamResult res = rtc::SR_SUCCESS; | 358 rtc::StreamResult res = rtc::SR_SUCCESS; |
| 357 // Write the file header if it has not been written yet. | 359 // Write the file header if it has not been written yet. |
| 358 if (!file_header_written_) { | 360 if (!file_header_written_) { |
| 359 res = WriteFileHeader(); | 361 res = WriteFileHeader(); |
| 360 if (res != rtc::SR_SUCCESS) { | 362 if (res != rtc::SR_SUCCESS) { |
| 361 return res; | 363 return res; |
| 362 } | 364 } |
| 363 file_header_written_ = true; | 365 file_header_written_ = true; |
| 364 } | 366 } |
| 365 | 367 |
| 366 // Figure out what to write. | 368 // Figure out what to write. |
| 367 size_t write_len = FilterPacket(data, data_len, rtcp); | 369 size_t write_len = FilterPacket(data, data_len, rtcp); |
| 368 if (write_len == 0) { | 370 if (write_len == 0) { |
| 369 return rtc::SR_SUCCESS; | 371 return rtc::SR_SUCCESS; |
| 370 } | 372 } |
| 371 | 373 |
| 372 // Write the dump packet header. | 374 // Write the dump packet header. |
| 373 rtc::ByteBuffer buf; | 375 rtc::ByteBuffer buf; |
| 374 buf.WriteUInt16(static_cast<uint16>( | 376 buf.WriteUInt16( |
| 375 RtpDumpPacket::kHeaderLength + write_len)); | 377 static_cast<uint16_t>(RtpDumpPacket::kHeaderLength + write_len)); |
| 376 buf.WriteUInt16(static_cast<uint16>(rtcp ? 0 : data_len)); | 378 buf.WriteUInt16(static_cast<uint16_t>(rtcp ? 0 : data_len)); |
| 377 buf.WriteUInt32(elapsed); | 379 buf.WriteUInt32(elapsed); |
| 378 res = WriteToStream(buf.Data(), buf.Length()); | 380 res = WriteToStream(buf.Data(), buf.Length()); |
| 379 if (res != rtc::SR_SUCCESS) { | 381 if (res != rtc::SR_SUCCESS) { |
| 380 return res; | 382 return res; |
| 381 } | 383 } |
| 382 | 384 |
| 383 // Write the header or full packet as indicated by write_len. | 385 // Write the header or full packet as indicated by write_len. |
| 384 return WriteToStream(data, write_len); | 386 return WriteToStream(data, write_len); |
| 385 } | 387 } |
| 386 | 388 |
| (...skipping 16 matching lines...) Expand all Loading... |
| 403 // RTCP header + payload | 405 // RTCP header + payload |
| 404 filtered_len = data_len; | 406 filtered_len = data_len; |
| 405 } | 407 } |
| 406 } | 408 } |
| 407 | 409 |
| 408 return filtered_len; | 410 return filtered_len; |
| 409 } | 411 } |
| 410 | 412 |
| 411 rtc::StreamResult RtpDumpWriter::WriteToStream( | 413 rtc::StreamResult RtpDumpWriter::WriteToStream( |
| 412 const void* data, size_t data_len) { | 414 const void* data, size_t data_len) { |
| 413 uint32 before = rtc::Time(); | 415 uint32_t before = rtc::Time(); |
| 414 rtc::StreamResult result = | 416 rtc::StreamResult result = |
| 415 stream_->WriteAll(data, data_len, NULL, NULL); | 417 stream_->WriteAll(data, data_len, NULL, NULL); |
| 416 uint32 delay = rtc::TimeSince(before); | 418 uint32_t delay = rtc::TimeSince(before); |
| 417 if (delay >= warn_slow_writes_delay_) { | 419 if (delay >= warn_slow_writes_delay_) { |
| 418 LOG(LS_WARNING) << "Slow RtpDump: took " << delay << "ms to write " | 420 LOG(LS_WARNING) << "Slow RtpDump: took " << delay << "ms to write " |
| 419 << data_len << " bytes."; | 421 << data_len << " bytes."; |
| 420 } | 422 } |
| 421 return result; | 423 return result; |
| 422 } | 424 } |
| 423 | 425 |
| 424 } // namespace cricket | 426 } // namespace cricket |
| OLD | NEW |