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());
        }
Exemple #2
0
        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());
            }
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        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;
            }
        }
Exemple #8
0
        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;
                }
            }
        }