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); }
/// <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)); }
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); } }
/// <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; }
public SetDescriptionResultEnum SetRemoteDescription(SdpType type, SDP sessionDescription) { RemoteDescription = sessionDescription; return(SetDescriptionResultEnum.OK); }
public static RTCSdpType ToPlatformNative(this SdpType nativePort) => (RTCSdpType)nativePort;
public SessionDescription(SdpType type, string sdp) { Sdp = sdp; Type = type; }
/// <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); }
/// <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); }