Beispiel #1
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);
        }
Beispiel #2
0
        /// <summary>
        /// Default incoming call constructor.
        /// </summary>
        /// <param name="ua">Owner UA.</param>
        /// <param name="invite">INVITE server transaction.</param>
        /// <exception cref="ArgumentNullException">Is riased when <b>ua</b> or <b>invite</b> is null reference.</exception>
        internal SIP_UA_Call(SIP_UA ua, SIP_ServerTransaction invite)
        {
            if (ua == null)
            {
                throw new ArgumentNullException("ua");
            }
            if (invite == null)
            {
                throw new ArgumentNullException("invite");
            }

            m_pUA = ua;
            m_pInitialInviteTransaction = invite;
            m_pLocalUri  = invite.Request.To.Address.Uri;
            m_pRemoteUri = invite.Request.From.Address.Uri;
            m_pInitialInviteTransaction.Canceled += new EventHandler(delegate(object sender, EventArgs e){
                // If transaction canceled, terminate call.
                SetState(SIP_UA_CallState.Terminated);
            });

            // Parse SDP if INVITE contains SDP.
            // RFC 3261 13.2.1. INVITE may be offerless, we must thne send offer and remote party sends sdp in ACK.
            if (invite.Request.ContentType != null && invite.Request.ContentType.ToLower().IndexOf("application/sdp") > -1)
            {
                m_pRemoteSDP = SDP_Message.Parse(Encoding.UTF8.GetString(invite.Request.Data));
            }

            m_pTags = new Dictionary <string, object>();

            m_State = SIP_UA_CallState.WaitingToAccept;
        }
Beispiel #3
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;
        }
Beispiel #4
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;
        }
Beispiel #5
0
        /// <summary>
        /// Cleans up any resource being used.
        /// </summary>
        public void Dispose()
        {
            lock (m_pLock){
                if (this.State == SIP_CallState.Disposed)
                {
                    return;
                }
                SetState(SIP_CallState.Disposed);

                // TODO: Clean up
                m_pStack    = null;
                m_pLocalSDP = null;
                if (m_pDialog != null)
                {
                    m_pDialog.Dispose();
                    m_pDialog = null;
                }
                m_pFlow = null;
                if (m_pKeepAliveTimer != null)
                {
                    m_pKeepAliveTimer.Dispose();
                    m_pKeepAliveTimer = null;
                }

                this.StateChanged = null;
            }
        }
Beispiel #6
0
        private void toResponse(SIP_RequestReceivedEventArgs e)
        {
            SIP_Uri uri = e.Request.RequestLine.Uri as SIP_Uri;

            try
            {
                _sdp     = SDP_Message.Parse(MyEncoder.Encoder.GetString(e.Request.Data));
                RemoteIP = _sdp.Origin.UnicastAddress;
                if (_sdp.MediaDescriptions.Count == 0)
                {
                    e.ServerTransaction.SendResponse(_sipServer.Stack.CreateResponse(SIP_ResponseCodes.x400_Bad_Request, e.Request));
                    return;
                }
                else
                {
                    RemotePort = _sdp.MediaDescriptions[0].Port;
                }
            }
            catch (Exception)
            {
                //解析SDP失败。
                e.ServerTransaction.SendResponse(_sipServer.Stack.CreateResponse(SIP_ResponseCodes.x400_Bad_Request, e.Request));
                return;
            }

            //send 100 Trying;
            e.ServerTransaction.SendResponse(_sipServer.Stack.CreateResponse(SIP_ResponseCodes.x100_Trying, e.Request));

            _videoId = _sipServer.DeviceManager.GetVideoId(uri.User);
            if (_videoId != null)
            {
                RTPServer   rtp     = _sipServer.RTPManager.GetOrAddServer(_videoId);
                SDP_Message respSDP = new SDP_Message();
                respSDP.Version     = "0";
                respSDP.Origin      = new SDP_Origin(uri.User, 0, 0, "IN", "IPV4", rtp.LocalIP);
                respSDP.SessionName = "Play";
                respSDP.Connection  = new SDP_Connection("IN", "IPV4", rtp.LocalIP);
                respSDP.SSRC        = SDP_Utils.SSRC2String(SDP_Utils.GenSSRC(uri.User, true)); //根据国标补充协议标准生成SSRC。
                respSDP.Times.Add(new SDP_Time(0, 0));
                respSDP.MediaDescriptions.Add(new SDP_MediaDescription("video", rtp.Port, 2, "RTP/AVP", new string[] { "96", "97", "98" }));
                respSDP.Attributes.Add(new SDP_Attribute("sendonly", ""));
                respSDP.Attributes.Add(new SDP_Attribute("rtpmap", "96 PS/90000"));
                respSDP.Attributes.Add(new SDP_Attribute("rtpmap", "97 MPEG4/90000"));
                respSDP.Attributes.Add(new SDP_Attribute("rtpmap", "98 H264/90000"));

                SIP_Response resp = _sipServer.Stack.CreateResponse(SIP_ResponseCodes.x200_Ok, e.Request);
                resp.Data = respSDP.ToByte();
                e.ServerTransaction.SendResponse(resp);
            }
            else
            {
                //没有找到视频源。
                e.ServerTransaction.SendResponse(_sipServer.Stack.CreateResponse(SIP_ResponseCodes.x404_Not_Found, e.Request));
            }
        }
