public IEnumerator UnitySetUp() { WebRTC.WebRTC.Initialize(); RTCConfiguration config = default; RTCIceCandidate candidate_ = null; 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); peer1.OnIceCandidate = candidate => { candidate_ = candidate; }; MediaStream stream = WebRTC.Audio.CaptureStream(); peer1.AddTrack(stream.GetTracks().First()); RTCOfferOptions offerOptions = new RTCOfferOptions(); var op1 = peer1.CreateOffer(ref offerOptions); yield return(op1); m_DescOffer = op1.Desc; var op2 = peer1.SetLocalDescription(ref m_DescOffer); yield return(op2); var op3 = peer2.SetRemoteDescription(ref m_DescOffer); yield return(op3); RTCAnswerOptions answerOptions = new RTCAnswerOptions(); var op4 = peer2.CreateAnswer(ref answerOptions); yield return(op4); m_DescAnswer = op4.Desc; var op5 = peer2.SetLocalDescription(ref m_DescAnswer); yield return(op5); var op6 = peer1.SetRemoteDescription(ref m_DescAnswer); yield return(op6); yield return(new WaitUntil(() => candidate_ != null)); m_candidate = candidate_; stream.Dispose(); peer1.Close(); peer2.Close(); m_Context = SynchronizationContext.Current; signaling1 = CreateSignaling(m_SignalingType, m_Context); signaling2 = CreateSignaling(m_SignalingType, m_Context); }
/// <summary> /// Start a "call" based on the current /// media options. /// Client only. /// </summary> /// <returns></returns> public async Task StartCall() { // only called by client, so no need to verify identity. if (this.PeerConnections.Count != 0) { throw new Exception("Peer connection already exists."); } this.PeerConnections.Add(this.LastRegisteredPeer, await this.BuildPeerConnection(this.MediaOpts)); var connectToPeer = this.MediaOpts.SendAudio || this.MediaOpts.ReceiveAudio || this.MediaOpts.SendVideo || this.MediaOpts.ReceiveVideo; if (connectToPeer) { var offerOptions = new RTCOfferOptions() { OfferToReceiveAudio = this.MediaOpts.ReceiveAudio, OfferToReceiveVideo = this.MediaOpts.ReceiveVideo }; // because this is the client, only one peer connection will exist. var offer = await this.PeerConnections[this.LastRegisteredPeer].CreateOffer(offerOptions); await this.PeerConnections[this.LastRegisteredPeer].SetLocalDescription(offer); await this.SendOffer((RTCSessionDescription)offer); } }
/// <summary> /// Creates a new WebRTC peer connection and send an SDP offer to the node DSS server. /// </summary> public IEnumerator Start() { var nodeDssClient = new HttpClient(); Debug.WriteLine($"node-dss starting receive task for server {_nodeDssServerUri}, our ID {_ourID} and their ID {_theirID}."); RTCOfferOptions offerOptions = new RTCOfferOptions(); var createOfferOp = _pc.CreateOffer(ref offerOptions); yield return(createOfferOp); if (createOfferOp.IsError) { Debug.WriteLine($"Error creating local description on peer connection. {createOfferOp.Error}"); } else { Debug.WriteLine($"Offer SDP: {createOfferOp.Desc.sdp}."); var init = createOfferOp.Desc; var setLocalOp = _pc.SetLocalDescription(ref init); yield return(setLocalOp); if (setLocalOp.IsError) { Debug.WriteLine($"Error setting local description on peer connection. {setLocalOp.Error}"); } else { Debug.WriteLine("node-dss sending initial SDP offer to server."); _ = Task.Run(() => ReceiveFromNSS(nodeDssClient, _pc)); } } }
IEnumerator SendOfferCoroutine(string connectionId, RTCPeerConnection pc) { RTCOfferOptions option = new RTCOfferOptions { offerToReceiveAudio = true, offerToReceiveVideo = true }; var offerOp = pc.CreateOffer(ref option); yield return(offerOp); if (offerOp.IsError) { Debug.LogError($"Network Error: {offerOp.Error.message}"); yield break; } if (pc.SignalingState != RTCSignalingState.Stable) { Debug.LogError($"peerConnection's signaling state is not stable. {pc.SignalingState}"); yield break; } var desc = offerOp.Desc; var setLocalSdp = pc.SetLocalDescription(ref desc); yield return(setLocalSdp); if (setLocalSdp.IsError) { Debug.LogError($"Network Error: {setLocalSdp.Error.message}"); yield break; } _signaling.SendOffer(connectionId, desc); }
public IEnumerator SetLocalDescriptionFailed() { var peer = new RTCPeerConnection(); var stream = new MediaStream(); var track = new AudioStreamTrack("audio"); var sender = peer.AddTrack(track, stream); RTCOfferOptions options = default; var op = peer.CreateOffer(ref options); yield return(op); Assert.True(op.IsDone); Assert.False(op.IsError); var desc = op.Desc; // change sdp to cannot parse desc.sdp = desc.sdp.Replace("m=audio", "m=audiable"); var op2 = peer.SetLocalDescription(ref desc); yield return(op2); Assert.True(op2.IsDone); Assert.True(op2.IsError); Assert.IsNotEmpty(op2.Error.message); peer.RemoveTrack(sender); track.Dispose(); stream.Dispose(); peer.Close(); peer.Dispose(); }
private RTCSessionDescriptionAsyncOperation StartClientOffer() { // Client caller code. RTCOfferOptions options = default; return(_peerConnection.CreateOffer(ref options)); }
public async Task StartCall() { if (this.peerConnection != null) { throw new Exception(); } this.peerConnection = await this.buildPeerConnection(this.mediaOptions); var connectToPeer = this.mediaOptions.SendAudio || this.mediaOptions.ReceiveAudio || this.mediaOptions.SendVideo || this.mediaOptions.ReceiveVideo; if (connectToPeer) { var offerOptions = new RTCOfferOptions() { OfferToReceiveAudio = this.mediaOptions.ReceiveAudio, OfferToReceiveVideo = this.mediaOptions.ReceiveVideo }; var offer = await this.peerConnection.CreateOffer(offerOptions); await this.peerConnection.SetLocalDescription(offer); await this.signaller.SendOffer((RTCSessionDescription)offer); } }
public IEnumerator SetLocalDescription() { var peer = new RTCPeerConnection(); RTCOfferOptions options = default; var op = peer.CreateOffer(ref options); yield return(op); Assert.True(op.IsDone); Assert.False(op.IsError); var desc = op.Desc; var op2 = peer.SetLocalDescription(ref desc); yield return(op2); Assert.True(op2.IsDone); Assert.False(op2.IsError); var desc2 = peer.LocalDescription; Assert.AreEqual(desc.sdp, desc2.sdp); Assert.AreEqual(desc.type, desc2.type); peer.Close(); peer.Dispose(); }
public Task <RTCSessionDescriptionInit> CreateOffer(RTCOfferOptions options) { var tcs = new TaskCompletionSource <RTCSessionDescriptionInit>(); ((Webrtc.PeerConnection)NativeObject).CreateOffer( new SdpObserverProxy(tcs), new Webrtc.MediaConstraints() /*NativeDefaultMediaConstraints*/); return(tcs.Task); }
public IEnumerator CurrentDirection() { var config = GetConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); var audioTrack = new AudioStreamTrack("audio"); var transceiver1 = peer1.AddTransceiver(TrackKind.Audio); transceiver1.Direction = RTCRtpTransceiverDirection.RecvOnly; Assert.IsNull(transceiver1.CurrentDirection); RTCOfferOptions options1 = new RTCOfferOptions { offerToReceiveAudio = true }; 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 transceiver2 = peer2.GetTransceivers().First(x => x.Receiver.Track.Kind == TrackKind.Audio); Assert.True(transceiver2.Sender.ReplaceTrack(audioTrack)); transceiver2.Direction = RTCRtpTransceiverDirection.SendOnly; 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); Assert.AreEqual(transceiver1.CurrentDirection, RTCRtpTransceiverDirection.RecvOnly); Assert.AreEqual(transceiver2.CurrentDirection, RTCRtpTransceiverDirection.SendOnly); audioTrack.Dispose(); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); }
public async Task <RTCSessionDescriptionInit> CreateOffer(RTCOfferOptions options) { var jsObjectRef = await JsRuntime.CallJsMethodAsync <JsObjectRef>(NativeObject, "createOffer", options); var descriptor = JsRuntime.GetJsPropertyValue <RTCSessionDescriptionInit>(jsObjectRef, null); JsRuntime.DeleteJsObjectRef(jsObjectRef.JsObjectRefId); return(descriptor); }
/// <summary> /// Attempts to place a new outgoing call. /// </summary> /// <param name="sipCallDescriptor">A call descriptor containing the information about how /// and where to place the call.</param> /// <param name="mediaSession">The media session used for this call</param> public async Task InitiateCallAsync(SIPCallDescriptor sipCallDescriptor, IMediaSession mediaSession) { m_cts = new CancellationTokenSource(); m_uac = new SIPClientUserAgent(m_transport); m_uac.CallTrying += ClientCallTryingHandler; m_uac.CallRinging += ClientCallRingingHandler; m_uac.CallAnswered += ClientCallAnsweredHandler; m_uac.CallFailed += ClientCallFailedHandler; // Can be DNS lookups involved in getting the call destination. SIPEndPoint serverEndPoint = await Task.Run <SIPEndPoint>(() => { return(m_uac.GetCallDestination(sipCallDescriptor)); }).ConfigureAwait(false); if (serverEndPoint != null) { MediaSession = mediaSession; MediaSession.OnRtpEvent += OnRemoteRtpEvent; //MediaSession.OnRtpClosed += (reason) => Hangup(); MediaSession.OnRtpClosed += (reason) => { if (!MediaSession.IsClosed) { logger.LogWarning($"RTP channel was closed with reason {reason}."); } }; RTCOfferOptions offerOptions = new RTCOfferOptions { RemoteSignallingAddress = serverEndPoint.Address }; var sdp = await mediaSession.createOffer(offerOptions).ConfigureAwait(false); mediaSession.setLocalDescription(new RTCSessionDescription { sdp = sdp, type = RTCSdpType.offer }); if (mediaSession.localDescription == null) { ClientCallFailed?.Invoke(m_uac, $"Could not create a local SDP offer."); CallEnded(); } else { sipCallDescriptor.Content = mediaSession.localDescription.sdp.ToString(); // This initiates the call but does not wait for an answer. m_uac.Call(sipCallDescriptor); } } else { ClientCallFailed?.Invoke(m_uac, $"Could not resolve destination when placing call to {sipCallDescriptor.Uri}."); CallEnded(); } }
private static IEnumerator SignalingPeers(RTCPeerConnection offerPc, RTCPeerConnection answerPc) { offerPc.OnIceCandidate = candidate => answerPc.AddIceCandidate(ref candidate); answerPc.OnIceCandidate = candidate => offerPc.AddIceCandidate(ref candidate); var offerOption = new RTCOfferOptions {offerToReceiveVideo = true}; var answerOption = new RTCAnswerOptions {iceRestart = false}; var pc1CreateOffer = offerPc.CreateOffer(ref offerOption); yield return pc1CreateOffer; Assert.False(pc1CreateOffer.IsError); var offerDesc = pc1CreateOffer.Desc; var pc1SetLocalDescription = offerPc.SetLocalDescription(ref offerDesc); yield return pc1SetLocalDescription; Assert.False(pc1SetLocalDescription.IsError); var pc2SetRemoteDescription = answerPc.SetRemoteDescription(ref offerDesc); yield return pc2SetRemoteDescription; Assert.False(pc2SetRemoteDescription.IsError); var pc2CreateAnswer = answerPc.CreateAnswer(ref answerOption); yield return pc2CreateAnswer; Assert.False(pc2CreateAnswer.IsError); var answerDesc = pc2CreateAnswer.Desc; var pc2SetLocalDescription = answerPc.SetLocalDescription(ref answerDesc); yield return pc2SetLocalDescription; Assert.False(pc2SetLocalDescription.IsError); var pc1SetRemoteDescription = offerPc.SetRemoteDescription(ref answerDesc); yield return pc1SetRemoteDescription; Assert.False(pc1SetRemoteDescription.IsError); var waitConnectOfferPc = new WaitUntilWithTimeout(() => offerPc.IceConnectionState == RTCIceConnectionState.Connected || offerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return waitConnectOfferPc; Assert.True(waitConnectOfferPc.IsCompleted); var waitConnectAnswerPc = new WaitUntilWithTimeout(() => answerPc.IceConnectionState == RTCIceConnectionState.Connected || answerPc.IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return waitConnectAnswerPc; Assert.True(waitConnectAnswerPc.IsCompleted); var checkSenders = new WaitUntilWithTimeout(() => offerPc.GetSenders().Any(), 5000); yield return checkSenders; Assert.True(checkSenders.IsCompleted); var checkReceivers = new WaitUntilWithTimeout(() => answerPc.GetReceivers().Any(), 5000); yield return checkReceivers; Assert.True(checkReceivers.IsCompleted); }
public async Task <RTCSessionDescriptionInit> CreateOffer(RTCOfferOptions options) { var tcs = new TaskCompletionSource <RTCSessionDescriptionInit>(); ((Webrtc.PeerConnection)NativeObject).CreateOffer( new SdpObserverProxy(tcs), new Webrtc.MediaConstraints() /*NativeDefaultMediaConstraints*/); var offer = await tcs.Task; // Android DOES NOT expose 'Type'!!! I set it manually here. offer.Type = RTCSdpType.Offer; return(offer); }
public IEnumerator PeerConnection_CreateOffer() { var config = GetConfiguration(); var peer = new RTCPeerConnection(ref config); RTCOfferOptions options = default; var op = peer.CreateOffer(ref options); yield return(op); Assert.True(op.isDone); Assert.False(op.isError); peer.Close(); }
public Task <RTCSessionDescriptionInit> CreateOffer(RTCOfferOptions options) { var tcs = new TaskCompletionSource <RTCSessionDescriptionInit>(); ((Webrtc.RTCPeerConnection)NativeObject).OfferForConstraints( new Webrtc.RTCMediaConstraints(null, null),////NativeDefaultRTCMediaConstraints, (nativeSessionDescription, nsError) => { if (nsError != null) { tcs.SetException(new Exception($"{nsError.LocalizedDescription}")); } tcs.SetResult(nativeSessionDescription.FromNative()); }); return(tcs.Task); }
IEnumerator OnNegotiationNeeded(ISignaling signaling, string connectionId, bool isOffer) { if (!isOffer) { yield break; } if (!m_mapConnectionIdAndPeer.TryGetValue(connectionId, out var pc)) { Debug.LogError($"connectionId: {connectionId}, did not created peerConnection"); yield break; } RTCOfferOptions option = new RTCOfferOptions { offerToReceiveAudio = true, offerToReceiveVideo = true }; var offerOp = pc.CreateOffer(ref option); yield return(offerOp); if (offerOp.IsError) { Debug.LogError($"Network Error: {offerOp.Error.message}"); yield break; } if (pc.SignalingState != RTCSignalingState.Stable) { Debug.LogError($"peerConnection's signaling state is not stable."); yield break; } var desc = offerOp.Desc; var setLocalSdp = pc.SetLocalDescription(ref desc); yield return(setLocalSdp); if (setLocalSdp.IsError) { Debug.LogError($"Network Error: {setLocalSdp.Error.message}"); yield break; } signaling.SendOffer(connectionId, desc); }
public IEnumerator SetRemoteDescription() { var config = GetConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); var conf = new RTCDataChannelInit(true); var channel1 = peer1.CreateDataChannel("data", ref conf); 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 desc2 = peer1.RemoteDescription; Assert.AreEqual(desc.sdp, desc2.sdp); Assert.AreEqual(desc.type, desc2.type); channel1.Dispose(); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); }
public async Task <ICallInfo> PlaceCallAsync(CallConfiguration config) { Debug.Assert(_peerId == -1); if (PeerConnection != null) { Debug.WriteLine("[Error] We only support connection to one peer at a time."); return(null); } if (CreatePeerConnection()) { string selectedAudioCodecName = (string)_localSettings.Values["SelectedAudioCodecName"]; string selectedVideoCodecName = (string)_localSettings.Values["SelectedVideoCodecName"]; _peerId = PeerId; var offerOptions = new RTCOfferOptions(); offerOptions.OfferToReceiveAudio = true; offerOptions.OfferToReceiveVideo = true; IRTCSessionDescription offer = await PeerConnection.CreateOffer(offerOptions); // Alter sdp to force usage of selected codecs string modifiedSdp = offer.Sdp; SdpUtils.SelectCodec(ref modifiedSdp, selectedAudioCodecName, "audio"); SdpUtils.SelectCodec(ref modifiedSdp, selectedVideoCodecName, "video"); RTCSessionDescriptionInit sdpInit = new RTCSessionDescriptionInit(); sdpInit.Sdp = modifiedSdp; sdpInit.Type = offer.SdpType; var modifiedOffer = new RTCSessionDescription(sdpInit); await PeerConnection.SetLocalDescription(modifiedOffer); Debug.WriteLine($"Sending offer: {modifiedOffer.Sdp}"); string jsonString = SdpToJsonString(modifiedOffer); CallInfo callInfo = new CallInfo(); callInfo.SetCall(new Call()); callInfo.SetSdp(modifiedSdp); callInfo.SetJsonString(jsonString); OnSendMessageToRemotePeer.Invoke(this, jsonString); return(callInfo); } return(null); }
public IEnumerator PeerConnection_SetRemoteDescription() { 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 channel1 = null; var conf = new RTCDataChannelInit(true); channel1 = peer1.CreateDataChannel("data", ref conf); RTCOfferOptions options1 = default; RTCAnswerOptions options2 = default; var op1 = peer1.CreateOffer(ref options1); yield return(op1); var op2 = peer1.SetLocalDescription(ref op1.desc); yield return(op2); var op3 = peer2.SetRemoteDescription(ref op1.desc); yield return(op3); var op4 = peer2.CreateAnswer(ref options2); yield return(op4); var op5 = peer2.SetLocalDescription(ref op4.desc); yield return(op5); var op6 = peer1.SetRemoteDescription(ref op4.desc); yield return(op6); channel1.Dispose(); peer1.Dispose(); peer2.Dispose(); }
public IEnumerator PeerConnection_SetLocalDescription() { var peer = new RTCPeerConnection(); RTCOfferOptions options = default; var op = peer.CreateOffer(ref options); yield return(op); Assert.True(op.isDone); Assert.False(op.isError); var op2 = peer.SetLocalDescription(ref op.desc); yield return(op2); Assert.True(op2.isDone); Assert.False(op2.isError); peer.Close(); }
public async Task <string> GenerateClientOffer() { Logger.Debug("PeerChannel", "GenerateClientOffer"); if (Conn == null) { Logger.Debug("PeerChannel", "should initialize beforehand"); return(string.Empty); } Conn.AddTransceiver("audio"); Conn.AddTransceiver("video"); var opts = new RTCOfferOptions(); var capabilities = await Conn.CreateOffer(opts); return(capabilities.Sdp); }
public Task <SDP> createOffer(RTCOfferOptions options) { SDP offerSdp = new SDP(IPAddress.Loopback); offerSdp.SessionId = Crypto.GetRandomInt(5).ToString(); offerSdp.Connection = new SDPConnectionInformation(IPAddress.Loopback); SDPMediaAnnouncement audioAnnouncement = new SDPMediaAnnouncement( SDPMediaTypesEnum.audio, 1234, new List <SDPMediaFormat> { new SDPMediaFormat(SDPMediaFormatsEnum.PCMU) }); audioAnnouncement.Transport = RTP_MEDIA_PROFILE; offerSdp.Media.Add(audioAnnouncement); return(Task.FromResult(offerSdp)); }
public IEnumerator SetRemoteDescriptionFailed() { var config = GetConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); var stream = new MediaStream(); var track = new AudioStreamTrack("audio"); var sender = peer1.AddTrack(track, stream); RTCOfferOptions options1 = default; var op1 = peer1.CreateOffer(ref options1); yield return(op1); var desc = op1.Desc; var op2 = peer1.SetLocalDescription(ref desc); yield return(op2); // change sdp to cannot parse desc.sdp = desc.sdp.Replace("m=audio", "m=audiable"); var op3 = peer2.SetRemoteDescription(ref desc); yield return(op3); Assert.True(op3.IsDone); Assert.True(op3.IsError); Assert.IsNotEmpty(op3.Error.message); peer1.RemoveTrack(sender); track.Dispose(); stream.Dispose(); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); }
public IEnumerator CreateAnswer() { var config = GetConfiguration(); var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); var conf = new RTCDataChannelInit(true); peer1.CreateDataChannel("data", ref conf); 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); Assert.True(op4.IsDone); Assert.False(op4.IsError); peer1.Close(); peer2.Close(); peer1.Dispose(); peer2.Dispose(); }
/// <summary> /// Answers the call request contained in the user agent server parameter. Note the /// <see cref="AcceptCall(SIPRequest)"/> method should be used to create the user agent server. /// Any existing call will be hungup. /// </summary> /// <param name="uas">The user agent server holding the pending call to answer.</param> /// <param name="mediaSession">The media session used for this call</param> /// <param name="customHeaders">Custom SIP-Headers to use in Answer.</param> public async Task Answer(SIPServerUserAgent uas, IMediaSession mediaSession, string[] customHeaders) { // This call is now taking over any existing call. if (IsCallActive) { Hangup(); } else if (uas.IsCancelled) { logger.LogDebug("The incoming call has been cancelled."); mediaSession?.Close("call cancelled"); } else { m_cts = new CancellationTokenSource(); var sipRequest = uas.ClientTransaction.TransactionRequest; MediaSession = mediaSession; MediaSession.OnRtpEvent += OnRemoteRtpEvent; //MediaSession.OnRtpClosed += (reason) => Hangup(); MediaSession.OnRtpClosed += (reason) => { if (!MediaSession.IsClosed) { logger.LogWarning($"RTP channel was closed with reason {reason}."); } }; string sdp = null; if (!String.IsNullOrEmpty(sipRequest.Body)) { // The SDP offer was included in the INVITE request. SDP remoteSdp = SDP.ParseSDPDescription(sipRequest.Body); MediaSession.setRemoteDescription(new RTCSessionDescription { sdp = remoteSdp, type = RTCSdpType.offer }); var sdpAnswer = await MediaSession.createAnswer(null).ConfigureAwait(false); if (sdpAnswer == null) { logger.LogWarning($"Could not generate an SDP answer."); m_uas.Reject(SIPResponseStatusCodesEnum.NotAcceptable, null); return; } else { MediaSession.setLocalDescription(new RTCSessionDescription { sdp = sdpAnswer, type = RTCSdpType.answer }); sdp = sdpAnswer.ToString(); } } else { // No SDP offer was included in the INVITE request need to wait for the ACK. RTCOfferOptions offerOptions = new RTCOfferOptions { RemoteSignallingAddress = sipRequest.RemoteSIPEndPoint.GetIPEndPoint().Address }; var sdpOffer = await MediaSession.createOffer(offerOptions).ConfigureAwait(false); if (sdpOffer == null) { // This shouldn't occur unless we're unable to create an audio/video track. logger.LogWarning($"Could not generate an SDP answer."); m_uas.Reject(SIPResponseStatusCodesEnum.NotAcceptable, null); return; } else { MediaSession.setLocalDescription(new RTCSessionDescription { sdp = sdpOffer, type = RTCSdpType.offer }); sdp = sdpOffer.ToString(); } } m_uas = uas; // In cases where the initial INVITE did not contain an SDP offer the action sequence is: // - INVITE with no SDP offer received, // - Reply with OK and an SDP offer, // - Wait for ACK with SDP answer. TaskCompletionSource <SIPDialogue> dialogueCreatedTcs = new TaskCompletionSource <SIPDialogue>(TaskCreationOptions.RunContinuationsAsynchronously); m_uas.OnDialogueCreated += (dialogue) => dialogueCreatedTcs.TrySetResult(dialogue); m_uas.Answer(m_sdpContentType, sdp, null, SIPDialogueTransferModesEnum.Default, customHeaders); await Task.WhenAny(dialogueCreatedTcs.Task, Task.Delay(WAIT_DIALOG_TIMEOUT)).ConfigureAwait(false); if (Dialogue != null) { if (MediaSession.remoteDescription == null || MediaSession.remoteDescription.sdp == null) { // If the initial INVITE did not contain an offer then the remote description will not yet be set. var remoteSDP = SDP.ParseSDPDescription(Dialogue.RemoteSDP); MediaSession.setRemoteDescription(new RTCSessionDescription { sdp = remoteSDP, type = RTCSdpType.answer }); } Dialogue.DialogueState = SIPDialogueStateEnum.Confirmed; await MediaSession.Start().ConfigureAwait(false); } else { logger.LogWarning("The attempt to answer a call failed as the dialog was not created. The likely cause is the ACK not being received in time."); MediaSession.Close("dialog creation failed"); Hangup(); } } }
public IEnumerator DataChannel_EventsAreSentToOther() { RTCConfiguration config = default; config.iceServers = new RTCIceServer[] { new RTCIceServer { urls = new string[] { "stun:stun.l.google.com:19302" } } }; var peer1 = new RTCPeerConnection(ref config); var peer2 = new RTCPeerConnection(ref config); RTCDataChannel channel1 = null, channel2 = null; peer1.OnIceCandidate = new DelegateOnIceCandidate(candidate => { peer2.AddIceCandidate(ref candidate); }); peer2.OnIceCandidate = new DelegateOnIceCandidate(candidate => { peer1.AddIceCandidate(ref candidate); }); peer2.OnDataChannel = new DelegateOnDataChannel(channel => { channel2 = channel; }); var conf = new RTCDataChannelInit(true); channel1 = peer1.CreateDataChannel("data", ref conf); RTCOfferOptions options1 = default; RTCAnswerOptions options2 = default; var op1 = peer1.CreateOffer(ref options1); yield return(op1); var op2 = peer1.SetLocalDescription(ref op1.desc); yield return(op2); var op3 = peer2.SetRemoteDescription(ref op1.desc); yield return(op3); var op4 = peer2.CreateAnswer(ref options2); yield return(op4); var op5 = peer2.SetLocalDescription(ref op4.desc); yield return(op5); var op6 = peer1.SetRemoteDescription(ref op4.desc); yield return(op6); yield return(new WaitUntil(() => peer1.IceConnectionState == RTCIceConnectionState.Connected || peer1.IceConnectionState == RTCIceConnectionState.Completed)); yield return(new WaitUntil(() => peer2.IceConnectionState == RTCIceConnectionState.Connected || peer2.IceConnectionState == RTCIceConnectionState.Completed)); yield return(new WaitUntil(() => channel2 != null)); Assert.AreEqual(channel1.Label, channel2.Label); Assert.AreEqual(channel1.Id, channel2.Id); string message1 = "hello"; string message2 = null; channel2.OnMessage = new DelegateOnMessage(bytes => { message2 = System.Text.Encoding.UTF8.GetString(bytes); }); channel1.Send(message1); yield return(new WaitUntil(() => !string.IsNullOrEmpty(message2))); Assert.AreEqual(message1, message2); byte[] message3 = { 1, 2, 3 }; byte[] message4 = null; channel2.OnMessage = new DelegateOnMessage(bytes => { message4 = bytes; }); channel1.Send(message3); yield return(new WaitUntil(() => message4 != null)); Assert.AreEqual(message3, message4); peer1.Close(); peer2.Close(); }
IEnumerator Start() { RTCConfiguration config = default; config.iceServers = new[] { new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } } }; peers[0] = new RTCPeerConnection(ref config); peers[1] = new RTCPeerConnection(ref config); dataChannels[peers[0]] = new List <RTCDataChannel>(); dataChannels[peers[1]] = new List <RTCDataChannel>(); RTCDataChannel channel = peers[0].CreateDataChannel("data"); dataChannels[peers[0]].Add(channel); peers[0].OnIceCandidate = candidate => { Assert.NotNull(candidate); Assert.NotNull(candidate.Candidate); peers[1].AddIceCandidate(candidate); }; peers[1].OnIceCandidate = candidate => { Assert.NotNull(candidate); Assert.NotNull(candidate.Candidate); peers[0].AddIceCandidate(candidate); }; peers[1].OnTrack = e => { Assert.NotNull(e); Assert.NotNull(e.Track); Assert.NotNull(e.Receiver); Assert.NotNull(e.Transceiver); peers[1].AddTrack(e.Track); }; peers[0].OnDataChannel = e => { if (peers[0].ConnectionState == RTCPeerConnectionState.Connected) { dataChannels[peers[0]].Add(e); } }; peers[1].OnDataChannel = e => { if (peers[1].ConnectionState == RTCPeerConnectionState.Connected) { dataChannels[peers[1]].Add(e); } }; if (m_stream != null) { foreach (var track in m_stream.GetTracks()) { peers[0].AddTrack(track, m_stream); } } RTCOfferOptions options1 = default; RTCAnswerOptions options2 = default; var op1 = peers[0].CreateOffer(ref options1); yield return(op1); Assert.False(op1.IsError); var desc = op1.Desc; var op2 = peers[0].SetLocalDescription(ref desc); yield return(op2); Assert.False(op2.IsError); desc.sdp = ReplaceOfferSdpForHardwareEncodeTest(desc.sdp); var op3 = peers[1].SetRemoteDescription(ref desc); yield return(op3); Assert.False(op3.IsError); var op4 = peers[1].CreateAnswer(ref options2); yield return(op4); Assert.False(op4.IsError); desc = op4.Desc; var op5 = peers[1].SetLocalDescription(ref desc); yield return(op5); Assert.False(op5.IsError); desc.sdp = ReplaceAnswerSdpForHardwareEncodeTest(desc.sdp); var op6 = peers[0].SetRemoteDescription(ref desc); yield return(op6); Assert.False(op6.IsError); var op7 = new WaitUntilWithTimeout(() => peers[0].IceConnectionState == RTCIceConnectionState.Connected || peers[0].IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op7); Assert.True(op7.IsCompleted); var op8 = new WaitUntilWithTimeout(() => peers[1].IceConnectionState == RTCIceConnectionState.Connected || peers[1].IceConnectionState == RTCIceConnectionState.Completed, 5000); yield return(op8); Assert.True(op8.IsCompleted); if (m_stream != null) { var op9 = new WaitUntilWithTimeout(() => GetPeerSenders(0).Any(), 5000); yield return(op9); Assert.True(op9.IsCompleted); } IsTestFinished = true; }
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(candidate); }; peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(candidate); }; peer2.OnDataChannel = channel => { channel2 = channel; }; var channel1 = peer1.CreateDataChannel("data"); 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(); }
public IEnumerator IceConnectionStateChange() { 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); peer1.OnIceCandidate = candidate => { peer2.AddIceCandidate(ref candidate); }; peer2.OnIceCandidate = candidate => { peer1.AddIceCandidate(ref candidate); }; MediaStream stream = Audio.CaptureStream(); peer1.AddTrack(stream.GetTracks().First()); 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); stream.Dispose(); peer1.Close(); peer2.Close(); }