コード例 #1
0
        /// <summary>
        /// Matches specified SIP request to SIP dialog. If no matching dialog found, returns null.
        /// </summary>
        /// <param name="request">SIP request.</param>
        /// <returns>Returns matched SIP dialog or null in no match found.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>request</b> is null.</exception>
        internal SIP_Dialog MatchDialog(SIP_Request request)
        {
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            SIP_Dialog dialog = null;

            try{
                string callID    = request.CallID;
                string localTag  = request.To.Tag;
                string remoteTag = request.From.Tag;
                if (callID != null && localTag != null && remoteTag != null)
                {
                    string dialogID = callID + "-" + localTag + "-" + remoteTag;
                    lock (m_pDialogs){
                        m_pDialogs.TryGetValue(dialogID, out dialog);
                    }
                }
            }
            catch {
            }

            return(dialog);
        }
コード例 #2
0
        /// <summary>
        /// Matches specified SIP response to SIP dialog. If no matching dialog found, returns null.
        /// </summary>
        /// <param name="response">SIP response.</param>
        /// <returns>Returns matched SIP dialog or null in no match found.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>response</b> is null.</exception>
        internal SIP_Dialog MatchDialog(SIP_Response response)
        {
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            SIP_Dialog dialog = null;

            try{
                string callID  = response.CallID;
                string fromTag = response.From.Tag;
                string toTag   = response.To.Tag;
                if (callID != null && fromTag != null && toTag != null)
                {
                    string dialogID = callID + "-" + fromTag + "-" + toTag;
                    lock (m_pDialogs){
                        m_pDialogs.TryGetValue(dialogID, out dialog);
                    }
                }
            }
            catch {
            }

            return(dialog);
        }
コード例 #3
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="stack">Reference to SIP stack.</param>
 /// <param name="flow">SIP data flow.</param>
 /// <param name="request">Recieved request.</param>
 /// <param name="dialog">SIP dialog which received request.</param>
 /// <param name="transaction">SIP server transaction which must be used to send response back to request maker.</param>
 internal SIP_RequestReceivedEventArgs(SIP_Stack stack, SIP_Flow flow, SIP_Request request, SIP_Dialog dialog, SIP_ServerTransaction transaction)
 {
     m_pStack       = stack;
     m_pFlow        = flow;
     m_pRequest     = request;
     m_pDialog      = dialog;
     m_pTransaction = transaction;
 }
コード例 #4
0
 /// <summary>
 /// Default constructor.
 /// </summary>
 /// <param name="stack">Reference to SIP stack.</param>
 /// <param name="flow">SIP data flow.</param>
 /// <param name="request">Recieved request.</param>
 /// <param name="dialog">SIP dialog which received request.</param>
 /// <param name="transaction">SIP server transaction which must be used to send response back to request maker.</param>
 internal SIP_RequestReceivedEventArgs(SIP_Stack stack,SIP_Flow flow,SIP_Request request,SIP_Dialog dialog,SIP_ServerTransaction transaction)
 {
     m_pStack       = stack;
     m_pFlow        = flow;
     m_pRequest     = request;
     m_pDialog      = dialog;
     m_pTransaction = transaction;
 }
コード例 #5
0
        /// <summary>
        /// Gets existing or creates new dialog.
        /// </summary>
        /// <param name="transaction">Owner transaction what forces to create dialog.</param>
        /// <param name="response">Response what forces to create dialog.</param>
        /// <returns>Returns dialog.</returns>
        /// <exception cref="ArgumentNullException">Is raised when <b>transaction</b> or <b>response</b> is null.</exception>
        public SIP_Dialog GetOrCreateDialog(SIP_Transaction transaction, SIP_Response response)
        {
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (response == null)
            {
                throw new ArgumentNullException("response");
            }

            string dialogID = "";

            if (transaction is SIP_ServerTransaction)
            {
                dialogID = response.CallID + "-" + response.To.Tag + "-" + response.From.Tag;
            }
            else
            {
                dialogID = response.CallID + "-" + response.From.Tag + "-" + response.To.Tag;
            }

            lock (m_pDialogs){
                SIP_Dialog dialog = null;
                m_pDialogs.TryGetValue(dialogID, out dialog);
                // Dialog doesn't exist, create it.
                if (dialog == null)
                {
                    if (response.CSeq.RequestMethod.ToUpper() == SIP_Methods.INVITE)
                    {
                        dialog = new SIP_Dialog_Invite();
                    }
                    else if (response.CSeq.RequestMethod.ToUpper() == SIP_Methods.REFER)
                    {
                        dialog = new SIP_Dialog_Refer();
                    }
                    else
                    {
                        throw new ArgumentException("Method '" + response.CSeq.RequestMethod + "' has no dialog handler.");
                    }

                    dialog.Init(m_pStack, transaction, response);
                    dialog.StateChanged += delegate(object s, EventArgs a){
                        if (dialog.State == SIP_DialogState.Terminated)
                        {
                            m_pDialogs.Remove(dialog.ID);
                        }
                    };
                    m_pDialogs.Add(dialog.ID, dialog);
                }

                return(dialog);
            }
        }
