| /* |
| * 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 <assert.h> |
| #include <string.h> |
| |
| #include "webrtc/common_types.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 |
| |
| #ifdef _WIN32 |
| // Disable warning C4355: 'this' : used in base member initializer list. |
| #pragma warning(disable : 4355) |
| #endif |
| |
| namespace webrtc { |
| |
| RtpRtcp::Configuration::Configuration() |
| : id(-1), |
| audio(false), |
| clock(NULL), |
| default_module(NULL), |
| receive_statistics(NullObjectReceiveStatistics()), |
| outgoing_transport(NULL), |
| rtcp_feedback(NULL), |
| intra_frame_callback(NULL), |
| bandwidth_callback(NULL), |
| rtt_stats(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_sender_(configuration.id, |
| configuration.audio, |
| configuration.clock, |
| configuration.outgoing_transport, |
| configuration.audio_messages, |
| configuration.paced_sender), |
| rtcp_sender_(configuration.id, configuration.audio, configuration.clock, |
| configuration.receive_statistics), |
| rtcp_receiver_(configuration.id, configuration.clock, this), |
| clock_(configuration.clock), |
| id_(configuration.id), |
| audio_(configuration.audio), |
| collision_detected_(false), |
| last_process_time_(configuration.clock->TimeInMilliseconds()), |
| last_bitrate_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)), |
| 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_stats_(configuration.rtt_stats), |
| critical_section_rtt_(CriticalSectionWrapper::CreateCriticalSection()), |
| rtt_ms_(0) { |
| 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); |
| SetRtcpReceiverSsrcs(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_bitrate_process_time_ + kRtpRtcpBitrateProcessTimeMs) { |
| rtp_sender_.ProcessBitrate(); |
| last_bitrate_process_time_ = now; |
| } |
| |
| if (!IsDefaultModule()) { |
| bool process_rtt = now >= last_rtt_process_time_ + kRtpRtcpRttProcessTimeMs; |
| 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_ && process_rtt) { |
| 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_stats_ && max_rtt != 0) |
| rtt_stats_->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_ && rtcp_sender_.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); |
| } |
| } |
| } else { |
| // Report rtt from receiver. |
| if (process_rtt) { |
| uint16_t rtt_ms; |
| if (rtt_stats_ && rtcp_receiver_.GetAndResetXrRrRtt(&rtt_ms)) { |
| rtt_stats_->OnRttUpdate(rtt_ms); |
| } |
| } |
| } |
| |
| // Get processed rtt. |
| if (process_rtt) { |
| last_rtt_process_time_ = now; |
| if (rtt_stats_) { |
| set_rtt_ms(rtt_stats_->LastProcessedRtt()); |
| } |
| } |
| |
| if (rtcp_sender_.TimeToSendRTCPReport()) { |
| RTCPSender::FeedbackState feedback_state(this); |
| rtcp_sender_.SendRTCP(feedback_state, kRtcpReport); |
| } |
| } |
| |
| if (UpdateRTCPReceiveInformationTimers()) { |
| // A receiver has timed out |
| rtcp_receiver_.UpdateTMMBR(); |
| } |
| return 0; |
| } |
| |
| int32_t ModuleRtpRtcpImpl::SetRTXSendStatus(int mode, bool set_ssrc, |
| uint32_t ssrc) { |
| rtp_sender_.SetRTXStatus(mode, set_ssrc, ssrc); |
| return 0; |
| } |
| |
| int32_t ModuleRtpRtcpImpl::RTXSendStatus(int* mode, uint32_t* ssrc, |
| int* payload_type) const { |
| rtp_sender_.RTXStatus(mode, ssrc, payload_type); |
| return 0; |
| } |
| |
| void ModuleRtpRtcpImpl::SetRtxSendPayloadType(int payload_type) { |
| rtp_sender_.SetRtxPayloadType(payload_type); |
| } |
| |
| 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_ is accessed when accessing child_modules_, so this write needs |
| // to be protected by the same lock. |
| CriticalSectionScoped lock(critical_section_module_ptrs_.get()); |
| simulcast_ = video_codec.numberOfSimulcastStreams > 1; |
| } |
| 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_sender_.SetSSRC(ssrc); |
| SetRtcpReceiverSsrcs(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); |
| |
| if (IsDefaultModule()) { |
| // 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 |
| RTCPSender::FeedbackState feedback_state(this); |
| if (rtcp_sender_.SetSendingStatus(feedback_state, 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_sender_.SetSSRC(SSRC); |
| SetRtcpReceiverSsrcs(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()"); |
| |
| if (!IsDefaultModule()) { |
| 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); |
| |
| if (!IsDefaultModule()) { |
| // Don't send RTCP from default module. |
| if (rtcp_sender_.TimeToSendRTCPReport(kVideoFrameKey == frame_type)) { |
| RTCPSender::FeedbackState feedback_state(this); |
| rtcp_sender_.SendRTCP(feedback_state, 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; |
| CriticalSectionScoped lock(critical_section_module_ptrs_.get()); |
| if (simulcast_) { |
| if (rtp_video_hdr == NULL) { |
| return -1; |
| } |
| int idx = 0; |
| 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 { |
| std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); |
| // Send to all "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; |
| } |
| |
| bool ModuleRtpRtcpImpl::TimeToSendPacket(uint32_t ssrc, |
| uint16_t sequence_number, |
| int64_t capture_time_ms, |
| bool retransmission) { |
| WEBRTC_TRACE( |
| kTraceStream, |
| kTraceRtpRtcp, |
| id_, |
| "TimeToSendPacket(ssrc:0x%x sequence_number:%u capture_time_ms:%ll)", |
| ssrc, sequence_number, capture_time_ms); |
| |
| if (!IsDefaultModule()) { |
| // Don't send from default module. |
| if (SendingMedia() && ssrc == rtp_sender_.SSRC()) { |
| return rtp_sender_.TimeToSendPacket(sequence_number, capture_time_ms, |
| retransmission); |
| } |
| } 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()) { |
| return (*it)->rtp_sender_.TimeToSendPacket(sequence_number, |
| capture_time_ms, |
| retransmission); |
| } |
| ++it; |
| } |
| } |
| // No RTP sender is interested in sending this packet. |
| return true; |
| } |
| |
| int ModuleRtpRtcpImpl::TimeToSendPadding(int bytes) { |
| WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_, "TimeToSendPadding(bytes: %d)", |
| bytes); |
| |
| if (!IsDefaultModule()) { |
| // Don't send from default module. |
| if (SendingMedia()) { |
| return rtp_sender_.TimeToSendPadding(bytes); |
| } |
| } else { |
| CriticalSectionScoped lock(critical_section_module_ptrs_.get()); |
| std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); |
| while (it != child_modules_.end()) { |
| // Send padding on one of the modules sending media. |
| if ((*it)->SendingMedia()) { |
| return (*it)->rtp_sender_.TimeToSendPadding(bytes); |
| } |
| ++it; |
| } |
| } |
| return 0; |
| } |
| |
| bool ModuleRtpRtcpImpl::GetSendSideDelay(int* avg_send_delay_ms, |
| int* max_send_delay_ms) const { |
| assert(avg_send_delay_ms); |
| assert(max_send_delay_ms); |
| |
| if (IsDefaultModule()) { |
| // This API is only supported for child modules. |
| return false; |
| } |
| return rtp_sender_.GetSendSideDelay(avg_send_delay_ms, max_send_delay_ms); |
| } |
| |
| 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; |
| |
| if (IsDefaultModule()) { |
| // 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); |
| } |
| |
| 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); |
| } |
| |
| // 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); |
| RTCPSender::FeedbackState feedback_state(this); |
| return rtcp_sender_.SendRTCP(feedback_state, 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); |
| } |
| |
| void ModuleRtpRtcpImpl::SetRtcpXrRrtrStatus(bool enable) { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, |
| "SetRtcpXrRrtrStatus(%s)", enable ? "true" : "false"); |
| return rtcp_sender_.SendRtcpXrReceiverReferenceTime(enable); |
| } |
| |
| bool ModuleRtpRtcpImpl::RtcpXrRrtrStatus() const { |
| return rtcp_sender_.RtcpXrReceiverReferenceTime(); |
| } |
| |
| int32_t ModuleRtpRtcpImpl::DataCountersRTP( |
| uint32_t* bytes_sent, |
| uint32_t* packets_sent) const { |
| WEBRTC_TRACE(kTraceStream, kTraceRtpRtcp, id_, "DataCountersRTP()"); |
| if (bytes_sent) { |
| *bytes_sent = rtp_sender_.Bytes(); |
| } |
| if (packets_sent) { |
| *packets_sent = rtp_sender_.Packets(); |
| } |
| return 0; |
| } |
| |
| 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_.AddExternalReportBlock(ssrc, report_block); |
| } |
| |
| int32_t ModuleRtpRtcpImpl::RemoveRTCPReportBlock( |
| const uint32_t ssrc) { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, "RemoveRTCPReportBlock()"); |
| return rtcp_sender_.RemoveExternalReportBlock(ssrc); |
| } |
| |
| void ModuleRtpRtcpImpl::GetRtcpPacketTypeCounters( |
| RtcpPacketTypeCounter* packets_sent, |
| RtcpPacketTypeCounter* packets_received) const { |
| rtcp_sender_.GetPacketTypeCounter(packets_sent); |
| rtcp_receiver_.GetPacketTypeCounter(packets_received); |
| } |
| |
| // (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); |
| } |
| |
| // 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); |
| |
| // Use RTT from RtcpRttStats class if provided. |
| uint16_t rtt = rtt_ms(); |
| if (rtt == 0) { |
| rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL); |
| } |
| |
| int64_t wait_time = 5 + ((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]; |
| |
| RTCPSender::FeedbackState feedback_state(this); |
| return rtcp_sender_.SendRTCP( |
| feedback_state, kRtcpNack, nackLength, &nack_list[start_id]); |
| } |
| |
| // 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. |
| } |
| |
| bool ModuleRtpRtcpImpl::StorePackets() const { |
| return rtp_sender_.StorePackets(); |
| } |
| |
| void ModuleRtpRtcpImpl::RegisterSendChannelRtcpStatisticsCallback( |
| RtcpStatisticsCallback* callback) { |
| rtcp_receiver_.RegisterRtcpStatisticsCallback(callback); |
| } |
| |
| RtcpStatisticsCallback* ModuleRtpRtcpImpl:: |
| GetSendChannelRtcpStatisticsCallback() { |
| return rtcp_receiver_.GetRtcpStatisticsCallback(); |
| } |
| |
| // 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::SendVideoCodec() const { |
| return rtp_sender_.VideoCodecType(); |
| } |
| |
| void ModuleRtpRtcpImpl::SetTargetSendBitrate( |
| const std::vector<uint32_t>& stream_bitrates) { |
| WEBRTC_TRACE(kTraceModuleCall, kTraceRtpRtcp, id_, |
| "SetTargetSendBitrate: %ld streams", stream_bitrates.size()); |
| if (IsDefaultModule()) { |
| CriticalSectionScoped lock(critical_section_module_ptrs_.get()); |
| if (simulcast_) { |
| std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); |
| for (size_t i = 0; |
| it != child_modules_.end() && i < stream_bitrates.size(); ++it) { |
| if ((*it)->SendingMedia()) { |
| RTPSender& rtp_sender = (*it)->rtp_sender_; |
| rtp_sender.SetTargetSendBitrate(stream_bitrates[i]); |
| ++i; |
| } |
| } |
| } else { |
| if (stream_bitrates.size() > 1) |
| return; |
| std::list<ModuleRtpRtcpImpl*>::iterator it = child_modules_.begin(); |
| for (; it != child_modules_.end(); ++it) { |
| RTPSender& rtp_sender = (*it)->rtp_sender_; |
| rtp_sender.SetTargetSendBitrate(stream_bitrates[0]); |
| } |
| } |
| } else { |
| if (stream_bitrates.size() > 1) |
| return; |
| rtp_sender_.SetTargetSendBitrate(stream_bitrates[0]); |
| } |
| } |
| |
| 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 SendRTCP(kRtcpPli); |
| case kKeyFrameReqFirRtcp: |
| return SendRTCP(kRtcpFir); |
| } |
| return -1; |
| } |
| |
| int32_t ModuleRtpRtcpImpl::SendRTCPSliceLossIndication( |
| const uint8_t picture_id) { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| id_, |
| "SendRTCPSliceLossIndication (picture_id:%d)", |
| picture_id); |
| RTCPSender::FeedbackState feedback_state(this); |
| return rtcp_sender_.SendRTCP( |
| feedback_state, kRtcpSli, 0, 0, false, picture_id); |
| } |
| |
| int32_t ModuleRtpRtcpImpl::SetCameraDelay(const int32_t delay_ms) { |
| WEBRTC_TRACE(kTraceModuleCall, |
| kTraceRtpRtcp, |
| id_, |
| "SetCameraDelay(%d)", |
| delay_ms); |
| if (IsDefaultModule()) { |
| 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; |
| if (IsDefaultModule()) { |
| // 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) { |
| if (IsDefaultModule()) { |
| // 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. |
| SendRTCP(kRtcpBye); |
| } |
| // Change local SSRC and inform all objects about the new SSRC. |
| rtcp_sender_.SetSSRC(new_ssrc); |
| SetRtcpReceiverSsrcs(new_ssrc); |
| } |
| } |
| |
| void ModuleRtpRtcpImpl::BitrateSent(uint32_t* total_rate, |
| uint32_t* video_rate, |
| uint32_t* fec_rate, |
| uint32_t* nack_rate) const { |
| if (IsDefaultModule()) { |
| // 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_.BitrateSent(); |
| 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(); |
| } |
| |
| void ModuleRtpRtcpImpl::RegisterVideoBitrateObserver( |
| BitrateStatisticsObserver* observer) { |
| assert(!IsDefaultModule()); |
| rtp_sender_.RegisterBitrateObserver(observer); |
| } |
| |
| BitrateStatisticsObserver* ModuleRtpRtcpImpl::GetVideoBitrateObserver() const { |
| return rtp_sender_.GetBitrateObserver(); |
| } |
| |
| void ModuleRtpRtcpImpl::OnRequestIntraFrame() { |
| RequestKeyFrame(); |
| } |
| |
| void ModuleRtpRtcpImpl::OnRequestSendReport() { |
| SendRTCP(kRtcpSr); |
| } |
| |
| int32_t ModuleRtpRtcpImpl::SendRTCPReferencePictureSelection( |
| const uint64_t picture_id) { |
| RTCPSender::FeedbackState feedback_state(this); |
| return rtcp_sender_.SendRTCP( |
| feedback_state, kRtcpRpsi, 0, 0, false, picture_id); |
| } |
| |
| uint32_t ModuleRtpRtcpImpl::SendTimeOfSendReport( |
| const uint32_t send_report) { |
| return rtcp_sender_.SendTimeOfSendReport(send_report); |
| } |
| |
| bool ModuleRtpRtcpImpl::SendTimeOfXrRrReport( |
| uint32_t mid_ntp, int64_t* time_ms) const { |
| return rtcp_sender_.SendTimeOfXrRrReport(mid_ntp, time_ms); |
| } |
| |
| void ModuleRtpRtcpImpl::OnReceivedNACK( |
| const std::list<uint16_t>& nack_sequence_numbers) { |
| if (!rtp_sender_.StorePackets() || |
| nack_sequence_numbers.size() == 0) { |
| return; |
| } |
| // Use RTT from RtcpRttStats class if provided. |
| uint16_t rtt = rtt_ms(); |
| if (rtt == 0) { |
| rtcp_receiver_.RTT(rtcp_receiver_.RemoteSSRC(), NULL, &rtt, NULL, NULL); |
| } |
| rtp_sender_.OnReceivedNACK(nack_sequence_numbers, 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::LastReceivedXrReferenceTimeInfo( |
| RtcpReceiveTimeInfo* info) const { |
| return rtcp_receiver_.LastReceivedXrReferenceTimeInfo(info); |
| } |
| |
| 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; |
| } |
| |
| void ModuleRtpRtcpImpl::SetRtcpReceiverSsrcs(uint32_t main_ssrc) { |
| std::set<uint32_t> ssrcs; |
| ssrcs.insert(main_ssrc); |
| int rtx_mode = kRtxOff; |
| uint32_t rtx_ssrc = 0; |
| int rtx_payload_type = 0; |
| rtp_sender_.RTXStatus(&rtx_mode, &rtx_ssrc, &rtx_payload_type); |
| if (rtx_mode != kRtxOff) |
| ssrcs.insert(rtx_ssrc); |
| rtcp_receiver_.SetSsrcs(main_ssrc, ssrcs); |
| } |
| |
| void ModuleRtpRtcpImpl::set_rtt_ms(uint32_t rtt_ms) { |
| CriticalSectionScoped cs(critical_section_rtt_.get()); |
| rtt_ms_ = rtt_ms; |
| } |
| |
| uint32_t ModuleRtpRtcpImpl::rtt_ms() const { |
| CriticalSectionScoped cs(critical_section_rtt_.get()); |
| return rtt_ms_; |
| } |
| |
| void ModuleRtpRtcpImpl::RegisterSendChannelRtpStatisticsCallback( |
| StreamDataCountersCallback* callback) { |
| rtp_sender_.RegisterRtpStatisticsCallback(callback); |
| } |
| |
| StreamDataCountersCallback* |
| ModuleRtpRtcpImpl::GetSendChannelRtpStatisticsCallback() const { |
| return rtp_sender_.GetRtpStatisticsCallback(); |
| } |
| |
| void ModuleRtpRtcpImpl::RegisterSendFrameCountObserver( |
| FrameCountObserver* observer) { |
| rtp_sender_.RegisterFrameCountObserver(observer); |
| } |
| |
| FrameCountObserver* ModuleRtpRtcpImpl::GetSendFrameCountObserver() const { |
| return rtp_sender_.GetFrameCountObserver(); |
| } |
| |
| bool ModuleRtpRtcpImpl::IsDefaultModule() const { |
| CriticalSectionScoped cs(critical_section_module_ptrs_.get()); |
| return !child_modules_.empty(); |
| } |
| |
| } // Namespace webrtc |