public void ListenThread() { CompoundPacket compoundPacket = new CompoundPacket(); EndPoint endPoint = null; while(!disposed) { try { // Reset the packet for the next round of data compoundPacket.Reset(); // Wait for data off the wire rtcpNetworkListener.ReceiveFrom(compoundPacket.Buffer, out endPoint); #region Fault Injection #if FaultInjection // Drop packets if (rtpSession.DropPacketsPercent > 0) { if (rtpSession.Rnd.Next(1, 100) <= rtpSession.DropPacketsPercent) { continue; } } #endif #endregion Fault Injection // Parse the data and rigorously validate it compoundPacket.ParseBuffer(); // Pass it on to the rtpSession to analyze and distribute data rtpSession.ProcessCompoundPacket(compoundPacket, ((IPEndPoint)endPoint).Address); } catch (System.Net.Sockets.SocketException e) { // No data received before timeout if (e.ErrorCode == 10060) { rtpSession.RaiseNetworkTimeoutEvent("Rtcp"); } // We get 10054 socket exceptions in some situations during unicast connections. Ignore them for now. // Pri2: Find a better solution for the unicast socket exceptions else if(e.ErrorCode == 10054 && !Utility.IsMulticast(rtcpNetworkListener.ExternalInterface) ) { continue; } else { Object[] args = new Object[]{this, new RtpEvents.HiddenSocketExceptionEventArgs((RtpSession)rtpSession, e)}; EventThrower.QueueUserWorkItem( new RtpEvents.RaiseEvent(RtpEvents.RaiseHiddenSocketExceptionEvent), args ); LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.Error); } } catch(RtcpHeader.RtcpHeaderException e) { // TODO - this is a pretty serious error - what should we do - exit thread, squelch? JVE LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.RtcpHeaderException); } catch(CompoundPacket.CompoundPacketException e) { // TODO - this is a pretty serious error - what should we do - exit thread, squelch? JVE LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.CompoundPacketException); } catch (ThreadAbortException) {} catch (Exception e) { LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.Error); } } }
private void Start() { //BufferChunk chunk = new BufferChunk(2048); CompoundPacket compoundPacket = new CompoundPacket(); EndPoint endPoint = null; while (isRunning) { try { compoundPacket.Reset(); udpListener.ReceiveFrom(compoundPacket.Buffer, out endPoint); compoundPacket.ParseBuffer(); //IPAddress ipAddress = ((IPEndPoint)endPoint).Address; IPEndPoint ipEndpoint = (IPEndPoint)endPoint; // The compound packet enumerator destroys its list during enumeration, // so we keep track of packets that have yet to be processed IList<RtcpPacket> yetToBeProcessed = new List<RtcpPacket>(); String venueName = null; //uint ssrc = 0; long when = 0; // in units of "ticks" // scan through the compound packet, looking for key pieces of meta-data // first, look for the app packet that specifies the venue // also, obtain the ssrc and the time stamp foreach (RtcpPacket packet in compoundPacket) { if (packet.PacketType == (byte)Rtcp.PacketType.APP) { AppPacket appPacket = new AppPacket(packet); if (appPacket.Name.Equals(Rtcp.APP_PACKET_NAME) && appPacket.Subtype == Rtcp.VENUE_APP_PACKET_SUBTYPE) { BufferChunk chunk = new BufferChunk(appPacket.Data); when = chunk.NextInt64(); venueName = chunk.NextUtf8String(chunk.Length); int padIndex = venueName.IndexOf((char)0); if (padIndex > 0) venueName = venueName.Substring(0, padIndex); } } else { yetToBeProcessed.Add(packet); } } if (venueName == null) continue; // can't do anything if we don't know the venue for this packet if (when == 0) continue; // need a timestamp VenueState venueState = null; // compound operations must always be locked... lock (venueStateMap) { if (!venueStateMap.ContainsKey(venueName)) venueState = new VenueState(venueName); else venueState = venueStateMap[venueName]; } // scan again, this time processing the RTCP packets foreach (RtcpPacket packet in yetToBeProcessed) { switch (packet.PacketType) { case (byte)Rtcp.PacketType.SR: { SrPacket sr = new SrPacket(packet); SenderData senderData = venueState.GetSenderState(sr.SSRC); senderData.Source = ipEndpoint; senderData.updateSenderState(sr.SenderReport, when); // this "refreshes" the host state (so that it won't expire) venueState.SenderData[sr.SSRC] = senderData; break; } case (byte)Rtcp.PacketType.RR: { RrPacket rr = new RrPacket(packet); ReceiverData receiverData = venueState.GetReceiverData (ipEndpoint); // currently, we replace all receiver summaries with the data // from a single RR packet receiverData.updateReceiverState(rr.ReceiverReports, when, venueState); // this "refreshes" the host state (so that it won't expire) venueState.ReceiverData[ipEndpoint] = receiverData; break; } case (byte)Rtcp.PacketType.SDES: { SdesPacket sdp = new SdesPacket(packet); foreach(SdesReport report in sdp.Reports()) { SenderData senderData = venueState.GetSenderState(report.SSRC); senderData.CName = report.SdesData.CName; senderData.Source = ipEndpoint; // this "refreshes" the host state (so that it won't expire) venueState.SenderData[report.SSRC] = senderData; ReceiverData receiverData = venueState.GetReceiverDataWithoutCreating(ipEndpoint); if (receiverData != null) receiverData.CName = report.SdesData.CName; } break; } case (byte)Rtcp.PacketType.BYE: { //BYE packets occur when capabilities stop. Clean out sender data only for the //ssrc's affected. We leave receiver reports alone for now. ByePacket byePacket = new ByePacket(packet); foreach (uint ssrc in byePacket.SSRCs) { venueState.SenderData.Remove(ssrc); } //Set a flag to cause the matrix for this venue to be rebuilt on the next request. venueState.ParticipantChange = true; continue; } case (byte)Rtcp.PacketType.APP: { // ignored break; } } } // foreach packet... // refresh the venue state venueStateMap[venueName] = venueState; } catch (Exception e) { Console.Out.WriteLine("Exception : " + e.ToString()); writeEventLog("Exception in receive thread: " + e.ToString(), EventLogEntryType.Warning); } } // loop forever... }