コード例 #6
0
        /// <summary>
        /// Default constructor.
        /// </summary>
        /// <param name="owner">Owner B2BUA server.</param>
        /// <param name="caller">Caller side dialog.</param>
        /// <param name="callee">Callee side dialog.</param>
        internal SIP_B2BUA_Call(SIP_B2BUA owner,SIP_Dialog caller,SIP_Dialog callee)
        {
            m_pOwner    = owner;
            m_pCaller   = caller;
            m_pCallee   = callee;
            m_StartTime = DateTime.Now;
            m_CallID    = Guid.NewGuid().ToString().Replace("-","");

            //m_pCaller.RequestReceived += new SIP_RequestReceivedEventHandler(m_pCaller_RequestReceived);
            //m_pCaller.Terminated += new EventHandler(m_pCaller_Terminated);

            //m_pCallee.RequestReceived += new SIP_RequestReceivedEventHandler(m_pCallee_RequestReceived);
            //m_pCallee.Terminated += new EventHandler(m_pCallee_Terminated);           
        }
コード例 #7
0
        /// <summary>
        /// Creates new client transaction.
        /// </summary>
        /// <param name="flow">SIP data flow which is used to send request.</param>
        /// <param name="request">SIP request that transaction will handle.</param>
        /// <param name="addVia">If true, transaction will add <b>Via:</b> header, otherwise it's user responsibility.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        /// <returns>Returns created transaction.</returns>
        public SIP_ClientTransaction CreateClientTransaction(SIP_Flow flow, SIP_Request request, bool addVia)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            // Add Via:
            if (addVia)
            {
                SIP_t_ViaParm via = new SIP_t_ViaParm();
                via.ProtocolName      = "SIP";
                via.ProtocolVersion   = "2.0";
                via.ProtocolTransport = flow.Transport;
                via.SentBy            = new HostEndPoint("transport_layer_will_replace_it", -1);
                via.Branch            = SIP_t_ViaParm.CreateBranch();
                via.RPort             = 0;
                request.Via.AddToTop(via.ToStringValue());
            }

            lock (m_pClientTransactions){
                SIP_ClientTransaction transaction = new SIP_ClientTransaction(m_pStack, flow, request);
                m_pClientTransactions.Add(transaction.Key, transaction);
                transaction.StateChanged += new EventHandler(delegate(object s, EventArgs e){
                    if (transaction.State == SIP_TransactionState.Terminated)
                    {
                        lock (m_pClientTransactions){
                            m_pClientTransactions.Remove(transaction.Key);
                        }
                    }
                });

                SIP_Dialog dialog = MatchDialog(request);
                if (dialog != null)
                {
                    dialog.AddTransaction(transaction);
                }

                return(transaction);
            }
        }
