blob: 1597ab2cd1f57d3b18d5082dd9e792e1f0370ac8 [file] [log] [blame]
/*
* 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(
const RtxMode mode,
const bool set_ssrc,
const uint32_t ssrc) {
rtp_sender_.SetRTXStatus(mode, set_ssrc, ssrc);
return 0;
}
int32_t ModuleRtpRtcpImpl::RTXSendStatus(RtxMode* mode, uint32_t* ssrc) const {
rtp_sender_.RTXStatus(mode, ssrc);
return 0;
}
int32_t ModuleRtpRtcpImpl::SetRTXReceiveStatus(
const bool enable,
const uint32_t ssrc) {
rtp_receiver_->SetRTXStatus(enable, ssrc);
return 0;
}
int32_t ModuleRtpRtcpImpl::RTXReceiveStatus(bool* enable,
uint32_t* ssrc) const {
rtp_receiver_->RTXStatus(enable, ssrc);
return 0;
}
// Called by the network module when we receive a packet.
int32_t ModuleRtpRtcpImpl::IncomingPacket(
const uint8_t* incoming_packet,
const uint16_t incoming_packet_length) {
WEBRTC_TRACE(kTraceStream,
kTraceRtpRtcp,
id_,
"IncomingPacket(packet_length:%u)",
incoming_packet_length);
// Minimum RTP is 12 bytes.
// Minimum RTCP is 8 bytes (RTCP BYE).
if (incoming_packet_length < 8 || incoming_packet == NULL) {
WEBRTC_TRACE(kTraceDebug,
kTraceRtpRtcp,
id_,
"IncomingPacket invalid buffer or length");
return -1;
}
// Check RTP version.
const uint8_t version = incoming_packet[0] >> 6;
if (version != 2) {
WEBRTC_TRACE(kTraceDebug,
kTraceRtpRtcp,
id_,
"IncomingPacket invalid RTP version");
return -1;
}
ModuleRTPUtility::RTPHeaderParser rtp_parser(incoming_packet,
incoming_packet_length);
if (rtp_parser.RTCP()) {
// Allow receive of non-compound RTCP packets.
RTCPUtility::RTCPParserV2 rtcp_parser(incoming_packet,
incoming_packet_length,
true);
const bool valid_rtcpheader = rtcp_parser.IsValid();
if (!valid_rtcpheader) {
WEBRTC_TRACE(kTraceDebug,
kTraceRtpRtcp,
id_,
"IncomingPacket 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;
} else {
WebRtcRTPHeader rtp_header;
memset(&rtp_header, 0, sizeof(rtp_header));
RtpHeaderExtensionMap map;
rtp_receiver_->GetHeaderExtensionMapCopy(&map);
const bool valid_rtpheader = rtp_parser.Parse(rtp_header, &map);
if (!valid_rtpheader) {
WEBRTC_TRACE(kTraceDebug,
kTraceRtpRtcp,
id_,
"IncomingPacket invalid RTP header");
return -1;
}
return rtp_receiver_->IncomingRTPPacket(&rtp_header,
incoming_packet,
incoming_packet_length);
}
}
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);
}
int32_t ModuleRtpRtcpImpl::RegisterReceiveRtpHeaderExtension(
const RTPExtensionType type,
const uint8_t id) {
return rtp_receiver_->RegisterRtpHeaderExtension(type, id);
}
int32_t ModuleRtpRtcpImpl::DeregisterReceiveRtpHeaderExtension(
const RTPExtensionType type) {
return rtp_receiver_->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);
if (enable) {
rtp_receiver_->RegisterRtpHeaderExtension(kRtpExtensionAudioLevel, id);
} else {
rtp_receiver_->DeregisterRtpHeaderExtension(kRtpExtensionAudioLevel);
}
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