public void Reset() { if (_peerConnection != null) { _peerConnection.ToggleRTCStats(false); _peerConnection = null; } if (_metricsTimer != null) { _metricsTimer.Dispose(); } }
public void Initialize(RTCPeerConnection pc) { if (pc != null) { _peerConnection = pc; _peerConnection.OnRTCStatsReportsReady += PeerConnection_OnRTCStatsReportsReady; } else { Debug.WriteLine("StatsManager: Cannot initialize peer connection by null pointer"); } }
protected override async void OnOpen() { base.OnOpen(); PeerConnection = await WebSocketOpened(this.Context); }
public void PeerConnection(RTCPeerConnection peerConnection, RTCDataChannel dataChannel) { System.Diagnostics.Debug.WriteLine($"Opened data channel: {dataChannel}"); }
public void PeerConnection(RTCPeerConnection peerConnection, RTCICEGatheringState newState) { System.Diagnostics.Debug.WriteLine($"ICE gathering changed: {newState}"); }
public void PeerConnectionRemoved(RTCPeerConnection peerConnection, RTCMediaStream stream) { System.Diagnostics.Debug.WriteLine("Stream was removed."); }
public void PeerConnection_Construct() { var peer = new RTCPeerConnection(); peer.Close(); }
void OnAddIceCandidateSuccess(RTCPeerConnection pc) { Debug.Log($"{GetName(pc)} addIceCandidate success"); }
private static RTCPeerConnection WebSocketOpened(WebSocketContext context) { WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(); winVideoEP.OnVideoSinkDecodedSample += (byte[] bmp, uint width, uint height, int stride, VideoPixelFormatsEnum pixelFormat) => { _form.BeginInvoke(new Action(() => { unsafe { fixed(byte *s = bmp) { System.Drawing.Bitmap bmpImage = new System.Drawing.Bitmap((int)width, (int)height, (int)(bmp.Length / height), System.Drawing.Imaging.PixelFormat.Format24bppRgb, (IntPtr)s); _picBox.Image = bmpImage; } } })); }; var peerConnection = new RTCPeerConnection(null); // Add local recvonly tracks. This ensures that the SDP answer includes only // the codecs we support. MediaStreamTrack audioTrack = new MediaStreamTrack(SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }, MediaStreamStatusEnum.RecvOnly); peerConnection.addTrack(audioTrack); MediaStreamTrack videoTrack = new MediaStreamTrack(winVideoEP.GetVideoSinkFormats(), MediaStreamStatusEnum.RecvOnly); peerConnection.addTrack(videoTrack); peerConnection.OnReceiveReport += RtpSession_OnReceiveReport; peerConnection.OnSendReport += RtpSession_OnSendReport; peerConnection.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => { bool hasUseCandidate = msg.Attributes.Any(x => x.AttributeType == STUNAttributeTypesEnum.UseCandidate); Console.WriteLine($"STUN {msg.Header.MessageType} received from {ep}, use candidate {hasUseCandidate}."); }; peerConnection.oniceconnectionstatechange += (state) => Console.WriteLine($"ICE connection state changed to {state}."); peerConnection.onconnectionstatechange += async(state) => { Console.WriteLine($"Peer connection state changed to {state}."); if (state == RTCPeerConnectionState.closed) { await winVideoEP.CloseVideo(); } }; //peerConnection.OnRtpPacketReceived += (IPEndPoint rep, SDPMediaTypesEnum media, RTPPacket rtpPkt) => //{ // //logger.LogDebug($"RTP {media} pkt received, SSRC {rtpPkt.Header.SyncSource}."); // if (media == SDPMediaTypesEnum.video) // { // winVideoEP.GotVideoRtp(rep, rtpPkt.Header.SyncSource, rtpPkt.Header.SequenceNumber, rtpPkt.Header.Timestamp, rtpPkt.Header.PayloadType, rtpPkt.Header.MarkerBit == 1, rtpPkt.Payload); // } //}; peerConnection.OnVideoFrameReceived += winVideoEP.GotVideoFrame; return(peerConnection); }
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(WEBCAM_NAME); bool initResult = await winVideoEP.InitialiseVideoSourceDevice(); if (!initResult) { throw new ApplicationException("Could not initialise video capture device."); } //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(false, 640, 480, 30); //WindowsVideoEndPoint winVideoEP = new WindowsVideoEndPoint(false, 1920, 1080, 30); //await winVideoEP.InitialiseVideoSourceDevice(); 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); }
private static RTCPeerConnection CreatePeerConnection(WebSocketContext context) { 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); // Add inactive audio and video tracks. MediaStreamTrack audioTrack = new MediaStreamTrack("0", SDPMediaTypesEnum.audio, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }, MediaStreamStatusEnum.Inactive); peerConnection.addTrack(audioTrack); MediaStreamTrack videoTrack = new MediaStreamTrack("1", SDPMediaTypesEnum.video, false, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.VP8) }, MediaStreamStatusEnum.Inactive); peerConnection.addTrack(videoTrack); peerConnection.onicecandidate += (candidate) => { logger.LogDebug($"ICE candidate discovered: {candidate}."); // Host candidates are included in the SDP we send. if (candidate.type != RTCIceCandidateType.host) { context.WebSocket.Send($"candidate:{candidate}"); } }; peerConnection.onconnectionstatechange += (state) => { logger.LogDebug($"Peer connection state change to {state}."); }; peerConnection.oniceconnectionstatechange += (state) => { logger.LogDebug($"ICE connection state change to {state}."); if (state == RTCIceConnectionState.connected) { var remoteEndPoint = peerConnection.IceSession.NominatedCandidate.DestinationEndPoint; logger.LogInformation($"ICE connected to remote end point {remoteEndPoint}."); } }; peerConnection.IceSession.StartGathering(); return(peerConnection); }
private void Call() { Debug.Log("Starting calls"); pc1Local = new RTCPeerConnection(ref configuration); pc1Remote = new RTCPeerConnection(ref configuration); pc1Remote.OnTrack = e => { if (e.Track is VideoStreamTrack videoTrack) { videoTrack.OnVideoReceived += tex => { receiveImage1.texture = tex; }; } if (e.Track is AudioStreamTrack audioTrack) { receiveAudio1.SetTrack(audioTrack); receiveAudio1.loop = true; receiveAudio1.Play(); } }; pc1Local.OnIceCandidate = candidate => pc1Remote.AddIceCandidate(candidate); pc1Remote.OnIceCandidate = candidate => pc1Local.AddIceCandidate(candidate); Debug.Log("pc1: created local and remote peer connection object"); pc2Local = new RTCPeerConnection(ref configuration); pc2Remote = new RTCPeerConnection(ref configuration); pc2Remote.OnTrack = e => { if (e.Track is VideoStreamTrack videoTrack) { videoTrack.OnVideoReceived += tex => { receiveImage2.texture = tex; }; } if (e.Track is AudioStreamTrack audioTrack) { receiveAudio2.SetTrack(audioTrack); receiveAudio2.loop = true; receiveAudio2.Play(); } }; pc2Local.OnIceCandidate = candidate => pc2Remote.AddIceCandidate(candidate); pc2Remote.OnIceCandidate = candidate => pc2Local.AddIceCandidate(candidate); Debug.Log("pc2: created local and remote peer connection object"); foreach (var track in sourceStream.GetTracks()) { pc1Local.AddTrack(track, sourceStream); pc2Local.AddTrack(track, sourceStream); } Debug.Log("Adding local stream to pc1Local/pc2Local"); StartCoroutine(NegotiationPeer(pc1Local, pc1Remote)); StartCoroutine(NegotiationPeer(pc2Local, pc2Remote)); callButton.interactable = false; hangUpButton.interactable = true; }
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(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 = peerConnection.createOffer(null); await peerConnection.setLocalDescription(offerSdp); _peerConnections.TryAdd(id, peerConnection); return(offerSdp); }
//======================================= string GetName(RTCPeerConnection pc) { return((pc == localConnection) ? "localConnection" : "remoteConnection"); }
IEnumerator Start() { RTCConfiguration config = default; config.iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } }; pc1Senders = new List <RTCRtpSender>(); pc2Senders = new List <RTCRtpSender>(); peer1 = new RTCPeerConnection(ref config); peer2 = new RTCPeerConnection(ref config); peer1.OnIceCandidate = candidate => { Assert.NotNull(candidate); Assert.NotNull(candidate.candidate); peer2.AddIceCandidate(ref candidate); }; peer2.OnIceCandidate = candidate => { Assert.NotNull(candidate); Assert.NotNull(candidate.candidate); peer1.AddIceCandidate(ref candidate); }; peer2.OnTrack = e => { Assert.NotNull(e); Assert.NotNull(e.Track); Assert.NotNull(e.Receiver); Assert.NotNull(e.Transceiver); pc2Senders.Add(peer2.AddTrack(e.Track, m_stream)); }; foreach (var track in m_stream.GetTracks()) { pc1Senders.Add(peer1.AddTrack(track, m_stream)); } 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(op7.IsCompleted); var op9 = new WaitUntilWithTimeout(() => pc2Senders.Count > 0, 5000); yield return(op9); Assert.True(op9.IsCompleted); m_isFinished = true; }
public IEnumerator PeerConnectionStateChange() { 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); RTCPeerConnectionState state1 = default; RTCPeerConnectionState state2 = default; RTCIceConnectionState iceState1 = default; RTCIceConnectionState iceState2 = default; peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(candidate); }; peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); }; peer1.OnConnectionStateChange = state => { state1 = state; }; peer2.OnConnectionStateChange = state => { state2 = state; }; peer1.OnIceConnectionChange = state => { iceState1 = state; }; peer2.OnIceConnectionChange = state => { iceState2 = state; }; Assert.That(state1, Is.EqualTo(RTCPeerConnectionState.New)); Assert.That(state2, Is.EqualTo(RTCPeerConnectionState.New)); AudioStreamTrack track1 = new AudioStreamTrack(); peer1.AddTrack(track1); var op1 = peer1.CreateOffer(); 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(); 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(() => state1 == RTCPeerConnectionState.Connected && state2 == RTCPeerConnectionState.Connected, 5000); yield return(op7); Assert.That(op7.IsCompleted, Is.True); var op8 = new WaitUntilWithTimeout(() => (iceState1 == RTCIceConnectionState.Connected || iceState1 == RTCIceConnectionState.Completed) && (iceState2 == RTCIceConnectionState.Connected || iceState2 == RTCIceConnectionState.Completed) , 5000); yield return(op8); Assert.That(op8.IsCompleted, Is.True); peer1.Close(); var op9 = new WaitUntilWithTimeout(() => state1 == RTCPeerConnectionState.Closed && iceState2 == RTCIceConnectionState.Disconnected, 5000); yield return(op9); Assert.That(op9.IsCompleted, Is.True); track1.Dispose(); peer2.Close(); }
void OnSetRemoteSuccess(RTCPeerConnection pc) { Debug.Log($"{GetName(pc)} SetRemoteDescription complete"); }
private static Task <RTCPeerConnection> CreatePeerConnection() { var peerConnection = new RTCPeerConnection(); //FileStream captureStream = new FileStream("capture.stm", FileMode.Create, FileAccess.ReadWrite); var videoEP = new Vp8NetVideoEncoderEndPoint(); videoEP.OnVideoSinkDecodedSample += (byte[] bmp, uint width, uint height, int stride, VideoPixelFormatsEnum pixelFormat) => { if (_isFormActivated) { _form?.BeginInvoke(new Action(() => { unsafe { fixed(byte *s = bmp) { Bitmap bmpImage = new Bitmap((int)width, (int)height, (int)(bmp.Length / height), PixelFormat.Format24bppRgb, (IntPtr)s); _picBox.Image = bmpImage; } } })); } }; // Sink (speaker) only audio end point. //WindowsAudioEndPoint windowsAudioEP = new WindowsAudioEndPoint(new AudioEncoder(), -1, -1, true, false); //MediaStreamTrack audioTrack = new MediaStreamTrack(windowsAudioEP.GetAudioSinkFormats(), MediaStreamStatusEnum.RecvOnly); //peerConnection.addTrack(audioTrack); MediaStreamTrack videoTrack = new MediaStreamTrack(videoEP.GetVideoSinkFormats(), MediaStreamStatusEnum.RecvOnly); peerConnection.addTrack(videoTrack); peerConnection.OnVideoFrameReceived += (rep, ts, frame, pixelFmt) => { Console.WriteLine($"Video frame received {frame.Length} bytes."); //Console.WriteLine(frame.HexStr()); //captureStream.Write(Encoding.ASCII.GetBytes($"{frame.Length},")); //captureStream.Write(frame); //captureStream.Flush(); videoEP.GotVideoFrame(rep, ts, frame, pixelFmt); }; peerConnection.OnVideoFormatsNegotiated += (formats) => videoEP.SetVideoSinkFormat(formats.First()); //peerConnection.OnAudioFormatsNegotiated += (formats) => // windowsAudioEP.SetAudioSinkFormat(formats.First()); peerConnection.OnTimeout += (mediaType) => logger.LogDebug($"Timeout on media {mediaType}."); peerConnection.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state changed to {state}."); peerConnection.onconnectionstatechange += (state) => { logger.LogDebug($"Peer connection connected changed to {state}."); if (state == RTCPeerConnectionState.closed || state == RTCPeerConnectionState.failed || state == RTCPeerConnectionState.disconnected) { //captureStream.Close(); } }; peerConnection.GetRtpChannel().OnStunMessageReceived += (msg, ep, isRelay) => { bool hasUseCandidate = msg.Attributes.Any(x => x.AttributeType == STUNAttributeTypesEnum.UseCandidate); Console.WriteLine($"STUN {msg.Header.MessageType} received from {ep}, use candidate {hasUseCandidate}."); }; peerConnection.OnRtpPacketReceived += (IPEndPoint rep, SDPMediaTypesEnum media, RTPPacket rtpPkt) => { //logger.LogDebug($"RTP {media} pkt received, SSRC {rtpPkt.Header.SyncSource}."); //if (media == SDPMediaTypesEnum.audio) //{ // windowsAudioEP.GotAudioRtp(rep, rtpPkt.Header.SyncSource, rtpPkt.Header.SequenceNumber, rtpPkt.Header.Timestamp, rtpPkt.Header.PayloadType, rtpPkt.Header.MarkerBit == 1, rtpPkt.Payload); //} }; return(Task.FromResult(peerConnection)); }
void OnAddIceCandidateError(RTCPeerConnection pc, RTCError error) { Debug.Log($"{GetName(pc)} failed to add ICE Candidate: ${error}"); }
private RTCPeerConnection GetOtherPc(RTCPeerConnection pc) { return((pc == _pc1) ? _pc2 : _pc1); }
public void PeerConnection(RTCPeerConnection peerConnection, RTCSignalingState stateChanged) { System.Diagnostics.Debug.WriteLine($"Signaling state changed: {stateChanged}"); }
private async static Task <RTCPeerConnection> CreatePeerConnection() { RTCConfiguration config = new RTCConfiguration { iceServers = new List <RTCIceServer> { new RTCIceServer { urls = STUN_URL } } }; var pc = new RTCPeerConnection(config); pc.ondatachannel += (rdc) => { rdc.onopen += () => logger.LogDebug($"Data channel {rdc.label} opened."); rdc.onclose += () => logger.LogDebug($"Data channel {rdc.label} closed."); rdc.onmessage += (datachan, type, data) => { switch (type) { case DataChannelPayloadProtocols.WebRTC_Binary_Empty: case DataChannelPayloadProtocols.WebRTC_String_Empty: logger.LogInformation($"Data channel {datachan.label} empty message type {type}."); break; case DataChannelPayloadProtocols.WebRTC_Binary: string jsSha256 = DoJavscriptSHA256(data); logger.LogInformation($"Data channel {datachan.label} received {data.Length} bytes, js mirror sha256 {jsSha256}."); rdc.send(jsSha256); if (_loadTestCount > 0) { DoLoadTestIteration(rdc, _loadTestPayloadSize); _loadTestCount--; } break; case DataChannelPayloadProtocols.WebRTC_String: var msg = Encoding.UTF8.GetString(data); logger.LogInformation($"Data channel {datachan.label} message {type} received: {msg}."); var loadTestMatch = Regex.Match(msg, @"^\s*(?<sendSize>\d+)\s*x\s*(?<testCount>\d+)"); if (loadTestMatch.Success) { uint sendSize = uint.Parse(loadTestMatch.Result("${sendSize}")); _loadTestCount = int.Parse(loadTestMatch.Result("${testCount}")); _loadTestCount = (_loadTestCount <= 0 || _loadTestCount > MAX_LOADTEST_COUNT) ? MAX_LOADTEST_COUNT : _loadTestCount; _loadTestPayloadSize = (sendSize > pc.sctp.maxMessageSize) ? pc.sctp.maxMessageSize : sendSize; logger.LogInformation($"Starting data channel binary load test, payload size {sendSize}, test count {_loadTestCount}."); DoLoadTestIteration(rdc, _loadTestPayloadSize); _loadTestCount--; } else { // Do a string echo. rdc.send($"echo: {msg}"); } break; } }; }; var dc = await pc.createDataChannel("test", null); 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}."); pc.onsignalingstatechange += () => logger.LogDebug($"Signalling state changed to {pc.signalingState}."); return(pc); }
public void PeerConnectionOnRenegotiationNeeded(RTCPeerConnection peerConnection) { System.Diagnostics.Debug.WriteLine("WARNING: Renegotiation needed but unimplemented."); }
private static Task <RTCPeerConnection> Createpc(WebSocketContext context, RTCIceServer stunServer, bool relayOnly) { if (_peerConnection != null) { _peerConnection.Close("normal"); } 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, //X_RemoteSignallingAddress = (context != null) ? context.UserEndPoint.Address : null, iceServers = stunServer != null ? new List <RTCIceServer> { stunServer } : null, iceTransportPolicy = relayOnly ? RTCIceTransportPolicy.relay : RTCIceTransportPolicy.all, //X_BindAddress = IPAddress.Any, // NOTE: Not reqd. Using this to filter out IPv6 addresses so can test with Pion. }; _peerConnection = new RTCPeerConnection(pcConfiguration); //_peerConnection.GetRtpChannel().MdnsResolve = (hostname) => Task.FromResult(NetServices.InternetDefaultAddress); _peerConnection.GetRtpChannel().MdnsResolve = MdnsResolve; //_peerConnection.GetRtpChannel().OnStunMessageReceived += (msg, ep, isrelay) => logger.LogDebug($"STUN message received from {ep}, message type {msg.Header.MessageType}."); //var dc = _peerConnection.createDataChannel(DATA_CHANNEL_LABEL, null); //dc.onmessage += (msg) => logger.LogDebug($"data channel receive ({dc.label}-{dc.id}): {msg}"); // Add a send-only audio track (this doesn't require any native libraries for encoding so is good for x-platform testing). AudioExtrasSource audioSource = new AudioExtrasSource(new AudioEncoder(), new AudioSourceOptions { AudioSource = AudioSourcesEnum.Music }); audioSource.OnAudioSourceEncodedSample += _peerConnection.SendAudio; MediaStreamTrack audioTrack = new MediaStreamTrack(audioSource.GetAudioSourceFormats(), MediaStreamStatusEnum.SendOnly); _peerConnection.addTrack(audioTrack); _peerConnection.OnAudioFormatsNegotiated += (formats) => audioSource.SetAudioSourceFormat(formats.First()); _peerConnection.onicecandidateerror += (candidate, error) => logger.LogWarning($"Error adding remote ICE candidate. {error} {candidate}"); _peerConnection.onconnectionstatechange += async(state) => { logger.LogDebug($"Peer connection state changed to {state}."); if (state == RTCPeerConnectionState.disconnected || state == RTCPeerConnectionState.failed) { _peerConnection.Close("remote disconnection"); } if (state == RTCPeerConnectionState.connected) { await audioSource.StartAudio(); } else if (state == RTCPeerConnectionState.closed) { await audioSource.CloseAudio(); } }; _peerConnection.OnReceiveReport += (re, media, rr) => logger.LogDebug($"RTCP Receive for {media} from {re}\n{rr.GetDebugSummary()}"); _peerConnection.OnSendReport += (media, sr) => logger.LogDebug($"RTCP Send for {media}\n{sr.GetDebugSummary()}"); _peerConnection.OnRtcpBye += (reason) => logger.LogDebug($"RTCP BYE receive, reason: {(string.IsNullOrWhiteSpace(reason) ? "<none>" : reason)}."); // Peer ICE connection state changes are for ICE events such as the STUN checks completing. _peerConnection.oniceconnectionstatechange += (state) => logger.LogDebug($"ICE connection state change to {state}."); _peerConnection.ondatachannel += (dc) => { logger.LogDebug($"Data channel opened by remote peer, label {dc.label}, stream ID {dc.id}."); dc.onmessage += (msg) => { logger.LogDebug($"data channel ({dc.label}:{dc.id}): {msg}."); }; }; return(Task.FromResult(_peerConnection)); }
public void PeerConnection(RTCPeerConnection peerConnection, RTCICECandidate candidate) { ARDICECandidateMessage message = new ARDICECandidateMessage(candidate); SendSignalingMessage(message).Wait(); }
private void OnSetLocalSuccess(RTCPeerConnection pc) { Debug.Log("SetLocalDescription complete"); }
public IEnumerator EventsAreSentToOther() { 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); RTCDataChannel channel2 = null; peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(ref candidate); }; peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(ref candidate); }; peer2.OnDataChannel = channel => { channel2 = channel; }; var conf = new RTCDataChannelInit(true); var channel1 = peer1.CreateDataChannel("data", ref conf); bool channel1Opened = false; bool channel1Closed = false; channel1.OnOpen = () => { channel1Opened = true; }; channel1.OnClose = () => { channel1Closed = true; }; 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); var op9 = new WaitUntilWithTimeout(() => channel2 != null, 5000); yield return(op9); Assert.True(op9.IsCompleted); Assert.True(channel1Opened); Assert.AreEqual(channel1.Label, channel2.Label); Assert.AreEqual(channel1.Id, channel2.Id); const string message1 = "hello"; string message2 = null; channel2.OnMessage = bytes => { message2 = System.Text.Encoding.UTF8.GetString(bytes); }; channel1.Send(message1); var op10 = new WaitUntilWithTimeout(() => !string.IsNullOrEmpty(message2), 5000); yield return(op10); Assert.True(op10.IsCompleted); Assert.AreEqual(message1, message2); byte[] message3 = { 1, 2, 3 }; byte[] message4 = null; channel2.OnMessage = bytes => { message4 = bytes; }; channel1.Send(message3); var op11 = new WaitUntilWithTimeout(() => message4 != null, 5000); yield return(op11); Assert.True(op11.IsCompleted); Assert.AreEqual(message3, message4); channel1.Close(); var op12 = new WaitUntilWithTimeout(() => channel1Closed, 5000); yield return(op12); Assert.True(op12.IsCompleted); channel2.Close(); peer1.Close(); peer2.Close(); }
/// <summary> /// /// </summary> /// <param name="pc"></param> /// <param name="streamEvent"></param> void OnIceCandidate(RTCPeerConnection pc, RTCIceCandidate candidate) { GetOtherPc(pc).AddIceCandidate(candidate); Debug.Log($"{GetName(pc)} ICE candidate:\n {candidate.Candidate}"); }
/// <summary> /// Creates a peer connection. /// </summary> /// <returns>True if connection to a peer is successfully created.</returns> private async Task <bool> CreatePeerConnection(CancellationToken cancelationToken) { Debug.Assert(_peerConnection == null); if (cancelationToken.IsCancellationRequested) { return(false); } var config = new RTCConfiguration() { BundlePolicy = RTCBundlePolicy.Balanced, #if ORTCLIB SignalingMode = _signalingMode, GatherOptions = new RTCIceGatherOptions() { IceServers = new List <RTCIceServer>(_iceServers), } #else IceTransportPolicy = RTCIceTransportPolicy.All, IceServers = _iceServers #endif }; Debug.WriteLine("Conductor: Creating peer connection."); _peerConnection = new RTCPeerConnection(config); if (_peerConnection == null) { throw new NullReferenceException("Peer connection is not created."); } #if !ORTCLIB _peerConnection.EtwStatsEnabled = _etwStatsEnabled; _peerConnection.ConnectionHealthStatsEnabled = _peerConnectionStatsEnabled; #endif if (cancelationToken.IsCancellationRequested) { return(false); } #if ORTCLIB OrtcStatsManager.Instance.Initialize(_peerConnection); #endif OnPeerConnectionCreated?.Invoke(); _peerConnection.OnIceCandidate += PeerConnection_OnIceCandidate; #if ORTCLIB _peerConnection.OnTrack += PeerConnection_OnAddTrack; _peerConnection.OnTrackGone += PeerConnection_OnRemoveTrack; _peerConnection.OnIceConnectionStateChange += () => { Debug.WriteLine("Conductor: Ice connection state change, state=" + (null != _peerConnection ? _peerConnection.IceConnectionState.ToString() : "closed")); }; #else _peerConnection.OnAddStream += PeerConnection_OnAddStream; _peerConnection.OnRemoveStream += PeerConnection_OnRemoveStream; _peerConnection.OnConnectionHealthStats += PeerConnection_OnConnectionHealthStats; #endif // Setup Data Channel _peerSendDataChannel = _peerConnection.CreateDataChannel( "SendDataChannel", new RTCDataChannelInit() { Ordered = true }); _peerSendDataChannel.OnOpen += PeerSendDataChannelOnOpen; _peerSendDataChannel.OnClose += PeerSendDataChannelOnClose; _peerSendDataChannel.OnError += _peerSendDataChannel_OnError; _peerConnection.OnDataChannel += _peerConnection_OnDataChannel; // DataChannel Setup Completed Debug.WriteLine("Conductor: Getting user media."); RTCMediaStreamConstraints mediaStreamConstraints = new RTCMediaStreamConstraints { // Always include audio/video enabled in the media stream, // so it will be possible to enable/disable audio/video if // the call was initiated without microphone/camera audioEnabled = true, videoEnabled = true }; if (cancelationToken.IsCancellationRequested) { return(false); } #if ORTCLIB var tracks = await _media.GetUserMedia(mediaStreamConstraints); if (tracks != null) { RTCRtpCapabilities audioCapabilities = RTCRtpSender.GetCapabilities("audio"); RTCRtpCapabilities videoCapabilities = RTCRtpSender.GetCapabilities("video"); _mediaStream = new MediaStream(tracks); Debug.WriteLine("Conductor: Adding local media stream."); IList <MediaStream> mediaStreamList = new List <MediaStream>(); mediaStreamList.Add(_mediaStream); foreach (var mediaStreamTrack in tracks) { //Create stream track configuration based on capabilities RTCMediaStreamTrackConfiguration configuration = null; if (mediaStreamTrack.Kind == MediaStreamTrackKind.Audio && audioCapabilities != null) { configuration = await Helper.GetTrackConfigurationForCapabilities(audioCapabilities, AudioCodec); } else if (mediaStreamTrack.Kind == MediaStreamTrackKind.Video && videoCapabilities != null) { configuration = await Helper.GetTrackConfigurationForCapabilities(videoCapabilities, VideoCodec); } if (configuration != null) { _peerConnection.AddTrack(mediaStreamTrack, mediaStreamList, configuration); } } } #else _mediaStream = await _media.GetUserMedia(mediaStreamConstraints); #endif if (cancelationToken.IsCancellationRequested) { return(false); } #if !ORTCLIB Debug.WriteLine("Conductor: Adding local media stream."); _peerConnection.AddStream(_mediaStream); #endif OnAddLocalStream?.Invoke(new MediaStreamEvent() { Stream = _mediaStream }); if (cancelationToken.IsCancellationRequested) { return(false); } return(true); }
string GetName(RTCPeerConnection pc) { return((pc == pc1) ? "pc1" : "pc2"); }
RTCPeerConnection GetOtherPc(RTCPeerConnection pc) { return((pc == pc1) ? pc2 : pc1); }
public IEnumerator AddIceCandidate() { 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); var peer1ReceiveCandidateQueue = new Queue <RTCIceCandidate>(); var peer2ReceiveCandidateQueue = new Queue <RTCIceCandidate>(); peer1.OnIceCandidate = candidate => { peer2ReceiveCandidateQueue.Enqueue(candidate); }; peer2.OnIceCandidate = candidate => { peer1ReceiveCandidateQueue.Enqueue(candidate); }; var track = new AudioStreamTrack(); peer1.AddTrack(track); var op1 = peer1.CreateOffer(); yield return(op1); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); yield return(new WaitUntil(() => peer2ReceiveCandidateQueue.Any())); Assert.That(peer2.AddIceCandidate(peer2ReceiveCandidateQueue.Peek()), Is.False); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); Assert.That(peer2.AddIceCandidate(peer2ReceiveCandidateQueue.Dequeue()), Is.True); var op4 = peer2.CreateAnswer(); yield return(op4); desc = op4.Desc; var op5 = peer2.SetLocalDescription(ref desc); yield return(op5); yield return(new WaitUntil(() => peer1ReceiveCandidateQueue.Any())); Assert.That(peer1.AddIceCandidate(peer1ReceiveCandidateQueue.Peek()), Is.False); var op6 = peer1.SetRemoteDescription(ref desc); yield return(op6); Assert.That(peer1.AddIceCandidate(peer1ReceiveCandidateQueue.Dequeue()), Is.True); var op7 = new WaitUntilWithTimeout( () => peer1.IceConnectionState == RTCIceConnectionState.Connected || peer1.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op7); Assert.That(op7.IsCompleted, Is.True); var op8 = new WaitUntilWithTimeout( () => peer2.IceConnectionState == RTCIceConnectionState.Connected || peer2.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op8); Assert.That(op8.IsCompleted, Is.True); foreach (var candidate in peer1ReceiveCandidateQueue) { Assert.That(peer1.AddIceCandidate(candidate), Is.True); } peer1ReceiveCandidateQueue.Clear(); foreach (var candidate in peer2ReceiveCandidateQueue) { Assert.That(peer2.AddIceCandidate(candidate), Is.True); } peer2ReceiveCandidateQueue.Clear(); track.Dispose(); peer1.Close(); peer2.Close(); }