Ejemplo n.º 1
0
 public Sdp.SessionDescription CreateSessionDescription(int version = 0)
 {
     Sdp.SessionDescription sdp = new Sdp.SessionDescription(version);
     foreach (Sdp.MediaDescription md in MediaDescriptions.Values)
     {
         sdp.Add(new Sdp.MediaDescription(md));
     }
     return(sdp);
 }
Ejemplo n.º 2
0
        //Writes a .Sdp file
        public virtual void WriteDescription(IMedia stream, Sdp.SessionDescription sdp)
        {
            if (!IsArchiving(stream))
            {
                return;
            }

            //Add lines with Alias info?

            System.IO.File.WriteAllText(BaseDirectory + '/' + stream.Id + '/' + "SessionDescription.sdp", sdp.ToString());
        }
Ejemplo n.º 3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="name"></param>
        /// <param name="sessionDescription"></param>
        public RtpSource(string name, Sdp.SessionDescription sessionDescription)
            : base(name, new System.Uri(string.Join(System.Uri.SchemeDelimiter, Rtp.RtpClient.RtpProtcolScheme, ((Sdp.Lines.SessionConnectionLine)sessionDescription.ConnectionLine).Host)))
        {
            if (IDisposedExtensions.IsNullOrDisposed(sessionDescription))
            {
                throw new ExceptionExtensions.ArgumentNullOrDisposedException("sessionDescription", sessionDescription);
            }

            RtpClient = Rtp.RtpClient.FromSessionDescription(SessionDescription = sessionDescription);

            RtpClient.FrameChangedEventsEnabled = PerPacket == false;
        }
Ejemplo n.º 4
0
        public RtpSource(string name, Sdp.SessionDescription sessionDescription)
            : base(name, new Uri(Rtp.RtpClient.RtpProtcolScheme + "://" + ((Sdp.Lines.SessionConnectionLine)sessionDescription.ConnectionLine).IPAddress))
        {
            if (sessionDescription == null)
            {
                throw new ArgumentNullException("sessionDescription");
            }

            RtpClient = Rtp.RtpClient.FromSessionDescription(SessionDescription = sessionDescription);

            RtpClient.FrameChangedEventsEnabled = PerPacket == false;
        }