コード例 #8
0
        /// <summary>
        /// Creates new SIP server transaction for specified request.
        /// </summary>
        /// <param name="flow">SIP data flow which is used to receive request.</param>
        /// <param name="request">SIP request.</param>
        /// <returns>Returns added server transaction.</returns>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>flow</b> or <b>request</b> is null reference.</exception>
        public SIP_ServerTransaction CreateServerTransaction(SIP_Flow flow, SIP_Request request)
        {
            if (m_IsDisposed)
            {
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if (flow == null)
            {
                throw new ArgumentNullException("flow");
            }
            if (request == null)
            {
                throw new ArgumentNullException("request");
            }

            lock (m_pServerTransactions){
                SIP_ServerTransaction transaction = new SIP_ServerTransaction(m_pStack, flow, request);
                m_pServerTransactions.Add(transaction.Key, transaction);
                transaction.StateChanged += new EventHandler(delegate(object s, EventArgs e){
                    if (transaction.State == SIP_TransactionState.Terminated)
                    {
                        lock (m_pClientTransactions){
                            m_pServerTransactions.Remove(transaction.Key);
                        }
                    }
                });

                SIP_Dialog dialog = MatchDialog(request);
                if (dialog != null)
                {
                    dialog.AddTransaction(transaction);
                }

                return(transaction);
            }
        }
コード例 #9
0
        /// <summary>
        /// Creates new SIP UAS dialog.
        /// </summary>
        /// <param name="transaction">Owner transaction what forces to create dialog.</param>
        /// <param name="request">Server transaction request what response it is.</param>
        /// <param name="response">SIP response what causes dialog creation.</param>
        /// <returns>Returns new SIP dialog.</returns>
        internal SIP_Dialog CreateDialog(SIP_ServerTransaction transaction,SIP_Request request,SIP_Response response)
        {
            // TODO: ren EnsureDialog

            SIP_Dialog dialog = new SIP_Dialog(m_pSipStack,request,response);
            m_pDialogs.Add(dialog);

            return dialog;
        }
コード例 #10
0
ファイル: VoIP.cs プロジェクト: Dfinitski/genesisradio
        private void Handle2xx(SIP_Dialog dialog, SIP_ServerTransaction transaction)
        {
            if (dialog == null)
            {
                throw new ArgumentNullException("dialog");
            }
            if (transaction == null)
            {
                throw new ArgumentException("transaction");
            }

            /* RFC 6026 8.1.
                Once the response has been constructed, it is passed to the INVITE
                server transaction.  In order to ensure reliable end-to-end
                transport of the response, it is necessary to periodically pass
                the response directly to the transport until the ACK arrives.  The
                2xx response is passed to the transport with an interval that
                starts at T1 seconds and doubles for each retransmission until it
                reaches T2 seconds (T1 and T2 are defined in Section 17).
                Response retransmissions cease when an ACK request for the
                response is received.  This is independent of whatever transport
                protocols are used to send the response.
             
                If the server retransmits the 2xx response for 64*T1 seconds without
                receiving an ACK, the dialog is confirmed, but the session SHOULD be
                terminated.  This is accomplished with a BYE, as described in Section
                15.
              
                 T1 - 500
                 T2 - 4000
            */

            TimerEx timer = null;

            EventHandler<SIP_RequestReceivedEventArgs> callback = delegate(object s1, SIP_RequestReceivedEventArgs e)
            {
                try
                {
                    if (e.Request.RequestLine.Method == SIP_Methods.ACK)
                    {
                        // ACK for INVITE 2xx response received, stop retransmitting INVITE 2xx response.
                        if (transaction.Request.CSeq.SequenceNumber == e.Request.CSeq.SequenceNumber)
                        {
                            if (timer != null)
                            {
                                timer.Dispose();
                            }
                        }
                    }
                }
                catch
                {
                    // We don't care about errors here.
                }
            };
            dialog.RequestReceived += callback;

            // Create timer and sart retransmitting INVITE 2xx response.
            timer = new TimerEx(500);
            timer.AutoReset = false;
            timer.Elapsed += delegate(object s, System.Timers.ElapsedEventArgs e)
            {
                try
                {
                    lock (transaction.SyncRoot)
                    {
                        if (transaction.State == SIP_TransactionState.Accpeted)
                        {
                            transaction.SendResponse(transaction.FinalResponse);
                        }
                        else
                        {
                            timer.Dispose();

                            return;
                        }
                    }

                    timer.Interval = Math.Min(timer.Interval * 2, 4000);
                    timer.Enabled = true;
                }
                catch
                {
                    // We don't care about errors here.
                }
            };
            timer.Disposed += delegate(object s1, EventArgs e1)
            {
                try
                {
                    dialog.RequestReceived -= callback;
                }
                catch
                {
                    // We don't care about errors here.
                }
            };
            timer.Enabled = true;
        }
コード例 #11
0
ファイル: VoIP.cs プロジェクト: Dfinitski/genesisradio
        /// <summary>
        /// Initializes call from Calling state to active..
        /// </summary>
        /// <param name="dialog">SIP dialog.</param>
        /// <param name="localSDP">Local SDP.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>dialog</b> or <b>localSDP</b> is null reference.</exception>
        internal void InitCalling(SIP_Dialog dialog, SDP_Message localSDP)
        {
            if (dialog == null)
            {
                throw new ArgumentNullException("dialog");
            }
            if (localSDP == null)
            {
                throw new ArgumentNullException("localSDP");
            }

            m_pDialog = (SIP_Dialog_Invite)dialog;
            m_pFlow = dialog.Flow;
            m_pLocalSDP = localSDP;

            m_StartTime = DateTime.Now;
            dialog.StateChanged += new EventHandler(m_pDialog_StateChanged);

            SetState(SIP_CallState.Active);

            // Start ping timer.
            m_pKeepAliveTimer = new TimerEx(40000);
            m_pKeepAliveTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pKeepAliveTimer_Elapsed);
            m_pKeepAliveTimer.Enabled = true;
        }
