Example #1
0
        /// <summary>
        /// Constructor to create a new RTC peer connection instance.
        /// </summary>
        /// <param name="configuration">Optional.</param>
        public RTCPeerConnection(RTCConfiguration configuration) :
            base(true, true, true, configuration?.X_BindAddress)
        {
            if (_configuration != null &&
                _configuration.iceTransportPolicy == RTCIceTransportPolicy.relay &&
                _configuration.iceServers?.Count == 0)
            {
                throw new ApplicationException("RTCPeerConnection must have at least one ICE server specified for a relay only transport policy.");
            }

            _configuration = configuration;
            if (_configuration != null)
            {
                if (_configuration.certificates?.Count > 0)
                {
                    _currentCertificate = _configuration.certificates.First();
                }

                if (_configuration.X_UseRtpFeedbackProfile)
                {
                    RTP_MEDIA_PROFILE = RTP_MEDIA_FEEDBACK_PROFILE;
                }
            }

            SessionID         = Guid.NewGuid().ToString();
            LocalSdpSessionID = Crypto.GetRandomInt(5).ToString();

            // Request the underlying RTP session to create a single RTP channel that will
            // be used to multiplex all required media streams.
            addSingleTrack();

            _rtpIceChannel = GetRtpChannel(SDPMediaTypesEnum.audio) as RtpIceChannel;

            _rtpIceChannel.OnIceCandidate             += (candidate) => onicecandidate?.Invoke(candidate);
            _rtpIceChannel.OnIceConnectionStateChange += (state) =>
            {
                if (state == RTCIceConnectionState.connected && _rtpIceChannel.NominatedEntry != null)
                {
                    var connectedEP = _rtpIceChannel.NominatedEntry.RemoteCandidate.DestinationEndPoint;
                    base.SetDestination(SDPMediaTypesEnum.audio, connectedEP, connectedEP);
                }

                iceConnectionState = state;
                oniceconnectionstatechange?.Invoke(iceConnectionState);

                if (base.IsSecureContextReady &&
                    iceConnectionState == RTCIceConnectionState.connected &&
                    connectionState != RTCPeerConnectionState.connected)
                {
                    // This is the case where the ICE connection checks completed after the DTLS handshake.
                    connectionState = RTCPeerConnectionState.connected;
                    onconnectionstatechange?.Invoke(RTCPeerConnectionState.connected);
                }
            };
            _rtpIceChannel.OnIceGatheringStateChange += (state) => onicegatheringstatechange?.Invoke(state);
            _rtpIceChannel.OnIceCandidateError       += (candidate, error) => onicecandidateerror?.Invoke(candidate, error);

            OnRtpClosed += Close;
            OnRtcpBye   += Close;

            onnegotiationneeded?.Invoke();

            _rtpIceChannel.StartGathering();
        }
Example #2
0
 public void setConfiguration(RTCConfiguration configuration = null)
 {
     throw new NotImplementedException();
 }
