WebRTC: Fixes to packet timing and loss statistics
This commit is contained in:
		
							parent
							
								
									3ba7723b10
								
							
						
					
					
						commit
						2a5a808107
					
				
					 4 changed files with 78 additions and 32 deletions
				
			
		|  | @ -516,7 +516,7 @@ namespace RTP{ | ||||||
|     }else{ |     }else{ | ||||||
|       // packet is very early - assume dropped after PACKET_DROP_TIMEOUT packets
 |       // packet is very early - assume dropped after PACKET_DROP_TIMEOUT packets
 | ||||||
|       while ((int16_t)(rtpSeq - pSNo) < -(int)PACKET_DROP_TIMEOUT){ |       while ((int16_t)(rtpSeq - pSNo) < -(int)PACKET_DROP_TIMEOUT){ | ||||||
|         WARN_MSG("Giving up on packet %u", rtpSeq); |         VERYHIGH_MSG("Giving up on track %" PRIu64 " packet %u", packTrack, rtpSeq); | ||||||
|         ++rtpSeq; |         ++rtpSeq; | ||||||
|         ++lostTotal; |         ++lostTotal; | ||||||
|         ++lostCurrent; |         ++lostCurrent; | ||||||
|  | @ -548,7 +548,7 @@ namespace RTP{ | ||||||
|     } |     } | ||||||
|     // packet is slightly early - buffer it
 |     // packet is slightly early - buffer it
 | ||||||
|     if ((int16_t)(rtpSeq - pSNo) < 0){ |     if ((int16_t)(rtpSeq - pSNo) < 0){ | ||||||
|       HIGH_MSG("Buffering early packet #%u->%u", rtpSeq, pack.getSequence()); |       VERYHIGH_MSG("Buffering early packet #%u->%u", rtpSeq, pack.getSequence()); | ||||||
|       packBuffer[pack.getSequence()] = pack; |       packBuffer[pack.getSequence()] = pack; | ||||||
|     } |     } | ||||||
|     // packet is late
 |     // packet is late
 | ||||||
|  | @ -616,7 +616,6 @@ namespace RTP{ | ||||||
|     if (M.getCodec(tid) == "opus"){ |     if (M.getCodec(tid) == "opus"){ | ||||||
|       m = 48.0; |       m = 48.0; | ||||||
|     } |     } | ||||||
|     bootMsOffset = M.getBootMsOffset(); |  | ||||||
|     setProperties(M.getID(tid), M.getCodec(tid), M.getType(tid), M.getInit(tid), m); |     setProperties(M.getID(tid), M.getCodec(tid), M.getType(tid), M.getInit(tid), m); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | @ -636,7 +635,7 @@ namespace RTP{ | ||||||
|       if (rtpTime > 0x80000000lu){rtp64Time -= 0x100000000ll;} |       if (rtpTime > 0x80000000lu){rtp64Time -= 0x100000000ll;} | ||||||
|     } |     } | ||||||
|     uint64_t msTime = (rtp64Time - firstTime + 1 + 0x100000000ull * wrapArounds) / multiplier + milliSync; |     uint64_t msTime = (rtp64Time - firstTime + 1 + 0x100000000ull * wrapArounds) / multiplier + milliSync; | ||||||
|     int32_t rtpDiff = (bootMsOffset + msTime) - (Util::bootMS() - msDiff); |     int32_t rtpDiff = msTime - (Util::bootMS() - msDiff); | ||||||
|     if (rtpDiff > 25 || rtpDiff < -25){ |     if (rtpDiff > 25 || rtpDiff < -25){ | ||||||
|       INFO_MSG("RTP difference (%s %s): %" PRId32 "ms, syncing...", type.c_str(), codec.c_str(), rtpDiff); |       INFO_MSG("RTP difference (%s %s): %" PRId32 "ms, syncing...", type.c_str(), codec.c_str(), rtpDiff); | ||||||
|       milliSync -= rtpDiff; |       milliSync -= rtpDiff; | ||||||
|  | @ -655,7 +654,7 @@ namespace RTP{ | ||||||
|     // This part isn't codec-specific, so we do it before anything else.
 |     // This part isn't codec-specific, so we do it before anything else.
 | ||||||
|     int64_t pTime = pkt.getTimeStamp(); |     int64_t pTime = pkt.getTimeStamp(); | ||||||
|     if (!firstTime){ |     if (!firstTime){ | ||||||
|       milliSync = Util::bootMS() - bootMsOffset; |       milliSync = Util::bootMS(); | ||||||
|       firstTime = pTime + 1; |       firstTime = pTime + 1; | ||||||
|       INFO_MSG("RTP timestamp rollover expected in " PRETTY_PRINT_TIME, |       INFO_MSG("RTP timestamp rollover expected in " PRETTY_PRINT_TIME, | ||||||
|                PRETTY_ARG_TIME((0xFFFFFFFFul - firstTime) / multiplier / 1000)); |                PRETTY_ARG_TIME((0xFFFFFFFFul - firstTime) / multiplier / 1000)); | ||||||
|  |  | ||||||
|  | @ -149,7 +149,6 @@ namespace RTP{ | ||||||
| 
 | 
 | ||||||
|   public: |   public: | ||||||
|     uint64_t trackId; |     uint64_t trackId; | ||||||
|     uint64_t bootMsOffset; |  | ||||||
|     double multiplier;    ///< Multiplier to convert from millis to RTP time
 |     double multiplier;    ///< Multiplier to convert from millis to RTP time
 | ||||||
|     std::string codec;    ///< Codec of this track
 |     std::string codec;    ///< Codec of this track
 | ||||||
|     std::string type;     ///< Type of this track
 |     std::string type;     ///< Type of this track
 | ||||||
|  | @ -161,7 +160,7 @@ namespace RTP{ | ||||||
|     bool recentWrap;      ///< True if a wraparound happened recently.
 |     bool recentWrap;      ///< True if a wraparound happened recently.
 | ||||||
|     uint32_t prevTime; |     uint32_t prevTime; | ||||||
|     uint64_t firstTime; |     uint64_t firstTime; | ||||||
|     int32_t milliSync; |     int64_t milliSync; | ||||||
|     void (*cbPack)(const DTSC::Packet &pkt); |     void (*cbPack)(const DTSC::Packet &pkt); | ||||||
|     void (*cbInit)(const uint64_t track, const std::string &initData); |     void (*cbInit)(const uint64_t track, const std::string &initData); | ||||||
|     // Codec-specific handlers
 |     // Codec-specific handlers
 | ||||||
|  |  | ||||||
|  | @ -50,11 +50,16 @@ namespace Mist{ | ||||||
|   /* ------------------------------------------------ */ |   /* ------------------------------------------------ */ | ||||||
| 
 | 
 | ||||||
|   OutWebRTC::OutWebRTC(Socket::Connection &myConn) : HTTPOutput(myConn){ |   OutWebRTC::OutWebRTC(Socket::Connection &myConn) : HTTPOutput(myConn){ | ||||||
|  |     totalPkts = 0; | ||||||
|  |     totalLoss = 0; | ||||||
|  |     totalRetrans = 0; | ||||||
|  |     setPacketOffset = false; | ||||||
|  |     packetOffset = 0; | ||||||
|     lastRecv = Util::bootMS(); |     lastRecv = Util::bootMS(); | ||||||
|     stats_jitter = 0; |     stats_jitter = 0; | ||||||
|     stats_nacknum = 0; |     stats_nacknum = 0; | ||||||
|     stats_lossnum = 0; |     stats_lossnum = 0; | ||||||
|     stats_lossperc = 0; |     stats_lossperc = 100.0; | ||||||
|     lastPackMs = 0; |     lastPackMs = 0; | ||||||
|     vidTrack = INVALID_TRACK_ID; |     vidTrack = INVALID_TRACK_ID; | ||||||
|     prevVidTrack = INVALID_TRACK_ID; |     prevVidTrack = INVALID_TRACK_ID; | ||||||
|  | @ -65,7 +70,6 @@ namespace Mist{ | ||||||
|     repeatInit = true; |     repeatInit = true; | ||||||
| 
 | 
 | ||||||
|     lastTimeSync = 0; |     lastTimeSync = 0; | ||||||
|     packetOffset = 0; |  | ||||||
|     maxSkipAhead = 0; |     maxSkipAhead = 0; | ||||||
|     needsLookAhead = 0; |     needsLookAhead = 0; | ||||||
|     webRTCInputOutputThread = NULL; |     webRTCInputOutputThread = NULL; | ||||||
|  | @ -994,6 +998,15 @@ namespace Mist{ | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   void OutWebRTC::connStats(uint64_t now, Comms::Statistics &statComm){ | ||||||
|  |     statComm.setUp(myConn.dataUp()); | ||||||
|  |     statComm.setDown(myConn.dataDown()); | ||||||
|  |     statComm.setPacketCount(totalPkts); | ||||||
|  |     statComm.setPacketLostCount(totalLoss); | ||||||
|  |     statComm.setPacketRetransmitCount(totalRetrans); | ||||||
|  |     statComm.setTime(now - myConn.connTime()); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   // Checks if there is data on our UDP socket. The data can be
 |   // Checks if there is data on our UDP socket. The data can be
 | ||||||
|   // STUN, DTLS, SRTP or SRTCP. When we're receiving media from
 |   // STUN, DTLS, SRTP or SRTCP. When we're receiving media from
 | ||||||
|   // the browser (e.g. from webcam) this function is called from
 |   // the browser (e.g. from webcam) this function is called from
 | ||||||
|  | @ -1022,6 +1035,33 @@ namespace Mist{ | ||||||
|         FAIL_MSG("Unhandled WebRTC data. Type: %02X", fb); |         FAIL_MSG("Unhandled WebRTC data. Type: %02X", fb); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     //If this is an incoming push, handle receiver reports and keyframe interval
 | ||||||
|  |     if (isPushing()){ | ||||||
|  |       uint64_t now = Util::bootMS(); | ||||||
|  |        | ||||||
|  |       //Receiver reports and packet loss calculations
 | ||||||
|  |       if (now >= rtcpTimeoutInMillis){ | ||||||
|  |         std::map<uint64_t, WebRTCTrack>::iterator it; | ||||||
|  |         for (it = webrtcTracks.begin(); it != webrtcTracks.end(); ++it){ | ||||||
|  |           if (M.getType(it->first) != "video"){continue;}//Video-only, at least for now
 | ||||||
|  |           sendRTCPFeedbackREMB(it->second); | ||||||
|  |           sendRTCPFeedbackRR(it->second); | ||||||
|  |         } | ||||||
|  |         rtcpTimeoutInMillis = now + 1000; /* was 5000, lowered for FEC */ | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       //Keyframe requests
 | ||||||
|  |       if (now >= rtcpKeyFrameTimeoutInMillis){ | ||||||
|  |         std::map<uint64_t, WebRTCTrack>::iterator it; | ||||||
|  |         for (it = webrtcTracks.begin(); it != webrtcTracks.end(); ++it){ | ||||||
|  |           if (M.getType(it->first) != "video"){continue;}//Video-only
 | ||||||
|  |           sendRTCPFeedbackPLI(it->second); | ||||||
|  |         } | ||||||
|  |         rtcpKeyFrameTimeoutInMillis = now + rtcpKeyFrameDelayInMillis; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     if (udp.getSock() == -1){onFail("UDP socket closed", true);} |     if (udp.getSock() == -1){onFail("UDP socket closed", true);} | ||||||
|     return hadPack; |     return hadPack; | ||||||
|   } |   } | ||||||
|  | @ -1125,6 +1165,7 @@ namespace Mist{ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void OutWebRTC::ackNACK(uint32_t pSSRC, uint16_t seq){ |   void OutWebRTC::ackNACK(uint32_t pSSRC, uint16_t seq){ | ||||||
|  |     totalRetrans++; | ||||||
|     if (!outBuffers.count(pSSRC)){ |     if (!outBuffers.count(pSSRC)){ | ||||||
|       WARN_MSG("Could not answer NACK for %" PRIu32 ": we don't know this track", pSSRC); |       WARN_MSG("Could not answer NACK for %" PRIu32 ": we don't know this track", pSSRC); | ||||||
|       return; |       return; | ||||||
|  | @ -1193,6 +1234,7 @@ namespace Mist{ | ||||||
|         uint16_t sNum = *(rtcTrack.sorter.wantedSeqs.begin()); |         uint16_t sNum = *(rtcTrack.sorter.wantedSeqs.begin()); | ||||||
|         if (packetLog.is_open()){packetLog << "[" << Util::bootMS() << "]" << "Sending NACK for sequence #" << sNum << std::endl;} |         if (packetLog.is_open()){packetLog << "[" << Util::bootMS() << "]" << "Sending NACK for sequence #" << sNum << std::endl;} | ||||||
|         stats_nacknum++; |         stats_nacknum++; | ||||||
|  |         totalRetrans++; | ||||||
|         sendRTCPFeedbackNACK(rtcTrack, sNum); |         sendRTCPFeedbackNACK(rtcTrack, sNum); | ||||||
|         rtcTrack.sorter.wantedSeqs.erase(sNum); |         rtcTrack.sorter.wantedSeqs.erase(sNum); | ||||||
|       } |       } | ||||||
|  | @ -1259,6 +1301,7 @@ namespace Mist{ | ||||||
|             uint64_t ntpTime = Bit::btohll(udp.data + 8); |             uint64_t ntpTime = Bit::btohll(udp.data + 8); | ||||||
|             uint32_t rtpTime = Bit::btohl(udp.data + 16); |             uint32_t rtpTime = Bit::btohl(udp.data + 16); | ||||||
|             uint32_t packets = Bit::btohl(udp.data + 20); |             uint32_t packets = Bit::btohl(udp.data + 20); | ||||||
|  |             totalPkts += packets; | ||||||
|             uint32_t bytes = Bit::btohl(udp.data + 24); |             uint32_t bytes = Bit::btohl(udp.data + 24); | ||||||
|             HIGH_MSG("Received sender report for track %s (%" PRIu32 " pkts, %" PRIu32 "b) time: %" PRIu32 " RTP = %" PRIu64 " NTP", it->second.rtpToDTSC.codec.c_str(), packets, bytes, rtpTime, ntpTime); |             HIGH_MSG("Received sender report for track %s (%" PRIu32 " pkts, %" PRIu32 "b) time: %" PRIu32 " RTP = %" PRIu64 " NTP", it->second.rtpToDTSC.codec.c_str(), packets, bytes, rtpTime, ntpTime); | ||||||
|             if (rtpTime && ntpTime){ |             if (rtpTime && ntpTime){ | ||||||
|  | @ -1277,7 +1320,8 @@ namespace Mist{ | ||||||
|         } |         } | ||||||
|       }else if (pt == 73){ |       }else if (pt == 73){ | ||||||
|         //73 = receiver report
 |         //73 = receiver report
 | ||||||
|         // \TODO Implement, maybe?
 |         uint32_t packets = Bit::btoh24(udp.data + 13); | ||||||
|  |         totalLoss = packets; | ||||||
|       }else{ |       }else{ | ||||||
|         if (packetLog.is_open()){packetLog << "[" << Util::bootMS() << "]" << "Unknown payload type: " << pt << std::endl;} |         if (packetLog.is_open()){packetLog << "[" << Util::bootMS() << "]" << "Unknown payload type: " << pt << std::endl;} | ||||||
|         WARN_MSG("Unknown RTP feedback payload type: %u", pt); |         WARN_MSG("Unknown RTP feedback payload type: %u", pt); | ||||||
|  | @ -1294,7 +1338,14 @@ namespace Mist{ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void OutWebRTC::onDTSCConverterHasPacket(const DTSC::Packet &pkt){ |   void OutWebRTC::onDTSCConverterHasPacket(const DTSC::Packet &pkt){ | ||||||
| 
 |     if (!M.getBootMsOffset()){ | ||||||
|  |       meta.setBootMsOffset(Util::bootMS() - pkt.getTime()); | ||||||
|  |       packetOffset = 0; | ||||||
|  |       setPacketOffset = true; | ||||||
|  |     }else if (!setPacketOffset){ | ||||||
|  |       packetOffset = (Util::bootMS() - pkt.getTime()) - M.getBootMsOffset(); | ||||||
|  |       setPacketOffset = true; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     // extract meta data (init data, width/height, etc);
 |     // extract meta data (init data, width/height, etc);
 | ||||||
|     size_t idx = M.trackIDToIndex(pkt.getTrackId(), getpid()); |     size_t idx = M.trackIDToIndex(pkt.getTrackId(), getpid()); | ||||||
|  | @ -1311,30 +1362,16 @@ namespace Mist{ | ||||||
|     if (codec == "VP8" && pkt.getFlag("keyframe")){extractFrameSizeFromVP8KeyFrame(pkt);} |     if (codec == "VP8" && pkt.getFlag("keyframe")){extractFrameSizeFromVP8KeyFrame(pkt);} | ||||||
|     if (codec == "VP9" && pkt.getFlag("keyframe")){extractFrameSizeFromVP8KeyFrame(pkt);} |     if (codec == "VP9" && pkt.getFlag("keyframe")){extractFrameSizeFromVP8KeyFrame(pkt);} | ||||||
| 
 | 
 | ||||||
|     // create rtcp packet (set bitrate and request keyframe).
 |  | ||||||
|     if (codec == "H264" || codec == "VP8" || codec == "VP9"){ |  | ||||||
|       uint64_t now = Util::bootMS(); |  | ||||||
| 
 |  | ||||||
|       if (now >= rtcpTimeoutInMillis){ |  | ||||||
|         WebRTCTrack &rtcTrack = webrtcTracks[idx]; |  | ||||||
|         sendRTCPFeedbackREMB(rtcTrack); |  | ||||||
|         sendRTCPFeedbackRR(rtcTrack); |  | ||||||
|         rtcpTimeoutInMillis = now + 1000; /* was 5000, lowered for FEC */ |  | ||||||
|       } |  | ||||||
| 
 |  | ||||||
|       if (now >= rtcpKeyFrameTimeoutInMillis){ |  | ||||||
|         WebRTCTrack &rtcTrack = webrtcTracks[idx]; |  | ||||||
|         sendRTCPFeedbackPLI(rtcTrack); |  | ||||||
|         rtcpKeyFrameTimeoutInMillis = now + rtcpKeyFrameDelayInMillis; |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if (!M.trackValid(idx)){ |     if (!M.trackValid(idx)){ | ||||||
|       INFO_MSG("Validated track %zu in meta", idx); |       INFO_MSG("Validated track %zu in meta", idx); | ||||||
|       meta.validateTrack(idx); |       meta.validateTrack(idx); | ||||||
|     } |     } | ||||||
|     DONTEVEN_MSG("DTSC: %s", pkt.toSummary().c_str()); |     DONTEVEN_MSG("DTSC: %s", pkt.toSummary().c_str()); | ||||||
|     bufferLivePacket(pkt); |     char *pktData; | ||||||
|  |     size_t pktDataLen; | ||||||
|  |     pkt.getString("data", pktData, pktDataLen); | ||||||
|  |     bufferLivePacket(pkt.getTime() + packetOffset, pkt.getInt("offset"), idx, pktData, | ||||||
|  |                      pktDataLen, 0, pkt.getFlag("keyframe")); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void OutWebRTC::onDTSCConverterHasInitData(size_t trackId, const std::string &initData){ |   void OutWebRTC::onDTSCConverterHasInitData(size_t trackId, const std::string &initData){ | ||||||
|  | @ -1397,6 +1434,7 @@ namespace Mist{ | ||||||
|     uint16_t seq = tmpPkt.getSequence(); |     uint16_t seq = tmpPkt.getSequence(); | ||||||
|     outBuffers[pSSRC].assign(seq, rtpOutBuffer, protectedSize); |     outBuffers[pSSRC].assign(seq, rtpOutBuffer, protectedSize); | ||||||
|     myConn.addUp(protectedSize); |     myConn.addUp(protectedSize); | ||||||
|  |     totalPkts++; | ||||||
| 
 | 
 | ||||||
|     if (volkswagenMode){ |     if (volkswagenMode){ | ||||||
|       if (srtpWriter.protectRtp((uint8_t *)(void *)rtpOutBuffer, &protectedSize) != 0){ |       if (srtpWriter.protectRtp((uint8_t *)(void *)rtpOutBuffer, &protectedSize) != 0){ | ||||||
|  | @ -1721,7 +1759,7 @@ namespace Mist{ | ||||||
|   // sequence numbers are lost it makes sense to implement this
 |   // sequence numbers are lost it makes sense to implement this
 | ||||||
|   // too.
 |   // too.
 | ||||||
|   void OutWebRTC::sendRTCPFeedbackNACK(const WebRTCTrack &rtcTrack, uint16_t lostSequenceNumber){ |   void OutWebRTC::sendRTCPFeedbackNACK(const WebRTCTrack &rtcTrack, uint16_t lostSequenceNumber){ | ||||||
|     INFO_MSG("Requesting missing sequence number %u", lostSequenceNumber); |     VERYHIGH_MSG("Requesting missing sequence number %u", lostSequenceNumber); | ||||||
| 
 | 
 | ||||||
|     std::vector<uint8_t> buffer; |     std::vector<uint8_t> buffer; | ||||||
|     buffer.push_back(0x80 | 0x01); // V=2 (0x80) | FMT=1 (0x01)
 |     buffer.push_back(0x80 | 0x01); // V=2 (0x80) | FMT=1 (0x01)
 | ||||||
|  | @ -1767,9 +1805,14 @@ namespace Mist{ | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   void OutWebRTC::sendRTCPFeedbackRR(WebRTCTrack &rtcTrack){ |   void OutWebRTC::sendRTCPFeedbackRR(WebRTCTrack &rtcTrack){ | ||||||
|     stats_lossperc = (double)(rtcTrack.sorter.lostCurrent * 100.) / (double)(rtcTrack.sorter.lostCurrent + rtcTrack.sorter.packCurrent); |     if ((rtcTrack.sorter.lostCurrent + rtcTrack.sorter.packCurrent) < 1){ | ||||||
|  |       stats_lossperc = 100.0; | ||||||
|  |     }else{ | ||||||
|  |       stats_lossperc = (double)(rtcTrack.sorter.lostCurrent * 100.) / (double)(rtcTrack.sorter.lostCurrent + rtcTrack.sorter.packCurrent); | ||||||
|  |     } | ||||||
|     stats_jitter = rtcTrack.jitter/rtcTrack.rtpToDTSC.multiplier; |     stats_jitter = rtcTrack.jitter/rtcTrack.rtpToDTSC.multiplier; | ||||||
|     stats_lossnum = rtcTrack.sorter.lostTotal; |     stats_lossnum = rtcTrack.sorter.lostTotal; | ||||||
|  |     totalLoss = stats_lossnum; | ||||||
| 
 | 
 | ||||||
|     //Print stats at appropriate log levels
 |     //Print stats at appropriate log levels
 | ||||||
|     if (stats_lossperc > 1 || stats_jitter > 20){ |     if (stats_lossperc > 1 || stats_jitter > 20){ | ||||||
|  |  | ||||||
|  | @ -143,10 +143,14 @@ namespace Mist{ | ||||||
|     void onDTSCConverterHasInitData(const size_t trackID, const std::string &initData); |     void onDTSCConverterHasInitData(const size_t trackID, const std::string &initData); | ||||||
|     void onRTPPacketizerHasRTPPacket(const char *data, size_t nbytes); |     void onRTPPacketizerHasRTPPacket(const char *data, size_t nbytes); | ||||||
|     void onRTPPacketizerHasRTCPPacket(const char *data, uint32_t nbytes); |     void onRTPPacketizerHasRTCPPacket(const char *data, uint32_t nbytes); | ||||||
|  |     virtual void connStats(uint64_t now, Comms::Statistics &statComm); | ||||||
| 
 | 
 | ||||||
|   private: |   private: | ||||||
|     uint64_t lastRecv; |     uint64_t lastRecv; | ||||||
|     uint64_t lastPackMs; |     uint64_t lastPackMs; | ||||||
|  |     uint64_t totalPkts; | ||||||
|  |     uint64_t totalLoss; | ||||||
|  |     uint64_t totalRetrans; | ||||||
|     std::ofstream jitterLog; |     std::ofstream jitterLog; | ||||||
|     std::ofstream packetLog; |     std::ofstream packetLog; | ||||||
|     std::string externalAddr; |     std::string externalAddr; | ||||||
|  | @ -209,6 +213,7 @@ namespace Mist{ | ||||||
|     double target_rate; ///< Target playback speed rate (1.0 = normal, 0 = auto)
 |     double target_rate; ///< Target playback speed rate (1.0 = normal, 0 = auto)
 | ||||||
| 
 | 
 | ||||||
|     bool didReceiveKeyFrame; /* TODO burst delay */ |     bool didReceiveKeyFrame; /* TODO burst delay */ | ||||||
|  |     bool setPacketOffset; | ||||||
|     int64_t packetOffset;    ///< For timestamp rewrite with BMO
 |     int64_t packetOffset;    ///< For timestamp rewrite with BMO
 | ||||||
|     uint64_t lastTimeSync; |     uint64_t lastTimeSync; | ||||||
|     bool firstKey; |     bool firstKey; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Thulinma
						Thulinma