void RtcpRrGenerator::handleSr(std::shared_ptr<dataPacket> packet) { RtcpHeader* chead = reinterpret_cast<RtcpHeader*>(packet->data); if (ssrc_ != chead->getSSRC()) { ELOG_DEBUG("message: handleRtpPacket ssrc not found, ssrc: %u", chead->getSSRC()); return; } rr_info_.last_sr_mid_ntp = chead->get32MiddleNtp(); rr_info_.last_sr_ts = packet->received_time_ms; }
void RRGenerationHandler::handleSR(std::shared_ptr<dataPacket> packet) { RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data); auto rr_packet_pair = rr_info_map_.find(chead->getSSRC()); if (rr_packet_pair == rr_info_map_.end()) { ELOG_DEBUG("%s message: handleRtpPacket ssrc not found, ssrc: %u", connection_->toLog(), chead->getSSRC()); return; } std::shared_ptr<RRPackets> selected_packet_info = rr_packet_pair->second; selected_packet_info->last_sr_mid_ntp = chead->get32MiddleNtp(); selected_packet_info->last_sr_ts = packet->received_time_ms; uint32_t expected = selected_packet_info->extended_seq - selected_packet_info->base_seq + 1; selected_packet_info->lost = expected - selected_packet_info->packets_received; uint8_t fraction = 0; uint32_t expected_interval = expected - selected_packet_info->expected_prior; selected_packet_info->expected_prior = expected; uint32_t received_interval = selected_packet_info->packets_received - selected_packet_info->received_prior; selected_packet_info->received_prior = selected_packet_info->packets_received; uint32_t lost_interval = expected_interval - received_interval; if (expected_interval != 0 && lost_interval > 0) { fraction = (lost_interval << 8) / expected_interval; } selected_packet_info->frac_lost = fraction; if (!use_timing_) { sendRR(selected_packet_info); } }
void WebRtcConnection::writeSsrc(char* buf, int len, unsigned int ssrc) { ELOG_DEBUG("LEN %d", len); RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); //if it is RTCP we check it it is a compound packet if (chead->isRtcp()) { char* movingBuf = buf; int rtcpLength = 0; int totalLength = 0; do{ movingBuf+=rtcpLength; RtcpHeader *chead= reinterpret_cast<RtcpHeader*>(movingBuf); rtcpLength= (ntohs(chead->length)+1)*4; totalLength+= rtcpLength; ELOG_DEBUG("Is RTCP, prev SSRC %u, new %u, len %d ", chead->getSSRC(), ssrc, rtcpLength); chead->ssrc=htonl(ssrc); if (chead->packettype == RTCP_PS_Feedback_PT){ FirHeader *thefir = reinterpret_cast<FirHeader*>(movingBuf); if (thefir->fmt == 4){ // It is a FIR Packet, we generate it this->sendPLI(); } } } while(totalLength<len); } else { head->setSSRC(ssrc); } }
void SenderBandwidthEstimationHandler::write(Context *ctx, std::shared_ptr<dataPacket> packet) { RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data); if (!chead->isRtcp() && packet->type == VIDEO_PACKET) { period_packets_sent_++; } else if (chead->getPacketType() == RTCP_Sender_PT && chead->getSSRC() == connection_->getVideoSinkSSRC()) { analyzeSr(chead); } ctx->fireWrite(packet); }
void MediaStream::read(std::shared_ptr<DataPacket> packet) { char* buf = packet->data; int len = packet->length; // PROCESS RTCP RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); uint32_t recvSSRC = 0; if (!chead->isRtcp()) { recvSSRC = head->getSSRC(); } else if (chead->packettype == RTCP_Sender_PT) { // Sender Report recvSSRC = chead->getSSRC(); } // DELIVER FEEDBACK (RR, FEEDBACK PACKETS) if (chead->isFeedback()) { if (fb_sink_ != nullptr && should_send_feedback_) { fb_sink_->deliverFeedback(std::move(packet)); } } else { // RTP or RTCP Sender Report if (bundle_) { // Check incoming SSRC // Deliver data if (isVideoSourceSSRC(recvSSRC)) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); video_sink_->deliverVideoData(std::move(packet)); } else if (isAudioSourceSSRC(recvSSRC)) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); audio_sink_->deliverAudioData(std::move(packet)); } else { ELOG_DEBUG("%s read video unknownSSRC: %u, localVideoSSRC: %u, localAudioSSRC: %u", toLog(), recvSSRC, this->getVideoSourceSSRC(), this->getAudioSourceSSRC()); } } else { if (packet->type == AUDIO_PACKET && audio_sink_ != nullptr) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); // Firefox does not send SSRC in SDP if (getAudioSourceSSRC() == 0) { ELOG_DEBUG("%s discoveredAudioSourceSSRC:%u", toLog(), recvSSRC); this->setAudioSourceSSRC(recvSSRC); } audio_sink_->deliverAudioData(std::move(packet)); } else if (packet->type == VIDEO_PACKET && video_sink_ != nullptr) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); // Firefox does not send SSRC in SDP if (getVideoSourceSSRC() == 0) { ELOG_DEBUG("%s discoveredVideoSourceSSRC:%u", toLog(), recvSSRC); this->setVideoSourceSSRC(recvSSRC); } // change ssrc for RTP packets, don't touch here if RTCP video_sink_->deliverVideoData(std::move(packet)); } } // if not bundle } // if not Feedback }
void SRPacketHandler::handleSR(std::shared_ptr<dataPacket> packet) { RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data); uint32_t ssrc = chead->getSSRC(); auto sr_selected_info_iter = sr_info_map_.find(ssrc); if (sr_selected_info_iter == sr_info_map_.end()) { ELOG_DEBUG("message: handleSR no info for this SSRC, ssrc: %u", ssrc); return; } std::shared_ptr<SRInfo> selected_info = sr_selected_info_iter->second; ELOG_DEBUG("message: Rewriting SR, ssrc: %u, octets_sent_before: %u, packets_sent_before: %u" " octets_sent_after %u packets_sent_after: %u", ssrc, chead->getOctetsSent(), chead->getPacketsSent(), selected_info->sent_octets, selected_info->sent_packets); chead->setOctetsSent(selected_info->sent_octets); chead->setPacketsSent(selected_info->sent_packets); }
void RtcpFeedbackGenerationHandler::read(Context *ctx, std::shared_ptr<DataPacket> packet) { // Pass packets to RR and NACK Generator RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data); if (!initialized_) { ctx->fireRead(std::move(packet)); return; } if (chead->getPacketType() == RTCP_Sender_PT) { uint32_t ssrc = chead->getSSRC(); auto generator_it = generators_map_.find(ssrc); if (generator_it != generators_map_.end()) { generator_it->second->rr_generator->handleSr(packet); } else { ELOG_DEBUG("message: no RrGenerator found, ssrc: %u", ssrc); } ctx->fireRead(std::move(packet)); return; } bool should_send_rr = false; bool should_send_nack = false; if (!chead->isRtcp()) { RtpHeader *head = reinterpret_cast<RtpHeader*>(packet->data); uint32_t ssrc = head->getSSRC(); auto generator_it = generators_map_.find(ssrc); if (generator_it != generators_map_.end()) { should_send_rr = generator_it->second->rr_generator->handleRtpPacket(packet); if (nacks_enabled_) { should_send_nack = generator_it->second->nack_generator->handleRtpPacket(packet); } } else { ELOG_DEBUG("message: no Generator found, ssrc: %u", ssrc); } if (should_send_rr || should_send_nack) { ELOG_DEBUG("message: Should send Rtcp, ssrc %u", ssrc); std::shared_ptr<DataPacket> rtcp_packet = generator_it->second->rr_generator->generateReceiverReport(); if (nacks_enabled_ && generator_it->second->nack_generator != nullptr) { generator_it->second->nack_generator->addNackPacketToRr(rtcp_packet); } ctx->fireWrite(std::move(rtcp_packet)); } } ctx->fireRead(std::move(packet)); }
int RtcpForwarder::analyzeFeedback(char *buf, int len) { RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(buf); if (chead->isFeedback()) { uint32_t sourceSsrc = chead->getSourceSSRC(); // We try to add it just in case it is not there yet (otherwise its noop) this->addSourceSsrc(sourceSsrc); struct timeval now; gettimeofday(&now, NULL); char* movingBuf = buf; int rtcpLength = 0; int totalLength = 0; int currentBlock = 0; do { movingBuf+=rtcpLength; chead = reinterpret_cast<RtcpHeader*>(movingBuf); rtcpLength = (ntohs(chead->length)+1) * 4; totalLength += rtcpLength; switch(chead->packettype){ case RTCP_SDES_PT: ELOG_DEBUG("SDES"); break; case RTCP_BYE: ELOG_DEBUG("BYE"); break; case RTCP_Receiver_PT: if (chead->getSourceSSRC() == rtcpSource_->getVideoSourceSSRC()){ ELOG_DEBUG("Analyzing Video RR: PacketLost %u, Ratio %u, currentBlock %d, blocks %d, sourceSSRC %u, ssrc %u changed to %u", chead->getLostPackets(), chead->getFractionLost(), currentBlock, chead->getBlockCount(), chead->getSourceSSRC(), chead->getSSRC(), rtcpSink_->getVideoSinkSSRC()); chead->setSSRC(rtcpSink_->getVideoSinkSSRC()); }else{ ELOG_DEBUG("Analyzing Audio RR: PacketLost %u, Ratio %u, currentBlock %d, blocks %d, sourceSSRC %u, ssrc %u changed to %u", chead->getLostPackets(), chead->getFractionLost(), currentBlock, chead->getBlockCount(), chead->getSourceSSRC(), chead->getSSRC(), rtcpSink_->getAudioSinkSSRC()); chead->setSSRC(rtcpSink_->getAudioSinkSSRC()); } break; case RTCP_RTP_Feedback_PT: ELOG_DEBUG("RTP FB: Usually NACKs: %u, currentBlock %d", chead->getBlockCount(), currentBlock); ELOG_DEBUG("NACK PID %u BLP %u", chead->getNackPid(), chead->getNackBlp()); // We analyze NACK to avoid sending repeated NACKs break; case RTCP_PS_Feedback_PT: // ELOG_DEBUG("RTCP PS FB TYPE: %u", chead->getBlockCount() ); switch(chead->getBlockCount()){ case RTCP_PLI_FMT: ELOG_DEBUG("PLI Message, currentBlock %d", currentBlock); // 1: PLI, 4: FIR break; case RTCP_SLI_FMT: ELOG_WARN("SLI Message"); break; case RTCP_FIR_FMT: ELOG_WARN("FIR Message"); break; case RTCP_AFB: { char *uniqueId = (char*)&chead->report.rembPacket.uniqueid; if (!strncmp(uniqueId,"REMB", 4)){ uint64_t bitrate = chead->getBrMantis() << chead->getBrExp(); uint64_t cappedBitrate = 0; cappedBitrate = bitrate < maxVideoBw_? bitrate: maxVideoBw_; if (bitrate < maxVideoBw_){ cappedBitrate = bitrate; }else{ cappedBitrate = maxVideoBw_; } ELOG_DEBUG("Received REMB %lu, partnum %u, cappedBitrate %lu", bitrate, currentBlock, cappedBitrate); chead->setREMBBitRate(cappedBitrate); } else{ ELOG_WARN("Unsupported AFB Packet not REMB") } break; } default: ELOG_WARN("Unsupported RTCP_PS FB TYPE %u",chead->getBlockCount()); break; } break; default: ELOG_WARN("Unknown RTCP Packet, %d", chead->packettype); break; } currentBlock++; } while (totalLength < len); return len; }
void SenderBandwidthEstimationHandler::read(Context *ctx, std::shared_ptr<dataPacket> packet) { RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(packet->data); if (chead->isFeedback() && chead->getSourceSSRC() == connection_->getVideoSinkSSRC()) { char* packet_pointer = packet->data; int rtcp_length = 0; int total_length = 0; int current_block = 0; do { packet_pointer+=rtcp_length; chead = reinterpret_cast<RtcpHeader*>(packet_pointer); rtcp_length = (ntohs(chead->length) + 1) * 4; total_length += rtcp_length; ELOG_DEBUG("%s ssrc %u, sourceSSRC %u, PacketType %u", connection_->toLog(), chead->getSSRC(), chead->getSourceSSRC(), chead->getPacketType()); switch (chead->packettype) { case RTCP_Receiver_PT: { ELOG_DEBUG("%s, Analyzing Video RR: PacketLost %u, Ratio %u, current_block %d, blocks %d" ", sourceSSRC %u, ssrc %u", connection_->toLog(), chead->getLostPackets(), chead->getFractionLost(), current_block, chead->getBlockCount(), chead->getSourceSSRC(), chead->getSSRC()); // calculate RTT + Update receiver block uint32_t delay_since_last_ms = (chead->getDelaySinceLastSr() * 1000) / 65536; int64_t now_ms = ClockUtils::timePointToMs(clock::now()); uint32_t last_sr = chead->getLastSr(); auto value = std::find_if(sr_delay_data_.begin(), sr_delay_data_.end(), [last_sr](const std::shared_ptr<SrDelayData> sr_info) { return sr_info->sr_ntp == last_sr; }); if (value != sr_delay_data_.end()) { uint32_t delay = now_ms - (*value)->sr_send_time - delay_since_last_ms; sender_bwe_->UpdateReceiverBlock(chead->getFractionLost(), delay, period_packets_sent_, now_ms); period_packets_sent_ = 0; updateEstimate(); } } break; case RTCP_PS_Feedback_PT: { if (chead->getBlockCount() == RTCP_AFB) { char *uniqueId = reinterpret_cast<char*>(&chead->report.rembPacket.uniqueid); if (!strncmp(uniqueId, "REMB", 4)) { int64_t now_ms = ClockUtils::timePointToMs(clock::now()); uint64_t bitrate = chead->getBrMantis() << chead->getBrExp(); ELOG_DEBUG("%s message: Updating Estimate with REMB, bitrate %llu", connection_->toLog(), bitrate); sender_bwe_->UpdateReceiverEstimate(now_ms, bitrate); sender_bwe_->UpdateEstimate(now_ms); updateEstimate(); } else { ELOG_DEBUG("%s message: Unsupported AFB Packet not REMB", connection_->toLog()); } } } break; default: break; } current_block++; } while (total_length < packet->length); } ctx->fireRead(packet); }
void WebRtcConnection::onTransportData(char* buf, int len, Transport *transport) { if (audioSink_ == NULL && videoSink_ == NULL && fbSink_==NULL){ return; } // PROCESS STATS if (this->statsListener_){ // if there is no listener we dont process stats RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); if (head->payloadtype != RED_90000_PT && head->payloadtype != PCMU_8000_PT) thisStats_.processRtcpPacket(buf, len); } RtcpHeader* chead = reinterpret_cast<RtcpHeader*>(buf); // DELIVER FEEDBACK (RR, FEEDBACK PACKETS) if (chead->isFeedback()){ if (fbSink_ != NULL) { fbSink_->deliverFeedback(buf,len); } } else { // RTP or RTCP Sender Report if (bundle_) { // Check incoming SSRC RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); unsigned int recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); }else{ recvSSRC = head->getSSRC(); } // Deliver data if (recvSSRC==this->getVideoSourceSSRC() || recvSSRC==this->getVideoSinkSSRC()) { videoSink_->deliverVideoData(buf, len); } else if (recvSSRC==this->getAudioSourceSSRC() || recvSSRC==this->getAudioSinkSSRC()) { audioSink_->deliverAudioData(buf, len); } else { ELOG_ERROR("Unknown SSRC %u, localVideo %u, remoteVideo %u, ignoring", recvSSRC, this->getVideoSourceSSRC(), this->getVideoSinkSSRC()); } } else if (transport->mediaType == AUDIO_TYPE) { if (audioSink_ != NULL) { RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getAudioSourceSSRC() == 0) { ELOG_DEBUG("Audio Source SSRC is %u", head->getSSRC()); this->setAudioSourceSSRC(head->getSSRC()); //this->updateState(TRANSPORT_READY, transport); } head->setSSRC(this->getAudioSinkSSRC()); audioSink_->deliverAudioData(buf, len); } } else if (transport->mediaType == VIDEO_TYPE) { if (videoSink_ != NULL) { RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getVideoSourceSSRC() == 0) { unsigned int recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); } else { recvSSRC = head->getSSRC(); } ELOG_DEBUG("Video Source SSRC is %u", recvSSRC); this->setVideoSourceSSRC(recvSSRC); //this->updateState(TRANSPORT_READY, transport); } // change ssrc for RTP packets, don't touch here if RTCP if (chead->packettype != RTCP_Sender_PT) { head->setSSRC(this->getVideoSinkSSRC()); } videoSink_->deliverVideoData(buf, len); } } } }
void RtcpProcessor::analyzeFeedback(char *buf, int len) { RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(buf); if (chead->isFeedback()) { uint32_t sourceSsrc = chead->getSourceSSRC(); // We try to add it just in case it is not there yet (otherwise its noop) this->addSourceSsrc(sourceSsrc); boost::mutex::scoped_lock mlock(mapLock_); boost::shared_ptr<RtcpData> theData = rtcpData_[sourceSsrc]; boost::mutex::scoped_lock lock(theData->dataLock); struct timeval now; gettimeofday(&now, NULL); char* movingBuf = buf; int rtcpLength = 0; int totalLength = 0; int partNum = 0; uint32_t calculatedlsr, delay, calculateLastSr; do { movingBuf+=rtcpLength; chead = reinterpret_cast<RtcpHeader*>(movingBuf); rtcpLength = (ntohs(chead->length)+1) * 4; totalLength += rtcpLength; switch(chead->packettype){ case RTCP_SDES_PT: ELOG_DEBUG("SDES"); break; case RTCP_BYE: ELOG_DEBUG("BYE"); break; case RTCP_Receiver_PT: theData->rrsReceivedInPeriod++; if (chead->getSourceSSRC() == rtcpSource_->getVideoSourceSSRC()){ ELOG_DEBUG("Analyzing Video RR: PacketLost %u, Ratio %u, partNum %d, blocks %d, sourceSSRC %u, ssrc %u", chead->getLostPackets(), chead->getFractionLost(), partNum, chead->getBlockCount(), chead->getSourceSSRC(), chead->getSSRC()); }else{ ELOG_DEBUG("Analyzing Audio RR: PacketLost %u, Ratio %u, partNum %d, blocks %d, sourceSSRC %u, ssrc %u", chead->getLostPackets(), chead->getFractionLost(), partNum, chead->getBlockCount(), chead->getSourceSSRC(), chead->getSSRC()); } theData->ratioLost = theData->ratioLost > chead->getFractionLost()? theData->ratioLost: chead->getFractionLost(); theData->totalPacketsLost = theData->totalPacketsLost > chead->getLostPackets()? theData->totalPacketsLost : chead->getLostPackets(); theData->highestSeqNumReceived = theData->highestSeqNumReceived > chead->getHighestSeqnum()? theData->highestSeqNumReceived : chead->getHighestSeqnum(); theData->seqNumCycles = theData->seqNumCycles > chead->getSeqnumCycles()? theData->seqNumCycles : chead->getSeqnumCycles(); theData->jitter = theData->jitter > chead->getJitter()? theData->jitter: chead->getJitter(); calculateLastSr = chead->getLastSr(); calculatedlsr = (chead->getDelaySinceLastSr()*1000)/65536; for (std::list<boost::shared_ptr<SrData>>::iterator it=theData->senderReports.begin(); it != theData->senderReports.end(); ++it){ if ((*it)->srNtp == calculateLastSr){ uint64_t nowms = (now.tv_sec * 1000) + (now.tv_usec / 1000); uint64_t sentts = ((*it)->timestamp.tv_sec * 1000) + ((*it)->timestamp.tv_usec / 1000); delay = nowms - sentts - calculatedlsr; } } if (theData->lastSr==0||theData->lastDelay < delay){ ELOG_DEBUG("Recording DLSR %u, lastSR %u last delay %u, calculated delay %u for SSRC %u", chead->getDelaySinceLastSr(), chead->getLastSr(), theData->lastDelay, delay, sourceSsrc); theData->lastSr = chead->getLastSr(); theData->delaySinceLastSr = chead->getDelaySinceLastSr(); theData->lastSrUpdated = now; theData->lastDelay = delay; }else{ // ELOG_DEBUG("Not recording delay %u, lastDelay %u", delay, theData->lastDelay); } break; case RTCP_RTP_Feedback_PT: ELOG_DEBUG("RTP FB: Usually NACKs: %u, partNum %d", chead->getBlockCount(), partNum); ELOG_DEBUG("PID %u BLP %u", chead->getNackPid(), chead->getNackBlp()); theData->shouldSendNACK = true; theData->nackSeqnum = chead->getNackPid(); theData->nackBlp = chead->getNackBlp(); theData->requestRr = true; break; case RTCP_PS_Feedback_PT: // ELOG_DEBUG("RTCP PS FB TYPE: %u", chead->getBlockCount() ); switch(chead->getBlockCount()){ case RTCP_PLI_FMT: ELOG_DEBUG("PLI Message, partNum %d", partNum); // 1: PLI, 4: FIR theData->shouldSendPli = true; break; case RTCP_SLI_FMT: ELOG_DEBUG("SLI Message"); break; case RTCP_FIR_FMT: ELOG_DEBUG("FIR Message"); break; case RTCP_AFB: { char *uniqueId = (char*)&chead->report.rembPacket.uniqueid; if (!strncmp(uniqueId,"REMB", 4)){ uint64_t bitrate = chead->getBrMantis() << chead->getBrExp(); ELOG_DEBUG("Received REMBO %lu", bitrate); if ((bitrate < theData->reportedBandwidth) || theData->reportedBandwidth==0){ ELOG_DEBUG("Should send Packet REMB, before BR %lu, will send with Br %lu", theData->reportedBandwidth, bitrate); theData->reportedBandwidth = bitrate; theData->shouldSendREMB = true; } } else{ ELOG_DEBUG("Unsupported AFB Packet not REMB") } break; } default: ELOG_WARN("Unsupported RTCP_PS FB TYPE %u",chead->getBlockCount()); break; } break; default: ELOG_DEBUG("Unknown RTCP Packet, %d", chead->packettype); break; } partNum++; } while (totalLength < len); }
int RtcpAggregator::analyzeFeedback(char *buf, int len) { RtcpHeader *chead = reinterpret_cast<RtcpHeader*>(buf); if (chead->isFeedback()) { if (chead->getBlockCount() == 0 && (chead->getLength()+1) * 4 == len) { ELOG_DEBUG("Ignoring empty RR"); return 0; } uint32_t sourceSsrc = chead->getSourceSSRC(); // We try to add it just in case it is not there yet (otherwise its noop) this->addSourceSsrc(sourceSsrc); boost::mutex::scoped_lock mlock(mapLock_); boost::shared_ptr<RtcpData> theData = rtcpData_[sourceSsrc]; boost::mutex::scoped_lock lock(theData->dataLock); uint64_t nowms = ClockUtils::timePointToMs(clock::now()); char* movingBuf = buf; int rtcpLength = 0; int totalLength = 0; int partNum = 0; uint16_t currentNackPos = 0; uint16_t blp = 0; uint32_t lostPacketSeq = 0; uint32_t delay = 0; uint32_t calculatedlsr, calculateLastSr, extendedSeqNo; do { movingBuf += rtcpLength; chead = reinterpret_cast<RtcpHeader*>(movingBuf); rtcpLength = (ntohs(chead->length) + 1) * 4; totalLength += rtcpLength; switch (chead->packettype) { case RTCP_SDES_PT: ELOG_DEBUG("SDES"); break; case RTCP_BYE: ELOG_DEBUG("BYE"); break; case RTCP_Receiver_PT: theData->rrsReceivedInPeriod++; if (rtcpSource_->isVideoSourceSSRC(chead->getSourceSSRC())) { ELOG_DEBUG("Analyzing Video RR: PacketLost %u, Ratio %u, partNum %d, blocks %d, sourceSSRC %u, ssrc %u", chead->getLostPackets(), chead->getFractionLost(), partNum, chead->getBlockCount(), chead->getSourceSSRC(), chead->getSSRC()); } else { ELOG_DEBUG("Analyzing Audio RR: PacketLost %u, Ratio %u, partNum %d, blocks %d, sourceSSRC %u, ssrc %u", chead->getLostPackets(), chead->getFractionLost(), partNum, chead->getBlockCount(), chead->getSourceSSRC(), chead->getSSRC()); } theData->ratioLost = theData->ratioLost > chead->getFractionLost() ? theData->ratioLost : chead->getFractionLost(); theData->totalPacketsLost = theData->totalPacketsLost > chead->getLostPackets() ? theData->totalPacketsLost : chead->getLostPackets(); extendedSeqNo = chead->getSeqnumCycles(); extendedSeqNo = (extendedSeqNo << 16) + chead->getHighestSeqnum(); if (extendedSeqNo > theData->extendedSeqNo) { theData->extendedSeqNo = extendedSeqNo; theData->highestSeqNumReceived = chead->getHighestSeqnum(); theData->seqNumCycles = chead->getSeqnumCycles(); } theData->jitter = theData->jitter > chead->getJitter()? theData->jitter: chead->getJitter(); calculateLastSr = chead->getLastSr(); calculatedlsr = (chead->getDelaySinceLastSr() * 1000) / 65536; for (std::list<boost::shared_ptr<SrDelayData>>::iterator it = theData->senderReports.begin(); it != theData->senderReports.end(); ++it) { if ((*it)->sr_ntp == calculateLastSr) { uint64_t sentts = (*it)->sr_send_time; delay = nowms - sentts - calculatedlsr; } } if (theData->lastSr == 0 || theData->lastDelay < delay) { ELOG_DEBUG("Recording DLSR %u, lastSR %u last delay %u, calculated delay %u for SSRC %u", chead->getDelaySinceLastSr(), chead->getLastSr(), theData->lastDelay, delay, sourceSsrc); theData->lastSr = chead->getLastSr(); theData->delaySinceLastSr = chead->getDelaySinceLastSr(); theData->last_sr_updated = nowms; theData->lastDelay = delay; } else { // ELOG_DEBUG("Not recording delay %u, lastDelay %u", delay, theData->lastDelay); } break; case RTCP_RTP_Feedback_PT: { ELOG_DEBUG("RTP FB: Usually NACKs: %u, partNum %d", chead->getBlockCount(), partNum); ELOG_DEBUG("NACK PID %u BLP %u", chead->getNackPid(), chead->getNackBlp()); // We analyze NACK to avoid sending repeated NACKs blp = chead->getNackBlp(); theData->shouldSendNACK = false; std::pair<std::set<uint32_t>::iterator, bool> ret; ret = theData->nackedPackets_.insert(chead->getNackPid()); if (ret.second) { ELOG_DEBUG("We received PID NACK for unacked packet %u", chead->getNackPid()); theData->shouldSendNACK = true; } else { if (theData->nackedPackets_.size() >= MAP_NACK_SIZE) { while (theData->nackedPackets_.size() >= MAP_NACK_SIZE) { theData->nackedPackets_.erase(theData->nackedPackets_.begin()); } } ELOG_DEBUG("We received PID NACK for ALREADY acked packet %u", chead->getNackPid()); } if (blp != 0) { for (int i = 0; i < 16; i++) { currentNackPos = blp & 0x0001; blp = blp >> 1; if (currentNackPos == 1) { lostPacketSeq = chead->getNackPid() + 1 + i; ret = theData->nackedPackets_.insert(lostPacketSeq); if (ret.second) { ELOG_DEBUG("We received NACK for unacked packet %u", lostPacketSeq); } else { ELOG_DEBUG("We received NACK for ALREADY acked packet %u", lostPacketSeq); } theData->shouldSendNACK |=ret.second; } } } if (theData->shouldSendNACK) { ELOG_DEBUG("Will send NACK"); theData->nackSeqnum = chead->getNackPid(); theData->nackBlp = chead->getNackBlp(); theData->requestRr = true; } else { ELOG_DEBUG("I'm ignoring a NACK"); } } break; case RTCP_PS_Feedback_PT: // ELOG_DEBUG("RTCP PS FB TYPE: %u", chead->getBlockCount() ); switch (chead->getBlockCount()) { case RTCP_PLI_FMT: ELOG_DEBUG("PLI Message, partNum %d", partNum); // 1: PLI, 4: FIR theData->shouldSendPli = true; break; case RTCP_SLI_FMT: ELOG_DEBUG("SLI Message"); break; case RTCP_FIR_FMT: ELOG_DEBUG("FIR Message"); break; case RTCP_AFB: { char *uniqueId = reinterpret_cast<char*>(&chead->report.rembPacket.uniqueid); if (!strncmp(uniqueId, "REMB", 4)) { uint64_t bitrate = chead->getBrMantis() << chead->getBrExp(); ELOG_DEBUG("Received REMB %lu", bitrate); if (bitrate < defaultVideoBw_) { theData->reportedBandwidth = bitrate; theData->shouldSendREMB = true; } else { theData->reportedBandwidth = defaultVideoBw_; } } else { ELOG_DEBUG("Unsupported AFB Packet not REMB") } break; } default: ELOG_WARN("Unsupported RTCP_PS FB TYPE %u", chead->getBlockCount()); break; } break; default: ELOG_DEBUG("Unknown RTCP Packet, %d", chead->packettype); break; } partNum++; } while (totalLength < len); } return 0; }
void WebRtcConnection::onTransportData(char* buf, int len, Transport *transport) { if (audioSink_ == NULL && videoSink_ == NULL && fbSink_==NULL){ return; } // PROCESS RTCP RtcpHeader* chead = reinterpret_cast<RtcpHeader*>(buf); if (chead->isRtcp()) { thisStats_.processRtcpPacket(buf, len); if (chead->packettype == RTCP_Sender_PT) { //Sender Report rtcpProcessor_->analyzeSr(chead); } } // DELIVER FEEDBACK (RR, FEEDBACK PACKETS) if (chead->isFeedback()){ if (fbSink_ != NULL && shouldSendFeedback_) { fbSink_->deliverFeedback(buf,len); } } else { // RTP or RTCP Sender Report if (bundle_) { // Check incoming SSRC RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); uint32_t recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); }else{ recvSSRC = head->getSSRC(); } // Deliver data if (recvSSRC==this->getVideoSourceSSRC()) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); videoSink_->deliverVideoData(buf, len); } else if (recvSSRC==this->getAudioSourceSSRC()) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); audioSink_->deliverAudioData(buf, len); } else { ELOG_ERROR("Unknown SSRC %u, localVideo %u, remoteVideo %u, ignoring", recvSSRC, this->getVideoSourceSSRC(), this->getVideoSinkSSRC()); } } else if (transport->mediaType == AUDIO_TYPE) { if (audioSink_ != NULL) { parseIncomingPayloadType(buf, len, AUDIO_PACKET); RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getAudioSourceSSRC() == 0) { unsigned int recvSSRC; this->setAudioSourceSSRC(head->getSSRC()); if (chead->packettype == RTCP_Sender_PT) { // Sender Report recvSSRC = chead->getSSRC(); } else { recvSSRC = head->getSSRC(); } ELOG_DEBUG("Audio Source SSRC is %u", recvSSRC); this->setAudioSourceSSRC(recvSSRC); } audioSink_->deliverAudioData(buf, len); } } else if (transport->mediaType == VIDEO_TYPE) { if (videoSink_ != NULL) { parseIncomingPayloadType(buf, len, VIDEO_PACKET); RtpHeader *head = reinterpret_cast<RtpHeader*> (buf); RtcpHeader *chead = reinterpret_cast<RtcpHeader*> (buf); // Firefox does not send SSRC in SDP if (this->getVideoSourceSSRC() == 0) { unsigned int recvSSRC; if (chead->packettype == RTCP_Sender_PT) { //Sender Report recvSSRC = chead->getSSRC(); } else { recvSSRC = head->getSSRC(); } ELOG_DEBUG("Video Source SSRC is %u", recvSSRC); this->setVideoSourceSSRC(recvSSRC); } // change ssrc for RTP packets, don't touch here if RTCP videoSink_->deliverVideoData(buf, len); } } } // check if we need to send FB || RR messages rtcpProcessor_->checkRtcpFb(); }