/// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="source"></param> /// <param name="client"></param> /// <param name="perPacket"></param> public RtpSource(string name, System.Uri source, Rtp.RtpClient client, bool perPacket = false) : this(name, source, perPacket) { if (IDisposedExtensions.IsNullOrDisposed(client)) { throw new ExceptionExtensions.ArgumentNullOrDisposedException(client); } RtpClient = client; }
public override void Dispose() { if (IsDisposed || ShouldDispose.Equals(false)) { return; } base.Dispose(); if (IDisposedExtensions.IsNullOrDisposed(RtpClient).Equals(false)) { RtpClient.Dispose(); RtpClient = null; } }
public override void Stop() { Ready = false; if (m_Watcher != null) { m_Watcher.EnableRaisingEvents = false; //m_Watcher.Created -= FileCreated; m_Watcher.Dispose(); m_Watcher = null; } if (m_RtpClient != null) { m_RtpClient.Disconnect(); m_RtpClient = null; } m_Frames.Clear(); SessionDescription = null; base.Stop(); }
public void TestBroadcast() { string testVector = @"v=0 o=sip 1247 1247 IN IP4 255.255.255.255 s=Talk c=IN IP4 255.255.255.255 t=0 0 m=video 5550 RTP/AVP 99 a=rtpmap:99 H264/90000 a=sendonly"; //Parse the sdp using (var sdp = new Media.Sdp.SessionDescription(testVector)) { //Verify the parsing if (false.Equals(sdp.Lines.Count().Equals(8))) { throw new System.Exception("Did not parse all lines"); } //Verify that a RtpClient can be created, since no ports are specified the default for rtp and rtcp are used. //Initialize fails on the attempt to hole punch and ports are set to 0. using (Rtp.RtpClient test = Rtp.RtpClient.FromSessionDescription(sdp)) { //Verify that there are the expected amount of context's if (false.Equals(test.GetTransportContexts().Count().Equals(1))) { throw new System.Exception("Unexpected amount of TransportContext's"); } Rtp.RtpClient.TransportContext firstContext = test.GetTransportContexts().First(); System.Net.IPEndPoint localEndPoint = firstContext.RtpSocket.Connected ? firstContext.RtpSocket.LocalEndPoint as System.Net.IPEndPoint : firstContext.LocalRtp as System.Net.IPEndPoint; //Verify our address addresses if (true.Equals(localEndPoint == null)) { throw new System.Exception("Unexpected LocalRtp or RtpSocket.LocalEndPoint"); } if (false.Equals(Common.Extensions.IPAddress.IPAddressExtensions.IsMulticast(localEndPoint.Address))) { throw new System.Exception("Unexpected IPAddress type for LocalEndPoint"); } //Get the first MulticastIPAddress on the system and ensure that it is equal to the IPAddress which would be used locally by the RtpClient //This may be different depending on the network which is being connected to in a real application. if (false.Equals(Common.Extensions.Socket.SocketExtensions.GetFirstMulticastIPAddress(localEndPoint.AddressFamily).Equals(localEndPoint.Address))) { throw new System.Exception("Unexpected RtpSocket.LocalEndPoint.IPAddress"); } //Verify their address System.Net.IPEndPoint remoteEndPoint = firstContext.RtpSocket.Connected ? firstContext.RtpSocket.RemoteEndPoint as System.Net.IPEndPoint as System.Net.IPEndPoint : firstContext.RemoteRtp as System.Net.IPEndPoint; if (true.Equals(remoteEndPoint == null)) { throw new System.Exception("Unexpected RemoteRtp or RtpSocket.RemoteEndPoint"); } if (false.Equals(System.Net.IPAddress.Broadcast.Equals(remoteEndPoint.Address)) && false.Equals(Common.Extensions.IPAddress.IPAddressExtensions.IsMulticast(remoteEndPoint.Address))) { throw new System.Exception("Unexpected IPAddress for RemoteEndPoint"); } } } }
//SUpparioucly thought that the last frame would remain in a not final state so one should check that the Goodbye has not been received when processing the event... //Shows what happpens when packets get out of order too badely.. public void TestFrameChangedEvents() { using (Rtp.RtpClient rtpClient = new Rtp.RtpClient()) { //Fire Frames with single packets and order = 3, 1, 2. //Each have marker //What is the expected order(3 final, 1 final, 2 final)? and count (3)! int count = 0, fcount = 0; Rtp.RtpClient.TransportContext tc = new Rtp.RtpClient.TransportContext(0, 1, 0); //Needed to resolve packet payload and avoid exception when validating packet... :( tc.MediaDescription = new Sdp.MediaDescription(Sdp.MediaType.unknown, 0, "RTP", 0); rtpClient.AddContext(tc); rtpClient.FrameChangedEventsEnabled = true; rtpClient.RtpFrameChanged += (s, z, t, f) => { ++count; if (f) { ++fcount; } Console.WriteLine("RtpFrameChanged=>" + z.HighestSequenceNumber + z.HasMarker + f); }; Console.WriteLine("Count: " + count); Console.WriteLine("Final Count: " + fcount); int tests = 4; Rtp.RtpPacket rtpPacket = new Rtp.RtpPacket(12) { Timestamp = tests * 1000, SequenceNumber = tests, Marker = true }; for (int i = tests; i >= 0; --i) { rtpPacket.Timestamp -= tests * 1000; rtpPacket.SequenceNumber = i; rtpClient.HandleIncomingRtpPacket(null, rtpPacket, tc); } //8 Frame Changes only 3 are final... if (count != tests || fcount != tests) { throw new Exception(); } count = fcount = 0; rtpPacket.SequenceNumber = 4; rtpPacket.Timestamp = 4000; rtpClient.HandleIncomingRtpPacket(null, rtpPacket, tc); rtpPacket.SequenceNumber = 1; rtpPacket.Timestamp = 1000; rtpClient.HandleIncomingRtpPacket(null, rtpPacket, tc); rtpPacket.SequenceNumber = 3; rtpPacket.Timestamp = 3000; rtpClient.HandleIncomingRtpPacket(null, rtpPacket, tc); rtpPacket.SequenceNumber = 2; rtpPacket.Timestamp = 2000; rtpClient.HandleIncomingRtpPacket(null, rtpPacket, tc); if (count != tests || fcount != tests) { throw new Exception(); } } }
/// <summary> /// /// </summary> /// <param name="name"></param> /// <param name="source"></param> /// <param name="client"></param> /// <param name="perPacket"></param> public RtpSink(string name, System.Uri source, Rtp.RtpClient client, bool perPacket = false) : base(name, source, perPacket) { //RtpClient = client; }
//SourceStream Implementation public override void Start() { if (m_RtpClient != null) { return; } //Create a RtpClient so events can be sourced from the Server to many clients without this Client knowing about all participants //If this class was used to send directly to one person it would be setup with the recievers address m_RtpClient = new Rtp.RtpClient(); SessionDescription = new Sdp.SessionDescription(0, "v√ƒ", Name); SessionDescription.Add(new Sdp.Lines.SessionConnectionLine() { ConnectionNetworkType = Sdp.Lines.SessionConnectionLine.InConnectionToken, ConnectionAddressType = Sdp.SessionDescription.WildcardString, ConnectionAddress = System.Net.IPAddress.Any.ToString() }); //Add a MediaDescription to our Sdp on any available port for RTP/AVP Transport using the RtpJpegPayloadType SessionDescription.Add(new Sdp.MediaDescription(Sdp.MediaType.video, 0, Rtp.RtpClient.RtpAvpProfileIdentifier, RFC2435Media.RFC2435Frame.RtpJpegPayloadType)); //Indicate control to each media description contained SessionDescription.Add(new Sdp.SessionDescriptionLine("a=control:*")); //Ensure the session members know they can only receive SessionDescription.Add(new Sdp.SessionDescriptionLine("a=sendonly")); //recvonly? //that this a broadcast. SessionDescription.Add(new Sdp.SessionDescriptionLine("a=type:broadcast")); //Add a Interleave (We are not sending Rtcp Packets becaues the Server is doing that) We would use that if we wanted to use this ImageSteam without the server. //See the notes about having a Dictionary to support various tracks m_RtpClient.TryAddContext(new Rtp.RtpClient.TransportContext(0, 1, sourceId, SessionDescription.MediaDescriptions.First(), false, 0)); //Add the control line SessionDescription.MediaDescriptions.First().Add(new Sdp.SessionDescriptionLine("a=control:trackID=1")); //Add the line with the clock rate in ms, obtained by TimeSpan.TicksPerMillisecond * clockRate //Make the thread m_RtpClient.m_WorkerThread = new System.Threading.Thread(SendPackets); m_RtpClient.m_WorkerThread.TrySetApartmentState(System.Threading.ApartmentState.MTA); //m_RtpClient.m_WorkerThread.IsBackground = true; //m_RtpClient.m_WorkerThread.Priority = System.Threading.ThreadPriority.BelowNormal; m_RtpClient.m_WorkerThread.Name = "SourceStream-" + Id; //If we are watching and there are already files in the directory then add them to the Queue if (m_Watcher != null && !string.IsNullOrWhiteSpace(base.Source.LocalPath) && System.IO.Directory.Exists(base.Source.LocalPath)) { foreach (string file in System.IO.Directory.GetFiles(base.Source.LocalPath)) { if (false == SupportedImageFormats.Any(ext => file.EndsWith(ext, StringComparison.OrdinalIgnoreCase))) { continue; } } //If we have not been stopped already if (/*State != StreamState.Started && */ m_RtpClient.m_WorkerThread != null) { //Only ready after all pictures are in the queue Ready = true; m_RtpClient.m_WorkerThread.Start(); } } else { //We are ready Ready = true; m_RtpClient.m_WorkerThread.Start(); } base.Start(); }
public RtspSink(string name, System.Uri source, Rtp.RtpClient client, bool perPacket = false) : base(name, source, perPacket, new RtspClient(RtspMessage.Wildcard)) { RtpClient = client; }