Example #3
0
        /// <summary>
        /// Constructor to create a new RTC peer connection instance.
        /// </summary>
        /// <param name="configuration">Optional.</param>
        public RTCPeerConnection(RTCConfiguration configuration) :
            base(true, true, true, configuration?.X_BindAddress)
        {
            if (_configuration != null &&
                _configuration.iceTransportPolicy == RTCIceTransportPolicy.relay &&
                _configuration.iceServers?.Count == 0)
            {
                throw new ApplicationException("RTCPeerConnection must have at least one ICE server specified for a relay only transport policy.");
            }

            if (configuration != null)
            {
                _configuration = configuration;
                if (_configuration.certificates?.Count > 0)
                {
                    // Find the first certificate that has a usable private key.
                    RTCCertificate usableCert = null;
                    foreach (var cert in _configuration.certificates)
                    {
                        // Attempting to check that a certificate has an exportable private key.
                        // TODO: Does not seem to be a particularly reliable way of checking private key exportability.
                        if (cert.Certificate.HasPrivateKey)
                        {
                            //if (cert.Certificate.PrivateKey is RSACryptoServiceProvider)
                            //{
                            //    var rsa = cert.Certificate.PrivateKey as RSACryptoServiceProvider;
                            //    if (!rsa.CspKeyContainerInfo.Exportable)
                            //    {
                            //        logger.LogWarning($"RTCPeerConnection was passed a certificate for {cert.Certificate.FriendlyName} with a non-exportable RSA private key.");
                            //    }
                            //    else
                            //    {
                            //        usableCert = cert;
                            //        break;
                            //    }
                            //}
                            //else
                            //{
                            usableCert = cert;
                            break;
                            //}
                        }
                    }

                    if (usableCert == null)
                    {
                        throw new ApplicationException("RTCPeerConnection was not able to find a certificate from the input configuration list with a usable private key.");
                    }
                    else
                    {
                        _currentCertificate = usableCert;
                    }
                }

                if (_configuration.X_UseRtpFeedbackProfile)
                {
                    RTP_MEDIA_PROFILE = RTP_MEDIA_FEEDBACK_PROFILE;
                }
            }
            else
            {
                _configuration = new RTCConfiguration();
            }

            // No certificate was provided so create a new self signed one.
            if (_configuration.certificates == null || _configuration.certificates.Count == 0)
            {
                _currentCertificate = new RTCCertificate {
                    Certificate = DtlsUtils.CreateSelfSignedCert()
                };
                _configuration.certificates = new List <RTCCertificate> {
                    _currentCertificate
                };
            }

            SessionID         = Guid.NewGuid().ToString();
            LocalSdpSessionID = Crypto.GetRandomInt(5).ToString();

            // Request the underlying RTP session to create a single RTP channel that will
            // be used to multiplex all required media streams.
            addSingleTrack();

            _rtpIceChannel = GetRtpChannel();

            _rtpIceChannel.OnIceCandidate             += (candidate) => onicecandidate?.Invoke(candidate);
            _rtpIceChannel.OnIceConnectionStateChange += (state) =>
            {
                if (state == RTCIceConnectionState.connected && _rtpIceChannel.NominatedEntry != null)
                {
                    var connectedEP = _rtpIceChannel.NominatedEntry.RemoteCandidate.DestinationEndPoint;
                    base.SetDestination(SDPMediaTypesEnum.audio, connectedEP, connectedEP);

                    logger.LogInformation($"ICE connected to remote end point {AudioDestinationEndPoint}.");

                    DtlsSrtpTransport dtlsHandle = new DtlsSrtpTransport(
                        IceRole == IceRolesEnum.active ?
                        (IDtlsSrtpPeer) new DtlsSrtpClient(_currentCertificate.Certificate) :
                        (IDtlsSrtpPeer) new DtlsSrtpServer(_currentCertificate.Certificate));

                    OnDtlsPacket += (buf) =>
                    {
                        logger.LogDebug($"DTLS transport received {buf.Length} bytes from {AudioDestinationEndPoint}.");
                        dtlsHandle.WriteToRecvStream(buf);
                    };

                    logger.LogDebug($"Starting DLS handshake with role {IceRole}.");
                    Task.Run <bool>(() => DoDtlsHandshake(dtlsHandle))
                    .ContinueWith(t =>
                    {
                        if (t.IsFaulted)
                        {
                            logger.LogWarning($"RTCPeerConnection DTLS handshake task completed in a faulted state. {t.Exception?.Flatten().Message}");

                            connectionState = RTCPeerConnectionState.failed;
                            onconnectionstatechange?.Invoke(connectionState);
                        }
                        else
                        {
                            connectionState = (t.Result) ? RTCPeerConnectionState.connected : connectionState = RTCPeerConnectionState.failed;
                            onconnectionstatechange?.Invoke(connectionState);
                        }
                    });
                }

                iceConnectionState = state;
                oniceconnectionstatechange?.Invoke(iceConnectionState);
            };
            _rtpIceChannel.OnIceGatheringStateChange += (state) => onicegatheringstatechange?.Invoke(state);
            _rtpIceChannel.OnIceCandidateError       += (candidate, error) => onicecandidateerror?.Invoke(candidate, error);

            OnRtpClosed += Close;
            OnRtcpBye   += Close;

            onnegotiationneeded?.Invoke();

            _rtpIceChannel.StartGathering();
        }