public static void TryWaitOnHandleAndDispose(ref System.Threading.WaitHandle handle)
        {
            if (object.ReferenceEquals(handle, NilWaitHandle))
            {
                return;
            }

            try
            {
                handle.WaitOne();
            }
            catch (System.ObjectDisposedException)
            {
                return;
            }
            catch (System.Exception ex)
            {
                //Should just return? (At least document that it will throw and how to catch or ignore)
                TaggedExceptionExtensions.TryRaiseTaggedException(handle, "An exception occured while waiting.", ex);
            }
            finally
            {
                if (object.ReferenceEquals(handle, NilWaitHandle).Equals(false))
                {
                    handle.Dispose();
                }
            }

            handle = null;
        }
Example #2
0
        public SessionDescriptionLine(string line, string seperator = null, int partCount = -1)
        {
            //Trim the line (Trim Line Value)?
            line = line.Trim();

            //Validate the line.

            //m_AllowWhiteSpace &&
            if (string.IsNullOrWhiteSpace(line))
            {
                throw new InvalidOperationException("line cannot be null or consist only of whitespace");
            }

            //m_AssumedPart &&
            if (line.Length < 2
                ||
                line[1] != SessionDescription.EqualsSign)
            {
                TaggedExceptionExtensions.RaiseTaggedException(this, "Invalid SessionDescriptionLine: \"" + line + "\"");
            }

            if (false == string.IsNullOrEmpty(seperator))
            {
                m_Seperator = seperator;
            }

            //Assign the type (move up with m_AssumedPart && above)
            m_Type = char.ToLower(line[0]);

            //Split the parts (creates new string array)

            //a=<flag>|<name>|:<value> where value = {...,...,...;x;y;z}

            //Could also add Space to the ToArray to ensure spaces are removed if all derived types agree spaces seperate their tokens.

            if (partCount > 0)
            {
                m_Parts = new List <string>(line.Substring(2).Split(ObjectExtensions.ToArray <string>(m_Seperator), partCount, StringSplitOptions.RemoveEmptyEntries));

                //Should have option to throw less parts than expected or truncate extra parts?
                EnsureParts(partCount);
            }
            else
            {
                m_Parts = new List <string>(line.Substring(2).Split(ObjectExtensions.ToArray <string>(m_Seperator), StringSplitOptions.RemoveEmptyEntries));
            }

            //m_Parts = new List<string>(line.Substring(2).Split(SessionDescription.SemiColonSplit));
        }
        public static bool TryWebClientDownload(System.Uri location, out System.IO.Stream result, System.Net.NetworkCredential credential = null)
        {
            result = null;

            try
            {
                result = WebClientDownload(location, credential);

                return(result != null);
            }
            catch (System.Exception ex)
            {
                TaggedExceptionExtensions.TryRaiseTaggedException(result, ex.Message, ex);

                return(false);
            }
        }
Example #4
0
        public TimeDescription(string[] sdpLines, ref int index)
            : this()
        {
            TimeDescriptionLine = new Lines.SessionTimeDescriptionLine(sdpLines, ref index);

            string sdpLine;

            //Iterate remaining lines
            for (int e = sdpLines.Length; index < e;)
            {
                //Scope a line
                sdpLine = sdpLines[index];

                if (string.IsNullOrWhiteSpace(sdpLine))
                {
                    ++index;

                    continue;
                }

                //If we are not extracing repeat times then there is no more TimeDescription to parse
                if (sdpLine[0] != Media.Sdp.Lines.SessionRepeatTimeLine.RepeatType)
                {
                    break;
                }

                //Parse and add the repeat time
                try
                {
                    //r=<repeat interval> <active duration> <offsets from start-time>
                    RepeatLines.Add(new Sdp.Lines.SessionRepeatTimeLine(sdpLines, ref index));
                }
                catch (Exception ex)
                {
                    TaggedExceptionExtensions.RaiseTaggedException(this, "Invalid Repeat Time", ex);
                    break;
                }
            }
        }
