Example #1
0
        /// <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;
        }
Example #2
0
        /// <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);
        }
Example #3
0
        /// <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;
        }
Example #4
0
        /// <summary>
        /// Accepts call.
        /// </summary>
        public void Accept()
        {
            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.");
            }

            // 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        = Encoding.Default.GetBytes(
                "v=0\r\n" +
                "o=LSSIP 333 242452 IN IP4 192.168.1.70\r\n" +
                "s=SIP Call\r\n" +
                "c=IN IP4 192.168.1.70\r\n" +
                "t=0 0\r\n" +
                "m=audio 11000 RTP/AVP 0\r\n" +
                "a=rtpmap:0 PCMU/8000\r\n" +
                "a=sendrecv\r\n"
                );
            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);
        }
Example #5
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);
        }
Example #6
0
        /// <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);
            }
        }
Example #7
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);
        }
Example #8
0
        /// <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);
            }
        }
Example #9
0
        /// <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);
            }
        }
Example #10
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);
        }
Example #11
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);           
        }
Example #12
0
        /// <summary>
        /// This method is called when SIP stack received new message.
        /// </summary>
        /// <param name="sender">Sender.</param>
        /// <param name="e">Event data.</param>
        private void m_pStack_RequestReceived(object sender, SIP_RequestReceivedEventArgs e)
        {
            // TODO: Performance: rise events on thread pool or see if this method called on pool aready, then we may not keep lock for events ?

            if (e.Request.RequestLine.Method == SIP_Methods.CANCEL)
            {
                /* RFC 3261 9.2.
                 *  If the UAS did not find a matching transaction for the CANCEL
                 *  according to the procedure above, it SHOULD respond to the CANCEL
                 *  with a 481 (Call Leg/Transaction Does Not Exist).
                 *
                 *  Regardless of the method of the original request, as long as the
                 *  CANCEL matched an existing transaction, the UAS answers the CANCEL
                 *  request itself with a 200 (OK) response.
                 */

                SIP_ServerTransaction trToCancel = m_pStack.TransactionLayer.MatchCancelToTransaction(e.Request);
                if (trToCancel != null)
                {
                    trToCancel.Cancel();
                    e.ServerTransaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x200_Ok, e.Request));
                }
                else
                {
                    e.ServerTransaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x481_Call_Transaction_Does_Not_Exist, e.Request));
                }
            }
            else if (e.Request.RequestLine.Method == SIP_Methods.BYE)
            {
                /* RFC 3261 15.1.2.
                 *  If the BYE does not match an existing dialog, the UAS core SHOULD generate a 481
                 *  (Call/Transaction Does Not Exist) response and pass that to the server transaction.
                 */
                // TODO:

                SIP_Dialog dialog = m_pStack.TransactionLayer.MatchDialog(e.Request);
                if (dialog != null)
                {
                    e.ServerTransaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x200_Ok, e.Request));
                    dialog.Terminate();
                }
                else
                {
                    e.ServerTransaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x481_Call_Transaction_Does_Not_Exist, e.Request));
                }
            }
            else if (e.Request.RequestLine.Method == SIP_Methods.INVITE)
            {
                // Supress INVITE retransmissions.
                e.ServerTransaction.SendResponse(m_pStack.CreateResponse(SIP_ResponseCodes.x100_Trying, e.Request));

                // Create call.
                SIP_UA_Call call = new SIP_UA_Call(this, e.ServerTransaction);
                call.StateChanged += new EventHandler(Call_StateChanged);
                m_pCalls.Add(call);

                OnIncomingCall(call);
            }
            else
            {
                OnRequestReceived(e);
            }
        }
Example #13
0
        /// <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)
        {
            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(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 += 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 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 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);
                }
            }
        }
Example #14
0
        /// <summary>
        /// Accepts call.
        /// </summary>
        public void Accept()
        {
            if (m_State == SIP_UA_CallState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (m_State != SIP_UA_CallState.WaitingToAccept)
            {
                throw new InvalidOperationException(
                    "Accept method can be called only in 'SIP_UA_CallState.WaitingToAccept' state.");
            }

            // 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 =
                Encoding.Default.GetBytes("v=0\r\n" + "o=LSSIP 333 242452 IN IP4 192.168.1.70\r\n" +
                                          "s=SIP Call\r\n" + "c=IN IP4 192.168.1.70\r\n" + "t=0 0\r\n" +
                                          "m=audio 11000 RTP/AVP 0\r\n" + "a=rtpmap:0 PCMU/8000\r\n" +
                                          "a=sendrecv\r\n");
            m_pInitialInviteTransaction.SendResponse(response);

            SetState(SIP_UA_CallState.Active);

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