コード例 #12
0
ファイル: VoIP.cs プロジェクト: Dfinitski/genesisradio
        /// <summary>
        /// Incoming call constructor.
        /// </summary>
        /// <param name="stack">Reference to SIP stack.</param>
        /// <param name="dialog">Reference SIP dialog.</param>
        /// <param name="session">Call RTP multimedia session.</param>
        /// <param name="localSDP">Local SDP.</param>
        /// <exception cref="ArgumentNullException">Is raised when <b>stack</b>,<b>dialog</b>,<b>session</b> or <b>localSDP</b> is null reference.</exception>
        internal SIP_Call(SIP_Stack stack, SIP_Dialog dialog, RTP_MultimediaSession session, SDP_Message localSDP)
        {
            if (stack == null)
            {
                throw new ArgumentNullException("stack");
            }
            if (dialog == null)
            {
                throw new ArgumentNullException("dialog");
            }
            if (session == null)
            {
                throw new ArgumentNullException("session");
            }
            if (localSDP == null)
            {
                throw new ArgumentNullException("localSDP");
            }

            m_pStack = stack;
            m_pDialog = (SIP_Dialog_Invite)dialog;
            m_pRtpMultimediaSession = session;
            m_pLocalSDP = localSDP;

            m_StartTime = DateTime.Now;
            m_pFlow = dialog.Flow;
            dialog.StateChanged += new EventHandler(m_pDialog_StateChanged);

            SetState(SIP_CallState.Active);

            // Start ping timer.
            m_pKeepAliveTimer = new TimerEx(40000);
            m_pKeepAliveTimer.Elapsed += new System.Timers.ElapsedEventHandler(m_pKeepAliveTimer_Elapsed);
            m_pKeepAliveTimer.Enabled = true;
        }
