/// <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; }
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)); } }
/// <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); } }
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()); } } }
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()); } } }