Beispiel #7
0
        /// <summary>
        /// Sends ringing to remote party.
        /// </summary>
        /// <param name="sdp">Early media answer or early media offer when initial INVITE don't have SDP.</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>
        public void SendRinging(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.");
            }

            SIP_Response response = m_pUA.Stack.CreateResponse(SIP_ResponseCodes.x180_Ringing, m_pInitialInviteTransaction.Request, m_pInitialInviteTransaction.Flow);

            if (sdp != null)
            {
                response.ContentType = "application/sdp";
                response.Data        = sdp.ToByte();

                m_pLocalSDP = sdp;
            }
            m_pInitialInviteTransaction.SendResponse(response);
        }
        /// <summary>
        /// Re-invites remote party.
        /// </summary>
        /// <param name="contact">New contact value. Value null means current contact value used.</param>
        /// <param name="sdp">SDP media offer.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when there is pending invite and this method is called or dialog is in invalid state.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>sdp</b> is null reference.</exception>
        public void ReInvite(SIP_Uri contact, SDP_Message sdp)
        {
            if (State == SIP_DialogState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (HasPendingInvite)
            {
                throw new InvalidOperationException("There is pending INVITE.");
            }
            if (State != SIP_DialogState.Confirmed)
            {
                throw new InvalidOperationException("ReInvite is only available in Confirmed state.");
            }
            if (sdp == null)
            {
                throw new ArgumentNullException("sdp");
            }

            lock (SyncRoot)
            {
                // TODO:

                SIP_Request reinvite = CreateRequest(SIP_Methods.INVITE);
                if (contact != null)
                {
                    reinvite.Contact.RemoveAll();
                    reinvite.Contact.Add(contact.ToString());
                }
                reinvite.ContentType = "application/sdp";
                // reinvite.Data = sdp.ToStringData();

                // TODO: Create request sender
                // TODO: Try to reuse existing data flow
                //SIP_RequestSender sender = this.Stack.CreateRequestSender(reinvite);
                //sender.Start();
            }
        }
Beispiel #9
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);
            }
        }
        /// <summary>
        /// Re-invites remote party.
        /// </summary>
        /// <param name="contact">New contact value. Value null means current contact value used.</param>
        /// <param name="sdp">SDP media offer.</param>
        /// <exception cref="ObjectDisposedException">Is raised when this class is Disposed and this method is accessed.</exception>
        /// <exception cref="InvalidOperationException">Is raised when there is pending invite and this method is called or dialog is in invalid state.</exception>
        /// <exception cref="ArgumentNullException">Is raised when <b>sdp</b> is null reference.</exception>
        public void ReInvite(SIP_Uri contact, SDP_Message sdp)
        {
            if (State == SIP_DialogState.Disposed)
            {
                throw new ObjectDisposedException(GetType().Name);
            }
            if (HasPendingInvite)
            {
                throw new InvalidOperationException("There is pending INVITE.");
            }
            if (State != SIP_DialogState.Confirmed)
            {
                throw new InvalidOperationException("ReInvite is only available in Confirmed state.");
            }
            if (sdp == null)
            {
                throw new ArgumentNullException("sdp");
            }

            lock (SyncRoot)
            {
                // TODO:

                SIP_Request reinvite = CreateRequest(SIP_Methods.INVITE);
                if (contact != null)
                {
                    reinvite.Contact.RemoveAll();
                    reinvite.Contact.Add(contact.ToString());
                }
                reinvite.ContentType = "application/sdp";
                // reinvite.Data = sdp.ToStringData();

                // TODO: Create request sender
                // TODO: Try to reuse existing data flow
                //SIP_RequestSender sender = this.Stack.CreateRequestSender(reinvite);
                //sender.Start();
            }
        }
