private void ProcessRTPPackets()
{
try
{
Thread.CurrentThread.Name = "rtpchanproc-" + _rtpPort;
_lastRTPReceivedAt = DateTime.Now;
_lastBWCalcAt = DateTime.Now;
while (!_isClosed)
{
while (_packets.Count() > 0)
{
RTPPacket rtpPacket = null;
lock (_packets)
{
try
{
rtpPacket = _packets.Dequeue();
}
catch { }
}
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 if(_frameType == FrameTypesEnum.Audio)
{
var frame = RTPFrame.MakeSinglePacketFrame(rtpPacket);
if (OnFrameReady != null)
{
try
{
//System.Diagnostics.Debug.WriteLine("RTP audio frame ready for timestamp " + frame.Timestamp + ".");
OnFrameReady(frame);
}
catch (Exception frameReadyExcp)
{
logger.Error("Exception RTPChannel.ProcessRTPPackets OnFrameReady Audio. " + frameReadyExcp);
}
}
}
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 + ".");
}
//int frameHeaderLength = 0;
//if (_frameType == FrameTypesEnum.VP8)
//{
// var vp8Header = RTPVP8Header.GetVP8Header(rtpPacket.Payload);
// // For a VP8 packet only the Payload descriptor part of the header is not part of the encoded bit stream.
// frameHeaderLength = vp8Header.PayloadDescriptorLength;
//}
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, FrameType = _frameType };
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 + ".");
_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 + ".");
_frames.Remove(oldFrame);
}
if (OnFrameReady != null)
{
try
{
//System.Diagnostics.Debug.WriteLine("RTP frame ready for timestamp " + frame.Timestamp + ".");
OnFrameReady(frame);
}
catch (Exception frameReadyExcp)
{
logger.Error("Exception RTPChannel.ProcessRTPPackets OnFrameReady. " + frameReadyExcp);
}
}
}
}
}
}
if (DateTime.Now.Subtract(_lastRTPReceivedAt).TotalSeconds > RTP_TIMEOUT_SECONDS)
{
logger.Warn("No RTP packets were receoved on local port " + _rtpPort + " for " + RTP_TIMEOUT_SECONDS + ". The session will now be closed.");
Close();
}
else
{
Thread.Sleep(1);
}
}
}
catch (Exception excp)
{
logger.Error("Exception RTPChannel.ProcessRTPPackets. " + excp);
}
}