Ejemplo n.º 5
0
        //Todo, cleanup and allow existing Rtp and Rtcp socket.

        /// <summary>
        /// Will create a <see cref="RtpClient"/> based on the given parameters
        /// </summary>
        /// <param name="sessionDescription"></param>
        /// <param name="sharedMemory"></param>
        /// <param name="incomingEvents"></param>
        /// <param name="rtcpEnabled"></param>
        /// <returns></returns>
        public static RtpClient FromSessionDescription(Sdp.SessionDescription sessionDescription, Common.MemorySegment sharedMemory = null, bool incomingEvents = true, bool rtcpEnabled = true, System.Net.Sockets.Socket existingSocket = null, int?rtpPort = null, int?rtcpPort = null, int remoteSsrc = 0, int minimumSequentialRtpPackets = 2, bool connect = true, System.Action <System.Net.Sockets.Socket> configure = null)
        {
            if (Common.IDisposedExtensions.IsNullOrDisposed(sessionDescription))
            {
                throw new System.ArgumentNullException("sessionDescription");
            }

            Sdp.Lines.SessionConnectionLine connectionLine = new Sdp.Lines.SessionConnectionLine(sessionDescription.ConnectionLine);

            System.Net.IPAddress remoteIp = System.Net.IPAddress.Parse(connectionLine.Host), localIp;

            System.Net.NetworkInformation.NetworkInterface localInterface;

            //If the socket is NOT null and IS BOUND use the localIp of the same address family
            if (object.ReferenceEquals(existingSocket, null).Equals(false) && existingSocket.IsBound)
            {
                //If the socket is IP based
                if (existingSocket.LocalEndPoint is System.Net.IPEndPoint)
                {
                    //Take the localIp from the LocalEndPoint
                    localIp = (existingSocket.LocalEndPoint as System.Net.IPEndPoint).Address;
                }
                else
                {
                    throw new System.NotSupportedException("Please create an issue for your use case.");
                }
            }
            else // There is no socket existing.
            {
                //If the remote address is the broadcast address or the remote address is multicast
                if (System.Net.IPAddress.Broadcast.Equals(remoteIp) || IPAddressExtensions.IsMulticast(remoteIp))
                {
                    //This interface should be the interface you plan on using for the Rtp communication
                    localIp = SocketExtensions.GetFirstMulticastIPAddress(remoteIp.AddressFamily, out localInterface);
                }
                else
                {
                    //This interface should be the interface you plan on using for the Rtp communication
                    localIp = SocketExtensions.GetFirstUnicastIPAddress(remoteIp.AddressFamily, out localInterface);
                }
            }

            RtpClient client = new RtpClient(sharedMemory, incomingEvents);

            byte lastChannel = 0;

            //Todo, check for session level ssrc
            //if (remoteSsrc.Equals(0))
            //{
            //    //Sdp.SessionDescriptionLine ssrcLine = sessionDescription.SsrcGroupLine; // SsrcLine @ the session level could imply Group
            //}

            //For each MediaDescription in the SessionDescription
            foreach (Media.Sdp.MediaDescription md in sessionDescription.MediaDescriptions)
            {
                //Make a RtpClient.TransportContext from the MediaDescription being parsed.
                TransportContext tc = TransportContext.FromMediaDescription(sessionDescription, lastChannel++, lastChannel++, md,
                                                                            rtcpEnabled, remoteSsrc, minimumSequentialRtpPackets,
                                                                            localIp, remoteIp, //The localIp and remoteIp
                                                                            rtpPort, rtcpPort, //The remote ports to receive data from
                                                                            connect, existingSocket, configure);

                //Try to add the context
                try
                {
                    client.AddContext(tc);
                }
                catch (System.Exception ex)
                {
                    TaggedExceptionExtensions.RaiseTaggedException(tc, "See Tag, Could not add the created TransportContext.", ex);
                }
            }

            //Return the participant
            return(client);
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Dynamically creates a Sdp.SessionDescription for the given SourceStream using the information already present and only re-writing the necessary values.
        /// </summary>
        /// <param name="stream">The source stream to create a SessionDescription for</param>
        /// <returns>The created SessionDescription</returns>
        internal Sdp.SessionDescription CreateSessionDescription(SourceMedia stream)
        {
            if (stream == null) throw new ArgumentNullException("stream");
            //else if (SessionDescription != null) throw new NotImplementedException("There is already a m_SessionDescription for this session, updating is not implemented at this time");

            string sessionId = Media.Ntp.NetworkTimeProtocol.DateTimeToNptTimestamp(DateTime.UtcNow).ToString(), sessionVersion = Media.Ntp.NetworkTimeProtocol.DateTimeToNptTimestamp(DateTime.UtcNow).ToString();

            string originatorString = "ASTI-Media-Server " + sessionId + " " + sessionVersion + " IN " + (m_RtspSocket.AddressFamily == AddressFamily.InterNetworkV6 ? "IP6 " : "IP4 " ) + ((IPEndPoint)m_RtspSocket.LocalEndPoint).Address.ToString();

            string sessionName = "ASTI-Streaming-Session-" + stream.Name;

            Sdp.SessionDescription sdp;

            RtpClient sourceClient;

            if (stream is RtpSource)
            {
                RtpSource rtpSource = stream as RtpSource;
                //Make the new SessionDescription
                sdp = new Sdp.SessionDescription(rtpSource.SessionDescription.ToString());

                //Remove the old connection lines if they exist
                while(sdp.ConnectionLine != null) sdp.Remove(sdp.ConnectionLine, false);

                sourceClient = rtpSource.RtpClient;
            }
            else
            {
                sdp = new Sdp.SessionDescription(0);
            }

            //Change the DocumentVersion and update the name
            sdp.SessionName = sessionName;

            //Change the DocumentVersion and update the originator
            sdp.OriginatorAndSessionIdentifier = originatorString;

            //Type = broadcast
            //charset

            string protcol = RtspMessage.MessageIdentifier.ToLowerInvariant(), controlLineBase = "a=control:" + protcol + "://" + ((IPEndPoint)(m_RtspSocket.LocalEndPoint)).Address.ToString() + "/live/" + stream.Id;
            //check for rtspu later...

            //Find an existing control line
            Media.Sdp.SessionDescriptionLine controlLine = sdp.ControlLine;

            //If there was one remove it
            while (controlLine != null)
            {
                sdp.Remove(controlLine);
                controlLine = sdp.ControlLine;
            }
            //Determine if session level control line should be present

            //Rewrite a new connection line
            string addressString = LocalEndPoint.Address.ToString();// +"/127/2";

            //int lastPort = Utility.FindOpenPort( stream.m_ForceTCP ? ProtocolType.Tcp : ProtocolType.Udp);

            //Indicate a port in the sdp, setup should also use this port, this should essentially reserve the port for the setup process...
            //if (!stream.m_ForceTCP)
                //addressString += "/127" +'/' +  lastPort + 1;
            //else
                //addressString += + ((IPEndPoint)RemoteEndPoint).Port;

            //Check for the existing connectionLine
            Sdp.Lines.SessionConnectionLine connectionLine = sdp.ConnectionLine as Sdp.Lines.SessionConnectionLine;

            //Add the new line if needed
            if (connectionLine == null) sdp.ConnectionLine = connectionLine = new Sdp.Lines.SessionConnectionLine()
            {
                ConnectionAddress = addressString,
                ConnectionAddressType = m_RtspSocket.AddressFamily == AddressFamily.InterNetworkV6 ? Media.Sdp.Lines.SessionConnectionLine.IP6 : Media.Sdp.Lines.SessionConnectionLine.IP4,
                ConnectionNetworkType = Media.Sdp.Lines.SessionConnectionLine.InConnectionToken
            };

            IEnumerable<Sdp.SessionDescriptionLine> bandwithLines;

            //Indicate that the server will not accept media as input for this session
            //Put the attribute in the Session Description,
            //Should check that its not already set?
            //sdp.Add(new Sdp.SessionDescriptionLine("a=recvonly"));

            //Remove any existing session range lines, don't upate the version
            while (sdp.RangeLine != null) sdp.Remove(sdp.RangeLine, false);

            //Todo add a Range line which shows the length of this media.

            //Iterate the source MediaDescriptions, could just create a new one with the fmt which contains the profile level information
            foreach (Sdp.MediaDescription md in sdp.MediaDescriptions)
            {
                //Find a control line
                controlLine = md.ControlLine;

                //Rewrite it if present to reflect the appropriate MediaDescription
                while (controlLine != null)
                {
                    md.Remove(controlLine);
                    controlLine = md.ControlLine;
                }

                //Remove old bandwith lines
                bandwithLines = md.BandwidthLines;

                //Remove existing bandwidth information, should check for AS
                if(stream.m_DisableQOS) foreach (Sdp.SessionDescriptionLine line in bandwithLines) md.Remove(line);

                //Remove all other alternate information
                //Should probably only remove certain ones.
                foreach (Sdp.SessionDescriptionLine line in md.Lines.Where(l => l.Parts.Any(p => p.Contains("alt"))).ToArray()) md.Remove(line);

                //Add a control line for the MedaiDescription (which is `rtsp://./Id/audio` (video etc)
                //Should be a TrackId and not the media type to allow more then one media type to be controlled.
                //e.g. Two audio streams or text streams is valid.
                md.Add(new Sdp.SessionDescriptionLine("a=control:" + "/live/" + stream.Id + '/' + md.MediaType));

                //Add the connection line for the media
                //md.Add(connectionLine);

                //Should check for Timing Info and update for playing streams

                if (stream.m_DisableQOS)
                {
                    md.Add(Sdp.Lines.SessionBandwidthLine.DisabledSendLine);
                    md.Add(Sdp.Lines.SessionBandwidthLine.DisabledReceiveLine);
                    md.Add(Sdp.Lines.SessionBandwidthLine.DisabledApplicationSpecificLine);
                }
                //else
                //{
                //    //ToDo use whatever values are defined for the session's bandwidth atp
                //    md.Add(new Sdp.SessionDescriptionLine("b=RS:140"));
                //    md.Add(new Sdp.SessionDescriptionLine("b=RR:140"));

                //    md.Add(new Sdp.SessionDescriptionLine("b=AS:0")); //Determine if AS needs to be forwarded
                //}

                //Should actually reflect outgoing port for this session
                md.MediaPort = 0;

                //Determine if attached and set the MediaPort.
                if (m_RtpClient != null)
                {
                    var context = m_RtpClient.GetContextForMediaDescription(md);

                    if (context != null) md.MediaPort = ((IPEndPoint)context.RemoteRtp).Port;

                    //Set any other variables which may be been changed in the session
                }

                #region Independent TCP

                //if (!stream.m_ForceTCP)
                //{
                //    //md.MediaPort = lastPort;
                //    //lastPort += 2;
                //}
                //else
                //{
                //    //VLC `Blows up` when this happens
                //    //bad SDP "m=" line: m=audio 40563 TCP/RTP/AVP 96
                //    //md.MediaProtocol = "TCP/RTP/AVP";
                //    //fmt should be the same

                //    //This mainly implies that stand-alone RTP over TCP is occuring anyway.

                //    //Since this code supports the RtspServer this is fine for now.

                //    //The RtpClient also deals with the framing from RTSP when used in conjunction with so..
                //    //This needs to be addressed in the RtpClient which allows currently allows Rtp and Rtcp to be duplexed in TCP and UDP
                //    //but does not handle the case of TCP when a sender wants to connect with 2 seperate TCP sockets as per RFC4571.

                //    //a=setup:passive
                //    //a=connection:new

                //    //The RtpClient would then need to have a RtcpSocket ready on the 'standby' just in case the remote end point connected and began sending the data.

                //    //The other way to hanle this would be use only a single socket in both cases and change the remote endpoint = 0.... and decypher the data based on the end point... e.g. the port.
                //}

                #endregion

                //Verify Timing lines.
                //Lines should have a startTime equal the Uptime of the stream
                //Lines should have a stopTime equal to the EndTime of the stream.

            }

            //Top level stream control line (Should only be added if Aggregate Control of the stream is allowed.
            //sdp.Add(new Sdp.SessionDescriptionLine(controlLineBase));

            return sdp;
        }
Ejemplo n.º 7
0
        //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();
        }