Example #5
0
        /// <summary>
        /// Parses a RFC2326 Rtp-Info header, if two sub headers are present only the values from the last header are returned.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="url"></param>
        /// <param name="seq"></param>
        /// <param name="rtpTime"></param>
        /// <returns></returns>
        ///NEEDS TO RETURN []s instead of single values out Uri[], etc.
        ///Or make en enumerator...
        public static bool TryParseRtpInfo(string value, out Uri url, out int?seq, out int?rtpTime, out int?ssrc)
        {
            url = null;

            seq = rtpTime = ssrc = null;

            if (string.IsNullOrWhiteSpace(value))
            {
                return(false);
            }

            try
            {
                string[] allParts = value.Split(Comma);

                for (int i = 0, e = allParts.Length; i < e; ++i)
                {
                    string part = allParts[i];

                    if (string.IsNullOrWhiteSpace(part))
                    {
                        continue;
                    }

                    foreach (var token in part.Split(SemiColon))
                    {
                        string[] subParts = token.Split(ValueSplit, 2);

                        if (subParts.Length < 2)
                        {
                            continue;
                        }

                        //todo put all tokens in static grammar

                        //possibly optomize as to lower produces another string.
                        switch (subParts[0].Trim().ToLowerInvariant())
                        {
                        case "url":
                        {
                            //UriDecode?

                            url = new Uri(subParts[1].Trim(), UriKind.RelativeOrAbsolute);

                            continue;
                        }

                        case "seq":
                        {
                            int parsed;

                            if (int.TryParse(subParts[1].Trim(), out parsed))
                            {
                                seq = parsed;
                            }

                            continue;
                        }

                        case "rtptime":
                        {
                            int parsed;

                            if (int.TryParse(subParts[1].Trim(), out parsed))
                            {
                                rtpTime = parsed;
                            }

                            continue;
                        }

                        case "ssrc":
                        {
                            string ssrcPart = subParts[1].Trim();

                            uint id;

                            if (false == uint.TryParse(ssrcPart, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out id) &&
                                false == uint.TryParse(ssrcPart, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out id))
                            {
                                TaggedExceptionExtensions.RaiseTaggedException(ssrcPart, "See Tag. Cannot Parse a ssrc datum as given.");
                            }

                            ssrc = (int)id;

                            continue;
                        }

                        default: continue;
                        }
                    }
                }

                return(true);
            }
            catch
            {
                return(false);
            }
        }