Beispiel #11
0
        private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
        {
            var time = e.Packet.Timeval.Date;
            var len  = e.Packet.Data.Length;

            var packet = PacketDotNet.Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data);

            var udpPacket = PacketDotNet.UdpPacket.GetEncapsulated(packet);

            if (udpPacket != null)
            {
                try
                {
                    // signalling packet
                    SIP_Message msg = ParseSIPMessage(udpPacket.PayloadData);
                    if (msg != null && msg.CallID != null)
                    {
                        SDP_Message sdp = null;

                        try
                        {
                            sdp = SDP_Message.Parse(System.Text.ASCIIEncoding.Default.GetString(msg.Data));
                        }
                        catch { }

                        if (msg is SIP_Request && msg.CallID != null)
                        {
                            SIP_Request r = (SIP_Request)msg;

                            if (!Call.Calls.ContainsKey(r.CallID))
                            {
                                if (r.RequestLine.Method == "INVITE")
                                {
                                    Call.Calls.Add(r.CallID, new Call(r.CallID));
                                    Call.Calls[r.CallID].CallerIP = ((IpPacket)udpPacket.ParentPacket).SourceAddress;
                                    Call.Calls[r.CallID].CalleeIP = ((IpPacket)udpPacket.ParentPacket).DestinationAddress;
                                }
                                else
                                {
                                    return;     // Ignore this conversation
                                }
                            }

                            // if this is an invite, do we have an audio rtp port defined?
                            if (r.RequestLine.Method == "INVITE")
                            {
                                if (sdp != null)
                                {
                                    foreach (var a in sdp.MediaDescriptions)
                                    {
                                        Console.Out.WriteLine(r.CallID + " - Got RTP Media Port: " + ((IpPacket)udpPacket.ParentPacket).SourceAddress + ":" + a.Port.ToString());
                                        if (Call.Calls[r.CallID].CallerIP.ToString() == ((IpPacket)udpPacket.ParentPacket).SourceAddress.ToString())
                                        {
                                            Call.Calls[r.CallID].CallerRTPPort = a.Port;
                                        }
                                        else
                                        {
                                            Call.Calls[r.CallID].CalleeRTPPort = a.Port;
                                        }
                                    }
                                }
                            }

                            if (r.RequestLine.Method == "BYE")
                            {
                                if (Call.Calls.ContainsKey(r.CallID))
                                {
                                    // Log bye was recevied
                                    Call.Calls[r.CallID].SeenBYE = true;

                                    // Now indicate who hung up
                                    Call.Calls[r.CallID].WhoHungUp = ((IpPacket)udpPacket.ParentPacket).SourceAddress == Call.Calls[r.CallID].CallerIP ?
                                                                     Call.CallDirection.Caller : Call.CallDirection.Callee;
                                }
                                else
                                {
                                    Console.WriteLine("Unknown CallID: " + r.CallID);
                                }
                            }
                        }
                        else if (msg is SIP_Response && msg.CallID != null)
                        {
                            SIP_Response r = (SIP_Response)msg;

                            if (sdp != null)
                            {
                                foreach (var a in sdp.MediaDescriptions)
                                {
                                    Console.Out.WriteLine(r.CallID + " - Got RTP Media Port: " + ((IpPacket)udpPacket.ParentPacket).SourceAddress + ":" + a.Port.ToString());
                                    if (Call.Calls[r.CallID].CallerIP.ToString() == ((IpPacket)udpPacket.ParentPacket).SourceAddress.ToString())
                                    {
                                        Call.Calls[r.CallID].CallerRTPPort = a.Port;
                                    }
                                    else
                                    {
                                        Call.Calls[r.CallID].CalleeRTPPort = a.Port;
                                    }
                                }
                            }

                            if (Call.Calls.ContainsKey(r.CallID))
                            {
                                if (r.StatusCodeType == SIP_StatusCodeType.Success && Call.Calls[r.CallID].SeenBYE)
                                {
                                    Call.Calls[r.CallID].Confirmed = true;
                                }
                            }
                        }

                        // Add packet to history
                        if (Call.Calls.ContainsKey(msg.CallID))
                        {
                            Call.Calls[msg.CallID].WritePacket(e.Packet, Call.PacketType.SIPDialog);
                            // Check to see is this call has been terminated
                            if (Call.Calls[msg.CallID].Confirmed)
                            {
                                // Close off the call now last data has been written
                                Console.WriteLine("Call Ended: " + msg.CallID);

                                // Close off the call
                                Call.Calls[msg.CallID].CloseCall();

                                // Remove the call from the in-memory list
                                Call.Calls.Remove(msg.CallID);
                            }
                        }
                    }
                    else
                    {
                        Call c = Call.GetCallByRTPPort(udpPacket.SourcePort);
                        if (c != null)
                        {
                            c.WritePacket(e.Packet, Call.PacketType.RTP);
                        }
                    }
                }
                catch (Exception ex) {
                    Console.WriteLine(ex.ToString());
                }
            }
        }
        /// <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);
                }
            }
        }
        public void Handler(Packet packet)
        {
            var udpPacket = UdpPacket.GetEncapsulated(packet);

            // if it's not udp , udpPacket will be null and we don't handle it.
            if (udpPacket != null)
            {
                try
                {
                    // signalling packet
                    SIP_Message msg = ParseSIPMessage(udpPacket.PayloadData);
                    if (msg != null && msg.CallID != null)
                    {
                        SDP_Message sdp = null;
                        Console.WriteLine("SIP capture");
                        try
                        {
                            sdp = SDP_Message.Parse(System.Text.Encoding.Default.GetString(msg.Data));
                        }
                        catch { }

                        if (msg is SIP_Request && msg.CallID != null)
                        {
                            SIP_Request r = (SIP_Request)msg;
                            //already containsKey
                            if (!Call.SIPSessions.ContainsKey(r.CallID))
                            {
                                if (r.RequestLine.Method == "INVITE")
                                {
                                    Call.SIPSessions.Add(r.CallID, new Call(r.CallID));
                                    Call.SIPSessions[r.CallID].CallerIP = ((IpPacket)udpPacket.ParentPacket).SourceAddress;
                                    Call.SIPSessions[r.CallID].CalleeIP = ((IpPacket)udpPacket.ParentPacket).DestinationAddress;
                                }
                                else
                                {
                                    return;     // Ignore this conversation
                                }
                            }

                            // if this is an invite, do we have an audio rtp port defined?
                            if (r.RequestLine.Method == "INVITE")
                            {
                                if (sdp != null)
                                {
                                    foreach (var a in sdp.MediaDescriptions)
                                    {
                                        Console.Out.WriteLine(r.CallID + " - Got RTP Media Port: " + ((IpPacket)udpPacket.ParentPacket).SourceAddress + ":" + a.Port.ToString());
                                        if (Call.SIPSessions[r.CallID].CallerIP.ToString() == ((IpPacket)udpPacket.ParentPacket).SourceAddress.ToString())
                                        {
                                            Call.SIPSessions[r.CallID].CallerRTPPort = a.Port;
                                        }
                                        else
                                        {
                                            Call.SIPSessions[r.CallID].CalleeRTPPort = a.Port;
                                        }
                                        a.MediaFormats.GetType();

                                        break; // First description is about audio . Second is about viedo and we don't need it, so break.
                                    }
                                }
                            }

                            if (r.RequestLine.Method == "BYE")
                            {
                                if (Call.SIPSessions.ContainsKey(r.CallID))
                                {
                                    // Log bye was recevied
                                    Call.SIPSessions[r.CallID].SeenBYE = true;

                                    // Now indicate who hung up
                                    Call.SIPSessions[r.CallID].WhoHungUp = ((IpPacket)udpPacket.ParentPacket).SourceAddress == Call.SIPSessions[r.CallID].CallerIP ?
                                                                           Call.CallDirection.Caller : Call.CallDirection.Callee;
                                }
                                else
                                {
                                    Console.WriteLine("Unknown CallID: " + r.CallID);
                                }
                            }
                        }//    if (msg is SIP_Request && msg.CallID != null)
                        else if (msg is SIP_Response && msg.CallID != null)
                        {
                            SIP_Response r = (SIP_Response)msg;

                            if (r.StatusCode != 183 && r.StatusCode != 100 && r.StatusCode != 200)
                            {
                                Call.SIPSessions[r.CallID].isEnd = true;
                            }

                            if (sdp != null)
                            {
                                foreach (var a in sdp.MediaDescriptions)
                                {
                                    Console.Out.WriteLine(r.CallID + " - Got RTP Media Port: " + ((IpPacket)udpPacket.ParentPacket).SourceAddress + ":" + a.Port.ToString());
                                    if (Call.SIPSessions[r.CallID].CallerIP.ToString() == ((IpPacket)udpPacket.ParentPacket).SourceAddress.ToString())
                                    {
                                        Call.SIPSessions[r.CallID].CallerRTPPort = a.Port;
                                    }
                                    else
                                    {
                                        Call.SIPSessions[r.CallID].CalleeRTPPort = a.Port;
                                    }

                                    break; // First description is about audio . Second is about viedo and we don't need it, so break.
                                }
                            }

                            if (Call.SIPSessions.ContainsKey(r.CallID))
                            {
                                if (r.StatusCodeType == SIP_StatusCodeType.Success && Call.SIPSessions[r.CallID].SeenBYE)
                                {
                                    Call.SIPSessions[r.CallID].Confirmed = true;
                                    Call.SIPSessions[r.CallID].isEnd     = true;
                                }
                            }
                        }

                        // Add packet to history
                        if (Call.SIPSessions.ContainsKey(msg.CallID))
                        {
                            Call.SIPSessions[msg.CallID].WritePacket(packet, Call.PacketType.SIPDialog);
                            // Check to see is this call has been terminated
                            if (Call.SIPSessions[msg.CallID].Confirmed)
                            {
                                // Close off the call now last data has been written
                                Console.WriteLine("Call Ended: " + msg.CallID);

                                // Close off the call
                                Call.SIPSessions[msg.CallID].CloseCall();

                                StringBuilder file        = new StringBuilder(Directory.GetCurrentDirectory() + "//" + Call.SIPSessions[msg.CallID].SIPPacketFilePathAndName);
                                StringBuilder StoragePath = new StringBuilder(Directory.GetCurrentDirectory() + "//" + Call.SIPSessions[msg.CallID].SIPPacketFilePath);
                                pacp_to_wav(file, StoragePath);
                            }

                            if (Call.SIPSessions[msg.CallID].isEnd == true)
                            {
                                Call.SIPSessions.Remove(msg.CallID);
                            }
                        }
                    }
                    else
                    {
                        Call c = Call.GetCallByRTPPort(udpPacket.SourcePort);
                        if (c != null)
                        {
                            c.WritePacket(packet, Call.PacketType.RTP);
                        }
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
            }
        }