コード例 #13
0
ファイル: VoIP.cs プロジェクト: Dfinitski/genesisradio
        private void ProcessMediaOffer(SIP_Dialog dialog, SIP_ServerTransaction transaction, RTP_MultimediaSession rtpMultimediaSession, SDP_Message offer, SDP_Message localSDP)
        {
            if (dialog == null)
            {
                throw new ArgumentNullException("dialog");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }
            if (rtpMultimediaSession == null)
            {
                throw new ArgumentNullException("rtpMultimediaSession");
            }
            if (offer == null)
            {
                throw new ArgumentNullException("offer");
            }
            if (localSDP == null)
            {
                throw new ArgumentNullException("localSDP");
            }

            try
            {
                #region SDP basic validation

                // Version field must exist.
                if (offer.Version == null)
                {
                    transaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x500_Server_Internal_Error + ": Invalid SDP answer: Required 'v'(Protocol Version) field is missing.", transaction.Request));

                    return;
                }

                // Origin field must exist.
                if (offer.Origin == null)
                {
                    transaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x500_Server_Internal_Error + ": Invalid SDP answer: Required 'o'(Origin) field is missing.", transaction.Request));

                    return;
                }

                // Session Name field.

                // Check That global 'c' connection attribute exists or otherwise each enabled media stream must contain one.
                if (offer.Connection == null)
                {
                    for (int i = 0; i < offer.MediaDescriptions.Count; i++)
                    {
                        if (offer.MediaDescriptions[i].Connection == null)
                        {
                            transaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x500_Server_Internal_Error + ": Invalid SDP answer: Global or per media stream no: " + i + " 'c'(Connection) attribute is missing.", transaction.Request));

                            return;
                        }
                    }
                }

                #endregion

                // Re-INVITE media streams count must be >= current SDP streams.
                if (localSDP.MediaDescriptions.Count > offer.MediaDescriptions.Count)
                {
                    transaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x500_Server_Internal_Error + ": re-INVITE SDP offer media stream count must be >= current session stream count.", transaction.Request));

                    return;
                }

                bool audioAccepted = false;
                // Process media streams info.
                for (int i = 0; i < offer.MediaDescriptions.Count; i++)
                {
                    SDP_MediaDescription offerMedia = offer.MediaDescriptions[i];
                    SDP_MediaDescription answerMedia = (localSDP.MediaDescriptions.Count > i ? localSDP.MediaDescriptions[i] : null);

                    // Disabled stream.
                    if (offerMedia.Port == 0)
                    {
                        // Remote-party offered new disabled stream.
                        if (answerMedia == null)
                        {
                            // Just copy offer media stream data to answer and set port to zero.
                            localSDP.MediaDescriptions.Add(offerMedia);
                            localSDP.MediaDescriptions[i].Port = 0;
                        }
                        // Existing disabled stream or remote party disabled it.
                        else
                        {
                            answerMedia.Port = 0;

                            #region Cleanup active RTP stream and it's resources, if it exists

                            // Dispose existing RTP session.
                            if (answerMedia.Tags.ContainsKey("rtp_session"))
                            {
                                ((RTP_Session)offerMedia.Tags["rtp_session"]).Dispose();
                                answerMedia.Tags.Remove("rtp_session");
                            }

                            // Release UPnPports if any.
                            if (answerMedia.Tags.ContainsKey("upnp_rtp_map"))
                            {
                                try
                                {
                                    m_pUPnP.DeletePortMapping((UPnP_NAT_Map)answerMedia.Tags["upnp_rtp_map"]);
                                }
                                catch
                                {
                                }
                                answerMedia.Tags.Remove("upnp_rtp_map");
                            }
                            if (answerMedia.Tags.ContainsKey("upnp_rtcp_map"))
                            {
                                try
                                {
                                    m_pUPnP.DeletePortMapping((UPnP_NAT_Map)answerMedia.Tags["upnp_rtcp_map"]);
                                }
                                catch
                                {
                                }
                                answerMedia.Tags.Remove("upnp_rtcp_map");
                            }

                            #endregion
                        }
                    }
                    // Remote-party wants to communicate with this stream.
                    else
                    {
                        // See if we can support this stream.
                        if (!audioAccepted && CanSupportMedia(offerMedia))
                        {
                            // New stream.
                            if (answerMedia == null)
                            {
                                answerMedia = new SDP_MediaDescription(SDP_MediaTypes.audio, 0, 2, "RTP/AVP", null);
                                localSDP.MediaDescriptions.Add(answerMedia);
                            }

                            #region Build audio codec map with codecs which we support

                            Dictionary<int, AudioCodec> audioCodecs = GetOurSupportedAudioCodecs(offerMedia);
                            answerMedia.MediaFormats.Clear();
                            answerMedia.Attributes.Clear();
                            foreach (KeyValuePair<int, AudioCodec> entry in audioCodecs)
                            {
                                answerMedia.Attributes.Add(new SDP_Attribute("rtpmap", entry.Key + " " + entry.Value.Name + "/" + entry.Value.CompressedAudioFormat.SamplesPerSecond));
                                answerMedia.MediaFormats.Add(entry.Key.ToString());
                            }
                            answerMedia.Attributes.Add(new SDP_Attribute("ptime", "20"));
                            answerMedia.Tags["audio_codecs"] = audioCodecs;

                            #endregion

                            #region Create/modify RTP session

                            // RTP session doesn't exist, create it.
                            if (!answerMedia.Tags.ContainsKey("rtp_session"))
                            {
                                RTP_Session rtpSess = CreateRtpSession(rtpMultimediaSession);
                                // RTP session creation failed,disable this stream.
                                if (rtpSess == null)
                                {
                                    answerMedia.Port = 0;

                                    break;
                                }
                                answerMedia.Tags.Add("rtp_session", rtpSess);

                                rtpSess.NewReceiveStream += delegate(object s, RTP_ReceiveStreamEventArgs e)
                                {
                                    if (answerMedia.Tags.ContainsKey("rtp_audio_out"))
                                    {
                                        ((AudioOut_RTP)answerMedia.Tags["rtp_audio_out"]).Dispose();
                                    }

                                    AudioOut_RTP audioOut = new AudioOut_RTP(m_pAudioOutDevice, e.Stream, audioCodecs);
                                    audioOut.Start();
                                    answerMedia.Tags["rtp_audio_out"] = audioOut;
                                };

                                // NAT
                                if (!HandleNAT(answerMedia, rtpSess))
                                {
                                    // NAT handling failed,disable this stream.
                                    answerMedia.Port = 0;

                                    break;
                                }
                            }

                            RTP_StreamMode offerStreamMode = GetRtpStreamMode(offer, offerMedia);
                            if (offerStreamMode == RTP_StreamMode.Inactive)
                            {
                                answerMedia.SetStreamMode("inactive");
                            }
                            else if (offerStreamMode == RTP_StreamMode.Receive)
                            {
                                answerMedia.SetStreamMode("sendonly");
                            }
                            else if (offerStreamMode == RTP_StreamMode.Send)
                            {
                                answerMedia.SetStreamMode("recvonly");
                            }
                            else if (offerStreamMode == RTP_StreamMode.SendReceive)
                            {
                                answerMedia.SetStreamMode("sendrecv");
                            }

                            RTP_Session rtpSession = (RTP_Session)answerMedia.Tags["rtp_session"];
                            rtpSession.Payload = Convert.ToInt32(answerMedia.MediaFormats[0]);
                            rtpSession.StreamMode = GetRtpStreamMode(localSDP, answerMedia);
                            rtpSession.RemoveTargets();
                            if (GetSdpHost(offer, offerMedia) != "0.0.0.0")
                            {
                                rtpSession.AddTarget(GetRtpTarget(offer, offerMedia));
                            }
                            rtpSession.Start();

                            #endregion

                            #region Create/modify audio-in source

                            if (!answerMedia.Tags.ContainsKey("rtp_audio_in"))
                            {
                                AudioIn_RTP rtpAudioIn = new AudioIn_RTP(m_pAudioInDevice, 20, audioCodecs, rtpSession.CreateSendStream());
                                rtpAudioIn.Start();
                                answerMedia.Tags.Add("rtp_audio_in", rtpAudioIn);
                            }
                            else
                            {
                                ((AudioIn_RTP)answerMedia.Tags["rtp_audio_in"]).AudioCodecs = audioCodecs;
                            }

                            #endregion

                            audioAccepted = true;
                        }
                        // We don't accept this stream, so disable it.
                        else
                        {
                            // Just copy offer media stream data to answer and set port to zero.

                            // Delete exisiting media stream.
                            if (answerMedia != null)
                            {
                                localSDP.MediaDescriptions.RemoveAt(i);
                            }
                            localSDP.MediaDescriptions.Add(offerMedia);
                            localSDP.MediaDescriptions[i].Port = 0;
                        }
                    }
                }

                #region Create and send 2xx response

                SIP_Response response = m_pStack.CreateResponse(SIP_ResponseCodes.x200_Ok, transaction.Request, transaction.Flow);
                //response.Contact = SIP stack will allocate it as needed;
                response.ContentType = "application/sdp";
                response.Data = localSDP.ToByte();

                transaction.SendResponse(response);

                // Start retransmitting 2xx response, while ACK receives.
                Handle2xx(dialog, transaction);

                // REMOVE ME: 27.11.2010
                // Start retransmitting 2xx response, while ACK receives.
                //m_pInvite2xxMgr.Add(dialog,transaction);

                #endregion
            }
            catch (Exception x)
            {
                transaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x500_Server_Internal_Error + ": " + x.Message, transaction.Request));
            }
        }