Example #6
0
        //TryParseAuthorizationHeader

        //Could just make a function to extract the tokens and values and then parse them as needed.

        //Values should be nullable...?
        public static bool TryParseTransportHeader(string value, out int ssrc,
                                                   out System.Net.IPAddress source,
                                                   out int serverRtpPort, out int serverRtcpPort,
                                                   out int clientRtpPort, out int clientRtcpPort,
                                                   out bool interleaved, out byte dataChannel, out byte controlChannel,
                                                   out string mode,
                                                   out bool unicast, out bool multicast, out System.Net.IPAddress destination, out int ttl)
        {
            if (string.IsNullOrWhiteSpace(value))
            {
                throw new InvalidOperationException("value cannot be null or whitespace.");
            }

            //layers = / Hops Ttl

            //Should also given tokens for profile e.g. SAVP or RAW etc.

            //it should always be the first value...

            ssrc = 0;

            //I think ttl should have a default of 0 in this case, but it probably doesn't matter in most cases.
            ttl = sbyte.MaxValue;

            source         = destination = System.Net.IPAddress.Any;
            serverRtpPort  = serverRtcpPort = clientRtpPort = clientRtcpPort = 0;
            dataChannel    = 0;
            controlChannel = 1;
            interleaved    = unicast = multicast = false;
            mode           = string.Empty;

            try
            {
                //Get the recognized parts of information from the transportHeader
                string[] parts = value.Split(SemiColon);

                for (int i = 0, e = parts.Length; i < e; ++i)
                {
                    string[] subParts = parts[i].Split((char)ASCII.EqualsSign);

                    switch (subParts[0].ToLowerInvariant())
                    {
                    case "unicast":
                    {
                        if (multicast)
                        {
                            throw new InvalidOperationException("Cannot be unicast and multicast");
                        }

                        unicast = true;

                        continue;
                    }

                    case "multicast":
                    {
                        if (unicast)
                        {
                            throw new InvalidOperationException("Cannot be unicast and multicast");
                        }

                        multicast = true;

                        continue;
                    }

                    case "mode":
                    {
                        mode = subParts[1];

                        continue;
                    }

                    //The header may indicate a source address different from that of the connection's address
                    case "source":
                    {
                        string sourcePart = subParts[1];

                        //Ensure not empty
                        if (string.IsNullOrWhiteSpace(sourcePart))
                        {
                            continue;
                        }

                        //Attempt to parse the token as an IPAddress
                        if (false == System.Net.IPAddress.TryParse(sourcePart, out source))
                        {
                            //new Uri(sourcePart).HostNameType == UriHostNameType.Dns

                            //Get the host entry
                            //var hostEntry = System.Net.Dns.GetHostEntry(sourcePart);

                            //Should either return the hostEntry or require an address family.

                            //hostEntry.AddressList.FirstOrDefault(e=>e.AddressFamily == connectionAddressType...)

                            //Could work around by always providing the v6 address if possible...


                            //Todo, this can fail and may take a long time.
                            source = System.Net.Dns.GetHostEntry(sourcePart).AddressList.First();
                        }

                        continue;
                    }

                    //The header may indicate the the destination address is different from that of the connection's address
                    case "destination":
                    {
                        string destinationPart = subParts[1];

                        //Ensure not empty
                        if (string.IsNullOrWhiteSpace(destinationPart))
                        {
                            continue;
                        }

                        //Attempt to parse the token as an IPAddress
                        if (false == System.Net.IPAddress.TryParse(destinationPart, out destination))
                        {
                            //new Uri(sourcePart).HostNameType == UriHostNameType.Dns

                            //Get the host entry
                            //var hostEntry = System.Net.Dns.GetHostEntry(sourcePart);

                            //Should either return the hostEntry or require an address family.

                            //hostEntry.AddressList.FirstOrDefault(e=>e.AddressFamily == connectionAddressType...)

                            //Could work around by always providing the v6 address if possible...

                            //Todo, this can fail and may take a long time.
                            destination = System.Net.Dns.GetHostEntry(destinationPart).AddressList.First();
                        }

                        continue;
                    }

                    case "ttl":
                    {
                        if (false == int.TryParse(subParts[1].Trim(), out ttl))
                        {
                            TaggedExceptionExtensions.RaiseTaggedException(ttl, "See Tag. Cannot Parse a ttl datum as given.");
                        }

                        //Could just clamp.
                        if (ttl < byte.MinValue || ttl > byte.MaxValue)
                        {
                            TaggedExceptionExtensions.RaiseTaggedException(ttl, "See Tag. Invalid ttl datum as given.");
                        }

                        continue;
                    }

                    case "ssrc":
                    {
                        string ssrcPart = subParts[1].Trim();

                        if (false == int.TryParse(ssrcPart, System.Globalization.NumberStyles.Integer, System.Globalization.CultureInfo.InvariantCulture, out ssrc) &&
                            false == int.TryParse(ssrcPart, System.Globalization.NumberStyles.HexNumber, System.Globalization.CultureInfo.InvariantCulture, out ssrc))
                        {
                            TaggedExceptionExtensions.RaiseTaggedException(ssrcPart, "See Tag. Cannot Parse a ssrc datum as given.");
                        }

                        continue;
                    }

                    //This parameter provides the RTP/RTCP port pair for a multicastsession. It is specified as a range, e.g., port=3456-3457.
                    case "port":
                    {
                        string[] multicastPorts = subParts[1].Split(HyphenSign);

                        int multicastPortsLength = multicastPorts.Length;

                        if (multicastPortsLength > 0)
                        {
                            clientRtpPort = serverRtpPort = int.Parse(multicastPorts[0], System.Globalization.CultureInfo.InvariantCulture);
                            if (multicastPortsLength > 1)
                            {
                                clientRtcpPort = serverRtcpPort = int.Parse(multicastPorts[1], System.Globalization.CultureInfo.InvariantCulture);
                            }
                            else
                            {
                                clientRtcpPort = clientRtpPort;          //multiplexing
                            }
                        }

                        continue;
                    }

                    case "client_port":
                    {
                        string[] clientPorts = subParts[1].Split(HyphenSign);

                        int clientPortsLength = clientPorts.Length;

                        if (clientPortsLength > 0)
                        {
                            clientRtpPort = int.Parse(clientPorts[0], System.Globalization.CultureInfo.InvariantCulture);
                            if (clientPortsLength > 1)
                            {
                                clientRtcpPort = int.Parse(clientPorts[1], System.Globalization.CultureInfo.InvariantCulture);
                            }
                            else
                            {
                                clientRtcpPort = clientRtpPort;          //multiplexing
                            }
                        }

                        continue;
                    }

                    case "server_port":
                    {
                        string[] serverPorts = subParts[1].Split(HyphenSign);

                        int serverPortsLength = serverPorts.Length;

                        if (serverPortsLength > 0)
                        {
                            serverRtpPort = int.Parse(serverPorts[0], System.Globalization.CultureInfo.InvariantCulture);
                            if (serverPortsLength > 1)
                            {
                                serverRtcpPort = int.Parse(serverPorts[1], System.Globalization.CultureInfo.InvariantCulture);
                            }
                            else
                            {
                                serverRtcpPort = serverRtpPort;          //multiplexing
                            }
                        }

                        continue;
                    }

                    case "interleaved":
                    {
                        interleaved = true;

                        //Should only be for Tcp
                        string[] channels = subParts[1].Split(TimeSplit, StringSplitOptions.RemoveEmptyEntries);

                        int channelsLength = channels.Length;

                        if (channelsLength > 1)
                        {
                            //DataChannel
                            dataChannel = byte.Parse(channels[0], System.Globalization.CultureInfo.InvariantCulture);
                            //Control Channel
                            if (channelsLength > 1)
                            {
                                controlChannel = byte.Parse(channels[1], System.Globalization.CultureInfo.InvariantCulture);
                            }
                        }

                        continue;
                    }
                    //case "connection":
                    //    {
                    //        continue;
                    //    }
                    //case "setup":
                    //    {
                    //        continue;
                    //    }
                    //case "rtcp-mux":
                    //    {
                    //        //C.2.2.  RTP over independent TCP

                    //        continue;
                    //    }
                    default: continue;
                    }
                }

                return(true);
            }
            catch
            {
                return(false);
            }
        }
        //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);
        }