internal void OnFrameReceivedEvent(BufferChunk frame) { framesReceived++; // Don't trigger the event if it isn't hooked // Although RtpEvents.FireEvent does this same check, we add it here for efficiency // As audio / video streams create alot of data, but don't use the FrameReceived event if (FrameReceived != null) { if (framesReceived == 1) { OnFirstFrameReceivedEvent(); } object[] args = { this, new FrameReceivedEventArgs(this, frame) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RaiseFrameReceivedEvent), args); } else // Audio and Video { if (frameReceived) { if (framesReceived == 1) { firstFrame = frame.Peek(frame.Index, frame.Length); OnFirstFrameReceivedEvent(); } lastFrame = frame; frameReceived = false; nextFrameEvent.Set(); } } }
internal void RaiseInvalidPacketInFrameEvent(string reason) { ++invalidPacketInFrameEvents; object[] args = { this, new RtpEvents.InvalidPacketInFrameEventArgs(this, reason) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseInvalidPacketInFrameEvent), args); }
// All of these events are called by Frame, and hence are internal // TODO - try to decouple JVE #region PacketOutOfSequence internal void RaisePacketOutOfSequenceEvent(int packetsLost, string message) { this.packetsLost += packetsLost; object[] args = { this, new RtpEvents.PacketOutOfSequenceEventArgs(this, packetsLost, message) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaisePacketOutOfSequenceEvent), args); }
/// <summary> /// Raises the ParticipantStatusChanged event if the data changed /// </summary> /// <param name="data"></param> internal new void UpdateData(SdesData data) { if (base.UpdateData(data)) { object[] args = { this, new RtpEvents.RtpParticipantEventArgs(this) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseRtpParticipantDataChangedEvent), args); } }
internal void RaiseFrameOutOfSequenceEvent(int framesLost, string message) { Trace.Assert(framesLost > 0, "framesLost should be greater than 0"); this.framesLost += framesLost; object[] args = { this, new RtpEvents.FrameOutOfSequenceEventArgs(this, framesLost, message) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseFrameOutOfSequenceEvent), args); }
private void ReceivePackets() { BufferChunk bc = null; while (true) { try { bc = GetBuffer(); EndPoint ep; rtpNetworkListener.ReceiveFrom(bc, out ep); receivedPackets.Enqueue(new object[] { bc, ep }); newPacket.Set(); unchecked { pcPackets++; } } catch (ThreadAbortException) {} catch (PoolExhaustedException e) { LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.UnboundedGrowth); return; // Exit the thread gracefully } catch (System.Net.Sockets.SocketException e) { ReturnBuffer(bc); // Something other than - No data received before timeout if (e.ErrorCode != 10060) { 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 (Exception e) { ReturnBuffer(bc); LogEvent(e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.Error); } } }
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); } } }
internal void OnDataStoppedEvent() { object[] args = { this, null }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RaiseDataStoppedEvent), args); }
internal void OnFirstFrameReceivedEvent() { object[] args = { this, null }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RaiseFirstFrameReceivedEvent), args); }
/// <summary> /// Collects the Rtcp data from the session, assembles it into CompoundPackets (via the /// CompoundPacketBuilder) and sends the packets /// /// The current design has a "forced" Send occurring on the thread that makes the call, and /// a normal Send occurring on the dedicated RtcpSender thread. /// /// To make sure that multiple threads aren't making the call at the same time, which can /// lead to data access exceptions (e.g. Queue empty), we lock here. /// </summary> /// <param name="forced">Is Send being called due to timing rules, or forced?</param> private void Send(bool forced) { lock (this) { try { // We're Sending despite timing rules if (forced) { lastSendForced = true; } else // We're Sending due to timing rules { // The timing rules may now be in conflict with a previous forced Send // Ask the timing rules to reconsider again before Sending if (lastSendForced) { lastSendForced = false; return; } } CompoundPacketBuilder cpb = rtpSession.RtcpReportIntervalReached(); cpb.BuildCompoundPackets(); Debug.Assert(cpb.PacketCount > 0); // Send all compound packets (in case there is more than 1) short packetCount = cpb.PacketCount; int bytes = 0; foreach (CompoundPacket cp in cpb) { BufferChunk data = cp.Data; bytes += data.Length; rtcpNetworkSender.Send(data); } // How long between the last send time and now TimeSpan interval = DateTime.Now - lastSendTime; // Update lastSendTime lastSendTime = DateTime.Now; // Update performance data // Packets before bytes, since packets doesn't have any dependencies // but BytesPerPacket requires a correct reading on the packet count UpdatePerformancePackets(packetCount); UpdatePerformanceBytes(bytes); UpdatePerformanceInterval(interval, forced); } catch (ThreadAbortException) {} catch (Exception e) { if (e is System.Net.Sockets.SocketException) { Object[] args = new Object[] { this, new RtpEvents.HiddenSocketExceptionEventArgs((RtpSession)rtpSession, (System.Net.Sockets.SocketException)e) }; EventThrower.QueueUserWorkItem(new RtpEvents.RaiseEvent(RtpEvents.RaiseHiddenSocketExceptionEvent), args); } rtpSession.LogEvent("RtcpSender", e.ToString(), EventLogEntryType.Error, (int)RtpEL.ID.Error); } } }