コード例 #14
0
ファイル: VoIP.cs プロジェクト: Dfinitski/genesisradio
        private void SendAck(SIP_Dialog dialog, SIP_Request ack)
        {
            if (dialog == null)
            {
                throw new ArgumentNullException("dialog");
            }
            if (ack == null)
            {
                throw new ArgumentNullException("ack");
            }

            try
            {
                // Try existing flow.
                dialog.Flow.Send(ack);

                // Log
                if (dialog.Stack.Logger != null)
                {
                    byte[] ackBytes = ack.ToByteData();

                    dialog.Stack.Logger.AddWrite(
                        dialog.ID,
                        null,
                        ackBytes.Length,
                        "Request [DialogID='" + dialog.ID + "';" + "method='" + ack.RequestLine.Method + "'; cseq='" + ack.CSeq.SequenceNumber + "'; " +
                        "transport='" + dialog.Flow.Transport + "'; size='" + ackBytes.Length + "'] sent '" + dialog.Flow.LocalEP + "' -> '" + dialog.Flow.RemoteEP + "'.",
                        dialog.Flow.LocalEP,
                        dialog.Flow.RemoteEP,
                        ackBytes
                    );
                }
            }
            catch
            {
                /* RFC 3261 13.2.2.4.
                    Once the ACK has been constructed, the procedures of [4] are used to
                    determine the destination address, port and transport.  However, the
                    request is passed to the transport layer directly for transmission,
                    rather than a client transaction.
                */
                try
                {
                    dialog.Stack.TransportLayer.SendRequest(ack);
                }
                catch (Exception x)
                {
                    // Log
                    if (dialog.Stack.Logger != null)
                    {
                        dialog.Stack.Logger.AddText("Dialog [id='" + dialog.ID + "'] ACK send for 2xx response failed: " + x.Message + ".");
                    }
                }
            }
        }
コード例 #15
0
ファイル: SIP_B2BUA.cs プロジェクト: CivilPol/LumiSoft.Net
        /// <summary>
        /// Adds specified call to calls list.
        /// </summary>
        /// <param name="caller">Caller side dialog.</param>
        /// <param name="calee">Calee side dialog.</param>
        internal void AddCall(SIP_Dialog caller,SIP_Dialog calee)
        {
            lock(m_pCalls){
                SIP_B2BUA_Call call = new SIP_B2BUA_Call(this,caller,calee);
                m_pCalls.Add(call);

                OnCallCreated(call);
            }            
        }
