public void Dispose() { lock (classLock) { try { disposed = true; // Unhook events RtpEvents.ReceiverReport -= new RtpEvents.ReceiverReportEventHandler(RtpReceiverReport); RtpEvents.DuplicateCNameDetected -= new RtpEvents.DuplicateCNameDetectedEventHandler(DuplicateCNameDetected); if (updateThread != null) { updateThread.Dispose(); updateThread = null; } if (rtpSession != null) { rtpSession.Dispose(); rtpSession = null; rtpSender = null; } } catch (Exception e) { eventLog.WriteEntry(string.Format(CultureInfo.CurrentCulture, Strings.ErrorDisposingConnectivityDetector, e.ToString()), EventLogEntryType.Error, 0); } } }
protected override void CreateRtpSenders() { // // Don't call base.CreateRtpSenders, because we need to customize the // creation of our RtpSenders // videoSender = CreateRtpSender(videoProps); audioSender = CreateRtpSender(audioProps); }
private void InitializeNetwork() { RtpEvents.ReceiverReport += new RtpEvents.ReceiverReportEventHandler(RtpReceiverReport); RtpEvents.DuplicateCNameDetected += new RtpEvents.DuplicateCNameDetectedEventHandler(DuplicateCNameDetected); // Create participant rtpParticipant = new RtpParticipant(cName, name); rtpParticipant.SetTool(true); // Create session with Participant and Rtp data rtpSession = new RtpSession(new IPEndPoint(IPAddress.Parse(ipAddress), port), rtpParticipant, true, true); // Create RtpSender rtpSender = rtpSession.CreateRtpSender(HostName, PayloadType.PipecleanerSignal, null); }
/// <summary> /// Finishes the creation of an RtpSender by adding it to local collections and announcing /// it to the remote sites via an Rtcp packet /// </summary> private void _CreateRtpSender(RtpSender rtpSender) { // Add it to the collection lock(rtpSenders) { rtpSenders.Add(rtpSender.SSRC, rtpSender); } // We would like to try and have the stream constructed at the remote sites before the // Rtp data starts arriving so that none of it is missed. To help with that, when an // RtpSender is constructed, it sets an Sdes private extension indicating its payload // type. Here we force an Rtcp compound packet to be sent and give it a little time. rtcpSender.SendRtcpDataNow(); Thread.Sleep(250); }
private void InitializeNetwork() { RtpEvents.ReceiverReport += new RtpEvents.ReceiverReportEventHandler(RtpReceiverReport); RtpEvents.DuplicateCNameDetected += new RtpEvents.DuplicateCNameDetectedEventHandler(DuplicateCNameDetected); // Create participant rtpParticipant = new RtpParticipant(cName, name); rtpParticipant.SetTool(true); // Create session with Participant and Rtp data rtpSession = new RtpSession(new IPEndPoint(IPAddress.Parse(ipAddress), port), rtpParticipant, true, true); // Create RtpSender rtpSender = rtpSession.CreateRtpSender(HostName, PayloadType.PipecleanerSignal, null, null); }
private void DisposeSender() { // Pri2: Account for the case that the sender creation has been fired, but the sender hasn't yet been created. if (rtpSender != null) { this.rtpSender.Dispose(); this.rtpSender = null; } this.createSenderFired = false; }
public void Add(uint ssrc, RtpSender rtpSender) { Dictionary.Add(ssrc, rtpSender); }
/// <summary> /// Thread entry point for attempting to recreate the network connection /// </summary> private void ResetThread() { while( true ) { using( Synchronizer.Lock( this ) ) { try { // Try to Reconnect ushort fec; short interpacketdelay; using( Synchronizer.Lock( this.m_Model.SyncRoot ) ) { using( Synchronizer.Lock( this.m_Model.ViewerState.SyncRoot ) ) { fec = (ushort)this.m_Model.ViewerState.ForwardErrorCorrection; interpacketdelay = (short)this.m_Model.ViewerState.InterPacketDelay; } } if( fec == 0 ) this.m_RtpSender = this.m_RtpSession.CreateRtpSender( "Classroom Presenter", PayloadType.dynamicPresentation, null); else this.m_RtpSender = this.m_RtpSession.CreateRtpSenderFec( "Classroom Presenter", PayloadType.dynamicPresentation, null, 0, fec ); this.m_RtpSender.DelayBetweenPackets = interpacketdelay; return; } catch( Exception ) { System.Threading.Thread.Sleep( 100 ); } } } }
// CF1, CF2 private void DShowNetworkFiltersForm_Load(object sender, System.EventArgs e) { HookRtpEvents(); // CF1 JoinRtpSession(); // CF1 if(presenter) { // CF2 Add devices to UI foreach(FilterInfo fi in VideoSource.Sources()) { cklbCameras.Items.Add(fi); } rtpSender = rtpSession.CreateRtpSender("Video", PayloadType.dynamicVideo, null); // CF1 } else { cklbCameras.Visible = false; } }
/// <summary> /// Creates the RtpSender for this stream asynchronously. This causes the 500ms Thread.Sleep that occurs in /// RtpSession.CreateRtpSender to not cause performance problems during playback. /// </summary> private void CreateSender(object stateVar) { // For multi-threading safety purposes, we create the sender before assigning the new sender to the class variable. RtpSender newSender = rtpSession.CreateRtpSender(string.Format(CultureInfo.CurrentCulture, Strings.Playback, cname, name), this.streamPayload, this.privExtns); this.rtpSender = newSender; }
protected void DisposeRtpSender(RtpSender rtpSender) { if(!rtpSenders.Contains(rtpSender)) { throw new ArgumentException("RtpSender did not originate from this capability!"); } rtpSenders.Remove(rtpSender); rtpSender.Dispose(); }
/// <summary> /// Send all the frames that should be sent up to this point in time. /// </summary> /// <param name="bytesSent">Number of bytes sent.</param> /// <param name="cumulativeLateness">Sum of temporal disparities over all frames sent.</param> /// <param name="firstStoredTick">The 'start' time on the first index in this whole stream.</param> /// <param name="sender">The RtpSender to send data on.</param> /// <param name="startTimeTicks">The start time of sending, in ticks.</param> /// <param name="timeUntilFrame">The temporal distance between the current frame and the next one to be sent, in ticks.</param> /// <returns>Number of frames sent.</returns> public int SendFrames( RtpSender sender, long timeBoundary, out long timeUntilFrame, ref long totalBytesSent, ref long cumulativeLateness ) { if( this.populating ) throw new InvalidOperationException(Strings.BufferplayerSendframesError); int framesSent = 0; try { while ( currentIndex < indexCount && indices[currentIndex].timestamp <= timeBoundary ) { long startTimer = DateTime.Now.Ticks; int frameLength = 1 + indices[currentIndex].end - indices[currentIndex].start; if ( frameLength > 0) { // Calculate how late the frame will be long lateness = (timeBoundary - indices[currentIndex].timestamp) / Constants.TicksPerMs; if( lateness > Constants.TicksSpent ) Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "--- FRAME LATENESS OF: {0} ms", lateness)); cumulativeLateness += lateness; // Send Frame buffer.Reset( indices[currentIndex].start - indices[0].start, frameLength ); sender.Send( buffer ); } else { // (pbristow) Why would this happen??? Debug.Fail("Frame of length zero found."); } totalBytesSent += frameLength; ++framesSent; ++currentIndex; long takenTime = DateTime.Now.Ticks - startTimer; if( takenTime > Constants.TicksSpent ) Trace.WriteLine(String.Format(CultureInfo.InvariantCulture, "TIME WASTED TO SEND A FRAME: {0} ms, ID: {1}, bytes: {2}", (takenTime / Constants.TicksPerMs), streamID, frameLength)); } if ( currentIndex == indexCount ) { timeUntilFrame = 0; } else { timeUntilFrame = (indices[currentIndex].timestamp - timeBoundary); } } catch(ObjectDisposedException) { // Sender is disposed by Stop being called timeUntilFrame = long.MaxValue; } return framesSent; }
private void DisposeRtpSession() { if (rtpSession != null) { rtpSession.Dispose(); rtpSession = null; rtpSender = null; } }
public void JoinRTPSession(bool receive) { if (receive) { RegisterRtpUserEvents(); RegisterRtpStreamEvents(); } rtpSession = new RtpSession(network.GetChannel(channel), new RtpParticipant(Environment.MachineName, Environment.MachineName), true, receive); rtpSender = rtpSession.CreateRtpSender("VOIP Listener", PayloadType.dynamicAudio, null); }
public void RenderNetwork(RtpSender rtpSender) { if(rtpSender == null) { string msg = Strings.NullRtpSenderError; Debug.Fail(msg); throw new ArgumentNullException(Strings.RtpSender, msg); } renderer = (Renderer)Filter.NetworkRenderer(); ((IRtpRenderer)renderer.BaseFilter).Initialize2(rtpSender,this.rtpRendererFlags); iGB.AddFilter(renderer.BaseFilter, renderer.FriendlyName); renderer.AddedToGraph(fgm); // Connect last pin (device or compressor) to the network renderer iGB.Connect(compressor != null ? compressor.OutputPin : source.OutputPin, renderer.InputPin); }
/// <summary> /// Hooks up the provided renderer to a pin of the provided media type on the file /// </summary> /// <param name="renderer">The filter to render data to</param> /// <param name="mediaType">The type of pin to connect to this renderer</param> /// <param name="rtpSender">RtpSender that will be used by the renderer</param> /// <param name="filterName">The name of the render filter in the graph</param> private void HookUpFilter(ref IBaseFilter renderer, Guid mediaType, RtpSender rtpSender, string filterName) { // Pin the Guid, so we can pass it as an IntPtr GCHandle hGuid = GCHandle.Alloc(mediaType, GCHandleType.Pinned); try { // Only create the filter once if (renderer == null) { // ConferenceXP's custom filter for sending data over network renderer = MDShow.RtpRendererClass.CreateInstance(); // Initialize the filter with an RtpSender to use ((IRtpRenderer)renderer).Initialize(rtpSender); // Add filter to graph iGB.AddFilter(renderer, filterName); } // The WM file may not have a pin of the desired category, so this may fail // e.g. Audio only file won't have video, video may not have audio, etc. iCGB2.RenderStream(IntPtr.Zero, hGuid.AddrOfPinnedObject(), wmASFReader, null, renderer); } catch (COMException ce) { Console.WriteLine(ce.ToString()); } finally { // Always unpin the Guid hGuid.Free(); } }
protected RtpSender CreateRtpSender(RtpSenderProperties props) { // Setup private extensions Hashtable priExns = new Hashtable(); // Add unique ID Debug.Assert(props.ID != Guid.Empty); priExns.Add(PEP_IDENTIFIER, props.ID.ToString()); // Set the delay between packets now, so that it happens in the constructor and goes out with // the first RTCP packet priExns.Add(Rtcp.PEP_DBP, props.DelayBetweenPackets.ToString(CultureInfo.InvariantCulture)); // Set the channel-ness or ownership of the stream... if(props.Channel && props.OwnedByLocalParticipant) { throw new ArgumentException(Strings.CannotBeChannelAndOwned); } if(props.Channel) { priExns.Add(PEP_CHANNEL, true.ToString()); } else if(props.OwnedByLocalParticipant) { priExns.Add(PEP_CHANNEL, false.ToString()); } // else neither are true (i.e. it's owned but not by the local participant - a concept only possible in CXP...) // For capabilities with shared forms only if(props.SharedFormID != Guid.Empty) { priExns.Add(PEP_SHAREDFORM, props.SharedFormID.ToString()); } // Create the sender RtpSender rtpSender = null; if(props.FecEnabled && props.FecChecksum > 0) { rtpSender = Conference.RtpSession.CreateRtpSenderFec(props.Name, props.PayloadType, priExns, props.FecData, props.FecChecksum); } else { rtpSender = Conference.RtpSession.CreateRtpSender(props.Name, props.PayloadType, priExns); } // Add to collection rtpSenders.Add(rtpSender); return rtpSender; }
// CF1 private void LeaveRtpSession() { UnhookRtpEvents(); if(rtpSession != null) { rtpSession.Dispose(); rtpSession = null; rtpSender = null; rtpStream = null; } }
protected void DisposeRtpSender(RtpSender rtpSender) { if(!rtpSenders.Contains(rtpSender)) { throw new ArgumentException(Strings.DidNotOriginateFromHere); } rtpSenders.Remove(rtpSender); rtpSender.Dispose(); }
public RTPMessageSender(IPEndPoint ep, PresenterModel model, ClassroomModel classroom) { this.m_Model = model; this.m_Classroom = classroom; this.m_RtpLocalParticipant = new RtpLocalParticipant(this.m_Model.Participant); using(Synchronizer.Lock(this)) { // Register the stream event listeners first, since otherwise there would be a chance // that streams could be added between creating the RtpSession (which connects immediately). this.m_ParticipantManager = new ParticipantManager(this); this.m_RtpSession = new RtpSession(ep, this.m_RtpLocalParticipant, true, true); // TODO: Choose a meaningful value for the RtpSender name. ushort fec; short interpacketdelay; using (Synchronizer.Lock(model.SyncRoot)) { using (Synchronizer.Lock(model.ViewerState.SyncRoot)) { fec = (ushort)model.ViewerState.ForwardErrorCorrection; interpacketdelay = (short)model.ViewerState.InterPacketDelay; } } if( fec == 0 ) this.m_RtpSender = this.m_RtpSession.CreateRtpSender( "Classroom Presenter", PayloadType.dynamicPresentation, null ); else this.m_RtpSender = this.m_RtpSession.CreateRtpSenderFec( "Classroom Presenter", PayloadType.dynamicPresentation, null, 0, fec ); this.m_RtpSender.DelayBetweenPackets = interpacketdelay; // Initialize the message chunking utilities. this.m_Encoder = new Chunk.ChunkEncoder(); // TODO: Make the buffer size dynamic, ie., grow if we send a single very large message. // Make the buffer store up to 5MB worth of data. this.m_FrameBuffer = new FrameBuffer(5 * 1024 * 1024 / this.m_Encoder.MaximumChunkSize); // Create the NackManager which is responsible for sending NACKs on behalf of // our set of RTPMessageReceivers. this.m_NackManager = new RTPNackManager(this, this.m_Classroom); } // Create network services outside of the "lock(this)" so they can lock their own objects // without worrying about locking order. // Create the PresenterNetworkService which will watch for changes to the model and send messages. this.m_PresenterNetworkService = new PresenterNetworkService(this, this.m_Model); // Create the StudentSubmissionsNetworkService which will watch for requests to submit and send messages. this.m_StudentSubmissionNetworkService = new StudentSubmissionNetworkService(this, this.m_Model); // Create the SynchronizationNetworkService which will watch for all synchronization messages. this.m_SynchronizationNetworkService = new SynchronizationNetworkService( this, this.m_Model ); // Create the ScriptingNetworkService which will watch for all scripting messages. this.m_ScriptingNetworkService = new ScriptingNetworkService( this, this.m_Model ); // Create the BeaconService which will broadcast periodic information about the presentation. this.m_BeaconService = new Beacons.DefaultBeaconService(this, this.m_Model); }
protected virtual void CreateRtpSenders() { // If the derived class hasn't created its own RtpSender, create one for it if (rtpSender == null) { rtpSender = CreateRtpSender(); msSend = new MemoryStream(); bfSend = new BinaryFormatter(); } // If the derived class hasn't created its own RtpSenderBackground, create one for it if(capProps.BackgroundSender) { if (rtpSenderBackground == null) { rtpSenderBackground = CreateRtpSender(); msSendBackground = new MemoryStream(); bfSendBackground = new BinaryFormatter(); } } }
protected void DisposeRtpSenders() { if (this.rtpSender != null) { DisposeRtpSender(this.rtpSender); this.rtpSender = null; } if(rtpSenderBackground != null) { DisposeRtpSender(rtpSenderBackground); rtpSenderBackground = null; } // Dispose any other RtpSenders that were created foreach(RtpSender rtpSender in (ArrayList)rtpSenders.Clone()) { DisposeRtpSender(rtpSender); } }
/// <summary> /// Creates the RtpSender for this stream asynchronously. This causes the 500ms Thread.Sleep that occurs in /// RtpSession.CreateRtpSender to not cause performance problems during playback. /// </summary> private void CreateSender(object stateVar) { // For multi-threading safety purposes, we create the sender before assigning the new sender to the class variable. RtpSender newSender = rtpSession.CreateRtpSender( "Playback: " + cname + " : " + name, this.streamPayload, this.privExtns ); this.rtpSender = newSender; }
private void _SendObject(object o, RtpSender rtpSender, MemoryStream ms, BinaryFormatter bf) { if (disposed) { throw new ObjectDisposedException(name); } if(!isSending) { throw new ApplicationException(string.Format(CultureInfo.CurrentCulture, Strings.CallSendBeforeSendObject, name)); } ms.Position = 0; // set the "useful bytes" "pointer" back to 0 bf.Serialize(ms, o); // serialize, which puts the "useful bytes pointer" at the end of hte useful data // Get a byte[] of the serialized object int numBytes = (int)ms.Position; // record the number of "useful bytes" byte[] byteObj = new Byte[numBytes]; ms.Position = 0; // set the pointer back to 0, so we can read from that point ms.Read(byteObj, 0, numBytes); // read all the useful bytes rtpSender.Send(byteObj); }
public RTPSendConnection(IPEndPoint ipe) { this.m_Participant = new RtpParticipant(Guid.NewGuid().ToString(), "Classroom Playback"); this.m_Session = new RtpSession(ipe, this.m_Participant, true, false); this.m_Sender = this.m_Session.CreateRtpSenderFec("Classroom Presenter", PayloadType.dynamicPresentation, null, 0, 100); this.m_Queue = new SendingQueue(this); }
public void RenderNetwork(RtpSender rtpSender) { if(rtpSender == null) { string msg = "Null is not a valid value for parameter 'rtpSender'"; Debug.Fail(msg); throw new ArgumentNullException("rtpSender", msg); } renderer = (Renderer)Filter.NetworkRenderer(); ((IRtpRenderer)renderer.BaseFilter).Initialize(rtpSender); iGB.AddFilter(renderer.BaseFilter, renderer.FriendlyName); renderer.AddedToGraph(fgm); // Connect last pin (device or compressor) to the network renderer iGB.Connect(compressor != null ? compressor.OutputPin : source.OutputPin, renderer.InputPin); }
public void Dispose() { lock(classLock) { try { disposed = true; // Unhook events RtpEvents.ReceiverReport -= new RtpEvents.ReceiverReportEventHandler(RtpReceiverReport); RtpEvents.DuplicateCNameDetected -= new RtpEvents.DuplicateCNameDetectedEventHandler(DuplicateCNameDetected); if(updateThread != null) { updateThread.Dispose(); updateThread = null; } if(rtpSession != null) { rtpSession.Dispose(); rtpSession = null; rtpSender = null; } } catch(Exception e) { eventLog.WriteEntry("Error disposing ConnectivityDetector. \n" + e.ToString(), EventLogEntryType.Error, 0); } } }
// CF2 Create participant, join session // CF3 Retrieve RtpSender private void JoinRtpSession(string name) { rtpSession = new RtpSession(ep, new RtpParticipant(name, name), true, true); rtpSender = rtpSession.CreateRtpSenderFec(name, PayloadType.Chat, null, 0, 200); }
public virtual void RenderNetwork(RtpSender rtpSender, PayloadType payload) { RenderNetwork(rtpSender); }
private void LeaveRtpSession() { if(rtpSession != null) { // Clean up all outstanding objects owned by the RtpSession rtpSession.Dispose(); rtpSession = null; rtpSender = null; } }
/// <summary> /// Connect up a branch of the graph for network sending. Source filter should already be in the graph. /// DVSplitter and compressor may also already be connected, but for uncompressed cases, the Splitter /// may not be there yet. /// </summary> /// <param name="rtpSender"></param> /// <param name="payload"></param> public override void RenderNetwork(RtpSender rtpSender, PayloadType payload) { if (rtpSender == null) { string msg = Strings.NullRtpSenderError; Debug.Fail(msg); throw new ArgumentNullException(Strings.RtpSender, msg); } //Splitter may not yet be added in network scenarios without compression if (!this.AddDVSplitter()) { throw new ApplicationException("Failed to add DV Splitter"); } networkContext = true; if (payload == PayloadType.dynamicVideo) { videoRenderer = (Renderer)Filter.NetworkRenderer(); ((IRtpRenderer)videoRenderer.BaseFilter).Initialize2(rtpSender, this.rtpRendererFlags); iGB.AddFilter(videoRenderer.BaseFilter, videoRenderer.FriendlyName); videoRenderer.AddedToGraph(fgm); iGB.Connect(videoCompressor != null ? videoCompressor.OutputPin : splitterVideoOut, videoRenderer.InputPin); } else if (payload == PayloadType.dynamicAudio) { audioRenderer = (Renderer)Filter.NetworkRenderer(); ((IRtpRenderer)audioRenderer.BaseFilter).Initialize2(rtpSender, this.rtpRendererFlags); iGB.AddFilter(audioRenderer.BaseFilter, audioRenderer.FriendlyName); audioRenderer.AddedToGraph(fgm); iGB.Connect(audioCompressor != null ? audioCompressor.OutputPin : splitterAudioOut, audioRenderer.InputPin); } }
public void RtpSenders(RtpSender audioSender, RtpSender videoSender) { this.audioSender = audioSender; this.videoSender = videoSender; }