Ejemplo n.º 1
0
        public bool SetupRemote(List <SDPSecurityDescription> securityDescription, SdpType sdpType)
        {
            m_remoteSecurityDescriptions = securityDescription;

            if (sdpType == SdpType.offer)
            {
                IsNegotiationComplete = false;
                return(true);
            }

            if (m_localSecurityDescriptions.Count == 0)
            {
                throw new ApplicationException("Setup remote crypto failed. No cryto attribute in offer.");
            }

            if (m_remoteSecurityDescriptions.Count == 0)
            {
                throw new ApplicationException("Setup remote crypto failed. No cryto attribute in answer.");
            }

            var rsec = m_remoteSecurityDescriptions[0];
            var lsec = m_localSecurityDescriptions.FirstOrDefault(x => x.CryptoSuite == rsec.CryptoSuite);

            if (lsec != null && lsec.Tag == rsec.Tag)
            {
                IsNegotiationComplete = true;
                SrtpEncoder           = GenerateRtpEncoder(lsec);
                SrtpDecoder           = GenerateRtpDecoder(rsec);
                SrtcpEncoder          = GenerateRtcpEncoder(lsec);
                SrtcpDecoder          = GenerateRtcpDecoder(rsec);
                return(true);
            }

            return(false);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// This set remote description overload is a convenience method for SIP/VoIP callers
        /// instead of WebRTC callers. The method signature better matches what the SIP
        /// user agent is expecting.
        /// TODO: Using two very similar overloads could cause confusion. Possibly
        /// consolidate.
        /// </summary>
        /// <param name="sdpType">Whether the remote SDP is an offer or answer.</param>
        /// <param name="sessionDescription">The SDP from the remote party.</param>
        /// <returns>The result of attempting to set the remote description.</returns>
        public override SetDescriptionResultEnum SetRemoteDescription(SdpType sdpType, SDP sessionDescription)
        {
            RTCSessionDescriptionInit init = new RTCSessionDescriptionInit
            {
                sdp  = sessionDescription.ToString(),
                type = (sdpType == SdpType.answer) ? RTCSdpType.answer : RTCSdpType.offer
            };

            return(setRemoteDescription(init));
        }
Ejemplo n.º 3
0
        public static SessionDescription.Type ToNative(this SdpType self)
        {
            switch (self)
            {
            case SdpType.Answer:
                return(SessionDescription.Type.Answer);

            case SdpType.Offer:
                return(SessionDescription.Type.Offer);

            default:
                throw new ArgumentOutOfRangeException(nameof(self), self, null);
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Updates the session after receiving the remote SDP.
        /// At this point check that the codecs match. We currently only support:
        ///  - Audio: PCMU,
        ///  - Video: VP8.
        /// If they are not available there's no point carrying on.
        /// </summary>
        /// <param name="sdpType">Whether the remote SDP is an offer or an answer.</param>
        /// <param name="remoteSdp">The answer/offer SDP from the remote party.</param>
        public void setRemoteDescription(SdpType sdpType, SDP remoteSdp)
        {
            var audioAnnounce = remoteSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).FirstOrDefault();

            if (audioAnnounce != null)
            {
                RtpSession.AddTrack(audioAnnounce.MediaID, SDPMediaTypesEnum.audio, true, audioAnnounce.MediaFormats);
            }

            var videoAnnounce = remoteSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).FirstOrDefault();

            if (videoAnnounce != null)
            {
                RtpSession.AddTrack(videoAnnounce.MediaID, SDPMediaTypesEnum.video, true, videoAnnounce.MediaFormats);
            }

            SdpSessionID      = remoteSdp.SessionId;
            RemoteIceUser     = remoteSdp.IceUfrag ?? remoteSdp.Media.First().IceUfrag;
            RemoteIcePassword = remoteSdp.IcePwd ?? remoteSdp.Media.First().IcePwd;

            // All browsers seem to have gone to trickling ICE candidates now but just
            // in case one or more are given we can start the STUN dance immediately.
            if (remoteSdp.IceCandidates != null)
            {
                foreach (var iceCandidate in remoteSdp.IceCandidates)
                {
                    AppendRemoteIceCandidate(iceCandidate);
                }
            }

            foreach (var media in remoteSdp.Media)
            {
                if (media.IceCandidates != null)
                {
                    foreach (var iceCandidate in media.IceCandidates)
                    {
                        AppendRemoteIceCandidate(iceCandidate);
                    }
                }
            }

            m_remoteSDP = remoteSdp;
        }
Ejemplo n.º 5
0
 public SetDescriptionResultEnum SetRemoteDescription(SdpType type, SDP sessionDescription)
 {
     RemoteDescription = sessionDescription;
     return(SetDescriptionResultEnum.OK);
 }
 public static RTCSdpType ToPlatformNative(this SdpType nativePort) => (RTCSdpType)nativePort;
Ejemplo n.º 7
0
 public SessionDescription(SdpType type, string sdp)
 {
     Sdp  = sdp;
     Type = type;
 }
Ejemplo n.º 8
0
        /// <summary>
        /// Updates the session after receiving the remote SDP.
        /// At this point check that the codecs match. We currently only support:
        ///  - Audio: PCMU,
        ///  - Video: VP8.
        /// If they are not available there's no point carrying on.
        /// </summary>
        /// <param name="sessionDescription">The answer/offer SDP from the remote party.</param>
        public SetDescriptionResultEnum setRemoteDescription(RTCSessionDescriptionInit init)
        {
            RTCSessionDescription description = new RTCSessionDescription {
                type = init.type, sdp = SDP.ParseSDPDescription(init.sdp)
            };

            remoteDescription = description;

            SDP remoteSdp = SDP.ParseSDPDescription(init.sdp);

            SdpType sdpType   = (init.type == RTCSdpType.offer) ? SdpType.offer : SdpType.answer;
            var     setResult = base.SetRemoteDescription(sdpType, remoteSdp);

            if (setResult == SetDescriptionResultEnum.OK)
            {
                string remoteIceUser     = remoteSdp.IceUfrag;
                string remoteIcePassword = remoteSdp.IcePwd;
                string dtlsFingerprint   = remoteSdp.DtlsFingerprint;

                var audioAnnounce = remoteSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).FirstOrDefault();
                if (audioAnnounce != null)
                {
                    remoteIceUser     = remoteIceUser ?? audioAnnounce.IceUfrag;
                    remoteIcePassword = remoteIcePassword ?? audioAnnounce.IcePwd;
                    dtlsFingerprint   = dtlsFingerprint ?? audioAnnounce.DtlsFingerprint;
                }

                var videoAnnounce = remoteSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).FirstOrDefault();
                if (videoAnnounce != null)
                {
                    if (remoteIceUser == null || remoteIcePassword == null || dtlsFingerprint == null)
                    {
                        remoteIceUser     = remoteIceUser ?? videoAnnounce.IceUfrag;
                        remoteIcePassword = remoteIcePassword ?? videoAnnounce.IcePwd;
                        dtlsFingerprint   = dtlsFingerprint ?? videoAnnounce.DtlsFingerprint;
                    }
                }

                SdpSessionID = remoteSdp.SessionId;

                if (init.type == RTCSdpType.answer)
                {
                    _rtpIceChannel.IsController = true;
                    // Set DTLS role to be server.
                    IceRole = IceRolesEnum.passive;
                }
                else
                {
                    // Set DTLS role to be server.
                    // As of 20 Jun 2020 the DTLS handshake logic is based on OpenSSL and the mechanism
                    // used hands over the socket handle to the C++ class. This logic works a lot better
                    // when acting as the server in the handshake.
                    IceRole = IceRolesEnum.passive;
                }

                if (remoteIceUser != null && remoteIcePassword != null)
                {
                    _rtpIceChannel.SetRemoteCredentials(remoteIceUser, remoteIcePassword);
                }

                if (!string.IsNullOrWhiteSpace(dtlsFingerprint))
                {
                    dtlsFingerprint = dtlsFingerprint.Trim().ToLower();

                    if (dtlsFingerprint.Length < DTLS_FINGERPRINT_DIGEST.Length + 1)
                    {
                        logger.LogWarning($"The DTLS fingerprint was too short.");
                        return(SetDescriptionResultEnum.DtlsFingerprintDigestNotSupported);
                    }
                    else if (!dtlsFingerprint.StartsWith(DTLS_FINGERPRINT_DIGEST))
                    {
                        logger.LogWarning($"The DTLS fingerprint was supplied with an unsupported digest function (supported one is {DTLS_FINGERPRINT_DIGEST}): {dtlsFingerprint}.");
                        return(SetDescriptionResultEnum.DtlsFingerprintDigestNotSupported);
                    }
                    else
                    {
                        dtlsFingerprint           = dtlsFingerprint.Substring(DTLS_FINGERPRINT_DIGEST.Length + 1).Trim().Replace(":", "").Replace(" ", "");
                        RemotePeerDtlsFingerprint = ByteBufferInfo.ParseHexStr(dtlsFingerprint);
                        logger.LogDebug($"The DTLS fingerprint for the remote peer's SDP {ByteBufferInfo.HexStr(RemotePeerDtlsFingerprint)}.");
                    }
                }
                else
                {
                    logger.LogWarning("The DTLS fingerprint was missing from the remote party's session description.");
                    return(SetDescriptionResultEnum.DtlsFingerprintMissing);
                }

                // All browsers seem to have gone to trickling ICE candidates now but just
                // in case one or more are given we can start the STUN dance immediately.
                if (remoteSdp.IceCandidates != null)
                {
                    foreach (var iceCandidate in remoteSdp.IceCandidates)
                    {
                        addIceCandidate(new RTCIceCandidateInit {
                            candidate = iceCandidate
                        });
                    }
                }

                foreach (var media in remoteSdp.Media)
                {
                    if (media.IceCandidates != null)
                    {
                        foreach (var iceCandidate in media.IceCandidates)
                        {
                            addIceCandidate(new RTCIceCandidateInit {
                                candidate = iceCandidate
                            });
                        }
                    }
                }

                signalingState = RTCSignalingState.have_remote_offer;
                onsignalingstatechange?.Invoke();
            }

            return(setResult);
        }
 public static RTCSdpType ToNative(this SdpType self)
 {
     return((RTCSdpType)self);
 }