コード例 #16
0
ファイル: SIP_UA_Call.cs プロジェクト: CivilPol/LumiSoft.Net
        /// <summary>
        /// Accepts call.
        /// </summary>
        /// <param name="sdp">Media answer.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this object is disposed and and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when call is not in valid state and this method is called.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>sdp</b> is null reference.</exception>
        public void Accept(SDP_Message sdp)
        {
            if(m_State == SIP_UA_CallState.Disposed){
                throw new ObjectDisposedException(this.GetType().Name);
            }
            if(m_State != SIP_UA_CallState.WaitingToAccept){
                throw new InvalidOperationException("Accept method can be called only in 'SIP_UA_CallState.WaitingToAccept' state.");
            }
            if(sdp == null){
                throw new ArgumentNullException("sdp");
            }

            m_pLocalSDP = sdp;

            // TODO: We must add Contact header and SDP to response.

            SIP_Response response = m_pUA.Stack.CreateResponse(SIP_ResponseCodes.x200_Ok,m_pInitialInviteTransaction.Request,m_pInitialInviteTransaction.Flow);            
            response.ContentType = "application/sdp";
            response.Data = sdp.ToByte();
            m_pInitialInviteTransaction.SendResponse(response);

            SetState(SIP_UA_CallState.Active);

            m_pDialog = m_pUA.Stack.TransactionLayer.GetOrCreateDialog(m_pInitialInviteTransaction,response);
            m_pDialog.StateChanged += new EventHandler(m_pDialog_StateChanged);

        }
コード例 #17
0
 /// <summary>
 /// Ensures that SIP dialog exists. If not, creates SIP dialog, if exists, updates dialog state.
 /// </summary>
 /// <param name="response">SIP response what causes dialog creation.</param>
 private void EnsureDialog(SIP_Response response)
 {
     lock(this){
         // Create dialog
         if(this.CanCreateDialog && this.Dialog == null){
             m_pDialog = m_pSipStack.TransactionLayer.CreateDialog(this,m_pRequest,response);
         }
     }
 }
コード例 #18
0
 /// <summary>
 /// Removes specified dialog from dialogs collection.
 /// </summary>
 /// <param name="dialog">SIP dialog to remove.</param>
 internal void RemoveDialog(SIP_Dialog dialog)
 {
     lock (m_pDialogs){
         m_pDialogs.Remove(dialog.ID);
     }
 }
コード例 #19
0
 /// <summary>
 /// Removes specified dialog from dialogs collection.
 /// </summary>
 /// <param name="dialog">SIP dialog to remove.</param>
 internal void RemoveDialog(SIP_Dialog dialog)
 {
     lock(m_pDialogs){
         m_pDialogs.Remove(dialog);
     }
 }
コード例 #20
0
ファイル: VoIP.cs プロジェクト: Dfinitski/genesisradio
        private void HandleAck(SIP_Dialog dialog, SIP_ClientTransaction transaction)
        {
            if (dialog == null)
            {
                throw new ArgumentNullException("dialog");
            }
            if (transaction == null)
            {
                throw new ArgumentNullException("transaction");
            }

            /* RFC 3261 6.
                The ACK for a 2xx response to an INVITE request is a separate transaction.
              
               RFC 3261 13.2.2.4.
                The UAC core MUST generate an ACK request for each 2xx received from
                the transaction layer.  The header fields of the ACK are constructed
                in the same way as for any request sent within a dialog (see Section
                12) with the exception of the CSeq and the header fields related to
                authentication.  The sequence number of the CSeq header field MUST be
                the same as the INVITE being acknowledged, but the CSeq method MUST
                be ACK.  The ACK MUST contain the same credentials as the INVITE.  If
                the 2xx contains an offer (based on the rules above), the ACK MUST
                carry an answer in its body.
            */

            SIP_t_ViaParm via = new SIP_t_ViaParm();
            via.ProtocolName = "SIP";
            via.ProtocolVersion = "2.0";
            via.ProtocolTransport = transaction.Flow.Transport;
            via.SentBy = new HostEndPoint(transaction.Flow.LocalEP);
            via.Branch = SIP_t_ViaParm.CreateBranch();
            via.RPort = 0;

            SIP_Request ackRequest = dialog.CreateRequest(SIP_Methods.ACK);
            ackRequest.Via.AddToTop(via.ToStringValue());
            ackRequest.CSeq = new SIP_t_CSeq(transaction.Request.CSeq.SequenceNumber, SIP_Methods.ACK);
            // Authorization
            foreach (SIP_HeaderField h in transaction.Request.Authorization.HeaderFields)
            {
                ackRequest.Authorization.Add(h.Value);
            }
            // Proxy-Authorization 
            foreach (SIP_HeaderField h in transaction.Request.ProxyAuthorization.HeaderFields)
            {
                ackRequest.Authorization.Add(h.Value);
            }

            // Send ACK.
            SendAck(dialog, ackRequest);

            // Start receive 2xx retransmissions.
            transaction.ResponseReceived += delegate(object sender, SIP_ResponseReceivedEventArgs e)
            {
                if (dialog.State == SIP_DialogState.Disposed || dialog.State == SIP_DialogState.Terminated)
                {
                    return;
                }

                // Don't send ACK for forked 2xx, our sent BYE(to all early dialogs) or their early timer will kill these dialogs.
                // Send ACK only to our accepted dialog 2xx response retransmission.
                if (e.Response.From.Tag == ackRequest.From.Tag && e.Response.To.Tag == ackRequest.To.Tag)
                {
                    SendAck(dialog, ackRequest);
                }
            };
        }
