/// <summary> /// Sets the remote end point for the RTP channel. This will be set from the SDP packet received from the remote /// end of the VoIP call. /// </summary> /// <param name="remoteEndPoint">The remote end point to send RTP to.</param> public void SetRemoteRTPEndPoints(IPEndPoint audioRemoteEndPoint, IPEndPoint videoRemoteEndPoint) { if (audioRemoteEndPoint != null) { logger.Debug("Remote RTP audio end point set as " + audioRemoteEndPoint + "."); _rtpAudioChannel.RemoteEndPoint = audioRemoteEndPoint; _rtpAudioChannel.Start(); } else if (videoRemoteEndPoint != null) { logger.Debug("Remote RTP video end point set as " + videoRemoteEndPoint + "."); _remoteVideoEP = videoRemoteEndPoint; _rtpVideoChannel.RemoteEndPoint = videoRemoteEndPoint; _rtpVideoChannel.Start(); } }
/// <summary> /// 实时视频请求 /// </summary> public void RealVideoRequest() { SipInitialize(); _mediaPort = _messageCore.SetMediaPort(); SIPRequest request = InviteRequest(); RealVideo real = new RealVideo() { Address = _cameraId, Variable = VariableType.RealMedia, Privilege = 90, Format = "4CIF CIF QCIF 720p 1080p", Video = "H.264", Audio = "G.711", MaxBitrate = 800, Socket = this.ToString() }; string xmlBody = RealVideo.Instance.Save <RealVideo>(real); request.Body = xmlBody; _m_sipTransport.SendRequest(_remoteEndPoint, request); //启动RTP通道 _rtpChannel.IsClosed = false; _rtpChannel.ReservePorts(_mediaPort[0], _mediaPort[1]); _rtpChannel.Start(); }
/// <summary> /// 确认接收视频请求 /// </summary> /// <param name="response">响应消息</param> /// <returns></returns> public void AckRequest(SIPResponse response) { _rtpChannel = new RTPChannel(_remoteEndPoint.GetIPEndPoint(), _mediaPort[0], _mediaPort[1], FrameTypesEnum.H264); _rtpChannel.OnFrameReady += _rtpChannel_OnFrameReady; _rtpChannel.Start(); SIPURI localUri = new SIPURI(_msgCore.LocalSIPId, _msgCore.LocalEndPoint.ToHost(), ""); SIPURI remoteUri = new SIPURI(_deviceId, _remoteEndPoint.ToHost(), ""); SIPRequest ackReq = _msgCore.Transport.GetRequest(SIPMethodsEnum.ACK, remoteUri); SIPFromHeader from = new SIPFromHeader(null, response.Header.From.FromURI, response.Header.From.FromTag); SIPToHeader to = new SIPToHeader(null, remoteUri, response.Header.To.ToTag); SIPContactHeader contactHeader = new SIPContactHeader(null, localUri); SIPHeader header = new SIPHeader(from, to, response.Header.CSeq, response.Header.CallId); header.CSeqMethod = SIPMethodsEnum.ACK; header.Contact = response.Header.Contact; header.Contact.Clear(); header.Contact.Add(contactHeader); header.Vias = response.Header.Vias; header.MaxForwards = response.Header.MaxForwards; header.ContentLength = response.Header.ContentLength; header.UserAgent = _msgCore.UserAgent; header.Allow = null; ackReq.Header = header; _okTag = response.Header.To.ToTag; _contact = header.Contact.FirstOrDefault(); _via = header.Vias; _msgCore.Transport.SendRequest(_remoteEndPoint, ackReq); }
public void MultipleRtpChannelLoopbackUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); const int PACKET_LENGTH = 100; List <Task> tasks = new List <Task>(); for (int i = 0; i < 3; i++) { var t = Task.Run(async() => { RTPChannel channel1 = new RTPChannel(false, null); bool testResult = false; ManualResetEventSlim testCompleteEvent = new ManualResetEventSlim(false); RTPChannel channel2 = new RTPChannel(false, null); channel2.OnRTPDataReceived += (lep, rep, pkt) => { logger.LogDebug($"RTP data receive packet length {pkt.Length}."); testResult = pkt.Length == PACKET_LENGTH; testCompleteEvent.Set(); }; channel1.Start(); channel2.Start(); // Give the socket receive tasks time to fire up. await Task.Delay(2000); IPAddress channel2Address = (channel2.RTPLocalEndPoint.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Loopback : IPAddress.Loopback; IPEndPoint channel2Dst = new IPEndPoint(channel2Address, channel2.RTPPort); logger.LogDebug($"Attempting to send packet from {channel1.RTPLocalEndPoint} to {channel2Dst}."); var sendResult = channel1.SendAsync(RTPChannelSocketsEnum.RTP, channel2Dst, new byte[PACKET_LENGTH]); logger.LogDebug($"Send result {sendResult}."); testCompleteEvent.Wait(TimeSpan.FromSeconds(TEST_TIMEOUT_SECONDS)); Assert.True(testResult); channel1.Close("normal"); channel2.Close("normal"); }); tasks.Add(t); } CancellationTokenSource cts = new CancellationTokenSource(); Assert.True(Task.WaitAll(tasks.ToArray(), 10000, cts.Token)); logger.LogDebug($"Test complete."); }
public async void RtpChannelLoopbackUnitTest() { logger.LogDebug("--> " + System.Reflection.MethodBase.GetCurrentMethod().Name); logger.BeginScope(System.Reflection.MethodBase.GetCurrentMethod().Name); RTPChannel channel1 = new RTPChannel(false, null); bool testResult = false; ManualResetEventSlim testCompleteEvent = new ManualResetEventSlim(false); RTPChannel channel2 = new RTPChannel(false, null); channel2.OnRTPDataReceived += (lep, rep, pkt) => { logger.LogDebug($"RTP data receive packet length {pkt.Length}."); testResult = true; testCompleteEvent.Set(); }; channel1.Start(); channel2.Start(); // Give the socket receive tasks time to fire up. await Task.Delay(1000); IPAddress channel2Address = (channel2.RTPLocalEndPoint.AddressFamily == AddressFamily.InterNetworkV6) ? IPAddress.IPv6Loopback : IPAddress.Loopback; IPEndPoint channel2Dst = new IPEndPoint(channel2Address, channel2.RTPPort); logger.LogDebug($"Attempting to send packet from {channel1.RTPLocalEndPoint} to {channel2Dst}."); var sendResult = channel1.SendAsync(RTPChannelSocketsEnum.RTP, channel2Dst, new byte[] { 0x00 }); logger.LogDebug($"Send result {sendResult}."); testCompleteEvent.Wait(TimeSpan.FromSeconds(TEST_TIMEOUT_SECONDS)); Assert.True(testResult); channel1.Close("normal"); channel2.Close("normal"); logger.LogDebug($"Test complete."); }
private void Uac_CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { logger.Debug($"{ prefix } Call answered; { sipResponse.StatusCode } { sipResponse.Status }"); switch (sipResponse.StatusCode) { case 404: logger.Error($"{ prefix } Received 404 Not Found from remote endpoint"); break; case 486: // Busy logger.Error($"{ prefix } Received 486 Remote endpoint is busy; try again later"); break; case 488: // Possible audio format issue logger.Error($"{ prefix } Received 488 Not Acceptable from remote endpoint; check audio format"); break; case 503: // Check Twilio service and geo-permissions logger.Error($"{ prefix } Received 503 Service Unavailable from remote endpoint; check service permissions"); break; case 200: if (sipResponse.Header.ContentType != SDP.SDP_MIME_CONTENTTYPE) { logger.Error($"{ prefix } Received incorrect content type"); Stop(); return; } if (sipResponse.Body.IsNullOrBlank()) { logger.Error($"{ prefix } Received an empty SDP payload"); Stop(); return; } var sdp = SDP.ParseSDPDescription(sipResponse.Body); var ip = IPAddress.Parse(sdp.Connection.ConnectionAddress); var announcement = sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).FirstOrDefault(); if (announcement != null) { if (announcement.Port != 0) { rtpChannel.OnControlDataReceived += (b) => { logger.Debug($"{prefix} Control Data Received; {b.Length} bytes"); }; rtpChannel.OnControlSocketDisconnected += () => { logger.Debug($"{prefix} Control Socket Disconnected"); }; rtpChannel.RemoteEndPoint = new IPEndPoint(ip, announcement.Port); rtpChannel.Start(); // Send some setup parameters to punch a hole in the firewall/router rtpChannel.SendRTPRaw(new byte[] { 80, 95, 198, 88, 55, 96, 225, 141, 215, 205, 185, 242, 00 }); } else { logger.Error($"{ prefix } Remote endpoint did not specify a port number"); return; } } else { logger.Error($"{ prefix } Remote endpoint has not valid audio announcement"); return; } break; } }
private void Transport_SIPTransportRequestReceived(SIPEndPoint localSIPEndPoint, SIPEndPoint remoteEndPoint, SIPRequest sipRequest) { var endpoint = new SIPEndPoint(SIPProtocolsEnum.udp, publicIPAddress, localSIPEndPoint.Port); if (sipRequest.Method == SIPMethodsEnum.INVITE) { if (transaction != null) { return; } logger.DebugFormat("{0} Incoming call from {1}", prefix, sipRequest.Header.From.FromURI.User); transaction = transport.CreateUASTransaction(sipRequest, remoteEndPoint, endpoint, null); agent = new SIPServerUserAgent( transport, null, sipRequest.Header.From.FromURI.User, null, SIPCallDirection.In, null, null, null, transaction); agent.CallCancelled += Agent_CallCancelled; agent.TransactionComplete += Agent_TransactionComplete; agent.Progress(SIPResponseStatusCodesEnum.Trying, null, null, null, null); agent.Progress(SIPResponseStatusCodesEnum.Ringing, null, null, null, null); var answer = SDP.ParseSDPDescription(agent.CallRequest.Body); var address = IPAddress.Parse(answer.Connection.ConnectionAddress); var port = answer.Media.FirstOrDefault(m => m.Media == SDPMediaTypesEnum.audio).Port; var random = Crypto.GetRandomInt(5).ToString(); var sdp = new SDP { Version = 2, Username = "******", SessionId = random, Address = localIPEndPoint.Address.ToString(), SessionName = "redfox_" + random, Timing = "0 0", Connection = new SDPConnectionInformation(publicIPAddress.ToString()) }; rtpChannel = new RTPChannel { DontTimeout = true, RemoteEndPoint = new IPEndPoint(address, port) }; rtpChannel.SetFrameType(FrameTypesEnum.Audio); // TODO Fix hardcoded ports rtpChannel.ReservePorts(15000, 15090); rtpChannel.OnFrameReady += Channel_OnFrameReady; rtpChannel.Start(); // Send some setup parameters to punch a hole in the firewall/router rtpChannel.SendRTPRaw(new byte[] { 80, 95, 198, 88, 55, 96, 225, 141, 215, 205, 185, 242, 00 }); rtpChannel.OnControlDataReceived += (b) => { logger.Debug($"{prefix} Control Data Received; {b.Length} bytes"); }; rtpChannel.OnControlSocketDisconnected += () => { logger.Debug($"{prefix} Control Socket Disconnected"); }; var announcement = new SDPMediaAnnouncement { Media = SDPMediaTypesEnum.audio, MediaFormats = new List <SDPMediaFormat>() { new SDPMediaFormat((int)SDPMediaFormatsEnum.PCMU, "PCMU", 8000) }, Port = rtpChannel.RTPPort }; sdp.Media.Add(announcement); SetState(State.Listening, sipRequest.Header.From.FromURI.User); agent.Progress(SIPResponseStatusCodesEnum.Accepted, null, null, null, null); agent.Answer(SDP.SDP_MIME_CONTENTTYPE, sdp.ToString(), null, SIPDialogueTransferModesEnum.NotAllowed); SetState(State.Busy, ""); return; } if (sipRequest.Method == SIPMethodsEnum.BYE) { if (State != State.Busy) { return; } logger.DebugFormat("{0} Hangup from {1}", prefix, sipRequest.Header.From.FromURI.User); var noninvite = transport.CreateNonInviteTransaction(sipRequest, remoteEndPoint, endpoint, null); var response = SIPTransport.GetResponse(sipRequest, SIPResponseStatusCodesEnum.Ok, null); noninvite.SendFinalResponse(response); SetState(State.Finished, Endpoint); rtpChannel.OnFrameReady -= Channel_OnFrameReady; rtpChannel.Close(); agent.TransactionComplete -= Agent_TransactionComplete; agent.CallCancelled -= Agent_CallCancelled; agent = null; transaction = null; SetState(State.Ready, Endpoint); return; } if (sipRequest.Method == SIPMethodsEnum.ACK) { } if (sipRequest.Method == SIPMethodsEnum.CANCEL) { } }