public void Clear() { SendVideoTrack?.Dispose(); SendVideoTrack = null; offerPc?.Close(); offerPc?.Dispose(); offerPc = null; answerPc?.Close(); answerPc?.Dispose(); answerPc = null; SendTexture = null; RecvTexture = null; }
public void CreateDataChannel() { RTCConfiguration config = default; config.iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } }; var peer = new RTCPeerConnection(ref config); var option1 = new RTCDataChannelInit(true); var channel1 = peer.CreateDataChannel("test1", ref option1); Assert.AreEqual("test1", channel1.Label); // It is return -1 when channel is not connected. Assert.AreEqual(channel1.Id, -1); channel1.Close(); peer.Close(); }
private void HangUp() { RemoveTracks(); _pc1.Close(); _pc2.Close(); Debug.Log("Close local/remote peer connection"); _pc1.Dispose(); _pc2.Dispose(); _pc1 = null; _pc2 = null; callButton.interactable = true; hangUpButton.interactable = false; bandwidthSelector.interactable = false; bandwidthSelector.value = 0; sourceImage.color = Color.black; receiveImage.color = Color.black; }
public IEnumerator SetRemoteDescriptionFailed() { var config = GetDefaultConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); var stream = new MediaStream(); var obj = new GameObject("audio"); var source = obj.AddComponent <AudioSource>(); source.clip = AudioClip.Create("test", 480, 2, 48000, false); var track = new AudioStreamTrack(source); var sender = peer1.AddTrack(track, stream); var op1 = peer1.CreateOffer(); yield return(op1); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); // change sdp to cannot parse desc.sdp = desc.sdp.Replace("a=mid:0", "a=mid:10"); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); Assert.True(op3.IsDone); Assert.True(op3.IsError); Assert.IsNotEmpty(op3.Error.message); peer1.RemoveTrack(sender); track.Dispose(); stream.Dispose(); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); Object.DestroyImmediate(source.clip); Object.DestroyImmediate(obj); }
public void Construct() { var peer = new RTCPeerConnection(); Assert.AreEqual(0, peer.GetReceivers().Count()); Assert.AreEqual(0, peer.GetSenders().Count()); Assert.AreEqual(0, peer.GetTransceivers().Count()); Assert.AreEqual(RTCPeerConnectionState.New, peer.ConnectionState); Assert.That(() => peer.LocalDescription, Throws.InvalidOperationException); Assert.That(() => peer.RemoteDescription, Throws.InvalidOperationException); Assert.That(() => peer.PendingLocalDescription, Throws.InvalidOperationException); Assert.That(() => peer.PendingRemoteDescription, Throws.InvalidOperationException); Assert.That(() => peer.CurrentLocalDescription, Throws.InvalidOperationException); Assert.That(() => peer.CurrentRemoteDescription, Throws.InvalidOperationException); peer.Close(); Assert.AreEqual(RTCPeerConnectionState.Closed, peer.ConnectionState); peer.Dispose(); }
private void HangUp() { RemoveTracks(); _pc1.Close(); _pc2.Close(); _pc1.Dispose(); _pc2.Dispose(); _pc1 = null; _pc2 = null; callButton.interactable = true; hangUpButton.interactable = false; codecSelector.interactable = true; codecSelector.value = 0; actualCodecText.text = string.Empty; sourceImage.color = Color.black; receiveImage.color = Color.black; }
public IEnumerator RestartIceInvokeOnNegotiationNeeded() { RTCConfiguration config = default; config.iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } }; var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); }; peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); }; AudioStreamTrack track = new AudioStreamTrack(); peer1.AddTrack(track); yield return(SignalingOffer(peer1, peer2)); bool isInvokeOnNegotiationNeeded1 = false; bool isInvokeOnNegotiationNeeded2 = false; peer1.OnNegotiationNeeded = () => isInvokeOnNegotiationNeeded1 = true; peer2.OnNegotiationNeeded = () => isInvokeOnNegotiationNeeded2 = true; peer1.RestartIce(); var op9 = new WaitUntilWithTimeout(() => isInvokeOnNegotiationNeeded1, 5000); yield return(op9); Assert.That(op9.IsCompleted, Is.True); peer2.RestartIce(); var op10 = new WaitUntilWithTimeout(() => isInvokeOnNegotiationNeeded2, 5000); yield return(op10); Assert.That(op10.IsCompleted, Is.True); track.Dispose(); peer1.Close(); peer2.Close(); }
private void HangUp() { foreach (var image in receiveImages.Concat(sourceImages)) { image.texture = null; DestroyImmediate(image.gameObject); } receiveImages.Clear(); sourceImages.Clear(); foreach (var cam in cameras) { DestroyImmediate(cam.gameObject); } cameras.Clear(); foreach (var track in videoStreamTrackList) { track.Dispose(); } videoStreamTrackList.Clear(); sendingSenderList.Clear(); _pc1.Close(); _pc2.Close(); Debug.Log("Close local/remote peer connection"); _pc1.Dispose(); _pc2.Dispose(); _pc1 = null; _pc2 = null; videoIndex = 0; objectIndex = 0; widthInput.interactable = true; heightInput.interactable = true; callButton.interactable = true; hangUpButton.interactable = false; addVideoObjectButton.interactable = false; addTracksButton.interactable = false; }
public void GetConfiguration() { var config = GetDefaultConfiguration(); var peer = new RTCPeerConnection(ref config); var config2 = peer.GetConfiguration(); Assert.NotNull(config.iceServers); Assert.NotNull(config2.iceServers); Assert.AreEqual(config.iceServers.Length, config2.iceServers.Length); Assert.AreEqual(config.iceServers[0].username, config2.iceServers[0].username); Assert.AreEqual(config.iceServers[0].credential, config2.iceServers[0].credential); Assert.AreEqual(config.iceServers[0].urls, config2.iceServers[0].urls); Assert.AreEqual(config.iceTransportPolicy, config2.iceTransportPolicy); Assert.AreEqual(config.iceCandidatePoolSize, config2.iceCandidatePoolSize); Assert.AreEqual(config.bundlePolicy, config2.bundlePolicy); peer.Close(); peer.Dispose(); }
private void HangUp() { videoStream.Dispose(); receiveStream.Dispose(); videoStream = null; receiveStream = null; _pc1.Close(); _pc2.Close(); Debug.Log("Close local/remote peer connection"); _pc1.Dispose(); _pc2.Dispose(); _pc1 = null; _pc2 = null; receiveImage.texture = null; callButton.interactable = true; hangUpButton.interactable = false; addTracksButton.interactable = false; removeTracksButton.interactable = false; }
private static Task <RTCPeerConnection> CreatePeerConnection() { RTCConfiguration config = new RTCConfiguration { iceServers = new List <RTCIceServer> { new RTCIceServer { urls = STUN_URL } } }; var pc = new RTCPeerConnection(config); var dc = pc.createDataChannel("test", null); dc.onopen += () => logger.LogDebug($"Data channel {dc.label} opened."); dc.onclose += () => logger.LogDebug($"Data channel {dc.label} closed."); dc.onmessage += async(msg) => { logger.LogInformation($"Data channel message received: {msg}."); await dc.sendasync($"echo: {msg}"); }; pc.onconnectionstatechange += (state) => { logger.LogDebug($"Peer connection state change to {state}."); if (state == RTCPeerConnectionState.failed) { pc.Close("ice disconnection"); } }; // Diagnostics. pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}"); pc.OnSendReport += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}"); pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}."); pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}."); return(Task.FromResult(pc)); }
private void DoProcessMessage(Message message) { switch (message.type) { case "Offer": // var offer = JsonUtility.FromJson<RTCSessionDescriptionInit>(message.args); if (RTCSessionDescriptionInit.TryParse(message.args, out RTCSessionDescriptionInit offer)) { Debug.Log($"Got remote SDP, type {offer.type}"); var result = rtcPeerConnection.setRemoteDescription(offer); if (result != SetDescriptionResultEnum.OK) { Debug.Log($"Failed to set remote description, {result}."); rtcPeerConnection.Close("Failed to set remote description"); } else { if (rtcPeerConnection.signalingState == RTCSignalingState.have_remote_offer) { var answerSdp = rtcPeerConnection.createAnswer(); rtcPeerConnection.setLocalDescription(answerSdp); Debug.Log($"Sending SDP answer"); Send("Offer", answerSdp.toJSON()); } } } break; case "IceCandidate": if (RTCIceCandidateInit.TryParse(message.args, out RTCIceCandidateInit candidate)) { Debug.Log($"Got remote Ice Candidate, uri {candidate.candidate}"); rtcPeerConnection.addIceCandidate(candidate); } break; } }
public IEnumerator SetRemoteDescriptionFailed() { var config = GetConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); var stream = new MediaStream(); var track = new AudioStreamTrack("audio"); var sender = peer1.AddTrack(track, stream); RTCOfferOptions options1 = default; var op1 = peer1.CreateOffer(ref options1); yield return(op1); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); // change sdp to cannot parse desc.sdp = desc.sdp.Replace("m=audio", "m=audiable"); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); Assert.True(op3.IsDone); Assert.True(op3.IsError); Assert.IsNotEmpty(op3.Error.message); peer1.RemoveTrack(sender); track.Dispose(); stream.Dispose(); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); }
public void GetConfiguration() { var config = GetDefaultConfiguration(); var peer = new RTCPeerConnection(ref config); var config2 = peer.GetConfiguration(); Assert.That(config.iceServers, Is.Not.Null); Assert.That(config2.iceServers, Is.Not.Null); Assert.That(config.iceServers.Length, Is.EqualTo(config2.iceServers.Length)); Assert.That(config.iceServers[0].username, Is.EqualTo(config2.iceServers[0].username)); Assert.That(config.iceServers[0].credential, Is.EqualTo(config2.iceServers[0].credential)); Assert.That(config.iceServers[0].urls, Is.EqualTo(config2.iceServers[0].urls)); Assert.That(config.iceTransportPolicy, Is.EqualTo(RTCIceTransportPolicy.All)); Assert.That(config.iceTransportPolicy, Is.EqualTo(config2.iceTransportPolicy)); Assert.That(config.enableDtlsSrtp, Is.Null); Assert.That(config.enableDtlsSrtp, Is.EqualTo(config2.enableDtlsSrtp)); Assert.That(config.iceCandidatePoolSize, Is.EqualTo(config2.iceCandidatePoolSize)); Assert.That(config.bundlePolicy, Is.EqualTo(config2.bundlePolicy)); peer.Close(); peer.Dispose(); }
public void CreateDataChannelFailed() { RTCConfiguration config = default; config.iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } }; var peer = new RTCPeerConnection(ref config); // Cannot be set along with "maxRetransmits" and "maxPacketLifeTime" var options = new RTCDataChannelInit { id = 231, maxRetransmits = 1, maxPacketLifeTime = 1, negotiated = false, ordered = false, protocol = "" }; Assert.Throws <ArgumentException>(() => peer.CreateDataChannel("test1", options)); peer.Close(); }
RTCPeerConnection CreatePeerConnection(ISignaling signaling, string connectionId, bool isOffer) { if (m_mapConnectionIdAndPeer.TryGetValue(connectionId, out var peer)) { peer.Close(); } var pc = new RTCPeerConnection(); m_mapConnectionIdAndPeer[connectionId] = pc; pc.OnDataChannel = new DelegateOnDataChannel(channel => { OnDataChannel(pc, channel); }); pc.SetConfiguration(ref m_conf); pc.OnIceCandidate = new DelegateOnIceCandidate(candidate => { signaling.SendCandidate(connectionId, candidate); }); pc.OnIceConnectionChange = new DelegateOnIceConnectionChange(state => { if (state == RTCIceConnectionState.Disconnected) { pc.Close(); m_mapConnectionIdAndPeer.Remove(connectionId); } }); pc.OnTrack = trackEvent => { foreach (var viewer in m_listVideoReceiveViewer) { viewer.AddTrack(connectionId, trackEvent.Track); } }; pc.OnNegotiationNeeded = () => StartCoroutine(OnNegotiationNeeded(signaling, connectionId, isOffer)); return(pc); }
public IEnumerator CreateAnswer() { var config = GetConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); var conf = new RTCDataChannelInit(true); peer1.CreateDataChannel("data", ref conf); RTCOfferOptions options1 = default; RTCAnswerOptions options2 = default; var op1 = peer1.CreateOffer(ref options1); yield return(op1); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); var op4 = peer2.CreateAnswer(ref options2); yield return(op4); Assert.True(op4.IsDone); Assert.False(op4.IsError); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); }
public IEnumerator SetLocalDescriptionFailed() { var peer = new RTCPeerConnection(); var stream = new MediaStream(); var obj = new GameObject("audio"); var source = obj.AddComponent <AudioSource>(); source.clip = AudioClip.Create("test", 480, 2, 48000, false); var track = new AudioStreamTrack(source); var sender = peer.AddTrack(track, stream); var op = peer.CreateOffer(); yield return(op); Assert.True(op.IsDone); Assert.False(op.IsError); var desc = op.Desc; // change sdp to cannot parse desc.sdp = desc.sdp.Replace("a=mid:0", "a=mid:10"); var op2 = peer.SetLocalDescription(ref desc); yield return(op2); Assert.True(op2.IsDone); Assert.True(op2.IsError); Assert.IsNotEmpty(op2.Error.message); Assert.That(peer.RemoveTrack(sender), Is.EqualTo(RTCErrorType.None)); track.Dispose(); stream.Dispose(); peer.Close(); peer.Dispose(); Object.DestroyImmediate(source.clip); Object.DestroyImmediate(obj); }
protected override void OnClose(CloseEventArgs e) { base.OnClose(e); PeerConnection.Close("remote party close"); }
private RTCPeerConnection Createpc() { List <RTCCertificate> presetCertificates = null; if (File.Exists(LOCALHOST_CERTIFICATE_PATH)) { var localhostCert = new X509Certificate2(LOCALHOST_CERTIFICATE_PATH, (string)null, X509KeyStorageFlags.Exportable); presetCertificates = new List <RTCCertificate> { new RTCCertificate { Certificate = localhostCert } }; } RTCConfiguration pcConfiguration = new RTCConfiguration { certificates = presetCertificates, }; var pc = new RTCPeerConnection(pcConfiguration); pc.GetRtpChannel().MdnsResolve = MdnsResolve; //pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isrelay) => logger.LogDebug($"{_peerName}: STUN message received from {ep}, message class {msg.Header.MessageClass}."); var dataChannel = pc.createDataChannel(_dataChannelLabel, null); dataChannel.onDatamessage -= DataChannel_onDatamessage; dataChannel.onDatamessage += DataChannel_onDatamessage; _dataChannels.Add(_dataChannelLabel, dataChannel); pc.onicecandidateerror += (candidate, error) => logger.LogWarning($"{_peerName}: Error adding remote ICE candidate. {error} {candidate}"); pc.oniceconnectionstatechange += (state) => logger.LogDebug($"{_peerName}: ICE connection state change to {state}."); pc.onconnectionstatechange += (state) => { logger.LogDebug($"{_peerName}: Peer connection state changed to {state}."); if (state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed) { pc.Close("remote disconnection"); } }; pc.onicecandidate += (candidate) => { if (pc.signalingState == RTCSignalingState.have_local_offer || pc.signalingState == RTCSignalingState.have_remote_offer) { OnIceCandidateAvailable?.Invoke(new RTCIceCandidateInit() { candidate = candidate.ToString(), sdpMid = candidate.sdpMid, sdpMLineIndex = candidate.sdpMLineIndex }); } }; pc.ondatachannel += (dc) => { dc.onopen += () => logger.LogDebug($"{_peerName}: Data channel now open label {dc.label}, stream ID {dc.id}."); dc.onDatamessage -= DataChannel_onDatamessage; dc.onDatamessage += DataChannel_onDatamessage; logger.LogDebug($"{_peerName}: Data channel created by remote peer, label {dc.label}, stream ID {dc.id}."); _dataChannels.Add(dc.label, dc); }; return(pc); }
private static async Task <RTCPeerConnection> CreatePeerConnection() { RTCConfiguration config = new RTCConfiguration { iceServers = new List <RTCIceServer> { new RTCIceServer { urls = STUN_URL } } }; var pc = new RTCPeerConnection(config); WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(new VpxVideoEncoder(), WEBCAM_NAME); //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(new FFmpegVideoEncoder(), WEBCAM_NAME); //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(WEBCAM_NAME, 1920, 1080, 30); //winVideoEP.RestrictFormats(x => x.Codec == SIPSorceryMedia.Abstractions.V1.VideoCodecsEnum.H264); bool initResult = await winVideoEP.InitialiseVideoSourceDevice(); if (!initResult) { throw new ApplicationException("Could not initialise video capture device."); } var audioSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions { AudioSource = AudioSourcesEnum.Music }); MediaStreamTrack videoTrack = new MediaStreamTrack(winVideoEP.GetVideoSourceFormats(), MediaStreamStatusEnum.SendRecv); pc.addTrack(videoTrack); MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendRecv); pc.addTrack(audioTrack); winVideoEP.OnVideoSourceEncodedSample += pc.SendVideo; audioSource.OnAudioSourceEncodedSample += pc.SendAudio; pc.OnVideoFormatsNegotiated += (videoFormats) => winVideoEP.SetVideoSourceFormat(videoFormats.First()); pc.OnAudioFormatsNegotiated += (audioFormats) => audioSource.SetAudioSourceFormat(audioFormats.First()); pc.onconnectionstatechange += async(state) => { logger.LogDebug($"Peer connection state change to {state}."); if (state == RTCPeerConnectionState.connected) { await audioSource.StartAudio(); await winVideoEP.StartVideo(); } else if (state == RTCPeerConnectionState.failed) { pc.Close("ice disconnection"); } else if (state == RTCPeerConnectionState.closed) { await winVideoEP.CloseVideo(); await audioSource.CloseAudio(); } }; // Diagnostics. pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}"); pc.OnSendReport += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}"); pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}."); pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}."); return(pc); }
public async Task <RTCSessionDescriptionInit> GotOffer(RTCSessionDescriptionInit offer) { _logger.LogDebug($"SDP offer received."); _logger.LogTrace($"Offer SDP:\n{offer.sdp}"); var pc = new RTCPeerConnection(); if (_publicIPv4 != null) { var rtpPort = pc.GetRtpChannel().RTPPort; var publicIPv4Candidate = new RTCIceCandidate(RTCIceProtocol.udp, _publicIPv4, (ushort)rtpPort, RTCIceCandidateType.host); pc.addLocalIceCandidate(publicIPv4Candidate); } if (_publicIPv6 != null) { var rtpPort = pc.GetRtpChannel().RTPPort; var publicIPv6Candidate = new RTCIceCandidate(RTCIceProtocol.udp, _publicIPv6, (ushort)rtpPort, RTCIceCandidateType.host); pc.addLocalIceCandidate(publicIPv6Candidate); } MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> { new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU) }, MediaStreamStatusEnum.SendRecv); pc.addTrack(audioTrack); MediaStreamTrack videoTrack = new MediaStreamTrack(new VideoFormat(VideoCodecsEnum.VP8, VP8_PAYLOAD_ID), MediaStreamStatusEnum.SendRecv); pc.addTrack(videoTrack); pc.OnRtpPacketReceived += (IPEndPoint rep, SDPMediaTypesEnum media, RTPPacket rtpPkt) => { pc.SendRtpRaw(media, rtpPkt.Payload, rtpPkt.Header.Timestamp, rtpPkt.Header.MarkerBit, rtpPkt.Header.PayloadType); //_logger.LogDebug($"RTP {media} pkt received, SSRC {rtpPkt.Header.SyncSource}, SeqNum {rtpPkt.Header.SequenceNumber}."); }; //peerConnection.OnReceiveReport += RtpSession_OnReceiveReport; //peerConnection.OnSendReport += RtpSession_OnSendReport; pc.OnTimeout += (mediaType) => _logger.LogWarning($"Timeout for {mediaType}."); pc.onconnectionstatechange += (state) => { _logger.LogDebug($"Peer connection state changed to {state}."); if (state == RTCPeerConnectionState.failed) { pc.Close("ice failure"); } }; var setResult = pc.setRemoteDescription(offer); if (setResult == SetDescriptionResultEnum.OK) { var offerSdp = pc.createOffer(null); await pc.setLocalDescription(offerSdp); var answer = pc.createAnswer(null); await pc.setLocalDescription(answer); _logger.LogTrace($"Answer SDP:\n{answer.sdp}"); return(answer); } else { return(null); } }
private static RTCPeerConnection CreatePeerConnection() { RTCConfiguration config = new RTCConfiguration { iceServers = new List <RTCIceServer> { new RTCIceServer { urls = STUN_URL } } }; var pc = new RTCPeerConnection(config); var testPatternSource = new VideoTestPatternSource(); WindowsVideoEndPoint windowsVideoEndPoint = new WindowsVideoEndPoint(true); var audioSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions { AudioSource = AudioSourcesEnum.Music }); MediaStreamTrack videoTrack = new MediaStreamTrack(windowsVideoEndPoint.GetVideoSourceFormats(), MediaStreamStatusEnum.SendRecv); pc.addTrack(videoTrack); MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendRecv); pc.addTrack(audioTrack); testPatternSource.OnVideoSourceRawSample += windowsVideoEndPoint.ExternalVideoSourceRawSample; windowsVideoEndPoint.OnVideoSourceEncodedSample += pc.SendVideo; audioSource.OnAudioSourceEncodedSample += pc.SendAudio; pc.OnVideoFormatsNegotiated += (sdpFormat) => windowsVideoEndPoint.SetVideoSourceFormat(SDPMediaFormatInfo.GetVideoCodecForSdpFormat(sdpFormat.First().FormatCodec)); pc.onconnectionstatechange += async(state) => { logger.LogDebug($"Peer connection state change to {state}."); if (state == RTCPeerConnectionState.connected) { await audioSource.StartAudio(); await windowsVideoEndPoint.StartVideo(); await testPatternSource.StartVideo(); } else if (state == RTCPeerConnectionState.failed) { pc.Close("ice disconnection"); } else if (state == RTCPeerConnectionState.closed) { await testPatternSource.CloseVideo(); await windowsVideoEndPoint.CloseVideo(); await audioSource.CloseAudio(); } }; // Diagnostics. pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}"); pc.OnSendReport += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}"); pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}."); pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}."); return(pc); }
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(); }
public IEnumerator IceConnectionStateChange() { RTCConfiguration config = default; config.iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } }; var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(ref candidate); }; peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(ref candidate); }; MediaStream stream = Audio.CaptureStream(); peer1.AddTrack(stream.GetTracks().First()); RTCOfferOptions options1 = default; RTCAnswerOptions options2 = default; var op1 = peer1.CreateOffer(ref options1); yield return(op1); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); var op4 = peer2.CreateAnswer(ref options2); yield return(op4); desc = op4.Desc; var op5 = peer2.SetLocalDescription(ref desc); yield return(op5); var op6 = peer1.SetRemoteDescription(ref desc); yield return(op6); var op7 = new WaitUntilWithTimeout( () => peer1.IceConnectionState == RTCIceConnectionState.Connected || peer1.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op7); Assert.True(op7.IsCompleted); var op8 = new WaitUntilWithTimeout( () => peer2.IceConnectionState == RTCIceConnectionState.Connected || peer2.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op8); Assert.True(op8.IsCompleted); stream.Dispose(); peer1.Close(); peer2.Close(); }
void OnOffer(ISignaling signaling, DescData e) { RTCSessionDescription _desc; _desc.type = RTCSdpType.Offer; _desc.sdp = e.sdp; var connectionId = e.connectionId; if (m_mapConnectionIdAndPeer.ContainsKey(connectionId)) { return; } var pc = new RTCPeerConnection(); m_mapConnectionIdAndPeer.Add(e.connectionId, pc); pc.OnDataChannel = new DelegateOnDataChannel(channel => { OnDataChannel(pc, channel); }); pc.SetConfiguration(ref m_conf); pc.OnIceCandidate = new DelegateOnIceCandidate(candidate => { signaling.SendCandidate(e.connectionId, candidate); }); pc.OnIceConnectionChange = new DelegateOnIceConnectionChange(state => { if (state == RTCIceConnectionState.Disconnected) { pc.Close(); m_mapConnectionIdAndPeer.Remove(e.connectionId); } }); //make video bit rate starts at 16000kbits, and 160000kbits at max. string pattern = @"(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n"; _desc.sdp = Regex.Replace(_desc.sdp, pattern, "$1;x-google-start-bitrate=16000;x-google-max-bitrate=160000\r\n"); pc.SetRemoteDescription(ref _desc); foreach (var track in m_listVideoStreamTrack) { pc.AddTrack(track); } foreach (var track in m_audioStream.GetTracks()) { pc.AddTrack(track); } RTCAnswerOptions options = default; var op = pc.CreateAnswer(ref options); while (op.MoveNext()) { } if (op.IsError) { Debug.LogError($"Network Error: {op.Error}"); return; } var desc = op.Desc; var opLocalDesc = pc.SetLocalDescription(ref desc); while (opLocalDesc.MoveNext()) { } if (opLocalDesc.IsError) { Debug.LogError($"Network Error: {opLocalDesc.Error}"); return; } signaling.SendAnswer(connectionId, desc); }
private static Task <RTCPeerConnection> CreatePeerConnection() { //var videoEP = new SIPSorceryMedia.Windows.WindowsVideoEndPoint(new VpxVideoEncoder()); //videoEP.RestrictFormats(format => format.Codec == VideoCodecsEnum.VP8); var videoEP = new SIPSorceryMedia.Windows.WindowsVideoEndPoint(new FFmpegVideoEncoder()); videoEP.RestrictFormats(format => format.Codec == VideoCodecsEnum.H264); videoEP.OnVideoSinkDecodedSample += (byte[] bmp, uint width, uint height, int stride, VideoPixelFormatsEnum pixelFormat) => { _form.BeginInvoke(new Action(() => { unsafe { if (_picBox.Width != (int)width || _picBox.Height != (int)height) { logger.LogDebug($"Adjusting video display from {_picBox.Width}x{_picBox.Height} to {width}x{height}."); _picBox.Width = (int)width; _picBox.Height = (int)height; } fixed(byte *s = bmp) { Bitmap bmpImage = new Bitmap((int)width, (int)height, (int)(bmp.Length / height), PixelFormat.Format24bppRgb, (IntPtr)s); _picBox.Image = bmpImage; } } })); }; RTCConfiguration config = new RTCConfiguration { //iceServers = new List<RTCIceServer> { new RTCIceServer { urls = STUN_URL } } X_UseRtpFeedbackProfile = true }; var pc = new RTCPeerConnection(config); // Add local receive only tracks. This ensures that the SDP answer includes only the codecs we support. if (!_options.NoAudio) { MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPAudioVideoMediaFormat> { new SDPAudioVideoMediaFormat(SDPWellKnownMediaFormatsEnum.PCMU) }, MediaStreamStatusEnum.RecvOnly); pc.addTrack(audioTrack); } MediaStreamTrack videoTrack = new MediaStreamTrack(videoEP.GetVideoSinkFormats(), MediaStreamStatusEnum.RecvOnly); //MediaStreamTrack videoTrack = new MediaStreamTrack(new VideoFormat(96, "VP8", 90000, "x-google-max-bitrate=5000000"), MediaStreamStatusEnum.RecvOnly); pc.addTrack(videoTrack); pc.OnVideoFrameReceived += videoEP.GotVideoFrame; pc.OnVideoFormatsNegotiated += (formats) => videoEP.SetVideoSinkFormat(formats.First()); pc.onconnectionstatechange += async(state) => { logger.LogDebug($"Peer connection state change to {state}."); if (state == RTCPeerConnectionState.failed) { pc.Close("ice disconnection"); } else if (state == RTCPeerConnectionState.closed) { await videoEP.CloseVideo(); } }; // Diagnostics. //pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}"); pc.OnSendReport += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}"); //pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"RECV STUN {msg.Header.MessageType} (txid: {msg.Header.TransactionId.HexStr()}) from {ep}."); //pc.GetRtpChannel().OnStunMessageSent += (msg, ep, isRelay) => logger.LogDebug($"SEND STUN {msg.Header.MessageType} (txid: {msg.Header.TransactionId.HexStr()}) to {ep}."); pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}."); return(Task.FromResult(pc)); }
private static Task <RTCPeerConnection> CreatePeerConnection(X509Certificate2 cert) { //RTCConfiguration config = new RTCConfiguration //{ // iceServers = new List<RTCIceServer> { new RTCIceServer { urls = STUN_URL } }, // certificates = new List<RTCCertificate> { new RTCCertificate { Certificate = cert } } //}; //var pc = new RTCPeerConnection(config); var pc = new RTCPeerConnection(null); //var testPatternSource = new VideoTestPatternSource(new SIPSorceryMedia.Encoders.VideoEncoder()); var testPatternSource = new VideoTestPatternSource(new FFmpegVideoEncoder()); testPatternSource.SetFrameRate(60); //testPatternSource.SetMaxFrameRate(true); //var videoEndPoint = new SIPSorceryMedia.FFmpeg.FFmpegVideoEndPoint(); //videoEndPoint.RestrictFormats(format => format.Codec == VideoCodecsEnum.H264); //testPatternSource.RestrictFormats(format => format.Codec == VideoCodecsEnum.H264); //var videoEndPoint = new SIPSorceryMedia.Windows.WindowsEncoderEndPoint(); //var videoEndPoint = new SIPSorceryMedia.Encoders.VideoEncoderEndPoint(); MediaStreamTrack track = new MediaStreamTrack(testPatternSource.GetVideoSourceFormats(), MediaStreamStatusEnum.SendOnly); pc.addTrack(track); //testPatternSource.OnVideoSourceRawSample += videoEndPoint.ExternalVideoSourceRawSample; testPatternSource.OnVideoSourceRawSample += MesasureTestPatternSourceFrameRate; testPatternSource.OnVideoSourceEncodedSample += pc.SendVideo; pc.OnVideoFormatsNegotiated += (formats) => testPatternSource.SetVideoSourceFormat(formats.First()); pc.onconnectionstatechange += async(state) => { logger.LogDebug($"Peer connection state change to {state}."); if (state == RTCPeerConnectionState.failed) { pc.Close("ice disconnection"); } else if (state == RTCPeerConnectionState.closed) { await testPatternSource.CloseVideo(); await testPatternSource.CloseVideo(); testPatternSource.Dispose(); } else if (state == RTCPeerConnectionState.connected) { await testPatternSource.StartVideo(); await testPatternSource.StartVideo(); } }; // Diagnostics. //pc.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}"); //pc.OnSendReport += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}"); //pc.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => logger.LogDebug($"STUN {msg.Header.MessageType} received from {ep}."); pc.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}."); pc.onsignalingstatechange += () => { if (pc.signalingState == RTCSignalingState.have_remote_offer) { logger.LogDebug(pc.RemoteDescription.ToString()); } }; return(Task.FromResult(pc)); }
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); }
void OnOffer(ISignaling signaling, DescData e) { RTCSessionDescription _desc; _desc.type = RTCSdpType.Offer; _desc.sdp = e.sdp; var connectionId = e.connectionId; if (m_mapConnectionIdAndPeer.ContainsKey(connectionId)) { return; } var pc = new RTCPeerConnection(); m_mapConnectionIdAndPeer.Add(e.connectionId, pc); pc.OnDataChannel = new DelegateOnDataChannel(channel => { OnDataChannel(pc, channel); }); pc.SetConfiguration(ref m_conf); pc.OnIceCandidate = new DelegateOnIceCandidate(candidate => { signaling.SendCandidate(e.connectionId, candidate); }); pc.OnIceConnectionChange = new DelegateOnIceConnectionChange(state => { if (state == RTCIceConnectionState.Disconnected) { pc.Close(); m_mapConnectionIdAndPeer.Remove(e.connectionId); } }); pc.SetRemoteDescription(ref _desc); foreach (var track in m_listVideoStreamTrack.Concat(m_audioStream.GetTracks())) { RTCRtpSender sender = pc.AddTrack(track); if (!m_mapTrackAndSenderList.TryGetValue(track, out List <RTCRtpSender> list)) { list = new List <RTCRtpSender>(); m_mapTrackAndSenderList.Add(track, list); } list.Add(sender); } RTCAnswerOptions options = default; var op = pc.CreateAnswer(ref options); while (op.MoveNext()) { } if (op.IsError) { Debug.LogError($"Network Error: {op.Error}"); return; } var desc = op.Desc; var opLocalDesc = pc.SetLocalDescription(ref desc); while (opLocalDesc.MoveNext()) { } if (opLocalDesc.IsError) { Debug.LogError($"Network Error: {opLocalDesc.Error}"); return; } signaling.SendAnswer(connectionId, desc); }