Ejemplo n.º 10
0
        /// <summary>
        /// Updates the session after receiving the remote SDP.
        /// At this point check that the codecs match. We currently only support:
        ///  - Audio: PCMU,
        ///  - Video: VP8.
        /// If they are not available there's no point carrying on.
        /// </summary>
        /// <param name="sessionDescription">The answer/offer SDP from the remote party.</param>
        public SetDescriptionResultEnum setRemoteDescription(RTCSessionDescriptionInit init)
        {
            RTCSessionDescription description = new RTCSessionDescription {
                type = init.type, sdp = SDP.ParseSDPDescription(init.sdp)
            };

            remoteDescription = description;

            SDP remoteSdp = SDP.ParseSDPDescription(init.sdp);

            SdpType sdpType   = (init.type == RTCSdpType.offer) ? SdpType.offer : SdpType.answer;
            var     setResult = base.SetRemoteDescription(sdpType, remoteSdp);

            if (setResult == SetDescriptionResultEnum.OK)
            {
                string remoteIceUser     = remoteSdp.IceUfrag;
                string remoteIcePassword = remoteSdp.IcePwd;
                string dtlsFingerprint   = remoteSdp.DtlsFingerprint;

                var audioAnnounce = remoteSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).FirstOrDefault();
                if (audioAnnounce != null)
                {
                    remoteIceUser     = remoteIceUser ?? audioAnnounce.IceUfrag;
                    remoteIcePassword = remoteIcePassword ?? audioAnnounce.IcePwd;
                    dtlsFingerprint   = dtlsFingerprint ?? audioAnnounce.DtlsFingerprint;
                }

                var videoAnnounce = remoteSdp.Media.Where(x => x.Media == SDPMediaTypesEnum.video).FirstOrDefault();
                if (videoAnnounce != null)
                {
                    if (remoteIceUser == null || remoteIcePassword == null || dtlsFingerprint == null)
                    {
                        remoteIceUser     = remoteIceUser ?? videoAnnounce.IceUfrag;
                        remoteIcePassword = remoteIcePassword ?? videoAnnounce.IcePwd;
                        dtlsFingerprint   = dtlsFingerprint ?? videoAnnounce.DtlsFingerprint;
                    }
                }

                SdpSessionID = remoteSdp.SessionId;

                if (init.type == RTCSdpType.answer)
                {
                    _rtpIceChannel.IsController = true;
                    // Set DTLS role to be server.
                    IceRole = IceRolesEnum.passive;
                }
                else
                {
                    // Set DTLS role as client.
                    IceRole = IceRolesEnum.active;
                }

                if (remoteIceUser != null && remoteIcePassword != null)
                {
                    _rtpIceChannel.SetRemoteCredentials(remoteIceUser, remoteIcePassword);
                }

                if (!string.IsNullOrWhiteSpace(dtlsFingerprint))
                {
                    dtlsFingerprint = dtlsFingerprint.Trim().ToLower();
                    if (RTCDtlsFingerprint.TryParse(dtlsFingerprint, out var remoteFingerprint))
                    {
                        RemotePeerDtlsFingerprint = remoteFingerprint;
                    }
                    else
                    {
                        logger.LogWarning($"The DTLS fingerprint was invalid or not supported.");
                        return(SetDescriptionResultEnum.DtlsFingerprintDigestNotSupported);
                    }
                }
                else
                {
                    logger.LogWarning("The DTLS fingerprint was missing from the remote party's session description.");
                    return(SetDescriptionResultEnum.DtlsFingerprintMissing);
                }

                // All browsers seem to have gone to trickling ICE candidates now but just
                // in case one or more are given we can start the STUN dance immediately.
                if (remoteSdp.IceCandidates != null)
                {
                    foreach (var iceCandidate in remoteSdp.IceCandidates)
                    {
                        addIceCandidate(new RTCIceCandidateInit {
                            candidate = iceCandidate
                        });
                    }
                }

                foreach (var media in remoteSdp.Media)
                {
                    if (media.IceCandidates != null)
                    {
                        foreach (var iceCandidate in media.IceCandidates)
                        {
                            addIceCandidate(new RTCIceCandidateInit {
                                candidate = iceCandidate
                            });
                        }
                    }
                }

                signalingState = RTCSignalingState.have_remote_offer;
                onsignalingstatechange?.Invoke();
            }

            return(setResult);
        }