コード例 #21
0
ファイル: SIP_UA_Call.cs プロジェクト: CivilPol/LumiSoft.Net
        /// <summary>
        /// This method is called when initial INVITE sender got response.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pInitialInviteSender_ResponseReceived(object sender,SIP_ResponseReceivedEventArgs e)
        {          
            try{
                lock(m_pLock){
                    // If remote party provided SDP, parse it.               
                    if(e.Response.ContentType != null && e.Response.ContentType.ToLower().IndexOf("application/sdp") > -1){
                        m_pRemoteSDP = SDP_Message.Parse(Encoding.UTF8.GetString(e.Response.Data));

                        // TODO: If parsing failed, end call.
                    }

                    if(e.Response.StatusCodeType == SIP_StatusCodeType.Provisional){
                        if(e.Response.StatusCode == 180){
                            SetState(SIP_UA_CallState.Ringing);
                        }
                        else if(e.Response.StatusCode == 182){
                            SetState(SIP_UA_CallState.Queued);
                        }
                        // We don't care other status responses.

                        /* RFC 3261 13.2.2.1.
                            Zero, one or multiple provisional responses may arrive before one or
                            more final responses are received.  Provisional responses for an
                            INVITE request can create "early dialogs".  If a provisional response
                            has a tag in the To field, and if the dialog ID of the response does
                            not match an existing dialog, one is constructed using the procedures
                            defined in Section 12.1.2.
                        */
                        if(e.Response.StatusCode > 100 && e.Response.To.Tag != null){
                            m_pEarlyDialogs.Add((SIP_Dialog_Invite)m_pUA.Stack.TransactionLayer.GetOrCreateDialog(e.ClientTransaction,e.Response));
                        }
                    }
                    else if(e.Response.StatusCodeType == SIP_StatusCodeType.Success){
                        m_StartTime = DateTime.Now;
                        SetState(SIP_UA_CallState.Active);

                        m_pDialog = m_pUA.Stack.TransactionLayer.GetOrCreateDialog(e.ClientTransaction,e.Response);
                        m_pDialog.StateChanged += new EventHandler(m_pDialog_StateChanged);

                        /* Exit all all other dialogs created by this call (due to forking).
                           That is not defined in RFC but, since UAC can send BYE to early and confirmed dialogs, 
                           because of this all 100% valid.
                        */
                        foreach(SIP_Dialog_Invite dialog in m_pEarlyDialogs.ToArray()){
                            if(!m_pDialog.Equals(dialog)){
                                dialog.Terminate("Another forking leg accepted.",true);
                            }
                        }
                    }
                    else{
                        /* RFC 3261 13.2.2.3.
                            All early dialogs are considered terminated upon reception of the non-2xx final response.
                        */
                        foreach(SIP_Dialog_Invite dialog in m_pEarlyDialogs.ToArray()){
                            dialog.Terminate("All early dialogs are considered terminated upon reception of the non-2xx final response. (RFC 3261 13.2.2.3)",false);
                        }
                        m_pEarlyDialogs.Clear();

                        Error();

                        SetState(SIP_UA_CallState.Terminated);                
                    }
                }
            }
            catch(Exception x){  
                m_pUA.Stack.OnError(x);            
            }

        }
コード例 #22
0
        /// <summary>
        /// Terminates call.
        /// </summary>
        public void Terminate()
        {
            if(m_IsTerminated){
                return;
            }
            m_IsTerminated = true;
   
            m_pOwner.RemoveCall(this);

            if(m_pCaller != null){
                //m_pCaller.Terminate();
                m_pCaller.Dispose();
                m_pCaller = null;
            }
            if(m_pCallee != null){
                //m_pCallee.Terminate();
                m_pCallee.Dispose();
                m_pCallee = null;
            }

            m_pOwner.OnCallTerminated(this);
        }