public override string GenerateSDPDescription() { StringBuilder body = new StringBuilder(); TimeVal timeVal = new TimeVal(); RTPTime.GetTimestamp(ref timeVal); body.Append("v=0\r\n"). AppendFormat("o=- {0}{1:06} 1 IN IP4 {2}\r\n", timeVal.tv_sec, timeVal.tv_usec, SocketExtensions.GetLocalIPV4Address()). AppendFormat("s=Session streamed by \"{0}\"\r\n", RTSPServer.ServerVersion). AppendFormat("i={0}\r\n", Name). Append("t=0 0\r\n"). AppendFormat("a=tool:{0}\r\n", RTSPServer.ServerVersion). Append("a=type:broadcast\r\n"). Append("a=control:*\r\n"). Append("a=range:npt=0-\r\n"). AppendFormat("a=x-qt-text-nam:Session streamed by \"{0}\"\r\n", RTSPServer.ServerVersion). AppendFormat("a=x-qt-text-inf:{0}\r\n", Name). Append("m=video 0 RTP/AVP 96\r\n"). Append("c=IN IP4 0.0.0.0\r\n"). Append("b=AS:500\r\n"). Append("a=rtpmap:96 H264/90000\r\n"). Append("a=fmtp:96 packetization-mode=1;profile-level-id=640028;sprop-parameter-sets=J2QAKKwrQCgC3QDxImo=,KO4Pyw==\r\n"). Append("a=control:track1\r\n"); return(body.ToString()); }
public uint CurrentTimeStamp() { TimeVal timeNow = new TimeVal(); RTPTime.GetTimestamp(ref timeNow); return(ConvertToRTPTimestamp(timeNow)); }
public void addSR() { enqueueCommonReportPrefix(RTCPConstants.RTCP_PT_SR, _stream.SSRC(), 5 /* extra words in a SR */); // Now, add the 'sender info' for our sink // Insert the NTP and RTP timestamps for the 'wallclock time': TimeVal timeNow = new TimeVal(); RTPTime.GetTimestamp(ref timeNow); _fOutBuf.WriteWord((uint)(timeNow.tv_sec + 0x83AA7E80)); // NTP timestamp most-significant word (1970 epoch -> 1900 epoch) double fractionalPart = (timeNow.tv_usec / 15625.0) * 0x04000000; // 2^32/10^6 _fOutBuf.WriteWord((uint)(fractionalPart + 0.5)); // NTP timestamp least-significant word uint rtpTimestamp = _stream.ConvertToRTPTimestamp(timeNow); _fOutBuf.WriteWord(rtpTimestamp); // RTP ts // Insert the packet and byte counts: uint packetCount = _stream.PacketCount() - _session.PacketsCount; uint octetCount = _stream.OctetCount() - _session.OctetCount; _fOutBuf.WriteWord(packetCount); _fOutBuf.WriteWord(octetCount); if (_logger.IsDebugEnabled) { _logger.Debug("Sending report : {0}.{1} packet {2} octet {3} Sequence {4}", timeNow.tv_sec + 0x83AA7E80, (uint)(fractionalPart + 0.5), packetCount, octetCount, _stream.CurrentSeqNo()); } }
public uint PresetNextTimestamp() { TimeVal timeNow = new TimeVal(); RTPTime.GetTimestamp(ref timeNow); uint tsNow = ConvertToRTPTimestamp(timeNow); if (_nextTimestampHasBeenPreset == false) { // Ideally, we shouldn't preset the timestamp if there _timestampBase = tsNow; _nextTimestampHasBeenPreset = true; } return(tsNow); }
public void ReapOldMembers() { TimeVal now = new TimeVal(); RTPTime.GetTimestamp(ref now); List <uint> oldMembers = new List <uint>(); foreach (var stat in _receivers.Values) { var timeReceived = stat.fTimeReceived; if (now.tv_sec - timeReceived.tv_sec > 60) { oldMembers.Add(stat.SSRC); } } foreach (var ssrc in oldMembers) { Console.WriteLine("Removing SSRC {0} from TransmissionStats", ssrc); _receivers.Remove(ssrc); } }
public RTPTransmissionStat(RTPStream stream, uint ssrc) { _stream = stream; SSRC = ssrc; fLastPacketNumReceived = 0; fPacketLossRatio = 0; fTotNumPacketsLost = 0; fJitter = 0; fLastSRTime = 0; fDiffSR_RRTime = 0; fAtLeastTwoRRsHaveBeenReceived = false; fFirstPacket = true; fTotalOctetCount_hi = 0; fTotalOctetCount_lo = 0; fTotalPacketCount_hi = 0; fTotalPacketCount_lo = 0; fTimeCreated = new TimeVal(); RTPTime.GetTimestamp(ref fTimeCreated); fLastOctetCount = _stream.OctetCount(); fLastPacketCount = _stream.PacketCount(); }
public void noteIncomingRR(IPEndPoint lastFromAddress, uint lossStats, uint lastPacketNumReceived, uint jitter, uint lastSRTime, uint diffSR_RRTime) { if (fFirstPacket) { fFirstPacket = false; fFirstPacketNumReported = lastPacketNumReceived; } else { fAtLeastTwoRRsHaveBeenReceived = true; fOldLastPacketNumReceived = fLastPacketNumReceived; fOldTotNumPacketsLost = fTotNumPacketsLost; } RTPTime.GetTimestamp(ref fTimeReceived); fLastFromAddress = lastFromAddress; fPacketLossRatio = (byte)(lossStats >> 24); fTotNumPacketsLost = lossStats & 0xFFFFFF; fLastPacketNumReceived = lastPacketNumReceived; fJitter = jitter; fLastSRTime = lastSRTime; fDiffSR_RRTime = diffSR_RRTime; if (_logger.IsDebugEnabled) { _logger.Debug("RTCP RR data (received at {0}.{1}): lossStats {2:x8}, TotNumLost {3} lastPacketNumReceived {4}, jitter {5}, lastSRTime {6}, diffSR_RRTime {7} from SSRC {0}", fTimeReceived.tv_sec, fTimeReceived.tv_usec, lossStats, fTotNumPacketsLost, lastPacketNumReceived, jitter, lastSRTime, diffSR_RRTime, SSRC); } if (_logger.IsDebugEnabled) { uint rtd = roundTripDelay(); _logger.Debug("=> round-trip delay: {0:x4} (== {1} seconds)", rtd, rtd / 65536.0); } // Update our counts of the total number of octets and packets sent towards // this receiver: uint newOctetCount = _stream.OctetCount(); uint octetCountDiff = newOctetCount - fLastOctetCount; fLastOctetCount = newOctetCount; uint prevTotalOctetCount_lo = fTotalOctetCount_lo; fTotalOctetCount_lo += octetCountDiff; if (fTotalOctetCount_lo < prevTotalOctetCount_lo) { // wrap around ++fTotalOctetCount_hi; } uint newPacketCount = _stream.PacketCount(); uint packetCountDiff = newPacketCount - fLastPacketCount; fLastPacketCount = newPacketCount; uint prevTotalPacketCount_lo = fTotalPacketCount_lo; fTotalPacketCount_lo += packetCountDiff; if (fTotalPacketCount_lo < prevTotalPacketCount_lo) { // wrap around ++fTotalPacketCount_hi; } }
public void OnNewNalUnit(byte[] frame, bool completedNalUnit, bool pictureEndMarker) { if (_logger.IsDebugEnabled) { _logger.Debug("Buffer {0}, {1}", frame.Length, _inputBuffer.Length); } int frameSize; // out Array.Copy(frame, 0, _inputBuffer, 1, frame.Length); int numValidDataBytes = frame.Length + 1; int numDelivered = 0; byte[] fragment; //Dump(buffer, (uint)buffer.Length, nalCompletedNalUnit, fPictureEndMarker); // We have NAL unit data in the buffer. There are two cases to consider: // 1. There is a new NAL unit in the buffer, and it's small enough to deliver // to the RTP sink (as is). // 2. 1) There is a new NAL unit in the buffer, but it's too large to deliver to // the RTP sink in its entirety. Deliver the first fragment of this data, // as a FU packet, with one extra preceding header byte (for the "FU header"). // then // 2) Deliver the next fragment of this data, // as a FU packet, with two (H.264) extra preceding header bytes // (for the "NAL header" and the "FU header"). if (_maxSize < _maxOutputPacketSize) { // shouldn't happen _logger.Error("MaxSize ({0}) is smaller than expected", _maxSize); throw new Exception(string.Format("MaxSize ({0}) is smaller than expected", _maxSize)); } else { _maxSize = _maxOutputPacketSize; } TimeVal tv = new TimeVal(); RTPTime.GetTimestamp(ref tv); bool lastFragmentCompletedNALUnit = true; // by default if (_currentDataOffset == 1) { // case 1 or 2 if (numValidDataBytes - 1 <= _maxSize) { // case 1 fragment = new byte[numValidDataBytes - 1]; for (int i = 0; i < numValidDataBytes - 1; i++) { fragment[i] = _inputBuffer[1 + i]; } frameSize = numValidDataBytes - 1; _currentDataOffset = numValidDataBytes; numDelivered = fragment.Length; _broadcaster.OnNewFragment(lastFragmentCompletedNALUnit, pictureEndMarker, fragment, tv); } else { // case 2 // We need to send the NAL unit data as FU packets. Deliver the first // packet now. Note that we add "NAL header" and "FU header" bytes to the front // of the packet (overwriting the existing "NAL header"). fragment = new byte[_maxSize]; _inputBuffer[0] = (byte)((_inputBuffer[1] & 0xE0) | 28); // FU indicator _inputBuffer[1] = (byte)(0x80 | (_inputBuffer[1] & 0x1F)); // FU header (with S bit) for (int i = 0; i < _maxSize; i++) { fragment[i] = _inputBuffer[i]; } frameSize = _maxSize; _currentDataOffset += _maxSize - 1; lastFragmentCompletedNALUnit = false; numDelivered += fragment.Length; _broadcaster.OnNewFragment(lastFragmentCompletedNALUnit, pictureEndMarker, fragment, tv); bool last = false; do { // case 3 // We are sending this NAL unit data as FU packets. We've already sent the // first packet (fragment). Now, send the next fragment. Note that we add // "NAL header" and "FU header" bytes to the front. (We reuse these bytes that // we already sent for the first fragment, but clear the S bit, and add the E // bit if this is the last fragment.) int numExtraHeaderBytes; _inputBuffer[_currentDataOffset - 2] = _inputBuffer[0]; // FU indicator _inputBuffer[_currentDataOffset - 1] = (byte)(_inputBuffer[1] & ~0x80); // FU header (no S bit) numExtraHeaderBytes = 2; int numBytesToSend = numExtraHeaderBytes + (numValidDataBytes - _currentDataOffset); if (numBytesToSend > _maxSize) { // We can't send all of the remaining data this time: numBytesToSend = _maxSize; lastFragmentCompletedNALUnit = false; } else { // This is the last fragment: _inputBuffer[_currentDataOffset - 1] |= 0x40; // set the E bit in the FU header lastFragmentCompletedNALUnit = true; last = true; } fragment = new byte[numBytesToSend]; numDelivered += fragment.Length; Array.Copy(_inputBuffer, _currentDataOffset - numExtraHeaderBytes, fragment, 0, numBytesToSend); if (last) { lastFragmentCompletedNALUnit = completedNalUnit; } _broadcaster.OnNewFragment(lastFragmentCompletedNALUnit, pictureEndMarker, fragment, tv); frameSize = numBytesToSend; _currentDataOffset += numBytesToSend - numExtraHeaderBytes; } while (!last); } if (_currentDataOffset >= numValidDataBytes) { // We're done with this data. Reset the pointers for receiving new data: if (_logger.IsDebugEnabled) { _logger.Debug("Done with NalUnit {0} {1}. NumDelivered {2}", sequenceNumber++, frame.Length, numDelivered); } numDelivered = 0; numValidDataBytes = _currentDataOffset = 1; } } }