
This is the first step in order to move bandwidth estimation closer to the network. The goal is to have RTP header parsing and bandwidth estimation before voice and video engine, and have a joint estimate for audio and video. Moving bandwidth estimation before the RTP module is also required for RTX. TEST=vie_auto_test, voe_auto_test, trybots. BUG=1811 R=andresp@webrtc.org, henrika@webrtc.org, mflodman@webrtc.org Review URL: https://webrtc-codereview.appspot.com/1545004 git-svn-id: http://webrtc.googlecode.com/svn/trunk@4129 4adac7df-926f-26a2-2b94-8c16560cd09d
2039 lines
64 KiB
C++
2039 lines
64 KiB
C++
/*
|
|
* Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_rtcp_impl.h"
|
|
|
|
#include <string.h>
|
|
#include <cassert>
|
|
|
|
#include "webrtc/common_types.h"
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_audio.h"
|
|
#include "webrtc/modules/rtp_rtcp/source/rtp_receiver_video.h"
|
|
#include "webrtc/system_wrappers/interface/logging.h"
|
|
#include "webrtc/system_wrappers/interface/trace.h"
|
|
|
|
#ifdef MATLAB
|
|
#include "webrtc/modules/rtp_rtcp/test/BWEStandAlone/MatlabPlot.h"
|
|
extern MatlabEngine eng; // Global variable defined elsewhere.
|
|
#endif
|
|
|
|
// Local for this file.
|
|
namespace {
|
|
|
|
const float kFracMs = 4.294967296E6f;
|
|
|
|
} // namespace
|
|
|
|
#ifdef _WIN32
|
|
// Disable warning C4355: 'this' : used in base member initializer list.
|
|
#pragma warning(disable : 4355)
|
|
#endif
|
|
|
|
namespace webrtc {
|
|
|
|
static RtpData* NullObjectRtpData() {
|
|
static NullRtpData null_rtp_data;
|
|
return &null_rtp_data;
|
|
}
|
|
|
|
static RtpFeedback* NullObjectRtpFeedback() {
|
|
static NullRtpFeedback null_rtp_feedback;
|
|
return &null_rtp_feedback;
|
|
}
|
|
|
|
static RtpAudioFeedback* NullObjectRtpAudioFeedback() {
|
|
static NullRtpAudioFeedback null_rtp_audio_feedback;
|
|
return &null_rtp_audio_feedback;
|
|
}
|
|
|
|
RtpRtcp::Configuration::Configuration()
|
|
: id(-1),
|
|
audio(false),
|
|
clock(NULL),
|
|
default_module(NULL),
|
|
incoming_data(NullObjectRtpData()),
|
|
incoming_messages(NullObjectRtpFeedback()),
|
|
outgoing_transport(NULL),
|
|
rtcp_feedback(NULL),
|
|
intra_frame_callback(NULL),
|
|
bandwidth_callback(NULL),
|
|
rtt_observer(NULL),
|
|
audio_messages(NullObjectRtpAudioFeedback()),
|
|
remote_bitrate_estimator(NULL),
|
|
paced_sender(NULL) {
|
|
}
|
|
|
|
RtpRtcp* RtpRtcp::CreateRtpRtcp(const RtpRtcp::Configuration& configuration) {
|
|
if (configuration.clock) {
|
|
return new ModuleRtpRtcpImpl(configuration);
|
|
} else {
|
|
RtpRtcp::Configuration configuration_copy;
|
|
memcpy(&configuration_copy, &configuration,
|
|
sizeof(RtpRtcp::Configuration));
|
|
configuration_copy.clock = Clock::GetRealTimeClock();
|
|
ModuleRtpRtcpImpl* rtp_rtcp_instance =
|
|
new ModuleRtpRtcpImpl(configuration_copy);
|
|
return rtp_rtcp_instance;
|
|
}
|
|
}
|
|
|
|
ModuleRtpRtcpImpl::ModuleRtpRtcpImpl(const Configuration& configuration)
|
|
: rtp_payload_registry_(
|
|
configuration.id,
|
|
RTPPayloadStrategy::CreateStrategy(configuration.audio)),
|
|
rtp_sender_(configuration.id,
|
|
configuration.audio,
|
|
configuration.clock,
|
|
configuration.outgoing_transport,
|
|
configuration.audio_messages,
|
|
configuration.paced_sender),
|
|
rtcp_sender_(configuration.id, configuration.audio, configuration.clock,
|
|
this),
|
|
rtcp_receiver_(configuration.id, configuration.clock, this),
|
|
clock_(configuration.clock),
|
|
rtp_telephone_event_handler_(NULL),
|
|
id_(configuration.id),
|
|
audio_(configuration.audio),
|
|
collision_detected_(false),
|
|
last_process_time_(configuration.clock->TimeInMilliseconds()),
|
|
last_bitrate_process_time_(configuration.clock->TimeInMilliseconds()),
|
|
last_packet_timeout_process_time_(
|
|
configuration.clock->TimeInMilliseconds()),
|
|
last_rtt_process_time_(configuration.clock->TimeInMilliseconds()),
|
|
packet_overhead_(28), // IPV4 UDP.
|
|
critical_section_module_ptrs_(
|
|
CriticalSectionWrapper::CreateCriticalSection()),
|
|
critical_section_module_ptrs_feedback_(
|
|
CriticalSectionWrapper::CreateCriticalSection()),
|
|
default_module_(
|
|
static_cast<ModuleRtpRtcpImpl*>(configuration.default_module)),
|
|
dead_or_alive_active_(false),
|
|
dead_or_alive_timeout_ms_(0),
|
|
dead_or_alive_last_timer_(0),
|
|
nack_method_(kNackOff),
|
|
nack_last_time_sent_full_(0),
|
|
nack_last_seq_number_sent_(0),
|
|
simulcast_(false),
|
|
key_frame_req_method_(kKeyFrameReqFirRtp),
|
|
remote_bitrate_(configuration.remote_bitrate_estimator),
|
|
#ifdef MATLAB
|
|
, plot1_(NULL),
|
|
#endif
|
|
rtt_observer_(configuration.rtt_observer) {
|
|
RTPReceiverStrategy* rtp_receiver_strategy;
|
|
if (configuration.audio) {
|
|
// If audio, we need to be able to handle telephone events too, so stash
|
|
// away the audio receiver for those situations.
|
|
rtp_telephone_event_handler_ =
|
|
new RTPReceiverAudio(configuration.id, configuration.incoming_data,
|
|
configuration.audio_messages);
|
|
rtp_receiver_strategy = rtp_telephone_event_handler_;
|
|
} else {
|
|
rtp_receiver_strategy =
|
|
new RTPReceiverVideo(configuration.id, &rtp_payload_registry_,
|
|
configuration.incoming_data);
|
|
}
|
|
rtp_receiver_.reset(new RTPReceiver(
|
|
configuration.id, configuration.clock, this,
|
|
configuration.audio_messages, configuration.incoming_data,
|
|
configuration.incoming_messages, rtp_receiver_strategy,
|
|
&rtp_payload_registry_));
|
|
|
|
|
|
send_video_codec_.codecType = kVideoCodecUnknown;
|
|
|
|
if (default_module_) {
|
|
default_module_->RegisterChildModule(this);
|
|
}
|
|
// TODO(pwestin) move to constructors of each rtp/rtcp sender/receiver object.
|
|
rtcp_receiver_.RegisterRtcpObservers(configuration.intra_frame_callback,
|
|
configuration.bandwidth_callback,
|
|
configuration.rtcp_feedback);
|
|
rtcp_sender_.RegisterSendTransport(configuration.outgoing_transport);
|
|
|
|
// Make sure that RTCP objects are aware of our SSRC
|
|
uint32_t SSRC = rtp_sender_.SSRC();
|
|
rtcp_sender_.SetSSRC(SSRC);
|
|
rtcp_receiver_.SetSSRC(SSRC);
|
|
|
|
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id_, "%s created", __FUNCTION__);
|
|
}
|
|
|
|
ModuleRtpRtcpImpl::~ModuleRtpRtcpImpl() {
|
|
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id_, "%s deleted", __FUNCTION__);
|
|
|
|
// All child modules MUST be deleted before deleting the default.
|
|
assert(child_modules_.empty());
|
|
|
|
// Deregister for the child modules.
|
|
// Will go in to the default and remove it self.
|
|
if (default_module_) {
|
|
default_module_->DeRegisterChildModule(this);
|
|
}
|
|
#ifdef MATLAB
|
|
if (plot1_) {
|
|
eng.DeletePlot(plot1_);
|
|
plot1_ = NULL;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::RegisterChildModule(RtpRtcp* module) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"RegisterChildModule(module:0x%x)",
|
|
module);
|
|
|
|
CriticalSectionScoped lock(
|
|
critical_section_module_ptrs_.get());
|
|
CriticalSectionScoped double_lock(
|
|
critical_section_module_ptrs_feedback_.get());
|
|
|
|
// We use two locks for protecting child_modules_, one
|
|
// (critical_section_module_ptrs_feedback_) for incoming
|
|
// messages (BitrateSent) and critical_section_module_ptrs_
|
|
// for all outgoing messages sending packets etc.
|
|
child_modules_.push_back(static_cast<ModuleRtpRtcpImpl*>(module));
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::DeRegisterChildModule(RtpRtcp* remove_module) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"DeRegisterChildModule(module:0x%x)", remove_module);
|
|
|
|
CriticalSectionScoped lock(
|
|
critical_section_module_ptrs_.get());
|
|
CriticalSectionScoped double_lock(
|
|
critical_section_module_ptrs_feedback_.get());
|
|
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module == remove_module) {
|
|
child_modules_.erase(it);
|
|
return;
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
|
|
// Returns the number of milliseconds until the module want a worker thread
|
|
// to call Process.
|
|
int32_t ModuleRtpRtcpImpl::TimeUntilNextProcess() {
|
|
const int64_t now = clock_->TimeInMilliseconds();
|
|
return kRtpRtcpMaxIdleTimeProcess - (now - last_process_time_);
|
|
}
|
|
|
|
// Process any pending tasks such as timeouts (non time critical events).
|
|
int32_t ModuleRtpRtcpImpl::Process() {
|
|
const int64_t now = clock_->TimeInMilliseconds();
|
|
last_process_time_ = now;
|
|
|
|
if (now >=
|
|
last_packet_timeout_process_time_ + kRtpRtcpPacketTimeoutProcessTimeMs) {
|
|
rtp_receiver_->PacketTimeout();
|
|
rtcp_receiver_.PacketTimeout();
|
|
last_packet_timeout_process_time_ = now;
|
|
}
|
|
|
|
if (now >= last_bitrate_process_time_ + kRtpRtcpBitrateProcessTimeMs) {
|
|
rtp_sender_.ProcessBitrate();
|
|
rtp_receiver_->ProcessBitrate();
|
|
last_bitrate_process_time_ = now;
|
|
}
|
|
|
|
ProcessDeadOrAliveTimer();
|
|
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
if (!default_instance) {
|
|
if (rtcp_sender_.Sending()) {
|
|
// Process RTT if we have received a receiver report and we haven't
|
|
// processed RTT for at least |kRtpRtcpRttProcessTimeMs| milliseconds.
|
|
if (rtcp_receiver_.LastReceivedReceiverReport() >
|
|
last_rtt_process_time_ && now >= last_rtt_process_time_ +
|
|
kRtpRtcpRttProcessTimeMs) {
|
|
last_rtt_process_time_ = now;
|
|
std::vector<RTCPReportBlock> receive_blocks;
|
|
rtcp_receiver_.StatisticsReceived(&receive_blocks);
|
|
uint16_t max_rtt = 0;
|
|
for (std::vector<RTCPReportBlock>::iterator it = receive_blocks.begin();
|
|
it != receive_blocks.end(); ++it) {
|
|
uint16_t rtt = 0;
|
|
rtcp_receiver_.RTT(it->remoteSSRC, &rtt, NULL, NULL, NULL);
|
|
max_rtt = (rtt > max_rtt) ? rtt : max_rtt;
|
|
}
|
|
// Report the rtt.
|
|
if (rtt_observer_ && max_rtt != 0)
|
|
rtt_observer_->OnRttUpdate(max_rtt);
|
|
}
|
|
|
|
// Verify receiver reports are delivered and the reported sequence number
|
|
// is increasing.
|
|
int64_t rtcp_interval = RtcpReportInterval();
|
|
if (rtcp_receiver_.RtcpRrTimeout(rtcp_interval)) {
|
|
LOG_F(LS_WARNING) << "Timeout: No RTCP RR received.";
|
|
} else if (rtcp_receiver_.RtcpRrSequenceNumberTimeout(rtcp_interval)) {
|
|
LOG_F(LS_WARNING) <<
|
|
"Timeout: No increase in RTCP RR extended highest sequence number.";
|
|
}
|
|
|
|
if (remote_bitrate_ && TMMBR()) {
|
|
unsigned int target_bitrate = 0;
|
|
std::vector<unsigned int> ssrcs;
|
|
if (remote_bitrate_->LatestEstimate(&ssrcs, &target_bitrate)) {
|
|
if (!ssrcs.empty()) {
|
|
target_bitrate = target_bitrate / ssrcs.size();
|
|
}
|
|
rtcp_sender_.SetTargetBitrate(target_bitrate);
|
|
}
|
|
}
|
|
}
|
|
if (rtcp_sender_.TimeToSendRTCPReport())
|
|
rtcp_sender_.SendRTCP(kRtcpReport);
|
|
}
|
|
|
|
if (UpdateRTCPReceiveInformationTimers()) {
|
|
// A receiver has timed out
|
|
rtcp_receiver_.UpdateTMMBR();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::ProcessDeadOrAliveTimer() {
|
|
bool RTCPalive = false;
|
|
int64_t now = 0;
|
|
bool do_callback = false;
|
|
|
|
// Do operations on members under lock but avoid making the
|
|
// ProcessDeadOrAlive() callback under the same lock.
|
|
{
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
if (dead_or_alive_active_) {
|
|
now = clock_->TimeInMilliseconds();
|
|
if (now > dead_or_alive_timeout_ms_ + dead_or_alive_last_timer_) {
|
|
// RTCP is alive if we have received a report the last 12 seconds.
|
|
dead_or_alive_last_timer_ += dead_or_alive_timeout_ms_;
|
|
|
|
if (rtcp_receiver_.LastReceived() + 12000 > now)
|
|
RTCPalive = true;
|
|
|
|
do_callback = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (do_callback)
|
|
rtp_receiver_->ProcessDeadOrAlive(RTCPalive, now);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetPeriodicDeadOrAliveStatus(
|
|
const bool enable,
|
|
const uint8_t sample_time_seconds) {
|
|
if (enable) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetPeriodicDeadOrAliveStatus(enable, %d)",
|
|
sample_time_seconds);
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetPeriodicDeadOrAliveStatus(disable)");
|
|
}
|
|
if (sample_time_seconds == 0) {
|
|
return -1;
|
|
}
|
|
{
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
dead_or_alive_active_ = enable;
|
|
dead_or_alive_timeout_ms_ = sample_time_seconds * 1000;
|
|
// Trigger the first after one period.
|
|
dead_or_alive_last_timer_ = clock_->TimeInMilliseconds();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::PeriodicDeadOrAliveStatus(
|
|
bool& enable,
|
|
uint8_t& sample_time_seconds) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"PeriodicDeadOrAliveStatus()");
|
|
|
|
enable = dead_or_alive_active_;
|
|
sample_time_seconds =
|
|
static_cast<uint8_t>(dead_or_alive_timeout_ms_ / 1000);
|
|
return 0;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetPacketTimeout(
|
|
const uint32_t rtp_timeout_ms,
|
|
const uint32_t rtcp_timeout_ms) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetPacketTimeout(%u,%u)",
|
|
rtp_timeout_ms,
|
|
rtcp_timeout_ms);
|
|
|
|
if (rtp_receiver_->SetPacketTimeout(rtp_timeout_ms) == 0) {
|
|
return rtcp_receiver_.SetPacketTimeout(rtcp_timeout_ms);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RegisterReceivePayload(
|
|
const CodecInst& voice_codec) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"RegisterReceivePayload(voice_codec)");
|
|
|
|
return rtp_receiver_->RegisterReceivePayload(
|
|
voice_codec.plname,
|
|
voice_codec.pltype,
|
|
voice_codec.plfreq,
|
|
voice_codec.channels,
|
|
(voice_codec.rate < 0) ? 0 : voice_codec.rate);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RegisterReceivePayload(
|
|
const VideoCodec& video_codec) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"RegisterReceivePayload(video_codec)");
|
|
|
|
return rtp_receiver_->RegisterReceivePayload(video_codec.plName,
|
|
video_codec.plType,
|
|
90000,
|
|
0,
|
|
video_codec.maxBitrate);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::ReceivePayloadType(
|
|
const CodecInst& voice_codec,
|
|
int8_t* pl_type) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"ReceivePayloadType(voice_codec)");
|
|
|
|
return rtp_receiver_->ReceivePayloadType(
|
|
voice_codec.plname,
|
|
voice_codec.plfreq,
|
|
voice_codec.channels,
|
|
(voice_codec.rate < 0) ? 0 : voice_codec.rate,
|
|
pl_type);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::ReceivePayloadType(
|
|
const VideoCodec& video_codec,
|
|
int8_t* pl_type) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"ReceivePayloadType(video_codec)");
|
|
|
|
return rtp_receiver_->ReceivePayloadType(video_codec.plName,
|
|
90000,
|
|
0,
|
|
video_codec.maxBitrate,
|
|
pl_type);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::DeRegisterReceivePayload(
|
|
const int8_t payload_type) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"DeRegisterReceivePayload(%d)",
|
|
payload_type);
|
|
|
|
return rtp_receiver_->DeRegisterReceivePayload(payload_type);
|
|
}
|
|
|
|
// Get the currently configured SSRC filter.
|
|
int32_t ModuleRtpRtcpImpl::SSRCFilter(
|
|
uint32_t& allowed_ssrc) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SSRCFilter()");
|
|
|
|
return rtp_receiver_->SSRCFilter(allowed_ssrc);
|
|
}
|
|
|
|
// Set a SSRC to be used as a filter for incoming RTP streams.
|
|
int32_t ModuleRtpRtcpImpl::SetSSRCFilter(
|
|
const bool enable,
|
|
const uint32_t allowed_ssrc) {
|
|
if (enable) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetSSRCFilter(enable, 0x%x)",
|
|
allowed_ssrc);
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetSSRCFilter(disable)");
|
|
}
|
|
|
|
return rtp_receiver_->SetSSRCFilter(enable, allowed_ssrc);
|
|
}
|
|
|
|
// Get last received remote timestamp.
|
|
uint32_t ModuleRtpRtcpImpl::RemoteTimestamp() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoteTimestamp()");
|
|
|
|
return rtp_receiver_->TimeStamp();
|
|
}
|
|
|
|
int64_t ModuleRtpRtcpImpl::LocalTimeOfRemoteTimeStamp() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"LocalTimeOfRemoteTimeStamp()");
|
|
|
|
return rtp_receiver_->LastReceivedTimeMs();
|
|
}
|
|
|
|
// Get the current estimated remote timestamp.
|
|
int32_t ModuleRtpRtcpImpl::EstimatedRemoteTimeStamp(
|
|
uint32_t& timestamp) const {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"EstimatedRemoteTimeStamp()");
|
|
|
|
return rtp_receiver_->EstimatedRemoteTimeStamp(timestamp);
|
|
}
|
|
|
|
// Get incoming SSRC.
|
|
uint32_t ModuleRtpRtcpImpl::RemoteSSRC() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoteSSRC()");
|
|
|
|
return rtp_receiver_->SSRC();
|
|
}
|
|
|
|
// Get remote CSRC
|
|
int32_t ModuleRtpRtcpImpl::RemoteCSRCs(
|
|
uint32_t arr_of_csrc[kRtpCsrcSize]) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoteCSRCs()");
|
|
|
|
return rtp_receiver_->CSRCs(arr_of_csrc);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetRTXSendStatus(RtxMode mode, bool set_ssrc,
|
|
uint32_t ssrc) {
|
|
rtp_sender_.SetRTXStatus(mode, set_ssrc, ssrc);
|
|
return 0;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RTXSendStatus(RtxMode* mode, uint32_t* ssrc,
|
|
int* payload_type) const {
|
|
rtp_sender_.RTXStatus(mode, ssrc, payload_type);
|
|
return 0;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetRTXReceiveStatus(bool enable,
|
|
uint32_t ssrc) {
|
|
rtp_receiver_->SetRTXStatus(enable, ssrc);
|
|
return 0;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RTXReceiveStatus(bool* enable, uint32_t* ssrc,
|
|
int* payload_type) const {
|
|
rtp_receiver_->RTXStatus(enable, ssrc, payload_type);
|
|
return 0;
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::SetRtxSendPayloadType(int payload_type) {
|
|
rtp_sender_.SetRtxPayloadType(payload_type);
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::SetRtxReceivePayloadType(int payload_type) {
|
|
rtp_receiver_->SetRtxPayloadType(payload_type);
|
|
}
|
|
|
|
// Called by the network module when we receive a packet.
|
|
int32_t ModuleRtpRtcpImpl::IncomingRtpPacket(
|
|
const uint8_t* incoming_packet,
|
|
const uint16_t incoming_packet_length,
|
|
const RTPHeader& parsed_rtp_header) {
|
|
WEBRTC_TRACE(kTraceStream,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"IncomingRtpPacket(packet_length:%u)",
|
|
incoming_packet_length);
|
|
RTPHeader rtp_header_copy = parsed_rtp_header;
|
|
return rtp_receiver_->IncomingRTPPacket(&rtp_header_copy,
|
|
incoming_packet,
|
|
incoming_packet_length);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::IncomingRtcpPacket(
|
|
const uint8_t* rtcp_packet,
|
|
const uint16_t length) {
|
|
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, -1,
|
|
"IncomingRtcpPacket(packet_length:%u)", length);
|
|
// Minimum RTP is 12 bytes.
|
|
// Minimum RTCP is 8 bytes (RTCP BYE).
|
|
if (length == 8) {
|
|
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, -1,
|
|
"IncomingRtcpPacket invalid length");
|
|
return false;
|
|
}
|
|
// Check RTP version.
|
|
const uint8_t version = rtcp_packet[0] >> 6;
|
|
if (version != 2) {
|
|
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, -1,
|
|
"IncomingRtcpPacket invalid RTP version");
|
|
return false;
|
|
}
|
|
// Allow receive of non-compound RTCP packets.
|
|
RTCPUtility::RTCPParserV2 rtcp_parser(rtcp_packet, length, true);
|
|
|
|
const bool valid_rtcpheader = rtcp_parser.IsValid();
|
|
if (!valid_rtcpheader) {
|
|
WEBRTC_TRACE(kTraceDebug, kTraceRtpRtcp, id_,
|
|
"IncomingRtcpPacket invalid RTCP packet");
|
|
return -1;
|
|
}
|
|
RTCPHelp::RTCPPacketInformation rtcp_packet_information;
|
|
int32_t ret_val = rtcp_receiver_.IncomingRTCPPacket(
|
|
rtcp_packet_information, &rtcp_parser);
|
|
if (ret_val == 0) {
|
|
rtcp_receiver_.TriggerCallbacksFromRTCPPacket(rtcp_packet_information);
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RegisterSendPayload(
|
|
const CodecInst& voice_codec) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"RegisterSendPayload(pl_name:%s pl_type:%d frequency:%u)",
|
|
voice_codec.plname,
|
|
voice_codec.pltype,
|
|
voice_codec.plfreq);
|
|
|
|
return rtp_sender_.RegisterPayload(
|
|
voice_codec.plname,
|
|
voice_codec.pltype,
|
|
voice_codec.plfreq,
|
|
voice_codec.channels,
|
|
(voice_codec.rate < 0) ? 0 : voice_codec.rate);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RegisterSendPayload(
|
|
const VideoCodec& video_codec) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"RegisterSendPayload(pl_name:%s pl_type:%d)",
|
|
video_codec.plName,
|
|
video_codec.plType);
|
|
|
|
send_video_codec_ = video_codec;
|
|
simulcast_ = (video_codec.numberOfSimulcastStreams > 1) ? true : false;
|
|
return rtp_sender_.RegisterPayload(video_codec.plName,
|
|
video_codec.plType,
|
|
90000,
|
|
0,
|
|
video_codec.maxBitrate);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::DeRegisterSendPayload(
|
|
const int8_t payload_type) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"DeRegisterSendPayload(%d)", payload_type);
|
|
|
|
return rtp_sender_.DeRegisterSendPayload(payload_type);
|
|
}
|
|
|
|
int8_t ModuleRtpRtcpImpl::SendPayloadType() const {
|
|
return rtp_sender_.SendPayloadType();
|
|
}
|
|
|
|
uint32_t ModuleRtpRtcpImpl::StartTimestamp() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "StartTimestamp()");
|
|
|
|
return rtp_sender_.StartTimestamp();
|
|
}
|
|
|
|
// Configure start timestamp, default is a random number.
|
|
int32_t ModuleRtpRtcpImpl::SetStartTimestamp(
|
|
const uint32_t timestamp) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetStartTimestamp(%d)",
|
|
timestamp);
|
|
rtcp_sender_.SetStartTimestamp(timestamp);
|
|
rtp_sender_.SetStartTimestamp(timestamp, true);
|
|
return 0; // TODO(pwestin): change to void.
|
|
}
|
|
|
|
uint16_t ModuleRtpRtcpImpl::SequenceNumber() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SequenceNumber()");
|
|
|
|
return rtp_sender_.SequenceNumber();
|
|
}
|
|
|
|
// Set SequenceNumber, default is a random number.
|
|
int32_t ModuleRtpRtcpImpl::SetSequenceNumber(
|
|
const uint16_t seq_num) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetSequenceNumber(%d)",
|
|
seq_num);
|
|
|
|
rtp_sender_.SetSequenceNumber(seq_num);
|
|
return 0; // TODO(pwestin): change to void.
|
|
}
|
|
|
|
uint32_t ModuleRtpRtcpImpl::SSRC() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SSRC()");
|
|
|
|
return rtp_sender_.SSRC();
|
|
}
|
|
|
|
// Configure SSRC, default is a random number.
|
|
int32_t ModuleRtpRtcpImpl::SetSSRC(const uint32_t ssrc) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SetSSRC(%d)", ssrc);
|
|
|
|
rtp_sender_.SetSSRC(ssrc);
|
|
rtcp_receiver_.SetSSRC(ssrc);
|
|
rtcp_sender_.SetSSRC(ssrc);
|
|
return 0; // TODO(pwestin): change to void.
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetCSRCStatus(const bool include) {
|
|
rtcp_sender_.SetCSRCStatus(include);
|
|
rtp_sender_.SetCSRCStatus(include);
|
|
return 0; // TODO(pwestin): change to void.
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::CSRCs(
|
|
uint32_t arr_of_csrc[kRtpCsrcSize]) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "CSRCs()");
|
|
|
|
return rtp_sender_.CSRCs(arr_of_csrc);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetCSRCs(
|
|
const uint32_t arr_of_csrc[kRtpCsrcSize],
|
|
const uint8_t arr_length) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetCSRCs(arr_length:%d)",
|
|
arr_length);
|
|
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
|
|
if (default_instance) {
|
|
// For default we need to update all child modules too.
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module) {
|
|
module->SetCSRCs(arr_of_csrc, arr_length);
|
|
}
|
|
it++;
|
|
}
|
|
} else {
|
|
for (int i = 0; i < arr_length; ++i) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "\tidx:%d CSRC:%u", i,
|
|
arr_of_csrc[i]);
|
|
}
|
|
rtcp_sender_.SetCSRCs(arr_of_csrc, arr_length);
|
|
rtp_sender_.SetCSRCs(arr_of_csrc, arr_length);
|
|
}
|
|
return 0; // TODO(pwestin): change to void.
|
|
}
|
|
|
|
uint32_t ModuleRtpRtcpImpl::PacketCountSent() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "PacketCountSent()");
|
|
|
|
return rtp_sender_.Packets();
|
|
}
|
|
|
|
uint32_t ModuleRtpRtcpImpl::ByteCountSent() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "ByteCountSent()");
|
|
|
|
return rtp_sender_.Bytes();
|
|
}
|
|
|
|
int ModuleRtpRtcpImpl::CurrentSendFrequencyHz() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"CurrentSendFrequencyHz()");
|
|
|
|
return rtp_sender_.SendPayloadFrequency();
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetSendingStatus(const bool sending) {
|
|
if (sending) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetSendingStatus(sending)");
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetSendingStatus(stopped)");
|
|
}
|
|
if (rtcp_sender_.Sending() != sending) {
|
|
// Sends RTCP BYE when going from true to false
|
|
if (rtcp_sender_.SetSendingStatus(sending) != 0) {
|
|
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_,
|
|
"Failed to send RTCP BYE");
|
|
}
|
|
|
|
collision_detected_ = false;
|
|
|
|
// Generate a new time_stamp if true and not configured via API
|
|
// Generate a new SSRC for the next "call" if false
|
|
rtp_sender_.SetSendingStatus(sending);
|
|
if (sending) {
|
|
// Make sure the RTCP sender has the same timestamp offset.
|
|
rtcp_sender_.SetStartTimestamp(rtp_sender_.StartTimestamp());
|
|
}
|
|
|
|
// Make sure that RTCP objects are aware of our SSRC (it could have changed
|
|
// Due to collision)
|
|
uint32_t SSRC = rtp_sender_.SSRC();
|
|
rtcp_receiver_.SetSSRC(SSRC);
|
|
rtcp_sender_.SetSSRC(SSRC);
|
|
return 0;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
bool ModuleRtpRtcpImpl::Sending() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "Sending()");
|
|
|
|
return rtcp_sender_.Sending();
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetSendingMediaStatus(const bool sending) {
|
|
if (sending) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetSendingMediaStatus(sending)");
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetSendingMediaStatus(stopped)");
|
|
}
|
|
rtp_sender_.SetSendingMediaStatus(sending);
|
|
return 0;
|
|
}
|
|
|
|
bool ModuleRtpRtcpImpl::SendingMedia() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "Sending()");
|
|
|
|
const bool have_child_modules(child_modules_.empty() ? false : true);
|
|
if (!have_child_modules) {
|
|
return rtp_sender_.SendingMedia();
|
|
}
|
|
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
std::list<ModuleRtpRtcpImpl*>::const_iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
|
if (rtp_sender.SendingMedia()) {
|
|
return true;
|
|
}
|
|
it++;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SendOutgoingData(
|
|
FrameType frame_type,
|
|
int8_t payload_type,
|
|
uint32_t time_stamp,
|
|
int64_t capture_time_ms,
|
|
const uint8_t* payload_data,
|
|
uint32_t payload_size,
|
|
const RTPFragmentationHeader* fragmentation,
|
|
const RTPVideoHeader* rtp_video_hdr) {
|
|
WEBRTC_TRACE(
|
|
kTraceStream,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SendOutgoingData(frame_type:%d payload_type:%d time_stamp:%u size:%u)",
|
|
frame_type, payload_type, time_stamp, payload_size);
|
|
|
|
rtcp_sender_.SetLastRtpTime(time_stamp, capture_time_ms);
|
|
|
|
const bool have_child_modules(child_modules_.empty() ? false : true);
|
|
if (!have_child_modules) {
|
|
// Don't send RTCP from default module.
|
|
if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) {
|
|
rtcp_sender_.SendRTCP(kRtcpReport);
|
|
}
|
|
return rtp_sender_.SendOutgoingData(frame_type,
|
|
payload_type,
|
|
time_stamp,
|
|
capture_time_ms,
|
|
payload_data,
|
|
payload_size,
|
|
fragmentation,
|
|
NULL,
|
|
&(rtp_video_hdr->codecHeader));
|
|
}
|
|
int32_t ret_val = -1;
|
|
if (simulcast_) {
|
|
if (rtp_video_hdr == NULL) {
|
|
return -1;
|
|
}
|
|
int idx = 0;
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
for (; idx < rtp_video_hdr->simulcastIdx; ++it) {
|
|
if (it == child_modules_.end()) {
|
|
return -1;
|
|
}
|
|
if ((*it)->SendingMedia()) {
|
|
++idx;
|
|
}
|
|
}
|
|
for (; it != child_modules_.end(); ++it) {
|
|
if ((*it)->SendingMedia()) {
|
|
break;
|
|
}
|
|
++idx;
|
|
}
|
|
if (it == child_modules_.end()) {
|
|
return -1;
|
|
}
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SendOutgoingData(SimulcastIdx:%u size:%u, ssrc:0x%x)",
|
|
idx, payload_size, (*it)->rtp_sender_.SSRC());
|
|
return (*it)->SendOutgoingData(frame_type,
|
|
payload_type,
|
|
time_stamp,
|
|
capture_time_ms,
|
|
payload_data,
|
|
payload_size,
|
|
fragmentation,
|
|
rtp_video_hdr);
|
|
} else {
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
if (it != child_modules_.end()) {
|
|
if ((*it)->SendingMedia()) {
|
|
ret_val = (*it)->SendOutgoingData(frame_type,
|
|
payload_type,
|
|
time_stamp,
|
|
capture_time_ms,
|
|
payload_data,
|
|
payload_size,
|
|
fragmentation,
|
|
rtp_video_hdr);
|
|
}
|
|
it++;
|
|
}
|
|
// Send to all remaining "child" modules
|
|
while (it != child_modules_.end()) {
|
|
if ((*it)->SendingMedia()) {
|
|
ret_val = (*it)->SendOutgoingData(frame_type,
|
|
payload_type,
|
|
time_stamp,
|
|
capture_time_ms,
|
|
payload_data,
|
|
payload_size,
|
|
fragmentation,
|
|
rtp_video_hdr);
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc,
|
|
uint16_t sequence_number,
|
|
int64_t capture_time_ms) {
|
|
WEBRTC_TRACE(
|
|
kTraceStream,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"TimeToSendPacket(ssrc:0x%x sequence_number:%u capture_time_ms:%ll)",
|
|
ssrc, sequence_number, capture_time_ms);
|
|
|
|
if (simulcast_) {
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) {
|
|
(*it)->rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms);
|
|
return;
|
|
}
|
|
++it;
|
|
}
|
|
} else {
|
|
bool have_child_modules = !child_modules_.empty();
|
|
if (!have_child_modules) {
|
|
// Don't send from default module.
|
|
if (SendingMedia() && ssrc == rtp_sender_.SSRC()) {
|
|
rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms);
|
|
}
|
|
} else {
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
if ((*it)->SendingMedia() && ssrc == (*it)->rtp_sender_.SSRC()) {
|
|
(*it)->rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms);
|
|
return;
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint16_t ModuleRtpRtcpImpl::MaxPayloadLength() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "MaxPayloadLength()");
|
|
|
|
return rtp_sender_.MaxPayloadLength();
|
|
}
|
|
|
|
uint16_t ModuleRtpRtcpImpl::MaxDataPayloadLength() const {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"MaxDataPayloadLength()");
|
|
|
|
// Assuming IP/UDP.
|
|
uint16_t min_data_payload_length = IP_PACKET_SIZE - 28;
|
|
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
if (default_instance) {
|
|
// For default we need to update all child modules too.
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
|
|
child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module) {
|
|
uint16_t data_payload_length =
|
|
module->MaxDataPayloadLength();
|
|
if (data_payload_length < min_data_payload_length) {
|
|
min_data_payload_length = data_payload_length;
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
|
|
uint16_t data_payload_length = rtp_sender_.MaxDataPayloadLength();
|
|
if (data_payload_length < min_data_payload_length) {
|
|
min_data_payload_length = data_payload_length;
|
|
}
|
|
return min_data_payload_length;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetTransportOverhead(
|
|
const bool tcp,
|
|
const bool ipv6,
|
|
const uint8_t authentication_overhead) {
|
|
WEBRTC_TRACE(
|
|
kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetTransportOverhead(TCP:%d, IPV6:%d authentication_overhead:%u)",
|
|
tcp, ipv6, authentication_overhead);
|
|
|
|
uint16_t packet_overhead = 0;
|
|
if (ipv6) {
|
|
packet_overhead = 40;
|
|
} else {
|
|
packet_overhead = 20;
|
|
}
|
|
if (tcp) {
|
|
// TCP.
|
|
packet_overhead += 20;
|
|
} else {
|
|
// UDP.
|
|
packet_overhead += 8;
|
|
}
|
|
packet_overhead += authentication_overhead;
|
|
|
|
if (packet_overhead == packet_overhead_) {
|
|
// Ok same as before.
|
|
return 0;
|
|
}
|
|
// Calc diff.
|
|
int16_t packet_over_head_diff = packet_overhead - packet_overhead_;
|
|
|
|
// Store new.
|
|
packet_overhead_ = packet_overhead;
|
|
|
|
uint16_t length =
|
|
rtp_sender_.MaxPayloadLength() - packet_over_head_diff;
|
|
return rtp_sender_.SetMaxPayloadLength(length, packet_overhead_);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetMaxTransferUnit(const uint16_t mtu) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SetMaxTransferUnit(%u)",
|
|
mtu);
|
|
|
|
if (mtu > IP_PACKET_SIZE) {
|
|
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_,
|
|
"Invalid in argument to SetMaxTransferUnit(%u)", mtu);
|
|
return -1;
|
|
}
|
|
return rtp_sender_.SetMaxPayloadLength(mtu - packet_overhead_,
|
|
packet_overhead_);
|
|
}
|
|
|
|
RTCPMethod ModuleRtpRtcpImpl::RTCP() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RTCP()");
|
|
|
|
if (rtcp_sender_.Status() != kRtcpOff) {
|
|
return rtcp_receiver_.Status();
|
|
}
|
|
return kRtcpOff;
|
|
}
|
|
|
|
// Configure RTCP status i.e on/off.
|
|
int32_t ModuleRtpRtcpImpl::SetRTCPStatus(const RTCPMethod method) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SetRTCPStatus(%d)",
|
|
method);
|
|
|
|
if (rtcp_sender_.SetRTCPStatus(method) == 0) {
|
|
return rtcp_receiver_.SetRTCPStatus(method);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Only for internal test.
|
|
uint32_t ModuleRtpRtcpImpl::LastSendReport(
|
|
uint32_t& last_rtcptime) {
|
|
return rtcp_sender_.LastSendReport(last_rtcptime);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetCNAME(const char c_name[RTCP_CNAME_SIZE]) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SetCNAME(%s)", c_name);
|
|
return rtcp_sender_.SetCNAME(c_name);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::CNAME(char c_name[RTCP_CNAME_SIZE]) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "CNAME()");
|
|
return rtcp_sender_.CNAME(c_name);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::AddMixedCNAME(
|
|
const uint32_t ssrc,
|
|
const char c_name[RTCP_CNAME_SIZE]) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"AddMixedCNAME(SSRC:%u)", ssrc);
|
|
|
|
return rtcp_sender_.AddMixedCNAME(ssrc, c_name);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RemoveMixedCNAME(const uint32_t ssrc) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"RemoveMixedCNAME(SSRC:%u)", ssrc);
|
|
return rtcp_sender_.RemoveMixedCNAME(ssrc);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RemoteCNAME(
|
|
const uint32_t remote_ssrc,
|
|
char c_name[RTCP_CNAME_SIZE]) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"RemoteCNAME(SSRC:%u)", remote_ssrc);
|
|
|
|
return rtcp_receiver_.CNAME(remote_ssrc, c_name);
|
|
}
|
|
|
|
uint16_t ModuleRtpRtcpImpl::RemoteSequenceNumber() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoteSequenceNumber()");
|
|
|
|
return rtp_receiver_->SequenceNumber();
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RemoteNTP(
|
|
uint32_t* received_ntpsecs,
|
|
uint32_t* received_ntpfrac,
|
|
uint32_t* rtcp_arrival_time_secs,
|
|
uint32_t* rtcp_arrival_time_frac,
|
|
uint32_t* rtcp_timestamp) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoteNTP()");
|
|
|
|
return rtcp_receiver_.NTP(received_ntpsecs,
|
|
received_ntpfrac,
|
|
rtcp_arrival_time_secs,
|
|
rtcp_arrival_time_frac,
|
|
rtcp_timestamp);
|
|
}
|
|
|
|
// Get RoundTripTime.
|
|
int32_t ModuleRtpRtcpImpl::RTT(const uint32_t remote_ssrc,
|
|
uint16_t* rtt,
|
|
uint16_t* avg_rtt,
|
|
uint16_t* min_rtt,
|
|
uint16_t* max_rtt) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RTT()");
|
|
|
|
return rtcp_receiver_.RTT(remote_ssrc, rtt, avg_rtt, min_rtt, max_rtt);
|
|
}
|
|
|
|
// Reset RoundTripTime statistics.
|
|
int32_t ModuleRtpRtcpImpl::ResetRTT(const uint32_t remote_ssrc) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "ResetRTT(SSRC:%u)",
|
|
remote_ssrc);
|
|
|
|
return rtcp_receiver_.ResetRTT(remote_ssrc);
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl:: SetRtt(uint32_t rtt) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SetRtt(rtt: %u)", rtt);
|
|
rtcp_receiver_.SetRTT(static_cast<uint16_t>(rtt));
|
|
}
|
|
|
|
// Reset RTP statistics.
|
|
int32_t ModuleRtpRtcpImpl::ResetStatisticsRTP() {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "ResetStatisticsRTP()");
|
|
|
|
return rtp_receiver_->ResetStatistics();
|
|
}
|
|
|
|
// Reset RTP data counters for the receiving side.
|
|
int32_t ModuleRtpRtcpImpl::ResetReceiveDataCountersRTP() {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"ResetReceiveDataCountersRTP()");
|
|
|
|
return rtp_receiver_->ResetDataCounters();
|
|
}
|
|
|
|
// Reset RTP data counters for the sending side.
|
|
int32_t ModuleRtpRtcpImpl::ResetSendDataCountersRTP() {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"ResetSendDataCountersRTP()");
|
|
|
|
rtp_sender_.ResetDataCounters();
|
|
return 0; // TODO(pwestin): change to void.
|
|
}
|
|
|
|
// Force a send of an RTCP packet.
|
|
// Normal SR and RR are triggered via the process function.
|
|
int32_t ModuleRtpRtcpImpl::SendRTCP(uint32_t rtcp_packet_type) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SendRTCP(0x%x)",
|
|
rtcp_packet_type);
|
|
|
|
return rtcp_sender_.SendRTCP(rtcp_packet_type);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetRTCPApplicationSpecificData(
|
|
const uint8_t sub_type,
|
|
const uint32_t name,
|
|
const uint8_t* data,
|
|
const uint16_t length) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetRTCPApplicationSpecificData(sub_type:%d name:0x%x)",
|
|
sub_type, name);
|
|
|
|
return rtcp_sender_.SetApplicationSpecificData(sub_type, name, data, length);
|
|
}
|
|
|
|
// (XR) VOIP metric.
|
|
int32_t ModuleRtpRtcpImpl::SetRTCPVoIPMetrics(
|
|
const RTCPVoIPMetric* voip_metric) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SetRTCPVoIPMetrics()");
|
|
|
|
return rtcp_sender_.SetRTCPVoIPMetrics(voip_metric);
|
|
}
|
|
|
|
// Our locally created statistics of the received RTP stream.
|
|
int32_t ModuleRtpRtcpImpl::StatisticsRTP(
|
|
uint8_t* fraction_lost,
|
|
uint32_t* cum_lost,
|
|
uint32_t* ext_max,
|
|
uint32_t* jitter,
|
|
uint32_t* max_jitter) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "StatisticsRTP()");
|
|
|
|
uint32_t jitter_transmission_time_offset = 0;
|
|
|
|
int32_t ret_val = rtp_receiver_->Statistics(
|
|
fraction_lost, cum_lost, ext_max, jitter, max_jitter,
|
|
&jitter_transmission_time_offset, (rtcp_sender_.Status() == kRtcpOff));
|
|
if (ret_val == -1) {
|
|
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, id_,
|
|
"StatisticsRTP() no statistics available");
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::DataCountersRTP(
|
|
uint32_t* bytes_sent,
|
|
uint32_t* packets_sent,
|
|
uint32_t* bytes_received,
|
|
uint32_t* packets_received) const {
|
|
WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_, "DataCountersRTP()");
|
|
|
|
if (bytes_sent) {
|
|
*bytes_sent = rtp_sender_.Bytes();
|
|
}
|
|
if (packets_sent) {
|
|
*packets_sent = rtp_sender_.Packets();
|
|
}
|
|
return rtp_receiver_->DataCounters(bytes_received, packets_received);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::ReportBlockStatistics(
|
|
uint8_t* fraction_lost,
|
|
uint32_t* cum_lost,
|
|
uint32_t* ext_max,
|
|
uint32_t* jitter,
|
|
uint32_t* jitter_transmission_time_offset) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "ReportBlockStatistics()");
|
|
int32_t missing = 0;
|
|
int32_t ret = rtp_receiver_->Statistics(fraction_lost,
|
|
cum_lost,
|
|
ext_max,
|
|
jitter,
|
|
NULL,
|
|
jitter_transmission_time_offset,
|
|
&missing,
|
|
true);
|
|
|
|
#ifdef MATLAB
|
|
if (plot1_ == NULL) {
|
|
plot1_ = eng.NewPlot(new MatlabPlot());
|
|
plot1_->AddTimeLine(30, "b", "lost", clock_->TimeInMilliseconds());
|
|
}
|
|
plot1_->Append("lost", missing);
|
|
plot1_->Plot();
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RemoteRTCPStat(RTCPSenderInfo* sender_info) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoteRTCPStat()");
|
|
|
|
return rtcp_receiver_.SenderInfoReceived(sender_info);
|
|
}
|
|
|
|
// Received RTCP report.
|
|
int32_t ModuleRtpRtcpImpl::RemoteRTCPStat(
|
|
std::vector<RTCPReportBlock>* receive_blocks) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoteRTCPStat()");
|
|
|
|
return rtcp_receiver_.StatisticsReceived(receive_blocks);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::AddRTCPReportBlock(
|
|
const uint32_t ssrc,
|
|
const RTCPReportBlock* report_block) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "AddRTCPReportBlock()");
|
|
|
|
return rtcp_sender_.AddReportBlock(ssrc, report_block);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RemoveRTCPReportBlock(
|
|
const uint32_t ssrc) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoveRTCPReportBlock()");
|
|
|
|
return rtcp_sender_.RemoveReportBlock(ssrc);
|
|
}
|
|
|
|
// (REMB) Receiver Estimated Max Bitrate.
|
|
bool ModuleRtpRtcpImpl::REMB() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "REMB()");
|
|
|
|
return rtcp_sender_.REMB();
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetREMBStatus(const bool enable) {
|
|
if (enable) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetREMBStatus(enable)");
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetREMBStatus(disable)");
|
|
}
|
|
return rtcp_sender_.SetREMBStatus(enable);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetREMBData(const uint32_t bitrate,
|
|
const uint8_t number_of_ssrc,
|
|
const uint32_t* ssrc) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetREMBData(bitrate:%d,?,?)", bitrate);
|
|
return rtcp_sender_.SetREMBData(bitrate, number_of_ssrc, ssrc);
|
|
}
|
|
|
|
// (IJ) Extended jitter report.
|
|
bool ModuleRtpRtcpImpl::IJ() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "IJ()");
|
|
|
|
return rtcp_sender_.IJ();
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetIJStatus(const bool enable) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetIJStatus(%s)", enable ? "true" : "false");
|
|
|
|
return rtcp_sender_.SetIJStatus(enable);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RegisterSendRtpHeaderExtension(
|
|
const RTPExtensionType type,
|
|
const uint8_t id) {
|
|
return rtp_sender_.RegisterRtpHeaderExtension(type, id);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::DeregisterSendRtpHeaderExtension(
|
|
const RTPExtensionType type) {
|
|
return rtp_sender_.DeregisterRtpHeaderExtension(type);
|
|
}
|
|
|
|
// (TMMBR) Temporary Max Media Bit Rate.
|
|
bool ModuleRtpRtcpImpl::TMMBR() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "TMMBR()");
|
|
|
|
return rtcp_sender_.TMMBR();
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetTMMBRStatus(const bool enable) {
|
|
if (enable) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetTMMBRStatus(enable)");
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetTMMBRStatus(disable)");
|
|
}
|
|
return rtcp_sender_.SetTMMBRStatus(enable);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetTMMBN(const TMMBRSet* bounding_set) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SetTMMBN()");
|
|
|
|
uint32_t max_bitrate_kbit =
|
|
rtp_sender_.MaxConfiguredBitrateVideo() / 1000;
|
|
return rtcp_sender_.SetTMMBN(bounding_set, max_bitrate_kbit);
|
|
}
|
|
|
|
// (NACK) Negative acknowledgment.
|
|
|
|
// Is Negative acknowledgment requests on/off?
|
|
NACKMethod ModuleRtpRtcpImpl::NACK() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "NACK()");
|
|
|
|
NACKMethod child_method = kNackOff;
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
if (default_instance) {
|
|
// For default we need to check all child modules too.
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
|
|
child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module) {
|
|
NACKMethod nackMethod = module->NACK();
|
|
if (nackMethod != kNackOff) {
|
|
child_method = nackMethod;
|
|
break;
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
|
|
NACKMethod method = nack_method_;
|
|
if (child_method != kNackOff) {
|
|
method = child_method;
|
|
}
|
|
return method;
|
|
}
|
|
|
|
// Turn negative acknowledgment requests on/off.
|
|
int32_t ModuleRtpRtcpImpl::SetNACKStatus(
|
|
NACKMethod method, int max_reordering_threshold) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetNACKStatus(%u)", method);
|
|
|
|
nack_method_ = method;
|
|
rtp_receiver_->SetNACKStatus(method, max_reordering_threshold);
|
|
return 0;
|
|
}
|
|
|
|
// Returns the currently configured retransmission mode.
|
|
int ModuleRtpRtcpImpl::SelectiveRetransmissions() const {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SelectiveRetransmissions()");
|
|
return rtp_sender_.SelectiveRetransmissions();
|
|
}
|
|
|
|
// Enable or disable a retransmission mode, which decides which packets will
|
|
// be retransmitted if NACKed.
|
|
int ModuleRtpRtcpImpl::SetSelectiveRetransmissions(uint8_t settings) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetSelectiveRetransmissions(%u)",
|
|
settings);
|
|
return rtp_sender_.SetSelectiveRetransmissions(settings);
|
|
}
|
|
|
|
// Send a Negative acknowledgment packet.
|
|
int32_t ModuleRtpRtcpImpl::SendNACK(const uint16_t* nack_list,
|
|
const uint16_t size) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SendNACK(size:%u)", size);
|
|
|
|
uint16_t avg_rtt = 0;
|
|
rtcp_receiver_.RTT(rtp_receiver_->SSRC(), NULL, &avg_rtt, NULL, NULL);
|
|
|
|
int64_t wait_time = 5 + ((avg_rtt * 3) >> 1); // 5 + RTT * 1.5.
|
|
if (wait_time == 5) {
|
|
wait_time = 100; // During startup we don't have an RTT.
|
|
}
|
|
const int64_t now = clock_->TimeInMilliseconds();
|
|
const int64_t time_limit = now - wait_time;
|
|
uint16_t nackLength = size;
|
|
uint16_t start_id = 0;
|
|
|
|
if (nack_last_time_sent_full_ < time_limit) {
|
|
// Send list. Set the timer to make sure we only send a full NACK list once
|
|
// within every time_limit.
|
|
nack_last_time_sent_full_ = now;
|
|
} else {
|
|
// Only send if extended list.
|
|
if (nack_last_seq_number_sent_ == nack_list[size - 1]) {
|
|
// Last seq num is the same don't send list.
|
|
return 0;
|
|
} else {
|
|
// Send NACKs only for new sequence numbers to avoid re-sending
|
|
// NACKs for sequences we have already sent.
|
|
for (int i = 0; i < size; ++i) {
|
|
if (nack_last_seq_number_sent_ == nack_list[i]) {
|
|
start_id = i + 1;
|
|
break;
|
|
}
|
|
}
|
|
nackLength = size - start_id;
|
|
}
|
|
}
|
|
// Our RTCP NACK implementation is limited to kRtcpMaxNackFields sequence
|
|
// numbers per RTCP packet.
|
|
if (nackLength > kRtcpMaxNackFields) {
|
|
nackLength = kRtcpMaxNackFields;
|
|
}
|
|
nack_last_seq_number_sent_ = nack_list[start_id + nackLength - 1];
|
|
|
|
switch (nack_method_) {
|
|
case kNackRtcp:
|
|
return rtcp_sender_.SendRTCP(kRtcpNack, nackLength, &nack_list[start_id]);
|
|
case kNackOff:
|
|
return -1;
|
|
};
|
|
return -1;
|
|
}
|
|
|
|
// Store the sent packets, needed to answer to a Negative acknowledgment
|
|
// requests.
|
|
int32_t ModuleRtpRtcpImpl::SetStorePacketsStatus(
|
|
const bool enable,
|
|
const uint16_t number_to_store) {
|
|
if (enable) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetStorePacketsStatus(enable, number_to_store:%d)",
|
|
number_to_store);
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetStorePacketsStatus(disable)");
|
|
}
|
|
rtp_sender_.SetStorePacketsStatus(enable, number_to_store);
|
|
return 0; // TODO(pwestin): change to void.
|
|
}
|
|
|
|
// Forward DTMFs to decoder for playout.
|
|
int ModuleRtpRtcpImpl::SetTelephoneEventForwardToDecoder(
|
|
bool forward_to_decoder) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetTelephoneEventForwardToDecoder(forward_to_decoder:%d)",
|
|
forward_to_decoder);
|
|
|
|
assert(audio_);
|
|
assert(rtp_telephone_event_handler_);
|
|
return rtp_telephone_event_handler_->SetTelephoneEventForwardToDecoder(
|
|
forward_to_decoder);
|
|
}
|
|
|
|
// Is forwarding of out-band telephone events turned on/off?
|
|
bool ModuleRtpRtcpImpl::TelephoneEventForwardToDecoder() const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"TelephoneEventForwardToDecoder()");
|
|
|
|
assert(audio_);
|
|
assert(rtp_telephone_event_handler_);
|
|
return rtp_telephone_event_handler_->TelephoneEventForwardToDecoder();
|
|
}
|
|
|
|
// Send a TelephoneEvent tone using RFC 2833 (4733).
|
|
int32_t ModuleRtpRtcpImpl::SendTelephoneEventOutband(
|
|
const uint8_t key,
|
|
const uint16_t time_ms,
|
|
const uint8_t level) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SendTelephoneEventOutband(key:%u, time_ms:%u, level:%u)", key,
|
|
time_ms, level);
|
|
|
|
return rtp_sender_.SendTelephoneEvent(key, time_ms, level);
|
|
}
|
|
|
|
bool ModuleRtpRtcpImpl::SendTelephoneEventActive(
|
|
int8_t& telephone_event) const {
|
|
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SendTelephoneEventActive()");
|
|
|
|
return rtp_sender_.SendTelephoneEventActive(&telephone_event);
|
|
}
|
|
|
|
// Set audio packet size, used to determine when it's time to send a DTMF
|
|
// packet in silence (CNG).
|
|
int32_t ModuleRtpRtcpImpl::SetAudioPacketSize(
|
|
const uint16_t packet_size_samples) {
|
|
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetAudioPacketSize(%u)",
|
|
packet_size_samples);
|
|
|
|
return rtp_sender_.SetAudioPacketSize(packet_size_samples);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetRTPAudioLevelIndicationStatus(
|
|
const bool enable,
|
|
const uint8_t id) {
|
|
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetRTPAudioLevelIndicationStatus(enable=%d, ID=%u)",
|
|
enable,
|
|
id);
|
|
|
|
return rtp_sender_.SetAudioLevelIndicationStatus(enable, id);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::GetRTPAudioLevelIndicationStatus(
|
|
bool& enable,
|
|
uint8_t& id) const {
|
|
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"GetRTPAudioLevelIndicationStatus()");
|
|
return rtp_sender_.AudioLevelIndicationStatus(&enable, &id);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetAudioLevel(
|
|
const uint8_t level_d_bov) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetAudioLevel(level_d_bov:%u)",
|
|
level_d_bov);
|
|
return rtp_sender_.SetAudioLevel(level_d_bov);
|
|
}
|
|
|
|
// Set payload type for Redundant Audio Data RFC 2198.
|
|
int32_t ModuleRtpRtcpImpl::SetSendREDPayloadType(
|
|
const int8_t payload_type) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetSendREDPayloadType(%d)",
|
|
payload_type);
|
|
|
|
return rtp_sender_.SetRED(payload_type);
|
|
}
|
|
|
|
// Get payload type for Redundant Audio Data RFC 2198.
|
|
int32_t ModuleRtpRtcpImpl::SendREDPayloadType(
|
|
int8_t& payload_type) const {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "SendREDPayloadType()");
|
|
|
|
return rtp_sender_.RED(&payload_type);
|
|
}
|
|
|
|
RtpVideoCodecTypes ModuleRtpRtcpImpl::ReceivedVideoCodec() const {
|
|
return rtp_receiver_->VideoCodecType();
|
|
}
|
|
|
|
RtpVideoCodecTypes ModuleRtpRtcpImpl::SendVideoCodec() const {
|
|
return rtp_sender_.VideoCodecType();
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::SetTargetSendBitrate(const uint32_t bitrate) {
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_,
|
|
"SetTargetSendBitrate: %ubit", bitrate);
|
|
|
|
const bool have_child_modules(child_modules_.empty() ? false : true);
|
|
if (have_child_modules) {
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
if (simulcast_) {
|
|
uint32_t bitrate_remainder = bitrate;
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
for (int i = 0; it != child_modules_.end() &&
|
|
i < send_video_codec_.numberOfSimulcastStreams; ++it) {
|
|
if ((*it)->SendingMedia()) {
|
|
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
|
if (send_video_codec_.simulcastStream[i].maxBitrate * 1000 >
|
|
bitrate_remainder) {
|
|
rtp_sender.SetTargetSendBitrate(bitrate_remainder);
|
|
bitrate_remainder = 0;
|
|
} else {
|
|
rtp_sender.SetTargetSendBitrate(
|
|
send_video_codec_.simulcastStream[i].maxBitrate * 1000);
|
|
bitrate_remainder -=
|
|
send_video_codec_.simulcastStream[i].maxBitrate * 1000;
|
|
}
|
|
++i;
|
|
}
|
|
}
|
|
} else {
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
for (; it != child_modules_.end(); ++it) {
|
|
RTPSender& rtp_sender = (*it)->rtp_sender_;
|
|
rtp_sender.SetTargetSendBitrate(bitrate);
|
|
}
|
|
}
|
|
} else {
|
|
rtp_sender_.SetTargetSendBitrate(bitrate);
|
|
}
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetKeyFrameRequestMethod(
|
|
const KeyFrameRequestMethod method) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetKeyFrameRequestMethod(method:%u)",
|
|
method);
|
|
|
|
key_frame_req_method_ = method;
|
|
return 0;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::RequestKeyFrame() {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"RequestKeyFrame");
|
|
|
|
switch (key_frame_req_method_) {
|
|
case kKeyFrameReqFirRtp:
|
|
return rtp_sender_.SendRTPIntraRequest();
|
|
case kKeyFrameReqPliRtcp:
|
|
return rtcp_sender_.SendRTCP(kRtcpPli);
|
|
case kKeyFrameReqFirRtcp:
|
|
return rtcp_sender_.SendRTCP(kRtcpFir);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SendRTCPSliceLossIndication(
|
|
const uint8_t picture_id) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SendRTCPSliceLossIndication (picture_id:%d)",
|
|
picture_id);
|
|
return rtcp_sender_.SendRTCP(kRtcpSli, 0, 0, false, picture_id);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetCameraDelay(%d)",
|
|
delay_ms);
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
|
|
if (default_instance) {
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module) {
|
|
module->SetCameraDelay(delay_ms);
|
|
}
|
|
it++;
|
|
}
|
|
return 0;
|
|
}
|
|
return rtcp_sender_.SetCameraDelay(delay_ms);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetGenericFECStatus(
|
|
const bool enable,
|
|
const uint8_t payload_type_red,
|
|
const uint8_t payload_type_fec) {
|
|
if (enable) {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetGenericFECStatus(enable, %u)",
|
|
payload_type_red);
|
|
} else {
|
|
WEBRTC_TRACE(kTraceModuleCall,
|
|
kTraceRtpRtcp,
|
|
id_,
|
|
"SetGenericFECStatus(disable)");
|
|
}
|
|
return rtp_sender_.SetGenericFECStatus(enable,
|
|
payload_type_red,
|
|
payload_type_fec);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::GenericFECStatus(
|
|
bool& enable,
|
|
uint8_t& payload_type_red,
|
|
uint8_t& payload_type_fec) {
|
|
|
|
WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "GenericFECStatus()");
|
|
|
|
bool child_enabled = false;
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
if (default_instance) {
|
|
// For default we need to check all child modules too.
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module) {
|
|
bool enabled = false;
|
|
uint8_t dummy_ptype_red = 0;
|
|
uint8_t dummy_ptype_fec = 0;
|
|
if (module->GenericFECStatus(enabled,
|
|
dummy_ptype_red,
|
|
dummy_ptype_fec) == 0 && enabled) {
|
|
child_enabled = true;
|
|
break;
|
|
}
|
|
}
|
|
it++;
|
|
}
|
|
}
|
|
int32_t ret_val = rtp_sender_.GenericFECStatus(&enable,
|
|
&payload_type_red,
|
|
&payload_type_fec);
|
|
if (child_enabled) {
|
|
// Returns true if enabled for any child module.
|
|
enable = child_enabled;
|
|
}
|
|
return ret_val;
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SetFecParameters(
|
|
const FecProtectionParams* delta_params,
|
|
const FecProtectionParams* key_params) {
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
if (default_instance) {
|
|
// For default we need to update all child modules too.
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_.get());
|
|
|
|
std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module) {
|
|
module->SetFecParameters(delta_params, key_params);
|
|
}
|
|
it++;
|
|
}
|
|
return 0;
|
|
}
|
|
return rtp_sender_.SetFecParameters(delta_params, key_params);
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::SetRemoteSSRC(const uint32_t ssrc) {
|
|
// Inform about the incoming SSRC.
|
|
rtcp_sender_.SetRemoteSSRC(ssrc);
|
|
rtcp_receiver_.SetRemoteSSRC(ssrc);
|
|
|
|
// Check for a SSRC collision.
|
|
if (rtp_sender_.SSRC() == ssrc && !collision_detected_) {
|
|
// If we detect a collision change the SSRC but only once.
|
|
collision_detected_ = true;
|
|
uint32_t new_ssrc = rtp_sender_.GenerateNewSSRC();
|
|
if (new_ssrc == 0) {
|
|
// Configured via API ignore.
|
|
return;
|
|
}
|
|
if (kRtcpOff != rtcp_sender_.Status()) {
|
|
// Send RTCP bye on the current SSRC.
|
|
rtcp_sender_.SendRTCP(kRtcpBye);
|
|
}
|
|
// Change local SSRC and inform all objects about the new SSRC.
|
|
rtcp_sender_.SetSSRC(new_ssrc);
|
|
rtcp_receiver_.SetSSRC(new_ssrc);
|
|
}
|
|
}
|
|
|
|
uint32_t ModuleRtpRtcpImpl::BitrateReceivedNow() const {
|
|
return rtp_receiver_->BitrateNow();
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate,
|
|
uint32_t* video_rate,
|
|
uint32_t* fec_rate,
|
|
uint32_t* nack_rate) const {
|
|
const bool default_instance(child_modules_.empty() ? false : true);
|
|
|
|
if (default_instance) {
|
|
// For default we need to update the send bitrate.
|
|
CriticalSectionScoped lock(critical_section_module_ptrs_feedback_.get());
|
|
|
|
if (total_rate != NULL)
|
|
*total_rate = 0;
|
|
if (video_rate != NULL)
|
|
*video_rate = 0;
|
|
if (fec_rate != NULL)
|
|
*fec_rate = 0;
|
|
if (nack_rate != NULL)
|
|
*nack_rate = 0;
|
|
|
|
std::list<ModuleRtpRtcpImpl*>::const_iterator it =
|
|
child_modules_.begin();
|
|
while (it != child_modules_.end()) {
|
|
RtpRtcp* module = *it;
|
|
if (module) {
|
|
uint32_t child_total_rate = 0;
|
|
uint32_t child_video_rate = 0;
|
|
uint32_t child_fec_rate = 0;
|
|
uint32_t child_nack_rate = 0;
|
|
module->BitrateSent(&child_total_rate,
|
|
&child_video_rate,
|
|
&child_fec_rate,
|
|
&child_nack_rate);
|
|
if (total_rate != NULL && child_total_rate > *total_rate)
|
|
*total_rate = child_total_rate;
|
|
if (video_rate != NULL && child_video_rate > *video_rate)
|
|
*video_rate = child_video_rate;
|
|
if (fec_rate != NULL && child_fec_rate > *fec_rate)
|
|
*fec_rate = child_fec_rate;
|
|
if (nack_rate != NULL && child_nack_rate > *nack_rate)
|
|
*nack_rate = child_nack_rate;
|
|
}
|
|
it++;
|
|
}
|
|
return;
|
|
}
|
|
if (total_rate != NULL)
|
|
*total_rate = rtp_sender_.BitrateLast();
|
|
if (video_rate != NULL)
|
|
*video_rate = rtp_sender_.VideoBitrateSent();
|
|
if (fec_rate != NULL)
|
|
*fec_rate = rtp_sender_.FecOverheadRate();
|
|
if (nack_rate != NULL)
|
|
*nack_rate = rtp_sender_.NackOverheadRate();
|
|
}
|
|
|
|
// Bad state of RTP receiver request a keyframe.
|
|
void ModuleRtpRtcpImpl::OnRequestIntraFrame() {
|
|
RequestKeyFrame();
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::OnRequestSendReport() {
|
|
rtcp_sender_.SendRTCP(kRtcpSr);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::SendRTCPReferencePictureSelection(
|
|
const uint64_t picture_id) {
|
|
return rtcp_sender_.SendRTCP(kRtcpRpsi, 0, 0, false, picture_id);
|
|
}
|
|
|
|
uint32_t ModuleRtpRtcpImpl::SendTimeOfSendReport(
|
|
const uint32_t send_report) {
|
|
return rtcp_sender_.SendTimeOfSendReport(send_report);
|
|
}
|
|
|
|
void ModuleRtpRtcpImpl::OnReceivedNACK(
|
|
const std::list<uint16_t>& nack_sequence_numbers) {
|
|
if (!rtp_sender_.StorePackets() ||
|
|
nack_sequence_numbers.size() == 0) {
|
|
return;
|
|
}
|
|
uint16_t avg_rtt = 0;
|
|
rtcp_receiver_.RTT(rtp_receiver_->SSRC(), NULL, &avg_rtt, NULL, NULL);
|
|
rtp_sender_.OnReceivedNACK(nack_sequence_numbers, avg_rtt);
|
|
}
|
|
|
|
int32_t ModuleRtpRtcpImpl::LastReceivedNTP(
|
|
uint32_t& rtcp_arrival_time_secs, // When we got the last report.
|
|
uint32_t& rtcp_arrival_time_frac,
|
|
uint32_t& remote_sr) {
|
|
// Remote SR: NTP inside the last received (mid 16 bits from sec and frac).
|
|
uint32_t ntp_secs = 0;
|
|
uint32_t ntp_frac = 0;
|
|
|
|
if (-1 == rtcp_receiver_.NTP(&ntp_secs,
|
|
&ntp_frac,
|
|
&rtcp_arrival_time_secs,
|
|
&rtcp_arrival_time_frac,
|
|
NULL)) {
|
|
return -1;
|
|
}
|
|
remote_sr = ((ntp_secs & 0x0000ffff) << 16) + ((ntp_frac & 0xffff0000) >> 16);
|
|
return 0;
|
|
}
|
|
|
|
bool ModuleRtpRtcpImpl::UpdateRTCPReceiveInformationTimers() {
|
|
// If this returns true this channel has timed out.
|
|
// Periodically check if this is true and if so call UpdateTMMBR.
|
|
return rtcp_receiver_.UpdateRTCPReceiveInformationTimers();
|
|
}
|
|
|
|
// Called from RTCPsender.
|
|
int32_t ModuleRtpRtcpImpl::BoundingSet(bool& tmmbr_owner,
|
|
TMMBRSet*& bounding_set) {
|
|
return rtcp_receiver_.BoundingSet(tmmbr_owner, bounding_set);
|
|
}
|
|
|
|
int64_t ModuleRtpRtcpImpl::RtcpReportInterval() {
|
|
if (audio_)
|
|
return RTCP_INTERVAL_AUDIO_MS;
|
|
else
|
|
return RTCP_INTERVAL_VIDEO_MS;
|
|
}
|
|
} // Namespace webrtc
|