int RtcpForwarder::addREMB(char* buf, int len, uint32_t bitrate){ buf+=len; RtcpHeader theREMB; theREMB.setPacketType(RTCP_PS_Feedback_PT); theREMB.setBlockCount(RTCP_AFB); memcpy(&theREMB.report.rembPacket.uniqueid, "REMB", 4); theREMB.setSSRC(rtcpSink_->getVideoSinkSSRC()); theREMB.setSourceSSRC(rtcpSource_->getVideoSourceSSRC()); theREMB.setLength(5); theREMB.setREMBBitRate(bitrate); theREMB.setREMBNumSSRC(1); theREMB.setREMBFeedSSRC(rtcpSource_->getVideoSourceSSRC()); int rembLength = (theREMB.getLength()+1)*4; memcpy(buf, (uint8_t*)&theREMB, rembLength); return (len+rembLength); }
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; }