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 cda776bf22b2cdcef3510233fe94acda11286aa4..9635e92bb85061b00a6f23d97b3a83240e915d27 100644 |
--- a/webrtc/modules/rtp_rtcp/source/rtp_sender.cc |
+++ b/webrtc/modules/rtp_rtcp/source/rtp_sender.cc |
@@ -22,6 +22,7 @@ |
#include "webrtc/call/rtc_event_log.h" |
#include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h" |
#include "webrtc/modules/rtp_rtcp/source/byte_io.h" |
+#include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h" |
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h" |
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h" |
#include "webrtc/modules/rtp_rtcp/source/time_util.h" |
@@ -288,7 +289,7 @@ int32_t RTPSender::DeregisterRtpHeaderExtension(RTPExtensionType type) { |
return rtp_header_extension_map_.Deregister(type); |
} |
-size_t RTPSender::RtpHeaderExtensionTotalLength() const { |
+size_t RTPSender::RtpHeaderExtensionMaxLength() const { |
rtc::CritScope lock(&send_critsect_); |
return rtp_header_extension_map_.GetTotalLengthInBytes(); |
} |
@@ -386,11 +387,11 @@ size_t RTPSender::MaxDataPayloadLength() const { |
rtx = rtx_; |
} |
if (audio_configured_) { |
- return max_payload_length_ - RTPHeaderLength(); |
+ return max_payload_length_ - RtpHeaderMaxLength(); |
} else { |
- return max_payload_length_ - RTPHeaderLength() // RTP overhead. |
- - video_->FECPacketOverhead() // FEC/ULP/RED overhead. |
- - ((rtx) ? 2 : 0); // RTX overhead. |
+ return max_payload_length_ - RtpHeaderMaxLength() // RTP overhead. |
+ - video_->FECPacketOverhead() // FEC/ULP/RED overhead. |
+ - ((rtx) ? 2 : 0); // RTX overhead. |
} |
} |
@@ -491,10 +492,12 @@ int32_t RTPSender::SendOutgoingData(FrameType frame_type, |
const RTPFragmentationHeader* fragmentation, |
const RTPVideoHeader* rtp_hdr) { |
uint32_t ssrc; |
+ uint16_t sequence_number; |
{ |
// Drop this packet if we're not sending media packets. |
rtc::CritScope lock(&send_critsect_); |
ssrc = ssrc_; |
+ sequence_number = sequence_number_; |
if (!sending_media_) { |
return 0; |
} |
@@ -523,10 +526,14 @@ int32_t RTPSender::SendOutgoingData(FrameType frame_type, |
if (frame_type == kEmptyFrame) |
return 0; |
- ret_val = |
- video_->SendVideo(video_type, frame_type, payload_type, |
- capture_timestamp, capture_time_ms, payload_data, |
- payload_size, fragmentation, rtp_hdr); |
+ if (rtp_hdr) { |
+ playout_delay_oracle_.UpdateRequest(ssrc, rtp_hdr->playout_delay, |
+ sequence_number); |
+ } |
+ |
+ ret_val = video_->SendVideo( |
+ video_type, frame_type, payload_type, capture_timestamp, |
+ capture_time_ms, payload_data, payload_size, fragmentation, rtp_hdr); |
} |
rtc::CritScope cs(&statistics_crit_); |
@@ -821,6 +828,11 @@ void RTPSender::OnReceivedNACK(const std::list<uint16_t>& nack_sequence_numbers, |
} |
} |
+void RTPSender::OnReceivedRtcpReceiverReport( |
+ const ReportBlockList& report_blocks) { |
+ playout_delay_oracle_.OnReceivedRtcpReceiverReport(report_blocks); |
+} |
+ |
bool RTPSender::ProcessNACKBitRate(uint32_t now) { |
uint32_t num = 0; |
size_t byte_count = 0; |
@@ -1139,11 +1151,19 @@ void RTPSender::ProcessBitrate() { |
video_->ProcessBitrate(); |
} |
-size_t RTPSender::RTPHeaderLength() const { |
+size_t RTPSender::RtpHeaderCurrentLength() const { |
rtc::CritScope lock(&send_critsect_); |
size_t rtp_header_length = kRtpHeaderLength; |
rtp_header_length += sizeof(uint32_t) * csrcs_.size(); |
- rtp_header_length += RtpHeaderExtensionTotalLength(); |
+ rtp_header_length += RtpHeaderExtensionCurrentLength(); |
+ return rtp_header_length; |
+} |
+ |
+size_t RTPSender::RtpHeaderMaxLength() const { |
+ rtc::CritScope lock(&send_critsect_); |
+ size_t rtp_header_length = kRtpHeaderLength; |
+ rtp_header_length += sizeof(uint32_t) * csrcs_.size(); |
+ rtp_header_length += RtpHeaderExtensionMaxLength(); |
return rtp_header_length; |
} |
@@ -1270,6 +1290,13 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer, |
block_length = BuildTransportSequenceNumberExtension( |
extension_data, transport_sequence_number_); |
break; |
+ case kRtpExtensionPlayoutDelay: |
+ if (playout_delay_oracle_.send_playout_delay()) { |
+ block_length = BuildPlayoutDelayExtension( |
+ extension_data, playout_delay_oracle_.min_playout_delay_ms(), |
+ playout_delay_oracle_.max_playout_delay_ms()); |
+ } |
+ break; |
default: |
assert(false); |
} |
@@ -1294,6 +1321,69 @@ uint16_t RTPSender::BuildRTPHeaderExtension(uint8_t* data_buffer, |
return kHeaderLength + total_block_length; |
} |
+size_t RTPSender::RtpHeaderExtensionCurrentLength() const { |
danilchap
2016/06/02 12:12:34
this function sums size of all extensions, includi
Irfan
2016/06/02 18:15:53
I did not realize TotalLength was already taking i
|
+ if (rtp_header_extension_map_.Size() <= 0) |
+ return 0; |
+ |
+ int header_length = 0; |
+ uint8_t id; |
+ |
+ RTPExtensionType type = rtp_header_extension_map_.First(); |
+ while (type != kRtpExtensionNone) { |
+ switch (type) { |
+ case kRtpExtensionTransmissionTimeOffset: |
+ if (rtp_header_extension_map_.GetId(kRtpExtensionTransmissionTimeOffset, |
Stefan
2016/06/02 08:07:09
Would have been nice with a method which simply ch
danilchap
2016/06/02 12:12:34
rtp_header_extension_map_ has method IsRegistered
Irfan
2016/06/02 18:15:53
This is now removed in favour of just treating pla
|
+ &id) == 0) { |
+ header_length += kTransmissionTimeOffsetLength; |
+ } |
+ break; |
+ case kRtpExtensionAudioLevel: |
+ if (rtp_header_extension_map_.GetId(kRtpExtensionAudioLevel, &id) == |
+ 0) { |
+ header_length += kAudioLevelLength; |
+ } |
+ break; |
+ case kRtpExtensionAbsoluteSendTime: |
+ if (rtp_header_extension_map_.GetId(kRtpExtensionAbsoluteSendTime, |
+ &id) == 0) { |
+ header_length += kAbsoluteSendTimeLength; |
+ } |
+ break; |
+ case kRtpExtensionVideoRotation: |
+ if (rtp_header_extension_map_.GetId(kRtpExtensionVideoRotation, &id) == |
danilchap
2016/06/02 12:12:34
this means video rotation extension would be count
Irfan
2016/06/02 18:15:53
see above
|
+ 0) { |
+ header_length += kVideoRotationLength; |
+ } |
+ break; |
+ case kRtpExtensionTransportSequenceNumber: |
+ if (rtp_header_extension_map_.GetId( |
+ kRtpExtensionTransportSequenceNumber, &id) == 0) { |
+ header_length += kTransportSequenceNumberLength; |
+ } |
+ break; |
+ case kRtpExtensionPlayoutDelay: |
+ if (playout_delay_oracle_.send_playout_delay()) { |
+ if (rtp_header_extension_map_.GetId(kRtpExtensionPlayoutDelay, &id) == |
+ 0) { |
+ header_length += kPlayoutDelayLength; |
+ } |
+ } |
+ break; |
+ default: |
danilchap
2016/06/02 12:12:34
do not use default, this way compiler would warn w
Irfan
2016/06/02 18:15:52
removed
|
+ assert(false); |
+ } |
+ type = rtp_header_extension_map_.Next(type); |
+ } |
+ if (header_length == 0) |
+ return 0; |
+ // Add padding to fill a 32 bit block. |
+ size_t padding_bytes = RtpUtility::Word32Align(header_length) - header_length; |
danilchap
2016/06/02 12:12:34
this three lines could be replaced with header_len
Irfan
2016/06/02 18:15:53
removed
|
+ if (padding_bytes > 0) |
+ header_length += padding_bytes; |
+ |
+ return header_length + kRtpOneByteHeaderLength; |
+} |
+ |
uint8_t RTPSender::BuildTransmissionTimeOffsetExtension( |
uint8_t* data_buffer) const { |
// From RFC 5450: Transmission Time Offsets in RTP Streams. |
@@ -1445,6 +1535,37 @@ uint8_t RTPSender::BuildTransportSequenceNumberExtension( |
return kTransportSequenceNumberLength; |
} |
+uint8_t RTPSender::BuildPlayoutDelayExtension( |
+ uint8_t* data_buffer, |
+ uint16_t min_playout_delay_ms, |
+ uint16_t max_playout_delay_ms) const { |
+ RTC_DCHECK_LE(min_playout_delay_ms, kPlayoutDelayMaxMs); |
+ RTC_DCHECK_LE(max_playout_delay_ms, kPlayoutDelayMaxMs); |
+ RTC_DCHECK_LE(min_playout_delay_ms, max_playout_delay_ms); |
+ // 0 1 2 3 |
+ // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ // | ID | len=2 | MIN delay | MAX delay | |
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
+ uint8_t id; |
+ if (rtp_header_extension_map_.GetId(kRtpExtensionPlayoutDelay, &id) != 0) { |
+ // Not registered. |
+ return 0; |
+ } |
+ size_t pos = 0; |
+ const uint8_t len = 2; |
+ // Convert MS to value to be sent on extension header. |
+ uint16_t min_playout = min_playout_delay_ms / kPlayoutDelayGranularityMs; |
+ uint16_t max_playout = max_playout_delay_ms / kPlayoutDelayGranularityMs; |
+ |
+ data_buffer[pos++] = (id << 4) + len; |
+ data_buffer[pos++] = min_playout >> 4; |
+ data_buffer[pos++] = ((min_playout & 0xf) << 4) | (max_playout >> 8); |
+ data_buffer[pos++] = max_playout & 0xff; |
+ assert(pos == kPlayoutDelayLength); |
+ return kPlayoutDelayLength; |
+} |
+ |
bool RTPSender::FindHeaderExtensionPosition(RTPExtensionType type, |
const uint8_t* rtp_packet, |
size_t rtp_packet_length, |