Exemplo n.º 1
0
        /// <summary>
        /// Initialises the WebRTC session by carrying out the ICE connectivity steps and when complete
        /// handing the RTP socket off for the DTLS handshake. Once the handshake is complete the session
        /// is ready for to exchange encrypted RTP and RTCP packets.
        /// </summary>
        /// <param name="turnServerEndPoint">An optional parameter that can be used include a TURN
        /// server in this session's ICE candidate gathering.</param>
        public async Task Initialise(DoDtlsHandshakeDelegate doDtlsHandshake, IPEndPoint turnServerEndPoint)
        {
            try
            {
                _doDtlsHandshake    = doDtlsHandshake;
                _turnServerEndPoint = turnServerEndPoint;

                DateTime startGatheringTime = DateTime.Now;

                IceConnectionState = IceConnectionStatesEnum.Gathering;

                await GetIceCandidatesAsync();

                logger.LogDebug($"ICE gathering completed for in {DateTime.Now.Subtract(startGatheringTime).TotalMilliseconds:#}ms, candidate count {LocalIceCandidates.Count}.");

                IceConnectionState = IceConnectionStatesEnum.GatheringComplete;

                if (LocalIceCandidates.Count == 0)
                {
                    logger.LogWarning("No local socket candidates were found for WebRTC call closing.");
                    Close("No local ICE candidates available.");
                }
                else
                {
                    string localIceCandidateString = null;

                    foreach (var iceCandidate in LocalIceCandidates)
                    {
                        localIceCandidateString += iceCandidate.ToString();
                    }

                    LocalIceUser     = LocalIceUser ?? Crypto.GetRandomString(20);
                    LocalIcePassword = LocalIcePassword ?? Crypto.GetRandomString(20) + Crypto.GetRandomString(20);
                    //var localIceCandidate = GetIceCandidatesForMediaType(RtpMediaTypesEnum.None).First();

                    var offerHeader = String.Format(_sdpOfferTemplate, Crypto.GetRandomInt(10).ToString());

                    string dtlsAttribute         = String.Format(_dtlsFingerprint, _dtlsCertificateFingerprint);
                    string rtpSecurityDescriptor = RTP_MEDIA_SECURE_DESCRIPTOR;

                    var audioOffer = String.Format(_sdpAudioPcmOfferTemplate,
                                                   _rtpChannel.RTPPort,
                                                   rtpSecurityDescriptor,
                                                   IPAddress.Loopback,
                                                   localIceCandidateString.TrimEnd(),
                                                   LocalIceUser,
                                                   LocalIcePassword,
                                                   dtlsAttribute);

                    var videoOffer = String.Format(_sdpVideoOfferTemplate,
                                                   rtpSecurityDescriptor,
                                                   IPAddress.Loopback,
                                                   LocalIceUser,
                                                   LocalIcePassword,
                                                   dtlsAttribute);

                    string offer = offerHeader + audioOffer + videoOffer;

                    //logger.LogDebug("WebRTC Offer SDP: " + offer);

                    SDP = offer;

                    OnSdpOfferReady?.Invoke(offer);
                }

                // We may have received some remote candidates from the remote part SDP so perform an immediate STUN check.
                // If there are no remote candidates this call will end up being a NOP.
                SendStunConnectivityChecks(null);

                if (_doDtlsHandshake != null)
                {
                    _ = Task.Run(() =>
                    {
                        int result = _doDtlsHandshake(this, _rtpChannel.m_rtpSocket, out _rtpSession.SrtpProtect, out _rtpSession.RtcpSession.SrtcpProtect);
                        IsDtlsNegotiationComplete = (result == 0);
                    });
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception WebRtcPeer.Initialise. " + excp);
                Close(excp.Message);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Initialises the WebRTC session by carrying out the ICE connectivity steps and when complete
        /// handing the RTP socket off for the DTLS handshake. Once the handshake is complete the session
        /// is ready for to exchange encrypted RTP and RTCP packets.
        /// </summary>
        /// <param name="turnServerEndPoint">An optional parameter that can be used include a TURN
        /// server in this session's ICE candidate gathering.</param>
        public async Task Initialise(DoDtlsHandshakeDelegate doDtlsHandshake, IPEndPoint turnServerEndPoint)
        {
            try
            {
                _doDtlsHandshake    = doDtlsHandshake;
                _turnServerEndPoint = turnServerEndPoint;

                DateTime startGatheringTime = DateTime.Now;

                IceConnectionState = IceConnectionStatesEnum.Gathering;

                await GetIceCandidatesAsync();

                logger.LogDebug($"ICE gathering completed for in {DateTime.Now.Subtract(startGatheringTime).TotalMilliseconds:#}ms, candidate count {LocalIceCandidates.Count}.");

                IceConnectionState = IceConnectionStatesEnum.GatheringComplete;

                if (LocalIceCandidates.Count == 0)
                {
                    logger.LogWarning("No local socket candidates were found for WebRTC call closing.");
                    Close("No local ICE candidates available.");
                }
                else
                {
                    bool includeAudioOffer          = _supportedAudioFormats?.Count() > 0;
                    bool includeVideoOffer          = _supportedVideoFormats?.Count() > 0;
                    bool haveIceCandidatesBeenAdded = false;
                    bool isMediaBundle = includeAudioOffer && includeVideoOffer;    // Is this SDP offer bundling audio and video on the same RTP connection.

                    string localIceCandidateString = null;

                    foreach (var iceCandidate in LocalIceCandidates)
                    {
                        localIceCandidateString += iceCandidate.ToString();
                    }

                    LocalIceUser     = LocalIceUser ?? Crypto.GetRandomString(20);
                    LocalIcePassword = LocalIcePassword ?? Crypto.GetRandomString(20) + Crypto.GetRandomString(20);

                    SDP offerSdp = new SDP(IPAddress.Loopback);
                    offerSdp.SessionId = Crypto.GetRandomInt(5).ToString();

                    // Add a bundle attribute. Indicates that audio and video sessions will be multiplexed
                    // on a single RTP socket.
                    if (isMediaBundle)
                    {
                        offerSdp.Group = MEDIA_GROUPING;
                    }

                    if (includeAudioOffer)
                    {
                        SDPMediaAnnouncement audioAnnouncement = new SDPMediaAnnouncement(
                            SDPMediaTypesEnum.audio,
                            _rtpChannel.RTPPort,
                            _supportedAudioFormats);

                        audioAnnouncement.Transport = RTP_MEDIA_PROFILE;
                        if (!haveIceCandidatesBeenAdded)
                        {
                            audioAnnouncement.IceCandidates = LocalIceCandidates;
                            haveIceCandidatesBeenAdded      = true;
                        }

                        audioAnnouncement.Connection      = new SDPConnectionInformation(IPAddress.Any);
                        audioAnnouncement.IceUfrag        = LocalIceUser;
                        audioAnnouncement.IcePwd          = LocalIcePassword;
                        audioAnnouncement.DtlsFingerprint = _dtlsCertificateFingerprint;
                        audioAnnouncement.AddExtra(RTCP_MUX_ATTRIBUTE);
                        audioAnnouncement.AddExtra(SETUP_ATTRIBUTE);
                        audioAnnouncement.MediaStreamStatus = AudioStreamStatus;

                        if (isMediaBundle)
                        {
                            audioAnnouncement.MediaID = AUDIO_MEDIA_ID;
                        }

                        offerSdp.Media.Add(audioAnnouncement);
                    }

                    if (includeVideoOffer)
                    {
                        SDPMediaAnnouncement videoAnnouncement = new SDPMediaAnnouncement(
                            SDPMediaTypesEnum.video,
                            _rtpChannel.RTPPort,
                            _supportedVideoFormats);

                        videoAnnouncement.Transport = RTP_MEDIA_PROFILE;
                        if (!haveIceCandidatesBeenAdded)
                        {
                            videoAnnouncement.IceCandidates = LocalIceCandidates;
                            haveIceCandidatesBeenAdded      = true;
                        }

                        videoAnnouncement.Connection      = new SDPConnectionInformation(IPAddress.Any);
                        videoAnnouncement.IceUfrag        = LocalIceUser;
                        videoAnnouncement.IcePwd          = LocalIcePassword;
                        videoAnnouncement.DtlsFingerprint = _dtlsCertificateFingerprint;
                        videoAnnouncement.AddExtra(RTCP_MUX_ATTRIBUTE);
                        videoAnnouncement.AddExtra(SETUP_ATTRIBUTE);
                        videoAnnouncement.MediaStreamStatus = VideoStreamStatus;

                        if (isMediaBundle)
                        {
                            videoAnnouncement.MediaID = VIDEO_MEDIA_ID;
                        }

                        offerSdp.Media.Add(videoAnnouncement);
                    }

                    SDP = offerSdp;

                    OnSdpOfferReady?.Invoke(SDP);
                }

                // We may have received some remote candidates from the remote part SDP so perform an immediate STUN check.
                // If there are no remote candidates this call will end up being a NOP.
                SendStunConnectivityChecks(null);

                if (_doDtlsHandshake != null)
                {
                    _ = Task.Run(() =>
                    {
                        int result = _doDtlsHandshake(this);
                        IsDtlsNegotiationComplete = (result == 0);
                    });
                }
            }
            catch (Exception excp)
            {
                logger.LogError("Exception WebRtcPeer.Initialise. " + excp);
                Close(excp.Message);
            }
        }