コード例 #1
0
ファイル: StatsManager.cs プロジェクト: openpeer/ChatterBox
 public void Reset()
 {
     if (_peerConnection != null)
     {
         _peerConnection.ToggleRTCStats(false);
         _peerConnection = null;
     }
     if (_metricsTimer != null) {
         _metricsTimer.Dispose();
     }
 }
コード例 #2
0
ファイル: StatsManager.cs プロジェクト: openpeer/ChatterBox
 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");
     }
 }
コード例 #3
0
 protected override async void OnOpen()
 {
     base.OnOpen();
     PeerConnection = await WebSocketOpened(this.Context);
 }
コード例 #4
0
 public void PeerConnection(RTCPeerConnection peerConnection, RTCDataChannel dataChannel)
 {
     System.Diagnostics.Debug.WriteLine($"Opened data channel: {dataChannel}");
 }
コード例 #5
0
 public void PeerConnection(RTCPeerConnection peerConnection, RTCICEGatheringState newState)
 {
     System.Diagnostics.Debug.WriteLine($"ICE gathering changed: {newState}");
 }
コード例 #6
0
 public void PeerConnectionRemoved(RTCPeerConnection peerConnection, RTCMediaStream stream)
 {
     System.Diagnostics.Debug.WriteLine("Stream was removed.");
 }
コード例 #7
0
    public void PeerConnection_Construct()
    {
        var peer = new RTCPeerConnection();

        peer.Close();
    }
コード例 #8
0
 void OnAddIceCandidateSuccess(RTCPeerConnection pc)
 {
     Debug.Log($"{GetName(pc)} addIceCandidate success");
 }
コード例 #9
0
ファイル: Program.cs プロジェクト: sdwflmw/sipsorcery
        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);
        }
コード例 #10
0
        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);
        }
コード例 #11
0
        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);
        }
コード例 #12
0
        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;
        }
コード例 #13
0
        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);
        }
コード例 #14
0
    //=======================================


    string GetName(RTCPeerConnection pc)
    {
        return((pc == localConnection) ? "localConnection" : "remoteConnection");
    }
コード例 #15
0
            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;
            }
コード例 #16
0
        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();
        }
コード例 #17
0
 void OnSetRemoteSuccess(RTCPeerConnection pc)
 {
     Debug.Log($"{GetName(pc)} SetRemoteDescription complete");
 }
コード例 #18
0
ファイル: Program.cs プロジェクト: zanzo420/sipsorcery
        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));
        }
コード例 #19
0
 void OnAddIceCandidateError(RTCPeerConnection pc, RTCError error)
 {
     Debug.Log($"{GetName(pc)} failed to add ICE Candidate: ${error}");
 }
コード例 #20
0
 private RTCPeerConnection GetOtherPc(RTCPeerConnection pc)
 {
     return((pc == _pc1) ? _pc2 : _pc1);
 }
コード例 #21
0
 public void PeerConnection(RTCPeerConnection peerConnection, RTCSignalingState stateChanged)
 {
     System.Diagnostics.Debug.WriteLine($"Signaling state changed: {stateChanged}");
 }
コード例 #22
0
        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);
        }
コード例 #23
0
 public void PeerConnectionOnRenegotiationNeeded(RTCPeerConnection peerConnection)
 {
     System.Diagnostics.Debug.WriteLine("WARNING: Renegotiation needed but unimplemented.");
 }
コード例 #24
0
        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));
        }
コード例 #25
0
        public void PeerConnection(RTCPeerConnection peerConnection, RTCICECandidate candidate)
        {
            ARDICECandidateMessage message = new ARDICECandidateMessage(candidate);

            SendSignalingMessage(message).Wait();
        }
コード例 #26
0
 private void OnSetLocalSuccess(RTCPeerConnection pc)
 {
     Debug.Log("SetLocalDescription complete");
 }
コード例 #27
0
        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();
        }
コード例 #28
0
 /// <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}");
 }
コード例 #29
0
        /// <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);
        }
コード例 #30
0
 string GetName(RTCPeerConnection pc)
 {
     return((pc == pc1) ? "pc1" : "pc2");
 }
コード例 #31
0
 RTCPeerConnection GetOtherPc(RTCPeerConnection pc)
 {
     return((pc == pc1) ? pc2 : pc1);
 }
コード例 #32
0
        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();
        }