/// <summary> /// Audio frames are generally contained within a single RTP packet. This method is a shortcut /// to construct a frame from a single RTP packet. /// </summary> public static RTPFrame MakeSinglePacketFrame(RTPPacket rtpPacket) { RTPFrame frame = new RTPFrame(); frame.AddRTPPacket(rtpPacket); frame.Timestamp = rtpPacket.Header.Timestamp; return(frame); }
private void ProcessRTPPackets() { try { Thread.CurrentThread.Name = "rtspclient-rtp"; _lastRTPReceivedAt = DateTime.Now; _lastBWCalcAt = DateTime.Now; while (!_isClosed) { while (_rtspSession.HasRTPPacket()) { RTPPacket rtpPacket = _rtspSession.GetNextRTPPacket(); if (rtpPacket != null) { _lastRTPReceivedAt = DateTime.Now; _bytesSinceLastBWCalc += RTPHeader.MIN_HEADER_LEN + rtpPacket.Payload.Length; if (_rtpTrackingAction != null) { double bwCalcSeconds = DateTime.Now.Subtract(_lastBWCalcAt).TotalSeconds; if (bwCalcSeconds > BANDWIDTH_CALCULATION_SECONDS) { _lastBWCalc = _bytesSinceLastBWCalc * 8 / bwCalcSeconds; _lastFrameRate = _framesSinceLastCalc / bwCalcSeconds; _bytesSinceLastBWCalc = 0; _framesSinceLastCalc = 0; _lastBWCalcAt = DateTime.Now; } var abbrevURL = (_url.Length <= 50) ? _url : _url.Substring(0, 50); string rtpTrackingText = String.Format("Url: {0}\r\nRcvd At: {1}\r\nSeq Num: {2}\r\nTS: {3}\r\nPayoad: {4}\r\nFrame Size: {5}\r\nBW: {6}\r\nFrame Rate: {7}", abbrevURL, DateTime.Now.ToString("HH:mm:ss:fff"), rtpPacket.Header.SequenceNumber, rtpPacket.Header.Timestamp, ((SDPMediaFormatsEnum)rtpPacket.Header.PayloadType).ToString(), _lastFrameSize + " bytes", _lastBWCalc.ToString("0.#") + "bps", _lastFrameRate.ToString("0.##") + "fps"); _rtpTrackingAction(rtpTrackingText); } if (rtpPacket.Header.Timestamp < _lastCompleteFrameTimestamp) { System.Diagnostics.Debug.WriteLine("Ignoring RTP packet with timestamp " + rtpPacket.Header.Timestamp + " as it's earlier than the last complete frame."); } else { while (_frames.Count > MAX_FRAMES_QUEUE_LENGTH) { var oldestFrame = _frames.OrderBy(x => x.Timestamp).First(); _frames.Remove(oldestFrame); System.Diagnostics.Debug.WriteLine("Receive queue full, dropping oldest frame with timestamp " + oldestFrame.Timestamp + "."); } var frame = _frames.Where(x => x.Timestamp == rtpPacket.Header.Timestamp).SingleOrDefault(); if (frame == null) { frame = new RTPFrame() { Timestamp = rtpPacket.Header.Timestamp, HasMarker = rtpPacket.Header.MarkerBit == 1 }; frame.AddRTPPacket(rtpPacket); _frames.Add(frame); } else { frame.HasMarker = (rtpPacket.Header.MarkerBit == 1); frame.AddRTPPacket(rtpPacket); } if (frame.IsComplete) { // The frame is ready for handing over to the UI. byte[] imageBytes = frame.GetFramePayload(); _lastFrameSize = imageBytes.Length; _framesSinceLastCalc++; _lastCompleteFrameTimestamp = rtpPacket.Header.Timestamp; //System.Diagnostics.Debug.WriteLine("Frame ready " + frame.Timestamp + ", sequence numbers " + frame.StartSequenceNumber + " to " + frame.EndSequenceNumber + ", payload length " + imageBytes.Length + "."); //logger.Debug("Frame ready " + frame.Timestamp + ", sequence numbers " + frame.StartSequenceNumber + " to " + frame.EndSequenceNumber + ", payload length " + imageBytes.Length + "."); _frames.Remove(frame); // Also remove any earlier frames as we don't care about anything that's earlier than the current complete frame. foreach (var oldFrame in _frames.Where(x => x.Timestamp <= rtpPacket.Header.Timestamp).ToList()) { System.Diagnostics.Debug.WriteLine("Discarding old frame for timestamp " + oldFrame.Timestamp + "."); logger.Warn("Discarding old frame for timestamp " + oldFrame.Timestamp + "."); _frames.Remove(oldFrame); } if (OnFrameReady != null) { try { //if (frame.FramePackets.Count == 1) //{ // // REMOVE. // logger.Warn("Discarding frame as there should have been more than 1 RTP packets."); //} //else //{ //System.Diagnostics.Debug.WriteLine("RTP frame ready for timestamp " + frame.Timestamp + "."); OnFrameReady(this, frame); //} } catch (Exception frameReadyExcp) { logger.Error("Exception RTSPClient.ProcessRTPPackets OnFrameReady. " + frameReadyExcp); } } } } } } if (DateTime.Now.Subtract(_lastRTPReceivedAt).TotalSeconds > RTP_TIMEOUT_SECONDS) { logger.Warn("No RTP packets were received on RTSP session " + _rtspSession.SessionID + " for " + RTP_TIMEOUT_SECONDS + ". The session will now be closed."); Close(); } else { Thread.Sleep(1); } } } catch (Exception excp) { logger.Error("Exception RTSPClient.ProcessRTPPackets. " + excp); } }