2011-07-07 08:21:25 +00:00
|
|
|
/*
|
2012-01-24 17:16:59 +00:00
|
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
2011-07-07 08:21:25 +00:00
|
|
|
*
|
|
|
|
|
* Use of this source code is governed by a BSD-style license
|
|
|
|
|
* that can be found in the LICENSE file in the root of the source
|
|
|
|
|
* tree. An additional intellectual property rights grant can be found
|
|
|
|
|
* in the file PATENTS. All contributing project authors may
|
|
|
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
|
|
|
*/
|
|
|
|
|
|
2012-11-13 21:12:39 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_sender.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-12-10 05:05:27 -08:00
|
|
|
#include <algorithm>
|
2015-04-21 20:24:50 +08:00
|
|
|
#include <utility>
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-04-21 20:24:50 +08:00
|
|
|
#include "webrtc/base/checks.h"
|
2015-10-28 16:39:33 +01:00
|
|
|
#include "webrtc/base/logging.h"
|
2016-07-13 09:11:28 -07:00
|
|
|
#include "webrtc/base/rate_limiter.h"
|
2015-10-20 23:00:48 -07:00
|
|
|
#include "webrtc/base/trace_event.h"
|
2016-05-10 16:31:47 +02:00
|
|
|
#include "webrtc/base/timeutils.h"
|
2016-01-21 05:42:04 -08:00
|
|
|
#include "webrtc/call.h"
|
Moved RtcEventLog files from call/ to logging/
The RtcEventLog headers need to be accessible from any place which needs
logging, and the implementation needs access to data structures that are
logged.
After a discussion in the code review, we all agreed to move the RtcEventLog implementation into its own top level directory - which I called "logging/" in expectation that other types of logging may have similar requirements. The directory contains two main build targets - "rtc_event_log_api", which is just rtc_event_log.h, that has no external dependencies and can be used from anywhere, and "rtc_event_log_impl" which contains the rest of the implementation and has many dependencies (more in the future).
The "api" target can be referenced from anywhere, while the "impl" target is only needed at the place of instantiation (currently Call, soon to be moved to PeerConnection by https://codereview.webrtc.org/2353033005/).
This change allows using RtcEventLog in the p2p/ directory, so that we
can log STUN pings and ICE state transitions.
BUG=webrtc:6393
R=kjellander@webrtc.org, kwiberg@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, terelius@webrtc.org
Review URL: https://codereview.webrtc.org/2380683005 .
Cr-Commit-Position: refs/heads/master@{#14485}
2016-10-03 18:31:22 -07:00
|
|
|
#include "webrtc/logging/rtc_event_log/rtc_event_log.h"
|
2016-09-14 05:04:36 -07:00
|
|
|
#include "webrtc/modules/remote_bitrate_estimator/test/bwe_test_logging.h"
|
2015-11-04 08:31:52 +01:00
|
|
|
#include "webrtc/modules/rtp_rtcp/include/rtp_cvo.h"
|
2015-03-17 16:42:49 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/byte_io.h"
|
2016-06-08 00:24:21 -07:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/playout_delay_oracle.h"
|
2016-08-03 18:27:40 +02:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_header_extensions.h"
|
|
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_packet_to_send.h"
|
2012-11-13 21:12:39 +00:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_audio.h"
|
|
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_sender_video.h"
|
2015-12-21 11:06:50 -08:00
|
|
|
#include "webrtc/modules/rtp_rtcp/source/time_util.h"
|
2011-07-07 08:21:25 +00:00
|
|
|
|
|
|
|
|
namespace webrtc {
|
2013-01-25 10:53:38 +00:00
|
|
|
|
2013-04-09 19:54:10 +00:00
|
|
|
namespace {
|
2016-08-03 18:27:40 +02:00
|
|
|
// Max in the RFC 3550 is 255 bytes, we limit it to be modulus 32 for SRTP.
|
|
|
|
|
constexpr size_t kMaxPaddingLength = 224;
|
|
|
|
|
constexpr int kSendSideDelayWindowMs = 1000;
|
|
|
|
|
constexpr size_t kRtpHeaderLength = 12;
|
|
|
|
|
constexpr uint16_t kMaxInitRtpSeqNumber = 32767; // 2^15 -1.
|
|
|
|
|
constexpr uint32_t kTimestampTicksPerMs = 90;
|
|
|
|
|
constexpr int kBitrateStatisticsWindowMs = 1000;
|
2015-03-04 22:55:15 +00:00
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
const char* FrameTypeToString(FrameType frame_type) {
|
2013-04-09 19:54:10 +00:00
|
|
|
switch (frame_type) {
|
2015-10-19 02:39:06 -07:00
|
|
|
case kEmptyFrame:
|
|
|
|
|
return "empty";
|
2013-04-09 19:54:10 +00:00
|
|
|
case kAudioFrameSpeech: return "audio_speech";
|
|
|
|
|
case kAudioFrameCN: return "audio_cn";
|
|
|
|
|
case kVideoFrameKey: return "video_key";
|
|
|
|
|
case kVideoFrameDelta: return "video_delta";
|
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
void CountPacket(RtpPacketCounter* counter, const RtpPacketToSend& packet) {
|
|
|
|
|
++counter->packets;
|
|
|
|
|
counter->header_bytes += packet.headers_size();
|
|
|
|
|
counter->padding_bytes += packet.padding_size();
|
|
|
|
|
counter->payload_bytes += packet.payload_size();
|
2015-10-21 13:41:48 +02:00
|
|
|
}
|
2016-08-03 18:27:40 +02:00
|
|
|
|
2013-04-09 19:54:10 +00:00
|
|
|
} // namespace
|
|
|
|
|
|
2015-09-21 15:11:14 -07:00
|
|
|
RTPSender::RTPSender(
|
|
|
|
|
bool audio,
|
|
|
|
|
Clock* clock,
|
|
|
|
|
Transport* transport,
|
|
|
|
|
RtpPacketSender* paced_sender,
|
2016-11-10 05:04:48 -08:00
|
|
|
FlexfecSender* flexfec_sender,
|
2015-09-21 15:11:14 -07:00
|
|
|
TransportSequenceNumberAllocator* sequence_number_allocator,
|
|
|
|
|
TransportFeedbackObserver* transport_feedback_observer,
|
|
|
|
|
BitrateStatisticsObserver* bitrate_callback,
|
|
|
|
|
FrameCountObserver* frame_count_observer,
|
2016-01-21 05:42:04 -08:00
|
|
|
SendSideDelayObserver* send_side_delay_observer,
|
2016-05-02 23:44:01 -07:00
|
|
|
RtcEventLog* event_log,
|
2016-07-13 09:11:28 -07:00
|
|
|
SendPacketObserver* send_packet_observer,
|
|
|
|
|
RateLimiter* retransmission_rate_limiter)
|
2013-12-13 09:46:59 +00:00
|
|
|
: clock_(clock),
|
2016-05-10 16:31:47 +02:00
|
|
|
// TODO(holmer): Remove this conversion?
|
|
|
|
|
clock_delta_ms_(clock_->TimeInMilliseconds() - rtc::TimeMillis()),
|
2015-12-15 00:30:07 -08:00
|
|
|
random_(clock_->TimeInMicroseconds()),
|
2013-12-13 09:46:59 +00:00
|
|
|
audio_configured_(audio),
|
2016-03-15 11:41:53 -07:00
|
|
|
audio_(audio ? new RTPSenderAudio(clock, this) : nullptr),
|
2016-11-10 05:04:48 -08:00
|
|
|
video_(audio ? nullptr : new RTPSenderVideo(clock, this, flexfec_sender)),
|
2013-12-13 09:46:59 +00:00
|
|
|
paced_sender_(paced_sender),
|
2015-09-21 15:11:14 -07:00
|
|
|
transport_sequence_number_allocator_(sequence_number_allocator),
|
2015-09-14 06:42:43 -07:00
|
|
|
transport_feedback_observer_(transport_feedback_observer),
|
2014-11-04 16:27:16 +00:00
|
|
|
last_capture_time_ms_sent_(0),
|
2013-12-13 09:46:59 +00:00
|
|
|
transport_(transport),
|
|
|
|
|
sending_media_(true), // Default to sending media.
|
|
|
|
|
max_payload_length_(IP_PACKET_SIZE - 28), // Default is IP-v4/UDP.
|
|
|
|
|
payload_type_(-1),
|
|
|
|
|
payload_type_map_(),
|
|
|
|
|
rtp_header_extension_map_(),
|
2013-12-04 10:24:26 +00:00
|
|
|
packet_history_(clock),
|
2013-01-25 10:53:38 +00:00
|
|
|
// Statistics
|
2016-07-13 09:11:28 -07:00
|
|
|
rtp_stats_callback_(nullptr),
|
|
|
|
|
total_bitrate_sent_(kBitrateStatisticsWindowMs,
|
|
|
|
|
RateStatistics::kBpsScale),
|
|
|
|
|
nack_bitrate_sent_(kBitrateStatisticsWindowMs, RateStatistics::kBpsScale),
|
2014-07-10 09:39:23 +00:00
|
|
|
frame_count_observer_(frame_count_observer),
|
2014-07-11 13:44:02 +00:00
|
|
|
send_side_delay_observer_(send_side_delay_observer),
|
2016-01-21 05:42:04 -08:00
|
|
|
event_log_(event_log),
|
2016-05-02 23:44:01 -07:00
|
|
|
send_packet_observer_(send_packet_observer),
|
2016-07-13 09:11:28 -07:00
|
|
|
bitrate_callback_(bitrate_callback),
|
2013-12-05 14:29:02 +00:00
|
|
|
// RTP variables
|
2016-02-02 08:31:45 -08:00
|
|
|
ssrc_db_(SSRCDatabase::GetSSRCDatabase()),
|
2013-12-13 09:46:59 +00:00
|
|
|
remote_ssrc_(0),
|
|
|
|
|
sequence_number_forced_(false),
|
|
|
|
|
ssrc_forced_(false),
|
2016-08-22 03:39:23 -07:00
|
|
|
last_rtp_timestamp_(0),
|
2013-12-13 09:46:59 +00:00
|
|
|
capture_time_ms_(0),
|
|
|
|
|
last_timestamp_time_ms_(0),
|
2014-07-17 16:10:14 +00:00
|
|
|
media_has_been_sent_(false),
|
2013-12-13 09:46:59 +00:00
|
|
|
last_packet_marker_bit_(false),
|
|
|
|
|
csrcs_(),
|
|
|
|
|
rtx_(kRtxOff),
|
2016-07-13 09:11:28 -07:00
|
|
|
retransmission_rate_limiter_(retransmission_rate_limiter) {
|
2016-02-02 08:31:45 -08:00
|
|
|
ssrc_ = ssrc_db_->CreateSSRC();
|
|
|
|
|
RTC_DCHECK(ssrc_ != 0);
|
|
|
|
|
ssrc_rtx_ = ssrc_db_->CreateSSRC();
|
|
|
|
|
RTC_DCHECK(ssrc_rtx_ != 0);
|
|
|
|
|
|
2016-08-18 02:01:49 -07:00
|
|
|
// This random initialization is not intended to be cryptographic strong.
|
|
|
|
|
timestamp_offset_ = random_.Rand<uint32_t>();
|
2013-03-15 23:21:52 +00:00
|
|
|
// Random start, 16 bits. Can't be 0.
|
2015-12-15 00:30:07 -08:00
|
|
|
sequence_number_rtx_ = random_.Rand(1, kMaxInitRtpSeqNumber);
|
|
|
|
|
sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-01-19 15:56:10 +00:00
|
|
|
RTPSender::~RTPSender() {
|
2016-02-02 08:31:45 -08:00
|
|
|
// TODO(tommi): Use a thread checker to ensure the object is created and
|
|
|
|
|
// deleted on the same thread. At the moment this isn't possible due to
|
|
|
|
|
// voe::ChannelOwner in voice engine. To reproduce, run:
|
|
|
|
|
// voe_auto_test --automated --gtest_filter=*MixManyChannelsForStressOpus
|
|
|
|
|
|
|
|
|
|
// TODO(tommi,holmer): We don't grab locks in the dtor before accessing member
|
|
|
|
|
// variables but we grab them in all other methods. (what's the design?)
|
|
|
|
|
// Start documenting what thread we're on in what method so that it's easier
|
|
|
|
|
// to understand performance attributes and possibly remove locks.
|
2013-01-25 10:53:38 +00:00
|
|
|
if (remote_ssrc_ != 0) {
|
2016-02-02 08:31:45 -08:00
|
|
|
ssrc_db_->ReturnSSRC(remote_ssrc_);
|
2012-01-19 15:56:10 +00:00
|
|
|
}
|
2016-02-02 08:31:45 -08:00
|
|
|
ssrc_db_->ReturnSSRC(ssrc_);
|
2012-01-19 15:56:10 +00:00
|
|
|
|
|
|
|
|
SSRCDatabase::ReturnSSRCDatabase();
|
2013-01-25 10:53:38 +00:00
|
|
|
while (!payload_type_map_.empty()) {
|
2014-07-08 12:10:51 +00:00
|
|
|
std::map<int8_t, RtpUtility::Payload*>::iterator it =
|
2013-01-25 10:53:38 +00:00
|
|
|
payload_type_map_.begin();
|
2012-01-19 15:56:10 +00:00
|
|
|
delete it->second;
|
2013-01-25 10:53:38 +00:00
|
|
|
payload_type_map_.erase(it);
|
2012-01-19 15:56:10 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
uint16_t RTPSender::ActualSendBitrateKbit() const {
|
2016-07-13 09:11:28 -07:00
|
|
|
rtc::CritScope cs(&statistics_crit_);
|
|
|
|
|
return static_cast<uint16_t>(
|
|
|
|
|
total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0) /
|
|
|
|
|
1000);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t RTPSender::VideoBitrateSent() const {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (video_) {
|
|
|
|
|
return video_->VideoBitrateSent();
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
|
|
|
|
return 0;
|
2011-10-27 16:08:29 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t RTPSender::FecOverheadRate() const {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (video_) {
|
|
|
|
|
return video_->FecOverheadRate();
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
|
|
|
|
return 0;
|
2011-10-14 14:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t RTPSender::NackOverheadRate() const {
|
2016-07-13 09:11:28 -07:00
|
|
|
rtc::CritScope cs(&statistics_crit_);
|
|
|
|
|
return nack_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
2011-10-14 14:24:54 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
int32_t RTPSender::RegisterRtpHeaderExtension(RTPExtensionType type,
|
|
|
|
|
uint8_t id) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2016-06-08 00:24:21 -07:00
|
|
|
switch (type) {
|
|
|
|
|
case kRtpExtensionVideoRotation:
|
|
|
|
|
case kRtpExtensionPlayoutDelay:
|
|
|
|
|
case kRtpExtensionTransmissionTimeOffset:
|
|
|
|
|
case kRtpExtensionAbsoluteSendTime:
|
|
|
|
|
case kRtpExtensionAudioLevel:
|
|
|
|
|
case kRtpExtensionTransportSequenceNumber:
|
|
|
|
|
return rtp_header_extension_map_.Register(type, id);
|
|
|
|
|
case kRtpExtensionNone:
|
2016-06-23 03:50:39 -07:00
|
|
|
case kRtpExtensionNumberOfExtensions:
|
2016-06-08 00:24:21 -07:00
|
|
|
LOG(LS_ERROR) << "Invalid RTP extension type for registration";
|
|
|
|
|
return -1;
|
2015-04-01 15:33:06 -07:00
|
|
|
}
|
2016-06-08 00:24:21 -07:00
|
|
|
return -1;
|
2011-12-16 14:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
2015-03-04 22:55:15 +00:00
|
|
|
bool RTPSender::IsRtpHeaderExtensionRegistered(RTPExtensionType type) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2015-03-04 22:55:15 +00:00
|
|
|
return rtp_header_extension_map_.IsRegistered(type);
|
|
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
int32_t RTPSender::DeregisterRtpHeaderExtension(RTPExtensionType type) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
return rtp_header_extension_map_.Deregister(type);
|
2011-12-16 14:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-08 00:24:21 -07:00
|
|
|
size_t RTPSender::RtpHeaderExtensionLength() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
return rtp_header_extension_map_.GetTotalLengthInBytes();
|
2011-12-16 14:31:37 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
int32_t RTPSender::RegisterPayload(
|
2013-01-25 10:53:38 +00:00
|
|
|
const char payload_name[RTP_PAYLOAD_NAME_SIZE],
|
2014-12-19 13:49:55 +00:00
|
|
|
int8_t payload_number,
|
|
|
|
|
uint32_t frequency,
|
Convert channel counts to size_t.
IIRC, this was originally requested by ajm during review of the other size_t conversions I did over the past year, and I agreed it made sense, but wanted to do it separately since those changes were already gargantuan.
BUG=chromium:81439
TEST=none
R=henrik.lundin@webrtc.org, henrika@webrtc.org, kjellander@webrtc.org, minyue@webrtc.org, perkj@webrtc.org, solenberg@webrtc.org, stefan@webrtc.org, tina.legrand@webrtc.org
Review URL: https://codereview.webrtc.org/1316523002 .
Cr-Commit-Position: refs/heads/master@{#11229}
2016-01-12 16:26:35 -08:00
|
|
|
size_t channels,
|
2014-12-19 13:49:55 +00:00
|
|
|
uint32_t rate) {
|
2016-02-26 16:31:37 +01:00
|
|
|
RTC_DCHECK_LT(strlen(payload_name), RTP_PAYLOAD_NAME_SIZE);
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
|
2014-07-08 12:10:51 +00:00
|
|
|
std::map<int8_t, RtpUtility::Payload*>::iterator it =
|
2013-01-25 10:53:38 +00:00
|
|
|
payload_type_map_.find(payload_number);
|
|
|
|
|
|
|
|
|
|
if (payload_type_map_.end() != it) {
|
|
|
|
|
// We already use this payload type.
|
2014-07-08 12:10:51 +00:00
|
|
|
RtpUtility::Payload* payload = it->second;
|
2012-01-19 15:56:10 +00:00
|
|
|
assert(payload);
|
|
|
|
|
|
2013-01-25 10:53:38 +00:00
|
|
|
// Check if it's the same as we already have.
|
2014-07-08 12:10:51 +00:00
|
|
|
if (RtpUtility::StringCompare(
|
|
|
|
|
payload->name, payload_name, RTP_PAYLOAD_NAME_SIZE - 1)) {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (audio_configured_ && payload->audio &&
|
2012-01-19 15:56:10 +00:00
|
|
|
payload->typeSpecific.Audio.frequency == frequency &&
|
|
|
|
|
(payload->typeSpecific.Audio.rate == rate ||
|
2013-01-25 10:53:38 +00:00
|
|
|
payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
|
2012-01-19 15:56:10 +00:00
|
|
|
payload->typeSpecific.Audio.rate = rate;
|
2013-01-25 10:53:38 +00:00
|
|
|
// Ensure that we update the rate if new or old is zero.
|
2012-01-19 15:56:10 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!audio_configured_ && !payload->audio) {
|
2012-01-19 15:56:10 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-01-19 15:56:10 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2015-04-14 21:28:08 +02:00
|
|
|
int32_t ret_val = 0;
|
2015-12-15 02:54:47 -08:00
|
|
|
RtpUtility::Payload* payload = nullptr;
|
2013-01-25 10:53:38 +00:00
|
|
|
if (audio_configured_) {
|
2015-04-14 21:28:08 +02:00
|
|
|
// TODO(mflodman): Change to CreateAudioPayload and make static.
|
2013-01-25 10:53:38 +00:00
|
|
|
ret_val = audio_->RegisterAudioPayload(payload_name, payload_number,
|
2015-12-15 02:54:47 -08:00
|
|
|
frequency, channels, rate, &payload);
|
2012-01-19 15:56:10 +00:00
|
|
|
} else {
|
2016-02-16 17:59:27 +01:00
|
|
|
payload = video_->CreateVideoPayload(payload_name, payload_number);
|
2012-01-19 15:56:10 +00:00
|
|
|
}
|
2012-11-07 17:01:04 +00:00
|
|
|
if (payload) {
|
2013-01-25 10:53:38 +00:00
|
|
|
payload_type_map_[payload_number] = payload;
|
2012-01-19 15:56:10 +00:00
|
|
|
}
|
2013-01-25 10:53:38 +00:00
|
|
|
return ret_val;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
int32_t RTPSender::DeRegisterSendPayload(int8_t payload_type) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2014-07-08 12:10:51 +00:00
|
|
|
std::map<int8_t, RtpUtility::Payload*>::iterator it =
|
2013-01-25 10:53:38 +00:00
|
|
|
payload_type_map_.find(payload_type);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-01-25 10:53:38 +00:00
|
|
|
if (payload_type_map_.end() == it) {
|
2012-11-07 17:01:04 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2014-07-08 12:10:51 +00:00
|
|
|
RtpUtility::Payload* payload = it->second;
|
2012-01-19 15:56:10 +00:00
|
|
|
delete payload;
|
2013-01-25 10:53:38 +00:00
|
|
|
payload_type_map_.erase(it);
|
2012-01-19 15:56:10 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2014-08-27 09:39:43 +00:00
|
|
|
void RTPSender::SetSendPayloadType(int8_t payload_type) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-08-27 09:39:43 +00:00
|
|
|
payload_type_ = payload_type;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-25 16:51:35 +00:00
|
|
|
int8_t RTPSender::SendPayloadType() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-03-25 16:51:35 +00:00
|
|
|
return payload_type_;
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-03-30 11:11:51 -07:00
|
|
|
void RTPSender::SetMaxPayloadLength(size_t max_payload_length) {
|
2013-01-25 10:53:38 +00:00
|
|
|
// Sanity check.
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(max_payload_length >= 100 && max_payload_length <= IP_PACKET_SIZE)
|
2015-07-14 16:08:02 +02:00
|
|
|
<< "Invalid max payload length: " << max_payload_length;
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
max_payload_length_ = max_payload_length;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
size_t RTPSender::MaxDataPayloadLength() const {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (audio_configured_) {
|
2016-06-08 00:24:21 -07:00
|
|
|
return max_payload_length_ - RtpHeaderLength();
|
2012-01-10 14:09:18 +00:00
|
|
|
} else {
|
2016-06-08 00:24:21 -07:00
|
|
|
return max_payload_length_ - RtpHeaderLength() // RTP overhead.
|
2016-09-13 03:23:29 -07:00
|
|
|
- video_->FecPacketOverhead() // FEC/ULP/RED overhead.
|
2016-08-03 18:27:40 +02:00
|
|
|
- (RtxStatus() ? kRtxHeaderSize : 0); // RTX overhead.
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
size_t RTPSender::MaxPayloadLength() const {
|
2013-01-25 10:53:38 +00:00
|
|
|
return max_payload_length_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-13 14:15:15 +00:00
|
|
|
void RTPSender::SetRtxStatus(int mode) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-03-15 23:21:52 +00:00
|
|
|
rtx_ = mode;
|
2014-06-05 08:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
2015-01-13 14:15:15 +00:00
|
|
|
int RTPSender::RtxStatus() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2015-01-13 14:15:15 +00:00
|
|
|
return rtx_;
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-05 08:25:29 +00:00
|
|
|
void RTPSender::SetRtxSsrc(uint32_t ssrc) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-06-05 08:25:29 +00:00
|
|
|
ssrc_rtx_ = ssrc;
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
|
|
|
|
|
2014-07-07 13:06:48 +00:00
|
|
|
uint32_t RTPSender::RtxSsrc() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-07 13:06:48 +00:00
|
|
|
return ssrc_rtx_;
|
|
|
|
|
}
|
|
|
|
|
|
2015-04-21 20:24:50 +08:00
|
|
|
void RTPSender::SetRtxPayloadType(int payload_type,
|
|
|
|
|
int associated_payload_type) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK_LE(payload_type, 127);
|
|
|
|
|
RTC_DCHECK_LE(associated_payload_type, 127);
|
2015-04-21 20:24:50 +08:00
|
|
|
if (payload_type < 0) {
|
|
|
|
|
LOG(LS_ERROR) << "Invalid RTX payload type: " << payload_type;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rtx_payload_type_map_[associated_payload_type] = payload_type;
|
2015-04-13 17:48:08 +02:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
int32_t RTPSender::CheckPayloadType(int8_t payload_type,
|
|
|
|
|
RtpVideoCodecTypes* video_type) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-01-25 10:53:38 +00:00
|
|
|
if (payload_type < 0) {
|
2014-04-08 11:06:12 +00:00
|
|
|
LOG(LS_ERROR) << "Invalid payload_type " << payload_type;
|
2012-01-19 15:56:10 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2013-01-25 10:53:38 +00:00
|
|
|
if (payload_type_ == payload_type) {
|
|
|
|
|
if (!audio_configured_) {
|
|
|
|
|
*video_type = video_->VideoCodecType();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
return 0;
|
2012-01-19 15:56:10 +00:00
|
|
|
}
|
2014-07-08 12:10:51 +00:00
|
|
|
std::map<int8_t, RtpUtility::Payload*>::iterator it =
|
2013-01-25 10:53:38 +00:00
|
|
|
payload_type_map_.find(payload_type);
|
|
|
|
|
if (it == payload_type_map_.end()) {
|
2015-12-07 10:26:18 +01:00
|
|
|
LOG(LS_WARNING) << "Payload type " << static_cast<int>(payload_type)
|
|
|
|
|
<< " not registered.";
|
2012-01-19 15:56:10 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2014-08-27 09:39:43 +00:00
|
|
|
SetSendPayloadType(payload_type);
|
2014-07-08 12:10:51 +00:00
|
|
|
RtpUtility::Payload* payload = it->second;
|
2012-01-19 15:56:10 +00:00
|
|
|
assert(payload);
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!payload->audio && !audio_configured_) {
|
|
|
|
|
video_->SetVideoCodecType(payload->typeSpecific.Video.videoCodecType);
|
|
|
|
|
*video_type = payload->typeSpecific.Video.videoCodecType;
|
2012-01-19 15:56:10 +00:00
|
|
|
}
|
|
|
|
|
return 0;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-02 17:46:41 -07:00
|
|
|
bool RTPSender::SendOutgoingData(FrameType frame_type,
|
|
|
|
|
int8_t payload_type,
|
|
|
|
|
uint32_t capture_timestamp,
|
|
|
|
|
int64_t capture_time_ms,
|
|
|
|
|
const uint8_t* payload_data,
|
|
|
|
|
size_t payload_size,
|
|
|
|
|
const RTPFragmentationHeader* fragmentation,
|
|
|
|
|
const RTPVideoHeader* rtp_header,
|
|
|
|
|
uint32_t* transport_frame_id_out) {
|
2014-07-07 13:06:48 +00:00
|
|
|
uint32_t ssrc;
|
2016-06-08 00:24:21 -07:00
|
|
|
uint16_t sequence_number;
|
2016-08-22 03:39:23 -07:00
|
|
|
uint32_t rtp_timestamp;
|
2012-11-07 17:01:04 +00:00
|
|
|
{
|
|
|
|
|
// Drop this packet if we're not sending media packets.
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-07 13:06:48 +00:00
|
|
|
ssrc = ssrc_;
|
2016-06-08 00:24:21 -07:00
|
|
|
sequence_number = sequence_number_;
|
2016-08-22 03:39:23 -07:00
|
|
|
rtp_timestamp = timestamp_offset_ + capture_timestamp;
|
|
|
|
|
if (transport_frame_id_out)
|
|
|
|
|
*transport_frame_id_out = rtp_timestamp;
|
2016-08-02 17:46:41 -07:00
|
|
|
if (!sending_media_)
|
|
|
|
|
return true;
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
2013-08-15 23:38:54 +00:00
|
|
|
RtpVideoCodecTypes video_type = kRtpVideoGeneric;
|
2013-01-25 10:53:38 +00:00
|
|
|
if (CheckPayloadType(payload_type, &video_type) != 0) {
|
2015-12-07 10:26:18 +01:00
|
|
|
LOG(LS_ERROR) << "Don't send data with unknown payload type: "
|
|
|
|
|
<< static_cast<int>(payload_type) << ".";
|
2016-08-02 17:46:41 -07:00
|
|
|
return false;
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-02 17:46:41 -07:00
|
|
|
bool result;
|
2013-01-25 10:53:38 +00:00
|
|
|
if (audio_configured_) {
|
2016-08-22 03:39:23 -07:00
|
|
|
TRACE_EVENT_ASYNC_STEP1("webrtc", "Audio", rtp_timestamp, "Send", "type",
|
|
|
|
|
FrameTypeToString(frame_type));
|
2013-01-25 10:53:38 +00:00
|
|
|
assert(frame_type == kAudioFrameSpeech || frame_type == kAudioFrameCN ||
|
2015-10-19 02:39:06 -07:00
|
|
|
frame_type == kEmptyFrame);
|
2012-05-31 10:47:35 +00:00
|
|
|
|
2016-08-22 03:39:23 -07:00
|
|
|
result = audio_->SendAudio(frame_type, payload_type, rtp_timestamp,
|
2016-08-02 17:46:41 -07:00
|
|
|
payload_data, payload_size, fragmentation);
|
2012-11-07 17:01:04 +00:00
|
|
|
} else {
|
2013-07-08 21:31:18 +00:00
|
|
|
TRACE_EVENT_ASYNC_STEP1("webrtc", "Video", capture_time_ms,
|
|
|
|
|
"Send", "type", FrameTypeToString(frame_type));
|
2013-01-25 10:53:38 +00:00
|
|
|
assert(frame_type != kAudioFrameSpeech && frame_type != kAudioFrameCN);
|
2012-11-07 17:01:04 +00:00
|
|
|
|
2015-10-19 02:39:06 -07:00
|
|
|
if (frame_type == kEmptyFrame)
|
2016-08-02 17:46:41 -07:00
|
|
|
return true;
|
2014-07-16 09:37:29 +00:00
|
|
|
|
2016-08-02 17:46:41 -07:00
|
|
|
if (rtp_header) {
|
|
|
|
|
playout_delay_oracle_.UpdateRequest(ssrc, rtp_header->playout_delay,
|
2016-06-08 00:24:21 -07:00
|
|
|
sequence_number);
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-02 17:46:41 -07:00
|
|
|
result = video_->SendVideo(video_type, frame_type, payload_type,
|
2016-08-22 03:39:23 -07:00
|
|
|
rtp_timestamp, capture_time_ms, payload_data,
|
2016-08-02 17:46:41 -07:00
|
|
|
payload_size, fragmentation, rtp_header);
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&statistics_crit_);
|
2014-12-18 13:50:16 +00:00
|
|
|
// Note: This is currently only counting for video.
|
|
|
|
|
if (frame_type == kVideoFrameKey) {
|
|
|
|
|
++frame_counts_.key_frames;
|
|
|
|
|
} else if (frame_type == kVideoFrameDelta) {
|
|
|
|
|
++frame_counts_.delta_frames;
|
|
|
|
|
}
|
2013-12-04 15:09:27 +00:00
|
|
|
if (frame_count_observer_) {
|
2014-12-18 13:50:16 +00:00
|
|
|
frame_count_observer_->FrameCountUpdated(frame_counts_, ssrc);
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
2013-12-04 15:09:27 +00:00
|
|
|
|
2016-08-02 17:46:41 -07:00
|
|
|
return result;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-01 06:31:17 -07:00
|
|
|
size_t RTPSender::TrySendRedundantPayloads(size_t bytes_to_send,
|
|
|
|
|
int probe_cluster_id) {
|
2014-08-14 08:24:47 +00:00
|
|
|
{
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2016-02-19 16:14:37 +01:00
|
|
|
if (!sending_media_)
|
|
|
|
|
return 0;
|
2014-08-14 08:24:47 +00:00
|
|
|
if ((rtx_ & kRtxRedundantPayloads) == 0)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
int bytes_left = static_cast<int>(bytes_to_send);
|
2013-12-04 10:24:26 +00:00
|
|
|
while (bytes_left > 0) {
|
2016-08-03 18:27:40 +02:00
|
|
|
std::unique_ptr<RtpPacketToSend> packet =
|
|
|
|
|
packet_history_.GetBestFittingPacket(bytes_left);
|
|
|
|
|
if (!packet)
|
2013-12-04 10:24:26 +00:00
|
|
|
break;
|
2016-08-03 18:27:40 +02:00
|
|
|
size_t payload_size = packet->payload_size();
|
|
|
|
|
if (!PrepareAndSendPacket(std::move(packet), true, false, probe_cluster_id))
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
break;
|
2016-08-03 18:27:40 +02:00
|
|
|
bytes_left -= payload_size;
|
2013-12-04 10:24:26 +00:00
|
|
|
}
|
|
|
|
|
return bytes_to_send - bytes_left;
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-19 05:37:56 -07:00
|
|
|
size_t RTPSender::SendPadData(size_t bytes, int probe_cluster_id) {
|
|
|
|
|
return DeprecatedSendPadData(bytes, false, 0, 0, probe_cluster_id);
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 11:14:31 +02:00
|
|
|
size_t RTPSender::SendPadData(size_t bytes,
|
|
|
|
|
bool timestamp_provided,
|
|
|
|
|
uint32_t timestamp,
|
2016-06-01 04:04:40 -07:00
|
|
|
int64_t capture_time_ms) {
|
2016-09-19 05:37:56 -07:00
|
|
|
return DeprecatedSendPadData(bytes, timestamp_provided, timestamp,
|
|
|
|
|
capture_time_ms, PacketInfo::kNotAProbe);
|
2016-06-01 06:31:17 -07:00
|
|
|
}
|
|
|
|
|
|
2016-09-19 05:37:56 -07:00
|
|
|
size_t RTPSender::DeprecatedSendPadData(size_t bytes,
|
|
|
|
|
bool timestamp_provided,
|
|
|
|
|
uint32_t timestamp,
|
|
|
|
|
int64_t capture_time_ms,
|
|
|
|
|
int probe_cluster_id) {
|
2015-09-21 15:11:14 -07:00
|
|
|
// Always send full padding packets. This is accounted for by the
|
|
|
|
|
// RtpPacketSender,
|
2015-09-18 11:14:31 +02:00
|
|
|
// which will make sure we don't send too much padding even if a single packet
|
|
|
|
|
// is larger than requested.
|
|
|
|
|
size_t padding_bytes_in_packet =
|
|
|
|
|
std::min(MaxDataPayloadLength(), kMaxPaddingLength);
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
size_t bytes_sent = 0;
|
2016-07-28 07:56:38 -07:00
|
|
|
bool using_transport_seq =
|
|
|
|
|
IsRtpHeaderExtensionRegistered(kRtpExtensionTransportSequenceNumber) &&
|
|
|
|
|
transport_sequence_number_allocator_;
|
2013-06-17 12:53:37 +00:00
|
|
|
for (; bytes > 0; bytes -= padding_bytes_in_packet) {
|
2015-09-18 11:14:31 +02:00
|
|
|
if (bytes < padding_bytes_in_packet)
|
|
|
|
|
bytes = padding_bytes_in_packet;
|
2014-07-16 09:37:29 +00:00
|
|
|
|
2013-06-19 14:13:42 +00:00
|
|
|
uint32_t ssrc;
|
|
|
|
|
uint16_t sequence_number;
|
2014-08-14 08:24:47 +00:00
|
|
|
int payload_type;
|
2014-07-16 09:37:29 +00:00
|
|
|
bool over_rtx;
|
2013-06-19 14:13:42 +00:00
|
|
|
{
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2016-02-19 16:14:37 +01:00
|
|
|
if (!sending_media_)
|
|
|
|
|
return bytes_sent;
|
2015-09-18 11:14:31 +02:00
|
|
|
if (!timestamp_provided) {
|
2016-08-22 03:39:23 -07:00
|
|
|
timestamp = last_rtp_timestamp_;
|
2015-09-18 11:14:31 +02:00
|
|
|
capture_time_ms = capture_time_ms_;
|
|
|
|
|
}
|
2013-06-19 14:13:42 +00:00
|
|
|
if (rtx_ == kRtxOff) {
|
2014-07-16 09:37:29 +00:00
|
|
|
// Without RTX we can't send padding in the middle of frames.
|
|
|
|
|
if (!last_packet_marker_bit_)
|
2014-08-14 08:24:47 +00:00
|
|
|
return 0;
|
2013-06-19 14:13:42 +00:00
|
|
|
ssrc = ssrc_;
|
|
|
|
|
sequence_number = sequence_number_;
|
|
|
|
|
++sequence_number_;
|
2014-08-14 08:24:47 +00:00
|
|
|
payload_type = payload_type_;
|
2014-07-16 09:37:29 +00:00
|
|
|
over_rtx = false;
|
2013-06-19 14:13:42 +00:00
|
|
|
} else {
|
2016-01-27 12:58:51 +01:00
|
|
|
// Without abs-send-time or transport sequence number a media packet
|
|
|
|
|
// must be sent before padding so that the timestamps used for
|
|
|
|
|
// estimation are correct.
|
|
|
|
|
if (!media_has_been_sent_ &&
|
|
|
|
|
!(rtp_header_extension_map_.IsRegistered(
|
|
|
|
|
kRtpExtensionAbsoluteSendTime) ||
|
|
|
|
|
using_transport_seq)) {
|
2014-08-14 08:24:47 +00:00
|
|
|
return 0;
|
2016-01-27 12:58:51 +01:00
|
|
|
}
|
2015-09-18 11:14:31 +02:00
|
|
|
// Only change change the timestamp of padding packets sent over RTX.
|
|
|
|
|
// Padding only packets over RTP has to be sent as part of a media
|
|
|
|
|
// frame (and therefore the same timestamp).
|
|
|
|
|
if (last_timestamp_time_ms_ > 0) {
|
|
|
|
|
timestamp +=
|
|
|
|
|
(clock_->TimeInMilliseconds() - last_timestamp_time_ms_) * 90;
|
|
|
|
|
capture_time_ms +=
|
|
|
|
|
(clock_->TimeInMilliseconds() - last_timestamp_time_ms_);
|
|
|
|
|
}
|
2013-06-19 14:13:42 +00:00
|
|
|
ssrc = ssrc_rtx_;
|
|
|
|
|
sequence_number = sequence_number_rtx_;
|
|
|
|
|
++sequence_number_rtx_;
|
2016-02-03 13:29:59 +01:00
|
|
|
payload_type = rtx_payload_type_map_.begin()->second;
|
2014-07-16 09:37:29 +00:00
|
|
|
over_rtx = true;
|
2013-06-19 14:13:42 +00:00
|
|
|
}
|
|
|
|
|
}
|
2014-07-07 13:06:48 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
RtpPacketToSend padding_packet(&rtp_header_extension_map_, IP_PACKET_SIZE);
|
|
|
|
|
padding_packet.SetPayloadType(payload_type);
|
|
|
|
|
padding_packet.SetMarker(false);
|
|
|
|
|
padding_packet.SetSequenceNumber(sequence_number);
|
|
|
|
|
padding_packet.SetTimestamp(timestamp);
|
|
|
|
|
padding_packet.SetSsrc(ssrc);
|
2014-07-10 16:24:54 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
2014-07-10 16:24:54 +00:00
|
|
|
|
|
|
|
|
if (capture_time_ms > 0) {
|
2016-08-03 18:27:40 +02:00
|
|
|
padding_packet.SetExtension<TransmissionOffset>(
|
|
|
|
|
kTimestampTicksPerMs * (now_ms - capture_time_ms));
|
2012-01-05 10:54:44 +00:00
|
|
|
}
|
2016-08-03 18:27:40 +02:00
|
|
|
padding_packet.SetExtension<AbsoluteSendTime>(now_ms);
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2015-10-02 03:39:33 -07:00
|
|
|
PacketOptions options;
|
2016-08-03 18:27:40 +02:00
|
|
|
bool has_transport_seq_no =
|
|
|
|
|
UpdateTransportSequenceNumber(&padding_packet, &options.packet_id);
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
padding_packet.SetPadding(padding_bytes_in_packet, &random_);
|
|
|
|
|
|
|
|
|
|
if (has_transport_seq_no && transport_feedback_observer_)
|
|
|
|
|
transport_feedback_observer_->AddPacket(
|
2016-08-23 17:51:42 +02:00
|
|
|
options.packet_id,
|
|
|
|
|
padding_packet.payload_size() + padding_packet.padding_size(),
|
|
|
|
|
probe_cluster_id);
|
2016-08-03 18:27:40 +02:00
|
|
|
|
|
|
|
|
if (!SendPacketToNetwork(padding_packet, options))
|
2015-10-27 08:29:42 -07:00
|
|
|
break;
|
|
|
|
|
|
2013-06-17 12:53:37 +00:00
|
|
|
bytes_sent += padding_bytes_in_packet;
|
2016-08-03 18:27:40 +02:00
|
|
|
UpdateRtpStats(padding_packet, over_rtx, false);
|
2012-01-05 10:54:44 +00:00
|
|
|
}
|
2014-07-10 16:24:54 +00:00
|
|
|
|
2013-06-17 12:53:37 +00:00
|
|
|
return bytes_sent;
|
2012-01-05 10:54:44 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
void RTPSender::SetStorePacketsStatus(bool enable, uint16_t number_to_store) {
|
2013-12-04 10:24:26 +00:00
|
|
|
packet_history_.SetStorePacketsStatus(enable, number_to_store);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-27 00:41:08 +00:00
|
|
|
bool RTPSender::StorePackets() const {
|
2013-12-04 10:24:26 +00:00
|
|
|
return packet_history_.StorePackets();
|
2013-04-27 00:41:08 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2015-01-12 21:51:21 +00:00
|
|
|
int32_t RTPSender::ReSendPacket(uint16_t packet_id, int64_t min_resend_time) {
|
2016-08-03 18:27:40 +02:00
|
|
|
std::unique_ptr<RtpPacketToSend> packet =
|
|
|
|
|
packet_history_.GetPacketAndSetSendTime(packet_id, min_resend_time, true);
|
|
|
|
|
if (!packet) {
|
2012-01-16 11:06:31 +00:00
|
|
|
// Packet not found.
|
2012-04-23 12:43:05 +00:00
|
|
|
return 0;
|
2012-01-16 11:06:31 +00:00
|
|
|
}
|
2013-04-27 00:41:08 +00:00
|
|
|
|
2016-07-13 09:11:28 -07:00
|
|
|
// Check if we're overusing retransmission bitrate.
|
|
|
|
|
// TODO(sprang): Add histograms for nack success or failure reasons.
|
|
|
|
|
RTC_DCHECK(retransmission_rate_limiter_);
|
2016-08-03 18:27:40 +02:00
|
|
|
if (!retransmission_rate_limiter_->TryUseRate(packet->size()))
|
2016-07-13 09:11:28 -07:00
|
|
|
return -1;
|
|
|
|
|
|
2013-04-27 00:41:08 +00:00
|
|
|
if (paced_sender_) {
|
2014-07-04 09:20:42 +00:00
|
|
|
// Convert from TickTime to Clock since capture_time_ms is based on
|
|
|
|
|
// TickTime.
|
2016-08-03 18:27:40 +02:00
|
|
|
int64_t corrected_capture_tims_ms =
|
|
|
|
|
packet->capture_time_ms() + clock_delta_ms_;
|
|
|
|
|
paced_sender_->InsertPacket(RtpPacketSender::kNormalPriority,
|
|
|
|
|
packet->Ssrc(), packet->SequenceNumber(),
|
|
|
|
|
corrected_capture_tims_ms,
|
|
|
|
|
packet->payload_size(), true);
|
|
|
|
|
|
|
|
|
|
return packet->size();
|
|
|
|
|
}
|
|
|
|
|
bool rtx = (RtxStatus() & kRtxRetransmitted) > 0;
|
|
|
|
|
int32_t packet_size = static_cast<int32_t>(packet->size());
|
|
|
|
|
if (!PrepareAndSendPacket(std::move(packet), rtx, true,
|
|
|
|
|
PacketInfo::kNotAProbe))
|
2015-08-03 04:38:41 -07:00
|
|
|
return -1;
|
2016-08-03 18:27:40 +02:00
|
|
|
return packet_size;
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
bool RTPSender::SendPacketToNetwork(const RtpPacketToSend& packet,
|
2015-10-02 03:39:33 -07:00
|
|
|
const PacketOptions& options) {
|
2013-04-27 00:41:08 +00:00
|
|
|
int bytes_sent = -1;
|
2013-01-25 10:53:38 +00:00
|
|
|
if (transport_) {
|
2016-08-03 18:27:40 +02:00
|
|
|
bytes_sent = transport_->SendRtp(packet.data(), packet.size(), options)
|
|
|
|
|
? static_cast<int>(packet.size())
|
2015-10-02 03:39:33 -07:00
|
|
|
: -1;
|
2016-01-21 05:42:04 -08:00
|
|
|
if (event_log_ && bytes_sent > 0) {
|
2016-08-03 18:27:40 +02:00
|
|
|
event_log_->LogRtpHeader(kOutgoingPacket, MediaType::ANY, packet.data(),
|
|
|
|
|
packet.size());
|
2016-01-21 05:42:04 -08:00
|
|
|
}
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
2015-02-16 12:06:00 +00:00
|
|
|
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
2016-08-03 18:27:40 +02:00
|
|
|
"RTPSender::SendPacketToNetwork", "size", packet.size(),
|
|
|
|
|
"sent", bytes_sent);
|
2014-04-08 11:06:12 +00:00
|
|
|
// TODO(pwestin): Add a separate bitrate for sent bitrate after pacer.
|
2012-01-16 11:06:31 +00:00
|
|
|
if (bytes_sent <= 0) {
|
2014-04-08 11:06:12 +00:00
|
|
|
LOG(LS_WARNING) << "Transport failed to send packet";
|
2013-04-27 00:41:08 +00:00
|
|
|
return false;
|
2012-01-10 14:09:18 +00:00
|
|
|
}
|
2013-04-27 00:41:08 +00:00
|
|
|
return true;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-12-22 12:52:41 +00:00
|
|
|
int RTPSender::SelectiveRetransmissions() const {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!video_)
|
|
|
|
|
return -1;
|
|
|
|
|
return video_->SelectiveRetransmissions();
|
2011-12-22 12:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!video_)
|
|
|
|
|
return -1;
|
2015-04-14 21:28:08 +02:00
|
|
|
video_->SetSelectiveRetransmissions(settings);
|
|
|
|
|
return 0;
|
2011-12-22 12:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-26 18:48:46 +02:00
|
|
|
void RTPSender::OnReceivedNack(
|
|
|
|
|
const std::vector<uint16_t>& nack_sequence_numbers,
|
|
|
|
|
int64_t avg_rtt) {
|
2015-02-16 12:06:00 +00:00
|
|
|
TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
|
|
|
|
"RTPSender::OnReceivedNACK", "num_seqnum",
|
|
|
|
|
nack_sequence_numbers.size(), "avg_rtt", avg_rtt);
|
2016-07-13 09:11:28 -07:00
|
|
|
for (uint16_t seq_no : nack_sequence_numbers) {
|
|
|
|
|
const int32_t bytes_sent = ReSendPacket(seq_no, 5 + avg_rtt);
|
|
|
|
|
if (bytes_sent < 0) {
|
2012-01-10 14:09:18 +00:00
|
|
|
// Failed to send one Sequence number. Give up the rest in this nack.
|
2016-07-13 09:11:28 -07:00
|
|
|
LOG(LS_WARNING) << "Failed resending RTP packet " << seq_no
|
2014-04-08 11:06:12 +00:00
|
|
|
<< ", Discard rest of packets";
|
2012-01-10 14:09:18 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-08 00:24:21 -07:00
|
|
|
void RTPSender::OnReceivedRtcpReportBlocks(
|
|
|
|
|
const ReportBlockList& report_blocks) {
|
|
|
|
|
playout_delay_oracle_.OnReceivedRtcpReportBlocks(report_blocks);
|
|
|
|
|
}
|
|
|
|
|
|
2013-04-27 00:41:08 +00:00
|
|
|
// Called from pacer when we can send the packet.
|
2013-06-20 20:18:31 +00:00
|
|
|
bool RTPSender::TimeToSendPacket(uint16_t sequence_number,
|
2013-11-13 15:29:21 +00:00
|
|
|
int64_t capture_time_ms,
|
2016-06-01 06:31:17 -07:00
|
|
|
bool retransmission,
|
|
|
|
|
int probe_cluster_id) {
|
2016-08-03 18:27:40 +02:00
|
|
|
std::unique_ptr<RtpPacketToSend> packet =
|
|
|
|
|
packet_history_.GetPacketAndSetSendTime(sequence_number, 0,
|
|
|
|
|
retransmission);
|
2016-08-23 17:51:42 +02:00
|
|
|
if (!packet) {
|
2013-06-20 20:18:31 +00:00
|
|
|
// Packet cannot be found. Allow sending to continue.
|
|
|
|
|
return true;
|
2016-08-23 17:51:42 +02:00
|
|
|
}
|
2016-05-02 23:44:01 -07:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
return PrepareAndSendPacket(
|
|
|
|
|
std::move(packet),
|
|
|
|
|
retransmission && (RtxStatus() & kRtxRetransmitted) > 0, retransmission,
|
|
|
|
|
probe_cluster_id);
|
2013-12-04 10:24:26 +00:00
|
|
|
}
|
2012-01-16 11:06:31 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
bool RTPSender::PrepareAndSendPacket(std::unique_ptr<RtpPacketToSend> packet,
|
2014-03-19 18:14:52 +00:00
|
|
|
bool send_over_rtx,
|
2016-06-01 06:31:17 -07:00
|
|
|
bool is_retransmit,
|
|
|
|
|
int probe_cluster_id) {
|
2016-08-03 18:27:40 +02:00
|
|
|
RTC_DCHECK(packet);
|
|
|
|
|
int64_t capture_time_ms = packet->capture_time_ms();
|
|
|
|
|
RtpPacketToSend* packet_to_send = packet.get();
|
2013-12-04 10:24:26 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
if (!is_retransmit && packet->Marker()) {
|
2015-02-16 12:06:00 +00:00
|
|
|
TRACE_EVENT_ASYNC_END0(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"), "PacedSend",
|
|
|
|
|
capture_time_ms);
|
2014-11-04 16:27:16 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
TRACE_EVENT_INSTANT2(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
|
|
|
|
"PrepareAndSendPacket", "timestamp", packet->Timestamp(),
|
|
|
|
|
"seqnum", packet->SequenceNumber());
|
2011-12-22 12:52:41 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
std::unique_ptr<RtpPacketToSend> packet_rtx;
|
2013-12-04 10:24:26 +00:00
|
|
|
if (send_over_rtx) {
|
2016-08-03 18:27:40 +02:00
|
|
|
packet_rtx = BuildRtxPacket(*packet);
|
|
|
|
|
if (!packet_rtx)
|
2016-08-01 06:58:34 -07:00
|
|
|
return false;
|
2016-08-03 18:27:40 +02:00
|
|
|
packet_to_send = packet_rtx.get();
|
2013-11-13 15:29:21 +00:00
|
|
|
}
|
|
|
|
|
|
2013-05-16 11:10:31 +00:00
|
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
|
|
|
|
int64_t diff_ms = now_ms - capture_time_ms;
|
2016-08-03 18:27:40 +02:00
|
|
|
packet_to_send->SetExtension<TransmissionOffset>(kTimestampTicksPerMs *
|
|
|
|
|
diff_ms);
|
|
|
|
|
packet_to_send->SetExtension<AbsoluteSendTime>(now_ms);
|
2015-08-03 04:38:41 -07:00
|
|
|
|
2015-10-02 03:39:33 -07:00
|
|
|
PacketOptions options;
|
2016-08-03 18:27:40 +02:00
|
|
|
if (UpdateTransportSequenceNumber(packet_to_send, &options.packet_id) &&
|
|
|
|
|
transport_feedback_observer_) {
|
|
|
|
|
transport_feedback_observer_->AddPacket(
|
2016-08-23 17:51:42 +02:00
|
|
|
options.packet_id,
|
|
|
|
|
packet_to_send->payload_size() + packet_to_send->padding_size(),
|
|
|
|
|
probe_cluster_id);
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
|
2016-05-02 23:44:01 -07:00
|
|
|
if (!is_retransmit && !send_over_rtx) {
|
2016-08-03 18:27:40 +02:00
|
|
|
UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
|
|
|
|
|
UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
|
|
|
|
|
packet->Ssrc());
|
2015-10-27 08:29:42 -07:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
if (!SendPacketToNetwork(*packet_to_send, options))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
{
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-17 16:10:14 +00:00
|
|
|
media_has_been_sent_ = true;
|
|
|
|
|
}
|
2016-08-03 18:27:40 +02:00
|
|
|
UpdateRtpStats(*packet_to_send, send_over_rtx, is_retransmit);
|
|
|
|
|
return true;
|
2013-12-05 14:29:02 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
void RTPSender::UpdateRtpStats(const RtpPacketToSend& packet,
|
2013-12-05 14:29:02 +00:00
|
|
|
bool is_rtx,
|
|
|
|
|
bool is_retransmit) {
|
2016-07-13 09:11:28 -07:00
|
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
2014-01-27 13:20:36 +00:00
|
|
|
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope lock(&statistics_crit_);
|
2016-09-20 15:48:09 +02:00
|
|
|
StreamDataCounters* counters = is_rtx ? &rtx_rtp_stats_ : &rtp_stats_;
|
2013-12-05 14:29:02 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
total_bitrate_sent_.Update(packet.size(), now_ms);
|
2015-02-04 08:34:47 +00:00
|
|
|
|
2016-09-20 15:48:09 +02:00
|
|
|
if (counters->first_packet_time_ms == -1)
|
|
|
|
|
counters->first_packet_time_ms = now_ms;
|
|
|
|
|
|
|
|
|
|
if (IsFecPacket(packet))
|
2016-08-03 18:27:40 +02:00
|
|
|
CountPacket(&counters->fec, packet);
|
2016-09-20 15:48:09 +02:00
|
|
|
|
2013-12-05 14:29:02 +00:00
|
|
|
if (is_retransmit) {
|
2016-08-03 18:27:40 +02:00
|
|
|
CountPacket(&counters->retransmitted, packet);
|
|
|
|
|
nack_bitrate_sent_.Update(packet.size(), now_ms);
|
2015-02-04 08:34:47 +00:00
|
|
|
}
|
2016-08-03 18:27:40 +02:00
|
|
|
CountPacket(&counters->transmitted, packet);
|
2016-07-13 09:11:28 -07:00
|
|
|
|
2016-09-20 15:48:09 +02:00
|
|
|
if (rtp_stats_callback_)
|
|
|
|
|
rtp_stats_callback_->DataCountersUpdated(*counters, packet.Ssrc());
|
2013-12-05 14:29:02 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
bool RTPSender::IsFecPacket(const RtpPacketToSend& packet) const {
|
2013-12-05 14:29:02 +00:00
|
|
|
if (!video_) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-11-07 02:08:51 -08:00
|
|
|
int pt_red;
|
|
|
|
|
int pt_fec;
|
2016-11-07 03:05:06 -08:00
|
|
|
video_->GetUlpfecConfig(&pt_red, &pt_fec);
|
|
|
|
|
const bool fec_enabled = (pt_fec != -1);
|
2016-11-07 02:08:51 -08:00
|
|
|
return fec_enabled && static_cast<int>(packet.PayloadType()) == pt_red &&
|
|
|
|
|
static_cast<int>(packet.payload()[0]) == pt_fec;
|
2012-01-16 11:06:31 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-01 06:31:17 -07:00
|
|
|
size_t RTPSender::TimeToSendPadding(size_t bytes, int probe_cluster_id) {
|
2015-12-07 10:26:18 +01:00
|
|
|
if (audio_configured_ || bytes == 0)
|
2015-07-01 06:31:06 -07:00
|
|
|
return 0;
|
2016-06-01 06:31:17 -07:00
|
|
|
size_t bytes_sent = TrySendRedundantPayloads(bytes, probe_cluster_id);
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
if (bytes_sent < bytes)
|
2016-09-19 05:37:56 -07:00
|
|
|
bytes_sent += SendPadData(bytes - bytes_sent, probe_cluster_id);
|
Use size_t more consistently for packet/payload lengths.
See design doc at https://docs.google.com/a/chromium.org/document/d/1I6nmE9D_BmCY-IoV6MDPY2V6WYpEI-dg2apWXTfZyUI/edit?usp=sharing for more information.
This CL was reviewed and approved in pieces in the following CLs:
https://webrtc-codereview.appspot.com/24209004/
https://webrtc-codereview.appspot.com/24229004/
https://webrtc-codereview.appspot.com/24259004/
https://webrtc-codereview.appspot.com/25109004/
https://webrtc-codereview.appspot.com/26099004/
https://webrtc-codereview.appspot.com/27069004/
https://webrtc-codereview.appspot.com/27969004/
https://webrtc-codereview.appspot.com/27989004/
https://webrtc-codereview.appspot.com/29009004/
https://webrtc-codereview.appspot.com/30929004/
https://webrtc-codereview.appspot.com/30939004/
https://webrtc-codereview.appspot.com/31999004/
Committing as TBR to the original reviewers.
BUG=chromium:81439
TEST=none
TBR=pthatcher,henrik.lundin,tina.legrand,stefan,tkchin,glaznev,kjellander,perkj,mflodman,henrika,asapersson,niklas.enbom
Review URL: https://webrtc-codereview.appspot.com/23129004
git-svn-id: http://webrtc.googlecode.com/svn/trunk@7726 4adac7df-926f-26a2-2b94-8c16560cd09d
2014-11-20 22:28:14 +00:00
|
|
|
return bytes_sent;
|
2013-06-17 12:53:37 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
bool RTPSender::SendToNetwork(std::unique_ptr<RtpPacketToSend> packet,
|
|
|
|
|
StorageType storage,
|
|
|
|
|
RtpPacketSender::Priority priority) {
|
|
|
|
|
RTC_DCHECK(packet);
|
2013-05-16 11:10:31 +00:00
|
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
|
|
|
|
|
2012-08-28 15:20:39 +00:00
|
|
|
// |capture_time_ms| <= 0 is considered invalid.
|
|
|
|
|
// TODO(holmer): This should be changed all over Video Engine so that negative
|
|
|
|
|
// time is consider invalid, while 0 is considered a valid time.
|
2016-08-03 18:27:40 +02:00
|
|
|
if (packet->capture_time_ms() > 0) {
|
|
|
|
|
packet->SetExtension<TransmissionOffset>(
|
|
|
|
|
kTimestampTicksPerMs * (now_ms - packet->capture_time_ms()));
|
2012-11-13 21:12:39 +00:00
|
|
|
}
|
2016-08-03 18:27:40 +02:00
|
|
|
packet->SetExtension<AbsoluteSendTime>(now_ms);
|
2013-03-15 23:21:52 +00:00
|
|
|
|
2016-09-14 05:04:36 -07:00
|
|
|
if (video_) {
|
2016-09-30 06:29:54 -07:00
|
|
|
BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoTotBitrate_kbps", now_ms,
|
2016-09-14 05:04:36 -07:00
|
|
|
ActualSendBitrateKbit(), packet->Ssrc());
|
2016-09-30 06:29:54 -07:00
|
|
|
BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoFecBitrate_kbps", now_ms,
|
2016-09-14 05:04:36 -07:00
|
|
|
FecOverheadRate() / 1000, packet->Ssrc());
|
2016-09-30 06:29:54 -07:00
|
|
|
BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "VideoNackBitrate_kbps", now_ms,
|
2016-09-14 05:04:36 -07:00
|
|
|
NackOverheadRate() / 1000, packet->Ssrc());
|
|
|
|
|
} else {
|
2016-09-30 06:29:54 -07:00
|
|
|
BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioTotBitrate_kbps", now_ms,
|
2016-09-14 05:04:36 -07:00
|
|
|
ActualSendBitrateKbit(), packet->Ssrc());
|
2016-09-30 06:29:54 -07:00
|
|
|
BWE_TEST_LOGGING_PLOT_WITH_SSRC(1, "AudioNackBitrate_kbps", now_ms,
|
2016-09-14 05:04:36 -07:00
|
|
|
NackOverheadRate() / 1000, packet->Ssrc());
|
|
|
|
|
}
|
|
|
|
|
|
2015-10-08 11:44:14 +02:00
|
|
|
if (paced_sender_) {
|
2016-08-03 18:27:40 +02:00
|
|
|
uint16_t seq_no = packet->SequenceNumber();
|
|
|
|
|
uint32_t ssrc = packet->Ssrc();
|
2014-11-04 16:27:16 +00:00
|
|
|
// Correct offset between implementations of millisecond time stamps in
|
|
|
|
|
// TickTime and Clock.
|
2016-08-03 18:27:40 +02:00
|
|
|
int64_t corrected_time_ms = packet->capture_time_ms() + clock_delta_ms_;
|
|
|
|
|
size_t payload_length = packet->payload_size();
|
|
|
|
|
packet_history_.PutRtpPacket(std::move(packet), storage, false);
|
|
|
|
|
|
|
|
|
|
paced_sender_->InsertPacket(priority, ssrc, seq_no, corrected_time_ms,
|
2015-10-08 11:44:14 +02:00
|
|
|
payload_length, false);
|
|
|
|
|
if (last_capture_time_ms_sent_ == 0 ||
|
|
|
|
|
corrected_time_ms > last_capture_time_ms_sent_) {
|
|
|
|
|
last_capture_time_ms_sent_ = corrected_time_ms;
|
|
|
|
|
TRACE_EVENT_ASYNC_BEGIN1(TRACE_DISABLED_BY_DEFAULT("webrtc_rtp"),
|
|
|
|
|
"PacedSend", corrected_time_ms,
|
|
|
|
|
"capture_time_ms", corrected_time_ms);
|
2012-11-06 13:09:39 +00:00
|
|
|
}
|
2016-08-02 17:46:41 -07:00
|
|
|
return true;
|
2012-07-03 13:21:22 +00:00
|
|
|
}
|
2016-01-27 12:58:51 +01:00
|
|
|
|
|
|
|
|
PacketOptions options;
|
2016-08-03 18:27:40 +02:00
|
|
|
if (UpdateTransportSequenceNumber(packet.get(), &options.packet_id) &&
|
|
|
|
|
transport_feedback_observer_) {
|
2016-08-23 17:51:42 +02:00
|
|
|
transport_feedback_observer_->AddPacket(
|
|
|
|
|
options.packet_id, packet->payload_size() + packet->padding_size(),
|
|
|
|
|
PacketInfo::kNotAProbe);
|
2016-01-27 12:58:51 +01:00
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
UpdateDelayStatistics(packet->capture_time_ms(), now_ms);
|
|
|
|
|
UpdateOnSendPacket(options.packet_id, packet->capture_time_ms(),
|
|
|
|
|
packet->Ssrc());
|
|
|
|
|
|
|
|
|
|
bool sent = SendPacketToNetwork(*packet, options);
|
|
|
|
|
|
|
|
|
|
if (sent) {
|
|
|
|
|
{
|
|
|
|
|
rtc::CritScope lock(&send_critsect_);
|
|
|
|
|
media_has_been_sent_ = true;
|
|
|
|
|
}
|
|
|
|
|
UpdateRtpStats(*packet, false, false);
|
|
|
|
|
}
|
2015-02-02 13:08:02 +00:00
|
|
|
|
2015-10-08 11:44:14 +02:00
|
|
|
// Mark the packet as sent in the history even if send failed. Dropping a
|
|
|
|
|
// packet here should be treated as any other packet drop so we should be
|
|
|
|
|
// ready for a retransmission.
|
2016-08-03 18:27:40 +02:00
|
|
|
packet_history_.PutRtpPacket(std::move(packet), storage, true);
|
2015-02-02 13:08:02 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
return sent;
|
2011-12-22 12:52:41 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-05 14:05:07 +00:00
|
|
|
void RTPSender::UpdateDelayStatistics(int64_t capture_time_ms, int64_t now_ms) {
|
2016-05-02 23:44:01 -07:00
|
|
|
if (!send_side_delay_observer_ || capture_time_ms <= 0)
|
2015-05-28 14:45:36 +02:00
|
|
|
return;
|
|
|
|
|
|
2014-07-11 13:44:02 +00:00
|
|
|
uint32_t ssrc;
|
|
|
|
|
int avg_delay_ms = 0;
|
|
|
|
|
int max_delay_ms = 0;
|
|
|
|
|
{
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-11 13:44:02 +00:00
|
|
|
ssrc = ssrc_;
|
|
|
|
|
}
|
|
|
|
|
{
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&statistics_crit_);
|
2014-07-11 13:44:02 +00:00
|
|
|
// TODO(holmer): Compute this iteratively instead.
|
|
|
|
|
send_delays_[now_ms] = now_ms - capture_time_ms;
|
|
|
|
|
send_delays_.erase(send_delays_.begin(),
|
|
|
|
|
send_delays_.lower_bound(now_ms -
|
|
|
|
|
kSendSideDelayWindowMs));
|
2015-05-28 14:45:36 +02:00
|
|
|
int num_delays = 0;
|
|
|
|
|
for (auto it = send_delays_.upper_bound(now_ms - kSendSideDelayWindowMs);
|
|
|
|
|
it != send_delays_.end(); ++it) {
|
|
|
|
|
max_delay_ms = std::max(max_delay_ms, it->second);
|
|
|
|
|
avg_delay_ms += it->second;
|
|
|
|
|
++num_delays;
|
|
|
|
|
}
|
|
|
|
|
if (num_delays == 0)
|
|
|
|
|
return;
|
|
|
|
|
avg_delay_ms = (avg_delay_ms + num_delays / 2) / num_delays;
|
2014-07-11 13:44:02 +00:00
|
|
|
}
|
2015-05-28 14:45:36 +02:00
|
|
|
send_side_delay_observer_->SendSideDelayUpdated(avg_delay_ms, max_delay_ms,
|
|
|
|
|
ssrc);
|
2013-12-05 14:05:07 +00:00
|
|
|
}
|
|
|
|
|
|
2016-05-02 23:44:01 -07:00
|
|
|
void RTPSender::UpdateOnSendPacket(int packet_id,
|
|
|
|
|
int64_t capture_time_ms,
|
|
|
|
|
uint32_t ssrc) {
|
|
|
|
|
if (!send_packet_observer_ || capture_time_ms <= 0 || packet_id == -1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
send_packet_observer_->OnSendPacket(packet_id, capture_time_ms, ssrc);
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-07 17:01:04 +00:00
|
|
|
void RTPSender::ProcessBitrate() {
|
2016-07-13 09:11:28 -07:00
|
|
|
if (!bitrate_callback_)
|
2012-11-07 17:01:04 +00:00
|
|
|
return;
|
2016-07-13 09:11:28 -07:00
|
|
|
int64_t now_ms = clock_->TimeInMilliseconds();
|
|
|
|
|
uint32_t ssrc;
|
|
|
|
|
{
|
|
|
|
|
rtc::CritScope lock(&send_critsect_);
|
|
|
|
|
ssrc = ssrc_;
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
2016-07-13 09:11:28 -07:00
|
|
|
|
|
|
|
|
rtc::CritScope lock(&statistics_crit_);
|
|
|
|
|
bitrate_callback_->Notify(total_bitrate_sent_.Rate(now_ms).value_or(0),
|
|
|
|
|
nack_bitrate_sent_.Rate(now_ms).value_or(0), ssrc);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-06-08 00:24:21 -07:00
|
|
|
size_t RTPSender::RtpHeaderLength() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2015-03-04 22:55:15 +00:00
|
|
|
size_t rtp_header_length = kRtpHeaderLength;
|
2014-11-24 08:25:50 +00:00
|
|
|
rtp_header_length += sizeof(uint32_t) * csrcs_.size();
|
2016-06-08 00:24:21 -07:00
|
|
|
rtp_header_length += RtpHeaderExtensionLength();
|
2013-01-25 10:53:38 +00:00
|
|
|
return rtp_header_length;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2015-04-14 21:28:08 +02:00
|
|
|
uint16_t RTPSender::AllocateSequenceNumber(uint16_t packets_to_send) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2015-04-14 21:28:08 +02:00
|
|
|
uint16_t first_allocated_sequence_number = sequence_number_;
|
|
|
|
|
sequence_number_ += packets_to_send;
|
|
|
|
|
return first_allocated_sequence_number;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2014-07-15 15:25:39 +00:00
|
|
|
void RTPSender::GetDataCounters(StreamDataCounters* rtp_stats,
|
|
|
|
|
StreamDataCounters* rtx_stats) const {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope lock(&statistics_crit_);
|
2014-07-15 15:25:39 +00:00
|
|
|
*rtp_stats = rtp_stats_;
|
|
|
|
|
*rtx_stats = rtx_rtp_stats_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-09-02 19:15:59 +02:00
|
|
|
std::unique_ptr<RtpPacketToSend> RTPSender::AllocatePacket() const {
|
|
|
|
|
rtc::CritScope lock(&send_critsect_);
|
|
|
|
|
std::unique_ptr<RtpPacketToSend> packet(
|
|
|
|
|
new RtpPacketToSend(&rtp_header_extension_map_, max_payload_length_));
|
|
|
|
|
packet->SetSsrc(ssrc_);
|
|
|
|
|
packet->SetCsrcs(csrcs_);
|
|
|
|
|
// Reserve extensions, if registered, RtpSender set in SendToNetwork.
|
|
|
|
|
packet->ReserveExtension<AbsoluteSendTime>();
|
|
|
|
|
packet->ReserveExtension<TransmissionOffset>();
|
|
|
|
|
packet->ReserveExtension<TransportSequenceNumber>();
|
2016-10-02 10:54:29 -07:00
|
|
|
if (playout_delay_oracle_.send_playout_delay()) {
|
|
|
|
|
packet->SetExtension<PlayoutDelayLimits>(
|
|
|
|
|
playout_delay_oracle_.playout_delay());
|
|
|
|
|
}
|
2016-09-02 19:15:59 +02:00
|
|
|
return packet;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool RTPSender::AssignSequenceNumber(RtpPacketToSend* packet) {
|
|
|
|
|
rtc::CritScope lock(&send_critsect_);
|
|
|
|
|
if (!sending_media_)
|
|
|
|
|
return false;
|
|
|
|
|
RTC_DCHECK_EQ(packet->Ssrc(), ssrc_);
|
|
|
|
|
packet->SetSequenceNumber(sequence_number_++);
|
|
|
|
|
|
|
|
|
|
// Remember marker bit to determine if padding can be inserted with
|
|
|
|
|
// sequence number following |packet|.
|
|
|
|
|
last_packet_marker_bit_ = packet->Marker();
|
|
|
|
|
// Save timestamps to generate timestamp field and extensions for the padding.
|
|
|
|
|
last_rtp_timestamp_ = packet->Timestamp();
|
|
|
|
|
last_timestamp_time_ms_ = clock_->TimeInMilliseconds();
|
|
|
|
|
capture_time_ms_ = packet->capture_time_ms();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
bool RTPSender::UpdateTransportSequenceNumber(RtpPacketToSend* packet,
|
|
|
|
|
int* packet_id) const {
|
|
|
|
|
RTC_DCHECK(packet);
|
|
|
|
|
RTC_DCHECK(packet_id);
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2016-08-03 18:27:40 +02:00
|
|
|
if (!rtp_header_extension_map_.IsRegistered(TransportSequenceNumber::kId))
|
2016-07-28 07:56:38 -07:00
|
|
|
return false;
|
|
|
|
|
|
2016-05-02 23:44:01 -07:00
|
|
|
if (!transport_sequence_number_allocator_)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
*packet_id = transport_sequence_number_allocator_->AllocateSequenceNumber();
|
2016-08-03 18:27:40 +02:00
|
|
|
|
|
|
|
|
if (!packet->SetExtension<TransportSequenceNumber>(*packet_id))
|
|
|
|
|
return false;
|
|
|
|
|
|
2016-05-02 23:44:01 -07:00
|
|
|
return true;
|
2015-08-03 04:38:41 -07:00
|
|
|
}
|
|
|
|
|
|
2013-09-09 16:02:19 +00:00
|
|
|
void RTPSender::SetSendingStatus(bool enabled) {
|
2016-08-18 02:01:49 -07:00
|
|
|
if (!enabled) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!ssrc_forced_) {
|
|
|
|
|
// Generate a new SSRC.
|
2016-02-02 08:31:45 -08:00
|
|
|
ssrc_db_->ReturnSSRC(ssrc_);
|
|
|
|
|
ssrc_ = ssrc_db_->CreateSSRC();
|
|
|
|
|
RTC_DCHECK(ssrc_ != 0);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
2012-11-07 17:01:04 +00:00
|
|
|
// Don't initialize seq number if SSRC passed externally.
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!sequence_number_forced_ && !ssrc_forced_) {
|
|
|
|
|
// Generate a new sequence number.
|
2015-12-15 00:30:07 -08:00
|
|
|
sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber);
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
|
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
void RTPSender::SetSendingMediaStatus(bool enabled) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
sending_media_ = enabled;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-11-07 17:01:04 +00:00
|
|
|
bool RTPSender::SendingMedia() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
return sending_media_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-18 02:01:49 -07:00
|
|
|
void RTPSender::SetTimestampOffset(uint32_t timestamp) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2016-08-18 02:01:49 -07:00
|
|
|
timestamp_offset_ = timestamp;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-08-18 02:01:49 -07:00
|
|
|
uint32_t RTPSender::TimestampOffset() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2016-08-18 02:01:49 -07:00
|
|
|
return timestamp_offset_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t RTPSender::GenerateNewSSRC() {
|
2013-01-25 10:53:38 +00:00
|
|
|
// If configured via API, return 0.
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-01-25 10:53:38 +00:00
|
|
|
if (ssrc_forced_) {
|
2012-11-07 17:01:04 +00:00
|
|
|
return 0;
|
|
|
|
|
}
|
2016-02-02 08:31:45 -08:00
|
|
|
ssrc_ = ssrc_db_->CreateSSRC();
|
|
|
|
|
RTC_DCHECK(ssrc_ != 0);
|
2013-01-25 10:53:38 +00:00
|
|
|
return ssrc_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
void RTPSender::SetSSRC(uint32_t ssrc) {
|
2013-01-25 10:53:38 +00:00
|
|
|
// This is configured via the API.
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2011-07-07 08:21:25 +00:00
|
|
|
|
2013-01-25 10:53:38 +00:00
|
|
|
if (ssrc_ == ssrc && ssrc_forced_) {
|
|
|
|
|
return; // Since it's same ssrc, don't reset anything.
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
2013-01-25 10:53:38 +00:00
|
|
|
ssrc_forced_ = true;
|
2016-02-02 08:31:45 -08:00
|
|
|
ssrc_db_->ReturnSSRC(ssrc_);
|
|
|
|
|
ssrc_db_->RegisterSSRC(ssrc);
|
2013-01-25 10:53:38 +00:00
|
|
|
ssrc_ = ssrc;
|
|
|
|
|
if (!sequence_number_forced_) {
|
2015-12-15 00:30:07 -08:00
|
|
|
sequence_number_ = random_.Rand(1, kMaxInitRtpSeqNumber);
|
2012-11-07 17:01:04 +00:00
|
|
|
}
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
uint32_t RTPSender::SSRC() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
return ssrc_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2014-11-24 08:25:50 +00:00
|
|
|
void RTPSender::SetCsrcs(const std::vector<uint32_t>& csrcs) {
|
|
|
|
|
assert(csrcs.size() <= kRtpCsrcSize);
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-11-24 08:25:50 +00:00
|
|
|
csrcs_ = csrcs;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
void RTPSender::SetSequenceNumber(uint16_t seq) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
sequence_number_forced_ = true;
|
|
|
|
|
sequence_number_ = seq;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-04-08 11:08:41 +00:00
|
|
|
uint16_t RTPSender::SequenceNumber() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2013-01-25 10:53:38 +00:00
|
|
|
return sequence_number_;
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2013-01-25 10:53:38 +00:00
|
|
|
// Audio.
|
2014-12-19 13:49:55 +00:00
|
|
|
int32_t RTPSender::SendTelephoneEvent(uint8_t key,
|
|
|
|
|
uint16_t time_ms,
|
|
|
|
|
uint8_t level) {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!audio_configured_) {
|
2012-11-07 17:01:04 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2013-01-25 10:53:38 +00:00
|
|
|
return audio_->SendTelephoneEvent(key, time_ms, level);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
int32_t RTPSender::SetAudioPacketSize(uint16_t packet_size_samples) {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (!audio_configured_) {
|
2012-11-07 17:01:04 +00:00
|
|
|
return -1;
|
|
|
|
|
}
|
2013-01-25 10:53:38 +00:00
|
|
|
return audio_->SetAudioPacketSize(packet_size_samples);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2014-12-19 13:49:55 +00:00
|
|
|
int32_t RTPSender::SetAudioLevel(uint8_t level_d_bov) {
|
2013-01-25 10:53:38 +00:00
|
|
|
return audio_->SetAudioLevel(level_d_bov);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2012-11-07 17:01:04 +00:00
|
|
|
RtpVideoCodecTypes RTPSender::VideoCodecType() const {
|
2013-03-18 16:39:03 +00:00
|
|
|
assert(!audio_configured_ && "Sender is an audio stream!");
|
2013-01-25 10:53:38 +00:00
|
|
|
return video_->VideoCodecType();
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-11-07 03:05:06 -08:00
|
|
|
void RTPSender::SetUlpfecConfig(int red_payload_type, int ulpfec_payload_type) {
|
2015-09-17 00:24:34 -07:00
|
|
|
RTC_DCHECK(!audio_configured_);
|
2016-11-07 03:05:06 -08:00
|
|
|
video_->SetUlpfecConfig(red_payload_type, ulpfec_payload_type);
|
2011-07-07 08:21:25 +00:00
|
|
|
}
|
|
|
|
|
|
2016-11-07 03:36:05 -08:00
|
|
|
bool RTPSender::SetFecParameters(const FecProtectionParams& delta_params,
|
|
|
|
|
const FecProtectionParams& key_params) {
|
2013-01-25 10:53:38 +00:00
|
|
|
if (audio_configured_) {
|
2016-11-07 03:36:05 -08:00
|
|
|
return false;
|
2012-03-20 22:10:56 +00:00
|
|
|
}
|
2015-04-14 21:28:08 +02:00
|
|
|
video_->SetFecParameters(delta_params, key_params);
|
2016-11-07 03:36:05 -08:00
|
|
|
return true;
|
2011-07-15 21:32:40 +00:00
|
|
|
}
|
2013-01-25 10:53:38 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
std::unique_ptr<RtpPacketToSend> RTPSender::BuildRtxPacket(
|
|
|
|
|
const RtpPacketToSend& packet) {
|
|
|
|
|
// TODO(danilchap): Create rtx packet with extra capacity for SRTP
|
|
|
|
|
// when transport interface would be updated to take buffer class.
|
|
|
|
|
std::unique_ptr<RtpPacketToSend> rtx_packet(new RtpPacketToSend(
|
|
|
|
|
&rtp_header_extension_map_, packet.size() + kRtxHeaderSize));
|
|
|
|
|
// Add original RTP header.
|
|
|
|
|
rtx_packet->CopyHeaderFrom(packet);
|
|
|
|
|
{
|
|
|
|
|
rtc::CritScope lock(&send_critsect_);
|
|
|
|
|
if (!sending_media_)
|
|
|
|
|
return nullptr;
|
2013-03-15 23:21:52 +00:00
|
|
|
|
Remove RED/RTX workaround from sender/receiver and VideoEngine2.
In older Chrome versions, the associated payload type in the RTX header
of retransmitted packets was always set to be the original media payload type,
regardless of the actual payload type of the packet. This meant that packets
encapsulated with RED headers had incorrect payload type information in the
RTX header. Due to an assumption in the receiver, this incorrect payload type
information would effectively be undone, leading to a working system.
Albeit working, this behaviour was undesired, and thus removed. In the interim,
several workarounds were introduced to not destroy interop between old and
new Chrome versions:
(1) https://codereview.webrtc.org/1649493004
- If no payload type mapping existed for RED over RTX, the payload type
of the underlying media would be used.
- If RED had been negotiated, received RTX packets would always be
assumed to contain RED.
(2) https://codereview.webrtc.org/1964473002
- If RED was removed from the remote description answer, it would be
disabled in the local receiver as well.
(3) https://codereview.webrtc.org/2033763002
- If RED was negotiated in the SDP, it would always be used, regardless
if ULPFEC was negotiated and used, or not.
Since the Chrome versions that exhibited the original bug now are very old,
this CL removes the workarounds from (1) and (2). In particular, after this
change, we will have the following behaviour:
- We assume that a payload type mapping for RED over RTX always is set.
If this is not the case, the RTX packet is not sent.
- The associated payload type of received RTX packets will always be obeyed.
- The (non)-existence of RED in the remote description does not affect the
local receiver.
The workaround in (3) still needs to exist, in order to interop with receivers
that did not have the workarounds in (1) and (2) removed. The change in (3)
can be removed in a couple of Chrome versions.
TESTED=Using AppRTC between patched Chrome (connected to ethernet) and standard Chrome M54 (connected to lossy internal Google WiFi), with and without FEC turned off using AppRTC flag. Also using "Munge SDP" sample on patched Chrome over loopback interface, with 100ms delay and 5% packet loss simulated using tc.
BUG=webrtc:6650
Review-Url: https://codereview.webrtc.org/2469093003
Cr-Commit-Position: refs/heads/master@{#15038}
2016-11-11 03:28:30 -08:00
|
|
|
// Replace payload type.
|
|
|
|
|
auto kv = rtx_payload_type_map_.find(packet.PayloadType());
|
2016-08-03 18:27:40 +02:00
|
|
|
if (kv == rtx_payload_type_map_.end())
|
Remove RED/RTX workaround from sender/receiver and VideoEngine2.
In older Chrome versions, the associated payload type in the RTX header
of retransmitted packets was always set to be the original media payload type,
regardless of the actual payload type of the packet. This meant that packets
encapsulated with RED headers had incorrect payload type information in the
RTX header. Due to an assumption in the receiver, this incorrect payload type
information would effectively be undone, leading to a working system.
Albeit working, this behaviour was undesired, and thus removed. In the interim,
several workarounds were introduced to not destroy interop between old and
new Chrome versions:
(1) https://codereview.webrtc.org/1649493004
- If no payload type mapping existed for RED over RTX, the payload type
of the underlying media would be used.
- If RED had been negotiated, received RTX packets would always be
assumed to contain RED.
(2) https://codereview.webrtc.org/1964473002
- If RED was removed from the remote description answer, it would be
disabled in the local receiver as well.
(3) https://codereview.webrtc.org/2033763002
- If RED was negotiated in the SDP, it would always be used, regardless
if ULPFEC was negotiated and used, or not.
Since the Chrome versions that exhibited the original bug now are very old,
this CL removes the workarounds from (1) and (2). In particular, after this
change, we will have the following behaviour:
- We assume that a payload type mapping for RED over RTX always is set.
If this is not the case, the RTX packet is not sent.
- The associated payload type of received RTX packets will always be obeyed.
- The (non)-existence of RED in the remote description does not affect the
local receiver.
The workaround in (3) still needs to exist, in order to interop with receivers
that did not have the workarounds in (1) and (2) removed. The change in (3)
can be removed in a couple of Chrome versions.
TESTED=Using AppRTC between patched Chrome (connected to ethernet) and standard Chrome M54 (connected to lossy internal Google WiFi), with and without FEC turned off using AppRTC flag. Also using "Munge SDP" sample on patched Chrome over loopback interface, with 100ms delay and 5% packet loss simulated using tc.
BUG=webrtc:6650
Review-Url: https://codereview.webrtc.org/2469093003
Cr-Commit-Position: refs/heads/master@{#15038}
2016-11-11 03:28:30 -08:00
|
|
|
return nullptr;
|
|
|
|
|
rtx_packet->SetPayloadType(kv->second);
|
2013-03-15 23:21:52 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
// Replace sequence number.
|
|
|
|
|
rtx_packet->SetSequenceNumber(sequence_number_rtx_++);
|
2013-03-15 23:21:52 +00:00
|
|
|
|
2016-08-03 18:27:40 +02:00
|
|
|
// Replace SSRC.
|
|
|
|
|
rtx_packet->SetSsrc(ssrc_rtx_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint8_t* rtx_payload =
|
|
|
|
|
rtx_packet->AllocatePayload(packet.payload_size() + kRtxHeaderSize);
|
|
|
|
|
RTC_DCHECK(rtx_payload);
|
2013-03-15 23:21:52 +00:00
|
|
|
// Add OSN (original sequence number).
|
2016-08-03 18:27:40 +02:00
|
|
|
ByteWriter<uint16_t>::WriteBigEndian(rtx_payload, packet.SequenceNumber());
|
2013-03-15 23:21:52 +00:00
|
|
|
|
|
|
|
|
// Add original payload data.
|
2016-08-03 18:27:40 +02:00
|
|
|
memcpy(rtx_payload + kRtxHeaderSize, packet.payload(), packet.payload_size());
|
|
|
|
|
|
|
|
|
|
return rtx_packet;
|
2013-03-15 23:21:52 +00:00
|
|
|
}
|
|
|
|
|
|
2013-12-05 14:29:02 +00:00
|
|
|
void RTPSender::RegisterRtpStatisticsCallback(
|
|
|
|
|
StreamDataCountersCallback* callback) {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&statistics_crit_);
|
2013-12-05 14:29:02 +00:00
|
|
|
rtp_stats_callback_ = callback;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StreamDataCountersCallback* RTPSender::GetRtpStatisticsCallback() const {
|
2016-04-14 03:05:31 -07:00
|
|
|
rtc::CritScope cs(&statistics_crit_);
|
2013-12-05 14:29:02 +00:00
|
|
|
return rtp_stats_callback_;
|
|
|
|
|
}
|
|
|
|
|
|
2014-11-05 14:05:29 +00:00
|
|
|
uint32_t RTPSender::BitrateSent() const {
|
2016-07-13 09:11:28 -07:00
|
|
|
rtc::CritScope cs(&statistics_crit_);
|
|
|
|
|
return total_bitrate_sent_.Rate(clock_->TimeInMilliseconds()).value_or(0);
|
2013-12-13 09:46:59 +00:00
|
|
|
}
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
void RTPSender::SetRtpState(const RtpState& rtp_state) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-07 13:06:48 +00:00
|
|
|
sequence_number_ = rtp_state.sequence_number;
|
|
|
|
|
sequence_number_forced_ = true;
|
2016-08-18 02:01:49 -07:00
|
|
|
timestamp_offset_ = rtp_state.start_timestamp;
|
2016-08-22 03:39:23 -07:00
|
|
|
last_rtp_timestamp_ = rtp_state.timestamp;
|
2014-07-07 13:06:48 +00:00
|
|
|
capture_time_ms_ = rtp_state.capture_time_ms;
|
|
|
|
|
last_timestamp_time_ms_ = rtp_state.last_timestamp_time_ms;
|
2014-07-17 16:10:14 +00:00
|
|
|
media_has_been_sent_ = rtp_state.media_has_been_sent;
|
2014-07-07 13:06:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtpState RTPSender::GetRtpState() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
RtpState state;
|
|
|
|
|
state.sequence_number = sequence_number_;
|
2016-08-18 02:01:49 -07:00
|
|
|
state.start_timestamp = timestamp_offset_;
|
2016-08-22 03:39:23 -07:00
|
|
|
state.timestamp = last_rtp_timestamp_;
|
2014-07-07 13:06:48 +00:00
|
|
|
state.capture_time_ms = capture_time_ms_;
|
|
|
|
|
state.last_timestamp_time_ms = last_timestamp_time_ms_;
|
2014-07-17 16:10:14 +00:00
|
|
|
state.media_has_been_sent = media_has_been_sent_;
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void RTPSender::SetRtxRtpState(const RtpState& rtp_state) {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-07 13:06:48 +00:00
|
|
|
sequence_number_rtx_ = rtp_state.sequence_number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RtpState RTPSender::GetRtxRtpState() const {
|
2016-02-02 08:31:45 -08:00
|
|
|
rtc::CritScope lock(&send_critsect_);
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
RtpState state;
|
|
|
|
|
state.sequence_number = sequence_number_rtx_;
|
2016-08-18 02:01:49 -07:00
|
|
|
state.start_timestamp = timestamp_offset_;
|
2014-07-07 13:06:48 +00:00
|
|
|
|
|
|
|
|
return state;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-07 17:01:04 +00:00
|
|
|
} // namespace webrtc
|