Chromium Code Reviews| Index: webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 
| diff --git a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 
| index e7306a11bd3f2ca56ffd5d733a7cb278607fc396..57fe33b88d94228abd3606e9739b912866503a55 100644 | 
| --- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 
| +++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc | 
| @@ -103,6 +103,7 @@ RTPSender::RTPSender(int32_t id, | 
| Transport* transport, | 
| RtpAudioFeedback* audio_feedback, | 
| PacedSender* paced_sender, | 
| + PacketRouter* packet_router, | 
| BitrateStatisticsObserver* bitrate_callback, | 
| FrameCountObserver* frame_count_observer, | 
| SendSideDelayObserver* send_side_delay_observer) | 
| @@ -119,6 +120,7 @@ RTPSender::RTPSender(int32_t id, | 
| : nullptr), | 
| video_(audio ? nullptr : new RTPSenderVideo(clock, this)), | 
| paced_sender_(paced_sender), | 
| + packet_router_(packet_router), | 
| last_capture_time_ms_sent_(0), | 
| send_critsect_(CriticalSectionWrapper::CreateCriticalSection()), | 
| transport_(transport), | 
| @@ -603,6 +605,9 @@ size_t RTPSender::SendPadData(uint32_t timestamp, | 
| size_t bytes) { | 
| size_t padding_bytes_in_packet = 0; | 
| size_t bytes_sent = 0; | 
| + bool using_transport_seq = rtp_header_extension_map_.IsRegistered( | 
| + kRtpExtensionTransportSequenceNumber) && | 
| + packet_router_; | 
| for (; bytes > 0; bytes -= padding_bytes_in_packet) { | 
| // Always send full padding packets. | 
| if (bytes < kMaxPaddingLength) | 
| @@ -659,8 +664,19 @@ size_t RTPSender::SendPadData(uint32_t timestamp, | 
| } | 
| UpdateAbsoluteSendTime(padding_packet, length, rtp_header, now_ms); | 
| + | 
| + uint16_t transport_seq = 0; | 
| + if (using_transport_seq) { | 
| + transport_seq = | 
| + UpdateTransportSequenceNumber(padding_packet, length, rtp_header); | 
| + } | 
| + | 
| + UpdateTransportSequenceNumber(padding_packet, length, rtp_header); | 
| if (!SendPacketToNetwork(padding_packet, length)) | 
| break; | 
| + if (using_transport_seq) | 
| + packet_router_->OnPacketSent(transport_seq, now_ms); | 
| + | 
| bytes_sent += padding_bytes_in_packet; | 
| UpdateRtpStats(padding_packet, length, rtp_header, over_rtx, false); | 
| } | 
| @@ -710,9 +726,11 @@ int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) { | 
| CriticalSectionScoped lock(send_critsect_.get()); | 
| rtx = rtx_; | 
| } | 
| - return PrepareAndSendPacket(data_buffer, length, capture_time_ms, | 
| - (rtx & kRtxRetransmitted) > 0, true) ? | 
| - static_cast<int32_t>(length) : -1; | 
| + if (!PrepareAndSendPacket(data_buffer, length, capture_time_ms, | 
| + (rtx & kRtxRetransmitted) > 0, true)) { | 
| + return -1; | 
| + } | 
| + return static_cast<int32_t>(length); | 
| } | 
| bool RTPSender::SendPacketToNetwork(const uint8_t *packet, size_t size) { | 
| @@ -897,11 +915,23 @@ bool RTPSender::PrepareAndSendPacket(uint8_t* buffer, | 
| UpdateTransmissionTimeOffset(buffer_to_send_ptr, length, rtp_header, | 
| diff_ms); | 
| UpdateAbsoluteSendTime(buffer_to_send_ptr, length, rtp_header, now_ms); | 
| + | 
| + uint16_t transport_seq = 0; | 
| + bool using_transport_seq = rtp_header_extension_map_.IsRegistered( | 
| + kRtpExtensionTransportSequenceNumber) && | 
| + packet_router_; | 
| + if (using_transport_seq) { | 
| + transport_seq = | 
| + UpdateTransportSequenceNumber(buffer_to_send_ptr, length, rtp_header); | 
| 
 
stefan-webrtc
2015/07/22 10:49:00
You have probably thought about this, but is there
 
sprang_webrtc
2015/07/22 15:11:32
Three reasons: 
1. When it's TimeToSendPadding<tm>
 
stefan-webrtc
2015/07/27 12:13:49
Acknowledged.
 
 | 
| + } | 
| + | 
| bool ret = SendPacketToNetwork(buffer_to_send_ptr, length); | 
| if (ret) { | 
| CriticalSectionScoped lock(send_critsect_.get()); | 
| media_has_been_sent_ = true; | 
| } | 
| + if (using_transport_seq) | 
| + packet_router_->OnPacketSent(transport_seq, now_ms); | 
| UpdateRtpStats(buffer_to_send_ptr, length, rtp_header, send_over_rtx, | 
| is_retransmit); | 
| return ret; | 
| @@ -960,7 +990,8 @@ size_t RTPSender::TimeToSendPadding(size_t bytes) { | 
| return 0; | 
| { | 
| CriticalSectionScoped cs(send_critsect_.get()); | 
| - if (!sending_media_) return 0; | 
| + if (!sending_media_) | 
| + return 0; | 
| } | 
| size_t bytes_sent = TrySendRedundantPayloads(bytes); | 
| if (bytes_sent < bytes) | 
| @@ -1212,7 +1243,8 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer, | 
| block_length = BuildVideoRotationExtension(extension_data); | 
| break; | 
| case kRtpExtensionTransportSequenceNumber: | 
| - block_length = BuildTransportSequenceNumberExtension(extension_data); | 
| + block_length = BuildTransportSequenceNumberExtension( | 
| + extension_data, transport_sequence_number_); | 
| break; | 
| default: | 
| assert(false); | 
| @@ -1365,7 +1397,8 @@ uint8_t RTPSender::BuildVideoRotationExtension(uint8_t* data_buffer) const { | 
| } | 
| uint8_t RTPSender::BuildTransportSequenceNumberExtension( | 
| - uint8_t* data_buffer) const { | 
| + uint8_t* data_buffer, | 
| + uint16_t sequence_number) const { | 
| // 0 1 2 | 
| // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 | 
| // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | 
| @@ -1382,8 +1415,7 @@ uint8_t RTPSender::BuildTransportSequenceNumberExtension( | 
| size_t pos = 0; | 
| const uint8_t len = 1; | 
| data_buffer[pos++] = (id << 4) + len; | 
| - ByteWriter<uint16_t>::WriteBigEndian(data_buffer + pos, | 
| - transport_sequence_number_); | 
| + ByteWriter<uint16_t>::WriteBigEndian(data_buffer + pos, sequence_number); | 
| pos += 2; | 
| assert(pos == kTransportSequenceNumberLength); | 
| return kTransportSequenceNumberLength; | 
| @@ -1426,35 +1458,62 @@ bool RTPSender::FindHeaderExtensionPosition(RTPExtensionType type, | 
| return true; | 
| } | 
| -void RTPSender::UpdateTransmissionTimeOffset(uint8_t* rtp_packet, | 
| - size_t rtp_packet_length, | 
| - const RTPHeader& rtp_header, | 
| - int64_t time_diff_ms) const { | 
| - CriticalSectionScoped cs(send_critsect_.get()); | 
| +RTPSender::ExtensionStatus RTPSender::VerifyExtension( | 
| + RTPExtensionType extension_type, | 
| + uint8_t* rtp_packet, | 
| + size_t rtp_packet_length, | 
| + const RTPHeader& rtp_header, | 
| + size_t extension_length_bytes, | 
| + size_t* extension_offset) const { | 
| // Get id. | 
| uint8_t id = 0; | 
| - if (rtp_header_extension_map_.GetId(kRtpExtensionTransmissionTimeOffset, | 
| - &id) != 0) { | 
| - // Not registered. | 
| - return; | 
| - } | 
| + if (rtp_header_extension_map_.GetId(extension_type, &id) != 0) | 
| + return ExtensionStatus::kNotRegistered; | 
| size_t block_pos = 0; | 
| - if (!FindHeaderExtensionPosition(kRtpExtensionTransmissionTimeOffset, | 
| - rtp_packet, rtp_packet_length, rtp_header, | 
| - &block_pos)) { | 
| - LOG(LS_WARNING) << "Failed to update transmission time offset."; | 
| - return; | 
| + if (!FindHeaderExtensionPosition(extension_type, rtp_packet, | 
| + rtp_packet_length, rtp_header, &block_pos)) | 
| + return ExtensionStatus::kError; | 
| + | 
| + // Verify that header contains extension. | 
| + if (!((rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs] == 0xBE) && | 
| + (rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs + 1] == 0xDE))) { | 
| + LOG(LS_WARNING) | 
| + << "Failed to update absolute send time, hdr extension not found."; | 
| + return ExtensionStatus::kError; | 
| } | 
| // Verify first byte in block. | 
| - const uint8_t first_block_byte = (id << 4) + 2; | 
| - if (rtp_packet[block_pos] != first_block_byte) { | 
| - LOG(LS_WARNING) << "Failed to update transmission time offset."; | 
| - return; | 
| + const uint8_t first_block_byte = (id << 4) + (extension_length_bytes - 2); | 
| + if (rtp_packet[block_pos] != first_block_byte) | 
| + return ExtensionStatus::kError; | 
| + | 
| + *extension_offset = block_pos; | 
| + return ExtensionStatus::kOk; | 
| +} | 
| + | 
| +void RTPSender::UpdateTransmissionTimeOffset(uint8_t* rtp_packet, | 
| + size_t rtp_packet_length, | 
| + const RTPHeader& rtp_header, | 
| + int64_t time_diff_ms) const { | 
| + size_t offset; | 
| + CriticalSectionScoped cs(send_critsect_.get()); | 
| + switch (VerifyExtension(kRtpExtensionTransmissionTimeOffset, rtp_packet, | 
| + rtp_packet_length, rtp_header, | 
| + kTransmissionTimeOffsetLength, &offset)) { | 
| + case ExtensionStatus::kNotRegistered: | 
| + return; | 
| + case ExtensionStatus::kError: | 
| + LOG(LS_WARNING) << "Failed to update transmission time offset."; | 
| + return; | 
| + case ExtensionStatus::kOk: | 
| + break; | 
| + default: | 
| + RTC_NOTREACHED(); | 
| } | 
| + | 
| // Update transmission offset field (converting to a 90 kHz timestamp). | 
| - ByteWriter<int32_t, 3>::WriteBigEndian(rtp_packet + block_pos + 1, | 
| + ByteWriter<int32_t, 3>::WriteBigEndian(rtp_packet + offset + 1, | 
| time_diff_ms * 90); // RTP timestamp. | 
| } | 
| @@ -1463,29 +1522,24 @@ bool RTPSender::UpdateAudioLevel(uint8_t* rtp_packet, | 
| const RTPHeader& rtp_header, | 
| bool is_voiced, | 
| uint8_t dBov) const { | 
| + size_t offset; | 
| CriticalSectionScoped cs(send_critsect_.get()); | 
| - // Get id. | 
| - uint8_t id = 0; | 
| - if (rtp_header_extension_map_.GetId(kRtpExtensionAudioLevel, &id) != 0) { | 
| - // Not registered. | 
| - return false; | 
| - } | 
| - | 
| - size_t block_pos = 0; | 
| - if (!FindHeaderExtensionPosition(kRtpExtensionAudioLevel, rtp_packet, | 
| - rtp_packet_length, rtp_header, &block_pos)) { | 
| - LOG(LS_WARNING) << "Failed to update audio level."; | 
| - return false; | 
| + switch (VerifyExtension(kRtpExtensionAudioLevel, rtp_packet, | 
| + rtp_packet_length, rtp_header, kAudioLevelLength, | 
| + &offset)) { | 
| + case ExtensionStatus::kNotRegistered: | 
| + return false; | 
| + case ExtensionStatus::kError: | 
| + LOG(LS_WARNING) << "Failed to update audio level."; | 
| + return false; | 
| + case ExtensionStatus::kOk: | 
| + break; | 
| + default: | 
| + RTC_NOTREACHED(); | 
| } | 
| - // Verify first byte in block. | 
| - const uint8_t first_block_byte = (id << 4) + 0; | 
| - if (rtp_packet[block_pos] != first_block_byte) { | 
| - LOG(LS_WARNING) << "Failed to update audio level."; | 
| - return false; | 
| - } | 
| - rtp_packet[block_pos + 1] = (is_voiced ? 0x80 : 0x00) + (dBov & 0x7f); | 
| + rtp_packet[offset + 1] = (is_voiced ? 0x80 : 0x00) + (dBov & 0x7f); | 
| return true; | 
| } | 
| @@ -1493,37 +1547,24 @@ bool RTPSender::UpdateVideoRotation(uint8_t* rtp_packet, | 
| size_t rtp_packet_length, | 
| const RTPHeader& rtp_header, | 
| VideoRotation rotation) const { | 
| + size_t offset; | 
| CriticalSectionScoped cs(send_critsect_.get()); | 
| - // Get id. | 
| - uint8_t id = 0; | 
| - if (rtp_header_extension_map_.GetId(kRtpExtensionVideoRotation, &id) != 0) { | 
| - // Not registered. | 
| - return false; | 
| - } | 
| - | 
| - size_t block_pos = 0; | 
| - if (!FindHeaderExtensionPosition(kRtpExtensionVideoRotation, rtp_packet, | 
| - rtp_packet_length, rtp_header, &block_pos)) { | 
| - LOG(LS_WARNING) << "Failed to update video rotation (CVO)."; | 
| - return false; | 
| - } | 
| - // Get length until start of header extension block. | 
| - int extension_block_pos = | 
| - rtp_header_extension_map_.GetLengthUntilBlockStartInBytes( | 
| - kRtpExtensionVideoRotation); | 
| - if (extension_block_pos < 0) { | 
| - // The feature is not enabled. | 
| - return false; | 
| + switch (VerifyExtension(kRtpExtensionVideoRotation, rtp_packet, | 
| + rtp_packet_length, rtp_header, kVideoRotationLength, | 
| + &offset)) { | 
| + case ExtensionStatus::kNotRegistered: | 
| + return false; | 
| + case ExtensionStatus::kError: | 
| + LOG(LS_WARNING) << "Failed to update CVO."; | 
| + return false; | 
| + case ExtensionStatus::kOk: | 
| + break; | 
| + default: | 
| + RTC_NOTREACHED(); | 
| } | 
| - // Verify first byte in block. | 
| - const uint8_t first_block_byte = (id << 4) + 0; | 
| - if (rtp_packet[block_pos] != first_block_byte) { | 
| - LOG(LS_WARNING) << "Failed to update CVO."; | 
| - return false; | 
| - } | 
| - rtp_packet[block_pos + 1] = ConvertVideoRotationToCVOByte(rotation); | 
| + rtp_packet[offset + 1] = ConvertVideoRotationToCVOByte(rotation); | 
| return true; | 
| } | 
| @@ -1531,49 +1572,55 @@ void RTPSender::UpdateAbsoluteSendTime(uint8_t* rtp_packet, | 
| size_t rtp_packet_length, | 
| const RTPHeader& rtp_header, | 
| int64_t now_ms) const { | 
| + size_t offset; | 
| CriticalSectionScoped cs(send_critsect_.get()); | 
| - // Get id. | 
| - uint8_t id = 0; | 
| - if (rtp_header_extension_map_.GetId(kRtpExtensionAbsoluteSendTime, | 
| - &id) != 0) { | 
| - // Not registered. | 
| - return; | 
| - } | 
| - // Get length until start of header extension block. | 
| - int extension_block_pos = | 
| - rtp_header_extension_map_.GetLengthUntilBlockStartInBytes( | 
| - kRtpExtensionAbsoluteSendTime); | 
| - if (extension_block_pos < 0) { | 
| - // The feature is not enabled. | 
| - return; | 
| - } | 
| - size_t block_pos = | 
| - kRtpHeaderLength + rtp_header.numCSRCs + extension_block_pos; | 
| - if (rtp_packet_length < block_pos + kAbsoluteSendTimeLength || | 
| - rtp_header.headerLength < block_pos + kAbsoluteSendTimeLength) { | 
| - LOG(LS_WARNING) << "Failed to update absolute send time, invalid length."; | 
| - return; | 
| - } | 
| - // Verify that header contains extension. | 
| - if (!((rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs] == 0xBE) && | 
| - (rtp_packet[kRtpHeaderLength + rtp_header.numCSRCs + 1] == 0xDE))) { | 
| - LOG(LS_WARNING) | 
| - << "Failed to update absolute send time, hdr extension not found."; | 
| - return; | 
| - } | 
| - // Verify first byte in block. | 
| - const uint8_t first_block_byte = (id << 4) + 2; | 
| - if (rtp_packet[block_pos] != first_block_byte) { | 
| - LOG(LS_WARNING) << "Failed to update absolute send time."; | 
| - return; | 
| + switch (VerifyExtension(kRtpExtensionAbsoluteSendTime, rtp_packet, | 
| + rtp_packet_length, rtp_header, | 
| + kAbsoluteSendTimeLength, &offset)) { | 
| + case ExtensionStatus::kNotRegistered: | 
| + return; | 
| + case ExtensionStatus::kError: | 
| + LOG(LS_WARNING) << "Failed to update absolute send time"; | 
| + return; | 
| + case ExtensionStatus::kOk: | 
| + break; | 
| + default: | 
| + RTC_NOTREACHED(); | 
| } | 
| + | 
| // Update absolute send time field (convert ms to 24-bit unsigned with 18 bit | 
| // fractional part). | 
| - ByteWriter<uint32_t, 3>::WriteBigEndian(rtp_packet + block_pos + 1, | 
| + ByteWriter<uint32_t, 3>::WriteBigEndian(rtp_packet + offset + 1, | 
| ((now_ms << 18) / 1000) & 0x00ffffff); | 
| } | 
| +uint16_t RTPSender::UpdateTransportSequenceNumber( | 
| + uint8_t* rtp_packet, | 
| + size_t rtp_packet_length, | 
| + const RTPHeader& rtp_header) const { | 
| + size_t offset; | 
| + CriticalSectionScoped cs(send_critsect_.get()); | 
| + | 
| + switch (VerifyExtension(kRtpExtensionTransportSequenceNumber, rtp_packet, | 
| + rtp_packet_length, rtp_header, | 
| + kTransportSequenceNumberLength, &offset)) { | 
| + case ExtensionStatus::kNotRegistered: | 
| + return 0; | 
| + case ExtensionStatus::kError: | 
| + LOG(LS_WARNING) << "Failed to update transport sequence number"; | 
| + return 0; | 
| + case ExtensionStatus::kOk: | 
| + break; | 
| + default: | 
| + RTC_NOTREACHED(); | 
| + } | 
| + | 
| + uint16_t seq = packet_router_->AllocateSequenceNumber(); | 
| + BuildTransportSequenceNumberExtension(rtp_packet + offset, seq); | 
| + return seq; | 
| +} | 
| + | 
| void RTPSender::SetSendingStatus(bool enabled) { | 
| if (enabled) { | 
| uint32_t frequency_hz = SendPayloadFrequency(); | 
| @@ -1588,6 +1635,8 @@ void RTPSender::SetSendingStatus(bool enabled) { | 
| ssrc_db_.ReturnSSRC(ssrc_); | 
| ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0. | 
| bitrates_->set_ssrc(ssrc_); | 
| + if (packet_router_) | 
| + packet_router_->OnSsrcChanged(); | 
| } | 
| // Don't initialize seq number if SSRC passed externally. | 
| if (!sequence_number_forced_ && !ssrc_forced_) { | 
| @@ -1639,6 +1688,8 @@ uint32_t RTPSender::GenerateNewSSRC() { | 
| } | 
| ssrc_ = ssrc_db_.CreateSSRC(); // Can't be 0. | 
| bitrates_->set_ssrc(ssrc_); | 
| + if (packet_router_) | 
| + packet_router_->OnSsrcChanged(); | 
| return ssrc_; | 
| } | 
| @@ -1658,6 +1709,8 @@ void RTPSender::SetSSRC(uint32_t ssrc) { | 
| sequence_number_ = | 
| rand() / (RAND_MAX / MAX_INIT_RTP_SEQ_NUMBER); // NOLINT | 
| } | 
| + if (packet_router_) | 
| + packet_router_->OnSsrcChanged(); | 
| } | 
| uint32_t RTPSender::SSRC() const { |