/// <summary> /// Hands the socket handle to the DTLS context and waits for the handshake to complete. /// </summary> /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param> /// <returns>True if the handshake completed successfully or false otherwise.</returns> private static bool DoDtlsHandshake(RTCPeerConnection peerConnection) { logger.LogDebug("DoDtlsHandshake started."); var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); int res = dtls.DoHandshakeAsServer((ulong)peerConnection.GetRtpChannel(SDPMediaTypesEnum.audio).RtpSocket.Handle); logger.LogDebug("DtlsContext initialisation result=" + res); if (dtls.IsHandshakeComplete()) { logger.LogDebug("DTLS negotiation complete."); var srtpSendContext = new Srtp(dtls, false); var srtpReceiveContext = new Srtp(dtls, true); peerConnection.SetSecurityContext( srtpSendContext.ProtectRTP, srtpReceiveContext.UnprotectRTP, srtpSendContext.ProtectRTCP, srtpReceiveContext.UnprotectRTCP); dtls.Shutdown(); return(true); } else { dtls.Shutdown(); return(false); } }
/// <summary> /// Runs a DTLS handshake test between two threads on a loopback address. The main motivation for /// this test was that the first DTLS handshake between this application and a client browser /// was often substantially slower and occasionally failed. By doing a loopback test the idea /// is that the internal OpenSSL state is initialised. /// </summary> private void DoDtlsHandshakeLoopbackTest() { IPAddress testAddr = IPAddress.Loopback; Socket svrSock = new Socket(testAddr.AddressFamily, SocketType.Dgram, ProtocolType.Udp); svrSock.Bind(new IPEndPoint(testAddr, 9000)); int svrPort = ((IPEndPoint)svrSock.LocalEndPoint).Port; DtlsHandshake svrHandshake = new DtlsHandshake(_dtlsCertificatePath, _dtlsKeyPath); //svrHandshake.Debug = true; var svrTask = Task.Run(() => svrHandshake.DoHandshakeAsServer((ulong)svrSock.Handle)); Socket cliSock = new Socket(testAddr.AddressFamily, SocketType.Dgram, ProtocolType.Udp); cliSock.Bind(new IPEndPoint(testAddr, 0)); cliSock.Connect(testAddr, svrPort); DtlsHandshake cliHandshake = new DtlsHandshake(); //cliHandshake.Debug = true; var cliTask = Task.Run(() => cliHandshake.DoHandshakeAsClient((ulong)cliSock.Handle, (short)testAddr.AddressFamily, testAddr.GetAddressBytes(), (ushort)svrPort)); bool result = Task.WaitAll(new Task[] { svrTask, cliTask }, TEST_DTLS_HANDSHAKE_TIMEOUT); cliHandshake.Shutdown(); svrHandshake.Shutdown(); cliSock.Close(); svrSock.Close(); }
/// <summary> /// Hands the socket handle to the DTLS context and waits for the handshake to complete. /// </summary> /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param> /// <returns>True if the handshake completes successfully. False if not.</returns> private static bool DoDtlsHandshake(WebRtcSession webRtcSession) { Console.WriteLine("DoDtlsHandshake started."); var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); webRtcSession.OnClose += (reason) => dtls.Shutdown(); int res = dtls.DoHandshakeAsServer((ulong)webRtcSession.RtpSession.RtpChannel.RtpSocket.Handle); Console.WriteLine("DtlsContext initialisation result=" + res); if (dtls.IsHandshakeComplete()) { Console.WriteLine("DTLS negotiation complete."); // TODO fix race condition!!! First RTP packet is not getting decrypted. var srtpSendContext = new Srtp(dtls, false); var srtpReceiveContext = new Srtp(dtls, true); webRtcSession.RtpSession.SetSecurityContext( srtpSendContext.ProtectRTP, srtpReceiveContext.UnprotectRTP, srtpSendContext.ProtectRTCP, srtpReceiveContext.UnprotectRTCP); return(true); } else { return(false); } }
/// <summary> /// Runs a DTLS handshake test between two threads on a loopback address. The main motivation for /// this test was that the first DTLS handshake between this application and a client browser /// was often substantially slower and occasionally failed. By doing a loopback test the idea /// is that the internal OpenSSL state is initialised. /// </summary> private static void DoDtlsHandshakeLoopbackTest() { IPAddress testAddr = IPAddress.Loopback; //var dtlsFingerprint = DTLS_CERTIFICATE_FINGERPRINT.Substring(DTLS_CERTIFICATE_FINGERPRINT.Length + 1).Trim().Replace(":", "").Replace(" ", ""); //var dtlsFingerprintBuffer = SIPSorcery.Sys.ByteBufferInfo.ParseHexStr(dtlsFingerprint); Socket svrSock = new Socket(testAddr.AddressFamily, SocketType.Dgram, ProtocolType.Udp); svrSock.Bind(new IPEndPoint(testAddr, 9000)); int svrPort = ((IPEndPoint)svrSock.LocalEndPoint).Port; DtlsHandshake svrHandshake = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); svrHandshake.Debug = true; byte[] clientFingerprint = null; var svrTask = Task.Run(() => svrHandshake.DoHandshakeAsServer((ulong)svrSock.Handle, ref clientFingerprint)); Socket cliSock = new Socket(testAddr.AddressFamily, SocketType.Dgram, ProtocolType.Udp); cliSock.Bind(new IPEndPoint(testAddr, 0)); cliSock.Connect(testAddr, svrPort); DtlsHandshake cliHandshake = new DtlsHandshake(); cliHandshake.Debug = true; byte[] serverFingerprint = null; var cliTask = Task.Run(() => cliHandshake.DoHandshakeAsClient((ulong)cliSock.Handle, (short)testAddr.AddressFamily, testAddr.GetAddressBytes(), (ushort)svrPort, ref serverFingerprint)); bool result = Task.WaitAll(new Task[] { svrTask, cliTask }, TEST_DTLS_HANDSHAKE_TIMEOUT); cliHandshake.Shutdown(); svrHandshake.Shutdown(); cliSock.Close(); svrSock.Close(); }
/// <summary> /// Hands the socket handle to the DTLS context and waits for the handshake to complete. /// </summary> /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param> /// <returns>True if the handshake completed successfully or false otherwise.</returns> private bool DoDtlsHandshake(WebRtcSession webRtcSession) { try { logger.LogDebug("DoDtlsHandshake started."); if (!File.Exists(_dtlsCertificatePath)) { throw new ApplicationException($"The DTLS certificate file could not be found at {_dtlsCertificatePath}."); } else if (!File.Exists(_dtlsKeyPath)) { throw new ApplicationException($"The DTLS key file could not be found at {_dtlsKeyPath}."); } var dtls = new DtlsHandshake(_dtlsCertificatePath, _dtlsKeyPath); webRtcSession.OnClose += (reason) => dtls.Shutdown(); int res = dtls.DoHandshakeAsServer((ulong)webRtcSession.RtpSession.RtpChannel.RtpSocket.Handle); logger.LogDebug("DtlsContext initialisation result=" + res); if (dtls.IsHandshakeComplete()) { logger.LogDebug("DTLS negotiation complete."); var srtpSendContext = new Srtp(dtls, false); var srtpReceiveContext = new Srtp(dtls, true); webRtcSession.RtpSession.SetSecurityContext( srtpSendContext.ProtectRTP, srtpReceiveContext.UnprotectRTP, srtpSendContext.ProtectRTCP, srtpReceiveContext.UnprotectRTCP); webRtcSession.IsDtlsNegotiationComplete = true; return(true); } else { return(false); } } catch (Exception excp) { logger.LogWarning($"Exception DoDtlsHandshake. {excp}"); return(false); } }
/// <summary> /// Hands the socket handle to the DTLS context and waits for the handshake to complete. /// </summary> /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param> private static bool DoDtlsHandshake(RTCPeerConnection peerConnection) { Log.LogDebug("DoDtlsHandshake started."); if (!File.Exists(DTLS_CERTIFICATE_PATH)) { throw new ApplicationException($"The DTLS certificate file could not be found at {DTLS_CERTIFICATE_PATH}."); } else if (!File.Exists(DTLS_KEY_PATH)) { throw new ApplicationException($"The DTLS key file could not be found at {DTLS_KEY_PATH}."); } var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); peerConnection.onconnectionstatechange += (state) => { if (state == RTCPeerConnectionState.closed) { dtls.Shutdown(); } }; byte[] clientFingerprint = null; int res = dtls.DoHandshakeAsServer((ulong)peerConnection.GetRtpChannel(SDPMediaTypesEnum.audio).RtpSocket.Handle, ref clientFingerprint); Log.LogDebug("DtlsContext initialisation result=" + res); if (dtls.IsHandshakeComplete()) { // TODO: Check client fingerprint matches one supplied in the SDP. Log.LogDebug("DTLS negotiation complete."); var srtpSendContext = new Srtp(dtls, false); var srtpReceiveContext = new Srtp(dtls, true); peerConnection.SetSecurityContext( srtpSendContext.ProtectRTP, srtpReceiveContext.UnprotectRTP, srtpSendContext.ProtectRTCP, srtpReceiveContext.UnprotectRTCP); return(true); } else { return(false); } }
/// <summary> /// Hands the socket handle to the DTLS context and waits for the handshake to complete. /// </summary> /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param> private static async Task <bool> DoDtlsHandshake(RTCPeerConnection peerConnection) { logger.LogDebug("DoDtlsHandshake started."); if (!File.Exists(DTLS_CERTIFICATE_PATH)) { throw new ApplicationException($"The DTLS certificate file could not be found at {DTLS_CERTIFICATE_PATH}."); } else if (!File.Exists(DTLS_KEY_PATH)) { throw new ApplicationException($"The DTLS key file could not be found at {DTLS_KEY_PATH}."); } var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); byte[] clientFingerprint = null; var dtlsResult = await Task.Run(() => dtls.DoHandshakeAsServer((ulong)peerConnection.GetRtpChannel(SDPMediaTypesEnum.audio).RtpSocket.Handle, ref clientFingerprint)); logger.LogDebug("DtlsContext initialisation result=" + dtlsResult); if (dtls.IsHandshakeComplete()) { logger.LogDebug("DTLS handshake succeeded."); // TODO: Check client fingerprint matches one supplied in the SDP. var srtpSendContext = new Srtp(dtls, false); var srtpReceiveContext = new Srtp(dtls, true); peerConnection.SetSecurityContext( srtpSendContext.ProtectRTP, srtpReceiveContext.UnprotectRTP, srtpSendContext.ProtectRTCP, srtpReceiveContext.UnprotectRTCP); return(true); } else { logger.LogWarning("DTLS handshake failed."); dtls.Shutdown(); return(false); } }
/// <summary> /// Hands the socket handle to the DTLS context and waits for the handshake to complete. /// </summary> /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param> private static int DoDtlsHandshake(WebRtcSession webRtcSession) { logger.LogDebug("DoDtlsHandshake started."); if (!File.Exists(DTLS_CERTIFICATE_PATH)) { throw new ApplicationException($"The DTLS certificate file could not be found at {DTLS_CERTIFICATE_PATH}."); } else if (!File.Exists(DTLS_KEY_PATH)) { throw new ApplicationException($"The DTLS key file could not be found at {DTLS_KEY_PATH}."); } var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); webRtcSession.OnClose += (reason) => dtls.Shutdown(); int res = dtls.DoHandshakeAsServer((ulong)webRtcSession.RtpSession.RtpChannel.RtpSocket.Handle); logger.LogDebug("DtlsContext initialisation result=" + res); if (dtls.IsHandshakeComplete()) { logger.LogDebug("DTLS negotiation complete."); var srtpSendContext = new Srtp(dtls, false); var srtpReceiveContext = new Srtp(dtls, true); webRtcSession.RtpSession.SetSecurityContext( srtpSendContext.ProtectRTP, srtpReceiveContext.UnprotectRTP, srtpSendContext.ProtectRTCP, srtpReceiveContext.UnprotectRTCP); if (!_isSampling) { Task.Run(StartMedia); } } return(res); }
/// <summary> /// Hands the socket handle to the DTLS context and waits for the handshake to complete. /// </summary> /// <param name="webRtcSession">The WebRTC session to perform the DTLS handshake on.</param> private static bool DoDtlsHandshake(RTCPeerConnection peerConnection, DtlsHandshake dtls) { Log.LogDebug("DoDtlsHandshake started."); if (!File.Exists(DTLS_CERTIFICATE_PATH)) { throw new ApplicationException($"The DTLS certificate file could not be found at {DTLS_CERTIFICATE_PATH}."); } else if (!File.Exists(DTLS_KEY_PATH)) { throw new ApplicationException($"The DTLS key file could not be found at {DTLS_KEY_PATH}."); } byte[] clientFingerprint = null; var dtlsResult = dtls.DoHandshakeAsServer((ulong)peerConnection.GetRtpChannel(SDPMediaTypesEnum.audio).RtpSocket.Handle, ref clientFingerprint); Log.LogDebug($"DtlsContext initialisation result {dtlsResult}."); if (dtls.IsHandshakeComplete()) { Log.LogDebug("DTLS negotiation complete."); var srtpSendContext = new Srtp(dtls, false); var srtpReceiveContext = new Srtp(dtls, true); peerConnection.SetSecurityContext( srtpSendContext.ProtectRTP, srtpReceiveContext.UnprotectRTP, srtpSendContext.ProtectRTCP, srtpReceiveContext.UnprotectRTCP); return(true); } else { Log.LogWarning("DTLS handshake failed."); dtls.Shutdown(); return(false); } }
public async Task <RTCSessionDescriptionInit> GetOffer(string id) { if (string.IsNullOrWhiteSpace(id)) { throw new ArgumentNullException("id", "A unique ID parameter must be supplied when creating a new peer connection."); } else if (_peerConnections.ContainsKey(id)) { throw new ArgumentNullException("id", "The specified peer connection ID is already in use."); } RTCConfiguration pcConfiguration = new RTCConfiguration { certificates = new List <RTCCertificate> { new RTCCertificate { X_CertificatePath = DTLS_CERTIFICATE_PATH, X_KeyPath = DTLS_KEY_PATH, X_Fingerprint = DTLS_CERTIFICATE_FINGERPRINT } } }; var peerConnection = new RTCPeerConnection(pcConfiguration); var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); MediaStreamTrack audioTrack = new MediaStreamTrack("0", SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }, MediaStreamStatusEnum.RecvOnly); peerConnection.addTrack(audioTrack); //peerConnection.OnRtpPacketReceived += (SDPMediaTypesEnum media, RTPPacket rtpPkt) => _logger.LogDebug($"RTP {media} pkt received, SSRC {rtpPkt.Header.SyncSource}, SeqNum {rtpPkt.Header.SequenceNumber}."); //peerConnection.OnReceiveReport += RtpSession_OnReceiveReport; //peerConnection.OnSendReport += RtpSession_OnSendReport; peerConnection.OnTimeout += (mediaType) => { peerConnection.Close("remote timeout"); dtls.Shutdown(); }; peerConnection.onconnectionstatechange += (state) => { if (state == RTCPeerConnectionState.closed || state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed) { //peerConnection.OnReceiveReport -= RtpSession_OnReceiveReport; //peerConnection.OnSendReport -= RtpSession_OnSendReport; _logger.LogDebug($"Peer connection {id} closed."); _peerConnections.TryRemove(id, out _); } else if (state == RTCPeerConnectionState.connected) { _logger.LogDebug("Peer connection connected."); } }; _ = Task <bool> .Run(() => Task.FromResult(DoDtlsHandshake(peerConnection, dtls))) .ContinueWith((t) => { _logger.LogDebug($"dtls handshake result {t.Result}."); if (t.Result) { var remoteEP = peerConnection.IceSession.ConnectedRemoteEndPoint; peerConnection.SetDestination(SDPMediaTypesEnum.audio, remoteEP, remoteEP); } else { dtls.Shutdown(); peerConnection.Close("dtls handshake failed."); } }); var offerSdp = await peerConnection.createOffer(null); await peerConnection.setLocalDescription(offerSdp); _peerConnections.TryAdd(id, peerConnection); return(offerSdp); }
static async Task Main() { Console.WriteLine("SIPSorcery sip.js Demo"); AddConsoleLogger(); var sipTransport = new SIPTransport(); EnableTraceLogs(sipTransport); var sipChannel = new SIPWebSocketChannel(IPAddress.Loopback, 80); var wssCertificate = new System.Security.Cryptography.X509Certificates.X509Certificate2("localhost.pfx"); var sipChannelSecure = new SIPWebSocketChannel(IPAddress.Loopback, 443, wssCertificate); sipTransport.AddSIPChannel(sipChannel); sipTransport.AddSIPChannel(sipChannelSecure); var userAgent = new SIPUserAgent(sipTransport, null, true); userAgent.OnIncomingCall += async(ua, req) => { Log.LogDebug($"Auto-answering incoming call from {req.Header.From}."); var uas = userAgent.AcceptCall(req); RTCConfiguration pcConfiguration = new RTCConfiguration { certificates = new List <RTCCertificate> { new RTCCertificate { X_CertificatePath = DTLS_CERTIFICATE_PATH, X_KeyPath = DTLS_KEY_PATH, X_Fingerprint = DTLS_CERTIFICATE_FINGERPRINT } }, //X_RemoteSignallingAddress = context.UserEndPoint.Address, //iceServers = new List<RTCIceServer> { new RTCIceServer { urls = SIPSORCERY_STUN_SERVER } } }; var peerConnection = new RTCPeerConnection(pcConfiguration); var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); peerConnection.OnTimeout += (mediaType) => { peerConnection.Close("remote timeout"); }; peerConnection.oniceconnectionstatechange += async(state) => { Log.LogDebug($"ICE connection state change to {state}."); if (state == RTCIceConnectionState.connected) { var remoteEndPoint = peerConnection.AudioDestinationEndPoint; Log.LogInformation($"ICE connected to remote end point {remoteEndPoint}."); await Task.Run(() => DoDtlsHandshake(peerConnection, dtls)) .ContinueWith((dtlsResult) => { Log.LogDebug($"dtls handshake result {dtlsResult.Result}."); if (dtlsResult.Result) { var remoteEP = peerConnection.AudioDestinationEndPoint; peerConnection.SetDestination(SDPMediaTypesEnum.audio, remoteEP, remoteEP); } else { dtls.Shutdown(); peerConnection.Close("dtls handshake failed."); } }); } }; peerConnection.onconnectionstatechange += (state) => { if (state == RTCPeerConnectionState.connected) { var remoteEP = peerConnection.AudioDestinationEndPoint; Log.LogDebug($"DTLS connected on {remoteEP}."); peerConnection.SetDestination(SDPMediaTypesEnum.audio, remoteEP, remoteEP); peerConnection.SetDestination(SDPMediaTypesEnum.video, remoteEP, remoteEP); peerConnection.OnReceiveReport += RtpSession_OnReceiveReport; peerConnection.OnSendReport += RtpSession_OnSendReport; // peerConnection.OnRtpPacketReceived += OnRtpPacketReceived; } }; MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }, MediaStreamStatusEnum.SendRecv); peerConnection.addTrack(audioTrack); //MediaStreamTrack videoTrack = new MediaStreamTrack("1", SDPMediaTypesEnum.video, false, new List<SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.VP8) }, MediaStreamStatusEnum.Inactive); //peerConnection.addTrack(videoTrack); var answerResult = await userAgent.Answer(uas, peerConnection); }; Console.Write("press any key to exit..."); Console.Read(); sipTransport.Shutdown(); }
private static async Task <RTCPeerConnection> SendSDPOffer(WebSocketContext context) { logger.LogDebug($"Web socket client connection from {context.UserEndPoint}."); RTCConfiguration pcConfiguration = new RTCConfiguration { certificates = new List <RTCCertificate> { new RTCCertificate { X_CertificatePath = DTLS_CERTIFICATE_PATH, X_KeyPath = DTLS_KEY_PATH, X_Fingerprint = DTLS_CERTIFICATE_FINGERPRINT } } }; var peerConnection = new RTCPeerConnection(pcConfiguration); var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }); peerConnection.addTrack(audioTrack); MediaStreamTrack videoTrack = new MediaStreamTrack(SDPMediaTypesEnum.video, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.VP8) }); peerConnection.addTrack(videoTrack); peerConnection.OnReceiveReport += RtpSession_OnReceiveReport; peerConnection.OnSendReport += RtpSession_OnSendReport; peerConnection.OnTimeout += (mediaType) => { peerConnection.Close("remote timeout"); dtls.Shutdown(); }; peerConnection.onconnectionstatechange += (state) => { if (state == RTCPeerConnectionState.closed || state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed) { logger.LogDebug($"RTC peer connection was closed."); OnMediaSampleReady -= peerConnection.SendMedia; peerConnection.OnReceiveReport -= RtpSession_OnReceiveReport; peerConnection.OnSendReport -= RtpSession_OnSendReport; } else if (state == RTCPeerConnectionState.connected) { logger.LogDebug("Peer connection connected."); OnMediaSampleReady += peerConnection.SendMedia; } }; peerConnection.oniceconnectionstatechange += (state) => { if (state == RTCIceConnectionState.connected) { logger.LogDebug("Starting DTLS handshake task."); bool dtlsResult = false; Task.Run(async() => dtlsResult = await DoDtlsHandshake(peerConnection, dtls, peerConnection.RemotePeerDtlsFingerprint)) .ContinueWith((t) => { logger.LogDebug($"dtls handshake result {dtlsResult}."); if (dtlsResult) { //peerConnection.SetDestination(SDPMediaTypesEnum.audio, peerConnection.IceSession.ConnectedRemoteEndPoint, peerConnection.IceSession.ConnectedRemoteEndPoint); } else { dtls.Shutdown(); peerConnection.Close("dtls handshake failed."); } }); } }; var offerInit = peerConnection.createOffer(null); await peerConnection.setLocalDescription(offerInit); logger.LogDebug($"Sending SDP offer to client {context.UserEndPoint}."); context.WebSocket.Send(offerInit.sdp); return(peerConnection); }
private static async void WebSocketMessageReceived(WebSocketContext context, RTCPeerConnection peerConnection, string msg) { if (peerConnection.RemoteDescription != null) { Console.WriteLine($"ICE Candidate: {msg}."); //await _peerConnections[0].addIceCandidate(new RTCIceCandidateInit { candidate = msg }); // await peerConnection.addIceCandidate(new RTCIceCandidateInit { candidate = msg }); Console.WriteLine("add ICE candidate complete."); } else { //Console.WriteLine($"websocket recv: {msg}"); //var offerSDP = SDP.ParseSDPDescription(msg); Console.WriteLine($"offer sdp: {msg}"); var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); await peerConnection.setRemoteDescription(new RTCSessionDescriptionInit { sdp = msg, type = RTCSdpType.offer }); peerConnection.OnReceiveReport += RtpSession_OnReceiveReport; peerConnection.OnSendReport += RtpSession_OnSendReport; peerConnection.onconnectionstatechange += (state) => { if (state == RTCPeerConnectionState.closed) { Console.WriteLine($"webrtc session closed."); //_peerConnections.Remove(peerConnection); } }; peerConnection.oniceconnectionstatechange += (state) => { if (state == RTCIceConnectionState.connected) { Console.WriteLine("Starting DTLS handshake task."); bool dtlsResult = false; Task.Run(async() => dtlsResult = await DoDtlsHandshake(peerConnection, dtls)) .ContinueWith((t) => { Console.WriteLine($"dtls handshake result {dtlsResult}."); if (dtlsResult) { //peerConnection.SetDestination(SDPMediaTypesEnum.audio, peerConnection.IceSession.ConnectedRemoteEndPoint, peerConnection.IceSession.ConnectedRemoteEndPoint); //_peerConnections.Add(peerConnection); peerConnection.OnRtpPacketReceived += RtpSession_OnRtpPacketReceived; } else { dtls.Shutdown(); peerConnection.Close("dtls handshake failed."); } }); } }; var answerInit = await peerConnection.createAnswer(null); await peerConnection.setLocalDescription(answerInit); Console.WriteLine($"answer sdp: {answerInit.sdp}"); context.WebSocket.Send(answerInit.sdp); } }
private static async Task <RTCPeerConnection> SendSDPOffer(WebSocketContext context) { logger.LogDebug($"Web socket client connection from {context.UserEndPoint}."); RTCConfiguration pcConfiguration = new RTCConfiguration { certificates = new List <RTCCertificate> { new RTCCertificate { X_CertificatePath = DTLS_CERTIFICATE_PATH, X_KeyPath = DTLS_KEY_PATH, X_Fingerprint = DTLS_CERTIFICATE_FINGERPRINT } } }; var peerConnection = new RTCPeerConnection(pcConfiguration); var dtls = new DtlsHandshake(DTLS_CERTIFICATE_PATH, DTLS_KEY_PATH); MediaStreamTrack audioTrack = new MediaStreamTrack("0", SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }, MediaStreamStatusEnum.RecvOnly); peerConnection.addTrack(audioTrack); peerConnection.OnReceiveReport += RtpSession_OnReceiveReport; peerConnection.OnSendReport += RtpSession_OnSendReport; peerConnection.OnTimeout += (mediaType) => { peerConnection.Close("remote timeout"); dtls.Shutdown(); }; peerConnection.onconnectionstatechange += (state) => { if (state == RTCPeerConnectionState.closed || state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed) { peerConnection.OnReceiveReport -= RtpSession_OnReceiveReport; peerConnection.OnSendReport -= RtpSession_OnSendReport; } else if (state == RTCPeerConnectionState.connected) { logger.LogDebug("Peer connection connected."); peerConnection.OnRtpPacketReceived += (SDPMediaTypesEnum media, RTPPacket rtpPkt) => logger.LogDebug($"RTP {media} pkt received, SSRC {rtpPkt.Header.SyncSource}."); } }; peerConnection.oniceconnectionstatechange += (state) => { if (state == RTCIceConnectionState.connected) { logger.LogDebug("Starting DTLS handshake task."); bool dtlsResult = false; Task.Run(async() => dtlsResult = await DoDtlsHandshake(peerConnection, dtls)) .ContinueWith((t) => { logger.LogDebug($"dtls handshake result {dtlsResult}."); if (dtlsResult) { var remoteEP = peerConnection.IceSession.ConnectedRemoteEndPoint; peerConnection.SetDestination(SDPMediaTypesEnum.audio, remoteEP, remoteEP); } else { dtls.Shutdown(); peerConnection.Close("dtls handshake failed."); } }); } }; var offerSdp = await peerConnection.createOffer(null); await peerConnection.setLocalDescription(offerSdp); logger.LogDebug($"Sending SDP offer to client {context.UserEndPoint}."); logger.LogDebug(offerSdp.sdp); context.WebSocket.Send(offerSdp.sdp); return(peerConnection); }