static const int kMaxTargetDelayMs = 10000;
static const float kMaxIncompleteTimeMultiplier = 3.5f;
+namespace {
+
+RTCPReportBlock AggregateReportBlocks(
+ const std::vector<RTCPReportBlock>& report_blocks,
+ std::map<uint32_t, RTCPReportBlock>* prev_report_blocks) {
+ int fraction_lost_sum = 0;
+ int fl_seq_num_sum = 0;
+ int jitter_sum = 0;
+ int number_of_report_blocks = 0;
+ RTCPReportBlock aggregate;
+ std::vector<RTCPReportBlock>::const_iterator report_block =
+ report_blocks.begin();
+ for (; report_block != report_blocks.end(); ++report_block) {
+ aggregate.cumulativeLost += report_block->cumulativeLost;
+ std::map<uint32_t, RTCPReportBlock>::iterator prev_report_block =
+ prev_report_blocks->find(report_block->sourceSSRC);
+ if (prev_report_block != prev_report_blocks->end()) {
+ // Skip the first report block since we won't be able to get a correct
+ // weight for it.
+ int seq_num_diff = report_block->extendedHighSeqNum -
+ prev_report_block->second.extendedHighSeqNum;
+ if (seq_num_diff > 0) {
+ fraction_lost_sum += report_block->fractionLost * seq_num_diff;
+ fl_seq_num_sum += seq_num_diff;
+ }
+ }
+ jitter_sum += report_block->jitter;
+ ++number_of_report_blocks;
+ (*prev_report_blocks)[report_block->sourceSSRC] = *report_block;
+ }
+ if (fl_seq_num_sum > 0) {
+ aggregate.fractionLost =
+ (fraction_lost_sum + fl_seq_num_sum / 2) / fl_seq_num_sum;
+ }
+ if (number_of_report_blocks > 0) {
+ aggregate.jitter =
+ (jitter_sum + number_of_report_blocks / 2) / number_of_report_blocks;
+ }
+ // Not well defined for aggregated report blocks.
+ aggregate.extendedHighSeqNum = 0;
+ return aggregate;
+}
+} // namespace
+
// Helper class receiving statistics callbacks.
class ChannelStatsObserver : public CallStatsObserver {
public:
callback_cs_(CriticalSectionWrapper::CreateCriticalSection()),
rtp_rtcp_cs_(CriticalSectionWrapper::CreateCriticalSection()),
default_rtp_rtcp_(default_rtp_rtcp),
- vcm_(*VideoCodingModule::Create()),
- vie_receiver_(channel_id, &vcm_, remote_bitrate_estimator, this),
+ vcm_(VideoCodingModule::Create()),
+ vie_receiver_(channel_id, vcm_, remote_bitrate_estimator, this),
vie_sender_(channel_id),
- vie_sync_(&vcm_, this),
+ vie_sync_(vcm_, this),
stats_observer_(new ChannelStatsObserver(this)),
module_process_thread_(module_process_thread),
codec_observer_(NULL),
intra_frame_observer_(intra_frame_observer),
rtt_stats_(rtt_stats),
paced_sender_(paced_sender),
+ pad_with_redundant_payloads_(false),
bandwidth_observer_(bandwidth_observer),
send_timestamp_extension_id_(kInvalidRtpExtensionId),
absolute_send_time_extension_id_(kInvalidRtpExtensionId),
sender_(sender),
nack_history_size_sender_(kSendSidePacketHistorySize),
max_nack_reordering_threshold_(kMaxPacketAgeToNack),
- pre_render_callback_(NULL),
- config_(config) {
+ pre_render_callback_(NULL) {
RtpRtcp::Configuration configuration;
configuration.id = ViEModuleId(engine_id, channel_id);
configuration.audio = false;
configuration.remote_bitrate_estimator = remote_bitrate_estimator;
configuration.paced_sender = paced_sender;
configuration.receive_statistics = vie_receiver_.GetReceiveStatistics();
+ configuration.send_bitrate_observer = &send_bitrate_observer_;
+ configuration.send_frame_count_observer = &send_frame_count_observer_;
+ configuration.send_side_delay_observer = &send_side_delay_observer_;
rtp_rtcp_.reset(RtpRtcp::CreateRtpRtcp(configuration));
vie_receiver_.SetRtpRtcpModule(rtp_rtcp_.get());
- vcm_.SetNackSettings(kMaxNackListSize, max_nack_reordering_threshold_, 0);
+ vcm_->SetNackSettings(kMaxNackListSize, max_nack_reordering_threshold_, 0);
}
int32_t ViEChannel::Init() {
if (paced_sender_) {
rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_);
}
- if (vcm_.InitializeReceiver() != 0) {
+ if (vcm_->InitializeReceiver() != 0) {
return -1;
}
- if (vcm_.SetVideoProtection(kProtectionKeyOnLoss, true)) {
+ if (vcm_->SetVideoProtection(kProtectionKeyOnLoss, true)) {
return -1;
}
- if (vcm_.RegisterReceiveCallback(this) != 0) {
+ if (vcm_->RegisterReceiveCallback(this) != 0) {
return -1;
}
- vcm_.RegisterFrameTypeCallback(this);
- vcm_.RegisterReceiveStatisticsCallback(this);
- vcm_.RegisterDecoderTimingCallback(this);
- vcm_.SetRenderDelay(kViEDefaultRenderDelayMs);
- if (module_process_thread_.RegisterModule(&vcm_) != 0) {
+ vcm_->RegisterFrameTypeCallback(this);
+ vcm_->RegisterReceiveStatisticsCallback(this);
+ vcm_->RegisterDecoderTimingCallback(this);
+ vcm_->SetRenderDelay(kViEDefaultRenderDelayMs);
+ if (module_process_thread_.RegisterModule(vcm_) != 0) {
return -1;
}
#ifdef VIDEOCODEC_VP8
VideoCodec video_codec;
- if (vcm_.Codec(kVideoCodecVP8, &video_codec) == VCM_OK) {
+ if (vcm_->Codec(kVideoCodecVP8, &video_codec) == VCM_OK) {
rtp_rtcp_->RegisterSendPayload(video_codec);
// TODO(holmer): Can we call SetReceiveCodec() here instead?
if (!vie_receiver_.RegisterPayload(video_codec)) {
return -1;
}
- vcm_.RegisterReceiveCodec(&video_codec, number_of_cores_);
- vcm_.RegisterSendCodec(&video_codec, number_of_cores_,
+ vcm_->RegisterReceiveCodec(&video_codec, number_of_cores_);
+ vcm_->RegisterSendCodec(&video_codec, number_of_cores_,
rtp_rtcp_->MaxDataPayloadLength());
} else {
assert(false);
// Make sure we don't get more callbacks from the RTP module.
module_process_thread_.DeRegisterModule(vie_receiver_.GetReceiveStatistics());
module_process_thread_.DeRegisterModule(rtp_rtcp_.get());
- module_process_thread_.DeRegisterModule(&vcm_);
+ module_process_thread_.DeRegisterModule(vcm_);
module_process_thread_.DeRegisterModule(&vie_sync_);
while (simulcast_rtp_rtcp_.size() > 0) {
std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
StopDecodeThread();
}
// Release modules.
- VideoCodingModule::Destroy(&vcm_);
+ VideoCodingModule::Destroy(vcm_);
}
int32_t ViEChannel::SetSendCodec(const VideoCodec& video_codec,
num_modules_to_add = 0;
}
- while (removed_rtp_rtcp_.size() > 0 && num_modules_to_add > 0) {
- RtpRtcp* rtp_rtcp = removed_rtp_rtcp_.front();
+ // Add back removed rtp modules. Order is important (allocate from front of
+ // removed modules) to preserve RTP settings such as SSRCs for simulcast
+ // streams.
+ std::list<RtpRtcp*> new_rtp_modules;
+ for (; removed_rtp_rtcp_.size() > 0 && num_modules_to_add > 0;
+ --num_modules_to_add) {
+ new_rtp_modules.push_back(removed_rtp_rtcp_.front());
removed_rtp_rtcp_.pop_front();
- simulcast_rtp_rtcp_.push_back(rtp_rtcp);
- rtp_rtcp->SetSendingStatus(rtp_rtcp_->Sending());
- rtp_rtcp->SetSendingMediaStatus(rtp_rtcp_->SendingMedia());
- module_process_thread_.RegisterModule(rtp_rtcp);
- --num_modules_to_add;
}
- for (int i = 0; i < num_modules_to_add; ++i) {
- RtpRtcp::Configuration configuration;
- configuration.id = ViEModuleId(engine_id_, channel_id_);
- configuration.audio = false; // Video.
- configuration.default_module = default_rtp_rtcp_;
- configuration.outgoing_transport = &vie_sender_;
- configuration.intra_frame_callback = intra_frame_observer_;
- configuration.bandwidth_callback = bandwidth_observer_.get();
- configuration.rtt_stats = rtt_stats_;
- configuration.paced_sender = paced_sender_;
+ for (int i = 0; i < num_modules_to_add; ++i)
+ new_rtp_modules.push_back(CreateRtpRtcpModule());
- RtpRtcp* rtp_rtcp = RtpRtcp::CreateRtpRtcp(configuration);
+ // Initialize newly added modules.
+ for (std::list<RtpRtcp*>::iterator it = new_rtp_modules.begin();
+ it != new_rtp_modules.end();
+ ++it) {
+ RtpRtcp* rtp_rtcp = *it;
- // Silently ignore error.
- module_process_thread_.RegisterModule(rtp_rtcp);
rtp_rtcp->SetRTCPStatus(rtp_rtcp_->RTCP());
if (rtp_rtcp_->StorePackets()) {
}
if (fec_enabled) {
- rtp_rtcp->SetGenericFECStatus(fec_enabled, payload_type_red,
- payload_type_fec);
+ rtp_rtcp->SetGenericFECStatus(
+ fec_enabled, payload_type_red, payload_type_fec);
}
rtp_rtcp->SetSendingStatus(rtp_rtcp_->Sending());
rtp_rtcp->SetSendingMediaStatus(rtp_rtcp_->SendingMedia());
+
+ int mode;
+ uint32_t ssrc;
+ int payload_type;
+ rtp_rtcp_->RTXSendStatus(&mode, &ssrc, &payload_type);
+ rtp_rtcp->SetRTXSendStatus(mode);
simulcast_rtp_rtcp_.push_back(rtp_rtcp);
+
+ // Silently ignore error.
+ module_process_thread_.RegisterModule(rtp_rtcp);
}
+
// Remove last in list if we have too many.
for (int j = simulcast_rtp_rtcp_.size();
j > (video_codec.numberOfSimulcastStreams - 1);
module_process_thread_.DeRegisterModule(rtp_rtcp);
rtp_rtcp->SetSendingStatus(false);
rtp_rtcp->SetSendingMediaStatus(false);
- rtp_rtcp->RegisterSendFrameCountObserver(NULL);
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
- rtp_rtcp->RegisterVideoBitrateObserver(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
}
rtp_rtcp->DeregisterSendRtpHeaderExtension(
kRtpExtensionAbsoluteSendTime);
}
- rtp_rtcp->RegisterSendFrameCountObserver(
- rtp_rtcp_->GetSendFrameCountObserver());
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(
rtp_rtcp_->GetSendChannelRtcpStatisticsCallback());
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(
rtp_rtcp_->GetSendChannelRtpStatisticsCallback());
- rtp_rtcp->RegisterVideoBitrateObserver(
- rtp_rtcp_->GetVideoBitrateObserver());
}
// |RegisterSimulcastRtpRtcpModules| resets all old weak pointers and old
// modules can be deleted after this step.
module_process_thread_.DeRegisterModule(rtp_rtcp);
rtp_rtcp->SetSendingStatus(false);
rtp_rtcp->SetSendingMediaStatus(false);
- rtp_rtcp->RegisterSendFrameCountObserver(NULL);
rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
- rtp_rtcp->RegisterVideoBitrateObserver(NULL);
simulcast_rtp_rtcp_.pop_back();
removed_rtp_rtcp_.push_front(rtp_rtcp);
}
// Clear any previous modules.
vie_receiver_.RegisterSimulcastRtpRtcpModules(simulcast_rtp_rtcp_);
}
- // Enable this if H264 is available.
- // This sets the wanted packetization mode.
- // if (video_codec.plType == kVideoCodecH264) {
- // if (video_codec.codecSpecific.H264.packetization == kH264SingleMode) {
- // rtp_rtcp_->SetH264PacketizationMode(H264_SINGLE_NAL_MODE);
- // } else {
- // rtp_rtcp_->SetH264PacketizationMode(H264_NON_INTERLEAVED_MODE);
- // }
- // if (video_codec.codecSpecific.H264.configParametersSize > 0) {
- // rtp_rtcp_->SetH264SendModeNALU_PPS_SPS(true);
- // }
- // }
// Don't log this error, no way to check in advance if this pl_type is
// registered or not...
if (video_codec.codecType != kVideoCodecRED &&
video_codec.codecType != kVideoCodecULPFEC) {
// Register codec type with VCM, but do not register RED or ULPFEC.
- if (vcm_.RegisterReceiveCodec(&video_codec, number_of_cores_,
+ if (vcm_->RegisterReceiveCodec(&video_codec, number_of_cores_,
wait_for_key_frame_) != VCM_OK) {
return -1;
}
}
int32_t ViEChannel::GetReceiveCodec(VideoCodec* video_codec) {
- if (vcm_.ReceiveCodec(video_codec) != 0) {
+ if (vcm_->ReceiveCodec(video_codec) != 0) {
return -1;
}
return 0;
bool buffered_rendering,
int32_t render_delay) {
int32_t result;
- result = vcm_.RegisterExternalDecoder(decoder, pl_type, buffered_rendering);
+ result = vcm_->RegisterExternalDecoder(decoder, pl_type, buffered_rendering);
if (result != VCM_OK) {
return result;
}
- return vcm_.SetRenderDelay(render_delay);
+ return vcm_->SetRenderDelay(render_delay);
}
int32_t ViEChannel::DeRegisterExternalDecoder(const uint8_t pl_type) {
VideoCodec current_receive_codec;
int32_t result = 0;
- result = vcm_.ReceiveCodec(¤t_receive_codec);
- if (vcm_.RegisterExternalDecoder(NULL, pl_type, false) != VCM_OK) {
+ result = vcm_->ReceiveCodec(¤t_receive_codec);
+ if (vcm_->RegisterExternalDecoder(NULL, pl_type, false) != VCM_OK) {
return -1;
}
if (result == 0 && current_receive_codec.plType == pl_type) {
- result = vcm_.RegisterReceiveCodec(¤t_receive_codec, number_of_cores_,
- wait_for_key_frame_);
+ result = vcm_->RegisterReceiveCodec(
+ ¤t_receive_codec, number_of_cores_, wait_for_key_frame_);
}
return result;
}
int32_t ViEChannel::ReceiveCodecStatistics(uint32_t* num_key_frames,
uint32_t* num_delta_frames) {
VCMFrameCount received_frames;
- if (vcm_.ReceivedFrameCount(received_frames) != VCM_OK) {
+ if (vcm_->ReceivedFrameCount(received_frames) != VCM_OK) {
return -1;
}
*num_key_frames = received_frames.numKeyFrames;
}
uint32_t ViEChannel::DiscardedPackets() const {
- return vcm_.DiscardedPackets();
+ return vcm_->DiscardedPackets();
}
int ViEChannel::ReceiveDelay() const {
- return vcm_.Delay();
+ return vcm_->Delay();
}
int32_t ViEChannel::WaitForKeyFrame(bool wait) {
bool only_key_frames) {
if (enable) {
if (only_key_frames) {
- vcm_.SetVideoProtection(kProtectionKeyOnLoss, false);
- if (vcm_.SetVideoProtection(kProtectionKeyOnKeyLoss, true) != VCM_OK) {
+ vcm_->SetVideoProtection(kProtectionKeyOnLoss, false);
+ if (vcm_->SetVideoProtection(kProtectionKeyOnKeyLoss, true) != VCM_OK) {
return -1;
}
} else {
- vcm_.SetVideoProtection(kProtectionKeyOnKeyLoss, false);
- if (vcm_.SetVideoProtection(kProtectionKeyOnLoss, true) != VCM_OK) {
+ vcm_->SetVideoProtection(kProtectionKeyOnKeyLoss, false);
+ if (vcm_->SetVideoProtection(kProtectionKeyOnLoss, true) != VCM_OK) {
return -1;
}
}
} else {
- vcm_.SetVideoProtection(kProtectionKeyOnLoss, false);
- vcm_.SetVideoProtection(kProtectionKeyOnKeyLoss, false);
+ vcm_->SetVideoProtection(kProtectionKeyOnLoss, false);
+ vcm_->SetVideoProtection(kProtectionKeyOnKeyLoss, false);
}
return 0;
}
int32_t ViEChannel::SetNACKStatus(const bool enable) {
// Update the decoding VCM.
- if (vcm_.SetVideoProtection(kProtectionNack, enable) != VCM_OK) {
+ if (vcm_->SetVideoProtection(kProtectionNack, enable) != VCM_OK) {
return -1;
}
if (enable) {
SetFECStatus(false, 0, 0);
}
// Update the decoding VCM.
- if (vcm_.SetVideoProtection(kProtectionNack, enable) != VCM_OK) {
+ if (vcm_->SetVideoProtection(kProtectionNack, enable) != VCM_OK) {
return -1;
}
return ProcessNACKRequest(enable);
}
vie_receiver_.SetNackStatus(true, max_nack_reordering_threshold_);
rtp_rtcp_->SetStorePacketsStatus(true, nack_history_size_sender_);
- vcm_.RegisterPacketRequestCallback(this);
+ vcm_->RegisterPacketRequestCallback(this);
CriticalSectionScoped cs(rtp_rtcp_cs_.get());
rtp_rtcp->SetStorePacketsStatus(true, nack_history_size_sender_);
}
// Don't introduce errors when NACK is enabled.
- vcm_.SetDecodeErrorMode(kNoErrors);
+ vcm_->SetDecodeErrorMode(kNoErrors);
} else {
CriticalSectionScoped cs(rtp_rtcp_cs_.get());
for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
rtp_rtcp->SetStorePacketsStatus(false, 0);
}
}
- vcm_.RegisterPacketRequestCallback(NULL);
+ vcm_->RegisterPacketRequestCallback(NULL);
if (paced_sender_ == NULL) {
rtp_rtcp_->SetStorePacketsStatus(false, 0);
}
vie_receiver_.SetNackStatus(false, max_nack_reordering_threshold_);
// When NACK is off, allow decoding with errors. Otherwise, the video
// will freeze, and will only recover with a complete key frame.
- vcm_.SetDecodeErrorMode(kWithErrors);
+ vcm_->SetDecodeErrorMode(kWithErrors);
}
return 0;
}
const bool enable,
const unsigned char payload_typeRED,
const unsigned char payload_typeFEC) {
- if (vcm_.SetVideoProtection(kProtectionNackFEC, enable) != VCM_OK) {
+ if (vcm_->SetVideoProtection(kProtectionNackFEC, enable) != VCM_OK) {
return -1;
}
max_incomplete_time_ms = static_cast<int>(kMaxIncompleteTimeMultiplier *
target_delay_ms + 0.5f);
}
- vcm_.SetNackSettings(max_nack_list_size, max_nack_reordering_threshold_,
+ vcm_->SetNackSettings(max_nack_list_size, max_nack_reordering_threshold_,
max_incomplete_time_ms);
- vcm_.SetMinReceiverDelay(target_delay_ms);
+ vcm_->SetMinReceiverDelay(target_delay_ms);
if (vie_sync_.SetTargetBufferingDelay(target_delay_ms) < 0)
return -1;
return 0;
int32_t ViEChannel::SetSSRC(const uint32_t SSRC,
const StreamType usage,
const uint8_t simulcast_idx) {
- int rtx_settings = kRtxRetransmitted;
- if (config_.Get<PaddingStrategy>().redundant_payloads)
- rtx_settings |= kRtxRedundantPayloads;
- if (simulcast_idx == 0) {
- if (usage == kViEStreamTypeRtx) {
- return rtp_rtcp_->SetRTXSendStatus(rtx_settings, true, SSRC);
- }
- return rtp_rtcp_->SetSSRC(SSRC);
- }
CriticalSectionScoped cs(rtp_rtcp_cs_.get());
- if (simulcast_idx > simulcast_rtp_rtcp_.size()) {
- return -1;
- }
- std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
- for (int i = 1; i < simulcast_idx; ++i, ++it) {
- if (it == simulcast_rtp_rtcp_.end()) {
- return -1;
- }
- }
- RtpRtcp* rtp_rtcp_module = *it;
+ ReserveRtpRtcpModules(simulcast_idx + 1);
+ RtpRtcp* rtp_rtcp = GetRtpRtcpModule(simulcast_idx);
+ if (rtp_rtcp == NULL)
+ return -1;
if (usage == kViEStreamTypeRtx) {
- return rtp_rtcp_module->SetRTXSendStatus(rtx_settings, true, SSRC);
+ rtp_rtcp->SetRtxSsrc(SSRC);
+ } else {
+ rtp_rtcp->SetSSRC(SSRC);
}
- return rtp_rtcp_module->SetSSRC(SSRC);
+ return 0;
}
int32_t ViEChannel::SetRemoteSSRCType(const StreamType usage,
const uint32_t SSRC) {
- vie_receiver_.SetRtxStatus(true, SSRC);
+ vie_receiver_.SetRtxSsrc(SSRC);
return 0;
}
int32_t ViEChannel::GetLocalSSRC(uint8_t idx, unsigned int* ssrc) {
- if (idx == 0) {
- *ssrc = rtp_rtcp_->SSRC();
- return 0;
- }
CriticalSectionScoped cs(rtp_rtcp_cs_.get());
- if (idx > simulcast_rtp_rtcp_.size()) {
+ RtpRtcp* rtp_rtcp = GetRtpRtcpModule(idx);
+ if (rtp_rtcp == NULL)
return -1;
- }
- std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
- for (int i = 1; i < idx; ++i, ++it) {
- if (it == simulcast_rtp_rtcp_.end()) {
- return -1;
- }
- }
- *ssrc = (*it)->SSRC();
+ *ssrc = rtp_rtcp->SSRC();
return 0;
}
return 0;
}
-int ViEChannel::SetRtxSendPayloadType(int payload_type) {
- if (rtp_rtcp_->Sending()) {
- return -1;
+void ViEChannel::SetPadWithRedundantPayloads(bool enable) {
+ {
+ CriticalSectionScoped cs(callback_cs_.get());
+ pad_with_redundant_payloads_ = enable;
+ }
+ int mode;
+ uint32_t ssrc;
+ int payload_type;
+ rtp_rtcp_->RTXSendStatus(&mode, &ssrc, &payload_type);
+ if (mode != kRtxOff) {
+ // Since RTX was already enabled we have to reset it with payload-based
+ // padding on.
+ SetRtxSendStatus(true);
}
+}
+
+int ViEChannel::SetRtxSendPayloadType(int payload_type) {
rtp_rtcp_->SetRtxSendPayloadType(payload_type);
- CriticalSectionScoped cs(rtp_rtcp_cs_.get());
for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
it != simulcast_rtp_rtcp_.end(); it++) {
(*it)->SetRtxSendPayloadType(payload_type);
}
+ SetRtxSendStatus(true);
return 0;
}
+void ViEChannel::SetRtxSendStatus(bool enable) {
+ int rtx_settings = kRtxOff;
+ if (enable) {
+ CriticalSectionScoped cs(callback_cs_.get());
+ rtx_settings = kRtxRetransmitted;
+ if (pad_with_redundant_payloads_)
+ rtx_settings |= kRtxRedundantPayloads;
+ }
+ rtp_rtcp_->SetRTXSendStatus(rtx_settings);
+ CriticalSectionScoped cs(rtp_rtcp_cs_.get());
+ for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
+ it != simulcast_rtp_rtcp_.end(); it++) {
+ (*it)->SetRTXSendStatus(rtx_settings);
+ }
+}
+
void ViEChannel::SetRtxReceivePayloadType(int payload_type) {
vie_receiver_.SetRtxPayloadType(payload_type);
}
return rtp_rtcp_->SetSequenceNumber(sequence_number);
}
+void ViEChannel::SetRtpStateForSsrc(uint32_t ssrc, const RtpState& rtp_state) {
+ assert(!rtp_rtcp_->Sending());
+ default_rtp_rtcp_->SetRtpStateForSsrc(ssrc, rtp_state);
+}
+
+RtpState ViEChannel::GetRtpStateForSsrc(uint32_t ssrc) {
+ assert(!rtp_rtcp_->Sending());
+
+ RtpState rtp_state;
+ if (!default_rtp_rtcp_->GetRtpStateForSsrc(ssrc, &rtp_state)) {
+ LOG(LS_ERROR) << "Couldn't get RTP state for ssrc: " << ssrc;
+ }
+ return rtp_state;
+}
+
int32_t ViEChannel::SetRTCPCName(const char rtcp_cname[]) {
if (rtp_rtcp_->Sending()) {
return -1;
return rtp_rtcp_->SetCNAME(rtcp_cname);
}
-int32_t ViEChannel::GetRTCPCName(char rtcp_cname[]) {
- return rtp_rtcp_->CNAME(rtcp_cname);
-}
-
int32_t ViEChannel::GetRemoteRTCPCName(char rtcp_cname[]) {
uint32_t remoteSSRC = vie_receiver_.GetRemoteSsrc();
return rtp_rtcp_->RemoteCNAME(remoteSSRC, rtcp_cname);
uint32_t* extended_max,
uint32_t* jitter_samples,
int32_t* rtt_ms) {
- // TODO(pwestin) how do we do this for simulcast ? average for all
- // except cumulative_lost that is the sum ?
- // CriticalSectionScoped cs(rtp_rtcp_cs_.get());
-
- // for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
- // it != simulcast_rtp_rtcp_.end();
- // it++) {
- // RtpRtcp* rtp_rtcp = *it;
- // }
- uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc();
+ // Aggregate the report blocks associated with streams sent on this channel.
+ std::vector<RTCPReportBlock> report_blocks;
+ rtp_rtcp_->RemoteRTCPStat(&report_blocks);
+ {
+ CriticalSectionScoped lock(rtp_rtcp_cs_.get());
+ for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
+ it != simulcast_rtp_rtcp_.end();
+ ++it) {
+ (*it)->RemoteRTCPStat(&report_blocks);
+ }
+ }
- // Get all RTCP receiver report blocks that have been received on this
- // channel. If we receive RTP packets from a remote source we know the
- // remote SSRC and use the report block from him.
- // Otherwise use the first report block.
- std::vector<RTCPReportBlock> remote_stats;
- if (rtp_rtcp_->RemoteRTCPStat(&remote_stats) != 0 || remote_stats.empty()) {
+ if (report_blocks.empty())
return -1;
- }
- std::vector<RTCPReportBlock>::const_iterator statistics =
- remote_stats.begin();
- for (; statistics != remote_stats.end(); ++statistics) {
- if (statistics->remoteSSRC == remote_ssrc)
+
+ uint32_t remote_ssrc = vie_receiver_.GetRemoteSsrc();
+ std::vector<RTCPReportBlock>::const_iterator it = report_blocks.begin();
+ for (; it != report_blocks.end(); ++it) {
+ if (it->remoteSSRC == remote_ssrc)
break;
}
-
- if (statistics == remote_stats.end()) {
- // If we have not received any RTCP packets from this SSRC it probably means
- // we have not received any RTP packets.
- // Use the first received report block instead.
- statistics = remote_stats.begin();
- remote_ssrc = statistics->remoteSSRC;
+ if (it == report_blocks.end()) {
+ // We have not received packets with an SSRC matching the report blocks. To
+ // have a chance of calculating an RTT we will try with the SSRC of the
+ // first report block received.
+ // This is very important for send-only channels where we don't know the
+ // SSRC of the other end.
+ remote_ssrc = report_blocks[0].remoteSSRC;
}
- *fraction_lost = statistics->fractionLost;
- *cumulative_lost = statistics->cumulativeLost;
- *extended_max = statistics->extendedHighSeqNum;
- *jitter_samples = statistics->jitter;
+ RTCPReportBlock report;
+ if (report_blocks.size() > 1)
+ report = AggregateReportBlocks(report_blocks, &prev_report_blocks_);
+ else
+ report = report_blocks[0];
+
+ *fraction_lost = report.fractionLost;
+ *cumulative_lost = report.cumulativeLost;
+ *extended_max = report.extendedHighSeqNum;
+ *jitter_samples = report.jitter;
uint16_t dummy;
uint16_t rtt = 0;
return valid_estimate;
}
+void ViEChannel::RegisterSendSideDelayObserver(
+ SendSideDelayObserver* observer) {
+ send_side_delay_observer_.Set(observer);
+}
+
void ViEChannel::RegisterSendBitrateObserver(
BitrateStatisticsObserver* observer) {
- rtp_rtcp_->RegisterVideoBitrateObserver(observer);
- CriticalSectionScoped cs(rtp_rtcp_cs_.get());
- for (std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
- it != simulcast_rtp_rtcp_.end();
- it++) {
- (*it)->RegisterVideoBitrateObserver(observer);
- }
+ send_bitrate_observer_.Set(observer);
}
void ViEChannel::GetReceiveBandwidthEstimatorStats(
int32_t ViEChannel::StopReceive() {
vie_receiver_.StopReceive();
StopDecodeThread();
- vcm_.ResetDecoder();
+ vcm_->ResetDecoder();
return 0;
}
}
bool ViEChannel::ChannelDecodeProcess() {
- vcm_.Decode(kMaxDecodeWaitTimeMs);
+ vcm_->Decode(kMaxDecodeWaitTimeMs);
return true;
}
void ViEChannel::OnRttUpdate(uint32_t rtt) {
- vcm_.SetReceiveChannelParameters(rtt);
+ vcm_->SetReceiveChannelParameters(rtt);
+}
+
+void ViEChannel::ReserveRtpRtcpModules(size_t num_modules) {
+ for (size_t total_modules =
+ 1 + simulcast_rtp_rtcp_.size() + removed_rtp_rtcp_.size();
+ total_modules < num_modules;
+ ++total_modules) {
+ RtpRtcp* rtp_rtcp = CreateRtpRtcpModule();
+ rtp_rtcp->SetSendingStatus(false);
+ rtp_rtcp->SetSendingMediaStatus(false);
+ rtp_rtcp->RegisterSendChannelRtcpStatisticsCallback(NULL);
+ rtp_rtcp->RegisterSendChannelRtpStatisticsCallback(NULL);
+ removed_rtp_rtcp_.push_back(rtp_rtcp);
+ }
+}
+
+RtpRtcp* ViEChannel::GetRtpRtcpModule(size_t index) const {
+ if (index == 0)
+ return rtp_rtcp_.get();
+ if (index <= simulcast_rtp_rtcp_.size()) {
+ std::list<RtpRtcp*>::const_iterator it = simulcast_rtp_rtcp_.begin();
+ for (size_t i = 1; i < index; ++i) {
+ ++it;
+ }
+ return *it;
+ }
+
+ // If the requested module exists it must be in the removed list. Index
+ // translation to this list must remove the default module as well as all
+ // active simulcast modules.
+ size_t removed_idx = index - simulcast_rtp_rtcp_.size() - 1;
+ if (removed_idx >= removed_rtp_rtcp_.size())
+ return NULL;
+
+ std::list<RtpRtcp*>::const_iterator it = removed_rtp_rtcp_.begin();
+ while (removed_idx-- > 0)
+ ++it;
+
+ return *it;
+}
+
+RtpRtcp* ViEChannel::CreateRtpRtcpModule() {
+ RtpRtcp::Configuration configuration;
+ configuration.id = ViEModuleId(engine_id_, channel_id_);
+ configuration.audio = false; // Video.
+ configuration.default_module = default_rtp_rtcp_;
+ configuration.outgoing_transport = &vie_sender_;
+ configuration.intra_frame_callback = intra_frame_observer_;
+ configuration.bandwidth_callback = bandwidth_observer_.get();
+ configuration.rtt_stats = rtt_stats_;
+ configuration.paced_sender = paced_sender_;
+ configuration.send_side_delay_observer = &send_side_delay_observer_;
+
+ return RtpRtcp::CreateRtpRtcp(configuration);
}
int32_t ViEChannel::StartDecodeThread() {
void ViEChannel::RegisterPreDecodeImageCallback(
EncodedImageCallback* pre_decode_callback) {
- CriticalSectionScoped cs(callback_cs_.get());
- vcm_.RegisterPreDecodeImageCallback(pre_decode_callback);
+ vcm_->RegisterPreDecodeImageCallback(pre_decode_callback);
}
void ViEChannel::OnApplicationDataReceived(const int32_t id,
const uint32_t rate) {
LOG(LS_INFO) << "OnInitializeDecoder " << payload_type << " "
<< payload_name;
- vcm_.ResetDecoder();
+ vcm_->ResetDecoder();
CriticalSectionScoped cs(callback_cs_.get());
decoder_reset_ = true;
void ViEChannel::RegisterSendFrameCountObserver(
FrameCountObserver* observer) {
- rtp_rtcp_->RegisterSendFrameCountObserver(observer);
- CriticalSectionScoped cs(rtp_rtcp_cs_.get());
- for (std::list<RtpRtcp*>::iterator it = simulcast_rtp_rtcp_.begin();
- it != simulcast_rtp_rtcp_.end();
- it++) {
- (*it)->RegisterSendFrameCountObserver(observer);
- }
+ send_frame_count_observer_.Set(observer);
}
void ViEChannel::ReceivedBWEPacket(int64_t arrival_time_ms,